pax_global_header00006660000000000000000000000064137575342350014530gustar00rootroot0000000000000052 comment=5b80a676a2918dbf4b8efc600520332be058aaec pyclustering-0.10.1.2/000077500000000000000000000000001375753423500144775ustar00rootroot00000000000000pyclustering-0.10.1.2/.codedocs000066400000000000000000000000511375753423500162570ustar00rootroot00000000000000DOXYFILE = docs/doxygen_conf_pyclusteringpyclustering-0.10.1.2/.github/000077500000000000000000000000001375753423500160375ustar00rootroot00000000000000pyclustering-0.10.1.2/.github/workflows/000077500000000000000000000000001375753423500200745ustar00rootroot00000000000000pyclustering-0.10.1.2/.github/workflows/build-pyclustering.yml000077500000000000000000000006601375753423500244510ustar00rootroot00000000000000name: Build and Test PyClustering Library on: [push, pull_request] jobs: test-pypi: name: Build and Test PyClustering Library runs-on: ubuntu-latest steps: - name: Clone repository uses: actions/checkout@v1 - name: Set rights to run CI script run: chmod u+x ci/github-ci.sh - name: Run a multi-line script run: ./ci/github-ci.sh TEST_CMAKE_PYCLUSTERING_BUILD pyclustering-0.10.1.2/.github/workflows/test-pypi-installer.yml000066400000000000000000000005611375753423500245520ustar00rootroot00000000000000name: Test PyPi Installer on: [workflow_dispatch] jobs: test-pypi: name: Test PyPi Installer runs-on: ubuntu-latest steps: - name: Clone repository uses: actions/checkout@v1 - name: Set rights to run CI script run: chmod u+x ci/github-ci.sh - name: Run a multi-line script run: ./ci/github-ci.sh PYPI_INSTALLER pyclustering-0.10.1.2/.github/workflows/test-testpypi-installer.yml000077500000000000000000000005751375753423500254620ustar00rootroot00000000000000name: Test TestPyPi Installer on: [workflow_dispatch] jobs: test-pypi: name: Test TestPyPi Installer runs-on: ubuntu-latest steps: - name: Clone repository uses: actions/checkout@v1 - name: Set rights to run CI script run: chmod u+x ci/github-ci.sh - name: Run a multi-line script run: ./ci/github-ci.sh TESTPYPI_INSTALLER pyclustering-0.10.1.2/.gitignore000066400000000000000000000041031375753423500164650ustar00rootroot00000000000000# C++ related files # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app # python related files # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ pyclustering-0.10.1.2/.travis.yml000077500000000000000000000053651375753423500166240ustar00rootroot00000000000000dist: bionic language: generic os: - linux addons: apt: sources: - ubuntu-toolchain-r-test packages: - g++ - gcc - python3 install: - chmod u+x ci/travis-ci.sh env: global: - secure: "wfln46zny1pbK12ZkicS/t/Fv/xDUiuwYF52uKWwoNJTDaTZ2nJlw7nr6kmSc/MoGBNvdsse2oSRqvWakOvsY+m3urNCqkzsaLILiumGsAy8zZOfEHrAXQJRmyvxdk+EQB3NJwVU41TYOAlmIKV85Dja1cnoDTfUt0gPFdgUCslZPvNFZT7jgiKnycjaveJjAdClENL0EHesqLh46Nml2UFoZRjRnMooqfxKNxdlStkzozHG9mrf7+sJSDWD0iByhaEK1RiIv7AJ7DS4gGNekoUET07EdvE9kg9Qq8O9T+9kOefYQf+1erg94cSbCV6ht2OmzlUDAlsZ7Gco4/PtgqNlWIShHlEuHsjfqz5dmyAHZsX+ICsaNTGqWnUVci/Eq09U80q2SSes2RbYvtmR9Be4X8FQ8effDrrTU9t4tpHB8/qnZj9nTjIZMH6yyprKSz+hDnNjuvYAx0LyBES/mGOKZx1LXhdZViknokwvquDtExL3dIXJDpnlr0z/nCmTdZMr8A4H09YvWnYVus2sWXbA8xO/yAenA719MTDcd4DiPzgZNtRNbWmW6M1M9UapVP8a/bSB5gMmfsLZtz34jTHO0TOKmPuANmepydurwniSh3S/0SoR8AR0/7M3RbDiODcttH9TY868UVPKj/oAe36VOEZuIYeIFU0Sv5z/Hz8=" - secure: "MlG1NaREINYp2vPAyOZNpN3KsbczdJwAdpzHmHmPNfxG14eEZSbEeLmVNfZm9rfOE12IKUsfQn0tLEfpQJA5AAuDr5pG+0HuWC9Kx4VZUQID+H5V9t5C3KxfPl4ESfEnsKbXWOAqnyhL+G7KqUhHLt7KCxk3/UCC//whum9SjrpjBQqx19fb48k8ylqN5Etwk3VtHPlKEHiD3FErfsLXp/F87ZDTGenl/GYFFFajHZT9SXWxOavoaeJRsP+f3vbKC6Sd/tsKyuJ9i9bQV91EOEf1QhInfNBCVoFZpGt1nAQglcnbpj7hvsWeI1ajm/GNUYIddDhwPWaibgBnu3Kw2AiKxHZKHsFu3uQ0aN8TjPGvFH9xrcCkwP/x66KIR01VQjeVvp8MPtttZm4PZChWnD8ydBooYCVTh78rIlm4LCOpKXVWSKBYFBRhecS1bxwQFtlHIiQzuJbFMVLJNMkknNeikIdMlHOSsioOU63bjH/maL0vtfIhuqCAAe1MA/KI/C9+mqTZUqDhOwSs91zkhwxyW+FZCRDlKr8LVREJnP0Tecn45Jr2yXGPTOWGPf912J5GEb2ttTy3Q/HYKyBIcfDv7NAijNQjjVuwxYpH9evQceoTaR/hmpxMYp5NiTKGSZjB1lNdMXYAzpIx+j3QGB1PHplOzYv5spTrTMncNuA=" jobs: include: - if: type = push OR type = pull_request name: "Build C/C++ part (Linux)." env: JOB_ID=BUILD_CCORE - if: type = push OR type = pull_request name: "Run C/C++ static code analyser." env: JOB_ID=ANALYSE_CCORE - if: type = push OR type = pull_request name: "Run unit-tests for C/C++ part." env: JOB_ID=UT_CCORE - if: type = push OR type = pull_request name: "Run memory leak analyser (valgrind) for C/C++ part." env: JOB_ID=VALGRIND_CCORE - if: type = push OR type = pull_request name: "PyClustering unit and integration testing." env: JOB_ID=TEST_PYCLUSTERING - if: type = push OR type = pull_request name: "Build C/C++ part (MacOS) and intergration testing." os: osx env: JOB_ID=BUILD_TEST_CCORE_MACOS - if: type = push OR type = pull_request name: "Build documentation." dist: trusty env: JOB_ID=DOCUMENTATION - if: type = api OR env(JOB_ID) = PYPI_INSTALL name: "Run PyPi installer and run tests." - if: type = api OR env(JOB_ID) = TESTPYPI_INSTALL name: "Run TestPyPi install and run tests." script: ./ci/travis-ci.sh $JOB_ID pyclustering-0.10.1.2/CHANGES000077500000000000000000001333461375753423500155070ustar00rootroot00000000000000------------------------------------------------------------------------ CHANGE NOTES FOR 0.10.1.2 (STARTED Nov 25, 2020), (RELEASED: Nov 25, 2020) ------------------------------------------------------------------------ CORRECTED MAJOR BUGS: - Corrected bug with empty clusters for K-Medoids (C++ `pyclustering::clst::kmeadois`). See: https://github.com/annoviko/pyclustering/issues/659 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.10.1.1 (STARTED Nov 24, 2020), (RELEASED: Nov 24, 2020) ------------------------------------------------------------------------ CORRECTED MAJOR BUGS: - Corrected bug with incorrect cluster allocation for K-Medoids (C++ `pyclustering::clst::kmeadois`). See: https://github.com/annoviko/pyclustering/issues/659 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.10.1 (STARTED Aug 17, 2020), (RELEASED: Nov 19, 2020) ------------------------------------------------------------------------ GENERAL CHANGES: - The library is distributed under `BSD-3-Clause` library. See: https://github.com/annoviko/pyclustering/issues/517 - C++ pyclustering can be built using CMake. See: https://github.com/annoviko/pyclustering/issues/603 - Supported dumping and loading for DBSCAN algorithm via `pickle` (Python: `pyclustering.cluster.dbscan`). See: https://github.com/annoviko/pyclustering/issues/650 - Package installer resolves all required dependencies automatically. See: https://github.com/annoviko/pyclustering/issues/647 - Introduced human-readable error for genetic clustering algorithm in case of non-normalized data (Python: `pyclustering.cluster.ga`). See: https://github.com/annoviko/pyclustering/issues/597 - Optimized windows implementation `parallel_for` and `parallel_for_each` by using `pyclustering::parallel` instead of `PPL` that affects all algorithms which use these functions (C++: `pyclustering::parallel`). See: https://github.com/annoviko/pyclustering/issues/642 - Optimized `parallel_for` algorithm for short cycles that affects all algorithms which use `parallel_for` (C++: `pyclustering::parallel`). See: https://github.com/annoviko/pyclustering/issues/642 - Introduced `kstep` parameter for `elbow` algorithm to use custom K search steps (Python: `pyclustering.cluster.elbow`, C++: `pyclustering::cluster::elbow`). See: https://github.com/annoviko/pyclustering/issues/489 - Introduced `p_step` parameter for `parallel_for` function (C++: `pyclustering::parallel`). See: https://github.com/annoviko/pyclustering/issues/640 - Optimized python implementation of K-Medoids algorithm (Python: `pyclustering.cluster.kmedoids`). See: https://github.com/annoviko/pyclustering/issues/526 - C++ pyclustering CLIQUE interface returns human-readable errors (Python: `pyclustering.cluster.clique`). See: https://github.com/annoviko/pyclustering/issues/635 See: https://github.com/annoviko/pyclustering/issues/634 - Introduced `metric` parameter for X-Means algorithm to use custom metric for clustering (Python: `pyclustering.cluster.xmeans`; C++ `pyclustering::clst::xmeans`). See: https://github.com/annoviko/pyclustering/issues/619 - Introduced `alpha` and `beta` probabilistic bounds for MNDL splitting criteria for X-Means algorithm (Python: `pyclustering.cluster.xmeans`; C++: `pyclustering::clst::xmeans`). See: https://github.com/annoviko/pyclustering/issues/624 CORRECTED MAJOR BUGS: - Corrected bug with a command `python3 -m pyclustering.tests` that was using the current folder to find tests to run (Python: `pyclustering`). See: https://github.com/annoviko/pyclustering/issues/648 - Corrected bug with Elbow algorithm where `kmax` is not used to calculate `K` (Python: `pyclustering.cluster.elbow`; C++: `pyclustering::clst::elbow`). See: https://github.com/annoviko/pyclustering/issues/639 - Corrected implementation of K-Medians (PAM) algorithm that is aligned with original algorithm (Python: `pyclustering.cluster.kmedoids`; C++: `pyclustering::clst::kmedoids`). See: https://github.com/annoviko/pyclustering/issues/503 - Corrected literature references that were for K-Medians (PAM) implementation (Python: `pyclustering.cluster.kmedoids`). See: https://github.com/annoviko/pyclustering/pull/572 - Corrected bug when K-Medoids updates input parameter `initial_medoids` that were provided to the algorithm (Python: `pyclustering.cluster.kmedoids`). See: https://github.com/annoviko/pyclustering/issues/630 - Corrected bug with Euclidean distance when numpy is used (Python: `pyclustering.utils.metric`). See: https://github.com/annoviko/pyclustering/issues/625 - Corrected bug with Minkowski distance when numpy is used (Python: `pyclustering.utils.metric`). See: https://github.com/annoviko/pyclustering/issues/626 - Corrected bug with Gower distance when numpy calculation is used and data shape is bigger than 1 (Python: `pyclustering.utils.metric`). See: https://github.com/annoviko/pyclustering/issues/627 - Corrected MNDL splitting criteria for X-Means algorithm (Python: `pyclustering.cluster.xmeans`; C++: `pyclustering::clst::xmeans`). See: https://github.com/annoviko/pyclustering/issues/623 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.10.0.1 (STARTED Aug 17, 2020), (RELEASED: Aug 17, 2020) ------------------------------------------------------------------------ GENERAL CHANGES: - Metadata of the library is updated. ------------------------------------------------------------------------ CHANGE NOTES FOR 0.10.0 (STARTED Jan 24, 2020), (RELEASED: Aug 17, 2020) ------------------------------------------------------------------------ GENERAL CHANGES: - Supported command `test` for `setup.py` script (Python: `pyclustering`). See: https://github.com/annoviko/pyclustering/issues/607 - Introduced parameter `random_seed` for algorithms/models to control the seed of the random functionality: `kmeans++`, `random_center_initializer`, `ga`, `gmeans`, `xmeans`, `som`, `somsc`, `elbow`, `silhouette_ksearch` (Python: `pyclustering.cluster`; C++: `pyclustering.clst`). See: https://github.com/annoviko/pyclustering/issues/578 - Introduced parameter `k_max` to G-Means algorithm to use it as an optional stop condition for the algorithm (Python: `pyclustering.cluster.gmeans`; C++: `pyclustering::clst::gmeans`). See: https://github.com/annoviko/pyclustering/issues/602 - Implemented method `save()` for `cluster_visualizer` and `cluster_visualizer_multidim` to save visualization to file (Python: `pyclustering.cluster`). See: https://github.com/annoviko/pyclustering/issues/601 - Optimization of CURE algorithm using balanced KD-tree (Python: `pyclustering.cluster.cure`; C++: `pyclustering::clst::cure`). See: https://github.com/annoviko/pyclustering/issues/589 - Optimization of OPTICS algorithm using balanced KD-tree (Python: `pyclustering.cluster.optics`; C++: `pyclustering::clst::optics`). See: https://github.com/annoviko/pyclustering/issues/588 - Optimization of DBSCAN algorithm using balanced KD-tree (Python: `pyclustering.cluster.dbscan`; C++: `pyclustering::clst::dbscan`). See: https://github.com/annoviko/pyclustering/issues/587 - Implemented new optimized balanced KD-tree `kdtree_balanced` (Python: `pyclustering.cluster.kdtree`; C++: `pyclustering::container::kdtree_balanced`). See: https://github.com/annoviko/pyclustering/issues/379 - Implemented KD-tree graphical visualizer `kdtree_visualizer` for KD-trees with 2-dimensional data (Python: `pyclustering.container.kdtree`). See: https://github.com/annoviko/pyclustering/issues/586 - Updated interface of each clustering algorithm in C/C++ pyclustering `cluster_data` is substituted by concrete classes (C++ `pyclustering::clst`). See: https://github.com/annoviko/pyclustering/issues/577 CORRECTED MAJOR BUGS: - Bug with wrong data type for `scores` in Silhouette K-search algorithm in case of using C++ (Python: `pyclustering.cluster.silhouette`). See: https://github.com/annoviko/pyclustering/issues/606 - Bug with a random distribution in the random center initializer (Python: `pyclustering.cluster.center_initializer`). See: https://github.com/annoviko/pyclustering/issues/573 - Bug with incorrect converting Index List and Object List to Labeling when clusters do not contains one or more points from an input data (Python `pyclustering.cluster.encoder`). See: https://github.com/annoviko/pyclustering/issues/596 - Bug with an exception in case of using user-defined metric for K-Means algorithm (Python `pyclustering.cluster.kmeans`). See: https://github.com/annoviko/pyclustering/pull/600 - Memory leakage in the interface between python and C++ pyclustering library in case of CURE algorithm usage (C++ `pyclustering`). See: https://github.com/annoviko/pyclustering/issues/581 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.9.3.1 (STARTED Dev 23, 2019), (RELEASED: Dev 23, 2019) ------------------------------------------------------------------------ CORRECTED MAJOR BUGS: - Hotfix for the CF-tree - call method with incorrect amount of arguments. See: https://github.com/annoviko/pyclustering/issues/570 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.9.3 (STARTED Oct 10, 2019), (RELEASED: Dev 23, 2019) ------------------------------------------------------------------------ GENERAL CHANGES: - Introduced `get_cf_clusters` and `get_cf_entries` methods for BIRCH algorithm to get CF-entry encoding information (pyclustering.cluster.birch). See: https://github.com/annoviko/pyclustering/issues/569 - Introduced `predict` method for SOMSC algorithm to find closest clusters for specified points (pyclustering.cluster.somsc). See: https://github.com/annoviko/pyclustering/issues/546 - Parallel optimization of C++ pyclustering compilation process. See: https://github.com/annoviko/pyclustering/issues/553 - Include folder for easy integration to other C++ projects. See: https://github.com/annoviko/pyclustering/issues/554 - Introduced new targets to build static libraries on Windows platform. See: https://github.com/annoviko/pyclustering/issues/555 - Introduced new targets to build static libraries on Linux/MacOS platforms. See: https://github.com/annoviko/pyclustering/issues/556 CORRECTED MAJOR BUGS: - Bug with incorrect finding of closest CF-entry (pyclustering.container.cftree). See: https://github.com/annoviko/pyclustering/issues/564 - Bug with incorrect BIRCH clustering due incorrect leaf analysis (pyclustering.cluster.birch). See: https://github.com/annoviko/pyclustering/issues/563 - Bug with incorrect search procedure of farthest nodes in CF-tree (pyclustering.container.cftree). See: https://github.com/annoviko/pyclustering/issues/551 - Bug with crash during clustering with the same points in case of BIRCH (pyclustering.cluster.birch). See: https://github.com/annoviko/pyclustering/issues/561 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.9.2 (STARTED Sep 9, 2019), (RELEASED: Oct 10, 2019) ------------------------------------------------------------------------ GENERAL CHANGES: - Introduced checking of input arguments for clustering algorithm to provide human-readable errors (pyclustering.cluster). See: https://github.com/annoviko/pyclustering/issues/548 - Implemented functionality to perform Anderson-Darling test for Gaussian distribution (ccore.stats). See: https://github.com/annoviko/pyclustering/issues/550 - Implemented new clustering algorithm G-Means (pyclustering.cluster.gmeans, ccore.clst.gmeans). See: https://github.com/annoviko/pyclustering/issues/506 - Introduced parameter `repeat` to improve parameters in X-Means algorithm (pyclustering.cluster.xmeans, ccore.clst.xmeans). See: https://github.com/annoviko/pyclustering/issues/525 - Introduced new distance metric: Gower (pyclustering.utils.metric, ccore.utils.metric). See: https://github.com/annoviko/pyclustering/issues/544 - Introduced sampling algorithms `reservoir_r` and `reservoir_x` (pyclustering.utils.sampling). See: https://github.com/annoviko/pyclustering/issues/542 - Introduced parameter `data_type` to Silhouette method to use distance matrix (pyclustering.cluster.silhouette, ccore.clst.silhouette). See: https://github.com/annoviko/pyclustering/issues/543 - Optimization of HHN (Hodgkin-Huxley Neural Network) by parallel processing (ccore.nnet.hhn). See: https://github.com/annoviko/pyclustering/issues/541 - Introduced `get_total_wce` method for `xmeans` algorithm to find WCE (pyclustering.cluster.xmeans). See: https://github.com/annoviko/pyclustering/issues/508 CORRECTED MAJOR BUGS: - Bug with incorrect center initialization in K-Means++ when candidates are not farthest (pyclustering.cluster.center_initializer). See: https://github.com/annoviko/pyclustering/issues/549 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.9.1 (STARTED Apr 14, 2019), (RELEASED: Sep 9, 2019) ------------------------------------------------------------------------ GENERAL CHANGES: - Introduced 'predict' method for X-Means algorithm to find closest clusters for particular points (pyclustering.cluster.xmeans). See: https://github.com/annoviko/pyclustering/issues/540 - Optimization of OPTICS algorithm by reducing complexity (ccore.clst.optics). See: https://github.com/annoviko/pyclustering/issues/521 - Optimization of K-Medians algorithm by parallel processing (ccore.clst.kmedians). See: https://github.com/annoviko/pyclustering/issues/529 - Introduced 'predict' method for K-Medoids algorithm to find closest clusters for particular points (pyclustering.cluster.kmedoids). See: https://github.com/annoviko/pyclustering/issues/527 - Introduced 'predict' method for K-Means algorithm to find closest clusters for particular points (pyclustering.cluster.kmeans). See: https://github.com/annoviko/pyclustering/issues/515 - Parallel optimization of Elbow method. (ccore.clst.elbow). See: https://github.com/annoviko/pyclustering/issues/511 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.9.0 (STARTED Nov 19, 2018), (RELEASED: Apr 14, 2019) ------------------------------------------------------------------------ GENERAL CHANGES: - CCORE (pyclustering core) is supported for MacOS. See: https://github.com/annoviko/pyclustering/issues/486 - Introduced parallel Fuzzy C-Means algorithm (pyclustering.cluster.fcm, ccore.clst.fcm). See: https://github.com/annoviko/pyclustering/issues/386 - Introduced new 'itermax' parameter for K-Means, K-Medians, K-Medoids algorithm to control maximum amount of iterations (pyclustering.cluster, ccore.clst). See: https://github.com/annoviko/pyclustering/issues/496 - Implemented Silhouette and Silhouette K-Search algorithm for CCORE (ccore.clst.silhouette, ccore.clst.silhouette_ksearch). See: https://github.com/annoviko/pyclustering/issues/490 - Implemented CLIQUE algorithms (pyclustering.cluster.clique, ccore.clst.clique). See: https://github.com/annoviko/pyclustering/issues/381 - Introduced new distance metrics: Canberra and Chi Square (pyclustering.utils.metric, ccore.utils.metric). See: https://github.com/annoviko/pyclustering/issues/482 - Optimization of CURE algorithm (C++ implementation) by using heap (multiset) instead of list to store clusters in queue (ccore.clst.cure). See: https://github.com/annoviko/pyclustering/issues/479 CORRECTED MAJOR BUGS: - Bug with crossover mask generation for genetic clustering algorithm (pyclustering.cluster.ga). See: https://github.com/annoviko/pyclustering/pull/474 - Bug with hanging of K-Medians algorithm for some cases when algorithm is initialized by wrong amount of centers (ccore.clst.kmedians). See: https://github.com/annoviko/pyclustering/issues/498 - Bug with incorrect center initialization, when the same point can be placed to result more than once (pyclustering.cluster.center_initializer, ccore.clst.kmeans_plus_plus). See: https://github.com/annoviko/pyclustering/issues/497 - Bug with incorrect clustering in case of CURE python implementation when clusters are allocated incorrectly (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/483 - Bug with incorrect distance calculation for kmeans++ in case of index representation for centers (pyclustering.cluster.center_initializer). See: https://github.com/annoviko/pyclustering/issues/485 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.8.2 (STARTED May 28, 2018), (RELEASED: Nov 19, 2018) ------------------------------------------------------------------------ GENERAL CHANGES: - Implemented Silhouette method and Silhouette KSearcher to find out proper amount of clusters (pyclustering.cluster.silhouette). See: https://github.com/annoviko/pyclustering/issues/416 - Introduced new 'return_index' parameter for kmeans_plus_plus and random_center_initializer algorithms (method 'initialize') to initialize initial medoids (pyclustering.cluster.center_initializer). See: https://github.com/annoviko/pyclustering/issues/421 - Display warning instead of throwing error if matplotlib or Pillow cannot be imported (MAC OS X problems). See: https://github.com/annoviko/pyclustering/issues/455 - Implemented Random Center Initializer for CCORE (ccore.clst.random_center_initializer). See: no reference. - Implemented Elbow method to find out proper amount of clusters in dataset (pyclustering.cluster.elbow, ccore.clst.elbow). See: https://github.com/annoviko/pyclustering/issues/416 - Introduced new method 'get_optics_objects' for OPTICS algorithm to obtain detailed information about ordering (pyclustering.cluster.optics, ccore.clst.optics). See: https://github.com/annoviko/pyclustering/issues/464 - Added new clustering answers for SAMPLE SIMPLE data collections (pyclustering.samples). See: https://github.com/annoviko/pyclustering/issues/459 - Implemented multidimensional cluster visualizer (pyclustering.cluster). See: https://github.com/annoviko/pyclustering/issues/450 - Parallel optimization of K-Medoids algorithm (ccore.clst.kmedoids). See: https://github.com/annoviko/pyclustering/issues/447 - Parallel optimization of K-Means and X-Means (that uses K-Means) algorithms (ccore.clst.kmeans, ccore.clst.xmeans). See: https://github.com/annoviko/pyclustering/issues/451 - Introduced new threshold parameter 'amount of block points' to BANG algorithm to allocate outliers more precisely (pyclustering.cluster.bang). See: https://github.com/annoviko/pyclustering/issues/446 - Optimization of conveying results from C++ to Python for K-Medians and K-Medoids (pyclustering.cluster.kmedoids, pyclustering.cluster.kmedians). See: https://github.com/annoviko/pyclustering/issues/445 - Implemented cluster generator (pyclustering.cluster.generator). See: https://github.com/annoviko/pyclustering/issues/444 - Implemented BANG animator to render animation of clustering process (pyclustering.cluster.bang). See: https://github.com/annoviko/pyclustering/issues/442 - Optimization of CURE algorithm by using Euclidean Square distance (pyclustering.cluster.cure, ccore.clst.cure). See: https://github.com/annoviko/pyclustering/issues/439 - Supported numpy.ndarray points in KD-tree (pyclustering.container.kdtree). See: https://github.com/annoviko/pyclustering/issues/438 CORRECTED MAJOR BUGS: - Bug with clustering failure in case of non-numpy user defined metric for K-Means algorithm (pyclustering.cluster.kmeans). See: https://github.com/annoviko/pyclustering/issues/471 - Bug with animation of correlation matrix in case of new versions of matplotlib (pyclustering.nnet.sync). See: no reference. - Bug with SOM and pickle when it was not possible to store and load network using pickle (pyclustering.nnet.som). See: https://github.com/annoviko/pyclustering/issues/456 - Bug with DBSCAN when points are marked as a noise (pyclustering.cluster.dbscan). See: https://github.com/annoviko/pyclustering/issues/462 - Bug with randomly enabled connection weights in case of SyncNet based algorithms using CCORE interface (pyclustering.nnet.syncnet). See: https://github.com/annoviko/pyclustering/issues/452 - Bug with calculation weighted connection for Sync based clustering algorithms in C++ implementation (ccore.nnet.syncnet). See: no reference - Bug with failure in case of numpy.ndarray data type in python part of CURE algorithm (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/438 - Bug with BANG algorithm with empty dimensions - when data contains column with the same values (pyclustering.cluster.bang). See: https://github.com/annoviko/pyclustering/issues/449 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.8.1 (STARTED Feb 23, 2018), (RELEASED: May 28, 2018) ------------------------------------------------------------------------ GENERAL CHANGES: - Implemented feature to use specific metric for distance calculation in K-Means algorithm (pyclustering.cluster.kmeans, ccore.clst.kmeans). See: https://github.com/annoviko/pyclustering/issues/434 - Implemented BANG-clustering algorithm with result visualizer (pyclustering.cluster.bang). See: https://github.com/annoviko/pyclustering/issues/424 - Implemented feature to use specific metric for distance calculation in K-Medians algorithm (pyclustering.cluster.kmedians, ccore.clst.kmedians). See: https://github.com/annoviko/pyclustering/issues/429 - Supported new type of input data for K-Medoids - distance matrix (pyclustering.cluster.kmedoids, ccore.clst.kmedoids). See: https://github.com/annoviko/pyclustering/issues/418 - Implemented TTSAS algorithm (pyclustering.cluster.ttsas, ccore.clst.ttsas). See: https://github.com/annoviko/pyclustering/issues/398 - Implemented MBSAS algorithm (pyclustering.cluster.mbsas, ccore.clst.mbsas). See: https://github.com/annoviko/pyclustering/issues/398 - Implemented BSAS algorithm (pyclustering.cluster.bsas, ccore.clst.bsas). See: https://github.com/annoviko/pyclustering/issues/398 - Implemented feature to use specific metric for distance calculation in K-Medoids algorithm (pyclustering.cluster.kmedoids, ccore.clst.kmedoids). See: https://github.com/annoviko/pyclustering/issues/417 - Implemented distance metric collection (pyclustering.utils.metric, ccore.utils.metric). See: no reference. - Supported new type of input data for OPTICS - distance matrix (pyclustering.cluster.optics, ccore.clst.optics). See: https://github.com/annoviko/pyclustering/issues/412 - Supported new type of input data for DBSCAN - distance matrix (pyclustering.cluster.dbscan, ccore.clst.dbscan). See: no reference. - Implemented K-Means observer and visualizer to visualize and animate clustering results (pyclustering.cluster.kmeans, ccore.clst.kmeans). See: no reference. CORRECTED MAJOR BUGS: - Bug with out of range in K-Medians (pyclustering.cluster.kmedians, ccore.clst.kmedians). See: https://github.com/annoviko/pyclustering/issues/428 - Bug with fast linking in PCNN (python implementation only) that wasn't used despite the corresponding option (pyclustering.nnet.pcnn). See: https://github.com/annoviko/pyclustering/issues/419 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.8.0 (STARTED Oct 23, 2017), (RELEASED: Feb 23, 2018) ------------------------------------------------------------------------ GENERAL CHANGES: - Optimization K-Means++ algorithm using numpy (pyclustering.cluster.center_initializer). See: no reference. - Implemented K-Means++ initializer for CCORE (ccore.clst.kmeans_plus_plus). See: https://github.com/annoviko/pyclustering/issues/382 - Optimization of X-Means clustering process by using KMeans++ for initial centers of split regions (pyclustering.cluster.xmeans, ccore.clst.xmeans). See: https://github.com/annoviko/pyclustering/issues/382 - Implemented parallel Sync-family algorithms for C/C++ implementation (CCORE) only (ccore.sync). See: https://github.com/annoviko/pyclustering/issues/170 - C/C++ implementation is used by default to increase performance. See: https://github.com/annoviko/pyclustering/issues/393 - Ignore 'ccore' flag to use C/C++ if platform is not supported (pyclustering.core). See: https://github.com/annoviko/pyclustering/issues/393 - Optimization of python implementation of the K-Means algorithm using numpy (pyclustering.cluster.kmeans). See: https://github.com/annoviko/pyclustering/issues/403 - Implemented dynamic visualizer for oscillatory networks (pyclustering.nnet.dynamic_visualizer). See: no reference. - Implemented C/C++ Hodgkin-Huxley oscillatory network for image segmentation in CCORE to increase performance (ccore.hhn, pyclustering.nnet.hhn). See: https://github.com/annoviko/pyclustering/issues/217 - Performance optimization for CCORE on linux platform. See: no reference. - 32-bit platform of CCORE is supported for Linux OS. See: https://github.com/annoviko/pyclustering/issues/253 - 32-bit platform of CCORE is supported for Windows OS. See: https://github.com/annoviko/pyclustering/issues/253 - Implemented method 'get_probabilities()' for obtaining belong probability in EM-algorithm (pyclustering.cluster.ema). See: https://github.com/annoviko/pyclustering/issues/387 - Python implementation of CURE algorithm method 'get_clusters()' returns list of indexes (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/384 - Implemented parallel processing for X-Means algorithm (ccore.clst.xmeans). See: https://github.com/annoviko/pyclustering/issues/372 - Implemented pool threads for parallel processing (ccore.parallel). See: https://github.com/annoviko/pyclustering/issues/383 - Optimization of OPTICS algorithm using KD-tree for searching nearest neighbors (pyclustering.cluster.optics, ccore.optics). See: https://github.com/annoviko/pyclustering/issues/370 - Optimization of DBSCAN algorithm using KD-tree for searching nearest neighbors (pyclustering.cluster.dbscan, ccore.dbscan). See: https://github.com/annoviko/pyclustering/issues/369 CORRECTED MAJOR BUGS: - Incorrect type of medoid's index in K-Medians algorithm in case of Python 2.x (pyclustering.cluster.kmedoids). See: https://github.com/annoviko/pyclustering/issues/415 - Hanging of method 'find_node' in KD-tree if it does not contain node with specified point and payload (pyclustering.container.kdtree). See: no reference. - Incorrect clustering by CURE algorithm in some cases when data have a lot of identical points (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/414 - Segmentation fault in CURE algorithm in some cases when data have a lot of identical points (ccore.clst.cure). See: no reference. - Incorrect segmentation by Python version of syncsegm - oscillatory network based on sync for image segmentation (pyclustering.nnet.syncsegm). See: https://github.com/annoviko/pyclustering/issues/409 - Zero value of sigma under logarithm function in Python version of pyclustering X-Means algorithm (pyclustering.cluster.xmeans). See: https://github.com/annoviko/pyclustering/issues/407 - Amplitude threshold is ignored during synchronous ensembles allocation for amplitude output dynamic 'allocate_sync_ensembles' - affect HNN, LEGION (pyclustering.utils). See: no reference. - Wrong indexes can be returned during synchronous ensembles allocation for amplitude output dynamic 'allocate_sync_ensembles' - affect HNN, LEGION (pyclustering.utils). See: no reference. - Amount of allocated clusters can be differ from amount of centers in X-Means algorithm (ccore.clst.xmeans). See: https://github.com/annoviko/pyclustering/issues/389 - Amount of allocated clusters can be bigger than kmax in X-Means algorithm (pyclustering.cluster.xmeans, ccore.clst.xmeans). See: https://github.com/annoviko/pyclustering/issues/388 - Corrected bug with returned nullptr in method 'kdtree_searcher::find_nearest_node()' (ccore.container.kdtree). See: no reference. ------------------------------------------------------------------------ CHANGE NOTES FOR 0.7.2 (STARTED Oct 19, 2017), (RELEASED: Oct 23, 2017) ------------------------------------------------------------------------ GENERAL CHANGES: - Correction for setup failure with PKG-INFO.rst. ------------------------------------------------------------------------ CHANGE NOTES FOR 0.7.1 (STARTED Oct 16, 2017), (RELEASED: Oct 19, 2017) ------------------------------------------------------------------------ GENERAL CHANGES: - Metadata and description of the pyclustering package is updated. ------------------------------------------------------------------------ CHANGE NOTES FOR 0.7.0 (STARTED Jun 01, 2016), (RELEASED: Oct 16, 2017) ------------------------------------------------------------------------ GENERAL CHANGES (pyclustering): - Implemented Expectation-Maximization clustering algorithm for Gaussian Mixute Model and clustering visualizer for this particular algorithm (pyclustering.cluster.ema). See: https://github.com/annoviko/pyclustering/issues/16 - Implemented Genetic Clustering Algorithm (GCA) and clustering visualizer for this particular algorithm (pyclustering.cluster.ga). See: https://github.com/annoviko/pyclustering/issues/360 - Implemented feature to obtain and visualize evolution of order parameter and local order parameter for Sync network and Sync-based algorithms (pyclustering.nnet.sync). See: https://github.com/annoviko/pyclustering/issues/355 - Implemented K-Means++ method for initialization of initial centers for algorithms like K-Means or X-Means (pyclustering.cluster.center_initializer). See: https://github.com/annoviko/pyclustering/issues/354 - Implemented fSync oscillatory network that is based on Landau-Stuart equation and Kuramoto model (pyclustering.nnet.fsync). See: https://github.com/annoviko/pyclustering/issues/168 - Optimization of pyclustering client to core library 'CCORE' library (pyclustering.core). See: https://github.com/annoviko/pyclustering/issues/289 See: https://github.com/annoviko/pyclustering/issues/351 - Implemented feature to show network structure of Sync family oscillatory networks in case 'ccore' usage. See: https://github.com/annoviko/pyclustering/issues/344 - Implemented feature to colorize OPTICS ordering diagram when amount of clusters is specified. See: no reference. - Improved clustering results in case of usage MNDL splitting criterion for small datasets. See: https://github.com/annoviko/pyclustering/issues/328 - Feature to display connectivity radius on cluster-ordering diagram by ordering_visualizer (pyclustering.cluster.optics). See: https://github.com/annoviko/pyclustering/issues/314 - Feature to use CCORE implementation of OPTICS algorithm to take advance in performance (pyclustering.cluster.optics). See: https://github.com/annoviko/pyclustering/issues/120 - Implemented feature to shows animation of pattern recognition process that has been performed by the SyncPR oscillatory network. Method 'animate_pattern_recognition()' of class 'syncpr_visualizer' (pyclustering.nnet.syncpr). See: https://www.youtube.com/watch?v=Ro7KbApL4MQ See: https://www.youtube.com/watch?v=iIusOsGehoY - Implemented feature to obtain nodes of specified level of CF-tree. Method 'get_level_nodes()' of class 'cftree' (pyclustering.container.cftree). See: no reference. - Implemented feature to allocate/display/animate phase matrix: 'allocate_phase_matrix()', 'show_phase_matrix()', 'animate_phase_matrix()' (pyclustering.nnet.sync). See: no reference. - Implemented chaotic neural network where clustering phenomenon can be observed: 'cnn_network', 'cnn_dynamic', 'cnn_visualizer' (pyclustering.nnet.cnn). See: https://github.com/annoviko/pyclustering/issues/301 - Implemented feature to analyse ordering diagram using amout of clusters that should be allocated as an input parameter to calculate correct connvectity radius for clustering (pyclustering.cluster.optics). See: https://github.com/annoviko/pyclustering/issues/307 - Implemented feature to omit usage of initial centers - X-Means starts processing from random initial center (pyclustering.cluster.xmeans). See: no reference. - Implemented feature for cluster visualizer: cluster attributes (pyclustering.cluster). See: https://github.com/annoviko/pyclustering/issues/295 - Implemented SOM-SC algorithm (SOM Simple Clustering) (pyclustering.cluster.somsc). See: https://github.com/annoviko/pyclustering/issues/321 GENERAL CHANGES (ccore): - Implemented feature to obtain and visualize evolution of order parameter and local order parameter for Sync network and Sync-based algorithms (ccore.nnet.sync). See: https://github.com/annoviko/pyclustering/issues/355 - Cygwin x64 platform is supported (ccore). See: https://github.com/annoviko/pyclustering/issues/353 - Optimization of CCORE library interface (ccore.interface). See: https://github.com/annoviko/pyclustering/issues/289 - Implemented MNDL splitting crinterion for X-Means algorithm (ccore.cluster_analysis.xmeans). See: https://github.com/annoviko/pyclustering/issues/159 - Implemented OPTICS algorithm and interface for client that results all clustering results (ccore.cluster_analysis.optics). See: https://github.com/annoviko/pyclustering/issues/120 - Implmeneted packing of connectivity matrix of Sync family oscillatory networks (ccore.interface.sync_interface). See: https://github.com/annoviko/pyclustering/issues/344 CORRECTED MAJOR BUGS: - Bug with segmentation fault during 'free()' on some linux operating systems. See: no reference. - Bug with sending the first element to cluster in OPTICS even if it is noise element. See: no reference. - Bug with amount of allocated clusters by K-Medoids algorithm in Python implementation and CCORE (pyclustering.cluster.kmedoids, ccore.cluster.medoids). See: https://github.com/annoviko/pyclustering/issues/366 See: https://github.com/annoviko/pyclustering/issues/367 - Bug with getting neighbors and getting information about connections in Sync-based network and algorithms in case of usage CCORE. See: no reference. - Bug with calculation of number of oscillations for output dynamics. See: no reference. - Memory leakage in LEGION in case of CCORE usage - API function 'legion_destroy()' was not called (pyclustering.nnet.legion). See: no reference. - Bug with crash of antmeans algorithm for python version 3.6.0:414df79263a11, Dec 23 2016 [MSC v.1900 64 bit (AMD64)] (pyclustering.cluster.antmeans). See: https://github.com/annoviko/pyclustering/issues/350 - Memory leakage in destructor of 'pyclustering_package' - exchange mechanism between ccore and pyclustering (ccore.interface.pyclustering_package'). See: https://github.com/annoviko/pyclustering/issues/347 - Bug with loosing of the initial state of hSync output dynamic in case of CCORE usage (ccore.cluster.hsyncnet). See: https://github.com/annoviko/pyclustering/issues/346 - Bug with hSync output dynamic that was displayed with discontinous parts as a set of rectangles (pyclustering.cluster.hsyncnet). See: https://github.com/annoviko/pyclustering/issues/345 - Bug with visualization of CNN network in case 3D data (pyclustering.nnet.cnn). See: https://github.com/annoviko/pyclustering/issues/338 - Bug with CCORE wrapper crashing after returning value from CCORE (pyclustering.core). See: https://github.com/annoviko/pyclustering/issues/337 - Bug with calculation BIC splitting criterion for X-Means algorithm (pyclustering.cluster.xmeans). See: https://github.com/annoviko/pyclustering/issues/326 - Bug with calculation MNDL splitting criterion for X-Means algorithm (pyclustering.cluster.xmeans). See: https://github.com/annoviko/pyclustering/issues/328 - Bug with loss of CF-nodes in CF-tree during inserting that leads unbalanced CF-tree (pyclustering.container.cftree). See: https://github.com/annoviko/pyclustering/issues/304 - Bug with time stamps for each iteration in hsyncnet algorithm (ccore.cluster.hsyncnet). See: https://github.com/annoviko/pyclustering/issues/306 - Bug with memory occupation by CCORE DBSCAN implementation due to adjacency matrix usage (ccore.cluster.dbscan). See: https://github.com/annoviko/pyclustering/issues/309 - Bug with CURE: always finds max two representative points (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/310 - Bug with infinite loop in case of incorrect number of clusters 'ordering_analyser' (pyclustering.cluster.optics). See: https://github.com/annoviko/pyclustering/issues/317 - Bug with incorrect connectivity radius for allocation specified amount of clusters 'ordering_analyser' (pyclustering.cluster.optics). See: https://github.com/annoviko/pyclustering/issues/316 - Bug with clusters are allocated in the homogeneous ordering 'ordering_analyser' (pyclustering.cluster.optics). See: https://github.com/annoviko/pyclustering/issues/315 ------------------------------------------------------------------------ CHANGE NOTES FOR 0.6.0 (STARTED: Jul 18, 2015), (RELEASED: Jun 01, 2016) ------------------------------------------------------------------------ GENERAL CHANGES (pyclustering): - Implemented phase oscillatory network syncpr (pyclustering.nnet.syncpr). See: https://github.com/annoviko/pyclustering/issues/208 - Feature for pyclustering.nnet.syncpr that allows to use ccore library for solving. See: https://github.com/annoviko/pyclustering/issues/232 - Optimized simulation algorithm for sync oscillatory network (pyclustering.nnet.sync) when collecting results are not requested. See: https://github.com/annoviko/pyclustering/issues/233 - Images of english alphabet 100x100. See: https://github.com/annoviko/pyclustering/commit/aa28f1a8a363fbeb5f074d22ec1e8258a1dd0579 - Implemented feature to use rectangular network structures in oscillatory networks. See: https://github.com/annoviko/pyclustering/issues/259 - Implemented CLARANS algorithm (pyclustering.cluster.clarans). See: https://github.com/annoviko/pyclustering/issues/52 - Implemented feature to analyse and visualize results of hysteresis oscillatory network (pyclustering.nnet.hysteresis). See: https://github.com/annoviko/pyclustering/issues/75 - Implemented feature to analyse and visualize results of graph coloring algorithm based on hysteresis oscillatory network (pyclustering.gcolor.hysteresis). See: https://github.com/annoviko/pyclustering/issues/75 - Implemented ant colony based algorithm for TSP problem (pyclustering.tsp.antcolony). See: https://github.com/annoviko/pyclustering/pull/277 - Implemented feature to use CCORE K-Medians algorithm using argument 'ccore' to ensure high performance (pyclustering.cluster.kmedians). See: https://github.com/annoviko/pyclustering/issues/231 - Implemented feature to place several plots on each row using parameter 'maximum number of rows' for cluster visualizer (pyclustering.cluster). See: https://github.com/annoviko/pyclustering/issues/274 - Implemented feature to specify initial number of neighbors to calculate initial connectivity radius and increase percent of number of neighbors (or radius if total number of object is exceeded) on each step (pyclustering.cluster.hsyncnet). See: https://github.com/annoviko/pyclustering/issues/284 - Implemented double-layer oscillatory network based on modified Kuramoto model for image segmentation (pyclustering.nnet.syncsegm). See: no reference - Added new examples and demos. See: no reference - Implemented feature to use CCORE K-Medoids algorithm using argument 'ccore' to ensure high performance (pyclustering.cluster.kmedoids). See: https://github.com/annoviko/pyclustering/issues/230 - Implemented feature for CURE algorithm that provides additional information about clustering results: representative points and mean point of each cluster (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/292 - Implemented feature to animate analysed output dynamic of Sync family oscillatory networks (sync_visualizer, syncnet_visualizer): correlation matrix, phase coordinates, cluster allocation (pyclustering.nnet.sync, pyclustering.cluster.syncnet). See: https://www.youtube.com/watch?v=5S5mFYVihso See: https://www.youtube.com/watch?v=Vd-ww9PcZvI See: https://www.youtube.com/watch?v=QYPqWoyNHO8 See: https://www.youtube.com/watch?v=RA0MiC2WlbY - Improved algorithm SYNC-SOM: accuracy of clustering and calculation are improved in line with proof of concept where connection between oscillator in the second layer (that is represented by the self-organized feature map) should be created in line with classical radius like in SyncNet, but indirectly: if objects that correspond to two different neurons can be connected than neurons should be also connected with each other (pyclustering.cluster.syncsom). See: https://github.com/annoviko/pyclustering/issues/297 GENERAL CHANGES (ccore): - Implemented phase oscillatory network for pattern recognition syncpr (ccore.cluster.syncpr). See: https://github.com/annoviko/pyclustering/issues/232 - Implemented agglomerative algorithm for cluster analysis (ccore.cluster.agglomerative). See: https://github.com/annoviko/pyclustering/issues/212 - Implemented feature to use rectangular network structures in oscillatory networks. See: https://github.com/annoviko/pyclustering/issues/259 - Implemented ant colony based algorithm for TSP problem (ccore.tsp.antcolony). See: https://github.com/annoviko/pyclustering/pull/277 - Implemented K-Medians algorithm for cluster analysis (ccore.cluster.kmedians). See: https://github.com/annoviko/pyclustering/issues/231 - Implemented feature to specify initial number of neighbors to calculate initial connectivity radius and increase percent of number of neighbors (or radius if total number of object is exceeded) on each step (ccore.cluster.hsyncnet). https://github.com/annoviko/pyclustering/issues/284 - Implemented K-Medoids algorithm for cluster analysis (ccore.cluster.kmedoids). See: https://github.com/annoviko/pyclustering/issues/230 - Implemented feature for CURE algorithm that provides additional information about clustering results: representative points and mean point of each cluster (ccore.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/293 - Implemented new class collection to oscillatory and neural network constructing. See: https://github.com/annoviko/pyclustering/issues/264 - Memory usage optimization for ROCK algorithm. See: no reference CORRECTED MAJOR BUGS: - Bug with callback methods in ccore library in syncnet (ccore.cluster.syncnet) and hsyncnet (ccore.cluster.hsyncnet) that may lead to loss of accuracy. - Bug with division by zero in kmeans algorithm (ccore.kmeans, pyclustering.cluster.kmeans) when cluster after center updating is not able to capture object. See: https://github.com/annoviko/pyclustering/issues/238 - Bug with stack overflow in KD tree in case of big data (pyclustering.container.kdtree, ccore.container.kdtree). See: https://github.com/annoviko/pyclustering/pull/239 See: https://github.com/annoviko/pyclustering/issues/255 See: https://github.com/annoviko/pyclustering/issues/254 - Bug with incorrect clustering in case of the same elements in cure algorithm (pyclustering.cluster.cure). See: https://github.com/annoviko/pyclustering/pull/239 - Bug with execution fail in case of wrong number of initial medians and in case of the same objects with several initial medians (pyclustering.cluster.kmedians). See: https://github.com/annoviko/pyclustering/issues/256 - Bug with calculation synchronous ensembles near by zero: oscillators 2*pi and 0 are considered as different (pyclustering.nnet.sync, ccore.nnet.sync). See: https://github.com/annoviko/pyclustering/issues/263 - Bug with cluster allocation in kmedoids algorithm in case of the same objects with several initial medoids (pyclustering.cluster.kmedoids). See: https://github.com/annoviko/pyclustering/issues/269 - Bug with visualization of clusters in 3D (pyclustering.cluster). See: https://github.com/annoviko/pyclustering/issues/273 - Bug with obtaining nearest entry for absorbing during inserting node (pyclustering.container.cftree). See: https://github.com/annoviko/pyclustering/issues/282 - Bug with SOM method show_network() in case of usage CCORE (pyclustering.nnet.som). See: https://github.com/annoviko/pyclustering/issues/283 - Bug with cluster allocation in case of switched off dynamic collecting (pyclustering.cluster.hsyncnet). See: https://github.com/annoviko/pyclustering/issues/285 - Bug with execution fail during clustering data with rough values of initial medians (pyclustering.cluster.kmedians). See: https://github.com/annoviko/pyclustering/issues/286 - Bug with meamory leakage on interface between CCORE and pyclustering (ccore). See: no reference - Bug with allocation correlation matrix in case of usage CCORE (pyclustering.nnet.sync). See: https://github.com/annoviko/pyclustering/issues/288 - Bug with memory leakage in CURE algorithm - deallocation of representative points (ccore.cluster.cure). See: https://github.com/annoviko/pyclustering/issues/294 - Bug with cluster visualization in case of 1D input data (pyclustering.cluster). See: https://github.com/annoviko/pyclustering/issues/296 pyclustering-0.10.1.2/LICENSE000077500000000000000000000027671375753423500155230ustar00rootroot00000000000000Copyright (c) 2014-2020 Andrei Novikov Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.pyclustering-0.10.1.2/MANIFEST.in000066400000000000000000000000401375753423500162270ustar00rootroot00000000000000include MANIFEST.in graft ccorepyclustering-0.10.1.2/PKG-INFO.rst000077500000000000000000000156731375753423500164220ustar00rootroot00000000000000|JOSS| PyClustering ============ **pyclustering** is a Python, C++ data mining library (clustering algorithm, oscillatory networks, neural networks). The library provides Python and C++ implementations (C++ pyclustering library) of each algorithm or model. C++ pyclustering library is a part of pyclustering and supported for Linux, Windows and MacOS operating systems. Official repository: https://github.com/annoviko/pyclustering/ Documentation: https://pyclustering.github.io/docs/0.10.1/html/ Dependencies ============ **Required packages**: scipy, matplotlib, numpy, Pillow **Python version**: >=3.6 (32-bit, 64-bit) **C++ version**: >= 14 (32-bit, 64-bit) Performance =========== Each algorithm is implemented using Python and C/C++ language, if your platform is not supported then Python implementation is used, otherwise C/C++. Implementation can be chosen by `ccore` flag (by default it is always 'True' and it means that C/C++ is used), for example: .. code:: python # As by default - C/C++ part of the library is used xmeans_instance_1 = xmeans(data_points, start_centers, 20, ccore=True); # The same - C/C++ part of the library is used by default xmeans_instance_2 = xmeans(data_points, start_centers, 20); # Switch off core - Python is used xmeans_instance_3 = xmeans(data_points, start_centers, 20, ccore=False); Installation ============ Installation using pip3 tool: .. code:: bash $ pip3 install pyclustering Manual installation from official repository using Makefile: .. code:: bash # get sources of the pyclustering library, for example, from repository $ mkdir pyclustering $ cd pyclustering/ $ git clone https://github.com/annoviko/pyclustering.git . # compile CCORE library (core of the pyclustering library). $ cd ccore/ $ make ccore_64bit # build for 64-bit OS # $ make ccore_32bit # build for 32-bit OS # return to parent folder of the pyclustering library $ cd ../ # install pyclustering library $ python3 setup.py install # optionally - test the library $ python3 setup.py test Manual installation using CMake: .. code:: bash # get sources of the pyclustering library, for example, from repository $ mkdir pyclustering $ cd pyclustering/ $ git clone https://github.com/annoviko/pyclustering.git . # generate build files. $ mkdir build $ cmake .. # build pyclustering-shared target depending on what was generated (Makefile or MSVC solution) # if Makefile has been generated then $ make pyclustering-shared # return to parent folder of the pyclustering library $ cd ../ # install pyclustering library $ python3 setup.py install # optionally - test the library $ python3 setup.py test Manual installation using Microsoft Visual Studio solution: 1. Clone repository from: https://github.com/annoviko/pyclustering.git 2. Open folder `pyclustering/ccore` 3. Open Visual Studio project `ccore.sln` 4. Select solution platform: `x86` or `x64` 5. Build `pyclustering-shared` project. 6. Add pyclustering folder to python path or install it using setup.py .. code:: bash # install pyclustering library $ python3 setup.py install # optionally - test the library $ python3 setup.py test Proposals, Questions, Bugs ========================== In case of any questions, proposals or bugs related to the pyclustering please contact to pyclustering@yandex.ru. Issue tracker: https://github.com/annoviko/pyclustering/issues Library Content =============== **Clustering algorithms (module pyclustering.cluster):** - **Agglomerative** (pyclustering.cluster.agglomerative); - **BANG** (pyclustering.cluster.bang); - **BIRCH** (pyclustering.cluster.birch); - **BSAS** (pyclustering.cluster.bsas); - **CLARANS** (pyclustering.cluster.clarans); - **CLIQUE** (pyclustering.cluster.clique); - **CURE** (pyclustering.cluster.cure); - **DBSCAN** (pyclustering.cluster.dbscan); - **Elbow** (pyclustering.cluster.elbow); - **EMA** (pyclustering.cluster.ema); - **Fuzzy C-Means** (pyclustering.cluster.fcm); - **GA (Genetic Algorithm)** (pyclustering.cluster.ga); - **G-Means** (pyclustering.cluster.gmeans); - **HSyncNet** (pyclustering.cluster.hsyncnet); - **K-Means** (pyclustering.cluster.kmeans); - **K-Means++** (pyclustering.cluster.center_initializer); - **K-Medians** (pyclustering.cluster.kmedians); - **K-Medoids** (pyclustering.cluster.kmedoids); - **MBSAS** (pyclustering.cluster.mbsas); - **OPTICS** (pyclustering.cluster.optics); - **ROCK** (pyclustering.cluster.rock); - **Silhouette** (pyclustering.cluster.silhouette); - **SOM-SC** (pyclustering.cluster.somsc); - **SyncNet** (pyclustering.cluster.syncnet); - **Sync-SOM** (pyclustering.cluster.syncsom); - **TTSAS** (pyclustering.cluster.ttsas); - **X-Means** (pyclustering.cluster.xmeans); **Oscillatory networks and neural networks (module pyclustering.nnet):** - **Oscillatory network based on Hodgkin-Huxley model** (pyclustering.nnet.hhn); - **fSync: Oscillatory Network based on Landau-Stuart equation and Kuramoto model** (pyclustering.nnet.fsync); - **Hysteresis Oscillatory Network** (pyclustering.nnet.hysteresis); - **LEGION: Local Excitatory Global Inhibitory Oscillatory Network** (pyclustering.nnet.legion); - **PCNN: Pulse-Coupled Neural Network** (pyclustering.nnet.pcnn); - **SOM: Self-Organized Map** (pyclustering.nnet.som); - **Sync: Oscillatory Network based on Kuramoto model** (pyclustering.nnet.sync); - **SyncPR: Oscillatory Network based on Kuramoto model for pattern recognition** (pyclustering.nnet.syncpr); - **SyncSegm: Oscillatory Network based on Kuramoto model for image segmentation** (pyclustering.nnet.syncsegm); **Graph Coloring Algorithms (module pyclustering.gcolor):** - **DSATUR** (pyclustering.gcolor.dsatur); - **Hysteresis Oscillatory Network for graph coloring** (pyclustering.gcolor.hysteresis); - **Sync: Oscillatory Network based on Kuramoto model for graph coloring** (pyclustering.gcolor.sync); **Containers (module pyclustering.container):** - **CF-Tree** (pyclustering.container.cftree); - **KD-Tree** (pyclustering.container.kdtree); Cite the Library ================ If you are using pyclustering library in a scientific paper, please, cite the library: Novikov, A., 2019. PyClustering: Data Mining Library. Journal of Open Source Software, 4(36), p.1230. Available at: http://dx.doi.org/10.21105/joss.01230. BibTeX entry: .. code:: @article{Novikov2019, doi = {10.21105/joss.01230}, url = {https://doi.org/10.21105/joss.01230}, year = 2019, month = {apr}, publisher = {The Open Journal}, volume = {4}, number = {36}, pages = {1230}, author = {Andrei Novikov}, title = {{PyClustering}: Data Mining Library}, journal = {Journal of Open Source Software} } .. |JOSS| image:: http://joss.theoj.org/papers/10.21105/joss.01230/status.svg :target: https://doi.org/10.21105/joss.01230 pyclustering-0.10.1.2/README.rst000077500000000000000000000464031375753423500162000ustar00rootroot00000000000000|Build Status Linux MacOS| |Build Status Win| |Coverage Status| |PyPi| |Download Counter| |JOSS| PyClustering ============ **pyclustering** is a Python, C++ data mining library (clustering algorithm, oscillatory networks, neural networks). The library provides Python and C++ implementations (C++ pyclustering library) of each algorithm or model. C++ pyclustering library is a part of pyclustering and supported for Linux, Windows and MacOS operating systems. **Version**: 0.10.1.2 **License**: The 3-Clause BSD License **E-Mail**: pyclustering@yandex.ru **Documentation**: https://pyclustering.github.io/docs/0.10.1/html/ **Homepage**: https://pyclustering.github.io/ **PyClustering Wiki**: https://github.com/annoviko/pyclustering/wiki Dependencies ============ **Required packages**: scipy, matplotlib, numpy, Pillow **Python version**: >=3.6 (32-bit, 64-bit) **C++ version**: >= 14 (32-bit, 64-bit) Performance =========== Each algorithm is implemented using Python and C/C++ language, if your platform is not supported then Python implementation is used, otherwise C/C++. Implementation can be chosen by `ccore` flag (by default it is always 'True' and it means that C/C++ is used), for example: .. code:: python # As by default - C/C++ part of the library is used xmeans_instance_1 = xmeans(data_points, start_centers, 20, ccore=True); # The same - C/C++ part of the library is used by default xmeans_instance_2 = xmeans(data_points, start_centers, 20); # Switch off core - Python is used xmeans_instance_3 = xmeans(data_points, start_centers, 20, ccore=False); Installation ============ Installation using pip3 tool: .. code:: bash $ pip3 install pyclustering Manual installation from official repository using Makefile: .. code:: bash # get sources of the pyclustering library, for example, from repository $ mkdir pyclustering $ cd pyclustering/ $ git clone https://github.com/annoviko/pyclustering.git . # compile CCORE library (core of the pyclustering library). $ cd ccore/ $ make ccore_64bit # build for 64-bit OS # $ make ccore_32bit # build for 32-bit OS # return to parent folder of the pyclustering library $ cd ../ # install pyclustering library $ python3 setup.py install # optionally - test the library $ python3 setup.py test Manual installation using CMake: .. code:: bash # get sources of the pyclustering library, for example, from repository $ mkdir pyclustering $ cd pyclustering/ $ git clone https://github.com/annoviko/pyclustering.git . # generate build files. $ mkdir build $ cmake .. # build pyclustering-shared target depending on what was generated (Makefile or MSVC solution) # if Makefile has been generated then $ make pyclustering-shared # return to parent folder of the pyclustering library $ cd ../ # install pyclustering library $ python3 setup.py install # optionally - test the library $ python3 setup.py test Manual installation using Microsoft Visual Studio solution: 1. Clone repository from: https://github.com/annoviko/pyclustering.git 2. Open folder `pyclustering/ccore` 3. Open Visual Studio project `ccore.sln` 4. Select solution platform: `x86` or `x64` 5. Build `pyclustering-shared` project. 6. Add pyclustering folder to python path or install it using setup.py .. code:: bash # install pyclustering library $ python3 setup.py install # optionally - test the library $ python3 setup.py test Proposals, Questions, Bugs ========================== In case of any questions, proposals or bugs related to the pyclustering please contact to pyclustering@yandex.ru or create an issue here. PyClustering Status =================== +----------------------+------------------------------+-------------------------------------+---------------------------------+ | Branch | master | 0.10.dev | 0.10.1.rel | +======================+==============================+=====================================+=================================+ | Build (Linux, MacOS) | |Build Status Linux MacOS| | |Build Status Linux MacOS 0.10.dev| | |Build Status Linux 0.10.1.rel| | +----------------------+------------------------------+-------------------------------------+---------------------------------+ | Build (Win) | |Build Status Win| | |Build Status Win 0.10.dev| | |Build Status Win 0.10.1.rel| | +----------------------+------------------------------+-------------------------------------+---------------------------------+ | Code Coverage | |Coverage Status| | |Coverage Status 0.10.dev| | |Coverage Status 0.10.1.rel| | +----------------------+------------------------------+-------------------------------------+---------------------------------+ Cite the Library ================ If you are using pyclustering library in a scientific paper, please, cite the library: Novikov, A., 2019. PyClustering: Data Mining Library. Journal of Open Source Software, 4(36), p.1230. Available at: http://dx.doi.org/10.21105/joss.01230. BibTeX entry: .. code:: @article{Novikov2019, doi = {10.21105/joss.01230}, url = {https://doi.org/10.21105/joss.01230}, year = 2019, month = {apr}, publisher = {The Open Journal}, volume = {4}, number = {36}, pages = {1230}, author = {Andrei Novikov}, title = {{PyClustering}: Data Mining Library}, journal = {Journal of Open Source Software} } Brief Overview of the Library Content ===================================== **Clustering algorithms and methods (module pyclustering.cluster):** +------------------------+---------+-----+ | Algorithm | Python | C++ | +========================+=========+=====+ | Agglomerative | ✓ | ✓ | +------------------------+---------+-----+ | BANG | ✓ | | +------------------------+---------+-----+ | BIRCH | ✓ | | +------------------------+---------+-----+ | BSAS | ✓ | ✓ | +------------------------+---------+-----+ | CLARANS | ✓ | | +------------------------+---------+-----+ | CLIQUE | ✓ | ✓ | +------------------------+---------+-----+ | CURE | ✓ | ✓ | +------------------------+---------+-----+ | DBSCAN | ✓ | ✓ | +------------------------+---------+-----+ | Elbow | ✓ | ✓ | +------------------------+---------+-----+ | EMA | ✓ | | +------------------------+---------+-----+ | Fuzzy C-Means | ✓ | ✓ | +------------------------+---------+-----+ | GA (Genetic Algorithm) | ✓ | ✓ | +------------------------+---------+-----+ | G-Means | ✓ | ✓ | +------------------------+---------+-----+ | HSyncNet | ✓ | ✓ | +------------------------+---------+-----+ | K-Means | ✓ | ✓ | +------------------------+---------+-----+ | K-Means++ | ✓ | ✓ | +------------------------+---------+-----+ | K-Medians | ✓ | ✓ | +------------------------+---------+-----+ | K-Medoids | ✓ | ✓ | +------------------------+---------+-----+ | MBSAS | ✓ | ✓ | +------------------------+---------+-----+ | OPTICS | ✓ | ✓ | +------------------------+---------+-----+ | ROCK | ✓ | ✓ | +------------------------+---------+-----+ | Silhouette | ✓ | ✓ | +------------------------+---------+-----+ | SOM-SC | ✓ | ✓ | +------------------------+---------+-----+ | SyncNet | ✓ | ✓ | +------------------------+---------+-----+ | Sync-SOM | ✓ | | +------------------------+---------+-----+ | TTSAS | ✓ | ✓ | +------------------------+---------+-----+ | X-Means | ✓ | ✓ | +------------------------+---------+-----+ **Oscillatory networks and neural networks (module pyclustering.nnet):** +--------------------------------------------------------------------------------+---------+-----+ | Model | Python | C++ | +================================================================================+=========+=====+ | CNN (Chaotic Neural Network) | ✓ | | +--------------------------------------------------------------------------------+---------+-----+ | fSync (Oscillatory network based on Landau-Stuart equation and Kuramoto model) | ✓ | | +--------------------------------------------------------------------------------+---------+-----+ | HHN (Oscillatory network based on Hodgkin-Huxley model) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ | Hysteresis Oscillatory Network | ✓ | | +--------------------------------------------------------------------------------+---------+-----+ | LEGION (Local Excitatory Global Inhibitory Oscillatory Network) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ | PCNN (Pulse-Coupled Neural Network) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ | SOM (Self-Organized Map) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ | Sync (Oscillatory network based on Kuramoto model) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ | SyncPR (Oscillatory network for pattern recognition) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ | SyncSegm (Oscillatory network for image segmentation) | ✓ | ✓ | +--------------------------------------------------------------------------------+---------+-----+ **Graph Coloring Algorithms (module pyclustering.gcolor):** +------------------------+---------+-----+ | Algorithm | Python | C++ | +========================+=========+=====+ | DSatur | ✓ | | +------------------------+---------+-----+ | Hysteresis | ✓ | | +------------------------+---------+-----+ | GColorSync | ✓ | | +------------------------+---------+-----+ **Containers (module pyclustering.container):** +------------------------+---------+-----+ | Algorithm | Python | C++ | +========================+=========+=====+ | KD Tree | ✓ | ✓ | +------------------------+---------+-----+ | CF Tree | ✓ | | +------------------------+---------+-----+ Examples in the Library ======================= The library contains examples for each algorithm and oscillatory network model: **Clustering examples:** ``pyclustering/cluster/examples`` **Graph coloring examples:** ``pyclustering/gcolor/examples`` **Oscillatory network examples:** ``pyclustering/nnet/examples`` .. image:: https://github.com/annoviko/pyclustering/blob/master/docs/img/example_cluster_place.png :alt: Where are examples? Code Examples ============= **Data clustering by CURE algorithm** .. code:: python from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.cure import cure; from pyclustering.utils import read_sample; from pyclustering.samples.definitions import FCPS_SAMPLES; # Input data in following format [ [0.1, 0.5], [0.3, 0.1], ... ]. input_data = read_sample(FCPS_SAMPLES.SAMPLE_LSUN); # Allocate three clusters. cure_instance = cure(input_data, 3); cure_instance.process(); clusters = cure_instance.get_clusters(); # Visualize allocated clusters. visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, input_data); visualizer.show(); **Data clustering by K-Means algorithm** .. code:: python from pyclustering.cluster.kmeans import kmeans, kmeans_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis. sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Prepare initial centers using K-Means++ method. initial_centers = kmeans_plusplus_initializer(sample, 2).initialize() # Create instance of K-Means algorithm with prepared centers. kmeans_instance = kmeans(sample, initial_centers) # Run cluster analysis and obtain results. kmeans_instance.process() clusters = kmeans_instance.get_clusters() final_centers = kmeans_instance.get_centers() # Visualize obtained results kmeans_visualizer.show_clusters(sample, clusters, final_centers) **Data clustering by OPTICS algorithm** .. code:: python from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Read sample for clustering from some file sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Run cluster analysis where connectivity radius is bigger than real radius = 2.0 neighbors = 3 amount_of_clusters = 3 optics_instance = optics(sample, radius, neighbors, amount_of_clusters) # Performs cluster analysis optics_instance.process() # Obtain results of clustering clusters = optics_instance.get_clusters() noise = optics_instance.get_noise() ordering = optics_instance.get_ordering() # Visualize ordering diagram analyser = ordering_analyser(ordering) ordering_visualizer.show_ordering_diagram(analyser, amount_of_clusters) # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() **Simulation of oscillatory network PCNN** .. code:: python from pyclustering.nnet.pcnn import pcnn_network, pcnn_visualizer # Create Pulse-Coupled neural network with 10 oscillators. net = pcnn_network(10) # Perform simulation during 100 steps using binary external stimulus. dynamic = net.simulate(50, [1, 1, 1, 0, 0, 0, 0, 1, 1, 1]) # Allocate synchronous ensembles from the output dynamic. ensembles = dynamic.allocate_sync_ensembles() # Show output dynamic. pcnn_visualizer.show_output_dynamic(dynamic, ensembles) **Simulation of chaotic neural network CNN** .. code:: python from pyclustering.cluster import cluster_visualizer from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.nnet.cnn import cnn_network, cnn_visualizer # Load stimulus from file. stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Create chaotic neural network, amount of neurons should be equal to amount of stimulus. network_instance = cnn_network(len(stimulus)) # Perform simulation during 100 steps. steps = 100 output_dynamic = network_instance.simulate(steps, stimulus) # Display output dynamic of the network. cnn_visualizer.show_output_dynamic(output_dynamic) # Display dynamic matrix and observation matrix to show clustering phenomenon. cnn_visualizer.show_dynamic_matrix(output_dynamic) cnn_visualizer.show_observation_matrix(output_dynamic) # Visualize clustering results. clusters = output_dynamic.allocate_sync_ensembles(10) visualizer = cluster_visualizer() visualizer.append_clusters(clusters, stimulus) visualizer.show() Illustrations ============= **Cluster allocation on FCPS dataset collection by DBSCAN:** .. image:: https://github.com/annoviko/pyclustering/blob/master/docs/img/fcps_cluster_analysis.png :alt: Clustering by DBSCAN **Cluster allocation by OPTICS using cluster-ordering diagram:** .. image:: https://github.com/annoviko/pyclustering/blob/master/docs/img/optics_example_clustering.png :alt: Clustering by OPTICS **Partial synchronization (clustering) in Sync oscillatory network:** .. image:: https://github.com/annoviko/pyclustering/blob/master/docs/img/sync_partial_synchronization.png :alt: Partial synchronization in Sync oscillatory network **Cluster visualization by SOM (Self-Organized Feature Map)** .. image:: https://github.com/annoviko/pyclustering/blob/master/docs/img/target_som_processing.png :alt: Cluster visualization by SOM .. |Build Status Linux MacOS| image:: https://travis-ci.org/annoviko/pyclustering.svg?branch=master :target: https://travis-ci.org/annoviko/pyclustering .. |Build Status Win| image:: https://ci.appveyor.com/api/projects/status/4uly2exfp49emwn0/branch/master?svg=true :target: https://ci.appveyor.com/project/annoviko/pyclustering/branch/master .. |Coverage Status| image:: https://coveralls.io/repos/github/annoviko/pyclustering/badge.svg?branch=master&ts=1 :target: https://coveralls.io/github/annoviko/pyclustering?branch=master .. |DOI| image:: https://zenodo.org/badge/DOI/10.5281/zenodo.4280556.svg :target: https://doi.org/10.5281/zenodo.4280556 .. |PyPi| image:: https://badge.fury.io/py/pyclustering.svg :target: https://badge.fury.io/py/pyclustering .. |Build Status Linux MacOS 0.10.dev| image:: https://travis-ci.org/annoviko/pyclustering.svg?branch=0.10.dev :target: https://travis-ci.org/annoviko/pyclustering .. |Build Status Win 0.10.dev| image:: https://ci.appveyor.com/api/projects/status/4uly2exfp49emwn0/branch/0.10.dev?svg=true :target: https://ci.appveyor.com/project/annoviko/pyclustering/branch/0.9.dev .. |Coverage Status 0.10.dev| image:: https://coveralls.io/repos/github/annoviko/pyclustering/badge.svg?branch=0.10.dev&ts=1 :target: https://coveralls.io/github/annoviko/pyclustering?branch=0.9.dev .. |Build Status Linux 0.10.1.rel| image:: https://travis-ci.org/annoviko/pyclustering.svg?branch=0.10.1.rel :target: https://travis-ci.org/annoviko/pyclustering .. |Build Status Win 0.10.1.rel| image:: https://ci.appveyor.com/api/projects/status/4uly2exfp49emwn0/branch/0.10.1.rel?svg=true :target: https://ci.appveyor.com/project/annoviko/pyclustering/branch/0.10.1.rel .. |Coverage Status 0.10.1.rel| image:: https://coveralls.io/repos/github/annoviko/pyclustering/badge.svg?branch=0.10.1.rel&ts=1 :target: https://coveralls.io/github/annoviko/pyclustering?branch=0.10.1.rel .. |Download Counter| image:: https://pepy.tech/badge/pyclustering :target: https://pepy.tech/project/pyclustering .. |JOSS| image:: http://joss.theoj.org/papers/10.21105/joss.01230/status.svg :target: https://doi.org/10.21105/joss.01230 pyclustering-0.10.1.2/appveyor.yml000077500000000000000000000011771375753423500171000ustar00rootroot00000000000000version: '{build}' os: Visual Studio 2015 platform: x64 init: [] environment: CYGWIN_PATH: C:\cygwin64\bin\bash PYTHON: C:\Python36-x64\python.exe TESTING_RESULT: "Success" GITHUB_TOKEN: secure: gzN7IIwlku2+7LB0SO+41zfT04Iir7WgCypBx/lwniP5JbxFl4dtjjMN/jj7sQZ1 YANDEX_DISK_TOKEN: secure: R//j8C73CXwMBOyzobmPYGMUz/uPo9QyQrYXpJyvPIR5EeaX7f054/z1uddYdYux matrix: - CI_JOB: "BUILD_WINDOWS_CCORE" - CI_JOB: "UT_WINDOWS_CCORE" - CI_JOB: "BUILD_CYGWIN_CCORE" - CI_JOB: "PYCLUSTERING_WINDOWS_X86" - CI_JOB: "PYCLUSTERING_WINDOWS_X64" build_script: - ps: ./ci/appveyor-ci.ps1 pyclustering-0.10.1.2/ccore/000077500000000000000000000000001375753423500155725ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/.cproject000066400000000000000000000376601375753423500174200ustar00rootroot00000000000000 pyclustering-0.10.1.2/ccore/.project000066400000000000000000000014461375753423500172460ustar00rootroot00000000000000 ccore org.eclipse.cdt.managedbuilder.core.genmakebuilder clean,full,incremental, org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder full,incremental, org.eclipse.cdt.core.cnature org.eclipse.cdt.core.ccnature org.eclipse.cdt.managedbuilder.core.managedBuildNature org.eclipse.cdt.managedbuilder.core.ScannerConfigNature pyclustering-0.10.1.2/ccore/CMakeLists.txt000077500000000000000000000007741375753423500203450ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # cmake_minimum_required(VERSION 3.10) project(pyclustering VERSION 0.10.1.2 LANGUAGES CXX) file(MAKE_DIRECTORY build) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/build) add_subdirectory(bvt) add_subdirectory(external) add_subdirectory(src) add_subdirectory(tst) pyclustering-0.10.1.2/ccore/bvt/000077500000000000000000000000001375753423500163655ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/bvt/CMakeLists.txt000077500000000000000000000013521375753423500211310ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # cmake_minimum_required(VERSION 3.10) # C++ standard set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) # Headers include_directories(${PROJECT_SOURCE_DIR}/include) # Build target - build verify test for static library add_executable(bvt-static static-test.cpp) add_dependencies(bvt-static pyclustering-static) target_link_libraries(bvt-static PUBLIC pyclustering-static) # Build target - build verify test for shared library add_executable(bvt-shared shared-test.cpp) add_dependencies(bvt-shared pyclustering-shared) if(CMAKE_DL_LIBS) target_link_libraries(bvt-shared ${CMAKE_DL_LIBS}) endif() pyclustering-0.10.1.2/ccore/bvt/bvt-shared.vcxproj000077500000000000000000000154461375753423500220560ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {B7248E9B-CB31-41E9-8192-06808C5AD767} bvtshared 8.1 Application true v140 MultiByte Application false v140 true MultiByte Application true v140 MultiByte Application false v140 true MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true Console Level3 Disabled true Console Level3 MaxSpeed true true true true true Console Level3 MaxSpeed true true true true true Console pyclustering-0.10.1.2/ccore/bvt/bvt-static.vcxproj000077500000000000000000000172021375753423500220670ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {21030D67-1950-4CDF-82DC-1B6876B98F72} bvtstatic 8.1 Application true v140 MultiByte Application false v140 true MultiByte Application true v140 MultiByte Application false v140 true MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true $(SolutionDir)\include pyclustering-static.lib $(OutDir) Console Level3 Disabled true $(SolutionDir)\include pyclustering-static.lib $(OutDir) Console Level3 MaxSpeed true true true $(SolutionDir)\include true true pyclustering-static.lib $(OutDir) Console Level3 MaxSpeed true true true $(SolutionDir)\include true true pyclustering-static.lib $(OutDir) Console pyclustering-0.10.1.2/ccore/bvt/shared-test.cpp000077500000000000000000000112321375753423500213160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ /* @brief This is a build verification test (smoke test) that checks possibility to use the library as a shared library by calling one of the functions. @return `0` if the build verification test passed, otherwise negative values that define errors that might occur. */ #if (defined (__GNUC__) && defined(__unix__)) || defined(__APPLE__) #include #elif defined (WIN32) || (_WIN32) || (_WIN64) #include #else #error Unsupported platform #endif #include #include #include #include #include #define SUCCESS 0 #define FAILURE_IMPOSSIBLE_TO_LOAD_LIBRARY 1 #define FAILURE_IMPOSSIBLE_TO_LOAD_FUNCTION 2 #define FAILURE_IMPOSSIBLE_TO_CHECK_VERSION 3 #define FAILURE_IMPOSSIBLE_TO_CHECK_DESCRIPTION 4 #define FAILURE_INCORRECT_VERSION 5 #define FAILURE_INCORRECT_DESCRIPTION 6 const std::unordered_map EXIT_CODE_DESCRIPTION = { { SUCCESS, "Build verification test for C++ pyclustering shared library is successfully passed." }, { FAILURE_IMPOSSIBLE_TO_LOAD_LIBRARY, "Error: Impossible to load C++ pyclustering shared library." }, { FAILURE_IMPOSSIBLE_TO_LOAD_FUNCTION, "Error: Impossible to load function from C++ pyclustering shared library." }, { FAILURE_IMPOSSIBLE_TO_CHECK_VERSION, "Error: Impossible to check version of C++ pyclustering shared library." }, { FAILURE_IMPOSSIBLE_TO_CHECK_DESCRIPTION, "Error: Impossible to check description of C++ pyclustering shared library." }, { FAILURE_INCORRECT_VERSION, "Error: C++ pyclustering library contains wrong version." }, { FAILURE_INCORRECT_DESCRIPTION, "Error: C++ pyclustering library contains wrong description." } }; void exit_with_code(const int p_code) { const auto iter = EXIT_CODE_DESCRIPTION.find(p_code); if (iter != EXIT_CODE_DESCRIPTION.cend()) { if (p_code != SUCCESS) { std::cerr << iter->second << std::endl; } else { std::cout << iter->second << std::endl; } } std::exit(p_code); } void * load_pyclustering(void) { #if (defined (__GNUC__) && defined(__unix__)) || defined(__APPLE__) return dlopen("./libpyclustering.so", RTLD_LAZY); #elif defined (WIN32) || (_WIN32) || (_WIN64) return LoadLibrary("pyclustering.dll"); #else #error Unsupported platform #endif } void close_pyclustering(void * library) { #if (defined (__GNUC__) && defined(__unix__)) || defined(__APPLE__) dlclose(library); #elif defined (WIN32) || (_WIN32) || (_WIN64) FreeLibrary((HMODULE) library); #endif } using interface_desc_func_t = void * (void); using interface_vers_func_t = void * (void); interface_desc_func_t * get_interface_desc_func(void * library) { #if (defined (__GNUC__) && defined(__unix__)) || defined(__APPLE__) return (interface_desc_func_t *) dlsym(library, "get_interface_description"); #elif defined (WIN32) || (_WIN32) || (_WIN64) return (interface_desc_func_t *) GetProcAddress((HMODULE) library, "get_interface_description"); #endif } interface_vers_func_t * get_interface_vers_func(void * library) { #if (defined (__GNUC__) && defined(__unix__)) || defined(__APPLE__) return (interface_vers_func_t *) dlsym(library, "get_interface_version"); #elif defined (WIN32) || (_WIN32) || (_WIN64) return (interface_vers_func_t *) GetProcAddress((HMODULE) library, "get_interface_version"); #endif } int main() { void * library = load_pyclustering(); if (!library) { exit_with_code(FAILURE_IMPOSSIBLE_TO_LOAD_LIBRARY); } interface_vers_func_t * get_version = get_interface_vers_func(library); if (!get_version) { exit_with_code(FAILURE_IMPOSSIBLE_TO_LOAD_FUNCTION); } interface_desc_func_t * get_description = get_interface_desc_func(library); if (!get_description) { exit_with_code(FAILURE_IMPOSSIBLE_TO_LOAD_FUNCTION); } const char * version = (const char *)get_version(); if (!version) { exit_with_code(FAILURE_IMPOSSIBLE_TO_CHECK_VERSION); } if (strlen(version) == 0) { exit_with_code(FAILURE_INCORRECT_VERSION); } const char * description = (const char *)get_description(); if (!description) { exit_with_code(FAILURE_IMPOSSIBLE_TO_CHECK_DESCRIPTION); } std::string description_as_string(description); if (description_as_string.find("pyclustering") == std::string::npos) { exit_with_code(FAILURE_INCORRECT_DESCRIPTION); } close_pyclustering(library); exit_with_code(SUCCESS); } pyclustering-0.10.1.2/ccore/bvt/static-test.cpp000077500000000000000000000011101375753423500213310ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #define SUCCESS 0 #define FAILURE_INCORRECT_RESULT 1 int main() { pyclustering::clst::gmeans_data result; pyclustering::clst::gmeans algorithm(2); algorithm.process({ { 1.0 }, { 1.2 }, { 1.1 }, { 3.0 }, { 3.2 }, { 3.1 }, { 8.0 }, { 8.2 }, { 8.1 } }, result); if (result.clusters().empty()) { return FAILURE_INCORRECT_RESULT; } return SUCCESS; } pyclustering-0.10.1.2/ccore/ccore.mk000077500000000000000000000065021375753423500172240ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # # Tools RM = rm -rf MKDIR = mkdir -p AR = ar rcs # C++ standard depending on operating system UNAME = $(shell uname -s | tr '[:upper:]' '[:lower:]') ifeq ($(findstring cygwin, $(UNAME)), cygwin) OSNAME = win CPLUS_STANDARD = gnu++14 CFLAG_PIC = else ifeq ($(UNAME), darwin) OSNAME = macos else OSNAME = linux endif CPLUS_STANDARD = c++14 CFLAG_PIC = -fPIC endif # Compiler (g++ compiler is used by default) ifeq ($(COMPILER), clang) CC = scan-build clang++ -c LD = scan-build clang++ else CC = g++ -c LD = g++ endif # Target flag depending on platform ifeq ($(PLATFORM), 32-bit) CFLAG_PLATFORM = -m32 LFLAG_PLATFORM = -m32 else ifeq ($(PLATFORM), 64-bit) CFLAG_PLATFORM = -m64 LFLAG_PLATFORM = -m64 else PLATFORM = 64-bit CFLAG_PLATFORM = -m64 LFLAG_PLATFORM = -m64 endif endif # Definitions DEFINITION_FLAGS = # Warnings WARNING_FLAGS = -Wall -Wpedantic # Shared library file SHARED_LIB_DEPLOY_DIRECTORY = ../pyclustering/core/$(PLATFORM)/$(OSNAME) SHARED_LIB_DIRECTORY = . SHARED_LIB = $(SHARED_LIB_DIRECTORY)/libpyclustering.so # Static library file STATIC_LIB_DIRECTORY = . STATIC_LIB = libpyclustering.a # Project sources MODULES = . cluster container differential interface nnet parallel utils PROJECT_DIRECTORY = . INCLUDE_DIRECTORY = $(PROJECT_DIRECTORY)/include/ SOURCES_DIRECTORY = src SOURCES_DIRECTORIES = $(addprefix $(SOURCES_DIRECTORY)/, $(MODULES)) SOURCES = $(foreach SUBDIR, $(SOURCES_DIRECTORIES), $(wildcard $(SUBDIR)/*.cpp)) INCLUDES = -I$(INCLUDE_DIRECTORY) LIBRARIES = # Toolchain arguments CFLAGS = -O2 -MMD -MP -pthread -std=$(CPLUS_STANDARD) $(CFLAG_PIC) $(CFLAG_PLATFORM) $(WARNING_FLAGS) $(DEFINITION_FLAGS) LFLAGS = -shared -pthread $(LFLAG_PLATFORM) $(LIBRARIES) # Project objects OBJECTS_ROOT = obj OBJECTS_DIRECTORY = $(OBJECTS_ROOT)/ccore/$(PLATFORM) OBJECTS_DIRECTORIES = $(addprefix $(OBJECTS_DIRECTORY)/, $(MODULES)) $(SHARED_LIB_DIRECTORY) OBJECTS = $(patsubst $(SOURCES_DIRECTORY)/%.cpp, $(OBJECTS_DIRECTORY)/%.o, $(SOURCES)) # Dependencies DEPENDENCIES = $(OBJECTS:.o=.d) # Targets .PHONY: cppcheck cppcheck: cppcheck --version cppcheck --inline-suppr --error-exitcode=1 --std=c++14 --inconclusive --enable=warning,style,performance,information,portability -I $(INCLUDE_DIRECTORY) $(SOURCES_DIRECTORY) .PHONY: ccore ccore: shared_library_definitions mkdirs $(SHARED_LIB) deploy .PHONY: shared_library_definitions shared_library_definitions: $(eval DEFINITION_FLAGS := -DEXPORT_PYCLUSTERING_INTERFACE) .PHONY: ccore_static ccore_static: mkdirs $(STATIC_LIB) .PHONY: mkdirs mkdirs: $(OBJECTS_DIRECTORIES) .PHONY: deploy deploy: $(SHARED_LIB) echo "Copy C++ shared library to Python pyclustering." cp $(SHARED_LIB) $(SHARED_LIB_DEPLOY_DIRECTORY) $(OBJECTS_DIRECTORIES): $(MKDIR) $@ .PHONY: clean: $(RM) $(OBJECTS_DIRECTORY) $(SHARED_LIB) $(STATIC_LIB) # Build targets $(SHARED_LIB): $(OBJECTS) $(LD) $(LFLAGS) $^ -o $@ $(STATIC_LIB): $(OBJECTS) $(AR) $@ $^ $(OBJECTS_DIRECTORY)/%.o: $(SOURCES_DIRECTORY)/%.cpp $(CC) $(CFLAGS) $(INCLUDES) $(LIBRARIES) $< -o $@ # Include dependencies -include $(DEPENDENCIES) pyclustering-0.10.1.2/ccore/ccore.sln000077500000000000000000000165261375753423500174200ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bvt", "bvt", "{841E66D7-A748-48AC-A655-7CB192224B69}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyclustering-shared", "src\pyclustering-shared.vcxproj", "{A1F1A829-2678-40A6-AF79-87E58AC4BADB}" ProjectSection(ProjectDependencies) = postProject {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} = {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyclustering-static", "src\pyclustering-static.vcxproj", "{4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bvt-shared", "bvt\bvt-shared.vcxproj", "{B7248E9B-CB31-41E9-8192-06808C5AD767}" ProjectSection(ProjectDependencies) = postProject {A1F1A829-2678-40A6-AF79-87E58AC4BADB} = {A1F1A829-2678-40A6-AF79-87E58AC4BADB} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bvt-static", "bvt\bvt-static.vcxproj", "{21030D67-1950-4CDF-82DC-1B6876B98F72}" ProjectSection(ProjectDependencies) = postProject {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} = {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ut", "ut", "{8C0E02D2-E81F-4B49-90DF-998DF86A3574}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ut-shared", "tst\ut-shared.vcxproj", "{5658C777-AC3B-4FF3-B009-DF9C9DB035A4}" ProjectSection(ProjectDependencies) = postProject {A1F1A829-2678-40A6-AF79-87E58AC4BADB} = {A1F1A829-2678-40A6-AF79-87E58AC4BADB} {40A75591-4C3C-466F-BCED-6CFEDABD4938} = {40A75591-4C3C-466F-BCED-6CFEDABD4938} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ut-static", "tst\ut-static.vcxproj", "{5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}" ProjectSection(ProjectDependencies) = postProject {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} = {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} {40A75591-4C3C-466F-BCED-6CFEDABD4938} = {40A75591-4C3C-466F-BCED-6CFEDABD4938} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "tst\gtest.vcxproj", "{40A75591-4C3C-466F-BCED-6CFEDABD4938}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Debug|x64.ActiveCfg = Debug|x64 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Debug|x64.Build.0 = Debug|x64 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Debug|x86.ActiveCfg = Debug|Win32 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Debug|x86.Build.0 = Debug|Win32 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Release|x64.ActiveCfg = Release|x64 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Release|x64.Build.0 = Release|x64 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Release|x86.ActiveCfg = Release|Win32 {A1F1A829-2678-40A6-AF79-87E58AC4BADB}.Release|x86.Build.0 = Release|Win32 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Debug|x64.ActiveCfg = Debug|x64 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Debug|x64.Build.0 = Debug|x64 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Debug|x86.ActiveCfg = Debug|Win32 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Debug|x86.Build.0 = Debug|Win32 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Release|x64.ActiveCfg = Release|x64 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Release|x64.Build.0 = Release|x64 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Release|x86.ActiveCfg = Release|Win32 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2}.Release|x86.Build.0 = Release|Win32 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Debug|x64.ActiveCfg = Debug|x64 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Debug|x64.Build.0 = Debug|x64 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Debug|x86.ActiveCfg = Debug|Win32 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Debug|x86.Build.0 = Debug|Win32 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Release|x64.ActiveCfg = Release|x64 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Release|x64.Build.0 = Release|x64 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Release|x86.ActiveCfg = Release|Win32 {B7248E9B-CB31-41E9-8192-06808C5AD767}.Release|x86.Build.0 = Release|Win32 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Debug|x64.ActiveCfg = Debug|x64 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Debug|x64.Build.0 = Debug|x64 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Debug|x86.ActiveCfg = Debug|Win32 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Debug|x86.Build.0 = Debug|Win32 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Release|x64.ActiveCfg = Release|x64 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Release|x64.Build.0 = Release|x64 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Release|x86.ActiveCfg = Release|Win32 {21030D67-1950-4CDF-82DC-1B6876B98F72}.Release|x86.Build.0 = Release|Win32 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Debug|x64.ActiveCfg = Debug|x64 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Debug|x64.Build.0 = Debug|x64 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Debug|x86.ActiveCfg = Debug|Win32 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Debug|x86.Build.0 = Debug|Win32 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Release|x64.ActiveCfg = Release|x64 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Release|x64.Build.0 = Release|x64 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Release|x86.ActiveCfg = Release|Win32 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4}.Release|x86.Build.0 = Release|Win32 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Debug|x64.ActiveCfg = Debug|x64 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Debug|x64.Build.0 = Debug|x64 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Debug|x86.ActiveCfg = Debug|Win32 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Debug|x86.Build.0 = Debug|Win32 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Release|x64.ActiveCfg = Release|x64 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Release|x64.Build.0 = Release|x64 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Release|x86.ActiveCfg = Release|Win32 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00}.Release|x86.Build.0 = Release|Win32 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Debug|x64.ActiveCfg = Debug|x64 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Debug|x64.Build.0 = Debug|x64 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Debug|x86.ActiveCfg = Debug|Win32 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Debug|x86.Build.0 = Debug|Win32 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Release|x64.ActiveCfg = Release|x64 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Release|x64.Build.0 = Release|x64 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Release|x86.ActiveCfg = Release|Win32 {40A75591-4C3C-466F-BCED-6CFEDABD4938}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {B7248E9B-CB31-41E9-8192-06808C5AD767} = {841E66D7-A748-48AC-A655-7CB192224B69} {21030D67-1950-4CDF-82DC-1B6876B98F72} = {841E66D7-A748-48AC-A655-7CB192224B69} {5658C777-AC3B-4FF3-B009-DF9C9DB035A4} = {8C0E02D2-E81F-4B49-90DF-998DF86A3574} {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00} = {8C0E02D2-E81F-4B49-90DF-998DF86A3574} {40A75591-4C3C-466F-BCED-6CFEDABD4938} = {8C0E02D2-E81F-4B49-90DF-998DF86A3574} EndGlobalSection EndGlobal pyclustering-0.10.1.2/ccore/external/000077500000000000000000000000001375753423500174145ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/CMakeLists.txt000077500000000000000000000006261375753423500221630ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # cmake_minimum_required(VERSION 3.10) # C++ standard set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) # Source for google test framework file(GLOB_RECURSE GTEST_SOURCES src/gtest "*.cpp") # Headers include_directories(include) # Build targets add_library(gtest STATIC ${GTEST_SOURCES}) pyclustering-0.10.1.2/ccore/external/include/000077500000000000000000000000001375753423500210375ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/include/gtest/000077500000000000000000000000001375753423500221655ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/include/gtest/gtest.h000077500000000000000000031261431375753423500235010ustar00rootroot00000000000000// Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for Google Test. It should be // included by any test program that uses Google Test. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! // // Acknowledgment: Google Test borrowed the idea of automatic test // registration from Barthelemy Dagenais' (barthelemy@prologique.com) // easyUnit framework. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_H_ #include #include #include // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares functions and macros used internally by // Google Test. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan) // // Low-level types and utilities for porting Google Test to various // platforms. They are subject to change without notice. DO NOT USE // THEM IN USER CODE. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // The user can define the following macros in the build script to // control Google Test's behavior. If the user doesn't define a macro // in this list, Google Test will define it. // // GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) // is/isn't available. // GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions // are enabled. // GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::string, which is different to std::string). // GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string // is/isn't available (some systems define // ::wstring, which is different to std::wstring). // GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // is/isn't available. // GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't // enabled. // GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that // std::wstring does/doesn't work (Google Test can // be used where std::wstring is unavailable). // GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple // is/isn't available. // GTEST_HAS_SEH - Define it to 1/0 to indicate whether the // compiler supports Microsoft's "Structured // Exception Handling". // GTEST_HAS_STREAM_REDIRECTION // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). // GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google // Test's own tr1 tuple implementation should be // used. Unused when the user sets // GTEST_HAS_TR1_TUPLE to 0. // GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test // is building in C++11/C++98 mode. // GTEST_LINKED_AS_SHARED_LIBRARY // - Define to 1 when compiling tests that use // Google Test as a shared library (known as // DLL on Windows). // GTEST_CREATE_SHARED_LIBRARY // - Define to 1 when compiling Google Test itself // as a shared library. // This header defines the following utilities: // // Macros indicating the current platform (defined to 1 if compiled on // the given platform; otherwise undefined): // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_IOS_SIMULATOR - iOS simulator // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // GTEST_OS_SOLARIS - Sun Solaris // GTEST_OS_SYMBIAN - Symbian // GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) // GTEST_OS_WINDOWS_DESKTOP - Windows Desktop // GTEST_OS_WINDOWS_MINGW - MinGW // GTEST_OS_WINDOWS_MOBILE - Windows Mobile // GTEST_OS_ZOS - z/OS // // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the // most stable support. Since core members of the Google Test project // don't have access to other platforms, support for them may be less // stable. If you notice any problems on your platform, please notify // googletestframework@googlegroups.com (patches for fixing them are // even more welcome!). // // Note that it is possible that none of the GTEST_OS_* macros are defined. // // Macros indicating available Google Test features (defined to 1 if // the corresponding feature is supported; otherwise undefined): // GTEST_HAS_COMBINE - the Combine() function (for value-parameterized // tests) // GTEST_HAS_DEATH_TEST - death tests // GTEST_HAS_PARAM_TEST - value-parameterized tests // GTEST_HAS_TYPED_TEST - typed tests // GTEST_HAS_TYPED_TEST_P - type-parameterized tests // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // GTEST_USES_SIMPLE_RE - our own simple regex is used; // the above two are mutually exclusive. // GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). // // Macros for basic C++ coding: // GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. // GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a // variable don't have to be used. // GTEST_DISALLOW_ASSIGN_ - disables operator=. // GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. // GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // GTEST_IS_THREADSAFE - defined to 1 to indicate that the above // synchronization primitives have real implementations // and Google Test is thread-safe; or 0 otherwise. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // IteratorTraits - partial implementation of std::iterator_traits, which // is not available in libCstd when compiled with Sun C++. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like // platforms, or a reduced regular exception syntax on // other platforms, including Windows. // // Logging: // GTEST_LOG_() - logs messages at the specified severity level. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. // // Stdout and stderr capturing: // CaptureStdout() - starts capturing stdout. // GetCapturedStdout() - stops capturing stdout and returns the captured // string. // CaptureStderr() - starts capturing stderr. // GetCapturedStderr() - stops capturing stderr and returns the captured // string. // // Integer types: // TypeWithSize - maps an integer to a int type. // Int32, UInt32, Int64, UInt64, TimeInMillis // - integers of known sizes. // BiggestInt - the biggest signed integer type. // // Command-line utilities: // GTEST_FLAG() - references a flag. // GTEST_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - returns the command line as a vector of strings. // // Environment variable utilities: // GetEnv() - gets the value of an environment variable. // BoolFromGTestEnv() - parses a bool environment variable. // Int32FromGTestEnv() - parses an Int32 environment variable. // StringFromGTestEnv() - parses a string environment variable. #include // for isspace, etc #include // for ptrdiff_t #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include // NOLINT #include // NOLINT #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" #define GTEST_FLAG_PREFIX_ "gtest_" #define GTEST_FLAG_PREFIX_DASH_ "gtest-" #define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" #define GTEST_NAME_ "Google Test" #define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" // Determines the version of gcc that is used to compile this. #ifdef __GNUC__ // 40302 means version 4.3.2. # define GTEST_GCC_VER_ \ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) #endif // __GNUC__ // Determines the platform on which Google Test is compiled. #ifdef __CYGWIN__ # define GTEST_OS_CYGWIN 1 #elif defined __SYMBIAN32__ # define GTEST_OS_SYMBIAN 1 #elif defined _WIN32 # define GTEST_OS_WINDOWS 1 # ifdef _WIN32_WCE # define GTEST_OS_WINDOWS_MOBILE 1 # elif defined(__MINGW__) || defined(__MINGW32__) # define GTEST_OS_WINDOWS_MINGW 1 # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # if TARGET_IPHONE_SIMULATOR # define GTEST_OS_IOS_SIMULATOR 1 # endif # endif #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ # define GTEST_OS_LINUX_ANDROID 1 # endif #elif defined __MVS__ # define GTEST_OS_ZOS 1 #elif defined(__sun) && defined(__SVR4) # define GTEST_OS_SOLARIS 1 #elif defined(_AIX) # define GTEST_OS_AIX 1 #elif defined(__hpux) # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 #endif // __CYGWIN__ #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. # if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else # define GTEST_LANG_CXX11 0 # endif #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if !GTEST_OS_WINDOWS // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include #elif !GTEST_OS_WINDOWS_MOBILE # include # include #endif #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif // Defines this to true iff Google Test can use POSIX regular expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. # define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else # define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # endif #endif #if GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_HAS_POSIX_RE #ifndef GTEST_HAS_EXCEPTIONS // The user didn't tell us whether exceptions are enabled, so we need // to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS // macro to enable exceptions, so we'll do the same. // Assumes that exceptions are enabled by default. # ifndef _HAS_EXCEPTIONS # define _HAS_EXCEPTIONS 1 # endif // _HAS_EXCEPTIONS # define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS # elif defined(__GNUC__) && __EXCEPTIONS // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__SUNPRO_CC) // Sun Pro CC supports exceptions. However, there is no compile-time way of // detecting whether they are enabled or not. Therefore, we assume that // they are enabled unless the user tells us otherwise. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__IBMCPP__) && __EXCEPTIONS // xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. # define GTEST_HAS_EXCEPTIONS 1 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. # define GTEST_HAS_EXCEPTIONS 1 # else // For other compilers, we assume exceptions are disabled to be // conservative. # define GTEST_HAS_EXCEPTIONS 0 # endif // defined(_MSC_VER) || defined(__BORLANDC__) #endif // GTEST_HAS_EXCEPTIONS #if !defined(GTEST_HAS_STD_STRING) // Even though we don't use this macro any longer, we keep it in case // some clients still depend on it. # define GTEST_HAS_STD_STRING 1 #elif !GTEST_HAS_STD_STRING // The user told us that ::std::string isn't available. # error "Google Test cannot be used where ::std::string isn't available." #endif // !defined(GTEST_HAS_STD_STRING) #ifndef GTEST_HAS_GLOBAL_STRING // The user didn't tell us whether ::string is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_STRING 0 #endif // GTEST_HAS_GLOBAL_STRING #ifndef GTEST_HAS_STD_WSTRING // The user didn't tell us whether ::std::wstring is available, so we need // to figure it out. // TODO(wan@google.com): uses autoconf to detect whether ::std::wstring // is available. // Cygwin 1.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). # define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) #endif // GTEST_HAS_STD_WSTRING #ifndef GTEST_HAS_GLOBAL_WSTRING // The user didn't tell us whether ::wstring is available, so we need // to figure it out. # define GTEST_HAS_GLOBAL_WSTRING \ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) #endif // GTEST_HAS_GLOBAL_WSTRING // Determines whether RTTI is available. #ifndef GTEST_HAS_RTTI // The user didn't tell us whether RTTI is enabled, so we need to // figure it out. # ifdef _MSC_VER # ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif // Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) # ifdef __GXX_RTTI // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else # define GTEST_HAS_RTTI 1 # endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. # elif defined(__clang__) # define GTEST_HAS_RTTI __has_feature(cxx_rtti) // Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if // both the typeid and dynamic_cast features are present. # elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) # ifdef __RTTI_ALL__ # define GTEST_HAS_RTTI 1 # else # define GTEST_HAS_RTTI 0 # endif # else // For all other compilers, we assume RTTI is enabled. # define GTEST_HAS_RTTI 1 # endif // _MSC_VER #endif // GTEST_HAS_RTTI // It's this header's responsibility to #include when RTTI // is enabled. #if GTEST_HAS_RTTI # include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we assume pthreads support is // available on Linux and Mac. // // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 // to your compiler flags. # define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ || GTEST_OS_QNX) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // NOLINT #endif // Determines whether Google Test can use tr1/tuple. You can define // this macro to 0 to prevent Google Test from using tuple (any // feature depending on tuple with be disabled in this mode). #ifndef GTEST_HAS_TR1_TUPLE # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 # endif #endif // GTEST_HAS_TR1_TUPLE // Determines whether Google Test's own tr1 tuple implementation // should be used. #ifndef GTEST_USE_OWN_TR1_TUPLE // The user didn't tell us, so we need to figure it out. // We use our own TR1 tuple if we aren't sure the user has an // implementation of it already. At this time, libstdc++ 4.0.0+ and // MSVC 2010 are the only mainstream standard libraries that come // with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler // pretends to be GCC by defining __GNUC__ and friends, but cannot // compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 // tuple in a 323 MB Feature Pack download, which we cannot assume the // user has. QNX's QCC compiler is a modified GCC but it doesn't // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif // C++11 specifies that provides std::tuple. Use that if gtest is used // in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 // can build with clang but need to use gcc4.2's libstdc++). # if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) # define GTEST_ENV_HAS_STD_TUPLE_ 1 # endif # if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ # define GTEST_USE_OWN_TR1_TUPLE 0 # else # define GTEST_USE_OWN_TR1_TUPLE 1 # endif #endif // GTEST_USE_OWN_TR1_TUPLE // To avoid conditional compilation everywhere, we make it // gtest-port.h's responsibility to #include the header implementing // tr1/tuple. #if GTEST_HAS_TR1_TUPLE # if GTEST_USE_OWN_TR1_TUPLE // This file was GENERATED by command: // pump.py gtest-tuple.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2009 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Implements a subset of TR1 tuple needed by Google Test and Google Mock. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ #include // For ::std::pair. // The compiler used in Symbian has a bug that prevents us from declaring the // tuple template as a friend (it complains that tuple is redefined). This // hack bypasses the bug by declaring the members that should otherwise be // private as public. // Sun Studio versions < 12 also have the above bug. #if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) # define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: #else # define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ template friend class tuple; \ private: #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // GTEST_n_TYPENAMES_(T) declares a list of n typenames. #define GTEST_0_TYPENAMES_(T) #define GTEST_1_TYPENAMES_(T) typename T##0 #define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 #define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 #define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3 #define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4 #define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5 #define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6 #define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 #define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8 #define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ typename T##3, typename T##4, typename T##5, typename T##6, \ typename T##7, typename T##8, typename T##9 // In theory, defining stuff in the ::std namespace is undefined // behavior. We can do this as we are playing the role of a standard // library vendor. namespace std { namespace tr1 { template class tuple; // Anything in namespace gtest_internal is Google Test's INTERNAL // IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. namespace gtest_internal { // ByRef::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), f1_(f1) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} template tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; return *this; } T0 f0_; T1 f1_; T2 f2_; }; template class GTEST_4_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), f3_(f3) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} template tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; }; template class GTEST_5_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} template tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; }; template class GTEST_6_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} template tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; }; template class GTEST_7_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} template tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; }; template class GTEST_8_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} template tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; }; template class GTEST_9_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} template tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; }; template class tuple { public: template friend class gtest_internal::Get; tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), f9_() {} explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} template tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; f2_ = t.f2_; f3_ = t.f3_; f4_ = t.f4_; f5_ = t.f5_; f6_ = t.f6_; f7_ = t.f7_; f8_ = t.f8_; f9_ = t.f9_; return *this; } T0 f0_; T1 f1_; T2 f2_; T3 f3_; T4 f4_; T5 f5_; T6 f6_; T7 f7_; T8 f8_; T9 f9_; }; // 6.1.3.2 Tuple creation functions. // Known limitations: we don't support passing an // std::tr1::reference_wrapper to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { return GTEST_3_TUPLE_(T)(f0, f1, f2); } template inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3) { return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); } template inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4) { return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); } template inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5) { return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); } template inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6) { return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); } template inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); } template inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8) { return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); } template inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, const T8& f8, const T9& f9) { return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); } // 6.1.3.3 Tuple helper classes. template struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::ConstField(t); } // 6.1.3.5 Relational operators // We only implement == and !=, as we don't have a need for the rest yet. namespace gtest_internal { // SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the // first k fields of t1 equals the first k fields of t2. // SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if // k1 != k2. template struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template inline bool operator!=(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return !(t == u); } // 6.1.4 Pairs. // Unimplemented. } // namespace tr1 } // namespace std #undef GTEST_0_TUPLE_ #undef GTEST_1_TUPLE_ #undef GTEST_2_TUPLE_ #undef GTEST_3_TUPLE_ #undef GTEST_4_TUPLE_ #undef GTEST_5_TUPLE_ #undef GTEST_6_TUPLE_ #undef GTEST_7_TUPLE_ #undef GTEST_8_TUPLE_ #undef GTEST_9_TUPLE_ #undef GTEST_10_TUPLE_ #undef GTEST_0_TYPENAMES_ #undef GTEST_1_TYPENAMES_ #undef GTEST_2_TYPENAMES_ #undef GTEST_3_TYPENAMES_ #undef GTEST_4_TYPENAMES_ #undef GTEST_5_TYPENAMES_ #undef GTEST_6_TYPENAMES_ #undef GTEST_7_TYPENAMES_ #undef GTEST_8_TYPENAMES_ #undef GTEST_9_TYPENAMES_ #undef GTEST_10_TYPENAMES_ #undef GTEST_DECLARE_TUPLE_AS_FRIEND_ #undef GTEST_BY_REF_ #undef GTEST_ADD_REF_ #undef GTEST_TUPLE_ELEMENT_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ # elif GTEST_ENV_HAS_STD_TUPLE_ # include // C++11 puts its tuple into the ::std namespace rather than // ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. // This causes undefined behavior, but supported compilers react in // the way we intend. namespace std { namespace tr1 { using ::std::get; using ::std::make_tuple; using ::std::tuple; using ::std::tuple_element; using ::std::tuple_size; } } # elif GTEST_OS_SYMBIAN // On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to // use STLport's tuple implementation, which unfortunately doesn't // work as the copy of STLport distributed with Symbian is incomplete. // By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to // use its own tuple implementation. # ifdef BOOST_HAS_TR1_TUPLE # undef BOOST_HAS_TR1_TUPLE # endif // BOOST_HAS_TR1_TUPLE // This prevents , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED # include # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . # if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. # else # include // NOLINT # endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 # else // If the compiler is not GCC 4.0+, we assume the user is using a // spec-conforming TR1 implementation. # include // NOLINT # endif // GTEST_USE_OWN_TR1_TUPLE #endif // GTEST_HAS_TR1_TUPLE // Determines whether clone(2) is supported. // Usually it will only be available on Linux, excluding // Linux on the Itanium architecture. // Also see http://linux.die.net/man/2/clone. #ifndef GTEST_HAS_CLONE // The user didn't tell us, so we need to figure it out. # if GTEST_OS_LINUX && !defined(__ia64__) # if GTEST_OS_LINUX_ANDROID // On Android, clone() is only available on ARM starting with Gingerbread. # if defined(__arm__) && __ANDROID_API__ >= 9 # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else # define GTEST_HAS_CLONE 1 # endif # else # define GTEST_HAS_CLONE 0 # endif // GTEST_OS_LINUX && !defined(__ia64__) #endif // GTEST_HAS_CLONE // Determines whether to support stream redirection. This is used to test // output correctness and to implement death tests. #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. # if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 # endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #endif // GTEST_HAS_STREAM_REDIRECTION // Determines whether to support death tests. // Google Test does not support death tests for VC 7.1 and earlier as // abort() in a VC 7.1 application compiled as GUI in debug config // pops up a dialog window that cannot be suppressed programmatically. #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ GTEST_OS_OPENBSD || GTEST_OS_QNX) # define GTEST_HAS_DEATH_TEST 1 # include // NOLINT #endif // We don't support MSVC 7.1 with exceptions disabled now. Therefore // all the compilers we care about are adequate for supporting // value-parameterized tests. #define GTEST_HAS_PARAM_TEST 1 // Determines whether to support type-driven tests. // Typed tests need and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # define GTEST_HAS_TYPED_TEST 1 # define GTEST_HAS_TYPED_TEST_P 1 #endif // Determines whether to support Combine(). This only makes sense when // value-parameterized tests are enabled. The implementation doesn't // work on Sun Studio since it doesn't understand templated conversion // operators. #if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) # define GTEST_HAS_COMBINE 1 #endif // Determines whether the system compiler uses UTF-16 for encoding wide strings. #define GTEST_WIDE_STRING_USES_UTF16_ \ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) // Determines whether test results can be streamed to a socket. #if GTEST_OS_LINUX # define GTEST_CAN_STREAM_RESULTS_ 1 #endif // Defines some utility macros. // The GNU compiler emits a warning if nested "if" statements are followed by // an "else" statement and braces are not used to explicitly disambiguate the // "else" binding. This leads to problems with code like: // // if (gate) // ASSERT_*(condition) << "Some message"; // // The "switch (0) case 0:" idiom is used to suppress this. #ifdef __INTEL_COMPILER # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ #else # define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT #endif // Use this annotation at the end of a struct/class definition to // prevent the compiler from optimizing away instances that are never // used. This is useful when all interesting logic happens inside the // c'tor and / or d'tor. Example: // // struct Foo { // Foo() { ... } // } GTEST_ATTRIBUTE_UNUSED_; // // Also use it after a variable or parameter declaration to tell the // compiler the variable/parameter does not have to be used. #if defined(__GNUC__) && !defined(COMPILER_ICC) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) #else # define GTEST_ATTRIBUTE_UNUSED_ #endif // A macro to disallow operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_ASSIGN_(type)\ void operator=(type const &) // A macro to disallow copy constructor and operator= // This should be used in the private: declarations for a class. #define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ type(type const &);\ GTEST_DISALLOW_ASSIGN_(type) // Tell the compiler to warn about unused return values for functions declared // with this macro. The macro should be used on function declarations // following the argument list: // // Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; #if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) # define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) #else # define GTEST_MUST_USE_RESULT_ #endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC // Determine whether the compiler supports Microsoft's Structured Exception // Handling. This is supported by several Windows compilers but generally // does not exist on any other system. #ifndef GTEST_HAS_SEH // The user didn't tell us, so we need to figure it out. # if defined(_MSC_VER) || defined(__BORLANDC__) // These two compilers are known to support SEH. # define GTEST_HAS_SEH 1 # else // Assume no SEH. # define GTEST_HAS_SEH 0 # endif #endif // GTEST_HAS_SEH #ifdef _MSC_VER # if GTEST_LINKED_AS_SHARED_LIBRARY # define GTEST_API_ __declspec(dllimport) # elif GTEST_CREATE_SHARED_LIBRARY # define GTEST_API_ __declspec(dllexport) # endif #endif // _MSC_VER #ifndef GTEST_API_ # define GTEST_API_ #endif #ifdef __GNUC__ // Ask the compiler to never inline a given function. # define GTEST_NO_INLINE_ __attribute__((noinline)) #else # define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) # define GTEST_HAS_CXXABI_H_ 1 #else # define GTEST_HAS_CXXABI_H_ 0 #endif namespace testing { class Message; namespace internal { // A secret type that Google Test users don't know about. It has no // definition on purpose. Therefore it's impossible to create a // Secret object, which is what we want. class Secret; // The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, // content_type_names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. template struct CompileAssert { }; #define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ // Implementation details of GTEST_COMPILE_ASSERT_: // // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outter parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // GTEST_COMPILE_ASSERT_(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. // StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. // // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper {}; #if GTEST_HAS_GLOBAL_STRING typedef ::string string; #else typedef ::std::string string; #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING typedef ::wstring wstring; #elif GTEST_HAS_STD_WSTRING typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING // A helper for suppressing warnings on constant condition. It just // returns 'condition'. GTEST_API_ bool IsTrue(bool condition); // Defines scoped_ptr. // This implementation of scoped_ptr is PARTIAL - it only contains // enough stuff to satisfy Google Test's need. template class scoped_ptr { public: typedef T element_type; explicit scoped_ptr(T* p = NULL) : ptr_(p) {} ~scoped_ptr() { reset(); } T& operator*() const { return *ptr_; } T* operator->() const { return ptr_; } T* get() const { return ptr_; } T* release() { T* const ptr = ptr_; ptr_ = NULL; return ptr; } void reset(T* p = NULL) { if (p != ptr_) { if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. delete ptr_; } ptr_ = p; } } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . It uses the POSIX Extended // Regular Expression syntax. class GTEST_API_ RE { public: // A copy constructor is required by the Standard to initialize object // references from r-values. RE(const RE& other) { Init(other.pattern()); } // Constructs an RE from a string. RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT #if GTEST_HAS_GLOBAL_STRING RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT #endif // GTEST_HAS_GLOBAL_STRING RE(const char* regex) { Init(regex); } // NOLINT ~RE(); // Returns the string representation of the regex. const char* pattern() const { return pattern_; } // FullMatch(str, re) returns true iff regular expression re matches // the entire str. // PartialMatch(str, re) returns true iff regular expression re // matches a substring of str (including str itself). // // TODO(wan@google.com): make FullMatch() and PartialMatch() work // when str contains NUL characters. static bool FullMatch(const ::std::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::std::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #if GTEST_HAS_GLOBAL_STRING static bool FullMatch(const ::string& str, const RE& re) { return FullMatch(str.c_str(), re); } static bool PartialMatch(const ::string& str, const RE& re) { return PartialMatch(str.c_str(), re); } #endif // GTEST_HAS_GLOBAL_STRING static bool FullMatch(const char* str, const RE& re); static bool PartialMatch(const char* str, const RE& re); private: void Init(const char* regex); // We use a const char* instead of an std::string, as Google Test used to be // used where std::string is not available. TODO(wan@google.com): change to // std::string. const char* pattern_; bool is_valid_; #if GTEST_USES_POSIX_RE regex_t full_regex_; // For FullMatch(). regex_t partial_regex_; // For PartialMatch(). #else // GTEST_USES_SIMPLE_RE const char* full_pattern_; // For FullMatch(); #endif GTEST_DISALLOW_ASSIGN_(RE); }; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, int line); // Defines logging utilities: // GTEST_LOG_(severity) - logs messages at the specified severity level. The // message itself is streamed into the macro. // LogToStderr() - directs all log messages to stderr. // FlushInfoLog() - flushes informational log messages. enum GTestLogSeverity { GTEST_INFO, GTEST_WARNING, GTEST_ERROR, GTEST_FATAL }; // Formats log entry severity, provides a stream object for streaming the // log message, and terminates the message with a newline when going out of // scope. class GTEST_API_ GTestLog { public: GTestLog(GTestLogSeverity severity, const char* file, int line); // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. ~GTestLog(); ::std::ostream& GetStream() { return ::std::cerr; } private: const GTestLogSeverity severity_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); }; #define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } // INTERNAL IMPLEMENTATION - DO NOT USE. // // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition // is not satisfied. // Synopsys: // GTEST_CHECK_(boolean_condition); // or // GTEST_CHECK_(boolean_condition) << "Additional message"; // // This checks the condition and if the condition is not satisfied // it prints message about the condition violation, including the // condition itself, plus additional message streamed into it, if any, // and then it aborts the program. It aborts the program irrespective of // whether it is built in the debug mode or not. #define GTEST_CHECK_(condition) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::IsTrue(condition)) \ ; \ else \ GTEST_LOG_(FATAL) << "Condition " #condition " failed. " // An all-mode assert to verify that the given POSIX-style function // call returns 0 (indicating success). Known limitation: this // doesn't expand to a balanced 'if' statement, so enclose the macro // in {} if you need to use it as the only statement in an 'if' // branch. #define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ if (const int gtest_error = (posix_call)) \ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ << gtest_error // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in // the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a // const Foo*). When you use ImplicitCast_, the compiler checks that // the cast is safe. Such explicit ImplicitCast_s are necessary in // surprisingly many situations where C++ demands an exact type match // instead of an argument type convertable to a target type. // // The syntax for using ImplicitCast_ is the same as for static_cast: // // ImplicitCast_(expr) // // ImplicitCast_ would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. template inline To ImplicitCast_(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. template // use like this: DownCast_(foo); inline To DownCast_(From* f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. if (false) { const To to = NULL; ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); #endif return static_cast(f); } // Downcasts the pointer of type Base to Derived. // Derived must be a subclass of Base. The parameter MUST // point to a class of type Derived, not any subclass of it. // When RTTI is available, the function performs a runtime // check to enforce this. template Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); return dynamic_cast(base); // NOLINT #else return static_cast(base); // Poor man's downcast. #endif } #if GTEST_HAS_STREAM_REDIRECTION // Defines the stderr capturer: // CaptureStdout - starts capturing stdout. // GetCapturedStdout - stops capturing stdout and returns the captured string. // CaptureStderr - starts capturing stderr. // GetCapturedStderr - stops capturing stderr and returns the captured string. // GTEST_API_ void CaptureStdout(); GTEST_API_ std::string GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST const ::std::vector& GetInjectableArgvs(); void SetInjectableArgvs(const ::std::vector* new_argvs); // A copy of all command line arguments. Set by InitGoogleTest(). extern ::std::vector g_argvs; #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milli-seconds. This function is only for // testing Google Test's own constructs. Don't use it in user tests, // either directly or indirectly. inline void SleepMilliseconds(int n) { const timespec time = { 0, // 0 seconds. n * 1000L * 1000L, // And n ms. }; nanosleep(&time, NULL); } // Allows a controller thread to pause execution of newly created // threads until notified. Instances of this class must be created // and destroyed in the controller thread. // // This class is only for testing Google Test's own constructs. Do not // use it in user tests, either directly or indirectly. class Notification { public: Notification() : notified_(false) { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); } ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { pthread_mutex_lock(&mutex_); notified_ = true; pthread_mutex_unlock(&mutex_); } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { for (;;) { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); if (notified) break; SleepMilliseconds(10); } } private: pthread_mutex_t mutex_; bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; // As a C-function, ThreadFuncWithCLinkage cannot be templated itself. // Consequently, it cannot select a correct instantiation of ThreadWithParam // in order to call its Run(). Introducing ThreadWithParamBase as a // non-templated base class for ThreadWithParam allows us to bypass this // problem. class ThreadWithParamBase { public: virtual ~ThreadWithParamBase() {} virtual void Run() = 0; }; // pthread_create() accepts a pointer to a function type with the C linkage. // According to the Standard (7.5/1), function types with different linkages // are different even if they are otherwise identical. Some compilers (for // example, SunStudio) treat them as different types. Since class methods // cannot be defined with C-linkage we need to define a free C-function to // pass into pthread_create(). extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { static_cast(thread)->Run(); return NULL; } // Helper class for testing Google Test's multi-threading constructs. // To use it, write: // // void ThreadFunc(int param) { /* Do things with param */ } // Notification thread_can_start; // ... // // The thread_can_start parameter is optional; you can supply NULL. // ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); // thread_can_start.Notify(); // // These classes are only for testing Google Test's own constructs. Do // not use them in user tests, either directly or indirectly. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void (*UserThreadFunc)(T); ThreadWithParam( UserThreadFunc func, T param, Notification* thread_can_start) : func_(func), param_(param), thread_can_start_(thread_can_start), finished_(false) { ThreadWithParamBase* const base = this; // The thread can be created only after all fields except thread_ // have been initialized. GTEST_CHECK_POSIX_SUCCESS_( pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); } ~ThreadWithParam() { Join(); } void Join() { if (!finished_) { GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); finished_ = true; } } virtual void Run() { if (thread_can_start_ != NULL) thread_can_start_->WaitForNotification(); func_(param_); } private: const UserThreadFunc func_; // User-supplied thread function. const T param_; // User-supplied parameter to the thread function. // When non-NULL, used to block execution until the controller thread // notifies. Notification* const thread_can_start_; bool finished_; // true iff we know that the thread function has finished. pthread_t thread_; // The native thread object. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // MutexBase and Mutex implement mutex on pthreads-based platforms. They // are used in conjunction with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the end // // of the current scope. // // MutexBase implements behavior for both statically and dynamically // allocated mutexes. Do not use MutexBase directly. Instead, write // the following to define a static mutex: // // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // // You can forward declare a static mutex like this: // // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // To create a dynamic mutex, just define an object of type Mutex. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); has_owner_ = true; } // Releases this mutex. void Unlock() { // Since the lock is being released the owner_ field should no longer be // considered valid. We don't protect writing to has_owner_ here, as it's // the caller's responsibility to ensure that the current thread holds the // mutex when this is called. has_owner_ = false; GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld() const { GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) << "The current thread is not holding the mutex @" << this; } // A static mutex may be used before main() is entered. It may even // be used before the dynamic initialization stage. Therefore we // must be able to initialize a static mutex object at link time. // This means MutexBase has to be a POD and its member variables // have to be public. public: pthread_mutex_t mutex_; // The underlying pthread mutex. // has_owner_ indicates whether the owner_ field below contains a valid thread // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All // accesses to the owner_ field should be protected by a check of this field. // An alternative might be to memset() owner_ to all zeros, but there's no // guarantee that a zero'd pthread_t is necessarily invalid or even different // from pthread_self(). bool has_owner_; pthread_t owner_; // The thread holding the mutex. }; // Forward-declares a static mutex. # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::MutexBase mutex // Defines and statically (i.e. at link time) initializes a static mutex. // The initialization list here does not explicitly initialize each field, // instead relying on default initialization for the unspecified fields. In // particular, the owner_ field (a pthread_t) is not explicitly initialized. // This allows initialization to work whether pthread_t is a scalar or struct. // The flag -Wmissing-field-initializers must not be specified for this to work. # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } // The Mutex class can only be used for mutexes created at runtime. It // shares its API with MutexBase otherwise. class Mutex : public MutexBase { public: Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); has_owner_ = false; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock as the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(MutexBase* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: MutexBase* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Helpers for ThreadLocal. // pthread_key_create() requires DeleteThreadLocalValue() to have // C-linkage. Therefore it cannot be templatized to access // ThreadLocal. Hence the need for class // ThreadLocalValueHolderBase. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Called by pthread to delete thread-local data stored by // pthread_setspecific(). extern "C" inline void DeleteThreadLocalValue(void* value_holder) { delete static_cast(value_holder); } // Implements thread-local storage on pthreads-based systems. // // // Thread 1 // ThreadLocal tl(100); // 100 is the default value for each thread. // // // Thread 2 // tl.set(150); // Changes the value for thread 2 only. // EXPECT_EQ(150, tl.get()); // // // Thread 1 // EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. // tl.set(200); // EXPECT_EQ(200, tl.get()); // // The template type argument T must have a public copy constructor. // In addition, the default ThreadLocal constructor requires T to have // a public default constructor. // // An object managed for a thread by a ThreadLocal instance is deleted // when the thread exits. Or, if the ThreadLocal instance dies in // that thread, when the ThreadLocal dies. It's the user's // responsibility to ensure that all other threads using a ThreadLocal // have exited when it dies, or the per-thread objects for those // threads will not be deleted. // // Google Test only uses global ThreadLocal objects. That means they // will die after main() has returned. Therefore, no per-thread // object managed by Google Test will be leaked as long as all threads // using Google Test have exited when main() returns. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_() {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_(value) {} ~ThreadLocal() { // Destroys the managed object for the current thread, if any. DeleteThreadLocalValue(pthread_getspecific(key_)); // Releases resources associated with the key. This will *not* // delete managed objects for other threads. GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); } T* pointer() { return GetOrCreateValue(); } const T* pointer() const { return GetOrCreateValue(); } const T& get() const { return *pointer(); } void set(const T& value) { *pointer() = value; } private: // Holds a value of type T. class ValueHolder : public ThreadLocalValueHolderBase { public: explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; static pthread_key_t CreateKey() { pthread_key_t key; // When a thread exits, DeleteThreadLocalValue() will be called on // the object managed for that thread. GTEST_CHECK_POSIX_SUCCESS_( pthread_key_create(&key, &DeleteThreadLocalValue)); return key; } T* GetOrCreateValue() const { ThreadLocalValueHolderBase* const holder = static_cast(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = new ValueHolder(default_); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; const T default_; // The default value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # define GTEST_IS_THREADSAFE 1 #else // GTEST_HAS_PTHREAD // A dummy implementation of synchronization primitives (mutex, lock, // and thread-local variable). Necessary for compiling Google Test where // mutex is not supported - using Google Test in multiple threads is not // supported on such platforms. class Mutex { public: Mutex() {} void Lock() {} void Unlock() {} void AssertHeld() const {} }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template class ThreadLocal { public: ThreadLocal() : value_() {} explicit ThreadLocal(const T& value) : value_(value) {} T* pointer() { return &value_; } const T* pointer() const { return &value_; } const T& get() const { return value_; } void set(const T& value) { value_ = value; } private: T value_; }; // The above synchronization primitives have dummy implementations. // Therefore Google Test is not thread-safe. # define GTEST_IS_THREADSAFE 0 #endif // GTEST_HAS_PTHREAD // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. GTEST_API_ size_t GetThreadCount(); // Passing non-POD classes through ellipsis (...) crashes the ARM // compiler and generates a warning in Sun Studio. The Nokia Symbian // and the IBM XL C/C++ compiler try to instantiate a copy constructor // for objects passed through ellipsis (...), failing for uncopyable // objects. We define this to ensure that only POD is passed through // ellipsis on these systems. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_ELLIPSIS_NEEDS_POD_ 1 #else # define GTEST_CAN_COMPARE_NULL 1 #endif // The Nokia Symbian and IBM XL C/C++ compilers cannot decide between // const T& and const T* in a function template. These compilers // _can_ decide between class template specializations for T and T*, // so a tr1::type_traits-like is_pointer works. #if defined(__SYMBIAN32__) || defined(__IBMCPP__) # define GTEST_NEEDS_IS_POINTER_ 1 #endif template struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; template struct IteratorTraits { typedef typename Iterator::value_type value_type; }; template struct IteratorTraits { typedef T value_type; }; template struct IteratorTraits { typedef T value_type; }; #if GTEST_OS_WINDOWS # define GTEST_PATH_SEP_ "\\" # define GTEST_HAS_ALT_PATH_SEP_ 1 // The biggest signed integer type the compiler supports. typedef __int64 BiggestInt; #else # define GTEST_PATH_SEP_ "/" # define GTEST_HAS_ALT_PATH_SEP_ 0 typedef long long BiggestInt; // NOLINT #endif // GTEST_OS_WINDOWS // Utilities for char. // isspace(int ch) and friends accept an unsigned char or EOF. char // may be signed, depending on the compiler (or compiler flags). // Therefore we need to cast a char to unsigned char before calling // isspace(), etc. inline bool IsAlpha(char ch) { return isalpha(static_cast(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } // The testing::internal::posix namespace holds wrappers for common // POSIX functions. These wrappers hide the differences between // Windows/MSVC and POSIX systems. Since some compilers define these // standard functions as macros, the wrapper cannot have the same name // as the wrapped function. namespace posix { // Functions with a different name on Windows. #if GTEST_OS_WINDOWS typedef struct _stat StatStruct; # ifdef __BORLANDC__ inline int IsATTY(int fd) { return isatty(fd); } inline int StrCaseCmp(const char* s1, const char* s2) { return stricmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } # else // !__BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int IsATTY(int /* fd */) { return 0; } # else inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { return _stricmp(s1, s2); } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ # if GTEST_OS_WINDOWS_MOBILE inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } // Stat(), RmDir(), and IsDir() are not needed on Windows CE at this // time and thus not defined there. # else inline int FileNo(FILE* file) { return _fileno(file); } inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } inline int RmDir(const char* dir) { return _rmdir(dir); } inline bool IsDir(const StatStruct& st) { return (_S_IFDIR & st.st_mode) != 0; } # endif // GTEST_OS_WINDOWS_MOBILE #else typedef struct stat StatStruct; inline int FileNo(FILE* file) { return fileno(file); } inline int IsATTY(int fd) { return isatty(fd); } inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } inline int StrCaseCmp(const char* s1, const char* s2) { return strcasecmp(s1, s2); } inline char* StrDup(const char* src) { return strdup(src); } inline int RmDir(const char* dir) { return rmdir(dir); } inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } #endif // GTEST_OS_WINDOWS // Functions deprecated by MSVC 8.0. #ifdef _MSC_VER // Temporarily disable warning 4996 (deprecated function). # pragma warning(push) # pragma warning(disable:4996) #endif inline const char* StrNCpy(char* dest, const char* src, size_t n) { return strncpy(dest, src, n); } // ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and // StrError() aren't needed on Windows CE at this time and thus not // defined there. #if !GTEST_OS_WINDOWS_MOBILE inline int ChDir(const char* dir) { return chdir(dir); } #endif inline FILE* FOpen(const char* path, const char* mode) { return fopen(path, mode); } #if !GTEST_OS_WINDOWS_MOBILE inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { return freopen(path, mode, stream); } inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } #endif inline int FClose(FILE* fp) { return fclose(fp); } #if !GTEST_OS_WINDOWS_MOBILE inline int Read(int fd, void* buf, unsigned int count) { return static_cast(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(write(fd, buf, count)); } inline int Close(int fd) { return close(fd); } inline const char* StrError(int errnum) { return strerror(errnum); } #endif inline const char* GetEnv(const char* name) { #if GTEST_OS_WINDOWS_MOBILE // We are on Windows CE, which has no environment variables. return NULL; #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) // Environment variables which we programmatically clear will be set to the // empty string rather than unset (NULL). Handle that case. const char* const env = getenv(name); return (env != NULL && env[0] != '\0') ? env : NULL; #else return getenv(name); #endif } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif #if GTEST_OS_WINDOWS_MOBILE // Windows CE has no C library. The abort() function is used in // several places in Google Test. This implementation provides a reasonable // imitation of standard behaviour. void Abort(); #else inline void Abort() { abort(); } #endif // GTEST_OS_WINDOWS_MOBILE } // namespace posix // MSVC "deprecates" snprintf and issues warnings wherever it is used. In // order to avoid these warnings, we need to use _snprintf or _snprintf_s on // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) // Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't // complain about _snprintf. # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf #endif // The maximum number a BiggestInt can represent. This definition // works no matter BiggestInt is represented in one's complement or // two's complement. // // We cannot rely on numeric_limits in STL, as __int64 and long long // are not part of standard C++ and numeric_limits doesn't need to be // defined for them. const BiggestInt kMaxBiggestInt = ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); // This template class serves as a compile-time function from size to // type. It maps a size in bytes to a primitive type with that // size. e.g. // // TypeWithSize<4>::UInt // // is typedef-ed to be unsigned int (unsigned integer made up of 4 // bytes). // // Such functionality should belong to STL, but I cannot find it // there. // // Google Test uses this class in the implementation of floating-point // comparison. // // For now it only handles UInt (unsigned int) as that's all Google Test // needs. Other types can be easily added in the future if need // arises. template class TypeWithSize { public: // This prevents the user from using TypeWithSize with incorrect // values of N. typedef void UInt; }; // The specialization for size 4. template <> class TypeWithSize<4> { public: // unsigned int has size 4 in both gcc and MSVC. // // As base/basictypes.h doesn't compile on Windows, we cannot use // uint32, uint64, and etc here. typedef int Int; typedef unsigned int UInt; }; // The specialization for size 8. template <> class TypeWithSize<8> { public: #if GTEST_OS_WINDOWS typedef __int64 Int; typedef unsigned __int64 UInt; #else typedef long long Int; // NOLINT typedef unsigned long long UInt; // NOLINT #endif // GTEST_OS_WINDOWS }; // Integer types of known sizes. typedef TypeWithSize<4>::Int Int32; typedef TypeWithSize<4>::UInt UInt32; typedef TypeWithSize<8>::Int Int64; typedef TypeWithSize<8>::UInt UInt64; typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. // Utilities for command line flags and environment variables. // Macro for referencing flags. #define GTEST_FLAG(name) FLAGS_gtest_##name // Macros for declaring flags. #define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) #define GTEST_DECLARE_int32_(name) \ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) #define GTEST_DECLARE_string_(name) \ GTEST_API_ extern ::std::string GTEST_FLAG(name) // Macros for defining flags. #define GTEST_DEFINE_bool_(name, default_val, doc) \ GTEST_API_ bool GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_int32_(name, default_val, doc) \ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) #define GTEST_DEFINE_string_(name, default_val, doc) \ GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) // Thread annotations #define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) #define GTEST_LOCK_EXCLUDED_(locks) // Parses 'str' for a 32-bit signed integer. If successful, writes the result // to *value and returns true; otherwise leaves *value unchanged and returns // false. // TODO(chandlerc): Find a better way to refactor flag and environment parsing // out of both gtest-port.cc and gtest.cc to avoid exporting this utility // function. bool ParseInt32(const Message& src_text, const char* str, Int32* value); // Parses a bool/Int32/string from the environment variable // corresponding to the given Google Test flag. bool BoolFromGTestEnv(const char* flag, bool default_val); GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); const char* StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #if GTEST_OS_LINUX # include # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the Message class. // // IMPORTANT NOTE: Due to limitation of the C++ language, we have to // leave some internal implementation details in this header file. // They are clearly marked by comments like this: // // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // // Such code is NOT meant to be used by a user directly, and is subject // to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user // program! #ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ #include // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); namespace testing { // The Message class works like an ostream repeater. // // Typical usage: // // 1. You stream a bunch of values to a Message object. // It will remember the text in a stringstream. // 2. Then you stream the Message object to an ostream. // This causes the text in the Message to be streamed // to the ostream. // // For example; // // testing::Message foo; // foo << 1 << " != " << 2; // std::cout << foo; // // will print "1 != 2". // // Message is not intended to be inherited from. In particular, its // destructor is not virtual. // // Note that stringstream behaves differently in gcc and in MSVC. You // can stream a NULL char pointer to it in the former, but not in the // latter (it causes an access violation if you do). The Message // class hides this difference by treating a NULL char pointer as // "(null)". class GTEST_API_ Message { private: // The type of basic IO manipulators (endl, ends, and flush) for // narrow streams. typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); public: // Constructs an empty Message. Message(); // Copy constructor. Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. explicit Message(const char* str) : ss_(new ::std::stringstream) { *ss_ << str; } #if GTEST_OS_SYMBIAN // Streams a value (either a pointer or not) to this object. template inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { // Some libraries overload << for STL containers. These // overloads are defined in the global namespace instead of ::std. // // C++'s symbol lookup rule (i.e. Koenig lookup) says that these // overloads are visible in either the std namespace or the global // namespace, but not other namespaces, including the testing // namespace which Google Test's Message class is in. // // To allow STL containers (and other types that has a << operator // defined in the global namespace) to be used in Google Test // assertions, testing::Message must access the custom << operator // from the global namespace. With this using declaration, // overloads of << defined in the global namespace and those // visible via Koenig lookup are both exposed in this function. using ::operator <<; *ss_ << val; return *this; } // Streams a pointer value to this object. // // This function is an overload of the previous one. When you // stream a pointer to a Message, this definition will be used as it // is more specialized. (The C++ Standard, section // [temp.func.order].) If you stream a non-pointer, then the // previous definition will be used. // // The reason for this overload is that streaming a NULL pointer to // ostream is undefined behavior. Depending on the compiler, you // may get "0", "(nil)", "(null)", or an access violation. To // ensure consistent result across compilers, we always treat NULL // as "(null)". template inline Message& operator <<(T* const& pointer) { // NOLINT if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } return *this; } #endif // GTEST_OS_SYMBIAN // Since the basic IO manipulators are overloaded for both narrow // and wide streams, we have to provide this specialized definition // of operator <<, even though its body is the same as the // templatized version above. Without this definition, streaming // endl or other basic IO manipulators to Message will confuse the // compiler. Message& operator <<(BasicNarrowIoManip val) { *ss_ << val; return *this; } // Instead of 1/0, we want to see true/false for bool values. Message& operator <<(bool b) { return *this << (b ? "true" : "false"); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& operator <<(const wchar_t* wide_c_str); Message& operator <<(wchar_t* wide_c_str); #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::std::wstring& wstr); #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& operator <<(const ::wstring& wstr); #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. std::string GetString() const; private: #if GTEST_OS_SYMBIAN // These are needed as the Nokia Symbian Compiler cannot decide between // const T& and const T* in a function template. The Nokia compiler _can_ // decide between class template specializations for T and T*, so a // tr1::type_traits-like is_pointer works, and we can overload on that. template inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } } template inline void StreamHelper(internal::false_type /*is_pointer*/, const T& value) { // See the comments in Message& operator <<(const T&) above for why // we need this using statement. using ::operator <<; *ss_ << value; } #endif // GTEST_OS_SYMBIAN // We'll hold the text streamed to this object here. const internal::scoped_ptr< ::std::stringstream> ss_; // We declare (but don't implement) this to prevent the compiler // from implementing the assignment operator. void operator=(const Message&); }; // Streams a Message to an ostream. inline std::ostream& operator <<(std::ostream& os, const Message& sb) { return os << sb.GetString(); } namespace internal { // Converts a streamable value to an std::string. A NULL pointer is // converted to "(null)". When the input value is a ::string, // ::std::string, ::wstring, or ::std::wstring object, each NUL // character in it is replaced with "\\0". template std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file declares the String class and functions used internally by // Google Test. They are subject to change without notice. They should not used // by code external to Google Test. // // This header file is #included by . // It should not be #included by other files. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ #ifdef __BORLANDC__ // string.h is not guaranteed to provide strcpy on C++ Builder. # include #endif #include #include namespace testing { namespace internal { // String - an abstract class holding static string utilities. class GTEST_API_ String { public: // Static utility methods // Clones a 0-terminated C string, allocating memory using new. The // caller is responsible for deleting the return value using // delete[]. Returns the cloned string, or NULL if the input is // NULL. // // This is different from strdup() in string.h, which allocates // memory using malloc(). static const char* CloneCString(const char* c_str); #if GTEST_OS_WINDOWS_MOBILE // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be // able to pass strings to Win32 APIs on CE we need to convert them // to 'Unicode', UTF-16. // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. // // The wide string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static LPCWSTR AnsiToUtf16(const char* c_str); // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. // // The returned string is created using the ANSI codepage (CP_ACP) to // match the behaviour of the ANSI versions of Win32 calls and the // C runtime. static const char* Utf16ToAnsi(LPCWSTR utf16_str); #endif // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CStringEquals(const char* lhs, const char* rhs); // Converts a wide C string to a String using the UTF-8 encoding. // NULL will be converted to "(null)". If an error occurred during // the conversion, "(failed to convert from wide string)" is // returned. static std::string ShowWideCString(const wchar_t* wide_c_str); // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Compares two C strings, ignoring case. Returns true iff they // have the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL C string, // including the empty string. static bool CaseInsensitiveCStringEquals(const char* lhs, const char* rhs); // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); // Returns true iff the given string ends with the given suffix, ignoring // case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); // Formats an int value as "%02d". static std::string FormatIntWidth2(int value); // "%02d" for width == 2 // Formats an int value as "%X". static std::string FormatHexInt(int value); // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); private: String(); // Not meant to be instantiated. }; // class String // Gets the content of the stringstream's buffer as an std::string. Each '\0' // character in the buffer is replaced with "\\0". GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: keith.ray@gmail.com (Keith Ray) // // Google Test filepath utilities // // This header file declares classes and functions used internally by // Google Test. They are subject to change without notice. // // This file is #included in . // Do not include this header file separately! #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ namespace testing { namespace internal { // FilePath - a class for file and directory pathname manipulation which // handles platform-specific conventions (like the pathname separator). // Used for helper functions for naming files in a directory for xml output. // Except for Set methods, all methods are const or static, which provides an // "immutable value object" -- useful for peace of mind. // A FilePath with a value ending in a path separator ("like/this/") represents // a directory, otherwise it is assumed to represent a file. In either case, // it may or may not represent an actual file or directory in the file system. // Names are NOT checked for syntax correctness -- no checking for illegal // characters, malformed paths, etc. class GTEST_API_ FilePath { public: FilePath() : pathname_("") { } FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } explicit FilePath(const std::string& pathname) : pathname_(pathname) { Normalize(); } FilePath& operator=(const FilePath& rhs) { Set(rhs); return *this; } void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } const std::string& string() const { return pathname_; } const char* c_str() const { return pathname_.c_str(); } // Returns the current working directory, or "" if unsuccessful. static FilePath GetCurrentDir(); // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. static FilePath MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension); // Given directory = "dir", relative_path = "test.xml", // returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. static FilePath ConcatPaths(const FilePath& directory, const FilePath& relative_path); // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. static FilePath GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension); // Returns true iff the path is "". bool IsEmpty() const { return pathname_.empty(); } // If input name has a trailing separator character, removes it and returns // the name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath RemoveTrailingPathSeparator() const; // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveDirectoryName() const; // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath RemoveFileName() const; // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath RemoveExtension(const char* extension) const; // Creates directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create // directories for any reason. Will also return false if the FilePath does // not represent a directory (that is, it doesn't end with a path separator). bool CreateDirectoriesRecursively() const; // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool CreateFolder() const; // Returns true if FilePath describes something in the file-system, // either a file, directory, or whatever, and that something exists. bool FileOrDirectoryExists() const; // Returns true if pathname describes a directory in the file-system // that exists. bool DirectoryExists() const; // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool IsDirectory() const; // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool IsRootDirectory() const; // Returns true if pathname describes an absolute path. bool IsAbsolutePath() const; private: // Replaces multiple consecutive separators with a single separator. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // // A pathname with multiple consecutive separators may occur either through // user error or as a result of some scripts or APIs that generate a pathname // with a trailing separator. On other platforms the same API or script // may NOT generate a pathname with a trailing "/". Then elsewhere that // pathname may have another "/" and pathname components added to it, // without checking for the separator already being there. // The script language and operating system may allow paths like "foo//bar" // but some of the functions in FilePath will not handle that correctly. In // particular, RemoveTrailingPathSeparator() only removes one separator, and // it is called in CreateDirectoriesRecursively() assuming that it will change // a pathname from directory syntax (trailing separator) to filename syntax. // // On Windows this method also replaces the alternate path separator '/' with // the primary path separator '\\', so that for example "bar\\/\\foo" becomes // "bar\\foo". void Normalize(); // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FindLastPathSeparator() const; std::string pathname_; }; // class FilePath } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ // This file was GENERATED by command: // pump.py gtest-type-util.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Type utilities needed for implementing typed and type-parameterized // tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently we support at most 50 types in a list, and at most 50 // type-parameterized tests in one type-parameterized test case. // Please contact googletestframework@googlegroups.com if you need // more. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::type is defined iff T1 and T2 are the same // type. This can be used as a compile-time assertion to ensure that // two types are equal. template struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // A unique type used as the default value for the arguments of class // template Types. This allows us to simulate variadic templates // (e.g. Types, Type, and etc), which C++ doesn't // support directly. struct None {}; // The following family of struct and struct templates are used to // represent type lists. In particular, TypesN // represents a type list with N types (T1, T2, ..., and TN) in it. // Except for Types0, every struct in the family has two member types: // Head for the first type in the list, and Tail for the rest of the // list. // The empty type list. struct Types0 {}; // Type lists of length 1, 2, 3, and so on. template struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 Tail; }; } // namespace internal // We don't want to require the users to write TypesN<...> directly, // as that would require them to count the length. Types<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Types // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::type // A unique struct template used as the default value for the // arguments of class template Templates. This allows us to simulate // variadic templates (e.g. Templates, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except // for Templates0, every struct in the family has two member types: // Head for the selector of the first template in the list, and Tail // for the rest of the list. // The empty template list. struct Templates0 {}; // Template lists of length 1, 2, 3, and so on. template struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 Tail; }; // We don't want to require the users to write TemplatesN<...> directly, // as that would require them to count the length. Templates<...> is much // easier to write, but generates horrible messages when there is a // compiler error, as gcc insists on printing out each template // argument, even if it has the default value (this means Templates // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 type; }; // The TypeList template makes it possible to use either a single type // or a Types<...> list in TYPED_TEST_CASE() and // INSTANTIATE_TYPED_TEST_CASE_P(). template struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ // Due to C++ preprocessor weirdness, we need double indirection to // concatenate two tokens when one of them is __LINE__. Writing // // foo ## __LINE__ // // will result in the token foo__LINE__, instead of foo followed by // the current line number. For more details, see // http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 #define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) #define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar class ProtocolMessage; namespace proto2 { class Message; } namespace testing { // Forward declarations. class AssertionResult; // Result of an assertion. class Message; // Represents a failure message. class Test; // Represents a test. class TestInfo; // Information about a test. class TestPartResult; // Result of a test part. class UnitTest; // A collection of test cases. template ::std::string PrintToString(const T& value); namespace internal { struct TraceInfo; // Information about a trace point. class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class UnitTestImpl; // Opaque implementation of UnitTest // How many times InitGoogleTest() has been called. GTEST_API_ extern int g_init_gtest_count; // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // Two overloaded helpers for checking at compile time whether an // expression is a null pointer literal (i.e. NULL or any 0-valued // compile-time integral constant). Their return values have // different sizes, so we can use sizeof() to test which version is // picked by the compiler. These helpers have no implementations, as // we only need their signatures. // // Given IsNullLiteralHelper(x), the compiler will pick the first // version if x can be implicitly converted to Secret*, and pick the // second version otherwise. Since Secret is a secret and incomplete // type, the only expression a user can write that has type Secret* is // a null pointer literal. Therefore, we know that x is a null // pointer literal if and only if the first version is picked by the // compiler. char IsNullLiteralHelper(Secret* p); char (&IsNullLiteralHelper(...))[2]; // NOLINT // A compile-time bool constant that is true if and only if x is a // null pointer literal (i.e. NULL or any 0-valued compile-time // integral constant). #ifdef GTEST_ELLIPSIS_NEEDS_POD_ // We lose support for NULL detection where the compiler doesn't like // passing non-POD classes through ellipsis (...). # define GTEST_IS_NULL_LITERAL_(x) false #else # define GTEST_IS_NULL_LITERAL_(x) \ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) #endif // GTEST_ELLIPSIS_NEEDS_POD_ // Appends the user-supplied message to the Google-Test-generated message. GTEST_API_ std::string AppendUserMessage( const std::string& gtest_msg, const Message& user_msg); #if GTEST_HAS_EXCEPTIONS // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions // are enabled). We derive it from std::runtime_error, which is for // errors presumably detectable only at run time. Since // std::runtime_error inherits from std::exception, many testing // frameworks know how to extract and print the message inside it. class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure); }; #endif // GTEST_HAS_EXCEPTIONS // A helper class for creating scoped traces in user programs. class GTEST_API_ ScopedTrace { public: // The c'tor pushes the given source file location and message onto // a trace stack maintained by Google Test. ScopedTrace(const char* file, int line, const Message& message); // The d'tor pops the info pushed by the c'tor. // // Note that the d'tor is not virtual in order to be efficient. // Don't inherit from ScopedTrace! ~ScopedTrace(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); } GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its // c'tor and d'tor. Therefore it doesn't // need to be used otherwise. // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. GTEST_API_ AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value); // This template class represents an IEEE floating-point number // (either single-precision or double-precision, depending on the // template parameters). // // The purpose of this class is to do more sophisticated number // comparison. (Due to round-off error, etc, it's very unlikely that // two floating-points will be equal exactly. Hence a naive // comparison by the == operation often doesn't work.) // // Format of IEEE floating-point: // // The most-significant bit being the leftmost, an IEEE // floating-point looks like // // sign_bit exponent_bits fraction_bits // // Here, sign_bit is a single bit that designates the sign of the // number. // // For float, there are 8 exponent bits and 23 fraction bits. // // For double, there are 11 exponent bits and 52 fraction bits. // // More details can be found at // http://en.wikipedia.org/wiki/IEEE_floating-point_standard. // // Template parameter: // // RawType: the raw floating-point type (either float or double) template class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::UInt Bits; // Constants. // # of bits in a number. static const size_t kBitCount = 8*sizeof(RawType); // # of fraction bits in a number. static const size_t kFractionBitCount = std::numeric_limits::digits - 1; // # of exponent bits in a number. static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; // The mask for the sign bit. static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(0) >> (kExponentBitCount + 1); // The mask for the exponent bits. static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); // How many ULP's (Units in the Last Place) we want to tolerate when // comparing two numbers. The larger the value, the more error we // allow. A 0 value means that two numbers must be exactly the same // to be considered equal. // // The maximum error of a single floating-point operation is 0.5 // units in the last place. On Intel CPU's, all floating-point // calculations are done with 80-bit precision, while double has 64 // bits. Therefore, 4 should be enough for ordinary use. // // See the following article for more details on ULP: // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ static const size_t kMaxUlps = 4; // Constructs a FloatingPoint from a raw floating-point number. // // On an Intel CPU, passing a non-normalized NAN (Not a Number) // around may change its bits, although the new value is guaranteed // to be also a NAN. Therefore, don't expect this constructor to // preserve the bits in x when x is a NAN. explicit FloatingPoint(const RawType& x) { u_.value_ = x; } // Static methods // Reinterprets a bit pattern as a floating-point number. // // This function is needed to test the AlmostEquals() method. static RawType ReinterpretBits(const Bits bits) { FloatingPoint fp(0); fp.u_.bits_ = bits; return fp.u_.value_; } // Returns the floating-point number that represent positive infinity. static RawType Infinity() { return ReinterpretBits(kExponentBitMask); } // Returns the maximum representable finite floating-point number. static RawType Max(); // Non-static methods // Returns the bits that represents this number. const Bits &bits() const { return u_.bits_; } // Returns the exponent bits of this number. Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } // Returns the fraction bits of this number. Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } // Returns the sign bit of this number. Bits sign_bit() const { return kSignBitMask & u_.bits_; } // Returns true iff this is NAN (not a number). bool is_nan() const { // It's a NAN if the exponent bits are all ones and the fraction // bits are not entirely zeros. return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); } // Returns true iff this number is at most kMaxUlps ULP's away from // rhs. In particular, this function: // // - returns false if either number is (or both are) NAN. // - treats really large numbers as almost equal to infinity. // - thinks +0.0 and -0.0 are 0 DLP's apart. bool AlmostEquals(const FloatingPoint& rhs) const { // The IEEE standard says that any comparison operation involving // a NAN must return false. if (is_nan() || rhs.is_nan()) return false; return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) <= kMaxUlps; } private: // The data type used to store the actual floating-point number. union FloatingPointUnion { RawType value_; // The raw floating-point number. Bits bits_; // The bits that represent the number. }; // Converts an integer from the sign-and-magnitude representation to // the biased representation. More precisely, let N be 2 to the // power of (kBitCount - 1), an integer x is represented by the // unsigned number x + N. // // For instance, // // -N + 1 (the most negative number representable using // sign-and-magnitude) is represented by 1; // 0 is represented by N; and // N - 1 (the biggest number representable using // sign-and-magnitude) is represented by 2N - 1. // // Read http://en.wikipedia.org/wiki/Signed_number_representations // for more details on signed number representations. static Bits SignAndMagnitudeToBiased(const Bits &sam) { if (kSignBitMask & sam) { // sam represents a negative number. return ~sam + 1; } else { // sam represents a positive number. return kSignBitMask | sam; } } // Given two numbers in the sign-and-magnitude representation, // returns the distance between them as an unsigned number. static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, const Bits &sam2) { const Bits biased1 = SignAndMagnitudeToBiased(sam1); const Bits biased2 = SignAndMagnitudeToBiased(sam2); return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); } FloatingPointUnion u_; }; // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint Double; // In order to catch the mistake of putting tests that use different // test fixture classes in the same test case, we need to assign // unique IDs to fixture classes and compare them. The TypeId type is // used to hold such IDs. The user should treat TypeId as an opaque // type: the only operation allowed on TypeId values is to compare // them for equality using the == operator. typedef const void* TypeId; template class TypeIdHelper { public: // dummy_ must not have a const type. Otherwise an overly eager // compiler (e.g. MSVC 7.1 & 8.0) may try to merge // TypeIdHelper::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() returns the ID of type T. Different values will be // returned for different types. Calling the function twice with the // same type argument is guaranteed to return the same ID. template TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::dummy_); } // Returns the type ID of ::testing::Test. Always call this instead // of GetTypeId< ::testing::Test>() to get the type ID of // ::testing::Test, as the latter may give the wrong result due to a // suspected linker bug when compiling Google Test as a Mac OS X // framework. GTEST_API_ TypeId GetTestTypeId(); // Defines the abstract factory interface that creates instances // of a Test object. class TestFactoryBase { public: virtual ~TestFactoryBase() {} // Creates a test instance to run. The instance is both created and destroyed // within TestInfoImpl::Run() virtual Test* CreateTest() = 0; protected: TestFactoryBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); }; // This class provides implementation of TeastFactoryBase interface. // It is used in TEST and TEST_F macros. template class TestFactoryImpl : public TestFactoryBase { public: virtual Test* CreateTest() { return new TestClass; } }; #if GTEST_OS_WINDOWS // Predicate-formatters for implementing the HRESULT checking macros // {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} // We pass a long instead of HRESULT to avoid causing an // include dependency for the HRESULT type. GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, long hr); // NOLINT GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, long hr); // NOLINT #endif // GTEST_OS_WINDOWS // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. GTEST_API_ TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory); // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // State of the definition of a type-parameterized test case. class GTEST_API_ TypedTestCasePState { public: TypedTestCasePState() : registered_(false) {} // Adds the given test name to defined_test_names_ and return true // if the test case hasn't been registered; otherwise aborts the // program. bool AddTestName(const char* file, int line, const char* case_name, const char* test_name) { if (registered_) { fprintf(stderr, "%s Test %s must be defined before " "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", FormatFileLocation(file, line).c_str(), test_name, case_name); fflush(stderr); posix::Abort(); } defined_test_names_.insert(test_name); return true; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests); private: bool registered_; ::std::set defined_test_names_; }; // Skips to the first non-space char after the first comma in 'str'; // returns NULL if no comma is found in 'str'. inline const char* SkipComma(const char* str) { const char* comma = strchr(str, ','); if (comma == NULL) { return NULL; } while (IsSpace(*(++comma))) {} return comma; } // Returns the prefix of 'str' before the first comma in it; returns // the entire string if it contains no comma. inline std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? str : std::string(str, comma); } // TypeParameterizedTest::Register() // registers a list of type-parameterized tests with Google Test. The // return value is insignificant - we just need to return something // such that we can call this function in a namespace scope. // // Implementation note: The GTEST_TEMPLATE_ macro declares a template // template parameter. It's defined in gtest-type-util.h. template class TypeParameterizedTest { public: // 'index' is the index of the test in the type list 'Types' // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, // Types). Valid values for 'index' are [0, N - 1] where N is the // length of Types. static bool Register(const char* prefix, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + StreamableToString(index)).c_str(), GetPrefixUntilComma(test_names).c_str(), GetTypeName().c_str(), NULL, // No value parameter. GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::Register() // registers *all combinations* of 'Tests' and 'Types' with Google // Test. The return value is insignificant - we just need to return // something such that we can call this function in a namespace scope. template class TypeParameterizedTestCase { public: static bool Register(const char* prefix, const char* case_name, const char* test_names) { typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, const char* /*case_name*/, const char* /*test_names*/) { return true; } }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( UnitTest* unit_test, int skip_count); // Helpers for suppressing warnings on unreachable code or constant // condition. // Always returns true. GTEST_API_ bool AlwaysTrue(); // Always returns false. inline bool AlwaysFalse() { return !AlwaysTrue(); } // Helper for suppressing false warning from Clang on a const char* // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { ConstCharPtr(const char* str) : value(str) {} operator bool() const { return true; } const char* value; }; // A simple Linear Congruential Generator for generating random // numbers with a uniform distribution. Unlike rand() and srand(), it // doesn't use global state (and therefore can't interfere with user // code). Unlike rand_r(), it's portable. An LCG isn't very random, // but it's good enough for our purposes. class GTEST_API_ Random { public: static const UInt32 kMaxRange = 1u << 31; explicit Random(UInt32 seed) : state_(seed) {} void Reseed(UInt32 seed) { state_ = seed; } // Generates a random number from [0, range). Crashes if 'range' is // 0 or greater than kMaxRange. UInt32 Generate(UInt32 range); private: UInt32 state_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); }; // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; // Removes the reference from a type if it is a reference type, // otherwise leaves it unchanged. This is the same as // tr1::remove_reference, which is not widely available yet. template struct RemoveReference { typedef T type; }; // NOLINT template struct RemoveReference { typedef T type; }; // NOLINT // A handy wrapper around RemoveReference that works when the argument // T depends on template parameters. #define GTEST_REMOVE_REFERENCE_(T) \ typename ::testing::internal::RemoveReference::type // Removes const from a type if it is a const type, otherwise leaves // it unchanged. This is the same as tr1::remove_const, which is not // widely available yet. template struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { typedef T type; }; // NOLINT // MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above // definition to fail to remove the const in 'const int[3]' and 'const // char[3][4]'. The following specialization works around the bug. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #if defined(_MSC_VER) && _MSC_VER < 1400 // This is the only specialization that allows VC++ 7.1 to remove const in // 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC // and thus needs to be conditionally compiled. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #endif // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GTEST_REMOVE_CONST_(T) \ typename ::testing::internal::RemoveConst::type // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) // Adds reference to a type if it is not a reference type, // otherwise leaves it unchanged. This is the same as // tr1::add_reference, which is not widely available yet. template struct AddReference { typedef T& type; }; // NOLINT template struct AddReference { typedef T& type; }; // NOLINT // A handy wrapper around AddReference that works when the argument T // depends on template parameters. #define GTEST_ADD_REFERENCE_(T) \ typename ::testing::internal::AddReference::type // Adds a reference to const on top of T as necessary. For example, // it transforms // // char ==> const char& // const char ==> const char& // char& ==> const char& // const char& ==> const char& // // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. template class ImplicitlyConvertible { private: // We need the following helper functions only for their types. // They have no implementations. // MakeFrom() is an expression whose type is From. We cannot simply // use From(), as the type From may not have a public default // constructor. static From MakeFrom(); // These two functions are overloaded. Given an expression // Helper(x), the compiler will pick the first version if x can be // implicitly converted to type To; otherwise it will pick the // second version. // // The first version returns a value of size 1, and the second // version returns a value of size 2. Therefore, by checking the // size of Helper(x), which can be done at compile time, we can tell // which version of Helper() is used, and hence whether x can be // implicitly converted to type To. static char Helper(To); static char (&Helper(...))[2]; // NOLINT // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: // MSVC warns about implicitly converting from double to int for // possible loss of data, so we need to temporarily disable the // warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4244) // Temporarily disables warning 4244. static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; # pragma warning(pop) // Restores the warning state. #elif defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; #endif // _MSV_VER }; template const bool ImplicitlyConvertible::value; // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template struct IsAProtocolMessage : public bool_constant< ImplicitlyConvertible::value || ImplicitlyConvertible::value> { }; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are // valid types and NULL can be implicitly converted to them). It will // be picked over the second overload as 'int' is a perfect match for // the type of argument 0. If C::iterator or C::const_iterator is not // a valid type, the first overload is not viable, and the second // overload will be picked. Therefore, we can determine whether C is // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // // Note that we look for both C::iterator and C::const_iterator. The // reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named // iterator is an STL container. // // Also note that the simpler approach of overloading // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add // "typename EnableIf::type* = 0" as the last parameter. template struct EnableIf; template<> struct EnableIf { typedef void type; }; // NOLINT // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the // elements' operator==, where k can be any integer >= 0. When k is // 0, ArrayEq() degenerates into comparing a single pair of values. template bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } // This helper reduces code bloat. If we instead put its logic inside // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template bool ArrayEq(const T* lhs, size_t size, const U* rhs) { for (size_t i = 0; i != size; i++) { if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { for (Iter it = begin; it != end; ++it) { if (internal::ArrayEq(*it, elem)) return it; } return end; } // CopyArray() copies a k-dimensional native array using the elements' // operator=, where k can be any integer >= 0. When k is 0, // CopyArray() degenerates into copying a single value. template void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template inline void CopyArray(const T(&from)[N], U(*to)[N]) { internal::CopyArray(from, N, *to); } // This helper reduces code bloat. If we instead put its logic inside // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template void CopyArray(const T* from, size_t size, U* to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } } // The relation between an NativeArray object (see below) and the // native array it represents. enum RelationToSource { kReference, // The NativeArray references the native array. kCopy // The NativeArray makes a copy of the native array and // owns the copy. }; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements // members useful for Google Mock's container matchers. New members // should be added as needed. To simplify the implementation, we only // support Element being a raw type (i.e. having no top-level const or // reference modifier). It's the client's responsibility to satisfy // this requirement. Element can be an array type itself (hence // multi-dimensional arrays are supported). template class NativeArray { public: // STL-style container typedefs. typedef Element value_type; typedef Element* iterator; typedef const Element* const_iterator; // Constructs from a native array. NativeArray(const Element* array, size_t count, RelationToSource relation) { Init(array, count, relation); } // Copy constructor. NativeArray(const NativeArray& rhs) { Init(rhs.array_, rhs.size_, rhs.relation_to_source_); } ~NativeArray() { // Ensures that the user doesn't instantiate NativeArray with a // const or reference type. static_cast(StaticAssertTypeEqHelper()); if (relation_to_source_ == kCopy) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } bool operator==(const NativeArray& rhs) const { return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: // Initializes this object; makes a copy of the input array if // 'relation' is kCopy. void Init(const Element* array, size_t a_size, RelationToSource relation) { if (relation == kReference) { array_ = array; } else { Element* const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; } size_ = a_size; relation_to_source_ = relation; } const Element* array_; size_t size_; RelationToSource relation_to_source_; GTEST_DISALLOW_ASSIGN_(NativeArray); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) #define GTEST_FATAL_FAILURE_(message) \ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) #define GTEST_NONFATAL_FAILURE_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) #define GTEST_SUCCESS_(message) \ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) // Suppresses MSVC warnings 4072 (unreachable code) for the code following // statement if it returns or throws (or doesn't return or throw in some // situations). #define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ if (::testing::internal::AlwaysTrue()) { statement; } #define GTEST_TEST_THROW_(statement, expected_exception, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::ConstCharPtr gtest_msg = "") { \ bool gtest_caught_expected = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (expected_exception const&) { \ gtest_caught_expected = true; \ } \ catch (...) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws a different type."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ if (!gtest_caught_expected) { \ gtest_msg.value = \ "Expected: " #statement " throws an exception of type " \ #expected_exception ".\n Actual: it throws nothing."; \ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ fail(gtest_msg.value) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail("Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws.") #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail("Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't.") // Implements Boolean test assertions such as EXPECT_TRUE. expression can be // either a boolean expression or an AssertionResult. text is a textual // represenation of expression as it was passed into the EXPECT_TRUE. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar_ = \ ::testing::AssertionResult(expression)) \ ; \ else \ fail(::testing::internal::GetBoolAssertionFailureMessage(\ gtest_ar_, text, #actual, #expected).c_str()) #define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail("Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does.") // Expands to the name of the class that implements the given test. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ test_case_name##_##test_name##_Test // Helper macro for defining tests. #define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ public:\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ private:\ virtual void TestBody();\ static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ };\ \ ::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ ::test_info_ =\ ::testing::internal::MakeAndRegisterTestInfo(\ #test_case_name, #test_name, NULL, NULL, \ (parent_id), \ parent_class::SetUpTestCase, \ parent_class::TearDownTestCase, \ new ::testing::internal::TestFactoryImpl<\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // // This header file defines the public API for death tests. It is // #included by gtest.h so a user doesn't need to include this // directly. #ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) // // The Google C++ Testing Framework (Google Test) // // This header file defines internal utilities needed for implementing // death tests. They are subject to change without notice. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ #include namespace testing { namespace internal { GTEST_DECLARE_string_(internal_run_death_test); // Names of the flags (needed for parsing Google Test flags). const char kDeathTestStyleFlag[] = "death_test_style"; const char kDeathTestUseFork[] = "death_test_use_fork"; const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; #if GTEST_HAS_DEATH_TEST // DeathTest is a class that hides much of the complexity of the // GTEST_DEATH_TEST_ macro. It is abstract; its static Create method // returns a concrete class that depends on the prevailing death test // style, as defined by the --gtest_death_test_style and/or // --gtest_internal_run_death_test flags. // In describing the results of death tests, these terms are used with // the corresponding definitions: // // exit status: The integer exit information in the format specified // by wait(2) // exit code: The integer code passed to exit(3), _exit(2), or // returned from main() class GTEST_API_ DeathTest { public: // Create returns false if there was an error determining the // appropriate action to take for the current death test; for example, // if the gtest_death_test_style flag is set to an invalid value. // The LastMessage method will return a more detailed message in that // case. Otherwise, the DeathTest pointer pointed to by the "test" // argument is set. If the death test should be skipped, the pointer // is set to NULL; otherwise, it is set to the address of a new concrete // DeathTest object that controls the execution of the current test. static bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); DeathTest(); virtual ~DeathTest() { } // A helper class that aborts a death test when it's deleted. class ReturnSentinel { public: explicit ReturnSentinel(DeathTest* test) : test_(test) { } ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } private: DeathTest* const test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); } GTEST_ATTRIBUTE_UNUSED_; // An enumeration of possible roles that may be taken when a death // test is encountered. EXECUTE means that the death test logic should // be executed immediately. OVERSEE means that the program should prepare // the appropriate environment for a child process to execute the death // test, then wait for it to complete. enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; // An enumeration of the three reasons that a test might be aborted. enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_THREW_EXCEPTION, TEST_DID_NOT_DIE }; // Assumes one of the above roles. virtual TestRole AssumeRole() = 0; // Waits for the death test to finish and returns its status. virtual int Wait() = 0; // Returns true if the death test passed; that is, the test process // exited during the test, its exit status matches a user-supplied // predicate, and its stderr output matches a user-supplied regular // expression. // The user-supplied predicate may be a macro expression rather // than a function pointer or functor, or else Wait and Passed could // be combined. virtual bool Passed(bool exit_status_ok) = 0; // Signals that the death test did not die as expected. virtual void Abort(AbortReason reason) = 0; // Returns a human-readable outcome message regarding the outcome of // the last death test. static const char* LastMessage(); static void set_last_death_test_message(const std::string& message); private: // A string containing a description of the outcome of the last death test. static std::string last_death_test_message_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); }; // Factory interface for death tests. May be mocked out for testing. class DeathTestFactory { public: virtual ~DeathTestFactory() { } virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) = 0; }; // A concrete DeathTestFactory implementation for normal use. class DefaultDeathTestFactory : public DeathTestFactory { public: virtual bool Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test); }; // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. GTEST_API_ bool ExitedUnsuccessfully(int exit_status); // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } catch (const ::std::exception& gtest_exception) { \ fprintf(\ stderr, \ "\n%s: Caught std::exception-derived exception escaping the " \ "death test statement. Exception message: %s\n", \ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ gtest_exception.what()); \ fflush(stderr); \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } catch (...) { \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } # else # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) # endif // This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, // ASSERT_EXIT*, and EXPECT_EXIT*. # define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ const ::testing::internal::RE& gtest_regex = (regex); \ ::testing::internal::DeathTest* gtest_dt; \ if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ __FILE__, __LINE__, >est_dt)) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ if (gtest_dt != NULL) { \ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ gtest_dt_ptr(gtest_dt); \ switch (gtest_dt->AssumeRole()) { \ case ::testing::internal::DeathTest::OVERSEE_TEST: \ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ } \ break; \ case ::testing::internal::DeathTest::EXECUTE_TEST: { \ ::testing::internal::DeathTest::ReturnSentinel \ gtest_sentinel(gtest_dt); \ GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ break; \ } \ default: \ break; \ } \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ fail(::testing::internal::DeathTest::LastMessage()) // The symbol "fail" here expands to something into which a message // can be streamed. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in // NDEBUG mode. In this case we need the statements to be executed, the regex is // ignored, and the macro must accept a streamed message even though the message // is never printed. # define GTEST_EXECUTE_STATEMENT_(statement, regex) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } else \ ::testing::Message() // A class representing the parsed contents of the // --gtest_internal_run_death_test flag, as it existed when // RUN_ALL_TESTS was called. class InternalRunDeathTestFlag { public: InternalRunDeathTestFlag(const std::string& a_file, int a_line, int an_index, int a_write_fd) : file_(a_file), line_(a_line), index_(an_index), write_fd_(a_write_fd) {} ~InternalRunDeathTestFlag() { if (write_fd_ >= 0) posix::Close(write_fd_); } const std::string& file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } private: std::string file_; int line_; int index_; int write_fd_; GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); }; // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); #else // GTEST_HAS_DEATH_TEST // This macro is used for implementing macros such as // EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where // death tests are not supported. Those macros must compile on such systems // iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on // systems that support death tests. This allows one to write such a macro // on a system that does not support death tests and be sure that it will // compile on a death-test supporting system. // // Parameters: // statement - A statement that a macro such as EXPECT_DEATH would test // for program termination. This macro has to make sure this // statement is compiled but not executed, to ensure that // EXPECT_DEATH_IF_SUPPORTED compiles with a certain // parameter iff EXPECT_DEATH compiles with it. // regex - A regex that a macro such as EXPECT_DEATH would use to test // the output of statement. This parameter has to be // compiled but not evaluated by this macro, to ensure that // this macro only accepts expressions that a macro such as // EXPECT_DEATH would accept. // terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED // and a return statement for ASSERT_DEATH_IF_SUPPORTED. // This ensures that ASSERT_DEATH_IF_SUPPORTED will not // compile inside functions where ASSERT_DEATH doesn't // compile. // // The branch that has an always false condition is used to ensure that // statement and regex are compiled (and thus syntactically correct) but // never executed. The unreachable code macro protects the terminator // statement from generating an 'unreachable code' warning in case // statement unconditionally returns or throws. The Message constructor at // the end allows the syntax of streaming additional messages into the // macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. # define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_LOG_(WARNING) \ << "Death tests are not supported on this platform.\n" \ << "Statement '" #statement "' cannot be verified."; \ } else if (::testing::internal::AlwaysFalse()) { \ ::testing::internal::RE::PartialMatch(".*", (regex)); \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ terminator; \ } else \ ::testing::Message() #endif // GTEST_HAS_DEATH_TEST } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ namespace testing { // This flag controls the style of death tests. Valid values are "threadsafe", // meaning that the death test child process will re-execute the test binary // from the start, running only a single death test, or "fast", // meaning that the child process will execute the test logic immediately // after forking. GTEST_DECLARE_string_(death_test_style); #if GTEST_HAS_DEATH_TEST namespace internal { // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. GTEST_API_ bool InDeathTestChild(); } // namespace internal // The following macros are useful for writing death tests. // Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is // executed: // // 1. It generates a warning if there is more than one active // thread. This is because it's safe to fork() or clone() only // when there is a single thread. // // 2. The parent process clone()s a sub-process and runs the death // test in it; the sub-process exits with code 0 at the end of the // death test, if it hasn't exited already. // // 3. The parent process waits for the sub-process to terminate. // // 4. The parent process checks the exit code and error message of // the sub-process. // // Examples: // // ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); // for (int i = 0; i < 5; i++) { // EXPECT_DEATH(server.ProcessRequest(i), // "Invalid request .* in ProcessRequest()") // << "Failed to die on request " << i; // } // // ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); // // bool KilledBySIGHUP(int exit_code) { // return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; // } // // ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); // // On the regular expressions used in death tests: // // On POSIX-compliant systems (*nix), we use the library, // which uses the POSIX extended regex syntax. // // On other platforms (e.g. Windows), we only support a simple regex // syntax implemented as part of Google Test. This limited // implementation should be enough most of the time when writing // death tests; though it lacks many features you can find in PCRE // or POSIX extended regex syntax. For example, we don't support // union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and // repetition count ("x{5,7}"), among others. // // Below is the syntax that we do support. We chose it to be a // subset of both PCRE and POSIX extended regex, so it's easy to // learn wherever you come from. In the following: 'A' denotes a // literal character, period (.), or a single \\ escape sequence; // 'x' and 'y' denote regular expressions; 'm' and 'n' are for // natural numbers. // // c matches any literal character c // \\d matches any decimal digit // \\D matches any character that's not a decimal digit // \\f matches \f // \\n matches \n // \\r matches \r // \\s matches any ASCII whitespace, including \n // \\S matches any character that's not a whitespace // \\t matches \t // \\v matches \v // \\w matches any letter, _, or decimal digit // \\W matches any character that \\w doesn't match // \\c matches any literal character c, which must be a punctuation // . matches any single character except \n // A? matches 0 or 1 occurrences of A // A* matches 0 or many occurrences of A // A+ matches 1 or many occurrences of A // ^ matches the beginning of a string (not that of each line) // $ matches the end of a string (not that of each line) // xy matches x followed by y // // If you accidentally use PCRE or POSIX extended regex features // not implemented by us, you will get a run-time failure. In that // case, please try to rewrite your regular expression within the // above syntax. // // This implementation is *not* meant to be as highly tuned or robust // as a compiled regex library, but should perform well enough for a // death test, which already incurs significant overhead by launching // a child process. // // Known caveats: // // A "threadsafe" style death test obtains the path to the test // program from argv[0] and re-executes it in the sub-process. For // simplicity, the current implementation doesn't search the PATH // when launching the sub-process. This means that the user must // invoke the test program via a path that contains at least one // path separator (e.g. path/to/foo_test and // /absolute/path/to/bar_test are fine, but foo_test is not). This // is rarely a problem as people usually don't put the test binary // directory in PATH. // // TODO(wan@google.com): make thread-safe death tests search the PATH. // Asserts that a given statement causes the program to exit, with an // integer exit status that satisfies predicate, and emitting error output // that matches regex. # define ASSERT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) // Like ASSERT_EXIT, but continues on to successive tests in the // test case, if any: # define EXPECT_EXIT(statement, predicate, regex) \ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) // Asserts that a given statement causes the program to exit, either by // explicitly exiting with a nonzero exit code or being killed by a // signal, and emitting error output that matches regex. # define ASSERT_DEATH(statement, regex) \ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Like ASSERT_DEATH, but continues on to successive tests in the // test case, if any: # define EXPECT_DEATH(statement, regex) \ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) // Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: // Tests that an exit code describes a normal exit with a given exit code. class GTEST_API_ ExitedWithCode { public: explicit ExitedWithCode(int exit_code); bool operator()(int exit_status) const; private: // No implementation - assignment is unsupported. void operator=(const ExitedWithCode& other); const int exit_code_; }; # if !GTEST_OS_WINDOWS // Tests that an exit code describes an exit due to termination by a // given signal. class GTEST_API_ KilledBySignal { public: explicit KilledBySignal(int signum); bool operator()(int exit_status) const; private: const int signum_; }; # endif // !GTEST_OS_WINDOWS // EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. // The death testing framework causes this to have interesting semantics, // since the sideeffects of the call are only visible in opt mode, and not // in debug mode. // // In practice, this can be used to test functions that utilize the // LOG(DFATAL) macro using the following style: // // int DieInDebugOr12(int* sideeffect) { // if (sideeffect) { // *sideeffect = 12; // } // LOG(DFATAL) << "death"; // return 12; // } // // TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { // int sideeffect = 0; // // Only asserts in dbg. // EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); // // #ifdef NDEBUG // // opt-mode has sideeffect visible. // EXPECT_EQ(12, sideeffect); // #else // // dbg-mode no visible sideeffect. // EXPECT_EQ(0, sideeffect); // #endif // } // // This will assert that DieInDebugReturn12InOpt() crashes in debug // mode, usually due to a DCHECK or LOG(DFATAL), but returns the // appropriate fallback value (12 in this case) in opt mode. If you // need to test that a function has appropriate side-effects in opt // mode, include assertions against the side-effects. A general // pattern for this is: // // EXPECT_DEBUG_DEATH({ // // Side-effects here will have an effect after this statement in // // opt mode, but none in debug mode. // EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); // }, "death"); // # ifdef NDEBUG # define EXPECT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # else # define EXPECT_DEBUG_DEATH(statement, regex) \ EXPECT_DEATH(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ ASSERT_DEATH(statement, regex) # endif // NDEBUG for EXPECT_DEBUG_DEATH #endif // GTEST_HAS_DEATH_TEST // EXPECT_DEATH_IF_SUPPORTED(statement, regex) and // ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if // death tests are supported; otherwise they just issue a warning. This is // useful when you are combining death test assertions with normal test // assertions in one test. #if GTEST_HAS_DEATH_TEST # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ EXPECT_DEATH(statement, regex) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ ASSERT_DEATH(statement, regex) #else # define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) # define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) #endif } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ // This file was GENERATED by command: // pump.py gtest-param-test.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: vladl@google.com (Vlad Losev) // // Macros and functions for implementing parameterized tests // in Google C++ Testing Framework (Google Test) // // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // #ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Value-parameterized tests allow you to test your code with different // parameters without writing multiple copies of the same test. // // Here is how you use value-parameterized tests: #if 0 // To write value-parameterized tests, first you should define a fixture // class. It is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam is itself derived from testing::Test. T can be any // copyable type. If it's a raw pointer, you are responsible for managing the // lifespan of the pointed values. class FooTest : public ::testing::TestWithParam { // You can implement all the usual class fixture members here. }; // Then, use the TEST_P macro to define as many parameterized tests // for this fixture as you want. The _P suffix is for "parameterized" // or "pattern", whichever you prefer to think. TEST_P(FooTest, DoesBlah) { // Inside a test, access the test parameter with the GetParam() method // of the TestWithParam class: EXPECT_TRUE(foo.Blah(GetParam())); ... } TEST_P(FooTest, HasBlahBlah) { ... } // Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test // case with any set of parameters you want. Google Test defines a number // of functions for generating test parameters. They return what we call // (surprise!) parameter generators. Here is a summary of them, which // are all in the testing namespace: // // // Range(begin, end [, step]) - Yields values {begin, begin+step, // begin+step+step, ...}. The values do not // include end. step defaults to 1. // Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. // ValuesIn(container) - Yields values from a C-style array, an STL // ValuesIn(begin,end) container, or an iterator range [begin, end). // Bool() - Yields sequence {false, true}. // Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product // for the math savvy) of the values generated // by the N generators. // // For more details, see comments at the definitions of these functions below // in this file. // // The following statement will instantiate tests from the FooTest test case // each with parameter values "meeny", "miny", and "moe". INSTANTIATE_TEST_CASE_P(InstantiationName, FooTest, Values("meeny", "miny", "moe")); // To distinguish different instances of the pattern, (yes, you // can instantiate it more then once) the first argument to the // INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the // actual test case name. Remember to pick unique prefixes for different // instantiations. The tests from the instantiation above will have // these names: // // * InstantiationName/FooTest.DoesBlah/0 for "meeny" // * InstantiationName/FooTest.DoesBlah/1 for "miny" // * InstantiationName/FooTest.DoesBlah/2 for "moe" // * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" // * InstantiationName/FooTest.HasBlahBlah/1 for "miny" // * InstantiationName/FooTest.HasBlahBlah/2 for "moe" // // You can use these names in --gtest_filter. // // This statement will instantiate all tests from FooTest again, each // with parameter values "cat" and "dog": const char* pets[] = {"cat", "dog"}; INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); // The tests from the instantiation above will have these names: // // * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" // * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" // * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" // * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" // // Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests // in the given test case, whether their definitions come before or // AFTER the INSTANTIATE_TEST_CASE_P statement. // // Please also note that generator expressions (including parameters to the // generators) are evaluated in InitGoogleTest(), after main() has started. // This allows the user on one hand, to adjust generator parameters in order // to dynamically determine a set of tests to run and on the other hand, // give the user a chance to inspect the generated tests with Google Test // reflection API before RUN_ALL_TESTS() is executed. // // You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc // for more examples. // // In the future, we plan to publish the API for defining new parameter // generators. But for now this interface remains part of the internal // implementation and is subject to change. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #if !GTEST_OS_SYMBIAN # include #endif // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ #include #include #include // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. // Copyright 2003 Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: Dan Egnor (egnor@google.com) // // A "smart" pointer type with reference tracking. Every pointer to a // particular object is kept on a circular linked list. When the last pointer // to an object is destroyed or reassigned, the object is deleted. // // Used properly, this deletes the object when the last reference goes away. // There are several caveats: // - Like all reference counting schemes, cycles lead to leaks. // - Each smart pointer is actually two pointers (8 bytes instead of 4). // - Every time a pointer is assigned, the entire list of pointers to that // object is traversed. This class is therefore NOT SUITABLE when there // will often be more than two or three pointers to a particular object. // - References are only tracked as long as linked_ptr<> objects are copied. // If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS // will happen (double deletion). // // A good use of this class is storing object references in STL containers. // You can safely put linked_ptr<> in a vector<>. // Other uses may not be as good. // // Note: If you use an incomplete type with linked_ptr<>, the class // *containing* linked_ptr<> must have a constructor and destructor (even // if they do nothing!). // // Bill Gibbons suggested we use something like this. // // Thread Safety: // Unlike other linked_ptr implementations, in this implementation // a linked_ptr object is thread-safe in the sense that: // - it's safe to copy linked_ptr objects concurrently, // - it's safe to copy *from* a linked_ptr and read its underlying // raw pointer (e.g. via get()) concurrently, and // - it's safe to write to two linked_ptrs that point to the same // shared object concurrently. // TODO(wan@google.com): rename this to safe_linked_ptr to avoid // confusion with normal linked_ptr. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ #include #include namespace testing { namespace internal { // Protects copying of all linked_ptr objects. GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); // This is used internally by all instances of linked_ptr<>. It needs to be // a non-template class because different types of linked_ptr<> can refer to // the same object (linked_ptr(obj) vs linked_ptr(obj)). // So, it needs to be possible for different types of linked_ptr to participate // in the same circular linked list, so we need a single class type here. // // DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. class linked_ptr_internal { public: // Create a new circle that includes only this instance. void join_new() { next_ = this; } // Many linked_ptr operations may change p.link_ for some linked_ptr // variable p in the same circle as this object. Therefore we need // to prevent two such operations from occurring concurrently. // // Note that different types of linked_ptr objects can coexist in a // circle (e.g. linked_ptr, linked_ptr, and // linked_ptr). Therefore we must use a single mutex to // protect all linked_ptr objects. This can create serious // contention in production code, but is acceptable in a testing // framework. // Join an existing circle. void join(linked_ptr_internal const* ptr) GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; while (p->next_ != ptr) p = p->next_; p->next_ = this; next_ = ptr; } // Leave whatever circle we're part of. Returns true if we were the // last member of the circle. Once this is done, you can join() another. bool depart() GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); if (next_ == this) return true; linked_ptr_internal const* p = next_; while (p->next_ != this) p = p->next_; p->next_ = next_; return false; } private: mutable linked_ptr_internal const* next_; }; template class linked_ptr { public: typedef T element_type; // Take over ownership of a raw pointer. This should happen as soon as // possible after the object is created. explicit linked_ptr(T* ptr = NULL) { capture(ptr); } ~linked_ptr() { depart(); } // Copy an existing linked_ptr<>, adding ourselves to the list of references. template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } linked_ptr(linked_ptr const& ptr) { // NOLINT assert(&ptr != this); copy(&ptr); } // Assignment releases the old value and acquires the new. template linked_ptr& operator=(linked_ptr const& ptr) { depart(); copy(&ptr); return *this; } linked_ptr& operator=(linked_ptr const& ptr) { if (&ptr != this) { depart(); copy(&ptr); } return *this; } // Smart pointer members. void reset(T* ptr = NULL) { depart(); capture(ptr); } T* get() const { return value_; } T* operator->() const { return value_; } T& operator*() const { return *value_; } bool operator==(T* p) const { return value_ == p; } bool operator!=(T* p) const { return value_ != p; } template bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template friend class linked_ptr; T* value_; linked_ptr_internal link_; void depart() { if (link_.depart()) delete value_; } void capture(T* ptr) { value_ = ptr; link_.join_new(); } template void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Test - The Google C++ Testing Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // A user can teach this function how to print a class type T by // defining either operator<<() or PrintTo() in the namespace that // defines T. More specifically, the FIRST defined function in the // following list will be used (assuming T is defined in namespace // foo): // // 1. foo::PrintTo(const T&, ostream*) // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. // // To aid debugging: when T is a reference type, the address of the // value is also printed; when T is a (const) char pointer, both the // pointer value and the NUL-terminated string it points to are // printed. // // We also provide some convenient wrappers: // // // Prints a value to a string. For a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // std::string ::testing::PrintToString(const T& value); // // // Prints a value tersely: for a reference type, the referenced // // value (but not the address) is printed; for a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // // // Prints value using the type inferred by the compiler. The difference // // from UniversalTersePrint() is that this function prints both the // // pointer and the NUL-terminated string for a (const or not) char pointer. // void ::testing::internal::UniversalPrint(const T& value, ostream*); // // // Prints the fields of a tuple tersely to a string vector, one // // element for each field. Tuple support must be enabled in // // gtest-port.h. // std::vector UniversalTersePrintTupleFieldsToStrings( // const Tuple& value); // // Known limitation: // // The print primitives print the elements of an STL-style container // using the compiler-inferred type of *iter where iter is a // const_iterator of the container. When const_iterator is an input // iterator but not a forward iterator, this inferred type may not // match value_type, and the print output may be incorrect. In // practice, this is rarely a problem as for most containers // const_iterator is a forward iterator. We'll fix this if there's an // actual need for it. Note that this fix cannot rely on value_type // being defined as many user-defined container types don't have // value_type. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #include // NOLINT #include #include #include #include namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are // subject to change without notice. DO NOT USE THEM IN USER CODE! namespace internal2 { // Prints the given number of bytes in the given object to the given // ostream. GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ::std::ostream* os); // For selecting which printer to use when a given type has neither << // nor PrintTo(). enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called // by the universal printer to print a value of type T when neither // operator<< nor PrintTo() is defined for T, where kTypeKind is the // "kind" of T as defined by enum TypeKind. template class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo(reinterpret_cast(&value), sizeof(value), os); } }; // We print a protobuf using its ShortDebugString() when the string // doesn't exceed this many characters; otherwise we print it using // DebugString() for better readability. const size_t kProtobufOneLinerMaxLength = 50; template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { const ::testing::internal::string short_str = value.ShortDebugString(); const ::testing::internal::string pretty_str = short_str.length() <= kProtobufOneLinerMaxLength ? short_str : ("\n" + value.DebugString()); *os << ("<" + pretty_str + ">"); } }; template class TypeWithoutFormatter { public: // Since T has no << operator or PrintTo() but can be implicitly // converted to BiggestInt, we print it as a BiggestInt. // // Most likely T is an enum type (either named or unnamed), in which // case printing it as an integer is the desired behavior. In case // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. static void PrintValue(const T& value, ::std::ostream* os) { const internal::BiggestInt kBigInt = value; *os << kBigInt; } }; // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an // integer; otherwise the bytes in the value are printed. This is // what UniversalPrinter::Print() does when it knows nothing about // type T and T has neither << operator nor PrintTo(). // // A user can override this behavior for a class type Foo by defining // a << operator in the namespace where Foo is defined. // // We put this operator in namespace 'internal2' instead of 'internal' // to simplify the implementation, as much code in 'internal' needs to // use << in STL, which would conflict with our own << were it defined // in 'internal'. // // Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If // we define it to take an std::ostream instead, we'll get an // "ambiguous overloads" compiler error when trying to print a type // Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : internal::ImplicitlyConvertible::value ? kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); return os; } } // namespace internal2 } // namespace testing // This namespace MUST NOT BE NESTED IN ::testing, or the name look-up // magic needed for implementing UniversalPrinter won't work. namespace testing_internal { // Used to print a value that is not an STL-style container when the // user doesn't define PrintTo() for it. template void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { // With the following statement, during unqualified name lookup, // testing::internal2::operator<< appears as if it was declared in // the nearest enclosing namespace that contains both // ::testing_internal and ::testing::internal2, i.e. the global // namespace. For more details, refer to the C++ Standard section // 7.3.4-1 [namespace.udir]. This allows us to fall back onto // testing::internal2::operator<< in case T doesn't come with a << // operator. // // We cannot write 'using ::testing::internal2::operator<<;', which // gcc 3.3 fails to compile due to a compiler bug. using namespace ::testing::internal2; // NOLINT // Assuming T is defined in namespace foo, in the next statement, // the compiler will consider all of: // // 1. foo::operator<< (thanks to Koenig look-up), // 2. ::operator<< (as the current namespace is enclosed in ::), // 3. testing::internal2::operator<< (thanks to the using statement above). // // The operator<< whose type matches T best will be picked. // // We deliberately allow #2 to be a candidate, as sometimes it's // impossible to define #1 (e.g. when foo is ::std, defining // anything in it is undefined behavior unless you are a compiler // vendor.). *os << value; } } // namespace testing_internal namespace testing { namespace internal { // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. // // We define UniversalPrinter as a class template (as opposed to a // function template), as we need to partially specialize it for // reference types, which cannot be done with function templates. template class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template void DefaultPrintTo(IsContainer /* dummy */, false_type /* is not a pointer */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; size_t count = 0; for (typename C::const_iterator it = container.begin(); it != container.end(); ++it, ++count) { if (count > 0) { *os << ','; if (count == kMaxCount) { // Enough has been printed. *os << " ..."; break; } } *os << ' '; // We cannot call PrintTo(*it, os) here as PrintTo() doesn't // handle *it being a native array. internal::UniversalPrint(*it, os); } if (count > 0) { *os << ' '; } *os << '}'; } // Used to print a pointer that is neither a char pointer nor a member // pointer, when the user doesn't define PrintTo() for it. (A member // variable pointer or member function pointer doesn't really point to // a location in the address space. Their representation is // implementation-defined. Therefore they will be printed as raw // bytes.) template void DefaultPrintTo(IsNotContainer /* dummy */, true_type /* is a pointer */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { // C++ doesn't allow casting from a function pointer to any object // pointer. // // IsTrue() silences warnings: "Condition is always true", // "unreachable code". if (IsTrue(ImplicitlyConvertible::value)) { // T is not a function type. We just call << to print p, // relying on ADL to pick up user-defined << for their pointer // types, if any. *os << p; } else { // T is a function type, so '*os << p' doesn't do what we want // (it just prints p as bool). We want to print p as a const // void*. However, we cannot cast it to const void* directly, // even using reinterpret_cast, as earlier versions of gcc // (e.g. 3.4.5) cannot compile the cast when p is a function // pointer. Casting to UInt64 first solves the problem. *os << reinterpret_cast( reinterpret_cast(p)); } } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template void DefaultPrintTo(IsNotContainer /* dummy */, false_type /* is not a pointer */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } // Prints the given value using the << operator if it has one; // otherwise prints the bytes in it. This is what // UniversalPrinter::Print() does when PrintTo() is not specialized // or overloaded for type T. // // A user can override this behavior for a class type Foo by defining // an overload of PrintTo() in the namespace where Foo is defined. We // give the user this option as sometimes defining a << operator for // Foo is not desirable (e.g. the coding style may prevent doing it, // or there is already a << operator but it doesn't do what the user // wants). template void PrintTo(const T& value, ::std::ostream* os) { // DefaultPrintTo() is overloaded. The type of its first two // arguments determine which version will be picked. If T is an // STL-style container, the version for container will be called; if // T is a pointer, the pointer version will be called; otherwise the // generic version will be called. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: // // For protocol messages, we want to give people a chance to // override Google Mock's format by defining a PrintTo() or // operator<<. For STL containers, other formats can be // incompatible with Google Mock's format for the container // elements; therefore we check for container types here to ensure // that our format is used. // // The second argument of DefaultPrintTo() is needed to bypass a bug // in Symbian's C++ compiler that prevents it from picking the right // overload between: // // PrintTo(const T& x, ...); // PrintTo(T* x, ...); DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::Print() how to print standard types (built-in // types, strings, plain arrays, and pointers). // Overloads for various char types. GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); inline void PrintTo(char c, ::std::ostream* os) { // When printing a plain char, we always treat it as unsigned. This // way, the output won't be affected by whether the compiler thinks // char is signed or not. PrintTo(static_cast(c), os); } // Overloads for other simple built-in types. inline void PrintTo(bool x, ::std::ostream* os) { *os << (x ? "true" : "false"); } // Overload for wchar_t type. // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its decimal code (except for L'\0'). // The L'\0' char is printed as "L'\\0'". The decimal code is printed // as signed integer when wchar_t is implemented by the compiler // as a signed type and is printed as an unsigned integer when wchar_t // is implemented as an unsigned type. GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); inline void PrintTo(char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // signed/unsigned char is often used for representing binary data, so // we print pointers to it as void* to be safe. inline void PrintTo(const signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // MSVC can be configured to define wchar_t as a typedef of unsigned // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native // type. When wchar_t is a typedef, defining an overload for const // wchar_t* would cause unsigned short* be printed as a wide string, // possibly causing invalid memory accesses. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Overloads for wide C strings GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); inline void PrintTo(wchar_t* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } #endif // Overload for C arrays. Multi-dimensional arrays are printed // properly. // Prints the given number of elements in an array, without printing // the curly braces. template void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { UniversalPrint(a[0], os); for (size_t i = 1; i != count; i++) { *os << ", "; UniversalPrint(a[i], os); } } // Overloads for ::string and ::std::string. #if GTEST_HAS_GLOBAL_STRING GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); inline void PrintTo(const ::string& s, ::std::ostream* os) { PrintStringTo(s, os); } #endif // GTEST_HAS_GLOBAL_STRING GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } // Overloads for ::wstring and ::std::wstring. #if GTEST_HAS_GLOBAL_WSTRING GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); inline void PrintTo(const ::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_TR1_TUPLE // Overload for ::std::tr1::tuple. Needed for printing function arguments, // which are packed as tuples. // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T& t, ::std::ostream* os); // Overloaded PrintTo() for tuples of various arities. We support // tuples of up-to 10 fields. The following implementation works // regardless of whether tr1::tuple is implemented using the // non-standard variadic template feature or not. inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo( const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_TR1_TUPLE // Overload for std::pair. template void PrintTo(const ::std::pair& value, ::std::ostream* os) { *os << '('; // We cannot use UniversalPrint(value.first, os) here, as T1 may be // a reference type. The same for printing value.second. UniversalPrinter::Print(value.first, os); *os << ", "; UniversalPrinter::Print(value.second, os); *os << ')'; } // Implements printing a non-reference type T by letting the compiler // pick the right overload of PrintTo() for T. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4180) // Temporarily disables warning 4180. #endif // _MSC_VER // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the // function. static void Print(const T& value, ::std::ostream* os) { // By default, ::testing::internal::PrintTo() is used for printing // the value. // // Thanks to Koenig look-up, if T is a class and has its own // PrintTo() function defined in its namespace, that function will // be visible here. Since it is more specific than the generic ones // in ::testing::internal, it will be picked by the compiler in the // following statement - exactly what we want. PrintTo(value, os); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif // _MSC_VER }; // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { if (len == 0) { *os << "{}"; } else { *os << "{ "; const size_t kThreshold = 18; const size_t kChunkSize = 8; // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. // TODO(wan@google.com): let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { PrintRawArrayTo(begin, kChunkSize, os); *os << ", ..., "; PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); } *os << " }"; } } // This overload prints a (const) char array compactly. GTEST_API_ void UniversalPrintArray( const char* begin, size_t len, ::std::ostream* os); // This overload prints a (const) wchar_t array compactly. GTEST_API_ void UniversalPrintArray( const wchar_t* begin, size_t len, ::std::ostream* os); // Implements printing an array type T[N]. template class UniversalPrinter { public: // Prints the given array, omitting some elements when there are too // many. static void Print(const T (&a)[N], ::std::ostream* os) { UniversalPrintArray(a, N, os); } }; // Implements printing a reference type T&. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4180) // Temporarily disables warning 4180. #endif // _MSC_VER static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here // as static_cast doesn't compile when T is a function type. *os << "@" << reinterpret_cast(&value) << " "; // Then prints the value itself. UniversalPrint(value, os); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif // _MSC_VER }; // Prints a value tersely: for a reference type, the referenced value // (but not the address) is printed; for a (const) char pointer, the // NUL-terminated string (but not the pointer) is printed. template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T (&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); } } }; #endif template <> class UniversalTersePrinter { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::Print(value, os); } // Prints a value using the type inferred by the compiler. The // difference between this and UniversalTersePrint() is that for a // (const) char pointer, this prints both the pointer and the // NUL-terminated string. template void UniversalPrint(const T& value, ::std::ostream* os) { // A workarond for the bug in VC++ 7.1 that prevents us from instantiating // UniversalPrinter with T directly. typedef T T1; UniversalPrinter::Print(value, os); } #if GTEST_HAS_TR1_TUPLE typedef ::std::vector Strings; // This helper template allows PrintTo() for tuples and // UniversalTersePrintTupleFieldsToStrings() to be defined by // induction on the number of tuple fields. The idea is that // TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. // The inductive case. template struct TuplePrefixPrinter { // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); *os << ", "; UniversalPrinter::type> ::Print(::std::tr1::get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; UniversalTersePrint(::std::tr1::get(t), &ss); strings->push_back(ss.str()); } }; // Base cases. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} template static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} }; // We have to specialize the entire TuplePrefixPrinter<> class // template here, even though the definition of // TersePrintPrefixToStrings() is the same as the generic version, as // Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't // support specializing a method template of a class template. template <> struct TuplePrefixPrinter<1> { template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { UniversalPrinter::type>:: Print(::std::tr1::get<0>(t), os); } template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { ::std::stringstream ss; UniversalTersePrint(::std::tr1::get<0>(t), &ss); strings->push_back(ss.str()); } }; // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T& t, ::std::ostream* os) { *os << "("; TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: PrintPrefixTo(t, os); *os << ")"; } // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: TersePrintPrefixToStrings(value, &result); return result; } #endif // GTEST_HAS_TR1_TUPLE } // namespace internal template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #if GTEST_HAS_PARAM_TEST namespace testing { namespace internal { // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Outputs a message explaining invalid registration of different // fixture class for the same test case. This may happen when // TEST_P macro is used to define two tests with the same name // but in different namespaces. GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line); template class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template class ParamIteratorInterface { public: virtual ~ParamIteratorInterface() {} // A pointer to the base generator instance. // Used only for the purposes of iterator comparison // to make sure that two iterators belong to the same generator. virtual const ParamGeneratorInterface* BaseGenerator() const = 0; // Advances iterator to point to the next element // provided by the generator. The caller is responsible // for not calling Advance() on an iterator equal to // BaseGenerator()->End(). virtual void Advance() = 0; // Clones the iterator object. Used for implementing copy semantics // of ParamIterator. virtual ParamIteratorInterface* Clone() const = 0; // Dereferences the current iterator and provides (read-only) access // to the pointed value. It is the caller's responsibility not to call // Current() on an iterator equal to BaseGenerator()->End(). // Used for implementing ParamGenerator::operator*(). virtual const T* Current() const = 0; // Determines whether the given iterator and other point to the same // element in the sequence generated by the generator. // Used for implementing ParamGenerator::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template class ParamIterator { public: typedef T value_type; typedef const T& reference; typedef ptrdiff_t difference_type; // ParamIterator assumes ownership of the impl_ pointer. ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} ParamIterator& operator=(const ParamIterator& other) { if (this != &other) impl_.reset(other.impl_->Clone()); return *this; } const T& operator*() const { return *impl_->Current(); } const T* operator->() const { return impl_->Current(); } // Prefix version of operator++. ParamIterator& operator++() { impl_->Advance(); return *this; } // Postfix version of operator++. ParamIterator operator++(int /*unused*/) { ParamIteratorInterface* clone = impl_->Clone(); impl_->Advance(); return ParamIterator(clone); } bool operator==(const ParamIterator& other) const { return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); } bool operator!=(const ParamIterator& other) const { return !(*this == other); } private: friend class ParamGenerator; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} ParamGenerator& operator=(const ParamGenerator& other) { impl_ = other.impl_; return *this; } iterator begin() const { return iterator(impl_->Begin()); } iterator end() const { return iterator(impl_->End()); } private: linked_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to // generate sequences of user-defined types that implement operator+() and // operator<(). // This class is used in the Range() function. template class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = value_ + step_; index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const int other_index = CheckedDowncastToActualType(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; T value_; int index_; const IncrementT step_; }; // class RangeGenerator::Iterator static int CalculateEndIndex(const T& begin, const T& end, const IncrementT& step) { int end_index = 0; for (T i = begin; i < end; i = i + step) end_index++; return end_index; } // No implementation - assignment is unsupported. void operator=(const RangeGenerator& other); const T begin_; const T end_; const IncrementT step_; // The index for the end() iterator. All the elements in the generated // sequence are indexed (0-based) to aid iterator comparison. const int end_index_; }; // class RangeGenerator // Generates values from a pair of STL-style iterators. Used in the // ValuesIn() function. The elements are copied from the source range // since the source can be located on the stack, and the generator // is likely to persist beyond that stack frame. template class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } // We need to use cached value referenced by iterator_ because *iterator_ // can return a temporary object (and of type other then T), so just // having "return &*iterator_;" doesn't work. // value_ is updated here and not in Advance() because Advance() // can advance iterator_ beyond the end of the range, and we cannot // detect that fact. The client code, on the other hand, is // responsible for not calling Current() on an out-of-range iterator. virtual const T* Current() const { if (value_.get() == NULL) value_.reset(new T(*iterator_)); return value_.get(); } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; return iterator_ == CheckedDowncastToActualType(&other)->iterator_; } private: Iterator(const Iterator& other) // The explicit constructor call suppresses a false warning // emitted by gcc when supplied with the -Wextra option. : ParamIteratorInterface(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* const base_; typename ContainerType::const_iterator iterator_; // A cached value of *iterator_. We keep it here to allow access by // pointer in the wrapping iterator's operator->(). // value_ needs to be mutable to be accessed in Current(). // Use of scoped_ptr helps manage cached value's lifetime, // which is bound by the lifespan of the iterator itself. mutable scoped_ptr value_; }; // class ValuesInIteratorRangeGenerator::Iterator // No implementation - assignment is unsupported. void operator=(const ValuesInIteratorRangeGenerator& other); const ContainerType container_; }; // class ValuesInIteratorRangeGenerator // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that // value. template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} virtual Test* CreateTest() { TestClass::SetParam(¶meter_); return new TestClass(); } private: const ParamType parameter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactoryBase is a base class for meta-factories that create // test factories for passing into MakeAndRegisterTestInfo function. template class TestMetaFactoryBase { public: virtual ~TestMetaFactoryBase() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // TestMetaFactory creates test factories for passing into // MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives // ownership of test factory pointer, same factory object cannot be passed // into that method twice. But ParameterizedTestCaseInfo is going to call // it for each Test/Parameter value combination. Thus it needs meta factory // creator class. template class TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(parameter); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfoBase is a generic interface // to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase // accumulates test information provided by TEST_P macro invocations // and generators provided by INSTANTIATE_TEST_CASE_P macro invocations // and uses that information to register all resulting test instances // in RegisterTests method. The ParameterizeTestCaseRegistry class holds // a collection of pointers to the ParameterizedTestCaseInfo objects // and calls RegisterTests() on each of them when asked. class ParameterizedTestCaseInfoBase { public: virtual ~ParameterizedTestCaseInfoBase() {} // Base part of test case name for display purposes. virtual const string& GetTestCaseName() const = 0; // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const = 0; // UnitTest class invokes this method to register tests in this // test case right before running them in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. virtual void RegisterTests() = 0; protected: ParameterizedTestCaseInfoBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); }; // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseInfo accumulates tests obtained from TEST_P // macro invocations for a particular test case and generators // obtained from INSTANTIATE_TEST_CASE_P macro invocations for that // test case. It registers tests with all values generated by all // generators when asked. template class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { public: // ParamType and GeneratorCreationFunc are private types but are required // for declarations of public methods AddTestPattern() and // AddTestCaseInstantiation(). typedef typename TestCase::ParamType ParamType; // A function that returns an instance of appropriate generator type. typedef ParamGenerator(GeneratorCreationFunc)(); explicit ParameterizedTestCaseInfo(const char* name) : test_case_name_(name) {} // Test case base name for display purposes. virtual const string& GetTestCaseName() const { return test_case_name_; } // Test case id to verify identity. virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } // TEST_P macro uses AddTestPattern() to record information // about a single test in a LocalTestInfo structure. // test_case_name is the base name of the test case (without invocation // prefix). test_base_name is the name of an individual test without // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is // test case base name and DoBar is test base name. void AddTestPattern(const char* test_case_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { tests_.push_back(linked_ptr(new TestInfo(test_case_name, test_base_name, meta_factory))); } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. int AddTestCaseInstantiation(const string& instantiation_name, GeneratorCreationFunc* func, const char* /* file */, int /* line */) { instantiations_.push_back(::std::make_pair(instantiation_name, func)); return 0; // Return value used only to run this method in namespace scope. } // UnitTest class invokes this method to register tests in this test case // test cases right before running tests in RUN_ALL_TESTS macro. // This method should not be called more then once on any single // instance of a ParameterizedTestCaseInfoBase derived class. // UnitTest has a guard to prevent from calling this method more then once. virtual void RegisterTests() { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { linked_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { const string& instantiation_name = gen_it->first; ParamGenerator generator((*gen_it->second)()); string test_case_name; if ( !instantiation_name.empty() ) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; int i = 0; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; test_name_stream << test_info->test_base_name << "/" << i; MakeAndRegisterTestInfo( test_case_name.c_str(), test_name_stream.GetString().c_str(), NULL, // No type parameter. PrintToString(*param_it).c_str(), GetTestCaseTypeId(), TestCase::SetUpTestCase, TestCase::TearDownTestCase, test_info->test_meta_factory->CreateTestFactory(*param_it)); } // for param_it } // for gen_it } // for test_it } // RegisterTests private: // LocalTestInfo structure keeps information about a single test registered // with TEST_P macro. struct TestInfo { TestInfo(const char* a_test_case_base_name, const char* a_test_base_name, TestMetaFactoryBase* a_test_meta_factory) : test_case_base_name(a_test_case_base_name), test_base_name(a_test_base_name), test_meta_factory(a_test_meta_factory) {} const string test_case_base_name; const string test_base_name; const scoped_ptr > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Keeps pairs of // received from INSTANTIATE_TEST_CASE_P macros. typedef ::std::vector > InstantiationContainer; const string test_case_name_; TestInfoContainer tests_; InstantiationContainer instantiations_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); }; // class ParameterizedTestCaseInfo // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase // classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P // macros use it to locate their corresponding ParameterizedTestCaseInfo // descriptors. class ParameterizedTestCaseRegistry { public: ParameterizedTestCaseRegistry() {} ~ParameterizedTestCaseRegistry() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { delete *it; } } // Looks up or creates and returns a structure containing information about // tests and instantiations of a particular test case. template ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, const char* file, int line) { ParameterizedTestCaseInfo* typed_test_info = NULL; for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { if ((*it)->GetTestCaseName() == test_case_name) { if ((*it)->GetTestCaseTypeId() != GetTypeId()) { // Complain about incorrect usage of Google Test facilities // and terminate the program since we cannot guaranty correct // test case setup and tear-down in this case. ReportInvalidTestCaseType(test_case_name, file, line); posix::Abort(); } else { // At this point we are sure that the object we found is of the same // type we are looking for, so we downcast it to that type // without further checks. typed_test_info = CheckedDowncastToActualType< ParameterizedTestCaseInfo >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo(test_case_name); test_case_infos_.push_back(typed_test_info); } return typed_test_info; } void RegisterTests() { for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); it != test_case_infos_.end(); ++it) { (*it)->RegisterTests(); } } private: typedef ::std::vector TestCaseInfoContainer; TestCaseInfoContainer test_case_infos_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); }; } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ // This file was GENERATED by command: // pump.py gtest-param-util-generated.h.pump // DO NOT EDIT BY HAND!!! // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: vladl@google.com (Vlad Losev) // Type and function utilities for implementing parameterized tests. // This file is generated by a SCRIPT. DO NOT EDIT BY HAND! // // Currently Google Test supports at most 50 arguments in Values, // and at most 10 arguments in Combine. Please contact // googletestframework@googlegroups.com if you need more. // Please note that the number of arguments to Combine is limited // by the maximum arity of the implementation of tr1::tuple which is // currently set at 10. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ // scripts/fuse_gtest.py depends on gtest's own header being #included // *unconditionally*. Therefore these #includes cannot be moved // inside #if GTEST_HAS_PARAM_TEST. #if GTEST_HAS_PARAM_TEST namespace testing { // Forward declarations of ValuesIn(), which is implemented in // include/gtest/gtest-param-test.h. template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray3& other); const T1 v1_; const T2 v2_; const T3 v3_; }; template class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray4& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; }; template class ValueArray5 { public: ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray5& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; }; template class ValueArray6 { public: ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray6& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; }; template class ValueArray7 { public: ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray7& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; }; template class ValueArray8 { public: ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray8& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; }; template class ValueArray9 { public: ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray9& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; }; template class ValueArray10 { public: ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray10& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; }; template class ValueArray11 { public: ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray11& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; }; template class ValueArray12 { public: ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray12& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; }; template class ValueArray13 { public: ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray13& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; }; template class ValueArray14 { public: ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray14& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; }; template class ValueArray15 { public: ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray15& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; }; template class ValueArray16 { public: ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray16& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; }; template class ValueArray17 { public: ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray17& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; }; template class ValueArray18 { public: ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray18& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; }; template class ValueArray19 { public: ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray19& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; }; template class ValueArray20 { public: ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray20& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; }; template class ValueArray21 { public: ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray21& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; }; template class ValueArray22 { public: ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray22& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; }; template class ValueArray23 { public: ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray23& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; }; template class ValueArray24 { public: ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray24& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; }; template class ValueArray25 { public: ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray25& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; }; template class ValueArray26 { public: ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray26& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; }; template class ValueArray27 { public: ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray27& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; }; template class ValueArray28 { public: ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray28& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; }; template class ValueArray29 { public: ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray29& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; }; template class ValueArray30 { public: ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray30& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; }; template class ValueArray31 { public: ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray31& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; }; template class ValueArray32 { public: ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray32& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; }; template class ValueArray33 { public: ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray33& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; }; template class ValueArray34 { public: ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray34& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; }; template class ValueArray35 { public: ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray35& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; }; template class ValueArray36 { public: ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray36& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; }; template class ValueArray37 { public: ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray37& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; }; template class ValueArray38 { public: ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray38& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; }; template class ValueArray39 { public: ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray39& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; }; template class ValueArray40 { public: ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray40& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; }; template class ValueArray41 { public: ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray41& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; }; template class ValueArray42 { public: ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray42& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; }; template class ValueArray43 { public: ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray43& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; }; template class ValueArray44 { public: ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray44& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; }; template class ValueArray45 { public: ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray45& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; }; template class ValueArray46 { public: ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray46& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; }; template class ValueArray47 { public: ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray47& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; }; template class ValueArray48 { public: ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray48& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; }; template class ValueArray49 { public: ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray49& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; }; template class ValueArray50 { public: ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_), static_cast(v50_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray50& other); const T1 v1_; const T2 v2_; const T3 v3_; const T4 v4_; const T5 v5_; const T6 v6_; const T7 v7_; const T8 v8_; const T9 v9_; const T10 v10_; const T11 v11_; const T12 v12_; const T13 v13_; const T14 v14_; const T15 v15_; const T16 v16_; const T17 v17_; const T18 v18_; const T19 v19_; const T20 v20_; const T21 v21_; const T22 v22_; const T23 v23_; const T24 v24_; const T25 v25_; const T26 v26_; const T27 v27_; const T28 v28_; const T29 v29_; const T30 v30_; const T31 v31_; const T32 v32_; const T33 v33_; const T34 v34_; const T35 v35_; const T36 v36_; const T37 v37_; const T38 v38_; const T39 v39_; const T40 v40_; const T41 v41_; const T42 v42_; const T43 v43_; const T44 v44_; const T45 v45_; const T46 v46_; const T47 v47_; const T48 v48_; const T49 v49_; const T50 v50_; }; # if GTEST_HAS_COMBINE // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Generates values from the Cartesian product of values produced // by the argument generators. // template class CartesianProductGenerator2 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current2_; if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current3_; if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current4_; if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current5_; if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current6_; if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current7_; if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current8_; if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current9_; if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::std::tr1::tuple > { public: typedef ::std::tr1::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} virtual ~CartesianProductGenerator10() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, g8_.end(), g9_, g9_.end(), g10_, g10_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::iterator& current10) : base_(base), begin1_(g1.begin()), end1_(g1.end()), current1_(current1), begin2_(g2.begin()), end2_(g2.end()), current2_(current2), begin3_(g3.begin()), end3_(g3.end()), current3_(current3), begin4_(g4.begin()), end4_(g4.end()), current4_(current4), begin5_(g5.begin()), end5_(g5.end()), current5_(current5), begin6_(g6.begin()), end6_(g6.end()), current6_(current6), begin7_(g7.begin()), end7_(g7.end()), current7_(current7), begin8_(g8.begin()), end8_(g8.end()), current8_(current8), begin9_(g9.begin()), end9_(g9.end()), current9_(current9), begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { ComputeCurrentValue(); } virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } // Advance should not be called on beyond-of-range iterators // so no component iterators must be beyond end of range, either. virtual void Advance() { assert(!AtEnd()); ++current10_; if (current10_ == end10_) { current10_ = begin10_; ++current9_; } if (current9_ == end9_) { current9_ = begin9_; ++current8_; } if (current8_ == end8_) { current8_ = begin8_; ++current7_; } if (current7_ == end7_) { current7_ = begin7_; ++current6_; } if (current6_ == end6_) { current6_ = begin6_; ++current5_; } if (current5_ == end5_) { current5_ = begin5_; ++current4_; } if (current4_ == end4_) { current4_ = begin4_; ++current3_; } if (current3_ == end3_) { current3_ = begin3_; ++current2_; } if (current2_ == end2_) { current2_ = begin2_; ++current1_; } ComputeCurrentValue(); } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& other) const { // Having the same base generator guarantees that the other // iterator is of the same type and we can downcast. GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) << "The program attempted to compare iterators " << "from different generators." << std::endl; const Iterator* typed_other = CheckedDowncastToActualType(&other); // We must report iterators equal if they both point beyond their // respective ranges. That can happen in a variety of fashions, // so we have to consult AtEnd(). return (AtEnd() && typed_other->AtEnd()) || ( current1_ == typed_other->current1_ && current2_ == typed_other->current2_ && current3_ == typed_other->current3_ && current4_ == typed_other->current4_ && current5_ == typed_other->current5_ && current6_ == typed_other->current6_ && current7_ == typed_other->current7_ && current8_ == typed_other->current8_ && current9_ == typed_other->current9_ && current10_ == typed_other->current10_); } private: Iterator(const Iterator& other) : base_(other.base_), begin1_(other.begin1_), end1_(other.end1_), current1_(other.current1_), begin2_(other.begin2_), end2_(other.end2_), current2_(other.current2_), begin3_(other.begin3_), end3_(other.end3_), current3_(other.current3_), begin4_(other.begin4_), end4_(other.end4_), current4_(other.current4_), begin5_(other.begin5_), end5_(other.end5_), current5_(other.current5_), begin6_(other.begin6_), end6_(other.end6_), current6_(other.current6_), begin7_(other.begin7_), end7_(other.end7_), current7_(other.current7_), begin8_(other.begin8_), end8_(other.end8_), current8_(other.current8_), begin9_(other.begin9_), end9_(other.end9_), current9_(other.current9_), begin10_(other.begin10_), end10_(other.end10_), current10_(other.current10_) { ComputeCurrentValue(); } void ComputeCurrentValue() { if (!AtEnd()) current_value_ = ParamType(*current1_, *current2_, *current3_, *current4_, *current5_, *current6_, *current7_, *current8_, *current9_, *current10_); } bool AtEnd() const { // We must report iterator past the end of the range when either of the // component iterators has reached the end of its range. return current1_ == end1_ || current2_ == end2_ || current3_ == end3_ || current4_ == end4_ || current5_ == end5_ || current6_ == end6_ || current7_ == end7_ || current8_ == end8_ || current9_ == end9_ || current10_ == end10_; } // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* const base_; // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. // current[i]_ is the actual traversing iterator. const typename ParamGenerator::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder3& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; }; // class CartesianProductHolder3 template class CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder4& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; }; // class CartesianProductHolder4 template class CartesianProductHolder5 { public: CartesianProductHolder5(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder5& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; }; // class CartesianProductHolder5 template class CartesianProductHolder6 { public: CartesianProductHolder6(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder6& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; }; // class CartesianProductHolder6 template class CartesianProductHolder7 { public: CartesianProductHolder7(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder7& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; }; // class CartesianProductHolder7 template class CartesianProductHolder8 { public: CartesianProductHolder8(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder8& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; }; // class CartesianProductHolder8 template class CartesianProductHolder9 { public: CartesianProductHolder9(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder9& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; }; // class CartesianProductHolder9 template class CartesianProductHolder10 { public: CartesianProductHolder10(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9), g10_(g10) {} template operator ParamGenerator< ::std::tr1::tuple >() const { return ParamGenerator< ::std::tr1::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(g10_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder10& other); const Generator1 g1_; const Generator2 g2_; const Generator3 g3_; const Generator4 g4_; const Generator5 g5_; const Generator6 g6_; const Generator7 g7_; const Generator8 g8_; const Generator9 g9_; const Generator10 g10_; }; // class CartesianProductHolder10 # endif // GTEST_HAS_COMBINE } // namespace internal } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #if GTEST_HAS_PARAM_TEST namespace testing { // Functions producing parameter generators. // // Google Test uses these generators to produce parameters for value- // parameterized tests. When a parameterized test case is instantiated // with a particular generator, Google Test creates and runs tests // for each element in the sequence produced by the generator. // // In the following sample, tests from test case FooTest are instantiated // each three times with parameter values 3, 5, and 8: // // class FooTest : public TestWithParam { ... }; // // TEST_P(FooTest, TestThis) { // } // TEST_P(FooTest, TestThat) { // } // INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); // // Range() returns generators providing sequences of values in a range. // // Synopsis: // Range(start, end) // - returns a generator producing a sequence of values {start, start+1, // start+2, ..., }. // Range(start, end, step) // - returns a generator producing a sequence of values {start, start+step, // start+step+step, ..., }. // Notes: // * The generated sequences never include end. For example, Range(1, 5) // returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) // returns a generator producing {1, 3, 5, 7}. // * start and end must have the same type. That type may be any integral or // floating-point type or a user defined type satisfying these conditions: // * It must be assignable (have operator=() defined). // * It must have operator+() (operator+(int-compatible type) for // two-operand version). // * It must have operator<() defined. // Elements in the resulting sequences will also have that type. // * Condition start < end must be satisfied in order for resulting sequences // to contain any elements. // template internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator Range(T start, T end) { return Range(start, end, 1); } // ValuesIn() function allows generation of tests with parameters coming from // a container. // // Synopsis: // ValuesIn(const T (&array)[N]) // - returns a generator producing sequences with elements from // a C-style array. // ValuesIn(const Container& container) // - returns a generator producing sequences with elements from // an STL-style container. // ValuesIn(Iterator begin, Iterator end) // - returns a generator producing sequences with elements from // a range [begin, end) defined by a pair of STL-style iterators. These // iterators can also be plain C pointers. // // Please note that ValuesIn copies the values from the containers // passed in and keeps them to generate tests in RUN_ALL_TESTS(). // // Examples: // // This instantiates tests from test case StringTest // each with C-string values of "foo", "bar", and "baz": // // const char* strings[] = {"foo", "bar", "baz"}; // INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); // // This instantiates tests from test case StlStringTest // each with STL strings with values "a" and "b": // // ::std::vector< ::std::string> GetParameterStrings() { // ::std::vector< ::std::string> v; // v.push_back("a"); // v.push_back("b"); // return v; // } // // INSTANTIATE_TEST_CASE_P(CharSequence, // StlStringTest, // ValuesIn(GetParameterStrings())); // // // This will also instantiate tests from CharTest // each with parameter values 'a' and 'b': // // ::std::list GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator ValuesIn( const Container& container) { return ValuesIn(container.begin(), container.end()); } // Values() allows generating tests from explicitly specified list of // parameters. // // Synopsis: // Values(T v1, T v2, ..., T vN) // - returns a generator producing sequences with elements v1, v2, ..., vN. // // For example, this instantiates tests from test case BarTest each // with values "one", "two", and "three": // // INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); // // This instantiates tests from test case BazTest each with values 1, 2, 3.5. // The exact type of values will depend on the type of parameter in BazTest. // // INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); // // Currently, Values() supports from 1 to 50 parameters. // template internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11) { return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12) { return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13) { return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) { return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17) { return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18) { return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { return internal::ValueArray21(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) { return internal::ValueArray22(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) { return internal::ValueArray23(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) { return internal::ValueArray24(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24); } template internal::ValueArray25 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { return internal::ValueArray25(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25); } template internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26) { return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); } template internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27) { return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); } template internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28) { return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28); } template internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29) { return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29); } template internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30); } template internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31); } template internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) { return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32); } template internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33) { return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); } template internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34) { return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); } template internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { return internal::ValueArray35(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); } template internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { return internal::ValueArray36(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36); } template internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37) { return internal::ValueArray37(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37); } template internal::ValueArray38 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) { return internal::ValueArray38(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38); } template internal::ValueArray39 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) { return internal::ValueArray39(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39); } template internal::ValueArray40 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); } template internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); } template internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42) { return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42); } template internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43) { return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43); } template internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44) { return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44); } template internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45); } template internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46); } template internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); } template internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) { return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); } template internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49) { return internal::ValueArray49(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); } template internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { return internal::ValueArray50(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50); } // Bool() allows generating tests with parameters in a set of (false, true). // // Synopsis: // Bool() // - returns a generator producing sequences with elements {false, true}. // // It is useful when testing code that depends on Boolean flags. Combinations // of multiple flags can be tested when several Bool()'s are combined using // Combine() function. // // In the following example all tests in the test case FlagDependentTest // will be instantiated twice with parameters false and true. // // class FlagDependentTest : public testing::TestWithParam { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator Bool() { return Values(false, true); } # if GTEST_HAS_COMBINE // Combine() allows the user to combine two or more sequences to produce // values of a Cartesian product of those sequences' elements. // // Synopsis: // Combine(gen1, gen2, ..., genN) // - returns a generator producing sequences with elements coming from // the Cartesian product of elements from the sequences generated by // gen1, gen2, ..., genN. The sequence elements will have a type of // tuple where T1, T2, ..., TN are the types // of elements from sequences produces by gen1, gen2, ..., genN. // // Combine can have up to 10 arguments. This number is currently limited // by the maximum number of elements in the tuple implementation used by Google // Test. // // Example: // // This will instantiate tests in test case AnimalTest each one with // the parameter values tuple("cat", BLACK), tuple("cat", WHITE), // tuple("dog", BLACK), and tuple("dog", WHITE): // // enum Color { BLACK, GRAY, WHITE }; // class AnimalTest // : public testing::TestWithParam > {...}; // // TEST_P(AnimalTest, AnimalLooksNice) {...} // // INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, // Combine(Values("cat", "dog"), // Values(BLACK, WHITE))); // // This will instantiate tests in FlagDependentTest with all variations of two // Boolean flags: // // class FlagDependentTest // : public testing::TestWithParam > { // virtual void SetUp() { // // Assigns external_flag_1 and external_flag_2 values from the tuple. // tie(external_flag_1, external_flag_2) = GetParam(); // } // }; // // TEST_P(FlagDependentTest, TestFeature1) { // // Test your code using external_flag_1 and external_flag_2 here. // } // INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, // Combine(Bool(), Bool())); // template internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7) { return internal::CartesianProductHolder7( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8) { return internal::CartesianProductHolder8( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9) { return internal::CartesianProductHolder9( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6, const Generator7& g7, const Generator8& g8, const Generator9& g9, const Generator10& g10) { return internal::CartesianProductHolder10( g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); } # endif // GTEST_HAS_COMBINE # define TEST_P(test_case_name, test_name) \ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ : public test_case_name { \ public: \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ virtual void TestBody(); \ private: \ static int AddToRegistry() { \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ #test_case_name, \ #test_name, \ new ::testing::internal::TestMetaFactory< \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ return 0; \ } \ static int gtest_registering_dummy_; \ GTEST_DISALLOW_COPY_AND_ASSIGN_(\ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ }; \ int GTEST_TEST_CLASS_NAME_(test_case_name, \ test_name)::gtest_registering_dummy_ = \ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ int gtest_##prefix##test_case_name##_dummy_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ // Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Google C++ Testing Framework definitions useful in production code. #ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ #define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // When you need to test the private or protected members of a class, // use the FRIEND_TEST macro to declare your tests as friends of the // class. For example: // // class MyClass { // private: // void MyMethod(); // FRIEND_TEST(MyClassTest, MyMethod); // }; // // class MyClassTest : public testing::Test { // // ... // }; // // TEST_F(MyClassTest, MyMethod) { // // Can call MyClass::MyMethod() here. // } #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test #endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ #include #include namespace testing { // A copyable object representing the result of a test part (i.e. an // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). // // Don't inherit from TestPartResult as its destructor is not virtual. class GTEST_API_ TestPartResult { public: // The possible outcomes of a test part (i.e. an assertion or an // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). enum Type { kSuccess, // Succeeded. kNonFatalFailure, // Failed but the test can continue. kFatalFailure // Failed and the test should be terminated. }; // C'tor. TestPartResult does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestPartResult object. TestPartResult(Type a_type, const char* a_file_name, int a_line_number, const char* a_message) : type_(a_type), file_name_(a_file_name == NULL ? "" : a_file_name), line_number_(a_line_number), summary_(ExtractSummary(a_message)), message_(a_message) { } // Gets the outcome of the test part. Type type() const { return type_; } // Gets the name of the source file where the test part took place, or // NULL if it's unknown. const char* file_name() const { return file_name_.empty() ? NULL : file_name_.c_str(); } // Gets the line in the source file where the test part took place, // or -1 if it's unknown. int line_number() const { return line_number_; } // Gets the summary of the failure message. const char* summary() const { return summary_.c_str(); } // Gets the message associated with the test part. const char* message() const { return message_.c_str(); } // Returns true iff the test part passed. bool passed() const { return type_ == kSuccess; } // Returns true iff the test part failed. bool failed() const { return type_ != kSuccess; } // Returns true iff the test part non-fatally failed. bool nonfatally_failed() const { return type_ == kNonFatalFailure; } // Returns true iff the test part fatally failed. bool fatally_failed() const { return type_ == kFatalFailure; } private: Type type_; // Gets the summary of the failure message by omitting the stack // trace in it. static std::string ExtractSummary(const char* message); // The name of the source file where the test part took place, or // "" if the source file is unknown. std::string file_name_; // The line in the source file where the test part took place, or -1 // if the line number is unknown. int line_number_; std::string summary_; // The test failure summary. std::string message_; // The test failure message. }; // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result); // An array of TestPartResult objects. // // Don't inherit from TestPartResultArray as its destructor is not // virtual. class GTEST_API_ TestPartResultArray { public: TestPartResultArray() {} // Appends the given TestPartResult to the array. void Append(const TestPartResult& result); // Returns the TestPartResult at the given index (0-based). const TestPartResult& GetTestPartResult(int index) const; // Returns the number of TestPartResult objects in the array. int size() const; private: std::vector array_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); }; // This interface knows how to report a test part result. class TestPartResultReporterInterface { public: virtual ~TestPartResultReporterInterface() {} virtual void ReportTestPartResult(const TestPartResult& result) = 0; }; namespace internal { // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a // statement generates new fatal failures. To do so it registers itself as the // current test part result reporter. Besides checking if fatal failures were // reported, it only delegates the reporting to the former result reporter. // The original result reporter is restored in the destructor. // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. class GTEST_API_ HasNewFatalFailureHelper : public TestPartResultReporterInterface { public: HasNewFatalFailureHelper(); virtual ~HasNewFatalFailureHelper(); virtual void ReportTestPartResult(const TestPartResult& result); bool has_new_fatal_failure() const { return has_new_fatal_failure_; } private: bool has_new_fatal_failure_; TestPartResultReporterInterface* original_reporter_; GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); }; } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) #ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ #define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // This header implements typed tests and type-parameterized tests. // Typed (aka type-driven) tests repeat the same test for types in a // list. You must know which types you want to test with when writing // typed tests. Here's how you do it: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { public: ... typedef std::list List; static T shared_; T value_; }; // Next, associate a list of types with the test case, which will be // repeated for each type in the list. The typedef is necessary for // the macro to parse correctly. typedef testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // TYPED_TEST_CASE(FooTest, int); // Then, use TYPED_TEST() instead of TEST_F() to define as many typed // tests for this test case as you want. TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. // Since we are inside a derived class template, C++ requires use to // visit the members of FooTest via 'this'. TypeParam n = this->value_; // To visit static members of the fixture, add the TestFixture:: // prefix. n += TestFixture::shared_; // To refer to typedefs in the fixture, add the "typename // TestFixture::" prefix. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } #endif // 0 // Type-parameterized tests are abstract test patterns parameterized // by a type. Compared with typed tests, type-parameterized tests // allow you to define the test pattern without knowing what the type // parameters are. The defined pattern can be instantiated with // different types any number of times, in any number of translation // units. // // If you are designing an interface or concept, you can define a // suite of type-parameterized tests to verify properties that any // valid implementation of the interface/concept should have. Then, // each implementation can easily instantiate the test suite to verify // that it conforms to the requirements, without having to write // similar tests repeatedly. Here's an example: #if 0 // First, define a fixture class template. It should be parameterized // by a type. Remember to derive it from testing::Test. template class FooTest : public testing::Test { ... }; // Next, declare that you will define a type-parameterized test case // (the _P suffix is for "parameterized" or "pattern", whichever you // prefer): TYPED_TEST_CASE_P(FooTest); // Then, use TYPED_TEST_P() to define as many type-parameterized tests // for this type-parameterized test case as you want. TYPED_TEST_P(FooTest, DoesBlah) { // Inside a test, refer to TypeParam to get the type parameter. TypeParam n = 0; ... } TYPED_TEST_P(FooTest, HasPropertyA) { ... } // Now the tricky part: you need to register all test patterns before // you can instantiate them. The first argument of the macro is the // test case name; the rest are the names of the tests in this test // case. REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA); // Finally, you are free to instantiate the pattern with the types you // want. If you put the above code in a header file, you can #include // it in multiple C++ source files and instantiate it multiple times. // // To distinguish different instances of the pattern, the first // argument to the INSTANTIATE_* macro is a prefix that will be added // to the actual test case name. Remember to pick unique prefixes for // different instances. typedef testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); // If the type list contains only one type, you can write that type // directly without Types<...>: // INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); #endif // 0 // Implements typed tests. #if GTEST_HAS_TYPED_TEST // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the typedef for the type parameters of the // given test case. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) # define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) # define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel< \ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ GTEST_TYPE_PARAMS_(CaseName)>::Register(\ "", #CaseName, #TestName, 0); \ template \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() #endif // GTEST_HAS_TYPED_TEST // Implements type-parameterized tests. #if GTEST_HAS_TYPED_TEST_P // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the namespace name that the type-parameterized tests for // the given type-parameterized test case are defined in. The exact // name of the namespace is subject to change without notice. # define GTEST_CASE_NAMESPACE_(TestCaseName) \ gtest_case_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Expands to the name of the variable used to remember the names of // the defined tests in the given test case. # define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ gtest_typed_test_case_p_state_##TestCaseName##_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. // // Expands to the name of the variable used to remember the names of // the registered tests in the given test case. # define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ gtest_registered_test_names_##TestCaseName##_ // The variables defined in the type-parameterized test macros are // static as typically these macros are used in a .h file that can be // #included in multiple translation units linked together. # define TYPED_TEST_CASE_P(CaseName) \ static ::testing::internal::TypedTestCasePState \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) # define TYPED_TEST_P(CaseName, TestName) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ template \ class TestName : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ __FILE__, __LINE__, #CaseName, #TestName); \ } \ template \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() # define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ namespace GTEST_CASE_NAMESPACE_(CaseName) { \ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ } \ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ __FILE__, __LINE__, #__VA_ARGS__) // The 'Types' template argument below must have spaces around it // since some compilers may choke on '>>' when passing a template // instance (e.g. Types) # define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ // Depending on the platform, different string classes are available. // On Linux, in addition to ::std::string, Google also makes use of // class ::string, which has the same interface as ::std::string, but // has a different implementation. // // The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that // ::string is available AND is a distinct type to ::std::string, or // define it to 0 to indicate otherwise. // // If the user's ::std::string and ::string are the same class due to // aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. // // If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined // heuristically. namespace testing { // Declares the flags. // This flag temporary enables the disabled tests. GTEST_DECLARE_bool_(also_run_disabled_tests); // This flag brings the debugger on an assertion failure. GTEST_DECLARE_bool_(break_on_failure); // This flag controls whether Google Test catches all test-thrown exceptions // and logs them as failures. GTEST_DECLARE_bool_(catch_exceptions); // This flag enables using colors in terminal output. Available values are // "yes" to enable colors, "no" (disable colors), or "auto" (the default) // to let Google Test decide. GTEST_DECLARE_string_(color); // This flag sets up the filter to select by name using a glob pattern // the tests to run. If the filter is not given all tests are executed. GTEST_DECLARE_string_(filter); // This flag causes the Google Test to list tests. None of the tests listed // are actually run if the flag is provided. GTEST_DECLARE_bool_(list_tests); // This flag controls whether Google Test emits a detailed XML report to a file // in addition to its normal textual output. GTEST_DECLARE_string_(output); // This flags control whether Google Test prints the elapsed time for each // test. GTEST_DECLARE_bool_(print_time); // This flag specifies the random number seed. GTEST_DECLARE_int32_(random_seed); // This flag sets how many times the tests are repeated. The default value // is 1. If the value is -1 the tests are repeating forever. GTEST_DECLARE_int32_(repeat); // This flag controls whether Google Test includes Google Test internal // stack frames in failure stack traces. GTEST_DECLARE_bool_(show_internal_stack_frames); // When this flag is specified, tests' order is randomized on every iteration. GTEST_DECLARE_bool_(shuffle); // This flag specifies the maximum number of stack frames to be // printed in a failure message. GTEST_DECLARE_int32_(stack_trace_depth); // When this flag is specified, a failed assertion will throw an // exception if exceptions are enabled, or exit the program with a // non-zero code otherwise. GTEST_DECLARE_bool_(throw_on_failure); // When this flag is set with a "host:port" string, on supported // platforms test results are streamed to the specified port on // the specified host machine. GTEST_DECLARE_string_(stream_result_to); // The upper limit for valid stack trace depths. const int kMaxStackTraceDepth = 100; namespace internal { class AssertHelper; class DefaultGlobalTestPartResultReporter; class ExecDeathTest; class NoExecDeathTest; class FinalSuccessChecker; class GTestFlagSaver; class StreamingListenerTest; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); } // namespace internal // The friend relationship of some of these classes is cyclic. // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; class TestCase; class TestInfo; class UnitTest; // A class for indicating whether an assertion was successful. When // the assertion wasn't successful, the AssertionResult object // remembers a non-empty message that describes how it failed. // // To create an instance of this class, use one of the factory functions // (AssertionSuccess() and AssertionFailure()). // // This class is useful for two purposes: // 1. Defining predicate functions to be used with Boolean test assertions // EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts // 2. Defining predicate-format functions to be // used with predicate assertions (ASSERT_PRED_FORMAT*, etc). // // For example, if you define IsEven predicate: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) // will print the message // // Value of: IsEven(Fib(5)) // Actual: false (5 is odd) // Expected: true // // instead of a more opaque // // Value of: IsEven(Fib(5)) // Actual: false // Expected: true // // in case IsEven is a simple Boolean predicate. // // If you expect your predicate to be reused and want to support informative // messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up // about half as often as positive ones in our tests), supply messages for // both success and failure cases: // // testing::AssertionResult IsEven(int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess() << n << " is even"; // else // return testing::AssertionFailure() << n << " is odd"; // } // // Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print // // Value of: IsEven(Fib(6)) // Actual: true (8 is even) // Expected: false // // NB: Predicates that support negative Boolean assertions have reduced // performance in positive ones so be careful not to use them in tests // that have lots (tens of thousands) of positive Boolean assertions. // // To use this class with EXPECT_PRED_FORMAT assertions such as: // // // Verifies that Foo() returns an even number. // EXPECT_PRED_FORMAT1(IsEven, Foo()); // // you need to define: // // testing::AssertionResult IsEven(const char* expr, int n) { // if ((n % 2) == 0) // return testing::AssertionSuccess(); // else // return testing::AssertionFailure() // << "Expected: " << expr << " is even\n Actual: it's " << n; // } // // If Foo() returns 5, you will see the following message: // // Expected: Foo() is even // Actual: it's 5 // class GTEST_API_ AssertionResult { public: // Copy constructor. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult(const AssertionResult& other); // Used in the EXPECT_TRUE/FALSE(bool_expression). explicit AssertionResult(bool success) : success_(success) {} // Returns true iff the assertion succeeded. operator bool() const { return success_; } // NOLINT // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult operator!() const; // Returns the text streamed into this AssertionResult. Test assertions // use it when they fail (i.e., the predicate's outcome doesn't match the // assertion's expectation). When nothing has been streamed into the // object, returns an empty string. const char* message() const { return message_.get() != NULL ? message_->c_str() : ""; } // TODO(vladl@google.com): Remove this after making sure no clients use it. // Deprecated; please use message() instead. const char* failure_message() const { return message(); } // Streams a custom failure message into this object. template AssertionResult& operator<<(const T& value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. AssertionResult& operator<<( ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { if (message_.get() == NULL) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Stores result of the assertion predicate. bool success_; // Stores the message describing the condition in case the expectation // construct is not satisfied with the predicate's outcome. // Referenced via a pointer to avoid taking too much stack frame space // with test assertions. internal::scoped_ptr< ::std::string> message_; GTEST_DISALLOW_ASSIGN_(AssertionResult); }; // Makes a successful assertion result. GTEST_API_ AssertionResult AssertionSuccess(); // Makes a failed assertion result. GTEST_API_ AssertionResult AssertionFailure(); // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << msg. GTEST_API_ AssertionResult AssertionFailure(const Message& msg); // The abstract class that all tests inherit from. // // In Google Test, a unit test program contains one or many TestCases, and // each TestCase contains one or many Tests. // // When you define a test using the TEST macro, you don't need to // explicitly derive from Test - the TEST macro automatically does // this for you. // // The only time you derive from Test is when defining a test fixture // to be used a TEST_F. For example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { ... } // virtual void TearDown() { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class TestInfo; // Defines types for pointers to functions that set up and tear down // a test case. typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; // The d'tor is virtual as we intend to inherit from Test. virtual ~Test(); // Sets up the stuff shared by all tests in this test case. // // Google Test will call Foo::SetUpTestCase() before running the first // test in test case Foo. Hence a sub-class can define its own // SetUpTestCase() method to shadow the one defined in the super // class. static void SetUpTestCase() {} // Tears down the stuff shared by all tests in this test case. // // Google Test will call Foo::TearDownTestCase() after running the last // test in test case Foo. Hence a sub-class can define its own // TearDownTestCase() method to shadow the one defined in the super // class. static void TearDownTestCase() {} // Returns true iff the current test has a fatal failure. static bool HasFatalFailure(); // Returns true iff the current test has a non-fatal failure. static bool HasNonfatalFailure(); // Returns true iff the current test has a (either fatal or // non-fatal) failure. static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } // Logs a property for the current test, test case, or for the entire // invocation of the test program when used outside of the context of a // test case. Only the last value for a given key is remembered. These // are public static so they can be called from utility functions that are // not members of the test fixture. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& key, int value); protected: // Creates a Test object. Test(); // Sets up the test fixture. virtual void SetUp(); // Tears down the test fixture. virtual void TearDown(); private: // Returns true iff the current test has the same fixture class as // the first test in the current test case. static bool HasSameFixtureClass(); // Runs the test after the test fixture has been set up. // // A sub-class must implement this to define the test logic. // // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. // Instead, use the TEST or TEST_F macro. virtual void TestBody() = 0; // Sets up, executes, and tears down the test. void Run(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } // Uses a GTestFlagSaver to save and restore all Google Test flags. const internal::GTestFlagSaver* const gtest_flag_saver_; // Often a user mis-spells SetUp() as Setup() and spends a long time // wondering why it is never called by Google Test. The declaration of // the following method is solely for catching such an error at // compile time: // // - The return type is deliberately chosen to be not void, so it // will be a conflict if a user declares void Setup() in his test // fixture. // // - This method is private, so it will be another compiler error // if a user calls it from his test fixture. // // DO NOT OVERRIDE THIS FUNCTION. // // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } // We disallow copying Tests. GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); }; typedef internal::TimeInMillis TimeInMillis; // A copyable object representing a user specified test property which can be // output as a key/value string pair. // // Don't inherit from TestProperty as its destructor is not virtual. class TestProperty { public: // C'tor. TestProperty does NOT have a default constructor. // Always use this constructor (with parameters) to create a // TestProperty object. TestProperty(const std::string& a_key, const std::string& a_value) : key_(a_key), value_(a_value) { } // Gets the user supplied key. const char* key() const { return key_.c_str(); } // Gets the user supplied value. const char* value() const { return value_.c_str(); } // Sets a new value, overriding the one supplied in the constructor. void SetValue(const std::string& new_value) { value_ = new_value; } private: // The key supplied by the user. std::string key_; // The value supplied by the user. std::string value_; }; // The result of a single Test. This includes a list of // TestPartResults, a list of TestProperties, a count of how many // death tests there are in the Test, and how much time it took to run // the Test. // // TestResult is not copyable. class GTEST_API_ TestResult { public: // Creates an empty TestResult. TestResult(); // D'tor. Do not inherit from TestResult. ~TestResult(); // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int total_part_count() const; // Returns the number of the test properties. int test_property_count() const; // Returns true iff the test passed (i.e. no test part failed). bool Passed() const { return !Failed(); } // Returns true iff the test failed. bool Failed() const; // Returns true iff the test fatally failed. bool HasFatalFailure() const; // Returns true iff the test has a non-fatal failure. bool HasNonfatalFailure() const; // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range // from 0 to test_property_count() - 1. If i is not in that range, aborts // the program. const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& GetTestProperty(int i) const; private: friend class TestInfo; friend class TestCase; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& test_properties() const { return test_properties_; } // Sets the elapsed time. void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } // Adds a test property to the list. The property is validated and may add // a non-fatal failure if invalid (e.g., if it conflicts with reserved // key names). If a property is already recorded for the same key, the // value will be updated, rather than storing multiple values for the same // key. xml_element specifies the element for which the property is being // recorded and is used for validation. void RecordProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a failure if the key is a reserved attribute of Google Test // testcase tags. Returns true if the property is valid. // TODO(russr): Validate attribute names are legal and human readable. static bool ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property); // Adds a test part result to the list. void AddTestPartResult(const TestPartResult& test_part_result); // Returns the death test count. int death_test_count() const { return death_test_count_; } // Increments the death test count, returning the new count. int increment_death_test_count() { return ++death_test_count_; } // Clears the test part results. void ClearTestPartResults(); // Clears the object. void Clear(); // Protects mutable state of the property vector and of owned // properties, whose values may be updated. internal::Mutex test_properites_mutex_; // The vector of TestPartResults std::vector test_part_results_; // The vector of TestProperties std::vector test_properties_; // Running count of death tests. int death_test_count_; // The elapsed time, in milliseconds. TimeInMillis elapsed_time_; // We disallow copying TestResult. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); }; // class TestResult // A TestInfo object stores the following information about a test: // // Test case name // Test name // Whether the test should be run // A function pointer that creates the test object when invoked // Test result // // The constructor of TestInfo registers itself with the UnitTest // singleton such that the RUN_ALL_TESTS() macro knows which tests to // run. class GTEST_API_ TestInfo { public: // Destructs a TestInfo object. This function is not virtual, so // don't inherit from TestInfo. ~TestInfo(); // Returns the test case name. const char* test_case_name() const { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { if (value_param_.get() != NULL) return value_param_->c_str(); return NULL; } // Returns true if this test should run, that is if the test is not // disabled (or it is disabled but the also_run_disabled_tests flag has // been specified) and its full name matches the user-specified filter. // // Google Test allows the user to filter the tests by their full names. // The full name of a test Bar in test case Foo is defined as // "Foo.Bar". Only the tests that match the filter will run. // // A filter is a colon-separated list of glob (not regex) patterns, // optionally followed by a '-' and a colon-separated list of // negative patterns (tests to exclude). A test is run if it // matches one of the positive patterns and does not match any of // the negative patterns. // // For example, *A*:Foo.* is a filter that matches any string that // contains the character 'A' or starts with "Foo.". bool should_run() const { return should_run_; } // Returns true iff this test will appear in the XML report. bool is_reportable() const { // For now, the XML report includes all tests matching the filter. // In the future, we may trim tests that are excluded because of // sharding. return matches_filter_; } // Returns the result of the test. const TestResult* result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const std::string& test_case_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // Increments the number of death tests encountered in this test so // far. int increment_death_test_count() { return result_.increment_death_test_count(); } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. const std::string test_case_name_; // Test case name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr value_param_; const internal::TypeId fixture_class_id_; // ID of the test fixture class bool should_run_; // True iff this test should run bool is_disabled_; // True iff this test is disabled bool matches_filter_; // True if this test matches the // user-specified filter. internal::TestFactoryBase* const factory_; // The factory that creates // the test object // This field is mutable and needs to be reset before running the // test for the second time. TestResult result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); }; // A test case, which consists of a vector of TestInfos. // // TestCase is not copyable. class GTEST_API_ TestCase { public: // Creates a TestCase with the given name. // // TestCase does NOT have a default constructor. Always use this // constructor to create a TestCase object. // // Arguments: // // name: name of the test case // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase(const char* name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Destructor of TestCase. virtual ~TestCase(); // Gets the name of the TestCase. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a // type-parameterized test case. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns true if any test in this test case should run. bool should_run() const { return should_run_; } // Gets the number of successful tests in this test case. int successful_test_count() const; // Gets the number of failed tests in this test case. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Get the number of tests in this test case that should run. int test_to_run_count() const; // Gets the number of all tests in this test case. int total_test_count() const; // Returns true iff the test case passed. bool Passed() const { return !Failed(); } // Returns true iff the test case failed. bool Failed() const { return failed_test_count() > 0; } // Returns the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* GetTestInfo(int i) const; // Returns the TestResult that holds test properties recorded during // execution of SetUpTestCase and TearDownTestCase. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& test_info_list() const { return test_info_list_; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* GetMutableTestInfo(int i); // Sets the should_run member. void set_should_run(bool should) { should_run_ = should; } // Adds a TestInfo to this test case. Will delete the TestInfo upon // destruction of the TestCase object. void AddTestInfo(TestInfo * test_info); // Clears the results of all tests in this test case. void ClearResult(); // Clears the results of all tests in the given test case. static void ClearTestCaseResult(TestCase* test_case) { test_case->ClearResult(); } // Runs every test in this TestCase. void Run(); // Runs SetUpTestCase() for this TestCase. This wrapper is needed // for catching exceptions thrown from SetUpTestCase(). void RunSetUpTestCase() { (*set_up_tc_)(); } // Runs TearDownTestCase() for this TestCase. This wrapper is // needed for catching exceptions thrown from TearDownTestCase(). void RunTearDownTestCase() { (*tear_down_tc_)(); } // Returns true iff test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } // Returns true iff test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } // Returns true iff the test is disabled and will be reported in the XML // report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } // Returns true iff test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } // Returns true iff this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo* test_info) { return test_info->should_run(); } // Shuffles the tests in this test case. void ShuffleTests(internal::Random* random); // Restores the test order to before the first shuffle. void UnshuffleTests(); // Name of the test case. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector test_info_list_; // Provides a level of indirection for the test list to allow easy // shuffling and restoring the test order. The i-th element in this // vector is the index of the i-th test in the shuffled test list. std::vector test_indices_; // Pointer to the function that sets up the test case. Test::SetUpTestCaseFunc set_up_tc_; // Pointer to the function that tears down the test case. Test::TearDownTestCaseFunc tear_down_tc_; // True iff any test in this test case should run. bool should_run_; // Elapsed time, in milliseconds. TimeInMillis elapsed_time_; // Holds test properties recorded during execution of SetUpTestCase and // TearDownTestCase. TestResult ad_hoc_test_result_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. The user should subclass this to define his own // environment(s). // // An Environment object does the set-up and tear-down in virtual // methods SetUp() and TearDown() instead of the constructor and the // destructor, as: // // 1. You cannot safely throw from a destructor. This is a problem // as in some cases Google Test is used where exceptions are enabled, and // we may want to implement ASSERT_* using exceptions where they are // available. // 2. You cannot use ASSERT_* directly in a constructor or // destructor. class Environment { public: // The d'tor is virtual as we need to subclass Environment. virtual ~Environment() {} // Override this to define how to set up the environment. virtual void SetUp() {} // Override this to define how to tear down the environment. virtual void TearDown() {} private: // If you see an error about overriding the following function or // about it being private, you have mis-spelled SetUp() as Setup(). struct Setup_should_be_spelled_SetUp {}; virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } }; // The interface for tracing execution of tests. The methods are organized in // the order the corresponding events are fired. class TestEventListener { public: virtual ~TestEventListener() {} // Fired before any test activity starts. virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; // Fired before each iteration of tests starts. There may be more than // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration // index, starting from 0. virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration) = 0; // Fired before environment set-up for each iteration of tests starts. virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; // Fired after environment set-up for each iteration of tests ends. virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; // Fired before the test case starts. virtual void OnTestCaseStart(const TestCase& test_case) = 0; // Fired before the test starts. virtual void OnTestStart(const TestInfo& test_info) = 0; // Fired after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; // Fired after the test ends. virtual void OnTestEnd(const TestInfo& test_info) = 0; // Fired after the test case ends. virtual void OnTestCaseEnd(const TestCase& test_case) = 0; // Fired before environment tear-down for each iteration of tests starts. virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; // Fired after environment tear-down for each iteration of tests ends. virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; // Fired after each iteration of tests finishes. virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration) = 0; // Fired after all test activities have ended. virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; }; // The convenience class for users who need to override just one or two // methods and are not concerned that a possible change to a signature of // the methods they override will not be caught during the build. For // comments about each method please see the definition of TestEventListener // above. class EmptyTestEventListener : public TestEventListener { public: virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} virtual void OnTestStart(const TestInfo& /*test_info*/) {} virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} virtual void OnTestEnd(const TestInfo& /*test_info*/) {} virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, int /*iteration*/) {} virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} }; // TestEventListeners lets users add listeners to track events in Google Test. class GTEST_API_ TestEventListeners { public: TestEventListeners(); ~TestEventListeners(); // Appends an event listener to the end of the list. Google Test assumes // the ownership of the listener (i.e. it will delete the listener when // the test program finishes). void Append(TestEventListener* listener); // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* Release(TestEventListener* listener); // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the caller and makes this // function return NULL the next time. TestEventListener* default_result_printer() const { return default_result_printer_; } // Returns the standard listener responsible for the default XML output // controlled by the --gtest_output=xml flag. Can be removed from the // listeners list by users who want to shut down the default XML output // controlled by this flag and substitute it with custom one. Note that // removing this object from the listener list with Release transfers its // ownership to the caller and makes this function return NULL the next // time. TestEventListener* default_xml_generator() const { return default_xml_generator_; } private: friend class TestCase; friend class TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; friend class internal::UnitTestImpl; // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* repeater(); // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultResultPrinter(TestEventListener* listener); // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void SetDefaultXmlGenerator(TestEventListener* listener); // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool EventForwardingEnabled() const; void SuppressEventForwarding(); // The actual list of listeners. internal::TestEventRepeater* repeater_; // Listener responsible for the standard result output. TestEventListener* default_result_printer_; // Listener responsible for the creation of the XML output file. TestEventListener* default_xml_generator_; // We disallow copying TestEventListeners. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); }; // A UnitTest consists of a vector of TestCases. // // This is a singleton class. The only instance of UnitTest is // created when UnitTest::GetInstance() is first called. This // instance is never deleted. // // UnitTest is not copyable. // // This class is thread-safe as long as the methods are called // according to their specification. class GTEST_API_ UnitTest { public: // Gets the singleton UnitTest object. The first time this method // is called, a UnitTest object is constructed and returned. // Consecutive calls will return the same object. static UnitTest* GetInstance(); // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // This method can only be called from the main thread. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. int Run() GTEST_MUST_USE_RESULT_; // Returns the working directory when the first TEST() or TEST_F() // was executed. The UnitTest object owns the string. const char* original_working_dir() const; // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // Returns the random seed used at the start of the current test run. int random_seed() const; #if GTEST_HAS_PARAM_TEST // Returns the ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_); #endif // GTEST_HAS_PARAM_TEST // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const; // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const; // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const; // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const; // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const; // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& ad_hoc_test_result() const; // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& listeners(); private: // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in // the order they were registered. After all tests in the program // have finished, all global test environments will be torn-down in // the *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // This method can only be called from the main thread. Environment* AddEnvironment(Environment* env); // Adds a TestPartResult to the current TestResult object. All // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) // eventually call this to report their results. The user code // should use the assertion macros instead of calling this directly. void AddTestPartResult(TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& value); // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i); // Accessors for the implementation object. internal::UnitTestImpl* impl() { return impl_; } const internal::UnitTestImpl* impl() const { return impl_; } // These classes and funcions are friends as they need to access private // members of UnitTest. friend class Test; friend class internal::AssertHelper; friend class internal::ScopedTrace; friend class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const std::string& message); // Creates an empty UnitTest. UnitTest(); // D'tor virtual ~UnitTest(); // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // Protects mutable state in *impl_. This is mutable as some const // methods need to lock it too. mutable internal::Mutex mutex_; // Opaque implementation object. This field is never changed once // the object is constructed. We don't mark it as const here, as // doing so will cause a warning in the constructor of UnitTest. // Mutable state in *impl_ is protected by mutex_. internal::UnitTestImpl* impl_; // We disallow copying UnitTest. GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); }; // A convenient wrapper for adding an environment for the test // program. // // You should call this before RUN_ALL_TESTS() is called, probably in // main(). If you use gtest_main, you need to call this before main() // starts for it to take effect. For example, you can define a global // variable like this: // // testing::Environment* const foo_env = // testing::AddGlobalTestEnvironment(new FooEnvironment); // // However, we strongly recommend you to write your own main() and // call AddGlobalTestEnvironment() there, as relying on initialization // of global variables makes the code harder to read and may cause // problems when you register multiple environments from different // translation units and the environments have dependencies among them // (remember that the compiler doesn't guarantee the order in which // global variables from different translation units are initialized). inline Environment* AddGlobalTestEnvironment(Environment* env) { return UnitTest::GetInstance()->AddEnvironment(env); } // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. GTEST_API_ void InitGoogleTest(int* argc, char** argv); // This overloaded version can be used in Windows programs compiled in // UNICODE mode. GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); namespace internal { // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion // (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in // the comparison, and is used to help determine the best way to // format the value. In particular, when the value is a C string // (char pointer) and the other operand is an STL string object, we // want to format the C string as a string, since we know it is // compared by value with the string object. If the value is a char // pointer but the other operand is not an STL string object, we don't // know whether the pointer is supposed to point to a NUL-terminated // string, and thus want to print it as a pointer to be safe. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // The default case. template class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. #define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ template \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(value)); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ // If a C string is compared with an STL string object, we know it's meant // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ template <> \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(value); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); #if GTEST_HAS_GLOBAL_STRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); #endif #if GTEST_HAS_GLOBAL_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); #endif #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); #endif #undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ // Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) // operand to be used in a failure message. The type (but not value) // of the other operand may affect the format. This allows us to // print a char* as a raw pointer when it is compared against another // char* or void*, and print it as a C string when it is compared // against an std::string object, for example. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4389) // Temporarily disables warning on // signed/unsigned mismatch. #endif if (expected == actual) { return AssertionSuccess(); } #ifdef _MSC_VER # pragma warning(pop) // Restores the warning state. #endif return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums // can be implicitly cast to BiggestInt. GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual); // The helper class for {ASSERT|EXPECT}_EQ. The template argument // lhs_is_null_literal is true iff the first argument to ASSERT_EQ() // is a null pointer literal. The following default implementation is // for lhs_is_null_literal being false. template class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // With this overloaded version, we allow anonymous enums to be used // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous // enums can be implicitly cast to BiggestInt. // // Even though its body looks the same as the above version, we // cannot merge the two, as it will make anonymous enums unhappy. static AssertionResult Compare(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal, like NULL, false, or 0. template <> class EqHelper { public: // We define two overloaded versions of Compare(). The first // version will be picked when the second argument to ASSERT_EQ() is // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or // EXPECT_EQ(false, a_bool). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, const T1& expected, const T2& actual, // The following line prevents this overload from being considered if T2 // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) // expands to Compare("", "", NULL, my_ptr), which requires a conversion // to match the Secret* in the other overload, which would otherwise make // this template match better. typename EnableIf::value>::type* = 0) { return CmpHelperEQ(expected_expression, actual_expression, expected, actual); } // This version will be picked when the second argument to ASSERT_EQ() is a // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( const char* expected_expression, const char* actual_expression, // We used to have a second template parameter instead of Secret*. That // template parameter would deduce to 'long', making this a better match // than the first overload even without the first overload's EnableIf. // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to // non-pointer argument" (even a deduced integral argument), so the old // implementation caused warnings in user code. Secret* /* expected (NULL) */, T* actual) { // We already know that 'expected' is a null pointer. return CmpHelperEQ(expected_expression, actual_expression, static_cast(NULL), actual); } }; // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste // of similar code. // // For each templatized helper function, we also define an overloaded // version for BiggestInt in order to reduce code bloat and allow // anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled // with gcc 4. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ template \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ }\ GTEST_API_ AssertionResult CmpHelper##op_name(\ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // Implements the helper function for {ASSERT|EXPECT}_NE GTEST_IMPL_CMP_HELPER_(NE, !=); // Implements the helper function for {ASSERT|EXPECT}_LE GTEST_IMPL_CMP_HELPER_(LE, <=); // Implements the helper function for {ASSERT|EXPECT}_LT GTEST_IMPL_CMP_HELPER_(LT, <); // Implements the helper function for {ASSERT|EXPECT}_GE GTEST_IMPL_CMP_HELPER_(GE, >=); // Implements the helper function for {ASSERT|EXPECT}_GT GTEST_IMPL_CMP_HELPER_(GT, >); #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual); // The helper function for {ASSERT|EXPECT}_STRNE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASENE. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // Helper function for *_STREQ on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual); // Helper function for *_STRNE on wide strings. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); } // namespace internal // IsSubstring() and IsNotSubstring() are intended to be used as the // first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by // themselves. They check whether needle is a substring of haystack // (NULL is considered a substring of itself only), and return an // appropriate error message when they fail. // // The {needle,haystack}_expr arguments are the stringified // expressions that generated the two real arguments. GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack); GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack); #if GTEST_HAS_STD_WSTRING GTEST_API_ AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); GTEST_API_ AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack); #endif // GTEST_HAS_STD_WSTRING namespace internal { // Helper template function for comparing floating-points. // // Template parameter: // // RawType: the raw floating-point type (either float or double) // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, const char* actual_expression, RawType expected, RawType actual) { const FloatingPoint lhs(expected), rhs(actual); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream expected_ss; expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) << expected; ::std::stringstream actual_ss; actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) << actual; return EqFailure(expected_expression, actual_expression, StringStreamToString(&expected_ss), StringStreamToString(&actual_ss), false); } // Helper function for implementing ASSERT_NEAR. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error); // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // A class that enables one to stream messages to assertion macros class GTEST_API_ AssertHelper { public: // Constructor. AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message); ~AssertHelper(); // Message assignment is a semantic trick to enable assertion // streaming; see the GTEST_MESSAGE_ macro below. void operator=(const Message& message) const; private: // We put our data in a struct so that the size of the AssertHelper class can // be as small as possible. This is important because gcc is incapable of // re-using stack space even for temporary variables, so every EXPECT_EQ // reserves stack space for another AssertHelper. struct AssertHelperData { AssertHelperData(TestPartResult::Type t, const char* srcfile, int line_num, const char* msg) : type(t), file(srcfile), line(line_num), message(msg) { } TestPartResult::Type const type; const char* const file; int const line; std::string const message; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); }; AssertHelperData* const data_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); }; } // namespace internal #if GTEST_HAS_PARAM_TEST // The pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting // from ::testing::TestWithParam, but more complicated test hierarchies // may need to inherit from Test and WithParamInterface at different levels. // // This interface has support for accessing the test parameter value via // the GetParam() method. // // Use it with one of the parameter generator defining functions, like Range(), // Values(), ValuesIn(), Bool(), and Combine(). // // class FooTest : public ::testing::TestWithParam { // protected: // FooTest() { // // Can use GetParam() here. // } // virtual ~FooTest() { // // Can use GetParam() here. // } // virtual void SetUp() { // // Can use GetParam() here. // } // virtual void TearDown { // // Can use GetParam() here. // } // }; // TEST_P(FooTest, DoesBar) { // // Can use GetParam() method here. // Foo foo; // ASSERT_TRUE(foo.DoesBar(GetParam())); // } // INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); template class WithParamInterface { public: typedef T ParamType; virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's // constructor. This member function is non-static, even though it only // references static data, to reduce the opportunity for incorrect uses // like writing 'WithParamInterface::GetParam()' for a test that // uses a fixture whose parameter type is int. const ParamType& GetParam() const { GTEST_CHECK_(parameter_ != NULL) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; return *parameter_; } private: // Sets parameter value. The caller is responsible for making sure the value // remains alive and unchanged throughout the current test. static void SetParam(const ParamType* parameter) { parameter_ = parameter; } // Static value used for accessing parameter during a test lifetime. static const ParamType* parameter_; // TestClass must be a subclass of WithParamInterface and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = NULL; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; #endif // GTEST_HAS_PARAM_TEST // Macros for indicating success/failure in test code. // ADD_FAILURE unconditionally adds a failure to the current test. // SUCCEED generates a success - it doesn't automatically make the // current test successful, as a test is only successful when it has // no failure. // // EXPECT_* verifies that a certain condition is satisfied. If not, // it behaves like ADD_FAILURE. In particular: // // EXPECT_TRUE verifies that a Boolean condition is true. // EXPECT_FALSE verifies that a Boolean condition is false. // // FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except // that they will also abort the current function on failure. People // usually want the fail-fast behavior of FAIL and ASSERT_*, but those // writing data-driven tests often find themselves using ADD_FAILURE // and EXPECT_* more. // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a nonfatal failure at the given source file location with // a generic message. #define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // Generates a fatal failure with a generic message. #define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") // Define this macro to 1 to omit the definition of FAIL(), which is a // generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_FAIL # define FAIL() GTEST_FAIL() #endif // Generates a success with a generic message. #define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") // Define this macro to 1 to omit the definition of SUCCEED(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_SUCCEED # define SUCCEED() GTEST_SUCCEED() #endif // Macros for testing exceptions. // // * {ASSERT|EXPECT}_THROW(statement, expected_exception): // Tests that the statement throws the expected exception. // * {ASSERT|EXPECT}_NO_THROW(statement): // Tests that the statement doesn't throw any exception. // * {ASSERT|EXPECT}_ANY_THROW(statement): // Tests that the statement throws an exception. #define EXPECT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) #define EXPECT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define EXPECT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) #define ASSERT_THROW(statement, expected_exception) \ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) #define ASSERT_NO_THROW(statement) \ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) #define ASSERT_ANY_THROW(statement) \ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) // Boolean assertions. Condition can be either a Boolean expression or an // AssertionResult. For more information on how to use AssertionResult with // these macros see comments on that class. #define EXPECT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_NONFATAL_FAILURE_) #define EXPECT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_NONFATAL_FAILURE_) #define ASSERT_TRUE(condition) \ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ GTEST_FATAL_FAILURE_) #define ASSERT_FALSE(condition) \ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ GTEST_FATAL_FAILURE_) // Includes the auto-generated header that implements a family of // generic predicate assertion macros. // Copyright 2006, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // This file is AUTOMATICALLY GENERATED on 10/31/2011 by command // 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! // // Implements a family of generic predicate assertion macros. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Makes sure this header is not included before gtest.h. #ifndef GTEST_INCLUDE_GTEST_GTEST_H_ # error Do not include gtest_pred_impl.h directly. Include gtest.h instead. #endif // GTEST_INCLUDE_GTEST_GTEST_H_ // This header implements a family of generic predicate assertion // macros: // // ASSERT_PRED_FORMAT1(pred_format, v1) // ASSERT_PRED_FORMAT2(pred_format, v1, v2) // ... // // where pred_format is a function or functor that takes n (in the // case of ASSERT_PRED_FORMATn) values and their source expression // text, and returns a testing::AssertionResult. See the definition // of ASSERT_EQ in gtest.h for an example. // // If you don't care about formatting, you can use the more // restrictive version: // // ASSERT_PRED1(pred, v1) // ASSERT_PRED2(pred, v1, v2) // ... // // where pred is an n-ary function or functor that returns bool, // and the values v1, v2, ..., must support the << operator for // streaming to std::ostream. // // We also define the EXPECT_* variations. // // For now we only support predicates whose arity is at most 5. // Please email googletestframework@googlegroups.com if you need // support for higher arities. // GTEST_ASSERT_ is the basic statement to which all of the assertions // in this file reduce. Don't use this in your code. #define GTEST_ASSERT_(expression, on_failure) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (const ::testing::AssertionResult gtest_ar = (expression)) \ ; \ else \ on_failure(gtest_ar.failure_message()) // Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. template AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, Pred pred, const T1& v1) { if (pred(v1)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. // Don't use this in your code. #define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ GTEST_ASSERT_(pred_format(#v1, v1), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use // this in your code. #define GTEST_PRED1_(pred, v1, on_failure)\ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ #v1, \ pred, \ v1), on_failure) // Unary predicate assertion macros. #define EXPECT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT1(pred_format, v1) \ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) #define ASSERT_PRED1(pred, v1) \ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. template AssertionResult AssertPred2Helper(const char* pred_text, const char* e1, const char* e2, Pred pred, const T1& v1, const T2& v2) { if (pred(v1, v2)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. // Don't use this in your code. #define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use // this in your code. #define GTEST_PRED2_(pred, v1, v2, on_failure)\ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ #v1, \ #v2, \ pred, \ v1, \ v2), on_failure) // Binary predicate assertion macros. #define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) #define ASSERT_PRED2(pred, v1, v2) \ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. template AssertionResult AssertPred3Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, Pred pred, const T1& v1, const T2& v2, const T3& v3) { if (pred(v1, v2, v3)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. // Don't use this in your code. #define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use // this in your code. #define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ #v1, \ #v2, \ #v3, \ pred, \ v1, \ v2, \ v3), on_failure) // Ternary predicate assertion macros. #define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) #define ASSERT_PRED3(pred, v1, v2, v3) \ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. template AssertionResult AssertPred4Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4) { if (pred(v1, v2, v3, v4)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. // Don't use this in your code. #define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use // this in your code. #define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ pred, \ v1, \ v2, \ v3, \ v4), on_failure) // 4-ary predicate assertion macros. #define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) #define ASSERT_PRED4(pred, v1, v2, v3, v4) \ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) // Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. template AssertionResult AssertPred5Helper(const char* pred_text, const char* e1, const char* e2, const char* e3, const char* e4, const char* e5, Pred pred, const T1& v1, const T2& v2, const T3& v3, const T4& v4, const T5& v5) { if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ", " << e4 << ", " << e5 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3 << "\n" << e4 << " evaluates to " << v4 << "\n" << e5 << " evaluates to " << v5; } // Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. // Don't use this in your code. #define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ on_failure) // Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use // this in your code. #define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ #v1, \ #v2, \ #v3, \ #v4, \ #v5, \ pred, \ v1, \ v2, \ v3, \ v4, \ v5), on_failure) // 5-ary predicate assertion macros. #define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) #define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) #endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ // Macros for testing equalities and inequalities. // // * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual // * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 // * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 // * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 // * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 // * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 // // When they are not, Google Test prints both the tested expressions and // their actual values. The values must be compatible built-in types, // or you will get a compiler error. By "compatible" we mean that the // values can be compared by the respective operator. // // Note: // // 1. It is possible to make a user-defined type work with // {ASSERT|EXPECT}_??(), but that requires overloading the // comparison operators and is thus discouraged by the Google C++ // Usage Guide. Therefore, you are advised to use the // {ASSERT|EXPECT}_TRUE() macro to assert that two objects are // equal. // // 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on // pointers (in particular, C strings). Therefore, if you use it // with two C strings, you are testing how their locations in memory // are related, not how their content is related. To compare two C // strings by content, use {ASSERT|EXPECT}_STR*(). // // 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to // {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you // what the actual value is when it fails, and similarly for the // other comparisons. // // 4. Do not depend on the order in which {ASSERT|EXPECT}_??() // evaluate their arguments, which is undefined. // // 5. These macros evaluate their arguments exactly once. // // Examples: // // EXPECT_NE(5, Foo()); // EXPECT_EQ(NULL, a_pointer); // ASSERT_LT(i, array_size); // ASSERT_GT(records.size(), 0) << "There is no record left."; #define EXPECT_EQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define EXPECT_NE(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) #define EXPECT_LE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define EXPECT_LT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define EXPECT_GE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define EXPECT_GT(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) #define GTEST_ASSERT_EQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ expected, actual) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define GTEST_ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define GTEST_ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define GTEST_ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ # define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE # define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE # define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT # define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE # define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // C-string Comparisons. All tests treat NULL and any non-NULL string // as different. Two NULLs are equal. // // * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 // * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 // * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case // * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case // // For wide or narrow string objects, you can use the // {ASSERT|EXPECT}_??() macros. // // Don't depend on the order in which the arguments are evaluated, // which is undefined. // // These macros evaluate their arguments exactly once. #define EXPECT_STREQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(expected, actual) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(expected, actual) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): // Tests that two double values are almost equal. // * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): // Tests that v1 and v2 are within the given distance to each other. // // Google Test uses ULP-based comparison to automatically pick a default // error bound that is appropriate for the operands. See the // FloatingPoint template class in gtest-internal.h if you are // interested in the implementation details. #define EXPECT_FLOAT_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_DOUBLE_EQ(expected, actual)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_FLOAT_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define ASSERT_DOUBLE_EQ(expected, actual)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ expected, actual) #define EXPECT_NEAR(val1, val2, abs_error)\ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) #define ASSERT_NEAR(val1, val2, abs_error)\ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ val1, val2, abs_error) // These predicate format functions work on floating-point values, and // can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. // // EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2); GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2); #if GTEST_OS_WINDOWS // Macros that test for HRESULT failure and success, these are only useful // on Windows, and rely on Windows SDK macros and APIs to compile. // // * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) // // When expr unexpectedly fails or succeeds, Google Test prints the // expected result and the actual result with both a human-readable // string representation of the error, if available, as well as the // hex result code. # define EXPECT_HRESULT_SUCCEEDED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define ASSERT_HRESULT_SUCCEEDED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) # define EXPECT_HRESULT_FAILED(expr) \ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) # define ASSERT_HRESULT_FAILED(expr) \ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) #endif // GTEST_OS_WINDOWS // Macros that execute statement and check that it doesn't generate new fatal // failures in the current thread. // // * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); // // Examples: // // EXPECT_NO_FATAL_FAILURE(Process()); // ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; // #define ASSERT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) #define EXPECT_NO_FATAL_FAILURE(statement) \ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) // Causes a trace (including the source file path, the current line // number, and the given message) to be included in every test failure // message generated by code in the current scope. The effect is // undone when the control leaves the current scope. // // The message argument can be anything streamable to std::ostream. // // In the implementation, we include the current line number as part // of the dummy variable name, thus allowing multiple SCOPED_TRACE()s // to appear in the same block - as long as they are on different // lines. #define SCOPED_TRACE(message) \ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ __FILE__, __LINE__, ::testing::Message() << (message)) // Compile-time assertion for type equality. // StaticAssertTypeEq() compiles iff type1 and type2 are // the same type. The value it returns is not interesting. // // Instead of making StaticAssertTypeEq a class template, we make it a // function template that invokes a helper class template. This // prevents a user from misusing StaticAssertTypeEq by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { (void)internal::StaticAssertTypeEqHelper(); return true; } // Defines a test. // // The first parameter is the name of the test case, and the second // parameter is the name of the test within the test case. // // The convention is to end the test case name with "Test". For // example, a test case for the Foo class can be named FooTest. // // The user should put his test code between braces after using this // macro. Example: // // TEST(FooTest, InitializesCorrectly) { // Foo foo; // EXPECT_TRUE(foo.StatusIsOK()); // } // Note that we call GetTestTypeId() instead of GetTypeId< // ::testing::Test>() here to get the type ID of testing::Test. This // is to work around a suspected linker bug when using Google Test as // a framework on Mac OS X. The bug causes GetTypeId< // ::testing::Test>() to return different values depending on whether // the call is from the Google Test framework itself or from user test // code. GetTestTypeId() is guaranteed to always return the same // value, as it always calls GetTypeId<>() from the Google Test // framework. #define GTEST_TEST(test_case_name, test_name)\ GTEST_TEST_(test_case_name, test_name, \ ::testing::Test, ::testing::internal::GetTestTypeId()) // Define this macro to 1 to omit the definition of TEST(), which // is a generic name and clashes with some other libraries. #if !GTEST_DONT_DEFINE_TEST # define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) #endif // Defines a test that uses a test fixture. // // The first parameter is the name of the test fixture class, which // also doubles as the test case name. The second parameter is the // name of the test within the test case. // // A test fixture class must be declared earlier. The user should put // his test code between braces after using this macro. Example: // // class FooTest : public testing::Test { // protected: // virtual void SetUp() { b_.AddElement(3); } // // Foo a_; // Foo b_; // }; // // TEST_F(FooTest, InitializesCorrectly) { // EXPECT_TRUE(a_.StatusIsOK()); // } // // TEST_F(FooTest, ReturnsElementCountCorrectly) { // EXPECT_EQ(0, a_.size()); // EXPECT_EQ(1, b_.size()); // } #define TEST_F(test_fixture, test_name)\ GTEST_TEST_(test_fixture, test_name, test_fixture, \ ::testing::internal::GetTypeId()) } // namespace testing // Use this function in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. // // RUN_ALL_TESTS() should be invoked after the command line has been // parsed by InitGoogleTest(). // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } #endif // GTEST_INCLUDE_GTEST_GTEST_H_ pyclustering-0.10.1.2/ccore/external/libs/000077500000000000000000000000001375753423500203455ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/linux/000077500000000000000000000000001375753423500215045ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/linux/x64/000077500000000000000000000000001375753423500221255ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/linux/x64/.linux.x64.libs000077500000000000000000000000641375753423500246400ustar00rootroot00000000000000Thrird-party libraries for linux x64 are placed herepyclustering-0.10.1.2/ccore/external/libs/linux/x86/000077500000000000000000000000001375753423500221315ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/linux/x86/.linux.x86.libs000077500000000000000000000000641375753423500246500ustar00rootroot00000000000000Thrird-party libraries for linux x86 are placed herepyclustering-0.10.1.2/ccore/external/libs/windows/000077500000000000000000000000001375753423500220375ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/windows/x64/000077500000000000000000000000001375753423500224605ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/windows/x64/.win.x64.libs000077500000000000000000000000661375753423500246330ustar00rootroot00000000000000Thrird-party libraries for windows x64 are placed herepyclustering-0.10.1.2/ccore/external/libs/windows/x86/000077500000000000000000000000001375753423500224645ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/libs/windows/x86/.win.x86.libs000077500000000000000000000000661375753423500246430ustar00rootroot00000000000000Thrird-party libraries for windows x86 are placed herepyclustering-0.10.1.2/ccore/external/src/000077500000000000000000000000001375753423500202035ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/src/gtest/000077500000000000000000000000001375753423500213315ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/external/src/gtest/gtest-all.cpp000077500000000000000000012640701375753423500237460ustar00rootroot00000000000000// Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // // Google C++ Testing Framework (Google Test) // // Sometimes it's desirable to build Google Test by compiling a single file. // This file serves this purpose. // This line ensures that gtest.h can be compiled on its own, even // when it's fused. #include "gtest/gtest.h" // The following lines pull in the real gtest *.cc files. // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // The Google C++ Testing Framework (Google Test) // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // // Utilities for testing Google Test itself and code that uses Google Test // (e.g. frameworks built on top of Google Test). #ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ namespace testing { // This helper class can be used to mock out Google Test failure reporting // so that we can test Google Test or code that builds on Google Test. // // An object of this class appends a TestPartResult object to the // TestPartResultArray object given in the constructor whenever a Google Test // failure is reported. It can either intercept only failures that are // generated in the same thread that created this object or it can intercept // all generated failures. The scope of this mock object can be controlled with // the second argument to the two arguments constructor. class GTEST_API_ ScopedFakeTestPartResultReporter : public TestPartResultReporterInterface { public: // The two possible mocking modes of this object. enum InterceptMode { INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. INTERCEPT_ALL_THREADS // Intercepts all failures. }; // The c'tor sets this object as the test part result reporter used // by Google Test. The 'result' parameter specifies where to report the // results. This reporter will only catch failures generated in the current // thread. DEPRECATED explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); // Same as above, but you can choose the interception scope of this object. ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, TestPartResultArray* result); // The d'tor restores the previous test part result reporter. virtual ~ScopedFakeTestPartResultReporter(); // Appends the TestPartResult object to the TestPartResultArray // received in the constructor. // // This method is from the TestPartResultReporterInterface // interface. virtual void ReportTestPartResult(const TestPartResult& result); private: void Init(); const InterceptMode intercept_mode_; TestPartResultReporterInterface* old_reporter_; TestPartResultArray* const result_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); }; namespace internal { // A helper class for implementing EXPECT_FATAL_FAILURE() and // EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. class GTEST_API_ SingleFailureChecker { public: // The constructor remembers the arguments. SingleFailureChecker(const TestPartResultArray* results, TestPartResult::Type type, const string& substr); ~SingleFailureChecker(); private: const TestPartResultArray* const results_; const TestPartResult::Type type_; const string substr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); }; } // namespace internal } // namespace testing // A set of macros for testing Google Test assertions or code that's expected // to generate Google Test fatal failures. It verifies that the given // statement will cause exactly one fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_FATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - 'statement' cannot reference local non-static variables or // non-static members of the current object. // - 'statement' cannot return a value. // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. The AcceptsMacroThatExpandsToUnprotectedComma test in // gtest_unittest.cc will fail to compile if we do that. #define EXPECT_FATAL_FAILURE(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do { \ class GTestExpectFatalFailureHelper {\ public:\ static void Execute() { statement; }\ };\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_failures);\ GTestExpectFatalFailureHelper::Execute();\ }\ } while (::testing::internal::AlwaysFalse()) // A macro for testing Google Test assertions or code that's expected to // generate Google Test non-fatal failures. It asserts that the given // statement will cause exactly one non-fatal Google Test failure with 'substr' // being part of the failure message. // // There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only // affects and considers failures generated in the current thread and // EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. // // 'statement' is allowed to reference local variables and members of // the current object. // // The verification of the assertion is done correctly even when the statement // throws an exception or aborts the current function. // // Known restrictions: // - You cannot stream a failure message to this macro. // // Note that even though the implementations of the following two // macros are much alike, we cannot refactor them to use a common // helper macro, due to some peculiarity in how the preprocessor // works. If we do that, the code won't compile when the user gives // EXPECT_NONFATAL_FAILURE() a statement that contains a macro that // expands to code containing an unprotected comma. The // AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc // catches that. // // For the same reason, we have to write // if (::testing::internal::AlwaysTrue()) { statement; } // instead of // GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) // to avoid an MSVC warning on unreachable code. #define EXPECT_NONFATAL_FAILURE(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ do {\ ::testing::TestPartResultArray gtest_failures;\ ::testing::internal::SingleFailureChecker gtest_checker(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_SYMBIAN # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # if GTEST_OS_WINDOWS_MINGW // MinGW has gettimeofday() but not _ftime64(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). // TODO(kenton@google.com): There are other ways to get the time on // Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW // supports these. consider using them instead. # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT #else // Assume other platforms have gettimeofday(). // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Utility functions and classes used by the Google C++ testing framework. // // Author: wan@google.com (Zhanyong Wan) // // This file contains purely Google Test's internal implementation. Please // DO NOT #INCLUDE IT IN A USER PROGRAM. #ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ #define GTEST_SRC_GTEST_INTERNAL_INL_H_ // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is // part of Google Test's implementation; otherwise it's undefined. #if !GTEST_IMPLEMENTATION_ // A user is trying to include this from his code - just say no. # error "gtest-internal-inl.h is part of Google Test's internal implementation." # error "It must not be included except by Google Test itself." #endif // GTEST_IMPLEMENTATION_ #ifndef _WIN32_WCE # include #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // NOLINT #endif // GTEST_OS_WINDOWS namespace testing { // Declares the flags. // // We don't want the users to modify this flag in the code, but want // Google Test's own unit tests to be able to access it. Therefore we // declare it here as opposed to in gtest.h. GTEST_DECLARE_bool_(death_test_use_fork); namespace internal { // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; // Names of the flags (needed for parsing Google Test flags). const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; const char kBreakOnFailureFlag[] = "break_on_failure"; const char kCatchExceptionsFlag[] = "catch_exceptions"; const char kColorFlag[] = "color"; const char kFilterFlag[] = "filter"; const char kListTestsFlag[] = "list_tests"; const char kOutputFlag[] = "output"; const char kPrintTimeFlag[] = "print_time"; const char kRandomSeedFlag[] = "random_seed"; const char kRepeatFlag[] = "repeat"; const char kShuffleFlag[] = "shuffle"; const char kStackTraceDepthFlag[] = "stack_trace_depth"; const char kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; // A valid random seed must be in [1, kMaxRandomSeed]. const int kMaxRandomSeed = 99999; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. GTEST_API_ extern bool g_help_flag; // Returns the current time in milliseconds. GTEST_API_ TimeInMillis GetTimeInMillis(); // Returns true iff Google Test should use colors in the output. GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); // Formats the given time in milliseconds as seconds. GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); // Converts the given time in milliseconds to a date string in the ISO 8601 // format, without the timezone information. N.B.: due to the use the // non-reentrant localtime() function, this function is not thread safe. Do // not use it in any code that can be called from multiple threads. GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); // Parses a string for an Int32 flag, in the form of "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. GTEST_API_ bool ParseInt32Flag( const char* str, const char* flag, Int32* value); // Returns a random seed in range [1, kMaxRandomSeed] based on the // given --gtest_random_seed flag value. inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { const unsigned int raw_seed = (random_seed_flag == 0) ? static_cast(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(kMaxRandomSeed)) + 1; return normalized_seed; } // Returns the first valid random seed after 'seed'. The behavior is // undefined if 'seed' is invalid. The seed after kMaxRandomSeed is // considered to be 1. inline int GetNextRandomSeed(int seed) { GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) << "Invalid random seed " << seed << " - must be in [1, " << kMaxRandomSeed << "]."; const int next_seed = seed + 1; return (next_seed > kMaxRandomSeed) ? 1 : next_seed; } // This class saves the values of all Google Test flags in its c'tor, and // restores them in its d'tor. class GTestFlagSaver { public: // The c'tor. GTestFlagSaver() { also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); break_on_failure_ = GTEST_FLAG(break_on_failure); catch_exceptions_ = GTEST_FLAG(catch_exceptions); color_ = GTEST_FLAG(color); death_test_style_ = GTEST_FLAG(death_test_style); death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); filter_ = GTEST_FLAG(filter); internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); list_tests_ = GTEST_FLAG(list_tests); output_ = GTEST_FLAG(output); print_time_ = GTEST_FLAG(print_time); random_seed_ = GTEST_FLAG(random_seed); repeat_ = GTEST_FLAG(repeat); shuffle_ = GTEST_FLAG(shuffle); stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); stream_result_to_ = GTEST_FLAG(stream_result_to); throw_on_failure_ = GTEST_FLAG(throw_on_failure); } // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. ~GTestFlagSaver() { GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; GTEST_FLAG(break_on_failure) = break_on_failure_; GTEST_FLAG(catch_exceptions) = catch_exceptions_; GTEST_FLAG(color) = color_; GTEST_FLAG(death_test_style) = death_test_style_; GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; GTEST_FLAG(filter) = filter_; GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; GTEST_FLAG(list_tests) = list_tests_; GTEST_FLAG(output) = output_; GTEST_FLAG(print_time) = print_time_; GTEST_FLAG(random_seed) = random_seed_; GTEST_FLAG(repeat) = repeat_; GTEST_FLAG(shuffle) = shuffle_; GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; GTEST_FLAG(stream_result_to) = stream_result_to_; GTEST_FLAG(throw_on_failure) = throw_on_failure_; } private: // Fields for saving the original values of flags. bool also_run_disabled_tests_; bool break_on_failure_; bool catch_exceptions_; std::string color_; std::string death_test_style_; bool death_test_use_fork_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; bool print_time_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; std::string stream_result_to_; bool throw_on_failure_; } GTEST_ATTRIBUTE_UNUSED_; // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded(); // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (e.g., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. GTEST_API_ bool ShouldShard(const char* total_shards_str, const char* shard_index_str, bool in_subprocess_for_death_test); // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error and // and aborts. GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. GTEST_API_ bool ShouldRunTestOnShard( int total_shards, int shard_index, int test_id); // STL container utilities. // Returns the number of elements in the given container that satisfy // the given predicate. template inline int CountIf(const Container& c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template void ForEach(const Container& c, Functor functor) { std::for_each(c.begin(), c.end(), functor); } // Returns the i-th element of the vector, or default_value if i is not // in range [0, v.size()). template inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; } // Performs an in-place shuffle of a range of the vector's elements. // 'begin' and 'end' are element indices as an STL-style range; // i.e. [begin, end) are shuffled, where 'end' == size() means to // shuffle to the end of the vector. template void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(v->size()); GTEST_CHECK_(0 <= begin && begin <= size) << "Invalid shuffle range start " << begin << ": must be in range [0, " << size << "]."; GTEST_CHECK_(begin <= end && end <= size) << "Invalid shuffle range finish " << end << ": must be in range [" << begin << ", " << size << "]."; // Fisher-Yates shuffle, from // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle for (int range_width = end - begin; range_width >= 2; range_width--) { const int last_in_range = begin + range_width - 1; const int selected = begin + random->Generate(range_width); std::swap((*v)[selected], (*v)[last_in_range]); } } // Performs an in-place shuffle of the vector's elements. template inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template static void Delete(T* x) { delete x; } // A predicate that checks the key of a TestProperty against a known key. // // TestPropertyKeyIs is copyable. class TestPropertyKeyIs { public: // Constructor. // // TestPropertyKeyIs has NO default constructor. explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } private: std::string key_; }; // Class UnitTestOptions. // // This class contains functions for processing options the user // specifies when running the tests. It has only static members. // // In most cases, the user can specify an option using either an // environment variable or a command line flag. E.g. you can set the // test filter using either GTEST_FILTER or --gtest_filter. If both // the variable and the flag are present, the latter overrides the // former. class GTEST_API_ UnitTestOptions { public: // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. static std::string GetOutputFormat(); // Returns the absolute path of the requested output file, or the // default (test_detail.xml in the original working directory) if // none was explicitly specified. static std::string GetAbsolutePathToOutputFile(); // Functions for processing the gtest_filter flag. // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. static bool PatternMatchesString(const char *pattern, const char *str); // Returns true iff the user-specified filter matches the test case // name and the test name. static bool FilterMatchesTest(const std::string &test_case_name, const std::string &test_name); #if GTEST_OS_WINDOWS // Function for supporting the gtest_catch_exception flag. // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. static int GTestShouldProcessSEH(DWORD exception_code); #endif // GTEST_OS_WINDOWS // Returns true if "name" matches the ':' separated list of glob-style // filters in "filter". static bool MatchesFilter(const std::string& name, const char* filter); }; // Returns the current application's name, removing directory path if that // is present. Used by UnitTestOptions::GetOutputFile. GTEST_API_ FilePath GetCurrentExecutableName(); // The role interface for getting the OS stack trace as a string. class OsStackTraceGetterInterface { public: OsStackTraceGetterInterface() {} virtual ~OsStackTraceGetterInterface() {} // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; // UponLeavingGTest() should be called immediately before Google Test calls // user code. It saves some information about the current stack that // CurrentStackTrace() will use to find and hide Google Test stack frames. virtual void UponLeavingGTest() = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() : caller_frame_(NULL) {} virtual string CurrentStackTrace(int max_depth, int skip_count) GTEST_LOCK_EXCLUDED_(mutex_); virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: Mutex mutex_; // protects all internal state // We save the stack frame below the frame that calls user code. // We do this because the address of the frame immediately below // the user code changes between the call to UponLeavingGTest() // and any calls to CurrentStackTrace() from within the user code. void* caller_frame_; GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; std::string message; }; // This is the default global test part result reporter used in UnitTestImpl. // This class should only be used by UnitTestImpl. class DefaultGlobalTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. Reports the test part // result in the current test. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); }; // This is the default per thread test part result reporter used in // UnitTestImpl. This class should only be used by UnitTestImpl. class DefaultPerThreadTestPartResultReporter : public TestPartResultReporterInterface { public: explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); // Implements the TestPartResultReporterInterface. The implementation just // delegates to the current global test part result reporter of *unit_test_. virtual void ReportTestPartResult(const TestPartResult& result); private: UnitTestImpl* const unit_test_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); }; // The private implementation of the UnitTest class. We don't protect // the methods under a mutex, as this class is not accessible by a // user and the UnitTest class that delegates work to this class does // proper locking. class GTEST_API_ UnitTestImpl { public: explicit UnitTestImpl(UnitTest* parent); virtual ~UnitTestImpl(); // There are two different ways to register your own TestPartResultReporter. // You can register your own repoter to listen either only for test results // from the current thread or for results from all threads. // By default, each per-thread test result repoter just passes a new // TestPartResult to the global test result reporter, which registers the // test part result for the currently running test. // Returns the global test part result reporter. TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); // Sets the global test part result reporter. void SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter); // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); // Sets the test part result reporter for the current thread. void SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter); // Gets the number of successful test cases. int successful_test_case_count() const; // Gets the number of failed test cases. int failed_test_case_count() const; // Gets the number of all test cases. int total_test_case_count() const; // Gets the number of all test cases that contain at least one test // that should run. int test_case_to_run_count() const; // Gets the number of successful tests. int successful_test_count() const; // Gets the number of failed tests. int failed_test_count() const; // Gets the number of disabled tests that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_test_count() const; // Gets the number of all tests. int total_test_count() const; // Gets the number of tests that should run. int test_to_run_count() const; // Gets the time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // Gets the elapsed time, in milliseconds. TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns true iff the unit test passed (i.e. all test cases passed). bool Passed() const { return !Failed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool Failed() const { return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* GetTestCase(int i) const { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[i]; } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* GetMutableTestCase(int i) { const int index = GetElementOr(test_case_indices_, i, -1); return index < 0 ? NULL : test_cases_[index]; } // Provides access to the event listener list. TestEventListeners* listeners() { return &listeners_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* current_test_result(); // Returns the TestResult for the ad hoc test. const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter // are the same; otherwise, deletes the old getter and makes the // input the current getter. void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* os_stack_trace_getter(); // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc); // Adds a TestInfo to the unit test. // // Arguments: // // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // test_info: the TestInfo object void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, TestInfo* test_info) { // In order to support thread-safe death tests, we need to // remember the original working directory when the test program // was first invoked. We cannot do this in RUN_ALL_TESTS(), as // the user may have changed the current directory before calling // RUN_ALL_TESTS(). Therefore we capture the current directory in // AddTestInfo(), which is called to register a TEST or TEST_F // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); GTEST_CHECK_(!original_working_dir_.IsEmpty()) << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), test_info->type_param(), set_up_tc, tear_down_tc)->AddTestInfo(test_info); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { return parameterized_test_registry_; } #endif // GTEST_HAS_PARAM_TEST // Sets the TestCase object for the test that's currently running. void set_current_test_case(TestCase* a_current_test_case) { current_test_case_ = a_current_test_case; } // Sets the TestInfo object for the test that's currently running. If // current_test_info is NULL, the assertion results will be stored in // ad_hoc_test_result_. void set_current_test_info(TestInfo* a_current_test_info) { current_test_info_ = a_current_test_info; } // Registers all parameterized tests defined using TEST_P and // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter // combination. This method can be called more then once; it has guards // protecting from registering the tests more then once. If // value-parameterized tests are disabled, RegisterParameterizedTests is // present but does nothing. void RegisterParameterizedTests(); // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, this test is considered to be failed, but // the rest of the tests will still be run. bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); } // Clears the results of ad-hoc test assertions. void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test or a test case, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); enum ReactionToSharding { HONOR_SHARDING_PROTOCOL, IGNORE_SHARDING_PROTOCOL }; // Matches the full name of each test against the user-specified // filter to decide whether the test should run, then records the // result in each TestCase and TestInfo object. // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests // based on sharding variables in the environment. // Returns the number of tests that should run. int FilterTests(ReactionToSharding shard_tests); // Prints the names of the tests matching the user-specified filter flag. void ListTestsMatchingFilter(); const TestCase* current_test_case() const { return current_test_case_; } TestInfo* current_test_info() { return current_test_info_; } const TestInfo* current_test_info() const { return current_test_info_; } // Returns the vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& gtest_trace_stack() const { return gtest_trace_stack_.get(); } #if GTEST_HAS_DEATH_TEST void InitDeathTestSubprocessControlInfo() { internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); } // Returns a pointer to the parsed --gtest_internal_run_death_test // flag, or NULL if that flag was not specified. // This information is useful only in a death test child process. // Must not be called before a call to InitGoogleTest. const InternalRunDeathTestFlag* internal_run_death_test_flag() const { return internal_run_death_test_flag_.get(); } // Returns a pointer to the current death test factory. internal::DeathTestFactory* death_test_factory() { return death_test_factory_.get(); } void SuppressTestEventsIfInSubprocess(); friend class ReplaceDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST // Initializes the event listener performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Initializes the event listener for streaming test results to a socket. // Must not be called before InitGoogleTest. void ConfigureStreamingOutput(); #endif // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void PostFlagParsingInit(); // Gets the random seed used at the start of the current test iteration. int random_seed() const { return random_seed_; } // Gets the random number generator. internal::Random* random() { return &random_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void ShuffleTests(); // Restores the test cases and tests to their order before the first shuffle. void UnshuffleTests(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment // UnitTest::Run() starts. bool catch_exceptions() const { return catch_exceptions_; } private: friend class ::testing::UnitTest; // Used by UnitTest::Run() to capture the state of // GTEST_FLAG(catch_exceptions) at the moment it starts. void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // The UnitTest object that owns this implementation object. UnitTest* const parent_; // The working directory when the first TEST() or TEST_F() was // executed. internal::FilePath original_working_dir_; // The default test part result reporters. DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; DefaultPerThreadTestPartResultReporter default_per_thread_test_part_result_reporter_; // Points to (but doesn't own) the global test part result reporter. TestPartResultReporterInterface* global_test_part_result_repoter_; // Protects read and write access to global_test_part_result_reporter_. internal::Mutex global_test_part_result_reporter_mutex_; // Points to (but doesn't own) the per-thread test part result reporter. internal::ThreadLocal per_thread_test_part_result_reporter_; // The vector of environments that need to be set-up/torn-down // before/after the tests are run. std::vector environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector test_cases_; // Provides a level of indirection for the test case list to allow // easy shuffling and restoring the test case order. The i-th // element of this vector is the index of the i-th test case in the // shuffled order. std::vector test_case_indices_; #if GTEST_HAS_PARAM_TEST // ParameterizedTestRegistry object used to register value-parameterized // tests. internal::ParameterizedTestCaseRegistry parameterized_test_registry_; // Indicates whether RegisterParameterizedTests() has been called already. bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST // Index of the last death test case registered. Initially -1. int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. // When no test is running, this is set to NULL and Google Test // stores assertion results in ad_hoc_test_result_. Initially NULL. TestCase* current_test_case_; // This points to the TestInfo for the currently running test. It // changes as Google Test goes through one test after another. When // no test is running, this is set to NULL and Google Test stores // assertion results in ad_hoc_test_result_. Initially NULL. TestInfo* current_test_info_; // Normally, a user only writes assertions inside a TEST or TEST_F, // or inside a function called by a TEST or TEST_F. Since Google // Test keeps track of which test is current running, it can // associate such an assertion with the test it belongs to. // // If an assertion is encountered when no TEST or TEST_F is running, // Google Test attributes the assertion result to an imaginary "ad hoc" // test, and records the result in ad_hoc_test_result_. TestResult ad_hoc_test_result_; // The list of event listeners that can be used to track events inside // Google Test. TestEventListeners listeners_; // The OS stack trace getter. Will be deleted when the UnitTest // object is destructed. By default, an OsStackTraceGetter is used, // but the user can set this field to use a custom getter if that is // desired. OsStackTraceGetterInterface* os_stack_trace_getter_; // True iff PostFlagParsingInit() has been called. bool post_flag_parse_init_performed_; // The random number seed used at the beginning of the test run. int random_seed_; // Our random number generator. internal::Random random_; // The time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp_; // How long the test took to run, in milliseconds. TimeInMillis elapsed_time_; #if GTEST_HAS_DEATH_TEST // The decomposed components of the gtest_internal_run_death_test flag, // parsed when RUN_ALL_TESTS is called. internal::scoped_ptr internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() // starts. bool catch_exceptions_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } #if GTEST_USES_SIMPLE_RE // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(char ch); GTEST_API_ bool IsValidEscape(char ch); GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); GTEST_API_ bool ValidateRegex(const char* regex); GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); GTEST_API_ bool MatchRepetitionAndRegexAtHead( bool escaped, char ch, char repeat, const char* regex, const char* str); GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); #endif // GTEST_USES_SIMPLE_RE // Parses the command line for Google Test flags, without initializing // other parts of Google Test. GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); #if GTEST_HAS_DEATH_TEST // Returns the message describing the last system error, regardless of the // platform. GTEST_API_ std::string GetLastErrnoDescription(); # if GTEST_OS_WINDOWS // Provides leak-safe Windows kernel handle ownership. class AutoHandle { public: AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} explicit AutoHandle(HANDLE handle) : handle_(handle) {} ~AutoHandle() { Reset(); } HANDLE Get() const { return handle_; } void Reset() { Reset(INVALID_HANDLE_VALUE); } void Reset(HANDLE handle) { if (handle != handle_) { if (handle_ != INVALID_HANDLE_VALUE) ::CloseHandle(handle_); handle_ = handle; } } private: HANDLE handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; # endif // GTEST_OS_WINDOWS // Attempts to parse a string into a positive integer pointed to by the // number parameter. Returns true if that is possible. // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use // it here. template bool ParseNaturalNumber(const ::std::string& str, Integer* number) { // Fail fast if the given string does not begin with a digit; // this bypasses strtoXXX's "optional leading whitespace and plus // or minus sign" semantics, which are undesirable here. if (str.empty() || !IsDigit(str[0])) { return false; } errno = 0; char* end; // BiggestConvertible is the largest integer type that system-provided // string-to-number conversion routines can return. # if GTEST_OS_WINDOWS && !defined(__GNUC__) // MSVC and C++ Builder define __int64 instead of the standard long long. typedef unsigned __int64 BiggestConvertible; const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); # else typedef unsigned long long BiggestConvertible; // NOLINT const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); # endif // GTEST_OS_WINDOWS && !defined(__GNUC__) const bool parse_success = *end == '\0' && errno == 0; // TODO(vladl@google.com): Convert this to compile time assertion when it is // available. GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); const Integer result = static_cast(parsed); if (parse_success && static_cast(result) == parsed) { *number = result; return true; } return false; } #endif // GTEST_HAS_DEATH_TEST // TestResult contains some private methods that should be hidden from // Google Test user but are required for testing. This class allow our tests // to access them. // // This class is supplied only for the purpose of testing Google Test's own // constructs. Do not use it in user tests, either directly or indirectly. class TestResultAccessor { public: static void RecordProperty(TestResult* test_result, const std::string& xml_element, const TestProperty& property) { test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. class StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { public: virtual ~AbstractSocketWriter() {} // Sends a string to the socket. virtual void Send(const string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. void SendLn(const string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: SocketWriter(const string& host, const string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } virtual ~SocketWriter() { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. virtual void Send(const string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; const int len = static_cast(message.length()); if (write(sockfd_, message.c_str(), len) != len) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; } } private: // Creates a client socket and connects to the server. void MakeConnection(); // Closes the socket. void CloseConnection() { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; close(sockfd_); sockfd_ = -1; } int sockfd_; // socket file descriptor const string host_name_; const string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". static string UrlEncode(const char* str); StreamingListener(const string& host, const string& port) : socket_writer_(new SocketWriter(host, port)) { Start(); } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } void OnTestProgramStart(const UnitTest& /* unit_test */) { SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); // Notify the streaming server to stop. socket_writer_->CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } void OnTestCaseStart(const TestCase& test_case) { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } void OnTestCaseEnd(const TestCase& test_case) { SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + "ms"); } void OnTestStart(const TestInfo& test_info) { SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); } private: // Sends the given message and a newline to the socket. void SendLn(const string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener #endif // GTEST_CAN_STREAM_RESULTS_ } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ #undef GTEST_IMPLEMENTATION_ #if GTEST_OS_WINDOWS # define vsnprintf _vsnprintf #endif // GTEST_OS_WINDOWS namespace testing { using internal::CountIf; using internal::ForEach; using internal::GetElementOr; using internal::Shuffle; // Constants. // A test whose test case name or test name matches this filter is // disabled and not run. static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; // A test case whose name matches this filter is considered a death // test case and will be run before test cases whose name doesn't // match this filter. static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; // A test filter that matches everything. static const char kUniversalFilter[] = "*"; // The default output file for XML output. static const char kDefaultOutputFile[] = "test_detail.xml"; // The environment variable name for the test shard index. static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; // The environment variable name for the total number of test shards. static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; // The environment variable name for the test shard status file. static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; namespace internal { // The text used in failure messages to indicate the start of the // stack trace. const char kStackTraceMarker[] = "\nStack trace:\n"; // g_help_flag is true iff the --help flag or an equivalent form is // specified on the command line. bool g_help_flag = false; } // namespace internal static const char* GetDefaultFilter() { return kUniversalFilter; } GTEST_DEFINE_bool_( also_run_disabled_tests, internal::BoolFromGTestEnv("also_run_disabled_tests", false), "Run disabled tests too, in addition to the tests normally being run."); GTEST_DEFINE_bool_( break_on_failure, internal::BoolFromGTestEnv("break_on_failure", false), "True iff a failed assertion should be a debugger break-point."); GTEST_DEFINE_bool_( catch_exceptions, internal::BoolFromGTestEnv("catch_exceptions", true), "True iff " GTEST_NAME_ " should catch exceptions and treat them as test failures."); GTEST_DEFINE_string_( color, internal::StringFromGTestEnv("color", "auto"), "Whether to use colors in the output. Valid values: yes, no, " "and auto. 'auto' means to use colors if the output is " "being sent to a terminal and the TERM environment variable " "is set to a terminal type that supports colors."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "A colon-separated list of glob (not regex) patterns " "for filtering the tests to run, optionally followed by a " "'-' and a : separated list of negative patterns (tests to " "exclude). A test is run if it matches one of the positive " "patterns and does not match any of the negative patterns."); GTEST_DEFINE_bool_(list_tests, false, "List all tests without running them."); GTEST_DEFINE_string_( output, internal::StringFromGTestEnv("output", ""), "A format (currently must be \"xml\"), optionally followed " "by a colon and an output file name or directory. A directory " "is indicated by a trailing pathname separator. " "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " "If a directory is specified, output files will be created " "within that directory, with file-names based on the test " "executable's name and, if necessary, made unique by adding " "digits."); GTEST_DEFINE_bool_( print_time, internal::BoolFromGTestEnv("print_time", true), "True iff " GTEST_NAME_ " should display elapsed time in text output."); GTEST_DEFINE_int32_( random_seed, internal::Int32FromGTestEnv("random_seed", 0), "Random number seed to use when shuffling test orders. Must be in range " "[1, 99999], or 0 to use a seed based on the current time."); GTEST_DEFINE_int32_( repeat, internal::Int32FromGTestEnv("repeat", 1), "How many times to repeat each test. Specify a negative number " "for repeating forever. Useful for shaking out flaky tests."); GTEST_DEFINE_bool_( show_internal_stack_frames, false, "True iff " GTEST_NAME_ " should include internal stack frames when " "printing test failure stack traces."); GTEST_DEFINE_bool_( shuffle, internal::BoolFromGTestEnv("shuffle", false), "True iff " GTEST_NAME_ " should randomize tests' order on every run."); GTEST_DEFINE_int32_( stack_trace_depth, internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), "The maximum number of stack frames to print when an " "assertion fails. The valid range is 0 through 100, inclusive."); GTEST_DEFINE_string_( stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); GTEST_DEFINE_bool_( throw_on_failure, internal::BoolFromGTestEnv("throw_on_failure", false), "When this flag is specified, a failed assertion will throw an exception " "if exceptions are enabled or exit the program with a non-zero code " "otherwise."); namespace internal { // Generates a random number from [0, range), using a Linear // Congruential Generator (LCG). Crashes if 'range' is 0 or greater // than kMaxRange. UInt32 Random::Generate(UInt32 range) { // These constants are the same as are used in glibc's rand(3). state_ = (1103515245U*state_ + 12345U) % kMaxRange; GTEST_CHECK_(range > 0) << "Cannot generate a number in the range [0, 0)."; GTEST_CHECK_(range <= kMaxRange) << "Generation of a number in [0, " << range << ") was requested, " << "but this can only generate numbers in [0, " << kMaxRange << ")."; // Converting via modulus introduces a bit of downward bias, but // it's simple, and a linear congruential generator isn't too good // to begin with. return state_ % range; } // GTestIsInitialized() returns true iff the user has initialized // Google Test. Useful for catching the user mistake of not initializing // Google Test before calling RUN_ALL_TESTS(). // // A user must call testing::InitGoogleTest() to initialize Google // Test. g_init_gtest_count is set to the number of times // InitGoogleTest() has been called. We don't protect this variable // under a mutex as it is only accessed in the main thread. GTEST_API_ int g_init_gtest_count = 0; static bool GTestIsInitialized() { return g_init_gtest_count != 0; } // Iterates over a vector of TestCases, keeping a running sum of the // results of calling a given int-returning method on each. // Returns the sum. static int SumOverTestCaseList(const std::vector& case_list, int (TestCase::*method)() const) { int sum = 0; for (size_t i = 0; i < case_list.size(); i++) { sum += (case_list[i]->*method)(); } return sum; } // Returns true iff the test case passed. static bool TestCasePassed(const TestCase* test_case) { return test_case->should_run() && test_case->Passed(); } // Returns true iff the test case failed. static bool TestCaseFailed(const TestCase* test_case) { return test_case->should_run() && test_case->Failed(); } // Returns true iff test_case contains at least one test that should // run. static bool ShouldRunTestCase(const TestCase* test_case) { return test_case->should_run(); } // AssertHelper constructor. AssertHelper::AssertHelper(TestPartResult::Type type, const char* file, int line, const char* message) : data_(new AssertHelperData(type, file, line, message)) { } AssertHelper::~AssertHelper() { delete data_; } // Message assignment, for assertion streaming support. void AssertHelper::operator=(const Message& message) const { UnitTest::GetInstance()-> AddTestPartResult(data_->type, data_->file, data_->line, AppendUserMessage(data_->message, message), UnitTest::GetInstance()->impl() ->CurrentOsStackTraceExceptTop(1) // Skips the stack frame for this function itself. ); // NOLINT } // Mutex for linked pointers. GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // Application pathname gotten in InitGoogleTest. std::string g_executable_path; // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(g_executable_path).RemoveExtension("exe")); #else result.Set(FilePath(g_executable_path)); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return std::string(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : std::string(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return ""; const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).string(); internal::FilePath output_name(colon + 1); if (!output_name.IsAbsolutePath()) // TODO(wan@google.com): on Windows \some\path is not an absolute // path (as its meaning depends on the current drive), yet the // following logic for turning it into an absolute path is wrong. // Fix it. output_name = internal::FilePath::ConcatPaths( internal::FilePath(UnitTest::GetInstance()->original_working_dir()), internal::FilePath(colon + 1)); if (!output_name.IsDirectory()) return output_name.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.string(); } // Returns true iff the wildcard pattern matches the string. The // first ':' or '\0' character in pattern marks the end of it. // // This recursive algorithm isn't very efficient, but is clear and // works well enough for matching test names, which are short. bool UnitTestOptions::PatternMatchesString(const char *pattern, const char *str) { switch (*pattern) { case '\0': case ':': // Either ':' or '\0' marks the end of the pattern. return *str == '\0'; case '?': // Matches any single character. return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); case '*': // Matches any string (possibly empty) of characters. return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str); default: // Non-special character. Matches itself. return *pattern == *str && PatternMatchesString(pattern + 1, str + 1); } } bool UnitTestOptions::MatchesFilter( const std::string& name, const char* filter) { const char *cur_pattern = filter; for (;;) { if (PatternMatchesString(cur_pattern, name.c_str())) { return true; } // Finds the next pattern in the filter. cur_pattern = strchr(cur_pattern, ':'); // Returns if no more pattern can be found. if (cur_pattern == NULL) { return false; } // Skips the pattern separater (the ':' character). cur_pattern++; } } // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const std::string &test_name) { const std::string& full_name = test_case_name + "." + test_name.c_str(); // Split --gtest_filter at '-', if there is one, to separate into // positive filter and negative filter portions const char* const p = GTEST_FLAG(filter).c_str(); const char* const dash = strchr(p, '-'); std::string positive; std::string negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { positive = std::string(p, dash); // Everything up to the dash negative = std::string(dash + 1); // Everything after the dash if (positive.empty()) { // Treat '-test1' as the same as '*-test1' positive = kUniversalFilter; } } // A filter is a colon-separated list of patterns. It matches a // test if any pattern in it matches the test. return (MatchesFilter(full_name, positive.c_str()) && !MatchesFilter(full_name, negative.c_str())); } #if GTEST_HAS_SEH // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. // This function is useful as an __except condition. int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { // Google Test should handle a SEH exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // // SEH exception code for C++ exceptions. // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; bool should_handle = true; if (!GTEST_FLAG(catch_exceptions)) should_handle = false; else if (exception_code == EXCEPTION_BREAKPOINT) should_handle = false; else if (exception_code == kCxxExceptionCode) should_handle = false; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_HAS_SEH } // namespace internal // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. Intercepts only failures from the current thread. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( TestPartResultArray* result) : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), result_(result) { Init(); } // The c'tor sets this object as the test part result reporter used by // Google Test. The 'result' parameter specifies where to report the // results. ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( InterceptMode intercept_mode, TestPartResultArray* result) : intercept_mode_(intercept_mode), result_(result) { Init(); } void ScopedFakeTestPartResultReporter::Init() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { old_reporter_ = impl->GetGlobalTestPartResultReporter(); impl->SetGlobalTestPartResultReporter(this); } else { old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); impl->SetTestPartResultReporterForCurrentThread(this); } } // The d'tor restores the test part result reporter used by Google Test // before. ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); if (intercept_mode_ == INTERCEPT_ALL_THREADS) { impl->SetGlobalTestPartResultReporter(old_reporter_); } else { impl->SetTestPartResultReporterForCurrentThread(old_reporter_); } } // Increments the test part result count and remembers the result. // This method is from the TestPartResultReporterInterface interface. void ScopedFakeTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { result_->Append(result); } namespace internal { // Returns the type ID of ::testing::Test. We should always call this // instead of GetTypeId< ::testing::Test>() to get the type ID of // testing::Test. This is to work around a suspected linker bug when // using Google Test as a framework on Mac OS X. The bug causes // GetTypeId< ::testing::Test>() to return different values depending // on whether the call is from the Google Test framework itself or // from user test code. GetTestTypeId() is guaranteed to always // return the same value, as it always calls GetTypeId<>() from the // gtest.cc, which is within the Google Test framework. TypeId GetTestTypeId() { return GetTypeId(); } // The value of GetTestTypeId() as seen from within the Google Test // library. This is solely for testing GetTestTypeId(). extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); // This predicate-formatter checks that 'results' contains a test part // failure of the given type and that the failure message contains the // given substring. AssertionResult HasOneFailure(const char* /* results_expr */, const char* /* type_expr */, const char* /* substr_expr */, const TestPartResultArray& results, TestPartResult::Type type, const string& substr) { const std::string expected(type == TestPartResult::kFatalFailure ? "1 fatal failure" : "1 non-fatal failure"); Message msg; if (results.size() != 1) { msg << "Expected: " << expected << "\n" << " Actual: " << results.size() << " failures"; for (int i = 0; i < results.size(); i++) { msg << "\n" << results.GetTestPartResult(i); } return AssertionFailure() << msg; } const TestPartResult& r = results.GetTestPartResult(0); if (r.type() != type) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } if (strstr(r.message(), substr.c_str()) == NULL) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; } return AssertionSuccess(); } // The constructor of SingleFailureChecker remembers where to look up // test part results, what type of failure we expect, and what // substring the failure message should contain. SingleFailureChecker:: SingleFailureChecker( const TestPartResultArray* results, TestPartResult::Type type, const string& substr) : results_(results), type_(type), substr_(substr) {} // The destructor of SingleFailureChecker verifies that the given // TestPartResultArray contains exactly one failure that has the given // type and contains the given substring. If that's not the case, a // non-fatal failure will be generated. SingleFailureChecker::~SingleFailureChecker() { EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); } DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultGlobalTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->current_test_result()->AddTestPartResult(result); unit_test_->listeners()->repeater()->OnTestPartResult(result); } DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( UnitTestImpl* unit_test) : unit_test_(unit_test) {} void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( const TestPartResult& result) { unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); } // Returns the global test part result reporter. TestPartResultReporterInterface* UnitTestImpl::GetGlobalTestPartResultReporter() { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); return global_test_part_result_repoter_; } // Sets the global test part result reporter. void UnitTestImpl::SetGlobalTestPartResultReporter( TestPartResultReporterInterface* reporter) { internal::MutexLock lock(&global_test_part_result_reporter_mutex_); global_test_part_result_repoter_ = reporter; } // Returns the test part result reporter for the current thread. TestPartResultReporterInterface* UnitTestImpl::GetTestPartResultReporterForCurrentThread() { return per_thread_test_part_result_reporter_.get(); } // Sets the test part result reporter for the current thread. void UnitTestImpl::SetTestPartResultReporterForCurrentThread( TestPartResultReporterInterface* reporter) { per_thread_test_part_result_reporter_.set(reporter); } // Gets the number of successful test cases. int UnitTestImpl::successful_test_case_count() const { return CountIf(test_cases_, TestCasePassed); } // Gets the number of failed test cases. int UnitTestImpl::failed_test_case_count() const { return CountIf(test_cases_, TestCaseFailed); } // Gets the number of all test cases. int UnitTestImpl::total_test_case_count() const { return static_cast(test_cases_.size()); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTestImpl::test_case_to_run_count() const { return CountIf(test_cases_, ShouldRunTestCase); } // Gets the number of successful tests. int UnitTestImpl::successful_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); } // Gets the number of failed tests. int UnitTestImpl::failed_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_disabled_test_count); } // Gets the number of disabled tests. int UnitTestImpl::disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); } // Gets the number of tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); } // Gets the number of all tests. int UnitTestImpl::total_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); } // Gets the number of tests that should run. int UnitTestImpl::test_to_run_count() const { return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // CurrentOsStackTraceExceptTop(1), Foo() will be included in the // trace but Bar() and CurrentOsStackTraceExceptTop() won't. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { (void)skip_count; return ""; } // Returns the current time in milliseconds. TimeInMillis GetTimeInMillis() { #if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) // Difference between 1970-01-01 and 1601-01-01 in milliseconds. // http://analogous.blogspot.com/2005/04/epoch.html const TimeInMillis kJavaEpochToWinFileTimeDelta = static_cast(116444736UL) * 100000UL; const DWORD kTenthMicrosInMilliSecond = 10000; SYSTEMTIME now_systime; FILETIME now_filetime; ULARGE_INTEGER now_int64; // TODO(kenton@google.com): Shouldn't this just use // GetSystemTimeAsFileTime()? GetSystemTime(&now_systime); if (SystemTimeToFileTime(&now_systime, &now_filetime)) { now_int64.LowPart = now_filetime.dwLowDateTime; now_int64.HighPart = now_filetime.dwHighDateTime; now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - kJavaEpochToWinFileTimeDelta; return now_int64.QuadPart; } return 0; #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ __timeb64 now; # ifdef _MSC_VER // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996. _ftime64(&now); # pragma warning(pop) // Restores the warning state. # else _ftime64(&now); # endif // _MSC_VER return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; #else # error "Don't know how to get the current time on your system." #endif } // Utilities // class String. #if GTEST_OS_WINDOWS_MOBILE // Creates a UTF-16 wide string from the given ANSI string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the wide string, or NULL if the // input is NULL. LPCWSTR String::AnsiToUtf16(const char* ansi) { if (!ansi) return NULL; const int length = strlen(ansi); const int unicode_length = MultiByteToWideChar(CP_ACP, 0, ansi, length, NULL, 0); WCHAR* unicode = new WCHAR[unicode_length + 1]; MultiByteToWideChar(CP_ACP, 0, ansi, length, unicode, unicode_length); unicode[unicode_length] = 0; return unicode; } // Creates an ANSI string from the given wide string, allocating // memory using new. The caller is responsible for deleting the return // value using delete[]. Returns the ANSI string, or NULL if the // input is NULL. const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { if (!utf16_str) return NULL; const int ansi_length = WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, NULL, 0, NULL, NULL); char* ansi = new char[ansi_length + 1]; WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, ansi, ansi_length, NULL, NULL); ansi[ansi_length] = 0; return ansi; } #endif // GTEST_OS_WINDOWS_MOBILE // Compares two C strings. Returns true iff they have the same content. // // Unlike strcmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::CStringEquals(const char * lhs, const char * rhs) { if ( lhs == NULL ) return rhs == NULL; if ( rhs == NULL ) return false; return strcmp(lhs, rhs) == 0; } #if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING // Converts an array of wide chars to a narrow string using the UTF-8 // encoding, and streams the result to the given Message object. static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, Message* msg) { for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING } // namespace internal // Constructs an empty Message. // We allocate the stringstream separately because otherwise each use of // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's // stack frame leading to huge stack frames in some cases; gcc does not reuse // the stack space. Message::Message() : ss_(new ::std::stringstream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& Message::operator <<(wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } #if GTEST_HAS_STD_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::std::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_GLOBAL_WSTRING // Converts the given wide string to a narrow string using the UTF-8 // encoding, and streams the result to this Message object. Message& Message::operator <<(const ::wstring& wstr) { internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); return *this; } #endif // GTEST_HAS_GLOBAL_WSTRING // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { return internal::StringStreamToString(ss_.get()); } // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new ::std::string(*other.message_) : static_cast< ::std::string*>(NULL)) { } // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. AssertionResult AssertionResult::operator!() const { AssertionResult negation(!success_); if (message_.get() != NULL) negation << *message_; return negation; } // Makes a successful assertion result. AssertionResult AssertionSuccess() { return AssertionResult(true); } // Makes a failed assertion result. AssertionResult AssertionFailure() { return AssertionResult(false); } // Makes a failed assertion result with the given failure message. // Deprecated; use AssertionFailure() << message. AssertionResult AssertionFailure(const Message& message) { return AssertionFailure() << message; } namespace internal { // Constructs and returns the message for an equality assertion // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. // // The first four parameters are the expressions used in the assertion // and their values, as strings. For example, for ASSERT_EQ(foo, bar) // where foo is 5 and bar is 6, we have: // // expected_expression: "foo" // actual_expression: "bar" // expected_value: "5" // actual_value: "6" // // The ignoring_case parameter is true iff the assertion is a // *_STRCASEEQ*. When it's true, the string " (ignoring case)" will // be inserted into the message. AssertionResult EqFailure(const char* expected_expression, const char* actual_expression, const std::string& expected_value, const std::string& actual_value, bool ignoring_case) { Message msg; msg << "Value of: " << actual_expression; if (actual_value != actual_expression) { msg << "\n Actual: " << actual_value; } msg << "\nExpected: " << expected_expression; if (ignoring_case) { msg << " (ignoring case)"; } if (expected_value != expected_expression) { msg << "\nWhich is: " << expected_value; } return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::string GetBoolAssertionFailureMessage( const AssertionResult& assertion_result, const char* expression_text, const char* actual_predicate_value, const char* expected_predicate_value) { const char* actual_message = assertion_result.message(); Message msg; msg << "Value of: " << expression_text << "\n Actual: " << actual_predicate_value; if (actual_message[0] != '\0') msg << " (" << actual_message << ")"; msg << "\nExpected: " << expected_predicate_value; return msg.GetString(); } // Helper function for implementing ASSERT_NEAR. AssertionResult DoubleNearPredFormat(const char* expr1, const char* expr2, const char* abs_error_expr, double val1, double val2, double abs_error) { const double diff = fabs(val1 - val2); if (diff <= abs_error) return AssertionSuccess(); // TODO(wan): do not print the value of an expression if it's // already a literal. return AssertionFailure() << "The difference between " << expr1 << " and " << expr2 << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" << expr1 << " evaluates to " << val1 << ",\n" << expr2 << " evaluates to " << val2 << ", and\n" << abs_error_expr << " evaluates to " << abs_error << "."; } // Helper template for implementing FloatLE() and DoubleLE(). template AssertionResult FloatingPointLE(const char* expr1, const char* expr2, RawType val1, RawType val2) { // Returns success if val1 is less than val2, if (val1 < val2) { return AssertionSuccess(); } // or if val1 is almost equal to val2. const FloatingPoint lhs(val1), rhs(val2); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } // Note that the above two checks will both fail if either val1 or // val2 is NaN, as the IEEE floating-point standard requires that // any predicate involving a NaN must return false. ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; return AssertionFailure() << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); } } // namespace internal // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult FloatLE(const char* expr1, const char* expr2, float val1, float val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } // Asserts that val1 is less than, or almost equal to, val2. Fails // otherwise. In particular, it fails if either val1 or val2 is NaN. AssertionResult DoubleLE(const char* expr1, const char* expr2, double val1, double val2) { return internal::FloatingPointLE(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* expected_expression, const char* actual_expression, BiggestInt expected, BiggestInt actual) { if (expected == actual) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, FormatForComparisonFailureMessage(expected, actual), FormatForComparisonFailureMessage(actual, expected), false); } // A macro for implementing the helper functions needed to implement // ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here // just to avoid copy-and-paste of similar code. #define GTEST_IMPL_CMP_HELPER_(op_name, op)\ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ BiggestInt val1, BiggestInt val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ } // Implements the helper function for {ASSERT|EXPECT}_NE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(NE, !=) // Implements the helper function for {ASSERT|EXPECT}_LE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LE, <=) // Implements the helper function for {ASSERT|EXPECT}_LT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(LT, < ) // Implements the helper function for {ASSERT|EXPECT}_GE with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GE, >=) // Implements the helper function for {ASSERT|EXPECT}_GT with int or // enum arguments. GTEST_IMPL_CMP_HELPER_(GT, > ) #undef GTEST_IMPL_CMP_HELPER_ // The helper function for {ASSERT|EXPECT}_STREQ. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, const char* actual_expression, const char* expected, const char* actual) { if (String::CaseInsensitiveCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), true); } // The helper function for {ASSERT|EXPECT}_STRNE. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // The helper function for {ASSERT|EXPECT}_STRCASENE. AssertionResult CmpHelperSTRCASENE(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2) { if (!String::CaseInsensitiveCStringEquals(s1, s2)) { return AssertionSuccess(); } else { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } } // namespace internal namespace { // Helper functions for implementing IsSubString() and IsNotSubstring(). // This group of overloaded functions return true iff needle is a // substring of haystack. NULL is considered a substring of itself // only. bool IsSubstringPred(const char* needle, const char* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return strstr(haystack, needle) != NULL; } bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { if (needle == NULL || haystack == NULL) return needle == haystack; return wcsstr(haystack, needle) != NULL; } // StringType here can be either ::std::string or ::std::wstring. template bool IsSubstringPred(const StringType& needle, const StringType& haystack) { return haystack.find(needle) != StringType::npos; } // This function implements either IsSubstring() or IsNotSubstring(), // depending on the value of the expected_to_be_substring parameter. // StringType here can be const char*, const wchar_t*, ::std::string, // or ::std::wstring. template AssertionResult IsSubstringImpl( bool expected_to_be_substring, const char* needle_expr, const char* haystack_expr, const StringType& needle, const StringType& haystack) { if (IsSubstringPred(needle, haystack) == expected_to_be_substring) return AssertionSuccess(); const bool is_wide_string = sizeof(needle[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << "Value of: " << needle_expr << "\n" << " Actual: " << begin_string_quote << needle << "\"\n" << "Expected: " << (expected_to_be_substring ? "" : "not ") << "a substring of " << haystack_expr << "\n" << "Which is: " << begin_string_quote << haystack << "\""; } } // namespace // IsSubstring() and IsNotSubstring() check whether needle is a // substring of haystack (NULL is considered a substring of itself // only), and return an appropriate error message when they fail. AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const char* needle, const char* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const wchar_t* needle, const wchar_t* haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::string& needle, const ::std::string& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #if GTEST_HAS_STD_WSTRING AssertionResult IsSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); } AssertionResult IsNotSubstring( const char* needle_expr, const char* haystack_expr, const ::std::wstring& needle, const ::std::wstring& haystack) { return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); } #endif // GTEST_HAS_STD_WSTRING namespace internal { #if GTEST_OS_WINDOWS namespace { // Helper function for IsHRESULT{SuccessFailure} predicates AssertionResult HRESULTFailureHelper(const char* expr, const char* expected, long hr) { // NOLINT # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't support FormatMessage. const char error_text[] = ""; # else // Looks up the human-readable system message for the HRESULT code // and since we're not passing any params to FormatMessage, we don't // want inserts expanded. const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; const DWORD kBufSize = 4096; // Gets the system's human readable message string for this HRESULT. char error_text[kBufSize] = { '\0' }; DWORD message_length = ::FormatMessageA(kFlags, 0, // no source, we're asking system hr, // the error 0, // no line width restrictions error_text, // output buffer kBufSize, // buf size NULL); // no arguments for inserts // Trims tailing white space (FormatMessage leaves a trailing CR-LF) for (; message_length && IsSpace(error_text[message_length - 1]); --message_length) { error_text[message_length - 1] = '\0'; } # endif // GTEST_OS_WINDOWS_MOBILE const std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << " " << error_text << "\n"; } } // namespace AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT if (SUCCEEDED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "succeeds", hr); } AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT if (FAILED(hr)) { return AssertionSuccess(); } return HRESULTFailureHelper(expr, "fails", hr); } #endif // GTEST_OS_WINDOWS // Utility functions for encoding Unicode text (wide strings) in // UTF-8. // A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 // like this: // // Code-point length Encoding // 0 - 7 bits 0xxxxxxx // 8 - 11 bits 110xxxxx 10xxxxxx // 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx // 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // The maximum code-point a one-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; // Chops off the n lowest bits from a bit pattern. Returns the n // lowest bits. As a side effect, the original bit pattern will be // shifted to the right by n bits. inline UInt32 ChopLowBits(UInt32* bits, int n) { const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); *bits >>= n; return low_bits; } // Converts a Unicode code point to a narrow string in UTF-8 encoding. // code_point parameter is of type UInt32 because wchar_t may not be // wide enough to contain a code point. // If the code_point is not a valid Unicode code point // (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } return str; } // The following two functions only make sense if the the system // uses UTF-16 for wide string encoding. All supported systems // with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. // Determines if the arguments constitute UTF-16 surrogate pair // and thus should be combined into a single Unicode code point // using CreateCodePointFromUtf16SurrogatePair. inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { return sizeof(wchar_t) == 2 && (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; } // Creates a Unicode code point from UTF16 surrogate pair. inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, wchar_t second) { const UInt32 mask = (1 << 10) - 1; return (sizeof(wchar_t) == 2) ? (((first & mask) << 10) | (second & mask)) + 0x10000 : // This function should not be called when the condition is // false, but we provide a sensible default in case it is. static_cast(first); } // Converts a wide string to a narrow string in UTF-8 encoding. // The wide string is assumed to have the following encoding: // UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) // UTF-32 if sizeof(wchar_t) == 4 (on Linux) // Parameter str points to a null-terminated wide string. // Parameter num_chars may additionally limit the number // of wchar_t characters processed. -1 is used when the entire string // should be processed. // If the string contains code points that are not valid Unicode code points // (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output // as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding // and contains invalid UTF-16 surrogate pairs, values in those pairs // will be encoded as individual Unicode characters from Basic Normal Plane. std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream stream; for (int i = 0; i < num_chars; ++i) { UInt32 unicode_code_point; if (str[i] == L'\0') { break; } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], str[i + 1]); i++; } else { unicode_code_point = static_cast(str[i]); } stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } // Compares two wide C strings. Returns true iff they have the same // content. // // Unlike wcscmp(), this function can handle NULL argument(s). A NULL // C string is considered different to any non-NULL C string, // including the empty string. bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return wcscmp(lhs, rhs) == 0; } // Helper function for *_STREQ on wide strings. AssertionResult CmpHelperSTREQ(const char* expected_expression, const char* actual_expression, const wchar_t* expected, const wchar_t* actual) { if (String::WideCStringEquals(expected, actual)) { return AssertionSuccess(); } return EqFailure(expected_expression, actual_expression, PrintToString(expected), PrintToString(actual), false); } // Helper function for *_STRNE on wide strings. AssertionResult CmpHelperSTRNE(const char* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2) { if (!String::WideCStringEquals(s1, s2)) { return AssertionSuccess(); } return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } // Compares two C strings, ignoring case. Returns true iff they have // the same content. // // Unlike strcasecmp(), this function can handle NULL argument(s). A // NULL C string is considered different to any non-NULL C string, // including the empty string. bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; return posix::StrCaseCmp(lhs, rhs) == 0; } // Compares two wide C strings, ignoring case. Returns true iff they // have the same content. // // Unlike wcscasecmp(), this function can handle NULL argument(s). // A NULL C string is considered different to any non-NULL wide C string, // including the empty string. // NB: The implementations on different platforms slightly differ. // On windows, this method uses _wcsicmp which compares according to LC_CTYPE // environment variable. On GNU platform this method uses wcscasecmp // which compares according to LC_CTYPE category of the current locale. // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the // current locale. bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, const wchar_t* rhs) { if (lhs == NULL) return rhs == NULL; if (rhs == NULL) return false; #if GTEST_OS_WINDOWS return _wcsicmp(lhs, rhs) == 0; #elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else // Android, Mac OS X and Cygwin don't define wcscasecmp. // Other unknown OSes may not define it either. wint_t left, right; do { left = towlower(*lhs++); right = towlower(*rhs++); } while (left && left == right); return left == right; #endif // OS selector } // Returns true iff str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, suffix.c_str()); } // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexInt(int value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast(value); return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); std::string result; result.reserve(2 * (end - start)); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { result += *ch; } } return result; } // Appends the user-supplied message to the Google-Test-generated message. std::string AppendUserMessage(const std::string& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } return gtest_msg + "\n" + user_msg_string; } } // namespace internal // class TestResult // Creates an empty TestResult. TestResult::TestResult() : death_test_count_(0), elapsed_time_(0) { } // D'tor. TestResult::~TestResult() { } // Returns the i-th test part result among all the results. i can // range from 0 to total_part_count() - 1. If i is not in that range, // aborts the program. const TestPartResult& TestResult::GetTestPartResult(int i) const { if (i < 0 || i >= total_part_count()) internal::posix::Abort(); return test_part_results_.at(i); } // Returns the i-th test property. i can range from 0 to // test_property_count() - 1. If i is not in that range, aborts the // program. const TestProperty& TestResult::GetTestProperty(int i) const { if (i < 0 || i >= test_property_count()) internal::posix::Abort(); return test_properties_.at(i); } // Clears the test part results. void TestResult::ClearTestPartResults() { test_part_results_.clear(); } // Adds a test part result to the list. void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { test_part_results_.push_back(test_part_result); } // Adds a test property to the list. If a property with the same key as the // supplied property is already represented, the value of this test_property // replaces the old value for that key. void TestResult::RecordProperty(const std::string& xml_element, const TestProperty& test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::iterator property_with_matching_key = std::find_if(test_properties_.begin(), test_properties_.end(), internal::TestPropertyKeyIs(test_property.key())); if (property_with_matching_key == test_properties_.end()) { test_properties_.push_back(test_property); return; } property_with_matching_key->SetValue(test_property.value()); } // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuitesAttributes[] = { "disabled", "errors", "failures", "name", "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time" }; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param" }; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { word_list << ", "; } if (i == words.size() - 1) { word_list << "and "; } word_list << "'" << words[i] << "'"; } return word_list.GetString(); } bool ValidateTestPropertyName(const std::string& property_name, const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } // Clears the object. void TestResult::Clear() { test_part_results_.clear(); test_properties_.clear(); death_test_count_ = 0; elapsed_time_ = 0; } // Returns true iff the test failed. bool TestResult::Failed() const { for (int i = 0; i < total_part_count(); ++i) { if (GetTestPartResult(i).failed()) return true; } return false; } // Returns true iff the test part fatally failed. static bool TestPartFatallyFailed(const TestPartResult& result) { return result.fatally_failed(); } // Returns true iff the test fatally failed. bool TestResult::HasFatalFailure() const { return CountIf(test_part_results_, TestPartFatallyFailed) > 0; } // Returns true iff the test part non-fatally failed. static bool TestPartNonfatallyFailed(const TestPartResult& result) { return result.nonfatally_failed(); } // Returns true iff the test has a non-fatal failure. bool TestResult::HasNonfatalFailure() const { return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; } // Gets the number of all test parts. This is the sum of the number // of successful test parts and the number of failed test parts. int TestResult::total_part_count() const { return static_cast(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the values of all Google Test flags. Test::Test() : gtest_flag_saver_(new internal::GTestFlagSaver) { } // The d'tor restores the values of all Google Test flags. Test::~Test() { delete gtest_flag_saver_; } // Sets up the test fixture. // // A sub-class may override this. void Test::SetUp() { } // Tears down the test fixture. // // A sub-class may override this. void Test::TearDown() { } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, const std::string& value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& key, int value) { Message value_message; value_message << value; RecordProperty(key, value_message.GetString().c_str()); } namespace internal { void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message) { // This function is a friend of UnitTest and as such has access to // AddTestPartResult. UnitTest::GetInstance()->AddTestPartResult( result_type, NULL, // No info about the source file where the exception occurred. -1, // We have no info on which line caused the exception. message, ""); // No stack trace, either. } } // namespace internal // Google Test requires all tests in the same test case to use the same test // fixture class. This function checks if the current test has the // same fixture class as the first test in the current test case. If // yes, it returns true; otherwise it generates a Google Test failure and // returns false. bool Test::HasSameFixtureClass() { internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); const TestCase* const test_case = impl->current_test_case(); // Info about the first test in the current test case. const TestInfo* const first_test_info = test_case->test_info_list()[0]; const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; const char* const first_test_name = first_test_info->name(); // Info about the current test. const TestInfo* const this_test_info = impl->current_test_info(); const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; const char* const this_test_name = this_test_info->name(); if (this_fixture_id != first_fixture_id) { // Is the first test defined using TEST? const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); // Is this test defined using TEST? const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); if (first_is_TEST || this_is_TEST) { // The user mixed TEST and TEST_F in this test case - we'll tell // him/her how to fix it. // Gets the name of the TEST and the name of the TEST_F. Note // that first_is_TEST and this_is_TEST cannot both be true, as // the fixture IDs are different for the two tests. const char* const TEST_name = first_is_TEST ? first_test_name : this_test_name; const char* const TEST_F_name = first_is_TEST ? this_test_name : first_test_name; ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class, so mixing TEST_F and TEST in the same test case is\n" << "illegal. In test case " << this_test_info->test_case_name() << ",\n" << "test " << TEST_F_name << " is defined using TEST_F but\n" << "test " << TEST_name << " is defined using TEST. You probably\n" << "want to change the TEST to TEST_F or move it to another test\n" << "case."; } else { // The user defined two fixture classes with the same name in // two namespaces - we'll tell him/her how to fix it. ADD_FAILURE() << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << this_test_info->test_case_name() << ",\n" << "you defined test " << first_test_name << " and test " << this_test_name << "\n" << "using two different test fixture classes. This can happen if\n" << "the two classes are from different namespaces or translation\n" << "units and have the same name. You should probably rename one\n" << "of the classes to put the tests into different test cases."; } return false; } return true; } #if GTEST_HAS_SEH // Adds an "exception thrown" fatal failure to the current test. This // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). static std::string* FormatSehExceptionMessage(DWORD exception_code, const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; if (description != NULL) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; } message << " thrown in " << location << "."; return message.GetString(); } static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template Result HandleSehExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { return (object->*method)(); } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; return static_cast(0); } #else (void)location; return (object->*method)(); #endif // GTEST_HAS_SEH } // Runs the given method and catches and reports C++ and/or SEH-style // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag // after the exception is caught and either report or re-throw the // exception based on the flag's value: // // try { // // Perform the test method. // } catch (...) { // if (GTEST_FLAG(catch_exceptions)) // // Report the exception as failure. // else // throw; // Re-throws the original exception. // } // // However, the purpose of this flag is to allow the program to drop into // the debugger when the exception is thrown. On most platforms, once the // control enters the catch block, the exception origin information is // lost and the debugger will stop the program at the point of the // re-throw in this function -- instead of at the point of the original // throw statement in the code under test. For this reason, we perform // the check early, sacrificing the ability to affect Google Test's // exception handling in the method where the exception is thrown. if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(NULL, location)); } return static_cast(0); #else return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS } else { return (object->*method)(); } } } // namespace internal // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "the test body"); } // However, we want to clean up as much as possible. Hence we will // always call TearDown(), even if SetUp() or the test body has // failed. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } // Returns true iff the current test has a fatal failure. bool Test::HasFatalFailure() { return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); } // Returns true iff the current test has a non-fatal failure. bool Test::HasNonfatalFailure() { return internal::GetUnitTestImpl()->current_test_result()-> HasNonfatalFailure(); } // class TestInfo // Constructs a TestInfo object. It assumes ownership of the test factory // object. TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } namespace internal { // Creates a new TestInfo object and registers it with Google Test; // returns the created object. // // Arguments: // // test_case_name: name of the test case // name: name of the test // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. // fixture_class_id: ID of the test fixture class // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case // factory: pointer to the factory that creates a test object. // The newly created TestInfo instance will assume // ownership of the factory object. TestInfo* MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, fixture_class_id, factory); GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); return test_info; } #if GTEST_HAS_PARAM_TEST void ReportInvalidTestCaseType(const char* test_case_name, const char* file, int line) { Message errors; errors << "Attempted redefinition of test case " << test_case_name << ".\n" << "All tests in the same test case must use the same test fixture\n" << "class. However, in test case " << test_case_name << ", you tried\n" << "to define a test using a fixture class different from the one\n" << "used earlier. This can happen if the two fixture classes are\n" << "from different namespaces and have the same name. You should\n" << "probably rename one of the classes to put the tests into different\n" << "test cases."; fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal namespace { // A predicate that checks the test name of a TestInfo against a known // value. // // This is used for implementation of the TestCase class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestNameIs is copyable. class TestNameIs { public: // Constructor. // // TestNameIs has NO default constructor. explicit TestNameIs(const char* name) : name_(name) {} // Returns true iff the test name of test_info matches name_. bool operator()(const TestInfo * test_info) const { return test_info && test_info->name() == name_; } private: std::string name_; }; } // namespace namespace internal { // This method expands all parameterized tests registered with macros TEST_P // and INSTANTIATE_TEST_CASE_P into regular tests and registers those. // This will be done just once during the program runtime. void UnitTestImpl::RegisterParameterizedTests() { #if GTEST_HAS_PARAM_TEST if (!parameterized_tests_registered_) { parameterized_test_registry_.RegisterTests(); parameterized_tests_registered_ = true; } #endif } } // namespace internal // Creates the test object, runs it, records its result, and then // deletes it. void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // Runs the test only if the test object was created and its // constructor didn't generate a fatal failure. if ((test != NULL) && !Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } // class TestCase // Gets the number of successful tests in this test case. int TestCase::successful_test_count() const { return CountIf(test_info_list_, TestPassed); } // Gets the number of failed tests in this test case. int TestCase::failed_test_count() const { return CountIf(test_info_list_, TestFailed); } // Gets the number of disabled tests that will be reported in the XML report. int TestCase::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } // Gets the number of disabled tests in this test case. int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. int TestCase::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } // Get the number of tests in this test case that should run. int TestCase::test_to_run_count() const { return CountIf(test_info_list_, ShouldRunTest); } // Gets the number of all tests. int TestCase::total_test_count() const { return static_cast(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // a_type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase::TestCase(const char* a_name, const char* a_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), set_up_tc_(set_up_tc), tear_down_tc_(tear_down_tc), should_run_(false), elapsed_time_(0) { } // Destructor of TestCase. TestCase::~TestCase() { // Deletes every Test in the collection. ForEach(test_info_list_, internal::Delete); } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. const TestInfo* TestCase::GetTestInfo(int i) const { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Returns the i-th test among all the tests. i can range from 0 to // total_test_count() - 1. If i is not in that range, returns NULL. TestInfo* TestCase::GetMutableTestInfo(int i) { const int index = GetElementOr(test_indices_, i, -1); return index < 0 ? NULL : test_info_list_[index]; } // Adds a test to this test case. Will delete the test upon // destruction of the TestCase object. void TestCase::AddTestInfo(TestInfo * test_info) { test_info_list_.push_back(test_info); test_indices_.push_back(static_cast(test_indices_.size())); } // Runs every test in this TestCase. void TestCase::Run() { if (!should_run_) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_case(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); repeater->OnTestCaseStart(*this); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } // Shuffles the tests in this test case. void TestCase::ShuffleTests(internal::Random* random) { Shuffle(random, &test_indices_); } // Restores the test order to before the first shuffle. void TestCase::UnshuffleTests() { for (size_t i = 0; i < test_indices_.size(); i++) { test_indices_[i] = static_cast(i); } } // Formats a countable noun. Depending on its quantity, either the // singular form or the plural form is used. e.g. // // FormatCountableNoun(1, "formula", "formuli") returns "1 formula". // FormatCountableNoun(5, "book", "books") returns "5 books". static std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::StreamableToString(count) + " " + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static std::string FormatTestCaseCount(int test_case_count) { return FormatCountableNoun(test_case_count, "test case", "test cases"); } // Converts a TestPartResult::Type enum to human-friendly string // representation. Both kNonFatalFailure and kFatalFailure are translated // to "Failure", as the user usually doesn't care about the difference // between the two when viewing the test result. static const char * TestPartResultTypeToString(TestPartResult::Type type) { switch (type) { case TestPartResult::kSuccess: return "Success"; case TestPartResult::kNonFatalFailure: case TestPartResult::kFatalFailure: #ifdef _MSC_VER return "error: "; #else return "Failure\n"; #endif default: return "Unknown result type"; } } namespace internal { // Prints a TestPartResult to an std::string. static std::string PrintTestPartResultToString( const TestPartResult& test_part_result) { return (Message() << internal::FormatFileLocation(test_part_result.file_name(), test_part_result.line_number()) << " " << TestPartResultTypeToString(test_part_result.type()) << test_part_result.message()).GetString(); } // Prints a TestPartResult. static void PrintTestPartResult(const TestPartResult& test_part_result) { const std::string& result = PrintTestPartResultToString(test_part_result); printf("%s\n", result.c_str()); fflush(stdout); // If the test program runs in Visual Studio or a debugger, the // following statements add the test part result message to the Output // window such that the user can double-click on it to jump to the // corresponding source code location; otherwise they do nothing. #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // We don't call OutputDebugString*() on Windows Mobile, as printing // to stdout is done by OutputDebugString() there already - we don't // want the same message printed twice. ::OutputDebugStringA(result.c_str()); ::OutputDebugStringA("\n"); #endif } // class PrettyUnitTestResultPrinter enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns the character attribute for the given color. WORD GetColorAttribute(GTestColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; default: return 0; } } #else // Returns the ANSI color code for the given color. COLOR_DEFAULT is // an invalid input. const char* GetAnsiColorCode(GTestColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; case COLOR_YELLOW: return "3"; default: return NULL; }; } #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE // Returns true iff Google Test should use colors in the output. bool ShouldUseColor(bool stdout_is_tty) { const char* const gtest_color = GTEST_FLAG(color).c_str(); if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { #if GTEST_OS_WINDOWS // On Windows the TERM variable is usually not set, but the // console there does support colors. return stdout_is_tty; #else // On non-Windows platforms, we rely on the TERM variable. const char* const term = posix::GetEnv("TERM"); const bool term_supports_color = String::CStringEquals(term, "xterm") || String::CStringEquals(term, "xterm-color") || String::CStringEquals(term, "xterm-256color") || String::CStringEquals(term, "screen") || String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "linux") || String::CStringEquals(term, "cygwin"); return stdout_is_tty && term_supports_color; #endif // GTEST_OS_WINDOWS } return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || String::CaseInsensitiveCStringEquals(gtest_color, "true") || String::CaseInsensitiveCStringEquals(gtest_color, "t") || String::CStringEquals(gtest_color, "1"); // We take "yes", "true", "t", and "1" as meaning "yes". If the // value is neither one of these nor "auto", we treat it as "no" to // be conservative. } // Helpers for printing colored strings to stdout. Note that on Windows, we // cannot simply emit special characters and have the terminal change colors. // This routine must actually emit the characters rather than return a string // that would be colored when printed, as can be done on Linux. void ColoredPrintf(GTestColor color, const char* fmt, ...) { va_list args; va_start(args, fmt); #if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS const bool use_color = false; #else static const bool in_color_mode = ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); const bool use_color = in_color_mode && (color != COLOR_DEFAULT); #endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS // The '!= 0' comparison is necessary to satisfy MSVC 7.1. if (!use_color) { vprintf(fmt, args); va_end(args); return; } #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); // Gets the current text color. CONSOLE_SCREEN_BUFFER_INFO buffer_info; GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); const WORD old_color_attrs = buffer_info.wAttributes; // We need to flush the stream buffers into the console before each // SetConsoleTextAttribute call lest it affect the text that is already // printed but has not yet reached the console. fflush(stdout); SetConsoleTextAttribute(stdout_handle, GetColorAttribute(color) | FOREGROUND_INTENSITY); vprintf(fmt, args); fflush(stdout); // Restores the text color. SetConsoleTextAttribute(stdout_handle, old_color_attrs); #else printf("\033[0;3%sm", GetAnsiColorCode(color)); vprintf(fmt, args); printf("\033[m"); // Resets the terminal to default. #endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE va_end(args); } // Text printed in Google Test's text output and --gunit_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); if (type_param != NULL || value_param != NULL) { printf(", where "); if (type_param != NULL) { printf("%s = %s", kTypeParamLabel, type_param); if (value_param != NULL) printf(" and "); } if (value_param != NULL) { printf("%s = %s", kValueParamLabel, value_param); } } } // This class implements the TestEventListener interface. // // Class PrettyUnitTestResultPrinter is copyable. class PrettyUnitTestResultPrinter : public TestEventListener { public: PrettyUnitTestResultPrinter() {} static void PrintTestName(const char * test_case, const char * test) { printf("%s.%s", test_case, test); } // The following methods override what's in the TestEventListener class. virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} private: static void PrintFailedTests(const UnitTest& unit_test); }; // Fired before each iteration of tests starts. void PrettyUnitTestResultPrinter::OnTestIterationStart( const UnitTest& unit_test, int iteration) { if (GTEST_FLAG(repeat) != 1) printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); const char* const filter = GTEST_FLAG(filter).c_str(); // Prints the filter if it's not *. This reminds the user that some // tests may be skipped. if (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, internal::posix::GetEnv(kTestTotalShards)); } if (GTEST_FLAG(shuffle)) { ColoredPrintf(COLOR_YELLOW, "Note: Randomizing tests' orders with a seed of %d .\n", unit_test.random_seed()); } ColoredPrintf(COLOR_GREEN, "[==========] "); printf("Running %s from %s.\n", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment set-up.\n"); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == NULL) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_info.test_case_name(), test_info.name()); printf("\n"); fflush(stdout); } // Called after an assertion failure. void PrettyUnitTestResultPrinter::OnTestPartResult( const TestPartResult& result) { // If the test part succeeded, we don't need to do anything. if (result.type() == TestPartResult::kSuccess) return; // Print failure message from the assertion (e.g. expected this and got that). PrintTestPartResult(result); fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { if (test_info.result()->Passed()) { ColoredPrintf(COLOR_GREEN, "[ OK ] "); } else { ColoredPrintf(COLOR_RED, "[ FAILED ] "); } PrintTestName(test_info.test_case_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); if (GTEST_FLAG(print_time)) { printf(" (%s ms)\n", internal::StreamableToString( test_info.result()->elapsed_time()).c_str()); } else { printf("\n"); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { if (!GTEST_FLAG(print_time)) return; const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s (%s ms total)\n\n", counts.c_str(), test_case.name(), internal::StreamableToString(test_case.elapsed_time()).c_str()); fflush(stdout); } void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( const UnitTest& /*unit_test*/) { ColoredPrintf(COLOR_GREEN, "[----------] "); printf("Global test environment tear-down\n"); fflush(stdout); } // Internal helper for printing the list of failed tests. void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { const int failed_test_count = unit_test.failed_test_count(); if (failed_test_count == 0) { return; } for (int i = 0; i < unit_test.total_test_case_count(); ++i) { const TestCase& test_case = *unit_test.GetTestCase(i); if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { continue; } for (int j = 0; j < test_case.total_test_count(); ++j) { const TestInfo& test_info = *test_case.GetTestInfo(j); if (!test_info.should_run() || test_info.result()->Passed()) { continue; } ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s.%s", test_case.name(), test_info.name()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { ColoredPrintf(COLOR_GREEN, "[==========] "); printf("%s from %s ran.", FormatTestCount(unit_test.test_to_run_count()).c_str(), FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); if (GTEST_FLAG(print_time)) { printf(" (%s ms total)", internal::StreamableToString(unit_test.elapsed_time()).c_str()); } printf("\n"); ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); int num_failures = unit_test.failed_test_count(); if (!unit_test.Passed()) { const int failed_test_count = unit_test.failed_test_count(); ColoredPrintf(COLOR_RED, "[ FAILED ] "); printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); PrintFailedTests(unit_test); printf("\n%2d FAILED %s\n", num_failures, num_failures == 1 ? "TEST" : "TESTS"); } int num_disabled = unit_test.reportable_disabled_test_count(); if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { if (!num_failures) { printf("\n"); // Add a spacer if no FAILURE banner is displayed. } ColoredPrintf(COLOR_YELLOW, " YOU HAVE %d DISABLED %s\n\n", num_disabled, num_disabled == 1 ? "TEST" : "TESTS"); } // Ensure that Google Test output is printed before, e.g., heapchecker output. fflush(stdout); } // End PrettyUnitTestResultPrinter // class TestEventRepeater // // This class forwards events to other event listeners. class TestEventRepeater : public TestEventListener { public: TestEventRepeater() : forwarding_enabled_(true) {} virtual ~TestEventRepeater(); void Append(TestEventListener *listener); TestEventListener* Release(TestEventListener* listener); // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled() const { return forwarding_enabled_; } void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } virtual void OnTestProgramStart(const UnitTest& unit_test); virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); virtual void OnTestCaseStart(const TestCase& test_case); virtual void OnTestStart(const TestInfo& test_info); virtual void OnTestPartResult(const TestPartResult& result); virtual void OnTestEnd(const TestInfo& test_info); virtual void OnTestCaseEnd(const TestCase& test_case); virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); virtual void OnTestProgramEnd(const UnitTest& unit_test); private: // Controls whether events will be forwarded to listeners_. Set to false // in death test child processes. bool forwarding_enabled_; // The list of listeners that receive events. std::vector listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } void TestEventRepeater::Append(TestEventListener *listener) { listeners_.push_back(listener); } // TODO(vladl@google.com): Factor the search functionality into Vector::Find. TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { for (size_t i = 0; i < listeners_.size(); ++i) { if (listeners_[i] == listener) { listeners_.erase(listeners_.begin() + i); return listener; } } return NULL; } // Since most methods are very similar, use macros to reduce boilerplate. // This defines a member that forwards the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (size_t i = 0; i < listeners_.size(); i++) { \ listeners_[i]->Name(parameter); \ } \ } \ } // This defines a member that forwards the call to all listeners in reverse // order. #define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ void TestEventRepeater::Name(const Type& parameter) { \ if (forwarding_enabled_) { \ for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ listeners_[i]->Name(parameter); \ } \ } \ } GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) #undef GTEST_REPEATER_METHOD_ #undef GTEST_REVERSE_REPEATER_METHOD_ void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (size_t i = 0; i < listeners_.size(); i++) { listeners_[i]->OnTestIterationStart(unit_test, iteration); } } } void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, int iteration) { if (forwarding_enabled_) { for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { listeners_[i]->OnTestIterationEnd(unit_test, iteration); } } } // End TestEventRepeater // This class generates an XML output file. class XmlUnitTestResultPrinter : public EmptyTestEventListener { public: explicit XmlUnitTestResultPrinter(const char* output_file); virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); private: // Is c a whitespace character that is normalized to a space character // when it appears in an XML attribute value? static bool IsNormalizableWhitespace(char c) { return c == 0x9 || c == 0xA || c == 0xD; } // May c appear in a well-formed XML document? static bool IsValidXmlCharacter(char c) { return IsNormalizableWhitespace(c) || c >= 0x20; } // Returns an XML-escaped copy of the input string str. If // is_attribute is true, the text is meant to appear as an attribute // value, and normalizable whitespace is preserved by replacing it // with character references. static std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static std::string EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. static void OutputXmlAttribute(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value); // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. static void OutputXmlCDataSection(::std::ostream* stream, const char* data); // Streams an XML representation of a TestInfo object. static void OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info); // Prints an XML representation of a TestCase object static void PrintXmlTestCase(::std::ostream* stream, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, const UnitTest& unit_test); // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. // When the std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const std::string output_file_; GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); }; // Creates a new XmlUnitTestResultPrinter. XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) : output_file_(output_file) { if (output_file_.c_str() == NULL || output_file_.empty()) { fprintf(stderr, "XML output file may not be null\n"); fflush(stderr); exit(EXIT_FAILURE); } } // Called after the unit test ends. void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, int /*iteration*/) { FILE* xmlout = NULL; FilePath output_file(output_file_); FilePath output_dir(output_file.RemoveFileName()); if (output_dir.CreateDirectoriesRecursively()) { xmlout = posix::FOpen(output_file_.c_str(), "w"); } if (xmlout == NULL) { // TODO(wan): report the reason of the failure. // // We don't do it for now as: // // 1. There is no urgent need for it. // 2. It's a bit involved to make the errno variable thread-safe on // all three operating systems (Linux, Windows, and Mac OS). // 3. To interpret the meaning of errno in a thread-safe way, // we need the strerror_r() function, which is not available on // Windows. fprintf(stderr, "Unable to open file \"%s\"\n", output_file_.c_str()); fflush(stderr); exit(EXIT_FAILURE); } std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); fclose(xmlout); } // Returns an XML-escaped copy of the input string str. If is_attribute // is true, the text is meant to appear as an attribute value, and // normalizable whitespace is preserved by replacing it with character // references. // // Invalid XML characters in str, if any, are stripped from the output. // It is expected that most, if not all, of the text processed by this // module will consist of ordinary English text. // If this module is ever modified to produce version 1.1 XML output, // most invalid characters can be retained using character references. // TODO(wan): It might be nice to have a minimally invasive, human-readable // escaping scheme for invalid characters, rather than dropping them. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; else m << ch; } break; } } return m.GetString(); } // Returns the given string with all characters invalid in XML removed. // Currently invalid characters are dropped from the string. An // alternative is to replace them with certain characters such as . or ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( const std::string& str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << ms/1000.0; return ss.str(); } // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { // Using non-reentrant version as localtime_r is not portable. time_t seconds = static_cast(ms / 1000); #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4996) // Temporarily disables warning 4996 // (function or variable may be unsafe). const struct tm* const time_struct = localtime(&seconds); // NOLINT # pragma warning(pop) // Restores the warning state again. #else const struct tm* const time_struct = localtime(&seconds); // NOLINT #endif if (time_struct == NULL) return ""; // Invalid ms value // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct->tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct->tm_mday) + "T" + String::FormatIntWidth2(time_struct->tm_hour) + ":" + String::FormatIntWidth2(time_struct->tm_min) + ":" + String::FormatIntWidth2(time_struct->tm_sec); } // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, const char* data) { const char* segment = data; *stream << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } void XmlUnitTestResultPrinter::OutputXmlAttribute( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value) { const std::vector& allowed_names = GetReservedAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } // Prints an XML representation of a TestInfo object. // TODO(wan): There is also value in printing properties with the plain printer. void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, const char* test_case_name, const TestInfo& test_info) { const TestResult& result = *test_info.result(); const std::string kTestcase = "testcase"; *stream << " \n"; } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); const string summary = location + "\n" + part.summary(); *stream << " "; const string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, const TestCase& test_case) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_case.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_case.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); OutputXmlAttribute( stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); OutputXmlAttribute(stream, kTestsuites, "time", FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { if (unit_test.GetTestCase(i)->reportable_test_count() > 0) PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); } *stream << "\n"; } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( const TestResult& result) { Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } return attributes.GetString(); } // End XmlUnitTestResultPrinter #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. string StreamingListener::UrlEncode(const char* str) { string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { case '%': case '=': case '&': case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); break; } } return result; } void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; addrinfo* servinfo = NULL; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. const int error_num = getaddrinfo( host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { close(sockfd_); sockfd_ = -1; } } } freeaddrinfo(servinfo); // all done with this structure if (sockfd_ == -1) { GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " << host_name_ << ":" << port_num_; } } // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter // Returns the current OS stack trace as an std::string. Parameters: // // max_depth - the maximum number of stack frames to be included // in the trace. // skip_count - the number of top frames to be skipped; doesn't count // against max_depth. // string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, int /* skip_count */) GTEST_LOCK_EXCLUDED_(mutex_) { return ""; } void OsStackTraceGetter::UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_) { } const char* const OsStackTraceGetter::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) : premature_exit_filepath_(premature_exit_filepath) { // If a path to the premature-exit file is specified... if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { remove(premature_exit_filepath_); } } private: const char* const premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; } // namespace internal // class TestEventListeners TestEventListeners::TestEventListeners() : repeater_(new internal::TestEventRepeater()), default_result_printer_(NULL), default_xml_generator_(NULL) { } TestEventListeners::~TestEventListeners() { delete repeater_; } // Returns the standard listener responsible for the default console // output. Can be removed from the listeners list to shut down default // console output. Note that removing this object from the listener list // with Release transfers its ownership to the user. void TestEventListeners::Append(TestEventListener* listener) { repeater_->Append(listener); } // Removes the given event listener from the list and returns it. It then // becomes the caller's responsibility to delete the listener. Returns // NULL if the listener is not found in the list. TestEventListener* TestEventListeners::Release(TestEventListener* listener) { if (listener == default_result_printer_) default_result_printer_ = NULL; else if (listener == default_xml_generator_) default_xml_generator_ = NULL; return repeater_->Release(listener); } // Returns repeater that broadcasts the TestEventListener events to all // subscribers. TestEventListener* TestEventListeners::repeater() { return repeater_; } // Sets the default_result_printer attribute to the provided listener. // The listener is also added to the listener list and previous // default_result_printer is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { if (default_result_printer_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_result_printer_); default_result_printer_ = listener; if (listener != NULL) Append(listener); } } // Sets the default_xml_generator attribute to the provided listener. The // listener is also added to the listener list and previous // default_xml_generator is removed from it and deleted. The listener can // also be NULL in which case it will not be added to the list. Does // nothing if the previous and the current listener objects are the same. void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { if (default_xml_generator_ != listener) { // It is an error to pass this method a listener that is already in the // list. delete Release(default_xml_generator_); default_xml_generator_ = listener; if (listener != NULL) Append(listener); } } // Controls whether events will be forwarded by the repeater to the // listeners in the list. bool TestEventListeners::EventForwardingEnabled() const { return repeater_->forwarding_enabled(); } void TestEventListeners::SuppressEventForwarding() { repeater_->set_forwarding_enabled(false); } // class UnitTest // Gets the singleton UnitTest object. The first time this method is // called, a UnitTest object is constructed and returned. Consecutive // calls will return the same object. // // We don't protect this under mutex_ as a user is not supposed to // call this before main() starts, from which point on the return // value will never change. UnitTest* UnitTest::GetInstance() { // When compiled with MSVC 7.1 in optimized mode, destroying the // UnitTest object upon exiting the program messes up the exit code, // causing successful tests to appear failed. We have to use a // different implementation in this case to bypass the compiler bug. // This implementation makes the compiler happy, at the cost of // leaking the UnitTest object. // CodeGear C++Builder insists on a public destructor for the // default implementation. Use this implementation to keep good OO // design with private destructor. #if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) static UnitTest* const instance = new UnitTest; return instance; #else static UnitTest instance; return &instance; #endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) } // Gets the number of successful test cases. int UnitTest::successful_test_case_count() const { return impl()->successful_test_case_count(); } // Gets the number of failed test cases. int UnitTest::failed_test_case_count() const { return impl()->failed_test_case_count(); } // Gets the number of all test cases. int UnitTest::total_test_case_count() const { return impl()->total_test_case_count(); } // Gets the number of all test cases that contain at least one test // that should run. int UnitTest::test_case_to_run_count() const { return impl()->test_case_to_run_count(); } // Gets the number of successful tests. int UnitTest::successful_test_count() const { return impl()->successful_test_count(); } // Gets the number of failed tests. int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } // Gets the number of disabled tests that will be reported in the XML report. int UnitTest::reportable_disabled_test_count() const { return impl()->reportable_disabled_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of tests to be printed in the XML report. int UnitTest::reportable_test_count() const { return impl()->reportable_test_count(); } // Gets the number of all tests. int UnitTest::total_test_count() const { return impl()->total_test_count(); } // Gets the number of tests that should run. int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } // Gets the time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { return impl()->start_timestamp(); } // Gets the elapsed time, in milliseconds. internal::TimeInMillis UnitTest::elapsed_time() const { return impl()->elapsed_time(); } // Returns true iff the unit test passed (i.e. all test cases passed). bool UnitTest::Passed() const { return impl()->Passed(); } // Returns true iff the unit test failed (i.e. some test case failed // or something outside of all tests failed). bool UnitTest::Failed() const { return impl()->Failed(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. const TestCase* UnitTest::GetTestCase(int i) const { return impl()->GetTestCase(i); } // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } // Gets the i-th test case among all the test cases. i can range from 0 to // total_test_case_count() - 1. If i is not in that range, returns NULL. TestCase* UnitTest::GetMutableTestCase(int i) { return impl()->GetMutableTestCase(i); } // Returns the list of event listeners that can be used to track events // inside Google Test. TestEventListeners& UnitTest::listeners() { return *impl()->listeners(); } // Registers and returns a global test environment. When a test // program is run, all global test environments will be set-up in the // order they were registered. After all tests in the program have // finished, all global test environments will be torn-down in the // *reverse* order they were registered. // // The UnitTest object takes ownership of the given environment. // // We don't protect this under mutex_, as we only support calling it // from the main thread. Environment* UnitTest::AddEnvironment(Environment* env) { if (env == NULL) { return NULL; } impl_->environments().push_back(env); return env; } // Adds a TestPartResult to the current TestResult object. All Google Test // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call // this to report their results. The user code should use the // assertion macros instead of calling this directly. void UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { Message msg; msg << message; internal::MutexLock lock(&mutex_); if (impl_->gtest_trace_stack().size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; for (int i = static_cast(impl_->gtest_trace_stack().size()); i > 0; --i) { const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) << " " << trace.message; } } if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { msg << internal::kStackTraceMarker << os_stack_trace; } const TestPartResult result = TestPartResult(result_type, file_name, line_number, msg.GetString().c_str()); impl_->GetTestPartResultReporterForCurrentThread()-> ReportTestPartResult(result); if (result_type != TestPartResult::kSuccess) { // gtest_break_on_failure takes precedence over // gtest_throw_on_failure. This allows a user to set the latter // in the code (perhaps in order to use Google Test assertions // with another testing framework) and specify the former on the // command line for debugging. if (GTEST_FLAG(break_on_failure)) { #if GTEST_OS_WINDOWS // Using DebugBreak on Windows allows gtest to still break into a debugger // when a failure happens and both the --gtest_break_on_failure and // the --gtest_catch_exceptions flags are specified. DebugBreak(); #else // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for // portability: Symbian doesn't implement abort() well, and some debuggers // don't correctly trap abort(). *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw internal::GoogleTestFailureException(result); #else // We cannot call abort() as it generates a pop-up in debug mode // that cannot be suppressed in VC 7.1 or below. exit(1); #endif } } } // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, const std::string& value) { impl_->RecordProperty(TestProperty(key, value)); } // Runs all tests in this UnitTest object and prints the result. // Returns 0 if successful, or 1 otherwise. // // We don't protect this under mutex_, as we only support calling it // from the main thread. int UnitTest::Run() { const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Google Test implements this protocol for catching that a test // program exits before returning control to Google Test: // // 1. Upon start, Google Test creates a file whose absolute path // is specified by the environment variable // TEST_PREMATURE_EXIT_FILE. // 2. When Google Test has finished its work, it deletes the file. // // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before // running a Google-Test-based test program and check the existence // of the file at the end of the test execution to see if it has // exited prematurely. // If we are in the child process of a death test, don't // create/delete the premature exit file, as doing so is unnecessary // and will confuse the parent process. Otherwise, create/delete // the file upon entering/leaving this function. If the program // somehow exits before this function has a chance to return, the // premature-exit file will be left undeleted, causing a test runner // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( in_death_test_child_process ? NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_HAS_SEH // Either the user wants Google Test to catch exceptions thrown by the // tests or this is executing in the context of death test child // process. In either case the user does not want to see pop-up dialogs // about crashes - they are expected. if (impl()->catch_exceptions() || in_death_test_child_process) { # if !GTEST_OS_WINDOWS_MOBILE // SetErrorMode doesn't exist on CE. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); # endif // !GTEST_OS_WINDOWS_MOBILE # if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE // Death test children can be terminated with _abort(). On Windows, // _abort() can show a dialog with a warning message. This forces the // abort message to go to stderr instead. _set_error_mode(_OUT_TO_STDERR); # endif # if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // In the debug version, Visual Studio pops up a separate dialog // offering a choice to debug the aborted program. We need to suppress // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement // executed. Google Test will notify the user of any unexpected // failure via stderr. // // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. // Users of prior VC versions shall suffer the agony and pain of // clicking through the countless debug dialogs. // TODO(vladl@google.com): find a way to suppress the abort dialog() in the // debug mode when compiled with VC 7.1 or lower. if (!GTEST_FLAG(break_on_failure)) _set_abort_behavior( 0x0, // Clear the following flags: _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. # endif } #endif // GTEST_HAS_SEH return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } // Returns the working directory when the first TEST() or TEST_F() was // executed. const char* UnitTest::original_working_dir() const { return impl_->original_working_dir_.c_str(); } // Returns the TestCase object for the test that's currently running, // or NULL if no test is running. const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_case(); } // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); return impl_->current_test_info(); } // Returns the random seed used at the start of the current test run. int UnitTest::random_seed() const { return impl_->random_seed(); } #if GTEST_HAS_PARAM_TEST // Returns ParameterizedTestCaseRegistry object used to keep track of // value-parameterized tests and instantiate and register them. internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { return impl_->parameterized_test_registry(); } #endif // GTEST_HAS_PARAM_TEST // Creates an empty UnitTest. UnitTest::UnitTest() { impl_ = new internal::UnitTestImpl(this); } // Destructor of UnitTest. UnitTest::~UnitTest() { delete impl_; } // Pushes a trace defined by SCOPED_TRACE() on to the per-thread // Google Test trace stack. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), #ifdef _MSC_VER # pragma warning(push) // Saves the current warning state. # pragma warning(disable:4355) // Temporarily disables warning 4355 // (using this in initializer). default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), # pragma warning(pop) // Restores the warning state again. #else default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), #endif // _MSC_VER global_test_part_result_repoter_( &default_global_test_part_result_reporter_), per_thread_test_part_result_reporter_( &default_per_thread_test_part_result_reporter_), #if GTEST_HAS_PARAM_TEST parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), os_stack_trace_getter_(NULL), post_flag_parse_init_performed_(false), random_seed_(0), // Will be overridden by the flag before first use. random_(0), // Will be reseeded before first use. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test, to current test case's ad_hoc_test_result when invoke // from SetUpTestCase/TearDownTestCase, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. if (current_test_info_ != NULL) { xml_element = "testcase"; test_result = &(current_test_info_->result_); } else if (current_test_case_ != NULL) { xml_element = "testsuite"; test_result = &(current_test_case_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; } test_result->RecordProperty(xml_element, test_property); } #if GTEST_HAS_DEATH_TEST // Disables event forwarding if the control is currently in a death test // subprocess. Must not be called before InitGoogleTest. void UnitTestImpl::SuppressTestEventsIfInSubprocess() { if (internal_run_death_test_flag_.get() != NULL) listeners()->SuppressEventForwarding(); } #endif // GTEST_HAS_DEATH_TEST // Initializes event listeners performing XML output as specified by // UnitTestOptions. Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureXmlOutput() { const std::string& output_format = UnitTestOptions::GetOutputFormat(); if (output_format == "xml") { listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); } else if (output_format != "") { printf("WARNING: unrecognized output format \"%s\" ignored.\n", output_format.c_str()); fflush(stdout); } } #if GTEST_CAN_STREAM_RESULTS_ // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", target.c_str()); fflush(stdout); } } } #endif // GTEST_CAN_STREAM_RESULTS_ // Performs initialization dependent upon flag values obtained in // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest // this function is also called from RunAllTests. Since this function can be // called more than once, it has to be idempotent. void UnitTestImpl::PostFlagParsingInit() { // Ensures that this function does not execute more than once. if (!post_flag_parse_init_performed_) { post_flag_parse_init_performed_ = true; #if GTEST_HAS_DEATH_TEST InitDeathTestSubprocessControlInfo(); SuppressTestEventsIfInSubprocess(); #endif // GTEST_HAS_DEATH_TEST // Registers parameterized tests. This makes parameterized tests // available to the UnitTest reflection API without running // RUN_ALL_TESTS. RegisterParameterizedTests(); // Configures listeners for XML output. This makes it possible for users // to shut down the default XML output before invoking RUN_ALL_TESTS. ConfigureXmlOutput(); #if GTEST_CAN_STREAM_RESULTS_ // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ } } // A predicate that checks the name of a TestCase against a known // value. // // This is used for implementation of the UnitTest class only. We put // it in the anonymous namespace to prevent polluting the outer // namespace. // // TestCaseNameIs is copyable. class TestCaseNameIs { public: // Constructor. explicit TestCaseNameIs(const std::string& name) : name_(name) {} // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: std::string name_; }; // Finds and returns a TestCase with the given name. If one doesn't // exist, creates one and returns it. It's the CALLER'S // RESPONSIBILITY to ensure that this function is only called WHEN THE // TESTS ARE NOT SHUFFLED. // // Arguments: // // test_case_name: name of the test case // type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized test case. // set_up_tc: pointer to the function that sets up the test case // tear_down_tc: pointer to the function that tears down the test case TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, const char* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::const_iterator test_case = std::find_if(test_cases_.begin(), test_cases_.end(), TestCaseNameIs(test_case_name)); if (test_case != test_cases_.end()) return *test_case; // No. Let's create one. TestCase* const new_test_case = new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(test_case_name, kDeathTestCaseFilter)) { // Yes. Inserts the test case after the last death test case // defined so far. This only works when the test cases haven't // been shuffled. Otherwise we may end up running a death test // after a non-death test. ++last_death_test_case_; test_cases_.insert(test_cases_.begin() + last_death_test_case_, new_test_case); } else { // No. Appends to the end of the list. test_cases_.push_back(new_test_case); } test_case_indices_.push_back(static_cast(test_case_indices_.size())); return new_test_case; } // Helpers for setting up / tearing down the given environment. They // are for use in the ForEach() function. static void SetUpEnvironment(Environment* env) { env->SetUp(); } static void TearDownEnvironment(Environment* env) { env->TearDown(); } // Runs all tests in this UnitTest object, prints the result, and // returns true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the // rest of the tests will still be run. // // When parameterized tests are enabled, it expands and registers // parameterized tests first in RegisterParameterizedTests(). // All other functions called from RunAllTests() may safely assume that // parameterized tests are ready to be counted and run. bool UnitTestImpl::RunAllTests() { // Makes sure InitGoogleTest() was called. if (!GTestIsInitialized()) { printf("%s", "\nThis test program did NOT call ::testing::InitGoogleTest " "before calling RUN_ALL_TESTS(). Please fix it.\n"); return false; } // Do not run any test if the --help flag was specified. if (g_help_flag) return true; // Repeats the call to the post-flag parsing initialization in case the // user didn't call InitGoogleTest. PostFlagParsingInit(); // Even if sharding is not on, test runners may want to use the // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding // protocol. internal::WriteToShardStatusFileIfNeeded(); // True iff we are in a subprocess for running a thread-safe-style // death test. bool in_subprocess_for_death_test = false; #if GTEST_HAS_DEATH_TEST in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); #endif // GTEST_HAS_DEATH_TEST const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, in_subprocess_for_death_test); // Compares the full test names with the filter to decide which // tests to run. const bool has_tests_to_run = FilterTests(should_shard ? HONOR_SHARDING_PROTOCOL : IGNORE_SHARDING_PROTOCOL) > 0; // Lists the tests and exits if the --gtest_list_tests flag was specified. if (GTEST_FLAG(list_tests)) { // This must be called *after* FilterTests() has been called. ListTestsMatchingFilter(); return true; } random_seed_ = GTEST_FLAG(shuffle) ? GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; // True iff at least one test has failed. bool failed = false; TestEventListener* repeater = listeners()->repeater(); start_timestamp_ = GetTimeInMillis(); repeater->OnTestProgramStart(*parent_); // How many times to repeat the tests? We don't want to repeat them // when we are inside the subprocess of a death test. const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); // Repeats forever if the repeat count is negative. const bool forever = repeat < 0; for (int i = 0; forever || i != repeat; i++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); const TimeInMillis start = GetTimeInMillis(); // Shuffles test cases and tests if requested. if (has_tests_to_run && GTEST_FLAG(shuffle)) { random()->Reseed(random_seed_); // This should be done before calling OnTestIterationStart(), // such that a test event listener can see the actual test order // in the event. ShuffleTests(); } // Tells the unit test event listeners that the tests are about to start. repeater->OnTestIterationStart(*parent_, i); // Runs each test case if there is at least one test to run. if (has_tests_to_run) { // Sets up all environments beforehand. repeater->OnEnvironmentsSetUpStart(*parent_); ForEach(environments_, SetUpEnvironment); repeater->OnEnvironmentsSetUpEnd(*parent_); // Runs the tests only if there was no fatal failure during global // set-up. if (!Test::HasFatalFailure()) { for (int test_index = 0; test_index < total_test_case_count(); test_index++) { GetMutableTestCase(test_index)->Run(); } } // Tears down all environments in reverse order afterwards. repeater->OnEnvironmentsTearDownStart(*parent_); std::for_each(environments_.rbegin(), environments_.rend(), TearDownEnvironment); repeater->OnEnvironmentsTearDownEnd(*parent_); } elapsed_time_ = GetTimeInMillis() - start; // Tells the unit test event listener that the tests have just finished. repeater->OnTestIterationEnd(*parent_, i); // Gets the result and clears it. if (!Passed()) { failed = true; } // Restores the original test order after the iteration. This // allows the user to quickly repro a failure that happens in the // N-th iteration without repeating the first (N - 1) iterations. // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in // case the user somehow changes the value of the flag somewhere // (it's always safe to unshuffle the tests). UnshuffleTests(); if (GTEST_FLAG(shuffle)) { // Picks a new random seed for each iteration. random_seed_ = GetNextRandomSeed(random_seed_); } } repeater->OnTestProgramEnd(*parent_); return !failed; } // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file // if the variable is present. If a file already exists at this location, this // function will write over it. If the variable is present, but the file cannot // be created, prints an error and exits. void WriteToShardStatusFileIfNeeded() { const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); if (test_shard_file != NULL) { FILE* const file = posix::FOpen(test_shard_file, "w"); if (file == NULL) { ColoredPrintf(COLOR_RED, "Could not write to the test shard status file \"%s\" " "specified by the %s environment variable.\n", test_shard_file, kTestShardStatusFile); fflush(stdout); exit(EXIT_FAILURE); } fclose(file); } } // Checks whether sharding is enabled by examining the relevant // environment variable values. If the variables are present, // but inconsistent (i.e., shard_index >= total_shards), prints // an error and exits. If in_subprocess_for_death_test, sharding is // disabled because it must only be applied to the original test // process. Otherwise, we could filter out death tests we intended to execute. bool ShouldShard(const char* total_shards_env, const char* shard_index_env, bool in_subprocess_for_death_test) { if (in_subprocess_for_death_test) { return false; } const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); if (total_shards == -1 && shard_index == -1) { return false; } else if (total_shards == -1 && shard_index != -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestShardIndex << " = " << shard_index << ", but have left " << kTestTotalShards << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (total_shards != -1 && shard_index == -1) { const Message msg = Message() << "Invalid environment variables: you have " << kTestTotalShards << " = " << total_shards << ", but have left " << kTestShardIndex << " unset.\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } else if (shard_index < 0 || shard_index >= total_shards) { const Message msg = Message() << "Invalid environment variables: we require 0 <= " << kTestShardIndex << " < " << kTestTotalShards << ", but you have " << kTestShardIndex << "=" << shard_index << ", " << kTestTotalShards << "=" << total_shards << ".\n"; ColoredPrintf(COLOR_RED, msg.GetString().c_str()); fflush(stdout); exit(EXIT_FAILURE); } return total_shards > 1; } // Parses the environment variable var as an Int32. If it is unset, // returns default_val. If it is not an Int32, prints an error // and aborts. Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { const char* str_val = posix::GetEnv(var); if (str_val == NULL) { return default_val; } Int32 result; if (!ParseInt32(Message() << "The value of environment variable " << var, str_val, &result)) { exit(EXIT_FAILURE); } return result; } // Given the total number of shards, the shard index, and the test id, // returns true iff the test should be run on this shard. The test id is // some arbitrary but unique non-negative integer assigned to each test // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { return (test_id % total_shards) == shard_index; } // Compares the name of each test with the user-specified filter to // decide whether the test should be run, then records the result in // each TestCase and TestInfo object. // If shard_tests == true, further filters tests based on sharding // variables in the environment - see // http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. // Returns the number of tests that should run. int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestTotalShards, -1) : -1; const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? Int32FromEnvOrDie(kTestShardIndex, -1) : -1; // num_runnable_tests are the number of tests that will // run across all shards (i.e., match filter and are not disabled). // num_selected_tests are the number of tests to be run on // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; for (size_t i = 0; i < test_cases_.size(); i++) { TestCase* const test_case = test_cases_[i]; const std::string &test_case_name = test_case->name(); test_case->set_should_run(false); for (size_t j = 0; j < test_case->test_info_list().size(); j++) { TestInfo* const test_info = test_case->test_info_list()[j]; const std::string test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. const bool is_disabled = internal::UnitTestOptions::MatchesFilter(test_case_name, kDisableTestFilter) || internal::UnitTestOptions::MatchesFilter(test_name, kDisableTestFilter); test_info->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->matches_filter_ = matches_filter; const bool is_runnable = (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && matches_filter; const bool is_selected = is_runnable && (shard_tests == IGNORE_SHARDING_PROTOCOL || ShouldRunTestOnShard(total_shards, shard_index, num_runnable_tests)); num_runnable_tests += is_runnable; num_selected_tests += is_selected; test_info->should_run_ = is_selected; test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { if (str != NULL) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); break; } if (*str == '\n') { printf("\\n"); i += 2; } else { printf("%c", *str); ++i; } } } } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; for (size_t i = 0; i < test_cases_.size(); i++) { const TestCase* const test_case = test_cases_[i]; bool printed_test_case_name = false; for (size_t j = 0; j < test_case->test_info_list().size(); j++) { const TestInfo* const test_info = test_case->test_info_list()[j]; if (test_info->matches_filter_) { if (!printed_test_case_name) { printed_test_case_name = true; printf("%s.", test_case->name()); if (test_case->type_param() != NULL) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_case->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); if (test_info->value_param() != NULL) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. PrintOnOneLine(test_info->value_param(), kMaxParamLength); } printf("\n"); } } } fflush(stdout); } // Sets the OS stack trace getter. // // Does nothing if the input and the current OS stack trace getter are // the same; otherwise, deletes the old getter and makes the input the // current getter. void UnitTestImpl::set_os_stack_trace_getter( OsStackTraceGetterInterface* getter) { if (os_stack_trace_getter_ != getter) { delete os_stack_trace_getter_; os_stack_trace_getter_ = getter; } } // Returns the current OS stack trace getter if it is not NULL; // otherwise, creates an OsStackTraceGetter, makes it the current // getter, and returns it. OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { if (os_stack_trace_getter_ == NULL) { os_stack_trace_getter_ = new OsStackTraceGetter; } return os_stack_trace_getter_; } // Returns the TestResult for the test that's currently running, or // the TestResult for the ad hoc test if no test is running. TestResult* UnitTestImpl::current_test_result() { return current_test_info_ ? &(current_test_info_->result_) : &ad_hoc_test_result_; } // Shuffles all test cases, and the tests within each test case, // making sure that death tests are still run first. void UnitTestImpl::ShuffleTests() { // Shuffles the death test cases. ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); // Shuffles the non-death test cases. ShuffleRange(random(), last_death_test_case_ + 1, static_cast(test_cases_.size()), &test_case_indices_); // Shuffles the tests inside each test case. for (size_t i = 0; i < test_cases_.size(); i++) { test_cases_[i]->ShuffleTests(random()); } } // Restores the test cases and tests to their order before the first shuffle. void UnitTestImpl::UnshuffleTests() { for (size_t i = 0; i < test_cases_.size(); i++) { // Unshuffles the tests in each test case. test_cases_[i]->UnshuffleTests(); // Resets the index of each test case. test_case_indices_[i] = static_cast(i); } } // Returns the current OS stack trace as an std::string. // // The maximum number of stack frames to be included is specified by // the gtest_stack_trace_depth flag. The skip_count parameter // specifies the number of top frames to be skipped, which doesn't // count against the number of frames to be included. // // For example, if Foo() calls Bar(), which in turn calls // GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in // the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, int skip_count) { // We pass skip_count + 1 to skip this wrapper function in addition // to what the user really wants to skip. return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); } // Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to // suppress unreachable code warnings. namespace { class ClassUniqueToAlwaysTrue {}; } bool IsTrue(bool condition) { return condition; } bool AlwaysTrue() { #if GTEST_HAS_EXCEPTIONS // This condition is always false so AlwaysTrue() never actually throws, // but it makes the compiler think that it may throw. if (IsTrue(false)) throw ClassUniqueToAlwaysTrue(); #endif // GTEST_HAS_EXCEPTIONS return true; } // If *pstr starts with the given prefix, modifies *pstr to be right // past the prefix and returns true; otherwise leaves *pstr unchanged // and returns false. None of pstr, *pstr, and prefix can be NULL. bool SkipPrefix(const char* prefix, const char** pstr) { const size_t prefix_len = strlen(prefix); if (strncmp(*pstr, prefix, prefix_len) == 0) { *pstr += prefix_len; return true; } return false; } // Parses a string as a command line flag. The string should have // the format "--flag=value". When def_optional is true, the "=value" // part can be omitted. // // Returns the value of the flag, or NULL if the parsing failed. const char* ParseFlagValue(const char* str, const char* flag, bool def_optional) { // str and flag must not be NULL. if (str == NULL || flag == NULL) return NULL; // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; const size_t flag_len = flag_str.length(); if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; // Skips the flag name. const char* flag_end = str + flag_len; // When def_optional is true, it's OK to not have a "=value" part. if (def_optional && (flag_end[0] == '\0')) { return flag_end; } // If def_optional is true and there are more characters after the // flag name, or if def_optional is false, there must be a '=' after // the flag name. if (flag_end[0] != '=') return NULL; // Returns the string after "=". return flag_end + 1; } // Parses a string for a bool flag, in the form of either // "--flag=value" or "--flag". // // In the former case, the value is taken as true as long as it does // not start with '0', 'f', or 'F'. // // In the latter case, the value is taken as true. // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseBoolFlag(const char* str, const char* flag, bool* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, true); // Aborts if the parsing failed. if (value_str == NULL) return false; // Converts the string value to a bool. *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); return true; } // Parses a string for an Int32 flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. return ParseInt32(Message() << "The value of flag --" << flag, value_str, value); } // Parses a string for a string flag, in the form of // "--flag=value". // // On success, stores the value of the flag in *value, and returns // true. On failure, returns false without changing *value. bool ParseStringFlag(const char* str, const char* flag, std::string* value) { // Gets the value of the flag as a string. const char* const value_str = ParseFlagValue(str, flag, false); // Aborts if the parsing failed. if (value_str == NULL) return false; // Sets *value to the value of the flag. *value = value_str; return true; } // Determines whether a string has a prefix that Google Test uses for its // flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. // If Google Test detects that a command line flag has its prefix but is not // recognized, it will print its help message. Flags starting with // GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test // internal flags and do not trigger the help message. static bool HasGoogleTestFlagPrefix(const char* str) { return (SkipPrefix("--", &str) || SkipPrefix("-", &str) || SkipPrefix("/", &str)) && !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); } // Prints a string containing code-encoded text. The following escape // sequences can be used in the string to control the text color: // // @@ prints a single '@' character. // @R changes the color to red. // @G changes the color to green. // @Y changes the color to yellow. // @D changes to the default terminal text color. // // TODO(wan@google.com): Write tests for this once we add stdout // capturing to Google Test. static void PrintColorEncoded(const char* str) { GTestColor color = COLOR_DEFAULT; // The current color. // Conceptually, we split the string into segments divided by escape // sequences. Then we print one segment at a time. At the end of // each iteration, the str pointer advances to the beginning of the // next segment. for (;;) { const char* p = strchr(str, '@'); if (p == NULL) { ColoredPrintf(color, "%s", str); return; } ColoredPrintf(color, "%s", std::string(str, p).c_str()); const char ch = p[1]; str = p + 2; if (ch == '@') { ColoredPrintf(color, "@"); } else if (ch == 'D') { color = COLOR_DEFAULT; } else if (ch == 'R') { color = COLOR_RED; } else if (ch == 'G') { color = COLOR_GREEN; } else if (ch == 'Y') { color = COLOR_YELLOW; } else { --str; } } } static const char kColorEncodedHelpMessage[] = "This program contains tests written using " GTEST_NAME_ ". You can use the\n" "following command line flags to control its behavior:\n" "\n" "Test Selection:\n" " @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" " List the names of all tests instead of running them. The name of\n" " TEST(Foo, Bar) is \"Foo.Bar\".\n" " @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" "[@G-@YNEGATIVE_PATTERNS]@D\n" " Run only the tests whose name matches one of the positive patterns but\n" " none of the negative patterns. '?' matches any single character; '*'\n" " matches any substring; ':' separates two patterns.\n" " @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" " Run all disabled tests too.\n" "\n" "Test Execution:\n" " @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" " Run the tests repeatedly; use a negative count to repeat forever.\n" " @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" " Randomize tests' orders on every iteration.\n" " @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" " Random number seed to use for shuffling test orders (between 1 and\n" " 99999, or 0 to use a seed based on the current time).\n" "\n" "Test Output:\n" " @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" " Enable/disable colored output. The default is @Gauto@D.\n" " -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" " Don't print the elapsed time of each test.\n" " @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" " Generate an XML report in the given directory or with the given file\n" " name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" #if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" #endif // GTEST_CAN_STREAM_RESULTS_ "\n" "Assertion Behavior:\n" #if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" " Set the default death test style.\n" #endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS " @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" " Turn assertion failures into debugger break-points.\n" " @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" " Turn assertion failures into C++ exceptions.\n" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" "\n" "Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " "the corresponding\n" "environment variable of a flag (all letters in upper-case). For example, to\n" "disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ "color=no@D or set\n" "the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" "\n" "For more information, please read the " GTEST_NAME_ " documentation at\n" "@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" "(not one in your own code or tests), please report it to\n" "@G<" GTEST_DEV_EMAIL_ ">@D.\n"; // Parses the command line for Google Test flags, without initializing // other parts of Google Test. The type parameter CharType can be // instantiated to either char or wchar_t. template void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; // Do we see a Google Test flag? if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)) ) { // Yes. Shift the remainder of the argv list left by one. Note // that argv has (*argc + 1) elements, the last one always being // NULL. The following loop moves the trailing NULL element as // well. for (int j = i; j != *argc; j++) { argv[j] = argv[j + 1]; } // Decrements the argument count. (*argc)--; // We also need to decrement the iterator as we just removed // an element. i--; } else if (arg_string == "--help" || arg_string == "-h" || arg_string == "-?" || arg_string == "/?" || HasGoogleTestFlagPrefix(arg)) { // Both help flag and unrecognized Google Test flags (excluding // internal ones) trigger help display. g_help_flag = true; } } if (g_help_flag) { // We print the help here instead of in RUN_ALL_TESTS(), as the // latter may not be called at all if the user is using Google // Test with another testing framework. PrintColorEncoded(kColorEncodedHelpMessage); } } // Parses the command line for Google Test flags, without initializing // other parts of Google Test. void ParseGoogleTestFlagsOnly(int* argc, char** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { ParseGoogleTestFlagsOnlyImpl(argc, argv); } // The internal implementation of InitGoogleTest(). // // The type parameter CharType can be instantiated to either char or // wchar_t. template void InitGoogleTestImpl(int* argc, CharType** argv) { g_init_gtest_count++; // We don't want to run the initialization code twice. if (g_init_gtest_count != 1) return; if (*argc <= 0) return; internal::g_executable_path = internal::StreamableToString(argv[0]); #if GTEST_HAS_DEATH_TEST g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } #endif // GTEST_HAS_DEATH_TEST ParseGoogleTestFlagsOnly(argc, argv); GetUnitTestImpl()->PostFlagParsingInit(); } } // namespace internal // Initializes Google Test. This must be called before calling // RUN_ALL_TESTS(). In particular, it parses a command line for the // flags that Google Test recognizes. Whenever a Google Test flag is // seen, it is removed from argv, and *argc is decremented. // // No value is returned. Instead, the Google Test flag variables are // updated. // // Calling the function for the second time has no user-visible effect. void InitGoogleTest(int* argc, char** argv) { internal::InitGoogleTestImpl(argc, argv); } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { internal::InitGoogleTestImpl(argc, argv); } } // namespace testing // Copyright 2005, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) // // This file implements death tests. #if GTEST_HAS_DEATH_TEST # if GTEST_OS_MAC # include # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # endif // GTEST_OS_QNX #endif // GTEST_HAS_DEATH_TEST // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { // Constants. // The default death test style. static const char kDefaultDeathTestStyle[] = "fast"; GTEST_DEFINE_string_( death_test_style, internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), "Indicates how to run a death test in a forked child process: " "\"threadsafe\" (child process re-executes the test binary " "from the beginning, running only the specific death test) or " "\"fast\" (child process runs the death test immediately " "after forking)."); GTEST_DEFINE_bool_( death_test_use_fork, internal::BoolFromGTestEnv("death_test_use_fork", false), "Instructs to use fork()/_exit() instead of clone() in death tests. " "Ignored and always uses fork() on POSIX systems where clone() is not " "implemented. Useful when running under valgrind or similar tools if " "those do not support clone(). Valgrind 3.3.1 will just fail if " "it sees an unsupported combination of clone() flags. " "It is not recommended to use this flag w/o valgrind though it will " "work in 99% of the cases. Once valgrind is fixed, this flag will " "most likely be removed."); namespace internal { GTEST_DEFINE_string_( internal_run_death_test, "", "Indicates the file, line number, temporal index of " "the single death test to run, and a file descriptor to " "which a success code may be sent, all separated by " "the '|' characters. This flag is specified if and only if the current " "process is a sub-process launched for running a thread-safe " "death test. FOR INTERNAL USE ONLY."); } // namespace internal #if GTEST_HAS_DEATH_TEST namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. static bool g_in_fast_death_test_child = false; // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { # if GTEST_OS_WINDOWS // On Windows, death tests are thread-safe regardless of the value of the // death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); else return g_in_fast_death_test_child; #endif } } // namespace internal // ExitedWithCode constructor. ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { } // ExitedWithCode function-call operator. bool ExitedWithCode::operator()(int exit_status) const { # if GTEST_OS_WINDOWS return exit_status == exit_code_; # else return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; # endif // GTEST_OS_WINDOWS } # if !GTEST_OS_WINDOWS // KilledBySignal constructor. KilledBySignal::KilledBySignal(int signum) : signum_(signum) { } // KilledBySignal function-call operator. bool KilledBySignal::operator()(int exit_status) const { return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; } # endif // !GTEST_OS_WINDOWS namespace internal { // Utilities needed for death tests. // Generates a textual description of a given exit code, in the format // specified by wait(2). static std::string ExitSummary(int exit_code) { Message m; # if GTEST_OS_WINDOWS m << "Exited with exit status " << exit_code; # else if (WIFEXITED(exit_code)) { m << "Exited with exit status " << WEXITSTATUS(exit_code); } else if (WIFSIGNALED(exit_code)) { m << "Terminated by signal " << WTERMSIG(exit_code); } # ifdef WCOREDUMP if (WCOREDUMP(exit_code)) { m << " (core dumped)"; } # endif # endif // GTEST_OS_WINDOWS return m.GetString(); } // Returns true if exit_status describes a process that was terminated // by a signal, or exited normally with a nonzero exit code. bool ExitedUnsuccessfully(int exit_status) { return !ExitedWithCode(0)(exit_status); } # if !GTEST_OS_WINDOWS // Generates a textual failure message when a death test finds more than // one thread running, or cannot determine the number of threads, prior // to executing the given statement. It is the responsibility of the // caller not to pass a thread_count of 1. static std::string DeathTestThreadWarning(size_t thread_count) { Message msg; msg << "Death tests use fork(), which is unsafe particularly" << " in a threaded context. For this test, " << GTEST_NAME_ << " "; if (thread_count == 0) msg << "couldn't detect the number of threads."; else msg << "detected " << thread_count << " threads."; return msg.GetString(); } # endif // !GTEST_OS_WINDOWS // Flag characters for reporting a death test that did not die. static const char kDeathTestLived = 'L'; static const char kDeathTestReturned = 'R'; static const char kDeathTestThrew = 'T'; static const char kDeathTestInternalError = 'I'; // An enumeration describing all of the possible ways that a death test can // conclude. DIED means that the process died while executing the test // code; LIVED means that process lived beyond the end of the test code; // RETURNED means that the test statement attempted to execute a return // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. // TODO(vladl@google.com): Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // Routine for aborting the program which is safe to call from an // exec-style death test child process, in which case the error // message is propagated back to the parent process. Otherwise, the // message is simply printed to stderr. In either case, the program // then exits with status 1. void DeathTestAbort(const std::string& message) { // On a POSIX system, this function may be called from a threadsafe-style // death test child process, which operates on a very small stack. Use // the heap for any additional non-minuscule memory requirements. const InternalRunDeathTestFlag* const flag = GetUnitTestImpl()->internal_run_death_test_flag(); if (flag != NULL) { FILE* parent = posix::FDOpen(flag->write_fd(), "w"); fputc(kDeathTestInternalError, parent); fprintf(parent, "%s", message.c_str()); fflush(parent); _exit(1); } else { fprintf(stderr, "%s", message.c_str()); fflush(stderr); posix::Abort(); } } // A replacement for CHECK that calls DeathTestAbort if the assertion // fails. # define GTEST_DEATH_TEST_CHECK_(expression) \ do { \ if (!::testing::internal::IsTrue(expression)) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression); \ } \ } while (::testing::internal::AlwaysFalse()) // This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for // evaluating any system call that fulfills two conditions: it must return // -1 on failure, and set errno to EINTR when it is interrupted and // should be tried again. The macro expands to a loop that repeatedly // evaluates the expression as long as it evaluates to -1 and sets // errno to EINTR. If the expression evaluates to -1 but errno is // something other than EINTR, DeathTestAbort is called. # define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ do { \ int gtest_retval; \ do { \ gtest_retval = (expression); \ } while (gtest_retval == -1 && errno == EINTR); \ if (gtest_retval == -1) { \ DeathTestAbort( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { return errno == 0 ? "" : posix::StrError(errno); } // This is called from a death test parent process to read a failure // message from the death test child process and log it with the FATAL // severity. On Windows, the message is read from a pipe handle. On other // platforms, it is read from a file descriptor. static void FailFromInternalError(int fd) { Message error; char buffer[256]; int num_read; do { while ((num_read = posix::Read(fd, buffer, 255)) > 0) { buffer[num_read] = '\0'; error << buffer; } } while (num_read == -1 && errno == EINTR); if (num_read == 0) { GTEST_LOG_(FATAL) << error.GetString(); } else { const int last_error = errno; GTEST_LOG_(FATAL) << "Error while reading death test internal: " << GetLastErrnoDescription() << " [" << last_error << "]"; } } // Death test constructor. Increments the running death test count // for the current test. DeathTest::DeathTest() { TestInfo* const info = GetUnitTestImpl()->current_test_info(); if (info == NULL) { DeathTestAbort("Cannot run a death test outside of a TEST or " "TEST_F construct"); } } // Creates and returns a death test by dispatching to the current // death test factory. bool DeathTest::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { return GetUnitTestImpl()->death_test_factory()->Create( statement, regex, file, line, test); } const char* DeathTest::LastMessage() { return last_death_test_message_.c_str(); } void DeathTest::set_last_death_test_message(const std::string& message) { last_death_test_message_ = message; } std::string DeathTest::last_death_test_message_; // Provides cross platform implementation for some death functionality. class DeathTestImpl : public DeathTest { protected: DeathTestImpl(const char* a_statement, const RE* a_regex) : statement_(a_statement), regex_(a_regex), spawned_(false), status_(-1), outcome_(IN_PROGRESS), read_fd_(-1), write_fd_(-1) {} // read_fd_ is expected to be closed and cleared by a derived class. ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } void Abort(AbortReason reason); virtual bool Passed(bool status_ok); const char* statement() const { return statement_; } const RE* regex() const { return regex_; } bool spawned() const { return spawned_; } void set_spawned(bool is_spawned) { spawned_ = is_spawned; } int status() const { return status_; } void set_status(int a_status) { status_ = a_status; } DeathTestOutcome outcome() const { return outcome_; } void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } int read_fd() const { return read_fd_; } void set_read_fd(int fd) { read_fd_ = fd; } int write_fd() const { return write_fd_; } void set_write_fd(int fd) { write_fd_ = fd; } // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void ReadAndInterpretStatusByte(); private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. const char* const statement_; // The regular expression which test output must match. DeathTestImpl // doesn't own this object and should not attempt to delete it. const RE* const regex_; // True if the death test child process has been successfully spawned. bool spawned_; // The exit status of the child process. int status_; // How the death test concluded. DeathTestOutcome outcome_; // Descriptor to the read end of the pipe to the child process. It is // always -1 in the child process. The child keeps its write end of the // pipe in write_fd_. int read_fd_; // Descriptor to the child's write end of the pipe to the parent process. // It is always -1 in the parent process. The parent keeps its end of the // pipe in read_fd_. int write_fd_; }; // Called in the parent process only. Reads the result code of the death // test child process via a pipe, interprets it to set the outcome_ // member, and closes read_fd_. Outputs diagnostics and terminates in // case of unexpected codes. void DeathTestImpl::ReadAndInterpretStatusByte() { char flag; int bytes_read; // The read() here blocks until data is available (signifying the // failure of the death test) or until the pipe is closed (signifying // its success), so it's okay to call this in the parent before // the child process has exited. do { bytes_read = posix::Read(read_fd(), &flag, 1); } while (bytes_read == -1 && errno == EINTR); if (bytes_read == 0) { set_outcome(DIED); } else if (bytes_read == 1) { switch (flag) { case kDeathTestReturned: set_outcome(RETURNED); break; case kDeathTestThrew: set_outcome(THREW); break; case kDeathTestLived: set_outcome(LIVED); break; case kDeathTestInternalError: FailFromInternalError(read_fd()); // Does not return. break; default: GTEST_LOG_(FATAL) << "Death test child process reported " << "unexpected status byte (" << static_cast(flag) << ")"; } } else { GTEST_LOG_(FATAL) << "Read from death test child process failed: " << GetLastErrnoDescription(); } GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); set_read_fd(-1); } // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then // calls _exit(1). void DeathTestImpl::Abort(AbortReason reason) { // The parent process considers the death test to be a failure if // it finds any data in our pipe. So, here we write a single flag byte // to the pipe, then exit. const char status_ch = reason == TEST_DID_NOT_DIE ? kDeathTestLived : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still // run after calling _exit(). On such systems, write_fd_ will be // indirectly closed from the destructor of UnitTestImpl, causing double // close if it is also closed here. On debug configurations, double close // may assert. As there are no in-process buffers to flush here, we are // relying on the OS to close the descriptor after the process terminates // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. static ::std::string FormatDeathTestOutput(const ::std::string& output) { ::std::string ret; for (size_t at = 0; ; ) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { ret += output.substr(at); break; } ret += output.substr(at, line_end + 1 - at); at = line_end + 1; } return ret; } // Assesses the success or failure of a death test, using both private // members which have previously been set, and one argument: // // Private data members: // outcome: An enumeration describing how the death test // concluded: DIED, LIVED, THREW, or RETURNED. The death test // fails in the latter three cases. // status: The exit status of the child process. On *nix, it is in the // in the format specified by wait(2). On Windows, this is the // value supplied to the ExitProcess() API or a numeric code // of the exception that terminated the program. // regex: A regular expression object to be applied to // the test's captured standard error output; the death test // fails if it does not match. // // Argument: // status_ok: true if exit_status is acceptable in the context of // this particular death test, which fails if it is false // // Returns true iff all of the above conditions are met. Otherwise, the // first failing condition, in the order given above, is the one that is // reported. Also sets the last death test message string. bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; const std::string error_message = GetCapturedStderr(); bool success = false; Message buffer; buffer << "Death test: " << statement() << "\n"; switch (outcome()) { case LIVED: buffer << " Result: failed to die.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case DIED: if (status_ok) { const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); if (matched) { success = true; } else { buffer << " Result: died but not with expected error.\n" << " Expected: " << regex()->pattern() << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } break; case IN_PROGRESS: default: GTEST_LOG_(FATAL) << "DeathTest::Passed somehow called before conclusion of test"; } DeathTest::set_last_death_test_message(buffer.GetString()); return success; } # if GTEST_OS_WINDOWS // WindowsDeathTest implements death tests on Windows. Due to the // specifics of starting new processes on Windows, death tests there are // always threadsafe, and Google Test considers the // --gtest_death_test_style=fast setting to be equivalent to // --gtest_death_test_style=threadsafe there. // // A few implementation notes: Like the Linux version, the Windows // implementation uses pipes for child-to-parent communication. But due to // the specifics of pipes on Windows, some extra steps are required: // // 1. The parent creates a communication pipe and stores handles to both // ends of it. // 2. The parent starts the child and provides it with the information // necessary to acquire the handle to the write end of the pipe. // 3. The child acquires the write end of the pipe and signals the parent // using a Windows event. // 4. Now the parent can release the write end of the pipe on its side. If // this is done before step 3, the object's reference count goes down to // 0 and it is destroyed, preventing the child from acquiring it. The // parent now has to release it, or read operations on the read end of // the pipe will not return when the child terminates. // 5. The parent reads child's output through the pipe (outcome code and // any possible error messages) from the pipe, and its stderr and then // determines whether to fail the test. // // Note: to distinguish Win32 API calls from the local method and function // calls, the former are explicitly resolved in the global namespace. // class WindowsDeathTest : public DeathTestImpl { public: WindowsDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} // All of these virtual functions are inherited from DeathTest. virtual int Wait(); virtual TestRole AssumeRole(); private: // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; // Handle to the write end of the pipe to the child process. AutoHandle write_handle_; // Child process handle. AutoHandle child_handle_; // Event the child process uses to signal the parent that it has // acquired the handle to the write end of the pipe. After seeing this // event the parent can release its own handles to make sure its // ReadFile() calls return when the child terminates. AutoHandle event_handle_; }; // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int WindowsDeathTest::Wait() { if (!spawned()) return 0; // Wait until the child either signals that it has acquired the write end // of the pipe or it dies. const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; switch (::WaitForMultipleObjects(2, wait_handles, FALSE, // Waits for any of the handles. INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: break; default: GTEST_DEATH_TEST_CHECK_(false); // Should not get here. } // The child has acquired the write end of the pipe or exited. // We release the handle on our side and continue. write_handle_.Reset(); event_handle_.Reset(); ReadAndInterpretStatusByte(); // Waits for the child process to exit if it haven't already. This // returns immediately if the child has already exited, regardless of // whether previous calls to WaitForMultipleObjects synchronized on this // handle or not. GTEST_DEATH_TEST_CHECK_( WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), INFINITE)); DWORD status_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); set_status(static_cast(status_code)); return status(); } // The AssumeRole process for a Windows death test. It creates a child // process with the same executable as the current process to run the // death test. The child process is given the --gtest_filter and // --gtest_internal_run_death_test flags such that it knows to run the // current death test only. DeathTest::TestRole WindowsDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { // ParseInternalRunDeathTestFlag() has performed all the necessary // processing. set_write_fd(flag->write_fd()); return EXECUTE_TEST; } // WindowsDeathTest uses an anonymous pipe to communicate results of // a death test. SECURITY_ATTRIBUTES handles_are_inheritable = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; HANDLE read_handle, write_handle; GTEST_DEATH_TEST_CHECK_( ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, 0) // Default buffer size. != FALSE); set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), O_RDONLY)); write_handle_.Reset(write_handle); event_handle_.Reset(::CreateEvent( &handles_are_inheritable, TRUE, // The event will automatically reset to non-signaled state. FALSE, // The initial state is non-signalled. NULL)); // The even is unnamed. GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + internal_flag + "\""; DeathTest::set_last_death_test_message(""); CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); // The child process will share the standard handles with the parent. STARTUPINFOA startup_info; memset(&startup_info, 0, sizeof(STARTUPINFO)); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION process_info; GTEST_DEATH_TEST_CHECK_(::CreateProcessA( executable_path, const_cast(command_line.c_str()), NULL, // Retuned process handle is not inheritable. NULL, // Retuned thread handle is not inheritable. TRUE, // Child inherits all inheritable handles (for write_handle_). 0x0, // Default creation flags. NULL, // Inherit the parent's environment. UnitTest::GetInstance()->original_working_dir(), &startup_info, &process_info) != FALSE); child_handle_.Reset(process_info.hProcess); ::CloseHandle(process_info.hThread); set_spawned(true); return OVERSEE_TEST; } # else // We are not on Windows. // ForkingDeathTest provides implementations for most of the abstract // methods of the DeathTest interface. Only the AssumeRole method is // left undefined. class ForkingDeathTest : public DeathTestImpl { public: ForkingDeathTest(const char* statement, const RE* regex); // All of these virtual functions are inherited from DeathTest. virtual int Wait(); protected: void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } private: // PID of child process during death test; 0 in the child process itself. pid_t child_pid_; }; // Constructs a ForkingDeathTest. ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) : DeathTestImpl(a_statement, a_regex), child_pid_(-1) {} // Waits for the child in a death test to exit, returning its exit // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int ForkingDeathTest::Wait() { if (!spawned()) return 0; ReadAndInterpretStatusByte(); int status_value; GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); set_status(status_value); return status_value; } // A concrete death test class that forks, then immediately runs the test // in the child process. class NoExecDeathTest : public ForkingDeathTest { public: NoExecDeathTest(const char* a_statement, const RE* a_regex) : ForkingDeathTest(a_statement, a_regex) { } virtual TestRole AssumeRole(); }; // The AssumeRole process for a fork-and-run death test. It implements a // straightforward fork, with a simple pipe to transmit the status byte. DeathTest::TestRole NoExecDeathTest::AssumeRole() { const size_t thread_count = GetThreadCount(); if (thread_count != 1) { GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); DeathTest::set_last_death_test_message(""); CaptureStderr(); // When we fork the process below, the log file buffers are copied, but the // file descriptors are shared. We flush all log files here so that closing // the file descriptors in the child process doesn't throw off the // synchronization between descriptors and buffers in the parent process. // This is as close to the fork as possible to avoid a race condition in case // there are multiple threads running before the death test, and another // thread writes to the log file. FlushInfoLog(); const pid_t child_pid = fork(); GTEST_DEATH_TEST_CHECK_(child_pid != -1); set_child_pid(child_pid); if (child_pid == 0) { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); set_write_fd(pipe_fd[1]); // Redirects all logging to stderr in the child process to prevent // concurrent writes to the log files. We capture stderr in the parent // process and append the child process' output to a log. LogToStderr(); // Event forwarding to the listeners of event listener API mush be shut // down in death test subprocesses. GetUnitTestImpl()->listeners()->SuppressEventForwarding(); g_in_fast_death_test_child = true; return EXECUTE_TEST; } else { GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } } // A concrete death test class that forks and re-executes the main // program from the beginning, with command-line flags set that cause // only this specific death test to be run. class ExecDeathTest : public ForkingDeathTest { public: ExecDeathTest(const char* a_statement, const RE* a_regex, const char* file, int line) : ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } virtual TestRole AssumeRole(); private: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); return args; } // The name of the file in which the death test is located. const char* const file_; // The line number on which the death test is located. const int line_; }; // Utility class for accumulating command-line arguments. class Arguments { public: Arguments() { args_.push_back(NULL); } ~Arguments() { for (std::vector::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::const_iterator i = arguments.begin(); i != arguments.end(); ++i) { args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); } } char* const* Argv() { return &args_[0]; } private: std::vector args_; }; // A struct that encompasses the arguments to the child process of a // threadsafe-style death test process. struct ExecDeathTestArgs { char* const* argv; // Command-line arguments for the child's call to exec int close_fd; // File descriptor to close; the read end of a pipe }; # if GTEST_OS_MAC inline char** GetEnviron() { // When Google Test is built as a framework on MacOS X, the environ variable // is unavailable. Apple's documentation (man environ) recommends using // _NSGetEnviron() instead. return *_NSGetEnviron(); } # else // Some POSIX platforms expect you to declare environ. extern "C" makes // it reside in the global namespace. extern "C" char** environ; inline char** GetEnviron() { return environ; } # endif // GTEST_OS_MAC # if !GTEST_OS_QNX // The main function for a threadsafe-style death test child process. // This function is called in a clone()-ed process and thus must avoid // any potentially unsafe operations like malloc or libc functions. static int ExecDeathTestChildMain(void* child_arg) { ExecDeathTestArgs* const args = static_cast(child_arg); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } // We can safely call execve() as it's a direct system call. We // cannot use execvp() as it's a libc function and thus potentially // unsafe. Since execve() doesn't search the PATH, the user must // invoke the test program via a valid path that contains at least // one path separator. execve(args->argv[0], args->argv, GetEnviron()); DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX // Two utility routines that together determine the direction the stack // grows. // This could be accomplished more elegantly by a single recursive // function, but we want to guard against the unlikely possibility of // a smart compiler optimizing the recursion away. // // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The // implementation uses fork(2) + exec. On systems where clone(2) is // available, it is used instead, being slightly more thread-safe. On QNX, // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; # if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); // We need to execute the test program in the same environment where // it was originally invoked. Therefore we change to the original // working directory first. const char* const original_dir = UnitTest::GetInstance()->original_working_dir(); // We can safely call chdir() as it's a direct system call. if (chdir(original_dir) != 0) { DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); # else // GTEST_OS_QNX # if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. struct sigaction saved_sigprof_action; struct sigaction ignore_sigprof_action; memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); # endif // GTEST_OS_LINUX # if GTEST_HAS_CLONE const bool use_fork = GTEST_FLAG(death_test_use_fork); if (!use_fork) { static const bool stack_grows_down = StackGrowsDown(); const size_t stack_size = getpagesize(); // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); // Maximum stack alignment in bytes: For a downward-growing stack, this // amount is subtracted from size of the stack space to get an address // that is within the stack space and is aligned on all systems we care // about. As far as I know there is no ABI with stack alignment greater // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && reinterpret_cast(stack_top) % kMaxStackAlignment == 0); child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); } # else const bool use_fork = true; # endif // GTEST_HAS_CLONE if (use_fork && (child_pid = fork()) == 0) { ExecDeathTestChildMain(&args); _exit(0); } # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( sigaction(SIGPROF, &saved_sigprof_action, NULL)); # endif // GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_(child_pid != -1); return child_pid; } // The AssumeRole process for a fork-and-exec death test. It re-executes the // main program from the beginning, setting the --gtest_filter // and --gtest_internal_run_death_test flags to cause only the current // death test to be re-run. DeathTest::TestRole ExecDeathTest::AssumeRole() { const UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const TestInfo* const info = impl->current_test_info(); const int death_test_index = info->result()->death_test_count(); if (flag != NULL) { set_write_fd(flag->write_fd()); return EXECUTE_TEST; } int pipe_fd[2]; GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); // Clear the close-on-exec flag on the write end of the pipe, lest // it be closed when the child process does an exec: GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); const std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); args.AddArgument(filter_flag.c_str()); args.AddArgument(internal_flag.c_str()); DeathTest::set_last_death_test_message(""); CaptureStderr(); // See the comment in NoExecDeathTest::AssumeRole for why the next line // is necessary. FlushInfoLog(); const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); set_child_pid(child_pid); set_read_fd(pipe_fd[0]); set_spawned(true); return OVERSEE_TEST; } # endif // !GTEST_OS_WINDOWS // Creates a concrete DeathTest-derived class that depends on the // --gtest_death_test_style flag, and sets the pointer pointed to // by the "test" argument to its address. If the test should be // skipped, sets that pointer to NULL. Returns true, unless the // flag is set to an invalid value. bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, const char* file, int line, DeathTest** test) { UnitTestImpl* const impl = GetUnitTestImpl(); const InternalRunDeathTestFlag* const flag = impl->internal_run_death_test_flag(); const int death_test_index = impl->current_test_info() ->increment_death_test_count(); if (flag != NULL) { if (death_test_index > flag->index()) { DeathTest::set_last_death_test_message( "Death test count (" + StreamableToString(death_test_index) + ") somehow exceeded expected maximum (" + StreamableToString(flag->index()) + ")"); return false; } if (!(flag->file() == file && flag->line() == line && flag->index() == death_test_index)) { *test = NULL; return true; } } # if GTEST_OS_WINDOWS if (GTEST_FLAG(death_test_style) == "threadsafe" || GTEST_FLAG(death_test_style) == "fast") { *test = new WindowsDeathTest(statement, regex, file, line); } # else if (GTEST_FLAG(death_test_style) == "threadsafe") { *test = new ExecDeathTest(statement, regex, file, line); } else if (GTEST_FLAG(death_test_style) == "fast") { *test = new NoExecDeathTest(statement, regex); } # endif // GTEST_OS_WINDOWS else { // NOLINT - this is more readable than unbalanced brackets inside #if. DeathTest::set_last_death_test_message( "Unknown death test style \"" + GTEST_FLAG(death_test_style) + "\" encountered"); return false; } return true; } // Splits a given string on a given delimiter, populating a given // vector with the fields. GTEST_HAS_DEATH_TEST implies that we have // ::std::string, so we can use it here. static void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest) { ::std::vector< ::std::string> parsed; ::std::string::size_type pos = 0; while (::testing::internal::AlwaysTrue()) { const ::std::string::size_type colon = str.find(delimiter, pos); if (colon == ::std::string::npos) { parsed.push_back(str.substr(pos)); break; } else { parsed.push_back(str.substr(pos, colon - pos)); pos = colon + 1; } } dest->swap(parsed); } # if GTEST_OS_WINDOWS // Recreates the pipe and event handles from the provided parameters, // signals the event, and returns a file descriptor wrapped around the pipe // handle. This function is called in the child process only. int GetStatusFileDescriptor(unsigned int parent_process_id, size_t write_handle_as_size_t, size_t event_handle_as_size_t) { AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, FALSE, // Non-inheritable. parent_process_id)); if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { DeathTestAbort("Unable to open parent process " + StreamableToString(parent_process_id)); } // TODO(vladl@google.com): Replace the following check with a // compile-time assertion when available. GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); const HANDLE write_handle = reinterpret_cast(write_handle_as_size_t); HANDLE dup_write_handle; // The newly initialized handle is accessible only in in the parent // process. To obtain one accessible within the child, we need to use // DuplicateHandle. if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, ::GetCurrentProcess(), &dup_write_handle, 0x0, // Requested privileges ignored since // DUPLICATE_SAME_ACCESS is used. FALSE, // Request non-inheritable handler. DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the pipe handle " + StreamableToString(write_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); HANDLE dup_event_handle; if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, ::GetCurrentProcess(), &dup_event_handle, 0x0, FALSE, DUPLICATE_SAME_ACCESS)) { DeathTestAbort("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort("Unable to convert pipe handle " + StreamableToString(write_handle_as_size_t) + " to a file descriptor"); } // Signals the parent that the write end of the pipe has been acquired // so the parent can release its own write end. ::SetEvent(dup_event_handle); return write_fd; } # endif // GTEST_OS_WINDOWS // Returns a newly created InternalRunDeathTestFlag object with fields // initialized from the GTEST_FLAG(internal_run_death_test) flag if // the flag is specified; otherwise returns NULL. InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { if (GTEST_FLAG(internal_run_death_test) == "") return NULL; // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we // can use it here. int line = -1; int index = -1; ::std::vector< ::std::string> fields; SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); int write_fd = -1; # if GTEST_OS_WINDOWS unsigned int parent_process_id = 0; size_t write_handle_as_size_t = 0; size_t event_handle_as_size_t = 0; if (fields.size() != 6 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &parent_process_id) || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } write_fd = GetStatusFileDescriptor(parent_process_id, write_handle_as_size_t, event_handle_as_size_t); # else if (fields.size() != 4 || !ParseNaturalNumber(fields[1], &line) || !ParseNaturalNumber(fields[2], &index) || !ParseNaturalNumber(fields[3], &write_fd)) { DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Authors: keith.ray@gmail.com (Keith Ray) #include #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include # include // Some Linux distributions define PATH_MAX here. #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_WINDOWS # define GTEST_PATH_MAX_ _MAX_PATH #elif defined(PATH_MAX) # define GTEST_PATH_MAX_ PATH_MAX #elif defined(_XOPEN_PATH_MAX) # define GTEST_PATH_MAX_ _XOPEN_PATH_MAX #else # define GTEST_PATH_MAX_ _POSIX_PATH_MAX #endif // GTEST_OS_WINDOWS namespace testing { namespace internal { #if GTEST_OS_WINDOWS // On Windows, '\\' is the standard path separator, but many tools and the // Windows API also accept '/' as an alternate path separator. Unless otherwise // noted, a file path can contain either kind of path separators, or a mixture // of them. const char kPathSeparator = '\\'; const char kAlternatePathSeparator = '/'; const char kPathSeparatorString[] = "\\"; const char kAlternatePathSeparatorString[] = "/"; # if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory. You should not use // the current directory in tests on Windows CE, but this at least // provides a reasonable fallback. const char kCurrentDirectoryString[] = "\\"; // Windows CE doesn't define INVALID_FILE_ATTRIBUTES const DWORD kInvalidFileAttributes = 0xffffffff; # else const char kCurrentDirectoryString[] = ".\\"; # endif // GTEST_OS_WINDOWS_MOBILE #else const char kPathSeparator = '/'; const char kPathSeparatorString[] = "/"; const char kCurrentDirectoryString[] = "./"; #endif // GTEST_OS_WINDOWS // Returns whether the given character is a valid path separator. static bool IsPathSeparator(char c) { #if GTEST_HAS_ALT_PATH_SEP_ return (c == kPathSeparator) || (c == kAlternatePathSeparator); #else return c == kPathSeparator; #endif } // Returns the current working directory, or "" if unsuccessful. FilePath FilePath::GetCurrentDir() { #if GTEST_OS_WINDOWS_MOBILE // Windows CE doesn't have a current directory, so we just return // something reasonable. return FilePath(kCurrentDirectoryString); #elif GTEST_OS_WINDOWS char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #else char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); #endif // GTEST_OS_WINDOWS_MOBILE } // Returns a copy of the FilePath with the case-insensitive extension removed. // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns // FilePath("dir/file"). If a case-insensitive extension is not // found, returns a copy of the original FilePath. FilePath FilePath::RemoveExtension(const char* extension) const { const std::string dot_extension = std::string(".") + extension; if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { return FilePath(pathname_.substr( 0, pathname_.length() - dot_extension.length())); } return *this; } // Returns a pointer to the last occurence of a valid path separator in // the FilePath. On Windows, for example, both '/' and '\' are valid path // separators. Returns NULL if no path separator was found. const char* FilePath::FindLastPathSeparator() const { const char* const last_sep = strrchr(c_str(), kPathSeparator); #if GTEST_HAS_ALT_PATH_SEP_ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); // Comparing two pointers of which only one is NULL is undefined. if (last_alt_sep != NULL && (last_sep == NULL || last_alt_sep > last_sep)) { return last_alt_sep; } #endif return last_sep; } // Returns a copy of the FilePath with the directory part removed. // Example: FilePath("path/to/file").RemoveDirectoryName() returns // FilePath("file"). If there is no directory part ("just_a_file"), it returns // the FilePath unmodified. If there is no file part ("just_a_dir/") it // returns an empty FilePath (""). // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveDirectoryName() const { const char* const last_sep = FindLastPathSeparator(); return last_sep ? FilePath(last_sep + 1) : *this; } // RemoveFileName returns the directory path with the filename removed. // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". // If the FilePath is "a_file" or "/a_file", RemoveFileName returns // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does // not have a file, like "just/a/dir/", it returns the FilePath unmodified. // On Windows platform, '\' is the path separator, otherwise it is '/'. FilePath FilePath::RemoveFileName() const { const char* const last_sep = FindLastPathSeparator(); std::string dir; if (last_sep) { dir = std::string(c_str(), last_sep + 1 - c_str()); } else { dir = kCurrentDirectoryString; } return FilePath(dir); } // Helper functions for naming files in a directory for xml output. // Given directory = "dir", base_name = "test", number = 0, // extension = "xml", returns "dir/test.xml". If number is greater // than zero (e.g., 12), returns "dir/test_12.xml". // On Windows platform, uses \ as the separator rather than /. FilePath FilePath::MakeFileName(const FilePath& directory, const FilePath& base_name, int number, const char* extension) { std::string file; if (number == 0) { file = base_name.string() + "." + extension; } else { file = base_name.string() + "_" + StreamableToString(number) + "." + extension; } return ConcatPaths(directory, FilePath(file)); } // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". // On Windows, uses \ as the separator rather than /. FilePath FilePath::ConcatPaths(const FilePath& directory, const FilePath& relative_path) { if (directory.IsEmpty()) return relative_path; const FilePath dir(directory.RemoveTrailingPathSeparator()); return FilePath(dir.string() + kPathSeparator + relative_path.string()); } // Returns true if pathname describes something findable in the file-system, // either a file, directory, or whatever. bool FilePath::FileOrDirectoryExists() const { #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; return attributes != kInvalidFileAttributes; #else posix::StatStruct file_stat; return posix::Stat(pathname_.c_str(), &file_stat) == 0; #endif // GTEST_OS_WINDOWS_MOBILE } // Returns true if pathname describes a directory in the file-system // that exists. bool FilePath::DirectoryExists() const { bool result = false; #if GTEST_OS_WINDOWS // Don't strip off trailing separator if path is a root directory on // Windows (like "C:\\"). const FilePath& path(IsRootDirectory() ? *this : RemoveTrailingPathSeparator()); #else const FilePath& path(*this); #endif #if GTEST_OS_WINDOWS_MOBILE LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); const DWORD attributes = GetFileAttributes(unicode); delete [] unicode; if ((attributes != kInvalidFileAttributes) && (attributes & FILE_ATTRIBUTE_DIRECTORY)) { result = true; } #else posix::StatStruct file_stat; result = posix::Stat(path.c_str(), &file_stat) == 0 && posix::IsDir(file_stat); #endif // GTEST_OS_WINDOWS_MOBILE return result; } // Returns true if pathname describes a root directory. (Windows has one // root directory per disk drive.) bool FilePath::IsRootDirectory() const { #if GTEST_OS_WINDOWS // TODO(wan@google.com): on Windows a network share like // \\server\share can be a root directory, although it cannot be the // current directory. Handle this properly. return pathname_.length() == 3 && IsAbsolutePath(); #else return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); #endif } // Returns true if pathname describes an absolute path. bool FilePath::IsAbsolutePath() const { const char* const name = pathname_.c_str(); #if GTEST_OS_WINDOWS return pathname_.length() >= 3 && ((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A' && name[0] <= 'Z')) && name[1] == ':' && IsPathSeparator(name[2]); #else return IsPathSeparator(name[0]); #endif } // Returns a pathname for a file that does not currently exist. The pathname // will be directory/base_name.extension or // directory/base_name_.extension if directory/base_name.extension // already exists. The number will be incremented until a pathname is found // that does not already exist. // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. // There could be a race condition if two or more processes are calling this // function at the same time -- they could both pick the same filename. FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, const FilePath& base_name, const char* extension) { FilePath full_pathname; int number = 0; do { full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); } while (full_pathname.FileOrDirectoryExists()); return full_pathname; } // Returns true if FilePath ends with a path separator, which indicates that // it is intended to represent a directory. Returns false otherwise. // This does NOT check that a directory (or file) actually exists. bool FilePath::IsDirectory() const { return !pathname_.empty() && IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); } // Create directories so that path exists. Returns true if successful or if // the directories already exist; returns false if unable to create directories // for any reason. bool FilePath::CreateDirectoriesRecursively() const { if (!this->IsDirectory()) { return false; } if (pathname_.length() == 0 || this->DirectoryExists()) { return true; } const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); return parent.CreateDirectoriesRecursively() && this->CreateFolder(); } // Create the directory so that path exists. Returns true if successful or // if the directory already exists; returns false if unable to create the // directory for any reason, including if the parent directory does not // exist. Not named "CreateDirectory" because that's a macro on Windows. bool FilePath::CreateFolder() const { #if GTEST_OS_WINDOWS_MOBILE FilePath removed_sep(this->RemoveTrailingPathSeparator()); LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); int result = CreateDirectory(unicode, NULL) ? 0 : -1; delete [] unicode; #elif GTEST_OS_WINDOWS int result = _mkdir(pathname_.c_str()); #else int result = mkdir(pathname_.c_str(), 0777); #endif // GTEST_OS_WINDOWS_MOBILE if (result == -1) { return this->DirectoryExists(); // An error is OK if the directory exists. } return true; // No error. } // If input name has a trailing separator character, remove it and return the // name, otherwise return the name string unmodified. // On Windows platform, uses \ as the separator, other platforms use /. FilePath FilePath::RemoveTrailingPathSeparator() const { return IsDirectory() ? FilePath(pathname_.substr(0, pathname_.length() - 1)) : *this; } // Removes any redundant separators that might be in the pathname. // For example, "bar///foo" becomes "bar/foo". Does not eliminate other // redundancies that might be in a pathname involving "." or "..". // TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). void FilePath::Normalize() { if (pathname_.c_str() == NULL) { pathname_ = ""; return; } const char* src = pathname_.c_str(); char* const dest = new char[pathname_.length() + 1]; char* dest_ptr = dest; memset(dest_ptr, 0, pathname_.length() + 1); while (*src != '\0') { *dest_ptr = *src; if (!IsPathSeparator(*src)) { src++; } else { #if GTEST_HAS_ALT_PATH_SEP_ if (*dest_ptr == kAlternatePathSeparator) { *dest_ptr = kPathSeparator; } #endif while (IsPathSeparator(*src)) src++; } dest_ptr++; } *dest_ptr = '\0'; pathname_ = dest; delete[] dest; } } // namespace internal } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) #include #include #include #include #if GTEST_OS_WINDOWS_MOBILE # include // For TerminateProcess() #elif GTEST_OS_WINDOWS # include # include #else # include #endif // GTEST_OS_WINDOWS_MOBILE #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_QNX # include # include #endif // GTEST_OS_QNX // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { namespace internal { #if defined(_MSC_VER) || defined(__BORLANDC__) // MSVC and C++Builder do not provide a definition of STDERR_FILENO. const int kStdOutFileno = 1; const int kStdErrFileno = 2; #else const int kStdOutFileno = STDOUT_FILENO; const int kStdErrFileno = STDERR_FILENO; #endif // _MSC_VER #if GTEST_OS_MAC // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const task_t task = mach_task_self(); mach_msg_type_number_t thread_count; thread_act_array_t thread_list; const kern_return_t status = task_threads(task, &thread_list, &thread_count); if (status == KERN_SUCCESS) { // task_threads allocates resources in thread_list and we need to free them // to avoid leaks. vm_deallocate(task, reinterpret_cast(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { return 0; } } #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const int fd = open("/proc/self/as", O_RDONLY); if (fd < 0) { return 0; } procfs_info process_info; const int status = devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); } else { return 0; } } #else size_t GetThreadCount() { // There's no portable way to detect the number of threads, so we just // return 0 to indicate that we cannot detect it. return 0; } #endif // GTEST_OS_MAC #if GTEST_USES_POSIX_RE // Implements RE. Currently only needed for death tests. RE::~RE() { if (is_valid_) { // regfree'ing an invalid regex might crash because the content // of the regex is undefined. Since the regex's are essentially // the same, one cannot be valid (or invalid) without the other // being so too. regfree(&partial_regex_); regfree(&full_regex_); } free(const_cast(pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.full_regex_, str, 1, &match, 0) == 0; } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { if (!re.is_valid_) return false; regmatch_t match; return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = posix::StrDup(regex); // Reserves enough bytes to hold the regular expression used for a // full match. const size_t full_regex_len = strlen(regex) + 10; char* const full_pattern = new char[full_regex_len]; snprintf(full_pattern, full_regex_len, "^(%s)$", regex); is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; // We want to call regcomp(&partial_regex_, ...) even if the // previous expression returns false. Otherwise partial_regex_ may // not be properly initialized can may cause trouble when it's // freed. // // Some implementation of POSIX regex (e.g. on at least some // versions of Cygwin) doesn't accept the empty string as a valid // regex. We change it to an equivalent form "()" to be safe. if (is_valid_) { const char* const partial_regex = (*regex == '\0') ? "()" : regex; is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; } EXPECT_TRUE(is_valid_) << "Regular expression \"" << regex << "\" is not a valid POSIX Extended regular expression."; delete[] full_pattern; } #elif GTEST_USES_SIMPLE_RE // Returns true iff ch appears anywhere in str (excluding the // terminating '\0' character). bool IsInSet(char ch, const char* str) { return ch != '\0' && strchr(str, ch) != NULL; } // Returns true iff ch belongs to the given classification. Unlike // similar functions in , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsAsciiWordChar(char ch) { return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9') || ch == '_'; } // Returns true iff "\\c" is a supported escape sequence. bool IsValidEscape(char c) { return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); } // Returns true iff the given atom (specified by escaped and pattern) // matches ch. The result is undefined if the atom is invalid. bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { if (escaped) { // "\\p" where p is pattern_char. switch (pattern_char) { case 'd': return IsAsciiDigit(ch); case 'D': return !IsAsciiDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; case 's': return IsAsciiWhiteSpace(ch); case 'S': return !IsAsciiWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; case 'w': return IsAsciiWordChar(ch); case 'W': return !IsAsciiWordChar(ch); } return IsAsciiPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; } // Helper function used by ValidateRegex() to format error messages. std::string FormatRegexSyntaxError(const char* regex, int index) { return (Message() << "Syntax error at index " << index << " in simple regular expression \"" << regex << "\": ").GetString(); } // Generates non-fatal failures and returns false if regex is invalid; // otherwise returns true. bool ValidateRegex(const char* regex) { if (regex == NULL) { // TODO(wan@google.com): fix the source file location in the // assertion failures to match where the regex is used in user // code. ADD_FAILURE() << "NULL is not a valid simple regular expression."; return false; } bool is_valid = true; // True iff ?, *, or + can follow the previous atom. bool prev_repeatable = false; for (int i = 0; regex[i]; i++) { if (regex[i] == '\\') { // An escape sequence i++; if (regex[i] == '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "'\\' cannot appear at the end."; return false; } if (!IsValidEscape(regex[i])) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) << "invalid escape sequence \"\\" << regex[i] << "\"."; is_valid = false; } prev_repeatable = true; } else { // Not an escape sequence. const char ch = regex[i]; if (ch == '^' && i > 0) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'^' can only appear at the beginning."; is_valid = false; } else if (ch == '$' && regex[i + 1] != '\0') { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'$' can only appear at the end."; is_valid = false; } else if (IsInSet(ch, "()[]{}|")) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' is unsupported."; is_valid = false; } else if (IsRepeat(ch) && !prev_repeatable) { ADD_FAILURE() << FormatRegexSyntaxError(regex, i) << "'" << ch << "' can only follow a repeatable token."; is_valid = false; } prev_repeatable = !IsInSet(ch, "^$?*+"); } } return is_valid; } // Matches a repeated regex atom followed by a valid simple regular // expression. The regex atom is defined as c if escaped is false, // or \c otherwise. repeat is the repetition meta character (?, *, // or +). The behavior is undefined if str contains too many // characters to be indexable by size_t, in which case the test will // probably time out anyway. We are fine with this limitation as // std::string has it too. bool MatchRepetitionAndRegexAtHead( bool escaped, char c, char repeat, const char* regex, const char* str) { const size_t min_count = (repeat == '+') ? 1 : 0; const size_t max_count = (repeat == '?') ? 1 : static_cast(-1) - 1; // We cannot call numeric_limits::max() as it conflicts with the // max() macro on Windows. for (size_t i = 0; i <= max_count; ++i) { // We know that the atom matches each of the first i characters in str. if (i >= min_count && MatchRegexAtHead(regex, str + i)) { // We have enough matches at the head, and the tail matches too. // Since we only care about *whether* the pattern matches str // (as opposed to *how* it matches), there is no need to find a // greedy match. return true; } if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) return false; } return false; } // Returns true iff regex matches a prefix of str. regex must be a // valid simple regular expression and not start with "^", or the // result is undefined. bool MatchRegexAtHead(const char* regex, const char* str) { if (*regex == '\0') // An empty regex matches a prefix of anything. return true; // "$" only matches the end of a string. Note that regex being // valid guarantees that there's nothing after "$" in it. if (*regex == '$') return *str == '\0'; // Is the first thing in regex an escape sequence? const bool escaped = *regex == '\\'; if (escaped) ++regex; if (IsRepeat(regex[1])) { // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so // here's an indirect recursion. It terminates as the regex gets // shorter in each recursion. return MatchRepetitionAndRegexAtHead( escaped, regex[0], regex[1], regex + 2, str); } else { // regex isn't empty, isn't "$", and doesn't start with a // repetition. We match the first atom of regex with the first // character of str and recurse. return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && MatchRegexAtHead(regex + 1, str + 1); } } // Returns true iff regex matches any substring of str. regex must be // a valid simple regular expression, or the result is undefined. // // The algorithm is recursive, but the recursion depth doesn't exceed // the regex length, so we won't need to worry about running out of // stack space normally. In rare cases the time complexity can be // exponential with respect to the regex length + the string length, // but usually it's must faster (often close to linear). bool MatchRegexAnywhere(const char* regex, const char* str) { if (regex == NULL || str == NULL) return false; if (*regex == '^') return MatchRegexAtHead(regex + 1, str); // A successful match can be anywhere in str. do { if (MatchRegexAtHead(regex, str)) return true; } while (*str++ != '\0'); return false; } // Implements the RE class. RE::~RE() { free(const_cast(pattern_)); free(const_cast(full_pattern_)); } // Returns true iff regular expression re matches the entire str. bool RE::FullMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); } // Returns true iff regular expression re matches a substring of str // (including str itself). bool RE::PartialMatch(const char* str, const RE& re) { return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); } // Initializes an RE from its string representation. void RE::Init(const char* regex) { pattern_ = full_pattern_ = NULL; if (regex != NULL) { pattern_ = posix::StrDup(regex); } is_valid_ = ValidateRegex(regex); if (!is_valid_) { // No need to calculate the full pattern when the regex is invalid. return; } const size_t len = strlen(regex); // Reserves enough bytes to hold the regular expression used for a // full match: we need space to prepend a '^', append a '$', and // terminate the string with '\0'. char* buffer = static_cast(malloc(len + 3)); full_pattern_ = buffer; if (*regex != '^') *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. // We don't use snprintf or strncpy, as they trigger a warning when // compiled with VC++ 8.0. memcpy(buffer, regex, len); buffer += len; if (len == 0 || regex[len - 1] != '$') *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. *buffer = '\0'; } #endif // GTEST_USES_POSIX_RE const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) { return file_name + ":"; } #ifdef _MSC_VER return file_name + "(" + StreamableToString(line) + "):"; #else return file_name + ":" + StreamableToString(line) + ":"; #endif // _MSC_VER } // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. // Note that FormatCompilerIndependentFileLocation() does NOT append colon // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) return file_name; else return file_name + ":" + StreamableToString(line); } GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) : severity_(severity) { const char* const marker = severity == GTEST_INFO ? "[ INFO ]" : severity == GTEST_WARNING ? "[WARNING]" : severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; GetStream() << ::std::endl << marker << " " << FormatFileLocation(file, line).c_str() << ": "; } // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. GTestLog::~GTestLog() { GetStream() << ::std::endl; if (severity_ == GTEST_FATAL) { fflush(stderr); posix::Abort(); } } // Disable Microsoft deprecation warnings for POSIX functions called from // this class (creat, dup, dup2, and close) #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4996) #endif // _MSC_VER #if GTEST_HAS_STREAM_REDIRECTION // Object that captures an output stream (stdout/stderr). class CapturedStream { public: // The ctor redirects the stream to a temporary file. explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { # if GTEST_OS_WINDOWS char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); const UINT success = ::GetTempFileNameA(temp_dir_path, "gtest_redir", 0, // Generate unique file name. temp_file_path); GTEST_CHECK_(success != 0) << "Unable to create a temporary file in " << temp_dir_path; const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " << temp_file_path; filename_ = temp_file_path; # else // There's no guarantee that a test has write access to the current // directory, so we create the temporary file in the /tmp directory // instead. We use /tmp on most systems, and /sdcard on Android. // That's because Android doesn't have /tmp. # if GTEST_OS_LINUX_ANDROID // Note: Android applications are expected to call the framework's // Context.getExternalStorageDirectory() method through JNI to get // the location of the world-writable SD Card directory. However, // this requires a Context handle, which cannot be retrieved // globally from native code. Doing so also precludes running the // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // // The location /sdcard is directly accessible from native code // and is the only location (unofficially) supported by the Android // team. It's generally a symlink to the real SD Card mount point // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or // other OEM-customized locations. Never rely on these, and always // use /sdcard. char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID const int captured_fd = mkstemp(name_template); filename_ = name_template; # endif // GTEST_OS_WINDOWS fflush(NULL); dup2(captured_fd, fd_); close(captured_fd); } ~CapturedStream() { remove(filename_.c_str()); } std::string GetCapturedString() { if (uncaptured_fd_ != -1) { // Restores the original stream. fflush(NULL); dup2(uncaptured_fd_, fd_); close(uncaptured_fd_); uncaptured_fd_ = -1; } FILE* const file = posix::FOpen(filename_.c_str(), "r"); const std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: // Reads the entire content of a file as an std::string. static std::string ReadEntireFile(FILE* file); // Returns the size (in bytes) of a file. static size_t GetFileSize(FILE* file); const int fd_; // A stream to capture. int uncaptured_fd_; // Name of the temporary file holding the stderr output. ::std::string filename_; GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); }; // Returns the size (in bytes) of a file. size_t CapturedStream::GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } // Reads the entire content of a file as a string. std::string CapturedStream::ReadEntireFile(FILE* file) { const size_t file_size = GetFileSize(file); char* const buffer = new char[file_size]; size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_read = 0; // # of bytes read so far fseek(file, 0, SEEK_SET); // Keeps reading the file until we cannot read further or the // pre-determined file size is reached. do { bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); bytes_read += bytes_last_read; } while (bytes_last_read > 0 && bytes_read < file_size); const std::string content(buffer, bytes_read); delete[] buffer; return content; } # ifdef _MSC_VER # pragma warning(pop) # endif // _MSC_VER static CapturedStream* g_captured_stderr = NULL; static CapturedStream* g_captured_stdout = NULL; // Starts capturing an output stream (stdout/stderr). void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { if (*stream != NULL) { GTEST_LOG_(FATAL) << "Only one " << stream_name << " capturer can exist at a time."; } *stream = new CapturedStream(fd); } // Stops capturing the output stream and returns the captured string. std::string GetCapturedStream(CapturedStream** captured_stream) { const std::string content = (*captured_stream)->GetCapturedString(); delete *captured_stream; *captured_stream = NULL; return content; } // Starts capturing stdout. void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); } // Starts capturing stderr. void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); } // Stops capturing stdout and returns the captured string. std::string GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. std::string GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #endif // GTEST_HAS_STREAM_REDIRECTION #if GTEST_HAS_DEATH_TEST // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector g_argvs; static const ::std::vector* g_injected_test_argvs = NULL; // Owned. void SetInjectableArgvs(const ::std::vector* argvs) { if (g_injected_test_argvs != argvs) delete g_injected_test_argvs; g_injected_test_argvs = argvs; } const ::std::vector& GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } return g_argvs; } #endif // GTEST_HAS_DEATH_TEST #if GTEST_OS_WINDOWS_MOBILE namespace posix { void Abort() { DebugBreak(); TerminateProcess(GetCurrentProcess(), 1); } } // namespace posix #endif // GTEST_OS_WINDOWS_MOBILE // Returns the name of the environment variable corresponding to the // given flag. For example, FlagToEnvVar("foo") will return // "GTEST_FOO" in the open-source version. static std::string FlagToEnvVar(const char* flag) { const std::string full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { env_var << ToUpper(full_flag.c_str()[i]); } return env_var.GetString(); } // Parses 'str' for a 32-bit signed integer. If successful, writes // the result to *value and returns true; otherwise leaves *value // unchanged and returns false. bool ParseInt32(const Message& src_text, const char* str, Int32* value) { // Parses the environment variable as a decimal integer. char* end = NULL; const long long_value = strtol(str, &end, 10); // NOLINT // Has strtol() consumed all characters in the string? if (*end != '\0') { // No - an invalid character was encountered. Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value \"" << str << "\".\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } // Is the parsed value in the range of an Int32? const Int32 result = static_cast(long_value); if (long_value == LONG_MAX || long_value == LONG_MIN || // The parsed value overflows as a long. (strtol() returns // LONG_MAX or LONG_MIN when the input overflows.) result != long_value // The parsed value overflows as an Int32. ) { Message msg; msg << "WARNING: " << src_text << " is expected to be a 32-bit integer, but actually" << " has value " << str << ", which overflows.\n"; printf("%s", msg.GetString().c_str()); fflush(stdout); return false; } *value = result; return true; } // Reads and returns the Boolean environment variable corresponding to // the given flag; if it's not set, returns default_value. // // The value is considered true iff it's not "0". bool BoolFromGTestEnv(const char* flag, bool default_value) { const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); return string_value == NULL ? default_value : strcmp(string_value, "0") != 0; } // Reads and returns a 32-bit integer stored in the environment // variable corresponding to the given flag; if it isn't set or // doesn't represent a valid 32-bit integer, returns default_value. Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { const std::string env_var = FlagToEnvVar(flag); const char* const string_value = posix::GetEnv(env_var.c_str()); if (string_value == NULL) { // The environment variable is not set. return default_value; } Int32 result = default_value; if (!ParseInt32(Message() << "Environment variable " << env_var, string_value, &result)) { printf("The default value %s is used.\n", (Message() << default_value).GetString().c_str()); fflush(stdout); return default_value; } return result; } // Reads and returns the string environment variable corresponding to // the given flag; if it's not set, returns default_value. const char* StringFromGTestEnv(const char* flag, const char* default_value) { const std::string env_var = FlagToEnvVar(flag); const char* const value = posix::GetEnv(env_var.c_str()); return value == NULL ? default_value : value; } } // namespace internal } // namespace testing // Copyright 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Google Test - The Google C++ Testing Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // It uses the << operator when possible, and prints the bytes in the // object otherwise. A user can override its behavior for a class // type Foo by defining either operator<<(::std::ostream&, const Foo&) // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. #include #include #include // NOLINT #include namespace testing { namespace { using ::std::ostream; // Prints a segment of bytes in the given object. void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; for (size_t i = 0; i != count; i++) { const size_t j = start + i; if (i != 0) { // Organizes the bytes into groups of 2 for easy parsing by // human. if ((j % 2) == 0) *os << ' '; else *os << '-'; } GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); *os << text; } } // Prints the bytes in the given value to the given ostream. void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, ostream* os) { // Tells the user how big the object is. *os << count << "-byte object <"; const size_t kThreshold = 132; const size_t kChunkSize = 64; // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. // TODO(wan): let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); *os << " ... "; // Rounds up to 2-byte boundary. const size_t resume_pos = (count - kChunkSize + 1)/2*2; PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); } *os << ">"; } } // namespace namespace internal2 { // Delegates to PrintBytesInObjectToImpl() to print the bytes in the // given object. The delegation simplifies the implementation, which // uses the << operator and thus is easier done outside of the // ::testing::internal namespace, which contains a << operator that // sometimes conflicts with the one in STL. void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ostream* os) { PrintBytesInObjectToImpl(obj_bytes, count, os); } } // namespace internal2 namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), // - as a hexidecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, kHexEscape, kSpecialEscape }; // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } // Prints a wide or narrow char c as a character literal without the // quotes, escaping it when necessary; returns how c was formatted. // The template argument UnsignedChar is the unsigned version of Char, // which is the type of c. template static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { switch (static_cast(c)) { case L'\0': *os << "\\0"; break; case L'\'': *os << "\\'"; break; case L'\\': *os << "\\\\"; break; case L'\a': *os << "\\a"; break; case L'\b': *os << "\\b"; break; case L'\f': *os << "\\f"; break; case L'\n': *os << "\\n"; break; case L'\r': *os << "\\r"; break; case L'\t': *os << "\\t"; break; case L'\v': *os << "\\v"; break; default: if (IsPrintableAscii(c)) { *os << static_cast(c); return kAsIs; } else { *os << "\\x" + String::FormatHexInt(static_cast(c)); return kHexEscape; } } return kSpecialEscape; } // Prints a wchar_t c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; return kAsIs; case L'"': *os << "\\\""; return kSpecialEscape; default: return PrintAsCharLiteralTo(c, os); } } // Prints a char c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { return PrintAsStringLiteralTo( static_cast(static_cast(c)), os); } // Prints a wide or narrow character c and its code. '\0' is printed // as "'\\0'", other unprintable characters are also properly escaped // using the standard C++ escape sequence. The template argument // UnsignedChar is the unsigned version of Char, which is the type of c. template void PrintCharAndCodeTo(Char c, ostream* os) { // First, print c as a literal in the most readable form we can find. *os << ((sizeof(c) > 1) ? "L'" : "'"); const CharFormat format = PrintAsCharLiteralTo(c, os); *os << "'"; // To aid user debugging, we also print c's code in decimal, unless // it's 0 (in which case c was printed as '\\0', making the code // obvious). if (c == 0) return; *os << " (" << static_cast(c); // For more convenience, we print c's code again in hexidecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its code. L'\0' is printed as "L'\\0'". void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); } // Prints the given array of characters to the ostream. CharType must be either // char or wchar_t. // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { // Previous character is of '\x..' form and this character can be // interpreted as another hexadecimal digit in its number. Break string to // disambiguate. *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; } *os << "\""; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code // const char kFoo[] = "foo"; // generates an array of 4, not 3, elements, with the last one being '\0'. // // Therefore when printing a char array, we don't print the last element if // it's '\0', such that the output matches the string literal as it's // written in the source code. if (len > 0 && begin[len - 1] == '\0') { PrintCharsAsStringTo(begin, len - 1, os); return; } // If, however, the last element in the array is not '\0', e.g. // const char kFoo[] = { 'f', 'o', 'o' }; // we must print the entire array. We also print a message to indicate // that the array is not NUL-terminated. PrintCharsAsStringTo(begin, len, os); *os << " (no terminating NUL)"; } // Prints a (const) char array of 'len' elements, starting at address 'begin'. void UniversalPrintArray(const char* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints a (const) wchar_t array of 'len' elements, starting at address // 'begin'. void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, strlen(s), os); } } // MSVC compiler can be configured to define whar_t as a typedef // of unsigned short. Defining an overload for const wchar_t* in that case // would cause pointers to unsigned shorts be printed as wide strings, // possibly accessing more memory than intended and causing invalid // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when // wchar_t is implemented as a native type. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, wcslen(s), os); } } #endif // wchar_t is native // Prints a ::string object. #if GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::std::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } // Prints a ::wstring object. #if GTEST_HAS_GLOBAL_WSTRING void PrintWideStringTo(const ::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING } // namespace internal } // namespace testing // Copyright 2008, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: mheule@google.com (Markus Heule) // // The Google C++ Testing Framework (Google Test) // Indicates that this translation unit is part of Google Test's // implementation. It must come before gtest-internal-inl.h is // included, or there will be a compiler error. This trick is to // prevent a user from accidentally including gtest-internal-inl.h in // his code. #define GTEST_IMPLEMENTATION_ 1 #undef GTEST_IMPLEMENTATION_ namespace testing { using internal::GetUnitTestImpl; // Gets the summary of the failure message by omitting the stack trace // in it. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); return stack_trace == NULL ? message : std::string(message, stack_trace); } // Prints a TestPartResult object. std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { return os << result.file_name() << ":" << result.line_number() << ": " << (result.type() == TestPartResult::kSuccess ? "Success" : result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : "Non-fatal failure") << ":\n" << result.message() << std::endl; } // Appends a TestPartResult to the array. void TestPartResultArray::Append(const TestPartResult& result) { array_.push_back(result); } // Returns the TestPartResult at the given index (0-based). const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { if (index < 0 || index >= size()) { printf("\nInvalid index (%d) into TestPartResultArray.\n", index); internal::posix::Abort(); } return array_[index]; } // Returns the number of TestPartResult objects in the array. int TestPartResultArray::size() const { return static_cast(array_.size()); } namespace internal { HasNewFatalFailureHelper::HasNewFatalFailureHelper() : has_new_fatal_failure_(false), original_reporter_(GetUnitTestImpl()-> GetTestPartResultReporterForCurrentThread()) { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); } HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( original_reporter_); } void HasNewFatalFailureHelper::ReportTestPartResult( const TestPartResult& result) { if (result.fatally_failed()) has_new_fatal_failure_ = true; original_reporter_->ReportTestPartResult(result); } } // namespace internal } // namespace testing // Copyright 2008 Google Inc. // All Rights Reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) namespace testing { namespace internal { #if GTEST_HAS_TYPED_TEST_P // Skips to the first non-space char in str. Returns an empty string if str // contains only whitespace characters. static const char* SkipSpaces(const char* str) { while (IsSpace(*str)) str++; return str; } // Verifies that registered_tests match the test names in // defined_test_names_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef ::std::set::const_iterator DefinedTestIter; registered_ = true; // Skip initial whitespace in registered_tests since some // preprocessors prefix stringizied literals with whitespace. registered_tests = SkipSpaces(registered_tests); Message errors; ::std::set tests; for (const char* names = registered_tests; names != NULL; names = SkipComma(names)) { const std::string name = GetPrefixUntilComma(names); if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (name == *it) { found = true; break; } } if (found) { tests.insert(name); } else { errors << "No test named " << name << " can be found in this test case.\n"; } } for (DefinedTestIter it = defined_test_names_.begin(); it != defined_test_names_.end(); ++it) { if (tests.count(*it) == 0) { errors << "You forgot to list test " << *it << ".\n"; } } const std::string& errors_str = errors.GetString(); if (errors_str != "") { fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), errors_str.c_str()); fflush(stderr); posix::Abort(); } return registered_tests; } #endif // GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing pyclustering-0.10.1.2/ccore/include/000077500000000000000000000000001375753423500172155ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/000077500000000000000000000000001375753423500217455ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/000077500000000000000000000000001375753423500234265ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/agglomerative.hpp000077500000000000000000000115631375753423500267760ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { /*! @brief A storage where Agglometative clustering results are stored. */ using agglomerative_data = cluster_data; /*! @class agglomerative agglomerative.hpp pyclustering/cluster/agglomerative.hpp @brief Agglomerative algorithm implementation that is used bottom up approach for clustering. @details Agglomerative algorithm considers each data point (object) as a separate cluster at the beginning and step by step finds the best pair of clusters for merge until required amount of clusters is obtained. Example of agglomerative algorithm where centroid link 'CENTROID_LINK' is used for clustering sample 'Simple01': @code using namespace pyclustering; using namespace pyclustering::clst; int main() { // Read an input data 'Simple01' from text file. dataset data = read_data("Simple01.txt"); // Create storage where the result is going to be stored. agglomerative_data result; // Create the algorithm and process the input data using centroid link. agglomerative(2, agglomerative::type_link::CENTROID_LINK).process(data, result); // Display allocated clusters. for (auto group : result.clusters()) { std::cout << "[ "; for (auto index : group) { std::cout << index << " "; } std::cout << "]"; } return 0; } @endcode Example of 'Lsun' clustering by the algorithm where single link method is more suitable due to elongated clusters: @code dataset data = read_data("Lsun.txt"); agglomerative_data result; agglomerative(2, agglomerative::type_link::SINGLE_LINK).process(data, result); @endcode There is an illustration how various methods affect the clustering result: @image html agglomerative_lsun_clustering_single_link.png Implementation based on paper @cite book::algorithms_for_clustering_data. */ class agglomerative { public: /*! @brief Defines methods (how to define closest clusters) for Agglomerative clustering. */ enum class type_link { SINGLE_LINK = 0, /**< Distance between the two nearest objects in clusters is considered as a link, so-called SLINK method (the single-link clustering method). */ COMPLETE_LINK = 1, /**< Distance between the farthest objects in clusters is considered as a link, so-called CLINK method (the complete-link clustering method). */ AVERAGE_LINK = 2, /**< Average distance between objects in clusters is considered as a link. */ CENTROID_LINK = 3 /**< Distance between centers of clusters is considered as a link. */ }; private: size_t m_number_clusters; type_link m_similarity; dataset m_centers; cluster_sequence * m_ptr_clusters; const dataset * m_ptr_data; public: /*! @brief Default constructor of the clustering algorithm. */ agglomerative(); /*! @brief Constructor of clustering algorithm where algorithm parameters for processing are specified. @param[in] number_clusters: amount of clusters that should be allocated. @param[in] link: type of the linking method for clustering. */ agglomerative(const size_t number_clusters, const type_link link); /*! @brief Default destructor of the algorithm. */ ~agglomerative() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: an input data that should be clusted. @param[out] p_result: agglomerative clustering result of an input data. */ void process(const dataset & p_data, agglomerative_data & p_result); private: /*! @brief Merges the most similar clusters in line with link type. */ void merge_similar_clusters(); /*! @brief Merges the most similar clusters in line with average link type. */ void merge_by_average_link(); /*! @brief Merges the most similar clusters in line with centroid link type. */ void merge_by_centroid_link(); /*! @brief Merges the most similar clusters in line with complete link type. */ void merge_by_complete_link(); /*! @brief Merges the most similar clusters in line with single link type. */ void merge_by_signle_link(); /*! @brief Calculates new center. @param[in] cluster: cluster whose center should be calculated. @param[out] center: coordinates of the cluster center. */ void calculate_center(const cluster & cluster, point & center) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/bsas.hpp000077500000000000000000000117331375753423500250770ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class bsas bsas.hpp pyclustering/cluster/bsas.hpp @brief Class represents BSAS clustering algorithm - basic sequential algorithmic scheme. @details Algorithm has two mandatory parameters: maximum allowable number of clusters and threshold of dissimilarity or in other words maximum distance between points. Distance metric also can be specified using 'metric' parameters, by default 'Manhattan' distance is used. BSAS using following rule for updating cluster representative: \f[ \vec{m}_{C_{k}}^{new}=\frac{ \left ( n_{C_{k}^{new}} - 1 \right )\vec{m}_{C_{k}}^{old} + \vec{x} }{n_{C_{k}^{new}}} \f] Clustering results of this algorithm depends on objects order in input data. Example of cluster analysis using BSAS algorithm: @code using namespace pyclustering; using namespace pyclustering::clst; int main() { dataset data = read_data("Simple02.txt"); // Algorithm configuration: amount of clusters to allocate and threshold of dissimilarity. const std::size_t amount_clusters = 3; const double threshold = 1.0; // Create and run BSAS algorithm. bsas_data result; bsas(amount_clusters, threshold).process(data, result); // Extract clustering results: clusters and representative points. const cluster_sequence & clusters = result.clusters(); const representative_sequence & representatives = result.representatives(); // Display allocated clusters. for (const auto group : clusters) { for (const auto index : group) { std::cout << index << " "; } std::cout << std::endl; } return 0; } @endcode There is another one example where distance metric is specified: @code // Create manhattan distance metric. auto metric = distance_metric_factory::manhattan(); // Create BSAS and run clustering algorithm using Manhattan distance. bsas_data result; bsas(amount_clusters, threshold, metric).process(data, result); @endcode Implementation based on paper @cite book::pattern_recognition::2009. */ class bsas { protected: /*! @brief Description of the nearest cluster to a point that is described by cluster index and distance from the cluster to the specified point. */ struct nearest_cluster { std::size_t m_index = (std::size_t) -1; /**< Cluster index. */ double m_distance = std::numeric_limits::max(); /**< Distance between the cluster and a specific point. */ }; protected: bsas_data * m_result_ptr = nullptr; /**< Temporary pointer to clustering result that is used only during processing. */ double m_threshold = 0.0; /**< Threshold of dissimilarity (maximum distance) between points. */ std::size_t m_amount = 0; /**< Amount of clusters that should be allocated. */ distance_metric m_metric; /**< Metric for distance calculation between points. */ public: /*! @brief Default constructor of the clustering algorithm. */ bsas() = default; /*! @brief Creates BSAS algorithm using specified parameters. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_threshold: threshold of dissimilarity (maximum distance) between points. @param[in] p_metric: metric for distance calculation between points. */ bsas(const std::size_t p_amount, const double p_threshold, const distance_metric & p_metric = distance_metric_factory::euclidean()); public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data. */ virtual void process(const dataset & p_data, bsas_data & p_result); protected: /*! @brief Find nearest cluster to the specified point. @param[in] p_point: point for which nearest cluster is searched. @return Description of nearest cluster that is defined by cluster index and distance to the point. */ nearest_cluster find_nearest_cluster(const point & p_point) const; /*! @brief Update cluster representative in line with new cluster size and added point to it. @param[in] p_index: index of cluster whose representative should be updated. @param[in] p_point: new point that was added to cluster. */ void update_representative(const std::size_t p_index, const point & p_point); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/bsas_data.hpp000077500000000000000000000032311375753423500260620ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { using representative_sequence = std::vector< std::vector >; using representative_sequence_ptr = std::shared_ptr; /*! @class bsas_data bsas_data.hpp pyclustering/cluster/bsas_data.hpp @brief Clustering results of BSAS algorithm that consists of information about allocated clusters and their representatives (points). */ class bsas_data : public cluster_data { private: representative_sequence m_representatives = { }; public: /*! @brief Default constructor of the clustering algorithm. */ bsas_data() = default; /*! @brief Copy constructor of the clustering algorithm. */ bsas_data(const bsas_data & p_other) = default; /*! @brief Move constructor of the clustering algorithm. */ bsas_data(bsas_data && p_other) = default; /*! @brief Default destructor of the clustering algorithm. */ virtual ~bsas_data() = default; public: /*! @brief Returns representatives that corresponds to allocated clusters. */ representative_sequence & representatives() { return m_representatives; } /*! @brief Returns representatives that corresponds to allocated clusters. */ const representative_sequence & representatives() const { return m_representatives; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/center_initializer.hpp000077500000000000000000000024641375753423500300330ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace clst { /*! @brief Center initializer interface that provides general services to initialize centers. */ class center_initializer { public: /*! @brief Performs center initialization process in line algorithm configuration. @param[in] p_data: data for that centers are calculated. @param[out] p_centers: initialized centers for the specified data. */ virtual void initialize(const dataset & p_data, dataset & p_centers) const = 0; /*! @brief Performs center initialization process in line algorithm configuration for specific range of points. @param[in] p_data: data for that centers are calculated. @param[in] p_indexes: point indexes from data that are defines which points should be considered during calculation process. If empty then all data points are considered. @param[out] p_centers: initialized centers for the specified data. */ virtual void initialize(const dataset & p_data, const index_sequence & p_indexes, dataset & p_centers) const = 0; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/clique.hpp000077500000000000000000000152361375753423500254330ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { /*! @class coordinate_iterator clique.hpp pyclustering/cluster/clique.hpp @brief Coordinate iterator is used to generate logical location description for each CLIQUE block. @details This class is used by CLIQUE algorithm for clustering process. */ class coordinate_iterator { private: std::size_t m_dimension = 0; std::size_t m_edge = 0; clique_block_location m_coordinate; public: /*! @brief Constructs coordinate iterator for CLIQUE algorithm. @param[in] p_dimension: amount of dimensions in input data space. @param[in] p_edge: amount of intervals in each dimension. */ coordinate_iterator(const std::size_t p_dimension, const std::size_t p_edge); public: /*! @brief Returns constant reference to current block coordinate. */ const clique_block_location & get_coordinate() const noexcept; /*! @brief Returns reference to current block coordinate. */ clique_block_location & get_coordinate() noexcept; public: /*! @brief Forms logical location for next block. @details Method `get_coordinate` should be used to get new coordinates. */ coordinate_iterator & operator++(); }; /*! @class clique clique.hpp pyclustering/cluster/clique.hpp @brief Class implements CLIQUE grid based clustering algorithm. @details CLIQUE automatically finds subspaces with high-density clusters. It produces identical results irrespective of the order in which the input records are presented and it does not presume any canonical distribution for input data @cite article::clique::1. Here is an example where data in two-dimensional space is clustered using CLIQUE algorithm: @code using namespace pyclustering; using namespace pyclustering::clst; int main() { // Read two-dimensional input data 'Target'. dataset data = read_data("Target.txt"); // Prepare algorithm's parameters. const std::size_t intervals = 10; // defines amount of cells in grid in each dimension const std::size_t threshold = 0; // no outliers // Create CLIQUE algorithm for processing. clique clique_instance = clique(intervals, threshold); // Run clustering process. clique_data result; clique_instance.process(data, result); // Obtain results. cluster_sequence & clusters = result.clusters(); clique_block_sequence & blocks = result.blocks(); noise & outliers = result.noise(); // in this case it is empty because threshold is 0. // Display information about extracted clusters: std::cout << "Amount of clusters: " << clusters.size() << std::endl; std::cout << "Amount of outliers: " << outliers.size() << std::endl; return 0; } @endcode Here is one of the example how to implement read function to get input data: @code dataset read_data(const std::string & filename) { dataset data; std::ifstream file(filename); std::string line; while (std::getline(file, line)) { std::stringstream stream(line); point coordinates; double value = 0.0; while (stream >> value) { coordinates.push_back(value); } data.push_back(coordinates); } file.close(); return data; } @endcode In example above, 6 clusters are allocated including four small cluster where each such small cluster consists of three points. There are visualized clustering results - grid that has been formed by CLIQUE algorithm with density and clusters itself (see Python version of pyclustering library for visualization): @image html clique_clustering_target.png "Fig. 1. CLIQUE clustering results (grid and clusters itself)." Sometimes such small clusters should be considered as outliers taking into account fact that two clusters in the central are relatively huge. To treat them as a noise threshold value should be increased: @code // Prepare algorithm's parameters. const std::size_t intervals = 10; // defines amount of cells in grid in each dimension const std::size_t threshold = 3; // block that contains 3 or less points is considered as a outlier as well as its points @endcode After execution following output is obtained: @code Amount of clusters: 2 Amount of outliers: 25 @endcode Two clusters are allocated, but in this case some points in cluster-"circle" are also considered as outliers, because CLIQUE operates with blocks, not with points: @image html clique_clustering_with_noise.png "Fig. 2. Noise allocation by CLIQUE." */ class clique { private: struct data_info { point m_min_corner; point m_max_corner; std::vector m_sizes; }; private: using block_map = std::unordered_map; private: std::size_t m_intervals = 0; std::size_t m_density_threshold = 0; const dataset * m_data_ptr = nullptr; clique_data * m_result_ptr = nullptr; block_map m_cells_map; public: /*! @brief Create CLIQUE clustering algorithm. @param[in] p_intervals: amount of intervals in each dimension that defines amount of CLIQUE blocks as \f[N_{ blocks } = intervals^{ dimensions }\f]. @param[in] p_threshold: minimum number of points that should be contained by CLIQUE block to consider its points as non-outliers. */ clique(const std::size_t p_intervals, const std::size_t p_threshold); public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, clique_data & p_result); private: void create_grid(); void expand_cluster(clique_block & p_block); void get_neighbors(const clique_block & p_block, std::list & p_neighbors) const; void get_spatial_location(const clique_block_location & p_location, const clique::data_info & p_info, clique_spatial_block & p_block) const; void get_data_info(clique::data_info & p_info) const; static std::string location_to_key(const clique_block_location & p_location); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/clique_block.hpp000077500000000000000000000123411375753423500265770ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { /*! @brief Defines logical location of CLIQUE block in a data space. */ using clique_block_location = std::vector; /*! @class clique_spatial_block clique_block.hpp pyclustering/cluster/clique_block.hpp @brief Geometrical description of CLIQUE block in a data space. @details Provides services related to spatial functionality. @see bang_block */ class clique_spatial_block { private: point m_max_corner; point m_min_corner; public: /*! @brief Default constructor of the CLIQUE spatial block. */ clique_spatial_block() = default; /*! @brief Constructor of the CLIQUE spatial block. @param[in] p_max_corner: maximum corner coordinates of the block. @param[in] p_min_corner: minimal corner coordinates of the block. */ clique_spatial_block(const point & p_max_corner, const point & p_min_corner); public: /*! @brief Point is considered as contained if it lies in block (belong to it). @param[in] p_point: maximum corner coordinates of the block. @return `true` if the point belongs to the block, otherwise `false` is returned. */ bool contains(const point & p_point) const; /*! @return Returns maximum corner coordinates of the block. */ const point & get_max_corner() const; /*! @brief Update maximum corner coordinates of the block. @param[in] p_corner: new maximum coordinates of the block. */ void move_max_corner(point && p_corner); /*! @return Returns minimum corner coordinates of the block. */ const point & get_min_corner() const; /*! @brief Update minimum corner coordinates of the block. @param[in] p_corner: new minimum coordinates of the block. */ void move_min_corner(point && p_corner); }; /*! @class clique_block clique_block.hpp pyclustering/cluster/clique_block.hpp @brief Defines CLIQUE block that contains information about its logical location and spatial location in a data space and set points that are covered by that block. */ class clique_block { public: /*! @brief Sequence container where points that belong to CLIQUE block are stored. */ using content = std::list; private: clique_block_location m_logical_location; clique_spatial_block m_spatial_location; content m_points; bool m_visited = false; public: /*! @brief CLIQUE block constructor. @param[in] p_location: logical location of the block in CLIQUE grid. @param[in] p_block: spatial location in data space. */ clique_block(const clique_block_location & p_location, const clique_spatial_block & p_block); /*! @brief CLIQUE block constructor that construct object by moving input arguments. @param[in] p_location: logical location of the block in CLIQUE grid. @param[in] p_block: spatial location in data space. */ clique_block(clique_block_location && p_location, clique_spatial_block && p_block); public: /*! @return Returns logical location of the block in CLIQUE grid. */ const clique_block_location & get_logical_location() const; /*! @return Returns spatial location of the block in data space. */ const clique_spatial_block & get_spatial_block() const; /*! @return Returns points that are belong to the block. */ const clique_block::content & get_points() const; /*! @return Returns `true` if the block has been already visited (processed) by CLIQUE algorithm. */ bool is_visited() const; /*! @brief Mark the block as visited (processed) by CLIQUE algorithm. */ void touch(); /*! @brief Finds points that belong to this block using availability map to reduce computational complexity by checking whether the point belongs to the block. @details Algorithm complexity of this method is O(n). @param[in] p_data: data where points are represented as coordinates. @param[in,out] p_availability: contains boolean values that denote whether point is already belong to another CLIQUE block. Points that are captured by the current block in this method are also marked as captured. */ void capture_points(const dataset & p_data, std::vector & p_availability); /*! @brief Forms list of logical location of each neighbor for this particular CLIQUE block. @param[in] p_edge: amount of intervals in each dimension that is used for clustering process. @param[in] p_neighbors: logical location of each neighbor for the CLIQUE block. */ void get_location_neighbors(const std::size_t p_edge, std::vector & p_neighbors) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/clique_data.hpp000077500000000000000000000026211375753423500264160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace clst { /*! @brief Sequence container where CLIQUE blocks are stored. */ using clique_block_sequence = std::vector; /*! @class clique_data clique_data.hpp pyclustering/cluster/clique_data.hpp @brief A storage where CLIQUE clustering results are stored. */ class clique_data : public cluster_data { private: clique_block_sequence m_blocks; clst::noise m_noise; public: /*! @brief Returns constant reference to CLIQUE blocks that are formed during clustering process. */ const clique_block_sequence & blocks() const { return m_blocks; } /*! @brief Returns reference to CLIQUE blocks that are formed during clustering process. */ clique_block_sequence & blocks() { return m_blocks; } /*! @brief Returns constant reference to outliers that are allocated during clustering process. */ const clst::noise & noise() const { return m_noise; } /*! @brief Returns reference to outliers that are allocated during clustering process. */ clst::noise & noise() { return m_noise; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/cluster_data.hpp000077500000000000000000000064241375753423500266220ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace clst { using noise = std::vector; using noise_ptr = std::shared_ptr; using index_sequence = std::vector; using cluster = std::vector; using cluster_sequence = std::vector; using cluster_sequence_ptr = std::shared_ptr; /*! @class cluster_data cluster_data.hpp pyclustering/cluster/cluster_data.hpp @brief Represents result of cluster analysis. */ class cluster_data { protected: cluster_sequence m_clusters = { }; /**< Allocated clusters during clustering process. */ public: /*! @brief Default constructor that creates empty clustering data. */ cluster_data() = default; /*! @brief Copy constructor that creates clustering data that is the same to specified. @param[in] p_other: another clustering data. */ cluster_data(const cluster_data & p_other) = default; /*! @brief Move constructor that creates clustering data from another by moving data. @param[in] p_other: another clustering data. */ cluster_data(cluster_data && p_other) = default; /*! @brief Default destructor that destroy clustering data. */ virtual ~cluster_data() = default; public: /*! @brief Returns reference to clusters. */ cluster_sequence & clusters(); /*! @brief Returns constant reference to clusters. */ const cluster_sequence & clusters() const; /*! @brief Returns amount of clusters. */ std::size_t size() const; public: /*! @brief Provides access to specified cluster. @param[in] p_index: index of specified cluster. */ cluster & operator[](const size_t p_index); /*! @brief Provides access to specified cluster. @param[in] p_index: index of specified cluster. */ const cluster & operator[](const size_t p_index) const; /*! @brief Set clustering data by copy it from another object. @param[in] p_other: another clustering data. */ cluster_data & operator=(const cluster_data & p_other); /*! @brief Set clustering data by move it from another object. @param[in] p_other: another clustering data. */ cluster_data & operator=(cluster_data && p_other); /*! @brief Compares clustering data. @param[in] p_other: another clustering data that is used for comparison. @return Returns true if both objects have the same amount of clusters with the same elements. */ bool operator==(const cluster_data & p_other) const; /*! @brief Compares clustering data. @param[in] p_other: another clustering data that is used for comparison. @return Returns true if both objects have are not the same. */ bool operator!=(const cluster_data & p_other) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/cure.hpp000077500000000000000000000254471375753423500251140ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include using namespace pyclustering::container; namespace pyclustering { namespace clst { /*! @class cure_cluster cure.hpp pyclustering/cluster/cure.hpp @brief CURE cluster description. */ struct cure_cluster { public: std::vector * mean; /**< Center of the cluster that is defined by mean value among cluster points. */ std::vector< std::vector * > * points; /**< Points that are contained by the cluster. */ std::vector< std::vector * > * rep; /**< Representative points of the cluster. */ cure_cluster * closest; /**< Pointer to the closest cluster. */ double distance_closest; /**< Distance to the closest cluster. */ public: /*! @brief Default constructor of CURE cluster. */ cure_cluster(); /*! @brief Construct CURE cluster using signle point. */ explicit cure_cluster(std::vector * point); /*! @brief Default destructor. */ ~cure_cluster(); /*! @brief Copy constructor is deleted due to safety reasons. */ cure_cluster(const cure_cluster & p_other) = delete; public: /*! @brief Insert points to cluster. */ void insert_points(std::vector *> * append_points); public: /*! @brief Assignment operator is deleted due to safety reasons. */ cure_cluster & operator=(const cure_cluster & p_other) = delete; /*! @brief Write object operator to represent CURE cluster by text. */ friend std::ostream & operator<<(std::ostream & p_stream, cure_cluster & p_cluster); }; /*! @class cure_cluster_comparator cure.hpp pyclustering/cluster/cure.hpp @brief CURE cluster comparator using closest distance. */ class cure_cluster_comparator { public: /*! @brief Defines compare procedure using closest distance without checking for nullptr. @details Arguments are not checked for nullptr, this checking should be done by client code. @param[in] obj1: pointer to left operand (CURE cluster 1). @param[in] obj2: pointer to right operand (CURE cluster 2). @return Returns `true` if left operand is less than right. */ bool operator()(const cure_cluster * const obj1, const cure_cluster * const obj2) const; }; /*! @class cure_queue cure.hpp pyclustering/cluster/cure.hpp @brief Cure sorted queue of cure clusters. Sorting is defined by distances between clusters. First element is always occupied by cluster whose distance to the neighbor cluster is the smallest in the queue. */ class cure_queue { private: std::multiset * queue; kdtree * tree; private: /*! @brief Creates sorted queue of points for specified data. @param[in] data: pointer to points. */ void create_queue(const dataset * data); /*! @brief Remove representative points of specified cluster from KD Tree. @param[in] cluster: pointer to points. */ void remove_representative_points(cure_cluster * cluster); /*! @brief Insert representative points of specified cluster to KD tree. @param[in] cluster: pointer to points. */ void insert_representative_points(cure_cluster * cluster); /*! @brief Insert cluster to sorted queue (it's not insertion of new object). @details Used by sorting procedures. @param[in] inserted_cluster: pointer to points. */ void insert_cluster(cure_cluster * inserted_cluster); /*! @brief Remove cluster from sorted queue (it's not removing of new object). Used by sorting procedures. @param[in] removed_cluster: pointer to points. */ void remove_cluster(cure_cluster * removed_cluster); /*! @brief Calculate distance between clusters. @param[in] cluster1: pointer to cure cluster 1. @param[in] cluster2: pointer to cure cluster 2. @return Return distance between clusters. */ static double get_distance(cure_cluster * cluster1, cure_cluster * cluster2); /*! @brief Checks if all elements of a merged cluster are same. @param[in] merged_cluster: pointer to cure merged_cluster. @return Returns true if all the elements in the cluster were found to be same. */ static bool are_all_elements_same(cure_cluster * merged_cluster); public: /*! @brief Iterator to iterate though CURE clusters in the sorted queue. */ using iterator = std::multiset::iterator; /*! @brief Constant iterator to iterate though CURE clusters in the sorted queue. */ using const_iterator = std::multiset::const_iterator; /*! @brief Default constructor of cure queue (always keeps sorted state). */ cure_queue(); /*! @brief Default constructor of sorted queue of cure clusters. @param[in] data: pointer to points. */ explicit cure_queue(const std::vector< std::vector > * data); /*! @brief Default copy constructor of sorted queue of cure clusters is forbidden. @param[in] p_other: other cure queue to copy. */ cure_queue(const cure_queue & p_other) = delete; /*! @brief Default destructor. */ ~cure_queue(); /*! @brief Merge cure clusters in line with the rule of merging of cure algorithm. @param[in,out] cluster1: pointer to cure cluster 1. @param[in,out] cluster2: pointer to cure cluster 2. @param[in] number_repr_points: number of representative points for merged cluster. @param[in] compression: level of compression for calculation representative points. */ void merge(cure_cluster * cluster1, cure_cluster * cluster2, const size_t number_repr_points, const double compression); /*! @brief Returns iterator to the first CURE cluster. */ inline iterator begin() { return queue->begin(); } /*! @brief Returns constant iterator to the first CURE cluster. */ inline const_iterator begin() const { return queue->begin(); }; /*! @brief Returns iterator to the end of CURE cluster collection (not a last element). */ inline iterator end() { return queue->end(); } /*! @brief Returns constant iterator to the end of CURE cluster collection (not a last element). */ inline const_iterator end() const { return queue->end(); } /*! @brief Returns amount of CURE clusters in the queue. */ inline std::size_t size() const { return queue->size(); } public: /*! @brief Assignment operator is forbidden. @param[in] p_other: other cure queue to copy. */ cure_queue & operator=(const cure_queue & p_other) = delete; }; /*! @class relocation_info cure.hpp pyclustering/cluster/cure.hpp @brief Defines relocation request for specific cluster in CURE queue. */ class relocation_info { private: cure_queue::iterator m_cluster_iterator; cure_cluster * m_closest_cluster; double m_closest_distance; public: /*! @brief Constructor for relocation request. @param[in] cluster_iterator: iterator that points to the cluster in the queue. @param[in] closest_cluster: new closest cluster for the cluster that should be relocated. @param[in] closest_distance: distance to the closest cluster. */ relocation_info(const cure_queue::iterator & cluster_iterator, cure_cluster * closest_cluster, const double closest_distance); public: /*! @brief Returns iterator to cluster in CURE queue. @return Iterator to cluster in CURE queue that should be relocated. */ cure_queue::iterator get_cluster_iterator() const; /*! @brief Returns distance to the closest cluster. @return Distance to the closest cluster. */ double get_closest_distance() const; /*! @brief Returns pointer to the closest cluster. @return Pointer to the closest cluster. */ cure_cluster * get_closest_cluster(); }; /*! @class cure cure.hpp pyclustering/cluster/cure.hpp @brief CURE clustering algorithm that employes a hierarchical clustering algorithm that adopts a middle ground between the centroid-based and the all-point extremes. @details CURE algorithm identifies clusters having non-spherical shapes and wide variances in size. CURE algorithm represents each cluster by a certain fixed number of points that are generated by selecting well scattered points from the cluster and then shrinking them toward the center of the cluster by a specified fraction. Having more than one representative point per cluster allows CURE to adjust well to the geometry of non-spherical shapes. Implementation based on paper @cite article::cure::1. */ class cure { private: cure_queue * queue; std::size_t number_points; std::size_t number_clusters; double compression; const dataset * data; public: /*! @brief Default CURE algorithm constructor. */ cure() = default; /*! @brief Constructor of CURE algorithm. @param[in] clusters_number: number of clusters that should be allocated. @param[in] points_number: number of representative points in each cluster. @param[in] level_compression: level of compression for calculation new representative points for merged cluster. */ cure(const size_t clusters_number, const size_t points_number, const double level_compression); /*! @brief Default destructor. */ ~cure(); public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, cure_data & p_result); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/cure_data.hpp000077500000000000000000000057151375753423500261010ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace clst { using representor_sequence = std::vector; using representor_sequence_ptr = std::shared_ptr; /*! @brief Clustering results of CURE algorithm that consists of information about allocated clusters and their representative points and mean value. */ class cure_data : public cluster_data { private: representor_sequence m_representative_sequence = { }; dataset m_mean_sequence = { }; public: /*! @brief Default constructor that creates empty clustering data. */ cure_data() = default; /*! @brief Copy constructor that creates clustering data that is the same to specified. @param[in] p_other: another clustering data. */ cure_data(const cure_data & p_other) = default; /*! @brief Move constructor that creates clustering data from another by moving data. @param[in] p_other: another clustering data. */ cure_data(cure_data && p_other) = default; /*! @brief Default destructor that destroys clustering data. */ virtual ~cure_data() = default; public: /*! @brief Returns reference to representative points of each cluster. @details Cluster index should be used to navigate in collections of representative points. An example of representative points of two clusters: { {{ 1.0, 2.0 }, { 3.4, 4.0 }}, {{ 7.5, 6.3 }, { -1.4, -4.7 }} } where points { {{ 1.0, 2.0 }, { 3.4, 4.0 }} are related to the first cluster and {{ 7.5, 6.3 }, { -1.4, -4.7 }} to the second. @return Shared pointer to representative points of each cluster. */ representor_sequence & representors() { return m_representative_sequence; } /*! @brief Returns constant reference to representative points of each cluster. */ const representor_sequence & representors() const { return m_representative_sequence; } /*! @brief Returns reference to mean point of each cluster. @details Cluster index should be used to navigate in collections of mean points. An example of mean points of three clusters: { { 1.0, 2.0 }, { 3.4, 4.0 }, { 7.0, 9.1 } } where { 1.0, 2.0 } is mean of the first cluster, { 3.4, 4.0 } - mean of the second and { 7.0, 9.1 } of the third. @return Shared pointer to mean point of each cluster. */ dataset & means() { return m_mean_sequence; } /*! @brief Returns constant reference to mean point of each cluster. */ const dataset & means() const { return m_mean_sequence; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/dbscan.hpp000077500000000000000000000072611375753423500254020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace clst { /*! @brief Defines types that are used for input data representation. */ enum class dbscan_data_t { POINTS, /**< Data is represented by a container of points. */ DISTANCE_MATRIX /**< Data is represented by a distance matrix between points. */ }; /*! @class dbscan dbscan.hpp pyclustering/cluster/dbscan.hpp @brief Represents DBSCAN clustering algorithm for cluster analysis. @details The algorithm related to density-based class. Implementation based on paper @cite inproceedings::dbscan::1. */ class dbscan { private: const dataset * m_data_ptr = nullptr; /* temporary pointer to input data that is used only during processing */ dbscan_data * m_result_ptr = nullptr; /* temporary pointer to clustering result that is used only during processing */ std::vector m_visited = { }; std::vector m_belong = { }; double m_initial_radius = 0.0; /* original radius that was specified by user */ size_t m_neighbors = 0; dbscan_data_t m_type = dbscan_data_t::POINTS; container::kdtree_balanced m_kdtree = container::kdtree_balanced(); public: /*! @brief Default constructor of clustering algorithm. */ dbscan() = default; /*! @brief Constructor of clustering algorithm where algorithm parameters for processing are specified. @param[in] p_radius_connectivity: connectivity radius between objects. @param[in] p_minimum_neighbors: minimum amount of shared neighbors that is require to connect two object (if distance between them is less than connectivity radius). */ dbscan(const double p_radius_connectivity, const size_t p_minimum_neighbors); /*! @brief Default destructor of the algorithm. */ ~dbscan() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data (points) for cluster analysis. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, dbscan_data & p_result); /*! @brief Performs cluster analysis of an input data of specific type. @param[in] p_data: input data for cluster analysis. @param[in] p_type: type of an input data that should be clustered. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, const dbscan_data_t p_type, dbscan_data & p_result); private: /*! @brief Obtains neighbors of the specified node (data object). @param[in] p_index: index of the node (data object). @param[out] p_neighbors: neighbor indexes of the specified node (data object). */ void get_neighbors(const size_t p_index, std::vector & p_neighbors); void get_neighbors_from_points(const size_t p_index, std::vector & p_neighbors); void get_neighbors_from_distance_matrix(const size_t p_index, std::vector & p_neighbors); void create_kdtree(const dataset & p_data); void expand_cluster(const std::size_t p_index, cluster & allocated_cluster); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/dbscan_data.hpp000077500000000000000000000030301375753423500263610ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { /*! @class dbscan_data dbscan_data.hpp pyclustering/cluster/dbscan_data.hpp @brief Clustering results of DBSCAM algorithm that consists of information about allocated clusters and noise (points that are not related to any cluster). */ class dbscan_data : public cluster_data { private: clst::noise m_noise; public: /*! @brief Default constructor that creates empty clustering data. */ dbscan_data() = default; /*! @brief Copy constructor of DBSCAN clustering data. @param[in] p_other: another DBSCAN clustering data. */ dbscan_data(const dbscan_data & p_other) = default; /*! @brief Move constructor of DBSCAN clustering data. @param[in] p_other: another clustering data. */ dbscan_data(dbscan_data && p_other) = default; /*! @brief Default destructor that destroys DBSCAN clustering data. */ virtual ~dbscan_data() = default; public: /*! @brief Returns reference to outliers represented by indexes. */ clst::noise & noise() { return m_noise; } /*! @brief Returns constant reference to outliers represented by indexes. */ const clst::noise & noise() const { return m_noise; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/elbow.hpp000077500000000000000000000267671375753423500252740ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include using namespace pyclustering::parallel; using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class elbow elbow.hpp pyclustering/cluster/elbow.hpp @brief The elbow is a heuristic method to find the appropriate number of clusters in a dataset. @details The elbow is a heuristic method of interpretation and validation of consistency within cluster analysis designed to help find the appropriate number of clusters in a dataset. Elbow method performs clustering using K-Means algorithm for each K and estimate clustering results using sum of square erros. By default K-Means++ algorithm is used to calculate initial centers that are used by K-Means algorithm. The Elbow is determined by max distance from each point (x, y) to segment from kmin-point (x0, y0) to kmax-point (x1, y1), where 'x' is K (amount of clusters), and 'y' is within-cluster error. Following expression is used to calculate Elbow length: \f[Elbow_{k} = \frac{\left ( y_{0} - y_{1} \right )x_{k} + \left ( x_{1} - x_{0} \right )y_{k} + \left ( x_{0}y_{1} - x_{1}y_{0} \right )}{\sqrt{\left ( x_{1} - x_{0} \right )^{2} + \left ( y_{1} - y_{0} \right )^{2}}}\f] Usage example of Elbow method for cluster analysis: @code #include #include #include #include #include using namespace pyclustering; using namespace pyclustering::clst; int main() { // Read two-dimensional input data 'Simple03'. dataset data = read_data("Simple03.txt"); // See an example of the implementation below. // Prepare methods's parameters. const std::size_t kmin = 1; // minimum amount of clusters that should be considered const std::size_t kmax = 10; // maximum amount of clusters // Create Elbow method for processing. elbow<> elbow_instance = elbow<>(kmin, kmax); // Run Elbow method to get optimal amount of clusters. elbow_data result; elbow_instance.process(data, result); // Obtain results. const std::size_t amount_clusters = result.get_amount(); const wce_sequence & wce = result.get_wce(); // total within-cluster errors for each K. // Perform cluster analysis using K-Means algorithm. // Prepare initial centers before running K-Means algorithm. dataset initial_centers; kmeans_plus_plus(amount_clusters, 5).initialize(data, initial_centers); // Create K-Means algorithm and run it. kmeans_data clustering_result; kmeans(initial_centers).process(data, clustering_result); // Obtain clustering results. const cluster_sequence & clusters = clustering_result.clusters(); const dataset & centers = clustering_result.centers(); // Print results to console. for (std::size_t i = 0; i < clusters.size(); i++) { std::cout << "Cluster #" << i + 1 << " with center at ( "; const point & center = centers[i]; for (const auto coordinate : center) { std::cout << coordinate << " "; } std::cout << " ): "; const cluster & group = clusters[i]; for (const auto index : group) { std::cout << index << " "; } std::cout << std::endl; } return 0; } @endcode Here is an example how to read input data from simple text file: @code dataset read_data(const std::string & filename) { dataset data; std::ifstream file(filename); std::string line; while (std::getline(file, line)) { std::stringstream stream(line); point coordinates; double value = 0.0; while (stream >> value) { coordinates.push_back(value); } data.push_back(coordinates); } file.close(); return data; } @endcode By default Elbow uses K-Means++ initializer to calculate initial centers for K-Means algorithm, it can be changed using argument 'initializer': @code // Prepare methods's parameters. const std::size_t kmin = 1; // minimum amount of clusters that should be considered const std::size_t kmax = 10; // maximum amount of clusters // Create and run Elbow method to get optimal amount of clusters using random center initializer. elbow_data result; elbow(kmin, kmax).process(data, result); @endcode @image html elbow_example_simple_03.png "Elbows analysis with further K-Means clustering." Implementation based on paper @cite article::cluster::elbow::1. */ template class elbow { private: std::size_t m_kmin = 0; std::size_t m_kmax = 0; std::size_t m_kstep = 0; std::size_t m_kamount = 0; long long m_random_state = RANDOM_STATE_CURRENT_TIME; std::vector m_elbow = { }; const dataset * m_data = nullptr; elbow_data * m_result = nullptr; /* temporary pointer to output result */ public: /*! @brief Default constructor of Elbow method. */ elbow() = default; /*! @brief Elbow method constructor with parameters of the method. @param[in] p_kmin: minimum amount of clusters that should be considered. @param[in] p_kmax: maximum amount of clusters that should be considered. */ elbow(const std::size_t p_kmin, const std::size_t p_kmax) : elbow(p_kmin, p_kmax, 1, RANDOM_STATE_CURRENT_TIME) { } /*! @brief Elbow method constructor with parameters of the method. @param[in] p_kmin: minimum amount of clusters that should be considered. @param[in] p_kmax: maximum amount of clusters that should be considered. @param[in] p_kstep: search step in the interval [kmin, kmax]. */ elbow(const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep) : elbow(p_kmin, p_kmax, p_kstep, RANDOM_STATE_CURRENT_TIME) { } /*! @brief Elbow method constructor with parameters of the method. @param[in] p_kmin: minimum amount of clusters that should be considered. @param[in] p_kmax: maximum amount of clusters that should be considered. @param[in] p_kstep: search step in the interval [kmin, kmax]. @param[in] p_random_state: seed for random state. */ elbow(const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep, const long long p_random_state) : m_kmin(p_kmin), m_kmax(p_kmax), m_kstep(p_kstep), m_kamount((m_kmax - m_kmin) / m_kstep + 1), m_random_state(p_random_state) { verify(); } /*! @brief Copy constructor of Elbow method. */ elbow(const elbow & p_other) = default; /*! @brief Move constructor of Elbow method. */ elbow(elbow && p_other) = default; /*! @brief Destructor of Elbow method. */ ~elbow() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: an input data that should be clusted. @param[out] p_result: elbow input data processing result. */ void process(const dataset & p_data, elbow_data & p_result) { if (p_data.size() < m_kmax) { throw std::invalid_argument("K max value '" + std::to_string(m_kmax) + "' is greater than amount of data points '" + std::to_string(p_data.size()) + "'."); } m_data = &p_data; m_result = &p_result; m_result->get_wce().resize(m_kamount); parallel_for(m_kmin, m_kmax + 1, m_kstep, [this](const std::size_t p_index){ calculate_wce(p_index); }); calculate_elbows(); m_result->set_amount(find_optimal_kvalue()); } private: template typename std::enable_if::value, void>::type static prepare_centers(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, dataset & p_initial_centers) { kmeans_plus_plus(p_amount, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, p_random_state).initialize(p_data, p_initial_centers); } template typename std::enable_if::value, void>::type static prepare_centers(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, dataset & p_initial_centers) { TypeInitializer(p_amount, p_random_state).initialize(p_data, p_initial_centers); } void calculate_wce(const std::size_t p_kvalue) { dataset initial_centers; prepare_centers(p_kvalue, *m_data, m_random_state, initial_centers); kmeans_data result; kmeans instance(initial_centers, kmeans::DEFAULT_TOLERANCE); instance.process(*m_data, result); m_result->get_wce().at((p_kvalue - m_kmin) / m_kstep) = result.wce(); } void verify() { if (m_kmin < 1) { throw std::invalid_argument("K min value '" + std::to_string(m_kmin) + "' should be greater than 0."); } if (m_kmax <= m_kmin) { throw std::invalid_argument("K max value '" + std::to_string(m_kmax) + "' should be greater than K min value '" + std::to_string(m_kmin) + "'."); } if (m_kmax + 1 < 3 + m_kmin) { throw std::invalid_argument("Amount of K '" + std::to_string(m_kmax - m_kmin) + "' is too small for analysis."); } if (m_kamount < 3) { throw std::invalid_argument("The search step is too high '" + std::to_string(m_kstep) + "' for analysis (amount of K for analysis is '" + std::to_string(m_kamount) + "')."); } } void calculate_elbows() { const wce_sequence & wce = m_result->get_wce(); const double x0 = 0.0; const double y0 = wce.front(); const double x1 = static_cast(wce.size()); const double y1 = wce.back(); const double norm = euclidean_distance(point({ x0, y0 }), point({ x1, y1 })); m_elbow.resize(wce.size() - 2, 0.0); for (std::size_t index_elbow = 1; index_elbow < m_result->get_wce().size() - 1; index_elbow++) { const double x = static_cast(index_elbow); const double y = wce.at(index_elbow); const double segment = std::abs((y0 - y1) * x + (x1 - x0) * y + (x0 * y1 - x1 * y0)); m_elbow[index_elbow - 1] = segment / norm; } } std::size_t find_optimal_kvalue() { auto optimal_elbow_iter = std::max_element(m_elbow.cbegin(), m_elbow.cend()); return (std::distance(m_elbow.cbegin(), optimal_elbow_iter) + 1) * m_kstep + m_kmin; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/elbow_data.hpp000077500000000000000000000035141375753423500262460ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { /*! @brief Sequence container to store within cluster errors (WCE) for each K-value. */ using wce_sequence = std::vector; /*! @class elbow_data elbow_data.hpp pyclustering/cluster/elbow_data.hpp @brief Elbow analysis result that contain information about optimal amount of clusters and total within cluster errors (WCE) for each K-value. */ class elbow_data { private: std::size_t m_amount = 0; wce_sequence m_wce = { }; public: /*! @brief Default constructor of the Elbow result. */ elbow_data() = default; /*! @brief Default desctructor of the Elbow result. */ ~elbow_data() = default; public: /*! @brief Returns constant reference to total within cluster errors (WCE) for each K-value. @return Constant reference to total within cluster errors (WCE) for each K-value. */ const wce_sequence & get_wce() const { return m_wce; } /*! @brief Returns reference to total within cluster errors (WCE) for each K-value. @return Reference to total within cluster errors (WCE) for each K-value. */ wce_sequence & get_wce() { return m_wce; } /*! @brief Set optimal amount of clusters. @details The method is used by Elbow method to set the final analysis result. */ void set_amount(const std::size_t p_amount) { m_amount = p_amount; } /*! @brief Returns optimal amount of clusters. @return Optimal amount of clusters. */ std::size_t get_amount() const { return m_amount; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/fcm.hpp000077500000000000000000000133621375753423500247140ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { /*! @class fcm fcm.hpp pyclustering/cluster/fcm.hpp @brief Class represents Fuzzy C-means (FCM) clustering algorithm. @details Fuzzy clustering is a form of clustering in which each data point can belong to more than one cluster. Fuzzy C-Means algorithm uses two general formulas for cluster analysis. The first is to updated membership of each point: \f[w_{ij}=\frac{1}{\sum_{k=0}^{c}\left ( \frac{\left \| x_{i}-c_{j} \right \|}{\left \| x_{i}-c_{k} \right \|} \right )^{\frac{2}{m-1}}}\f] The second formula is used to update centers in line with obtained centers: \f[c_{k}=\frac{\sum_{i=0}^{N}w_{k}\left ( x_{i} \right )^{m}x_{i}}{\sum_{i=0}^{N}w_{k}\left ( x_{i} \right )^{m}}\f] Fuzzy C-Means clustering results depend on initial centers. Algorithm K-Means++ can used for center initialization to improve clustering quality. Here is an example how to perform cluster analysis using Fuzzy C-Means algorithm: @code int main() { // Read two-dimensional input data 'OldFaithful'. dataset data = read_data("OldFaithful.txt"); // Prepare initial centers const std::size_t amount_clusters = 2; const std::size_t candidates = 5; dataset initial_centers; kmeans_plus_plus(amount_clusters, candidates).initialize(data, initial_centers); // Create and run FCM clustering algorithm. fcm_data result; fcm(initial_centers).process(data, result); // Obtain clustering results. const cluster_sequence & clusters = result.clusters(); const dataset & centers = result.centers(); const membership_sequence & membership = result.membership(); // Display points which have membership probability less than 90%. std::cout << "Points that have membership probability less than 90%: "; for (std::size_t i = 0; i < membership.size(); i++) { if (membership[i][0] > 0.1 && membership[i][0] < 0.9) { std::cout << i << " "; } } std::cout << std::endl; return 0; } @endcode The next example shows how to perform image segmentation using Fuzzy C-Means algorithm: @code // Read image (photo), for example, using OpenCV2 or any other library. dataset data = read_image("stpetersburg_admiral.jpg"); // Prepare initial centers const std::size_t amount_segments = 3; const std::size_t candidates = kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE; dataset initial_centers; kmeans_plus_plus(amount_segments, candidates).initialize(data, initial_centers); // Create and run FCM clustering algorithm to extract color segments from the image. fcm_data result; fcm(initial_centers).process(data, result); @endcode @image html fcm_segmentation_stpetersburg.png "Image segmentation using Fuzzy C-Means algorithm." Visualization has been done using Python version of pyclustering library. */ class fcm { public: const static double DEFAULT_TOLERANCE; /**< Default value of the tolerance stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. */ const static std::size_t DEFAULT_ITERMAX; /**< Default value of the step stop condition - maximum number of iterations that is used for clustering process. */ const static double DEFAULT_HYPER_PARAMETER; /**< Default value of hyper-parameter that controls how fuzzy the cluster will be. */ private: double m_tolerance = DEFAULT_TOLERANCE; std::size_t m_itermax = DEFAULT_ITERMAX; dataset m_initial_centers = { }; double m_degree = 0.0; fcm_data * m_ptr_result = nullptr; /* temporary pointer to output result */ const dataset * m_ptr_data = nullptr; /* used only during processing */ public: /*! @brief Default constructor of FCM clustering algorithm. */ fcm() = default; /*! @brief Constructor of FCM clustering algorithm with specific parameters. @param[in] p_initial_centers: initial centers for clusters. @param[in] p_m: hyper-parameter that controls how fuzzy the cluster will be; the higher it is, the fuzzier the cluster will be in the end. @param[in] p_tolerance: stop condition value: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. @param[in] p_itermax: maximum number of iterations that is used for clustering process. */ fcm(const dataset & p_initial_centers, const double p_m = DEFAULT_HYPER_PARAMETER, const double p_tolerance = DEFAULT_TOLERANCE, const std::size_t p_itermax = DEFAULT_ITERMAX); /*! @brief Default destructor of FCM clustering algorithm. */ ~fcm() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: FCM clustering result of an input data. */ void process(const dataset & p_data, fcm_data & p_result); private: void verify() const; double update_centers(); double update_center(const std::size_t p_index); void update_membership(); void update_point_membership(const std::size_t p_index); void extract_clusters(cluster_sequence & p_clusters); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/fcm_data.hpp000077500000000000000000000034171375753423500257050ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace clst { /*! @brief Container for membership (probability) of each point from data. */ using membership_sequence = dataset; /*! @class fcm_data fcm_data.hpp pyclustering/cluster/fcm_data.hpp @brief Clustering results of Fuzzy C-Means algorithm that consists of information about allocated clusters and centers of each cluster. */ class fcm_data : public cluster_data { private: dataset m_centers = { }; dataset m_membership = { }; public: /*! @brief Returns reference to centers of allocated clusters. @return Reference to centers of allocated clusters. */ dataset & centers() { return m_centers; } /*! @brief Returns const reference to centers of allocated clusters. @return Const reference to centers of allocated clusters. */ const dataset & centers() const { return m_centers; }; /*! @brief Returns reference to cluster membership (probability) for each point in data. @return Reference to cluster membership (probability) for each point in data. */ membership_sequence & membership() { return m_membership; } /*! @brief Returns constant reference to cluster membership (probability) for each point in data. @return Constant reference to cluster membership (probability) for each point in data. */ const membership_sequence & membership() const { return m_membership; }; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/gmeans.hpp000077500000000000000000000156531375753423500254260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class gmeans gmeans.hpp pyclustering/cluster/gmeans.hpp @brief Represents G-Means clustering algorithm for cluster analysis. @details The G-means algorithm starts with a small number of centers, and grows the number of centers. Each iteration of the G-Means algorithm splits into two those centers whose data appear not to come from a Gaussian distribution. G-means repeatedly makes decisions based on a statistical test for the data assigned to each center. @image html gmeans_example_clustering.png "G-Means clustering results on most common data-sets." Example #1. In this example, G-Means starts analysis from single cluster. @code int main() { // Read two-dimensional input data 'Lsun'. dataset data = read_data("Lsun.txt"); // Create and run G-Means clustering algorithm. // By default the algorithm starts search from a single cluster. gmeans_data result; gmeans().process(data, result); // Obtain clustering results. const cluster_sequence & clusters = result.clusters(); const dataset & centers = result.centers(); // Display results to console. for (std::size_t i = 0; i < clusters.size(); i++) { std::cout << "Cluster #" << i + 1 << std::endl; std::cout << " - Center: "; const auto & center = centers[i]; for (const auto coordinate : center) { std::cout << coordinate << " "; } std::cout << std::endl; std::cout << "- Size: " << clusters[i].size() << std::endl << std::endl; } return 0; } @endcode Example #2. Sometimes G-Means may found local optimum. 'repeat' value can be used to increase probability to find global optimum. Argument 'repeat' defines how many times K-Means clustering with K-Means++ initialization should be run to find optimal clusters. @code // Create and run G-Means clustering algorithm. const std::size_t initial_k = 1; const double tolerance = gmeans::DEFAULT_TOLERANCE; const std::size_t repeat = 5; // Repeat each iteration 5 time to find optimum. gmeans_data result; gmeans(initial_k, tolerance, repeat).process(data, result); @endcode Implementation based on the paper @cite inproceedings::cluster::gmeans::1. */ class gmeans { private: using projection = std::vector; public: const static long long IGNORE_KMAX; /**< Defines value that means to ignore K maximum value. */ const static std::size_t DEFAULT_AMOUNT_CENTERS; /**< Defaule value of amount of initial K - the value from that the search procedure is started. */ const static double DEFAULT_TOLERANCE; /**< Default value of the tolerance (stop condition): if the maximum value of cluster changes is less than tolerance then the algorithm stops processing. */ const static std::size_t DEFAULT_REPEAT; /**< Default value that defines how many times K-Means should be run to improve parameters. */ const static std::size_t DEFAULT_CANDIDATES; /**< Default value of amount of candidates to consider by K-Means++ to initialize initial centers for K-Means on each iteration. */ private: std::size_t m_amount = DEFAULT_AMOUNT_CENTERS; double m_tolerance = DEFAULT_TOLERANCE; std::size_t m_repeat = DEFAULT_REPEAT; long long m_kmax = IGNORE_KMAX; long long m_random_state = RANDOM_STATE_CURRENT_TIME; gmeans_data * m_ptr_result = nullptr; /* temporary pointer to output result */ const dataset * m_ptr_data = nullptr; /* used only during processing */ public: /*! @brief Default constructor of G-Means clustering algorithm. */ gmeans() = default; /*! @brief Constructor of clustering algorithm where algorithm parameters for processing are specified. @param[in] p_k_initial: initial amount of centers. @param[in] p_tolerance: stop condition in following way: when maximum value of distance change of cluster centers is less than tolerance then algorithm stops processing. @param[in] p_repeat: how many times K-Means should be run to improve parameters (by default is 3), with larger `repeat` values suggesting higher probability of finding global optimum. @param[in] p_kmax: maximum amount of clusters that might be allocated. The argument is considered as a stop condition. When the maximum amount is reached then algorithm stops processing. By default the maximum amount of clusters is not restricted (`k_max` is `IGNORE_KMAX`). @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). */ gmeans(const std::size_t p_k_initial, const double p_tolerance = DEFAULT_TOLERANCE, const std::size_t p_repeat = DEFAULT_REPEAT, const long long p_kmax = IGNORE_KMAX, const long long p_random_state = RANDOM_STATE_CURRENT_TIME); /*! @brief Default destructor of G-Means algorithm. */ ~gmeans() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[in,out] p_result: clustering result of an input data, it is also considered as an input argument to where observer parameter can be set to collect changes of clusters and centers on each step of processing. */ void process(const dataset & p_data, gmeans_data & p_result); private: bool is_run_condition() const; void search_optimal_parameters(const dataset & p_data, const std::size_t p_amount, cluster_sequence & p_clusters, dataset & p_centers) const; void statistical_optimization(); void perform_clustering(); void split_and_search_optimal(const cluster & p_cluster, dataset & p_centers) const; static bool is_null_hypothesis(const dataset & p_data, const point & p_center1, const point & p_center2); static std::size_t get_amount_candidates(const dataset & p_data); static projection calculate_projection(const dataset & p_data, const point & p_vector); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/gmeans_data.hpp000077500000000000000000000045731375753423500264160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace clst { /*! @class gmeans_data gmeans_data.hpp pyclustering/cluster/gmeans_data.hpp @brief Clustering results of G-Means algorithm that consists of information about allocated clusters and centers of each cluster. */ class gmeans_data : public cluster_data { private: dataset m_centers = { }; double m_wce = 0.0; public: /*! @brief Default constructor that creates empty clustering data. @details In case of default constructor clusters and centers are not stored on each clustering iteration. */ gmeans_data() = default; /*! @brief Copy constructor that creates clustering data that is the same to specified. @param[in] p_other: another clustering data. */ gmeans_data(const gmeans_data & p_other) = default; /*! @brief Move constructor that creates clustering data from another by moving data. @param[in] p_other: another clustering data. */ gmeans_data(gmeans_data && p_other) = default; /*! @brief Default destructor that destroys clustering data. */ virtual ~gmeans_data() = default; public: /*! @brief Returns reference to centers that correspond to allocated clusters. @return Reference to centers that correspond to allocated clusters. */ dataset & centers() { return m_centers; } /*! @brief Returns constant reference to centers that correspond to allocated clusters. @return Constant reference to centers that correspond to allocated clusters. */ const dataset & centers() const { return m_centers; }; /*! @brief Returns total within-cluster errors. @return Total within-cluster errors. */ double & wce() { return m_wce; } /*! @brief Returns constant total within-cluster errors. @return Constant total within-cluster errors. */ const double & wce() const { return m_wce; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/hsyncnet.hpp000077500000000000000000000060121375753423500257740ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { typedef std::vector hsyncnet_cluster; typedef ensemble_data hsyncnet_cluster_data; typedef syncnet_analyser hsyncnet_analyser; /*! @class hsyncnet hsyncnet.hpp pyclustering/cluster/hsyncnet.hpp @brief Oscillatory neural network based on Kuramoto model for cluster analysis. @see hsyncnet_analyser */ class hsyncnet: public syncnet { private: std::size_t m_number_clusters; std::size_t m_initial_neighbors; double m_increase_persent; double m_time; private: const static double DEFAULT_TIME_STEP; const static std::size_t DEFAULT_INCREASE_STEP; public: /*! @brief Constructor of HSyncNet (Hierarchical Sync Network) algorithm. @param[in] input_data: input data for cluster analysis. @param[in] cluster_number: amount of clusters that should be allocated. @param[in] initial_phases: initial phases for oscillators. */ hsyncnet(dataset * input_data, const std::size_t cluster_number, const initial_type initial_phases); /*! @brief Constructor of HSyncNet (Hierarchical Sync Network) algorithm. @param[in] input_data: input data for cluster analysis. @param[in] cluster_number: amount of clusters that should be allocated. @param[in] initial_phases: initial phases for oscillators. @param[in] initial_neighbors: defines initial connectivity-radius by average distance to connect specified amount of oscillators (points). @param[in] increase_persent: percent of increasing of connectivity-radius on each iteration (input values in range (0.0; 1.0) correspond to (0%; 100%)). */ hsyncnet(dataset * input_data, const std::size_t cluster_number, const initial_type initial_phases, const std::size_t initial_neighbors, const double increase_persent); /*! @brief Default destructor of HSyncNet (Hierarchical Sync Network) algorithm. */ virtual ~hsyncnet() = default; public: /*! @brief Performs cluster analysis by the network simulation. @param[in] order: order of synchronization that is used as indication for stopping processing, the `order` value should be in range `(0, 1)`. @param[in] solver: specified type of solving diff. equation. @param[in] collect_dynamic: specified requirement to collect whole dynamic of the network. @param[out] analyser: analyser of sync results of clustering. */ virtual void process(const double order, const solve_type solver, const bool collect_dynamic, hsyncnet_analyser & analyser) override; private: void store_state(sync_network_state & state, hsyncnet_analyser & analyser); double calculate_radius(const double radius, const std::size_t amount_neighbors) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmeans.hpp000077500000000000000000000115161375753423500254240ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class kmeans kmeans.hpp pyclustering/cluster/kmeans.hpp @brief Represents K-Means clustering algorithm for cluster analysis. @details The algorithm related to partitional class when input data is divided into groups. */ class kmeans { public: const static double DEFAULT_TOLERANCE; /**< Default value of the tolerance stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. */ const static std::size_t DEFAULT_ITERMAX; /**< Default value of the step stop condition - maximum number of iterations that is used for clustering process. */ private: double m_tolerance = DEFAULT_TOLERANCE; std::size_t m_itermax = DEFAULT_ITERMAX; dataset m_initial_centers = { }; kmeans_data * m_ptr_result = nullptr; /* temporary pointer to output result */ const dataset * m_ptr_data = nullptr; /* used only during processing */ const index_sequence * m_ptr_indexes = nullptr; /* temporary pointer to indexes */ distance_metric m_metric; public: /*! @brief Default constructor of clustering algorithm. */ kmeans() = default; /*! @brief Constructor of clustering algorithm where algorithm parameters for processing are specified. @param[in] p_initial_centers: initial centers that are used for processing. @param[in] p_tolerance: stop condition in following way: when maximum value of distance change of cluster centers is less than tolerance than algorithm will stop processing. @param[in] p_itermax: maximum number of iterations (by default kmeans::DEFAULT_ITERMAX). @param[in] p_metric: distance metric calculator for two points. */ kmeans(const dataset & p_initial_centers, const double p_tolerance = DEFAULT_TOLERANCE, const std::size_t p_itermax = DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()); /*! @brief Default destructor of the algorithm. */ ~kmeans() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[in,out] p_result: clustering result of an input data, it is also considered as an input argument to where observer parameter can be set to collect changes of clusters and centers on each step of processing. */ void process(const dataset & p_data, kmeans_data & p_result); /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[in] p_indexes: specify indexes of objects in 'p_data' that should be used during clustering process. @param[in,out] p_result: clustering result of an input data, it is also considered as an input argument to where observer parameter can be set to collect changes of clusters and centers on each step of processing. */ void process(const dataset & p_data, const index_sequence & p_indexes, kmeans_data & p_result); private: void update_clusters(const dataset & p_centers, cluster_sequence & p_clusters); double update_centers(const cluster_sequence & clusters, dataset & centers); void assign_point_to_cluster(const std::size_t p_index_point, const dataset & p_centers, index_sequence & p_clusters); /*! @brief Calculate new center for specified cluster. @param[in] p_cluster: cluster whose center should be calculated. @param[in,out] p_center: cluster's center that should calculated. @return Difference between old and new cluster's center. */ double update_center(const cluster & p_cluster, point & p_center); /*! @brief Calculates total within-cluster errors that is based on distance metric. */ void calculate_total_wce(); /*! @brief Erases clusters that do not have any points. @param[in,out] p_clusters: clusters that should be analyzed and modified. */ static void erase_empty_clusters(cluster_sequence & p_clusters); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmeans_data.hpp000077500000000000000000000071761375753423500264240ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace clst { /*! @class kmeans_data kmeans_data.hpp pyclustering/cluster/kmeans_data.hpp @brief Clustering results of K-Means algorithm that consists of information about allocated clusters and centers of each cluster. */ class kmeans_data : public cluster_data { private: dataset m_centers = { }; bool m_observed = false; double m_wce = 0.0; std::vector m_evolution_centers = { }; std::vector m_evolution_clusters = { }; public: /*! @brief Default constructor that creates empty clustering data. @details In case of default constructor clusters and centers are not stored on each clustering iteration. */ kmeans_data() = default; /*! @brief Constructor that provides flag to specify that clusters and centers changes are stored on each step. @param[in] p_iteration_observe: if 'true' then cluster and centers changes on each iteration are collected. */ explicit kmeans_data(const bool p_iteration_observe); /*! @brief Copy constructor that creates clustering data that is the same to specified. @param[in] p_other: another clustering data. */ kmeans_data(const kmeans_data & p_other) = default; /*! @brief Move constructor that creates clustering data from another by moving data. @param[in] p_other: another clustering data. */ kmeans_data(kmeans_data && p_other) = default; /*! @brief Default destructor that destroys clustering data. */ virtual ~kmeans_data() = default; public: /*! @brief Returns reference to centers that correspond to allocated clusters. */ dataset & centers() { return m_centers; } /*! @brief Returns constant reference to centers that correspond to allocated clusters. */ const dataset & centers() const { return m_centers; }; /*! @brief Returns 'true' if clusters and centers are collected during process of clustering. */ bool is_observed() const { return m_observed; } /*! @brief Returns total within-cluster errors. */ double & wce() { return m_wce; } /*! @brief Returns constant total within-cluster errors. */ const double & wce() const { return m_wce; } /*! @brief Returns reference to evolution of centers. @details The evolution does not contain initial centers. */ std::vector & evolution_centers() { return m_evolution_centers; } /*! @brief Returns constant reference to evolution of centers. @details The evolution does not contain initial centers. */ const std::vector & evolution_centers() const { return m_evolution_centers; } /*! @brief Returns reference to evolution of clusters. */ std::vector & evolution_clusters() { return m_evolution_clusters; } /*! @brief Returns constant reference to evolution of clusters. */ const std::vector & evolution_clusters() const { return m_evolution_clusters; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmeans_plus_plus.hpp000077500000000000000000000217001375753423500275260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /** * * @brief K-Means++ center initializer algorithm. * */ class kmeans_plus_plus : public center_initializer { public: /** * * @brief Denotes that the farthest center candidate (with highest probability) should be used as a center. * */ static const std::size_t FARTHEST_CENTER_CANDIDATE; /** * * @brief Non-existed index that represents non-initialized value. * */ static const std::size_t INVALID_INDEX; public: /** * * @brief Metric that is used for distance calculation between two points. * */ using metric = distance_functor< std::vector >; private: using index_set = std::unordered_set; using center_description = std::tuple; enum { POINT, INDEX }; using store_result = std::function; private: std::size_t m_amount = 0; std::size_t m_candidates = 0; metric m_dist_func; long long m_random_state = RANDOM_STATE_CURRENT_TIME; mutable std::mt19937 m_generator; /* temporal members that are used only during initialization */ mutable dataset const * m_data_ptr = nullptr; mutable index_sequence const * m_indexes_ptr = nullptr; mutable index_set m_free_indexes; mutable index_sequence m_allocated_indexes; public: /** * * @brief Default constructor to create initializer algorithm K-Means++. * */ kmeans_plus_plus() = default; /** * * @brief Constructor of center initializer algorithm K-Means++. * * @param[in] p_amount: amount of centers that should initialized. * @param[in] p_candidates: amount of candidates that are considered to find the best center, if * the farthest candidate is required (with highest probability) than static constant * FARTHEST_CENTER_CANDIDATE can be specified. * @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). * * @see FARTHEST_CENTER_CANDIDATE * */ kmeans_plus_plus(const std::size_t p_amount, const std::size_t p_candidates = 1, const long long p_random_state = RANDOM_STATE_CURRENT_TIME) noexcept; /** * * @brief Constructor of center initializer algorithm K-Means++. * @details By default algorithm uses square Euclidean distance as a metric. * * @param[in] p_amount: amount of centers that should initialized. * @param[in] p_candidates: amount of candidates that are considered to find the best center, if * the farthest candidate is required (with highest probability) than static constant * FARTHEST_CENTER_CANDIDATE can be specified. * @param[in] p_metric: metric for distance calculation between points. * @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). * * @see FARTHEST_CENTER_CANDIDATE * */ kmeans_plus_plus(const std::size_t p_amount, const std::size_t p_candidates, const metric & p_metric, const long long p_random_state = RANDOM_STATE_CURRENT_TIME) noexcept; /** * * @brief Default copy constructor to create initializer algorithm K-Means++. * */ kmeans_plus_plus(const kmeans_plus_plus & p_other) = default; /** * * @brief Default move constructor to create initializer algorithm K-Means++. * */ kmeans_plus_plus(kmeans_plus_plus && p_other) = default; /** * * @brief Default destructor to destroy initializer algorithm K-Means++. * */ ~kmeans_plus_plus() = default; public: /** * * @brief Performs center initialization process in line algorithm configuration. * * @param[in] p_data: data for that centers are calculated. * @param[out] p_centers: initialized centers for the specified data. * */ void initialize(const dataset & p_data, dataset & p_centers) const override; /** * * @brief Performs center initialization process in line algorithm configuration for * specific range of points. * * @param[in] p_data: data for that centers are calculated. * @param[in] p_indexes: point indexes from data that are defines which points should be considered * during calculation process. If empty then all data points are considered. * @param[out] p_centers: initialized centers for the specified data. * */ void initialize(const dataset & p_data, const index_sequence & p_indexes, dataset & p_centers) const override; /** * * @brief Performs center initialization process in line algorithm configuration using real points from dataset as centers. * * @param[in] p_data: data for that centers are calculated. * @param[out] p_center_indexes: initialized center indexes for the specified data where indexes correspond to points from the data. * */ void initialize(const dataset & p_data, index_sequence & p_center_indexes) const; private: /** * * @brief Assigns seed to the random generator that is used by the algorithm. * */ void initialize_random_generator(); /** * * @brief Performs center initialization process in line algorithm configuration. * * @param[in] p_data: data for that centers are calculated. * @param[in] p_indexes: point indexes from data that are defines which points should be considered * during calculation process. If empty then all data points are considered. * @param[out] p_proc: function that defines how to store output result of the algorithm. * */ void initialize(const dataset & p_data, const index_sequence & p_indexes, const store_result & p_proc) const; /** * * @brief Store obtained center. * * @param[in] p_proc: function that defines how to store output result of the algorithm. * @param[in] p_result: initialized center that should be stored. * */ void store_center(const store_result & p_proc, center_description & p_result) const; /** * * @brief Store pointers to data, indexes and centers to avoiding passing them between class methods. * @details Pointers are reseted when center initialization is over. * * @param[in] p_data: data for that centers are calculated. * @param[in] p_indexes: point indexes from data that are defines which points should be * considered during calculation process. * * @return The first initialized center. * */ void store_temporal_params(const dataset & p_data, const index_sequence & p_indexes) const; /** * * @brief Reset (fill by nullptr) temporal points. * */ void free_temporal_params() const; /** * * @brief Calculates the first initial center using uniform distribution. * * @return The first initialized center. * */ center_description get_first_center() const; /** * * @brief Calculates the next most probable center in line with weighted distribution. * * @return The next initialized center. * */ center_description get_next_center() const; /** * * @brief Calculates distances from each point to closest center. * * @param[out] p_distances: the shortest distances from each point to center. * */ void calculate_shortest_distances(std::vector & p_distances) const; /** * * @brief Calculates distance from the specified point to the closest center. * * @param[in] p_point: point for that the shortest distance is calculated. * */ double get_shortest_distance(const point & p_point) const; /** * * @brief Calculates center probability for each point using distances to closest centers. * * @param[in] p_distances: distances from each point to closest center. * @param[out] p_probabilities: probability of each point to be next center. * */ void calculate_probabilities(const std::vector & p_distances, std::vector & p_probabilities) const; /** * * @brief Calculates most probable center. * * @param[in] p_distances: distances from each point to closest center. * @param[in] p_probabilities: probability of each point to be next center. * */ std::size_t get_probable_center(const std::vector & p_distances, const std::vector & p_probabilities) const; }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmedians.hpp000077500000000000000000000111611375753423500257350ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /** * * @brief Represents K-Medians clustering algorithm for cluster analysis. * @details The algorithm related to partitional class when input data is divided into groups. * */ class kmedians { public: const static double DEFAULT_TOLERANCE; /**< Default value of the tolerance stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. */ const static std::size_t DEFAULT_ITERMAX; /**< Default value of the step stop condition - maximum number of iterations that is used for clustering process. */ private: const static double THRESHOLD_CHANGE; private: double m_tolerance = 0.0; std::size_t m_max_iter = 0; dataset m_initial_medians = { }; kmedians_data * m_ptr_result = nullptr; /* temporary pointer to output result */ const dataset * m_ptr_data = nullptr; /* used only during processing */ distance_metric m_metric; public: /** * * @brief Default constructor of clustering algorithm. * */ kmedians() = default; /** * * @brief Constructor of clustering algorithm where algorithm parameters for processing are * specified. * * @param[in] p_initial_medians: initial medians that are used for processing. * @param[in] p_tolerance: stop condition in following way: when maximum value of distance change of * medians of clusters is less than tolerance than algorithm will stop processing. * @param[in] p_max_iter: maximum amount of iteration for clustering. * @param[in] p_metric: distance metric for distance calculation between objects. * */ kmedians(const dataset & p_initial_medians, const double p_tolerance = DEFAULT_TOLERANCE, const std::size_t p_max_iter = DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()); /** * * @brief Default destructor of the algorithm. * */ ~kmedians() = default; public: /** * * @brief Performs cluster analysis of an input data. * * @param[in] p_data: input data for cluster analysis. * @param[out] p_output_result: clustering result of an input data. * */ void process(const dataset & p_data, kmedians_data & p_output_result); private: /** * * @brief Updates clusters in line with current medians. * * @param[in] p_medians: medians that are used for updating clusters. * @param[out] p_clusters: updated clusters in line with the specified medians. * */ void update_clusters(const dataset & p_medians, cluster_sequence & p_clusters); /** * * @brief Assign point to cluster by marking corresponding index in container 'p_lables'. * * @param[in] p_index_point: index of point that should be assigned to cluster. * @param[in] p_medians: medians that corresponds to clusters. * @param[out] p_lables: cluster labels for each point (cluster labels has the same size as an input data). * */ void assign_point_to_cluster(const std::size_t p_index_point, const dataset & p_medians, index_sequence & p_lables); /** * * @brief Updates medians in line with current clusters. * * @param[in,out] clusters: clusters that are sorted and used for updating medians. * @param[out] medians: updated medians in line with the specified clusters. * */ double update_medians(cluster_sequence & clusters, dataset & medians); /** * * @brief Calculate median for particular cluster. * * @param[in,out] current_cluster: cluster that is sorted and used for updating medians. * @param[out] median: calculate median for particular cluster. * */ void calculate_median(cluster & current_cluster, point & median); /** * * @brief Erases clusters that do not have any points. * * @param[in,out] p_clusters: clusters that should be analyzed and modified. * */ static void erase_empty_clusters(cluster_sequence & p_clusters); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmedians_data.hpp000077500000000000000000000031401375753423500267240ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace clst { /** * * @brief Clustering results of K-Medians algorithm that consists of information about allocated * clusters and medians of each cluster. * */ class kmedians_data : public cluster_data { private: dataset m_medians = { }; public: /** * * @brief Default constructor that creates empty clustering data. * */ kmedians_data() = default; /** * * @brief Copy constructor that creates clustering data that is the same to specified. * * @param[in] p_other: another clustering data. * */ kmedians_data(const kmedians_data & p_other) = default; /** * * @brief Move constructor that creates clustering data from another by moving data. * * @param[in] p_other: another clustering data. * */ kmedians_data(kmedians_data && p_other) = default; /** * * @brief Default destructor that destroys clustering data. * */ virtual ~kmedians_data() = default; public: /** * * @brief Returns reference to medians that correspond to allocated clusters. * */ dataset & medians() { return m_medians; } /** * * @brief Returns constant reference to medians that correspond to allocated clusters. * */ const dataset & medians() const { return m_medians; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmedoids.hpp000077500000000000000000000152361375753423500257500ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @brief Defines data representation (point, distance matrix) that is used for processing by K-Medoids algorithm. */ enum class kmedoids_data_t { POINTS, DISTANCE_MATRIX }; /*! @brief Represents K-Medoids clustering algorithm (PAM algorithm) for cluster analysis. @details PAM is a partitioning clustering algorithm that uses the medoids instead of centers like in case of K-Means algorithm. Medoid is an object with the smallest dissimilarity to all others in the cluster. PAM algorithm complexity is \f$O\left ( k\left ( n-k \right )^{2} \right )\f$. Implementation based on paper @cite inproceedings::cluster::kmedoids::1. */ class kmedoids { public: static const double DEFAULT_TOLERANCE; /**< Default value of the tolerance stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. */ static const std::size_t DEFAULT_ITERMAX; /**< Default value of the step stop condition - maximum number of iterations that is used for clustering process. */ private: static const std::size_t OBJECT_ALREADY_CONTAINED; static const std::size_t INVALID_INDEX; static const double NOTHING_TO_SWAP; private: using distance_calculator = std::function; struct appropriate_cluster { public: appropriate_cluster() = default; appropriate_cluster(const std::size_t p_index, const double p_distance_first_medoid, const double p_distance_second_medoid); public: std::size_t m_index = INVALID_INDEX; double m_distance_to_first_medoid = -1.0; double m_distance_to_second_medoid = -1.0; }; private: const dataset * m_data_ptr = nullptr; /* temporary pointer to input data that is used only during processing */ kmedoids_data * m_result_ptr = nullptr; /* temporary pointer to clustering result that is used only during processing */ medoid_sequence m_initial_medoids = { }; double m_tolerance = DEFAULT_TOLERANCE; std::size_t m_itermax = DEFAULT_ITERMAX; index_sequence m_labels; std::vector m_distance_first_medoid; std::vector m_distance_second_medoid; distance_metric m_metric; distance_calculator m_calculator; public: /*! @brief Default constructor of clustering algorithm. */ kmedoids() = default; /*! @brief Constructor of clustering algorithm where algorithm parameters for processing are specified. @param[in] p_initial_medoids: initial medoids that are used for processing. @param[in] p_tolerance: stop condition in following way: when maximum value of distance change of medoids of clusters is less than tolerance than algorithm will stop processing. @param[in] p_itermax: maximum amount of iterations (by default kmedoids::DEFAULT_ITERMAX). @param[in] p_metric: distance metric calculator for two points. */ kmedoids(const medoid_sequence & p_initial_medoids, const double p_tolerance = DEFAULT_TOLERANCE, const std::size_t p_itermax = DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()); /*! @brief Default destructor of the algorithm. */ ~kmedoids(); public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, kmedoids_data & p_result); /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[in] p_type: data type (points or distance matrix). @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, const kmedoids_data_t p_type, kmedoids_data & p_result); private: /*! @brief Updates clusters in line with current medoids. */ double update_clusters(); /*! @brief Creates distance calcultor in line with data type and distance metric metric. @param[in] p_type: data type (points or distance matrix). @return Distance calculator. */ distance_calculator create_distance_calculator(const kmedoids_data_t p_type); /*! @brief Find appropriate cluster for the particular point. @param[in] p_index: Index of point that should be placed to cluster. @param[in] p_medoids: Medoids that corresponds to clusters. @return Index of cluster that is appropriate for the particular point and distance from this point to correspoding medoid. If point is a medoid then OBJECT_ALREADY_CONTAINED value is returned. */ appropriate_cluster find_appropriate_cluster(const std::size_t p_index, medoid_sequence & p_medoids); /*! @brief Swap existed medoid with non-medoid points in order to find the most optimal medoid. @return Cost that is needed to swap medoid and non-medoid point. */ double swap_medoids(); /*! @brief Calculates cost to swap `p_index_candidate` with the current medoid `p_index_cluster`. @param[in] p_index_candidate: index point that is considered as a medoid candidate. @param[in] p_index_cluster: index of a cluster where the current medoid is used for calculation. @return Cost that is needed to swap medoids. */ double calculate_swap_cost(const std::size_t p_index_candidate, const std::size_t p_index_cluster) const; /*! @brief Erase empty clusters and their medoids. @details Data might have identical points and a lot of identical points and as a result medoids might correspond to points that are totally identical. */ void erase_empty_clusters(); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/kmedoids_data.hpp000077500000000000000000000033671375753423500267430ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { using medoid_sequence = std::vector; using medoid_sequence_ptr = std::shared_ptr; /** * * @brief Clustering results of K-Medoids algorithm that consists of information about allocated * clusters and medoids that correspond to them. * */ class kmedoids_data : public cluster_data { private: medoid_sequence m_medoids = { }; public: /** * * @brief Default constructor that creates empty clustering data. * */ kmedoids_data() = default; /** * * @brief Copy constructor that creates clustering data that is the same to specified. * * @param[in] p_other: another clustering data. * */ kmedoids_data(const kmedoids_data & p_other) = default; /** * * @brief Move constructor that creates clustering data from another by moving data. * * @param[in] p_other: another clustering data. * */ kmedoids_data(kmedoids_data && p_other) = default; /** * * @brief Default destructor that destroys clustering data. * */ virtual ~kmedoids_data() = default; public: /** * * @brief Returns medoids that corresponds to allocated clusters. * */ medoid_sequence & medoids() { return m_medoids; } /** * * @brief Returns medoids that corresponds to allocated clusters. * */ const medoid_sequence & medoids() const { return m_medoids; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/mbsas.hpp000077500000000000000000000033441375753423500252530ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class mbsas mbsas.hpp pyclustering/cluster/mbsas.hpp @brief Class represents MBSAS (Modified Basic Sequential Algorithmic Scheme). @details Interface of MBSAS algorithm is the same as for BSAS. This algorithm performs clustering in two steps. The first - is determination of amount of clusters. The second - is assignment of points that were not marked as a cluster representatives to clusters. */ class mbsas : public bsas { public: /*! @brief Default constructor of the clustering algorithm. */ mbsas() = default; /*! @brief Creates MBSAS algorithm using specified parameters. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_threshold: threshold of dissimilarity (maximum distance) between points. @param[in] p_metric: metric for distance calculation between points. */ mbsas(const std::size_t p_amount, const double p_threshold, const distance_metric & p_metric = distance_metric_factory::euclidean()); public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, mbsas_data & p_result); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/mbsas_data.hpp000077500000000000000000000004631375753423500262430ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { using mbsas_data = bsas_data; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/optics.hpp000077500000000000000000000141211375753423500254420ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include namespace pyclustering { namespace clst { /*! @brief Enumeration of input data type that are processed by OPTICS algorithm. */ enum class optics_data_t { POINTS, /**< Data is represented by a container of points. */ DISTANCE_MATRIX /**< Data is represented by a distance matrix between points. */ }; /*! @brief Class represents clustering algorithm OPTICS (Ordering Points To Identify Clustering Structure). @details OPTICS is a density-based algorithm. Purpose of the algorithm is to provide explicit clusters, but create clustering-ordering representation of the input data. Clustering-ordering information contains information about internal structures of data set in terms of density and proper connectivity radius can be obtained for allocation required amount of clusters using this diagram. In case of usage additional input parameter 'amount of clusters' connectivity radius should be bigger than real - because it will be calculated by the algorithms. Implementation based on paper @cite article::optics::1. */ class optics { public: static const double NONE_DISTANCE; /**< Defines no distance value. */ static const std::size_t INVALID_INDEX; /**< Defines incorrect index. */ private: struct neighbor_descriptor { public: std::size_t m_index = INVALID_INDEX; double m_reachability_distance = 0; public: neighbor_descriptor(const std::size_t p_index, const double p_distance) : m_index(p_index), m_reachability_distance(p_distance) { } }; struct neighbor_descriptor_less { public: bool operator()(const neighbor_descriptor & p_object1, const neighbor_descriptor & p_object2) const { return p_object1.m_reachability_distance < p_object2.m_reachability_distance; } }; using neighbors_collection = std::multiset; private: const dataset * m_data_ptr = nullptr; optics_data * m_result_ptr = nullptr; double m_radius = 0.0; std::size_t m_neighbors = 0; std::size_t m_amount_clusters = 0; optics_data_t m_type = optics_data_t::POINTS; container::kdtree_balanced m_kdtree = container::kdtree_balanced(); optics_object_sequence * m_optics_objects = nullptr; std::list m_ordered_database = { }; public: /*! @brief Default constructor of the algorithm. */ optics() = default; /*! @brief Default copy constructor of the algorithm. */ optics(const optics & p_other) = default; /*! @brief Default move constructor of the algorithm. */ optics(optics && p_other) = default; /*! @brief Parameterized constructor of the algorithm. @param[in] p_radius: connectivity radius between objects. @param[in] p_neighbors: minimum amount of shared neighbors that is require to connect two object (if distance between them is less than connectivity radius). */ optics(const double p_radius, const std::size_t p_neighbors); /*! @brief Creates algorithm with specified parameters. @param[in] p_radius: connectivity radius between objects. @param[in] p_neighbors: minimum amount of shared neighbors that is require to connect two object (if distance between them is less than connectivity radius). @param[in] p_amount_clusters: amount of clusters that should be allocated (in this case connectivity radius may be changed by the algorithm. */ optics(const double p_radius, const std::size_t p_neighbors, const std::size_t p_amount_clusters); /*! @brief Default destructor to destroy algorithm instance. */ ~optics() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data (consists of allocated clusters, cluster-ordering, noise and proper connectivity radius). */ void process(const dataset & p_data, optics_data & p_result); /*! @brief Performs cluster analysis of specific input data (points or distance matrix) that is defined by the `p_type` argument. @param[in] p_data: input data for cluster analysis. @param[in] p_type: type of input data (points or distance matrix). @param[out] p_result: clustering result of an input data (consists of allocated clusters, cluster-ordering, noise and proper connectivity radius). */ void process(const dataset & p_data, const optics_data_t p_type, optics_data & p_result); private: void initialize(); void allocate_clusters(); void expand_cluster_order(optics_descriptor & p_object); void extract_clusters(); void get_neighbors(const std::size_t p_index, neighbors_collection & p_neighbors); void get_neighbors_from_points(const std::size_t p_index, neighbors_collection & p_neighbors); void get_neighbors_from_distance_matrix(const std::size_t p_index, neighbors_collection & p_neighbors); double get_core_distance(const neighbors_collection & p_neighbors) const; void update_order_seed(const optics_descriptor & p_object, const neighbors_collection & p_neighbors, std::multiset & order_seed); void calculate_ordering(); void calculate_cluster_result(); void create_kdtree(); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/optics_data.hpp000077500000000000000000000070031375753423500264340ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace clst { /*! @brief Sequence container where ordering diagram is stored. */ using ordering = std::vector; /*! @brief Sequence container where OPTICS descriptors are stored. */ using optics_object_sequence = std::vector; /*! @class optics_data optics_data.hpp pyclustering/cluster/optics_data.hpp @brief Clustering results of OPTICS algorithm that consists of information about allocated clusters and noise (points that are not related to any cluster), ordering (that represents density-based clustering structure) and proper radius. */ class optics_data : public dbscan_data { private: ordering m_ordering = { }; double m_radius = 0; optics_object_sequence m_optics_objects = { }; public: /*! @brief Default constructor that creates empty clustering data. */ optics_data() = default; /*! @brief Default copy constructor. @param[in] p_other: another clustering data. */ optics_data(const optics_data & p_other) = default; /*! @brief Default move constructor. @param[in] p_other: another clustering data. */ optics_data(optics_data && p_other) = default; /*! @brief Default destructor that destroys clustering data. */ virtual ~optics_data() = default; public: /*! @brief Returns reference to cluster-ordering that represents density-based clustering structure. @return Reference to cluster-ordering that represents density-based clustering structure. */ ordering & cluster_ordering() { return m_ordering; } /*! @brief Returns const reference to cluster-ordering that represents density-based clustering structure. @return Const reference to cluster-ordering that represents density-based clustering structure. */ const ordering & cluster_ordering() const { return m_ordering; } /*! @brief Returns reference to optics objects that corresponds to points from input dataspace. @return Reference to optics objects that corresponds to points from input dataspace. */ optics_object_sequence & optics_objects() { return m_optics_objects; } /*! @brief Returns const reference to optics objects that corresponds to points from input dataspace. @return Const reference to optics objects that corresponds to points from input dataspace. */ const optics_object_sequence & optics_objects() const { return m_optics_objects; } /*! @brief Returns connectivity radius that can be differ from input parameter. @details It may be changed by OPTICS ('optics') algorithm if there is requirement to allocate specified amount of clusters. @return Connectivity radius. */ double get_radius() const { return m_radius; } /*! @brief Set new value for connectivity radius. @param[in] p_radius: new value of the connectivity radius. */ void set_radius(const double p_radius) { m_radius = p_radius; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/optics_descriptor.hpp000077500000000000000000000057561375753423500277160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { /*! @class optics_descriptor optics_descriptor.hpp pyclustering/cluster/optics_descriptor.hpp @brief Object description that used by OPTICS algorithm for cluster analysis. */ struct optics_descriptor { public: static const double NONE_DISTANCE; /**< Denotes if a distance value is not defined. */ public: std::size_t m_index = -1; /**< Index of the object in the data set. */ double m_core_distance = 0; /**< Core distance that is minimum distance to specified number of neighbors. */ double m_reachability_distance = 0; /**< Reachability distance to this object. */ bool m_processed = false; /**< Defines the object is processed -`true` if is current object has been already processed. */ public: /** * * @brief Default constructor to create optics object descriptor. * */ optics_descriptor() = default; /** * * @brief Default copy constructor to create optics object descriptor. * */ optics_descriptor(const optics_descriptor & p_other) = default; /** * * @brief Default move constructor to create optics object descriptor. * */ optics_descriptor(optics_descriptor && p_other) = default; /** * * @brief Creates optics object descriptor using specified parameters. * @details Processing is always false after creating for any created optics descriptor. * * @param[in] p_index: index of optics object that corresponds to index of real object in dataset. * @param[in] p_core_distance: core distance of optics-object. * @param[in] p_reachability_distance: reachability distance of optics-object. * */ optics_descriptor(const std::size_t p_index, const double p_core_distance, const double p_reachability_distance); /** * * @brief Default destructor to destroy optics object descriptor. * */ ~optics_descriptor() = default; public: /** * * @brief Clears core and reachability distances and processing flag (at the same time index is not reseted). * */ void clear(); }; /** * * @brief Less comparator for object description that used by OPTICS algorithm for cluster analysis. * */ struct optics_pointer_descriptor_less { /** * * @brief Compare two OPTICS object using following rule: p_object1 < p_object2. * * @param[in] p_object1: the left operand to compare. * @param[in] p_object2: the right operand to compare. * * @return `true` if left operand is less than right operand. * */ bool operator()(const optics_descriptor * p_object1, const optics_descriptor * p_object2) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/ordering_analyser.hpp000077500000000000000000000044061375753423500276550ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { /** * * @brief Analyzer of cluster ordering data. * */ class ordering_analyser { public: /** * * @brief Default constructor of the analyser. * */ ordering_analyser() = default; /** * * @brief Default copy constructor of the analyser. * */ ordering_analyser(const ordering_analyser & p_other) = default; /** * * @brief Default move constructor of the analyser. * */ ordering_analyser(ordering_analyser && p_other) = default; /** * * @brief Default destructor. * */ ~ordering_analyser() = default; public: /** * * @brief Calculates connectivity radius of allocation specified amount of clusters using ordering diagram. * * @param[in] p_ordering: clustering ordering that is used for analysis. * @param[in] p_amount_clusters: amount of clusters that should be allocated by calculated connectivity radius. * @param[in] p_maximum_iterations: maximum number of iteration for searching connectivity radius to allocated * specified amount of clusters (by default it is restricted by 100 iterations). * * @return Value of connectivity radius, it may return value < 0 if connectivity radius hasn't been found for the specified amount of iterations. * */ static double calculate_connvectivity_radius(const ordering & p_ordering, const std::size_t p_amount_clusters, const std::size_t p_maximum_iterations = 100); /** * * @brief Obtains amount of clustering that can be allocated by using specified radius for ordering diagram * * @param[in] p_ordering: clustering ordering that is used for analysis. * @param[in] p_radius: connectivity radius that is used for cluster allocation. * * @return Amount of clusters that can be allocated by the connectivity radius on ordering diagram. * */ static std::size_t extract_cluster_amount(const ordering & p_ordering, const double p_radius); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/random_center_initializer.hpp000077500000000000000000000071171375753423500313730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class random_center_initializer random_center_initializer.hpp pyclustering/cluster/random_center_initializer.hpp @brief Random center initializer is for generation specified amount of random of centers for specified data. */ class random_center_initializer : public center_initializer { private: /** * * @brief Storage where indexes are stored. * */ using index_storage = std::unordered_set; private: std::size_t m_amount = 0; long long m_random_state = RANDOM_STATE_CURRENT_TIME; mutable std::mt19937 m_generator; mutable index_storage m_available_indexes = { }; public: /** * * @brief Default constructor to create random center initializer. * */ random_center_initializer() = default; /** * * @brief Constructor of center initializer algorithm K-Means++. * * @param[in] p_amount: amount of centers that should initialized. * @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). * */ explicit random_center_initializer(const std::size_t p_amount, const long long p_random_state); /** * * @brief Default copy constructor to create random center initializer. * */ random_center_initializer(const random_center_initializer & p_other) = default; /** * * @brief Default move constructor to create random center initializer. * */ random_center_initializer(random_center_initializer && p_other) = default; /** * * @brief Default destructor to destroy random center initializer. * */ ~random_center_initializer() = default; public: /** * * @brief Performs center initialization process in line algorithm configuration. * * @param[in] p_data: data for that centers are calculated. * @param[out] p_centers: initialized centers for the specified data. * */ void initialize(const dataset & p_data, dataset & p_centers) const override; /** * * @brief Performs center initialization process in line algorithm configuration for * specific range of points. * * @param[in] p_data: data for that centers are calculated. * @param[in] p_indexes: point indexes from data that are defines which points should be considered * during calculation process. If empty then all data points are considered. * @param[out] p_centers: initialized centers for the specified data. * */ void initialize(const dataset & p_data, const index_sequence & p_indexes, dataset & p_centers) const override; private: /** * * @brief Creates random center and place it to specified storage. * * @param[in] p_data: data for that centers are calculated. * @param[out] p_centers: storage where new center should be placed. * */ void create_center(const dataset & p_data, dataset & p_centers) const; /** * * @brief Assigns seed to the random generator that is used by the algorithm. * */ void initialize_random_generator(); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/rock.hpp000077500000000000000000000070531375753423500251050ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include using namespace pyclustering::container; namespace pyclustering { namespace clst { using rock_data = cluster_data; /*! @class rock rock.hpp pyclustering/cluster/rock.hpp @brief The class represents a clustering algorithm ROCK. @details Implementation of the algorithm is based on the paper @cite inproceedings::rock::1. */ class rock { private: /* for optimization list representation is of clusters is used and than * it is moved to output result */ using rock_cluster_sequence = std::list; private: adjacency_matrix m_adjacency_matrix; double m_radius; double m_degree_normalization; size_t m_number_clusters; rock_cluster_sequence m_clusters; public: /** * * @brief Default constructor of clustering algorithm. * */ rock(); /** * * @brief Creates ROCK solver in line with specified parameters of the algorithm. * * @param[in] radius: connectivity radius (similarity threshold), points are neighbors if distance between them is less than connectivity radius. * @param[in] number_clusters: amount of clusters that should be allocated. * @param[in] threshold: defines degree of normalization that influences on choice of clusters for merging during processing. * */ rock(const double radius, const std::size_t number_clusters, const double threshold); /** * * @brief Default destructor of the algorithm. * */ ~rock() = default; public: /** * * @brief Performs cluster analysis of an input data. * * @param[in] p_data: input data for cluster analysis. * @param[out] p_result: clustering result of an input data. * */ void process(const dataset & p_data, rock_data & p_result); private: /** * * @brief Creates adjacency matrix where each element described existence of link between points (means that points are neighbors). * * @param[in] p_data: input data for cluster analysis. * */ void create_adjacency_matrix(const dataset & p_data); /** * * @brief Finds two clusters that are most suitable candidates for merging and than merges them. * */ bool merge_cluster(); /** * * @brief Returns number of link between two clusters. * @details Link between objects (points) exists only if distance between them less than connectivity radius. * * @param[in] cluster1: the first cluster. * @param[in] cluster2: the second cluster. * * @return Number of links between two clusters. * */ size_t calculate_links(const cluster & cluster1, const cluster & cluster2) const; /** * * @brief Calculates coefficient 'goodness measurement' between two clusters. * @details The coefficient defines level of suitability of clusters for merging. * * @param[in] cluster1: the first cluster. * @param[in] cluster2: the second cluster. * * @return Goodness measure between two clusters. * */ double calculate_goodness(const cluster & cluster1, const cluster & cluster2) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/silhouette.hpp000077500000000000000000000152371375753423500263370ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @brief Defines types that are used for input data representation. */ enum class silhouette_data_t { POINTS, DISTANCE_MATRIX }; /*! @class silhouette silhouette.hpp pyclustering/cluster/silhouette.hpp @brief Represents Silhouette method that is used interpretation and validation of consistency. @details The silhouette value is a measure of how similar an object is to its own cluster compared to other clusters. Be aware that silhouette method is applicable for K algorithm family, such as K-Means, K-Medians, K-Medoids, X-Means, etc., not not applicable for DBSCAN, OPTICS, CURE, etc. The Silhouette value is calculated using following formula: \f[s\left ( i \right )=\frac{ b\left ( i \right ) - a\left ( i \right ) }{ max\left \{ a\left ( i \right ), b\left ( i \right ) \right \}}\f] where \f$a\left ( i \right )\f$ - is average distance from object i to objects in its own cluster, \f$b\left ( i \right )\f$ - is average distance from object i to objects in the nearest cluster (the appropriate among other clusters). Here is an example where Silhouette score is calculated for K-Means's clustering result: @code #include #include #include #include // ... `read_data` implementation to read sample ... int main() { // Read two-dimensional input data 'Simple03'. dataset data = read_data("Simple03.txt"); // Prepare initial centers for K-Means algorithm. dataset initial_centers; const std::size_t amount_clusters = 4; const std::size_t candidates_to_consider = 5; kmeans_plus_plus(amount_clusters, candidates_to_consider).initialize(data, initial_centers); // Perform cluster analysis. auto kmeans_instance = kmeans(initial_centers); kmeans_data clustering_result; kmeans_instance.process(data, clustering_result); // Obtain allocated clusters. const auto & clusters = clustering_result.clusters(); // Calculate Silhouette score. silhouette_data estimation_result; silhouette().process(data, clusters, estimation_result); // Print Silhouette score for each point. for (const auto score : estimation_result.get_score()) { std::cout << score << std::endl; } return 0; } @endcode Here is an illustration where clustering has been performed using various `K` values (2, 4, 6 and 8) for the same sample as before. `K = 4` is the optimal amount of clusters in line with Silhouette method because the score for each point is close to `1.0` and the average score for `K = 4` is biggest value among others `K`. @image html silhouette_score_for_various_K.png "Fig. 1. Silhouette scores for various K." Implementation based on paper @cite article::cluster::silhouette::1. @see kmeans, kmedoids, kmedians, xmeans, elbow */ class silhouette { private: const dataset * m_data = nullptr; /* temporary object, exists during processing */ const cluster_sequence * m_clusters = nullptr; /* temporary object, exists during processing */ silhouette_data * m_result = nullptr; /* temporary object, exists during processing */ silhouette_data_t m_type = silhouette_data_t::POINTS; distance_metric m_metric = distance_metric_factory::euclidean_square(); public: /*! @brief Default constructor for Silhouette method. */ silhouette() = default; /*! @brief Constructor for Silhouette method with specific parameters. @param[in] p_metric: metric that was used for cluster analysis and should be used for Silhouette score calculation (by default Square Euclidean distance). */ explicit silhouette(const distance_metric & p_metric); /*! @brief Default copy constructor for Silhouette method. */ silhouette(const silhouette & p_other) = default; /*! @brief Default move constructor for Silhouette method. */ silhouette(silhouette && p_other) = default; /*! @brief Default destructor for Silhouette method. */ ~silhouette() = default; public: /*! @brief Performs analysis of an input data in order to calculate score for each point where input data is represented by points. @param[in] p_data: input data (points) for analysis. @param[in] p_clusters: clusters that have been obtained after cluster analysis. @param[out] p_result: silhouette input data processing result. */ void process(const dataset & p_data, const cluster_sequence & p_clusters, silhouette_data & p_result); /*! @brief Performs analysis of an input data in order to calculate score for each point. @param[in] p_data: input data for analysis. @param[in] p_clusters: clusters that have been obtained after cluster analysis. @param[in] p_type: data type of input sample `p_data` that is processed by the method (`POINTS`, `DISTANCE_MATRIX`). @param[out] p_result: silhouette input data processing result. */ void process(const dataset & p_data, const cluster_sequence & p_clusters, const silhouette_data_t & p_type, silhouette_data & p_result); private: double calculate_score(const std::size_t p_index_point, const std::size_t p_index_cluster) const; void calculate_dataset_difference(const std::size_t p_index_point, std::vector & p_dataset_difference) const; double calculate_cluster_difference(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const; double calculate_within_cluster_score(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const; double calculate_cluster_score(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const; double caclulate_optimal_neighbor_cluster_score(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/silhouette_data.hpp000077500000000000000000000017561375753423500273310ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { /*! @brief Sequence container that contains Silhouette's score for each point. */ using silhouette_sequence = std::vector; /*! @class silhouette_data silhouette_data.hpp pyclustering/cluster/silhouette_data.hpp @brief Silhouette analysis result that contain information about Silhouette score for each point. */ class silhouette_data { private: silhouette_sequence m_scores; public: /*! @brief Returns constant reference to the container with Silhouette score for each point */ const silhouette_sequence & get_score() const { return m_scores; } /*! @brief Returns reference to the container with Silhouette score for each point */ silhouette_sequence & get_score() { return m_scores; } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/silhouette_ksearch.hpp000077500000000000000000000176241375753423500300410ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace clst { /*! @class silhouette_ksearch_allocator silhouette_ksearch.hpp pyclustering/cluster/silhouette_ksearch.hpp @brief Interface of silhouette's K-search allocator that is used by the algorithm to define strategy that defines how to perform cluster analysis. @see kmeans_allocator @see kmedians_allocator @see kmedoids_allocator */ class silhouette_ksearch_allocator { public: /*! @brief Defines shared pointer to the interface 'silhouette_ksearch_allocator'. */ using ptr = std::shared_ptr; public: /*! @brief Default destructor of the algorithm. */ virtual ~silhouette_ksearch_allocator() = default; public: /*! @brief Performs cluster analysis in order to allocate specified amount of cluster from an input data. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) = 0; /*! @brief Performs cluster analysis in order to allocate specified amount of cluster from an input data. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[in] p_random_state: seed for random state (value `RANDOM_STATE_CURRENT_TIME` means the current system time is going to used as a seed). @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) = 0; }; /*! @class kmeans_allocator silhouette_ksearch.hpp pyclustering/cluster/silhouette_ksearch.hpp @brief Silhouette K-search allocator based on K-Means algorithm. */ class kmeans_allocator : public silhouette_ksearch_allocator { public: /*! @brief Performs cluster analysis using K-Means algorithm. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) override; /*! @brief Performs cluster analysis using K-Means algorithm. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[in] p_random_state: seed for random state (value `RANDOM_STATE_CURRENT_TIME` means the current system time is going to used as a seed). @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) override; }; /*! @class kmedians_allocator silhouette_ksearch.hpp pyclustering/cluster/silhouette_ksearch.hpp @brief Silhouette K-search allocator based on K-Medians algorithm. */ class kmedians_allocator : public silhouette_ksearch_allocator { public: /*! @brief Performs cluster analysis using K-Medians algorithm. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) override; /*! @brief Performs cluster analysis using K-Medians algorithm. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[in] p_random_state: seed for random state (value `RANDOM_STATE_CURRENT_TIME` means the current system time is going to used as a seed). @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) override; }; /*! @class kmedoids_allocator silhouette_ksearch.hpp pyclustering/cluster/silhouette_ksearch.hpp @brief Silhouette K-search allocator based on K-Medoids algorithm. */ class kmedoids_allocator : public silhouette_ksearch_allocator { public: /*! @brief Performs cluster analysis using K-Medoids algorithm. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) override; /*! @brief Performs cluster analysis using K-Medoids algorithm. @param[in] p_amount: amount of clusters that should be allocated. @param[in] p_data: input data for cluster analysis. @param[in] p_random_state: seed for random state (value `RANDOM_STATE_CURRENT_TIME` means the current system time is going to used as a seed). @param[out] p_clusters: container where result (allocated clusters) is placed. */ virtual void allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) override; }; /*! @class silhouette_ksearch silhouette_ksearch.hpp pyclustering/cluster/silhouette_ksearch.hpp @brief Defines algorithms that is used to find optimal number of cluster using Silhouette method. */ class silhouette_ksearch { private: std::size_t m_kmin; std::size_t m_kmax; silhouette_ksearch_allocator::ptr m_allocator = std::make_shared(); long long m_random_state; public: /*! @brief Default constructor of Silhouette search algorithm. */ silhouette_ksearch() = default; /*! @brief Constructor of Silhouette search algorithm. @param[in] p_kmin: minimum amount of clusters that might be allocated. @param[in] p_kmax: maximum amount of clusters that might be allocated. @param[in] p_allocator: strategy that is used to allocate clusters or in other words, to perform cluster analysis. @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). */ silhouette_ksearch(const std::size_t p_kmin, const std::size_t p_kmax, const silhouette_ksearch_allocator::ptr & p_allocator = std::make_shared(), const long long p_random_state = RANDOM_STATE_CURRENT_TIME); /*! @brief Default copy constructor of Silhouette search algorithm. */ silhouette_ksearch(const silhouette_ksearch & p_other) = default; /*! @brief Default move constructor of Silhouette search algorithm. */ silhouette_ksearch(silhouette_ksearch && p_other) = default; /*! @brief Default destructor of Silhouette search algorithm. */ ~silhouette_ksearch() = default; public: /*! @brief Performs analysis to find optimal amount of clusters. @param[in] p_data: input data that is used for searching optimal amount of clusters. @param[in] p_result: analysis result of an input data. */ void process(const dataset & p_data, silhouette_ksearch_data & p_result); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/silhouette_ksearch_data.hpp000077500000000000000000000045331375753423500310250ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { using silhouette_score_sequence = std::vector; /*! @class silhouette_ksearch_data silhouette_ksearch_data.hpp pyclustering/cluster/silhouette_ksearch_data.hpp @brief Defines result of silhouette K-search algorithm. */ class silhouette_ksearch_data { private: std::size_t m_amount = 0; double m_score = 0; silhouette_score_sequence m_scores = { }; public: /*! @brief Return optimal amount of clusters. @return Optimal amount of clusters. */ const std::size_t get_amount() const; /*! @brief Set optimal amount of clusters (this method is used by Silhouette K-search algorithm). @param[in] p_amount: optimal amount of clusters. */ void set_amount(const std::size_t p_amount); /*! @brief Returns optimal amount of clusters that has been found during the analysis. @return Optimal amount of clusters that has been found during the analysis. */ const double get_score() const; /*! @brief Set optimal amount of clusters that has been found during the analysis (this method is used by Silhouette K-search algorithm). @param[in] p_score: optimal amount of clusters that has been found during the analysis. */ void set_score(const double p_score); /*! @brief Returns constant reference to silhouette score for each K value (amount of clusters). @return Constant reference to silhouette score for each K value (amount of clusters). */ const silhouette_score_sequence & scores() const; /*! @brief Returns reference to silhouette score for each K value (amount of clusters). @return Reference to silhouette score for each K value (amount of clusters). */ silhouette_score_sequence & scores(); public: /*! @brief Compares Silhouette K-search results. @param[in] p_other: another Silhouette K-search result that is used for comparison. @return Returns true if both objects are the same. */ bool operator==(const silhouette_ksearch_data & p_other) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/somsc.hpp000077500000000000000000000040541375753423500252710ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace clst { /*! @class somsc somsc.hpp pyclustering/cluster/somsc.hpp @brief The class represents a simple clustering algorithm based on the self-organized feature map. @details This algorithm uses amount of clusters that should be allocated as a size of SOM map. Captured objects by neurons are considered as clusters. The algorithm is designed to process data with Gaussian distribution that has spherical forms. */ class somsc { private: std::size_t m_amount_clusters = 0; std::size_t m_epoch = 0; public: /** * * @brief Default constructor to create algorithm instance. * */ somsc() = default; /** * * @brief Default copy constructor to create algorithm instance. * */ somsc(const somsc & p_other) = default; /** * * @brief Default move constructor to create algorithm instance. * */ somsc(somsc && p_other) = default; /** * * @brief Creates algorithm with specified parameters. * * @param[in] p_amount_clusters: amount of clusters that should be allocated. * @param[in] p_epoch: maximum iterations for SOM learning process. * */ somsc(const std::size_t p_amount_clusters, const std::size_t p_epoch = 100); /** * * @brief Default destructor to destroy algorithm instance. * */ ~somsc() = default; public: /** * * @brief Performs cluster analysis of an input data. * * @param[in] p_data: input data for cluster analysis. * @param[out] p_result: clustering result of an input data (consists of allocated clusters). * */ void process(const dataset & p_data, somsc_data & p_result); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/somsc_data.hpp000077500000000000000000000004231375753423500262560ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace clst { using somsc_data = cluster_data; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/syncnet.hpp000077500000000000000000000116431375753423500256320ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include using namespace pyclustering::nnet; namespace pyclustering { namespace clst { using syncnet_cluster = std::vector; using syncnet_cluster_data = ensemble_data; /*! @class syncnet_analyser syncnet.hpp pyclustering/cluster/syncnet.hpp @brief Analyser for syncnet - oscillatory neural network based on Kuramoto model for cluster analysis. @see syncnet */ class syncnet_analyser: public sync_dynamic { public: /*! @brief Default constructor of the output dynamic of Sync network. */ syncnet_analyser() = default; /*! @brief Default destructor of the output dynamic of Sync network. */ virtual ~syncnet_analyser() = default; public: /*! @brief Performs analysis of the output dynamic in order to obtain clusters. @details Allocated clusters are placed to output argument `data`. @param[in] eps: tolerance that defines the maximum difference between phases of oscillators that belong to one cluster. @param[out] data: allocated clusters during the analysis of the output dynamic. */ void allocate_clusters(const double eps, syncnet_cluster_data & data); }; /*! @class syncnet syncnet.hpp pyclustering/cluster/syncnet.hpp @brief Oscillatory neural network based on Kuramoto model for cluster analysis. @see syncnet_analyser */ class syncnet: public sync_network { protected: std::vector > * oscillator_locations; /**< Spatial location of each oscillator. */ std::vector > * distance_conn_weights; /**< Weight of each connection in the network. */ public: /*! @brief Contructor of the adapted oscillatory network SYNC for cluster analysis. @param[in] input_data: input data for clustering. @param[in] connectivity_radius: connectivity radius between points. @param[in] enable_conn_weight: if True - enable mode when strength between oscillators depends on distance between two oscillators. Otherwise all connection between oscillators have the same strength. @param[in] initial_phases: type of initialization of initial phases of oscillators. */ syncnet(std::vector > * input_data, const double connectivity_radius, const bool enable_conn_weight, const initial_type initial_phases); /*! @brief Copy-contructor of the sync-net algorithm is forbidden. @param[in] p_other: other syncnet instance. */ syncnet(const syncnet & p_other) = delete; /* @brief Default destructor. */ virtual ~syncnet(); /*! @brief Performs cluster analysis by the network simulation. @param[in] order: order of synchronization that is used as indication for stopping processing, the `order` value should be in range `(0, 1)`. @param[in] solver: specified type of solving diff. equation. @param[in] collect_dynamic: specified requirement to collect whole dynamic of the network. @param[out] analyser: analyser of sync results of clustering. */ virtual void process(const double order, const solve_type solver, const bool collect_dynamic, syncnet_analyser & analyser); /*! @brief Overrided method for calculation of oscillator phase. @param[in] t: current value of phase. @param[in] teta: time (can be ignored). @param[in] argv: index of oscillator whose phase represented by argument teta. @return Return new value of phase of oscillator with index 'argv'. */ virtual double phase_kuramoto(const double t, const double teta, const std::vector & argv) const override; virtual void phase_kuramoto_equation(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const override; public: /*! @brief Assignment operator for the sync-net algorithm is forbidden. @param[in] p_other: other syncnet instance. */ syncnet & operator=(const syncnet & p_other) = delete; protected: /*! @brief Create connections between oscillators in line with input radius of connectivity. @param[in] connectivity_radius: connectivity radius between oscillators. @param[in] enable_conn_weight: if True - enable mode when strength between oscillators depends on distance between two oscillators. Otherwise all connection between oscillators have the same strength. */ void create_connections(const double connectivity_radius, const bool enable_conn_weight); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/ttsas.hpp000077500000000000000000000073701375753423500253070ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @class ttsas ttsas.hpp pyclustering/cluster/ttsas.hpp @brief Class represents TTSAS (Two-Threshold Sequential Algorithmic Scheme). @details Clustering results of BSAS and MBSAS are strongly dependent on the order in which the points in data. TTSAS helps to overcome this shortcoming by using two threshold parameters. The first - if the distance to the nearest cluster is less than the first threshold then point is assigned to the cluster. The second - if distance to the nearest cluster is greater than the second threshold then new cluster is allocated. Code example of TTSAS usage: @code #include #include // ... `read_data` implementation to read sample ... int main() { // Read two-dimensional input data 'Simple03'. dataset data = read_data("Simple03.txt"); // Prepare parameters for TTSAS algorithm. const double threshold1 = 1.0; const double threshold2 = 2.0; // Create TTSAS algorithm and perform cluster analysis. ttsas ttsas_instance = ttsas(threshold1, threshold2); ttsas_data clustering_result; ttsas_instance.process(data, clustering_result); // Obtain allocated clusters. const auto & clusters = clustering_result.clusters(); // Print result. std::cout << "Amount of allocated clusters: " << clusters.size() << std::endl; return 0; } @endcode Implementation based on paper @cite book::pattern_recognition::2009. */ class ttsas : public bsas { private: const dataset * m_data_ptr = nullptr; /* temporary pointer to data - exists only during processing */ double m_threshold2 = 0.0; std::vector m_skipped_objects = { }; std::size_t m_start; public: /*! @brief Default TTSAS constructor. */ ttsas() = default; /*! @brief TTSAS constructor with specific parameters. @param[in] p_threshold1: dissimilarity level (distance) between point and its closest cluster, if the distance is less than `threshold1` value then point is assigned to the cluster. @param[in] p_threshold2: dissimilarity level (distance) between point and its closest cluster, if the distance is greater than `threshold2` value then point is considered as a new cluster. @param[in] p_metric: metric that is used for distance calculation between two points. */ ttsas(const double p_threshold1, const double p_threshold2, const distance_metric & p_metric = distance_metric_factory::euclidean()); public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: TTSAS clustering result of an input data. */ virtual void process(const dataset & p_data, ttsas_data & p_result) override; private: void process_objects(const std::size_t p_changes); void process_skipped_object(const std::size_t p_index_point); void append_to_cluster(const std::size_t p_index_cluster, const std::size_t p_index_point, const point & p_point); void allocate_cluster(const std::size_t p_index_point, const point & p_point); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/ttsas_data.hpp000077500000000000000000000005761375753423500263010ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace clst { /*! @brief A storage where TTSAS clustering results are stored. */ using ttsas_data = bsas_data; } }pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/xmeans.hpp000077500000000000000000000146351375753423500254460ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { /*! @brief Defines splitting types for clusters that are used by X-Means algorithm. */ enum class splitting_type { BAYESIAN_INFORMATION_CRITERION = 0, /**< Bayesian information criterion (BIC) to approximate the correct number of clusters. */ MINIMUM_NOISELESS_DESCRIPTION_LENGTH = 1, /**< Minimum noiseless description length (MNDL) to approximate the correct number of clusters. */ }; /*! @class xmeans xmeans.hpp pyclustering/cluster/xmeans.hpp @brief Class represents clustering algorithm X-Means. @details X-means clustering method starts with the assumption of having a minimum number of clusters, and then dynamically increases them. X-means uses specified splitting criterion to control the process of splitting clusters. Method K-Means++ can be used for calculation of initial centers. */ class xmeans { private: const static std::size_t AMOUNT_CENTER_CANDIDATES; const static double DEFAULT_SPLIT_DIFFERENCE; public: const static double DEFAULT_TOLERANCE; /**< Default value of the tolerance stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. */ const static splitting_type DEFAULT_SPLITTING_TYPE; /**< Default splitting criteria that is used by the X-Means algorithm. */ const static double DEFAULT_MNDL_ALPHA_PROBABILISTIC_VALUE; /**< Default MNDL alpha probabilistic value. */ const static double DEFAULT_MNDL_BETA_PROBABILISTIC_VALUE; /**< Default MNDL beta probabilistic value. */ private: dataset m_initial_centers; xmeans_data * m_ptr_result = nullptr; /* temporary pointer to output result */ const dataset * m_ptr_data = nullptr; /* used only during processing */ double m_alpha = DEFAULT_MNDL_ALPHA_PROBABILISTIC_VALUE; double m_beta = DEFAULT_MNDL_BETA_PROBABILISTIC_VALUE; std::size_t m_maximum_clusters; double m_tolerance = DEFAULT_TOLERANCE; splitting_type m_criterion = splitting_type::BAYESIAN_INFORMATION_CRITERION; std::size_t m_repeat = 1; long long m_random_state = RANDOM_STATE_CURRENT_TIME; distance_metric m_metric; public: /*! @brief Constructor of X-Means clustering algorithm. @param[in] p_initial_centers: initial centers that are used for processing. @param[in] p_kmax: maximum number of clusters that can be allocated. @param[in] p_tolerance: stop condition in following way: when maximum value of distance change of cluster centers is less than tolerance than algorithm will stop processing. @param[in] p_criterion: splitting criterion that is used for making descision about cluster splitting (by default `splitting_type::BAYESIAN_INFORMATION_CRITERION`). @param[in] p_repeat: how many times K-Means should be run to improve parameters (by default is 1), with larger 'repeat' values suggesting higher probability of finding global optimum. @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). @param[in] p_metric: distance metric calculator for two points (by default is Euclidean Square metric). */ xmeans(const dataset & p_initial_centers, const std::size_t p_kmax, const double p_tolerance = DEFAULT_TOLERANCE, const splitting_type p_criterion = DEFAULT_SPLITTING_TYPE, const std::size_t p_repeat = 1, const long long p_random_state = RANDOM_STATE_CURRENT_TIME, const distance_metric & p_metric = distance_metric_factory::euclidean_square()); /*! @brief Default destructor of the algorithm. */ ~xmeans() = default; public: /*! @brief Performs cluster analysis of an input data. @param[in] p_data: input data for cluster analysis. @param[out] p_result: clustering result of an input data. */ void process(const dataset & p_data, xmeans_data & p_result); /*! @brief Set alpha based probabilistic bound \f$\Q\left(\alpha\right)\f$ that is distributed from [0, 1]. @details The alpha probabilistic bound is used only in case of MNDL splitting criteria, in all other cases this value is ignored. @param[in] p_alpha: value distributed [0.0, 1.0] for alpha probabilistic bound \f$\Q\left(\alpha\right)\f$. */ void set_mndl_alpha_bound(const double p_alpha); /*! @brief Set beta based probabilistic bound \f$\Q\left(\beta\right)\f$ that is distributed from [0, 1]. @details The beta probabilistic bound is used only in case of MNDL splitting criteria, in all other cases this value is ignored. @param[in] p_alpha: value distributed [0.0, 1.0] for beta probabilistic bound \f$\Q\left(\beta\right)\f$. */ void set_mndl_beta_bound(const double p_beta); private: void improve_structure(); void improve_region_structure(const cluster & p_cluster, const point & p_center, dataset & p_allocated_centers) const; double search_optimal_parameters(cluster_sequence & improved_clusters, dataset & improved_centers, const index_sequence & available_indexes) const; double improve_parameters(cluster_sequence & improved_clusters, dataset & improved_centers, const index_sequence & available_indexes) const; double splitting_criterion(const cluster_sequence & analysed_clusters, const dataset & analysed_centers) const; double bayesian_information_criterion(const cluster_sequence & analysed_clusters, const dataset & analysed_centers) const; double minimum_noiseless_description_length(const cluster_sequence & clusters, const dataset & centers) const; }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/cluster/xmeans_data.hpp000077500000000000000000000006331375753423500264300ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include namespace pyclustering { namespace clst { using xmeans_data = kmeans_data; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/000077500000000000000000000000001375753423500237275ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency.hpp000077500000000000000000000077211375753423500263730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace container { /** * * @brief Abstract class of the adjacency collection that provides interface to control collection. * */ class adjacency_collection { public: /** * * @brief Default destructor. * */ virtual ~adjacency_collection() { } public: /** * * @brief Returns amount of nodes in the adjacency collection. * */ virtual size_t size() const = 0; /** * * @brief Establishes one-way connection from the first node to the second in adjacency collection. * * @param[in] node_index1: index of node in the collection that should be connected with another. * @param[in] node_index2: index of another node in the collection that should be connected with * the node defined by the first argument 'node_index1'. * */ virtual void set_connection(const size_t node_index1, const size_t node_index2) = 0; /** * * @brief Removes one-way connection from the first node to the second in adjacency collection. * * @param[in] node_index1: index of node in the collection that should be disconnected from another. * @param[in] node_index2: index of another node in the collection that should be diconnected from * the node defined by the first argument 'node_index1'. * */ virtual void erase_connection(const size_t node_index1, const size_t node_index2) = 0; /** * * @brief Checks existance of connection between specified nodes. * * @param[in] node_index1: index of node in the collection. * @param[in] node_index2: index of another node in the collection. * * @return 'true' - connection between the nodes exists, 'false' - connection does not exist. * */ virtual bool has_connection(const size_t node_index1, const size_t node_index2) const = 0; /** * * @brief Returns vector of indexes of neighbors of specified node in line with adjacency collection. * * @param[in] node_index: index of node in the collection. * @param[out] node_neighbors: vector of indexes of neighbors of specified node. * */ virtual void get_neighbors(const size_t node_index, std::vector & node_neighbors) const = 0; /** * * @brief Clear content of adjacency matrix. * */ virtual void clear() = 0; }; /** * * @brief Abstract class of the adjacency collection that provides interface to control collection. * */ class adjacency_weight_collection : public adjacency_collection { public: /** * * @brief Set weight of connection between nodes where zero value means lack of connection and * non-zero means connection with specified weight. * * @param[in] node_index1: index of node in the collection whose connection weight should be updated * with another node. * @param[in] node_index2: index of another node in the collection. * @param[in] weight: new value of weight of connection between the nodes. * */ virtual void set_connection_weight(const size_t node_index1, const size_t node_index2, const double weight) = 0; /** * * @brief Returns weight of one-way connection between specified nodes. * * @param[in] node_index1: index of node in the collection whose connection weight should be * updated with another node. * @param[in] node_index2: index of another node in the collection that is connected to the * first node. * * @return Weight of one-way connection between specified nodes. * */ virtual double get_connection_weight(const size_t node_index1, const size_t node_index2) const = 0; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency_bit_matrix.hpp000077500000000000000000000130101375753423500306010ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace container { /** * * @brief Implementation of classical bit adjacency matrix where each node has bit map where * each bit stores state of connection to correspoding node. * * @details Bit matrix implementation helps to significantly reduce usage of memory than list matrix * and classic matrix representations. But operations of getting and setting are slower than * mentioned implementations. * * @see adjacency_list * @see adjacency_matrix * */ class adjacency_bit_matrix : public adjacency_collection { private: using adjacency_bit_matrix_container = std::vector>; protected: adjacency_bit_matrix_container m_adjacency; size_t m_size; public: /** * * @brief Default destructor without arguments is forbiden. * */ adjacency_bit_matrix() = delete; /** * * @brief Default copy constructor. * * @param[in] another_matrix: adjacency matrix that should be copied. * */ adjacency_bit_matrix(const adjacency_bit_matrix & another_matrix) = default; /** * * @brief Default move constructor. * * @param[in] another_matrix: adjacency matrix that should be moved. * */ adjacency_bit_matrix(adjacency_bit_matrix && another_matrix) = default; /** * * @brief Adjacency bit matrix constructor. * * @param[in] node_amount: number of nodes whose connections are described in matrix. * */ explicit adjacency_bit_matrix(const std::size_t node_amount); /** * * @brief Default destructor. * */ virtual ~adjacency_bit_matrix(); private: static const size_t DEFAULT_EXISTANCE_CONNECTION_VALUE; static const size_t DEFAULT_NON_EXISTANCE_CONNECTION_VALUE; public: /** * * @brief Returns amount of nodes in adjacency collection. * */ virtual size_t size() const override; /** * * @brief Establishes one-way connection from the first node to the second in adjacency collection. * * @details Requies math-logical operations to set connection. No bounds checking is performed. * * @param[in] node_index1: index of node in the collection that should be connected with another. * @param[in] node_index2: index of another node in the collection that should be connected with * the node defined by the first argument 'node_index1'. * */ virtual void set_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Removes one-way connection from the first node to the second in adjacency collection. * * @details No bounds checking is performed. * * @param[in] node_index1: index of node in the collection that should be disconnected from another. * @param[in] node_index2: index of another node in the collection that should be disconnected from * the node defined by the first argument 'node_index1'. * */ virtual void erase_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Checks existence of connection between specified nodes. * * @details No bounds checking is performed. * * @param[in] node_index1: index of node in the collection. * @param[in] node_index2: index of another node in the collection. * * @return 'true' - connection between the nodes exists, 'false' - connection does not exist. * */ virtual bool has_connection(const size_t node_index1, const size_t node_index2) const override; /** * * @brief Returns vector of indexes of neighbors of specified node in line with adjacency collection. * * @details Requies math-logical operations to set connection. No bounds checking is performed. * * @param[in] node_index: index of node in the collection. * @param[out] node_neighbors: vector of indexes of neighbors of specified node. * */ virtual void get_neighbors(const size_t node_index, std::vector & node_neighbors) const override; /** * * @brief Clear content of adjacency matrix. * */ virtual void clear() override; private: /** * * @brief Sets or erases connection in line with specified state of connection. * * @details Requires math-logical operations to set connection. * * @param[in] node_index1: index of node whose state of connection should be updated. * @param[in] node_index2: index of another node in the collection. * */ void update_connection(const size_t node_index1, const size_t node_index2, const size_t state_connection); public: /** * * @brief Set adjacency bit matrix by copy it from another object. * * @param[in] p_other: another adjacency collection. * */ adjacency_bit_matrix & operator=(const adjacency_bit_matrix & another_matrix) = default; /** * * @brief Set adjacency bit matrix by move it from another object. * * @param[in] p_other: another adjacency collection. * */ adjacency_bit_matrix & operator=(adjacency_bit_matrix && another_matrix); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency_connector.hpp000077500000000000000000000364451375753423500304520ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include namespace pyclustering { namespace container { /** * * @brief Enumeration of pre-defined structures of connections between nodes in collection. * */ enum class connection_t { /*!< Connections does not exists. */ CONNECTION_NONE = 0, /*!< Each node is connected with all nodes except itself. */ CONNECTION_ALL_TO_ALL = 1, /*!< Each node is connected with four neighbors: left, upper, right and lower. */ CONNECTION_GRID_FOUR = 2, /*!< Each node is connected with eight neighbors: left, left-upper, upper, upper-right, right, right-lower, lower and lower-left. */ CONNECTION_GRID_EIGHT = 3, /*!< Each node is connected with two neighbors: left and right. */ CONNECTION_LIST_BIDIRECTIONAL = 4, }; /** * * @brief Generates a sequence of characters with the representation of structure of connections. * */ std::ostream & operator<<(std::ostream & p_stream, const connection_t & p_structure); /** * * @brief Class for creating pre-defined most popular structures by establishing connections * between nodes in unweight adjacency collections. * */ template class adjacency_connector { protected: using connector_controller = std::function; protected: connector_controller m_connector; public: /* @brief Default constructor of connector. */ adjacency_connector() : m_connector([](const size_t index1, const size_t index2, TypeCollection & collection) { collection.set_connection(index1, index2); }) { } public: /** * * @brief Creates connections between nodes in adjacency collection in line with specified * structure. * @details In case of grid structures it creates only square grids only, otherwise special * methods should be used such as 'create_grid_four_connections(...)' or * 'create_grid_eight_connections(...)'. * * @param[in] structure_type: structure of connections in adjacency collection that should be created. * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_structure(const connection_t structure_type, TypeCollection & output_adjacency_collection) { switch(structure_type) { case connection_t::CONNECTION_NONE: create_none_connections(output_adjacency_collection); break; case connection_t::CONNECTION_ALL_TO_ALL: create_all_to_all_connections(output_adjacency_collection); break; case connection_t::CONNECTION_GRID_FOUR: create_grid_four_connections(output_adjacency_collection); break; case connection_t::CONNECTION_GRID_EIGHT: create_grid_eight_connections(output_adjacency_collection); break; case connection_t::CONNECTION_LIST_BIDIRECTIONAL: create_list_bidir_connections(output_adjacency_collection); break; default: throw std::runtime_error("Type of connection is not supported."); } } /** * * @brief Removes all connections in adjacency collection. * * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_none_connections(TypeCollection & output_adjacency_collection) { for (size_t i = 0; i < output_adjacency_collection.size(); i++) { output_adjacency_collection.erase_connection(i, i); for (size_t j = i + 1; j < output_adjacency_collection.size(); j++) { output_adjacency_collection.erase_connection(i, j); output_adjacency_collection.erase_connection(j, i); } } } /** * * @brief Creates connections between all nodes where each node has connection with others. * @details This method does not connect node with itself. * * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_all_to_all_connections(TypeCollection & output_adjacency_collection) { for (size_t i = 0; i < output_adjacency_collection.size(); i++) { output_adjacency_collection.erase_connection(i, i); for (size_t j = i + 1; j < output_adjacency_collection.size(); j++) { m_connector(i, j, output_adjacency_collection); m_connector(j, i, output_adjacency_collection); } } } /** * * @brief Creates connections where each node is connected with two node-neighbors (except the * first and the last node): left and right in line with following scheme: 1 <-> 2 <-> 3 <- ... -> * (N - 2) <-> (N - 1) <-> N. * * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_list_bidir_connections(TypeCollection & output_adjacency_collection) { create_none_connections(output_adjacency_collection); for (size_t i = 0; i < output_adjacency_collection.size(); i++) { if (i > 0) { m_connector(i, i - 1, output_adjacency_collection); } if (i < (output_adjacency_collection.size() - 1)) { m_connector(i, i + 1, output_adjacency_collection); } } } /** * * @brief Creates connections where each node is connected with four node-neighbors: left, right, * upper and lower. * @details This method does not receive arguments that specify grid description: width and height. * Every adjacency collection is considered as a square and if root cannot be extracted * from amount of nodes then exception will be generated. * * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_grid_four_connections(TypeCollection & output_adjacency_collection) { const double conv_side_size = std::sqrt((double)output_adjacency_collection.size()); if (conv_side_size - std::floor(conv_side_size) > 0) { throw std::runtime_error("Invalid number of nodes in the adjacency for the square grid structure."); } const size_t edge = (size_t) conv_side_size; create_grid_four_connections(edge, edge, output_adjacency_collection); } /** * * @brief Creates connections where each node is connected with four node-neighbors: left, right, * upper and lower. * * @param[in] width: width of created grid structure that is defined by amount of nodes in a column. * @param[in] height: height of created grid structure that is defined by amount of nodes in a row. * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_grid_four_connections(const size_t width, const size_t height, TypeCollection & output_adjacency_collection) { if (width * height != output_adjacency_collection.size()) { throw std::runtime_error("Invalid number of nodes in the adjacency for the grid structure."); } create_none_connections(output_adjacency_collection); const int signed_width = static_cast(width); for (int index = 0; index < static_cast(output_adjacency_collection.size()); index++) { const int upper_index = index - signed_width; const int lower_index = index + signed_width; const int left_index = index - 1; const int right_index = index + 1; const int node_row_index = (int) std::ceil(index / signed_width); if (upper_index >= 0) { m_connector(index, upper_index, output_adjacency_collection); } if (lower_index < (int) output_adjacency_collection.size()) { m_connector(index, lower_index, output_adjacency_collection); } if ((left_index >= 0) && (std::ceil(left_index / signed_width) == node_row_index)) { m_connector(index, left_index, output_adjacency_collection); } if ((right_index < (int) output_adjacency_collection.size()) && (std::ceil(right_index / signed_width) == node_row_index)) { m_connector(index, right_index, output_adjacency_collection); } } } /** * * @brief Creates connections where each node is connected with eight node-neighbors: left, * left-upper, upper, upper-right, right, right-lower, lower, lower-left. * @details This method does not receive arguments that specify grid description: width and height. * Every adjacency collection is considered as a square and if root cannot be extracted * from amount of nodes then exception will be generated. * * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_grid_eight_connections(TypeCollection & output_adjacency_collection) { const double conv_side_size = std::sqrt((double)output_adjacency_collection.size()); if (conv_side_size - std::floor(conv_side_size) > 0) { throw std::runtime_error("Invalid number of nodes in the adjacency for the square grid structure."); } const size_t edge = (size_t) conv_side_size; create_grid_eight_connections(edge, edge, output_adjacency_collection); } /** * * @brief Creates connections where each node is connected with eight node-neighbors: left, * left-upper, upper, upper-right, right, right-lower, lower, lower-left. * * @param[in] width: width of created grid structure that is defined by amount of nodes in a column. * @param[in] height: height of created grid structure that is defined by amount of nodes in a row. * @param[out] output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_grid_eight_connections(const size_t width, const size_t height, TypeCollection & output_adjacency_collection) { create_grid_four_connections(width, height, output_adjacency_collection); /* create connection with right, upper, left, lower neighbor */ for (int index = 0; index < (int) output_adjacency_collection.size(); index++) { const int upper_left_index = index - 1 - (int) width; const int upper_right_index = index + 1 - (int) width; const int lower_left_index = index - 1 + (int) width; const int lower_right_index = index + 1 + (int) width; const int node_row_index = (int) std::floor(index / width); const int upper_row_index = node_row_index - 1; const int lower_row_index = node_row_index + 1; if ((upper_left_index >= 0) && (std::floor(upper_left_index / width) == upper_row_index)) { m_connector(index, upper_left_index, output_adjacency_collection); } if ((upper_right_index >= 0) && (std::floor(upper_right_index / width) == upper_row_index)) { m_connector(index, upper_right_index, output_adjacency_collection); } if ((lower_left_index < (int) output_adjacency_collection.size()) && (std::floor(lower_left_index / width) == lower_row_index)) { m_connector(index, lower_left_index, output_adjacency_collection); } if ((lower_right_index < (int) output_adjacency_collection.size()) && (std::floor(lower_right_index / width) == lower_row_index)) { m_connector(index, lower_right_index, output_adjacency_collection); } } } /** * * @brief Creates rectangle grid structure in line with specify type of connections. * @details It throws exception if non-grid structures is specify as a grid type. * * @param[in] p_grid: type of grid structure (for example, four grid or eight grid). * @param[in] p_width: width of created grid structure that is defined by amount of nodes in a column. * @param[in] p_height: height of created grid structure that is defined by amount of nodes in a row. * @param[out] p_output_adjacency_collection: adjacency collection whose connections should be updated. * */ virtual void create_grid_structure(const connection_t p_grid, const size_t p_width, const size_t p_height, TypeCollection & p_output_adjacency_collection) { switch (p_grid) { case connection_t::CONNECTION_GRID_FOUR: create_grid_four_connections(p_width, p_height, p_output_adjacency_collection); break; case connection_t::CONNECTION_GRID_EIGHT: create_grid_eight_connections(p_width, p_height, p_output_adjacency_collection); break; default: throw std::runtime_error("Grid structure of connection is expected"); } } }; /** * * @brief Class for creating pre-defined most popular structures by establishing connections * between nodes in weight adjacency collections. * */ template class adjacency_weight_connector : public adjacency_connector { public: using adjacency_weight_initializer = std::function; protected: adjacency_weight_initializer m_initializer; public: /** * * @brief Default constructor of connector where weight initializer is not specified. * @details In this case adjacency collection defines default value of weight by itself in * method 'set_connection()'. * */ adjacency_weight_connector() { } /** * * @brief Constructor of connector with weight initializer. * @details Initializer is used during creating connections between nodes for assigning weight * for each connection. Generally the initializer represents pointer to some function * that is used to assign weight, for example, if constant value is required then * the function should return always the same value, otherwise some logic can be * implemented. * * @param[in] initializer: initializer that is used for setting value of each weight connection. * */ explicit adjacency_weight_connector(const adjacency_weight_initializer & initializer) { if (initializer) { m_initializer = initializer; /* [this](const size_t index1, const size_t index2, TypeCollection & collection) { collection.set_connection_weight(index1, index2, initializer()); }; */ } } }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency_factory.hpp000077500000000000000000000064311375753423500301170ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace container { /** * * @brief Enumeration of pre-defined types of ajacency collections where weight of connections * is not used. * */ enum class adjacency_unweight_t { ADJACENCY_BIT_MATRIX, ADJACENCY_MATRIX, ADJACENCY_LIST }; /** * * @brief Enumeration of pre-defined types of ajacency collections where weight of connections * is supported. * */ enum class adjacency_weight_t { ADJACENCY_MATRIX, ADJACENCY_LIST }; /** * * @brief Factory of adjacency collections without weights. * */ class adjacency_unweight_factory { public: /** * * @brief Creates adjacency collection with specified size without connections between nodes. * * @param[in] amount_nodes: size of adjacency collection that is defined by amount of nodes in it. * @param[in] storing_type: type of collection that should be used for representation of adjacency * collection, for example, bit-matrix, list or classical matrix. * @param[in] structure_type: type of connections that should be formed in the collection. * */ static std::shared_ptr create_collection(const size_t amount_nodes, const adjacency_unweight_t storing_type = adjacency_unweight_t::ADJACENCY_MATRIX, const connection_t structure_type = connection_t::CONNECTION_NONE); }; /** * * @brief Factory of adjacency collections that supports weights when each connection between * nodes has weight. * */ class adjacency_weight_factory { public: /** * * @brief Creates adjacency collection with specified size without connections between nodes * and initial value for weight of each connection. * * @param[in] amount_nodes: size of adjacency collection that is defined by amount of nodes in it. * @param[in] storing_type: type of collection that should be used for representation of adjacency * collection, for example, bit-matrix, list or classical matrix. * @param[in] structure_type: type of connections that should be formed in the collection. * @param[in] default_weight_value: value that is assign to each connection weight. * @param[in] weight_value_generator: generator of values that are assigned to connection weights. * */ static std::shared_ptr create_collection(const size_t amount_nodes, const adjacency_weight_t storing_type = adjacency_weight_t::ADJACENCY_MATRIX, const connection_t structure_type = connection_t::CONNECTION_NONE, const std::function & weight_value_generator = nullptr); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency_list.hpp000077500000000000000000000113661375753423500274260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace container { /** * * @brief Implementation of adjacency matrix where each node stores its neighbors in unordered * set. * * @details Unordered ensures maximum performance in case of getting elements by index because only * indexes are used as keys that ensures uniform distribution. It takes less memory * than classical matrix representation. And it is faster in case of getting neighbors than * bit matrix and classical matrix representation. * * @see adjacency_bit_matrix * @see adjacency_matrix * */ class adjacency_list : public adjacency_collection { private: typedef std::vector> adjacency_list_container; protected: adjacency_list_container m_adjacency; public: /** * * @brief Default destructor. * */ adjacency_list(); /** * * @brief Default copy constructor. * * @param[in] another_matrix: adjacency matrix that should be copied. * */ adjacency_list(const adjacency_list & another_matrix) = default; /** * * @brief Default move constructor. * * @param[in] another_matrix: adjacency matrix that should be moved. * */ adjacency_list(adjacency_list && another_matrix) = default; /** * * @brief Adjacency list matrix constructor. * * @param[in] node_amount: number of nodes whose connections are described in matrix. * */ explicit adjacency_list(const size_t node_amount); /** * * @brief Default destructor. * */ virtual ~adjacency_list(); public: /** * * @brief Returns amount of nodes in adjacency collection. * */ virtual size_t size() const override; /** * * @brief Establishes one-way connection from the first node to the second in adjacency collection. * * @details Complexity equals to complexity of insertion of std::unrodered_set. No bounds checking * is performed. * * @param[in] node_index1: index of node in the collection that should be connected with another. * @param[in] node_index2: index of another node in the collection that should be connected with * the node defined by the first argument 'node_index1'. * */ virtual void set_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Removes one-way connection from the first node to the second in adjacency collection. * * @details Complexity equals to complexity of erasing of std::unrodered_set. No bounds checking * is performed. * * @param[in] node_index1: index of node in the collection that should be disconnected from another. * @param[in] node_index2: index of another node in the collection that should be diconnected from * the node defined by the first argument 'node_index1'. * */ virtual void erase_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Checks existence of connection between specified nodes. * * @details Complexity equal to searching of std::unrodered_set. No bounds checking * is performed. * * @param[in] node_index1: index of node in the collection. * @param[in] node_index2: index of another node in the collection. * * @return 'true' - connection between the nodes exists, 'false' - connection does not exist. * */ virtual bool has_connection(const size_t node_index1, const size_t node_index2) const override; /** * * @brief Returns vector of indexes of neighbors of specified node in line with adjacency collection. * * @details Complexity equals to complexity of copying from unordered_set to vector. No bounds checking * is performed. * * @param[in] node_index: index of node in the collection whose neighbors are required. * @param[out] node_neighbors: vector of indexes of neighbors of specified node. * */ virtual void get_neighbors(const size_t node_index, std::vector & node_neighbors) const override; /** * * @brief Clear content of adjacency matrix. * */ virtual void clear() override; public: adjacency_list & operator=(const adjacency_list & another_collection); adjacency_list & operator=(adjacency_list && another_collection); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency_matrix.hpp000077500000000000000000000145071375753423500277570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace container { /** * * @brief Implementation of classical adjacency matrix where each node stores weight of connection * to each node. * * @details This collection requires much more memory O(n^2) than others adjacency collections, but * setting and getting connection operations are faster O(1). Classic adjacency matrix * collection allows to specify weight of each connection between nodes. * * @see adjacency_bit_matrix * @see adjacency_list * */ class adjacency_matrix : public adjacency_weight_collection { private: typedef std::vector> adjacency_matrix_container; protected: adjacency_matrix_container m_adjacency = { }; public: /** * * @brief Default destructor without arguments is forbiden. * */ adjacency_matrix() = default; /** * * @brief Default copy constructor. * * @param[in] another_matrix: adjacency matrix that should be copied. * */ adjacency_matrix(const adjacency_matrix & another_matrix) = default; /** * * @brief Default move constructor. * * @param[in] another_matrix: adjacency matrix that should be moved. * */ adjacency_matrix(adjacency_matrix && another_matrix) = default; /** * * @brief Classic adjacency matrix constructor. * * @param[in] node_amount: number of nodes whose connections are described in matrix. * */ explicit adjacency_matrix(const size_t node_amount); /** * * @brief Default destructor. * */ virtual ~adjacency_matrix(); private: /** * * @brief Default value that denotes existance of connection (non-zero weight of connection). * */ static const double DEFAULT_EXISTANCE_CONNECTION_VALUE; /** * * @brief Default value that denotes lack of connection (zero weight of connection). * */ static const double DEFAULT_NON_EXISTANCE_CONNECTION_VALUE; public: /** * * @brief Returns amount of nodes in the adjacency collection. * */ virtual std::size_t size() const override; /** * * @brief Establishes one-way connection from the first node to the second in adjacency collection. * * @details Complexity of setting weight of connection is O(1). * * @param[in] node_index1: index of node in the collection that should be connected with another. * @param[in] node_index2: index of another node in the collection that should be connected with * the node defined by the first argument 'node_index1'. * */ virtual void set_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Removes one-way connection from the first node to the second in adjacency collection. * * @details Complexity of removing is O(1). * * @param[in] node_index1: index of node in the collection that should be disconnected from another. * @param[in] node_index2: index of another node in the collection that should be diconnected from * the node defined by the first argument 'node_index1'. * */ virtual void erase_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Checks existance of connection between specified nodes. * * @details Complexity of checking is O(1). * * @param[in] node_index1: index of node in the collection. * @param[in] node_index2: index of another node in the collection. * * @return 'true' - connection between the nodes exists, 'false' - connection does not exist. * */ virtual bool has_connection(const size_t node_index1, const size_t node_index2) const override; /** * * @brief Returns vector of indexes of neighbors of specified node in line with adjacency collection. * * @details Complexity of getting neighbors is O(n). * * @param[in] node_index: index of node in the collection whose neighbors are required. * @param[out] node_neighbors: vector of indexes of neighbors of specified node. * */ virtual void get_neighbors(const size_t node_index, std::vector & node_neighbors) const override; /** * * @brief Set weight of connection between nodes where zero value means lack of connection and * non-zero means connection with specified weight. * * @details Complexity of updating weight of connection is O(1). * * @param[in] node_index1: index of node in the collection whose connection weight should be updated * with another node. * @param[in] node_index2: index of another node in the collection. * @param[in] weight: new value of weight of connection between the nodes. * */ virtual void set_connection_weight(const size_t node_index1, const size_t node_index2, const double weight) override; /** * * @brief Returns weight of one-way connection between specified nodes. * * @details If connection from the first node to the second does not exist than zero value is * returned and if it exists than non-zero value is returned. Complexity of getting weight * of connection is O(1). * * @param[in] node_index1: index of node in the collection whose connection weight should be * updated with another node. * @param[in] node_index2: index of another node in the collection that is connected to the * first node. * * @return Weight of one-way connection between specified nodes. * */ virtual double get_connection_weight(const size_t node_index1, const size_t node_index2) const override; /** * * @brief Clear content of adjacency matrix. * */ virtual void clear() override; public: adjacency_matrix & operator=(const adjacency_matrix & another_collection); adjacency_matrix & operator=(adjacency_matrix && another_collection); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/adjacency_weight_list.hpp000077500000000000000000000151701375753423500307720ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace container { /** * * @brief Implementation of adjacency matrix where each node stores its neighbors in unordered * set with corresponding weight of connection to corresponding neighbor. * * @details Unordered ensures maximum performance in case of getting elements by index because only * indexes are used as keys that ensures uniform distribution. It takes less memory * than classical matrix representation. And it is faster in case of getting neighbors than * bit matrix and classical matrix representation. Unlike adjacency_list this implementation * requires twice as much memory because of storing weight of each connection. * * @see adjacency_bit_matrix * @see adjacency_matrix * */ class adjacency_weight_list : public adjacency_weight_collection { private: using adjacency_list_container = std::vector>; protected: adjacency_list_container m_adjacency; public: /** * * @brief Default destructor without arguments is forbiden. * */ adjacency_weight_list() = delete; /** * * @brief Default copy constructor. * * @param[in] another_matrix: adjacency matrix that should be copied. * */ adjacency_weight_list(const adjacency_weight_list & another_matrix) = default; /** * * @brief Default move constructor. * * @param[in] another_matrix: adjacency matrix that should be moved. * */ adjacency_weight_list(adjacency_weight_list && another_matrix) = default; /** * * @brief Adjacency list constructor. * * @param[in] node_amount: number of nodes whose connections are described in matrix. * */ explicit adjacency_weight_list(const size_t node_amount); /** * * @brief Default destructor. * */ virtual ~adjacency_weight_list(); private: /** * * @brief Default value that denotes existance of connection (non-zero weight of connection). * */ static const double DEFAULT_EXISTANCE_CONNECTION_VALUE; /** * * @brief Default value that denotes lack of connection (zero weight of connection). * */ static const double DEFAULT_NON_EXISTANCE_CONNECTION_VALUE; public: /** * * @brief Returns amount of nodes in the adjacency collection. * */ virtual size_t size() const override; /** * * @brief Establishes one-way connection from the first node to the second in adjacency collection. * * @details Complexity equals to complexity of insertion of std::unrodered_map. * * @param[in] node_index1: index of node in the collection that should be connected with another. * @param[in] node_index2: index of another node in the collection that should be connected with * the node defined by the first argument 'node_index1'. * */ virtual void set_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Removes one-way connection from the first node to the second in adjacency collection. * * @details Complexity equals to complexity of erasing of std::unrodered_map. * * @param[in] node_index1: index of node in the collection that should be disconnected from another. * @param[in] node_index2: index of another node in the collection that should be diconnected from * the node defined by the first argument 'node_index1'. * */ virtual void erase_connection(const size_t node_index1, const size_t node_index2) override; /** * * @brief Checks existance of connection between specified nodes. * * @details Complexity equal to searching element in std::unrodered_map. * * @param[in] node_index1: index of node in the collection. * @param[in] node_index2: index of another node in the collection. * * @return 'true' - connection between the nodes exists, 'false' - connection does not exist. * */ virtual bool has_connection(const size_t node_index1, const size_t node_index2) const override; /** * * @brief Returns vector of indexes of neighbors of specified node in line with adjacency collection. * * @details Complexity equals to complexity of traversing of unrodered_map. * * @param[in] node_index: index of node in the collection whose neighbors are required. * @param[out] node_neighbors: vector of indexes of neighbors of specified node. * */ virtual void get_neighbors(const size_t node_index, std::vector & node_neighbors) const override; /** * * @brief Set weight of connection between nodes where zero value means lack of connection and * non-zero means connection with specified weight. * * @details Complexity equal to searching element in std::unrodered_map. * * @param[in] node_index1: index of node in the collection whose connection weight should be updated * with another node. * @param[in] node_index2: index of another node in the collection. * @param[in] weight: new value of weight of connection between the nodes. * */ virtual void set_connection_weight(const size_t node_index1, const size_t node_index2, const double weight) override; /** * * @brief Returns weight of one-way connection between specified nodes. * * @details Complexity equal to searching element in std::unrodered_map. * * @param[in] node_index1: index of node in the collection whose connection weight should be * updated with another node. * @param[in] node_index2: index of another node in the collection that is connected to the * first node. * * @return Weight of one-way connection between specified nodes. * */ virtual double get_connection_weight(const size_t node_index1, const size_t node_index2) const override; /** * * @brief Clear content of adjacency matrix. * */ virtual void clear() override; public: adjacency_weight_list & operator=(const adjacency_weight_list & another_collection) = default; adjacency_weight_list & operator=(adjacency_weight_list && another_collection) = default; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/dynamic_data.hpp000077500000000000000000000046331375753423500270660ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace container { /** * * @brief Collection that stores dynamic of oscillatory network - state of each oscillator on * each iteration. * */ template class dynamic_data : public std::vector { public: std::size_t m_oscillators = 0; public: dynamic_data() = default; explicit dynamic_data(const std::size_t p_size) : std::vector(p_size), m_oscillators(0) { } dynamic_data(const std::size_t p_size, const DynamicType & p_value) : std::vector(p_size, p_value), m_oscillators(0) { } dynamic_data(const dynamic_data & p_dynamic) = default; dynamic_data(dynamic_data && p_dynamic) = default; virtual ~dynamic_data() = default; public: void push_back(const DynamicType & p_value) { check_set_oscillators(p_value); std::vector::push_back(p_value); } void push_back(DynamicType && p_value) { check_set_oscillators(p_value); std::vector::push_back(p_value); } void resize(const std::size_t p_size, const std::size_t p_oscillators) { std::vector::resize(p_size); m_oscillators = p_oscillators; } void clear() { std::vector::clear(); m_oscillators = 0; } std::size_t oscillators() const { return m_oscillators; } private: void check_set_oscillators(const DynamicType & p_value) { if (std::vector::empty()) { m_oscillators = p_value.size(); } else if (m_oscillators != p_value.size()) { throw std::range_error("Dynamic collection can consist of network states with the same size only"); } } private: using std::vector::assign; using std::vector::clear; using std::vector::emplace; using std::vector::erase; using std::vector::insert; using std::vector::push_back; using std::vector::pop_back; using std::vector::resize; using std::vector::data; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/ensemble_data.hpp000077500000000000000000000006601375753423500272300ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace container { template using ensemble_data = std::vector; using basic_ensemble = std::vector; using basic_ensemble_data = std::vector; } } pyclustering-0.10.1.2/ccore/include/pyclustering/container/kdnode.hpp000077500000000000000000000147441375753423500257210ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace container { /*! @brief Node of KD Tree. */ class kdnode : public std::enable_shared_from_this { public: using ptr = std::shared_ptr; private: using weak_ptr = std::weak_ptr; using search_node_rule = std::function< bool(const kdnode&) >; private: std::vector m_data = { }; void * m_payload = nullptr; ptr m_left = nullptr; ptr m_right = nullptr; weak_ptr m_parent = weak_ptr(); std::size_t m_discriminator = 0; public: /*! @brief Default constructor to create empty node. */ kdnode() = default; /*! @brief Constructs a KD-tree node. @param[in] p_data: points that represents the node. @param[in] p_payload: point to data block that is associated with the node. @param[in] p_left: pointer to the left child node. @param[in] p_right: pointer to the right child node. @param[in] p_parent: pointer to the parent node. @param[in] p_desc: dimension value of the node. */ kdnode(const std::vector & p_data, void * p_payload, const kdnode::ptr & p_left, const kdnode::ptr & p_right, const kdnode::ptr & p_parent, const std::size_t p_desc); /*! @brief Default copy constructor. */ kdnode(const kdnode & p_other) = default; /*! @brief Default move constructor. */ kdnode(kdnode && p_other) = default; /*! @brief Default destructor. */ virtual ~kdnode() = default; public: /*! @brief Set left child of the node. @param[in] p_node: left child node. */ void set_left(const kdnode::ptr & p_node); /*! @brief Set right child of the node. @param[in] p_node: right child node. */ void set_right(const kdnode::ptr & p_node); /*! @brief Set parent of the node. @param[in] p_node: parent node. */ void set_parent(const kdnode::ptr & p_node); /*! @brief Set data of the node. @param[in] p_data: point that represents node. */ void set_data(const point & p_data); /*! @brief Set payload of the node. @param[in] p_payload: pointer to data block that is associated with the node. */ void set_payload(void * p_payload); /*! @brief Set discriminator of the node. @param[in] disc: discriminator value (dimension). */ void set_discriminator(const std::size_t disc); public: /*! @brief Return left child node. @return Left child node. */ kdnode::ptr get_left() const; /*! @brief Return right child node. @return Right child node. */ kdnode::ptr get_right() const; /*! @brief Return parent node. @return Parent node. */ kdnode::ptr get_parent() const; /*! @brief Return pointer to data block that is associated with the current node. @return Pointer to data block that. */ void * get_payload() const; /*! @brief Find node in KD-tree using current node as a root of a subtree, the first founded node with specified coordinates is returned. @param[in] p_point: coordinates of searched node. @return Pointer to found node in the sub-tree. */ kdnode::ptr find_node(const point & p_point); /*! @brief Find node using specified rule, it returns the first node that satisfy search rule. @param[in] p_point: coordinates of searched node. @param[in] p_cur_node: node from which search is performed. @param[in] p_rule: rule that should be satisfied by searched node. @return Return the smallest node in specified subtree in line with discriminator. */ kdnode::ptr find_node(const point & p_point, const search_node_rule & p_rule); /*! @brief Return constant reference to a point (coordinates) that represents the current node. @return Constant reference to a point (coordinates) of the current node. */ const std::vector & get_data() const; /*! @brief Return reference to a point (coordinates) that represents the current node. @return Reference to a point (coordinates) of the current node. */ std::vector & get_data(); /*! @brief Return coordinate value that represents the current node. @return Coordinate value that represents the current node. */ double get_value() const; /*! @brief Return coordinate value of the specified dimension (discriminator) of the current node. @param[in] p_descr: dimension at which coordinate value is required. @return Coordinate value of the specified dimension (discriminator) of the current node. */ double get_value(const std::size_t p_descr) const; /*! @brief Return discriminator value of the current node. @return Discriminator value of the current node. */ std::size_t get_discriminator() const; /*! @brief Return dimension - amount of coordinates that represents the current node. @return Dimension - amount of coordinates that represents the current node. */ std::size_t get_dimension() const; /*! @brief Return non-null child points. @details For example, if a node has only right node and the left node is nullptr then only right node is returned. If node does not have children then empty container is returned. @return Dimension - amount of coordinates that represents the current node. */ void get_children(std::vector & p_children); }; bool operator < (const kdnode & node, const std::vector & point); bool operator < (const std::vector & point, const kdnode & node); bool operator > (const kdnode & node, const std::vector & point); bool operator > (const std::vector & point, const kdnode & node); bool operator <= (const kdnode & node, const std::vector & point); bool operator <= (const std::vector & point, const kdnode & node); bool operator >= (const kdnode & node, const std::vector & point); bool operator >= (const std::vector & point, const kdnode & node); bool operator == (const kdnode & node, const std::vector & point); bool operator == (const std::vector & point, const kdnode & node); } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/kdtree.hpp000077500000000000000000000066641375753423500257350ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include "kdtree_balanced.hpp" #include #include #include #include namespace pyclustering { namespace container { /** * * @brief KD Tree - structure for storing data where fast distance searching is required. * */ class kdtree : public kdtree_balanced { private: /** * * @brief Recursive remove of node in tree. * * @param[in] p_node: node that should be removed. * * @return Node that should replace removed node (if it's not leaf). * */ kdnode::ptr recursive_remove(kdnode::ptr & p_node); /** * * @brief Find minimal node in subtree in line with specified discriminator. * * @param[in] p_cur_node: root of subtree where searching should be performed. * @param[in] p_discriminator: discriminator that is used for comparison of nodes. * * @return Return the smallest node in specified subtree in line with discriminator. * */ static kdnode::ptr find_minimal_node(const kdnode::ptr & p_cur_node, const std::size_t p_discriminator); public: kdtree() = default; kdtree(const dataset & p_data, const std::vector & p_payloads = {}); kdtree(const kdtree & p_other) = default; kdtree(kdtree && p_other) = default; virtual ~kdtree() = default; public: /** * * @brief Insert new node in the tree. * * @param[in] p_point: coordinates that describe node in tree. * @param[in] p_payload: payloads of node (can be nullptr if it's not required). * * @return Pointer to added node in the tree. * */ kdnode::ptr insert(const std::vector & p_point, void * p_payload = nullptr); /** * * @brief Remove point with specified coordinates. * * @param[in] p_point: coordinates that describe node in tree. * */ void remove(const std::vector & p_point); /** * * @brief Remove point with specified coordinates and specific payload. * @details This remove is useful when points with the same coordinates are located * in the tree and but only one of them should be removed with specific payload where * node ID or other unique information is stored. * * @param[in] p_point: coordinates that describe node in tree. * @param[in] p_payload: payload that is used to identify node. * */ void remove(const std::vector & p_point, const void * p_payload); /** * * @brief Remove node from the tree. * * @param[in] p_node_for_remove: pointer to node that is located in tree. * */ void remove(kdnode::ptr & p_node_for_remove); public: /*! @brief Assignment operator for KD-tree. @param[in] p_other: another KD-tree that should be copied to the tree. @return Returns reference to KD-tree to where another tree was copied. */ kdtree & operator=(const kdtree & p_other) = default; /*! @brief Movement operator for KD-tree. @param[in,out] p_other: another KD-tree that should be moved to the tree. @return Returns reference to KD-tree to where another was moved. */ kdtree & operator=(kdtree && p_other) = default; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/kdtree_balanced.hpp000077500000000000000000000140151375753423500275330ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include "kdnode.hpp" #include #include #include #include namespace pyclustering { namespace container { /*! @brief Represents balanced static KD-tree that does not provide services to add and remove nodes after initialization. @details In the term KD tree, k denotes the dimensionality of the space being represented. Each data point is represented as a node in the k-d tree in the form of a record of type node. There is an example how to create KD-tree: @code #include #include #include #include using namespace pyclustering; using namespace pyclustering::container; int main() { // Points that should be stored in KD-tree. dataset coord = { { 30, 59 },{ 5, 51 },{ 4, 52 },{ 12, 41 },{ 12, 45 } }; // Lets create payload that is associated with each point. std::vector payload = { "St-Petersburg", "Eindhoven", "Amsterdam", "Rome", "Venice" }; // Create balanced KD-tree. kdtree_balanced tree(coord, payload); // Check each city in the tree. for (const auto & p : coord) { auto node = tree.find_node(p); std::cout << p[0] << ", " << p[1] << ": " << (char *)node->get_payload() << std::endl; } // Find closest cities to Eindhoven in distance 10. kdtree_searcher searcher({ 5, 51 }, tree.get_root(), 10); std::cout << "The closest city to Eindhoven is " << (char *)searcher.find_nearest_node()->get_payload() << std::endl; // Cities to which from Eidhoven less than 10. std::vector distances; std::vector nodes; searcher.find_nearest_nodes(distances, nodes); std::cout << "Cities to which distance is less or equal to 10:" << std::endl; for (std::size_t i = 0; i < nodes.size(); i++) { std::cout << distances[i] << ": " << (char *)nodes[i]->get_payload() << std::endl; } return 0; } @endcode There is an illustration of balanced KD-tree above that has been done by python version of pyclustering library. @image html kd_tree_balanced_lsun.png "Fig. 1. Balanced KD-tree for sample 'Lsun'." Implementation based on paper @cite book::the_design_and_analysis. @see kdtree */ class kdtree_balanced { protected: kdnode::ptr m_root = nullptr; std::size_t m_dimension = 0; std::size_t m_size = 0; public: /*! @brief Default constructor of balanced KD-tree. */ kdtree_balanced() = default; /*! @brief Parameterized constructor of balanced KD-tree. @param[in] p_data: data that should be stored in the tree. @param[in] p_payloads: payload for each point in `p_data`. */ kdtree_balanced(const dataset & p_data, const std::vector & p_payloads = { }); /*! @brief Default copy constructor of balanced KD-tree. @param[in] p_other: another tree that is used as a copy for constructed tree. */ kdtree_balanced(const kdtree_balanced & p_other) = default; /*! @brief Default move constructor of balanced KD-tree. @param[in,out] p_other: another tree that is used to move to constructed tree. */ kdtree_balanced(kdtree_balanced && p_other) = default; /*! @brief Default deconstructor of balanced KD-tree. */ virtual ~kdtree_balanced() = default; public: /*! @brief Find node in KD-tree using coordinates. @param[in] p_point: coordinates of searched node. @return Pointer to found node in tree. */ kdnode::ptr find_node(const point & p_point) const; /*! @brief Find node in KD-tree using coordinates. @param[in] p_point: coordinates of searched node. @param[in] p_payload: payload that is used to identify node. @return Pointer to found node in tree. */ kdnode::ptr find_node(const point & p_point, const void * p_payload) const; /*! @brief Return the root of the tree. @return Returns pointer to the root of the tree. */ kdnode::ptr get_root() const; /*! @brief Return size of KD-tree. @return Returns amount of nodes in KD-tree. */ std::size_t get_size() const; protected: /*! @brief Creates sub-tree of KD-tree from node `p_parent`. @param[in] p_begin: iterator to the beginning of the collection that should be used to build KD-tree. @param[in] p_end: iterator to the end of the collection that should be used to build KD-tree. @param[in] p_parent: node that is parent for tree that is going to be built. @param[in] p_depth: depth of the tree that where children of the `parent` should be placed. @return Returns a node that is a root for the created sub-tree. */ kdnode::ptr create_tree( std::vector::iterator p_begin, std::vector::iterator p_end, const kdnode::ptr & p_parent, const std::size_t p_depth); public: /*! @brief Assignment operator for KD-tree. @param[in] p_other: another KD-tree that should be copied to the tree. @return Returns reference to KD-tree to where another tree was copied. */ kdtree_balanced & operator=(const kdtree_balanced & p_other); /*! @brief Movement operator for KD-tree. @param[in,out] p_other: another KD-tree that should be moved to the tree. @return Returns reference to KD-tree to where another was moved. */ kdtree_balanced & operator=(kdtree_balanced && p_other); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/container/kdtree_searcher.hpp000077500000000000000000000111571375753423500276020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace container { /*! @brief Searcher in KD Tree provides services related to searching in KD Tree. */ class kdtree_searcher { public: using rule_store = std::function; private: using proc_store = std::function; private: mutable std::vector m_nodes_distance = { }; mutable std::vector m_nearest_nodes = { }; mutable dataset m_nearest_points = { }; mutable rule_store m_user_rule = nullptr; mutable proc_store m_proc = nullptr; double m_distance = -1; double m_sqrt_distance = -1; kdnode::ptr m_initial_node = nullptr; std::vector m_search_point = { }; public: /** * * @brief Default constructor. Search will not be performed until it's initialized. * */ kdtree_searcher() = default; /** * * @brief Constructor of searcher with request for searching. * * @param[in] point: point for which nearest nodes should be found. * @param[in] node: initial node in tree from which searching should started. * @param[in] radius_search: allowable distance for searching from the point. * */ kdtree_searcher(const std::vector & point, const kdnode::ptr & node, const double radius_search); /** * * @brief Default destructor. * */ ~kdtree_searcher() = default; public: /** * * @brief Search nodes that are located in specified distance from specified point. * * @param[out] p_distances: distances from the point to nodes in the location (that are radius-reachable). * @param[out] p_nearest_nodes: nodes in the location (radius-reachable). * * @return Return vector of found nodes in kd tree that satisfy the request. If distances are * specified then it will be filled by corresponding distances. * */ void find_nearest_nodes(std::vector & p_distances, std::vector & p_nearest_nodes) const; /** * * @brief Search the nearest node in specified location for specified point in the request. * * @return Return pointer to the nearest node in kd tree that satisfy the request. * */ kdnode::ptr find_nearest_node() const; /** * * @brief Search the nearest nodes and store information about found node using user-defined way. * * @param[in] p_store_rule: defines how to store KD-node. * */ void find_nearest(const rule_store & p_store_rule) const; private: /** * * @brief Initialization of new request for searching. * * @param[in] point: point for which nearest nodes should be found. * @param[in] node: initial node in tree from which searching should started. * @param[in] radius_search: allowable distance for searching from the point. * */ void initialize(const std::vector & point, const kdnode::ptr & node, const double radius_search); /** * * @brief Clear internal temporary structures. * */ void clear() const; /** * * @brief Recursive method for searching nodes that satisfy the request. * * @param[in] node: initial node in tree from which searching should performed. * */ void recursive_nearest_nodes(const kdnode::ptr & node) const; /** * * @brief Append to storage reachable node and distance to it. * * @param[in] node: node that should be added to best collection if it is reachable. * */ void store_if_reachable(const kdnode::ptr & node) const; /** * * @brief Store only one node in collection if it the best node. * * @param[in] node: node that should be added to best collection if it is reachable. * */ void store_best_if_reachable(const kdnode::ptr & node) const; /** * * @brief Store nodes using user-defined rule. * * @param[in] node: node that should be added to best collection if it is reachable. * */ void store_user_nodes_if_reachable(const kdnode::ptr & node) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/definitions.hpp000077500000000000000000000056121375753423500250000ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #if (defined (__GNUC__) && defined(__unix__)) || defined(__APPLE__) #if defined(EXPORT_PYCLUSTERING_INTERFACE) #define DECLARATION __attribute__ ((__visibility__("default"))) #else #define DECLARATION #endif #elif defined (WIN32) || (_WIN32) || (_WIN64) #if defined(EXPORT_PYCLUSTERING_INTERFACE) #define DECLARATION __declspec(dllexport) #else #define DECLARATION #endif #else #error Unsupported platform #endif namespace pyclustering { constexpr long long RANDOM_STATE_CURRENT_TIME = -1; /**< Defines value of the random state that means to use current system time as a seed for random functionality. */ /*! @brief Defines a patten that consists of features that describe this pattern. */ using pattern = std::vector; /*! @brief Defines shared pointer to pattern container. */ using pattern_ptr = std::shared_ptr; /*! @brief Defines point that represents a container with coordinates. */ using point = std::vector; /*! @brief Defines shared pointer to point container. */ using point_ptr = std::shared_ptr; /*! @brief Defines dataset that represents a container with points. */ using dataset = std::vector; /*! @brief Defines shared pointer to dataset container. */ using dataset_ptr = std::shared_ptr; /*! @brief Converts an input scalar value to string representation. @param[in] p_value: scalar value that should be represented by string. @return String representation of a scalar value. */ template::value >::type* = nullptr > std::string to_string(const Type & p_value) { return std::to_string(p_value); } /*! @brief Converts a container to string representation. @param[in] p_container: container that should be represented by string. @return String representation of a container. */ template >::value >::type* = nullptr > std::string to_string(const TypeContainer & p_container) { std::stringstream stream; stream << "["; for (std::size_t p_index = 0; p_index < p_container.size(); p_index++) { stream << pyclustering::to_string(p_container[p_index]); if (p_index != (p_container.size() - 1)) { stream << " "; } } stream << "]"; return stream.str(); } } pyclustering-0.10.1.2/ccore/include/pyclustering/differential/000077500000000000000000000000001375753423500244015ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/differential/differ_factor.hpp000077500000000000000000000020651375753423500277150ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once namespace pyclustering { namespace differential { class factor { public: const static double A2; const static double B2; const static double A3; const static double B3; const static double C3; const static double A4; const static double B4; const static double C4; const static double D4; const static double A5; const static double B5; const static double C5; const static double D5; const static double E5; const static double A6; const static double B6; const static double C6; const static double D6; const static double E6; const static double F6; const static double N1; const static double N3; const static double N4; const static double N5; const static double R1; const static double R3; const static double R4; const static double R5; const static double R6; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/differential/differ_state.hpp000077500000000000000000000220321375753423500275530ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include "solve_type.hpp" namespace pyclustering { namespace differential { template > class differ_state { public: typedef state_type value_type; typedef std::vector differ_variables; typedef typename differ_variables::iterator iterator; typedef typename differ_variables::const_iterator const_iterator; typedef typename differ_variables::reverse_iterator reverse_iterator; typedef typename differ_variables::const_reverse_iterator const_reverse_iterator; public: differ_state() : m_variable_state(std::vector()) { } explicit differ_state(const size_t size) : m_variable_state(std::vector(size)) { } differ_state(const size_t size, const state_type value) : m_variable_state(std::vector(size, value)) { } differ_state(const std::initializer_list & value, const allocator & alloc = allocator()) : m_variable_state(std::vector(value, alloc)) { } differ_state(const differ_state & instance) : m_variable_state(instance.m_variable_state) { } differ_state(const differ_state && instance) : m_variable_state(std::move(instance.m_variable_state)) { } ~differ_state() { } public: void insert(iterator position, const value_type & value) { m_variable_state.insert(position, value); } void push_back(const value_type & value) { m_variable_state.push_back(value); } void pop_back() { m_variable_state.pop_back(); } iterator begin() { return m_variable_state.begin(); } iterator end() { return m_variable_state.end(); } const_iterator cbegin() const { return m_variable_state.begin(); } const_iterator cend() const { return m_variable_state.end(); } reverse_iterator rbegin() { return m_variable_state.rbegin(); } reverse_iterator rend() { return m_variable_state.rend(); } const_reverse_iterator crbegin() const { return m_variable_state.crbegin(); } const_reverse_iterator crend() const { return m_variable_state.crend(); } void reserve(size_t size) { m_variable_state.reserve(size); } void resize(size_t size) { m_variable_state.resize(size); } void clear() { m_variable_state.clear(); } bool empty() const { return m_variable_state.empty(); } std::size_t size() const { return m_variable_state.size(); } public: value_type & operator[](std::size_t index) { return m_variable_state[index]; } const value_type & operator[](std::size_t index) const { return m_variable_state[index]; } /* Comparison */ bool operator==(const differ_state & rhs) const { bool result = true; if (this->size() != rhs.size()) { result = false; } else { for (size_t i = 0; i < size(); i++) { if ((*this)[i] != rhs[i]) { result = false; break; } } } return result; } bool operator!=(const differ_state & rhs) const { return !(*this == rhs); } differ_state & operator=(const differ_state & rhs) = default; differ_state & operator=(differ_state && rhs) = default; differ_state & operator+=(const double & rhs) { for (size_t i = 0; i < size(); i++) { (*this)[i] += rhs; } return *this; } differ_state & operator+=(const differ_state & rhs) { if (this->size() != rhs.size()) { throw std::runtime_error("Differetial states should consist of the same number of variables"); } for (size_t i = 0; i < size(); i++) { (*this)[i] += rhs[i]; } return *this; } differ_state & operator-=(const double & rhs) { for (size_t i = 0; i < size(); i++) { (*this)[i] -= rhs; } return *this; } differ_state & operator-=(const differ_state & rhs) { if (this->size() != rhs.size()) { throw std::runtime_error("Differetial states should consist of the same number of variables"); } for (size_t i = 0; i < size(); i++) { (*this)[i] -= rhs[i]; } return *this; } differ_state & operator*=(const double & rhs) { for (size_t i = 0; i < size(); i++) { (*this)[i] *= rhs; } return *this; } differ_state & operator*=(const differ_state & rhs) { if (this->size() != rhs.size()) { throw std::runtime_error("Differetial states should consist of the same number of variables"); } for (size_t i = 0; i < size(); i++) { (*this)[i] *= rhs[i]; } return *this; } differ_state & operator/=(const double & rhs) { for (size_t i = 0; i < size(); i++) { (*this)[i] /= rhs; } return *this; } differ_state & operator/=(const differ_state & rhs) { if (this->size() != rhs.size()) { throw std::runtime_error("Differetial states should consist of the same number of variables"); } for (size_t i = 0; i < size(); i++) { (*this)[i] /= rhs[i]; } return *this; } /* Arithmetic */ differ_state operator+() const { return this; } differ_state operator-() const { return 0 - *this; } friend differ_state operator+(const differ_state & lhs, const double rhs) { differ_state result(lhs.size()); for (std::size_t i = 0; i < result.size(); i++) { result[i] = lhs[i] + rhs; } return result; } friend differ_state operator+(const double lhs, const differ_state & rhs) { return rhs + lhs; } differ_state operator+(const differ_state & rhs) const { if (this->size() != rhs.size()) { throw std::runtime_error("Differetial states should consist of the same number of variables"); } differ_state result(size()); for (size_t i = 0; i < size(); i++) { result[i] = (*this)[i] + rhs[i]; } return result; } friend differ_state operator-(const differ_state & lhs, const double rhs) { differ_state result(lhs.size()); for (std::size_t i = 0; i < result.size(); i++) { result[i] = lhs[i] - rhs; } return result; } friend differ_state operator-(const double lhs, const differ_state & rhs) { differ_state result(rhs.size()); for (std::size_t i = 0; i < result.size(); i++) { result[i] = lhs - rhs[i]; } return result; } differ_state operator-(const differ_state & rhs) const { if (this->size() != rhs.size()) { throw std::runtime_error("Differetial states should consist of the same number of variables"); } differ_state result(size()); for (size_t i = 0; i < size(); i++) { result[i] = (*this)[i] - rhs[i]; } return result; } friend differ_state operator/(const differ_state & lhs, const double rhs) { differ_state result(lhs.size()); for (std::size_t i = 0; i < result.size(); i++) { result[i] = lhs[i] / rhs; } return result; } friend differ_state operator/(const double lhs, const differ_state & rhs) { differ_state result(rhs.size()); for (std::size_t i = 0; i < result.size(); i++) { result[i] = lhs / rhs[i]; } return result; } friend differ_state operator*(const differ_state & lhs, const double rhs) { differ_state result(lhs.size()); for (std::size_t i = 0; i < result.size(); i++) { result[i] = lhs[i] * rhs; } return result; } friend differ_state operator*(const double lhs, const differ_state & rhs) { return rhs * lhs; } private: differ_variables m_variable_state; }; template using differ_extra = std::vector; template struct differ_output { double time; differ_state state; }; template using differ_result = std::vector< differ_output >; template using differ_result_ptr = std::shared_ptr< differ_result >; } }pyclustering-0.10.1.2/ccore/include/pyclustering/differential/equation.hpp000077500000000000000000000010251375753423500267400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace differential { template using equation = std::function &, const differ_extra &, differ_state &) >; } }pyclustering-0.10.1.2/ccore/include/pyclustering/differential/runge_kutta_4.hpp000077500000000000000000000045101375753423500276700ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include namespace pyclustering { namespace differential { template void runge_kutta_4(const equation & func, const differ_state & inputs, const double time_start, const double time_end, const std::size_t steps, const bool flag_collect, const differ_extra & argv, /* additional arguments that are used in the equation */ differ_result & outputs) { const double step = (time_end - time_start) / (double) steps; if (flag_collect) { outputs.resize(steps); } else { outputs.resize(1); } differ_output current_result; current_result.time = time_start; current_result.state = inputs; for (std::size_t i = 0; i < steps; i++) { differ_state fp1, fp2, fp3, fp4; differ_state k1, k2, k3, k4; func(current_result.time, current_result.state, argv, fp1); k1 = fp1 * step; func(current_result.time + step / 2.0, current_result.state + k1 / 2.0, argv, fp2); k2 = fp2 * step; func(current_result.time + step / 2.0, current_result.state + k2 / 2.0, argv, fp3); k3 = fp3 * step; func(current_result.time + step, current_result.state + k3, argv, fp4); k4 = fp4 * step; current_result.state += (k1 + 2.0 * k2 + 2.0 * k3 + k4) / 6.0; current_result.time += step; if (flag_collect) { outputs[i].time = current_result.time; outputs[i].state = current_result.state; } } if (!flag_collect) { outputs[0].time = current_result.time; outputs[0].state = current_result.state; } } } }pyclustering-0.10.1.2/ccore/include/pyclustering/differential/runge_kutta_fehlberg_45.hpp000077500000000000000000000111661375753423500316200ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include namespace pyclustering { namespace differential { template void runge_kutta_fehlberg_45( const equation & func, const differ_state & inputs, const double time_start, const double time_end, const double tolerance, const bool flag_collect, const differ_extra & argv, differ_result & outputs) { if (flag_collect) { outputs.clear(); } else { outputs.resize(1); } differ_output current_result; current_result.time = time_start; current_result.state = inputs; double h = (time_end - time_start) / 10.0; /* default number of steps */ const double hmin = h / 1000.0; /* default multiplier for maximum step size */ const double hmax = 1000.0 * h; /* default multiplier for minimum step size */ const double br = time_end - 0.00001 * (double) std::abs(time_end); const unsigned int iteration_limit = 300; unsigned int iteration_counter = 0; while (current_result.time < time_end) { const double current_time = current_result.time; const differ_state current_value = current_result.state; if ( (current_time + h) > br ) { h = time_end - current_result.time; } differ_state fp1, fp2, fp3, fp4, fp5, fp6; differ_state k1, k2, k3, k4, k5, k6; differ_state y2, y3, y4, y5, y6; func(current_time, current_value, argv, fp1); k1 = h * fp1; y2 = current_value + factor::B2 * k1; func(current_time + factor::A2 * h, y2, argv, fp2); k2 = h * fp2; y3 = current_value + factor::B3 * k1 + factor::C3 * k2; func(current_time + factor::A3 * h, y3, argv, fp3); k3 = h * fp3; y4 = current_value + factor::B4 * k1 + factor::C4 * k2 + factor::D4 * k3; func(current_time + factor::A4 * h, y4, argv, fp4); k4 = h * fp4; y5 = current_value + factor::B5 * k1 + factor::C5 * k2 + factor::D5 * k3 + factor::E5 * k4; func(current_time + factor::A5 * h, y5, argv, fp5); k5 = h * fp5; y6 = current_value + factor::B6 * k1 + factor::C6 * k2 + factor::D6 * k3 + factor::E6 * k4 + factor::F6 * k5; func(current_time + factor::A6 * h, y6, argv, fp6); k6 = h * fp6; /* Calculate error (difference between Runge-Kutta 4 and Runge-Kutta 5) and new value. */ differ_state errors = factor::R1 * k1 + factor::R3 * k3 + factor::R4 * k4 + factor::R5 * k5 + factor::R6 * k6; double err = 0.0; for (typename differ_state::const_iterator iter = errors.cbegin(); iter != errors.cend(); ++iter) { double current_error = std::abs(*iter); if (current_error > err) { err = current_error; } } if ( (err < tolerance) || (h < 2.0 * hmin) ) { /* Calculate new value. */ current_result.state = current_value + factor::N1 * k1 + factor::N3 * k3 + factor::N4 * k4 + factor::N5 * k5; if (current_time + h > br) { current_result.time = time_end; } else { current_result.time = current_time + h; } if (flag_collect) { outputs.push_back(current_result); } else { outputs[0] = current_result; } iteration_counter++; } double s = 0.0; if (err != 0.0) { s = 0.84 * std::pow( (tolerance * h / err), 0.25 ); } if ( (s < 0.75) && (h > 2.0 * hmin) ) { h = h / 2.0; } if ( (s > 1.5) && (h * 2.0 < hmax) ) { h = 2.0 * h; } if (iteration_counter >= iteration_limit) { break; } } } } }pyclustering-0.10.1.2/ccore/include/pyclustering/differential/solve_type.hpp000077500000000000000000000005011375753423500273020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace differential { enum class solve_type { FORWARD_EULER, RUNGE_KUTTA_4, RUNGE_KUTTA_FEHLBERG_45, }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/interface/000077500000000000000000000000001375753423500237055ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/interface/agglomerative_interface.h000077500000000000000000000015211375753423500307260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /*! @brief Clustering algorithm Agglomerative returns allocated clusters. @details Caller should destroy returned result in 'pyclustering_package'. @param[in] p_sample: input data for clustering. @param[in] p_number_clusters: amount of clusters that should be allocated. @param[in] p_link: type of links for merging clusters. @return Returns result of clustering - array of allocated clusters. The last cluster in the array is noise. */ extern "C" DECLARATION pyclustering_package * agglomerative_algorithm(const pyclustering_package * const p_sample, const std::size_t p_number_clusters, const std::size_t p_link); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/bsas_interface.h000077500000000000000000000030471375753423500270350ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief BSAS result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum bsas_package_indexer { BSAS_PACKAGE_INDEX_CLUSTERS = 0, BSAS_PACKAGE_INDEX_REPRESENTATIVES, BSAS_PACKAGE_SIZE }; /** * * @brief Clustering algorithm BSAS returns allocated clusters. * @details Caller should destroy returned result that is in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_amount: maximum allowable number of clusters that can be allocated during processing. * @param[in] p_threshold: threshold of dissimilarity (maximum distance) between points. * @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. * * @return Returns result of clustering - array of allocated clusters in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * bsas_algorithm(const pyclustering_package * const p_sample, const std::size_t p_amount, const double p_threshold, const void * const p_metric);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/clique_interface.h000077500000000000000000000027441375753423500273720ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /*! @brief CLIQUE result is returned by pyclustering_package that consist sub-packages and this enumerator provides named indexes for sub-packages. */ enum clique_package_indexer { CLIQUE_PACKAGE_INDEX_CLUSTERS = 0, CLIQUE_PACKAGE_INDEX_NOISE, CLIQUE_PACKAGE_INDEX_LOGICAL_LOCATION, CLIQUE_PACKAGE_INDEX_MAX_CORNER, CLIQUE_PACKAGE_INDEX_MIN_CORNER, CLIQUE_PACKAGE_INDEX_BLOCK_POINTS, CLIQUE_PACKAGE_SIZE }; /*! @brief Performs cluster analysis of an input data using CLIQUE algorithm. @details Caller should destroy returned clustering data using 'cure_data_destroy' when it is not required anymore. @param[in] p_sample: input data for clustering. @param[in] p_intervals: amount of intervals in each dimension that defines amount of CLIQUE blocks. @param[in] p_threshold: minimum number of objects that should be contained by non-outlier CLIQUE block. @return Returns pointer to CLIQUE data - clustering result that can be used to obtain allocated clusters, outliers, logical locations, points captured by each block, min and max spatial corners. */ extern "C" DECLARATION pyclustering_package * clique_algorithm(const pyclustering_package * const p_sample, const std::size_t p_intervals, const std::size_t p_threshold);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/cure_interface.h000077500000000000000000000047361375753423500270510ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Clustering algorithm CURE returns allocated clusters. * @details Caller should destroy returned clustering data using 'cure_data_destroy' when * it is not required anymore. * * @param[in] sample: input data for clustering. * @param[in] number_clusters: number of clusters that should be allocated. * @param[in] number_repr_points: number of representation points for each cluster. * @param[in] compression: coefficient defines level of shrinking of representation * points toward the mean of the new created cluster after merging on each step. * * @return Returns pointer to cure data - clustering result that can be used for obtaining * allocated clusters, representative points and means of each cluster. * */ extern "C" DECLARATION void * cure_algorithm(const pyclustering_package * const sample, const size_t number_clusters, const size_t number_repr_points, const double compression); /** * * @brief Destroys CURE clustering data (clustering results). * * @param[in] pointer_cure_data: pointer to CURE clustering data. * */ extern "C" DECLARATION void cure_data_destroy(void * pointer_cure_data); /** * * @brief Returns allocated clusters by CURE algorithm. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] pointer_cure_data: pointer to CURE clustering data. * * @return Package where results of clustering are stored. * */ extern "C" DECLARATION pyclustering_package * cure_get_clusters(void * pointer_cure_data); /** * * @brief Returns CURE representors of each cluster. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] pointer_cure_data: pointer to CURE clustering data. * * @return Package where representative points for each cluster are stored. * */ extern "C" DECLARATION pyclustering_package * cure_get_representors(void * pointer_cure_data); /** * * @brief Returns CURE mean points of each cluster. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] pointer_cure_data: pointer to CURE clustering data. * * @return Package where mean point of each cluster is stored. * */ extern "C" DECLARATION pyclustering_package * cure_get_means(void * pointer_cure_data); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/dbscan_interface.h000077500000000000000000000026321375753423500273360ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Clustering algorithm DBSCAN returns allocated clusters and noise that are consisted * from input data. * @details Caller should destroy returned result by 'free_pyclustering_package'. * * @param[in] p_sample: input data for clustering (points or distance matrix). * @param[in] p_radius: connectivity radius between points, points may be connected if distance * between them less then the radius. * @param[in] p_minumum_neighbors: minimum number of shared neighbors that is required for * establish links between points. * @param[in] p_data_type: defines data type that is used for clustering process ('0' - points, '1' - distance matrix). * * @return Returns result of clustering - array of allocated clusters. The last cluster in the * array is noise. * */ extern "C" DECLARATION pyclustering_package * dbscan_algorithm(const pyclustering_package * const p_sample, const double p_radius, const size_t p_minumum_neighbors, const size_t p_data_type); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/elbow_interface.h000077500000000000000000000111251375753423500272110ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include /*! @brief Elbow result is returned by `pyclustering_package` that consists sub-packages and this enumerator provides named indexes for sub-packages. */ enum elbow_package_indexer { ELBOW_PACKAGE_AMOUNT = 0, ELBOW_PACKAGE_WCE, ELBOW_PACKAGE_SIZE }; /*! @brief Performs data analysis using Elbow method and a center initializer that is specified by template. @details Caller should destroy returned result by 'free_pyclustering_package'. @param[in] p_sample: input data for analysis. @param[in] p_kmin: minimum amount of clusters that should be considered. @param[in] p_kmax: maximum amount of clusters that should be considered. @param[in] p_kstep: search step in the interval [kmin, kmax]. @param[in] p_random_state: seed for random state. @return Returns Elbow's analysis results as a pyclustering package [ [ amount of clusters ], [ within cluster errors (wce) ] ]. */ template pyclustering_package * elbow_method(const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep, const long long p_random_state) { pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::elbow_data result; pyclustering::clst::elbow solver(p_kmin, p_kmax, p_kstep, p_random_state); solver.process(input_dataset, result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = ELBOW_PACKAGE_SIZE; package->data = new pyclustering_package * [ELBOW_PACKAGE_SIZE]; std::vector amount_cluters = { result.get_amount() }; ((pyclustering_package **) package->data)[ELBOW_PACKAGE_AMOUNT] = create_package(&amount_cluters); ((pyclustering_package **) package->data)[ELBOW_PACKAGE_WCE] = create_package(&result.get_wce()); return package; } /*! @brief Performs data analysis using Elbow method and K-Means++ center initialization to found out proper amount of clusters. @details Caller should destroy returned result by 'free_pyclustering_package'. @param[in] p_sample: input data for analysis. @param[in] p_kmin: minimum amount of clusters that should be considered. @param[in] p_kmax: maximum amount of clusters that should be considered. @param[in] p_kstep: search step in the interval [kmin, kmax]. @param[in] p_random_state: seed for random state. @return Returns Elbow's analysis results as a pyclustering package [ [ amount of clusters ], [ within cluster errors (wce) ] ]. */ extern "C" DECLARATION pyclustering_package * elbow_method_ikpp(const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep, const long long p_random_state); /*! @brief Performs data analysis using Elbow method and random center initialization to found out proper amount of clusters. @details Caller should destroy returned result by 'free_pyclustering_package'. @param[in] p_sample: input data for analysis. @param[in] p_kmin: minimum amount of clusters that should be considered. @param[in] p_kmax: maximum amount of clusters that should be considered. @param[in] p_kstep: search step in the interval [kmin, kmax]. @param[in] p_random_state: seed for random state. @return Returns Elbow's analysis results as a pyclustering package [ [ amount of clusters ], [ within cluster errors (wce) ] ]. */ extern "C" DECLARATION pyclustering_package * elbow_method_irnd(const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep, const long long p_random_state); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/fcm_interface.h000077500000000000000000000031251375753423500266470ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Fuzzy C-Means result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum fcm_package_indexer { FCM_PACKAGE_INDEX_CLUSTERS = 0, FCM_PACKAGE_INDEX_CENTERS, FCM_PACKAGE_INDEX_MEMBERSHIP, FCM_PACKAGE_SIZE }; /** * * @brief Clustering algorithm Fuzzy C-Medians returns allocated clusters. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_centers: initial cluster centers. * @param[in] p_m: hyper parameter that controls how fuzzy the cluster will be. * @param[in] p_tolerance: stop condition - when changes of medians are less then tolerance value. * @param[in] p_itermax: maximum amount of iterations for cluster analysis. * * @return Returns result of clustering - array of allocated clusters. * */ extern "C" DECLARATION pyclustering_package * fcm_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_centers, const double p_m, const double p_tolerance, const std::size_t p_itermax);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/gmeans_interface.h000077500000000000000000000041541375753423500273570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief G-Means result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum gmeans_package_indexer { GMEANS_PACKAGE_INDEX_CLUSTERS = 0, GMEANS_PACKAGE_INDEX_CENTERS, GMEANS_PACKAGE_INDEX_WCE, GMEANS_PACKAGE_SIZE }; /*! @brief Clustering algorithm G-Means returns allocated clusters. @details Caller should destroy returned result in `pyclustering_package`. @param[in] p_sample: input data for clustering. @param[in] p_amount: initial amount of centers. @param[in] p_tolerance: stop condition that stops the algorithm's processing when changes of medians are less than tolerance value. @param[in] p_repeat: how many times K-Means should be run to improve parameters, with larger `repeat` values suggesting higher probability of finding global optimum. @param[in] p_kmax: maximum amount of clusters that might be allocated. The argument is considered as a stop condition. When the maximum amount is reached then algorithm stops processing. By default the maximum amount of clusters is not restricted (`k_max` is -1). @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). @return Returns result of clustering - array of allocated clusters. */ extern "C" DECLARATION pyclustering_package * gmeans_algorithm(const pyclustering_package * const p_sample, const std::size_t p_amount, const double p_tolerance, const std::size_t p_repeat, const long long p_kmax, const long long p_random_state); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/hhn_interface.h000077500000000000000000000125621375753423500266640ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Create HHN oscillatory network. * @details HHN oscillatory network should be freed by 'hhn_destroy'. * * @param[in] p_size: Defines amount peripheral neurons in the network. * @param[in] p_params: Parameters of the HHN network. * * @return Pointer to HHN network. * */ extern "C" DECLARATION void * hhn_create(const std::size_t p_size, const void * const p_params); /** * * @brief Destroy HHN network 'hhn_network'. * * @param[in] p_network_pointer: Pointer to HHN network. * */ extern "C" DECLARATION void hhn_destroy(const void * p_network_pointer); /** * * @brief Create HHN dynamic where collect parameters are specified. * @details HHN dynamic should be freed by 'hhn_destroy_dynamic'. * * @param[in] p_collect_membrane: If 'true' then membrane potential will be collected during simulation. * @param[in] p_collect_active_cond_sodium: If 'true' then active cond sodium current will be collected during simulation. * @param[in] p_collect_inactive_cond_sodium: If 'true' then inactive cond sodium current will be collected during simulation. * @param[in] p_collect_active_cond_potassium: If 'true' then active cond potassium current will be collected during simulation. * * @return Pointer to HHN dynamic. * */ extern "C" DECLARATION void * hhn_dynamic_create(bool p_collect_membrane, bool p_collect_active_cond_sodium, bool p_collect_inactive_cond_sodium, bool p_collect_active_cond_potassium); /** * * @brief Destroy HHN dynamic. * * @param[in] p_dynamic: Pointer to HHN dynamic. * */ extern "C" DECLARATION void hhn_dynamic_destroy(const void * p_dynamic); /** * * @brief Performs simulation of HHN network. * * @param[in] p_network_pointer: Pointer to HHN network. * @param[in] p_steps: Number steps of simulations during simulation. * @param[in] p_time: Time of simulation. * @param[in] p_solver: Method that is used for differential equation. * @param[in] p_stimulus: Stimulus for oscillators, number of stimulus should be equal to number of oscillators. * @param[in,out] p_output_dynamic: Pointer to HHN dynamic where collected results are stored. * */ extern "C" DECLARATION void hhn_simulate(const void * p_network_pointer, const std::size_t p_steps, const double p_time, const std::size_t p_solver, const pyclustering_package * const p_stimulus, const void * p_output_dynamic); /** * * @brief Get specific dynamic evolution of peripheral neurons that is defined by collection index. * @details Collection indexes: * 0 - membrane potential; * 1 - active cond sodium; * 2 - inactive cond sodium; * 3 - active cond potassium; * * Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_output_dynamic: Pointer to HHN dynamic. * @param[in] p_collection_index: Index of collection that should be returned. * * @return Pointer to pyclustering package where dynamic evolution of peripheral neurons is stored. * */ extern "C" DECLARATION pyclustering_package * hhn_dynamic_get_peripheral_evolution(const void * p_output_dynamic, const std::size_t p_collection_index); /** * * @brief Get specific dynamic evolution of central elements that is defined by collection index. * @details Collection indexes: * 0 - membrane potential; * 1 - active cond sodium; * 2 - inactive cond sodium; * 3 - active cond potassium; * * Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_output_dynamic: Pointer to HHN dynamic. * @param[in] p_collection_index: Index of collection that should be returned. * */ extern "C" DECLARATION pyclustering_package * hhn_dynamic_get_central_evolution(const void * p_output_dynamic, const std::size_t p_collection_index); /** * * @brief Returns time points of simulation process that corresponds to amplitude. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_output_dynamic: Pointer to HHN dynamic. * * @return Pyclustering package where simulation time points are stored. * */ extern "C" DECLARATION pyclustering_package * hhn_dynamic_get_time(const void * p_output_dynamic); /** * * @brief Write out output dynamic to specified file in human-readable text format. * * @param[in] p_output_dynamic: Pointer to HHN dynamic. * @param[in] p_file: Output text file where output dynamic should be stored. * */ extern "C" DECLARATION void hhn_dynamic_write(const void * p_output_dynamic, const char * p_filename); /** * * @brief Read and construct HHN output dynamic from specified file. * @details Returned HHN output dynamic should be freed by 'hhn_dynamic_destroy'. * * @param[in] p_file: File where output dynamic is stored. * * @return HHN output dynamic with values from file. * */ extern "C" DECLARATION void * hhn_dynamic_read(const char * p_filename); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/hsyncnet_interface.h000077500000000000000000000056301375753423500277400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Create oscillatory network HSyncNet (hierarchical Sync) for cluster analysis. * * @param[in] p_sample: Input data for clustering. * @param[in] p_number_clusters: Number of clusters that should be allocated. * @param[in] p_initial_phases: Type of initialization of initial phases of oscillators. * @param[in] p_initial_neighbors: Defines initial radius connectivity by calculation average distance * to connect specify number of oscillators. * @param[in] p_increase_persent: Percent of increasing of radius connectivity on each step (input * values in range (0.0; 1.0) correspond to (0%; 100%)). * * @return Pointer of hsyncnet network. Caller should free it by 'hsyncnet_destroy_network'. * */ extern "C" DECLARATION void * hsyncnet_create_network(const pyclustering_package * const p_sample, const unsigned int p_number_clusters, const unsigned int p_initial_phases, const unsigned int p_initial_neighbors, const double p_increase_persent); /** * * @brief Destroy oscillatory network HSyncNet (calls destructor). * * @param[in] pointer_network: Pointer to HSyncNet oscillatory network. * */ extern "C" DECLARATION void hsyncnet_destroy_network(const void * p_pointer_network); /** * * @brief Simulate oscillatory network hierarchical SYNC until clustering problem is not resolved. * @details Caller should destroy instance of hsyncnet analyser of output dynamic using 'hsyncnet_analyser_destroy'. * * @param[in] p_pointer_network: Pointer to instance of hsyncnet. * @param[in] p_order: Order of synchronization that is used as indication for stopping processing. * @param[in] p_solver: Specified type of solving diff. equation. * @param[in] p_collect_dynamic: Specified requirement to collect whole dynamic of the network. * * @return Return pointer to hsyncnet analyser of output dynamic. * */ extern "C" DECLARATION void * hsyncnet_process(const void * p_pointer_network, const double p_order, const unsigned int p_solver, const bool p_collect_dynamic); /** * * @brief Destroy instance of analyser of hsyncnet (hierarchical sync oscillatory network). * * @param[in] p_pointer_analyser: Pointer to hsyncnet output dynamic analyser. * */ extern "C" DECLARATION void hsyncnet_analyser_destroy(const void * p_pointer_analyser);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/interface_property.h000077500000000000000000000010521375753423500277630ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include /** * * @brief Returns text description of the library * * @returns Returns const char pointer to text library description. * */ extern "C" DECLARATION void * get_interface_description(); /** * * @brief Returns version of the library interface * * @returns Returns const char pointer to version of the library interface. * */ extern "C" DECLARATION void * get_interface_version();pyclustering-0.10.1.2/ccore/include/pyclustering/interface/kmeans_interface.h000077500000000000000000000040331375753423500273570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief K-Means result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum kmeans_package_indexer { KMEANS_PACKAGE_INDEX_CLUSTERS = 0, KMEANS_PACKAGE_INDEX_CENTERS, KMEANS_PACKAGE_INDEX_EVOLUTION_CLUSTERS, KMEANS_PACKAGE_INDEX_EVOLUTION_CENTERS, KMEANS_PACKAGE_INDEX_WCE, KMEANS_PACKAGE_SIZE }; /** * * @brief Clustering algorithm K-Means returns allocated clusters. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_centers: initial cluster centers. * @param[in] p_tolerance: stop condition - when changes of medians are less then tolerance value. * @param[in] p_itermax: maximum number of iterations for cluster analysis. * @param[in] p_observe: if 'true' then evolution of cluster and center changes are collected to result. * @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. * * @return Returns result of clustering - array of allocated clusters, if 'p_observe' is 'true' then package contains * evolution of cluster and center changes. * */ extern "C" DECLARATION pyclustering_package * kmeans_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_initial_centers, const double p_tolerance, const std::size_t p_itermax, const bool p_observe, const void * const p_metric); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/kmedians_interface.h000077500000000000000000000031671375753423500277030ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief K-Medians result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum kmedians_package_indexer { KMEDIANS_PACKAGE_INDEX_CLUSTERS = 0, KMEDIANS_PACKAGE_INDEX_MEDIANS, KMEDIANS_PACKAGE_SIZE }; /** * * @brief Clustering algorithm K-Medians returns allocated clusters. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_initial_medians: initial medians of clusters. * @param[in] p_tolerance: stop condition - when changes of medians are less then tolerance value. * @param[in] p_itermax: maximum amount of iterations for cluster analysis. * @param[in] p_metric: distance metric for distance calculation between objects. * * @return Returns result of clustering - array of allocated clusters. * */ extern "C" DECLARATION pyclustering_package * kmedians_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_initial_medians, const double p_tolerance, const std::size_t p_itermax, const void * const p_metric); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/kmedoids_interface.h000077500000000000000000000036311375753423500277030ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief K-Medians result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum kmedoids_package_indexer { KMEDOIDS_PACKAGE_INDEX_CLUSTERS = 0, KMEDOIDS_PACKAGE_INDEX_MEDOIDS, KMEDOIDS_PACKAGE_SIZE }; /** * * @brief Clustering algorithm K-Medoids returns allocated clusters. * @details Caller should destroy returned result that is in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_medoids: initial medoids of clusters. * @param[in] p_tolerance: stop condition - when changes of medians are less then tolerance value. * @param[in] p_itermax: maximum number of iterations for cluster analysis. * @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. * @param[in] p_type: representation of data type ('0' - points, '1' - distance matrix). * * @return Returns result of clustering - array of allocated clusters in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * kmedoids_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_medoids, const double p_tolerance, const std::size_t p_itermax, const void * const p_metric, const std::size_t p_type); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/legion_interface.h000077500000000000000000000105751375753423500273660ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Create instance of LEGION (local excitatory global inhibitory oscillatory network). * @details Caller should destroy returned instance using 'legion_destroy' when it is not required anymore. * * @param[in] p_size: Number of oscillators in the network. * @param[in] p_connection_type: Type of connection between oscillators in the network. * @param[in] p_parameters: Parameters of the network that are defined by structure 'legion_parameters'. * * @return Returns pointer to LEGION instance. * */ extern "C" DECLARATION void * legion_create(const unsigned int p_size, const unsigned int p_connection_type, const void * const p_parameters); /** * * @brief Destroy 'legion_network'. * * @param[in] p_network_pointer: Pointer to instance of LEGION. * */ extern "C" DECLARATION void legion_destroy(const void * p_network_pointer); /** * * @brief Performs static simulation of LEGION oscillatory network. * @details Returned output dynamic of the network should be destoyed by 'legion_dynamic_destroy'. * * @param[in] p_network_pointer: Pointer to instance of LEGION. * @param[in] p_steps: Number steps of simulations during simulation. * @param[in] p_time: Time of simulation. * @param[in] p_solver: Method that is used for differential equation. * @param[in] p_collect_dynamic: If true - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. * @param[in] p_stimulus: Stimulus for oscillators, number of stimulus should be equal to number of oscillators, * example of stimulus for 5 oscillators [0, 0, 1, 1, 0], value of stimulus is defined by parameter 'I'. * * @return Pointer to dynamic of oscillatory network. * */ extern "C" DECLARATION void * legion_simulate(const void * p_network_pointer, const unsigned int p_steps, const double p_time, const unsigned int p_solver, const bool p_collect_dynamic, const pyclustering_package * const p_stimulus); /** * * @brief Returns size of the oscillatory network (LEGION) that is defined by amount of oscillators. * * @param[in] p_network_pointer: Pointer to instance of LEGION. * */ extern "C" DECLARATION std::size_t legion_get_size(const void * p_network_pointer); /** * * @brief Destroy instance of output dynamic of LEGION. * * @param[in] p_dynamic_pointer: Pointer to instance of LEGION. * */ extern "C" DECLARATION void legion_dynamic_destroy(const void * p_dynamic_pointer); /** * * @brief Returns output dynamic (amplitude of the excitatory component) of each oscillator during simulation process that corresponds to time points. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_dynamic_pointer: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * legion_dynamic_get_output(const void * p_dynamic_pointer); /** * * @brief Returns output dynamic (amplitude of the inhibitory component) of each oscillator during simulation process that corresponds to time points. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_dynamic_pointer: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * legion_dynamic_get_inhibitory_output(const void * p_dynamic_pointer); /** * * @brief Returns time points of simulation process that corresponds to amplitude. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_dynamic_pointer: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * legion_dynamic_get_time(const void * p_dynamic_pointer); /** * * @brief Returns length of dynamic that is defined by amount of time-points of simulation process. * * @param[in] p_dynamic_pointer: Pointer to output dynamic. * */ extern "C" DECLARATION std::size_t legion_dynamic_get_size(const void * p_dynamic_pointer);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/mbsas_interface.h000077500000000000000000000023551375753423500272130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Clustering algorithm MBSAS returns allocated clusters. * @details Caller should destroy returned result that is in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_amount: maximum allowable number of clusters that can be allocated during processing. * @param[in] p_threshold: threshold of dissimilarity (maximum distance) between points. * @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. * * @return Returns result of clustering - array of allocated clusters in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * mbsas_algorithm(const pyclustering_package * const p_sample, const std::size_t p_amount, const double p_threshold, const void * const p_metric);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/metric_interface.h000077500000000000000000000036401375753423500273670ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include enum metric_t { EUCLIDEAN = 0, EUCLIDEAN_SQUARE, MANHATTAN, CHEBYSHEV, MINKOWSKI, CANBERRA, CHI_SQUARE, GOWER, USER_DEFINED = 1000 }; /** * * @brief Create distance metric for calculation distance between two points. * * @param[in] p_type: metric type that is require to create. * @param[in] p_arguments: additional arguments, for example, degree in case of minkowski distance. * @param[in] p_solver: pointer to user-defined function that should be used for calculation, used only * in case of 'USER_DEFINED' metric type. * * @return Returns pointer to metric object, returned object should be destroyed by 'metric_destroy'. * */ extern "C" DECLARATION void * metric_create(const std::size_t p_type, const pyclustering_package * const p_arguments, double (*p_solver)(const void *, const void *)); /** * * @brief Destroy distance metric object. * * @param[in] p_pointer_metric: pointer to distance metric object. * */ extern "C" DECLARATION void metric_destroy(const void * p_pointer_metric); /** * * @brief Calculate metric between two points. * * @param[in] p_pointer_metric: pointer to distance metric object. * @param[in] p_point1: pointer to package with the first point. * @param[in] p_point2: pointer to package with the second point. * * @return Distance metric between two points. * */ extern "C" DECLARATION double metric_calculate(const void * p_pointer_metric, const pyclustering_package * const p_point1, const pyclustering_package * const p_point2); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/optics_interface.h000077500000000000000000000047341375753423500274120ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief OPTICS result is returned by pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum optics_package_indexer { OPTICS_PACKAGE_INDEX_CLUSTERS = 0, OPTICS_PACKAGE_INDEX_NOISE, OPTICS_PACKAGE_INDEX_ORDERING, OPTICS_PACKAGE_INDEX_RADIUS, OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_INDEX, OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_CORE_DISTANCE, OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_REACHABILITY_DISTANCE, OPTICS_PACKAGE_SIZE }; /** * * @brief Clustering algorithm OPTICS returns allocated clusters, noise, ordering and proper connectivity radius. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering that is represented by points or distance matrix (see p_data_type argument). * @param[in] p_radius: connectivity radius between points, points may be connected if distance * between them less then the radius. * @param[in] p_minumum_neighbors: minimum number of shared neighbors that is required for * establish links between points. * @param[in] p_amount_clusters: amount of clusters that should be allocated. * @param[in] p_data_type: defines data type that is used for clustering process ('0' - points, '1' - distance matrix). * * @return Returns result of clustering - array that consists of four general clustering results that are represented by arrays too: * [ [allocated clusters], [noise], [ordering], [connectivity radius], [optics objects indexes], [ optics objects core distances ], * [ optics objects reachability distances ] ]. It is important to note that connectivity radius is also placed into array. * */ extern "C" DECLARATION pyclustering_package * optics_algorithm(const pyclustering_package * const p_sample, const double p_radius, const size_t p_minumum_neighbors, const size_t p_amount_clusters, const size_t p_data_type); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/pcnn_interface.h000077500000000000000000000124501375753423500270410ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include /** * * @brief Creates Pulse Coupled Neural Network (PCNN). * @details Caller should destroy created instance by 'pcnn_destroy' when it is not required. * * @param[in] p_size: network size that is defined by amount of oscillator (neurons). * @param[in] p_connection_type: type of connections that is used in the network (all-to-all, grid, etc.). * @param[in] p_height: height of grid network structure (used only in case of grid structure types). * @param[in] p_width: width of grid network structure (used only in case of grid structure types). * @param[in] p_parameters: pointer to parameters of the network. * * @return Pointer to instance of created oscillatory network. * * @see pcnn_destroy * */ extern "C" DECLARATION void * pcnn_create(const unsigned int p_size, const unsigned int p_connection_type, const unsigned int p_height, const unsigned int p_width, const void * const p_parameters); /** * * @brief Destroy instance of Pulse Coupled Neural Network. * * @param[in] p_pointer: pointer to instance of destroying network. * */ extern "C" DECLARATION void pcnn_destroy(const void * p_pointer); /** * * @brief Simulates Pulse Coupled Neural Network during specify simulation time. * @details Caller should destroy output dynamic of the network when it is not required. * * @param[in] p_pointer: pointer to instance of the network that is simulated. * @param[in] p_steps: simulation time that is measured in steps (iterations). * @param[in] p_stimulus: stimulus for oscillators (neurons). * * @return Pointer to instance of output dynamic of the network. * * @see pcnn_dynamic_destroy * */ extern "C" DECLARATION void * pcnn_simulate(const void * p_pointer, const unsigned int p_steps, const void * const p_stimulus); /** * * @brief Returns size of the oscillatory network that is defined by amount of oscillators. * * @param[in] p_pointer: pointer to instance of the network. * * @return Size of the oscillatory network. * */ extern "C" DECLARATION std::size_t pcnn_get_size(const void * p_pointer); /** * * @brief Destroys instance of the output dynamic of Pulse Coupled Neural Network (PCNN). * * @param[in] p_pointer: pointer to instance of the network. * */ extern "C" DECLARATION void pcnn_dynamic_destroy(const void * pointer); /** * * @brief Allocates synchronous ensembles of oscillators. * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] p_pointer: pointer to instance of output dynamic of the oscillatory network (PCNN). * * @return Pointer to pyclustering package where allocated synchronous are located. * */ extern "C" DECLARATION pyclustering_package * pcnn_dynamic_allocate_sync_ensembles(const void * pointer); /** * * @brief Allocates spike ensembles of the network (PCNN). * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] p_pointer: pointer to instance of output dynamic of the oscillatory network (PCNN). * * @return Pointer to pyclustering package where allocated spikes ensembles are located. * */ extern "C" DECLARATION pyclustering_package * pcnn_dynamic_allocate_spike_ensembles(const void * pointer); /** * * @brief Allocates time signal of output dynamic of the network (PCNN). * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] p_pointer: pointer to instance of output dynamic of the oscillatory network (PCNN). * * @return Pointer to pyclustering package where time signal is located. * */ extern "C" DECLARATION pyclustering_package * pcnn_dynamic_allocate_time_signal(const void * pointer); /** * * @brief Returns output of each oscillator on each step of simulation. * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] p_pointer: pointer to instance of output dynamic of the oscillatory network (PCNN). * * @return Pointer to pyclustering package where output of each oscillator is located. * */ extern "C" DECLARATION pyclustering_package * pcnn_dynamic_get_output(const void * pointer); /** * * @brief Returns steps of simulation of the network (PCNN). * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] p_pointer: pointer to instance of output dynamic of the oscillatory network (PCNN). * * @return Pointer to pyclustering package where time steps are located. * */ extern "C" DECLARATION pyclustering_package * pcnn_dynamic_get_time(const void * pointer); /** * * @brief Returns size of the output dynamic that is defined by amount of simulation steps * stored in the output dynamic of the network (PCNN). * * @param[in] p_pointer: pointer to instance of output dynamic of the oscillatory network (PCNN). * * @return Size of the output dynamic of the network (PCNN). * */ extern "C" DECLARATION size_t pcnn_dynamic_get_size(const void * pointer); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/pyclustering_interface.h000077500000000000000000000005751375753423500306400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include /** * * @brief Deallocate pyclustering package. * * @param[in]: package: pointer to clustering results. * */ extern "C" DECLARATION void free_pyclustering_package(pyclustering_package * package); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/pyclustering_package.hpp000077500000000000000000000346621375753423500306370ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include #include #include /*! @brief Enumerates types that are supported by pyclustering package. @see pyclustering_package */ enum pyclustering_data_t { PYCLUSTERING_TYPE_INT = 0, /**< Represents basic `int` type. */ PYCLUSTERING_TYPE_UNSIGNED_INT = 1, /**< Represents basic `unsigned int` type. */ PYCLUSTERING_TYPE_FLOAT = 2, /**< Represents basic `float` type. */ PYCLUSTERING_TYPE_DOUBLE = 3, /**< Represents basic `double` type. */ PYCLUSTERING_TYPE_LONG = 4, /**< Represents basic `long` type. */ PYCLUSTERING_TYPE_CHAR = 5, /**< Represents basic `char` type. */ PYCLUSTERING_TYPE_LIST = 6, /**< Represents `pyclustering_package` type. */ PYCLUSTERING_TYPE_SIZE_T = 7, /**< Represents basic `std::size_t` type. */ PYCLUSTERING_TYPE_WCHAR_T = 8, /**< Represents basic `wchar_t` type. */ PYCLUSTERING_TYPE_UNDEFINED = 9 /**< Indicates incorrect type. */ }; /*! @class pyclustering_package pyclustering_package.hpp pyclustering/interface/pyclustering_package.hpp @brief Container that is used as data storage to communicate with the Python implementation of the library. @details The package uses dynamic memory allocation and user of the package is responsible for the deallocation to avoid memory leakage. */ struct DECLARATION pyclustering_package { public: std::size_t size = 0; /**< Amount of elements that are contained by the package. */ unsigned int type = static_cast(PYCLUSTERING_TYPE_UNDEFINED); /**< Type of elements that are contained by the package. */ void * data = nullptr; /**< Pointer to elements that are contained by the package. */ public: /*! @brief Default constructor of the package. */ pyclustering_package() = default; /*! @brief Constructor of the package that contains elements with specific type. @param[in] package_type: type of elements that are contained by the package. */ explicit pyclustering_package(const pyclustering_data_t package_type); /*! @brief Destructor of the package. */ ~pyclustering_package(); public: /*! @brief Returns reference to package element at the specified position like in case of array or vector. @param[in] index: index of an element in the package. @return Reference to the element in the package. @throw `std::out_of_range` if the package does not have element with index `index`. */ template auto & at(const std::size_t index) const { if (size <= index) { throw std::out_of_range("pyclustering_package::at() [" + std::to_string(__LINE__) + "]: index '" + std::to_string(index) + "' out of range (size: '" + std::to_string(size) + "')."); } return ((TypeValue *) data)[index]; } /*! @brief Returns reference to package element at the specified position like in case of two-dimensional array or vector. @param[in] index_row: row index in the package where required element is located. @param[in] index_column: column index in the package where required element is located. @return Reference to the element in the package. @throw `std::out_of_range` if the package does not have row with index `index_row` or does not have column with index `index_column`. */ template auto & at(const std::size_t index_row, const std::size_t index_column) const { if (size <= index_row) { throw std::out_of_range("pyclustering_package::at() [" + std::to_string(__LINE__) + "]: index '" + std::to_string(index_row) + "' out of range (size: '" + std::to_string(size) + "')."); } pyclustering_package * package = at(index_row); return ((TypeValue *) package->data)[index_column]; } /*! @brief Extract content of the package to standard container. @details Extraction is a copying procedure. @param[in] container: container that is used as a destination for the extraction procedure. */ template void extract(std::vector & container) const { extract(container, this); } /*! @brief Extract content of the package to standard container. @details Extraction is a copying procedure. @param[in] container: container that is used as a destination for the extraction procedure. */ template void extract(std::vector> & container) const { if (type != PYCLUSTERING_TYPE_LIST) { throw std::invalid_argument("pyclustering_package::extract() [" + std::to_string(__LINE__) + "]: argument is not 'PYCLUSTERING_TYPE_LIST')."); } for (std::size_t i = 0; i < size; i++) { std::vector subcontainer = { }; extract(subcontainer, at(i)); container.push_back(subcontainer); } } private: /*! @brief Extract content of the package to standard container from specific pyclustering package. @param[in] container: container that is used as a destination for the extraction procedure. @param[in] package: package that is used as a source for the extraction procedure. */ template void extract(std::vector & container, const pyclustering_package * const package) const { for (std::size_t i = 0; i < package->size; i++) { container.push_back(package->at(i)); } } }; /*! @brief Create pyclustering package with specified size that defines amount of elements that are going to be stored in the package. @param[in] p_size: package size that defines amount of elements. @return Pointer to created pyclustering package. */ pyclustering_package * create_package_container(const std::size_t p_size); /*! @brief Returns data type of the pyclustering package. @details If the template parameter of the function contains unsupported data type then `PYCLUSTERING_TYPE_UNDEFINED` is returned. @return Data type of the pyclustering package. */ template pyclustering_data_t get_package_type() { pyclustering_data_t type_package = PYCLUSTERING_TYPE_UNDEFINED; if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_INT; } // cppcheck-suppress multiCondition ; 'int' and 'unsigned int' are not the same. else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_UNSIGNED_INT; } else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_FLOAT; } else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE; } else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_LONG; } else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_CHAR; } else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_WCHAR_T; } // cppcheck-suppress multiCondition ; 'std::size_t' and 'long' are not the same for x64. else if (std::is_same::value) { type_package = pyclustering_data_t::PYCLUSTERING_TYPE_SIZE_T; } return type_package; } /*! @brief Create pyclustering package with specified size and data type. @param[in] p_size: package size that defines amount of elements. @return Pointer to created pyclustering package. */ template pyclustering_package * create_package(const std::size_t p_size) { const pyclustering_data_t type_package = get_package_type(); if (type_package == pyclustering_data_t::PYCLUSTERING_TYPE_UNDEFINED) { return nullptr; } pyclustering_package * package = new pyclustering_package(type_package); package->size = p_size; package->data = new TypeValue[package->size]; return package; } /*! @brief Create pyclustering package with specified size, data type and default value for each elements in the package. @param[in] p_size: package size that defines amount of elements. @param[in] p_value: default value for each element in the package. @return Pointer to created pyclustering package. */ template pyclustering_package * create_package(const std::size_t p_size, const TypeValue & p_value) { pyclustering_package * package = create_package(p_size); if (package) { for (std::size_t i = 0; i < p_size; i++) { ((TypeValue *) package->data)[i] = p_value; } } return package; } /*! @brief Create pyclustering package using pointer to one-dimensional container with fundamental data and that container supports `std::begin`, `std::end` methods and incremental iterators. @details All data from the container will be copied to the package. @param[in] data: a pointer to container that is used to create pyclustering container. @tparam TypeContainer: a pointer type to a container. @return Pointer to created pyclustering package. */ template ::value && !pyclustering::utils::traits::is_string::value && pyclustering::utils::traits::is_container_with_fundamental_content< typename pyclustering::utils::traits::remove_cvp_t >::value >::type* = nullptr > pyclustering_package * create_package(TypeContainer data) { using container_t = typename std::remove_pointer::type; using contaner_data_t = typename container_t::value_type; pyclustering_package * package = create_package(data->size()); if (package) { std::size_t index = 0; for (auto iter = std::begin(*data); iter != std::end(*data); iter++, index++) { static_cast(package->data)[index] = *iter; } } return package; } /*! @brief Create pyclustering package using pointer to a two-dimensional vector container. @details All data from the container will be copied to the package. @param[in] data: container that is used to create pyclustering container. @tparam TypeObject: an object type that is used by the container. @return Pointer to created pyclustering package. */ template pyclustering_package * create_package(const std::vector< std::vector > * const data) { pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = data->size(); package->data = new pyclustering_package * [package->size]; for (size_t i = 0; i < package->size; i++) { ((pyclustering_package **) package->data)[i] = create_package(&(*data)[i]); } return package; } /*! @brief Create pyclustering package using pointer to a two-dimensional vector container that uses pointers for internal elements. @details All data from the container will be copied to the package. @param[in] data: container that is used to create pyclustering container. @tparam TypeObject: an object type that is used by the container. @return Pointer to created pyclustering package. */ template pyclustering_package * create_package(const std::vector< std::vector * > * const data) { pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = data->size(); package->data = new pyclustering_package * [package->size]; for (size_t i = 0; i < package->size; i++) { ((pyclustering_package **) package->data)[i] = create_package((*data)[i]); } return package; } /*! @brief Create pyclustering package using raw string such as `char *`, `wchar_t *` including any cv-qualified variants. @details All data from the raw string will be copied to the package. @param[in] p_message: string line that is used to create pyclustering package. @tparam TypeRawString: a character type that is used by the string line. @return Pointer to created pyclustering package. */ template ::value >::type* = nullptr > pyclustering_package * create_package(TypeRawString p_message) { using element_string_t = typename std::remove_cv::type>::type; const std::size_t length = std::char_traits::length(p_message); pyclustering_package * package = create_package(length + 1); if (package) { std::char_traits::copy(static_cast(package->data), p_message, length); static_cast(package->data)[package->size - 1] = static_cast(0); } return package; } /*! @brief Create pyclustering package using standard string line such as `std::string`, `std::wstring` including any cv-qualified variants. @details All data from the raw string will be copied to the package. @param[in] p_message: string line that is used to create pyclustering container. @tparam TypeString: a string type that is used to create pyclustering container. @return Pointer to created pyclustering package. */ template ::value >::type* = nullptr > pyclustering_package * create_package(TypeString & p_message) { return create_package(p_message.c_str()); } pyclustering-0.10.1.2/ccore/include/pyclustering/interface/rock_interface.h000077500000000000000000000020321375753423500270340ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Clustering algorithm ROCK returns allocated clusters. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_radius: connectivity radius (similarity threshold). * @param[in] p_number_clusters: defines number of clusters that should be allocated from the input data set. * @param[in] p_threshold: value that defines degree of normalization that influences * on choice of clusters for merging during processing. * * @return Returns result of clustering - array of allocated clusters in the pyclustering package. * */ extern "C" DECLARATION pyclustering_package * rock_algorithm(const pyclustering_package * const p_sample, const double p_radius, const size_t p_number_clusters, const double p_threshold); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/silhouette_interface.h000077500000000000000000000062131375753423500302700ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include /** * * @brief Silhouette K-Search result is returned using pyclustering_package that consist sub-packages and this enumerator provides * named indexes for sub-packages. * */ enum silhouette_ksearch_package_indexer { SILHOUETTE_KSEARCH_PACKAGE_AMOUNT = 0, SILHOUETTE_KSEARCH_PACKAGE_SCORE, SILHOUETTE_KSEARCH_PACKAGE_SCORES, SILHOUETTE_KSEARCH_PACKAGE_SIZE }; /** * * @brief Silhouette K-Search cluster allocators. * */ enum silhouette_ksearch_type { KMEANS = 0, KMEDIANS, KMEDOIDS }; /** * * @brief Returns cluster allocator for Silhouette K-Search algorithm. * * @param[in] p_algorithm: cluster allocator type that should be created. * * @return Returns cluster allocator. * */ pyclustering::clst::silhouette_ksearch_allocator::ptr get_silhouette_ksearch_allocator( const silhouette_ksearch_type p_algorithm); /** * * @brief Performs data analysis using Silhouette method using center initializer that is specified by template. * @details Caller should destroy returned result by 'free_pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_clusters: clusters that have been allocated for that data. * @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. * @param[in] p_data_type: defines data type that is used for clustering process ('0' - points, '1' - distance matrix). * * @return Returns Silhouette's analysis results as a pyclustering package [ scores ]. * */ extern "C" DECLARATION pyclustering_package * silhouette_algorithm( const pyclustering_package * const p_sample, const pyclustering_package * const p_clusters, const void * const p_metric, const std::size_t p_data_type); /** * * @brief Performs data analysis using Silhouette K-Search algorithm using center initializer that is specified by template. * @details Caller should destroy returned result by 'free_pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_kmin: minimum amount of clusters that should be considered. * @param[in] p_kmax: maximum amount of clusters that should be considered. * @param[in] p_metric: cluster allocator that is used by Silhouette K-Search method. * @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). * * @return Returns Silhouette K-Search results as a pyclustering package [ [ amount of clusters], [ optimal score ], [ score for each K ] ]. * */ extern "C" DECLARATION pyclustering_package * silhouette_ksearch_algorithm( const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_algorithm, const long long p_random_state);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/som_interface.h000077500000000000000000000122531375753423500267020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include /** * * @brief Creates self-organized feature map (SOM). * @details Caller should destroy created instance by 'som_destroy' when it is not required. * * @param[in] num_rows: amount of neurons in each row of the map. * @param[in] num_cols: amount of neurons in each column of the map. * @param[in] type_conn: type of connections between neurons (grid-four, grid-eight, honeycomb, defined by neighbor function, etc.). * @param[in] parameters: pointer to parameters of the map. * * @return Pointer to instance of self-organized feature map. * * @see som_destroy * */ extern "C" DECLARATION void * som_create(const size_t num_rows, const size_t num_cols, const size_t type_conn, const void * parameters); /** * * @brief Destroy instance of self-organized feature map (SOM). * * @param[in] pointer: pointer to instance of self-organized feature map. * */ extern "C" DECLARATION void som_destroy(const void * pointer); /** * * @brief Load network parameters such weights, amount of won objects by each neuron (optional), captuted objects by each neuron (optional). * * @param[in] p_pointer: pointer to instance of self-organized feature map. * @param[in] p_weights: weights that should be load to the network. * @param[in] p_awards: amount of captured objects by each neuron (optional parameter and can be 'nullptr'). * @param[in] p_captured_objects: captured objects by each neuron (optional parameter and can be 'nullptr'). * * @see som_destroy * */ extern "C" DECLARATION void som_load(const void * p_pointer, const pyclustering_package * p_weights, const pyclustering_package * p_awards, const pyclustering_package * p_captured_objects); /** * * @brief Trains self-organized feature map (SOM). * * @param[in] pointer: pointer to instance of self-organized feature map. * @param[in] sample: pointer to input dataset for training. * @param[in] epochs: number of epochs for training. * @param[in] autostop: stop learining when convergance is too low. * * @return Returns number of learining iterations. * */ extern "C" DECLARATION size_t som_train(const void * pointer, const pyclustering_package * const sample, const size_t epochs, const bool autostop); /** * * @brief Processes input pattern (no learining) and returns index of neuron-winner. * @details Using index of neuron winner catched object can be obtained by som_get_capture_objects(). * * @param[in] pointer: pointer to instance of self-organized feature map. * @param[in] p_pattern: input pattern for processing. * * @return Returns index of neuron-winner. * * @see som_get_capture_objects() * */ extern "C" DECLARATION size_t som_simulate(const void * pointer, const pyclustering_package * const p_pattern); /** * * @brief Returns number of neuron winners at the last step of learning process. * * @param[in] pointer: pointer to instance of self-organized feature map. * * @return Returns amout of neurons that are winners. * */ extern "C" DECLARATION size_t som_get_winner_number(const void * pointer); /** * * @brief Returns size of self-organized map (number of neurons in the map). * * @param[in] pointer: pointer to instance of self-organized feature map. * */ extern "C" DECLARATION size_t som_get_size(const void * pointer); /** * * @brief Returns neuron weights in pyclustering package. * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] pointer: pointer to instance of self-organized feature map. * * @return Neuron weights in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * som_get_weights(const void * pointer); /** * * @brief Returns sequence of captured objects by each neuron during training. * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] pointer: pointer to instance of self-organized feature map. * * @return Captured objects by each neuron in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * som_get_capture_objects(const void * pointer); /** * * @brief Returns amount of captured objects by each neuron during training. * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] pointer: pointer to instance of self-organized feature map. * * @return Amount of captured objects by each neuron in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * som_get_awards(const void * pointer); /** * * @brief Returns neighbor indexes of each neuron. * @details Allocated puclustering package should be freed by caller using 'free_pyclustering_package'. * * @param[in] pointer: pointer to instance of self-organized feature map. * * @return Neighbor indexes of each neuron in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * som_get_neighbors(const void * pointer); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/sync_interface.h000077500000000000000000000200721375753423500270560ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Create oscillatory network Sync that is based on Kuramoto model. * @details Caller should destroy returned instance using 'sync_destroy_network' when * it is not required anymore. * * @param[in] size: number of oscillators in the network. * @param[in] weight_factor: coupling strength of the links between oscillators. * @param[in] frequency_factor: multiplier of internal frequency of the oscillators. * @param[in] connection_type: type of connection between oscillators in the network. * @param[in] initial_phases: type of initialization of initial phases of oscillators. * * @return Returns pointer to sync oscillatory network. * */ extern "C" DECLARATION void * sync_create_network(const unsigned int size, const double weight_factor, const double frequency_factor, const unsigned int connection_type, const unsigned int initial_phases); /** * * @brief Returns size of the Sync oscillatory network that is defined by amount of oscillators. * * @param[in] pointer_network: pointer to the Sync network. * */ extern "C" DECLARATION std::size_t sync_get_size(const void * pointer_network); /** * * @brief Destroy sync_network (calls destructor). * * @param[in] pointer_network: pointer to the Sync network. * */ extern "C" DECLARATION void sync_destroy_network(const void * pointer_network); /** * * @brief Simulate dynamic of the oscillatory Sync network. * @details Caller should destroy returned instance using 'sync_dynamic_destroy' when * it is not required anymore. * * @param[in] pointer_network: pointer to the Sync network. * @param[in] steps: number steps of simulations during simulation. * @param[in] time: time of simulation. * @param[in] solver: type of solution (solving). * @param[in] collect_dynamic: if 'true' then returns whole dynamic of oscillatory network, * otherwise returns only last values of dynamics. * * @return Returns dynamic of simulation of the network. * */ extern "C" DECLARATION void * sync_simulate_static(const void * pointer_network, unsigned int steps, const double time, const unsigned int solver, const bool collect_dynamic); /** * * @brief Simulate dynamic of the oscillatory Sync network until stop condition is not reached. * * @param[in] pointer_network: pointer to the Sync network. * @param[in] order: order of process synchronization, destributed in (0..1). * @param[in] solver: type of solution (solving). * @param[in] collect_dynamic: if true - returns whole dynamic of oscillatory network, * otherwise returns only last values of dynamics. * @param[in] step: time step of one iteration of simulation. * @param[in] step_int: integration step, should be less than step. * @param[in] threshold_changes: additional stop condition that helps prevent infinite * simulation, defines limit of changes of oscillators between current and previous steps. * * @return Returns pointer to output dynamic of the network. * */ extern "C" DECLARATION void * sync_simulate_dynamic(const void * pointer_network, const double order, const unsigned int solver, const bool collect_dynamic, const double step, const double step_int, const double threshold_changes); /** * * @brief Returns level of global synchorization in the network. * * @param[in] pointer_network: pointer to the Sync network. * */ extern "C" DECLARATION double sync_order(const void * pointer_network); /** * * @brief Returns level of local (partial) synchronization in the network. * * @param[in] pointer_network: pointer to the Sync network. * */ extern "C" DECLARATION double sync_local_order(const void * pointer_network); /** * * @brief Returns connectivity matrix that defines connections between oscillators in the network. * * @param[in] pointer_network: pointer to the Sync network. * * @return Package where connectivity matrix is stored. * */ extern "C" DECLARATION pyclustering_package * sync_connectivity_matrix(const void * pointer_network); /** * * @brief Returns length of dynamic that is defined by amount of time-points of simulation process. * * @param[in] pointer_dynamic: pointer to the output dynamic. * */ extern "C" DECLARATION std::size_t sync_dynamic_get_size(const void * pointer_dynamic); /** * * @brief Destroy output dynamic of Sync algorithm. * * @param[in] pointer_dynamic: pointer to the output dynamic. * */ extern "C" DECLARATION void sync_dynamic_destroy(const void * pointer_dynamic); /** * * @brief Allocates ensembles (groups) of synchronous oscillators where each group consists of oscillator indexes. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] pointer_network: pointer to the output dynamic. * * @return Package where synchronous ensembles are stored. * */ extern "C" DECLARATION pyclustering_package * sync_dynamic_allocate_sync_ensembles(const void * pointer_dynamic, const double tolerance, const std::size_t iteration); /** * * @brief Allocate correlation matrix between oscillators at the specified step of simulation. * @details Caller should destroy returned result in 'pyclustering_package'. * * @param[in] pointer_network: pointer to the output dynamic. * @param[in] tolerance: maximum error for allocation of synchronous ensemble oscillators. * @param[in] iteration: iteration number of simulation that should be used for allocation. * * @return Package where matrix is stored. * */ extern "C" DECLARATION pyclustering_package * sync_dynamic_allocate_correlation_matrix(const void * pointer_dynamic, const std::size_t iteration); /** * * @brief Returns time points of simulation process that corresponds to phases. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] pointer_dynamic: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * sync_dynamic_get_time(const void * pointer_dynamic); /** * * @brief Returns phases of each oscillator during simulation process that corresponds to time points. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] pointer_dynamic: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * sync_dynamic_get_output(const void * pointer_dynamic); /** * * @brief Returns order parameter evolution for output dynamic in specified range. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_pointer: Pointer to output dynamic. * @param[in] p_start: Iteration from which evolution should be calculated. * @param[in] p_stop: Iteration where evolution calculation should be stopped. * * @return Package where evolution order parameter (estimation of global synchronization) is stored. * */ extern "C" DECLARATION pyclustering_package * sync_dynamic_calculate_order(const void * p_pointer, const std::size_t p_start, const std::size_t p_stop); /** * * @brief Returns local order parameter evolution for output dynamic in specified range. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] p_pointer_pointer: Pointer to output dynamic of the Sync network. * @param[in] p_network_pointer: Sync network connections that are used for calculation. * @param[in] p_start: Iteration from which evolution should be calculated. * @param[in] p_stop: Iteration where evolution calculation should be stopped. * * @return Package where evolution local order parameter (estimation of partial synchronization) is stored. * */ extern "C" DECLARATION pyclustering_package * sync_dynamic_calculate_local_order(const void * p_dynamic_pointer, const void * p_network_pointer, const std::size_t p_start, const std::size_t p_stop);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/syncnet_interface.h000077500000000000000000000047301375753423500275700ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Create oscillatory network SYNC for cluster analysis. * * @param[in] p_sample: input data for clustering. * @param[in] p_connectivity_radius: connectivity radius between points. * @param[in] p_enable_conn_weight: if True - enable mode when strength between oscillators depends on distance between two oscillators. Otherwise all connection between * oscillators have the same strength. * @param[in] p_initial_phases: type of initialization of initial phases of oscillators. * */ extern "C" DECLARATION void * syncnet_create_network(const pyclustering_package * const p_sample, const double p_connectivity_radius, const bool p_enable_conn_weight, const unsigned int p_initial_phases); /** * * @brief Destroy SyncNet (calls destructor). * * @param[in] p_pointer_network: pointer to the SyncNet network. * */ extern "C" DECLARATION void syncnet_destroy_network(const void * p_pointer_network); /** * * @brief Simulate oscillatory network SYNC until clustering problem is not resolved. * @details Allocated output dynamic analyser should be destroyed by called using 'syncnet_analyser_destroy'. * * @param[in] p_pointer_network: pointer to syncnet instance. * @param[in] p_order: order of synchronization that is used as indication for stopping processing. * @param[in] p_solver: specified type of solving diff. equation. * @param[in] p_collect_dynamic: specified requirement to collect whole dynamic of the network. * * @return Returns analyser of output dynamic. * */ extern "C" DECLARATION void * syncnet_process(const void * p_pointer_network, const double p_order, const unsigned int p_solver, const bool p_collect_dynamic); /** * * @brief Destroy syncnet output dynamic analyser instance. * * @param[in] p_pointer_analyser: pointer to syncnet output dynamic analyser. * */ extern "C" DECLARATION void syncnet_analyser_destroy(const void * p_pointer_analyser);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/syncpr_interface.h000077500000000000000000000144541375753423500274270ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Creates Sync-PR (Sync Pattern Recognition) oscillatory network. * @details Caller should destroy returned pointer to instance of the oscillatory network using function 'syncpr_destroy'. * * @param[in] num_osc: Number of oscillators in the network. * @param[in] increase_strength1: Parameter for increasing strength of the second term of the Fourier component. * @param[in] increase_strength2: Parameter for increasing strength of the third term of the Fourier component. * * @return Returns pointer to instance of created oscillatory network. * */ extern "C" DECLARATION void * syncpr_create(const unsigned int num_osc, const double increase_strength1, const double increase_strength2); /** * * @brief Deallocate oscillatory network. * * @param[in] pointer_network: Pointer to the instance of the Sync-PR oscillatory network. * */ extern "C" DECLARATION void syncpr_destroy(const void * pointer_network); /** * * @brief Returns size of oscillatory network that is defined by amount of oscillators. * * @param[in] pointer_network: Pointer to the instance of the Sync-PR oscillatory network. * */ extern "C" DECLARATION std::size_t syncpr_get_size(const void * pointer_network); /** * * @brief Trans oscillatory network using specified patterns. * * @param[in] pointer_network: Pointer to the instance of the Sync-PR oscillatory network. * @param[in] patterns: Pyclustering package pointer to patterns. * */ extern "C" DECLARATION void syncpr_train(const void * pointer_network, const void * const patterns); /** * * @brief Simulates oscillatory network during specified amount of steps - so-called static simulation. * * @param[in] pointer_network: Pointer to the instance of the Sync-PR oscillatory network. * @param[in] steps: Number steps of simulations during simulation. * @param[in] time: Time of simulation. * @param[in] pattern: Pyclustering package of pattern for recognition represented by list of features that are equal to [-1; 1]. * @param[in] solution: Type of solver that should be used for simulation. * @param[in] collect_dynamic: If true - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. * * @return Pointer to output dynamic. * */ extern "C" DECLARATION void * syncpr_simulate_static(const void * pointer_network, unsigned int steps, const double time, const void * const pattern, const unsigned int solver, const bool collect_dynamic); /** * * @brief Simulates oscillatory network until partial synchronization is reached that is defined by 'order'. * * @param[in] pointer_network: pointer to the instance of the Sync-PR oscillatory network. * @param[in] pattern: Pointer to pattern for recognition represented by list of features that are equal to [-1; 1]. * @param[in] order: Order of process synchronization, distributed 0..1. * @param[in] solver: Type of solution. * @param[in] collect_dynamic: If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. * @param[in] step: Time step of one iteration of simulation. * * @return Pointer to output dynamic. * */ extern "C" DECLARATION void * syncpr_simulate_dynamic(const void * pointer_network, const void * const pattern, const double order, const unsigned int solver, const bool collect_dynamic, const double step); /** * * @brief Calculates function of the memorized pattern. * * @param[in] pointer_network: Pointer to the instance of the Sync-PR oscillatory network. * @param[in] pattern: Pattern for recognition represented by list of features that are equal to [-1; 1]. * * @return Order of memory for the specified pattern. * */ extern "C" DECLARATION double syncpr_memory_order(const void * pointer_network, const void * const pattern); /** * * @brief Returns size of output SyncPR dynamic. * * @param[in] pointer_network: Pointer to the instance of the Sync-PR oscillatory network. * */ extern "C" DECLARATION std::size_t syncpr_dynamic_get_size(const void * pointer_network); /** * * @brief Deallocate output dynamic. * * @param[in] pointer_network: Pointer to output dynamic. * */ extern "C" DECLARATION void syncpr_dynamic_destroy(const void * pointer_dynamic); /** * * @brief Allocates synchronous ensembles of oscillators (groups). * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] pointer_network: Pointer to output dynamic. * @param[in] tolerance: Maximum error for allocation of synchronous ensemble oscillators. * */ extern "C" DECLARATION pyclustering_package * syncpr_dynamic_allocate_sync_ensembles(const void * pointer_dynamic, const double tolerance); /** * * @brief Returns time points of simulation process that corresponds to phases. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] pointer_network: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * syncpr_dynamic_get_time(const void * pointer_dynamic); /** * * @brief Returns phases of each oscillator during simulation process that corresponds to time points. * @details Returned package should deallocated by 'free_pyclustering_package'. * * @param[in] pointer_network: Pointer to output dynamic. * */ extern "C" DECLARATION pyclustering_package * syncpr_dynamic_get_output(const void * pointer_dynamic);pyclustering-0.10.1.2/ccore/include/pyclustering/interface/ttsas_interface.h000077500000000000000000000027131375753423500272420ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include /** * * @brief Clustering algorithm TTSAS returns allocated clusters. * @details Caller should destroy returned result that is in 'pyclustering_package'. * * @param[in] p_sample: input data for clustering. * @param[in] p_threshold1: dissimilarity level (distance) between point and its closest cluster, if the distance is less than 'threshold1' value then point is assigned to the cluster. * @param[in] p_threshold2: dissimilarity level (distance) between point and its closest cluster, if the distance is greater than 'threshold2' value then point is considered as a new cluster. * @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. * * @return Returns result of clustering - array of allocated clusters in pyclustering package. * */ extern "C" DECLARATION pyclustering_package * ttsas_algorithm(const pyclustering_package * const p_sample, const double p_threshold1, const double p_threshold2, const void * const p_metric); pyclustering-0.10.1.2/ccore/include/pyclustering/interface/xmeans_interface.h000077500000000000000000000054231375753423500274000ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include /*! @brief X-Means result is returned using pyclustering_package that consist sub-packages and this enumerator provides named indexes for sub-packages. */ enum xmeans_package_indexer { XMEANS_PACKAGE_INDEX_CLUSTERS = 0, XMEANS_PACKAGE_INDEX_CENTERS, XMEANS_PACKAGE_INDEX_WCE, XMEANS_PACKAGE_SIZE }; /*! @brief Clustering algorithm X-Means returns allocated clusters. @details Caller should destroy returned result in 'pyclustering_package'. @param[in] p_sample: input data for clustering. @param[in] p_centers: initial coordinates of centers of clusters. @param[in] p_kmax: maximum number of clusters that can be allocated. @param[in] p_tolerance: stop condition for local parameter improvement. @param[in] p_criterion: cluster splitting criterion. @param[in] p_alpha: alpha based probabilistic bound \f$\Q\left(\alpha\right)\f$ that is distributed from [0, 1] and that is used only in case MNDL splitting criteria. @param[in] p_beta: beta based probabilistic bound \f$\Q\left(\beta\right)\f$ that is distributed from [0, 1] and that is used only in case MNDL splitting criteria. @param[in] p_repeat: how many times K-Means should be run to improve parameters (by default is `1`), with larger 'repeat' values suggesting higher probability of finding global optimum. @param[in] p_random_state: seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). @param[in] p_metric: pointer to distance metric 'distance_metric' that is used for distance calculation between two points. @return Returns result of clustering - array of allocated clusters in the pyclustering package. */ extern "C" DECLARATION pyclustering_package * xmeans_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_centers, const std::size_t p_kmax, const double p_tolerance, const unsigned int p_criterion, const double p_alpha, const double p_beta, const std::size_t p_repeat, const long long p_random_state, const void * const p_metric); pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/000077500000000000000000000000001375753423500227115ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/dynamic_analyser.hpp000077500000000000000000000146401375753423500267540ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include using namespace pyclustering::container; namespace pyclustering { namespace nnet { class spike { public: using ptr = std::shared_ptr; private: std::size_t m_begin = 0; std::size_t m_duration = 0; std::size_t m_end = 0; public: spike() = default; spike(const std::size_t p_begin, const std::size_t p_end); spike(const spike & p_other) = default; spike(spike && p_other) = default; public: std::size_t get_start() const; std::size_t get_duration() const; std::size_t get_stop() const; bool compare(const spike & p_other, const double p_tolerance) const; }; class dynamic_analyser { private: using spike_collection = std::vector; private: const static std::size_t INVALID_ITERATION; const static std::size_t DEFAULT_AMOUNT_SPIKES; const static double DEFAULT_TOLERANCE; private: double m_threshold = -1; std::size_t m_spikes = DEFAULT_AMOUNT_SPIKES; double m_tolerance = DEFAULT_TOLERANCE; public: dynamic_analyser() = default; dynamic_analyser(const double p_threshold, const double p_tolerance = DEFAULT_TOLERANCE, const std::size_t p_spikes = DEFAULT_AMOUNT_SPIKES); template void allocate_sync_ensembles(const DynamicType & p_dynamic, EnsemblesType & p_ensembles, typename EnsemblesType::value_type & p_dead) const; private: template void extract_oscillations(const DynamicType & p_dynamic, std::vector & p_oscillations) const; template void extract_spikes(const DynamicType & p_dynamic, const std::size_t p_index, spike_collection & p_spikes) const; template void extract_ensembles(const std::vector & p_oscillations, EnsemblesType & p_ensembles, typename EnsemblesType::value_type & p_dead) const; template std::size_t find_spike_end(const DynamicType & p_dynamic, const std::size_t p_index, const std::size_t p_position) const; bool is_sync_spikes(const spike_collection & p_spikes1, const spike_collection & p_spikes2) const; }; template void dynamic_analyser::allocate_sync_ensembles(const DynamicType & p_dynamic, EnsemblesType & p_ensembles, typename EnsemblesType::value_type & p_dead) const { std::vector oscillations; extract_oscillations(p_dynamic, oscillations); extract_ensembles(oscillations, p_ensembles, p_dead); } template void dynamic_analyser::extract_oscillations(const DynamicType & p_dynamic, std::vector & p_oscillations) const { std::size_t amount_oscillators = p_dynamic[0].size(); p_oscillations = std::vector(amount_oscillators); /* extract marker spikes */ for (std::size_t index_neuron = 0; index_neuron < amount_oscillators; index_neuron++) { extract_spikes(p_dynamic, index_neuron, p_oscillations[index_neuron]); } } template void dynamic_analyser::extract_spikes(const DynamicType & p_dynamic, const std::size_t p_index, spike_collection & p_spikes) const { std::size_t position = p_dynamic.size() - 1; for (std::size_t cur_spike = 0; (cur_spike < m_spikes) && (position > 0); cur_spike++) { std::size_t stop = find_spike_end(p_dynamic, p_index, position); if (stop == INVALID_ITERATION) { return; } for (position = stop; (position > 0) && (p_dynamic[position][p_index] >= m_threshold); position--) { } if (p_dynamic[position][p_index] < m_threshold) { p_spikes.emplace_back(position, stop); } } } template std::size_t dynamic_analyser::find_spike_end(const DynamicType & p_dynamic, const std::size_t p_index, const std::size_t p_position) const { std::size_t time_stop_simulation = p_position; bool spike_fired = false; if (p_dynamic[time_stop_simulation][p_index] >= m_threshold) { spike_fired = true; } /* if active state is detected, it means we don't have whole oscillatory period for the considered oscillator, should be skipped */ if (spike_fired) { for (; (p_dynamic[time_stop_simulation][p_index] >= m_threshold) && (time_stop_simulation > 0); time_stop_simulation--) { } if (time_stop_simulation == 0) { return INVALID_ITERATION; } } for (; (p_dynamic[time_stop_simulation][p_index] < m_threshold) && (time_stop_simulation > 0); time_stop_simulation--) { } return (time_stop_simulation == 0) ? INVALID_ITERATION : time_stop_simulation; } template void dynamic_analyser::extract_ensembles(const std::vector & p_oscillations, EnsemblesType & p_ensembles, typename EnsemblesType::value_type & p_dead) const { if (p_oscillations.empty()) { return; } for (std::size_t index_neuron = 0; index_neuron < p_oscillations.size(); index_neuron++) { /* if oscillator does not have enough spikes than it's dead neuron */ if (p_oscillations[index_neuron].size() < m_spikes) { p_dead.push_back(index_neuron); continue; } if (p_ensembles.empty()) { p_ensembles.push_back({ index_neuron }); continue; } const spike_collection & neuron_spikes = p_oscillations[index_neuron]; bool ensemble_found = false; for (auto & ensemble : p_ensembles) { const std::size_t anchour_neuron_index = ensemble[0]; const spike_collection & ensemble_anchor_spikes = p_oscillations[anchour_neuron_index]; if (is_sync_spikes(neuron_spikes, ensemble_anchor_spikes)) { ensemble.push_back(index_neuron); ensemble_found = true; break; } } if (!ensemble_found) { p_ensembles.push_back({ index_neuron }); } } } } } pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/hhn.hpp000077500000000000000000000633541375753423500242150ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include #include using namespace pyclustering::differential; using namespace pyclustering::utils::random; namespace pyclustering { namespace nnet { /*! @class hnn_parameters hhn.hpp pyclustering/nnet/hhn.hpp @brief Defines parameters of Hodgkin-Hixley Oscillatory Network. */ struct hnn_parameters { public: double m_nu = generate_uniform_random(-1.0, 1.0); /**< Intrinsic noise. */ double m_gNa = 120.0 * (1.0 + 0.02 * m_nu); /**< Maximal conductivity for sodium current. */ double m_gK = 36.0 * (1.0 + 0.02 * m_nu); /**< Maximal conductivity for potassium current. */ double m_gL = 0.3 * (1.0 + 0.02 * m_nu); /**< Maximal conductivity for leakage current. */ double m_vNa = 50.0; /**< Reverse potential of sodium current [mV]. */ double m_vK = -77.0; /**< Reverse potential of potassium current [mV]. */ double m_vL = -54.4; /**< Reverse potantial of leakage current [mV]. */ double m_vRest = -65.0; /**< Rest potential [mV]. */ double m_Icn1 = 5.0; /**< External current [mV] for central element 1. */ double m_Icn2 = 30.0; /**< External current [mV] for central element 2. */ double m_Vsyninh = -80.0; /**< Synaptic reversal potential [mV] for inhibitory effects. */ double m_Vsynexc = 0.0; /**< Synaptic reversal potential [mV] for exciting effects. */ double m_alfa_inhibitory = 6.0; /**< Alfa-parameter for alfa-function for inhibitory effect. */ double m_betta_inhibitory = 0.3; /**< Betta-parameter for alfa-function for inhibitory effect. */ double m_alfa_excitatory = 40.0; /**< Alfa-parameter for alfa-function for excitatoty effect. */ double m_betta_excitatory = 2.0; /**< Betta-parameter for alfa-function for excitatoty effect. */ double m_w1 = 0.1; /**< Strength of the synaptic connection from PN to CN1. */ double m_w2 = 9.0; /**< Strength of the synaptic connection from CN1 to PN. */ double m_w3 = 5.0; /**< Strength of the synaptic connection from CN2 to PN. */ double m_deltah = 650.0; /**< Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN. */ double m_threshold = -10; /**< Threshold of the membrane potential that should exceeded by oscillator to be considered as an active. */ double m_eps = 0.16; /**< Devider of pulse threshold counter `1.0 / eps`. */ }; /*! @class basic_neuron_state hhn.hpp pyclustering/nnet/hhn.hpp @brief Basic state (applicable for central and peripheral oscillators) of a neuron in Hodgkin-Hixley Oscillatory Network. */ struct basic_neuron_state { public: double m_membrane_potential = 0.0; /**< Membrane potential of cenral neuron (V). */ double m_active_cond_sodium = 0.0; /**< Activation conductance of the sodium channel (m). */ double m_inactive_cond_sodium = 0.0; /**< Inactivaton conductance of the sodium channel (h). */ double m_active_cond_potassium = 0.0; /**< Activaton conductance of the sodium channel (h). */ bool m_pulse_generation = false; /**< Spike generation of central neuron. */ std::vector m_pulse_generation_time = { }; /**< Timestamps of generated pulses. */ double m_Iext = 0.0; /**< External current [mV] for neuron. */ }; /*! @class central_element hhn.hpp pyclustering/nnet/hhn.hpp @brief Defines a state of the central neuron that is based on Hodgkin-Huxley model. */ struct central_element : public basic_neuron_state { }; /*! @class hhn_oscillator hhn.hpp pyclustering/nnet/hhn.hpp @brief Defines a state of the peripheral neuron that is based on Hodgkin-Huxley model. */ struct hhn_oscillator : public basic_neuron_state { double m_link_activation_time = 0.0; /**< The onset time of plasticity. */ double m_link_pulse_counter = 0.0; /**< The iteration counter of the spike duration. */ double m_link_weight3 = 0.0; /**< The modifiable GABAergic connection strength from Central Neuron 2 to the i-th peripheral neuron, representing the short-term plasticity. */ }; /*! @class hhn_dynamic hhn.hpp pyclustering/nnet/hhn.hpp @brief Output dynamic of the oscillatory network based on HHN. @details The output dynamic is a container that stores state of each neuron in the network on each simulation step. */ class hhn_dynamic { public: /*! @brief Defines what kind of information can be collected and stored by the dynamic. */ enum class collect { MEMBRANE_POTENTIAL, /**< Neuron's membrane potential. */ ACTIVE_COND_SODIUM, /**< Activation conductance of the sodium channel. */ INACTIVE_COND_SODIUM, /**< Inactivaton conductance of the sodium channel. */ ACTIVE_COND_POTASSIUM, /**< Activaton conductance of the sodium channel. */ }; /*! @brief Defines hash calculation for `hhn_dynamic::collect` type. @see hhn_dynamic::collect */ struct collect_hash { /*! @brief Calculates hash of the output dynamic component (membrane potential, conductance of the sodium channel, etc.). @param[in] t: output dynamic component value for that hash should be calculated. @returns Hash value of the output dynamic component. */ std::size_t operator()(hhn_dynamic::collect t) const { return static_cast(t); } }; public: /*! @brief Defines shared pointer to the output dynamic of the HHN. */ using ptr = std::shared_ptr; /*! @brief Defines container to store specific state of each neuron of the HHN. */ using value_dynamic = std::vector; /*! @brief Defines shared pointer to the container to store state of each neuron of the HHN. */ using value_dynamic_ptr = std::shared_ptr; /*! @brief Defines containers to store simulation process where specific state of each neuron on each iteration is stored. */ using evolution_dynamic = std::vector; /*! @brief Filter that defines what kind of states should be collected (membrane potential, conductance of the sodium channel, etc.). */ using network_collector = std::unordered_map; /*! @brief Defines container to store the evolution of neurons per state type. @details The container is represented by a associative container where the key is a state that is collected and the value is a evolution of neurons that corresponds to the state. */ using network_dynamic = std::unordered_map; /*! @brief Defines shared pointer to the network dynamic - container to store the evolution of neurons per state type. */ using network_dynamic_ptr = std::shared_ptr; private: network_collector m_enable = { { collect::MEMBRANE_POTENTIAL, true }, { collect::ACTIVE_COND_SODIUM, false }, { collect::INACTIVE_COND_SODIUM, false }, { collect::ACTIVE_COND_POTASSIUM, false } }; std::size_t m_amount_collections = 1; std::size_t m_size_dynamic = 0; std::size_t m_size_network = 0; network_dynamic_ptr m_peripheral_dynamic = std::make_shared(); network_dynamic_ptr m_central_dynamic = std::make_shared(); value_dynamic_ptr m_time = std::make_shared(); public: /*! @brief Default constructor of the output dynamic of the HHN. */ hhn_dynamic(); /*! @brief Default destructor of the output dynamic of the HHN. */ ~hhn_dynamic() = default; public: /*! @brief Returns amount of stored simulation steps (iterations). @return Amount of stored simulation steps (iterations). */ std::size_t size_dynamic() const; /*! @brief Returns amount of neurons in the network whose output dynamic was stored in the current output dynamic object. @return Amount of neurons in the HHN network. */ std::size_t size_network() const; /*! @brief Enable collecting of the specific output dynamic component for each neuron (membrane potential, conductance of the sodium channel, etc.). @param[in] p_state: output dynamic component that should be collected for each neuron. */ void enable(const hhn_dynamic::collect p_state); /*! @brief Enable collecting of a set of output dynamic components for each neuron (membrane potential, conductance of the sodium channel, etc.). @param[in] p_types: iterable container that contains output dynamic components that should be collected for each neuron. */ template void enable(const ContainerType & p_types); /*! @brief Enable collecting of all possible output dynamic components for each neuron (membrane potential, conductance of the sodium channel, etc.). */ void enable_all(); /*! @brief Disable collecting of the specific output dynamic component for each neuron (membrane potential, conductance of the sodium channel, etc.). @param[in] p_state: output dynamic component that should not be collected for each neuron. */ void disable(const hhn_dynamic::collect p_state); /*! @brief Disable collecting of a set of output dynamic components for each neuron (membrane potential, conductance of the sodium channel, etc.). @param[in] p_types: iterable container that contains output dynamic components that should not be collected for each neuron. */ template void disable(const ContainerType & p_types); /*! @brief Disable collecting of all possible output dynamic components for each neuron (membrane potential, conductance of the sodium channel, etc.). */ void disable_all(); /*! @brief Returns collecting neuron states (membrane potential, conductance of the sodium channel, etc.). @param[out] p_enabled: a container where collecting states are going to be placed. */ void get_enabled(std::set & p_enabled) const; /*! @brief Returns neurons states that are not collected (membrane potential, conductance of the sodium channel, etc.). @param[out] p_disabled: a container where non-collecting states are going to be placed. */ void get_disabled(std::set & p_disabled) const; /*! @brief Stores current state of the oscillatory network that is defined by timestamp, peripheral and central neurons. @param[in] p_time: current simulation time. @param[in] p_peripheral: container with states of peripheral neurons. @param[in] p_central: container with states of central neurons. */ void store(const double p_time, const std::vector & p_peripheral, const std::vector & p_central); /*! @brief Reserves memory for the evolution that is defined by amount of iterations for simulation. @param[in] p_dynamic_size: size of the dynamic evolution. */ void reserve(const std::size_t p_dynamic_size); /*! @brief Returns dynamic of peripheral neurons for the specified state (membrane potential, conductance of the sodium channel, etc.). @param[in] p_type: state of neuron for which evolution is required. @return Dynamic of peripheral neurons for the specified state. */ evolution_dynamic & get_peripheral_dynamic(const hhn_dynamic::collect & p_type); /*! @brief Returns full dynamic of peripheral neurons. @return Full dynamic of peripheral neurons. */ network_dynamic_ptr get_peripheral_dynamic() const; /*! @brief Returns full dynamic of central neurons. @returns Full dynamic of central neurons. */ network_dynamic_ptr get_central_dynamic() const; /*! @brief Returns all timestamps of simulation process of the oscillatory network. @return All timestamps of simulation process of the oscillatory network. */ value_dynamic_ptr get_time() const; /*! @brief Returns dynamic of central neurons for the specified state (membrane potential, conductance of the sodium channel, etc.). @param[in] p_type: neuron state for which evolution is required. @return Dynamic of central neurons for the specified state. */ evolution_dynamic & get_central_dynamic(const hhn_dynamic::collect & p_type); /*! @brief Returns state value for specific peripheral neuron on specified iteration. @param[in] p_iteration: iteration of simulation process of the oscillatory network. @param[in] p_index: neuron index in the oscillatory network. @param[in] p_type: neuron state value type (membrane potential, conductance of the sodium channel, etc.). @return State value for specific peripheral neuron on specified iteration. */ double get_peripheral_value(const std::size_t p_iteration, const std::size_t p_index, const hhn_dynamic::collect p_type) const; /*! @brief Returns state value for specific central neuron on specified iteration. @details The oscillatory network always has only two central neurons that forms central unit. Thus there are two possible indexes could be: 0 and 1. @param[in] p_iteration: iteration of simulation process of the oscillatory network. @param[in] p_index: neuron index in the oscillatory network. @param[in] p_type: neuron state value type (membrane potential, conductance of the sodium channel, etc.). @return State value for specific central neuron on specified iteration. */ double get_central_value(const std::size_t p_iteration, const std::size_t p_index, const hhn_dynamic::collect p_type) const; private: void get_collected_types(const bool p_enabled, std::set & p_types) const; void reserve_collection(const hhn_dynamic::collect p_state, const std::size_t p_size); void store_membrane_potential(const std::vector & p_peripheral, const std::vector & p_central); void store_active_cond_sodium(const std::vector & p_peripheral, const std::vector & p_central); void store_inactive_cond_sodium(const std::vector & p_peripheral, const std::vector & p_central); void store_active_cond_potassium(const std::vector & p_peripheral, const std::vector & p_central); static void reserve_dynamic_collection(const hhn_dynamic::collect p_state, const std::size_t p_size, network_dynamic & p_dynamic); static void initialize_collection(network_dynamic & p_dynamic); public: /*! @brief Comparison operator `==` to compare output dynamics. @param[in] p_other: another output dynamic that should be compared with current. @return `true` if output dynamic objects are equal, otherwise `false`. */ bool operator==(const hhn_dynamic & p_other) const; /*! @brief Writes to an output stream output dynamic of the oscillatory network. @param[in] p_stream: output stream for writing. @param[in] p_dynamic: output dynamic of the network that should be written. */ friend std::ostream& operator<<(std::ostream & p_stream, const hhn_dynamic & p_dynamic); }; template void hhn_dynamic::enable(const ContainerType & p_types) { for (auto & type : p_types) { enable(type); } } template void hhn_dynamic::disable(const ContainerType & p_types) { for (auto & type : p_types) { disable(type); } } /*! @class hhn_dynamic_reader hhn.hpp pyclustering/nnet/hhn.hpp @brief Reader of the output dynamic of the oscillatory network based on Hodgkin-Huxley neurons. @details The dynamic reader reads the output dynamic from a text file with the specific format. */ class hhn_dynamic_reader { private: std::string m_filename; hhn_dynamic * m_dynamic = nullptr; std::ifstream m_file_stream; std::vector m_order = { }; std::size_t m_size_network = 0; public: /*! @brief Default constructor of the dynamic reader of HHN. */ hhn_dynamic_reader() = default; /*! @brief Constructor of the dynamic reader of HHN where path to a file where output dynamic of the network is stored. */ explicit hhn_dynamic_reader(const std::string & p_filename); /*! @brief Default destructor of the dynamic reader of HHN. */ ~hhn_dynamic_reader(); public: /*! @brief Reads output dynamic of the network to the specified output dynamic container. @param[in] p_dynamic: output dynamic container to which output dynamic from the file should be placed. */ void read(hhn_dynamic & p_dynamic); private: void parse_size_header(); void parse_enable_header(); void parse_dynamic(); void extract_dynamic(const std::string & p_line, double & p_time, std::vector & p_peripheral, std::vector & p_central); void extract_state(std::istringstream & p_stream, basic_neuron_state & p_state) const; static void extract_size_header(const std::string & p_line, std::size_t & p_size_dynamic, std::size_t & p_size_network); static void extract_enable_header(const std::string & p_line, std::vector & p_collect); }; /*! @brief Defines external input (stimulus) to the oscillatory network. @details External input type is represented by a container with a random access to its elements. */ using hhn_stimulus = std::vector; /*! @class hhn_network hhn.hpp pyclustering/nnet/hhn.hpp @brief The two-layer oscillatory network that is based on Hodgkin-Huxley neurons. @details The oscillatory network consists of two types of neurons: peripheral neurons and central neurons. Peripheral neurons represent feature detectors in the primary areas of the neocortex that are activated by external stimuli. It assumed that the external input to peripheral neurons is sufficiently large to cause their firing at some particular frequency. Considering image segmentation problem and visual attention modelling, the peripheral neurons are located on another grid of the same size as the an image, with each peripheral neuron receiving a signal from the pixel whose location on the grid is identical to the location of the peripheral neuron. The oscillatory network has two central neurons that forms so-called the central unit. The central unit is an extremely simplified version of the central executive. The 1st central neuron enables attention to be focused on a selected subset of peripheral neurons. The 2nd central neuron controls the shift of attention from one stimulus to another. The architecture of the oscillatory network is presented on figure 1. @image html hhn_architecture.png "Fig. 1. The architecture of the oscillatory network based on Hodgkin-Huxley neurons." The Implementation is based on paper @cite article::nnet::hnn::1. */ class hhn_network { private: enum: std::size_t { POSITION_MEMBRAN_POTENTIAL = 0, POSITION_ACTIVE_COND_SODIUM, POSITION_INACTIVE_COND_SODIUM, POSITION_ACTIVE_COND_POTASSIUM, POSITION_AMOUNT }; private: using hhn_state = differ_result; using hhn_states = std::vector< hhn_state >; private: std::vector m_peripheral = { }; std::vector m_central = { }; hhn_stimulus * m_stimulus = nullptr; hnn_parameters m_params; public: /*! @brief Default constructor of the oscillatory network based on Hodgkin-Huxley network. */ hhn_network() = default; /*! @brief Constructor of the oscillatory network based on Hodgkin-Huxley network that creates the network with specified size and parameters. @param[in] p_size: amount of neurons in the oscillatory network. @param[in] p_parameters: parameters of the oscillatory network that defines its behaviour. */ hhn_network(const std::size_t p_size, const hnn_parameters & p_parameters); /*! @brief Default destructor of the oscillatory network based on Hodgkin-Huxley network. */ ~hhn_network() = default; public: /*! @brief Runs oscillatory network simulation for the specific time with specified external inputs. @param[in] p_steps: number steps of simulations during simulation. @param[in] p_time: time of simulation. @param[in] p_solver: type of the solver for the simulation. @param[in] p_stimulus: external inputs (stimulus) to the network. @param[in] p_output_dynamic: output dynamic of the network. @return Amount of neurons that are in the oscillatory network. */ void simulate(const std::size_t p_steps, const double p_time, const solve_type p_solver, const hhn_stimulus & p_stimulus, hhn_dynamic & p_output_dynamic); /*! @brief Returns size of the oscillatory network. @details Size of the network is defined by amount of neurons (oscillators) in it. @return Amount of neurons that are in the oscillatory network. */ std::size_t size() const; private: void store_dynamic(const double p_time, hhn_dynamic & p_dynamic); void calculate_states(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step); void calculate_peripheral_states(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step, hhn_states & p_next_states); void calculate_central_states(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step, hhn_states & p_next_states); void perform_calculation(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step, const differ_state & p_inputs, const differ_extra<> & p_extra, hhn_state & p_next_states); void neuron_states(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const; double peripheral_external_current(const std::size_t p_index) const; double peripheral_synaptic_current(const std::size_t p_index, const double p_time, const double p_membrane) const; double central_first_synaptic_current(const double p_time, const double p_membrane) const; void initialize_current(); void update_peripheral_current(); void assign_neuron_states(const double p_time, const double p_step, const hhn_states & p_next_peripheral, const hhn_states & p_next_central); static double alpha_function(const double p_time, const double p_alfa, const double p_betta); template static void pack_equation_input(const NeuronType & p_neuron, differ_state & p_inputs); template static void unpack_equation_output(const hhn_state & p_outputs, NeuronType & p_neuron); }; template void hhn_network::pack_equation_input(const NeuronType & p_neuron, differ_state & p_inputs) { p_inputs.resize(POSITION_AMOUNT); p_inputs[POSITION_MEMBRAN_POTENTIAL] = p_neuron.m_membrane_potential; p_inputs[POSITION_ACTIVE_COND_SODIUM] = p_neuron.m_active_cond_sodium; p_inputs[POSITION_INACTIVE_COND_SODIUM] = p_neuron.m_inactive_cond_sodium; p_inputs[POSITION_ACTIVE_COND_POTASSIUM] = p_neuron.m_active_cond_potassium; } template void hhn_network::unpack_equation_output(const hhn_state & p_outputs, NeuronType & p_neuron) { p_neuron.m_membrane_potential = p_outputs[0].state[POSITION_MEMBRAN_POTENTIAL]; p_neuron.m_active_cond_sodium = p_outputs[0].state[POSITION_ACTIVE_COND_SODIUM]; p_neuron.m_inactive_cond_sodium = p_outputs[0].state[POSITION_INACTIVE_COND_SODIUM]; p_neuron.m_active_cond_potassium = p_outputs[0].state[POSITION_ACTIVE_COND_POTASSIUM]; } } } pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/legion.hpp000077500000000000000000000111111375753423500246750ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include #include #include #include using namespace pyclustering::container; using namespace pyclustering::differential; namespace pyclustering { namespace nnet { typedef std::vector legion_ensemble; typedef std::vector legion_stimulus; struct legion_network_state { public: std::vector m_output; double m_inhibitor = 0.0; double m_time = 0.0; public: legion_network_state() = default; explicit legion_network_state(const std::size_t size) : m_output(size, 0.0), m_inhibitor(0.0), m_time(0.0) { } public: std::size_t size() const; }; class legion_dynamic : public dynamic_data { public: legion_dynamic() { } virtual ~legion_dynamic() { } }; struct legion_parameters { double eps = 0.02; double alpha = 0.005; double gamma = 6.0; double betta = 0.1; double lamda = 0.1; double teta = 0.9; double teta_x = -1.5; double teta_p = 1.5; double teta_xz = 0.1; double teta_zx = 0.1; double T = 2.0; double mu = 0.01; double Wz = 1.5; double Wt = 8.0; double fi = 3.0; double ro = 0.02; double I = 0.2; bool ENABLE_POTENTIAL = true; }; struct legion_oscillator { double m_excitatory; double m_inhibitory; double m_potential; double m_coupling_term; double m_buffer_coupling_term; double m_noise; legion_oscillator() : m_excitatory(0.0), m_inhibitory(0.0), m_potential(0.0), m_coupling_term(0.0), m_buffer_coupling_term(0.0), m_noise(0.0) { } }; class legion_network { private: std::vector m_oscillators; double m_global_inhibitor = 0.0; legion_parameters m_params; std::shared_ptr m_static_connections; std::vector > m_dynamic_connections; legion_stimulus * m_stimulus = nullptr; /* just keep it during simulation for convinience (pointer to external object, legion is not owner) */ std::random_device m_device; std::default_random_engine m_generator; std::uniform_real_distribution m_noise_distribution; private: const static size_t MAXIMUM_MATRIX_REPRESENTATION_SIZE; public: legion_network() = default; legion_network(const size_t num_osc, const connection_t connection_type, const legion_parameters & params); legion_network(const size_t num_osc, const connection_t connection_type, const size_t height, const size_t width, const legion_parameters & params); virtual ~legion_network(); public: void simulate(const unsigned int steps, const double time, const solve_type solver, const bool collect_dynamic, const legion_stimulus & stimulus, legion_dynamic & output_dynamic); inline size_t size() const { return m_oscillators.size(); } private: void create_dynamic_connections(const legion_stimulus & stimulus); void calculate_states(const legion_stimulus & stimulus, const solve_type solver, const double t, const double step, const double int_step); void inhibitor_state(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const; void neuron_states(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs); void neuron_simplify_states(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs); void store_dynamic(const double time, const bool collect_dynamic, legion_dynamic & dynamic) const; void initialize(const size_t num_osc, const connection_t connection_type, const size_t height, const size_t width, const legion_parameters & params); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/network.hpp000077500000000000000000000003531375753423500251170ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once namespace pyclustering { namespace nnet { enum class initial_type { RANDOM_GAUSSIAN, EQUIPARTITION, }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/pcnn.hpp000077500000000000000000000067031375753423500243710ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include using namespace pyclustering::container; namespace pyclustering { namespace nnet { #define OUTPUT_ACTIVE_STATE (double) 1.0 #define OUTPUT_INACTIVE_STATE (double) 0.0 struct pcnn_oscillator { double output; double feeding; double linking; double threshold; pcnn_oscillator() : output(0.0), feeding(0.0), linking(0.0), threshold(0.0) { } }; struct pcnn_parameters { double VF = 1.0; double VL = 1.0; double VT = 10.0; double AF = 0.1; double AL = 0.1; double AT = 0.5; double W = 1.0; double M = 1.0; double B = 0.1; bool FAST_LINKING = false; }; using pcnn_ensemble = std::vector; using pcnn_stimulus = std::vector; using pcnn_time_signal = std::vector; struct pcnn_network_state { public: std::vector m_output; double m_time; public: std::size_t size() const; }; class pcnn_dynamic : public dynamic_data { public: pcnn_dynamic(); ~pcnn_dynamic(); public: void allocate_sync_ensembles(ensemble_data & sync_ensembles) const; void allocate_spike_ensembles(ensemble_data & spike_ensembles) const; void allocate_time_signal(pcnn_time_signal & time_signal) const; public: /** * * @brief Returns dynamic state of oscillator of the pulse-coupled neural network at the * specified iteration step. * * @param[in] iteration: number of iteration at which oscillator state is required. * @param[in] index_oscillator: index of oscillator whose state is required. * * @return dynamic state of the oscillator at the specified iteration. * */ inline double dynamic_oscillator_at(const size_t iteration, const size_t index_oscillator) const { return at(iteration).m_output[index_oscillator]; } }; class pcnn { protected: std::vector m_oscillators; std::shared_ptr m_connection; pcnn_parameters m_params; private: const static size_t MAXIMUM_MATRIX_REPRESENTATION_SIZE; public: pcnn(); pcnn(const size_t p_size, const connection_t p_structure, const pcnn_parameters & p_parameters); pcnn(const size_t p_size, const connection_t p_structure, const size_t p_height, const size_t p_width, const pcnn_parameters & p_parameters); virtual ~pcnn() = default; public: void simulate(const std::size_t steps, const pcnn_stimulus & stimulus, pcnn_dynamic & output_dynamic); inline size_t size() const { return m_oscillators.size(); } private: void initilize(const size_t p_size, const connection_t p_structure, const size_t p_height, const size_t p_width, const pcnn_parameters & p_parameters); void calculate_states(const pcnn_stimulus & stimulus); void store_dynamic(const std::size_t step, pcnn_dynamic & dynamic) const; void fast_linking(const std::vector & feeding, std::vector & linking, std::vector & output); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/som.hpp000077500000000000000000000262221375753423500242270ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace nnet { /*! @class som_conn_type som.hpp pyclustering/nnet/som.hpp @brief Connection structures that can be established between neurons in self-organized feature map. */ enum class som_conn_type { /*!< Each node is connected with four neighbors: left, upper, right and lower. */ SOM_GRID_FOUR = 0, /*!< Grid type of connections when each oscillator has connections with left, upper-left, upper, upper-right, right, right-lower, lower, lower-left neighbors. */ SOM_GRID_EIGHT = 1, /*!< Grid type of connections when each oscillator has connections with left, upper-left, upper-right, right, right-lower, lower-left neighbors. */ SOM_HONEYCOMB = 2, /*!< Grid type of connections when existance of each connection is defined by the SOM rule on each step of simulation. */ SOM_FUNC_NEIGHBOR = 3 }; /** * * @brief Types of inititalization of weights in self-organized feature map. * */ enum class som_init_type { /*!< Weights are randomly distributed using Gaussian distribution (0, 1). */ SOM_RANDOM = 0, /*!< Weights are randomly distributed using Gaussian distribution (input data centroid, 1). */ SOM_RANDOM_CENTROID = 1, /*!< Weights are randomly distrbiuted using Gaussian distribution (input data centroid, surface of input data). */ SOM_RANDOM_SURFACE = 2, /*!< Weights are distributed as a uniform grid that covers whole surface of the input data. */ SOM_UNIFORM_GRID = 3 }; /*! @class som_parameters som.hpp pyclustering/nnet/som.hpp @brief Parameters of self-organized feature map. */ struct som_parameters { som_init_type init_type = som_init_type::SOM_UNIFORM_GRID; /**< Defines an initialization way for neuron weights (random, random in center of the input data, random distributed in data, ditributed in line with uniform grid). */ double init_radius = 0.0; /**< Initial radius. If the initial radius is not specified (equals to `0.0`) then it will be calculated by SOM. */ double init_learn_rate = 0.1; /**< Rate of learning. */ double adaptation_threshold = 0.01; /**< Condition that defines when the learining process should be stopped. It is used when the autostop mode is on. */ long long random_state = RANDOM_STATE_CURRENT_TIME; /**< Seed for random state (by default is `RANDOM_STATE_CURRENT_TIME`, current system time is used). */ public: /*! @brief Default constructor of SOM parameters. */ som_parameters() = default; /*! @brief Default move constructor of SOM parameters. */ som_parameters(som_parameters && p_other) = default; /*! @brief Default copy constructor of SOM parameters. */ som_parameters(const som_parameters & p_other) = default; /*! @brief Default destructor of SOM parameters. */ ~som_parameters() = default; public: /*! @brief Set parameters by copy it from another object. @param[in] p_other: another SOM parameters. */ som_parameters & operator=(const som_parameters & p_other); }; using som_award_sequence = std::vector; using som_gain_sequence = std::vector >; using som_neighbor_sequence = std::vector >; /*! @class som som.hpp pyclustering/nnet/som.hpp @brief Self-Orzanized Feature Map based on Kohonen desription of SOM. */ class som { private: /* network description */ std::size_t m_rows; std::size_t m_cols; std::size_t m_size; som_conn_type m_conn_type; dataset m_weights; dataset m_previous_weights; som_award_sequence m_awards; /* store pointer to training data for convinience */ const dataset * m_data = nullptr; /* just for convenience (avoid excess calculation during learning) */ dataset m_location; dataset m_sqrt_distances; som_gain_sequence m_capture_objects; som_neighbor_sequence m_neighbors; /* describe learning process and internal state */ std::size_t m_epouchs = 0; som_parameters m_params; /* dynamic changes learning parameters */ double m_local_radius = 0.0; double m_learn_rate = 0.0; public: /** * * @brief Constructor of self-organized map. * * @param[in] num_rows: number of neurons in the column (number of rows). * @param[in] num_cols: number of neurons in the row (number of columns). * @param[in] type_conn: type of connection between oscillators in the network. * @param[in] parameters: others parameters of the network. * */ som(const std::size_t num_rows, const std::size_t num_cols, const som_conn_type type_conn, const som_parameters & parameters); /** * * @brief Copy constructor. * * @param[in] p_other: self-organized map that should be copied. * */ som(const som & p_other); /** * * @brief Default destructor. * */ ~som(); public: /** * * @brief Trains self-organized feature map (SOM). * * @param[in] input_data: input dataset for training. * @param[in] num_epochs: number of epochs for training. * @param[in] autostop: stop learining when convergance is too low. * * @return Returns number of learining iterations. * */ std::size_t train(const dataset & input_data, const size_t num_epochs, bool autostop); /** * * @brief Initialize SOM network by loading weights. * @details This method is provided service to load trained network parameters to avoid network training that may take * a lot of time. * * @param[in] p_weights: neuron weights. * @param[in] p_awards: amount of captured objects by each neuron during training (can be empty if it is not required). * @param[in] p_capture_objects: captured objects by each neuron during training (can be empty if it is not required). * * @return Returns number of learining iterations. * */ void load(const dataset & p_weights, const som_award_sequence & p_awards, const som_gain_sequence & p_capture_objects); /** * * @brief Processes input pattern (no learining) and returns index of neuron-winner. * @details Using index of neuron winner catched object can be obtained by get_capture_objects(). * * @param[in] input_pattern: input pattern for processing. * * @return Returns index of neuron-winner. * */ std::size_t simulate(const pattern & input_pattern) const; /** * * @return Returns number of winner at the last step of learning process. * */ std::size_t get_winner_number() const; /** * * @return Returns size of self-organized map (number of neurons). * */ inline size_t get_size() const { return m_size; } /** * * @return Constant reference to neurons weights for read-only purposes. * */ inline const dataset & get_weights() const { return m_weights; } /** * * @return Constant reference to sequence of captured objects by each neuron during training for read-only purposes. * */ inline const som_gain_sequence & get_capture_objects() const { return m_capture_objects; } /** * * @return Constant reference to neighbors of each neuron for read-only purposes. * */ inline const som_neighbor_sequence & get_neighbors() const { return m_neighbors; } /** * * @return Constant reference to amount of captured objects by each neuron during training for read-only purposes. * */ inline const som_award_sequence & get_awards() const { return m_awards; } /** * * @return Reference to amount of captured objects by each neuron during training. * */ inline som_award_sequence & get_awards() { return m_awards; } private: /** * * @brief Create connections in line with input rule (grid four, grid eight, honeycomb, * function neighbour). * * @param[in] type: type of connection between oscillators in the network. * */ void create_connections(const som_conn_type type); /** * * @brief Creates initial weights for neurons in line with the specified initialization. * * @param[in] type: type of initialization of initial neuron weights (random, * random in center of the input data, random distributed in * data, ditributed in line with uniform grid). * */ void create_initial_weights(const som_init_type type); /** * * @brief Returns neuron winner (distance, neuron index). * * @param[in] input_pattern: input pattern from the input data set, for example it can be * coordinates of point. * * @return Returns index of neuron that is winner. * */ std::size_t competition(const pattern & input_pattern) const; /** * * @brief Change weight of neurons in line with won neuron. * * @param[in] index_winner: index of neuron-winner. * @param[in] input_pattern: input pattern from the input data set. * */ std::size_t adaptation(const size_t index_winner, const pattern & input_pattern); /** * * @brief Returns maximum changes of weight in line with comparison between previous weights * and current weights. * * @return Returns value that represents maximum changes of weight after adaptation process. * */ double calculate_maximal_adaptation() const; /** * * @brief Calculates appropriate initial radius. * * @param[in] p_rows: amount of rows in the map. * @param[in] p_cals: amount of columns in the map. * * @return Initial radius. * */ static double calculate_init_radius(const size_t p_rows, const size_t p_cols); public: /** * * @brief Store network to stream. * * @param[in] p_stream: stream that is used to store network. * @param[in] p_network: SOM network that is stored to the stream 'p_stream'. * * @return Stream where network is stored. * */ friend std::ostream & operator<<(std::ostream & p_stream, const som & p_network); /** * * @brief Overloaded assignment operator to make deep copy of SOM. * * @param[in] p_other: another instance of SOM. * * @return Reference to updated SOM instance. * */ som & operator=(const som & p_other); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/sync.hpp000077500000000000000000000557301375753423500244130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include #include #include #include using namespace pyclustering::container; using namespace pyclustering::differential; namespace pyclustering { namespace nnet { /*! @class sync_oscillator sync.hpp pyclustering/nnet/sync.hpp @brief Describes an oscillator state in Sync oscillatory network. */ struct sync_oscillator { double phase = 0.0; /**< Phase of the current oscillator in range (0, 2*pi). */ double frequency = 0.0; /**< Frequeney of the current oscillator. */ }; using sync_ensemble = std::vector; using sync_corr_row = std::vector; using sync_corr_matrix = std::vector; /** * * @class sync_network_state sync.hpp pyclustering/nnet/sync.hpp * * @brief Oscillatory network state where oscillator phases and corresponding time-point are stored. * */ struct sync_network_state { public: std::vector m_phase = { }; /**< Container where phase of each oscillator is stored in time `m_time`. */ double m_time = 0.0; /**< Time point when oscillator phases were stored. */ public: /*! @brief Default constructor of the oscillatory network state. */ sync_network_state() = default; /*! @brief Default copy constructor of the oscillatory network state. @param[in] p_other: another network state that should be copied to the current. */ sync_network_state(const sync_network_state & p_other) = default; /*! @brief Default move constructor of the oscillatory network state. @param[in] p_other: another network state that should be moved to the current. */ sync_network_state(sync_network_state && p_other) = default; /*! @brief Constructor of the oscillatory network state. @param[in] size: creates the network state for the network with size `size`. */ explicit sync_network_state(const std::size_t size) : m_phase(size, 0.0), m_time(0.0) { } /*! @brief Constructor of the oscillatory network state. @param[in] time: time point when the network state were stored. @param[in] phases: oscillator phases that defined the network state in time `time`. */ sync_network_state(const double time, const std::vector & phases) : m_phase(phases), m_time(time) { } /*! @brief Constructor of the oscillatory network state. @param[in] time: time point when the network state were stored. @param[in] initializer: oscillator phases that defined the network state in time `time`. */ sync_network_state(const double time, const std::initializer_list & initializer) : m_phase(initializer), m_time(time) { } public: /*! @brief Returns amount of oscillators in the current state. @return Amount of oscillators in the current state. */ inline std::size_t size() const { return m_phase.size(); } public: /*! @brief Default copy operator of the oscillatory network state. @param[in] p_other: another network state that should be copied to the current. */ sync_network_state & operator=(const sync_network_state & p_other) = default; /*! @brief Default move operator of the oscillatory network state. @param[in] p_other: another network state that should be moved to the current. */ sync_network_state & operator=(sync_network_state && p_other) = default; }; /** * * @class sync_ordering sync.hpp pyclustering/nnet/sync.hpp * * @brief Provides methods related to calculation of ordering parameters. * */ class sync_ordering { private: using phase_getter = std::function; public: /** * * @brief Default constructor is forbidden. * */ sync_ordering() = delete; /** * * @brief Default destructor is forbidden. * */ ~sync_ordering() = delete; public: /** * * @brief Calculates level of global synchronization (order parameter) for input phases. * @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it * tend to 0.0 when desynchronization is observed in the network. * * @param[in] p_phases: Oscillator phases that are used for calculation. * * @return Order parameter for the specified state. * */ static double calculate_sync_order(const std::vector & p_phases); /** * * @brief Calculates level of global synchronization (order parameter) for input phases. * @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it * tend to 0.0 when desynchronization is observed in the network. * * @param[in] p_oscillators: Network oscillators that are used for calculation. * * @return Order parameter for the specified state. * */ static double calculate_sync_order(const std::vector & p_oscillators); /** * * @brief Calculates level of local synchronization (order parameter) for input phases. * @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it * tend to 0.0 when desynchronization is observed in the network. * * @param[in] p_connections: Connections between oscillators in the network for which calculation is performed. * @param[in] p_phases: Oscillator phases that are used for calculation. * * @return Order parameter for the specified state. * */ static double calculate_local_sync_order( const std::shared_ptr & p_connections, const std::vector & p_phases); /** * * @brief Calculates level of local synchronization (order parameter) for input phases. * @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it * tend to 0.0 when desynchronization is observed in the network. * * @param[in] p_connections: Connections between oscillators in the network for which calculation is performed. * @param[in] p_oscillators: Network oscillators that are used for calculation. * * @return Order parameter for the specified state. * */ static double calculate_local_sync_order( const std::shared_ptr & p_connections, const std::vector & p_oscillators); private: template static double calculate_sync_order_parameter( const TypeContainer & p_container, const phase_getter & p_getter); template static double calculate_local_sync_order_parameter( const std::shared_ptr & p_connections, const TypeContainer & p_container, const phase_getter & p_getter); }; /** * * @class sync_dynamic sync.hpp pyclustering/nnet/sync.hpp * * @brief Output dynamic of the oscillatory network 'sync' based on Kuramoto model. * */ class sync_dynamic : public dynamic_data { public: /** * * @brief Default destructor. * */ virtual ~sync_dynamic() = default; public: /** * * @brief Allocate clusters in line with ensembles of synchronous oscillators. * @details Each synchronous ensemble corresponds to only one cluster. * * @param[in] tolerance: maximum error for allocation of synchronous ensemble oscillators. * @param[out] ensembles: synchronous ensembles of oscillators where each ensemble consists of * indexes of oscillators that are synchronous to each other. * */ void allocate_sync_ensembles(const double tolerance, ensemble_data & ensembles) const; /** * * @brief Allocate clusters in line with ensembles of synchronous oscillators at the specify iteration * of simulation. * @details Each synchronous ensemble corresponds to only one cluster. * * @param[in] tolerance: maximum error for allocation of synchronous ensemble oscillators. * @param[in] iteration: simulation iteration that should be used for allocation. * @param[out] ensembles: synchronous ensembles of oscillators where each ensemble consists of * indexes of oscillators that are synchronous to each other. * */ void allocate_sync_ensembles(const double tolerance, const std::size_t iteration, ensemble_data & ensembles) const; /** * * @brief Allocate correlation matrix between oscillators at the last step of simulation. * * @param[out] p_matrix: correlation matrix between oscillators on specified iteration. * */ void allocate_correlation_matrix(sync_corr_matrix & p_matrix) const; /** * * @brief Allocate correlation matrix between oscillators at the specified step of simulation. * * @param[in] p_iteration: Number of iteration of simulation for which correlation matrix should * be allocated. * @param[out] p_matrix: correlation matrix between oscillators on specified iteration. * */ void allocate_correlation_matrix(const std::size_t p_iteration, sync_corr_matrix & p_matrix) const; /** * * @brief Calculates evolution of level of global synchronization (order parameter). * * @param[in] start_iteration: The first iteration that is used for calculation. * @param[in] stop_iteration: The last iteration that is used for calculation. * @param[out] sequence_order: Evolution of order parameter. * */ void calculate_order_parameter( const std::size_t start_iteration, const std::size_t stop_iteration, std::vector & sequence_order) const; /** * * @brief Calculates evolution of level of partial synchronization (local order parameter). * * @param[in] connections: Connections of Sync oscillatory network. * @param[in] start_iteration: The first iteration that is used for calculation. * @param[in] stop_iteration: The last iteration that is used for calculation. * @param[out] sequence_order: Evolution of local order parameter. * */ void calculate_local_order_parameter( const std::shared_ptr & connections, const std::size_t start_iteration, const std::size_t stop_iteration, std::vector & sequence_local_order) const; }; /** * * @class sync_network sync.hpp pyclustering/nnet/sync.hpp * * @brief Oscillatory neural network based on Kuramoto model with phase oscillator. * */ class sync_network { private: const static std::size_t MAXIMUM_MATRIX_REPRESENTATION_SIZE; private: using iterator = std::vector::iterator; protected: std::vector m_oscillators; /**< State of each oscillator of the network. */ std::shared_ptr m_connections; /**< Connections between oscillators in the network. */ double weight; /**< Coupling strength of the links between oscillators. */ private: equation m_equation; public: /** * * @brief Contructor of the oscillatory network SYNC based on Kuramoto model. * * @param[in] size: number of oscillators in the network. * @param[in] weight_factor: coupling strength of the links between oscillators. * @param[in] frequency_factor: multiplier of internal frequency of the oscillators. * @param[in] connection_type: type of connection between oscillators in the network. * @param[in] initial_phases: type of initialization of initial phases of oscillators. * */ sync_network(const size_t size, const double weight_factor, const double frequency_factor, const connection_t connection_type, const initial_type initial_phases); /** * * @brief Contructor of the oscillatory network SYNC based on Kuramoto model. * * @param[in] size: number of oscillators in the network. * @param[in] weight_factor: coupling strength of the links between oscillators. * @param[in] frequency_factor: multiplier of internal frequency of the oscillators. * @param[in] connection_type: type of connection between oscillators in the network. * @param[in] height: number of oscillators in column of the network, this argument is * used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types * this argument is ignored. * @param[in] width: number of oscillotors in row of the network, this argument is used * only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this * argument is ignored. * @param[in] initial_phases: type of initialization of initial phases of oscillators. * */ sync_network(const std::size_t size, const double weight_factor, const double frequency_factor, const connection_t connection_type, const std::size_t height, const std::size_t width, const initial_type initial_phases); /** * * @brief Default destructor. * */ virtual ~sync_network(); public: /** * * @brief Calculates level of global synchronization in the network. * * @return Return level of global synchronization in the network. * */ virtual double sync_order() const; /** * * @brief Calculates level of local (partial) synchronization in the network. * * @return Return level of local (partial) synchronization in the network. * */ virtual double sync_local_order() const; /** * * @brief Performs static simulation of oscillatory network. * @details In case 'collect_dynamic = True' output dynamic will consists all steps of simulation * and the initial state of the network, for example, in case of 20 steps, length of * output dynamic will be 21 (20 simulation steps + 1 initial state). * * @param[in] steps: number steps of simulations during simulation. * @param[in] time: time of simulation. * @param[in] solver: type of solver for simulation. * @param[in] collect_dynamic: if true - returns whole dynamic of oscillatory network, * otherwise returns only last values of dynamics. * @param[out] output_dynamic: output dynamic of the network, if argument 'collect_dynamic' = true, * than it will be dynamic for the whole simulation time, otherwise returns only last * values (last step of simulation) of dynamic. * */ virtual void simulate_static( const std::size_t steps, const double time, const solve_type solver, const bool collect_dynamic, sync_dynamic & output_dynamic); /** * * @brief Performs dynamic simulation of oscillatory network until stop condition is not * reached. Stop condition is defined by input argument 'order'. * @details In case 'collect_dynamic = True' output dynamic will consists all steps of simulation * and the initial state of the network, for example, in case of 20 steps, length of * output dynamic will be 21 (20 simulation steps + 1 initial state). * * @param[in] order: order of process synchronization, distributed 0..1. * @param[in] step: time step of one iteration of simulation. * @param[in] solver: type of solver for simulation. * @param[in] collect_dynamic: if true - returns whole dynamic of oscillatory network, * otherwise returns only last values of dynamics. * @param[out] output_dynamic: output dynamic of the network, if argument 'collect_dynamic' = true, * than it will be dynamic for the whole simulation time, otherwise returns only last * values (last step of simulation) of dynamic. * */ virtual void simulate_dynamic( const double order, const double step, const solve_type solver, const bool collect_dynamic, sync_dynamic & output_dynamic); /** * * @brief Returns size of the oscillatory network that is defined by amount of oscillators. * */ inline std::size_t size() const { return m_oscillators.size(); } /** * * @brief Returns connections represented by chosen adjacency collection. * */ inline std::shared_ptr connections() const { return m_connections; } protected: /** * * @brief Normalization of phase of oscillator that should be placed between [0; 2 * pi]. * * @param[in] teta: phase of oscillator. * * @return Normalized phase. * */ virtual double phase_normalization(const double teta) const; /** * * @brief Calculation of oscillator phase using Kuramoto model. * * @param[in] t: time (can be ignored). * @param[in] teta: current value of phase. * @param[in] argv: index of oscillator whose phase represented by argument teta. * * @return Return new value of phase of oscillator with index 'argv[1]'. * */ virtual double phase_kuramoto( const double t, const double teta, const std::vector & argv) const; /** * * @brief Calculates state of phase oscillator using classic Kuramoto synchonization model. * * @param[in] t: time (can be ignored). * @param[in] inputs: current state of the oscillator (current phase). * @param[in] argv: additional parameters that are used by the oscillator's equation (index of oscillator whose phase represented by argument teta). * @param[out] outputs: new states of the oscillator (new phase value). * */ virtual void phase_kuramoto_equation( const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const; /** * * @brief Calculates new phases for oscillators in the network in line with current step. * * @param[in] solver: type solver of the differential equation. * @param[in] t: time of simulation. * @param[in] step: step of solution at the end of which states of oscillators should be calculated. * @param[in] int_step: step differentiation that is used for solving differential equation (can * be ignored in case of solvers when integration step is defined by solver itself). * */ virtual void calculate_phases( const solve_type solver, const double t, const double step, const double int_step); /** * * @brief Calculates new phases for specific range of oscillators in the network in line with current step. * * @param[in] solver: type solver of the differential equation. * @param[in] t: time of simulation. * @param[in] step: step of solution at the end of which states of oscillators should be calculated. * @param[in] int_step: step differentiation that is used for solving differential equation (can * be ignored in case of solvers when integration step is defined by solver itself). * @param[in] index: index of the particular oscillator whose phase should be calculated. * @param[in,out] p_next_phases: container where new oscillator phases from the range are placed. * */ virtual void calculate_phase( const solve_type solver, const double t, const double step, const double int_step, const std::size_t index, std::vector & p_next_phases); /** * * @brief Stores dynamic of oscillators. Type of saving depends on argument 'collect_dynamic', * if it's true - than new values are added to previous, otherwise new values rewrite * previous. * * @param[in] time: timestamp that corresponds time point when dyncamic is collected. * @param[in] collect_dynamic: if true - added new values to previous, otherwise rewrites * previous values by new values of dynamics. * @param[out] output_dynamic: storage of output dynamic. * */ virtual void store_dynamic( const double time, const bool collect_dynamic, sync_dynamic & output_dynamic) const; /** * * @brief Set phase oscillator equation that is used to calculate state of each oscillator in the network. * * @param[in] solver: equation of phase oscillator. * */ virtual void set_equation(equation & solver); private: /*! @brief Initializer of the oscillatory network SYNC based on Kuramoto model. @param[in] size: number of oscillators in the network. @param[in] weight_factor: coupling strength of the links between oscillators. @param[in] frequency_factor: multiplier of internal frequency of the oscillators. @param[in] connection_type: type of connection between oscillators in the network. @param[in] height: number of oscillators in column of the network, this argument is used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored. @param[in] width: number of oscillotors in row of the network, this argument is used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored. @param[in] initial_phases: type of initialization of initial phases of oscillators. */ void initialize( const size_t size, const double weight_factor, const double frequency_factor, const connection_t connection_type, const size_t height, const size_t width, const initial_type initial_phases); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/nnet/syncpr.hpp000077500000000000000000000050361375753423500247470ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace nnet { typedef std::vector > matrix; typedef std::vector syncpr_pattern; /* it is enough functionality in parent dynamic */ typedef sync_dynamic syncpr_dynamic; class syncpr_invalid_pattern : public std::runtime_error { public: syncpr_invalid_pattern(); explicit syncpr_invalid_pattern(const std::string & description); }; class syncpr: public sync_network { private: using sync_network::simulate_static; using sync_network::simulate_dynamic; protected: double m_increase_strength1; double m_increase_strength2; matrix m_coupling; public: syncpr(const unsigned int num_osc, const double increase_strength1, const double increase_strength2); syncpr(const unsigned int num_osc, const size_t height, const size_t width, const double increase_strength1, const double increase_strength2); virtual ~syncpr() = default; public: void train(const std::vector & patterns); void simulate_static(const unsigned int steps, const double time, const syncpr_pattern & input_pattern, const solve_type solver, const bool collect_dynamic, syncpr_dynamic & output_dynamic); void simulate_dynamic(const syncpr_pattern & input_pattern, const double order, const double step, const solve_type solver, const bool collect_dynamic, syncpr_dynamic & output_dynamic); double memory_order(const syncpr_pattern & input_pattern) const; protected: double phase_kuramoto(const double t, const double teta, const std::vector & argv) const override; void phase_kuramoto_equation(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const override; private: void validate_pattern(const syncpr_pattern & sample) const; void initialize_phases(const syncpr_pattern & sample); double calculate_memory_order(const syncpr_pattern & input_pattern) const; }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/parallel/000077500000000000000000000000001375753423500235415ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/parallel/parallel.hpp000077500000000000000000000246131375753423500260570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #if defined(WIN32) || (_WIN32) || (_WIN64) #define PARALLEL_IMPLEMENTATION_ASYNC_POOL /* 'PARALLEL_IMPLEMENTATION_ASYNC_POOL' demostrates more efficiency than 'PARALLEL_IMPLEMENTATION_PPL' in scope of the pyclustering library. */ #else #define PARALLEL_IMPLEMENTATION_ASYNC_POOL #endif #if defined(PARALLEL_IMPLEMENTATION_PPL) #include #endif namespace pyclustering { namespace parallel { /* Pool of threads is used to prevent overhead in case of nested loop */ static const std::size_t AMOUNT_HARDWARE_THREADS = std::thread::hardware_concurrency(); static const std::size_t AMOUNT_THREADS = (AMOUNT_HARDWARE_THREADS > 1) ? (AMOUNT_HARDWARE_THREADS - 1) : 0; /*! @brief Parallelizes for-loop using all available cores. @details `parallel_for` uses PPL in case of Windows operating system and own implemention that is based on pure C++ functionality for concurency such as `std::future` and `std::async`. Advanced uses might use one of the define to use specific implementation of the `parallel_for` loop: 1. PARALLEL_IMPLEMENTATION_ASYNC_POOL - own parallel implementation based on `std::async` pool. 2. PARALLEL_IMPLEMENTATION_NONE - parallel implementation is not used. 3. PARALLEL_IMPLEMENTATION_PPL - parallel PPL implementation (windows system only). 4. PARALLEL_IMPLEMENTATION_OPENMP - parallel OpenMP implementation. @param[in] p_start: initial value for the loop. @param[in] p_end: final value of the loop - calculations are performed until the current counter value is less than the final value `i < p_end`. @param[in] p_step: step that is used to iterate over the loop. @param[in] p_task: body of the loop that defines actions that should be done on each iteration. @param[in] p_threads: amount of threads that are going to be used for processing (by default the efficient amount of threads). */ template void parallel_for(const TypeIndex p_start, const TypeIndex p_end, const TypeIndex p_step, const TypeAction & p_task, const std::size_t p_threads = AMOUNT_THREADS) { #if defined(PARALLEL_IMPLEMENTATION_ASYNC_POOL) /* Microsoft `concurrency::parallel_for` implementation does not support negative step. The cite from the documentation about `concurrency::parallel_for`. The loop iteration must be forward. The parallel_for algorithm throws an exception of type std::invalid_argument if the _Step parameter is less than 1. Therefore let's support the same behavior. */ if (p_end < p_start) { throw std::invalid_argument("Start index '" + std::to_string(p_start) + "' is greater than end '" + std::to_string(p_end) + "'."); } const TypeIndex interval_length = p_end - p_start; /* Full interval to process */ if (interval_length == 0) { return; /* There are no work for threads. */ } if ((interval_length > 0) && (interval_length <= p_step)) { p_task(p_start); /* There is only one iteration in the loop. */ return; } TypeIndex interval_thread_length = interval_length / p_step / static_cast(p_threads); /* How many iterations should be performed by each thread */ if (interval_thread_length < p_step) { /* There is not enough work to load all threads. Still tasks could be splitted between threads, we do not how long they are going to be executed, but if input task is small than we should expect huge performance degradation (see hsyncnet tests). */ #if defined(DEVIDE_AND_CONQUER_STRATEGY) interval_thread_length = p_step; #else for (TypeIndex i = p_start; i < p_end; i += p_step) { p_task(i); } return; #endif } else if (interval_thread_length % p_step != 0) { interval_thread_length = interval_thread_length - (interval_thread_length % p_step); } TypeIndex current_start = p_start; TypeIndex current_end = p_start + interval_thread_length; std::vector> future_storage; future_storage.reserve(p_threads); /* It is possible that there are not enough work for all threads, lets check that we are not out of range. */ for (std::size_t i = 0; false && (i < static_cast(p_threads) - 1) && (current_end < p_end); ++i) { const auto async_task = [&p_task, current_start, current_end, p_step](){ for (TypeIndex i = current_start; i < current_end; i += p_step) { p_task(i); } }; /* There was an optimization for nested 'parallel_for' loops, but the maximum depth in the current library is 2. If the optimization is needed - get it from repository (versions that are <= 0.10.0.1). */ future_storage.push_back(std::async(std::launch::async, async_task)); current_start = current_end; current_end += interval_thread_length; } for (TypeIndex i = current_start; i < p_end; i += p_step) { p_task(i); } for (auto & feature : future_storage) { feature.get(); } #elif defined(PARALLEL_IMPLEMENTATION_PPL) (void) p_threads; concurrency::parallel_for(p_start, p_end, p_step, p_task); #elif defined(PARALLEL_IMPLEMENTATION_OPENMP) #pragma omp parallel for for (TypeIndex i = p_start; i < p_end, i += p_step) { p_task(i); } #else for (std::size_t i = p_start; i < p_end; i += p_step) { p_task(i); } #endif } /*! @brief Parallelizes for-loop using all available cores. @details `parallel_for` uses PPL in case of Windows operating system and own implemention that is based on pure C++ functionality for concurency such as `std::future` and `std::async`. Advanced uses might use one of the define to use specific implementation of the `parallel_for` loop: 1. PARALLEL_IMPLEMENTATION_ASYNC_POOL - own parallel implementation based on `std::async` pool. 2. PARALLEL_IMPLEMENTATION_NONE - parallel implementation is not used. 3. PARALLEL_IMPLEMENTATION_PPL - parallel PPL implementation (windows system only). 4. PARALLEL_IMPLEMENTATION_OPENMP - parallel OpenMP implementation. @param[in] p_start: initial value for the loop. @param[in] p_end: final value of the loop - calculations are performed until current counter value is less than final value `i < p_end`. @param[in] p_task: body of the loop that defines actions that should be done on each iteration. */ template void parallel_for(const TypeIndex p_start, const TypeIndex p_end, const TypeAction & p_task) { parallel_for(p_start, p_end, std::size_t(1), p_task); } /*! @brief Parallelizes for-each-loop using all available cores. @details `parallel_each` uses PPL in case of Windows operating system and own implemention that is based on pure C++ functionality for concurency such as `std::future` and `std::async`. Advanced uses might use one of the define to use specific implementation of the `parallel_for_each` loop: 1. PARALLEL_IMPLEMENTATION_ASYNC_POOL - own parallel implementation based on `std::async` pool. 2. PARALLEL_IMPLEMENTATION_NONE - parallel implementation is not used. 3. PARALLEL_IMPLEMENTATION_PPL - parallel PPL implementation (windows system only). 4. PARALLEL_IMPLEMENTATION_OPENMP - parallel OpenMP implementation. @param[in] p_begin: initial iterator from that the loop starts. @param[in] p_end: end iterator that defines when the loop should stop `iter != p_end`. @param[in] p_task: body of the loop that defines actions that should be done for each element. @param[in] p_threads: amount of threads that are going to be used for processing (by default the efficient amount of threads). */ template void parallel_for_each(const TypeIter p_begin, const TypeIter p_end, const TypeAction & p_task, const std::size_t p_threads = AMOUNT_THREADS) { #if defined(PARALLEL_IMPLEMENTATION_ASYNC_POOL) const std::size_t interval_length = std::distance(p_begin, p_end); if (interval_length == 0) { return; } if (interval_length == 1) { p_task(*p_begin); return; } const std::size_t step = std::max(interval_length / p_threads, std::size_t(1)); std::size_t amount_threads = static_cast(interval_length / step); if (amount_threads > p_threads) { amount_threads = p_threads; } else if (amount_threads > 0) { amount_threads--; /* current thread is also considered. */ } auto current_start = p_begin; auto current_end = p_begin + step; std::vector> future_storage(amount_threads); for (std::size_t i = 0; i < amount_threads; ++i) { auto async_task = [&p_task, current_start, current_end](){ for (auto iter = current_start; iter != current_end; ++iter) { p_task(*iter); } }; future_storage[i] = std::async(std::launch::async, async_task); current_start = current_end; current_end += step; } for (auto iter = current_start; iter != p_end; ++iter) { p_task(*iter); } for (auto & feature : future_storage) { feature.get(); } #elif defined(PARALLEL_IMPLEMENTATION_PPL) (void) p_threads; concurrency::parallel_for_each(p_begin, p_end, p_task); #else for (auto iter = p_begin; iter != p_end; ++iter) { p_task(*iter); } #endif } /*! @brief Parallelizes for-each-loop using all available cores. @details `parallel_each` uses PPL in case of Windows operating system and own implemention that is based on pure C++ functionality for concurency such as `std::future` and `std::async`. @param[in] p_container: iterable container that should be processed. @param[in] p_task: body of the loop that defines actions that should be done for each element. */ template void parallel_for_each(const TypeContainer & p_container, const TypeAction & p_task) { parallel_for_each(std::begin(p_container), std::end(p_container), p_task); } } }pyclustering-0.10.1.2/ccore/include/pyclustering/parallel/spinlock.hpp000077500000000000000000000022201375753423500260730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace parallel { /*! @class spinlock spinlock.hpp pyclustering/parallel/spinlock.hpp @brief Spinlock mechanism for synchronization. @details Spinlock is a lock which causes a thread trying to acquire it to simply wait in a loop while repeatedly checking if the lock is available. */ class spinlock { private: std::atomic_flag m_lock = ATOMIC_FLAG_INIT; public: /*! @brief Default spinlock constructor. */ spinlock() = default; /*! @brief Default spinlock destructor. */ ~spinlock() = default; public: /*! @brief Tries to lock once and if it is impossible then the spinlock returns control. @return Returns `true` if the resource was successfully locked. */ bool try_lock(); /*! @brief Tries to lock until success. */ void lock(); /*! @brief Unlocks the resource. */ void unlock(); }; } }pyclustering-0.10.1.2/ccore/include/pyclustering/parallel/task.hpp000077500000000000000000000041361375753423500252230ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include namespace pyclustering { namespace parallel { class thread_executor; /* @class task task.hpp pyclustering/parallel/task.hpp @brief Defines a task for thread pool that should be executed. @details The executed task is marked as a ready-task. @see thread_pool */ class task { friend thread_executor; public: /*! @brief Defines a task for the thread pool and should have the following signature `void()`. */ using proc = std::function; /*! @brief Defines shared pointer to the task. */ using ptr = std::shared_ptr; /*! @brief Defines ID type of the task. */ using id = std::size_t; private: proc m_task = proc(); mutable spinlock m_ready; public: /*! @brief Default task constructor. */ task() = default; /*! @brief Constructor of the task where actions are defined by an input function with `void()` signature. @param[in] p_task: function with `void()` signature that should executed. */ explicit task(const proc & p_task); /*! @brief Default copy constructor of the task. */ task(const task & p_other) = default; /*! @brief Default move constructor of the task. */ task(task && p_other) = default; /*! @brief Default desctructor of the task. */ ~task() = default; private: /*! @brief Marks the current task as complited. */ void set_ready(); public: /*! @brief Blocks until the current task is complited. */ void wait_ready() const; public: /*! @brief Runs execution of the current task. */ void operator()(); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/parallel/thread_executor.hpp000077500000000000000000000043301375753423500274420ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace parallel { /*! @class thread_executor thread_executor.hpp pyclustering/parallel/thread_executor.hpp @brief Task executor for the thread pool. @details Task executor is responsible for executing task in separate thread and for notification the thread pool about task readiness. @see thread_pool */ class thread_executor { public: /*! @brief Defines function to get next task for execution from the thread pool. @details The signature of the getter function should have following signature void(task::ptr &)`. */ using task_getter = std::function; /*! @brief Defines shared pointer of the thread executor. */ using ptr = std::shared_ptr; private: bool m_stop = true; task_getter m_getter = nullptr; std::thread m_executor; public: /*! @brief Default constructor of the thread executor. */ thread_executor() = default; /*! @brief Constructor of the thread executor with the task getting function. @param[in] p_getter: function with signatire `void(task::ptr &)` that is used to get next task to execute. */ explicit thread_executor(const task_getter & p_getter); /*! @brief Default copy constructor of the thread executor. */ thread_executor(const thread_executor & p_other) = delete; /*! @brief Default move constructor of the thread executor. */ thread_executor(thread_executor && p_other) = delete; /*! @brief Default destructor of the thread executor. */ ~thread_executor() = default; public: /*! @brief Terminates thread executor: stops current task and join thread of the executor. */ void stop(); private: /*! @brief Run thread executor. */ void run(); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/parallel/thread_pool.hpp000077500000000000000000000060151375753423500265570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include namespace pyclustering { namespace parallel { /*! @class thread_pool thread_pool.hpp pyclustering/parallel/thread_pool.hpp @brief Thread pool provides service to execute client tasks asynchronously in parallel way. */ class thread_pool { public: /*! @brief Defines shared pointer of the thread pool. */ using ptr = std::shared_ptr; private: using thread_container = std::vector; public: static const std::size_t DEFAULT_AMOUNT_THREADS; /**< Default amount of threads. */ static const std::size_t DEFAULT_POOL_SIZE; /**< Default size of the thread pool. */ private: thread_container m_pool = { }; std::deque m_queue = { }; mutable std::mutex m_common_mutex; std::condition_variable m_queue_not_empty_cond; std::size_t m_free = 0; std::size_t m_reserve = 0; bool m_stop = false; public: /*! @brief Default constructor of the thread pool. */ thread_pool(); /*! @brief Constructor of the thread pool where specific size of the pool is specified. @param[in] p_size: amount of threads in the pool that are going to be used for processing. */ explicit thread_pool(const std::size_t p_size); /*! @brief Default copy constructor of the thread pool. */ thread_pool(const thread_pool & p_pool) = delete; /*! @brief Default move constructor of the thread pool. */ thread_pool(thread_pool && p_pool) = delete; /*! @brief Default destructor of the thread pool. */ ~thread_pool(); public: /*! @brief Add new task for execution to the current thread pool. @param[in] p_raw_task: task with signature `void()` that should be executed. @return Shared pointer to the task that is going to be executed. */ task::ptr add_task(const task::proc & p_raw_task); /*! @brief Add new task for execution to the current thread pool if there is enough capacity to serve it without delay. @param[in] p_raw_task: task with signature `void()` that should be executed. @return Shared pointer to the task that is going to be executed if there is enough capacity, otherwise `nullptr`. */ task::ptr add_task_if_free(const task::proc & p_raw_task); /*! @brief Returns amount of tasks in the current thread pool. @return Amount of tasks in the current thread pool. */ std::size_t size() const; private: void initialize(const std::size_t p_size); void get_task(task::ptr & p_task); }; } } pyclustering-0.10.1.2/ccore/include/pyclustering/utils/000077500000000000000000000000001375753423500231055ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/include/pyclustering/utils/algorithm.hpp000077500000000000000000000071031375753423500256100ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace utils { namespace algorithm { /*! @brief Returns the element at the left side from the right border with the same value as the last element in the range `[p_begin, p_end)`. @details The element at the right is considered as target to search. `[p_begin, p_end)` must be sorted collection. `InputIt` must meet the requirements of `LegacyInputIterator` and `LegacyRandomAccessIterator`. The complexity of the algorithm is `O(log(n))`. The algorithm is based on the binary search algorithm. @param[in] p_begin: iterator pointing to the first element. @param[in] p_end: iterator pointing to the end of the range. @param[in] p_comparator: comparison function object which returns `true` if the first argument is less than the second. The signature of the compare function should be equivalent to the following: `bool comparator(const Type & p_val1, const Type & p_val2)`. @return The element at the left side from the right border with the same value as the last element in the range `[p_begin, p_end)`. */ template InputIt find_left_element(const InputIt p_begin, const InputIt p_end, Comparator p_comparator) { if (p_begin == p_end) { return p_end; } InputIt left = p_begin, right = p_end - 1; InputIt middle = p_begin + (std::distance(left, right) / 2); auto target = *right; while (left < right) { if (p_comparator(*middle, target)) { left = middle + 1; } else { right = middle; } const auto offset = std::distance(left, right) / 2; middle = left + offset; } return left; } /*! @brief Returns the element at the left side from the right border with the same value as the last element in the range `[p_begin, p_end)`. @details The element at the right is considered as target to search. `[p_begin, p_end)` must be sorted collection. `InputIt` must meet the requirements of `LegacyInputIterator` and `LegacyRandomAccessIterator`. The complexity of the algorithm is `O(log(n))`. The algorithm is based on the binary search algorithm. @param[in] p_begin: iterator pointing to the first element. @param[in] p_end: iterator pointing to the end of the range. @return The element at the left side from the right border with the same value as the last element in the range `[p_begin, p_end)`. @code #include #include #include #include using namespace pyclustering::utils::algorithm; int main() { std::vector seq = { 1, 2, 2, 3, 3, 3, 6, 6, 6 }; for (auto iter = seq.begin() + 1; iter != seq.end(); iter++) { auto left = find_left_element(seq.begin(), iter); std::cout << "Index of the left element: " << std::distance(seq.begin(), left) << " for " << *iter << std::endl; } return 0; } @endcode */ template InputIt find_left_element(const InputIt p_begin, const InputIt p_end) { using iter_type = typename std::iterator_traits::value_type; return find_left_element(p_begin, p_end, [](iter_type & p_val1, iter_type & p_val2) { return p_val1 < p_val2; }); } } } }pyclustering-0.10.1.2/ccore/include/pyclustering/utils/linalg.hpp000077500000000000000000000014641375753423500250740ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include namespace pyclustering { namespace utils { namespace linalg { using sequence = std::vector; using matrix = std::vector; sequence subtract(const sequence & a, const sequence & b); sequence subtract(const sequence & a, const double b); sequence multiply(const sequence & a, const sequence & b); sequence multiply(const sequence & a, const double b); matrix multiply(const matrix & a, const sequence & b); sequence divide(const sequence & a, const sequence & b); sequence divide(const sequence & a, const double b); double sum(const sequence & a); sequence sum(const matrix & a, std::size_t axis = 0); } } }pyclustering-0.10.1.2/ccore/include/pyclustering/utils/math.hpp000077500000000000000000000020511375753423500245500ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once namespace pyclustering { namespace utils { namespace math { /*! @brief Mathematical constant pi. */ const double pi = 3.14159265358979323846; /** * * @brief Calculates Heaviside function. * @details If value >= 0.0 then 1.0 is returned, otherwise 0.0 is returned. * * @param[in] value: Input argument of the Heaviside function. * * @return Returns result of Heaviside function. * */ double heaviside(const double value); /** * * @brief Calculates absolute difference between two objects. * * @param[in] p_value1: The first value of the operation. * @param[in] p_value2: The second value of the operation. * * @return Returns absolute difference. * */ template TypeValue absolute_difference(const TypeValue & p_value1, const TypeValue & p_value2) { return (p_value1 >= p_value2) ? p_value1 - p_value2 : p_value2 - p_value1; } } } }pyclustering-0.10.1.2/ccore/include/pyclustering/utils/metric.hpp000077500000000000000000000475501375753423500251170ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include #include #include namespace pyclustering { namespace utils { namespace metric { /*! @brief Encapsulates distance metric calculation function between two objects. */ template using distance_functor = std::function; /*! @brief Calculates square of Euclidean distance between points. @param[in] point1: point #1 that is represented by coordinates. @param[in] point2: point #2 that is represented by coordinates. @return Returns square of Euclidean distance between points. */ template double euclidean_distance_square(const TypeContainer & point1, const TypeContainer & point2) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = point1.begin(); for (const auto & dim_point2 : point2) { double difference = (*iter_point1 - dim_point2); distance += difference * difference; ++iter_point1; } return distance; } /*! @brief Calculates Euclidean distance between points. @param[in] point1: point #1 that is represented by coordinates. @param[in] point2: point #2 that is represented by coordinates. @return Returns Euclidean distance between points. */ template double euclidean_distance(const TypeContainer & point1, const TypeContainer & point2) { return std::sqrt(euclidean_distance_square(point1, point2)); } /*! @brief Calculates Manhattan distance between points. @param[in] point1: point #1 that is represented by coordinates. @param[in] point2: point #2 that is represented by coordinates. @return Returns Manhattan distance between points. */ template double manhattan_distance(const TypeContainer & point1, const TypeContainer & point2) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = point1.begin(); for (const auto & dim_point2 : point2) { distance += std::abs(*iter_point1 - dim_point2); ++iter_point1; } return distance; } /*! @brief Calculates Chebyshev distance between points. @param[in] point1: point #1 that is represented by coordinates. @param[in] point2: point #2 that is represented by coordinates. @return Returns Chebyshev distance between points. */ template double chebyshev_distance(const TypeContainer & point1, const TypeContainer & point2) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = point1.begin(); for (const auto & dim_point2 : point2) { distance = std::max(distance, std::abs(*iter_point1 - dim_point2)); ++iter_point1; } return distance; } /*! @brief Calculates Minkowski distance between points. @param[in] p_point1: point #1 that is represented by coordinates. @param[in] p_point2: point #2 that is represented by coordinates. @param[in] p_degree: degree of Minkownski equation. @return Returns Minkowski distance between points. */ template double minkowski_distance(const TypeContainer & p_point1, const TypeContainer & p_point2, const double p_degree) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = p_point1.begin(); for (const auto & dim_point2 : p_point2) { double difference = (*iter_point1 - dim_point2); distance += std::pow(difference, p_degree); ++iter_point1; } return std::pow(distance, 1.0 / p_degree); } /*! @brief Calculates Canberra distance between points. @param[in] point1: point #1 that is represented by coordinates. @param[in] point2: point #2 that is represented by coordinates. @return Returns Canberra distance between points. */ template double canberra_distance(const TypeContainer & point1, const TypeContainer & point2) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = point1.begin(); for (const auto & dim_point2 : point2) { const auto dim_point1 = *iter_point1; const double divider = std::abs(dim_point1) + std::abs(dim_point2); if (divider == 0) { continue; } distance += std::abs(dim_point1 - dim_point2) / divider; ++iter_point1; } return distance; } /*! @brief Calculates Chi square distance between points. @param[in] point1: point #1 that is represented by coordinates. @param[in] point2: point #2 that is represented by coordinates. @return Returns Chi square distance between points. */ template double chi_square_distance(const TypeContainer & point1, const TypeContainer & point2) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = point1.begin(); for (const auto & dim_point2 : point2) { const auto dim_point1 = *iter_point1; const double divider = std::abs(dim_point1) + std::abs(dim_point2); if (divider == 0) { continue; } distance += std::pow(dim_point1 - dim_point2, 2) / divider; ++iter_point1; } return distance; } /*! @brief Calculates Gower distance between points. @param[in] p_point1: point #1 that is represented by coordinates. @param[in] p_point2: point #2 that is represented by coordinates. @param[in] p_max_range: max range in each data dimension. @return Returns Gower distance between points. */ template double gower_distance(const TypeContainer & p_point1, const TypeContainer & p_point2, const TypeContainer & p_max_range) { double distance = 0.0; typename TypeContainer::const_iterator iter_point1 = p_point1.begin(); typename TypeContainer::const_iterator iter_range = p_max_range.begin(); for (const auto & dim_point2 : p_point2) { if (*iter_range != 0.0) { distance += std::abs(*iter_point1 - dim_point2) / *iter_range; } ++iter_point1; ++iter_range; } return distance / p_point1.size(); } /*! @class distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Basic distance metric provides interface for calculation distance between objects in line with specific metric. */ template class distance_metric { protected: distance_functor m_functor = nullptr; /**< Function that defines metric calculation. */ public: /*! @brief Default constructor of distance metric. */ distance_metric() = default; /*! @brief Parameterized constructor of distance metric. @param[in] p_functor: function that defines how to calculate distance metric. */ explicit distance_metric(const distance_functor & p_functor) : m_functor(p_functor) { } /*! @brief Default copy constructor of distance metric. @param[in] p_other: other distance metric that should be copied. */ distance_metric(const distance_metric & p_other) = default; /*! @brief Default move constructor of distance metric. @param[in] p_other: other distance metric that should be copied. */ distance_metric(distance_metric && p_other) = default; /*! @brief Default destructor of distance metric. */ virtual ~distance_metric() = default; public: /*! @brief Performs calculation of distance metric between two points. @param[in] p_point1: the first iterable point. @param[in] p_point2: the second iterable point. @return Calculated distance between two points. */ double operator()(const TypeContainer & p_point1, const TypeContainer & p_point2) const { return m_functor(p_point1, p_point2); } public: /*! @brief Check if the distance metric is initialized. @return `true` if distance metric has been initialized by a non-nullptr function that defines how to calculate distance metric. */ operator bool() const { return m_functor != nullptr; } /*! @brief Assignment operator to copy distance metric. @param[in] p_other: other distance metric that should be copied. @return Reference to the distance metric. */ distance_metric& operator=(const distance_metric& p_other) { if (this != &p_other) { m_functor = p_other.m_functor; } return *this; } }; /*! @class euclidean_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Euclidean distance metric calculator between two points. \f[dist(a, b) = \sqrt{ \sum_{i=0}^{N}(a_{i} - b_{i})^{2} };\f] */ template class euclidean_distance_metric : public distance_metric { public: /*! @brief Constructor of Euclidean distance metric. */ euclidean_distance_metric() : distance_metric(std::bind(euclidean_distance, std::placeholders::_1, std::placeholders::_2)) { } }; /*! @class euclidean_distance_square_metric metric.hpp pyclustering/utils/metric.hpp @brief Square Euclidean distance metric calculator between two points. \f[dist(a, b) = \sum_{i=0}^{N}(a_{i} - b_{i})^{2};\f] */ template class euclidean_distance_square_metric : public distance_metric { public: /*! @brief Constructor of square Euclidean distance metric. */ euclidean_distance_square_metric() : distance_metric(std::bind(euclidean_distance_square, std::placeholders::_1, std::placeholders::_2)) { } }; /*! @class manhattan_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Manhattan distance metric calculator between two points. \f[dist(a, b) = \sum_{i=0}^{N}\left | a_{i} - b_{i} \right |;\f] */ template class manhattan_distance_metric : public distance_metric { public: /*! @brief Constructor of Manhattan distance metric. */ manhattan_distance_metric() : distance_metric(std::bind(manhattan_distance, std::placeholders::_1, std::placeholders::_2)) { } }; /*! @class chebyshev_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Chebyshev distance metric calculator between two points. @details Chebyshev distance is a metric defined on a vector space where the distance between two vectors is the greatest of their differences along any coordinate dimension. \f[dist(a, b) = \max_{}i\left (\left | a_{i} - b_{i} \right |\right );\f] */ template class chebyshev_distance_metric : public distance_metric { public: /*! @brief Constructor of Chebyshev distance metric. */ chebyshev_distance_metric() : distance_metric(std::bind(chebyshev_distance, std::placeholders::_1, std::placeholders::_2)) { } }; /*! @class minkowski_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Minkowski distance metric calculator between two points. \f[dist(a, b) = \sqrt[p]{ \sum_{i=0}^{N}\left(a_{i} - b_{i}\right)^{p} };\f] */ template class minkowski_distance_metric : public distance_metric { public: /*! @brief Constructor of Minkowski distance metric. @param[in] p_degree: degree of Minkowski equation. */ explicit minkowski_distance_metric(const double p_degree) : distance_metric(std::bind(minkowski_distance, std::placeholders::_1, std::placeholders::_2, p_degree)) { } }; /*! @class canberra_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Canberra distance metric calculator between two points. \f[dist(a, b) = \sum_{i=0}^{N}\frac{\left | a_{i} - b_{i} \right |}{\left | a_{i} \right | + \left | b_{i} \right |};\f] */ template class canberra_distance_metric : public distance_metric { public: /*! @brief Constructor of Canberra distance metric. */ canberra_distance_metric() : distance_metric(std::bind(canberra_distance, std::placeholders::_1, std::placeholders::_2)) { } }; /*! @class chi_square_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Chi square distance metric calculator between two points. \f[dist(a, b) = \sum_{i=0}^{N}\frac{\left ( a_{i} - b_{i} \right )^{2}}{\left | a_{i} \right | + \left | b_{i} \right |};\f] */ template class chi_square_distance_metric : public distance_metric { public: /*! @brief Constructor of Chi square distance metric. */ chi_square_distance_metric() : distance_metric(std::bind(chi_square_distance, std::placeholders::_1, std::placeholders::_2)) { } }; /*! @class gower_distance_metric metric.hpp pyclustering/utils/metric.hpp @brief Gower distance metric calculator between two points. @details Implementation is based on the paper @cite article::utils::metric::gower. Gower distance is calculate using following formula: \f[ dist\left ( a, b \right )=\frac{1}{p}\sum_{i=0}^{p}\frac{\left | a_{i} - b_{i} \right |}{R_{i}}, \f] where \f$R_{i}\f$ is a max range for ith dimension. \f$R\f$ is defined in line following formula: \f[ R=max\left ( X \right )-min\left ( X \right ) \f] */ template class gower_distance_metric : public distance_metric { public: /*! @brief Constructor of Gower distance metric. @param[in] p_max_range: max range in each data dimension. */ explicit gower_distance_metric(const TypeContainer & p_max_range) : distance_metric(std::bind(gower_distance, std::placeholders::_1, std::placeholders::_2, p_max_range)) { } }; /*! @class distance_metric_factory metric.hpp pyclustering/utils/metric.hpp @brief Distance metric factory provides services for creation available metric in the 'pyclustering::utils::metric' and also user-defined. */ template class distance_metric_factory { public: /*! @brief Creates Euclidean distance metric. @return Euclidean distance metric. */ static distance_metric euclidean() { return euclidean_distance_metric(); } /*! @brief Creates square Euclidean distance metric. @return Square Euclidean distance metric */ static distance_metric euclidean_square() { return euclidean_distance_square_metric(); } /*! @brief Creates Manhattan distance metric. @return Manhattan distance metric. */ static distance_metric manhattan() { return manhattan_distance_metric(); } /*! @brief Creates Chebyshev distance metric. @return Chebyshev distance metric. */ static distance_metric chebyshev() { return chebyshev_distance_metric(); } /*! @brief Creates Minkowski distance metric. @param[in] p_degree: degree of Minkowski equation. @return Minkowski distance metric. */ static distance_metric minkowski(const double p_degree) { return minkowski_distance_metric(p_degree); } /*! @brief Creates Canberra distance metric. @return Canberra distance metric. */ static distance_metric canberra() { return canberra_distance_metric(); } /*! @brief Creates Chi square distance metric. @return Chi square distance metric. */ static distance_metric chi_square() { return chi_square_distance_metric(); } /*! @brief Creates Gower distance metric. @param[in] p_max_range: max range in each data dimension. @return Gower distance metric. */ static distance_metric gower(const TypeContainer & p_max_range) { return gower_distance_metric(p_max_range); } /*! @brief Creates user-defined distance metric. @param[in] p_functor: user-defined metric for calculation distance between two points. @return User-defined distance metric. */ static distance_metric user_defined(const distance_functor & p_functor) { return distance_metric(p_functor); } }; /*! @brief Returns average distance for establish links between specified number of neighbors. @param[in] points: input data. @param[in] num_neigh: number of neighbors. @return Returns average distance for establish links between `num_neigh` in data set `points`. */ double average_neighbor_distance(const std::vector > * points, const std::size_t num_neigh); /*! @brief Finds farthest distance between points in specified container (data). @param[in] p_container: input data. @param[in] p_metric: metric that is used for distance calculation between points. @return Returns farthest distance between points. */ template double farthest_distance(const TypeContainer & p_container, const distance_metric & p_metric) { double distance = 0; for (std::size_t i = 0; i < p_container.size(); i++) { for (std::size_t j = i + 1; j < p_container.size(); j++) { double candidate_distance = p_metric(p_container[i], p_container[j]); if (candidate_distance > distance) { distance = candidate_distance; } } } return distance; } /*! @brief Calculates distance matrix using points container using Euclidean distance. @param[in] p_points: input data that is represented by points. @param[in] p_metric: metric for distance calculation between points. @param[out] p_distance_matrix: output distance matrix of points. */ template void distance_matrix(const TypeContainer & p_points, const distance_metric & p_metric, TypeContainer & p_distance_matrix) { using TypeElement = typename TypeContainer::value_type; p_distance_matrix = TypeContainer(p_points.size(), TypeElement(p_points.size(), 0.0)); for (std::size_t i = 0; i < p_points.size(); i++) { for (std::size_t j = i + 1; j < p_points.size(); j++) { const double distance = p_metric(p_points.at(i), p_points.at(j)); p_distance_matrix[i][j] = distance; p_distance_matrix[j][i] = distance; } } } /*! @brief Calculates distance matrix using points container using Euclidean distance. @param[in] p_points: input data that is represented by points. @param[out] p_distance_matrix: output distance matrix of points. */ template void distance_matrix(const TypeContainer & p_points, TypeContainer & p_distance_matrix) { distance_matrix(p_points, distance_metric_factory::euclidean(), p_distance_matrix); } } } } pyclustering-0.10.1.2/ccore/include/pyclustering/utils/random.hpp000077500000000000000000000010051375753423500250750ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once namespace pyclustering { namespace utils { namespace random { /** * * @brief Returns random value in specified range using uniform distribution. * * @param[in] p_from: Mean. * @param[in] p_to: Standard deviation. * * @return Returns random variable. * */ double generate_uniform_random(const double p_from = 0.0, const double p_to = 1.0); } } }pyclustering-0.10.1.2/ccore/include/pyclustering/utils/stats.hpp000077500000000000000000000114251375753423500247620ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include namespace pyclustering { namespace utils { namespace stats { const double SQRT_0_5 = 0.70710678118654752440084436210485; /** * * @brief Calculates data's mean. * * @param[in] p_container: data to calculate mean. * * @return Mean value. * */ template double mean(const TypeContainer & p_container) { double result = 0.0; for (const auto value : p_container) { result += static_cast(value); } return result / p_container.size(); } /** * * @brief Calculates correct variance deviation (degree of freedom = 1). * * @param[in] p_container: data to calculate standard deviation. * @param[in] p_mean: data's mean value. * * @return Correct standard deviation. * */ template double var(const TypeContainer & p_container, const double p_mean) { double result = 0.0; for (const auto value : p_container) { result += std::pow(value - p_mean, 2); } result /= (p_container.size() - 1); return result; } /** * * @brief Calculates correct variance deviation (degree of freedom = 1). * * @param[in] p_container: data to calculate standard deviation. * * @return Correct standard deviation. * */ template double var(const TypeContainer & p_container) { double mu = mean(p_container); return var(p_container, mu); } /** * * @brief Calculates correct standard deviation (degree of freedom = 1). * * @param[in] p_container: data to calculate standard deviation. * @param[in] p_mean: data's mean value. * * @return Correct standard deviation. * */ template double std(const TypeContainer & p_container, const double p_mean) { return std::sqrt(var(p_container, p_mean)); } /** * * @brief Calculates correct standard deviation (degree of freedom = 1). * * @param[in] p_container: data to calculate standard deviation. * * @return Correct standard deviation. * */ template double std(const TypeContainer & p_container) { return std::sqrt(var(p_container)); } /** * * @brief Calculates PDF (Probability Distribution Function) for Gaussian (normal) distribution. * * @param[in] p_data: data to calculate probability distribution function. * * @return Probability distribution function. * */ template std::vector pdf(const TypeContainer & p_data) { double m = 1.0 / std::sqrt(2.0 * pyclustering::utils::math::pi); std::vector result; result.reserve(p_data.size()); for (auto & value : p_data) { result.push_back(m * std::exp(-0.5 * std::pow(value, 2))); } return result; } /** * * @brief Calculates CDF (Cumulative Distribution Function) for Gaussian (normal) distribution. * * @param[in] p_data: data to calculate probability distribution function. * * @return Cumulative distribution function. * */ template std::vector cdf(const TypeContainer & p_data) { std::vector result; result.reserve(p_data.size()); for (auto & value : p_data) { result.push_back(0.5 * std::erfc(-value * SQRT_0_5)); } return result; } /** * * @brief Calculates Anderson-Darling test value for Gaussian distribution. * * @param[in] p_data: data to test against Gaussian distribution. * * @return Anderson-Darling test value. * */ template double anderson(const TypeContainer & p_data) { const double m = mean(p_data); const double v = pyclustering::utils::stats::std(p_data, m); TypeContainer sample = p_data; for (auto & value : sample) { value = (value - m) / v; } std::sort(std::begin(sample), std::end(sample)); const auto y = cdf(sample); double s = 0.0; std::size_t n = p_data.size(); for (std::size_t i = 0; i < n; ++i) { const double k = 2.0 * (i + 1.0) - 1.0; s += k * (std::log(y[i]) + std::log(1.0 - y[n - i - 1])); } s /= n; return -s - n; } /** * * @brief Calculates critical values for data with Gaussian distribution for the following * significance levels: 15%, 10%, 5%, 2.5%, 1%. * * @param[in] p_data_size: Data size for that critical values should be calculated. * * @return Calculates critical values. * */ std::vector critical_values(const std::size_t p_data_size); } } }pyclustering-0.10.1.2/ccore/include/pyclustering/utils/traits.hpp000077500000000000000000000064621375753423500251370ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include namespace pyclustering { namespace utils { namespace traits { /*! @brief Utility metafunction that maps a sequence of any types to the type `void`. */ template using void_t = void; /*! @brief Checks whether `TypeRawString` is a raw-string type. @details Provides the member constant value which is equal to `true`, if `TypeRawString` is the type `char *`, `wchar_t *`, including any cv-qualified variants. Otherwise, value is equal to `false`. @tparam TypeRawString: a type to check. */ template struct is_raw_string : std::integral_constant::value && (std::is_same::type>::type>::value || std::is_same::type>::type>::value) > { }; /*! @brief Checks whether `TypeRawString` is a string type. @details Provides the member constant value which is equal to `true`, if `TypeRawString` is the type `std::string`, `std::wstring`, including any cv-qualified variants. Otherwise, value is equal to `false`. @tparam TypeString: a type to check. */ template struct is_string : std::integral_constant::type>::value || std::is_same::type>::value > { }; /*! @brief Checks whether `Type` is a container and its elements type is fundamental. @details Provides the member constant value which is equal to `true`, if `TypeContainer` is the has `value_type`, `size_type`, `const_iterator`, `cbegin()`, `cend()`. Otherwise, value is equal to `false`. @tparam Type: a type to check. */ template > struct is_container_with_fundamental_content : std::false_type { }; /*! @brief Checks whether `Type` is a container and its elements type is fundamental. @details Provides the member constant value which is equal to `true`, if `TypeContainer` is the has `value_type`, `size_type`, `const_iterator`, `cbegin()`, `cend()`. Otherwise, value is equal to `false`. @tparam Type: a type to check. */ template struct is_container_with_fundamental_content < Type, void_t< typename Type::value_type, typename Type::size_type, typename Type::const_iterator, decltype(std::declval().cbegin()), decltype(std::declval().cend()) > > : std::is_fundamental { }; /*! @brief Removes pointer, `const`, `volatile` from type `Type` if they have a place in the type. @tparam Type: a type to update. */ template using remove_cvp = std::remove_cv::type>; /*! @brief Helper type that removes pointer, `const`, `volatile` from type `Type` if they have a place in the type. @tparam Type: a type to update. */ template using remove_cvp_t = typename remove_cvp::type; } } }pyclustering-0.10.1.2/ccore/makefile000077500000000000000000000076121375753423500173030ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # MAKE = make NCORES = 1 UNAME = $(shell uname -s | tr '[:upper:]' '[:lower:]') ifeq ($(findstring cygwin, $(UNAME)), cygwin) NCORES = $(shell grep -c ^processor /proc/cpuinfo) else ifeq ($(UNAME), darwin) NCORES = $(shell sysctl -n hw.ncpu) else NCORES = $(shell grep -c ^processor /proc/cpuinfo) endif endif MKFLAG = -j$(NCORES) -f default: @echo "List of targets:" @echo "ccore_64bit - to build release shared pyclustering library (64-bit platform)." @echo "ccore_64bit_static - to build release static pyclustering library (64-bit platform)." @echo "ccore_64bit_clean - to clean build files of pyclustering library (64-bit platform)." @echo "ccore_32bit - to build release shared pyclustering library (32-bit platform)." @echo "ccore_32bit_static - to build release static pyclustering library (32-bit platform)." @echo "ccore_32bit_clean - to clean build files of pyclustering library (32-bit platform)." @echo "ccore - to build release shared pyclustering library using default compiler." @echo "ccore_clean - to clean all build files of pyclustering library." @echo " " @echo "cppcheck - to perform static analysis of source code." @echo "clang - to perform compilation and static analysis using clang compiler." @echo " " @echo "ut - to build release unit-tests for pyclustering library." @echo "utdbg - to build debug unit-tests for pyclustering library." @echo "utrun - to run unit-tests of pyclustering library." @echo "utclean - to clean build files of unit-tests of pyclustering library." @echo " " @echo "valgrind - to build and run unit-tests for memory leak checking of pyclustering library." @echo "valgrind_shock - to build and run shock scope of unit-tests for memory leak checking of pyclustering library." @echo " " @echo "clean - to clean everything." .PHONY: ccore_64bit ccore_64bit: $(MAKE) $(MKFLAG) ccore.mk ccore PLATFORM="64-bit" .PHONY: ccore_64bit_static ccore_64bit_static: $(MAKE) $(MKFLAG) ccore.mk ccore_static PLATFORM="64-bit" .PHONY: ccore_64bit_clean ccore_64bit_clean: $(MAKE) $(MKFLAG) ccore.mk clean PLATFORM="64-bit" .PHONY: ccore_32bit ccore_32bit: $(MAKE) $(MKFLAG) ccore.mk ccore PLATFORM="32-bit" .PHONY: ccore_32bit_static ccore_32bit_static: $(MAKE) $(MKFLAG) ccore.mk ccore_static PLATFORM="32-bit" .PHONY: ccore_32bit_clean ccore_32bit_clean: $(MAKE) $(MKFLAG) ccore.mk clean PLATFORM="32-bit" .PHONY: ccore ccore: $(MAKE) $(MKFLAG) ccore.mk ccore .PHONY: ccore_clean ccore_clean: $(MAKE) $(MKFLAG) ccore.mk clean PLATFORM="64-bit" $(MAKE) $(MKFLAG) ccore.mk clean PLATFORM="32-bit" .PHONY: cppcheck cppcheck: $(MAKE) $(MKFLAG) ccore.mk cppcheck .PHONY: clang clang: $(MAKE) $(MKFLAG) ccore.mk ccore PLATFORM="64-bit" COMPILER="clang" .PHONY: ut ut: $(MAKE) $(MKFLAG) utcore.mk ut .PHONY: utdbg utdbg: $(MAKE) $(MKFLAG) utcore.mk ut CONFIG="debug" .PHONY: utrun utrun: cd tst/ && python3 ut-runner.py -e utcore .PHONY: utclean utclean: $(MAKE) $(MKFLAG) utcore.mk clean .PHONE: valgrind valgrind: $(MAKE) $(MKFLAG) utcore.mk ut CONFIG="valgrind" cd tst/ && valgrind --leak-check=full --leak-check=yes --max-threads=1000 --error-exitcode=1 ./utcore .PHONE: valgrind_shock valgrind_shock: $(MAKE) $(MKFLAG) utcore.mk ut CONFIG="valgrind" BUILD_VERSION="valgrind_shock" cd tst/ && valgrind --leak-check=full --leak-check=yes --max-threads=1000 --error-exitcode=1 ./utcore .PHONY: clean clean: $(MAKE) $(MKFLAG) ccore.mk clean $(MAKE) $(MKFLAG) ccore.mk clean PLATFORM="64-bit" $(MAKE) $(MKFLAG) ccore.mk clean PLATFORM="32-bit" $(MAKE) $(MKFLAG) utcore.mk clean pyclustering-0.10.1.2/ccore/src/000077500000000000000000000000001375753423500163615ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/CMakeLists.txt000077500000000000000000000034561375753423500211340ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # cmake_minimum_required(VERSION 3.10) # C++ standard set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) # Required packages find_package(Threads REQUIRED) # Sources file(GLOB_RECURSE PYCLUSTERING_SOURCES "*.cpp") # Headers include_directories(${PROJECT_SOURCE_DIR}/include) # Build targets add_library(pyclustering-static STATIC ${PYCLUSTERING_SOURCES}) target_link_libraries(pyclustering-static Threads::Threads) add_library(pyclustering-shared SHARED ${PYCLUSTERING_SOURCES}) target_compile_definitions(pyclustering-shared PUBLIC EXPORT_PYCLUSTERING_INTERFACE) target_link_libraries(pyclustering-shared Threads::Threads) set_target_properties(pyclustering-shared PROPERTIES OUTPUT_NAME "pyclustering") add_library(pyclustering SHARED ${PYCLUSTERING_SOURCES}) target_compile_definitions(pyclustering PUBLIC EXPORT_PYCLUSTERING_INTERFACE) target_link_libraries(pyclustering Threads::Threads) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(PYCLUSTERING_BINARY_DIR "pyclustering/core/64-bit") elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) set(PYCLUSTERING_BINARY_DIR "pyclustering/core/32-bit") endif() if (UNIX) string(CONCAT PYCLUSTERING_BINARY_DIR ${PYCLUSTERING_BINARY_DIR} "/linux") elseif (WIN32) string(CONCAT PYCLUSTERING_BINARY_DIR ${PYCLUSTERING_BINARY_DIR} "/win") elseif (APPLE) string(CONCAT PYCLUSTERING_BINARY_DIR ${PYCLUSTERING_BINARY_DIR} "/macos") endif() string(CONCAT PYCLUSTERING_BINARY_DIR "${PROJECT_SOURCE_DIR}/../" ${PYCLUSTERING_BINARY_DIR}) add_custom_command(TARGET pyclustering-shared POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ ${PYCLUSTERING_BINARY_DIR} COMMENT "Copying pyclustering binary to the package '${PYCLUSTERING_BINARY_DIR}'." ) pyclustering-0.10.1.2/ccore/src/cluster/000077500000000000000000000000001375753423500200425ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/cluster/agglomerative.cpp000077500000000000000000000172061375753423500234050ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { agglomerative::agglomerative() : m_number_clusters(1), m_similarity(type_link::SINGLE_LINK), m_centers(0), m_ptr_clusters(nullptr), m_ptr_data(nullptr) { } agglomerative::agglomerative(const size_t number_clusters, const type_link link) : m_number_clusters(number_clusters), m_similarity(link), m_centers(0), m_ptr_clusters(nullptr), m_ptr_data(nullptr) { } void agglomerative::process(const dataset & p_data, agglomerative_data & p_result) { m_ptr_data = &p_data; m_ptr_clusters = &p_result.clusters(); m_centers.clear(); m_ptr_clusters->clear(); size_t current_number_clusters = p_data.size(); m_centers.resize(current_number_clusters); m_ptr_clusters->resize(current_number_clusters); std::copy(p_data.begin(), p_data.end(), m_centers.begin()); for (size_t i = 0; i < p_data.size(); i++) { (*m_ptr_clusters)[i].push_back(i); } while(current_number_clusters > m_number_clusters) { merge_similar_clusters(); current_number_clusters = m_ptr_clusters->size(); } m_ptr_data = nullptr; } void agglomerative::merge_similar_clusters() { switch(m_similarity) { case type_link::SINGLE_LINK: merge_by_signle_link(); break; case type_link::COMPLETE_LINK: merge_by_complete_link(); break; case type_link::AVERAGE_LINK: merge_by_average_link(); break; case type_link::CENTROID_LINK: merge_by_centroid_link(); break; default: throw std::runtime_error("Unknown type of similarity is used."); } } void agglomerative::merge_by_average_link() { double minimum_average_distance = std::numeric_limits::max(); const std::vector & data = *m_ptr_data; size_t index1 = 0; size_t index2 = 1; for (size_t index_cluster1 = 0; index_cluster1 < m_ptr_clusters->size(); index_cluster1++) { for (size_t index_cluster2 = index_cluster1 + 1; index_cluster2 < m_ptr_clusters->size(); index_cluster2++) { double candidate_average_distance = 0.0; for (auto index_object1 : (*m_ptr_clusters)[index_cluster1]) { for (auto index_object2 : (*m_ptr_clusters)[index_cluster2]) { candidate_average_distance += euclidean_distance_square(data[index_object1], data[index_object2]); } } candidate_average_distance /= ((*m_ptr_clusters)[index_cluster1].size() + (*m_ptr_clusters)[index_cluster2].size()); if (candidate_average_distance < minimum_average_distance) { minimum_average_distance = candidate_average_distance; index1 = index_cluster1; index2 = index_cluster2; } } } (*m_ptr_clusters)[index1].insert((*m_ptr_clusters)[index1].end(), (*m_ptr_clusters)[index2].begin(), (*m_ptr_clusters)[index2].end()); m_ptr_clusters->erase(m_ptr_clusters->begin() + index2); } void agglomerative::merge_by_centroid_link() { double minimum_average_distance = std::numeric_limits::max(); size_t index_cluster1 = 0; size_t index_cluster2 = 1; for (size_t index1 = 0; index1 < m_centers.size(); index1++) { for (size_t index2 = index1 + 1; index2 < m_centers.size(); index2++) { double distance = euclidean_distance_square(m_centers[index1], m_centers[index2]); if (distance < minimum_average_distance) { minimum_average_distance = distance; index_cluster1 = index1; index_cluster2 = index2; } } } (*m_ptr_clusters)[index_cluster1].insert((*m_ptr_clusters)[index_cluster1].end(), (*m_ptr_clusters)[index_cluster2].begin(), (*m_ptr_clusters)[index_cluster2].end()); calculate_center((*m_ptr_clusters)[index_cluster1], m_centers[index_cluster2]); m_ptr_clusters->erase(m_ptr_clusters->begin() + index_cluster2); m_centers.erase(m_centers.begin() + index_cluster2); } void agglomerative::merge_by_complete_link() { double minimum_complete_distance = std::numeric_limits::max(); size_t index1 = 0; size_t index2 = 1; const std::vector & data = *m_ptr_data; for (size_t index_cluster1 = 0; index_cluster1 < m_ptr_clusters->size(); index_cluster1++) { for (size_t index_cluster2 = index_cluster1 + 1; index_cluster2 < m_ptr_clusters->size(); index_cluster2++) { double candidate_maximum_distance = 0.0; for (auto index_object1 : (*m_ptr_clusters)[index_cluster1]) { for (auto index_object2 : (*m_ptr_clusters)[index_cluster2]) { double distance = euclidean_distance_square(data[index_object1], data[index_object2]); if (distance > candidate_maximum_distance) { candidate_maximum_distance = distance; } } } if (candidate_maximum_distance < minimum_complete_distance) { minimum_complete_distance = candidate_maximum_distance; index1 = index_cluster1; index2 = index_cluster2; } } } (*m_ptr_clusters)[index1].insert((*m_ptr_clusters)[index1].end(), (*m_ptr_clusters)[index2].begin(), (*m_ptr_clusters)[index2].end()); m_ptr_clusters->erase(m_ptr_clusters->begin() + index2); } void agglomerative::merge_by_signle_link() { double minimum_single_distance = std::numeric_limits::max(); size_t index1 = 0; size_t index2 = 1; const std::vector & data = *m_ptr_data; for (size_t index_cluster1 = 0; index_cluster1 < m_ptr_clusters->size(); index_cluster1++) { for (size_t index_cluster2 = index_cluster1 + 1; index_cluster2 < m_ptr_clusters->size(); index_cluster2++) { double candidate_minimum_distance = std::numeric_limits::max(); for (auto index_object1 : (*m_ptr_clusters)[index_cluster1]) { for (auto index_object2 : (*m_ptr_clusters)[index_cluster2]) { double distance = euclidean_distance_square(data[index_object1], data[index_object2]); if (distance < candidate_minimum_distance) { candidate_minimum_distance = distance; } } } if (candidate_minimum_distance < minimum_single_distance) { minimum_single_distance = candidate_minimum_distance; index1 = index_cluster1; index2 = index_cluster2; } } } (*m_ptr_clusters)[index1].insert((*m_ptr_clusters)[index1].end(), (*m_ptr_clusters)[index2].begin(), (*m_ptr_clusters)[index2].end()); m_ptr_clusters->erase(m_ptr_clusters->begin() + index2); } void agglomerative::calculate_center(const cluster & cluster, point & center) const { const std::vector & data = *m_ptr_data; const size_t dimension = data[0].size(); center.resize(dimension, 0.0); for (auto index_point : cluster) { for (size_t index_dimension = 0; index_dimension < dimension; index_dimension++) { center[index_dimension] += data[index_point][index_dimension]; } } for (size_t index_dimension = 0; index_dimension < dimension; index_dimension++) { center[index_dimension] /= cluster.size(); } } } } pyclustering-0.10.1.2/ccore/src/cluster/bsas.cpp000077500000000000000000000037371375753423500215130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { bsas::bsas(const std::size_t p_amount, const double p_threshold, const distance_metric & p_metric) : m_threshold(p_threshold), m_amount(p_amount), m_metric(p_metric) { } void bsas::process(const dataset & p_data, bsas_data & p_result) { m_result_ptr = &p_result; cluster_sequence & clusters = m_result_ptr->clusters(); representative_sequence & representatives = m_result_ptr->representatives(); clusters.push_back({ 0 }); representatives.push_back( p_data[0] ); for (std::size_t i = 1; i < p_data.size(); i++) { auto nearest = find_nearest_cluster(p_data[i]); if ( (nearest.m_distance > m_threshold) && (clusters.size() < m_amount) ) { representatives.push_back(p_data[i]); clusters.push_back({ i }); } else { clusters[nearest.m_index].push_back(i); update_representative(nearest.m_index, p_data[i]); } } } bsas::nearest_cluster bsas::find_nearest_cluster(const point & p_point) const { bsas::nearest_cluster result; for (std::size_t i = 0; i < m_result_ptr->clusters().size(); i++) { double distance = m_metric(p_point, m_result_ptr->representatives()[i]); if (distance < result.m_distance) { result.m_distance = distance; result.m_index = i; } } return result; } void bsas::update_representative(const std::size_t p_index, const point & p_point) { auto len = static_cast(m_result_ptr->clusters().size()); auto & rep = m_result_ptr->representatives()[p_index]; for (std::size_t dim = 0; dim < rep.size(); dim++) { rep[dim] = ( (len - 1) * rep[dim] + p_point[dim] ) / len; } } } }pyclustering-0.10.1.2/ccore/src/cluster/clique.cpp000077500000000000000000000150221375753423500220330ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace clst { coordinate_iterator::coordinate_iterator(const std::size_t p_dimension, const std::size_t p_edge) : m_dimension(p_dimension), m_edge(p_edge), m_coordinate(p_dimension, std::size_t(0)) { } const clique_block_location & coordinate_iterator::get_coordinate() const noexcept { return m_coordinate; } clique_block_location & coordinate_iterator::get_coordinate() noexcept { return m_coordinate; } coordinate_iterator & coordinate_iterator::operator++() { for (std::size_t index_dimension = 0; index_dimension < m_dimension; ++index_dimension) { if (m_coordinate[index_dimension] + 1 < m_edge) { ++m_coordinate[index_dimension]; return *this; } else { m_coordinate[index_dimension] = 0; } } m_coordinate = clique_block_location(m_dimension, 0); return *this; } clique::clique(const std::size_t p_intervals, const std::size_t p_threshold) : m_intervals(p_intervals), m_density_threshold(p_threshold) { } void clique::process(const dataset & p_data, clique_data & p_result) { m_data_ptr = &p_data; m_result_ptr = &p_result; create_grid(); for (auto & block : m_result_ptr->blocks()) { if (!block.is_visited()) { expand_cluster(block); } } m_cells_map.clear(); } void clique::expand_cluster(clique_block & p_block) { p_block.touch(); const auto & points = p_block.get_points(); if (points.size() <= m_density_threshold) { if (!points.empty()) { m_result_ptr->noise().insert(m_result_ptr->noise().end(), points.begin(), points.end()); } return; } m_result_ptr->clusters().push_back({ }); cluster & cur_cluster = m_result_ptr->clusters().back(); cur_cluster.insert(cur_cluster.end(), p_block.get_points().begin(), p_block.get_points().end()); std::list neighbors; get_neighbors(p_block, neighbors); for (clique_block * neighbor : neighbors) { const auto & points = neighbor->get_points(); if (points.size() > m_density_threshold) { cur_cluster.insert(cur_cluster.end(), points.begin(), points.end()); get_neighbors(*neighbor, neighbors); } else if (!points.empty()) { m_result_ptr->noise().insert(m_result_ptr->noise().end(), points.begin(), points.end()); } } } void clique::get_neighbors(const clique_block & p_block, std::list & p_neighbors) const { std::vector location_neighbors; p_block.get_location_neighbors(m_intervals, location_neighbors); for (const auto & location : location_neighbors) { const std::string key = location_to_key(location); clique_block * candidate = m_cells_map.at(key); if (!candidate->is_visited()) { candidate->touch(); p_neighbors.push_back(candidate); } } } void clique::create_grid() { clique::data_info info; get_data_info(info); const std::size_t dimension = m_data_ptr->at(0).size(); const auto amount_blocks = static_cast(std::pow(m_intervals, dimension)); auto & blocks = m_result_ptr->blocks(); blocks.reserve(amount_blocks); auto iterator = coordinate_iterator(dimension, m_intervals); std::vector point_availability(m_data_ptr->size(), true); for (std::size_t i = 0; i < amount_blocks; ++i) { clique_block_location logical_location = iterator.get_coordinate(); ++iterator; clique_spatial_block spatial_block; get_spatial_location(logical_location, info, spatial_block); clique_block cell(logical_location, std::move(spatial_block)); cell.capture_points(*m_data_ptr, point_availability); blocks.push_back(std::move(cell)); m_cells_map.insert({ location_to_key(blocks.back().get_logical_location()), &(blocks.back()) }); } } std::string clique::location_to_key(const clique_block_location & p_location) { std::string result; for (const auto coordinate : p_location) { result += std::to_string(coordinate) + '.'; } return result; } void clique::get_spatial_location(const clique_block_location & p_location, const clique::data_info & p_info, clique_spatial_block & p_block) const { point min_corner = p_info.m_min_corner; point max_corner = p_info.m_max_corner; const std::size_t dimension = m_data_ptr->at(0).size(); std::vector cell_sizes(dimension, 0.0); for (std::size_t i = 0; i < cell_sizes.size(); ++i) { cell_sizes[i] = p_info.m_sizes[i] / m_intervals; } for (std::size_t index_dimension = 0; index_dimension < dimension; ++index_dimension) { min_corner[index_dimension] += cell_sizes[index_dimension] * p_location[index_dimension]; if (p_location[index_dimension] == m_intervals - 1) { max_corner[index_dimension] = p_info.m_max_corner[index_dimension]; } else { max_corner[index_dimension] = min_corner[index_dimension] + cell_sizes[index_dimension]; } } p_block.move_max_corner(std::move(max_corner)); p_block.move_min_corner(std::move(min_corner)); } void clique::get_data_info(clique::data_info & p_info) const { p_info.m_min_corner = m_data_ptr->at(0); p_info.m_max_corner = p_info.m_min_corner; const std::size_t dimension = p_info.m_min_corner.size(); const dataset & data = *m_data_ptr; for (const auto & data_point : data) { for (std::size_t index_dimension = 0; index_dimension < dimension; ++index_dimension) { const double coordinate = data_point[index_dimension]; if (coordinate > p_info.m_max_corner[index_dimension]) { p_info.m_max_corner[index_dimension] = coordinate; } if (coordinate < p_info.m_min_corner[index_dimension]) { p_info.m_min_corner[index_dimension] = coordinate; } } } for (std::size_t index_dimension = 0; index_dimension < dimension; ++index_dimension) { p_info.m_sizes.push_back(p_info.m_max_corner[index_dimension] - p_info.m_min_corner[index_dimension]); } } } }pyclustering-0.10.1.2/ccore/src/cluster/clique_block.cpp000077500000000000000000000060231375753423500232060ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { clique_spatial_block::clique_spatial_block(const point & p_max_corner, const point & p_min_corner) : m_max_corner(p_max_corner), m_min_corner(p_min_corner) { } bool clique_spatial_block::contains(const point & p_point) const { for (std::size_t i = 0; i < p_point.size(); ++i) { if ((p_point[i] < m_min_corner[i]) || (p_point[i] > m_max_corner[i])) { return false; } } return true; } const point & clique_spatial_block::get_max_corner() const { return m_max_corner; } void clique_spatial_block::move_max_corner(point && p_corner) { m_max_corner = std::move(p_corner); } const point & clique_spatial_block::get_min_corner() const { return m_min_corner; } void clique_spatial_block::move_min_corner(point && p_corner) { m_min_corner = std::move(p_corner); } clique_block::clique_block(const clique_block_location & p_location, const clique_spatial_block & p_block) : m_logical_location(p_location), m_spatial_location(p_block), m_points(), m_visited(false) { } clique_block::clique_block(clique_block_location && p_location, clique_spatial_block && p_block) : m_logical_location(std::move(p_location)), m_spatial_location(std::move(p_block)), m_points(), m_visited(false) { } const clique_block_location & clique_block::get_logical_location() const { return m_logical_location; } const clique_spatial_block & clique_block::get_spatial_block() const { return m_spatial_location; } const clique_block::content & clique_block::get_points() const { return m_points; } bool clique_block::is_visited() const { return m_visited; } void clique_block::touch() { m_visited = true; } void clique_block::capture_points(const dataset & p_data, std::vector & p_availability) { for (std::size_t index_point = 0; index_point < p_data.size(); ++index_point) { if (p_availability[index_point] && m_spatial_location.contains(p_data[index_point])) { m_points.push_back(index_point); p_availability[index_point] = false; } } } void clique_block::get_location_neighbors(const std::size_t p_edge, std::vector & p_neighbors) const { for (std::size_t index_dimension = 0; index_dimension < m_logical_location.size(); ++index_dimension) { if (m_logical_location[index_dimension] + 1 < p_edge) { clique_block_location position = m_logical_location; ++position[index_dimension]; p_neighbors.push_back(position); } if (m_logical_location[index_dimension] != 0) { clique_block_location position = m_logical_location; --position[index_dimension]; p_neighbors.push_back(position); } } } } }pyclustering-0.10.1.2/ccore/src/cluster/cluster_data.cpp000077500000000000000000000023251375753423500232250ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { cluster_sequence & cluster_data::clusters() { return m_clusters; } const cluster_sequence & cluster_data::clusters() const { return m_clusters; } size_t cluster_data::size() const { return m_clusters.size(); } cluster & cluster_data::operator[](const size_t p_index) { return m_clusters[p_index]; } const cluster & cluster_data::operator[](const size_t p_index) const { return m_clusters[p_index]; } cluster_data & cluster_data::operator=(const cluster_data & p_other) { if (this != &p_other) { m_clusters = p_other.m_clusters; } return *this; } cluster_data & cluster_data::operator=(cluster_data && p_other) { if (this != &p_other) { m_clusters = std::move(p_other.m_clusters); } return *this; } bool cluster_data::operator==(const cluster_data & p_other) const { return (m_clusters == p_other.m_clusters); } bool cluster_data::operator!=(const cluster_data & p_other) const { return !(*this == p_other); } } }pyclustering-0.10.1.2/ccore/src/cluster/cure.cpp000077500000000000000000000355411375753423500215170ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include using namespace pyclustering::container; using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { cure_cluster::cure_cluster() : mean(nullptr), closest(nullptr), distance_closest(0) { points = new std::vector< std::vector * >(); rep = new std::vector< std::vector * >(); } cure_cluster::cure_cluster(std::vector * point) : closest(nullptr), distance_closest(0) { mean = new std::vector(*point); points = new std::vector< std::vector * >(1, point); /* use user data points */ rep = new std::vector< std::vector * >(1, new std::vector(*point)); /* it's our - despite at the beginning it the same */ } cure_cluster::~cure_cluster() { if (mean != nullptr) { delete mean; mean = nullptr; } delete points; /* only storage, we are not owners of points */ points = nullptr; for (auto point_ptr : *rep) { delete point_ptr; } delete rep; /* only storage, we are not owners of points */ rep = nullptr; } void cure_cluster::insert_points(std::vector *> * append_points) { points->insert(points->end(), append_points->begin(), append_points->end()); } std::ostream & operator<<(std::ostream & p_stream, cure_cluster & p_cluster) { p_stream << p_cluster.distance_closest << "["; for (auto & point : *(p_cluster.points)) { p_stream << "[ "; for (auto & coordinate : *point) { p_stream << coordinate << " "; } p_stream << "]"; } p_stream << "]"; return p_stream; } bool cure_cluster_comparator::operator()(const cure_cluster * const obj1, const cure_cluster * const obj2) const { return obj1->distance_closest < obj2->distance_closest; } cure_queue::cure_queue() { queue = new std::multiset(); tree = new kdtree(); } cure_queue::cure_queue(const std::vector< std::vector > * data) { queue = new std::multiset(); create_queue(data); std::vector points; std::vector payloads; points.reserve(data->size()); payloads.reserve(data->size()); for (auto cluster : *queue) { for (auto point : *(cluster->rep)) { points.push_back(*point); payloads.push_back((void *) cluster); } } tree = new kdtree(points, payloads); } cure_queue::~cure_queue() { if (queue != nullptr) { for (auto cluster : *queue) { delete cluster; } delete queue; queue = nullptr; } if (tree != nullptr) { delete tree; tree = nullptr; } } void cure_queue::create_queue(const dataset * data) { std::list temporary_storage; for (auto & data_point : (*data)) { cure_cluster * cluster = new cure_cluster((std::vector *) &data_point); temporary_storage.push_back(cluster); } for (auto & first_cluster : temporary_storage) { double minimal_distance = std::numeric_limits::max(); cure_cluster * closest_cluster = nullptr; for (auto & second_cluster : temporary_storage) { if (first_cluster != second_cluster) { double dist = get_distance(first_cluster, second_cluster); if (dist < minimal_distance) { minimal_distance = dist; closest_cluster = second_cluster; } } } first_cluster->closest = closest_cluster; first_cluster->distance_closest = minimal_distance; } for (const auto & cluster : temporary_storage) { queue->insert(cluster); } } double cure_queue::get_distance(cure_cluster * cluster1, cure_cluster * cluster2) { double distance = std::numeric_limits::max(); for (auto & point1 : *(cluster1->rep)) { for (auto & point2 : *(cluster2->rep)) { double candidate_distance = euclidean_distance_square(*point1, *point2); if (candidate_distance < distance) { distance = candidate_distance; } } } return distance; } bool cure_queue::are_all_elements_same(cure_cluster * merged_cluster) { auto & data_points = *(merged_cluster->points); auto & first_point = data_points.front(); for (std::size_t i = 1; i < data_points.size(); i++) { if (data_points[i] != first_point) { return false; } } return true; } void cure_queue::merge(cure_cluster * cluster1, cure_cluster * cluster2, const size_t number_repr_points, const double compression) { remove_representative_points(cluster1); remove_representative_points(cluster2); remove_cluster(cluster1); remove_cluster(cluster2); cure_cluster * merged_cluster = new cure_cluster(); merged_cluster->insert_points(cluster1->points); merged_cluster->insert_points(cluster2->points); merged_cluster->mean = new std::vector((*cluster1->points)[0]->size(), 0); //If all elements were same then avoid calculating the mean mathematically as it may lead to precision error. if (are_all_elements_same(merged_cluster)) { for (std::size_t i = 0; i < (*merged_cluster->points)[0]->size(); i++) { (*merged_cluster->mean)[i] = (*(*merged_cluster->points)[0])[i]; } } else { for (std::size_t dimension = 0; dimension < merged_cluster->mean->size(); dimension++) { (*merged_cluster->mean)[dimension] = (cluster1->points->size() * (*cluster1->mean)[dimension] + cluster2->points->size() * (*cluster2->mean)[dimension]) / (cluster1->points->size() + cluster2->points->size()); } } std::set *> * temporary = new std::set *>(); for (std::size_t index = 0; index < number_repr_points; index++) { double maximal_distance = 0; std::vector * maximal_point = nullptr; for (auto & point : *(merged_cluster->points)) { double minimal_distance = 0; if (index == 0) { minimal_distance = euclidean_distance_square(*point, *(merged_cluster->mean)); } else { double temp_minimal_distance = std::numeric_limits::max(); for (auto p : (*temporary)) { double minimal_candidate = euclidean_distance_square(*point, *p); if (minimal_candidate < temp_minimal_distance) { temp_minimal_distance = minimal_candidate; } } minimal_distance = temp_minimal_distance; } if (minimal_distance >= maximal_distance) { maximal_distance = minimal_distance; maximal_point = point; } } if (temporary->find(maximal_point) == temporary->end()) { temporary->insert(maximal_point); } } for (auto & point : *temporary) { std::vector * representative_point = new std::vector(point->size(), 0); for (std::size_t index = 0; index < point->size(); index++) { (*representative_point)[index] = (*point)[index] + compression * ( (*merged_cluster->mean)[index] - (*point)[index] ); } merged_cluster->rep->push_back(representative_point); } delete temporary; temporary = nullptr; insert_representative_points(merged_cluster); std::list relocation_request; if (!queue->empty()) { merged_cluster->closest = *(queue->begin()); merged_cluster->distance_closest = get_distance(merged_cluster, merged_cluster->closest); /* relocation request */ for (auto iterator_cluster = queue->begin(); iterator_cluster != queue->end(); iterator_cluster++) { auto cluster = *iterator_cluster; const double distance = get_distance(merged_cluster, cluster); const double real_euclidean_distance = std::sqrt(distance); /* Check if distance between new cluster and current is the best than now. */ if (distance < merged_cluster->distance_closest) { merged_cluster->closest = cluster; merged_cluster->distance_closest = distance; } /* Check if current cluster has removed neighbor. */ if ( (cluster->closest == cluster1) || (cluster->closest == cluster2) ) { /* If previous distance was less then distance to new cluster then nearest cluster should be found in the tree. */ if (cluster->distance_closest < distance) { cure_cluster * nearest_cluster = nullptr; double nearest_distance = std::numeric_limits::max(); for (auto & point : *(cluster->rep)) { /* we are using Eucliean Square metric, but kdtree searcher requires common Eucliean distance (but output results are square) */ kdtree_searcher searcher(*point, tree->get_root(), real_euclidean_distance); std::vector nearest_node_distances; std::vector nearest_nodes; searcher.find_nearest_nodes(nearest_node_distances, nearest_nodes); for (std::size_t index = 0; index < nearest_nodes.size(); index++) { if ( (nearest_node_distances[index] < nearest_distance) && ( nearest_nodes[index]->get_payload() != cluster ) ) { nearest_distance = nearest_node_distances[index]; nearest_cluster = static_cast(nearest_nodes[index]->get_payload()); } } } if (nearest_cluster == nullptr) { relocation_request.emplace_back(iterator_cluster, merged_cluster, distance); } else { relocation_request.emplace_back(iterator_cluster, nearest_cluster, nearest_distance); } } else { relocation_request.emplace_back(iterator_cluster, merged_cluster, distance); } } } } delete cluster1; cluster1 = nullptr; delete cluster2; cluster2 = nullptr; /* insert merged cluster */ insert_cluster(merged_cluster); /* relocate requested clusters */ if (!relocation_request.empty()) { for (auto & info : relocation_request) { auto cluster = *(info.get_cluster_iterator()); queue->erase(info.get_cluster_iterator()); cluster->closest = info.get_closest_cluster(); cluster->distance_closest = info.get_closest_distance(); insert_cluster(cluster); } } } void cure_queue::insert_cluster(cure_cluster * inserted_cluster) { queue->insert(inserted_cluster); } void cure_queue::remove_cluster(cure_cluster * removed_cluster) { auto range = queue->equal_range(removed_cluster); for (auto iter = range.first; iter != range.second; iter++) { if (*iter == removed_cluster) { queue->erase(iter); return; } } throw std::runtime_error("CURE queue corruption detected, impossible to remove cluster from the queue. Please report to 'pyclustering@yandex.ru'."); } void cure_queue::remove_representative_points(cure_cluster * cluster) { for (auto & point : *(cluster->rep)) { tree->remove(*point, (void *) cluster); } } void cure_queue::insert_representative_points(cure_cluster * cluster) { for (auto & point : *(cluster->rep)) { tree->insert(*point, cluster); } } relocation_info::relocation_info(const cure_queue::iterator & cluster_iterator, cure_cluster * closest_cluster, const double closest_distance) : m_cluster_iterator(cluster_iterator), m_closest_cluster(closest_cluster), m_closest_distance(closest_distance) { } cure_queue::iterator relocation_info::get_cluster_iterator() const { return m_cluster_iterator; } cure_cluster * relocation_info::get_closest_cluster() { return m_closest_cluster; } double relocation_info::get_closest_distance() const { return m_closest_distance; } cure::cure(const size_t clusters_number, size_t points_number, const double level_compression) : queue(nullptr), number_points(points_number), number_clusters(clusters_number), compression(level_compression), data(nullptr) { } cure::~cure() { delete queue; } void cure::process(const dataset & p_data, cure_data & p_result) { delete queue; queue = new cure_queue(&p_data); data = &p_data; std::size_t allocated_clusters = queue->size(); while(allocated_clusters > number_clusters) { cure_cluster * cluster1 = *(queue->begin()); cure_cluster * cluster2 = cluster1->closest; /* merge new cluster using these clusters */ queue->merge(cluster1, cluster2, number_points, compression); allocated_clusters = queue->size(); } cure_data & result = p_result; /* prepare standard representation of clusters */ cluster_sequence & clusters = result.clusters(); representor_sequence & representors = result.representors(); clusters.resize(queue->size()); representors.resize(queue->size()); size_t cluster_index = 0; for (auto cure_cluster = queue->begin(); cure_cluster != queue->end(); ++cure_cluster, cluster_index++) { cluster & standard_cluster = clusters[cluster_index]; for (auto point = (*cure_cluster)->points->begin(); point != (*cure_cluster)->points->end(); ++point) { size_t index_point = (size_t) (*point - &(*(data->begin()))); standard_cluster.push_back(index_point); } dataset & cluster_representors = representors[cluster_index]; for (auto point : *(*cure_cluster)->rep) { cluster_representors.push_back(*point); } result.means().push_back((*(*cure_cluster)->mean)); } delete queue; queue = nullptr; } } } pyclustering-0.10.1.2/ccore/src/cluster/dbscan.cpp000077500000000000000000000124171375753423500220100ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include namespace pyclustering { namespace clst { dbscan::dbscan(const double p_radius_connectivity, const size_t p_minimum_neighbors) : m_data_ptr(nullptr), m_result_ptr(nullptr), m_visited(std::vector()), m_belong(std::vector()), m_initial_radius(p_radius_connectivity), m_neighbors(p_minimum_neighbors) { } void dbscan::process(const dataset & p_data, dbscan_data & p_result) { process(p_data, dbscan_data_t::POINTS, p_result); } void dbscan::process(const dataset & p_data, const dbscan_data_t p_type, dbscan_data & p_result) { m_data_ptr = &p_data; m_type = p_type; if (m_type == dbscan_data_t::POINTS) { create_kdtree(*m_data_ptr); } m_visited = std::vector(m_data_ptr->size(), false); m_belong = m_visited; m_result_ptr = &p_result; for (size_t i = 0; i < m_data_ptr->size(); i++) { if (m_visited[i]) { continue; } m_visited[i] = true; /* expand cluster */ cluster allocated_cluster; expand_cluster(i, allocated_cluster); if (!allocated_cluster.empty()) { m_result_ptr->clusters().emplace_back(std::move(allocated_cluster)); } } for (size_t i = 0; i < m_data_ptr->size(); i++) { if (!m_belong[i]) { m_result_ptr->noise().emplace_back(i); } } m_data_ptr = nullptr; m_result_ptr = nullptr; } void dbscan::expand_cluster(const std::size_t p_index, cluster & allocated_cluster) { std::vector index_matrix_neighbors; get_neighbors(p_index, index_matrix_neighbors); if (index_matrix_neighbors.size() >= m_neighbors) { allocated_cluster.push_back(p_index); m_belong[p_index] = true; for (std::size_t k = 0; k < index_matrix_neighbors.size(); k++) { std::size_t index_neighbor = index_matrix_neighbors[k]; if (!m_visited[index_neighbor]) { m_visited[index_neighbor] = true; /* check for neighbors of the current neighbor - maybe it's noise */ std::vector neighbor_neighbor_indexes; get_neighbors(index_neighbor, neighbor_neighbor_indexes); if (neighbor_neighbor_indexes.size() >= m_neighbors) { /* Add neighbors of the neighbor for checking */ for (auto neighbor_index : neighbor_neighbor_indexes) { /* Check if some of neighbors already in check list */ std::vector::const_iterator position = std::find(index_matrix_neighbors.begin(), index_matrix_neighbors.end(), neighbor_index); if (position == index_matrix_neighbors.end()) { /* Add neighbor if it does not exist in the list */ index_matrix_neighbors.push_back(neighbor_index); } } } } if (!m_belong[index_neighbor]) { allocated_cluster.push_back(index_neighbor); m_belong[index_neighbor] = true; } } index_matrix_neighbors.clear(); } } void dbscan::get_neighbors(const size_t p_index, std::vector & p_neighbors) { switch(m_type) { case dbscan_data_t::POINTS: get_neighbors_from_points(p_index, p_neighbors); break; case dbscan_data_t::DISTANCE_MATRIX: get_neighbors_from_distance_matrix(p_index, p_neighbors); break; default: throw std::invalid_argument("Incorrect input data type is specified '" + std::to_string((unsigned) m_type) + "'"); } } void dbscan::get_neighbors_from_points(const size_t p_index, std::vector & p_neighbors) { container::kdtree_searcher searcher((*m_data_ptr)[p_index], m_kdtree.get_root(), m_initial_radius); searcher.find_nearest([&p_index, &p_neighbors](const container::kdnode::ptr & node, const double distance) { if (p_index != (std::size_t) node->get_payload()) { p_neighbors.push_back((std::size_t) node->get_payload()); } }); } void dbscan::get_neighbors_from_distance_matrix(const size_t p_index, std::vector & p_neighbors) { const auto & distances = m_data_ptr->at(p_index); for (std::size_t index_neighbor = 0; index_neighbor < distances.size(); index_neighbor++) { const double candidate_distance = distances[index_neighbor]; if ( (candidate_distance <= m_initial_radius) && (index_neighbor != p_index) ) { p_neighbors.push_back(index_neighbor); } } } void dbscan::create_kdtree(const dataset & p_data) { std::vector payload(p_data.size()); for (std::size_t index = 0; index < p_data.size(); index++) { payload[index] = (void *)index; } m_kdtree = container::kdtree_balanced(p_data, payload); } } }pyclustering-0.10.1.2/ccore/src/cluster/fcm.cpp000077500000000000000000000115301375753423500213160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::parallel; using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { const double fcm::DEFAULT_TOLERANCE = 0.001; const std::size_t fcm::DEFAULT_ITERMAX = 100; const double fcm::DEFAULT_HYPER_PARAMETER = 2.0; fcm::fcm(const dataset & p_initial_centers, const double p_m, const double p_tolerance, const std::size_t p_itermax) : m_tolerance(p_tolerance), m_itermax(p_itermax), m_initial_centers(p_initial_centers) { if (p_m <= 1.0) { throw std::invalid_argument("Hyper parameter should be greater than 1.0."); } m_degree = 2.0 / (p_m - 1.0); } void fcm::process(const dataset & p_data, fcm_data & p_result) { m_ptr_data = &p_data; m_ptr_result = &p_result; m_ptr_result->centers().assign(m_initial_centers.begin(), m_initial_centers.end()); if (m_itermax == 0) { return; } m_ptr_result->membership().resize(m_ptr_data->size(), point(m_initial_centers.size(), 0.0)); double current_change = std::numeric_limits::max(); for(std::size_t iteration = 0; iteration < m_itermax && current_change > m_tolerance; iteration++) { update_membership(); current_change = update_centers(); } extract_clusters(m_ptr_result->clusters()); } void fcm::verify() const { if (m_ptr_data->at(0).size() != m_initial_centers[0].size()) { throw std::invalid_argument("Dimension of the input data and dimension of the initial cluster centers must be the same."); } } double fcm::update_centers() { const std::size_t amount_centers = m_ptr_result->centers().size(); std::vector changes(amount_centers, 0.0); parallel_for(std::size_t(0), amount_centers, [this, &changes](const std::size_t p_index) { changes[p_index] = update_center(p_index); }); return *(std::max_element(changes.cbegin(), changes.cend())); } double fcm::update_center(const std::size_t p_index) { const std::size_t dimensions = m_ptr_data->at(0).size(); const std::size_t data_length = m_ptr_data->size(); std::vector dividend(dimensions, 0.0); std::vector divider(dimensions, 0.0); for (std::size_t j = 0; j < data_length; j++) { for (std::size_t dimension = 0; dimension < dimensions; dimension++) { dividend[dimension] += m_ptr_data->at(j).at(dimension) * m_ptr_result->membership()[j][p_index]; divider[dimension] += m_ptr_result->membership()[j][p_index]; } } point update_center(dimensions, 0.0); for (std::size_t dimension = 0; dimension < dimensions; dimension++) { update_center[dimension] = dividend[dimension] / divider[dimension]; } double change = euclidean_distance(update_center, m_ptr_result->centers().at(p_index)); m_ptr_result->centers().at(p_index) = std::move(update_center); return change; } void fcm::update_membership() { const std::size_t data_size = m_ptr_result->membership().size(); parallel_for(std::size_t(0), data_size, [this](std::size_t p_index) { update_point_membership(p_index); }); } void fcm::update_point_membership(const std::size_t p_index) { const std::size_t center_amount = m_ptr_result->centers().size(); std::vector differences(center_amount, 0.0); for (std::size_t j = 0; j < center_amount; j++) { differences[j] = euclidean_distance_square(m_ptr_data->at(p_index), m_ptr_result->centers().at(j)); } for (std::size_t j = 0; j < center_amount; j++) { double divider = 0.0; for (std::size_t k = 0; k < center_amount; k++) { if (differences[k] != 0.0) { divider += std::pow(differences[j] / differences[k], m_degree); } } if (divider == 0.0) { m_ptr_result->membership()[p_index][j] = 1.0; } else { m_ptr_result->membership()[p_index][j] = 1.0 / divider; } } } void fcm::extract_clusters(cluster_sequence & p_clusters) { m_ptr_result->clusters() = cluster_sequence(m_ptr_result->centers().size()); for (std::size_t i = 0; i < m_ptr_data->size(); i++) { const auto & membership = m_ptr_result->membership().at(i); auto iter = std::max_element(membership.begin(), membership.end()); std::size_t index_cluster = iter - membership.begin(); m_ptr_result->clusters().at(index_cluster).push_back(i); } } } }pyclustering-0.10.1.2/ccore/src/cluster/gmeans.cpp000077500000000000000000000136061375753423500220310ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include using namespace pyclustering::parallel; using namespace pyclustering::utils::linalg; using namespace pyclustering::utils::metric; using namespace pyclustering::utils::stats; namespace pyclustering { namespace clst { const long long gmeans::IGNORE_KMAX = -1; const std::size_t gmeans::DEFAULT_AMOUNT_CENTERS = 1; const double gmeans::DEFAULT_TOLERANCE = 0.001; const std::size_t gmeans::DEFAULT_REPEAT = 3; const std::size_t gmeans::DEFAULT_CANDIDATES = 3; gmeans::gmeans(const std::size_t p_k_initial, const double p_tolerance, const std::size_t p_repeat, const long long p_kmax, const long long p_random_state) : m_amount(p_k_initial), m_tolerance(p_tolerance), m_repeat(p_repeat), m_kmax(p_kmax), m_random_state(p_random_state), m_ptr_result(nullptr), m_ptr_data(nullptr) { } void gmeans::process(const dataset & p_data, gmeans_data & p_result) { m_ptr_data = &p_data; m_ptr_result = &p_result; if (!m_ptr_result) { throw std::invalid_argument("Invalid result storage is specified: impossible to cast to 'gmeans_data'."); } search_optimal_parameters(p_data, m_amount, m_ptr_result->clusters(), m_ptr_result->centers()); while(is_run_condition()) { std::size_t current_amount_clusters = m_ptr_result->clusters().size(); statistical_optimization(); if (current_amount_clusters == m_ptr_result->centers().size()) { break; } perform_clustering(); } } bool gmeans::is_run_condition() const { if ((m_kmax != IGNORE_KMAX) && (m_ptr_result->clusters().size() >= static_cast(m_kmax))) { return false; } return true; } void gmeans::search_optimal_parameters(const dataset & p_data, const std::size_t p_amount, cluster_sequence & p_clusters, dataset & p_centers) const { double best_wce = std::numeric_limits::infinity(); cluster_sequence best_clusters = { }; dataset best_centers = { }; for (std::size_t i = 0; i < m_repeat; i++) { dataset initial_centers; kmeans_plus_plus(p_amount, get_amount_candidates(p_data), m_random_state).initialize(p_data, initial_centers); kmeans_data result; kmeans(initial_centers, m_tolerance).process(p_data, result); if (result.wce() < best_wce) { best_wce = result.wce(); best_clusters = std::move(result.clusters()); best_centers = std::move(result.centers()); } if (p_amount == 1) { break; /* No need to rerun clustering for one initial center. */ } } p_clusters = std::move(best_clusters); p_centers = std::move(best_centers); } void gmeans::statistical_optimization() { dataset centers; long long potential_amount_clusters = static_cast(m_ptr_result->clusters().size()); for (std::size_t i = 0; i < m_ptr_result->clusters().size(); i++) { dataset new_centers; split_and_search_optimal(m_ptr_result->clusters().at(i), new_centers); if (new_centers.empty() || ((m_kmax != IGNORE_KMAX) && (potential_amount_clusters >= m_kmax))) { centers.push_back(std::move(m_ptr_result->centers().at(i))); } else { centers.push_back(std::move(new_centers[0])); centers.push_back(std::move(new_centers[1])); potential_amount_clusters++; } } m_ptr_result->centers() = std::move(centers); } void gmeans::perform_clustering() { kmeans_data result; kmeans(m_ptr_result->centers(), m_tolerance).process(*m_ptr_data, result); m_ptr_result->clusters() = std::move(result.clusters()); m_ptr_result->centers() = std::move(result.centers()); m_ptr_result->wce() = result.wce(); } void gmeans::split_and_search_optimal(const cluster & p_cluster, dataset & p_centers) const { if (p_cluster.size() == 1) { return; } dataset region_points(p_cluster.size()); for (std::size_t i = 0; i < region_points.size(); i++) { region_points[i] = m_ptr_data->at(p_cluster[i]); } cluster_sequence new_clusters; dataset new_centers; search_optimal_parameters(region_points, 2, new_clusters, new_centers); if (new_centers.size() > 1) { if (!is_null_hypothesis(region_points, new_centers[0], new_centers[1])) { p_centers = std::move(new_centers); } } } bool gmeans::is_null_hypothesis(const dataset & p_data, const point & p_center1, const point & p_center2) { point v = subtract(p_center1, p_center2); projection sample = calculate_projection(p_data, v); double estimation = anderson(sample); std::vector critical = critical_values(sample.size()); return (estimation < critical.back()); /* true - Gaussian distribution, false - not a Gaussian distribution */ } std::size_t gmeans::get_amount_candidates(const dataset & p_data) { return (p_data.size() > DEFAULT_CANDIDATES) ? DEFAULT_CANDIDATES : p_data.size(); } gmeans::projection gmeans::calculate_projection(const dataset & p_data, const point & p_vector) { double square_norm = sum(multiply(p_vector, p_vector)); return divide(sum(multiply(p_data, p_vector), 1), square_norm); } } }pyclustering-0.10.1.2/ccore/src/cluster/hsyncnet.cpp000077500000000000000000000064261375753423500224140ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::utils::metric; using namespace pyclustering::nnet; namespace pyclustering { namespace clst { const double hsyncnet::DEFAULT_TIME_STEP = 1.0; const std::size_t hsyncnet::DEFAULT_INCREASE_STEP = 1; hsyncnet::hsyncnet(dataset * input_data, const std::size_t cluster_number, const initial_type initial_phases) : syncnet(input_data, 0, false, initial_phases), m_number_clusters(cluster_number), m_initial_neighbors(3), m_increase_persent(0.15), m_time(0.0) { } hsyncnet::hsyncnet(dataset * input_data, const std::size_t cluster_number, const initial_type initial_phases, const std::size_t initial_neighbors, const double increase_persent) : syncnet(input_data, 0, false, initial_phases), m_number_clusters(cluster_number), m_initial_neighbors(initial_neighbors), m_increase_persent(increase_persent), m_time(0.0) { } void hsyncnet::process(const double order, const solve_type solver, const bool collect_dynamic, hsyncnet_analyser & analyser) { std::size_t number_neighbors = m_initial_neighbors; std::size_t current_number_clusters = m_oscillators.size(); if (current_number_clusters <= m_number_clusters) { return; /* Nothing to process, amount of objects is less than required amount of clusters. */ } double radius = average_neighbor_distance(oscillator_locations, number_neighbors); std::size_t increase_step = static_cast(round(oscillator_locations->size() * static_cast(m_increase_persent))); if (increase_step < 1) { increase_step = DEFAULT_INCREASE_STEP; } sync_dynamic current_dynamic; do { create_connections(radius, false); simulate_dynamic(order, 0.1, solver, collect_dynamic, current_dynamic); if (collect_dynamic) { if (analyser.empty()) { store_state(*(current_dynamic.begin()), analyser); } store_state(*(current_dynamic.end() - 1), analyser); } else { m_time += DEFAULT_TIME_STEP; } hsyncnet_cluster_data clusters; current_dynamic.allocate_sync_ensembles(0.05, clusters); current_number_clusters = clusters.size(); number_neighbors += increase_step; radius = calculate_radius(radius, number_neighbors); } while(current_number_clusters > m_number_clusters); if (!collect_dynamic) { store_state(*(current_dynamic.end() - 1), analyser); } } void hsyncnet::store_state(sync_network_state & state, hsyncnet_analyser & analyser) { state.m_time = m_time; analyser.push_back(state); m_time += DEFAULT_TIME_STEP; } double hsyncnet::calculate_radius(const double radius, const std::size_t amount_neighbors) const { double next_radius = 0.0; if (amount_neighbors >= oscillator_locations->size()) { next_radius = radius * m_increase_persent + radius; } else { next_radius = average_neighbor_distance(oscillator_locations, amount_neighbors); } return next_radius; } } }pyclustering-0.10.1.2/ccore/src/cluster/kmeans.cpp000077500000000000000000000153731375753423500220400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include using namespace pyclustering::parallel; using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { const double kmeans::DEFAULT_TOLERANCE = 0.001; const std::size_t kmeans::DEFAULT_ITERMAX = 100; kmeans::kmeans(const dataset & p_initial_centers, const double p_tolerance, const std::size_t p_itermax, const distance_metric & p_metric) : m_tolerance(p_tolerance), m_itermax(p_itermax), m_initial_centers(p_initial_centers), m_ptr_result(nullptr), m_ptr_data(nullptr), m_metric(p_metric) { } void kmeans::process(const dataset & p_data, kmeans_data & p_result) { process(p_data, { }, p_result); } void kmeans::process(const dataset & p_data, const index_sequence & p_indexes, kmeans_data & p_result) { m_ptr_data = &p_data; m_ptr_indexes = &p_indexes; m_ptr_result = &p_result; if (p_data[0].size() != m_initial_centers[0].size()) { throw std::invalid_argument("Dimension of the input data and dimension of the initial cluster centers must be the same."); } m_ptr_result->centers().assign(m_initial_centers.begin(), m_initial_centers.end()); if (m_ptr_result->is_observed()) { cluster_sequence sequence; update_clusters(m_initial_centers, sequence); m_ptr_result->evolution_centers().push_back(m_initial_centers); m_ptr_result->evolution_clusters().push_back(sequence); } double current_change = std::numeric_limits::max(); for(std::size_t iteration = 0; iteration < m_itermax && current_change > m_tolerance; iteration++) { update_clusters(m_ptr_result->centers(), m_ptr_result->clusters()); current_change = update_centers(m_ptr_result->clusters(), m_ptr_result->centers()); if (m_ptr_result->is_observed()) { m_ptr_result->evolution_centers().push_back(m_ptr_result->centers()); m_ptr_result->evolution_clusters().push_back(m_ptr_result->clusters()); } } calculate_total_wce(); } void kmeans::update_clusters(const dataset & p_centers, cluster_sequence & p_clusters) { const dataset & data = *m_ptr_data; p_clusters.clear(); p_clusters.resize(p_centers.size()); /* fill clusters again in line with centers. */ if (m_ptr_indexes->empty()) { index_sequence winners(data.size(), 0); parallel_for(std::size_t(0), data.size(), [this, &p_centers, &winners](std::size_t p_index) { assign_point_to_cluster(p_index, p_centers, winners); }); for (std::size_t index_point = 0; index_point < winners.size(); index_point++) { const std::size_t suitable_index_cluster = winners[index_point]; p_clusters[suitable_index_cluster].push_back(index_point); } } else { /* This part of code is used by X-Means and in case of parallel implementation of this part in scope of X-Means performance is slightly reduced. Experiments has been performed our implementation and Intel TBB library. But in K-Means case only - it works perfectly and increase performance. */ std::vector winners(data.size(), 0); parallel_for_each(*m_ptr_indexes, [this, &p_centers, &winners](std::size_t p_index) { assign_point_to_cluster(p_index, p_centers, winners); }); for (std::size_t index_point : *m_ptr_indexes) { const std::size_t suitable_index_cluster = winners[index_point]; p_clusters[suitable_index_cluster].push_back(index_point); } } erase_empty_clusters(p_clusters); } void kmeans::assign_point_to_cluster(const std::size_t p_index_point, const dataset & p_centers, index_sequence & p_clusters) { double minimum_distance = std::numeric_limits::max(); size_t suitable_index_cluster = 0; for (size_t index_cluster = 0; index_cluster < p_centers.size(); index_cluster++) { double distance = m_metric(p_centers[index_cluster], (*m_ptr_data)[p_index_point]); if (distance < minimum_distance) { minimum_distance = distance; suitable_index_cluster = index_cluster; } } p_clusters[p_index_point] = suitable_index_cluster; } void kmeans::erase_empty_clusters(cluster_sequence & p_clusters) { for (size_t index_cluster = p_clusters.size() - 1; index_cluster != (size_t) -1; index_cluster--) { if (p_clusters[index_cluster].empty()) { p_clusters.erase(p_clusters.begin() + index_cluster); } } } double kmeans::update_centers(const cluster_sequence & clusters, dataset & centers) { const dataset & data = *m_ptr_data; const size_t dimension = data[0].size(); dataset calculated_clusters(clusters.size(), point(dimension, 0.0)); std::vector changes(clusters.size(), 0.0); parallel_for(std::size_t(0), clusters.size(), [this, &clusters, ¢ers, &calculated_clusters, &changes](const std::size_t p_index) { calculated_clusters[p_index] = centers[p_index]; changes[p_index] = update_center(clusters[p_index], calculated_clusters[p_index]); }); centers = std::move(calculated_clusters); return *(std::max_element(changes.begin(), changes.end())); } double kmeans::update_center(const cluster & p_cluster, point & p_center) { point total(p_center.size(), 0.0); /* for each object in cluster */ for (auto object_index : p_cluster) { /* for each dimension */ for (size_t dimension = 0; dimension < total.size(); dimension++) { total[dimension] += (*m_ptr_data)[object_index][dimension]; } } /* average for each dimension */ for (auto & dimension : total) { dimension /= p_cluster.size(); } const double change = m_metric(p_center, total); p_center = std::move(total); return change; } void kmeans::calculate_total_wce() { double & wce = m_ptr_result->wce(); for (std::size_t i = 0; i < m_ptr_result->clusters().size(); i++) { const auto & current_cluster = m_ptr_result->clusters().at(i); const auto & cluster_center = m_ptr_result->centers().at(i); for (const auto & cluster_point : current_cluster) { wce += m_metric(m_ptr_data->at(cluster_point), cluster_center); } } } } } pyclustering-0.10.1.2/ccore/src/cluster/kmeans_data.cpp000077500000000000000000000004541375753423500230230ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { kmeans_data::kmeans_data(const bool p_iteration_observe) : m_observed(p_iteration_observe) { } } }pyclustering-0.10.1.2/ccore/src/cluster/kmeans_plus_plus.cpp000077500000000000000000000177421375753423500241500ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include namespace pyclustering { namespace clst { const std::size_t kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE = std::numeric_limits::max(); const std::size_t kmeans_plus_plus::INVALID_INDEX = std::numeric_limits::max(); kmeans_plus_plus::kmeans_plus_plus(const std::size_t p_amount, const std::size_t p_candidates, const long long p_random_state) noexcept : m_amount(p_amount), m_candidates(p_candidates), m_dist_func([](const point &p1, const point &p2) { return euclidean_distance_square(p1, p2); }), m_random_state(p_random_state), m_generator(std::random_device()()) { initialize_random_generator(); } kmeans_plus_plus::kmeans_plus_plus(const std::size_t p_amount, const std::size_t p_candidates, const metric & p_metric, const long long p_random_state) noexcept : m_amount(p_amount), m_candidates(p_candidates), m_dist_func(p_metric), m_random_state(p_random_state), m_generator(std::random_device()()) { initialize_random_generator(); } void kmeans_plus_plus::initialize_random_generator() { if (m_random_state == RANDOM_STATE_CURRENT_TIME) { m_generator.seed(static_cast(std::chrono::system_clock::now().time_since_epoch().count())); } else { m_generator.seed(static_cast(m_random_state)); } } void kmeans_plus_plus::initialize(const dataset & p_data, dataset & p_centers) const { initialize(p_data, { }, p_centers); } void kmeans_plus_plus::initialize(const dataset & p_data, index_sequence & p_center_indexes) const { p_center_indexes.clear(); p_center_indexes.reserve(m_amount); initialize(p_data, { }, [&p_center_indexes](center_description & p_center) { p_center_indexes.push_back(std::get(p_center)); }); } void kmeans_plus_plus::initialize(const dataset & p_data, const index_sequence & p_indexes, dataset & p_centers) const { p_centers.clear(); p_centers.reserve(m_amount); initialize(p_data, p_indexes, [&p_centers](center_description & p_center) { p_centers.push_back(std::move(std::get(p_center))); }); } void kmeans_plus_plus::initialize(const dataset & p_data, const index_sequence & p_indexes, const store_result & p_proc) const { if (!m_amount) { return; } store_temporal_params(p_data, p_indexes); auto center = get_first_center(); store_center(p_proc, center); for (std::size_t i = 1; i < m_amount; i++) { center = get_next_center(); store_center(p_proc, center); } free_temporal_params(); } void kmeans_plus_plus::store_center(const store_result & p_proc, center_description & p_result) const { m_allocated_indexes.push_back(std::get(p_result)); m_free_indexes.erase(std::get(p_result)); p_proc(p_result); } void kmeans_plus_plus::store_temporal_params(const dataset & p_data, const index_sequence & p_indexes) const { if (p_data.empty()) { throw std::invalid_argument("Input data is empty."); } if (p_data.size() < m_amount) { throw std::invalid_argument("Amount of objects should be equal or greater then amount of initialized centers."); } if (!p_indexes.empty() && p_indexes.size() < m_amount) { throw std::invalid_argument("Amount of objects defined by range should be equal or greater then amount of initialized centers."); } m_data_ptr = (dataset *) &p_data; m_indexes_ptr = (index_sequence *) &p_indexes; m_allocated_indexes.clear(); m_free_indexes.clear(); if (m_indexes_ptr->empty()) { for (std::size_t i = 0; i < m_data_ptr->size(); i++) { m_free_indexes.insert(i); } } else { for (const auto index : *m_indexes_ptr) { m_free_indexes.insert(index); } } } void kmeans_plus_plus::free_temporal_params() const { m_data_ptr = nullptr; m_indexes_ptr = nullptr; } kmeans_plus_plus::center_description kmeans_plus_plus::get_first_center() const { std::size_t length = m_indexes_ptr->empty() ? m_data_ptr->size() : m_indexes_ptr->size(); std::uniform_int_distribution distribution(0, length - 1); std::size_t index = distribution(m_generator); const auto & center = m_indexes_ptr->empty() ? (*m_data_ptr)[index] : (*m_data_ptr)[ (*m_indexes_ptr)[index] ]; return std::make_tuple(center, index); } kmeans_plus_plus::center_description kmeans_plus_plus::get_next_center() const { std::vector distances; calculate_shortest_distances(distances); std::size_t index = 0; if (m_candidates == FARTHEST_CENTER_CANDIDATE) { auto iter = std::max_element(distances.begin(), distances.end()); index = std::distance(distances.begin(), iter); } else { std::vector probabilities; calculate_probabilities(distances, probabilities); index = get_probable_center(distances, probabilities); } const auto & center = m_indexes_ptr->empty() ? (*m_data_ptr)[index] : (*m_data_ptr)[ (*m_indexes_ptr)[index] ]; return std::make_tuple(center, index); } void kmeans_plus_plus::calculate_shortest_distances(std::vector & p_distances) const { p_distances.reserve(m_data_ptr->size()); if (m_indexes_ptr->empty()) { for (auto & point : (*m_data_ptr)) { double shortest_distance = get_shortest_distance(point); p_distances.push_back(shortest_distance); } } else { for (auto index : (*m_indexes_ptr)) { double shortest_distance = get_shortest_distance((*m_data_ptr)[index]); p_distances.push_back(shortest_distance); } } } double kmeans_plus_plus::get_shortest_distance(const point & p_point) const { double shortest_distance = std::numeric_limits::max(); for (auto & index_point : m_allocated_indexes) { double distance = std::abs(m_dist_func(p_point, m_data_ptr->at(index_point))); if (distance < shortest_distance) { shortest_distance = distance; } } return shortest_distance; } void kmeans_plus_plus::calculate_probabilities(const std::vector & p_distances, std::vector & p_probabilities) const { double sum = std::accumulate(p_distances.begin(), p_distances.end(), 0.0); p_probabilities.reserve(m_data_ptr->size()); double previous_probability = 0.0; for (auto distance : p_distances) { double current_probability = distance / sum; p_probabilities.push_back( current_probability + previous_probability ); previous_probability += current_probability; } p_probabilities.back() = 1.0; } std::size_t kmeans_plus_plus::get_probable_center(const std::vector & p_distances, const std::vector & p_probabilities) const { std::uniform_real_distribution distribution(0.0, 1.0); std::size_t best_index_candidate = 0; for (std::size_t i = 0; i < m_candidates; i++) { std::size_t current_index_candidate = kmeans_plus_plus::INVALID_INDEX; double candidate_probability = distribution(m_generator); for (std::size_t j = 0; j < p_probabilities.size(); j++) { if (candidate_probability < p_probabilities[j]) { current_index_candidate = j; break; } } if (current_index_candidate == kmeans_plus_plus::INVALID_INDEX) { best_index_candidate = *(m_free_indexes.begin()); } else if (p_distances[current_index_candidate] > p_distances[best_index_candidate]) { best_index_candidate = current_index_candidate; } } return best_index_candidate; } } } pyclustering-0.10.1.2/ccore/src/cluster/kmedians.cpp000077500000000000000000000127701375753423500223530ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include using namespace pyclustering::parallel; using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { const double kmedians::THRESHOLD_CHANGE = 0.000001; const double kmedians::DEFAULT_TOLERANCE = 0.001; const std::size_t kmedians::DEFAULT_ITERMAX = 50; kmedians::kmedians(const dataset & p_initial_medians, const double p_tolerance, const std::size_t p_max_iter, const distance_metric & p_metric) : m_tolerance(p_tolerance), m_max_iter(p_max_iter), m_initial_medians(p_initial_medians), m_ptr_result(nullptr), m_ptr_data(nullptr), m_metric(p_metric) { } void kmedians::process(const dataset & p_data, kmedians_data & p_output_result) { m_ptr_data = &p_data; m_ptr_result = &p_output_result; if (p_data[0].size() != m_initial_medians[0].size()) { throw std::invalid_argument("kmedians: dimension of the input data and dimension of the initial medians must be equal."); } m_ptr_result->medians() = m_initial_medians; double changes = std::numeric_limits::max(); double prev_changes = 0.0; std::size_t counter_repeaters = 0; for (std::size_t iteration = 0; (iteration < m_max_iter) && (changes > m_tolerance) && (counter_repeaters < 10); iteration++) { update_clusters(m_ptr_result->medians(), m_ptr_result->clusters()); changes = update_medians(m_ptr_result->clusters(), m_ptr_result->medians()); double change_difference = std::abs(changes - prev_changes); if (change_difference < THRESHOLD_CHANGE) { counter_repeaters++; } else { counter_repeaters = 0; } prev_changes = changes; } m_ptr_data = nullptr; m_ptr_result = nullptr; } void kmedians::update_clusters(const dataset & p_medians, cluster_sequence & p_clusters) { const dataset & data = *m_ptr_data; p_clusters.clear(); p_clusters.resize(p_medians.size()); index_sequence labels(data.size(), 0); parallel_for(std::size_t(0), data.size(), [this, &p_medians, &labels](std::size_t index) { assign_point_to_cluster(index, p_medians, labels); }); for (std::size_t index_point = 0; index_point < labels.size(); index_point++) { const std::size_t suitable_index_cluster = labels[index_point]; p_clusters[suitable_index_cluster].push_back(index_point); } erase_empty_clusters(p_clusters); } void kmedians::assign_point_to_cluster(const std::size_t p_index_point, const dataset & p_medians, index_sequence & p_lables) { size_t index_cluster_optim = 0; double distance_optim = std::numeric_limits::max(); for (size_t index_cluster = 0; index_cluster < p_medians.size(); index_cluster++) { double distance = m_metric((*m_ptr_data)[p_index_point], p_medians[index_cluster]); if (distance < distance_optim) { index_cluster_optim = index_cluster; distance_optim = distance; } } p_lables[p_index_point] = index_cluster_optim; } void kmedians::erase_empty_clusters(cluster_sequence & p_clusters) { for (std::size_t index_cluster = p_clusters.size() - 1; index_cluster != (std::size_t) -1; index_cluster--) { if (p_clusters[index_cluster].empty()) { p_clusters.erase(p_clusters.begin() + index_cluster); } } } double kmedians::update_medians(cluster_sequence & clusters, dataset & medians) { const dataset & data = *m_ptr_data; const std::size_t dimension = data[0].size(); std::vector prev_medians(medians); medians.clear(); medians.resize(clusters.size(), point(dimension, 0.0)); std::vector changes(clusters.size(), 0); parallel_for(std::size_t(0), clusters.size(), [this, &medians, &prev_medians, &clusters, &changes](std::size_t index_cluster) { calculate_median(clusters[index_cluster], medians[index_cluster]); changes[index_cluster] = m_metric(prev_medians[index_cluster], medians[index_cluster]); }); return *std::max_element(changes.cbegin(), changes.cend()); } void kmedians::calculate_median(cluster & current_cluster, point & median) { const dataset & data = *m_ptr_data; const std::size_t dimension = data[0].size(); for (size_t index_dimension = 0; index_dimension < dimension; index_dimension++) { std::sort(current_cluster.begin(), current_cluster.end(), [this](std::size_t index_object1, std::size_t index_object2) { return (*m_ptr_data)[index_object1] > (*m_ptr_data)[index_object2]; }); std::size_t relative_index_median = (std::size_t) (current_cluster.size() - 1) / 2; std::size_t index_median = current_cluster[relative_index_median]; if (current_cluster.size() % 2 == 0) { std::size_t index_median_second = current_cluster[relative_index_median + 1]; median[index_dimension] = (data[index_median][index_dimension] + data[index_median_second][index_dimension]) / 2.0; } else { median[index_dimension] = data[index_median][index_dimension]; } } } } } pyclustering-0.10.1.2/ccore/src/cluster/kmedoids.cpp000077500000000000000000000203631375753423500223540ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include using namespace pyclustering::parallel; namespace pyclustering { namespace clst { const double kmedoids::DEFAULT_TOLERANCE = 0.0001; const std::size_t kmedoids::DEFAULT_ITERMAX = 100; const std::size_t kmedoids::OBJECT_ALREADY_CONTAINED = std::numeric_limits::max(); const std::size_t kmedoids::INVALID_INDEX = std::numeric_limits::max(); const double kmedoids::NOTHING_TO_SWAP = std::numeric_limits::max(); kmedoids::appropriate_cluster::appropriate_cluster(const std::size_t p_index, const double p_distance_first_medoid, const double p_distance_second_medoid) : m_index(p_index), m_distance_to_first_medoid(p_distance_first_medoid), m_distance_to_second_medoid(p_distance_second_medoid) { } kmedoids::kmedoids(const medoid_sequence & p_initial_medoids, const double p_tolerance, const std::size_t p_itermax, const distance_metric & p_metric) : m_data_ptr(nullptr), m_result_ptr(nullptr), m_initial_medoids(p_initial_medoids), m_tolerance(p_tolerance), m_itermax(p_itermax), m_metric(p_metric) { } kmedoids::~kmedoids() { } void kmedoids::process(const dataset & p_data, kmedoids_data & p_result) { process(p_data, kmedoids_data_t::POINTS, p_result); } void kmedoids::process(const dataset & p_data, const kmedoids_data_t p_type, kmedoids_data & p_result) { m_data_ptr = &p_data; m_result_ptr = (kmedoids_data *) &p_result; m_calculator = create_distance_calculator(p_type); medoid_sequence & medoids = m_result_ptr->medoids(); medoids.assign(m_initial_medoids.begin(), m_initial_medoids.end()); m_labels = index_sequence(p_data.size(), -1); m_distance_first_medoid = std::vector(p_data.size(), std::numeric_limits::max()); m_distance_second_medoid = std::vector(p_data.size(), std::numeric_limits::max()); double changes = std::numeric_limits::max(); double previous_deviation = std::numeric_limits::max(); double current_deviation = std::numeric_limits::max(); if (m_itermax > 0) { current_deviation = update_clusters(); } for (std::size_t iteration = 0; (iteration < m_itermax) && (changes > m_tolerance); iteration++) { const double swap_cost = swap_medoids(); if (swap_cost != NOTHING_TO_SWAP) { previous_deviation = current_deviation; current_deviation = update_clusters(); changes = previous_deviation - current_deviation; } else { break; } } erase_empty_clusters(); m_data_ptr = nullptr; m_result_ptr = nullptr; } double kmedoids::update_clusters() { cluster_sequence & clusters = m_result_ptr->clusters(); medoid_sequence & medoids = m_result_ptr->medoids(); clusters.clear(); clusters.resize(medoids.size()); std::vector cluster_markers(m_data_ptr->size()); parallel_for(std::size_t(0), m_data_ptr->size(), [this, &medoids, &cluster_markers](const std::size_t p_index) { cluster_markers[p_index] = find_appropriate_cluster(p_index, medoids); }); double total_deviation = 0.0; for (std::size_t index_point = 0; index_point < m_data_ptr->size(); index_point++) { const std::size_t index_optim = cluster_markers[index_point].m_index; total_deviation += cluster_markers[index_point].m_distance_to_first_medoid; m_labels[index_point] = index_optim; clusters[index_optim].push_back(index_point); m_distance_first_medoid[index_point] = cluster_markers[index_point].m_distance_to_first_medoid; m_distance_second_medoid[index_point] = cluster_markers[index_point].m_distance_to_second_medoid; } return total_deviation; } kmedoids::distance_calculator kmedoids::create_distance_calculator(const kmedoids_data_t p_type) { if (p_type == kmedoids_data_t::POINTS) { return [this](const std::size_t index1, const std::size_t index2) { return m_metric((*m_data_ptr)[index1], (*m_data_ptr)[index2]); }; } else if (p_type == kmedoids_data_t::DISTANCE_MATRIX) { return [this](const std::size_t index1, const std::size_t index2) { return (*m_data_ptr)[index1][index2]; }; } else { throw std::invalid_argument("Unknown type data is specified"); } } kmedoids::appropriate_cluster kmedoids::find_appropriate_cluster(const std::size_t p_index, medoid_sequence & p_medoids) { size_t index_optim = INVALID_INDEX; double dist_optim_first = std::numeric_limits::max(); double dist_optim_second = std::numeric_limits::max(); for (size_t index = 0; index < p_medoids.size(); index++) { const size_t index_medoid = p_medoids[index]; const double distance = m_calculator(p_index, index_medoid); if (distance < dist_optim_first) { dist_optim_second = dist_optim_first; index_optim = index; dist_optim_first = distance; } else if (distance < dist_optim_second) { dist_optim_second = distance; } } return kmedoids::appropriate_cluster(index_optim, dist_optim_first, dist_optim_second); } double kmedoids::swap_medoids() { double optimal_swap_cost = std::numeric_limits::max(); std::size_t optimal_index_cluster = INVALID_INDEX; std::size_t optimal_index_medoid = INVALID_INDEX; auto & medoids = m_result_ptr->medoids(); for (std::size_t index_cluster = 0; index_cluster < m_result_ptr->clusters().size(); index_cluster++) { for (std::size_t candidate_medoid_index = 0; candidate_medoid_index < m_data_ptr->size(); candidate_medoid_index++) { const bool is_already_medoid = std::find(medoids.cbegin(), medoids.cend(), candidate_medoid_index) != medoids.cend(); if (is_already_medoid || (m_distance_first_medoid[candidate_medoid_index] == 0.0)) { continue; } const double swap_cost = calculate_swap_cost(candidate_medoid_index, index_cluster); if (swap_cost < optimal_swap_cost) { optimal_swap_cost = swap_cost; optimal_index_cluster = index_cluster; optimal_index_medoid = candidate_medoid_index; } } } if (optimal_index_cluster != INVALID_INDEX) { medoids[optimal_index_cluster] = optimal_index_medoid; } return optimal_swap_cost; } double kmedoids::calculate_swap_cost(const std::size_t p_index_candidate, const std::size_t p_index_cluster) const { double cost = 0.0; for (std::size_t index_point = 0; index_point < m_data_ptr->size(); index_point++) { if (index_point == p_index_candidate) { continue; } double candidate_distance = m_calculator(index_point, p_index_candidate); if (m_labels[index_point] == p_index_cluster) { cost += std::min(candidate_distance, m_distance_second_medoid[index_point]) - m_distance_first_medoid[index_point]; } else if (candidate_distance < m_distance_first_medoid[index_point]) { cost += candidate_distance - m_distance_first_medoid[index_point]; } } return cost - m_distance_first_medoid[p_index_candidate]; } void kmedoids::erase_empty_clusters() { auto & clusters = m_result_ptr->clusters(); auto & medoids = m_result_ptr->medoids(); for (std::size_t index_cluster = clusters.size() - 1; index_cluster != static_cast(-1); index_cluster--) { if (clusters[index_cluster].empty()) { clusters.erase(clusters.begin() + index_cluster); medoids.erase(medoids.begin() + index_cluster); } } } } } pyclustering-0.10.1.2/ccore/src/cluster/mbsas.cpp000077500000000000000000000025711375753423500216630ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { mbsas::mbsas(const std::size_t p_amount, const double p_threshold, const distance_metric & p_metric) : bsas(p_amount, p_threshold, p_metric) { } void mbsas::process(const dataset & p_data, mbsas_data & p_result) { m_result_ptr = &p_result; cluster_sequence & clusters = m_result_ptr->clusters(); representative_sequence & representative = m_result_ptr->representatives(); clusters.push_back({ 0 }); representative.push_back( p_data[0] ); std::vector skipped_objects = { }; for (std::size_t i = 1; i < p_data.size(); i++) { auto nearest = find_nearest_cluster(p_data[i]); if ( (nearest.m_distance > m_threshold) && (clusters.size() < m_amount) ) { representative.push_back(p_data[i]); clusters.push_back({ i }); } else { skipped_objects.push_back(i); } } for (auto index : skipped_objects) { auto nearest = find_nearest_cluster(p_data[index]); clusters.at(nearest.m_index).push_back(index); update_representative(nearest.m_index, p_data[index]); } } } }pyclustering-0.10.1.2/ccore/src/cluster/optics.cpp000077500000000000000000000217561375753423500220650ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include #include namespace pyclustering { namespace clst { const double optics::NONE_DISTANCE = optics_descriptor::NONE_DISTANCE; const std::size_t optics::INVALID_INDEX = std::numeric_limits::max(); optics::optics(const double p_radius, const std::size_t p_neighbors) : optics() { m_radius = p_radius; m_neighbors = p_neighbors; } optics::optics(const double p_radius, const std::size_t p_neighbors, const std::size_t p_amount_clusters) : optics() { m_radius = p_radius; m_neighbors = p_neighbors; m_amount_clusters = p_amount_clusters; } void optics::process(const dataset & p_data, optics_data & p_result) { process(p_data, optics_data_t::POINTS, p_result); } void optics::process(const dataset & p_data, const optics_data_t p_type, optics_data & p_result) { m_data_ptr = &p_data; m_result_ptr = &p_result; m_type = p_type; calculate_cluster_result(); if ( (m_amount_clusters > 0) && (m_amount_clusters != m_result_ptr->clusters().size()) ) { double radius = ordering_analyser::calculate_connvectivity_radius(m_result_ptr->cluster_ordering(), m_amount_clusters); if (radius > 0) { m_radius = radius; calculate_cluster_result(); } } m_result_ptr->set_radius(m_radius); m_data_ptr = nullptr; m_result_ptr = nullptr; } void optics::calculate_cluster_result() { initialize(); allocate_clusters(); calculate_ordering(); } void optics::initialize() { if (m_type == optics_data_t::POINTS) { create_kdtree(); } m_optics_objects = &(m_result_ptr->optics_objects()); if (m_optics_objects->empty()) { m_optics_objects->reserve(m_data_ptr->size()); for (std::size_t i = 0; i < m_data_ptr->size(); i++) { m_optics_objects->emplace_back(i, optics::NONE_DISTANCE, optics::NONE_DISTANCE); } } else { std::for_each(m_optics_objects->begin(), m_optics_objects->end(), [](auto & p_object) { p_object.clear(); }); } m_ordered_database.clear(); m_result_ptr->clusters().clear(); m_result_ptr->noise().clear(); } void optics::allocate_clusters() { for (auto & optics_object : *m_optics_objects) { if (!optics_object.m_processed) { expand_cluster_order(optics_object); } } extract_clusters(); } void optics::expand_cluster_order(optics_descriptor & p_object) { p_object.m_processed = true; neighbors_collection neighbors; get_neighbors(p_object.m_index, neighbors); m_ordered_database.push_back(&p_object); if (neighbors.size() >= m_neighbors) { p_object.m_core_distance = get_core_distance(neighbors); std::multiset order_seed; update_order_seed(p_object, neighbors, order_seed); while(!order_seed.empty()) { optics_descriptor * descriptor = *(order_seed.begin()); order_seed.erase(order_seed.begin()); get_neighbors(descriptor->m_index, neighbors); descriptor->m_processed = true; m_ordered_database.push_back(descriptor); if (neighbors.size() >= m_neighbors) { descriptor->m_core_distance = get_core_distance(neighbors); update_order_seed(*descriptor, neighbors, order_seed); } else { descriptor->m_core_distance = optics::NONE_DISTANCE; } } } else { p_object.m_core_distance = optics::NONE_DISTANCE; } } void optics::update_order_seed(const optics_descriptor & p_object, const neighbors_collection & p_neighbors, std::multiset & order_seed) { for (auto & descriptor : p_neighbors) { std::size_t index_neighbor = descriptor.m_index; double current_reachability_distance = descriptor.m_reachability_distance; optics_descriptor & optics_object = m_optics_objects->at(index_neighbor); if (!optics_object.m_processed) { double reachable_distance = std::max({ current_reachability_distance, p_object.m_core_distance }); if (optics_object.m_reachability_distance == optics::NONE_DISTANCE) { optics_object.m_reachability_distance = reachable_distance; order_seed.insert(&optics_object); } else { if (reachable_distance < optics_object.m_reachability_distance) { optics_object.m_reachability_distance = reachable_distance; auto object_iterator = std::find_if(order_seed.begin(), order_seed.end(), [&optics_object](optics_descriptor * obj) { return obj->m_index == optics_object.m_index; }); order_seed.erase(object_iterator); order_seed.insert(&optics_object); } } } } } void optics::extract_clusters() { cluster_sequence & clusters = m_result_ptr->clusters(); clst::noise & noise = m_result_ptr->noise(); cluster * current_cluster = (cluster *) &noise; for (auto optics_object : m_ordered_database) { if ( (optics_object->m_reachability_distance == optics::NONE_DISTANCE) || (optics_object->m_reachability_distance > m_radius) ) { if ( (optics_object->m_core_distance != optics::NONE_DISTANCE) && (optics_object->m_core_distance <= m_radius) ) { clusters.push_back({ optics_object->m_index }); current_cluster = &clusters.back(); } else { noise.push_back(optics_object->m_index); } } else { current_cluster->push_back(optics_object->m_index); } } } void optics::get_neighbors(const size_t p_index, neighbors_collection & p_neighbors) { switch(m_type) { case optics_data_t::POINTS: get_neighbors_from_points(p_index, p_neighbors); break; case optics_data_t::DISTANCE_MATRIX: get_neighbors_from_distance_matrix(p_index, p_neighbors); break; default: throw std::invalid_argument("Incorrect input data type is specified '" + std::to_string((unsigned) m_type) + "'"); } } void optics::get_neighbors_from_points(const std::size_t p_index, neighbors_collection & p_neighbors) { p_neighbors.clear(); container::kdtree_searcher searcher((*m_data_ptr)[p_index], m_kdtree.get_root(), m_radius); container::kdtree_searcher::rule_store rule = [&p_index, &p_neighbors](const container::kdnode::ptr & p_node, const double p_distance) { if (p_index != (std::size_t) p_node->get_payload()) { p_neighbors.emplace((std::size_t) p_node->get_payload(), std::sqrt(p_distance)); } }; searcher.find_nearest(rule); } void optics::get_neighbors_from_distance_matrix(const std::size_t p_index, neighbors_collection & p_neighbors) { p_neighbors.clear(); const auto & distances = m_data_ptr->at(p_index); for (std::size_t index_neighbor = 0; index_neighbor < distances.size(); index_neighbor++) { const double candidate_distance = distances[index_neighbor]; if ( (candidate_distance <= m_radius) && (index_neighbor != p_index) ) { p_neighbors.emplace(index_neighbor, candidate_distance); } } } double optics::get_core_distance(const neighbors_collection & p_neighbors) const { auto iter = p_neighbors.cbegin(); for (std::size_t index = 0; index < (m_neighbors - 1); ++index) { ++iter; } return iter->m_reachability_distance; } void optics::calculate_ordering() { if (!m_result_ptr->cluster_ordering().empty()) { return; } ordering & ordering = m_result_ptr->cluster_ordering(); cluster_sequence & clusters = m_result_ptr->clusters(); for (auto & cluster : clusters) { for (auto index_object : cluster) { const optics_descriptor & optics_object = m_optics_objects->at(index_object); if (optics_object.m_reachability_distance != optics::NONE_DISTANCE) { ordering.push_back(optics_object.m_reachability_distance); } } } } void optics::create_kdtree() { std::vector payload(m_data_ptr->size()); for (std::size_t index = 0; index < m_data_ptr->size(); index++) { payload[index] = (void *)index; } m_kdtree = container::kdtree_balanced(*m_data_ptr, payload); } } }pyclustering-0.10.1.2/ccore/src/cluster/optics_descriptor.cpp000077500000000000000000000017531375753423500243160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace clst { const double optics_descriptor::NONE_DISTANCE = -1.0; optics_descriptor::optics_descriptor(const std::size_t p_index, const double p_core_distance, const double p_reachability_distance) : m_index(p_index), m_core_distance(p_core_distance), m_reachability_distance(p_reachability_distance), m_processed(false) { } void optics_descriptor::clear() { m_core_distance = optics_descriptor::NONE_DISTANCE; m_reachability_distance = optics_descriptor::NONE_DISTANCE; m_processed = false; } bool optics_pointer_descriptor_less::operator()(const optics_descriptor * p_object1, const optics_descriptor * p_object2) const { return p_object1->m_reachability_distance < p_object2->m_reachability_distance; } } }pyclustering-0.10.1.2/ccore/src/cluster/ordering_analyser.cpp000077500000000000000000000053121375753423500242610ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include namespace pyclustering { namespace clst { double ordering_analyser::calculate_connvectivity_radius(const ordering & p_ordering, const std::size_t p_amount_clusters, const std::size_t p_maximum_iterations) { const double maximum_distance = *std::max_element(p_ordering.cbegin(), p_ordering.cend()); double upper_distance = maximum_distance; double lower_distance = 0.0; double result = -1.0; if (extract_cluster_amount(p_ordering, maximum_distance) > p_amount_clusters) { return result; } for(std::size_t i = 0; i < p_maximum_iterations; i++) { double radius = (lower_distance + upper_distance) / 2.0; std::size_t amount = extract_cluster_amount(p_ordering, radius); if (amount == p_amount_clusters) { result = radius; break; } else if (amount == 0) { break; } else if (amount > p_amount_clusters) { lower_distance = radius; } else if (amount < p_amount_clusters) { upper_distance = radius; } } return result; } std::size_t ordering_analyser::extract_cluster_amount(const ordering & p_ordering, const double p_radius) { std::size_t amount_clusters = 1; bool cluster_start = false; bool cluster_pick = false; bool total_similariry = true; double previous_cluster_distance = 0.0; double previous_distance = -1.0; for (auto & distance : p_ordering) { if (distance >= p_radius) { if (!cluster_start) { cluster_start = true; amount_clusters++; } else { if ( (distance < previous_cluster_distance) && (!cluster_pick) ) { cluster_pick = true; } else if ( (distance > previous_cluster_distance) && (cluster_pick) ) { cluster_pick = false; amount_clusters += 1; } } previous_cluster_distance = distance; } else { cluster_start = false; cluster_pick = false; } if ( (previous_distance >= 0) && (previous_distance != distance) ) { total_similariry = false; } previous_distance = distance; } if ( (total_similariry) && (previous_distance > p_radius) ) { amount_clusters = 0; } return amount_clusters; } } }pyclustering-0.10.1.2/ccore/src/cluster/random_center_initializer.cpp000077500000000000000000000042341375753423500257770ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include namespace pyclustering { namespace clst { random_center_initializer::random_center_initializer(const std::size_t p_amount, const long long p_random_state) : m_amount(p_amount), m_random_state(p_random_state), m_generator(std::random_device()()) { initialize_random_generator(); } void random_center_initializer::initialize(const dataset & p_data, dataset & p_centers) const { initialize(p_data, { }, p_centers); } void random_center_initializer::initialize_random_generator() { if (m_random_state == RANDOM_STATE_CURRENT_TIME) { m_generator.seed(static_cast(std::chrono::system_clock::now().time_since_epoch().count())); } else { m_generator.seed(static_cast(m_random_state)); } } void random_center_initializer::initialize(const dataset & p_data, const index_sequence & p_indexes, dataset & p_centers) const { p_centers.clear(); p_centers.reserve(m_amount); if ((m_amount > p_data.size()) || (m_amount == 0)) { return; } m_available_indexes.reserve(p_data.size()); for (std::size_t i = 0; i < p_data.size(); i++) { m_available_indexes.insert(i); } if (m_amount == p_data.size()) { p_centers = p_data; return; } for (std::size_t i = 0; i < m_amount; i++) { create_center(p_data, p_centers); } } void random_center_initializer::create_center(const dataset & p_data, dataset & p_centers) const { std::uniform_int_distribution distribution(0, p_data.size() - 1); std::size_t random_index_point = distribution(m_generator); index_storage::iterator available_index = m_available_indexes.find(random_index_point); if (available_index == m_available_indexes.end()) { random_index_point = *m_available_indexes.begin(); available_index = m_available_indexes.begin(); } p_centers.push_back(p_data.at(random_index_point)); m_available_indexes.erase(available_index); } } }pyclustering-0.10.1.2/ccore/src/cluster/rock.cpp000077500000000000000000000074351375753423500215200ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include using namespace pyclustering::utils::metric; using namespace pyclustering::container; namespace pyclustering { namespace clst { rock::rock() : m_adjacency_matrix(adjacency_matrix()), m_radius(0.0), m_degree_normalization(0.0), m_number_clusters(0) { } rock::rock(const double radius, const std::size_t number_clusters, const double threshold) : m_adjacency_matrix(adjacency_matrix()), m_radius(radius * radius), m_degree_normalization(1.0 + 2.0 * ( (1.0 - threshold) / (1.0 + threshold) )), m_number_clusters(number_clusters) { } void rock::process(const dataset & p_data, rock_data & p_result) { create_adjacency_matrix(p_data); /* initialize first version of clusters */ for (size_t index = 0; index < p_data.size(); index++) { m_clusters.push_back(cluster(1, index)); } while( (m_number_clusters < m_clusters.size()) && (merge_cluster()) ) { } /* copy results to the output result (it much more optimal to store in list representation for ROCK algorithm) */ p_result.clusters().insert(p_result.clusters().begin(), m_clusters.begin(), m_clusters.end()); m_clusters.clear(); /* no need it anymore - clear to save memory */ m_adjacency_matrix.clear(); /* no need it anymore - clear to save memory */ } void rock::create_adjacency_matrix(const dataset & p_data) { m_adjacency_matrix = adjacency_matrix(p_data.size()); for (size_t i = 0; i < m_adjacency_matrix.size(); i++) { for (size_t j = i + 1; j < m_adjacency_matrix.size(); j++) { double distance = euclidean_distance_square(p_data[i], p_data[j]); if (distance < m_radius) { m_adjacency_matrix.set_connection(i, j); m_adjacency_matrix.set_connection(j, i); } } } } bool rock::merge_cluster() { auto cluster1 = m_clusters.end(); auto cluster2 = m_clusters.end(); double maximum_goodness = 0; for (auto i = m_clusters.begin(); i != m_clusters.end(); ++i) { auto next = i; for (auto j = ++next; j != m_clusters.end(); ++j) { double goodness = calculate_goodness(*i, *j); if (goodness > maximum_goodness) { maximum_goodness = goodness; cluster1 = i; cluster2 = j; } } } if (cluster1 == cluster2) { return false; /* clusters are totally separated (no links between them), it's impossible to made a desicion which of them should be merged */ } (*cluster1).insert((*cluster1).end(), (*cluster2).begin(), (*cluster2).end()); m_clusters.erase(cluster2); return true; } size_t rock::calculate_links(const cluster & cluster1, const cluster & cluster2) const { size_t number_links = 0; for (auto i : cluster1) { for (auto j : cluster2) { number_links += (size_t) m_adjacency_matrix.has_connection(i, j); } } return number_links; } double rock::calculate_goodness(const cluster & cluster1, const cluster & cluster2) const { const double number_links = (double) calculate_links(cluster1, cluster2); const double size_cluster1 = (double) cluster1.size(); const double size_cluster2 = (double) cluster2.size(); return number_links / ( std::pow( size_cluster1 + size_cluster2, m_degree_normalization ) - std::pow( size_cluster1, m_degree_normalization ) - std::pow( size_cluster2, m_degree_normalization ) ); } } } pyclustering-0.10.1.2/ccore/src/cluster/silhouette.cpp000077500000000000000000000077001375753423500227420ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { silhouette::silhouette(const distance_metric & p_metric) : m_metric(p_metric) { } void silhouette::process(const dataset & p_data, const cluster_sequence & p_clusters, silhouette_data & p_result) { process(p_data, p_clusters, silhouette_data_t::POINTS, p_result); } void silhouette::process(const dataset & p_data, const cluster_sequence & p_clusters, const silhouette_data_t & p_type, silhouette_data & p_result) { m_data = &p_data; m_clusters = &p_clusters; m_result = &p_result; m_type = p_type; m_result->get_score().reserve(m_data->size()); for (std::size_t index_cluster = 0; index_cluster < m_clusters->size(); index_cluster++) { const auto & current_cluster = m_clusters->at(index_cluster); for (const auto index_point : current_cluster) { m_result->get_score().push_back(calculate_score(index_point, index_cluster)); } } } double silhouette::calculate_score(const std::size_t p_index_point, const std::size_t p_index_cluster) const { std::vector dataset_difference; calculate_dataset_difference(p_index_point, dataset_difference); const double a_score = calculate_within_cluster_score(p_index_cluster, dataset_difference); const double b_score = caclulate_optimal_neighbor_cluster_score(p_index_cluster, dataset_difference); return (b_score - a_score) / std::max(a_score, b_score); } void silhouette::calculate_dataset_difference(const std::size_t p_index_point, std::vector & p_dataset_difference) const { if (m_type == silhouette_data_t::DISTANCE_MATRIX) { p_dataset_difference = m_data->at(p_index_point); return; } p_dataset_difference.reserve(m_data->size()); const auto & current_point = m_data->at(p_index_point); for (const auto & point : *m_data) { p_dataset_difference.push_back(m_metric(current_point, point)); } } double silhouette::calculate_cluster_difference(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const { double cluster_difference = 0.0; const auto & current_cluster = m_clusters->at(p_index_cluster); for (const auto index_point : current_cluster) { cluster_difference += p_dataset_difference[index_point]; } return cluster_difference; } double silhouette::calculate_within_cluster_score(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const { double score = calculate_cluster_difference(p_index_cluster, p_dataset_difference); const std::size_t cluster_size = m_clusters->at(p_index_cluster).size(); if (cluster_size == 1) { return std::nan("1"); } return score / (cluster_size - 1); } double silhouette::calculate_cluster_score(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const { const double score = calculate_cluster_difference(p_index_cluster, p_dataset_difference); return score / m_clusters->at(p_index_cluster).size(); } double silhouette::caclulate_optimal_neighbor_cluster_score(const std::size_t p_index_cluster, const std::vector & p_dataset_difference) const { double optimal_score = std::numeric_limits::infinity(); for (std::size_t index_neighbor_cluster = 0; index_neighbor_cluster < m_clusters->size(); index_neighbor_cluster++) { if (p_index_cluster != index_neighbor_cluster) { const double candidate_score = calculate_cluster_score(index_neighbor_cluster, p_dataset_difference); if (candidate_score < optimal_score) { optimal_score = candidate_score; } } } return optimal_score; } } }pyclustering-0.10.1.2/ccore/src/cluster/silhouette_ksearch.cpp000077500000000000000000000075121375753423500244430ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include namespace pyclustering { namespace clst { void kmeans_allocator::allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) { allocate(p_amount, p_data, RANDOM_STATE_CURRENT_TIME, p_clusters); } void kmeans_allocator::allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) { dataset initial_centers; kmeans_plus_plus(p_amount, 1, p_random_state).initialize(p_data, initial_centers); kmeans_data result; kmeans(initial_centers).process(p_data, result); p_clusters = std::move(result.clusters()); } void kmedians_allocator::allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) { allocate(p_amount, p_data, RANDOM_STATE_CURRENT_TIME, p_clusters); } void kmedians_allocator::allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) { dataset initial_medians; kmeans_plus_plus(p_amount, 1, p_random_state).initialize(p_data, initial_medians); kmedians_data result; kmedians(initial_medians).process(p_data, result); p_clusters = std::move(result.clusters()); } void kmedoids_allocator::allocate(const std::size_t p_amount, const dataset & p_data, cluster_sequence & p_clusters) { allocate(p_amount, p_data, RANDOM_STATE_CURRENT_TIME, p_clusters); } void kmedoids_allocator::allocate(const std::size_t p_amount, const dataset & p_data, const long long p_random_state, cluster_sequence & p_clusters) { medoid_sequence initial_medoids; kmeans_plus_plus(p_amount, 1, p_random_state).initialize(p_data, initial_medoids); kmedoids_data result; kmedoids(initial_medoids).process(p_data, result); p_clusters = std::move(result.clusters()); } silhouette_ksearch::silhouette_ksearch(const std::size_t p_kmin, const std::size_t p_kmax, const silhouette_ksearch_allocator::ptr & p_allocator, const long long p_random_state) : m_kmin(p_kmin), m_kmax(p_kmax), m_allocator(p_allocator), m_random_state(p_random_state) { if (m_kmin <= 1) { throw std::invalid_argument("K min value '" + std::to_string(m_kmin) + "' should be greater than 1 (impossible to provide silhouette score for only one cluster)."); } } void silhouette_ksearch::process(const dataset & p_data, silhouette_ksearch_data & p_result) { if (m_kmax > p_data.size()) { throw std::invalid_argument("K max value '" + std::to_string(m_kmax) + "' should be bigger than amount of objects '" + std::to_string(p_data.size()) + "' in input data."); } p_result.scores().reserve(m_kmax - m_kmin); for (std::size_t k = m_kmin; k < m_kmax; k++) { cluster_sequence clusters; m_allocator->allocate(k, p_data, m_random_state, clusters); if (clusters.size() != k) { p_result.scores().push_back(std::nan("1")); continue; } silhouette_data result; silhouette().process(p_data, clusters, result); const auto & scores = result.get_score(); const double score = std::accumulate(scores.begin(), scores.end(), 0.0) / scores.size(); p_result.scores().push_back(score); if (score > p_result.get_score()) { p_result.set_amount(k); p_result.set_score(score); } } } } }pyclustering-0.10.1.2/ccore/src/cluster/silhouette_ksearch_data.cpp000077500000000000000000000026561375753423500254400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace clst { const std::size_t silhouette_ksearch_data::get_amount() const { return m_amount; } void silhouette_ksearch_data::set_amount(const std::size_t p_amount) { m_amount = p_amount; } const double silhouette_ksearch_data::get_score() const { return m_score; } void silhouette_ksearch_data::set_score(const double p_score) { m_score = p_score; } const silhouette_score_sequence & silhouette_ksearch_data::scores() const { return m_scores; } silhouette_score_sequence & silhouette_ksearch_data::scores() { return m_scores; } bool silhouette_ksearch_data::operator==(const silhouette_ksearch_data & p_other) const { if (this == &p_other) { return true; } if ((m_amount != p_other.m_amount) || (m_score != p_other.m_score) || (m_scores.size() != p_other.m_scores.size())) { return false; } for (std::size_t i = 0; i < m_scores.size(); i++) { if (std::isnan(m_scores[i]) && std::isnan(p_other.m_scores[i])) { continue; } else if (m_scores[i] == p_other.m_scores[i]) { continue; } return false; } return true; } } }pyclustering-0.10.1.2/ccore/src/cluster/somsc.cpp000077500000000000000000000012731375753423500217000ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include using namespace pyclustering::nnet; namespace pyclustering { namespace clst { somsc::somsc(const std::size_t p_amount_clusters, const std::size_t p_epoch) : m_amount_clusters(p_amount_clusters), m_epoch(p_epoch) { } void somsc::process(const dataset & p_data, somsc_data & p_result) { som_parameters params; som som_map(1, m_amount_clusters, som_conn_type::SOM_GRID_FOUR, params); som_map.train(p_data, m_epoch, true); p_result.clusters() = som_map.get_capture_objects(); } } }pyclustering-0.10.1.2/ccore/src/cluster/syncnet.cpp000077500000000000000000000115171375753423500222410ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::metric; using namespace pyclustering::nnet; using namespace std::placeholders; namespace pyclustering { namespace clst { void syncnet_analyser::allocate_clusters(const double eps, syncnet_cluster_data & data) { allocate_sync_ensembles(eps, data); } syncnet::syncnet(std::vector > * input_data, const double connectivity_radius, const bool enable_conn_weight, const initial_type initial_phases) : sync_network(input_data->size(), 1, 0, connection_t::CONNECTION_NONE, initial_type::RANDOM_GAUSSIAN) { equation oscillator_equation = std::bind(&syncnet::phase_kuramoto_equation, this, _1, _2, _3, _4); set_equation(oscillator_equation); oscillator_locations = new std::vector >(*input_data); create_connections(connectivity_radius, enable_conn_weight); } syncnet::~syncnet() { if (oscillator_locations != nullptr) { delete oscillator_locations; oscillator_locations = nullptr; } if (distance_conn_weights != nullptr) { delete distance_conn_weights; distance_conn_weights = nullptr; } } void syncnet::create_connections(const double connectivity_radius, const bool enable_conn_weight) { double sqrt_connectivity_radius = connectivity_radius * connectivity_radius; if (enable_conn_weight == true) { std::vector instance(size(), 0); distance_conn_weights = new std::vector >(size(), instance); } else { distance_conn_weights = nullptr; } double maximum_distance = 0; double minimum_distance = std::numeric_limits::max(); for (std::size_t i = 0; i < size(); i++) { for (std::size_t j = i + 1; j < size(); j++) { double distance = euclidean_distance_square( (*oscillator_locations)[i], (*oscillator_locations)[j] ); if (distance <= sqrt_connectivity_radius) { m_connections->set_connection(j, i); m_connections->set_connection(i, j); } if (enable_conn_weight == true) { (*distance_conn_weights)[i][j] = distance; (*distance_conn_weights)[j][i] = distance; if (distance > maximum_distance) { maximum_distance = distance; } if (distance < maximum_distance) { maximum_distance = distance; } } } } if (enable_conn_weight == true) { double multiplier = 1; double subtractor = 0; if (maximum_distance != minimum_distance) { multiplier = maximum_distance - minimum_distance; subtractor = minimum_distance; } for (std::size_t i = 0; i < size(); i++) { for (std::size_t j = i + 1; j < size(); j++) { double value_weight = ((*distance_conn_weights)[i][j] - subtractor) / multiplier; (*distance_conn_weights)[i][j] = value_weight; (*distance_conn_weights)[j][i] = value_weight; } } } } double syncnet::phase_kuramoto(const double t, const double teta, const std::vector & argv) const { std::size_t index = *(unsigned int *) argv[0]; std::size_t num_neighbors = 0; double phase = 0; /* Avoid a lot of checking of this condition in the loop */ if (distance_conn_weights != nullptr) { for (std::size_t k = 0; k < size(); k++) { if (m_connections->has_connection(index, k)) { phase += (*distance_conn_weights)[index][k] * std::sin( m_oscillators[k].phase - teta ); num_neighbors++; } } } else { for (std::size_t k = 0; k < size(); k++) { if (m_connections->has_connection(index, k)) { phase += std::sin( m_oscillators[k].phase - teta ); num_neighbors++; } } } if (num_neighbors == 0) { num_neighbors = 1; } phase = phase * weight / num_neighbors; return phase; } void syncnet::phase_kuramoto_equation(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const { outputs.resize(1); outputs[0] = phase_kuramoto(t, inputs[0], argv); } void syncnet::process(const double order, const solve_type solver, const bool collect_dynamic, syncnet_analyser & analyser) { simulate_dynamic(order, 0.1, solver, collect_dynamic, analyser); } } } pyclustering-0.10.1.2/ccore/src/cluster/ttsas.cpp000077500000000000000000000047421375753423500217160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace clst { ttsas::ttsas(const double p_threshold1, const double p_threshold2, const distance_metric & p_metric) : bsas(0, p_threshold1, p_metric), m_data_ptr(nullptr), m_threshold2(p_threshold2), m_skipped_objects(), m_start(0) { } void ttsas::process(const dataset & p_data, ttsas_data & p_result) { m_result_ptr = (ttsas_data *) &p_result; m_data_ptr = (dataset *) &p_data; m_amount = p_data.size(); m_skipped_objects = std::vector(p_data.size(), true); m_start = 0; std::size_t changes = 0; while (m_amount != 0) { const std::size_t previous_amount = m_amount; process_objects(changes); changes = previous_amount - m_amount; } } void ttsas::process_objects(const std::size_t p_changes) { for (; m_start < m_skipped_objects.size(); m_start++) { if (m_skipped_objects[m_start]) { break; } } if (p_changes == 0.0) { allocate_cluster(m_start, m_data_ptr->at(m_start)); m_start++; } for (std::size_t i = m_start; i < m_skipped_objects.size(); i++) { if (m_skipped_objects[i]) { process_skipped_object(i); } } } void ttsas::process_skipped_object(const std::size_t p_index_point) { const point & cur_point = m_data_ptr->at(p_index_point); const nearest_cluster nearest = find_nearest_cluster(cur_point); if (nearest.m_distance <= m_threshold) { append_to_cluster(nearest.m_index, p_index_point, cur_point); } else if (nearest.m_distance > m_threshold2) { allocate_cluster(p_index_point, cur_point); } } void ttsas::append_to_cluster(const std::size_t p_index_cluster, const std::size_t p_index_point, const point & p_point) { m_result_ptr->clusters()[p_index_cluster].push_back(p_index_point); update_representative(p_index_cluster, p_point); m_amount--; m_skipped_objects[p_index_point] = false; } void ttsas::allocate_cluster(const std::size_t p_index_point, const point & p_point) { m_result_ptr->clusters().push_back({ p_index_point }); m_result_ptr->representatives().push_back(p_point); m_amount--; m_skipped_objects[p_index_point] = false; } } }pyclustering-0.10.1.2/ccore/src/cluster/xmeans.cpp000077500000000000000000000254101375753423500220460ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include using namespace pyclustering::parallel; using namespace pyclustering::utils::metric; namespace pyclustering { namespace clst { const std::size_t xmeans::AMOUNT_CENTER_CANDIDATES = 5; const double xmeans::DEFAULT_SPLIT_DIFFERENCE = 0.001; const double xmeans::DEFAULT_TOLERANCE = 0.001; const splitting_type xmeans::DEFAULT_SPLITTING_TYPE = splitting_type::BAYESIAN_INFORMATION_CRITERION; const double xmeans::DEFAULT_MNDL_ALPHA_PROBABILISTIC_VALUE = 0.9; const double xmeans::DEFAULT_MNDL_BETA_PROBABILISTIC_VALUE = 0.9; xmeans::xmeans(const dataset & p_initial_centers, const std::size_t p_kmax, const double p_tolerance, const splitting_type p_criterion, std::size_t p_repeat, const long long p_random_state, const distance_metric & p_metric) : m_initial_centers(p_initial_centers), m_ptr_result(nullptr), m_ptr_data(nullptr), m_maximum_clusters(p_kmax), m_tolerance(p_tolerance), m_criterion(p_criterion), m_repeat(p_repeat), m_random_state(p_random_state), m_metric(p_metric) { } void xmeans::process(const dataset & p_data, xmeans_data & p_result) { m_ptr_data = &p_data; m_ptr_result = &p_result; m_ptr_result->centers() = m_initial_centers; dataset & centers = m_ptr_result->centers(); cluster_sequence & clusters = m_ptr_result->clusters(); std::size_t current_number_clusters = centers.size(); const index_sequence dummy; while (current_number_clusters <= m_maximum_clusters) { improve_parameters(clusters, centers, dummy); improve_structure(); if (current_number_clusters == centers.size()) { break; } current_number_clusters = centers.size(); } m_ptr_result->wce() = improve_parameters(clusters, centers, dummy); } void xmeans::set_mndl_alpha_bound(const double p_alpha) { if ((p_alpha > 1.0) || (p_alpha < 0)) { throw std::invalid_argument("Parameter for the probabilistic bound Q(alpha) should in the following range [0, 1] (current value: '" + std::to_string(p_alpha) + "')."); } m_alpha = p_alpha; } void xmeans::set_mndl_beta_bound(const double p_beta) { if ((p_beta > 1.0) || (p_beta < 0)) { throw std::invalid_argument("Parameter for the probabilistic bound Q(beta) should in the following range [0, 1] (current value: '" + std::to_string(p_beta) + "')."); } m_beta = p_beta; } double xmeans::improve_parameters(cluster_sequence & improved_clusters, dataset & improved_centers, const index_sequence & available_indexes) const { kmeans_data result; kmeans(improved_centers, m_tolerance, kmeans::DEFAULT_ITERMAX, m_metric).process((*m_ptr_data), available_indexes, result); improved_centers = result.centers(); improved_clusters = result.clusters(); return result.wce(); } double xmeans::search_optimal_parameters(cluster_sequence & improved_clusters, dataset & improved_centers, const index_sequence & available_indexes) const { double optimal_wce = std::numeric_limits::max(); for (std::size_t attempt = 0; attempt < m_repeat; attempt++) { /* initialize initial center using k-means++ */ dataset candidate_centers; const std::size_t candidates = available_indexes.size() < AMOUNT_CENTER_CANDIDATES ? available_indexes.size() : AMOUNT_CENTER_CANDIDATES; kmeans_plus_plus(2U, candidates, m_random_state).initialize(*m_ptr_data, available_indexes, candidate_centers); /* perform cluster analysis and update optimum if results became better */ cluster_sequence candidate_clusters; double candidate_wce = improve_parameters(candidate_clusters, candidate_centers, available_indexes); if (candidate_wce < optimal_wce) { improved_clusters = std::move(candidate_clusters); improved_centers = std::move(candidate_centers); optimal_wce = candidate_wce; } } return optimal_wce; } void xmeans::improve_structure() { cluster_sequence & clusters = m_ptr_result->clusters(); dataset & current_centers = m_ptr_result->centers(); std::vector region_allocated_centers(m_ptr_result->clusters().size(), dataset()); parallel_for(std::size_t(0), m_ptr_result->clusters().size(), [this, &clusters, ¤t_centers, ®ion_allocated_centers](const std::size_t p_index) { improve_region_structure(clusters[p_index], current_centers[p_index], region_allocated_centers[p_index]); }); /* update current centers */ dataset allocated_centers = { }; std::size_t amount_free_centers = m_maximum_clusters - clusters.size(); for (const auto & centers : region_allocated_centers) { if ( (centers.size() > 1) && (amount_free_centers > 0) ) { /* separate cluster */ allocated_centers.push_back(centers[0]); allocated_centers.push_back(centers[1]); amount_free_centers--; } else { allocated_centers.push_back(centers[0]); } } current_centers = allocated_centers; } void xmeans::improve_region_structure(const cluster & p_cluster, const point & p_center, dataset & p_allocated_centers) const { /* in case of cluster with one object */ if (p_cluster.size() == 1) { std::size_t index_center = p_cluster[0]; p_allocated_centers.push_back((*m_ptr_data)[index_center]); return; } /* solve k-means problem for children where data of parent are used */ dataset parent_child_centers; cluster_sequence parent_child_clusters; search_optimal_parameters(parent_child_clusters, parent_child_centers, p_cluster); if (parent_child_clusters.size() == 1) { /* real situation when all points in cluster are identical */ p_allocated_centers.push_back(p_center); return; } /* splitting criterion */ cluster_sequence parent_cluster(1, p_cluster); dataset parent_center(1, p_center); double parent_scores = splitting_criterion(parent_cluster, parent_center); double child_scores = splitting_criterion(parent_child_clusters, parent_child_centers); bool divide_descision = false; if (m_criterion == splitting_type::BAYESIAN_INFORMATION_CRITERION) { divide_descision = (parent_scores <= child_scores); } else if (m_criterion == splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH) { divide_descision = (parent_scores >= child_scores); } if (divide_descision) { p_allocated_centers.push_back(parent_child_centers[0]); p_allocated_centers.push_back(parent_child_centers[1]); } else { p_allocated_centers.push_back(p_center); } } double xmeans::splitting_criterion(const cluster_sequence & analysed_clusters, const dataset & analysed_centers) const { switch(m_criterion) { case splitting_type::BAYESIAN_INFORMATION_CRITERION: return bayesian_information_criterion(analysed_clusters, analysed_centers); case splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH: return minimum_noiseless_description_length(analysed_clusters, analysed_centers); default: /* Unexpected state - return default */ return bayesian_information_criterion(analysed_clusters, analysed_centers); } } double xmeans::bayesian_information_criterion(const cluster_sequence & analysed_clusters, const dataset & analysed_centers) const { double score = std::numeric_limits::max(); double dimension = (double) analysed_centers[0].size(); double sigma = 0.0; std::size_t K = analysed_centers.size(); std::size_t N = 0; for (std::size_t index_cluster = 0; index_cluster < analysed_clusters.size(); index_cluster++) { for (auto & index_object : analysed_clusters[index_cluster]) { sigma += m_metric((*m_ptr_data)[index_object], analysed_centers[index_cluster]); } N += analysed_clusters[index_cluster].size(); } if (N != K) { std::vector scores(analysed_centers.size(), 0.0); sigma /= (double) (N - K); double p = (K - 1) + dimension * K + 1; /* splitting criterion */ for (std::size_t index_cluster = 0; index_cluster < analysed_centers.size(); index_cluster++) { double n = (double) analysed_clusters[index_cluster].size(); double L = n * std::log(n) - n * std::log(N) - n * std::log(2.0 * utils::math::pi) / 2.0 - n * dimension * std::log(sigma) / 2.0 - (n - K) / 2.0; scores[index_cluster] = L - p * 0.5 * std::log(N); } score = std::accumulate(scores.begin(), scores.end(), 0.0); } return score; } double xmeans::minimum_noiseless_description_length(const cluster_sequence & clusters, const dataset & centers) const { double score = std::numeric_limits::max(); double W = 0.0; double K = (double) clusters.size(); double N = 0.0; double sigma_square = 0.0; for (std::size_t index_cluster = 0; index_cluster < clusters.size(); index_cluster++) { if (clusters[index_cluster].empty()) { return std::numeric_limits::max(); } double Ni = (double) clusters[index_cluster].size(); double Wi = 0.0; for (auto & index_object : clusters[index_cluster]) { Wi += m_metric((*m_ptr_data)[index_object], centers[index_cluster]); } sigma_square += Wi; W += Wi / Ni; N += Ni; } if (N - K > 0) { const double alpha = m_alpha; const double alpha_square = alpha * alpha; const double beta = m_beta; sigma_square /= (N - K); const double sigma = std::sqrt(sigma_square); const double Kw = (1.0 - K / N) * sigma_square; const double Ks = (2.0 * alpha * sigma / std::sqrt(N)) * std::sqrt(alpha_square * sigma_square / N + W - Kw / 2.0); const double UQa = W - Kw + (2.0 * alpha_square * sigma_square) / N + Ks; score = sigma_square * K / N + UQa + sigma_square * beta * std::sqrt(2.0 * K) / N; } return score; } } } pyclustering-0.10.1.2/ccore/src/container/000077500000000000000000000000001375753423500203435ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/container/adjacency_bit_matrix.cpp000077500000000000000000000062251375753423500252220ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include namespace pyclustering { namespace container { const size_t adjacency_bit_matrix::DEFAULT_EXISTANCE_CONNECTION_VALUE = 0x01; const size_t adjacency_bit_matrix::DEFAULT_NON_EXISTANCE_CONNECTION_VALUE = 0x00; adjacency_bit_matrix::adjacency_bit_matrix(const size_t node_amount) : m_adjacency(node_amount, std::vector(node_amount, 0)), m_size(node_amount) { } adjacency_bit_matrix::~adjacency_bit_matrix() { } size_t adjacency_bit_matrix::size() const { return m_size; } void adjacency_bit_matrix::set_connection(const size_t node_index1, const size_t node_index2) { update_connection(node_index1, node_index2, DEFAULT_EXISTANCE_CONNECTION_VALUE); } void adjacency_bit_matrix::erase_connection(const size_t node_index1, const size_t node_index2) { update_connection(node_index1, node_index2, DEFAULT_NON_EXISTANCE_CONNECTION_VALUE); } bool adjacency_bit_matrix::has_connection(const size_t node_index1, const size_t node_index2) const { const size_t index_element = node_index2 / (sizeof(size_t) << 3); const size_t bit_number = node_index2 - (index_element * (sizeof(size_t) << 3)); const size_t bit_value = (m_adjacency[node_index1][index_element] >> bit_number) & (size_t) DEFAULT_EXISTANCE_CONNECTION_VALUE; return (bit_value > 0); } void adjacency_bit_matrix::get_neighbors(const size_t node_index, std::vector & node_neighbors) const { node_neighbors.clear(); for (size_t neighbor_index = 0; neighbor_index != m_adjacency.size(); neighbor_index++) { if (has_connection(node_index, neighbor_index)) { node_neighbors.push_back(neighbor_index); } } } void adjacency_bit_matrix::clear() { m_adjacency.clear(); m_size = 0; } void adjacency_bit_matrix::update_connection(const size_t node_index1, const size_t node_index2, const size_t state_connection) { size_t element_byte_length = (sizeof(size_t) << 3); size_t index_element = node_index2 / element_byte_length; size_t bit_number = node_index2 % element_byte_length; if ( (node_index1 > m_adjacency.size()) || (index_element > m_adjacency.size()) ) { std::string message("adjacency bit matrix size: " + std::to_string(m_adjacency.size()) + ", index1: " + std::to_string(node_index1) + ", index2: " + std::to_string(node_index2)); throw std::out_of_range(message); } if (state_connection > 0) { m_adjacency[node_index1][index_element] |= ((size_t) 0x01 << bit_number); } else { m_adjacency[node_index1][index_element] &= ~((size_t) 0x01 << bit_number); } } adjacency_bit_matrix & adjacency_bit_matrix::operator=(adjacency_bit_matrix && another_matrix) { if (this != &another_matrix) { m_adjacency = std::move(another_matrix.m_adjacency); m_size = std::move(another_matrix.m_size); another_matrix.m_size = 0; } return *this; } } }pyclustering-0.10.1.2/ccore/src/container/adjacency_connector.cpp000077500000000000000000000017071375753423500250520ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace container { std::ostream & operator<<(std::ostream & p_stream, const connection_t & p_structure) { switch (p_structure) { case connection_t::CONNECTION_ALL_TO_ALL: p_stream << "all-to-all"; break; case connection_t::CONNECTION_GRID_EIGHT: p_stream << "grid eight"; break; case connection_t::CONNECTION_GRID_FOUR: p_stream << "grid four"; break; case connection_t::CONNECTION_LIST_BIDIRECTIONAL: p_stream << "bidirectional list"; break; case connection_t::CONNECTION_NONE: p_stream << "none structure"; break; default: p_stream << "unknown structure"; break; } return p_stream; } } }pyclustering-0.10.1.2/ccore/src/container/adjacency_factory.cpp000077500000000000000000000047161375753423500245320ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include namespace pyclustering { namespace container { std::shared_ptr adjacency_unweight_factory::create_collection(const size_t amount_nodes, const adjacency_unweight_t storing_type, const connection_t structure_type) { adjacency_collection * collection = nullptr; switch(storing_type) { case adjacency_unweight_t::ADJACENCY_BIT_MATRIX: collection = new adjacency_bit_matrix(amount_nodes); break; case adjacency_unweight_t::ADJACENCY_LIST: collection = new adjacency_list(amount_nodes); break; case adjacency_unweight_t::ADJACENCY_MATRIX: collection = new adjacency_matrix(amount_nodes); break; default: throw std::runtime_error("Unknown type of adjacency collection without weights is required from the factory."); } /* establish structures between nodes */ adjacency_connector connector; connector.create_structure(structure_type, *collection); return std::shared_ptr(collection); } std::shared_ptr adjacency_weight_factory::create_collection(const size_t amount_nodes, const adjacency_weight_t storing_type, const connection_t structure_type, const std::function & weight_value_generator) { adjacency_weight_collection * collection = nullptr; switch(storing_type) { case adjacency_weight_t::ADJACENCY_LIST: collection = new adjacency_weight_list(amount_nodes); break; case adjacency_weight_t::ADJACENCY_MATRIX: collection = new adjacency_matrix(amount_nodes); break; default: throw std::runtime_error("Unknown type of adjacency collection without weights is required from the factory."); } /* establish structures between nodes */ adjacency_weight_connector connector(weight_value_generator); connector.create_structure(structure_type, *collection); return std::shared_ptr(collection); } } }pyclustering-0.10.1.2/ccore/src/container/adjacency_list.cpp000077500000000000000000000036651375753423500240400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include namespace pyclustering { namespace container { adjacency_list::adjacency_list() : m_adjacency(adjacency_list_container()) { } adjacency_list::adjacency_list(const size_t node_amount) : m_adjacency(node_amount) { } adjacency_list::~adjacency_list() { } size_t adjacency_list::size() const { return m_adjacency.size(); } void adjacency_list::set_connection(const size_t node_index1, const size_t node_index2) { m_adjacency[node_index1].insert(node_index2); } void adjacency_list::erase_connection(const size_t node_index1, const size_t node_index2) { m_adjacency[node_index1].erase(node_index2); } bool adjacency_list::has_connection(const size_t node_index1, const size_t node_index2) const { const std::unordered_set & node_neighbors = m_adjacency[node_index1]; if (node_neighbors.find(node_index2) != node_neighbors.end()) { return true; } return false; } void adjacency_list::get_neighbors(const size_t node_index, std::vector & node_neighbors) const { node_neighbors.resize(m_adjacency[node_index].size()); std::copy(m_adjacency[node_index].begin(), m_adjacency[node_index].end(), node_neighbors.begin()); } void adjacency_list::clear() { m_adjacency.clear(); } adjacency_list & adjacency_list::operator=(const adjacency_list & another_collection) { if (this != &another_collection) { m_adjacency = another_collection.m_adjacency; } return *this; } adjacency_list & adjacency_list::operator=(adjacency_list && another_collection) { if (this != &another_collection) { m_adjacency = std::move(another_collection.m_adjacency); } return *this; } } }pyclustering-0.10.1.2/ccore/src/container/adjacency_matrix.cpp000077500000000000000000000051061375753423500243610ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace container { const double adjacency_matrix::DEFAULT_EXISTANCE_CONNECTION_VALUE = 1.0; const double adjacency_matrix::DEFAULT_NON_EXISTANCE_CONNECTION_VALUE = 0.0; adjacency_matrix::adjacency_matrix(const size_t node_amount) : m_adjacency(node_amount, std::vector(node_amount, DEFAULT_NON_EXISTANCE_CONNECTION_VALUE)) { } adjacency_matrix::~adjacency_matrix() { } size_t adjacency_matrix::size() const { return m_adjacency.size(); } void adjacency_matrix::set_connection(const size_t node_index1, const size_t node_index2) { m_adjacency[node_index1][node_index2] = DEFAULT_EXISTANCE_CONNECTION_VALUE; } bool adjacency_matrix::has_connection(const size_t node_index1, const size_t node_index2) const { return (m_adjacency[node_index1][node_index2] != DEFAULT_NON_EXISTANCE_CONNECTION_VALUE); } void adjacency_matrix::erase_connection(const size_t node_index1, const size_t node_index2) { m_adjacency[node_index1][node_index2] = DEFAULT_NON_EXISTANCE_CONNECTION_VALUE; } void adjacency_matrix::get_neighbors(const size_t node_index, std::vector & node_neighbors) const { node_neighbors.clear(); const std::vector & node_neighbor_connections = m_adjacency[node_index]; for (size_t neighbor_index = 0; neighbor_index != node_neighbor_connections.size(); neighbor_index++) { if (node_neighbor_connections[neighbor_index] != DEFAULT_NON_EXISTANCE_CONNECTION_VALUE) { node_neighbors.push_back(neighbor_index); } } } void adjacency_matrix::set_connection_weight(const size_t node_index1, const size_t node_index2, const double weight) { m_adjacency[node_index1][node_index2] = weight; } double adjacency_matrix::get_connection_weight(const size_t node_index1, const size_t node_index2) const { return m_adjacency[node_index1][node_index2]; } void adjacency_matrix::clear() { m_adjacency.clear(); } adjacency_matrix & adjacency_matrix::operator=(const adjacency_matrix & another_collection) { if (this != &another_collection) { m_adjacency = another_collection.m_adjacency; } return *this; } adjacency_matrix & adjacency_matrix::operator=(adjacency_matrix && another_collection) { if (this != &another_collection) { m_adjacency = std::move(another_collection.m_adjacency); } return *this; } } }pyclustering-0.10.1.2/ccore/src/container/adjacency_weight_list.cpp000077500000000000000000000050301375753423500253730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace container { const double adjacency_weight_list::DEFAULT_EXISTANCE_CONNECTION_VALUE = 1.0; const double adjacency_weight_list::DEFAULT_NON_EXISTANCE_CONNECTION_VALUE = 0.0; adjacency_weight_list::adjacency_weight_list(const size_t node_amount) : m_adjacency(node_amount) { } adjacency_weight_list::~adjacency_weight_list() { } size_t adjacency_weight_list::size() const { return m_adjacency.size(); } void adjacency_weight_list::set_connection(const size_t node_index1, const size_t node_index2) { m_adjacency[node_index1].insert( { node_index2, DEFAULT_EXISTANCE_CONNECTION_VALUE } ); } void adjacency_weight_list::erase_connection(const size_t node_index1, const size_t node_index2) { m_adjacency[node_index1].erase(node_index2); } bool adjacency_weight_list::has_connection(const size_t node_index1, const size_t node_index2) const { const std::unordered_map & node_neighbors = m_adjacency[node_index1]; if (node_neighbors.find(node_index2) != node_neighbors.end()) { return true; } return false; } void adjacency_weight_list::get_neighbors(const size_t node_index, std::vector & node_neighbors) const { node_neighbors.clear(); node_neighbors.reserve(m_adjacency[node_index].size()); for (auto index_neighbor : m_adjacency[node_index]) { node_neighbors.push_back(index_neighbor.first); } } void adjacency_weight_list::set_connection_weight(const size_t node_index1, const size_t node_index2, const double weight) { std::unordered_map & node_neighbors = m_adjacency[node_index1]; if (weight != 0.0) { node_neighbors[node_index2] = weight; } else { node_neighbors.erase(node_index2); } } double adjacency_weight_list::get_connection_weight(const size_t node_index1, const size_t node_index2) const { const std::unordered_map & node_neighbors = m_adjacency[node_index1]; const std::unordered_map::const_iterator connection_iterator = node_neighbors.find(node_index2); if (connection_iterator != node_neighbors.end()) { return connection_iterator->second; } return DEFAULT_NON_EXISTANCE_CONNECTION_VALUE; } void adjacency_weight_list::clear() { m_adjacency.clear(); } } }pyclustering-0.10.1.2/ccore/src/container/kdnode.cpp000077500000000000000000000077601375753423500223300ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace container { kdnode::kdnode(const std::vector & p_data, void * p_payload, const kdnode::ptr & p_left, const kdnode::ptr & p_right, const kdnode::ptr & p_parent, const std::size_t p_desc) : m_data(p_data), m_payload(p_payload), m_left(p_left), m_right(p_right), m_parent(p_parent), m_discriminator(p_desc) { } void kdnode::set_left(const kdnode::ptr & p_node) { m_left = p_node; } void kdnode::set_right(const kdnode::ptr & p_node) { m_right = p_node; } void kdnode::set_parent(const kdnode::ptr & p_node) { m_parent = p_node; } void kdnode::set_data(const point & p_data) { m_data = p_data; } void kdnode::set_payload(void * p_payload) { m_payload = p_payload; } void kdnode::set_discriminator(const std::size_t disc) { m_discriminator = disc; } kdnode::ptr kdnode::get_left() const { return m_left; } kdnode::ptr kdnode::get_right() const { return m_right; } kdnode::ptr kdnode::get_parent() const { return m_parent.lock(); } void * kdnode::get_payload() const { return m_payload; } kdnode::ptr kdnode::find_node(const point & p_point) { search_node_rule rule = [&p_point](const kdnode & p_node) { return p_point == p_node.get_data(); }; return find_node(p_point, rule); } kdnode::ptr kdnode::find_node(const point & p_point, const search_node_rule & p_rule) { kdnode::ptr cur_node = shared_from_this(); while (cur_node != nullptr) { if (*cur_node <= p_point) { if (p_rule(*cur_node)) { /* Less or equal - check if equal. */ return cur_node; } cur_node = cur_node->get_right(); } else { cur_node = cur_node->get_left(); } } return nullptr; } const std::vector & kdnode::get_data() const { return m_data; } std::vector & kdnode::get_data() { return m_data; } double kdnode::get_value() const { return m_data[m_discriminator]; } double kdnode::get_value(const std::size_t p_descr) const { return m_data[p_descr]; } std::size_t kdnode::get_discriminator() const { return m_discriminator; } std::size_t kdnode::get_dimension() const { return m_data.size(); } void kdnode::get_children(std::vector & p_children) { p_children.clear(); if (m_left != nullptr) { p_children.push_back(m_left); } if (m_right != nullptr) { p_children.push_back(m_right); } } bool operator < (const kdnode & node, const std::vector & point) { return node.get_value() < point[node.get_discriminator()]; } bool operator < (const std::vector & point, const kdnode & node) { return point[node.get_discriminator()] < node.get_value(); } bool operator > (const kdnode & node, const std::vector & point) { return point[node.get_discriminator()] < node.get_value(); } bool operator > (const std::vector & point, const kdnode & node) { return node.get_value() < point[node.get_discriminator()]; } bool operator <= (const kdnode & node, const std::vector & point) { return !(node.get_value() > point[node.get_discriminator()]); } bool operator <= (const std::vector & point, const kdnode & node) { return !(point[node.get_discriminator()] > node.get_value()); } bool operator >= (const kdnode & node, const std::vector & point) { return !(node.get_value() < point[node.get_discriminator()]); } bool operator >= (const std::vector & point, const kdnode & node) { return !(point[node.get_discriminator()] < node.get_value()); } bool operator == (const kdnode & node, const std::vector & point) { return node.get_value() == point[node.get_discriminator()]; } bool operator == (const std::vector & point, const kdnode & node) { return node == point; } } }pyclustering-0.10.1.2/ccore/src/container/kdtree.cpp000077500000000000000000000134421375753423500223340ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include namespace pyclustering { namespace container { kdtree::kdtree(const dataset & p_data, const std::vector & p_payloads) : kdtree_balanced(p_data, p_payloads) { } kdnode::ptr kdtree::insert(const std::vector & p_point, void * p_payload) { kdnode::ptr inserted_kdnode; if (m_root == nullptr) { kdnode::ptr node = std::make_shared(p_point, p_payload, nullptr, nullptr, nullptr, 0); m_root = node; m_dimension = node->get_dimension(); inserted_kdnode = std::move(node); } else { kdnode::ptr cur_node = m_root; while(true) { /* If new node is greater or equal than current node then check right leaf */ if (*cur_node <= p_point) { if (cur_node->get_right() == nullptr) { std::size_t discriminator = cur_node->get_discriminator() + 1; if (discriminator >= m_dimension) { discriminator = 0; } cur_node->set_right(std::make_shared(p_point, p_payload, nullptr, nullptr, cur_node, discriminator)); inserted_kdnode = cur_node->get_right(); break; } else { cur_node = cur_node->get_right(); } } /* If new node is less than current then check left leaf */ else { if (cur_node->get_left() == nullptr) { std::size_t discriminator = cur_node->get_discriminator() + 1; if (discriminator >= m_dimension) { discriminator = 0; } cur_node->set_left(std::make_shared(p_point, p_payload, nullptr, nullptr, cur_node, discriminator)); inserted_kdnode = cur_node->get_left(); break; } else { cur_node = cur_node->get_left(); } } } } m_size++; return inserted_kdnode; } void kdtree::remove(const std::vector & p_point) { kdnode::ptr node_for_remove = find_node(p_point); if (node_for_remove == nullptr) { return; } remove(node_for_remove); } void kdtree::remove(const std::vector & p_point, const void * p_payload) { kdnode::ptr node_for_remove = find_node(p_point, p_payload); if (node_for_remove == nullptr) { return; } remove(node_for_remove); } void kdtree::remove(kdnode::ptr & p_node_for_remove) { kdnode::ptr parent = p_node_for_remove->get_parent(); kdnode::ptr node = recursive_remove(p_node_for_remove); if (parent == nullptr) { m_root = node; /* if tree is almost destroyed */ if (node != nullptr) { node->set_parent(nullptr); } m_size--; } else { if (parent->get_left() == p_node_for_remove) { parent->set_left(node); } else if (parent->get_right() == p_node_for_remove) { parent->set_right(node); } else { throw std::runtime_error("Structure of KD Tree is corrupted"); } m_size--; } } kdnode::ptr kdtree::recursive_remove(kdnode::ptr & p_node) { if ( (p_node->get_right() == nullptr) && (p_node->get_left() == nullptr) ) { return nullptr; } std::size_t discriminator = p_node->get_discriminator(); /* Check if only left branch exist */ if (p_node->get_right() == nullptr) { p_node->set_right(p_node->get_left()); p_node->set_left(nullptr); } /* Find minimal node in line with coordinate that is defined by discriminator */ kdnode::ptr minimal_node = find_minimal_node(p_node->get_right(), discriminator); kdnode::ptr parent = minimal_node->get_parent(); if (parent->get_left() == minimal_node) { parent->set_left(recursive_remove(minimal_node)); } else if (parent->get_right() == minimal_node) { parent->set_right(recursive_remove(minimal_node)); } else { throw std::runtime_error("Structure of KD Tree is corrupted"); } minimal_node->set_parent(p_node->get_parent()); minimal_node->set_discriminator(p_node->get_discriminator()); minimal_node->set_right(p_node->get_right()); minimal_node->set_left(p_node->get_left()); /* Update parent for successors of previous parent */ if (minimal_node->get_right() != nullptr) { minimal_node->get_right()->set_parent(minimal_node); } if (minimal_node->get_left() != nullptr) { minimal_node->get_left()->set_parent(minimal_node); } return minimal_node; } kdnode::ptr kdtree::find_minimal_node(const kdnode::ptr & p_cur_node, std::size_t p_discriminator) { std::stack stack; kdnode::ptr minimal_node = p_cur_node; kdnode::ptr cursor = p_cur_node; std::vector candidates; bool is_done = false; while (!is_done) { if (cursor != nullptr) { stack.push(cursor); cursor = cursor->get_left(); } else { if (!stack.empty()) { cursor = stack.top(); candidates.push_back(cursor); stack.pop(); cursor = cursor->get_right(); } else { is_done = true; } } } for (size_t i = 0; i < candidates.size(); i++) { if (candidates[i]->get_value(p_discriminator) <= minimal_node->get_value(p_discriminator)) { minimal_node = candidates[i]; } } return minimal_node; } } } pyclustering-0.10.1.2/ccore/src/container/kdtree_balanced.cpp000077500000000000000000000061351375753423500241460ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::algorithm; namespace pyclustering { namespace container { kdtree_balanced::kdtree_balanced(const dataset & p_data, const std::vector & p_payloads) { if (p_data.empty()) { return; } std::vector nodes(p_data.size()); for (std::size_t i = 0; i < p_data.size(); i++) { nodes[i] = std::make_shared(p_data[i], nullptr, nullptr, nullptr, nullptr, 0); if (!p_payloads.empty()) { nodes[i]->set_payload(p_payloads[i]); } } m_dimension = p_data.at(0).size(); m_root = create_tree(nodes.begin(), nodes.end(), nullptr, 0); } kdnode::ptr kdtree_balanced::create_tree(std::vector::iterator p_begin, std::vector::iterator p_end, const kdnode::ptr & p_parent, const std::size_t p_depth) { const int length = static_cast(std::distance(p_begin, p_end)); if (length == 0) { return nullptr; } const std::size_t discriminator = p_depth % m_dimension; const int median = length / 2; std::sort(p_begin, p_end, [discriminator](const kdnode::ptr & p1, const kdnode::ptr & p2) { return p1->get_data()[discriminator] < p2->get_data()[discriminator]; }); auto median_iter = find_left_element(p_begin, p_begin + median + 1, [discriminator](const kdnode::ptr & p1, const kdnode::ptr & p2) { return p1->get_data()[discriminator] < p2->get_data()[discriminator]; } ); kdnode::ptr new_node = *median_iter; new_node->set_parent(p_parent); new_node->set_discriminator(discriminator); new_node->set_left(create_tree(p_begin, median_iter, new_node, p_depth + 1)); new_node->set_right(create_tree(median_iter + 1, p_end, new_node, p_depth + 1)); m_size++; return new_node; } kdnode::ptr kdtree_balanced::find_node(const point & p_point) const { return m_root ? m_root->find_node(p_point) : nullptr; } kdnode::ptr kdtree_balanced::find_node(const point & p_point, const void * p_payload) const { if (!m_root) { return nullptr; } return m_root->find_node(p_point, [&p_point, p_payload](const kdnode & p_node) { return (p_point == p_node.get_data()) && (p_payload == p_node.get_payload()); }); } kdnode::ptr kdtree_balanced::get_root() const { return m_root; } std::size_t kdtree_balanced::get_size() const { return m_size; } kdtree_balanced & kdtree_balanced::operator=(const kdtree_balanced & p_other) { if (this != &p_other) { m_root = p_other.m_root; m_dimension = p_other.m_dimension; m_size = p_other.m_size; } return *this; } kdtree_balanced & kdtree_balanced::operator=(kdtree_balanced && p_other) { if (this != &p_other) { m_root = std::move(p_other.m_root); m_dimension = std::move(p_other.m_dimension); m_size = std::move(p_other.m_size); } return *this; } } }pyclustering-0.10.1.2/ccore/src/container/kdtree_searcher.cpp000077500000000000000000000065641375753423500242170ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace container { kdtree_searcher::kdtree_searcher(const std::vector & point, const kdnode::ptr & node, const double radius_search) { initialize(point, node, radius_search); } void kdtree_searcher::initialize(const std::vector & point, const kdnode::ptr & node, const double radius_search) { m_distance = radius_search; m_sqrt_distance = radius_search * radius_search; m_initial_node = node; m_search_point = point; } void kdtree_searcher::recursive_nearest_nodes(const kdnode::ptr & node) const { double minimum = node->get_value() - m_distance; double maximum = node->get_value() + m_distance; if (node->get_right() != nullptr) { if (m_search_point[node->get_discriminator()] >= minimum) { recursive_nearest_nodes(node->get_right()); } } if (node->get_left() != nullptr) { if (m_search_point[node->get_discriminator()] < maximum) { recursive_nearest_nodes(node->get_left()); } } m_proc(node); } void kdtree_searcher::store_if_reachable(const kdnode::ptr & node) const { double candidate_distance = euclidean_distance_square(m_search_point, node->get_data()); if (candidate_distance <= m_sqrt_distance) { m_nearest_nodes.push_back(node); m_nodes_distance.push_back(candidate_distance); } } void kdtree_searcher::store_best_if_reachable(const kdnode::ptr & node) const { double candidate_distance = euclidean_distance_square(m_search_point, node->get_data()); if (candidate_distance <= m_nodes_distance[0]) { m_nearest_nodes[0] = node; m_nodes_distance[0] = candidate_distance; } } void kdtree_searcher::store_user_nodes_if_reachable(const kdnode::ptr & node) const { double candidate_distance = euclidean_distance_square(m_search_point, node->get_data()); if (candidate_distance <= m_sqrt_distance) { m_user_rule(node, candidate_distance); } } void kdtree_searcher::find_nearest_nodes(std::vector & p_distances, std::vector & p_nearest_nodes) const { m_proc = std::bind(&kdtree_searcher::store_if_reachable, this, std::placeholders::_1); recursive_nearest_nodes(m_initial_node); p_distances = std::move(m_nodes_distance); p_nearest_nodes = std::move(m_nearest_nodes); clear(); } void kdtree_searcher::find_nearest(const rule_store & p_store_rule) const { m_proc = std::bind(&kdtree_searcher::store_user_nodes_if_reachable, this, std::placeholders::_1); m_user_rule = p_store_rule; recursive_nearest_nodes(m_initial_node); clear(); } kdnode::ptr kdtree_searcher::find_nearest_node() const { m_nearest_nodes = { nullptr }; m_nodes_distance = { std::numeric_limits::max() }; m_proc = std::bind(&kdtree_searcher::store_best_if_reachable, this, std::placeholders::_1); recursive_nearest_nodes(m_initial_node); kdnode::ptr node = m_nearest_nodes.front(); clear(); return node; } void kdtree_searcher::clear() const { m_nodes_distance = {}; m_nearest_nodes = {}; m_nearest_points = {}; m_user_rule = nullptr; m_proc = nullptr; } } }pyclustering-0.10.1.2/ccore/src/differential/000077500000000000000000000000001375753423500210155ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/differential/differ_factor.cpp000077500000000000000000000026161375753423500243260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace differential { const double factor::A2 = 1.0 / 4.0; const double factor::B2 = 1.0 / 4.0; const double factor::A3 = 3.0 / 8.0; const double factor::B3 = 3.0 / 32.0; const double factor::C3 = 9.0 / 32.0; const double factor::A4 = 12.0 / 13.0; const double factor::B4 = 1932.0 / 2197.0; const double factor::C4 = -7200.0 / 2197.0; const double factor::D4 = 7296.0 / 2197.0; const double factor::A5 = 1.0; const double factor::B5 = 439.0 / 216.0; const double factor::C5 = -8.0; const double factor::D5 = 3680.0 / 513.0; const double factor::E5 = -845.0 / 4104.0; const double factor::A6 = 1.0 / 2.0; const double factor::B6 = -8.0 / 27.0; const double factor::C6 = 2.0; const double factor::D6 = -3544.0 / 2565.0; const double factor::E6 = 1859.0 / 4104.0; const double factor::F6 = -11.0 / 40.0; const double factor::N1 = 25.0 / 216.0; const double factor::N3 = 1408.0 / 2565.0; const double factor::N4 = 2197.0 / 4104.0; const double factor::N5 = -1.0 / 5.0; const double factor::R1 = 1.0 / 360.0; const double factor::R3 = -128.0 / 4275.0; const double factor::R4 = -2197.0 / 75240.0; const double factor::R5 = 1.0 / 50.0; const double factor::R6 = 2.0 / 55.0; } }pyclustering-0.10.1.2/ccore/src/interface/000077500000000000000000000000001375753423500203215ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/interface/agglomerative_interface.cpp000077500000000000000000000013451375753423500257010ustar00rootroot00000000000000/* @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * agglomerative_algorithm(const pyclustering_package * const p_sample, const std::size_t p_number_clusters, const std::size_t p_link) { pyclustering::clst::agglomerative algorithm(p_number_clusters, (pyclustering::clst::agglomerative::type_link) p_link); pyclustering::dataset data; p_sample->extract(data); pyclustering::clst::agglomerative_data result; algorithm.process(data, result); pyclustering_package * package = create_package(&result.clusters()); return package; } pyclustering-0.10.1.2/ccore/src/interface/bsas_interface.cpp000077500000000000000000000031141375753423500237770ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering; using namespace pyclustering::utils::metric; pyclustering_package * bsas_algorithm(const pyclustering_package * const p_sample, const std::size_t p_amount, const double p_threshold, const void * const p_metric) { distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::bsas algorithm(p_amount, p_threshold, *metric); dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::bsas_data output_result; algorithm.process(input_dataset, output_result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = BSAS_PACKAGE_SIZE; package->data = new pyclustering_package * [BSAS_PACKAGE_SIZE]; ((pyclustering_package **) package->data)[BSAS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[BSAS_PACKAGE_INDEX_REPRESENTATIVES] = create_package(&output_result.representatives()); return package; }pyclustering-0.10.1.2/ccore/src/interface/clique_interface.cpp000077500000000000000000000057271375753423500243450ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include constexpr const char * CLIQUE_NOT_ENOUGH_MEMORY = "There is not enough memory to perform cluster analysis using CLIQUE algorithm. " "CLIQUE algorithm might not be suitable in case of high dimension data because CLIQUE is a grid-based algorithm and " "the amount of CLIQUE blocks (cells) is defined as '[amount_intervals]^[amount_dimensions]'."; pyclustering_package * clique_algorithm(const pyclustering_package * const p_sample, const std::size_t p_intervals, const std::size_t p_threshold) try { pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::clique solver(p_intervals, p_threshold); pyclustering::clst::clique_data output_result; solver.process(input_dataset, output_result); pyclustering_package * package = create_package_container(CLIQUE_PACKAGE_SIZE); ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_NOISE] = create_package(&output_result.noise()); const auto & blocks = output_result.blocks(); ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_LOGICAL_LOCATION] = create_package_container(blocks.size()); ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_MAX_CORNER] = create_package_container(blocks.size()); ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_MIN_CORNER] = create_package_container(blocks.size()); ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_BLOCK_POINTS] = create_package_container(blocks.size()); pyclustering_package * logical_location = ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_LOGICAL_LOCATION]; pyclustering_package * max_corner = ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_MAX_CORNER]; pyclustering_package * min_corner = ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_MIN_CORNER]; pyclustering_package * block_points = ((pyclustering_package **) package->data)[CLIQUE_PACKAGE_INDEX_BLOCK_POINTS]; for (std::size_t i = 0; i < blocks.size(); i++) { ((pyclustering_package **) logical_location->data)[i] = create_package(&(blocks[i].get_logical_location())); ((pyclustering_package **) max_corner->data)[i] = create_package(&(blocks[i].get_spatial_block().get_max_corner())); ((pyclustering_package **) min_corner->data)[i] = create_package(&(blocks[i].get_spatial_block().get_min_corner())); ((pyclustering_package **) block_points->data)[i] = create_package(&(blocks[i].get_points())); } return package; } catch (std::bad_alloc &) { return create_package(CLIQUE_NOT_ENOUGH_MEMORY); } catch (std::exception & p_exception) { return create_package(p_exception.what()); }pyclustering-0.10.1.2/ccore/src/interface/cure_interface.cpp000077500000000000000000000033271375753423500240130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include void * cure_algorithm(const pyclustering_package * const sample, const size_t number_clusters, const size_t number_repr_points, const double compression) { pyclustering::dataset input_dataset; sample->extract(input_dataset); pyclustering::clst::cure solver(number_clusters, number_repr_points, compression); pyclustering::clst::cure_data * output_result = new pyclustering::clst::cure_data(); solver.process(input_dataset, *output_result); return output_result; } void cure_data_destroy(void * pointer_cure_data) { delete (pyclustering::clst::cure_data *) pointer_cure_data; } pyclustering_package * cure_get_clusters(void * pointer_cure_data) { pyclustering::clst::cure_data & output_result = (pyclustering::clst::cure_data &) *((pyclustering::clst::cure_data *)pointer_cure_data); pyclustering_package * package = create_package(&output_result.clusters()); return package; } pyclustering_package * cure_get_representors(void * pointer_cure_data) { pyclustering::clst::cure_data & output_result = (pyclustering::clst::cure_data &) *((pyclustering::clst::cure_data *)pointer_cure_data); pyclustering_package * package = create_package(&output_result.representors()); return package; } pyclustering_package * cure_get_means(void * pointer_cure_data) { pyclustering::clst::cure_data & output_result = (pyclustering::clst::cure_data &) *((pyclustering::clst::cure_data *)pointer_cure_data); pyclustering_package * package = create_package(&output_result.means()); return package; } pyclustering-0.10.1.2/ccore/src/interface/dbscan_interface.cpp000077500000000000000000000024571375753423500243120ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * dbscan_algorithm(const pyclustering_package * const p_sample, const double p_radius, const size_t p_minumum_neighbors, const size_t p_data_type) { pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::dbscan solver(p_radius, p_minumum_neighbors); pyclustering::clst::dbscan_data output_result; solver.process(input_dataset, (pyclustering::clst::dbscan_data_t) p_data_type, output_result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = output_result.size() + 1; /* the last for noise */ package->data = new pyclustering_package * [package->size + 1]; for (std::size_t i = 0; i < package->size - 1; i++) { ((pyclustering_package **) package->data)[i] = create_package(&output_result[i]); } ((pyclustering_package **) package->data)[package->size - 1] = create_package(&output_result.noise()); return package; } pyclustering-0.10.1.2/ccore/src/interface/elbow_interface.cpp000077500000000000000000000024341375753423500241630ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include pyclustering_package * elbow_method_ikpp(const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep, const long long p_random_state) try { return elbow_method(p_sample, p_kmin, p_kmax, p_kstep, p_random_state); } catch (std::exception & p_exception) { return create_package(p_exception.what()); } pyclustering_package * elbow_method_irnd(const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_kstep, const long long p_random_state) try { return elbow_method(p_sample, p_kmin, p_kmax, p_kstep, p_random_state); } catch (std::exception & p_exception) { return create_package(p_exception.what()); }pyclustering-0.10.1.2/ccore/src/interface/fcm_interface.cpp000077500000000000000000000024041375753423500236150ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * fcm_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_centers, const double p_m, const double p_tolerance, const std::size_t p_itermax) { pyclustering::dataset data, centers; p_sample->extract(data); p_centers->extract(centers); pyclustering::clst::fcm algorithm(centers, p_m, p_tolerance, p_itermax); pyclustering::clst::fcm_data output_result; algorithm.process(data, output_result); pyclustering_package * package = create_package_container(FCM_PACKAGE_SIZE); ((pyclustering_package **) package->data)[FCM_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[FCM_PACKAGE_INDEX_CENTERS] = create_package(&output_result.centers()); ((pyclustering_package **) package->data)[FCM_PACKAGE_INDEX_MEMBERSHIP] = create_package(&output_result.membership()); return package; }pyclustering-0.10.1.2/ccore/src/interface/gmeans_interface.cpp000077500000000000000000000025661375753423500243330ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * gmeans_algorithm(const pyclustering_package * const p_sample, const std::size_t p_amount, const double p_tolerance, const std::size_t p_repeat, const long long p_kmax, const long long p_random_state) { pyclustering::dataset data; p_sample->extract(data); pyclustering::clst::gmeans algorithm(p_amount, p_tolerance, p_repeat, p_kmax, p_random_state); pyclustering::clst::gmeans_data output_result; algorithm.process(data, output_result); std::vector wce_storage(1, output_result.wce()); pyclustering_package * package = create_package_container(GMEANS_PACKAGE_SIZE); ((pyclustering_package **) package->data)[GMEANS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[GMEANS_PACKAGE_INDEX_CENTERS] = create_package(&output_result.centers()); ((pyclustering_package **) package->data)[GMEANS_PACKAGE_INDEX_WCE] = create_package(&wce_storage); return package; } pyclustering-0.10.1.2/ccore/src/interface/hhn_interface.cpp000077500000000000000000000070471375753423500236350ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::nnet; void * hhn_create(const std::size_t p_size, const void * const p_params) { hhn_network * network = new hhn_network(p_size, *((hnn_parameters *) p_params)); return network; } void hhn_destroy(const void * p_network_pointer) { delete (hhn_network *) p_network_pointer; } void * hhn_dynamic_create(bool p_collect_membrane, bool p_collect_active_cond_sodium, bool p_collect_inactive_cond_sodium, bool p_collect_active_cond_potassium) { hhn_dynamic * output_dynamic = new hhn_dynamic(); output_dynamic->disable_all(); if (p_collect_membrane) { output_dynamic->enable(hhn_dynamic::collect::MEMBRANE_POTENTIAL); } if (p_collect_active_cond_sodium) { output_dynamic->enable(hhn_dynamic::collect::ACTIVE_COND_SODIUM); } if (p_collect_inactive_cond_sodium) { output_dynamic->enable(hhn_dynamic::collect::INACTIVE_COND_SODIUM); } if (p_collect_active_cond_potassium) { output_dynamic->enable(hhn_dynamic::collect::ACTIVE_COND_POTASSIUM); } return output_dynamic; } void hhn_dynamic_destroy(const void * p_dynamic) { delete (hhn_dynamic *) p_dynamic; } void hhn_simulate(const void * p_network_pointer, const std::size_t p_steps, const double p_time, const std::size_t p_solver, const pyclustering_package * const p_stimulus, const void * p_output_dynamic) { hhn_network * network = (hhn_network *) p_network_pointer; hhn_dynamic * dynamic = (hhn_dynamic *) p_output_dynamic; hhn_stimulus stimulus_vector((double *)p_stimulus->data, ((double *)p_stimulus->data) + p_stimulus->size); network->simulate(p_steps, p_time, (solve_type) p_solver, stimulus_vector, *dynamic); } pyclustering_package * hhn_dynamic_get_peripheral_evolution(const void * p_output_dynamic, const std::size_t p_collection_index) { hhn_dynamic * dynamic = (hhn_dynamic *) p_output_dynamic; hhn_dynamic::evolution_dynamic & evolution = dynamic->get_peripheral_dynamic((hhn_dynamic::collect) p_collection_index); pyclustering_package * package = create_package(&evolution); return package; } pyclustering_package * hhn_dynamic_get_central_evolution(const void * p_output_dynamic, const std::size_t p_collection_index) { hhn_dynamic * dynamic = (hhn_dynamic *) p_output_dynamic; hhn_dynamic::evolution_dynamic & evolution = dynamic->get_central_dynamic((hhn_dynamic::collect) p_collection_index); pyclustering_package * package = create_package(&evolution); return package; } pyclustering_package * hhn_dynamic_get_time(const void * p_output_dynamic) { hhn_dynamic * dynamic = (hhn_dynamic *) p_output_dynamic; hhn_dynamic::value_dynamic_ptr evolution = dynamic->get_time(); pyclustering_package * package = create_package(evolution.get()); return package; } void hhn_dynamic_write(const void * p_output_dynamic, const char * p_filename) { hhn_dynamic * dynamic = (hhn_dynamic *) p_output_dynamic; std::ofstream file_stream(p_filename); file_stream << *dynamic; file_stream.close(); } void * hhn_dynamic_read(const char * p_filename) { hhn_dynamic * output_dynamic = new hhn_dynamic(); hhn_dynamic_reader(p_filename).read(*output_dynamic); return output_dynamic; } pyclustering-0.10.1.2/ccore/src/interface/hsyncnet_interface.cpp000077500000000000000000000027241375753423500247100ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::clst; using namespace pyclustering::nnet; void * hsyncnet_create_network(const pyclustering_package * const p_sample, const unsigned int p_number_clusters, const unsigned int p_initial_phases, const unsigned int p_initial_neighbors, const double p_increase_persent) { pyclustering::dataset input_data; p_sample->extract(input_data); return new hsyncnet(&input_data, p_number_clusters, (initial_type) p_initial_phases, p_initial_neighbors, p_increase_persent); } void hsyncnet_destroy_network(const void * p_pointer_network) { delete (hsyncnet *) p_pointer_network; } void * hsyncnet_process(const void * p_pointer_network, const double p_order, const unsigned int p_solver, const bool p_collect_dynamic) { hsyncnet * network = (hsyncnet *) p_pointer_network; hsyncnet_analyser * analyser = new hsyncnet_analyser(); network->process(p_order, (solve_type) p_solver, p_collect_dynamic, *analyser); return (void *) analyser; } void hsyncnet_analyser_destroy(const void * p_pointer_analyser) { delete (hsyncnet_analyser *) p_pointer_analyser; }pyclustering-0.10.1.2/ccore/src/interface/interface_property.cpp000077500000000000000000000007621375753423500247410ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include const char * INTERFACE_DESCRIPTION = "pyclustering library is a C/C++ part of python pyclustering library"; const char * INTERFACE_VERSION = "0.10.1.2"; void * get_interface_description() { return (void *) INTERFACE_DESCRIPTION; } void * get_interface_version() { return (void *) INTERFACE_VERSION; }pyclustering-0.10.1.2/ccore/src/interface/kmeans_interface.cpp000077500000000000000000000041201375753423500243230ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::metric; pyclustering_package * kmeans_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_initial_centers, const double p_tolerance, const std::size_t p_itermax, const bool p_observe, const void * const p_metric) { pyclustering::dataset data, centers; p_sample->extract(data); p_initial_centers->extract(centers); distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::kmeans algorithm(centers, p_tolerance, p_itermax, *metric); pyclustering::clst::kmeans_data output_result(p_observe); algorithm.process(data, output_result); pyclustering_package * package = create_package_container(KMEANS_PACKAGE_SIZE); ((pyclustering_package **) package->data)[KMEANS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[KMEANS_PACKAGE_INDEX_CENTERS] = create_package(&output_result.centers()); ((pyclustering_package **) package->data)[KMEANS_PACKAGE_INDEX_EVOLUTION_CLUSTERS] = create_package(&output_result.evolution_clusters()); ((pyclustering_package **) package->data)[KMEANS_PACKAGE_INDEX_EVOLUTION_CENTERS] = create_package(&output_result.evolution_centers()); std::vector wce_storage(1, output_result.wce()); ((pyclustering_package **) package->data)[KMEANS_PACKAGE_INDEX_WCE] = create_package(&wce_storage); return package; } pyclustering-0.10.1.2/ccore/src/interface/kmedians_interface.cpp000077500000000000000000000030061375753423500246420ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * kmedians_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_initial_medians, const double p_tolerance, const std::size_t p_itermax, const void * const p_metric) { pyclustering::dataset data, medians; p_sample->extract(data); p_initial_medians->extract(medians); distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::kmedians algorithm(medians, p_tolerance, p_itermax, *metric); pyclustering::clst::kmedians_data output_result; algorithm.process(data, output_result); pyclustering_package * package = create_package_container(KMEDIANS_PACKAGE_SIZE); ((pyclustering_package **) package->data)[KMEDIANS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[KMEDIANS_PACKAGE_INDEX_MEDIANS] = create_package(&output_result.medians()); return package; } pyclustering-0.10.1.2/ccore/src/interface/kmedoids_interface.cpp000077500000000000000000000034651375753423500246570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::metric; pyclustering_package * kmedoids_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_medoids, const double p_tolerance, const std::size_t p_itermax, const void * const p_metric, const std::size_t p_type) { pyclustering::clst::medoid_sequence medoids; p_medoids->extract(medoids); distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::kmedoids algorithm(medoids, p_tolerance, p_itermax, *metric); pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::kmedoids_data output_result; algorithm.process(input_dataset, (pyclustering::clst::kmedoids_data_t) p_type, output_result); pyclustering_package * package = create_package_container(KMEDOIDS_PACKAGE_SIZE); ((pyclustering_package **) package->data)[KMEDOIDS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[KMEDOIDS_PACKAGE_INDEX_MEDOIDS] = create_package(&output_result.medoids()); return package; } pyclustering-0.10.1.2/ccore/src/interface/legion_interface.cpp000077500000000000000000000063501375753423500243310ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::nnet; void * legion_create(const unsigned int p_size, const unsigned int p_connection_type, const void * const p_parameters) { legion_network * network = new legion_network(p_size, (connection_t) p_connection_type, *((legion_parameters *) p_parameters)); return (void *) network; } void legion_destroy(const void * p_network_pointer) { delete (legion_network *) p_network_pointer; } void * legion_simulate( const void * p_network_pointer, const unsigned int p_steps, const double p_time, const unsigned int p_solver, const bool p_collect_dynamic, const pyclustering_package * const p_stimulus) { legion_stimulus stimulus_vector((double *)p_stimulus->data, ((double *)p_stimulus->data) + p_stimulus->size); legion_dynamic * dynamic = new legion_dynamic(); ((legion_network *) p_network_pointer)->simulate(p_steps, p_time, (solve_type) p_solver, p_collect_dynamic, stimulus_vector, (*dynamic)); return dynamic; } std::size_t legion_get_size(const void * p_network_pointer) { return ((legion_network *) p_network_pointer)->size(); } void legion_dynamic_destroy(const void * p_dynamic_pointer) { delete (legion_dynamic *) p_dynamic_pointer; } pyclustering_package * legion_dynamic_get_output(const void * p_dynamic_pointer) { legion_dynamic & dynamic = *((legion_dynamic *) p_dynamic_pointer); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = dynamic.size(); package->data = new pyclustering_package * [package->size]; for (std::size_t i = 0; i < package->size; i++) { ((pyclustering_package **) package->data)[i] = create_package(&dynamic[i].m_output); } return package; } pyclustering_package * legion_dynamic_get_inhibitory_output(const void * p_dynamic_pointer) { legion_dynamic & dynamic = *((legion_dynamic *) p_dynamic_pointer); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE); package->size = dynamic.size(); package->data = new double[package->size]; for (std::size_t i = 0; i < package->size; i++) { ((double *) package->data)[i] = dynamic[i].m_inhibitor; } return package; } pyclustering_package * legion_dynamic_get_time(const void * p_dynamic_pointer) { legion_dynamic & dynamic = *((legion_dynamic *) p_dynamic_pointer); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE); package->size = dynamic.size(); package->data = new double[package->size]; for (std::size_t i = 0; i < package->size; i++) { ((double *) package->data)[i] = dynamic[i].m_time; } return package; } std::size_t legion_dynamic_get_size(const void * p_dynamic_pointer) { return ((legion_dynamic *) p_dynamic_pointer)->size(); } pyclustering-0.10.1.2/ccore/src/interface/mbsas_interface.cpp000077500000000000000000000032571375753423500241640ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::utils::metric; pyclustering_package * mbsas_algorithm(const pyclustering_package * const p_sample, const std::size_t p_amount, const double p_threshold, const void * const p_metric) { distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::mbsas algorithm(p_amount, p_threshold, *metric); pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::mbsas_data output_result; algorithm.process(input_dataset, output_result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = BSAS_PACKAGE_SIZE; package->data = new pyclustering_package * [BSAS_PACKAGE_SIZE]; ((pyclustering_package **) package->data)[BSAS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[BSAS_PACKAGE_INDEX_REPRESENTATIVES] = create_package(&output_result.representatives()); return package; }pyclustering-0.10.1.2/ccore/src/interface/metric_interface.cpp000077500000000000000000000065101375753423500243350ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering; using namespace pyclustering::utils::metric; void * metric_create(const std::size_t p_type, const pyclustering_package * const p_arguments, double (*p_solver)(const void *, const void *)) { switch(p_type) { case EUCLIDEAN: { distance_metric metric = distance_metric_factory::euclidean(); return new distance_metric(std::move(metric)); } case EUCLIDEAN_SQUARE: { distance_metric metric = distance_metric_factory::euclidean_square(); return new distance_metric(std::move(metric)); } case MANHATTAN: { distance_metric metric = distance_metric_factory::manhattan(); return new distance_metric(std::move(metric)); } case CHEBYSHEV: { distance_metric metric = distance_metric_factory::chebyshev(); return new distance_metric(std::move(metric)); } case MINKOWSKI: { std::vector arguments; p_arguments->extract(arguments); distance_metric metric = distance_metric_factory::minkowski(arguments[0]); return new distance_metric(std::move(metric)); } case CANBERRA: { distance_metric metric = distance_metric_factory::canberra(); return new distance_metric(std::move(metric)); } case CHI_SQUARE: { distance_metric metric = distance_metric_factory::chi_square(); return new distance_metric(std::move(metric)); } case GOWER: { point max_range; p_arguments->extract(max_range); distance_metric metric = distance_metric_factory::gower(max_range); return new distance_metric(std::move(metric)); } case USER_DEFINED: { auto functor_wrapper = [p_solver](const point & p1, const point & p2) { pyclustering_package * point1 = create_package(&p1); pyclustering_package * point2 = create_package(&p2); const double distance = p_solver(point1, point2); delete point1; delete point2; return distance; }; distance_metric metric = distance_metric_factory::user_defined(functor_wrapper); return new distance_metric(std::move(metric)); } default: return nullptr; } } void metric_destroy(const void * p_pointer_metric) { delete (distance_metric *) p_pointer_metric; } double metric_calculate(const void * p_pointer_metric, const pyclustering_package * const p_point1, const pyclustering_package * const p_point2) { point point1, point2; p_point1->extract(point1); p_point2->extract(point2); distance_metric & metric = *((distance_metric *) p_pointer_metric); return metric(point1, point2); } pyclustering-0.10.1.2/ccore/src/interface/optics_interface.cpp000077500000000000000000000054001375753423500243500ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * optics_algorithm(const pyclustering_package * const p_sample, const double p_radius, const size_t p_minumum_neighbors, const size_t p_amount_clusters, const size_t p_data_type) { pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::optics solver(p_radius, p_minumum_neighbors, p_amount_clusters); pyclustering::clst::optics_data output_result; solver.process(input_dataset, (pyclustering::clst::optics_data_t) p_data_type, output_result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = OPTICS_PACKAGE_SIZE; package->data = new pyclustering_package * [OPTICS_PACKAGE_SIZE]; ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_NOISE] = create_package(&output_result.noise()); ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_ORDERING] = create_package(&output_result.cluster_ordering()); std::vector radius_storage(1, output_result.get_radius()); ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_RADIUS] = create_package(&radius_storage); /* Pack OPTICS objects to pyclustering packages */ const auto & objects = output_result.optics_objects(); std::size_t package_size = objects.size(); pyclustering_package * package_object_indexes = create_package(package_size); pyclustering_package * package_core_distance = create_package(package_size); pyclustering_package * package_reachability_distance = create_package(package_size); for (std::size_t i = 0; i < objects.size(); i++) { ((std::size_t *) package_object_indexes->data)[i] = objects[i].m_index; ((double *) package_core_distance->data)[i] = objects[i].m_core_distance; ((double *) package_reachability_distance->data)[i] = objects[i].m_reachability_distance; } ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_INDEX] = package_object_indexes; ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_CORE_DISTANCE] = package_core_distance; ((pyclustering_package **) package->data)[OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_REACHABILITY_DISTANCE] = package_reachability_distance; return package; }pyclustering-0.10.1.2/ccore/src/interface/pcnn_interface.cpp000077500000000000000000000064711375753423500240160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include using namespace pyclustering::nnet; void * pcnn_create(const unsigned int p_size, const unsigned int p_connection_type, const unsigned int p_height, const unsigned int p_width, const void * const p_parameters) { pcnn * pcnn_network = new pcnn(p_size, (connection_t) p_connection_type, p_height, p_width, *((pcnn_parameters *) p_parameters)); return (void *) pcnn_network; } void pcnn_destroy(const void * p_pointer) { delete (pcnn *) p_pointer; } void * pcnn_simulate(const void * p_pointer, const unsigned int p_steps, const void * const p_stimulus) { const pyclustering_package * const package_stimulus = static_cast(p_stimulus); pcnn_stimulus stimulus_vector((double *) package_stimulus->data, ((double *) package_stimulus->data) + package_stimulus->size); pcnn_dynamic * dynamic = new pcnn_dynamic(); ((pcnn *)p_pointer)->simulate(p_steps, stimulus_vector, (*dynamic)); return dynamic; } std::size_t pcnn_get_size(const void * p_pointer) { return ((pcnn *) p_pointer)->size(); } void pcnn_dynamic_destroy(const void * pointer) { delete (pcnn_dynamic *) pointer; } pyclustering_package * pcnn_dynamic_allocate_sync_ensembles(const void * pointer) { ensemble_data sync_ensembles; ((pcnn_dynamic *) pointer)->allocate_sync_ensembles(sync_ensembles); pyclustering_package * package = create_package(&sync_ensembles); return package; } pyclustering_package * pcnn_dynamic_allocate_spike_ensembles(const void * pointer) { ensemble_data spike_ensembles; ((pcnn_dynamic *) pointer)->allocate_spike_ensembles(spike_ensembles); pyclustering_package * package = create_package(&spike_ensembles); return package; } pyclustering_package * pcnn_dynamic_allocate_time_signal(const void * pointer) { pcnn_time_signal time_signal; ((pcnn_dynamic *) pointer)->allocate_time_signal(time_signal); pyclustering_package * package = create_package(&time_signal); return package; } pyclustering_package * pcnn_dynamic_get_output(const void * pointer) { pcnn_dynamic & dynamic = *((pcnn_dynamic *) pointer); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = dynamic.size(); package->data = new pyclustering_package * [package->size]; for (std::size_t i = 0; i < package->size; i++) { ((pyclustering_package **) package->data)[i] = create_package(&dynamic[i].m_output); } return package; } pyclustering_package * pcnn_dynamic_get_time(const void * pointer) { pcnn_dynamic & dynamic = *((pcnn_dynamic *) pointer); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE); package->size = dynamic.size(); package->data = new double[package->size]; for (std::size_t i = 0; i < package->size; i++) { ((double *) package->data)[i] = dynamic[i].m_time; } return package; } size_t pcnn_dynamic_get_size(const void * pointer) { return ((pcnn_dynamic *) pointer)->size(); } pyclustering-0.10.1.2/ccore/src/interface/pyclustering_interface.cpp000077500000000000000000000003701375753423500256000ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include void free_pyclustering_package(pyclustering_package * package) { delete package; } pyclustering-0.10.1.2/ccore/src/interface/pyclustering_package.cpp000077500000000000000000000044101375753423500252320ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package::pyclustering_package(const pyclustering_data_t package_type) : size(0), type((unsigned int) package_type), data(nullptr) { } pyclustering_package::~pyclustering_package() { if (type != (unsigned int) pyclustering_data_t::PYCLUSTERING_TYPE_LIST) { switch(type) { case pyclustering_data_t::PYCLUSTERING_TYPE_INT: delete [] (int *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_UNSIGNED_INT: delete [] (unsigned int *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_FLOAT: delete [] (float *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE: delete [] (double *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_LONG: delete [] (long *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_SIZE_T: delete [] (size_t *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_CHAR: delete[] (char *) data; break; case pyclustering_data_t::PYCLUSTERING_TYPE_WCHAR_T: delete[] (wchar_t *) data; break; default: /* Memory Leak */ break; } } else { for (std::size_t i = 0; i < size; i++) { pyclustering_package * package = ((pyclustering_package **) data)[i]; delete package; package = nullptr; } delete [] (pyclustering_package **) data; data = nullptr; } } pyclustering_package * create_package_container(const std::size_t p_size) { pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = p_size; package->data = new pyclustering_package * [p_size]; return package; } pyclustering-0.10.1.2/ccore/src/interface/rock_interface.cpp000077500000000000000000000013221375753423500240040ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include pyclustering_package * rock_algorithm(const pyclustering_package * const p_sample, const double p_radius, const size_t p_number_clusters, const double p_threshold) { pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::rock solver(p_radius, p_number_clusters, p_threshold); pyclustering::clst::rock_data output_result; solver.process(input_dataset, output_result); pyclustering_package * package = create_package(&output_result.clusters()); return package; } pyclustering-0.10.1.2/ccore/src/interface/silhouette_interface.cpp000077500000000000000000000060671375753423500252460ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include pyclustering::clst::silhouette_ksearch_allocator::ptr get_silhouette_ksearch_allocator( const silhouette_ksearch_type p_algorithm) { switch(p_algorithm) { case silhouette_ksearch_type::KMEANS: return std::make_shared(); case silhouette_ksearch_type::KMEDIANS: return std::make_shared(); case silhouette_ksearch_type::KMEDOIDS: return std::make_shared(); default: throw std::invalid_argument("Unknown allocator '" + std::to_string(static_cast(p_algorithm)) + "' is specified."); } } pyclustering_package * silhouette_algorithm( const pyclustering_package * const p_sample, const pyclustering_package * const p_clusters, const void * const p_metric, const std::size_t p_data_type) { pyclustering::dataset data; p_sample->extract(data); pyclustering::clst::cluster_sequence clusters; p_clusters->extract(clusters); distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::silhouette_data result; pyclustering::clst::silhouette(*metric).process(data, clusters, static_cast(p_data_type), result); return create_package(&result.get_score()); } pyclustering_package * silhouette_ksearch_algorithm( const pyclustering_package * const p_sample, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_algorithm, const long long p_random_state) { pyclustering::dataset data; p_sample->extract(data); auto allocator = get_silhouette_ksearch_allocator(static_cast(p_algorithm)); pyclustering::clst::silhouette_ksearch_data result; pyclustering::clst::silhouette_ksearch(p_kmin, p_kmax, allocator, p_random_state).process(data, result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = SILHOUETTE_KSEARCH_PACKAGE_SIZE; package->data = new pyclustering_package * [SILHOUETTE_KSEARCH_PACKAGE_SIZE]; std::vector amount_cluters = { result.get_amount() }; std::vector score = { result.get_score() }; ((pyclustering_package **) package->data)[SILHOUETTE_KSEARCH_PACKAGE_AMOUNT] = create_package(&amount_cluters); ((pyclustering_package **) package->data)[SILHOUETTE_KSEARCH_PACKAGE_SCORE] = create_package(&score); ((pyclustering_package **) package->data)[SILHOUETTE_KSEARCH_PACKAGE_SCORES] = create_package(&result.scores()); return package; }pyclustering-0.10.1.2/ccore/src/interface/som_interface.cpp000077500000000000000000000054711375753423500236550ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include using namespace pyclustering::nnet; void * som_create(const size_t num_rows, const size_t num_cols, const size_t type_conn, const void * parameters) { return new som(num_rows, num_cols, (som_conn_type) type_conn, *((som_parameters *) parameters)); } void som_destroy(const void * pointer) { delete (som *) pointer; } void som_load(const void * p_pointer, const pyclustering_package * p_weights, const pyclustering_package * p_awards, const pyclustering_package * p_captured_objects) { pyclustering::dataset weights; p_weights->extract(weights); som_award_sequence awards = { }; if (p_awards) { p_awards->extract(awards); } som_gain_sequence captured_objects = { }; if (p_captured_objects) { p_captured_objects->extract(captured_objects); } ((som *) p_pointer)->load(weights, awards, captured_objects); } size_t som_train(const void * pointer, const pyclustering_package * const sample, const size_t epochs, const bool autostop) { pyclustering::dataset input_dataset; sample->extract(input_dataset); size_t result = ((som *) pointer)->train(input_dataset, epochs, autostop); return result; } size_t som_simulate(const void * pointer, const pyclustering_package * const p_pattern) { pyclustering::pattern input_pattern; p_pattern->extract(input_pattern); return ((som *) pointer)->simulate(input_pattern); } size_t som_get_winner_number(const void * pointer) { return ((som *) pointer)->get_winner_number(); } size_t som_get_size(const void * pointer) { return ((som *) pointer)->get_size(); } pyclustering_package * som_get_weights(const void * pointer) { const pyclustering::dataset & weights = ((som *) pointer)->get_weights(); pyclustering_package * package = create_package(&weights); return package; } pyclustering_package * som_get_capture_objects(const void * pointer) { const som_gain_sequence & capture_objects = ((som *) pointer)->get_capture_objects(); pyclustering_package * package = create_package(&capture_objects); return package; } pyclustering_package * som_get_awards(const void * pointer) { const som_award_sequence & awards = ((som *) pointer)->get_awards(); pyclustering_package * package = create_package(&awards); return package; } pyclustering_package * som_get_neighbors(const void * pointer) { pyclustering_package * package = nullptr; const som_neighbor_sequence & neighbors = ((som *) pointer)->get_neighbors(); if (!neighbors.empty()) { package = create_package(&neighbors); } return package; } pyclustering-0.10.1.2/ccore/src/interface/sync_interface.cpp000077500000000000000000000135511375753423500240310ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::nnet; void * sync_create_network(const unsigned int size, const double weight_factor, const double frequency_factor, const unsigned int connection_type, const unsigned int initial_phases) { return new sync_network(size, weight_factor, frequency_factor, (connection_t) connection_type, (initial_type) initial_phases); } std::size_t sync_get_size(const void * pointer_network) { return ((sync_network *) pointer_network)->size(); } void sync_destroy_network(const void * pointer_network) { if (pointer_network != nullptr) { delete (sync_network *) pointer_network; } } void * sync_simulate_static(const void * pointer_network, unsigned int steps, const double time, const unsigned int solver, const bool collect_dynamic) { sync_network * network = (sync_network *) pointer_network; sync_dynamic * dynamic = new sync_dynamic(); network->simulate_static(steps, time, (solve_type) solver, collect_dynamic, (*dynamic)); return (void *) dynamic; } void * sync_simulate_dynamic(const void * pointer_network, const double order, const unsigned int solver, const bool collect_dynamic, const double step, const double step_int, const double threshold_changes) { sync_network * network = (sync_network *) pointer_network; sync_dynamic * dynamic = new sync_dynamic(); network->simulate_dynamic(order, step, (solve_type) solver, collect_dynamic, (*dynamic)); return (void *) dynamic; } double sync_order(const void * pointer_network) { return ((sync_network *) pointer_network)->sync_order(); } double sync_local_order(const void * pointer_network) { return ((sync_network *) pointer_network)->sync_local_order(); } pyclustering_package * sync_connectivity_matrix(const void * pointer_network) { std::shared_ptr connections = ((sync_network *) pointer_network)->connections(); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = ((sync_network *) pointer_network)->size(); package->data = new pyclustering_package * [package->size]; for (std::size_t i = 0; i < package->size; i++) { pyclustering_package * subpackage = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE); subpackage->size = ((sync_network *) pointer_network)->size(); subpackage->data = (void *) new double[subpackage->size]; for (std::size_t j = 0; j < subpackage->size; j++) { ((double *) subpackage->data)[j] = connections->has_connection(i, j) ? 1.0 : 0.0; } ((pyclustering_package **) package->data)[i] = subpackage; } return package; } std::size_t sync_dynamic_get_size(const void * pointer_dynamic) { return ((sync_dynamic *) pointer_dynamic)->size(); } void sync_dynamic_destroy(const void * pointer_dynamic) { delete (sync_dynamic *) pointer_dynamic; } pyclustering_package * sync_dynamic_allocate_sync_ensembles(const void * pointer_dynamic, const double tolerance, const std::size_t iteration) { ensemble_data ensembles; ((sync_dynamic *)pointer_dynamic)->allocate_sync_ensembles(tolerance, iteration, ensembles); pyclustering_package * package = create_package(&ensembles); return package; } pyclustering_package * sync_dynamic_allocate_correlation_matrix(const void * pointer_dynamic, const std::size_t iteration) { sync_corr_matrix matrix; ((sync_dynamic *) pointer_dynamic)->allocate_correlation_matrix(iteration, matrix); pyclustering_package * package = create_package(&matrix); return package; } pyclustering_package * sync_dynamic_get_time(const void * pointer_dynamic) { sync_dynamic & dynamic = *((sync_dynamic *)pointer_dynamic); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_DOUBLE); package->size = dynamic.size(); package->data = new double[package->size]; for (std::size_t i = 0; i < package->size; i++) { ((double *) package->data)[i] = dynamic[i].m_time; } return package; } pyclustering_package * sync_dynamic_get_output(const void * pointer_dynamic) { sync_dynamic & dynamic = *((sync_dynamic *)pointer_dynamic); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = dynamic.size(); package->data = new pyclustering_package * [package->size]; for (std::size_t i = 0; i < package->size; i++) { ((pyclustering_package **) package->data)[i] = create_package(&dynamic[i].m_phase); } return package; } pyclustering_package * sync_dynamic_calculate_order(const void * p_pointer, const std::size_t p_start, const std::size_t p_stop) { sync_dynamic & dynamic = *((sync_dynamic *) p_pointer); std::vector order_evolution; dynamic.calculate_order_parameter(p_start, p_stop, order_evolution); pyclustering_package * package = create_package(&order_evolution); return package; } pyclustering_package * sync_dynamic_calculate_local_order(const void * p_dynamic_pointer, const void * p_network_pointer, const std::size_t p_start, const std::size_t p_stop) { sync_dynamic & dynamic = *((sync_dynamic *) p_dynamic_pointer); sync_network & network = *((sync_network *) p_network_pointer); std::vector local_order_evolution; dynamic.calculate_local_order_parameter(network.connections(), p_start, p_stop, local_order_evolution); pyclustering_package * package = create_package(&local_order_evolution); return package; }pyclustering-0.10.1.2/ccore/src/interface/syncnet_interface.cpp000077500000000000000000000025521375753423500245370ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::clst; using namespace pyclustering::nnet; void * syncnet_create_network(const pyclustering_package * const p_sample, const double p_connectivity_radius, const bool p_enable_conn_weight, const unsigned int p_initial_phases) { pyclustering::dataset input_data; p_sample->extract(input_data); return new syncnet(&input_data, p_connectivity_radius, p_enable_conn_weight, (initial_type) p_initial_phases); } void syncnet_destroy_network(const void * p_pointer_network) { delete (syncnet *) p_pointer_network; } void * syncnet_process(const void * p_pointer_network, const double p_order, const unsigned int p_solver, const bool p_collect_dynamic) { syncnet * network = (syncnet *) p_pointer_network; syncnet_analyser * analyser = new syncnet_analyser(); network->process(p_order, (solve_type) p_solver, p_collect_dynamic, (*analyser)); ensemble_data ensembles; analyser->allocate_sync_ensembles(0.1, ensembles); return analyser; } void syncnet_analyser_destroy(const void * p_pointer_analyser) { delete (syncnet_analyser *) p_pointer_analyser; }pyclustering-0.10.1.2/ccore/src/interface/syncpr_interface.cpp000077500000000000000000000076531375753423500244010ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::nnet; void * syncpr_create(const unsigned int num_osc, const double increase_strength1, const double increase_strength2) { return new syncpr(num_osc, increase_strength1, increase_strength2); } void syncpr_destroy(const void * pointer_network) { delete (syncpr *) pointer_network; } std::size_t syncpr_get_size(const void * pointer_network) { return ((syncpr *)pointer_network)->size(); } void syncpr_train(const void * pointer_network, const void * const patterns) { syncpr * network = (syncpr *)pointer_network; const pyclustering_package * const package_patterns = static_cast(patterns); std::vector external_patterns; package_patterns->extract(external_patterns); network->train(external_patterns); } void * syncpr_simulate_static(const void * pointer_network, unsigned int steps, const double time, const void * const pattern, const unsigned int solver, const bool collect_dynamic) { syncpr * network = (syncpr *)pointer_network; const pyclustering_package * const package_pattern = static_cast(pattern); syncpr_pattern external_pattern(static_cast(package_pattern->data), static_cast(package_pattern->data) + package_pattern->size); syncpr_dynamic * dynamic = new syncpr_dynamic(); network->simulate_static(steps, time, external_pattern, (solve_type)solver, collect_dynamic, (*dynamic)); return (void *)dynamic; } void * syncpr_simulate_dynamic(const void * pointer_network, const void * const pattern, const double order, const unsigned int solver, const bool collect_dynamic, const double step) { syncpr * network = (syncpr *)pointer_network; const pyclustering_package * const package_pattern = static_cast(pattern); syncpr_pattern external_pattern((int *)package_pattern->data, ((int *)package_pattern->data) + package_pattern->size); syncpr_dynamic * dynamic = new syncpr_dynamic(); network->simulate_dynamic(external_pattern, order, step, (solve_type)solver, collect_dynamic, (*dynamic)); return (void *)dynamic; } double syncpr_memory_order(const void * pointer_network, const void * const pattern) { const pyclustering_package * const package_pattern = static_cast(pattern); syncpr_pattern external_pattern((int *)package_pattern->data, ((int *)package_pattern->data) + package_pattern->size); return ((syncpr *)pointer_network)->memory_order(external_pattern); } std::size_t syncpr_dynamic_get_size(const void * pointer_network) { return ((syncpr_dynamic *)pointer_network)->size(); } void syncpr_dynamic_destroy(const void * pointer_dynamic) { delete (syncpr_dynamic *)pointer_dynamic; } pyclustering_package * syncpr_dynamic_allocate_sync_ensembles(const void * pointer_dynamic, const double tolerance) { return sync_dynamic_allocate_sync_ensembles(pointer_dynamic, tolerance, syncpr_dynamic_get_size(pointer_dynamic) - 1); } pyclustering_package * syncpr_dynamic_get_time(const void * pointer_dynamic) { return sync_dynamic_get_time(pointer_dynamic); } pyclustering_package * syncpr_dynamic_get_output(const void * pointer_dynamic) { return sync_dynamic_get_output(pointer_dynamic); }pyclustering-0.10.1.2/ccore/src/interface/ttsas_interface.cpp000077500000000000000000000032641375753423500242130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::utils::metric; pyclustering_package * ttsas_algorithm(const pyclustering_package * const p_sample, const double p_threshold1, const double p_threshold2, const void * const p_metric) { distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::ttsas algorithm(p_threshold1, p_threshold2, *metric); pyclustering::dataset input_dataset; p_sample->extract(input_dataset); pyclustering::clst::ttsas_data output_result; algorithm.process(input_dataset, output_result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = BSAS_PACKAGE_SIZE; package->data = new pyclustering_package * [BSAS_PACKAGE_SIZE]; ((pyclustering_package **) package->data)[BSAS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[BSAS_PACKAGE_INDEX_REPRESENTATIVES] = create_package(&output_result.representatives()); return package; }pyclustering-0.10.1.2/ccore/src/interface/xmeans_interface.cpp000077500000000000000000000046421375753423500243510ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::metric; pyclustering_package * xmeans_algorithm(const pyclustering_package * const p_sample, const pyclustering_package * const p_centers, const std::size_t p_kmax, const double p_tolerance, const unsigned int p_criterion, const double p_alpha, const double p_beta, const std::size_t p_repeat, const long long p_random_state, const void * const p_metric) { pyclustering::dataset data, centers; p_sample->extract(data); p_centers->extract(centers); distance_metric * metric = ((distance_metric *) p_metric); distance_metric default_metric = distance_metric_factory::euclidean_square(); if (!metric) { metric = &default_metric; } pyclustering::clst::xmeans solver(centers, p_kmax, p_tolerance, (pyclustering::clst::splitting_type) p_criterion, p_repeat, p_random_state, *metric); solver.set_mndl_alpha_bound(p_alpha); solver.set_mndl_beta_bound(p_beta); pyclustering::clst::xmeans_data output_result; solver.process(data, output_result); pyclustering_package * package = new pyclustering_package(pyclustering_data_t::PYCLUSTERING_TYPE_LIST); package->size = xmeans_package_indexer::XMEANS_PACKAGE_SIZE; package->data = new pyclustering_package * [package->size]; ((pyclustering_package **) package->data)[xmeans_package_indexer::XMEANS_PACKAGE_INDEX_CLUSTERS] = create_package(&output_result.clusters()); ((pyclustering_package **) package->data)[xmeans_package_indexer::XMEANS_PACKAGE_INDEX_CENTERS] = create_package(&output_result.centers()); ((pyclustering_package **) package->data)[xmeans_package_indexer::XMEANS_PACKAGE_INDEX_WCE] = create_package(1, output_result.wce()); return package; } pyclustering-0.10.1.2/ccore/src/nnet/000077500000000000000000000000001375753423500173255ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/nnet/dynamic_analyser.cpp000077500000000000000000000045561375753423500233700ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::utils::math; namespace pyclustering { namespace nnet { spike::spike(const std::size_t p_begin, const std::size_t p_end) { if (p_end < p_begin) { std::stringstream stream; stream << __FUNCTION__ << ": End time '" << p_end << "' of the spike cannot be less or equal to begin time '" << p_begin << "'."; throw std::invalid_argument(stream.str()); } m_begin = p_begin; m_duration = p_end - p_begin; m_end = p_end; } std::size_t spike::get_start() const { return m_begin; } std::size_t spike::get_duration() const { return m_duration; } std::size_t spike::get_stop() const { return m_end; } bool spike::compare(const spike & p_other, const double p_tolerance) const { const double delta = m_duration * p_tolerance; if (absolute_difference(p_other.get_duration(), get_duration()) > delta) { return false; } const double difference = (double) absolute_difference(p_other.get_start(), get_start()) + absolute_difference(p_other.get_stop(), get_stop()); if (difference > delta) { return false; } return true; } const std::size_t dynamic_analyser::INVALID_ITERATION = std::numeric_limits::max(); const std::size_t dynamic_analyser::DEFAULT_AMOUNT_SPIKES = 1; const double dynamic_analyser::DEFAULT_TOLERANCE = 0.1; dynamic_analyser::dynamic_analyser(const double p_threshold, const double p_tolerance, const std::size_t p_spikes) : m_threshold(p_threshold), m_spikes(p_spikes), m_tolerance(p_tolerance) { } bool dynamic_analyser::is_sync_spikes(const spike_collection & p_spikes1, const spike_collection & p_spikes2) const { if (p_spikes1.size() != p_spikes2.size()) { return false; } for (std::size_t index_spike = 0; index_spike < p_spikes1.size(); index_spike++) { auto & spike1 = p_spikes1[index_spike]; auto & spike2 = p_spikes2[index_spike]; if (!spike1.compare(spike2, m_tolerance)) { return false; } } return true; } } }pyclustering-0.10.1.2/ccore/src/nnet/hhn.cpp000077500000000000000000000652311375753423500206200ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include using namespace std::placeholders; namespace pyclustering { namespace nnet { hhn_dynamic::hhn_dynamic() { initialize_collection(*m_peripheral_dynamic); initialize_collection(*m_central_dynamic); } std::size_t hhn_dynamic::size_dynamic() const { return m_size_dynamic; } std::size_t hhn_dynamic::size_network() const { return m_size_network; } void hhn_dynamic::enable(const hhn_dynamic::collect p_state) { if (m_enable[p_state] != true) { m_enable[p_state] = true; m_amount_collections++; } } void hhn_dynamic::enable_all() { for (auto & collection : m_enable) { collection.second = true; } m_amount_collections = m_enable.size(); } void hhn_dynamic::disable(const hhn_dynamic::collect p_state) { if (m_enable[p_state] != false) { m_enable[p_state] = false; m_amount_collections--; } } void hhn_dynamic::disable_all() { for (auto & collection : m_enable) { collection.second = false; } m_amount_collections = 0; } void hhn_dynamic::get_enabled(std::set & p_enabled) const { get_collected_types(true, p_enabled); } void hhn_dynamic::get_disabled(std::set & p_disabled) const { get_collected_types(false, p_disabled); } void hhn_dynamic::store(const double p_time, const std::vector & p_peripheral, const std::vector & p_central) { if (!m_amount_collections) { return; } if (m_enable[collect::MEMBRANE_POTENTIAL]) { store_membrane_potential(p_peripheral, p_central); } if (m_enable[collect::ACTIVE_COND_POTASSIUM]) { store_active_cond_potassium(p_peripheral, p_central); } if (m_enable[collect::ACTIVE_COND_SODIUM]) { store_active_cond_sodium(p_peripheral, p_central); } if (m_enable[collect::INACTIVE_COND_SODIUM]) { store_inactive_cond_sodium(p_peripheral, p_central); } m_time->push_back(p_time); if (m_size_network != 0) { if (m_size_network != p_peripheral.size()) { throw std::invalid_argument("Amount of neurons on each iteration should be the same."); } } else { m_size_network = p_peripheral.size(); } m_size_dynamic++; } void hhn_dynamic::reserve(const std::size_t p_dynamic_size) { if (m_enable[collect::MEMBRANE_POTENTIAL]) { reserve_collection(collect::MEMBRANE_POTENTIAL, p_dynamic_size); } if (m_enable[collect::ACTIVE_COND_POTASSIUM]) { reserve_collection(collect::ACTIVE_COND_POTASSIUM, p_dynamic_size); } if (m_enable[collect::ACTIVE_COND_SODIUM]) { reserve_collection(collect::ACTIVE_COND_SODIUM, p_dynamic_size); } if (m_enable[collect::INACTIVE_COND_SODIUM]) { reserve_collection(collect::INACTIVE_COND_SODIUM, p_dynamic_size); } } hhn_dynamic::evolution_dynamic & hhn_dynamic::get_peripheral_dynamic(const hhn_dynamic::collect & p_type) { return (*m_peripheral_dynamic)[p_type]; } hhn_dynamic::network_dynamic_ptr hhn_dynamic::get_peripheral_dynamic() const { return m_peripheral_dynamic; } hhn_dynamic::evolution_dynamic & hhn_dynamic::get_central_dynamic(const hhn_dynamic::collect & p_type) { return (*m_central_dynamic)[p_type]; } hhn_dynamic::network_dynamic_ptr hhn_dynamic::get_central_dynamic() const { return m_central_dynamic; } hhn_dynamic::value_dynamic_ptr hhn_dynamic::get_time() const { return m_time; } double hhn_dynamic::get_peripheral_value(const std::size_t p_iteration, const std::size_t p_index, const hhn_dynamic::collect p_type) const { return (*m_peripheral_dynamic)[p_type][p_iteration][p_index]; } double hhn_dynamic::get_central_value(const std::size_t p_iteration, const std::size_t p_index, const hhn_dynamic::collect p_type) const { return (*m_central_dynamic)[p_type][p_iteration][p_index]; } void hhn_dynamic::initialize_collection(network_dynamic & p_dynamic) { p_dynamic[hhn_dynamic::collect::MEMBRANE_POTENTIAL] = evolution_dynamic(); p_dynamic[hhn_dynamic::collect::ACTIVE_COND_SODIUM] = evolution_dynamic(); p_dynamic[hhn_dynamic::collect::INACTIVE_COND_SODIUM] = evolution_dynamic(); p_dynamic[hhn_dynamic::collect::ACTIVE_COND_POTASSIUM] = evolution_dynamic(); } void hhn_dynamic::get_collected_types(const bool p_enabled, std::set & p_types) const { for (const auto & p_collect_element : m_enable) { if (p_collect_element.second == p_enabled) { p_types.insert(p_collect_element.first); } } } void hhn_dynamic::reserve_collection(const hhn_dynamic::collect p_state, const std::size_t p_size) { reserve_dynamic_collection(p_state, p_size, *m_peripheral_dynamic); reserve_dynamic_collection(p_state, p_size, *m_central_dynamic); m_time->reserve(p_size); } void hhn_dynamic::reserve_dynamic_collection(const hhn_dynamic::collect p_state, const std::size_t p_size, network_dynamic & p_dynamic) { if (p_dynamic.find(p_state) != p_dynamic.end()) { p_dynamic.at(p_state).reserve(p_size); } else { evolution_dynamic dynamic; dynamic.reserve(p_size); p_dynamic[p_state] = std::move(dynamic); } } void hhn_dynamic::store_membrane_potential(const std::vector & p_peripheral, const std::vector & p_central) { std::vector peripheral_membrane_values(p_peripheral.size(), 0.0); for (std::size_t index = 0; index < p_peripheral.size(); index++) { peripheral_membrane_values[index] = p_peripheral[index].m_membrane_potential; } m_peripheral_dynamic->at(collect::MEMBRANE_POTENTIAL).emplace_back(std::move(peripheral_membrane_values)); std::vector central_membrane_values(p_central.size(), 0.0); for (std::size_t index = 0; index < p_central.size(); index++) { central_membrane_values[index] = p_central[index].m_membrane_potential; } m_central_dynamic->at(collect::MEMBRANE_POTENTIAL).emplace_back(std::move(central_membrane_values)); } void hhn_dynamic::store_active_cond_sodium(const std::vector & p_peripheral, const std::vector & p_central) { std::vector peripheral_active_sodium(p_peripheral.size(), 0.0); for (std::size_t index = 0; index < p_peripheral.size(); index++) { peripheral_active_sodium[index] = p_peripheral[index].m_active_cond_sodium; } m_peripheral_dynamic->at(collect::ACTIVE_COND_SODIUM).emplace_back(std::move(peripheral_active_sodium)); std::vector central_active_sodium(p_central.size(), 0.0); for (std::size_t index = 0; index < p_central.size(); index++) { central_active_sodium[index] = p_central[index].m_active_cond_sodium; } m_central_dynamic->at(collect::ACTIVE_COND_SODIUM).emplace_back(std::move(central_active_sodium)); } void hhn_dynamic::store_inactive_cond_sodium(const std::vector & p_peripheral, const std::vector & p_central) { std::vector peripheral_inactive_sodium(p_peripheral.size(), 0.0); for (std::size_t index = 0; index < p_peripheral.size(); index++) { peripheral_inactive_sodium[index] = p_peripheral[index].m_inactive_cond_sodium; } m_peripheral_dynamic->at(collect::INACTIVE_COND_SODIUM).emplace_back(std::move(peripheral_inactive_sodium)); std::vector central_inactive_sodium(p_central.size(), 0.0); for (std::size_t index = 0; index < p_central.size(); index++) { central_inactive_sodium[index] = p_central[index].m_inactive_cond_sodium; } m_central_dynamic->at(collect::INACTIVE_COND_SODIUM).emplace_back(std::move(central_inactive_sodium)); } void hhn_dynamic::store_active_cond_potassium(const std::vector & p_peripheral, const std::vector & p_central) { std::vector peripheral_active_potassium(p_peripheral.size(), 0.0); for (std::size_t index = 0; index < p_peripheral.size(); index++) { peripheral_active_potassium[index] = p_peripheral[index].m_active_cond_potassium; } m_peripheral_dynamic->at(collect::ACTIVE_COND_POTASSIUM).emplace_back(std::move(peripheral_active_potassium)); std::vector central_active_potassium(p_central.size(), 0.0); for (std::size_t index = 0; index < p_central.size(); index++) { central_active_potassium[index] = p_central[index].m_active_cond_potassium; } m_central_dynamic->at(collect::ACTIVE_COND_POTASSIUM).emplace_back(std::move(central_active_potassium)); } bool hhn_dynamic::operator==(const hhn_dynamic & p_other) const { if ( (m_amount_collections == p_other.m_amount_collections) && (*m_peripheral_dynamic == *(p_other.m_peripheral_dynamic)) && (*m_central_dynamic == *(p_other.m_central_dynamic)) && (*m_time == *(p_other.m_time)) ) { return true; } return false; } std::ostream& operator<<(std::ostream & p_stream, const hhn_dynamic & p_dynamic) { const hhn_dynamic::network_dynamic_ptr peripheral = p_dynamic.get_peripheral_dynamic(); const hhn_dynamic::network_dynamic_ptr central = p_dynamic.get_central_dynamic(); std::set enabled; p_dynamic.get_enabled(enabled); const std::vector order_types = { hhn_dynamic::collect::MEMBRANE_POTENTIAL, hhn_dynamic::collect::ACTIVE_COND_SODIUM, hhn_dynamic::collect::INACTIVE_COND_SODIUM, hhn_dynamic::collect::ACTIVE_COND_POTASSIUM }; p_stream << p_dynamic.size_dynamic() << " " << p_dynamic.size_network() << "\n"; for (std::size_t index_order = 0; index_order < order_types.size(); index_order++) { if (enabled.find(order_types[index_order]) != enabled.cend()) { p_stream << index_order << " "; } } p_stream << "\n"; for (std::size_t iter = 0; iter < p_dynamic.size_dynamic(); iter++) { p_stream << p_dynamic.get_time()->at(iter); for (std::size_t neuron_index = 0; neuron_index < p_dynamic.size_network() + 2; neuron_index++) { p_stream << " [ "; for (auto & type : order_types) { if (enabled.find(type) == enabled.cend()) { continue; } if (neuron_index < p_dynamic.size_network()) { p_stream << p_dynamic.get_peripheral_value(iter, neuron_index, type) << " "; } else { std::size_t central_index = neuron_index - p_dynamic.size_network(); p_stream << p_dynamic.get_central_value(iter, central_index, type) << " "; } } p_stream << "]"; } p_stream << "\n"; } return p_stream; } hhn_dynamic_reader::hhn_dynamic_reader(const std::string & p_filename) : m_filename(p_filename), m_dynamic(nullptr), m_file_stream() { } hhn_dynamic_reader::~hhn_dynamic_reader() { if (m_file_stream.is_open()) { m_file_stream.close(); } } void hhn_dynamic_reader::read(hhn_dynamic & p_dynamic) { m_file_stream.open(m_filename.c_str(), std::ifstream::in); m_dynamic = &p_dynamic; parse_size_header(); parse_enable_header(); parse_dynamic(); m_file_stream.close(); } void hhn_dynamic_reader::parse_size_header() { std::string line; std::size_t dynamic_size, dynamic_network; std::getline(m_file_stream, line); extract_size_header(line, dynamic_size, dynamic_network); m_size_network = dynamic_network; m_dynamic->reserve(dynamic_size); } void hhn_dynamic_reader::extract_size_header(const std::string & p_line, std::size_t & p_size_dynamic, std::size_t & p_size_network) { std::istringstream string_stream(p_line); std::string item; if (!std::getline(string_stream, item, ' ')) { throw std::invalid_argument("Impossible parse size dynamic from line header: " + p_line); } p_size_dynamic = (std::size_t) std::stoll(item); if (!std::getline(string_stream, item, '\n')) { throw std::invalid_argument("Impossible parse size network from line header: " + p_line); } p_size_network = (std::size_t) std::stoll(item); } void hhn_dynamic_reader::parse_enable_header() { std::string line; std::getline(m_file_stream, line); extract_enable_header(line, m_order); m_dynamic->disable_all(); m_dynamic->enable(m_order); } void hhn_dynamic_reader::extract_enable_header(const std::string & p_line, std::vector & p_collect) { std::istringstream string_stream(p_line); std::string item; while (std::getline(string_stream, item, ' ')) { /* Each collection type has whitespace after itself */ p_collect.push_back((hhn_dynamic::collect) std::stoll(item)); } } void hhn_dynamic_reader::parse_dynamic() { for (std::string line; std::getline(m_file_stream, line); ) { double time = -1; std::vector peripheral = { }; std::vector central = { }; extract_dynamic(line, time, peripheral, central); m_dynamic->store(time, peripheral, central); } } void hhn_dynamic_reader::extract_dynamic(const std::string & p_line, double & p_time, std::vector & p_peripheral, std::vector & p_central) { std::istringstream string_stream(p_line); std::string item; p_peripheral.resize(m_size_network); p_central.resize(2); std::size_t counter_filling = p_peripheral.size() + 2; std::getline(string_stream, item, ' '); p_time = std::stod(item); bool extract_status = (bool) std::getline(string_stream, item, ' '); for (std::size_t item_index = 0; extract_status; item_index++) { if (item == "[") { if (item_index < p_peripheral.size()) { extract_state(string_stream, p_peripheral[item_index]); } else { std::size_t index_central = item_index - p_peripheral.size(); extract_state(string_stream, p_central[index_central]); } } counter_filling--; extract_status = (bool) std::getline(string_stream, item, ' '); if (!extract_status) { extract_status = (bool) std::getline(string_stream, item, '\n'); } } if (counter_filling != 0) { throw std::invalid_argument("Incorrect format of HHN output dynamic: not all neuron states are found."); } } void hhn_dynamic_reader::extract_state(std::istringstream & p_stream, basic_neuron_state & p_state) const { std::string item; for (std::size_t item_index = 0; std::getline(p_stream, item, ' '); item_index++) { if (item == "]") { return; } hhn_dynamic::collect type_value = m_order[item_index]; switch(type_value) { case hhn_dynamic::collect::MEMBRANE_POTENTIAL: p_state.m_membrane_potential = std::stod(item); break; case hhn_dynamic::collect::ACTIVE_COND_SODIUM: p_state.m_active_cond_sodium = std::stod(item); break; case hhn_dynamic::collect::INACTIVE_COND_SODIUM: p_state.m_inactive_cond_sodium = std::stod(item); break; case hhn_dynamic::collect::ACTIVE_COND_POTASSIUM: p_state.m_active_cond_potassium = std::stod(item); break; default: throw std::invalid_argument("Invalid type of value is detected '" + std::to_string((std::size_t) type_value) + "'"); } } } hhn_network::hhn_network(const std::size_t p_size, const hnn_parameters & p_parameters) : m_peripheral(p_size), m_central(2), m_stimulus(nullptr), m_params(p_parameters) { } void hhn_network::simulate(const std::size_t p_steps, const double p_time, const solve_type p_solver, const hhn_stimulus & p_stimulus, hhn_dynamic & p_output_dynamic) { p_output_dynamic.reserve(p_steps + 1); m_stimulus = (hhn_stimulus *) &p_stimulus; const double step = p_time / (double) p_steps; const double int_step = step / 10.0; initialize_current(); store_dynamic(0.0, p_output_dynamic); double cur_time = 0.0; for (std::size_t cur_step = 0; cur_step < p_steps; cur_step++) { calculate_states(p_solver, cur_time, step, int_step); cur_time += step; store_dynamic(cur_time + step, p_output_dynamic); update_peripheral_current(); } } std::size_t hhn_network::size() const { return m_peripheral.size(); } void hhn_network::store_dynamic(const double p_time, hhn_dynamic & p_dynamic) { p_dynamic.store(p_time, m_peripheral, m_central); } void hhn_network::calculate_states(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step) { hhn_states next_peripheral_states(m_peripheral.size()); calculate_peripheral_states(p_solver, p_time, p_step, p_int_step, next_peripheral_states); hhn_states next_central_states(m_central.size()); calculate_central_states(p_solver, p_time, p_step, p_int_step, next_central_states); assign_neuron_states(p_time, p_step, next_peripheral_states, next_central_states); } void hhn_network::assign_neuron_states(const double p_time, const double p_step, const hhn_states & p_next_peripheral, const hhn_states & p_next_central) { for (std::size_t index = 0; index < m_peripheral.size(); index++) { hhn_oscillator & oscillator = m_peripheral[index]; unpack_equation_output(p_next_peripheral[index], oscillator); if (!oscillator.m_pulse_generation) { if (oscillator.m_membrane_potential >= 0.0) { oscillator.m_pulse_generation = true; oscillator.m_pulse_generation_time.push_back(p_time); } } else if (oscillator.m_membrane_potential < 0.0) { oscillator.m_pulse_generation = false; } if (oscillator.m_link_weight3 == 0.0) { if (oscillator.m_membrane_potential >= m_params.m_threshold) { oscillator.m_link_pulse_counter += p_step; if (oscillator.m_link_pulse_counter >= (1.0 / m_params.m_eps)) { oscillator.m_link_weight3 = m_params.m_w3; oscillator.m_link_activation_time = p_time; } } } else if ( !((oscillator.m_link_activation_time < p_time) && (p_time < oscillator.m_link_activation_time + m_params.m_deltah)) ) { oscillator.m_link_weight3 = 0.0; oscillator.m_link_pulse_counter = 0.0; } } for (std::size_t index = 0; index < m_central.size(); index++) { unpack_equation_output(p_next_central[index], m_central[index]); central_element & elem = m_central[index]; if (!elem.m_pulse_generation) { if (elem.m_membrane_potential >= 0.0) { elem.m_pulse_generation = true; elem.m_pulse_generation_time.push_back(p_time); } } else if (elem.m_membrane_potential < 0.0) { elem.m_pulse_generation = false; } } } void hhn_network::calculate_peripheral_states(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step, hhn_states & p_next_states) { parallel::parallel_for(std::size_t(0), m_peripheral.size(), [this, &p_solver, p_time, p_step, p_int_step, &p_next_states](const std::size_t p_index) { std::vector argv(1, nullptr); argv[0] = (void *) p_index; differ_state inputs; pack_equation_input(m_peripheral[p_index], inputs); perform_calculation(p_solver, p_time, p_step, p_int_step, inputs, argv, p_next_states[p_index]); }); } void hhn_network::calculate_central_states(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step, hhn_states & p_next_states) { parallel::parallel_for(std::size_t(0), m_central.size(), [this, &p_solver, p_time, p_step, p_int_step, &p_next_states](const std::size_t p_index) { std::vector argv(1, nullptr); std::size_t index_central = p_index + m_peripheral.size(); argv[0] = (void *) index_central; differ_state inputs; pack_equation_input(m_central[p_index], inputs); perform_calculation(p_solver, p_time, p_step, p_int_step, inputs, argv, p_next_states[p_index]); }); } void hhn_network::perform_calculation(const solve_type p_solver, const double p_time, const double p_step, const double p_int_step, const differ_state & p_inputs, const differ_extra<> & p_extra, hhn_state & p_next_states) { equation peripheral_equation = std::bind(&hhn_network::neuron_states, this, _1, _2, _3, _4); switch(p_solver) { case solve_type::FORWARD_EULER: { throw std::invalid_argument("Forward Euler first-order method is not supported due to low accuracy."); } case solve_type::RUNGE_KUTTA_4: { std::size_t number_int_steps = (std::size_t) (p_step / p_int_step); runge_kutta_4(peripheral_equation, p_inputs, p_time, p_time + p_step, number_int_steps, false, p_extra, p_next_states); break; } case solve_type::RUNGE_KUTTA_FEHLBERG_45: { runge_kutta_fehlberg_45(peripheral_equation, p_inputs, p_time, p_time + p_step, 0.00001, false, p_extra, p_next_states); break; } default: { throw std::invalid_argument("Specified differential solver is not supported."); } } } void hhn_network::neuron_states(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const { std::size_t index = (std::size_t) argv[0]; double v = inputs[POSITION_MEMBRAN_POTENTIAL]; /* membrane potential (v) */ double m = inputs[POSITION_ACTIVE_COND_SODIUM]; /* activation conductance of the sodium channel (m) */ double h = inputs[POSITION_INACTIVE_COND_SODIUM]; /* inactivaton conductance of the sodium channel (h) */ double n = inputs[POSITION_ACTIVE_COND_POTASSIUM]; /* activation conductance of the potassium channel (n) */ /* Calculate ion current */ double active_sodium_part = m_params.m_gNa * std::pow(m, 3.0) * h * (v - m_params.m_vNa); double inactive_sodium_part = m_params.m_gK * std::pow(n, 4.0) * (v - m_params.m_vK); double active_potassium_part = m_params.m_gL * (v - m_params.m_vL); double Iion = active_sodium_part + inactive_sodium_part + active_potassium_part; double Iext = 0.0; double Isyn = 0.0; /* External and internal currents */ if (index < size()) { Iext = m_peripheral[index].m_Iext; Isyn = peripheral_synaptic_current(index, t, v); } else { std::size_t central_index = index - size(); Iext = m_central[central_index].m_Iext; if (central_index == 0) { Isyn = central_first_synaptic_current(t, v); } } /* Membrane potential */ double dv = -Iion + Iext - Isyn; /* Calculate variables */ double potential = v - m_params.m_vRest; double am = (2.5 - 0.1 * potential) / (std::expm1(2.5 - 0.1 * potential)); /* 'exp(x) - 1' can be replaced by 'expm1(x)' */ double ah = 0.07 * std::exp(-potential / 20.0); double an = (0.1 - 0.01 * potential) / (std::expm1(1.0 - 0.1 * potential)); /* 'exp(x) - 1' can be replaced by 'expm1(x)' */ double bm = 4.0 * std::exp(-potential / 18.0); double bh = 1.0 / (std::exp(3.0 - 0.1 * potential) + 1.0); double bn = 0.125 * std::exp(-potential / 80.0); double dm = am * (1.0 - m) - bm * m; double dh = ah * (1.0 - h) - bh * h; double dn = an * (1.0 - n) - bn * n; outputs = { dv, dm, dh, dn }; } double hhn_network::peripheral_external_current(const std::size_t p_index) const { return (*m_stimulus)[p_index] * (1.0 + 0.01 * generate_uniform_random(-1.0, 1.0)); } double hhn_network::peripheral_synaptic_current(const std::size_t p_index, const double p_time, const double p_membrane) const { double memory_impact1 = 0.0; for (auto & pulse_time : m_central[0].m_pulse_generation_time) { memory_impact1 += alpha_function(p_time - pulse_time, m_params.m_alfa_inhibitory, m_params.m_betta_inhibitory); } double memory_impact2 = 0.0; for (auto & pulse_time : m_central[1].m_pulse_generation_time) { memory_impact2 += alpha_function(p_time - pulse_time, m_params.m_alfa_inhibitory, m_params.m_betta_inhibitory); } return m_params.m_w2 * (p_membrane - m_params.m_Vsyninh) * memory_impact1 + m_peripheral[p_index].m_link_weight3 * (p_membrane - m_params.m_Vsyninh) * memory_impact2; } double hhn_network::central_first_synaptic_current(const double p_time, const double p_membrane) const { double memory_impact = 0.0; for (std::size_t index_oscillator = 0; index_oscillator < size(); index_oscillator++) { for (auto & pulse_time : m_peripheral[index_oscillator].m_pulse_generation_time) { memory_impact += alpha_function(p_time - pulse_time, m_params.m_alfa_excitatory, m_params.m_betta_excitatory); } } return m_params.m_w1 * (p_membrane - m_params.m_Vsynexc) * memory_impact; } double hhn_network::alpha_function(const double p_time, const double p_alfa, const double p_betta) { return p_alfa * p_time * std::exp(-p_betta * p_time); } void hhn_network::initialize_current() { update_peripheral_current(); m_central[0].m_Iext = m_params.m_Icn1; m_central[1].m_Iext = m_params.m_Icn2; } void hhn_network::update_peripheral_current() { for (std::size_t index = 0; index < m_peripheral.size(); index++) { m_peripheral[index].m_Iext = peripheral_external_current(index); } } } } pyclustering-0.10.1.2/ccore/src/nnet/legion.cpp000077500000000000000000000274741375753423500213270ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include #include using namespace std::placeholders; using namespace pyclustering::utils::math; namespace pyclustering { namespace nnet { const size_t legion_network::MAXIMUM_MATRIX_REPRESENTATION_SIZE = 4096; std::size_t legion_network_state::size() const { return m_output.size(); } legion_network::legion_network(const size_t num_osc, const connection_t connection_type, const legion_parameters & params) { initialize(num_osc, connection_type, 0, 0, params); } legion_network::legion_network(const size_t num_osc, const connection_t connection_type, const size_t height, const size_t width, const legion_parameters & params) { initialize(num_osc, connection_type, height, width, params); } legion_network::~legion_network() { m_stimulus = nullptr; } void legion_network::simulate(const unsigned int steps, const double time, const solve_type solver, const bool collect_dynamic, const legion_stimulus & stimulus, legion_dynamic & output_dynamic) { output_dynamic.clear(); m_stimulus = (legion_stimulus *) &stimulus; create_dynamic_connections(stimulus); const double step = time / (double) steps; const double int_step = step / 10.0; store_dynamic(0.0, collect_dynamic, output_dynamic); /* store initial state */ for (double cur_time = step; cur_time < time; cur_time += step) { calculate_states(stimulus, solver, cur_time, step, int_step); store_dynamic(cur_time, collect_dynamic, output_dynamic); /* store initial state */ } } void legion_network::create_dynamic_connections(const legion_stimulus & stimulus) { for (size_t i = 0; i < size(); i++) { /* re-initialization by 0.0 */ std::fill(m_dynamic_connections[i].begin(), m_dynamic_connections[i].end(), 0.0); std::vector neighbors; m_static_connections->get_neighbors(i, neighbors); if (neighbors.size() > 0 && stimulus[i] > 0) { int number_stimulated_neighbors = 0; for (auto & index_neighbor : neighbors) { if (stimulus[index_neighbor] > 0) { number_stimulated_neighbors++; } } if (number_stimulated_neighbors > 0) { double dynamic_weight = m_params.Wt / (double) number_stimulated_neighbors; for (auto & index_neighbor : neighbors) { m_dynamic_connections[i][index_neighbor] = dynamic_weight; } } } } } void legion_network::store_dynamic(const double time, const bool collect_dynamic, legion_dynamic & dynamic) const { legion_network_state state(size()); for (std::size_t index = 0; index < size(); index++) { state.m_output[index] = m_oscillators[index].m_excitatory; } state.m_inhibitor = m_global_inhibitor; state.m_time = time; if ( (collect_dynamic == false) && (!dynamic.empty()) ) { dynamic[0] = state; } else { dynamic.push_back(state); } } void legion_network::calculate_states(const legion_stimulus & stimulus, const solve_type solver, const double t, const double step, const double int_step) { std::vector< differ_result > next_states(size()); std::vector argv(1, nullptr); std::size_t number_int_steps = static_cast(step / int_step); for (std::size_t index = 0; index < size(); index++) { argv[0] = (void *) index; differ_state inputs { m_oscillators[index].m_excitatory, m_oscillators[index].m_inhibitory }; if (m_params.ENABLE_POTENTIAL) { inputs.push_back(m_oscillators[index].m_potential); } switch(solver) { case solve_type::FORWARD_EULER: { throw std::invalid_argument("Forward Euler first-order method is not supported due to low accuracy."); } case solve_type::RUNGE_KUTTA_4: { if (m_params.ENABLE_POTENTIAL) { equation neuron_equation = std::bind(&legion_network::neuron_states, this, _1, _2, _3, _4); runge_kutta_4(neuron_equation, inputs, t, t + step, number_int_steps, false /* only last states */, argv, next_states[index]); } else { equation neuron_simplify_equation = std::bind(&legion_network::neuron_simplify_states, this, _1, _2, _3, _4); runge_kutta_4(neuron_simplify_equation, inputs, t, t + step, number_int_steps, false /* only last states */, argv, next_states[index]); } break; } case solve_type::RUNGE_KUTTA_FEHLBERG_45: { if (m_params.ENABLE_POTENTIAL) { equation neuron_equation = std::bind(&legion_network::neuron_states, this, _1, _2, _3, _4); runge_kutta_fehlberg_45(neuron_equation, inputs, t, t + step, 0.00001, false /* only last states */, argv, next_states[index]); } else { equation neuron_simplify_equation = std::bind(&legion_network::neuron_simplify_states, this, _1, _2, _3, _4); runge_kutta_fehlberg_45(neuron_simplify_equation, inputs, t, t + step, 0.00001, false /* only last states */, argv, next_states[index]); } break; } default: { throw std::invalid_argument("Not supported solver is used."); } } std::vector neighbors; m_static_connections->get_neighbors(index, neighbors); double coupling = 0.0; for (auto & index_neighbor : neighbors) { coupling += m_dynamic_connections[index][index_neighbor] * heaviside(m_oscillators[index_neighbor].m_excitatory - m_params.teta_x); } m_oscillators[index].m_buffer_coupling_term = coupling - m_params.Wz * heaviside(m_global_inhibitor - m_params.teta_xz); } differ_result inhibitor_next_state; differ_state inhibitor_input { m_global_inhibitor }; equation inhibitor_equation = std::bind(&legion_network::inhibitor_state, this, _1, _2, _3, _4); switch (solver) { case solve_type::RUNGE_KUTTA_4: { runge_kutta_4(inhibitor_equation, inhibitor_input, t, t + step, number_int_steps, false /* only last states */, argv, inhibitor_next_state); break; } case solve_type::RUNGE_KUTTA_FEHLBERG_45: { runge_kutta_fehlberg_45(inhibitor_equation, inhibitor_input, t, t + step, 0.00001, false /* only last states */, argv, inhibitor_next_state); break; } default: throw std::invalid_argument("Not supported solver is used."); } m_global_inhibitor = inhibitor_next_state[0].state[0]; for (std::size_t i = 0; i < size(); i++) { m_oscillators[i].m_excitatory = next_states[i][0].state[0]; m_oscillators[i].m_inhibitory = next_states[i][0].state[1]; if (m_params.ENABLE_POTENTIAL) { m_oscillators[i].m_potential = next_states[i][0].state[2]; } m_oscillators[i].m_coupling_term = m_oscillators[i].m_buffer_coupling_term; m_oscillators[i].m_noise = m_noise_distribution(m_generator); } } void legion_network::neuron_states(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) { std::size_t index = (std::size_t) argv[0]; const double x = inputs[0]; const double y = inputs[1]; const double p = inputs[2]; double potential_influence = heaviside(p + std::exp(-m_params.alpha * t) - m_params.teta); double stumulus = 0.0; if ((*m_stimulus)[index] > 0) { stumulus = m_params.I; } double dx = 3.0 * x - std::pow(x, 3) + 2.0 - y + stumulus * potential_influence + m_oscillators[index].m_coupling_term + m_oscillators[index].m_noise; double dy = m_params.eps * (m_params.gamma * (1.0 + std::tanh(x / m_params.betta)) - y); std::vector neighbors; m_static_connections->get_neighbors(index, neighbors); double potential = 0.0; for (auto index_neighbor : neighbors) { potential += m_params.T * heaviside(m_oscillators[index_neighbor].m_excitatory - m_params.teta_x); } double dp = m_params.lamda * (1 - p) * heaviside(potential - m_params.teta_p) - m_params.mu * p; outputs.clear(); outputs.push_back(dx); outputs.push_back(dy); outputs.push_back(dp); } void legion_network::neuron_simplify_states(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) { unsigned int index = *(unsigned int *) argv[0]; const double x = inputs[0]; const double y = inputs[1]; double stumulus = 0.0; if ((*m_stimulus)[index] > 0) { stumulus = m_params.I; } double dx = 3.0 * x - std::pow(x, 3) + 2.0 - y + stumulus + m_oscillators[index].m_coupling_term + m_oscillators[index].m_noise; double dy = m_params.eps * (m_params.gamma * (1.0 + std::tanh(x / m_params.betta)) - y); outputs.clear(); outputs.push_back(dx); outputs.push_back(dy); } void legion_network::inhibitor_state(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const { const double z = inputs[0]; double sigma = 0.0; for (std::size_t index = 0; index < size(); index++) { if (m_oscillators[index].m_excitatory > m_params.teta_zx) { sigma = 1.0; break; } } double dz = m_params.fi * (sigma - z); outputs.clear(); outputs.push_back(dz); } void legion_network::initialize(const size_t num_osc, const connection_t connection_type, const size_t height, const size_t width, const legion_parameters & params) { m_oscillators = std::vector(num_osc, legion_oscillator()); m_dynamic_connections = std::vector >(num_osc, std::vector(num_osc, 0.0)), m_stimulus = nullptr; m_generator = std::default_random_engine(m_device()); m_generator.seed(static_cast(std::chrono::system_clock::now().time_since_epoch().count())); m_noise_distribution = std::uniform_real_distribution(0.0, params.ro); m_global_inhibitor = 0; m_params = params; for (size_t index = 0; index < m_oscillators.size(); index++) { m_oscillators[index].m_noise = m_noise_distribution(m_generator); } if (num_osc > MAXIMUM_MATRIX_REPRESENTATION_SIZE) { m_static_connections = std::shared_ptr(new adjacency_bit_matrix(num_osc)); } else { m_static_connections = std::shared_ptr(new adjacency_matrix(num_osc)); } adjacency_connector connector; if ((height != 0) && (width != 0)) { connector.create_grid_structure(connection_type, width, height, *m_static_connections); } else { connector.create_structure(connection_type, *m_static_connections); } } } }pyclustering-0.10.1.2/ccore/src/nnet/pcnn.cpp000077500000000000000000000175601375753423500210030ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include namespace pyclustering { namespace nnet { const std::size_t pcnn::MAXIMUM_MATRIX_REPRESENTATION_SIZE = 4096; std::size_t pcnn_network_state::size() const { return m_output.size(); } pcnn::pcnn() : m_oscillators(0), m_connection(), m_params() { } pcnn::pcnn(const size_t p_size, const connection_t p_structure, const pcnn_parameters & p_parameters) { initilize(p_size, p_structure, 0, 0, p_parameters); } pcnn::pcnn(const size_t p_size, const connection_t p_structure, const size_t p_height, const size_t p_width, const pcnn_parameters & p_parameters) { initilize(p_size, p_structure, p_height, p_width, p_parameters); } void pcnn::simulate(const std::size_t steps, const pcnn_stimulus & stimulus, pcnn_dynamic & output_dynamic) { output_dynamic.resize(steps, size()); for (std::size_t i = 0; i < steps; i++) { calculate_states(stimulus); store_dynamic(i, output_dynamic); } } void pcnn::calculate_states(const pcnn_stimulus & stimulus) { std::vector feeding(size(), 0.0); std::vector linking(size(), 0.0); std::vector outputs(size(), 0.0); if (stimulus.size() != size()) { throw std::out_of_range("pcnn::calculate_states: length of stimulus should be equal to amount of oscillators in the network."); } for (std::size_t index = 0; index < size(); index++) { pcnn_oscillator & current_oscillator = m_oscillators[index]; std::vector neighbors; m_connection->get_neighbors(index, neighbors); double feeding_influence = 0.0; double linking_influence = 0.0; for (auto & index : neighbors) { const double output_neighbor = m_oscillators[index].output; feeding_influence += output_neighbor * m_params.M; linking_influence += output_neighbor * m_params.W; } feeding_influence *= m_params.VF; linking_influence *= m_params.VL; feeding[index] = m_params.AF * current_oscillator.feeding + stimulus[index] + feeding_influence; linking[index] = m_params.AL * current_oscillator.linking + linking_influence; /* calculate internal activity */ double internal_activity = feeding[index] * (1.0 + m_params.B * linking[index]); /* calculate output of the oscillator */ if (internal_activity > current_oscillator.threshold) { outputs[index] = OUTPUT_ACTIVE_STATE; } else { outputs[index] = OUTPUT_INACTIVE_STATE; } } /* fast linking */ if (m_params.FAST_LINKING) { fast_linking(feeding, linking, outputs); } /* update states of oscillators */ for (std::size_t index = 0; index < size(); index++) { pcnn_oscillator & oscillator = m_oscillators[index]; oscillator.feeding = feeding[index]; oscillator.linking = linking[index]; oscillator.output = outputs[index]; oscillator.threshold = m_params.AT * oscillator.threshold + m_params.VT * outputs[index]; } } void pcnn::fast_linking(const std::vector & feeding, std::vector & linking, std::vector & output) { std::vector previous_outputs(output.cbegin(), output.cend()); bool previous_output_change = true; bool current_output_change = false; while (previous_output_change) { for (std::size_t index = 0; index < size(); index++) { pcnn_oscillator & current_oscillator = m_oscillators[index]; std::vector neighbors; m_connection->get_neighbors(index, neighbors); double linking_influence = 0.0; for (auto & index_neighbor : neighbors) { linking_influence += previous_outputs[index_neighbor] * m_params.W; } linking_influence *= m_params.VL; linking[index] = linking_influence; double internal_activity = feeding[index] * (1.0 + m_params.B * linking[index]); if (internal_activity > current_oscillator.threshold) { output[index] = OUTPUT_ACTIVE_STATE; } else { output[index] = OUTPUT_INACTIVE_STATE; } if (output[index] != previous_outputs[index]) { current_output_change = true; } } /* check for changes for avoiding useless operation copy */ if (current_output_change) { std::copy(output.begin(), output.end(), previous_outputs.begin()); } previous_output_change = current_output_change; current_output_change = false; } } void pcnn::store_dynamic(const std::size_t step, pcnn_dynamic & dynamic) const { pcnn_network_state & current_state = (pcnn_network_state &) dynamic[step]; current_state.m_output.resize(size()); current_state.m_time = (double) step; for (size_t i = 0; i < m_oscillators.size(); i++) { current_state.m_output[i] = m_oscillators[i].output; } } void pcnn::initilize(const size_t p_size, const connection_t p_structure, const size_t p_height, const size_t p_width, const pcnn_parameters & p_parameters) { m_oscillators = std::vector(p_size, pcnn_oscillator()); if (p_size > MAXIMUM_MATRIX_REPRESENTATION_SIZE) { m_connection = std::shared_ptr(new adjacency_bit_matrix(p_size)); } else { m_connection = std::shared_ptr(new adjacency_matrix(p_size)); } adjacency_connector connector; if ((p_height != 0) && (p_width != 0)) { connector.create_grid_structure(p_structure, p_width, p_height, *m_connection); } else { connector.create_structure(p_structure, *m_connection); } m_params = p_parameters; } pcnn_dynamic::pcnn_dynamic() { } pcnn_dynamic::~pcnn_dynamic() { } void pcnn_dynamic::allocate_sync_ensembles(ensemble_data & sync_ensembles) const { std::unordered_set traverse_oscillators; traverse_oscillators.reserve(oscillators()); for (const_reverse_iterator iter_state = crbegin(); iter_state != crend(); ++iter_state) { pcnn_ensemble ensemble; const pcnn_network_state & state_network = (*iter_state); for (std::size_t i = 0; i < oscillators(); i++) { if (state_network.m_output[i] == OUTPUT_ACTIVE_STATE) { if (traverse_oscillators.find(i) == traverse_oscillators.end()) { ensemble.push_back(i); traverse_oscillators.insert(i); } } } if (!ensemble.empty()) { sync_ensembles.push_back(ensemble); } } } void pcnn_dynamic::allocate_spike_ensembles(ensemble_data & spike_ensembles) const { for (const_iterator iter_state = cbegin(); iter_state != cend(); ++iter_state) { pcnn_ensemble ensemble; const pcnn_network_state & state_network = (*iter_state); for (std::size_t i = 0; i < oscillators(); i++) { if (state_network.m_output[i] == OUTPUT_ACTIVE_STATE) { ensemble.push_back(i); } } if (!ensemble.empty()) { spike_ensembles.push_back(ensemble); } } } void pcnn_dynamic::allocate_time_signal(pcnn_time_signal & time_signal) const { time_signal.resize(size()); for (std::size_t t = 0; t < size(); t++) { const pcnn_network_state & state_network = (*this)[t]; for (std::size_t i = 0; i < oscillators(); i++) { if (state_network.m_output[i] == OUTPUT_ACTIVE_STATE) { time_signal[t]++; } } } } } }pyclustering-0.10.1.2/ccore/src/nnet/som.cpp000077500000000000000000000455751375753423500206520ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include using namespace pyclustering::utils::metric; namespace pyclustering { namespace nnet { som_parameters & som_parameters::operator=(const som_parameters & p_other) { if (&p_other != this) { init_type = p_other.init_type; init_radius = p_other.init_radius; init_learn_rate = p_other.init_learn_rate; adaptation_threshold = p_other.adaptation_threshold; random_state = p_other.random_state; } return *this; } som::som(const size_t num_rows, const size_t num_cols, const som_conn_type type_conn, const som_parameters & parameters) : m_rows(num_rows), m_cols(num_cols), m_size(num_rows * num_cols), m_conn_type(type_conn), m_awards(m_size, 0), m_data(nullptr), m_location(m_size), m_sqrt_distances(m_size, std::vector(m_size, 0)), m_capture_objects(m_size), m_params(parameters) { if (m_params.init_radius == 0.0) { m_params.init_radius = calculate_init_radius(m_rows, m_cols); } /* location */ for (size_t i = 0; i < m_rows; i++) { for (size_t j = 0; j < m_cols; j++) { std::vector neuron_location(2, 0); neuron_location[0] = (double) i; neuron_location[1] = (double) j; m_location[i * m_cols + j] = neuron_location; } } /* distances */ for (std::size_t i = 0; i < m_size; i++) { std::vector column_distances(m_size, 0); m_sqrt_distances[i] = column_distances; } for (std::size_t i = 0; i < m_size; i++) { m_sqrt_distances[i][i] = 0.0; for (std::size_t j = i + 1; j < m_size; j++) { double distance = euclidean_distance_square(m_location[i], m_location[j]); m_sqrt_distances[i][j] = distance; m_sqrt_distances[j][i] = distance; } } /* connections */ if (type_conn != som_conn_type::SOM_FUNC_NEIGHBOR) { create_connections(type_conn); } } som::som(const som & p_other) { operator=(p_other); } som::~som() { } void som::create_connections(const som_conn_type type) { m_neighbors.resize(m_size); for (int index = 0; index < (int) m_size; index++) { std::vector & neuron_neighbors = m_neighbors[index]; int upper_index = index - (int) m_cols; int upper_left_index = index - (int) m_cols - 1; int upper_right_index = index - (int) m_cols + 1; int lower_index = index + (int) m_cols; int lower_left_index = index + (int) m_cols - 1; int lower_right_index = index + (int) m_cols + 1; int left_index = index - 1; int right_index = index + 1; int node_row_index = (int) std::floor( (double) index / (double) m_cols ); int upper_row_index = node_row_index - 1; int lower_row_index = node_row_index + 1; if ( (type == som_conn_type::SOM_GRID_EIGHT) || (type == som_conn_type::SOM_GRID_FOUR) ) { if (upper_index >= 0) { neuron_neighbors.push_back(upper_index); } if (lower_index < (int) m_size) { neuron_neighbors.push_back(lower_index); } } if ( (type == som_conn_type::SOM_GRID_EIGHT) || (type == som_conn_type::SOM_GRID_FOUR) || (type == som_conn_type::SOM_HONEYCOMB) ) { if ( (left_index >= 0) && ( (int) std::floor((double) left_index / (double) m_cols) == node_row_index) ) { neuron_neighbors.push_back(left_index); } if ( (int) std::floor((double) right_index / (double) m_cols) == node_row_index ) { neuron_neighbors.push_back(right_index); } } if (type == som_conn_type::SOM_GRID_EIGHT) { if ( (upper_left_index >= 0) && ( (int) std::floor((double) upper_left_index / (double) m_cols) == upper_row_index) ) { neuron_neighbors.push_back(upper_left_index); } if ( (upper_right_index >= 0) && ( (int) std::floor((double) upper_right_index / (double) m_cols) == upper_row_index) ) { neuron_neighbors.push_back(upper_right_index); } if ( (lower_left_index < (int) m_size) && ( (int) std::floor((double) lower_left_index / (double) m_cols) == lower_row_index) ) { neuron_neighbors.push_back(lower_left_index); } if ( (lower_right_index < (int) m_size) && ( (int) std::floor((double) lower_right_index / (double) m_cols) == lower_row_index) ) { neuron_neighbors.push_back(lower_right_index); } } if (type == som_conn_type::SOM_HONEYCOMB) { if ( (node_row_index % 2) == 0 ) { upper_left_index = index - (int) m_cols; upper_right_index = index - (int) m_cols + 1; lower_left_index = index + (int) m_cols; lower_right_index = index + (int) m_cols + 1; } else { upper_left_index = index - (int) m_cols - 1; upper_right_index = index - (int) m_cols; lower_left_index = index + (int) m_cols - 1; lower_right_index = index + (int) m_cols; } if ( (upper_left_index >= 0) && ( (int) std::floor((double) upper_left_index / (double) m_cols) == upper_row_index) ) { neuron_neighbors.push_back(upper_left_index); } if ( (upper_right_index >= 0) && ( (int) std::floor((double) upper_right_index / (double) m_cols) == upper_row_index) ) { neuron_neighbors.push_back(upper_right_index); } if ( (lower_left_index < (int) m_size) && ( (int) std::floor((double) lower_left_index / (double) m_cols) == lower_row_index) ) { neuron_neighbors.push_back(lower_left_index); } if ( (lower_right_index < (int) m_size) && ( (int) std::floor((double) lower_right_index / (double) m_cols) == lower_row_index) ) { neuron_neighbors.push_back(lower_right_index); } } } } void som::create_initial_weights(const som_init_type type) { size_t dimension = (*m_data)[0].size(); m_weights.resize(m_size, std::vector(dimension, 0.0)); std::vector maximum_value_dimension(dimension, -std::numeric_limits::max()); std::vector minimum_value_dimension(dimension, std::numeric_limits::max()); for (size_t i = 0; i < m_data->size(); i++) { for (size_t dim = 0; dim < dimension; dim++) { if (maximum_value_dimension[dim] < (*m_data)[i][dim]) { maximum_value_dimension[dim] = (*m_data)[i][dim]; } if (minimum_value_dimension[dim] > (*m_data)[i][dim]) { minimum_value_dimension[dim] = (*m_data)[i][dim]; } } } std::vector width_value_dimension(dimension, 0); std::vector center_value_dimension(dimension, 0); for (size_t dim = 0; dim < dimension; dim++) { width_value_dimension[dim] = maximum_value_dimension[dim] - minimum_value_dimension[dim]; center_value_dimension[dim] = (maximum_value_dimension[dim] + minimum_value_dimension[dim]) / 2.0; } double step_x = center_value_dimension[0]; double step_y = 0.0; if (dimension > 1) { step_y = center_value_dimension[1]; if (m_cols > 1) { step_y = width_value_dimension[1] / (m_cols - 1.0); } } if (m_rows > 1) { step_x = width_value_dimension[0] / (m_rows - 1.0); } /* generate weights (topological coordinates) */ std::random_device device; std::default_random_engine generator(device()); if (m_params.random_state == RANDOM_STATE_CURRENT_TIME) { generator.seed(static_cast(std::chrono::system_clock::now().time_since_epoch().count())); } else { generator.seed(static_cast(m_params.random_state)); } switch (type) { case som_init_type::SOM_UNIFORM_GRID: { for (size_t i = 0; i < m_size; i++) { std::vector & neuron_location = m_location[i]; std::vector & neuron_weight = m_weights[i]; for (size_t dim = 0; dim < dimension; dim++) { if (dim == 0) { if (m_rows > 1) { neuron_weight[dim] = minimum_value_dimension[dim] + step_x * neuron_location[dim]; } else { neuron_weight[dim] = center_value_dimension[dim]; } } else if (dim == 1) { if (m_cols > 1) { neuron_weight[dim] = minimum_value_dimension[dim] + step_y * neuron_location[dim]; } else { neuron_weight[dim] = center_value_dimension[dim]; } } else { neuron_weight[dim] = center_value_dimension[dim]; } } } break; } case som_init_type::SOM_RANDOM_SURFACE: { /* Random weights at the full surface. */ for (size_t i = 0; i < m_size; i++) { std::vector & neuron_weight = m_weights[i]; for (size_t dim = 0; dim < dimension; dim++) { std::uniform_real_distribution position_distribution(minimum_value_dimension[dim], maximum_value_dimension[dim]); neuron_weight[dim] = position_distribution(generator); } } break; } case som_init_type::SOM_RANDOM_CENTROID: case som_init_type::SOM_RANDOM: { /* Random weights of input data. */ std::uniform_real_distribution position_distribution(-0.5, 0.5); for (size_t i = 0; i < m_size; i++) { std::vector & neuron_weight = m_weights[i]; for (size_t dim = 0; dim < dimension; dim++) { neuron_weight[dim] = position_distribution(generator); } } break; } } m_previous_weights = m_weights; } size_t som::competition(const pattern & input_pattern) const { size_t index = 0; double minimum = euclidean_distance_square(m_weights[0], input_pattern); for (size_t i = 1; i < m_size; i++) { double candidate = euclidean_distance_square(m_weights[i], input_pattern); if (candidate < minimum) { index = i; minimum = candidate; } } return index; } size_t som::adaptation(const size_t index_winner, const pattern & input_pattern) { size_t dimensions = m_weights[0].size(); size_t number_adapted_neurons = 0; if (m_conn_type == som_conn_type::SOM_FUNC_NEIGHBOR) { for (size_t neuron_index = 0; neuron_index < m_size; neuron_index++) { double distance = m_sqrt_distances[index_winner][neuron_index]; if (distance < m_local_radius) { double influence = std::exp( -( distance / (2.0 * m_local_radius) ) ); std::vector & neuron_weight = m_weights[neuron_index]; for (size_t dim = 0; dim < dimensions; dim++) { neuron_weight[dim] += m_learn_rate * influence * (input_pattern[dim] - m_weights[neuron_index][dim]); } number_adapted_neurons++; } } } else { std::vector & neuron_winner_weight = m_weights[index_winner]; for (size_t dim = 0; dim < dimensions; dim++) { neuron_winner_weight[dim] += m_learn_rate * (input_pattern[dim] - neuron_winner_weight[dim] ); } std::vector & winner_neighbors = m_neighbors[index_winner]; for (auto & neighbor_index : winner_neighbors) { double distance = m_sqrt_distances[index_winner][neighbor_index]; if (distance < m_local_radius) { double influence = std::exp( -( distance / (2.0 * m_local_radius) ) ); std::vector & neighbor_weight = m_weights[neighbor_index]; for (size_t dim = 0; dim < dimensions; dim++) { neighbor_weight[dim] += m_learn_rate * influence * (input_pattern[dim] - neighbor_weight[dim]); } number_adapted_neurons++; } } } return number_adapted_neurons; } size_t som::train(const dataset & input_data, const size_t num_epochs, bool autostop) { for (size_t i = 0; i < m_capture_objects.size(); i++) { m_capture_objects[i].clear(); m_awards[i] = 0; } /* number of epouch */ m_epouchs = num_epochs; /* store pointer to data (we are not owners, we don't need them after training) */ m_data = &input_data; /* create weights */ create_initial_weights(m_params.init_type); size_t epouch = 1; for ( ; epouch < (m_epouchs + 1); epouch++) { /* Depression term of coupling */ m_local_radius = std::pow( ( m_params.init_radius * std::exp(-( (double) epouch / (double) m_epouchs)) ), 2); m_learn_rate = m_params.init_learn_rate * std::exp(-( (double) epouch / (double) m_epouchs)); if (autostop == true) { for (size_t i = 0; i < m_size; i++) { m_awards[i] = 0; m_capture_objects[i].clear(); } } for (size_t i = 0; i < m_data->size(); i++) { /* Step 1: Competition */ size_t index_winner = competition((*m_data)[i]); /* Step 2: Adaptation */ adaptation(index_winner, (*m_data)[i]); /* Update statistics */ if ( (autostop == true) || (epouch == m_epouchs) ) { m_awards[index_winner]++; m_capture_objects[index_winner].push_back(i); } } if (autostop == true) { double maximal_adaptation = calculate_maximal_adaptation(); if (maximal_adaptation < m_params.adaptation_threshold) { return epouch; } for (size_t i = 0; i < m_weights.size(); i++) { std::copy(m_weights[i].begin(), m_weights[i].end(), m_previous_weights[i].begin()); } } } return epouch; } void som::load(const dataset & p_weights, const som_award_sequence & p_awards, const som_gain_sequence & p_capture_objects) { if (p_weights.size() != m_size) { throw std::invalid_argument("Provided weights (" + std::to_string(p_weights.size()) + ") for loading does not correspond to network size (" + std::to_string(m_size) + ")."); } m_weights = p_weights; if (!p_capture_objects.empty()) { if (p_capture_objects.size() != m_size) { throw std::invalid_argument("Provided capture objects (size '" + std::to_string(p_capture_objects.size()) + "') for loading does not correspond to network size '" + std::to_string(m_size) + "'."); } m_capture_objects = p_capture_objects; } if (!p_awards.empty()) { if (p_awards.size() != m_size) { throw std::invalid_argument("Provided amount of capture objects by each neuron (size '" + std::to_string(p_awards.size()) + "') for loading does not correspond to network size '" + std::to_string(m_size) + "'."); } m_awards = p_awards; } } size_t som::simulate(const pattern & input_pattern) const { return competition(input_pattern); } double som::calculate_maximal_adaptation() const { size_t dimensions = (*m_data)[0].size(); double maximal_adaptation = 0; for (size_t neuron_index = 0; neuron_index < m_size; neuron_index++) { const std::vector & neuron_weight = m_weights[neuron_index]; const std::vector & previous_neuron_weight = m_previous_weights[neuron_index]; for (size_t dim = 0; dim < dimensions; dim++) { double current_adaptation = previous_neuron_weight[dim] - neuron_weight[dim]; if (current_adaptation < 0) { current_adaptation = -current_adaptation; } if (maximal_adaptation < current_adaptation) { maximal_adaptation = current_adaptation; } } } return maximal_adaptation; } std::size_t som::get_winner_number() const { std::size_t winner_number = 0; for (std::size_t i = 0; i < m_size; i++) { if (m_awards[i] > 0) { winner_number++; } } return winner_number; } double som::calculate_init_radius(const size_t p_rows, const size_t p_cols) { if ((double)(p_cols + p_rows) / 4.0 > 1.0) { return 2.0; } else if ((p_cols > 1) && (p_rows > 1)) { return 1.5; } else { return 1.0; } } std::ostream & operator<<(std::ostream & p_stream, const som & p_network) { p_stream << p_network.m_rows << "\n"; p_stream << p_network.m_cols << "\n"; p_stream << (unsigned) p_network.m_conn_type << "\n"; p_stream << pyclustering::to_string(p_network.m_weights) << "\n"; p_stream << pyclustering::to_string(p_network.m_awards) << "\n"; p_stream << pyclustering::to_string(p_network.m_location) << "\n"; p_stream << pyclustering::to_string(p_network.m_capture_objects) << "\n"; p_stream << pyclustering::to_string(p_network.m_neighbors) << "\n"; return p_stream; } som & som::operator=(const som & p_other) { if (&p_other == this) { return *this; } m_rows = p_other.m_rows; m_cols = p_other.m_cols; m_size = p_other.m_size; m_conn_type = p_other.m_conn_type; m_weights = p_other.m_weights; m_previous_weights = p_other.m_previous_weights; m_awards = p_other.m_awards; m_location = p_other.m_location; m_sqrt_distances = p_other.m_sqrt_distances; m_capture_objects = p_other.m_capture_objects; m_neighbors = p_other.m_neighbors; m_epouchs = p_other.m_epouchs; m_params = p_other.m_params; m_local_radius = p_other.m_local_radius; m_learn_rate = p_other.m_learn_rate; return *this; } } } pyclustering-0.10.1.2/ccore/src/nnet/sync.cpp000077500000000000000000000371671375753423500210260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace pyclustering::container; using namespace pyclustering::differential; using namespace pyclustering::parallel; using namespace pyclustering::utils::math; using namespace pyclustering::utils::metric; using namespace std::placeholders; namespace pyclustering { namespace nnet { const std::size_t sync_network::MAXIMUM_MATRIX_REPRESENTATION_SIZE = 4096; double sync_ordering::calculate_sync_order(const std::vector & p_phases) { phase_getter getter = [&p_phases](std::size_t index){ return p_phases[index]; }; return calculate_sync_order_parameter(p_phases, getter); } double sync_ordering::calculate_sync_order(const std::vector & p_oscillators) { phase_getter getter = [&p_oscillators](std::size_t index){ return p_oscillators[index].phase; }; return calculate_sync_order_parameter(p_oscillators, getter); } template double sync_ordering::calculate_sync_order_parameter(const TypeContainer & p_container, const phase_getter & p_getter) { double exp_amount = 0.0; double average_phase = 0.0; for (std::size_t index = 0; index < p_container.size(); index++) { const double phase = p_getter(index); exp_amount += std::exp( std::abs( std::complex(0, 1) * phase ) ); average_phase += phase; } exp_amount /= p_container.size(); average_phase = std::exp( std::abs( std::complex(0, 1) * (average_phase / p_container.size()) ) ); return std::abs(average_phase) / std::abs(exp_amount); } double sync_ordering::calculate_local_sync_order(const std::shared_ptr & p_connections, const std::vector & p_phases) { phase_getter getter = [&p_phases](std::size_t index){ return p_phases[index]; }; return calculate_local_sync_order_parameter(p_connections, p_phases, getter); } double sync_ordering::calculate_local_sync_order(const std::shared_ptr & p_connections, const std::vector & p_oscillators) { phase_getter getter = [&p_oscillators](std::size_t index){ return p_oscillators[index].phase; }; return calculate_local_sync_order_parameter(p_connections, p_oscillators, getter); } template double sync_ordering::calculate_local_sync_order_parameter(const std::shared_ptr & p_connections, const TypeContainer & p_container, const phase_getter & p_getter) { double exp_amount = 0.0; double number_neighbors = 0.0; for (std::size_t i = 0; i < p_container.size(); i++) { double phase = p_getter(i); std::vector neighbors; p_connections->get_neighbors(i, neighbors); for (auto & index_neighbor : neighbors) { double phase_neighbor = p_getter(index_neighbor); exp_amount += std::exp( -std::abs( phase_neighbor - phase ) ); } number_neighbors += static_cast(neighbors.size()); } if (number_neighbors == 0.0) { number_neighbors = 1.0; } return exp_amount / number_neighbors; } sync_network::sync_network(const size_t size, const double weight_factor, const double frequency_factor, const connection_t connection_type, const initial_type initial_phases) { initialize(size, weight_factor, frequency_factor, connection_type, 0, 0, initial_phases); } sync_network::sync_network(const size_t size, const double weight_factor, const double frequency_factor, const connection_t connection_type, const size_t height, const size_t width, const initial_type initial_phases) { initialize(size, weight_factor, frequency_factor, connection_type, height, width, initial_phases); } sync_network::~sync_network() { } void sync_network::initialize(const std::size_t size, const double weight_factor, const double frequency_factor, const connection_t connection_type, const std::size_t height, const std::size_t width, const initial_type initial_phases) { m_oscillators = std::vector(size, sync_oscillator()); if (size > MAXIMUM_MATRIX_REPRESENTATION_SIZE) { m_connections = std::shared_ptr(new adjacency_bit_matrix(size)); } else { m_connections = std::shared_ptr(new adjacency_matrix(size)); } adjacency_connector connector; if ((height != 0) && (width != 0)) { connector.create_grid_structure(connection_type, width, height, *m_connections); } else { connector.create_structure(connection_type, *m_connections); } weight = weight_factor; m_equation = std::bind(&sync_network::phase_kuramoto_equation, this, _1, _2, _3, _4); std::random_device device; std::default_random_engine generator(device()); generator.seed(static_cast(std::chrono::system_clock::now().time_since_epoch().count())); std::uniform_real_distribution phase_distribution(0.0, 2.0 * pi); std::uniform_real_distribution frequency_distribution(0.0, 1.0); for (std::size_t index = 0; index < size; index++) { sync_oscillator & oscillator_context = m_oscillators[index]; switch (initial_phases) { case initial_type::RANDOM_GAUSSIAN: oscillator_context.phase = phase_distribution(generator); break; case initial_type::EQUIPARTITION: oscillator_context.phase = pi / static_cast(size) * static_cast(index); break; default: throw std::runtime_error("Unknown type of initialization"); } oscillator_context.frequency = frequency_distribution(generator) * frequency_factor; } } double sync_network::sync_order() const { return sync_ordering::calculate_sync_order(m_oscillators); } double sync_network::sync_local_order() const { return sync_ordering::calculate_local_sync_order(m_connections, m_oscillators); } void sync_network::set_equation(equation & solver) { m_equation = solver; } void sync_network::phase_kuramoto_equation(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const { outputs.resize(1); outputs[0] = phase_kuramoto(t, inputs[0], argv); } double sync_network::phase_kuramoto(const double t, const double teta, const std::vector & argv) const { std::size_t index = *(std::size_t *) argv[0]; double phase = 0.0; std::vector neighbors; m_connections->get_neighbors(index, neighbors); for (auto & index_neighbor : neighbors) { phase += std::sin(m_oscillators[index_neighbor].phase - teta); } phase = m_oscillators[index].frequency + (phase * weight / static_cast(size())); return phase; } void sync_network::simulate_static(const std::size_t steps, const double time, const solve_type solver, const bool collect_dynamic, sync_dynamic & output_dynamic) { output_dynamic.clear(); const double step = time / (double) steps; const double int_step = step / 10.0; store_dynamic(0.0, collect_dynamic, output_dynamic); /* store initial state */ double cur_time = step; for (std::size_t cur_step = 0; cur_step < steps; cur_step++) { calculate_phases(solver, cur_time, step, int_step); store_dynamic(cur_time, collect_dynamic, output_dynamic); cur_time += step; } } void sync_network::simulate_dynamic(const double order, const double step, const solve_type solver, const bool collect_dynamic, sync_dynamic & output_dynamic) { output_dynamic.clear(); store_dynamic(0, collect_dynamic, output_dynamic); /* store initial state */ double current_order = sync_local_order(); double integration_step = step / 10.0; for (double time_counter = step; current_order < order; time_counter += step) { calculate_phases(solver, time_counter, step, integration_step); store_dynamic(time_counter, collect_dynamic, output_dynamic); double previous_order = current_order; current_order = sync_local_order(); if (std::abs(current_order - previous_order) < 0.000001) { // std::cout << "Warning: sync_network::simulate_dynamic - simulation is aborted due to low level of convergence rate (order = " << current_order << ")." << std::endl; break; } } } void sync_network::store_dynamic(const double time, const bool collect_dynamic, sync_dynamic & output_dynamic) const { sync_network_state state(size()); for (std::size_t index = 0; index < size(); index++) { state.m_phase[index] = m_oscillators[index].phase; } state.m_time = time; if ( (collect_dynamic == false) && (!output_dynamic.empty()) ) { output_dynamic[0] = state; } else { output_dynamic.push_back(state); } } void sync_network::calculate_phases(const solve_type solver, const double t, const double step, const double int_step) { std::vector next_phases(size(), 0.0); parallel_for(std::size_t(0), size(), [this, solver, t, step, int_step, &next_phases](const std::size_t p_index) { calculate_phase(solver, t, step, int_step, p_index, next_phases); }); /* store result */ for (std::size_t index = 0; index < size(); index++) { m_oscillators[index].phase = next_phases[index]; } } void sync_network::calculate_phase(const solve_type solver, const double t, const double step, const double int_step, const std::size_t index, std::vector & p_next_phases) { std::size_t number_int_steps = (std::size_t) (step / int_step); std::vector argv(1, nullptr); argv[0] = (void *) &index; switch(solver) { case solve_type::FORWARD_EULER: { double result = m_oscillators[index].phase + phase_kuramoto(t, m_oscillators[index].phase, argv); p_next_phases[index] = phase_normalization(result); break; } case solve_type::RUNGE_KUTTA_4: { differ_state inputs(1, m_oscillators[index].phase); differ_result outputs; runge_kutta_4(m_equation, inputs, t, t + step, number_int_steps, false, argv, outputs); p_next_phases[index] = phase_normalization( outputs[0].state[0] ); break; } case solve_type::RUNGE_KUTTA_FEHLBERG_45: { differ_state inputs(1, m_oscillators[index].phase); differ_result outputs; runge_kutta_fehlberg_45(m_equation, inputs, t, t + step, 0.00001, false, argv, outputs); p_next_phases[index] = phase_normalization( outputs[0].state[0] ); break; } default: { throw std::runtime_error("Unknown type of solver"); } } } double sync_network::phase_normalization(const double teta) const { double norm_teta = teta; while ( (norm_teta > 2.0 * pi) || (norm_teta < 0.0) ) { if (norm_teta > 2.0 * pi) { norm_teta -= 2.0 * pi; } else { norm_teta += 2.0 * pi; } } return norm_teta; } void sync_dynamic::allocate_sync_ensembles(const double tolerance, const size_t iteration, ensemble_data & ensembles) const { ensembles.clear(); if (size() == 0) { return; } /* push back the first object to the first cluster */ ensembles.push_back(sync_ensemble()); ensembles[0].push_back(0); sync_dynamic::const_iterator last_state_dynamic = cbegin() + iteration; for (std::size_t i = 1; i < oscillators(); i++) { bool cluster_allocated = false; for (auto & cluster : ensembles) { for (auto & index : cluster) { double phase_first = (*last_state_dynamic).m_phase[i]; double phase_second = (*last_state_dynamic).m_phase[index]; double phase_shifted = std::abs((*last_state_dynamic).m_phase[i] - 2 * pi); if (((phase_first < (phase_second + tolerance)) && (phase_first >(phase_second - tolerance))) || ((phase_shifted < (phase_second + tolerance)) && (phase_shifted >(phase_second - tolerance)))) { cluster_allocated = true; cluster.push_back(i); break; } } if (cluster_allocated == true) { break; } } if (cluster_allocated == false) { sync_ensemble allocated_cluster; allocated_cluster.push_back(i); ensembles.push_back(allocated_cluster); } } } void sync_dynamic::allocate_sync_ensembles(const double tolerance, ensemble_data & ensembles) const { allocate_sync_ensembles(tolerance, size() - 1, ensembles); } void sync_dynamic::allocate_correlation_matrix(sync_corr_matrix & p_matrix) const { allocate_correlation_matrix(size() - 1, p_matrix); } void sync_dynamic::allocate_correlation_matrix(const size_t p_iteration, sync_corr_matrix & p_matrix) const { if ( (empty()) || (p_iteration >= size()) ) { return; } p_matrix.resize(oscillators(), sync_corr_row(oscillators(), 0.0)); for (size_t i = 0; i < oscillators(); i++) { for (size_t j = i + 1; j < oscillators(); j++) { const double phase1 = at(p_iteration).m_phase[i]; const double phase2 = at(p_iteration).m_phase[j]; p_matrix[i][j] = std::abs(std::sin(phase1 - phase2)); p_matrix[j][i] = p_matrix[i][j]; } } } void sync_dynamic::calculate_order_parameter(const std::size_t start_iteration, const std::size_t stop_iteration, std::vector & sequence_order) const { sequence_order.resize(stop_iteration - start_iteration, 0.0); for (std::size_t i = start_iteration; i < stop_iteration; i++) { const double order_value = sync_ordering::calculate_sync_order(at(i).m_phase); sequence_order[i - start_iteration] = order_value; } } void sync_dynamic::calculate_local_order_parameter(const std::shared_ptr & connections, const std::size_t start_iteration, const std::size_t stop_iteration, std::vector & sequence_local_order) const { sequence_local_order.resize(stop_iteration - start_iteration, 0.0); for (std::size_t i = start_iteration; i < stop_iteration; i++) { const double order_value = sync_ordering::calculate_local_sync_order(connections, at(i).m_phase); sequence_local_order[i - start_iteration] = order_value; } } } }pyclustering-0.10.1.2/ccore/src/nnet/syncpr.cpp000077500000000000000000000153041375753423500213550ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include using namespace std::placeholders; using namespace pyclustering::utils::math; using namespace pyclustering::utils::metric; namespace pyclustering { namespace nnet { syncpr_invalid_pattern::syncpr_invalid_pattern() : runtime_error("invalid pattern is used") { } syncpr_invalid_pattern::syncpr_invalid_pattern(const std::string & description) : runtime_error(description) { } syncpr::syncpr(const unsigned int num_osc, const double increase_strength1, const double increase_strength2) : sync_network(num_osc, 1, 0, connection_t::CONNECTION_ALL_TO_ALL, initial_type::RANDOM_GAUSSIAN), m_increase_strength1(increase_strength1), m_increase_strength2(increase_strength2), m_coupling(num_osc, std::vector(num_osc, 0.0)) { equation oscillator_equation = std::bind(&syncpr::phase_kuramoto_equation, this, _1, _2, _3, _4); set_equation(oscillator_equation); } syncpr::syncpr(const unsigned int num_osc, const size_t height, const size_t width, const double increase_strength1, const double increase_strength2) : sync_network(num_osc, 1, 0, connection_t::CONNECTION_ALL_TO_ALL, height, width, initial_type::RANDOM_GAUSSIAN), m_increase_strength1(increase_strength1), m_increase_strength2(increase_strength2), m_coupling(num_osc, std::vector(num_osc, 0.0)) { equation oscillator_equation = std::bind(&syncpr::phase_kuramoto_equation, this, _1, _2, _3, _4); set_equation(oscillator_equation); } void syncpr::train(const std::vector & patterns) { for (auto & pattern : patterns) { validate_pattern(pattern); } for (std::size_t i = 0; i < size(); i++) { for (std::size_t j = i + 1; j < size(); j++) { /* go through via all patterns */ for (std::size_t p = 0; p < patterns.size(); p++) { double value1 = patterns[p][i]; double value2 = patterns[p][j]; m_coupling[i][j] += value1 * value2; } m_coupling[i][j] /= (double) size(); m_coupling[j][i] = m_coupling[i][j]; } } } void syncpr::simulate_static(const unsigned int steps, const double time, const syncpr_pattern & input_pattern, const solve_type solver, const bool collect_dynamic, syncpr_dynamic & output_dynamic) { validate_pattern(input_pattern); initialize_phases(input_pattern); output_dynamic.clear(); const double step = time / (double) steps; const double int_step = step / 10.0; store_dynamic(0.0, collect_dynamic, output_dynamic); /* store initial state */ for (double cur_time = step; cur_time < (time + step); cur_time += step) { calculate_phases(solver, cur_time, step, int_step); store_dynamic(cur_time, collect_dynamic, output_dynamic); /* store initial state */ } } void syncpr::simulate_dynamic(const syncpr_pattern & input_pattern, const double order, const double step, const solve_type solver, const bool collect_dynamic, syncpr_dynamic & output_dynamic) { validate_pattern(input_pattern); initialize_phases(input_pattern); output_dynamic.clear(); double current_order = calculate_memory_order(input_pattern); double integration_step = step / 10; store_dynamic(0, collect_dynamic, output_dynamic); /* store initial state */ for (double time_counter = step; current_order < order; time_counter += step) { calculate_phases(solver, time_counter, step, integration_step); store_dynamic(time_counter, collect_dynamic, output_dynamic); double previous_order = current_order; current_order = calculate_memory_order(input_pattern); if (std::abs(current_order - previous_order) < 0.000001) { // std::cout << "Warning: sync_network::simulate_dynamic - simulation is aborted due to low level of convergence rate (order = " << current_order << ")." << std::endl; break; } } } void syncpr::initialize_phases(const syncpr_pattern & sample) { for (size_t i = 0; i < sample.size(); i++) { if (sample[i] > 0.0) { m_oscillators[i].phase = 0.0; } else { m_oscillators[i].phase = pi / 2.0; } } } double syncpr::memory_order(const syncpr_pattern & input_pattern) const { validate_pattern(input_pattern); return calculate_memory_order(input_pattern); } double syncpr::calculate_memory_order(const syncpr_pattern & input_pattern) const { std::complex order(0, 0); for (size_t i = 0; i < size(); i++) { order += std::complex(input_pattern[i], 0) * std::exp(std::complex(0, 1) * m_oscillators[i].phase); } order /= std::complex((double) size(), 0); return std::abs(order); } double syncpr::phase_kuramoto(const double t, const double teta, const std::vector & argv) const { size_t oscillator_index = *(unsigned int *)argv[0]; double phase = 0.0; double term = 0.0; for (size_t neighbor_index = 0; neighbor_index < size(); neighbor_index++) { if (oscillator_index != neighbor_index) { double phase_delta = m_oscillators[neighbor_index].phase - m_oscillators[oscillator_index].phase; phase += m_coupling[oscillator_index][neighbor_index] * std::sin(phase_delta); double term1 = m_increase_strength1 * std::sin(2.0 * phase_delta); double term2 = m_increase_strength2 * std::sin(3.0 * phase_delta); term += (term1 - term2); } } return ( phase + term / ((double) size()) ); } void syncpr::phase_kuramoto_equation(const double t, const differ_state & inputs, const differ_extra & argv, differ_state & outputs) const { outputs.resize(1); outputs[0] = phase_kuramoto(t, inputs[0], argv); } void syncpr::validate_pattern(const syncpr_pattern & sample) const { if (sample.size() != size()) { throw syncpr_invalid_pattern("invalid size of the pattern, it should be the same as network size"); } for (size_t i = 0; i < sample.size(); i++) { if ((sample[i] != 1) && (sample[i] != -1)) { throw syncpr_invalid_pattern("invalid value in the pattern, pattern value should be +1 or -1"); } } } } } pyclustering-0.10.1.2/ccore/src/parallel/000077500000000000000000000000001375753423500201555ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/parallel/spinlock.cpp000077500000000000000000000010321375753423500225020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace parallel { bool spinlock::try_lock() { return !m_lock.test_and_set(std::memory_order_acquire); } void spinlock::lock() { for(std::size_t i = 0; !try_lock(); i++) { if (i % 100) { std::this_thread::yield(); } } } void spinlock::unlock() { m_lock.clear(std::memory_order_release); } } }pyclustering-0.10.1.2/ccore/src/parallel/task.cpp000077500000000000000000000007271375753423500216340ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace parallel { task::task(const proc & p_task) : m_task(p_task) { m_ready.lock(); } void task::set_ready() { m_ready.unlock(); } void task::wait_ready() const { m_ready.lock(); } void task::operator()() { m_task(); } } } pyclustering-0.10.1.2/ccore/src/parallel/thread_executor.cpp000077500000000000000000000014641375753423500240560ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace parallel { thread_executor::thread_executor(const task_getter & p_getter) : m_stop(false), m_getter(p_getter), m_executor(&thread_executor::run, this) { } void thread_executor::run() { while(!m_stop) { task::ptr task = nullptr; m_getter(task); if (task) { (*task)(); task->set_ready(); } else { m_stop = true; } } } void thread_executor::stop() { m_stop = true; if (m_executor.joinable()) { m_executor.join(); } } } } pyclustering-0.10.1.2/ccore/src/parallel/thread_pool.cpp000077500000000000000000000052641375753423500231730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace parallel { const std::size_t thread_pool::DEFAULT_AMOUNT_THREADS = 4; const std::size_t thread_pool::DEFAULT_POOL_SIZE = (std::thread::hardware_concurrency() > 1) ? std::thread::hardware_concurrency() : DEFAULT_AMOUNT_THREADS; thread_pool::thread_pool() { initialize(DEFAULT_POOL_SIZE); } thread_pool::thread_pool(const std::size_t p_size) { initialize(p_size); } thread_pool::~thread_pool() { { std::lock_guard lock_common(m_common_mutex); m_stop = true; } m_queue_not_empty_cond.notify_all(); for (auto executor : m_pool) { executor->stop(); } } task::ptr thread_pool::add_task(const task::proc & p_raw_task) { task::ptr client_task = std::make_shared(p_raw_task); { std::lock_guard lock_common(m_common_mutex); m_queue.push_back(client_task); } m_queue_not_empty_cond.notify_one(); return client_task; } task::ptr thread_pool::add_task_if_free(const task::proc & p_raw_task) { task::ptr client_task = nullptr; { std::lock_guard lock_common(m_common_mutex); if (m_reserve > 0) { client_task = std::make_shared(p_raw_task); m_queue.push_back(client_task); m_queue_not_empty_cond.notify_one(); m_reserve--; } } return client_task; } std::size_t thread_pool::size() const { return m_pool.size(); } void thread_pool::initialize(const std::size_t p_size) { m_pool = { }; m_queue = { }; m_stop = false; thread_executor::task_getter getter = std::bind(&thread_pool::get_task, this, std::placeholders::_1); for (std::size_t index = 0; index < p_size; index++) { m_pool.emplace_back(std::make_shared(getter)); } m_reserve = m_free = p_size; } void thread_pool::get_task(task::ptr & p_task) { std::unique_lock lock_common(m_common_mutex); p_task = nullptr; m_reserve++; m_free++; while(m_queue.empty() && !m_stop) { m_queue_not_empty_cond.wait(lock_common, [this]{ return !m_queue.empty() || m_stop; }); } if (!m_queue.empty()) { p_task = m_queue.front(); m_queue.pop_front(); if (m_reserve == m_free) { m_reserve--; } m_free--; } } } } pyclustering-0.10.1.2/ccore/src/pyclustering-shared.vcxproj000077500000000000000000000334071375753423500240040ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {A1F1A829-2678-40A6-AF79-87E58AC4BADB} pyclusteringshared 8.1 DynamicLibrary true v140 Unicode DynamicLibrary false v140 true Unicode DynamicLibrary true v140 Unicode DynamicLibrary false v140 true Unicode .dll pyclustering $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ false .dll pyclustering $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ false .dll pyclustering false $(Platform)\$(Configuration)\$(ProjectName)\ .dll pyclustering false $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true $(SolutionDir)include true true EXPORT_PYCLUSTERING_INTERFACE;%(PreprocessorDefinitions) false false pyclustering-static.lib $(OutDir) true Level3 Disabled true $(SolutionDir)include true true EXPORT_PYCLUSTERING_INTERFACE;%(PreprocessorDefinitions) false false pyclustering-static.lib $(OutDir) true Level3 MaxSpeed true true true $(SolutionDir)include true true EXPORT_PYCLUSTERING_INTERFACE;%(PreprocessorDefinitions) false true true false pyclustering-static.lib $(OutDir) true copy "$(TargetPath)" "..\..\pyclustering\core\32-bit\win\$(TargetName)$(TargetExt)" /y Level3 MaxSpeed true true true $(SolutionDir)include true true EXPORT_PYCLUSTERING_INTERFACE;%(PreprocessorDefinitions) false true true false pyclustering-static.lib $(OutDir) true copy "$(TargetPath)" "..\..\pyclustering\core\64-bit\win\$(TargetName)$(TargetExt)" /y pyclustering-0.10.1.2/ccore/src/pyclustering-shared.vcxproj.filters000077500000000000000000000206121375753423500254450ustar00rootroot00000000000000 {7cfd5dab-6355-4ac4-8dd7-d60764b157f9} {e28ad693-aec7-4da1-bf80-016766c26014} {00b3f3cc-00fc-4637-b4d7-74e636a236d3} {a8612c05-7bda-47cb-ba97-75f8aaff1679} Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Header Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface Source Files\interface pyclustering-0.10.1.2/ccore/src/pyclustering-static.vcxproj000077500000000000000000000427031375753423500240240ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {4B72A338-F4CC-4CBB-89B0-B31DF3C076C2} pyclusteringstatic 8.1 StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(ProjectName) .lib $(ProjectName) .lib $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(ProjectName) $(ProjectName) $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true $(SolutionDir)include true MultiThreadedDebugDLL false false true true Level3 Disabled true $(SolutionDir)include true MultiThreadedDebugDLL false false true true Level3 MaxSpeed true true true true true %(PreprocessorDefinitions) false $(SolutionDir)include MultiThreadedDLL true true true Level3 MaxSpeed true true true true true %(PreprocessorDefinitions) MultiThreadedDLL false $(SolutionDir)include true true true pyclustering-0.10.1.2/ccore/src/pyclustering-static.vcxproj.filters000077500000000000000000000470361375753423500254770ustar00rootroot00000000000000 {27a9777f-d548-4f76-8529-960e00c5c612} {656fa00d-a810-4249-a2dc-91dcaa506ae0} {e74ddeed-208b-4af4-a99e-05b5c5d6c1f8} {24cdfa26-f5f7-4e13-8d67-04ed66b2b202} {d9188b45-3da8-41bc-a0d1-3a9f8d7f0f5a} {d6976e8c-8206-4a67-bc3a-55497f9923bf} {78477d0b-3b49-4c9e-961f-d6cd1b332287} {4ab057bd-88f1-4c2d-a98c-8663c1896b70} {40dcd61f-59ff-429a-91d1-1d9417b63c21} {44d0df1f-3fd6-40ac-bbc1-8976c39fe667} {e12524b6-94f0-46ae-b811-560dc99f31dc} {bf9c6ade-57a9-4254-b21b-61213fec0e47} {9f76cd55-ba93-4801-9312-19f3eb8009b6} {3822bba0-e57c-4699-976f-0a319bcee35f} Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\cluster Source Files\container Source Files\container Source Files\container Source Files\container Source Files\container Source Files\container Source Files\container Source Files\container Source Files\container Source Files\container Source Files\differential Source Files\nnet Source Files\nnet Source Files\nnet Source Files\nnet Source Files\nnet Source Files\nnet Source Files\nnet Source Files\parallel Source Files\parallel Source Files\parallel Source Files\parallel Source Files\utils Source Files\utils Source Files\utils Source Files\utils Source Files\utils Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\cluster Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\container Header Files\differential Header Files\differential Header Files\differential Header Files\differential Header Files\differential Header Files\differential Header Files\utils Header Files\utils Header Files\utils Header Files\utils Header Files\utils Header Files\utils Header Files\utils Header Files\parallel Header Files\parallel Header Files\parallel Header Files\parallel Header Files\parallel Header Files\nnet Header Files\nnet Header Files\nnet Header Files\nnet Header Files\nnet Header Files\nnet Header Files\nnet Header Files\nnet pyclustering-0.10.1.2/ccore/src/utils/000077500000000000000000000000001375753423500175215ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/src/utils/linalg.cpp000077500000000000000000000071061375753423500215020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include namespace pyclustering { namespace utils { namespace linalg { static sequence action_for_each_component(const sequence & a, const sequence & b, const std::function && func) { if (a.size() != b.size()) { throw std::invalid_argument("Both vectors should have the same size."); } sequence result(a.size(), 0.0); for (std::size_t i = 0; i < result.size(); i++) { result[i] = func(a[i], b[i]); } return result; } static sequence action_for_each_component(const sequence & a, const double b, const std::function && func) { sequence result(a.size(), 0.0); for (std::size_t i = 0; i < result.size(); i++) { result[i] = func(a[i], b); } return result; } sequence subtract(const sequence & a, const sequence & b) { return action_for_each_component(a, b, [](double v1, double v2) { return v1 - v2; }); } sequence subtract(const sequence & a, const double b) { return action_for_each_component(a, b, [](double v1, double v2) { return v1 - v2; }); } sequence multiply(const sequence & a, const sequence & b) { return action_for_each_component(a, b, [](double v1, double v2) { return v1 * v2; }); } sequence multiply(const sequence & a, const double b) { return action_for_each_component(a, b, [](double v1, double v2) { return v1 * v2; }); } matrix multiply(const matrix & a, const sequence & b) { if (a.empty()) { throw std::invalid_argument("Matrix is empty."); } if (a.begin()->size() != b.size()) { std::stringstream stream; stream << "Matrix vector (" << a.begin()->size() << ") and vector (" << b.size() << ") should have the same size."; throw std::invalid_argument(stream.str()); } matrix result; result.reserve(a.size()); for (const auto & v : a) { result.push_back(action_for_each_component(v, b, [](double v1, double v2) { return v1 * v2; })); } return result; } sequence divide(const sequence & a, const sequence & b) { return action_for_each_component(a, b, [](double v1, double v2) { return v1 / v2; }); } sequence divide(const sequence & a, const double b) { return action_for_each_component(a, b, [](double v1, double v2) { return v1 / v2; }); } double sum(const sequence & a) { return std::accumulate(std::begin(a), std::end(a), 0.0); } sequence sum(const matrix & a, std::size_t axis) { if (a.empty()) { throw std::invalid_argument("Matrix is empty."); } if (axis == 0) { sequence result(a.begin()->size(), 0.0); for (std::size_t col = 0; col < a.begin()->size(); col++) { for (std::size_t row = 0; row < a.size(); row++) { result[col] += a[row][col]; } } return result; } else if (axis == 1) { sequence result(a.size(), 0.0); for (std::size_t row = 0; row < a.size(); row++) { result[row] = std::move(sum(a[row])); } return result; } else { throw std::invalid_argument("Axis is out of matrix's dimension."); } } } } }pyclustering-0.10.1.2/ccore/src/utils/math.cpp000077500000000000000000000005241375753423500211620ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace utils { namespace math { double heaviside(const double value) { if (value >= 0.0) { return 1.0; } return 0.0; } } } }pyclustering-0.10.1.2/ccore/src/utils/metric.cpp000077500000000000000000000022241375753423500215130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include namespace pyclustering { namespace utils { namespace metric { double average_neighbor_distance(const std::vector > * points, const std::size_t num_neigh) { std::vector > dist_matrix( points->size(), std::vector(points->size(), 0.0) ); for (std::size_t i = 0; i < points->size(); i++) { for (std::size_t j = i + 1; j < points->size(); j++) { double distance = euclidean_distance( (*points)[i], (*points)[j] ); dist_matrix[i][j] = distance; dist_matrix[j][i] = distance; } std::sort(dist_matrix[i].begin(), dist_matrix[i].end()); } double total_distance = 0.0; for (std::size_t i = 0; i < points->size(); i++) { for (std::size_t j = 0; j < num_neigh; j++) { total_distance += dist_matrix[i][j + 1]; } } return total_distance / ( (double) num_neigh * (double) points->size() ); } } } } pyclustering-0.10.1.2/ccore/src/utils/random.cpp000077500000000000000000000011431375753423500215070ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include namespace pyclustering { namespace utils { namespace random { double generate_uniform_random(const double p_from, const double p_to) { unsigned seed = (unsigned) std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); std::uniform_real_distribution distribution(p_from, p_to); return distribution(generator); } } } }pyclustering-0.10.1.2/ccore/src/utils/stats.cpp000077500000000000000000000010771375753423500213730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include namespace pyclustering { namespace utils { namespace stats { std::vector critical_values(const std::size_t p_data_size) { std::vector result = { 0.576, 0.656, 0.787, 0.918, 1.092 }; const double size = static_cast(p_data_size); for (auto & value : result) { value /= (1.0 + 4.0 / size - 25.0 / size / size); } return result; } } } }pyclustering-0.10.1.2/ccore/tst/000077500000000000000000000000001375753423500164045ustar00rootroot00000000000000pyclustering-0.10.1.2/ccore/tst/CMakeLists.txt000077500000000000000000000013101375753423500211420ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # cmake_minimum_required(VERSION 3.10) # C++ standard set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED True) # Sources file(GLOB_RECURSE UT_SOURCES "*.cpp") # Header folders include_directories(${PROJECT_SOURCE_DIR}/include) include_directories(${PROJECT_SOURCE_DIR}/external/include) # Library folders link_directories(${PROJECT_SOURCE_DIR}/build) # Build targets add_executable(utcore ${UT_SOURCES}) # Dependecies add_dependencies(utcore pyclustering-static) add_dependencies(utcore gtest) target_link_libraries(utcore PUBLIC pyclustering-static) target_link_libraries(utcore PUBLIC gtest) pyclustering-0.10.1.2/ccore/tst/answer.hpp000077500000000000000000000014751375753423500204260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include using cluster = std::vector; using cluster_sequence = std::vector; using length_sequence = std::vector; class answer { private: cluster_sequence m_clusters; length_sequence m_cluster_lengths; cluster m_noise; public: const cluster_sequence & clusters() const { return m_clusters; } cluster_sequence & clusters() { return m_clusters; } const length_sequence & cluster_lengths() const { return m_cluster_lengths; } length_sequence & cluster_lengths() { return m_cluster_lengths; } const cluster & noise() const { return m_noise; } cluster & noise() { return m_noise; } };pyclustering-0.10.1.2/ccore/tst/answer_reader.cpp000077500000000000000000000053551375753423500217440ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include "answer_reader.hpp" #include #include #if defined _WIN32 || defined __CYGWIN__ #define separator std::string("\\") #else #define separator std::string("/") #endif const std::string answer_reader::PATH_SIMPLE_ANSWER_FOLDER = ".." + separator + ".." + separator + "pyclustering" + separator + "samples" + separator + "samples" + separator + "simple" + separator; const std::map answer_reader::SIMPLE_ANSWER_MAP = { { SAMPLE_SIMPLE::SAMPLE_SIMPLE_01, PATH_SIMPLE_ANSWER_FOLDER + "Simple01.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_02, PATH_SIMPLE_ANSWER_FOLDER + "Simple02.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_03, PATH_SIMPLE_ANSWER_FOLDER + "Simple03.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_04, PATH_SIMPLE_ANSWER_FOLDER + "Simple04.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_05, PATH_SIMPLE_ANSWER_FOLDER + "Simple05.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_06, PATH_SIMPLE_ANSWER_FOLDER + "Simple06.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_07, PATH_SIMPLE_ANSWER_FOLDER + "Simple07.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_08, PATH_SIMPLE_ANSWER_FOLDER + "Simple08.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_09, PATH_SIMPLE_ANSWER_FOLDER + "Simple09.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_10, PATH_SIMPLE_ANSWER_FOLDER + "Simple10.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_11, PATH_SIMPLE_ANSWER_FOLDER + "Simple11.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_12, PATH_SIMPLE_ANSWER_FOLDER + "Simple12.answer" }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_13, PATH_SIMPLE_ANSWER_FOLDER + "Simple13.answer" } }; answer answer_reader::read(const std::string & p_path) { answer result; std::ifstream file_stream(p_path); std::string line; std::size_t index_point = 0; while(std::getline(file_stream, line)) { if (line[0] == 'n') { result.noise().push_back(index_point); index_point++; continue; } std::size_t index_cluster = std::stoul(line); if (index_cluster >= result.clusters().size()) { result.clusters().push_back({ index_point }); } else { result.clusters().at(index_cluster).push_back(index_point); } index_point++; } file_stream.close(); for (auto & current_cluster : result.clusters()) { result.cluster_lengths().push_back(current_cluster.size()); } return result; } answer answer_reader::read(const SAMPLE_SIMPLE p_sample) { return read(SIMPLE_ANSWER_MAP.at(p_sample)); } pyclustering-0.10.1.2/ccore/tst/answer_reader.hpp000077500000000000000000000007471375753423500217510ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include "answer.hpp" #include "samples.hpp" #include class answer_reader { private: const static std::string PATH_SIMPLE_ANSWER_FOLDER; const static std::map SIMPLE_ANSWER_MAP; public: static answer read(const std::string & p_path); static answer read(const SAMPLE_SIMPLE p_sample); }; pyclustering-0.10.1.2/ccore/tst/gtest.vcxproj000077500000000000000000000156441375753423500211640ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {40A75591-4C3C-466F-BCED-6CFEDABD4938} gtest 8.1 StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode StaticLibrary true v140 Unicode StaticLibrary false v140 true Unicode $(SolutionDir)$(Platform)\$(Configuration)\ $(ProjectName) $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(ProjectName) $(Platform)\$(Configuration)\$(ProjectName)\ $(ProjectName) $(Platform)\$(Configuration)\$(ProjectName)\ $(ProjectName) $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true $(SolutionDir)external\include\ Level3 Disabled true $(SolutionDir)external\include\ Level3 MaxSpeed true true true $(SolutionDir)external\include\ true true Level3 MaxSpeed true true true $(SolutionDir)external\include\ true true pyclustering-0.10.1.2/ccore/tst/gtest.vcxproj.filters000077500000000000000000000007121375753423500226210ustar00rootroot00000000000000 {6487e715-7646-4435-a4e5-6ee47e64def6} Source Files pyclustering-0.10.1.2/ccore/tst/main.cpp000077500000000000000000000003531375753423500200400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } pyclustering-0.10.1.2/ccore/tst/samples.cpp000077500000000000000000000215531375753423500205650ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include "samples.hpp" #include #include #include #include #include #if defined _WIN32 || defined __CYGWIN__ #define separator std::string("\\") #else #define separator std::string("/") #endif const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_FOLDER = ".." + separator + ".." + separator + "pyclustering" + separator + "samples" + separator + "samples" + separator + "simple" + separator; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_01 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple01.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_02 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple02.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_03 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple03.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_04 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple04.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_05 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple05.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_06 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple06.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_07 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple07.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_08 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple08.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_09 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple09.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_10 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple10.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_11 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple11.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_12 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple12.data"; const std::string simple_sample_factory::PATH_SAMPLE_SIMPLE_13 = PATH_SAMPLE_SIMPLE_FOLDER + "Simple13.data"; const simple_sample_factory::map_sample simple_sample_factory::m_sample_table = { { SAMPLE_SIMPLE::SAMPLE_SIMPLE_01, simple_sample_factory::PATH_SAMPLE_SIMPLE_01 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_02, simple_sample_factory::PATH_SAMPLE_SIMPLE_02 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_03, simple_sample_factory::PATH_SAMPLE_SIMPLE_03 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_04, simple_sample_factory::PATH_SAMPLE_SIMPLE_04 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_05, simple_sample_factory::PATH_SAMPLE_SIMPLE_05 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_06, simple_sample_factory::PATH_SAMPLE_SIMPLE_06 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_07, simple_sample_factory::PATH_SAMPLE_SIMPLE_07 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_08, simple_sample_factory::PATH_SAMPLE_SIMPLE_08 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_09, simple_sample_factory::PATH_SAMPLE_SIMPLE_09 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_10, simple_sample_factory::PATH_SAMPLE_SIMPLE_10 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_11, simple_sample_factory::PATH_SAMPLE_SIMPLE_11 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_12, simple_sample_factory::PATH_SAMPLE_SIMPLE_12 }, { SAMPLE_SIMPLE::SAMPLE_SIMPLE_13, simple_sample_factory::PATH_SAMPLE_SIMPLE_13 } }; const std::string fcps_sample_factory::PATH_FCPS_SAMPLE_FOLDER = ".." + separator + ".." + separator + "pyclustering" + separator + "samples" + separator + "samples" + separator + "fcps" + separator; const std::string fcps_sample_factory::PATH_SAMPLE_ATOM = PATH_FCPS_SAMPLE_FOLDER + "Atom.data"; const std::string fcps_sample_factory::PATH_SAMPLE_CHAINLINK = PATH_FCPS_SAMPLE_FOLDER + "Chainlink.data"; const std::string fcps_sample_factory::PATH_SAMPLE_ENGY_TIME = PATH_FCPS_SAMPLE_FOLDER + "EngyTime.data"; const std::string fcps_sample_factory::PATH_SAMPLE_GOLF_BALL = PATH_FCPS_SAMPLE_FOLDER + "GolfBall.data"; const std::string fcps_sample_factory::PATH_SAMPLE_HEPTA = PATH_FCPS_SAMPLE_FOLDER + "Hepta.data"; const std::string fcps_sample_factory::PATH_SAMPLE_LSUN = PATH_FCPS_SAMPLE_FOLDER + "Lsun.data"; const std::string fcps_sample_factory::PATH_SAMPLE_TARGET = PATH_FCPS_SAMPLE_FOLDER + "Target.data"; const std::string fcps_sample_factory::PATH_SAMPLE_TETRA = PATH_FCPS_SAMPLE_FOLDER + "Tetra.data"; const std::string fcps_sample_factory::PATH_SAMPLE_TWO_DIAMONDS = PATH_FCPS_SAMPLE_FOLDER + "TwoDiamonds.data"; const std::string fcps_sample_factory::PATH_SAMPLE_WING_NUT = PATH_FCPS_SAMPLE_FOLDER + "WingNut.data"; const fcps_sample_factory::map_sample fcps_sample_factory::m_sample_table = { { FCPS_SAMPLE::ATOM, fcps_sample_factory::PATH_SAMPLE_ATOM }, { FCPS_SAMPLE::CHAINLINK, fcps_sample_factory::PATH_SAMPLE_CHAINLINK }, { FCPS_SAMPLE::ENGY_TIME, fcps_sample_factory::PATH_SAMPLE_ENGY_TIME }, { FCPS_SAMPLE::GOLF_BALL, fcps_sample_factory::PATH_SAMPLE_GOLF_BALL }, { FCPS_SAMPLE::HEPTA, fcps_sample_factory::PATH_SAMPLE_HEPTA }, { FCPS_SAMPLE::LSUN, fcps_sample_factory::PATH_SAMPLE_LSUN }, { FCPS_SAMPLE::TARGET, fcps_sample_factory::PATH_SAMPLE_TARGET }, { FCPS_SAMPLE::TETRA, fcps_sample_factory::PATH_SAMPLE_TETRA }, { FCPS_SAMPLE::TWO_DIAMONDS, fcps_sample_factory::PATH_SAMPLE_TWO_DIAMONDS }, { FCPS_SAMPLE::WING_NUT, fcps_sample_factory::PATH_SAMPLE_WING_NUT } }; const std::string famous_sample_factory::PATH_FAMOUS_SAMPLE_FOLDER = ".." + separator + ".." + separator + "pyclustering" + separator + "samples" + separator + "samples" + separator + "famous" + separator; const std::string famous_sample_factory::PATH_OLD_FAITHFUL = PATH_FAMOUS_SAMPLE_FOLDER + "OldFaithful.data"; const std::string famous_sample_factory::PATH_IRIS = PATH_FAMOUS_SAMPLE_FOLDER + "Iris.data"; const famous_sample_factory::map_sample famous_sample_factory::m_sample_table = { { FAMOUS_SAMPLE::OLD_FAITHFUL, famous_sample_factory::PATH_OLD_FAITHFUL }, { FAMOUS_SAMPLE::SAMPLE_IRIS, famous_sample_factory::PATH_IRIS } }; std::shared_ptr generic_sample_factory::create_sample(const std::string & path_sample) { std::shared_ptr sample_data(new dataset); size_t sample_dimension = 0; std::ifstream file_sample(path_sample); if (file_sample.is_open()) { std::string file_line; while(std::getline(file_sample, file_line)) { if (file_line.empty()) continue; double value = 0.0; point sample_point; std::istringstream stream_value(file_line); while(stream_value >> value) { sample_point.push_back(value); } if (sample_dimension == 0) { sample_dimension = sample_point.size(); } else { if (sample_dimension != sample_point.size()) { throw std::runtime_error("Points from input data set should have the same dimension."); } } sample_data->push_back(sample_point); } } return sample_data; } std::shared_ptr simple_sample_factory::create_sample(const SAMPLE_SIMPLE p_sample, const bool p_random_order) { const std::string path_sample = m_sample_table.at(p_sample); auto points = generic_sample_factory::create_sample(path_sample); if (p_random_order) { std::random_device device; std::mt19937 generator(device()); std::shuffle(points->begin(), points->end(), generator); } return points; } std::shared_ptr simple_sample_factory::create_random_sample(const std::size_t p_cluster_size, const std::size_t p_clusters) { std::shared_ptr sample_data(new dataset); std::random_device device; std::mt19937 generator(device()); for (std::size_t index_cluster = 0; index_cluster < p_clusters; index_cluster++) { for (std::size_t index_point = 0; index_point < p_cluster_size; index_point++) { sample_data->push_back({ std::generate_canonical(generator) + index_point * 5, std::generate_canonical(generator) + index_point * 5 }); } } return sample_data; } std::shared_ptr fcps_sample_factory::create_sample(const FCPS_SAMPLE sample) { const std::string path_sample = m_sample_table.at(sample); return generic_sample_factory::create_sample(path_sample); } std::shared_ptr famous_sample_factory::create_sample(const FAMOUS_SAMPLE sample) { const std::string path_sample = m_sample_table.at(sample); return generic_sample_factory::create_sample(path_sample); }pyclustering-0.10.1.2/ccore/tst/samples.hpp000077500000000000000000000120641375753423500205670ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include using namespace pyclustering; class generic_sample_factory { public: /** * * @brief Creates sample for cluster analysis. * * @param[in] sample: sample that should be created. * * @return Smart pointer to created dataset. * */ static std::shared_ptr create_sample(const std::string & path_sample); }; /** * * @brief Samples from set SIMPLE SAMPLE that is used for easy testing of clustering algorithms. * */ enum class SAMPLE_SIMPLE { SAMPLE_SIMPLE_01, SAMPLE_SIMPLE_02, SAMPLE_SIMPLE_03, SAMPLE_SIMPLE_04, SAMPLE_SIMPLE_05, SAMPLE_SIMPLE_06, SAMPLE_SIMPLE_07, SAMPLE_SIMPLE_08, SAMPLE_SIMPLE_09, SAMPLE_SIMPLE_10, SAMPLE_SIMPLE_11, SAMPLE_SIMPLE_12, SAMPLE_SIMPLE_13 }; /** * * @brief Factory of samples from SIMPLE SAMPLE set. * */ class simple_sample_factory { private: typedef std::map map_sample; private: const static map_sample m_sample_table; private: const static std::string PATH_SAMPLE_SIMPLE_FOLDER; const static std::string PATH_SAMPLE_SIMPLE_01; const static std::string PATH_SAMPLE_SIMPLE_02; const static std::string PATH_SAMPLE_SIMPLE_03; const static std::string PATH_SAMPLE_SIMPLE_04; const static std::string PATH_SAMPLE_SIMPLE_05; const static std::string PATH_SAMPLE_SIMPLE_06; const static std::string PATH_SAMPLE_SIMPLE_07; const static std::string PATH_SAMPLE_SIMPLE_08; const static std::string PATH_SAMPLE_SIMPLE_09; const static std::string PATH_SAMPLE_SIMPLE_10; const static std::string PATH_SAMPLE_SIMPLE_11; const static std::string PATH_SAMPLE_SIMPLE_12; const static std::string PATH_SAMPLE_SIMPLE_13; public: /** * * @brief Creates sample for cluster analysis. * * @param[in] p_sample: sample that should be created. * @param[in] p_random_order: rearrange randomly data sample. * * @return Smart pointer to created dataset. * */ static std::shared_ptr create_sample(const SAMPLE_SIMPLE p_sample, const bool p_random_order = false); /** * * @brief Creates random (uniform distribution) sample for cluster analysis. * * @param[in] p_cluster_size: size of each cluster in dataset. * @param[in] p_clusters: amount of clusters in dataset. * * @return Smart pointer to created dataset. * */ static std::shared_ptr create_random_sample(const std::size_t p_cluster_size, const std::size_t p_clusters); }; /** * * @brief Samples from set FCPS that is used for functional testing of clustering algorithms. * */ enum class FCPS_SAMPLE { ATOM, CHAINLINK, ENGY_TIME, GOLF_BALL, HEPTA, LSUN, TARGET, TETRA, TWO_DIAMONDS, WING_NUT }; /** * * @brief Factory of samples from SIMPLE SAMPLE set. * */ class fcps_sample_factory { private: typedef std::map map_sample; private: const static map_sample m_sample_table; private: const static std::string PATH_FCPS_SAMPLE_FOLDER; const static std::string PATH_SAMPLE_ATOM; const static std::string PATH_SAMPLE_CHAINLINK; const static std::string PATH_SAMPLE_ENGY_TIME; const static std::string PATH_SAMPLE_GOLF_BALL; const static std::string PATH_SAMPLE_HEPTA; const static std::string PATH_SAMPLE_LSUN; const static std::string PATH_SAMPLE_TARGET; const static std::string PATH_SAMPLE_TETRA; const static std::string PATH_SAMPLE_TWO_DIAMONDS; const static std::string PATH_SAMPLE_WING_NUT; public: /** * * @brief Creates sample for cluster analysis. * * @param[in] sample: sample that should be created. * * @return Smart pointer to created dataset. * */ static std::shared_ptr create_sample(const FCPS_SAMPLE sample); }; /** * * @brief Samples from set FAMOUS that is used for functional testing of clustering algorithms. * */ enum class FAMOUS_SAMPLE { OLD_FAITHFUL, SAMPLE_IRIS }; /** * * @brief Factory of samples from FAMOUS SAMPLE set. * */ class famous_sample_factory { private: typedef std::map map_sample; private: const static map_sample m_sample_table; private: const static std::string PATH_FAMOUS_SAMPLE_FOLDER; const static std::string PATH_OLD_FAITHFUL; const static std::string PATH_IRIS; public: /** * * @brief Creates sample for cluster analysis. * * @param[in] sample: sample that should be created. * * @return Smart pointer to created dataset. * */ static std::shared_ptr create_sample(const FAMOUS_SAMPLE sample); }; pyclustering-0.10.1.2/ccore/tst/ut-runner.py000077500000000000000000000056311375753423500207250ustar00rootroot00000000000000import argparse import enum import logging import os.path import re import signal import subprocess class EExitCode(enum.IntEnum): success = 0, executable_not_found = -1 failure_tests_not_found = -2 class Runner: def __init__(self, executable, attempts=1): self.__executable = executable self.__attempts = attempts self.__exit_code = EExitCode.success def run(self): if os.path.isfile(self.__executable): result = subprocess.run(self.__executable, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = result.stdout.decode('utf-8') print(output) exit_code = result.returncode if exit_code == EExitCode.success: exit(exit_code) elif exit_code == -signal.SIGSEGV: logging.error("Segmentation fault signal is received during unit-testing process.") exit(exit_code) for _ in range(self.__attempts): exit_code, output = self.__rerun(output) if exit_code == EExitCode.success: exit(exit_code) elif exit_code == EExitCode.failure_tests_not_found: logging.error("There is nothing to rerun - failure tests are not found despite failure code '" + str(result.returncode) + "'.") exit(exit_code) else: logging.error("Impossible to find executable file '%s'." % self.__executable) exit(EExitCode.executable_not_found) def __rerun(self, output): failures = Runner.__get_failures(output) if len(failures) == 0: return EExitCode.failure_tests_not_found, None logging.info("Rerun failed tests: '%s'" % failures) argument = "--gtest_filter=" for fail in failures: argument += ":" + fail result = subprocess.run([self.__executable, argument], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) output = result.stdout.decode('utf-8') print(output) return result.returncode, output @staticmethod def __get_failures(output): failures = set() lines = output.splitlines() expression_failure = re.compile("\[\s+FAILED\s+\] (\S+)\.(\S+)") for line in lines: result = expression_failure.match(line) if result is not None: suite = result.group(1) test = result.group(2) failures.add("%s.%s" % (suite, test)) return failures parser = argparse.ArgumentParser() parser.add_argument('-e', '--executable', required=True, type=str, help='Execution object to run.') arguments = parser.parse_args() executable = arguments.executable logging.basicConfig(level=logging.INFO) Runner("./" + arguments.executable).run() pyclustering-0.10.1.2/ccore/tst/ut-shared.vcxproj000077500000000000000000000246351375753423500217320ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {5658C777-AC3B-4FF3-B009-DF9C9DB035A4} utshared 8.1 Application true v140 MultiByte Application false v140 true MultiByte Application true v140 MultiByte Application false v140 true MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true $(SolutionDir)include;$(SolutionDir)external\include true $(OutDir) gtest.lib;pyclustering.lib;pyclustering-static.lib Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y; copy "$(OutDir)pyclustering.dll" "..\tst\pyclustering.dll" /y; Level3 Disabled true $(SolutionDir)include;$(SolutionDir)external\include true $(OutDir) gtest.lib;pyclustering.lib;pyclustering-static.lib Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y; copy "$(OutDir)pyclustering.dll" "..\tst\pyclustering.dll" /y; Level3 MaxSpeed true true true $(SolutionDir)include;$(SolutionDir)external\include true true true $(OutDir) gtest.lib;pyclustering.lib;pyclustering-static.lib Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y; copy "$(OutDir)pyclustering.dll" "..\tst\pyclustering.dll" /y; Level3 MaxSpeed true true true $(SolutionDir)include;$(SolutionDir)external\include true true true $(OutDir) gtest.lib;pyclustering.lib;pyclustering-static.lib Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y; copy "$(OutDir)pyclustering.dll" "..\tst\pyclustering.dll" /y; pyclustering-0.10.1.2/ccore/tst/ut-shared.vcxproj.filters000077500000000000000000000072671375753423500234030ustar00rootroot00000000000000 {bc6f8e41-938f-41a8-a51c-367eec96ba87} {5a1b9e4c-a61b-4acf-9e99-190af45278dc} Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Utils Utils Utils Utils Utils pyclustering-0.10.1.2/ccore/tst/ut-static.vcxproj000077500000000000000000000275421375753423500217530ustar00rootroot00000000000000 Debug Win32 Release Win32 Debug x64 Release x64 {5ADB0D1D-CE04-4FC8-9C5A-116CA3694D00} utstatic 8.1 Application true v140 MultiByte Application false v140 true MultiByte Application true v140 MultiByte Application false v140 true MultiByte $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration)\$(ProjectName)\ $(Platform)\$(Configuration)\$(ProjectName)\ Level3 Disabled true $(SolutionDir)include;$(SolutionDir)external\include true true false gtest.lib;pyclustering-static.lib $(OutDir) Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y Level3 Disabled true $(SolutionDir)include;$(SolutionDir)external\include true true false gtest.lib;pyclustering-static.lib $(OutDir) Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y Level3 MaxSpeed true true true $(SolutionDir)include;$(SolutionDir)external\include true true true true gtest.lib;pyclustering-static.lib $(OutDir) Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y Level3 MaxSpeed true true true $(SolutionDir)include;$(SolutionDir)external\include true true true true gtest.lib;pyclustering-static.lib $(OutDir) Console copy "$(TargetPath)" "..\tst\$(TargetName)$(TargetExt)" /y pyclustering-0.10.1.2/ccore/tst/ut-static.vcxproj.filters000077500000000000000000000146421375753423500234170ustar00rootroot00000000000000 Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Unit Tests Utils Utils Utils Utils Unit Tests Unit Tests Utils Utils Utils Utils Utils {585418de-54c7-4bb5-b2b2-1c276c2528de} {22c82d50-1989-428d-91bb-3a0a42011bb0} pyclustering-0.10.1.2/ccore/tst/utenv_check.cpp000077500000000000000000000055531375753423500214210ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include "utenv_check.hpp" #include #include #include using namespace pyclustering::clst; void ASSERT_CLUSTER_SIZES( const dataset & p_data, const cluster_sequence & p_actual_clusters, const std::vector & p_expected_cluster_length, const index_sequence & p_indexes) { ASSERT_CLUSTER_NOISE_SIZES(p_data, p_actual_clusters, p_expected_cluster_length, { }, -1, p_indexes); } void ASSERT_CLUSTER_NOISE_SIZES( const dataset & p_data, const cluster_sequence & p_actual_clusters, const std::vector & p_expected_cluster_length, const noise & p_actual_noise, const std::size_t & p_expected_noise_length, const index_sequence & p_indexes) { if (p_expected_cluster_length.empty() && p_actual_clusters.empty()) { return; } std::size_t total_size = 0; std::unordered_map unique_objects; std::vector obtained_cluster_length; for (auto & cluster : p_actual_clusters) { total_size += cluster.size(); obtained_cluster_length.push_back(cluster.size()); for (auto index_object : cluster) { unique_objects[index_object] = false; } } total_size += p_actual_noise.size(); for (auto index_object : p_actual_noise) { unique_objects[index_object] = false; } ASSERT_EQ(total_size, unique_objects.size()); if (!p_expected_cluster_length.empty()) { std::size_t expected_total_size = std::accumulate(p_expected_cluster_length.cbegin(), p_expected_cluster_length.cend(), (std::size_t) 0); if (p_expected_noise_length != (std::size_t) -1) { expected_total_size += p_expected_noise_length; } ASSERT_EQ(expected_total_size, total_size); std::sort(obtained_cluster_length.begin(), obtained_cluster_length.end()); std::vector sorted_expected_cluster_length(p_expected_cluster_length); std::sort(sorted_expected_cluster_length.begin(), sorted_expected_cluster_length.end()); for (size_t i = 0; i < obtained_cluster_length.size(); i++) { ASSERT_EQ(obtained_cluster_length[i], sorted_expected_cluster_length[i]); } } else { if (!p_indexes.empty()) { ASSERT_EQ(p_indexes.size(), unique_objects.size()); for (auto index : p_indexes) { ASSERT_TRUE( unique_objects.find(index) != unique_objects.cend() ); } } else { ASSERT_EQ(p_data.size(), total_size); } } if (p_expected_noise_length != (std::size_t) -1) { ASSERT_EQ(p_expected_noise_length, p_actual_noise.size()); } }pyclustering-0.10.1.2/ccore/tst/utenv_check.hpp000077500000000000000000000061541375753423500214240ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include #include #include using namespace pyclustering; using namespace pyclustering::clst; /** * * @brief Checks that clusters have all allocated objects together from input data and that * sizes of allocated clusters are expected. * @details If 'p_expected_cluster_length' is empty than only total number of allocated object * is checked - clusters consist of each point index from input data. * * @param[in] p_data: data that has been processed. * @param[in] p_actual_clusters: allocated clusters. * @param[in] p_expected_cluster_length: expected clusters length - can be empty. * @param[in] p_indexes: specific object indexes that are used for clustering. * */ void ASSERT_CLUSTER_SIZES( const dataset & p_data, const cluster_sequence & p_actual_clusters, const std::vector & p_expected_cluster_length, const index_sequence & p_indexes = { }); void ASSERT_CLUSTER_NOISE_SIZES( const dataset & p_data, const cluster_sequence & p_actual_clusters, const std::vector & p_expected_cluster_length, const noise & p_actual_noise, const std::size_t & p_expected_noise_length, const index_sequence & p_indexes = { }); template bool COMPARE_SYNC_ENSEMBLES( EnsemblesType & p_ensembles, EnsemblesType & p_expected_ensembles, typename EnsemblesType::value_type & p_dead, typename EnsemblesType::value_type & p_expected_dead) { /* compare dead neurons */ std::sort(p_dead.begin(), p_dead.end()); std::sort(p_expected_dead.begin(), p_expected_dead.end()); if (p_expected_dead != p_dead) { return false; } /* compare ensembles */ if (p_expected_ensembles.size() != p_ensembles.size()) { return false; } /* sort indexes in ensembles */ for (auto & ensemble : p_ensembles) { std::sort(ensemble.begin(), ensemble.end()); } for (auto & ensemble : p_expected_ensembles) { std::sort(ensemble.begin(), ensemble.end()); } /* compare */ bool ensemble_found = false; for (auto & ensemble : p_ensembles) { for (auto & expected_ensemble : p_expected_ensembles) { if (ensemble == expected_ensemble) { ensemble_found = true; break; } } if (!ensemble_found) { return false; } } return true; } template void ASSERT_SYNC_ENSEMBLES(EnsemblesType & p_ensembles, EnsemblesType & p_expected_ensembles, typename EnsemblesType::value_type & p_dead, typename EnsemblesType::value_type & p_expected_dead) { ASSERT_TRUE(COMPARE_SYNC_ENSEMBLES(p_ensembles, p_expected_ensembles, p_dead, p_expected_dead)); }pyclustering-0.10.1.2/ccore/tst/utenv_utils.cpp000077500000000000000000000001761375753423500215000ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include "utenv_utils.hpp"pyclustering-0.10.1.2/ccore/tst/utenv_utils.hpp000077500000000000000000000007051375753423500215030ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include template static std::shared_ptr pack(const ContainerType & container) { pyclustering_package * package = create_package(&container); std::shared_ptr shared_package(package); return shared_package; }pyclustering-0.10.1.2/ccore/tst/utest-adjacency.cpp000077500000000000000000000200041375753423500221720ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::container; void template_set_connection(adjacency_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = i + 1; j < collection.size(); j++) { ASSERT_FALSE(collection.has_connection(i, j)); collection.set_connection(i, j); ASSERT_TRUE(collection.has_connection(i, j)); ASSERT_FALSE(collection.has_connection(j, i)); collection.set_connection(j, i); ASSERT_TRUE(collection.has_connection(j, i)); } } } void template_has_no_connection(adjacency_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { ASSERT_FALSE(collection.has_connection(i, j)); } } } void template_has_all_connection(adjacency_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { collection.set_connection(i, j); } } for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { ASSERT_TRUE(collection.has_connection(i, j)); } } } void template_erase_connection(adjacency_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = i + 1; j < collection.size(); j++) { collection.set_connection(i, j); collection.set_connection(j, i); } } for (size_t i = 0; i < collection.size(); i++) { for (size_t j = i + 1; j < collection.size(); j++) { ASSERT_TRUE(collection.has_connection(i, j)); ASSERT_TRUE(collection.has_connection(j, i)); collection.erase_connection(i, j); ASSERT_FALSE(collection.has_connection(i, j)); ASSERT_TRUE(collection.has_connection(j, i)); collection.erase_connection(j, i); ASSERT_FALSE(collection.has_connection(i, j)); ASSERT_FALSE(collection.has_connection(j, i)); } } } void template_get_neighbors_sizes(adjacency_collection & collection) { std::vector node_neighbors; for (size_t i = 0; i < collection.size(); i++) { for (size_t j = i + 1; j < collection.size(); j++) { collection.set_connection(i, j); collection.set_connection(j, i); collection.get_neighbors(i, node_neighbors); ASSERT_EQ(j, node_neighbors.size()); collection.get_neighbors(j, node_neighbors); ASSERT_EQ(i + 1, node_neighbors.size()); } } } void template_get_neighbors_indexes(adjacency_collection & collection) { std::vector node_neighbors; for (size_t i = 0; i < collection.size(); i++) { for (size_t j = i + 1; j < collection.size(); j++) { collection.set_connection(i, j); collection.set_connection(j, i); } } for (size_t i = 0; i < collection.size(); i++) { collection.get_neighbors(i, node_neighbors); ASSERT_EQ(collection.size() - 1, node_neighbors.size()); std::vector index_neighbor_checker(collection.size(), false); for (size_t j = 0; j < node_neighbors.size(); j++) { size_t neighbor_index = node_neighbors[j]; index_neighbor_checker[neighbor_index] = true; } for (size_t j = 0; j < node_neighbors.size(); j++) { if (i != j) { ASSERT_TRUE(index_neighbor_checker[j]); } else { ASSERT_FALSE(index_neighbor_checker[i]); } } } } void template_no_get_neighbors(adjacency_collection & collection) { std::vector node_neighbors; for (size_t i = 0; i < collection.size(); i++) { collection.get_neighbors(i, node_neighbors); ASSERT_EQ(0U, node_neighbors.size()); } } void template_all_get_neighbors(adjacency_collection & collection) { std::vector node_neighbors; for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { collection.set_connection(i, j); } } for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { collection.get_neighbors(i, node_neighbors); ASSERT_EQ(collection.size(), node_neighbors.size()); std::sort(node_neighbors.begin(), node_neighbors.end()); for (size_t index = 0; index < collection.size(); index++) { ASSERT_EQ(index, node_neighbors[index]); } } } } void template_get_neighbors_after_erase(adjacency_collection & collection) { /* full insert */ for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { collection.set_connection(i, j); } } /* full erase */ for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { collection.erase_connection(i, j); } } /* check that there is no neighbors */ for (size_t i = 0; i < collection.size(); i++) { std::vector node_neighbors; collection.get_neighbors(i, node_neighbors); ASSERT_EQ(0U, node_neighbors.size()); } } void template_set_weight_connection(adjacency_weight_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { ASSERT_EQ(0.0, collection.get_connection_weight(i, j)); ASSERT_FALSE(collection.has_connection(i, j)); const double weight = (double) i + (double) j / 10.0 + 1.0; collection.set_connection_weight(i, j, weight); ASSERT_EQ(weight, collection.get_connection_weight(i, j)); ASSERT_TRUE(collection.has_connection(i, j)); } } } void template_set_default_weight_connection(adjacency_weight_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { ASSERT_EQ(0.0, collection.get_connection_weight(i, j)); ASSERT_FALSE(collection.has_connection(i, j)); collection.set_connection(i, j); ASSERT_NE(0.0, collection.get_connection_weight(i, j)); ASSERT_TRUE(collection.has_connection(i, j)); } } } void template_set_negative_weight(adjacency_weight_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { ASSERT_EQ(0.0, collection.get_connection_weight(i, j)); ASSERT_FALSE(collection.has_connection(i, j)); collection.set_connection_weight(i, j, -1.0); ASSERT_EQ(-1.0, collection.get_connection_weight(i, j)); ASSERT_TRUE(collection.has_connection(i, j)); } } } void template_get_neighbors_positive_negative(adjacency_weight_collection & collection) { for (size_t i = 0; i < collection.size(); i++) { for (size_t j = 0; j < collection.size(); j++) { if (i % 2 == 0) { collection.set_connection_weight(i, j, 10.0); } else { collection.set_connection_weight(i, j, -10.0); } } } for (size_t i = 0; i < collection.size(); i++) { std::vector node_neighbors; collection.get_neighbors(i, node_neighbors); ASSERT_EQ(collection.size(), node_neighbors.size()); } } pyclustering-0.10.1.2/ccore/tst/utest-adjacency.hpp000077500000000000000000000022771375753423500222130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include using namespace pyclustering::container; void template_set_connection(adjacency_collection & collection); void template_has_no_connection(adjacency_collection & collection); void template_has_all_connection(adjacency_collection & collection); void template_erase_connection(adjacency_collection & collection); void template_get_neighbors_sizes(adjacency_collection & collection); void template_get_neighbors_indexes(adjacency_collection & collection); void template_no_get_neighbors(adjacency_collection & collection); void template_all_get_neighbors(adjacency_collection & collection); void template_get_neighbors_after_erase(adjacency_collection & collection); void template_set_weight_connection(adjacency_weight_collection & collection); void template_set_default_weight_connection(adjacency_weight_collection & collection); void template_set_negative_weight(adjacency_weight_collection & collection); void template_get_neighbors_positive_negative(adjacency_weight_collection & collection);pyclustering-0.10.1.2/ccore/tst/utest-adjacency_bit_matrix.cpp000077500000000000000000000100611375753423500244160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "utest-adjacency.hpp" #include #include using namespace pyclustering::container; TEST(utest_adjacency_bit_matrix, create_delete) { adjacency_bit_matrix * matrix = new adjacency_bit_matrix(10); ASSERT_EQ(10U, matrix->size()); for (size_t i = 0; i < matrix->size(); i++) { for (size_t j = i + 1; j < matrix->size(); j++) { ASSERT_FALSE(matrix->has_connection(i, j)); } } delete matrix; } TEST(utest_adjacency_bit_matrix, null_size) { adjacency_bit_matrix matrix(0); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_bit_matrix, create_clear) { adjacency_bit_matrix matrix(10); ASSERT_EQ(10U, matrix.size()); matrix.clear(); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_bit_matrix, copy_matrix) { adjacency_bit_matrix matrix_first(20); adjacency_bit_matrix matrix_second(10); ASSERT_EQ(20U, matrix_first.size()); ASSERT_EQ(10U, matrix_second.size()); matrix_first.set_connection(1, 2); matrix_first.set_connection(2, 3); matrix_second.set_connection(2, 1); matrix_second.set_connection(4, 7); matrix_first = matrix_second; ASSERT_EQ(10U, matrix_first.size()); ASSERT_EQ(10U, matrix_second.size()); ASSERT_FALSE(matrix_first.has_connection(1, 2)); ASSERT_FALSE(matrix_first.has_connection(2, 3)); ASSERT_TRUE(matrix_first.has_connection(2, 1)); ASSERT_TRUE(matrix_first.has_connection(4, 7)); } TEST(utest_adjacency_bit_matrix, move_matrix) { adjacency_bit_matrix matrix_first(40); adjacency_bit_matrix matrix_second(40); ASSERT_TRUE(matrix_first.size() == matrix_second.size()); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(40U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) == 0) { matrix_first.set_connection(i, j); ASSERT_TRUE(matrix_first.has_connection(i, j)); ASSERT_FALSE(matrix_second.has_connection(i, j)); } else { matrix_second.set_connection(i, j); ASSERT_FALSE(matrix_first.has_connection(i, j)); ASSERT_TRUE(matrix_second.has_connection(i, j)); } } } matrix_first = std::move(matrix_second); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(0U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) != 0) { ASSERT_TRUE(matrix_first.has_connection(i, j)); } } } } TEST(utest_adjacency_bit_matrix, has_no_connection) { adjacency_bit_matrix matrix(30); template_has_no_connection(matrix); } TEST(utest_adjacency_bit_matrix, has_all_connection) { adjacency_bit_matrix matrix(25); template_has_all_connection(matrix); } TEST(utest_adjacency_bit_matrix, set_get_connection) { adjacency_bit_matrix matrix(100); template_set_connection(matrix); } TEST(utest_adjacency_bit_matrix, erase_get_connection) { adjacency_bit_matrix matrix(20); template_erase_connection(matrix); } TEST(utest_adjacency_bit_matrix, get_neighbors_sizes) { adjacency_bit_matrix matrix(20); template_get_neighbors_sizes(matrix); } TEST(utest_adjacency_bit_matrix, get_neighbors_indexes) { adjacency_bit_matrix matrix(20); template_get_neighbors_indexes(matrix); } TEST(utest_adjacency_bit_matrix, no_get_neighbors) { adjacency_bit_matrix matrix(41); template_no_get_neighbors(matrix); } TEST(utest_adjacency_bit_matrix, all_get_neighbors) { adjacency_bit_matrix matrix(9); template_all_get_neighbors(matrix); } TEST(utest_adjacency_bit_matrix, get_neighbors_after_erase) { adjacency_bit_matrix matrix(18); template_get_neighbors_after_erase(matrix); } pyclustering-0.10.1.2/ccore/tst/utest-adjacency_connector.cpp000077500000000000000000000347251375753423500242630ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include #include using namespace pyclustering::container; enum class grid_t { GRID_FOUR, GRID_EIGHT }; template static void template_grid_connections(const grid_t p_connections, const size_t p_elements, const size_t p_width = 0, const size_t p_height = 0) { TypeCollection collection(p_elements); adjacency_connector connector; switch (p_connections) { case grid_t::GRID_FOUR: if ((p_width != 0U) && (p_height != 0U)) { connector.create_grid_four_connections(p_width, p_height, collection); } else { connector.create_grid_four_connections(collection); } break; case grid_t::GRID_EIGHT: if ((p_width != 0U) && (p_height != 0U)) { connector.create_grid_eight_connections(p_width, p_height, collection); } else { connector.create_grid_eight_connections(collection); } break; } int base = (int) p_width; if (base == 0) { base = (int) std::sqrt(p_elements); } for (int index = 0; index < (int) collection.size(); index++) { const int upper_index = index - base; const int upper_left_index = index - base - 1; const int upper_right_index = index - base + 1; const int lower_index = index + base; const int lower_left_index = index + base - 1; const int lower_right_index = index + base + 1; const int left_index = index - 1; const int right_index = index + 1; const int node_row_index = (int) std::ceil(index / base); const int upper_row_index = node_row_index - 1; const int lower_row_index = node_row_index + 1; std::vector neighbors; collection.get_neighbors(index, neighbors); if (upper_index >= 0) { ASSERT_EQ(true, collection.has_connection(index, upper_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) upper_index)); } if (lower_index < (int) collection.size()) { ASSERT_EQ(true, collection.has_connection(index, lower_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) lower_index)); } if ((left_index >= 0) && (std::ceil(left_index / base) == node_row_index)) { ASSERT_TRUE(collection.has_connection(index, left_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) left_index)); } if ((right_index < (int) collection.size()) && (std::ceil(right_index / base) == node_row_index)) { ASSERT_TRUE(collection.has_connection(index, right_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) right_index)); } if (p_connections == grid_t::GRID_EIGHT) { if ((upper_left_index >= 0) && (std::floor(upper_left_index / base) == upper_row_index)) { ASSERT_TRUE(collection.has_connection(index, upper_left_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) upper_left_index)); } if ((upper_right_index >= 0) && (std::floor(upper_right_index / base) == upper_row_index)) { ASSERT_TRUE(collection.has_connection(index, upper_right_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) upper_right_index)); } if ((lower_left_index < (int) collection.size()) && (std::floor(lower_left_index / base) == lower_row_index)) { ASSERT_TRUE(collection.has_connection(index, lower_left_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) lower_left_index)); } if ((lower_right_index < (int) collection.size()) && (std::floor(lower_right_index / base) == lower_row_index)) { ASSERT_TRUE(collection.has_connection(index, lower_right_index)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) lower_right_index)); } for (int j = 0; j < (int) collection.size(); j++) { if ((j != index) && (j != upper_index) && (j != lower_index) && (j != left_index) && (j != right_index) && (j != upper_left_index) && (j != upper_right_index) && (j != lower_left_index) && (j != lower_right_index)) { ASSERT_FALSE(collection.has_connection(index, j)); ASSERT_TRUE(neighbors.cend() == std::find(neighbors.cbegin(), neighbors.cend(), (size_t) j)); } } } else { for (int j = 0; j < (int) collection.size(); j++) { if ((j != index) && (j != upper_index) && (j != lower_index) && (j != left_index) && (j != right_index)) { ASSERT_FALSE(collection.has_connection(index, j)); ASSERT_TRUE(neighbors.cend() == std::find(neighbors.cbegin(), neighbors.cend(), (size_t) j)); } } } } } TEST(utest_adjacency_connector, grid_four_bit_matrix_25) { template_grid_connections(grid_t::GRID_FOUR, 25); } TEST(utest_adjacency_connector, grid_four_list_25) { template_grid_connections(grid_t::GRID_FOUR, 25); } TEST(utest_adjacency_connector, grid_four_matrix_25) { template_grid_connections(grid_t::GRID_FOUR, 25); } TEST(utest_adjacency_connector, grid_four_list_weight_25) { template_grid_connections(grid_t::GRID_FOUR, 25); } TEST(utest_adjacency_connector, grid_four_36) { template_grid_connections(grid_t::GRID_FOUR, 36); template_grid_connections(grid_t::GRID_FOUR, 36); template_grid_connections(grid_t::GRID_FOUR, 36); template_grid_connections(grid_t::GRID_FOUR, 36); } TEST(utest_adjacency_connector, grid_four_49) { template_grid_connections(grid_t::GRID_FOUR, 49); template_grid_connections(grid_t::GRID_FOUR, 49); template_grid_connections(grid_t::GRID_FOUR, 49); template_grid_connections(grid_t::GRID_FOUR, 49); } TEST(utest_adjacency_connector, grid_eight_bit_matrix_16) { template_grid_connections(grid_t::GRID_EIGHT, 16); } TEST(utest_adjacency_connector, grid_eight_list_16) { template_grid_connections(grid_t::GRID_EIGHT, 16); } TEST(utest_adjacency_connector, grid_eight_matrix_16) { template_grid_connections(grid_t::GRID_EIGHT, 16); } TEST(utest_adjacency_connector, grid_eight_list_weight_16) { template_grid_connections(grid_t::GRID_EIGHT, 16); } TEST(utest_adjacency_connector, grid_eight_25) { template_grid_connections(grid_t::GRID_EIGHT, 25); template_grid_connections(grid_t::GRID_EIGHT, 25); template_grid_connections(grid_t::GRID_EIGHT, 25); template_grid_connections(grid_t::GRID_EIGHT, 25); } TEST(utest_adjacency_connector, grid_four_rectangle_10) { template_grid_connections(grid_t::GRID_FOUR, 10, 5, 2); template_grid_connections(grid_t::GRID_FOUR, 10, 5, 2); template_grid_connections(grid_t::GRID_FOUR, 10, 5, 2); template_grid_connections(grid_t::GRID_FOUR, 10, 5, 2); } TEST(utest_adjacency_connector, grid_eight_rectangle_10) { template_grid_connections(grid_t::GRID_EIGHT, 10, 5, 2); template_grid_connections(grid_t::GRID_EIGHT, 10, 5, 2); template_grid_connections(grid_t::GRID_EIGHT, 10, 5, 2); template_grid_connections(grid_t::GRID_EIGHT, 10, 5, 2); } TEST(utest_adjacency_connector, grid_four_rectangle_50) { template_grid_connections(grid_t::GRID_FOUR, 50, 5, 10); template_grid_connections(grid_t::GRID_FOUR, 50, 5, 10); template_grid_connections(grid_t::GRID_FOUR, 50, 5, 10); template_grid_connections(grid_t::GRID_FOUR, 50, 5, 10); } TEST(utest_adjacency_connector, grid_eight_rectangle_50) { template_grid_connections(grid_t::GRID_EIGHT, 50, 5, 10); template_grid_connections(grid_t::GRID_EIGHT, 50, 5, 10); template_grid_connections(grid_t::GRID_EIGHT, 50, 5, 10); template_grid_connections(grid_t::GRID_EIGHT, 50, 5, 10); } TEST(utest_adjacency_connector, grid_four_rectangle_as_list) { template_grid_connections(grid_t::GRID_FOUR, 15, 1, 15); template_grid_connections(grid_t::GRID_FOUR, 15, 1, 15); template_grid_connections(grid_t::GRID_FOUR, 15, 1, 15); template_grid_connections(grid_t::GRID_FOUR, 15, 1, 15); template_grid_connections(grid_t::GRID_FOUR, 7, 7, 1); template_grid_connections(grid_t::GRID_FOUR, 7, 7, 1); template_grid_connections(grid_t::GRID_FOUR, 7, 7, 1); template_grid_connections(grid_t::GRID_FOUR, 7, 7, 1); } TEST(utest_adjacency_connector, grid_eight_rectangle_as_list) { template_grid_connections(grid_t::GRID_EIGHT, 15, 1, 15); template_grid_connections(grid_t::GRID_EIGHT, 15, 1, 15); template_grid_connections(grid_t::GRID_EIGHT, 15, 1, 15); template_grid_connections(grid_t::GRID_EIGHT, 15, 1, 15); template_grid_connections(grid_t::GRID_EIGHT, 7, 7, 1); template_grid_connections(grid_t::GRID_EIGHT, 7, 7, 1); template_grid_connections(grid_t::GRID_EIGHT, 7, 7, 1); template_grid_connections(grid_t::GRID_EIGHT, 7, 7, 1); } template static void template_list_connection(const size_t p_elements) { TypeCollection collection(p_elements); adjacency_connector connector; connector.create_list_bidir_connections(collection); for (size_t i = 0; i < p_elements; i++) { std::vector neighbors; collection.get_neighbors(i, neighbors); if (i > 0) { ASSERT_TRUE(collection.has_connection(i, i - 1)); ASSERT_TRUE(collection.has_connection(i - 1, i)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) i - 1)); } if (i < (p_elements - 1)) { ASSERT_TRUE(collection.has_connection(i, i + 1)); ASSERT_TRUE(collection.has_connection(i + 1, i)); ASSERT_TRUE(neighbors.cend() != std::find(neighbors.cbegin(), neighbors.cend(), (size_t) i + 1)); } for (std::size_t j = 0; j < p_elements; j++) { if ((i != j) && (j != (i + 1)) && (j != (i - 1))) { ASSERT_FALSE(collection.has_connection(i, j)); ASSERT_TRUE(neighbors.cend() == std::find(neighbors.cbegin(), neighbors.cend(), (size_t) j)); } } } } TEST(utest_adjacency_connector, bidir_10) { template_list_connection(10); template_list_connection(10); template_list_connection(10); template_list_connection(10); } TEST(utest_adjacency_connector, bidir_15) { template_list_connection(15); template_list_connection(15); template_list_connection(15); template_list_connection(15); } template static void template_all_to_all_connections(const size_t p_elements) { TypeCollection collection(p_elements); adjacency_connector connector; connector.create_all_to_all_connections(collection); for (size_t i = 0; i < collection.size(); i++) { ASSERT_FALSE(collection.has_connection(i, i)); for (size_t j = i + 1; j < collection.size(); j++) { ASSERT_TRUE(collection.has_connection(i, j)); ASSERT_TRUE(collection.has_connection(j, i)); } } } TEST(utest_adjacency_connector, all_to_all_25) { template_all_to_all_connections(25); template_all_to_all_connections(25); template_all_to_all_connections(25); template_all_to_all_connections(25); } template static void template_none_connections(const size_t p_elements) { TypeCollection collection(p_elements); adjacency_connector connector; /* create all-to-all connections and then set none */ connector.create_all_to_all_connections(collection); connector.create_none_connections(collection); for (size_t i = 0; i < collection.size(); i++) { ASSERT_FALSE(collection.has_connection(i, i)); for (size_t j = i; j < collection.size(); j++) { ASSERT_FALSE(collection.has_connection(i, j)); ASSERT_FALSE(collection.has_connection(j, i)); } } } TEST(utest_adjacency_connector, none_10) { template_none_connections(10U); template_none_connections(10U); template_none_connections(10U); template_none_connections(10U); } pyclustering-0.10.1.2/ccore/tst/utest-adjacency_list.cpp000077500000000000000000000075621375753423500232430ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "utest-adjacency.hpp" #include #include using namespace pyclustering::container; TEST(utest_adjacency_list, create_delete) { adjacency_list * matrix = new adjacency_list(10); ASSERT_EQ(10U, matrix->size()); for (size_t i = 0; i < matrix->size(); i++) { for (size_t j = i + 1; j < matrix->size(); j++) { ASSERT_FALSE(matrix->has_connection(i, j)); } } delete matrix; } TEST(utest_adjacency_list, null_size) { adjacency_list matrix(0); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_list, create_clear) { adjacency_list matrix(10); ASSERT_EQ(10U, matrix.size()); matrix.clear(); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_list, copy_matrix) { adjacency_list matrix_first(20); adjacency_list matrix_second(10); ASSERT_EQ(20U, matrix_first.size()); ASSERT_EQ(10U, matrix_second.size()); matrix_first.set_connection(1, 2); matrix_first.set_connection(2, 3); matrix_second.set_connection(2, 1); matrix_second.set_connection(4, 7); matrix_first = matrix_second; ASSERT_EQ(10U, matrix_first.size()); ASSERT_EQ(10U, matrix_second.size()); ASSERT_FALSE(matrix_first.has_connection(1, 2)); ASSERT_FALSE(matrix_first.has_connection(2, 3)); ASSERT_TRUE(matrix_first.has_connection(2, 1)); ASSERT_TRUE(matrix_first.has_connection(4, 7)); } TEST(utest_adjacency_list, move_matrix) { adjacency_list matrix_first(40); adjacency_list matrix_second(40); ASSERT_TRUE(matrix_first.size() == matrix_second.size()); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(40U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) == 0) { matrix_first.set_connection(i, j); ASSERT_TRUE(matrix_first.has_connection(i, j)); ASSERT_FALSE(matrix_second.has_connection(i, j)); } else { matrix_second.set_connection(i, j); ASSERT_FALSE(matrix_first.has_connection(i, j)); ASSERT_TRUE(matrix_second.has_connection(i, j)); } } } matrix_first = std::move(matrix_second); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(0U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) != 0) { ASSERT_TRUE(matrix_first.has_connection(i, j)); } } } } TEST(utest_adjacency_list, has_no_connection) { adjacency_list matrix(30); template_has_no_connection(matrix); } TEST(utest_adjacency_list, has_all_connection) { adjacency_list matrix(25); template_has_all_connection(matrix); } TEST(utest_adjacency_list, set_get_connection) { adjacency_list matrix(100); template_set_connection(matrix); } TEST(utest_adjacency_list, erase_get_connection) { adjacency_list matrix(20); template_erase_connection(matrix); } TEST(utest_adjacency_list, get_neighbors_sizes) { adjacency_list matrix(20); template_get_neighbors_sizes(matrix); } TEST(utest_adjacency_list, get_neighbors_indexes) { adjacency_list matrix(20); template_get_neighbors_indexes(matrix); } TEST(utest_adjacency_list, no_get_neighbors) { adjacency_list matrix(30); template_no_get_neighbors(matrix); } TEST(utest_adjacency_list, all_get_neighbors) { adjacency_list matrix(11); template_all_get_neighbors(matrix); } TEST(utest_adjacency_list, get_neighbors_after_erase) { adjacency_list matrix(17); template_get_neighbors_after_erase(matrix); } pyclustering-0.10.1.2/ccore/tst/utest-adjacency_matrix.cpp000077500000000000000000000112531375753423500235640ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "utest-adjacency.hpp" #include #include using namespace pyclustering::container; TEST(utest_adjacency_matrix, create_delete) { adjacency_matrix * matrix = new adjacency_matrix(10); ASSERT_EQ(10U, matrix->size()); for (size_t i = 0; i < matrix->size(); i++) { for (size_t j = i + 1; j < matrix->size(); j++) { ASSERT_FALSE(matrix->has_connection(i, j)); } } delete matrix; } TEST(utest_adjacency_matrix, null_size) { adjacency_matrix matrix(0); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_matrix, create_clear) { adjacency_matrix matrix(10); ASSERT_EQ(10U, matrix.size()); matrix.clear(); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_matrix, copy_matrix) { adjacency_matrix matrix_first(40); adjacency_matrix matrix_second(25); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(25U, matrix_second.size()); matrix_first.set_connection(1, 2); matrix_first.set_connection(2, 3); matrix_second.set_connection(2, 1); matrix_second.set_connection(4, 7); matrix_first = matrix_second; ASSERT_EQ(25U, matrix_first.size()); ASSERT_EQ(25U, matrix_second.size()); ASSERT_FALSE(matrix_first.has_connection(1, 2)); ASSERT_FALSE(matrix_first.has_connection(2, 3)); ASSERT_TRUE(matrix_first.has_connection(2, 1)); ASSERT_TRUE(matrix_first.has_connection(4, 7)); } TEST(utest_adjacency_matrix, move_matrix) { adjacency_matrix matrix_first(40); adjacency_matrix matrix_second(40); ASSERT_TRUE(matrix_first.size() == matrix_second.size()); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(40U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) == 0) { matrix_first.set_connection(i, j); ASSERT_TRUE(matrix_first.has_connection(i, j)); ASSERT_FALSE(matrix_second.has_connection(i, j)); } else { matrix_second.set_connection(i, j); ASSERT_FALSE(matrix_first.has_connection(i, j)); ASSERT_TRUE(matrix_second.has_connection(i, j)); } } } matrix_first = std::move(matrix_second); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(0U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) != 0) { ASSERT_TRUE(matrix_first.has_connection(i, j)); } } } } TEST(utest_adjacency_matrix, has_no_connection) { adjacency_matrix matrix(30); template_has_no_connection(matrix); } TEST(utest_adjacency_matrix, has_all_connection) { adjacency_matrix matrix(25); template_has_all_connection(matrix); } TEST(utest_adjacency_matrix, set_get_connection) { adjacency_matrix matrix(100); template_set_connection(matrix); } TEST(utest_adjacency_matrix, erase_get_connection) { adjacency_matrix matrix(20); template_erase_connection(matrix); } TEST(utest_adjacency_matrix, get_neighbors_sizes) { adjacency_matrix matrix(20); template_get_neighbors_sizes(matrix); } TEST(utest_adjacency_matrix, get_neighbors_indexes) { adjacency_matrix matrix(20); template_get_neighbors_indexes(matrix); } TEST(utest_adjacency_matrix, no_get_neighbors) { adjacency_matrix matrix(30); template_no_get_neighbors(matrix); } TEST(utest_adjacency_matrix, all_get_neighbors) { adjacency_matrix matrix(11); template_all_get_neighbors(matrix); } TEST(utest_adjacency_matrix, get_neighbors_after_erase) { adjacency_matrix matrix(17); template_get_neighbors_after_erase(matrix); } TEST(utest_adjacency_matrix, set_weight_connection) { adjacency_matrix matrix(40); template_set_weight_connection(matrix); } TEST(utest_adjacency_matrix, set_default_weight_connection) { adjacency_matrix matrix(32); template_set_default_weight_connection(matrix); } TEST(utest_adjacency_matrix, set_negative_weight) { adjacency_matrix matrix(18); template_set_negative_weight(matrix); } TEST(utest_adjacency_matrix, get_neighbors_positive_negative) { adjacency_matrix matrix(25); template_get_neighbors_positive_negative(matrix); } pyclustering-0.10.1.2/ccore/tst/utest-adjacency_weight_list.cpp000077500000000000000000000116221375753423500246020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "utest-adjacency.hpp" #include #include using namespace pyclustering; using namespace pyclustering::container; TEST(utest_adjacency_weight_list, create_delete) { adjacency_weight_list * matrix = new adjacency_weight_list(10); ASSERT_EQ(10U, matrix->size()); for (size_t i = 0; i < matrix->size(); i++) { for (size_t j = i + 1; j < matrix->size(); j++) { ASSERT_FALSE(matrix->has_connection(i, j)); } } delete matrix; } TEST(utest_adjacency_weight_list, null_size) { adjacency_weight_list matrix(0); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_weight_list, create_clear) { adjacency_weight_list matrix(10); ASSERT_EQ(10U, matrix.size()); matrix.clear(); ASSERT_EQ(0U, matrix.size()); } TEST(utest_adjacency_weight_list, copy_matrix) { adjacency_weight_list matrix_first(40); adjacency_weight_list matrix_second(25); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(25U, matrix_second.size()); matrix_first.set_connection(1, 2); matrix_first.set_connection(2, 3); matrix_second.set_connection(2, 1); matrix_second.set_connection(4, 7); matrix_first = matrix_second; ASSERT_EQ(25U, matrix_first.size()); ASSERT_EQ(25U, matrix_second.size()); ASSERT_FALSE(matrix_first.has_connection(1, 2)); ASSERT_FALSE(matrix_first.has_connection(2, 3)); ASSERT_TRUE(matrix_first.has_connection(2, 1)); ASSERT_TRUE(matrix_first.has_connection(4, 7)); } TEST(utest_adjacency_weight_list, move_matrix) { adjacency_weight_list matrix_first(40); adjacency_weight_list matrix_second(40); ASSERT_TRUE(matrix_first.size() == matrix_second.size()); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(40U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) == 0) { matrix_first.set_connection(i, j); ASSERT_TRUE(matrix_first.has_connection(i, j)); ASSERT_FALSE(matrix_second.has_connection(i, j)); } else { matrix_second.set_connection(i, j); ASSERT_FALSE(matrix_first.has_connection(i, j)); ASSERT_TRUE(matrix_second.has_connection(i, j)); } } } matrix_first = std::move(matrix_second); ASSERT_EQ(40U, matrix_first.size()); ASSERT_EQ(0U, matrix_second.size()); for (size_t i = 0; i < matrix_first.size(); i++) { for (size_t j = i + 1; j < matrix_first.size(); j++) { if ((i % 2) != 0) { ASSERT_TRUE(matrix_first.has_connection(i, j)); } } } } TEST(utest_adjacency_weight_list, has_no_connection) { adjacency_weight_list matrix(30); template_has_no_connection(matrix); } TEST(utest_adjacency_weight_list, has_all_connection) { adjacency_weight_list matrix(25); template_has_all_connection(matrix); } TEST(utest_adjacency_weight_list, set_get_connection) { adjacency_weight_list matrix(100); template_set_connection(matrix); } TEST(utest_adjacency_weight_list, erase_get_connection) { adjacency_weight_list matrix(20); template_erase_connection(matrix); } TEST(utest_adjacency_weight_list, get_neighbors_sizes) { adjacency_weight_list matrix(20); template_get_neighbors_sizes(matrix); } TEST(utest_adjacency_weight_list, get_neighbors_indexes) { adjacency_weight_list matrix(20); template_get_neighbors_indexes(matrix); } TEST(utest_adjacency_weight_list, no_get_neighbors) { adjacency_weight_list matrix(30); template_no_get_neighbors(matrix); } TEST(utest_adjacency_weight_list, all_get_neighbors) { adjacency_weight_list matrix(11); template_all_get_neighbors(matrix); } TEST(utest_adjacency_weight_list, get_neighbors_after_erase) { adjacency_weight_list matrix(17); template_get_neighbors_after_erase(matrix); } TEST(utest_adjacency_weight_list, set_weight_connection) { adjacency_weight_list matrix(40); template_set_weight_connection(matrix); } TEST(utest_adjacency_weight_list, set_default_weight_connection) { adjacency_weight_list matrix(32); template_set_default_weight_connection(matrix); } TEST(utest_adjacency_weight_list, set_negative_weight) { adjacency_weight_list matrix(18); template_set_negative_weight(matrix); } TEST(utest_adjacency_weight_list, get_neighbors_positive_negative) { adjacency_weight_list matrix(25); template_get_neighbors_positive_negative(matrix); } pyclustering-0.10.1.2/ccore/tst/utest-agglomerative.cpp000077500000000000000000000220251375753423500231040ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "samples.hpp" #include using namespace pyclustering; using namespace pyclustering::clst; static void template_length_process_data(const std::shared_ptr & data, const size_t number_clusters, const agglomerative::type_link link, const std::vector & expected_cluster_length) { agglomerative solver(number_clusters, link); cluster_data results_data; solver.process(*data.get(), results_data); cluster_sequence & results = results_data.clusters(); /* Check number of clusters */ ASSERT_EQ(expected_cluster_length.size(), results.size()); /* Check cluster sizes */ std::vector obtained_cluster_length; for (size_t i = 0; i < results.size(); i++) { obtained_cluster_length.push_back(results[i].size()); } std::sort(obtained_cluster_length.begin(), obtained_cluster_length.end()); std::vector sorted_expected_cluster_length(expected_cluster_length); std::sort(sorted_expected_cluster_length.begin(), sorted_expected_cluster_length.end()); for (size_t i = 0; i < obtained_cluster_length.size(); i++) { ASSERT_EQ(obtained_cluster_length[i], sorted_expected_cluster_length[i]); } } TEST(utest_agglomerative, clustering_sampl_simple_01_two_cluster_link_average) { std::vector expected_clusters_length_1 = {5, 5}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, agglomerative::type_link::AVERAGE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_01_one_cluster_link_average) { std::vector expected_clusters_length_2 = {10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, agglomerative::type_link::AVERAGE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_01_two_cluster_link_centroid) { std::vector expected_clusters_length_1 = {5, 5}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, agglomerative::type_link::CENTROID_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_01_one_cluster_link_centroid) { std::vector expected_clusters_length_2 = {10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, agglomerative::type_link::CENTROID_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_01_two_cluster_link_complete) { std::vector expected_clusters_length_1 = {5, 5}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, agglomerative::type_link::COMPLETE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_01_one_cluster_link_complete) { std::vector expected_clusters_length_2 = {10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, agglomerative::type_link::COMPLETE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_01_two_cluster_link_single) { std::vector expected_clusters_length_1 = {5, 5}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, agglomerative::type_link::SINGLE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_01_one_cluster_link_single) { std::vector expected_clusters_length_2 = {10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, agglomerative::type_link::SINGLE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_02_three_cluster_link_average) { std::vector expected_clusters_length_1 = {5, 8, 10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, agglomerative::type_link::AVERAGE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_02_one_cluster_link_average) { std::vector expected_clusters_length_2 = {23}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, agglomerative::type_link::AVERAGE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_02_three_cluster_link_centroid) { std::vector expected_clusters_length_1 = {5, 8, 10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, agglomerative::type_link::CENTROID_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_02_one_cluster_link_centroid) { std::vector expected_clusters_length_2 = {23}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, agglomerative::type_link::CENTROID_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_02_three_cluster_link_complete) { std::vector expected_clusters_length_1 = {5, 8, 10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, agglomerative::type_link::COMPLETE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_02_one_cluster_link_complete) { std::vector expected_clusters_length_2 = {23}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, agglomerative::type_link::COMPLETE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_02_three_cluster_link_single) { std::vector expected_clusters_length_1 = {5, 8, 10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, agglomerative::type_link::SINGLE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_02_one_cluster_link_single) { std::vector expected_clusters_length_2 = {23}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, agglomerative::type_link::SINGLE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_03_four_cluster_link_average) { std::vector expected_clusters_length_1 = {10, 10, 10, 30}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, agglomerative::type_link::AVERAGE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_03_one_cluster_link_average) { std::vector expected_clusters_length_2 = {60}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, agglomerative::type_link::AVERAGE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_03_four_cluster_link_centroid) { std::vector expected_clusters_length_1 = {10, 10, 10, 30}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, agglomerative::type_link::CENTROID_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_03_one_cluster_link_centroid) { std::vector expected_clusters_length_2 = {60}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, agglomerative::type_link::CENTROID_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_03_four_cluster_link_complete) { std::vector expected_clusters_length_1 = {10, 10, 10, 30}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, agglomerative::type_link::COMPLETE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_03_one_cluster_link_complete) { std::vector expected_clusters_length_2 = {60}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, agglomerative::type_link::COMPLETE_LINK, expected_clusters_length_2); } TEST(utest_agglomerative, clustering_sampl_simple_03_four_cluster_link_single) { std::vector expected_clusters_length_1 = {10, 10, 10, 30}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, agglomerative::type_link::SINGLE_LINK, expected_clusters_length_1); } TEST(utest_agglomerative, clustering_sampl_simple_03_one_cluster_link_single) { std::vector expected_clusters_length_2 = {60}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, agglomerative::type_link::SINGLE_LINK, expected_clusters_length_2); } pyclustering-0.10.1.2/ccore/tst/utest-bsas.cpp000077500000000000000000000137411375753423500212130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_bsas_length_process_data(const dataset_ptr p_data, const std::size_t & p_amount, const double & p_threshold, const std::vector & p_expected_cluster_length, const distance_metric & p_metric = distance_metric_factory::manhattan()) { bsas_data output_result; bsas solver(p_amount, p_threshold, p_metric); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const representative_sequence & actual_repr = output_result.representatives(); for (auto & repr : actual_repr) ASSERT_EQ(data[0].size(), repr.size()); ASSERT_EQ(actual_repr.size(), actual_clusters.size()); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_bsas, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length); } TEST(utest_bsas, allocation_sample_simple_01_euclidean) { const std::vector expected_clusters_length = { 5, 5 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::euclidean()); } TEST(utest_bsas, allocation_sample_simple_01_euclidean_square) { const std::vector expected_clusters_length = { 5, 5 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::euclidean_square()); } TEST(utest_bsas, allocation_sample_simple_01_manhattan) { const std::vector expected_clusters_length = { 5, 5 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::manhattan()); } TEST(utest_bsas, allocation_sample_simple_01_chebyshev) { const std::vector expected_clusters_length = { 5, 5 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::chebyshev()); } TEST(utest_bsas, allocation_sample_simple_01_minkowski) { const std::vector expected_clusters_length = { 5, 5 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::minkowski(2.0)); } TEST(utest_bsas, allocation_sample_simple_01_user_defined) { const std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::user_defined(user_metric)); } TEST(utest_bsas, allocation_one_allocation_sample_simple_01) { const std::vector expected_clusters_length = { 10 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 10.0, expected_clusters_length); } TEST(utest_bsas, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 5, 8, 10 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 1.0, expected_clusters_length); } TEST(utest_bsas, allocation_one_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 23 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 10.0, expected_clusters_length); } TEST(utest_bsas, allocation_one_dimension_points_1) { const std::vector expected_clusters_length = { 10, 10 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 3, 1.0, expected_clusters_length); } TEST(utest_bsas, allocation_one_allocation_one_dimension_points_1) { const std::vector expected_clusters_length = { 20 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 3, 10.0, expected_clusters_length); } TEST(utest_bsas, allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 10, 20 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 3, 1.0, expected_clusters_length); } TEST(utest_bsas, allocation_one_allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 30 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 3, 10.0, expected_clusters_length); } TEST(utest_bsas, allocation_three_dimension_points_2) { const std::vector expected_clusters_length = { 10, 10 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 1.0, expected_clusters_length); } TEST(utest_bsas, allocation_three_allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 20 }; template_bsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 10.0, expected_clusters_length); }pyclustering-0.10.1.2/ccore/tst/utest-clique.cpp000077500000000000000000000231601375753423500215410ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_clique_length_process_data( const dataset_ptr p_data, const std::size_t p_intervals, const std::size_t p_threshold, const std::vector & p_expected_cluster_length, const std::size_t p_expected_noise_length) { clique_data output_result; clique solver(p_intervals, p_threshold); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const noise & noise = output_result.noise(); const clique_block_sequence & blocks = output_result.blocks(); for (auto & block : blocks) { ASSERT_TRUE(block.is_visited()); } ASSERT_CLUSTER_NOISE_SIZES(data, actual_clusters, p_expected_cluster_length, noise, p_expected_noise_length); } TEST(utest_clique, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 8, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 7, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 6, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 5, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_01_one_cluster) { const std::vector expected_clusters_length = { 10 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_01_only_noise) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 6, 1000, { }, 10); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 6, 10, { }, 10); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 5, { }, 10); } TEST(utest_clique, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 5, 8, 10 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 7, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 6, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_02_one_cluster) { const std::vector expected_clusters_length = { 23 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_02_only_noise) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 6, 20, { }, 23); } TEST(utest_clique, allocation_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 9, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 8, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_03_one_cluster) { const std::vector expected_clusters_length = { 60 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_03_only_noise) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 6, 20, { }, 60); } TEST(utest_clique, allocation_sample_simple_03_one_point_noise) { const std::vector expected_clusters_length = { 59 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 2, 9, expected_clusters_length, 1); } TEST(utest_clique, allocation_sample_simple_04_one_cluster) { const std::vector expected_clusters_length = { 75 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 1, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_05) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 8, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 7, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 6, 0, expected_clusters_length, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 5, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_sample_simple_05_one_cluster) { const std::vector expected_clusters_length = { 60 }; template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 1, 0, expected_clusters_length, 0); } TEST(utest_clique, allocation_one_dimensional_data1) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 4, 0, { 10, 10 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 2, 0, { 20 }, 0); } TEST(utest_clique, allocation_one_dimensional_data2) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 15, 0, { 15, 20, 30, 80 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 2, 0, { 145 }, 0); } TEST(utest_clique, allocation_one_dimensional_data3_similar) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 7, 0, { 10, 20 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 2, 0, { 30 }, 0); } TEST(utest_clique, allocation_sample_simple_10) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 8, 0, { 11, 11, 11 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 7, 0, { 11, 11, 11 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 2, 0, { 33 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 1, 0, { 33 }, 0); } TEST(utest_clique, allocation_three_dimensional_data1) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 6, 0, { 10, 10 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 5, 0, { 10, 10 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 1, 0, { 20 }, 0); } TEST(utest_clique, allocation_similar_points) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 8, 0, { 5, 5, 5 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 7, 0, { 5, 5, 5 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 5, 0, { 5, 5, 5 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 2, 0, { 15 }, 0); } TEST(utest_clique, allocation_zero_column) { template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13), 3, 0, { 5, 5 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13), 2, 0, { 5, 5 }, 0); template_clique_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13), 1, 0, { 10 }, 0); } TEST(utest_clique, allocation_fcps_lsun) { template_clique_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN), 15, 0, { 100, 101, 202 }, 0); } TEST(utest_clique, allocation_fcps_hepta) { template_clique_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 9, 0, { 30, 30, 30, 30, 30, 30, 32 }, 0); } TEST(utest_clique, allocation_fcps_wingnut) { template_clique_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::WING_NUT), 15, 0, { 508, 508 }, 0); } TEST(utest_clique, allocation_fcps_target) { template_clique_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::TARGET), 10, 0, { 3, 3, 3, 3, 363, 395 }, 0); } pyclustering-0.10.1.2/ccore/tst/utest-cure.cpp000077500000000000000000000222631375753423500212200ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_length_process_data(const std::shared_ptr & p_data, const size_t p_amount_clusters, const size_t p_number_represent_points, const double p_compression, const std::vector & p_expected_cluster_length) { cure_data output_result; cure solver(p_amount_clusters, p_number_represent_points, p_compression); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); ASSERT_EQ(p_amount_clusters, output_result.representors().size()); for (auto cluster_representors : output_result.representors()) { ASSERT_TRUE(cluster_representors.size() > 0); } const size_t dimension = (*p_data)[0].size(); ASSERT_EQ(p_amount_clusters, output_result.means().size()); for (auto cluster_mean : output_result.means()) { ASSERT_EQ(dimension, cluster_mean.size()); } } TEST(utest_cure, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_01_one_representative) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_01_no_compression) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 5, 0.0, expected_clusters_length); } TEST(utest_cure, allocation_sample_one_allocation_simple_01) { const std::vector expected_clusters_length = { 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_02_one_representative) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 1, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_02_no_compression) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 5, 0.0, expected_clusters_length); } TEST(utest_cure, allocation_sample_one_allocation_simple_02) { const std::vector expected_clusters_length = { 23 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_one_allocation_simple_03) { const std::vector expected_clusters_length = { 60 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_04) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 5, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_05) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 4, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_07) { const std::vector expected_clusters_length = { 10, 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 2, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_08) { const std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 4, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_09) { const std::vector expected_clusters_length = { 10, 20 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 2, 5, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_10) { const std::vector expected_clusters_length = { 11, 11, 11 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 3, 5, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_10_one_representative) { const std::vector expected_clusters_length = { 11, 11, 11 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 3, 1, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_11) { const std::vector expected_clusters_length = { 10, 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 5, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_11_one_representative) { const std::vector expected_clusters_length = { 10, 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 1, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_12) { const std::vector expected_clusters_length = { 5, 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 3, 5, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_sample_simple_12_one_representative) { const std::vector expected_clusters_length = { 5, 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 3, 1, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_hepta) { const std::vector expected_clusters_length = { 30, 30, 30, 30, 30, 30, 32 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 7, 5, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_hepta_max_compression) { const std::vector expected_clusters_length = { 30, 30, 30, 30, 30, 30, 32 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 7, 5, 1.0, expected_clusters_length); } TEST(utest_cure, allocation_hepta_one_representative) { const std::vector expected_clusters_length = { 30, 30, 30, 30, 30, 30, 32 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 7, 1, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_hepta_one_cluster_allocation) { const std::vector expected_clusters_length = { 212 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 1, 0.3, expected_clusters_length); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_cure, allocation_tetra) { const std::vector expected_clusters_length = { 100, 100, 100, 100 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::TETRA), 4, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_lsun) { const std::vector expected_clusters_length = { 100, 101, 202 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN), 3, 5, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_two_diamonds) { const std::vector expected_clusters_length = { 399, 401 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::TWO_DIAMONDS), 2, 5, 0.5, expected_clusters_length); } TEST(utest_cure, allocation_wing_nut) { const std::vector expected_clusters_length = { 508, 508 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::WING_NUT), 2, 4, 0.3, expected_clusters_length); } TEST(utest_cure, allocation_chainlink) { const std::vector expected_clusters_length = { 500, 500 }; template_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::CHAINLINK), 2, 10, 0.3, expected_clusters_length); } #endif pyclustering-0.10.1.2/ccore/tst/utest-dbscan.cpp000077500000000000000000000252761375753423500215230ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; using namespace pyclustering::utils::metric; static std::shared_ptr template_length_process_data(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const std::vector & p_expected_cluster_length) { std::shared_ptr ptr_output_result = std::make_shared(); dbscan solver(p_radius, p_neighbors); solver.process(*p_data, *ptr_output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = ptr_output_result->clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); return ptr_output_result; } static std::shared_ptr template_length_process_distance_matrix(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const std::vector & p_expected_cluster_length) { std::shared_ptr ptr_output_result = std::make_shared(); dbscan solver(p_radius, p_neighbors); dataset matrix; distance_matrix(*p_data, matrix); solver.process(matrix, dbscan_data_t::DISTANCE_MATRIX, *ptr_output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = ptr_output_result->clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); return ptr_output_result; } TEST(utest_dbscan, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 0.5, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_01_randomize) { for (std::size_t i = 0; i < 10; i++) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01, true), 0.5, 2, expected_clusters_length); } } TEST(utest_dbscan, allocation_sample_simple_01_distance_matrix) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 0.5, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_one_allocation_simple_01) { const std::vector expected_clusters_length = { 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_one_allocation_simple_01_distance_matrix) { const std::vector expected_clusters_length = { 10 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1.0, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_02_randomize) { for (std::size_t i = 0; i < 10; i++) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02, true), 1.0, 2, expected_clusters_length); } } TEST(utest_dbscan, allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1.0, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_one_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 23 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_one_allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { 23 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 2, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 0.7, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_03_randomize) { for (std::size_t i = 0; i < 10; i++) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 0.7, 3, expected_clusters_length); } } TEST(utest_dbscan, allocation_sample_simple_03_distance_matrix) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 0.7, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_04) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 0.7, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_04_randomize) { for (std::size_t i = 0; i < 10; i++) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 0.7, 3, expected_clusters_length); } } TEST(utest_dbscan, allocation_sample_simple_04_distance_matrix) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 0.7, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_05) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 0.7, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_05_distance_matrix) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 0.7, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_07) { const std::vector expected_clusters_length = { 10, 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 0.5, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_07_distance_matrix) { const std::vector expected_clusters_length = { 10, 10 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 0.5, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_08) { const std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 0.5, 3, expected_clusters_length); } TEST(utest_dbscan, allocation_sample_simple_08_distance_matrix) { const std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 0.5, 3, expected_clusters_length); } static std::shared_ptr template_noise_allocation(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const std::vector & p_expected_cluster_length, const std::size_t p_noise_length) { std::shared_ptr ptr_output_result = template_length_process_data(p_data, p_radius, p_neighbors, p_expected_cluster_length); EXPECT_EQ(p_noise_length, ptr_output_result->noise().size()); return ptr_output_result; } static std::shared_ptr template_noise_allocation_distance_matrix(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const std::vector & p_expected_cluster_length, const std::size_t p_noise_length) { std::shared_ptr ptr_output_result = template_length_process_distance_matrix(p_data, p_radius, p_neighbors, p_expected_cluster_length); EXPECT_EQ(p_noise_length, ptr_output_result->noise().size()); return ptr_output_result; } TEST(utest_dbscan, noise_allocation_sample_simple_01) { const std::vector expected_clusters_length = { }; template_noise_allocation(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 20, expected_clusters_length, 10); } TEST(utest_dbscan, noise_allocation_sample_simple_01_distance_matrix) { const std::vector expected_clusters_length = { }; template_noise_allocation_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 20, expected_clusters_length, 10); } TEST(utest_dbscan, noise_allocation_sample_simple_02) { const std::vector expected_clusters_length = { }; template_noise_allocation(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 0.5, 20, expected_clusters_length, 23); } TEST(utest_dbscan, noise_allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { }; template_noise_allocation_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 0.5, 20, expected_clusters_length, 23); } TEST(utest_dbscan, noise_cluster_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 10 }; template_noise_allocation(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2.0, 9, expected_clusters_length, 13); } TEST(utest_dbscan, noise_cluster_allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { 10 }; template_noise_allocation_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2.0, 9, expected_clusters_length, 13); } pyclustering-0.10.1.2/ccore/tst/utest-differential.cpp000077500000000000000000000100261375753423500227100ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::differential; TEST(utest_differential, plus_states) { differ_state state1 { 0, 1, 2, 3, 4 }; differ_state state2 { 0, 1, 2, 3, 4 }; differ_state expected_result { 0, 2, 4, 6, 8 }; ASSERT_TRUE(expected_result != state1); ASSERT_TRUE(expected_result != state2); ASSERT_TRUE(state1 == state2); ASSERT_TRUE(expected_result == state1 + state2); } TEST(utest_differential, plus_various_states) { differ_state state1 { 12, -6, 11, 12, 5 }; differ_state state2 { -5, 5.5, 100, 32, 1 }; differ_state expected_result { 12 - 5, 5.5 - 6, 11 + 100, 12 + 32, 5 + 1 }; ASSERT_TRUE(expected_result == state1 + state2); } TEST(utest_differential, plus_value) { differ_state state { 0, 1, 2, 3, 4 }; differ_state expected_result1 { 1, 2, 3, 4, 5 }; ASSERT_TRUE(expected_result1 == state + 1); ASSERT_TRUE(expected_result1 == 1 + state); differ_state expected_result2 { 0.5, 1.5, 2.5, 3.5, 4.5 }; ASSERT_TRUE(expected_result2 == state + 0.5); ASSERT_TRUE(expected_result2 == 0.5 + state); differ_state expected_result3 { -1, 0, 1, 2, 3 }; ASSERT_TRUE(expected_result3 == state + (-1)); ASSERT_TRUE(expected_result3 == (-1) + state); } TEST(utest_differential, minus_states) { differ_state state1 { 0, 1, 2, 3, 4 }; differ_state state2 { 0, 1, 2, 3, 4 }; differ_state expected_result { 0, 0, 0, 0, 0 }; ASSERT_TRUE(expected_result == state1 - state2); } TEST(utest_differential, minus_various_states) { differ_state state1 { 5, 10, 15, 20, 25, 30 }; differ_state state2 { 2, 12, 12, 22, 22, 32 }; differ_state expected_result { 3, -2, 3, -2, 3, -2 }; ASSERT_TRUE(expected_result == state1 - state2); } TEST(utest_differential, minus_value) { differ_state state { 0, 1, 2, 3, 4 }; differ_state expected_result1 { -1, 0, 1, 2, 3 }; ASSERT_TRUE(expected_result1 == state - 1); differ_state expected_result2 { 1, 0, -1, -2, -3 }; ASSERT_TRUE(expected_result2 == 1 - state); } TEST(utest_differential, multiply_value) { differ_state state1 { -2, -1, 0, 1, 2 }; ASSERT_TRUE(state1 == state1 * 1); ASSERT_TRUE(state1 == 1 * state1); differ_state expected_result1 { -4, -2, 0, 2, 4 }; differ_state expected_result2 { -6, -3, 0, 3, 6 }; ASSERT_TRUE(expected_result1 == state1 * 2); ASSERT_TRUE(expected_result1 == 2 * state1); ASSERT_TRUE(expected_result2 == state1 * 3); ASSERT_TRUE(expected_result2 == 3 * state1); } TEST(utest_differential, divide_value) { differ_state state1 { -2, -1, 0, 1, 2 }; differ_state expected_result1 { -2, -1, 0, 1, 2 }; ASSERT_TRUE(expected_result1 == state1 / 1); differ_state expected_result2 { -1, -0.5, 0, 0.5, 1 }; ASSERT_TRUE(expected_result2 == state1 / 2); } TEST(utest_differential, assign_operations) { differ_state state1 { -2, -1, 0, 1, 2 }; differ_state state2 = state1; ASSERT_TRUE(state1 == state2); ASSERT_TRUE(state2 == state1); state1 += 10; differ_state expected_result1 { 8, 9, 10, 11, 12 }; ASSERT_TRUE(expected_result1 == state1); state1 -= 5; differ_state expected_result2 { 3, 4, 5, 6, 7 }; ASSERT_TRUE(expected_result2 == state1); state1 *= 2; differ_state expected_result3 { 6, 8, 10, 12, 14 }; ASSERT_TRUE(expected_result3 == state1); state1 /= 0.5; differ_state expected_result4 { 12, 16, 20, 24, 28 }; ASSERT_TRUE(expected_result4 == state1); state1 = state2; ASSERT_TRUE(state1 == state2); } pyclustering-0.10.1.2/ccore/tst/utest-dynamic_analyser.cpp000077500000000000000000000315001375753423500235760ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "utenv_check.hpp" #include using namespace pyclustering::nnet; using network_dynamic = std::vector>; using ensemble_collection = std::vector>; template static void template_sync_ensembles(const double p_amplitude, const double p_tolerance, const std::size_t p_spikes, const DynamicType & p_dynamic, EnsemblesType & p_expected_ensembles, typename EnsemblesType::value_type & p_expected_dead) { EnsemblesType ensembles; typename EnsemblesType::value_type dead; dynamic_analyser(p_amplitude, p_tolerance, p_spikes).allocate_sync_ensembles(p_dynamic, ensembles, dead); ASSERT_SYNC_ENSEMBLES(ensembles, p_expected_ensembles, dead, p_expected_dead); } TEST(utest_dynamic_analyser, two_absolutely_sync) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 2.0, 2.0 }, { 3.0, 3.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, three_absolutely_sync) { network_dynamic dynamic = { { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 2.0, 2.0, 2.0 }, { 3.0, 3.0, 3.0 }, { 0.0, 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1, 2 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, absolutely_sync_two_spikes_but_one) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 2.0, 2.0 }, { 3.0, 3.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, absolutely_sync_two_spikes) { network_dynamic dynamic = { { 0.0, 0.0 }, { 2.0, 2.0 }, { 3.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 2.0 }, { 3.0, 3.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, async_absolutely_sync) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 2.0 }, { 0.0, 3.0 }, { 2.0, 0.0 }, { 3.0, 0.0 }, { 0.0, 2.0 } }; ensemble_collection expected_ensembles = { { 0 }, { 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_at_end_one_spike) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 0.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_at_end_two_spikes) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 0.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0 }, { 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, no_oscillations) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, activity_under_threshold_01) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.9, 1.9 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(2.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, activity_under_threshold_02) { network_dynamic dynamic = { { 0.0, 0.0 }, { 2.0, 2.0 }, { 0.0, 0.0 }, { 2.9, 2.9 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(3.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, permanent_aplitude_over_threshold) { network_dynamic dynamic = { { 2.0, 3.0 }, { 2.0, 3.0 }, { 2.0, 3.0 }, { 2.0, 3.0 }, { 2.0, 3.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, oscillations_over_threshold) { network_dynamic dynamic = { { 2.0, 2.0 }, { 4.0, 8.0 }, { 2.0, 2.0 }, { 4.0, 8.0 }, { 2.0, 2.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, oscillations_under_threshold) { network_dynamic dynamic = { { 2.0, 2.0 }, { 4.0, 8.0 }, { 2.0, 2.0 }, { 4.0, 8.0 }, { 2.0, 2.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(10.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_but_one_under_threshold) { network_dynamic dynamic = { { 0.0, 0.0 }, { 3.0, 1.0 }, { 0.0, 0.0 }, { 3.0, 1.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0 } }; ensemble_collection::value_type expected_dead = { 1 }; template_sync_ensembles(2.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, two_sync_ensembles) { network_dynamic dynamic = { { 0.0, 0.0, 1.0, 1.0 }, { 1.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 1.0 }, { 1.0, 1.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 1.0 }, { 1.0, 1.0, 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 }, { 2, 3 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, three_sync_ensembles) { network_dynamic dynamic = { { 0.0, 0.0, 1.0, 1.0, 0.0, 0.0 }, { 1.0, 1.0, 0.0, 0.0, 1.0, 1.0 }, { 0.0, 0.0, 1.0, 1.0, 0.0, 0.0 }, { 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 }, { 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 }, { 1.0, 1.0, 0.0, 0.0, 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, incomplete_spike_at_end) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 1.0, 1.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, incomplete_spike_at_begin) { network_dynamic dynamic = { { 1.0, 1.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, incomplete_spike_at_begin_and_end) { network_dynamic dynamic = { { 1.0, 1.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 1.0, 1.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0, 1 }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, two_sync_with_incomplete) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 1.0, 1.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, two_sync_with_async_incomplete) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 1.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_after_time_one_spike) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_after_time_two_spikes) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_after_time_three_spikes) { network_dynamic dynamic = { { 0.0, 0.0 }, { 1.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0 }, { 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.0, 3, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_with_tolerance_01) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.5, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, sync_with_tolerance_02) { network_dynamic dynamic = { { 0.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 1.0, 1.0 }, { 0.0, 0.0 }, { 0.0, 0.0 }, { 0.0, 0.0 } }; ensemble_collection expected_ensembles = { { 0, 1 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.25, 1, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, one_neuron_oscillation) { network_dynamic dynamic = { { 0.0 }, { 1.0 }, { 0.0 }, { 1.0 }, { 0.0 } }; ensemble_collection expected_ensembles = { { 0 } }; ensemble_collection::value_type expected_dead = { }; template_sync_ensembles(1.0, 0.25, 2, dynamic, expected_ensembles, expected_dead); } TEST(utest_dynamic_analyser, one_neuron_no_oscillation_01) { network_dynamic dynamic = { { 0.0 }, { 0.0 }, { 0.0 }, { 0.0 }, { 0.0 } }; ensemble_collection expected_ensembles = { }; ensemble_collection::value_type expected_dead = { 0 }; template_sync_ensembles(1.0, 0.25, 2, dynamic, expected_ensembles, expected_dead); }pyclustering-0.10.1.2/ccore/tst/utest-elbow.cpp000077500000000000000000000100031375753423500213570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include "utest-elbow.hpp" #include "samples.hpp" #include #define IGNORE_CLUSTERS_CHECK (std::size_t) -1 TEST(utest_elbow, simple_01) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1, 10); } TEST(utest_elbow, simple_01_random_initializer) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1, 10); } TEST(utest_elbow, simple_01_border_step) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), IGNORE_CLUSTERS_CHECK, 1, 3, 1); } TEST(utest_elbow, simple_01_step_2) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), IGNORE_CLUSTERS_CHECK, 1, 10, 2); } TEST(utest_elbow, simple_01_step_3) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), IGNORE_CLUSTERS_CHECK, 1, 10, 3); } TEST(utest_elbow, simple_01_step_4) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), IGNORE_CLUSTERS_CHECK, 1, 10, 4); } TEST(utest_elbow, simple_02) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 1, 10); } TEST(utest_elbow, simple_02_step_2) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 1, 10, 2); } TEST(utest_elbow, simple_02_step_3) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), IGNORE_CLUSTERS_CHECK, 1, 10, 3); } TEST(utest_elbow, simple_02_step_4) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), IGNORE_CLUSTERS_CHECK, 1, 10, 4); } TEST(utest_elbow, simple_02_random_initializer) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 1, 10); } TEST(utest_elbow, simple_03) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, 1, 10); } TEST(utest_elbow, simple_05) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 4, 1, 10); } TEST(utest_elbow, simple_05_step_2) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 4, 1, 10, 3); } TEST(utest_elbow, simple_06) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), 2, 1, 10); } TEST(utest_elbow, one_dimensional_simple_07) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 2, 1, 10); } TEST(utest_elbow, simple_09) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 2, 1, 10); } TEST(utest_elbow, three_dimensional_simple_11) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 1, 10); } TEST(utest_elbow, simple_12) { elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 3, 1, 10); } TEST(utest_elbow, exception_kmin_zero) { EXPECT_THROW({ elbow(0, 10); }, std::invalid_argument); } TEST(utest_elbow, exception_kmax_less_than_kmin) { EXPECT_THROW({ elbow(10, 1); }, std::invalid_argument); } TEST(utest_elbow, exception_kmax_less_than_3_kmin) { EXPECT_THROW({ elbow(1, 2); }, std::invalid_argument); } TEST(utest_elbow, exception_kstep_too_big) { EXPECT_THROW({ elbow(1, 10, 5, RANDOM_STATE_CURRENT_TIME); }, std::invalid_argument); } TEST(utest_elbow, exception_kmax_greater_than_data) { EXPECT_THROW({ elbow_template(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), IGNORE_CLUSTERS_CHECK, 1, 11, 1); }, std::invalid_argument); }pyclustering-0.10.1.2/ccore/tst/utest-elbow.hpp000077500000000000000000000021161375753423500213720ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #pragma once #include #include #include "utenv_check.hpp" #include using namespace pyclustering::clst; template void elbow_template(const dataset_ptr p_data, const std::size_t p_amount_clusters, const std::size_t p_kmin, const std::size_t p_kmax, const std::size_t p_step = 1) { elbow instance(p_kmin, p_kmax, p_step, 1000); elbow_data result; instance.process(*p_data, result); ASSERT_GT(result.get_amount(), p_kmin); ASSERT_LT(result.get_amount(), p_kmax); ASSERT_EQ(result.get_wce().size(), (p_kmax - p_kmin) / p_step + 1); ASSERT_GT(result.get_wce().front(), result.get_wce().back()); if (p_amount_clusters != static_cast(-1)) { ASSERT_EQ(result.get_amount(), p_amount_clusters); } } pyclustering-0.10.1.2/ccore/tst/utest-fcm.cpp000077500000000000000000000257221375753423500210320ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include "utenv_check.hpp" #include #include using namespace pyclustering; using namespace pyclustering::clst; static void template_fcm_data_processing( const dataset_ptr & p_data, const dataset & p_start_centers, const double p_m, const std::vector & p_expected_cluster_length, const std::size_t p_itermax = fcm::DEFAULT_ITERMAX) { fcm_data output_result; fcm solver(p_start_centers, p_m, fcm::DEFAULT_TOLERANCE, p_itermax); solver.process(*p_data, output_result); if (p_itermax == 0) { ASSERT_TRUE(output_result.clusters().empty()); ASSERT_TRUE(output_result.membership().empty()); ASSERT_EQ(p_start_centers, output_result.centers()); return; } for (const auto & probablities : output_result.membership()) { double total_probability = std::accumulate(probablities.begin(), probablities.end(), 0.0); ASSERT_DOUBLE_EQ(1.0, total_probability); } ASSERT_CLUSTER_SIZES(*p_data, output_result.clusters(), p_expected_cluster_length); const std::size_t dimension = p_data->at(0).size(); for (const auto & center : output_result.centers()) { ASSERT_EQ(dimension, center.size()); for (std::size_t dim = 0; dim < center.size(); dim++) { ASSERT_FALSE(std::isnan(center[dim])); } } ASSERT_EQ(output_result.centers().size(), output_result.clusters().size()); } TEST(utest_fcm, allocation_sample_simple_01) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_01_centers_are_points) { dataset start_centers = { { 3.522979, 5.487981 }, { 6.750795, 7.269541 } }; std::vector expected_clusters_length = { 5, 5 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_01_one_cluster) { dataset start_centers = { { 3.7, 5.5 } }; std::vector expected_clusters_length = { 10 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_01_hyper_4) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 4, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_02) { dataset start_centers = { { 3.5, 4.8 },{ 6.9, 7.0 },{ 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_02_centers_are_points) { dataset start_centers = { { 3.889032, 4.103663 }, { 7.090406, 6.647416 }, { 7.482343, 0.762685 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_02_one_cluster) { dataset start_centers = { { 3.5, 4.8 } }; std::vector expected_clusters_length = { 23 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_03) { dataset start_centers = { { 0.2, 0.1 },{ 4.0, 1.0 },{ 2.0, 2.0 },{ 2.3, 3.9 } }; std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_04) { dataset start_centers = { { 1.5, 0.0 }, { 1.5, 2.0 }, { 1.5, 4.0 }, { 1.5, 6.0 }, { 1.5, 8.0 } }; std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_05) { dataset start_centers = { { 0.0, 1.0 }, { 0.0, 0.0 }, { 1.0, 1.0 }, { 1.0, 0.0 } }; std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_07) { dataset start_centers = { { -3.0 }, { 2.0 } }; std::vector expected_clusters_length = { 10, 10 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_07_centers_are_points) { dataset start_centers = { { -2.18865771721 }, { 4.18586756767 } }; std::vector expected_clusters_length = { 10, 10 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_08) { dataset start_centers = { { -4.0 }, { 3.1 }, { 6.1 }, { 12.0 } }; std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_09) { dataset start_centers = { { 4.0 }, { 8.0 } }; std::vector expected_clusters_length = { 10, 20 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_09_centers_are_points) { dataset start_centers = { { 4.1232 }, { 7.8391 } }; std::vector expected_clusters_length = { 30, 0 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_11) { dataset start_centers = { { 1.0, 0.6, 0.8 }, { 4.1, 4.2, 4.3 } }; std::vector expected_clusters_length = { 10, 10 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_sample_simple_12) { dataset start_centers = { { 1.0, 1.0 }, { 2.5, 2.5 }, { 4.0, 4.0 } }; std::vector expected_clusters_length = { 5, 5, 5 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_famous_old_faithful) { dataset start_centers = { { 4.0, 70 }, { 1.0, 48 } }; std::vector expected_clusters_length = { }; template_fcm_data_processing(famous_sample_factory::create_sample(FAMOUS_SAMPLE::OLD_FAITHFUL), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_fcps_hepta) { dataset start_centers = { { -0.06, 0.02, 0.02 }, { 2.41, 0.49, 0.03 }, { -2.69, 0.34, 0.29 }, { 0.49, 2.89, 0.78 }, { -0.60, -2.31, 0.05 }, { -0.15, 0.77, 3.23 }, { -0.50, 0.43, -2.60 } }; std::vector expected_clusters_length = { 30, 30, 30, 30, 30, 30, 32 }; template_fcm_data_processing(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, allocation_fcps_tetra) { dataset start_centers = { { 1.001, -0.083, -0.681 }, { -0.811, 0.476, -0.759 }, { -0.956, -1.427, -0.020 }, { 0.225, 0.560, 1.794 } }; std::vector expected_clusters_length = { 100, 100, 100, 100 }; template_fcm_data_processing(fcps_sample_factory::create_sample(FCPS_SAMPLE::TETRA), start_centers, 2, expected_clusters_length); } TEST(utest_fcm, incorrect_hyper_parameter_positive) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; EXPECT_THROW(fcm(start_centers, 1.0), std::invalid_argument); } TEST(utest_fcm, incorrect_hyper_parameter_negative) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; EXPECT_THROW(fcm(start_centers, -1.0), std::invalid_argument); } TEST(utest_fcm, itermax_0) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 2, expected_clusters_length, 0); } TEST(utest_fcm, itermax_1) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; /* it is enough to make one step to obtain proper result */ template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 2, expected_clusters_length, 1); } TEST(utest_fcm, itermax_10_simple01) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 2, expected_clusters_length, 10); } TEST(utest_fcm, itermax_10_simple02) { dataset start_centers = { { 3.5, 4.8 },{ 6.9, 7.0 },{ 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_fcm_data_processing(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 2, expected_clusters_length, 10); } #ifdef UT_PERFORMANCE_SESSION #include TEST(performance_fcm, big_data) { auto points = simple_sample_factory::create_random_sample(100000, 10); auto centers = simple_sample_factory::create_random_sample(1, 10); auto start = std::chrono::system_clock::now(); const std::size_t repeat = 1; for (std::size_t i = 0; i < repeat; i++) { fcm_data output_result; fcm solver(*centers, 2.0); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } #endifpyclustering-0.10.1.2/ccore/tst/utest-gmeans.cpp000077500000000000000000000245331375753423500215360ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include "answer.hpp" #include "answer_reader.hpp" using namespace pyclustering::clst; using namespace pyclustering::utils::metric; static void template_gmeans_clustering( const dataset_ptr & p_data, const std::size_t p_k_init, const answer & p_answer, const long long p_kmax = gmeans::IGNORE_KMAX) { const std::size_t attempts = 10; for (std::size_t i = 0; i < attempts; i++) { gmeans_data output_result; gmeans(1, gmeans::DEFAULT_TOLERANCE, 3, p_kmax).process(*p_data, output_result); auto expected_cluster_lengths = p_answer.cluster_lengths(); auto expected_clusters = p_answer.clusters(); std::sort(expected_cluster_lengths.begin(), expected_cluster_lengths.end()); auto clusters = output_result.clusters(); auto centers = output_result.centers(); std::vector actual_cluster_lengths; std::set unique; for (const auto & item : clusters) { actual_cluster_lengths.push_back(item.size()); unique.insert(item.begin(), item.end()); } std::sort(actual_cluster_lengths.begin(), actual_cluster_lengths.end()); if (expected_clusters.size() != clusters.size()) { continue; } if (expected_clusters.size() != centers.size()) { continue; } if (p_data->size() != unique.size()) { continue; } if (expected_cluster_lengths != actual_cluster_lengths) { continue; } if (clusters.size() > 1) { if (output_result.wce() <= 0.0) { continue; } } else { if (output_result.wce() < 0.0) { continue; } } return; } FAIL(); } static void template_gmeans_clustering( const dataset_ptr & p_data, const std::size_t p_k_init, const std::vector & p_expected_cluster_lengths, const long long p_kmax = gmeans::IGNORE_KMAX) { const std::size_t attempts = 10; for (std::size_t i = 0; i < attempts; i++) { gmeans_data output_result; gmeans(1, gmeans::DEFAULT_TOLERANCE, 3, p_kmax).process(*p_data, output_result); auto clusters = output_result.clusters(); auto centers = output_result.centers(); std::vector actual_cluster_lengths; std::set unique; for (const auto & item : clusters) { actual_cluster_lengths.push_back(item.size()); unique.insert(item.begin(), item.end()); } std::sort(actual_cluster_lengths.begin(), actual_cluster_lengths.end()); if (p_expected_cluster_lengths.size() != clusters.size()) { continue; } if (p_expected_cluster_lengths.size() != centers.size()) { continue; } if (p_data->size() != unique.size()) { continue; } if (p_expected_cluster_lengths != actual_cluster_lengths) { continue; } if (clusters.size() > 1) { if (output_result.wce() <= 0.0) { continue; } } else { if (output_result.wce() < 0.0) { continue; } } return; } FAIL(); } static void template_gmeans_clustering( const dataset_ptr & p_data, const std::size_t p_k_init, const std::size_t & p_expected_amount_clusters, const long long p_kmax = gmeans::IGNORE_KMAX, const long long p_random_state = RANDOM_STATE_CURRENT_TIME) { const std::size_t attempts = 10; for (std::size_t i = 0; i < attempts; i++) { gmeans_data output_result; gmeans(1, gmeans::DEFAULT_TOLERANCE, 3, p_kmax, p_random_state).process(*p_data, output_result); auto clusters = output_result.clusters(); auto centers = output_result.centers(); std::set unique; for (const auto & item : clusters) { unique.insert(item.begin(), item.end()); } if (p_expected_amount_clusters != clusters.size()) { continue; } if (p_expected_amount_clusters != centers.size()) { continue; } if (p_data->size() != unique.size()) { continue; } if (clusters.size() > 1) { if (output_result.wce() <= 0.0) { continue; } } else { if (output_result.wce() < 0.0) { continue; } } return; } FAIL(); } TEST(utest_gmeans, simple01) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_gmeans, simple01_kmax_1) { std::vector expected_length = { 10 }; template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, expected_length, 1); } TEST(utest_gmeans, simple01_kmax_2) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2); } TEST(utest_gmeans, simple01_kmax_10) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10); } TEST(utest_gmeans, simple02) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02)); } TEST(utest_gmeans, simple02_kmax_1) { std::vector expected_length = { 23 }; template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, expected_length, 1); } TEST(utest_gmeans, simple02_kmax_2) { std::vector expected_length = { 8, 15 }; template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, expected_length, 2); } TEST(utest_gmeans, simple02_kmax_3) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3); } TEST(utest_gmeans, simple02_kmax_4) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 4); } TEST(utest_gmeans, simple02_kmax_10) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 10); } TEST(utest_gmeans, simple03) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03)); } TEST(utest_gmeans, simple05) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05)); } TEST(utest_gmeans, simple06) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06)); } TEST(utest_gmeans, simple07) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07)); } TEST(utest_gmeans, simple08) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08)); } TEST(utest_gmeans, simple09) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09)); } TEST(utest_gmeans, simple10) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10)); } TEST(utest_gmeans, simple11) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11)); } TEST(utest_gmeans, simple12) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12)); } TEST(utest_gmeans, simple13) { template_gmeans_clustering(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13), 1, answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13)); } TEST(utest_gmeans, hepta_kmax_01) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 1, 1, 1); } TEST(utest_gmeans, hepta_kmax_02) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 2, 2, 1); } TEST(utest_gmeans, hepta_kmax_03) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 3, 3, 1); } TEST(utest_gmeans, hepta_kmax_04) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 4, 4, 1); } TEST(utest_gmeans, hepta_kmax_05) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 5, 5, 1); } TEST(utest_gmeans, hepta_kmax_06) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 6, 6, 1); } TEST(utest_gmeans, hepta_kmax_07) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 7, 7, 1); } TEST(utest_gmeans, hepta_kmax_08) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 7, 8, 1); } TEST(utest_gmeans, hepta_kmax_09) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 7, 9, 1); } TEST(utest_gmeans, hepta_kmax_10) { template_gmeans_clustering(fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA), 1, 7, 10, 1); } pyclustering-0.10.1.2/ccore/tst/utest-hhn.cpp000077500000000000000000000247031375753423500210400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "utenv_check.hpp" #include #include #include using namespace pyclustering::differential; using namespace pyclustering::nnet; static void template_create_delete(const std::size_t p_num_osc) { hnn_parameters parameters; hhn_network * network = new hhn_network(p_num_osc, parameters); ASSERT_EQ(p_num_osc, network->size()); delete network; } TEST(utest_hhn, create_10_oscillators) { template_create_delete(10); } TEST(utest_hhn, create_20_oscillators) { template_create_delete(20); } TEST(utest_hhn, create_200_oscillators) { template_create_delete(200); } static void template_collect_dynamic(const std::size_t p_num_osc, const std::size_t p_steps, const hhn_stimulus & p_stimulus, const std::vector & collect) { hnn_parameters parameters; hhn_network network(p_num_osc, parameters); hhn_dynamic output_dynamic; output_dynamic.disable_all(); for (auto & data_type : collect) { output_dynamic.enable(data_type); } /* check collected elements */ std::set collected_types; output_dynamic.get_enabled(collected_types); std::set not_collected_types; output_dynamic.get_disabled(not_collected_types); ASSERT_EQ(collect.size(), collected_types.size()); ASSERT_EQ(4 - collect.size(), not_collected_types.size()); /* simulate and check collected outputs */ network.simulate(p_steps, 10, solve_type::RUNGE_KUTTA_4, p_stimulus, output_dynamic); for (auto & data_type : collected_types) { ASSERT_EQ(p_steps + 1, output_dynamic.get_peripheral_dynamic()->at(data_type).size()); } for (auto & data_type : not_collected_types) { ASSERT_EQ(0U, output_dynamic.get_central_dynamic()->at(data_type).size()); } } TEST(utest_hhn, collect_membran_size_1_steps_10_unstimulated) { hhn_stimulus stimulus({ 0 }); template_collect_dynamic(1, 10, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL }); } TEST(utest_hhn, collect_membran_size_1_steps_10_stimulated) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 10, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL }); } TEST(utest_hhn, collect_active_potassium) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 10, stimulus, { hhn_dynamic::collect::ACTIVE_COND_POTASSIUM }); } TEST(utest_hhn, collect_active_sodium) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 10, stimulus, { hhn_dynamic::collect::ACTIVE_COND_SODIUM }); } TEST(utest_hhn, collect_inactive_sodium) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 10, stimulus, { hhn_dynamic::collect::INACTIVE_COND_SODIUM }); } TEST(utest_hhn, collect_all_parameters) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 10, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL, hhn_dynamic::collect::ACTIVE_COND_SODIUM, hhn_dynamic::collect::INACTIVE_COND_SODIUM, hhn_dynamic::collect::ACTIVE_COND_POTASSIUM }); } TEST(utest_hhn, collect_membran_size_1_steps_50) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 50, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL }); } TEST(utest_hhn, collect_membran_size_1_steps_200) { hhn_stimulus stimulus({ 1 }); template_collect_dynamic(1, 200, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL }); } TEST(utest_hhn, collect_membran_size_5_steps_20) { hhn_stimulus stimulus({ 10, 10, 10, 50, 50 }); template_collect_dynamic(5, 20, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL }); } TEST(utest_hhn, collect_membran_size_5_steps_50) { hhn_stimulus stimulus({ 50, 50, 0, 10, 10 }); template_collect_dynamic(5, 50, stimulus, { hhn_dynamic::collect::MEMBRANE_POTENTIAL }); } static void template_ensemble_generation(const std::size_t p_num_osc, const std::size_t p_steps, const std::size_t p_time, const double p_tolerance, const hhn_stimulus & p_stimulus, basic_ensemble_data & p_expected_ensembles, basic_ensemble & p_expected_dead_neurons) { const std::size_t attempts = 3; bool result = false; for (std::size_t i = 0; (i < attempts) && (result != true); i++) { hnn_parameters parameters; hhn_network network(p_num_osc, parameters); hhn_dynamic output_dynamic; output_dynamic.enable(hhn_dynamic::collect::MEMBRANE_POTENTIAL); /* simulate and check collected outputs */ network.simulate(p_steps, (double) p_time, solve_type::RUNGE_KUTTA_4, p_stimulus, output_dynamic); basic_ensemble_data ensembles; basic_ensemble dead_neurons; hhn_dynamic::evolution_dynamic & membrane_dynamic = output_dynamic.get_peripheral_dynamic(hhn_dynamic::collect::MEMBRANE_POTENTIAL); dynamic_analyser(p_tolerance).allocate_sync_ensembles(membrane_dynamic, ensembles, dead_neurons); if ( !COMPARE_SYNC_ENSEMBLES(ensembles, p_expected_ensembles, dead_neurons, p_expected_dead_neurons) ) { continue; } result = true; } EXPECT_TRUE(result); } TEST(utest_hhn, one_without_stimulation) { basic_ensemble_data expected_ensembles = { }; basic_ensemble dead_neurons = { 0 }; template_ensemble_generation(1, 400, 100, 0.0, { 0 }, expected_ensembles, dead_neurons); } TEST(utest_hhn, one_with_stimulation) { basic_ensemble_data expected_ensembles = { { 0 } }; basic_ensemble dead_neurons = { }; template_ensemble_generation(1, 400, 100, 0.0, { 25 }, expected_ensembles, dead_neurons); } TEST(utest_hhn, global_sync) { basic_ensemble_data expected_ensembles = { { 0, 1, 2 } }; basic_ensemble dead_neurons = { }; template_ensemble_generation(3, 300, 50, 0.0, { 27, 27, 27 }, expected_ensembles, dead_neurons); } TEST(utest_hhn, without_stimulation) { basic_ensemble_data expected_ensembles = { }; basic_ensemble dead_neurons = { 0, 1, 2 }; template_ensemble_generation(3, 400, 100, 0.0, { 0, 0, 0 }, expected_ensembles, dead_neurons); } TEST(utest_hhn, one_with_one_without_stimulation) { basic_ensemble_data expected_ensembles = { { 1 } }; basic_ensemble dead_neurons = { 0 }; template_ensemble_generation(2, 400, 100, 0.0, { 0, 25 }, expected_ensembles, dead_neurons); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_hhn, two_sync_ensembles_01) { basic_ensemble_data expected_ensembles = { { 0, 1 }, { 2, 3 } }; basic_ensemble dead_neurons = { }; template_ensemble_generation(4, 800, 200, 0.1, { 20, 20, 80, 80 }, expected_ensembles, dead_neurons); } TEST(utest_hhn, two_sync_ensembles_02) { basic_ensemble_data expected_ensembles = { { 0, 1, 2 }, { 3, 4, 5 } }; basic_ensemble dead_neurons = { }; template_ensemble_generation(6, 800, 200, 0.1, { 20, 20, 20, 50, 50, 50 }, expected_ensembles, dead_neurons); } #endif static void template_write_read_dynamic(const std::size_t p_num_osc, const std::size_t p_steps, const std::size_t p_time, const hhn_stimulus & p_stimulus, const std::vector & p_enables) { hnn_parameters parameters; hhn_network network(p_num_osc, parameters); hhn_dynamic output_dynamic; output_dynamic.disable_all(); output_dynamic.enable(p_enables); /* simulate and check collected outputs */ network.simulate(p_steps, (double) p_time, solve_type::RUNGE_KUTTA_4, p_stimulus, output_dynamic); const std::string filename = "utest_dynamic_storage.txt"; std::ofstream output_file(filename); output_file << output_dynamic; output_file.close(); hhn_dynamic loaded_dynamic; hhn_dynamic_reader(filename).read(loaded_dynamic); ASSERT_EQ(output_dynamic.size_dynamic(), loaded_dynamic.size_dynamic()); ASSERT_EQ(output_dynamic.size_network(), loaded_dynamic.size_network()); std::stringstream text_dynamic_original; std::stringstream text_dynamic_obtained; text_dynamic_original << output_dynamic; text_dynamic_obtained << loaded_dynamic; ASSERT_EQ(text_dynamic_original.str(), text_dynamic_obtained.str()); } TEST(utest_hhn, wr_one_oscillator) { std::vector enables = { hhn_dynamic::collect::MEMBRANE_POTENTIAL }; template_write_read_dynamic(1, 20, 1, { 40 }, enables); } TEST(utest_hhn, wr_two_oscillators) { std::vector enables = { hhn_dynamic::collect::MEMBRANE_POTENTIAL }; template_write_read_dynamic(2, 30, 1, { 40, 20 }, enables); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_hhn, wr_ten_oscillators) { std::vector enables = { hhn_dynamic::collect::MEMBRANE_POTENTIAL }; template_write_read_dynamic(10, 100, 10, { 10, 10, 10, 12, 12, 12, 20, 20, 20, 20 }, enables); } TEST(utest_hhn, wr_full_dynamic_collection) { std::vector enables = { hhn_dynamic::collect::MEMBRANE_POTENTIAL, hhn_dynamic::collect::ACTIVE_COND_SODIUM, hhn_dynamic::collect::INACTIVE_COND_SODIUM, hhn_dynamic::collect::ACTIVE_COND_POTASSIUM }; template_write_read_dynamic(2, 50, 2, { 40, 20 }, enables); } TEST(utest_hhn, wr_specific_dynamic_collection) { std::vector enables = { hhn_dynamic::collect::MEMBRANE_POTENTIAL, hhn_dynamic::collect::ACTIVE_COND_POTASSIUM }; template_write_read_dynamic(4, 50, 3, { 40, 20, 70, 120 }, enables); } #endif pyclustering-0.10.1.2/ccore/tst/utest-hsyncnet.cpp000077500000000000000000000025611375753423500221140ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::clst; static void template_cluster_allocation(const unsigned int number_clusters) { bool result_testing = false; for (unsigned int i = 0; i < 3; i++) { std::vector > sample; sample.push_back( { 0.1, 0.1 } ); sample.push_back( { 1.2, 1.1 } ); sample.push_back( { 5.0, 5.0 } ); sample.push_back( { 10.2, 10.1 } ); sample.push_back( { 11.3, 11.0 } ); sample.push_back( { 15.1, 15.4 } ); hsyncnet network(&sample, number_clusters, initial_type::EQUIPARTITION); hsyncnet_analyser analyser; network.process(0.998, solve_type::FORWARD_EULER, true, analyser); hsyncnet_cluster_data ensembles; analyser.allocate_clusters(0.1, ensembles); if (number_clusters != ensembles.size()) { continue; } result_testing = true; } ASSERT_TRUE(result_testing); } TEST(utest_hsyncnet, allocation_2_clusters) { template_cluster_allocation(2); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_hsyncnet, allocation_1_clusters) { template_cluster_allocation(1); } #endif pyclustering-0.10.1.2/ccore/tst/utest-interface-agglomerative.cpp000077500000000000000000000012761375753423500250470ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; TEST(utest_interface_agglomerative, agglomerative_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); pyclustering_package * agglomerative_result = agglomerative_algorithm(sample.get(), 2, 0); ASSERT_NE(nullptr, agglomerative_result); delete agglomerative_result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-bsas.cpp000077500000000000000000000014771375753423500231540ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_bsas, bsas_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * bsas_result = bsas_algorithm(sample.get(), 2, 1.0, &metric); ASSERT_NE(nullptr, bsas_result); delete bsas_result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-clique.cpp000077500000000000000000000012571375753423500235020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; TEST(utest_interface_clique, clique_algorithm) { std::shared_ptr sample = pack(dataset({ { 1.0, 1.0 }, { 1.1, 1.0 }, { 1.2, 1.4 }, { 10.0, 10.3 }, { 10.1, 10.2 }, { 10.2, 10.4 } })); pyclustering_package * result = clique_algorithm(sample.get(), 2, 0); ASSERT_EQ((std::size_t) CLIQUE_PACKAGE_SIZE, result->size); delete result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-cure.cpp000077500000000000000000000034011375753423500231470ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_utils.hpp" #include "utenv_check.hpp" #include using namespace pyclustering; TEST(utest_interface_cure, cure_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); void * cure_result = cure_algorithm(sample.get(), 2, 1, 0.5); ASSERT_NE(nullptr, cure_result); std::shared_ptr clusters(cure_get_clusters(cure_result)); ASSERT_EQ(2U, clusters->size); std::shared_ptr representors(cure_get_representors(cure_result)); ASSERT_EQ(2U, representors->size); std::shared_ptr means(cure_get_means(cure_result)); ASSERT_EQ(2U, means->size); cure_data_destroy(cure_result); } TEST(utest_interface_cure, cure_api_long_result) { auto sample_sptr = fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA); std::shared_ptr sample = pack(*sample_sptr); void * cure_result = cure_algorithm(sample.get(), 7, 1, 0.3); ASSERT_NE(nullptr, cure_result); std::shared_ptr clusters(cure_get_clusters(cure_result)); ASSERT_EQ(7U, clusters->size); std::shared_ptr representors(cure_get_representors(cure_result)); ASSERT_EQ(7U, representors->size); std::shared_ptr means(cure_get_means(cure_result)); ASSERT_EQ(7U, means->size); cure_data_destroy(cure_result); }pyclustering-0.10.1.2/ccore/tst/utest-interface-dbscan.cpp000077500000000000000000000012631375753423500234470ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; TEST(utest_interface_dbscan, dbscan_algorithm) { std::shared_ptr sample = pack(dataset({ { 1.0, 1.0 }, { 1.1, 1.0 }, { 1.2, 1.4 }, { 10.0, 10.3 }, { 10.1, 10.2 }, { 10.2, 10.4 } })); pyclustering_package * result = dbscan_algorithm(sample.get(), 4, 2, 0); ASSERT_EQ(3U, result->size); /* allocated clustes + noise */ delete result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-elbow.cpp000077500000000000000000000034241375753423500233260ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_utils.hpp" #include using namespace pyclustering; TEST(utest_interface_elbow, elbow_method) { std::shared_ptr sample = pack(dataset({ { 1.0, 1.0 }, { 1.1, 1.0 }, { 1.2, 1.4 }, { 10.0, 10.3 }, { 10.1, 10.2 }, { 10.2, 10.4 } })); pyclustering_package * result = elbow_method_ikpp(sample.get(), 1, sample->size, 1, RANDOM_STATE_CURRENT_TIME); ASSERT_EQ((std::size_t) ELBOW_PACKAGE_SIZE, result->size); delete result; result = elbow_method_irnd(sample.get(), 1, sample->size, 1, RANDOM_STATE_CURRENT_TIME); ASSERT_EQ((std::size_t) ELBOW_PACKAGE_SIZE, result->size); delete result; } TEST(utest_interface_elbow, elbow_method_simple3_ikpp) { auto sample_ptr = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); std::shared_ptr sample = pack(*sample_ptr); pyclustering_package * result = elbow_method_ikpp(sample.get(), 1, 10, 1, RANDOM_STATE_CURRENT_TIME); ASSERT_EQ((std::size_t) ELBOW_PACKAGE_SIZE, result->size); delete result; } TEST(utest_interface_elbow, elbow_method_simple3_irnd) { auto sample_ptr = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); std::shared_ptr sample = pack(*sample_ptr); pyclustering_package * result = elbow_method_irnd(sample.get(), 1, 10, 1, RANDOM_STATE_CURRENT_TIME); ASSERT_EQ((std::size_t) ELBOW_PACKAGE_SIZE, result->size); delete result; } pyclustering-0.10.1.2/ccore/tst/utest-interface-fcm.cpp000077500000000000000000000016121375753423500227600ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_utils.hpp" using namespace pyclustering; TEST(utest_interface_fcm, fcm_api) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); std::shared_ptr sample = pack(*data); std::shared_ptr centers = pack(dataset({ { 3.7, 5.5 },{ 6.7, 7.5 } })); pyclustering_package * fcm_result = fcm_algorithm(sample.get(), centers.get(), 2.0, 0.001, 200); ASSERT_NE(nullptr, fcm_result); ASSERT_EQ(fcm_package_indexer::FCM_PACKAGE_SIZE, fcm_result->size); delete fcm_result; fcm_result = nullptr; }pyclustering-0.10.1.2/ccore/tst/utest-interface-gmeans.cpp000077500000000000000000000026771375753423500235010ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include "samples.hpp" #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::clst; using namespace pyclustering::utils::metric; TEST(utest_interface_gmeans, gmeans_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); pyclustering_package * gmeans_result = gmeans_algorithm(sample.get(), 2, 0.001, 5, -1, RANDOM_STATE_CURRENT_TIME); ASSERT_NE(nullptr, gmeans_result); ASSERT_EQ(gmeans_result->size, GMEANS_PACKAGE_SIZE); delete gmeans_result; } TEST(utest_interface_gmeans, hepta_kmax_08) { auto data = fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA); auto sample = pack(*data); pyclustering_package * gmeans_result = gmeans_algorithm(sample.get(), 1, 0.001, 3, 8, 1); ASSERT_NE(nullptr, gmeans_result); std::size_t amount_clusters = ((pyclustering_package **)gmeans_result->data)[GMEANS_PACKAGE_INDEX_CLUSTERS]->size; ASSERT_EQ(7ul, amount_clusters); free_pyclustering_package(gmeans_result); } pyclustering-0.10.1.2/ccore/tst/utest-interface-hhn.cpp000077500000000000000000000033201375753423500227660ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering::nnet; static void CHECK_FREE_PACKAGE(pyclustering_package * package) { ASSERT_NE(nullptr, package); ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_hhn, hhn_api) { std::shared_ptr stimulus = pack(hhn_stimulus({ 20, 20, 30, 30, 40, 40 })); hnn_parameters parameters; void * network = hhn_create(6, ¶meters); ASSERT_NE(nullptr, network); void * dynamic = hhn_dynamic_create(true, false, false, true); ASSERT_NE(nullptr, dynamic); hhn_simulate(network, 10, 1.0, 1, stimulus.get(), dynamic); ASSERT_EQ(11U, ((hhn_dynamic *) dynamic)->size_dynamic()); ASSERT_EQ(6U, ((hhn_dynamic *) dynamic)->size_network()); pyclustering_package * package = hhn_dynamic_get_central_evolution(dynamic, 0); CHECK_FREE_PACKAGE(package); package = hhn_dynamic_get_peripheral_evolution(dynamic, 0); CHECK_FREE_PACKAGE(package); package = hhn_dynamic_get_time(dynamic); CHECK_FREE_PACKAGE(package); hhn_dynamic_write(dynamic, "test_hhn_dynamic.txt"); void * dynamic_copy = hhn_dynamic_read("test_hhn_dynamic.txt"); ASSERT_NE(nullptr, dynamic_copy); hhn_dynamic_destroy(dynamic); hhn_dynamic_destroy(dynamic_copy); hhn_destroy(network); } pyclustering-0.10.1.2/ccore/tst/utest-interface-hsyncnet.cpp000077500000000000000000000033701375753423500240510ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering; static void CHECK_FREE_PACKAGE(pyclustering_package * package) { ASSERT_NE(nullptr, package); ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_hsyncnet, hsyncnet_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); void * network_pointer = hsyncnet_create_network(sample.get(), 3, (unsigned int) initial_type::EQUIPARTITION, 3, 0.1); ASSERT_NE(nullptr, network_pointer); void * analyser_pointer = hsyncnet_process(network_pointer, 0.995, (unsigned int) solve_type::FORWARD_EULER, true); ASSERT_NE(nullptr, analyser_pointer); pyclustering_package * package = sync_dynamic_allocate_sync_ensembles(analyser_pointer, 0.1, sync_dynamic_get_size(analyser_pointer) - 1); CHECK_FREE_PACKAGE(package); package = sync_dynamic_allocate_correlation_matrix(analyser_pointer, sync_dynamic_get_size(analyser_pointer) - 1); CHECK_FREE_PACKAGE(package); package = sync_dynamic_get_time(analyser_pointer); CHECK_FREE_PACKAGE(package); package = sync_dynamic_get_output(analyser_pointer); CHECK_FREE_PACKAGE(package); hsyncnet_destroy_network(network_pointer); hsyncnet_analyser_destroy(analyser_pointer); }pyclustering-0.10.1.2/ccore/tst/utest-interface-kmeans.cpp000077500000000000000000000022001375753423500234630ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_kmeans, kmeans_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); std::shared_ptr centers = pack(dataset({ { 1 }, { 10 } })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * kmeans_result = kmeans_algorithm(sample.get(), centers.get(), 0.001, 200, false, &metric); ASSERT_NE(nullptr, kmeans_result); delete kmeans_result; kmeans_result = nullptr; kmeans_result = kmeans_algorithm(sample.get(), centers.get(), 0.1, 100, true, &metric); ASSERT_NE(nullptr, kmeans_result); delete kmeans_result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-kmedians.cpp000077500000000000000000000026221375753423500240100ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_kmedians, kmedians_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); std::shared_ptr medians = pack(dataset({ { 1 }, { 10 } })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * kmedians_result = kmedians_algorithm(sample.get(), medians.get(), 0.001, 100, &metric); ASSERT_NE(nullptr, kmedians_result); delete kmedians_result; } TEST(utest_interface_kmedians, kmedians_api_null_metric) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); std::shared_ptr medians = pack(dataset({ { 1 }, { 10 } })); pyclustering_package * kmedians_result = kmedians_algorithm(sample.get(), medians.get(), 0.001, 100, nullptr); ASSERT_NE(nullptr, kmedians_result); delete kmedians_result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-kmedoids.cpp000077500000000000000000000027551375753423500240230ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::clst; using namespace pyclustering::utils::metric; TEST(utest_interface_kmedoids, kmedoids_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); std::shared_ptr medoids = pack(medoid_sequence({ 2, 4 })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * kmedoids_result = kmedoids_algorithm(sample.get(), medoids.get(), 0.001, 100, &metric, 0); ASSERT_NE(nullptr, kmedoids_result); delete kmedoids_result; } TEST(utest_interface_kmedoids, kmedoids_api_null_metric) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); std::shared_ptr medoids = pack(medoid_sequence({ 2, 4 })); pyclustering_package * kmedoids_result = kmedoids_algorithm(sample.get(), medoids.get(), 0.001, 100, nullptr, 0); ASSERT_NE(nullptr, kmedoids_result); delete kmedoids_result; } pyclustering-0.10.1.2/ccore/tst/utest-interface-legion.cpp000077500000000000000000000032471375753423500234760ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering::nnet; static void CHECK_FREE_PACKAGE(pyclustering_package * package) { ASSERT_NE(nullptr, package); ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_legion, legion_api) { std::shared_ptr stimulus = pack(legion_stimulus({ 1, 0, 1, 1, 0, 1, 1, 1, 1, 1 })); legion_parameters parameters; void * legion_network = legion_create(10, (unsigned int) connection_t::CONNECTION_ALL_TO_ALL, (void *) ¶meters); ASSERT_NE(nullptr, legion_network); void * dynamic = legion_simulate(legion_network, 10, 10, (unsigned) solve_type::RUNGE_KUTTA_4, true, stimulus.get()); ASSERT_NE(nullptr, dynamic); std::size_t size_network = legion_get_size(legion_network); ASSERT_EQ(10U, size_network); pyclustering_package * package = legion_dynamic_get_output(dynamic); CHECK_FREE_PACKAGE(package); package = legion_dynamic_get_inhibitory_output(dynamic); CHECK_FREE_PACKAGE(package); package = legion_dynamic_get_time(dynamic); CHECK_FREE_PACKAGE(package); std::size_t size_dynamic = legion_dynamic_get_size(dynamic); ASSERT_GT(size_dynamic, 0U); legion_dynamic_destroy(dynamic); legion_destroy(legion_network); }pyclustering-0.10.1.2/ccore/tst/utest-interface-mbsas.cpp000077500000000000000000000015061375753423500233220ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_mbsas, mbsas_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * mbsas_result = mbsas_algorithm(sample.get(), 2, 1.0, &metric); ASSERT_NE(nullptr, mbsas_result); delete mbsas_result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-metric.cpp000077500000000000000000000031771375753423500235060ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_metric, euclidean) { std::shared_ptr arguments = pack(std::vector()); double (*p_solver)(const void *, const void *) = nullptr; void * metric_pointer = metric_create(metric_t::EUCLIDEAN, arguments.get(), p_solver); ASSERT_NE(nullptr, metric_pointer); std::shared_ptr point1 = pack(point({1.0, 1.0})); std::shared_ptr point2 = pack(point({2.0, 1.0})); double distance = metric_calculate(metric_pointer, point1.get(), point2.get()); ASSERT_EQ(1.0, distance); metric_destroy(metric_pointer); } TEST(utest_interface_metric, gower) { std::shared_ptr arguments = pack(std::vector({1.0, 0.0})); double (*p_solver)(const void *, const void *) = nullptr; void * metric_pointer = metric_create(metric_t::GOWER, arguments.get(), p_solver); ASSERT_NE(nullptr, metric_pointer); std::shared_ptr point1 = pack(point({1.0, 1.0})); std::shared_ptr point2 = pack(point({2.0, 1.0})); double distance = metric_calculate(metric_pointer, point1.get(), point2.get()); ASSERT_EQ(0.5, distance); metric_destroy(metric_pointer); } pyclustering-0.10.1.2/ccore/tst/utest-interface-optics.cpp000077500000000000000000000012651375753423500235200ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; TEST(utest_interface_optics, optics_algorithm) { std::shared_ptr sample = pack(dataset({ { 1.0, 1.0 }, { 1.1, 1.0 }, { 1.2, 1.4 }, { 10.0, 10.3 }, { 10.1, 10.2 }, { 10.2, 10.4 } })); pyclustering_package * result = optics_algorithm(sample.get(), 4, 2, 2, 0); ASSERT_EQ((std::size_t) OPTICS_PACKAGE_SIZE, result->size); delete result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-pcnn.cpp000077500000000000000000000033641375753423500231570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering::nnet; static void CHECK_FREE_PACKAGE(pyclustering_package * package) { ASSERT_NE(nullptr, package); ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_pcnn, pcnn_api) { std::shared_ptr stimulus = pack(pcnn_stimulus({ 1, 0, 1, 1, 0, 1, 1, 1, 1, 1 })); pcnn_parameters parameters; void * pcnn_network = pcnn_create(10, (unsigned int) connection_t::CONNECTION_ALL_TO_ALL, 0, 0, (void *) ¶meters); ASSERT_NE(nullptr, pcnn_network); void * dynamic = pcnn_simulate(pcnn_network, 10, stimulus.get()); ASSERT_NE(nullptr, dynamic); std::size_t size_network = pcnn_get_size(pcnn_network); ASSERT_EQ(10U, size_network); pyclustering_package * package = pcnn_dynamic_allocate_sync_ensembles(dynamic); CHECK_FREE_PACKAGE(package); package = pcnn_dynamic_allocate_spike_ensembles(dynamic); CHECK_FREE_PACKAGE(package); package = pcnn_dynamic_allocate_time_signal(dynamic); CHECK_FREE_PACKAGE(package); package = pcnn_dynamic_get_output(dynamic); CHECK_FREE_PACKAGE(package); package = pcnn_dynamic_get_time(dynamic); CHECK_FREE_PACKAGE(package); std::size_t size_dynamic = pcnn_dynamic_get_size(dynamic); ASSERT_GT(size_dynamic, 0U); pcnn_dynamic_destroy(dynamic); pcnn_destroy(pcnn_network); } pyclustering-0.10.1.2/ccore/tst/utest-interface-pyclustering.cpp000077500000000000000000000173611375753423500247530ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include template static void template_pyclustering_package(const TypeContainer & container) { using container_data_t = typename TypeContainer::value_type; pyclustering_package * package = create_package(&container); ASSERT_EQ(container.size(), package->size); if (package->type != PYCLUSTERING_TYPE_LIST) { for (std::size_t index = 0; index < container.size(); index++) { ASSERT_EQ(container[index], package->at(index)); } } delete package; } TEST(utest_pyclustering, package_integer) { std::vector container = { 1, 2, 3, 4, 5 }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_double) { std::vector container = { 1.0, 1.5, 2.0, 2.5, 3.0 }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_unsigned) { std::vector container = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_float) { std::vector container = { -1.0, -0.5, 0.0, 0.5, 1.0 }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_size_t) { std::vector container = { 1, 2, 3, 4, 5, 6, 7 }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_empty) { std::vector container = { }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_list) { std::vector> container = { { 1, 2 }, { 1, 2, 3, 4 } }; template_pyclustering_package(container); } TEST(utest_pyclustering, package_pointer_list) { std::vector *> container; container.push_back(new std::vector({ 1, 2, 3, 4, 5})); template_pyclustering_package(container); delete container[0]; } TEST(utest_pyclustering, package_char_message) { const char * message = "message char"; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(std::strlen(message) + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_CHAR, package->type); ASSERT_STREQ(message, (const char *)package->data); } TEST(utest_pyclustering, package_empty_char_message) { const char * message = ""; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(std::strlen(message) + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_CHAR, package->type); ASSERT_STREQ(message, (const char *)package->data); } TEST(utest_pyclustering, package_wchar_message) { const wchar_t * message = L"message wchar_t"; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(std::wcslen(message) + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_WCHAR_T, package->type); ASSERT_EQ(0, std::wcscmp(message, (const wchar_t *)package->data)); } TEST(utest_pyclustering, package_empty_wchar_message) { const wchar_t * message = L""; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(std::wcslen(message) + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_WCHAR_T, package->type); ASSERT_EQ(0, std::wcscmp(message, (const wchar_t *)package->data)); } TEST(utest_pyclustering, package_string_message) { std::string message = "message string"; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(message.size() + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_CHAR, package->type); ASSERT_STREQ(message.c_str(), (const char *)package->data); } TEST(utest_pyclustering, package_empty_string_message) { std::string message = ""; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(message.size() + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_CHAR, package->type); ASSERT_STREQ(message.c_str(), (const char *)package->data); } TEST(utest_pyclustering, package_wstring_message) { std::wstring message = L"message wstring"; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(message.size() + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_WCHAR_T, package->type); ASSERT_EQ(0, std::wcscmp(message.c_str(), (const wchar_t *)package->data)); } TEST(utest_pyclustering, package_empty_wstring_message) { std::wstring message = L""; std::shared_ptr package = std::shared_ptr(create_package(message)); ASSERT_NE(nullptr, package); ASSERT_EQ(message.size() + 1, package->size); ASSERT_EQ(PYCLUSTERING_TYPE_WCHAR_T, package->type); ASSERT_EQ(0, std::wcscmp(message.c_str(), (const wchar_t *)package->data)); } template static void template_two_dimension_pyclustering_package(const TypeContainer & container) { using sub_container_t = typename TypeContainer::value_type; using container_data_t = typename sub_container_t::value_type; pyclustering_package * package = create_package(&container); ASSERT_EQ(container.size(), package->size); for (std::size_t i = 0; i < container.size(); i++) { pyclustering_package * sub_package = package->at(i); ASSERT_EQ(container[i].size(), sub_package->size); for (std::size_t j = 0; j < container[i].size(); j++) { ASSERT_EQ(container[i][j], package->at(i, j)); } } delete package; } TEST(utest_pyclustering, package_two_dimension_integer) { std::vector> container = { { 1, 2, 3 }, { 4, 5 }, { 6, 7, 8, 9 } }; template_two_dimension_pyclustering_package(container); } TEST(utest_pyclustering, package_two_dimension_double) { std::vector> container = { { 1.0, 2.5, 3.0 }, { 4.5, 5.5 }, { 6.1, 7.2, 8.3, 9.4 } }; template_two_dimension_pyclustering_package(container); } TEST(utest_pyclustering, package_two_dimension_empty) { std::vector> container = { { }, { 4, 5 }, { }, { 6 } }; template_two_dimension_pyclustering_package(container); } template static void template_pack_unpack(const Container & container) { pyclustering_package * package = create_package(&container); Container unpack_container; package->extract(unpack_container); ASSERT_EQ(container, unpack_container); delete package; } TEST(utest_pyclustering, package_unpack_int) { template_pack_unpack(std::vector({ 1, 2, 3, 4 })); } TEST(utest_pyclustering, package_unpack_long) { template_pack_unpack(std::vector({ 1, 2, 3, 4, 5, 6 })); } TEST(utest_pyclustering, package_unpack_empty) { template_pack_unpack(std::vector({ })); } TEST(utest_pyclustering, package_unpack_two_dimension) { template_pack_unpack(std::vector>({ { 1.2, 2.4 }, { 3.6, 4.8, 5.0 }, { 6.0 } })); }pyclustering-0.10.1.2/ccore/tst/utest-interface-silhouette.cpp000077500000000000000000000036341375753423500244060ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "samples.hpp" #include "answer.hpp" #include "answer_reader.hpp" #include "utenv_utils.hpp" #include using namespace pyclustering; TEST(utest_interface_silhouette, silhouette) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); answer ans = answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); dataset matrix; distance_matrix(*data, distance_metric_factory::euclidean_square(), matrix); std::shared_ptr data_package = pack(*data); std::shared_ptr matrix_package = pack(matrix); std::shared_ptr cluster_package = pack(ans.clusters()); pyclustering_package * result_points = silhouette_algorithm(data_package.get(), cluster_package.get(), nullptr, 0); pyclustering_package * result_matrix = silhouette_algorithm(matrix_package.get(), cluster_package.get(), nullptr, 1); ASSERT_NE(nullptr, result_points); ASSERT_NE(nullptr, result_matrix); ASSERT_EQ(result_points->size, result_matrix->size); ASSERT_EQ(result_points->type, result_matrix->type); delete result_matrix; delete result_points; } TEST(utest_interface_silhouette, silhouette_ksearch) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); std::shared_ptr sample = pack(*data); pyclustering_package * result = silhouette_ksearch_algorithm(sample.get(), 2, 5, 0, -1); ASSERT_EQ((std::size_t) SILHOUETTE_KSEARCH_PACKAGE_SIZE, result->size); delete result; } pyclustering-0.10.1.2/ccore/tst/utest-interface-som.cpp000077500000000000000000000046631375753423500230220ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::nnet; static void CHECK_FREE_PACKAGE(pyclustering_package * package, const std::size_t size = 0) { ASSERT_NE(nullptr, package); if (size > 0) ASSERT_EQ(size, package->size); else ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_som, som_api) { som_parameters params; void * network = som_create(1, 3, 0, ¶ms); ASSERT_NE(nullptr, network); dataset input_data = { {1.0}, {1.2}, {1.3}, {3.2}, {3.5}, {3.2} }; pyclustering_package * package_dataset = create_package(&input_data); size_t iterations = som_train(network, package_dataset, 100, true); ASSERT_LT(0U, iterations); free_pyclustering_package(package_dataset); pattern input_pattern = {2.3}; pyclustering_package * package_pattern = create_package(&input_pattern); size_t index_winner = som_simulate(network, package_pattern); ASSERT_LE(0U, index_winner); ASSERT_GT(3U, index_winner); free_pyclustering_package(package_pattern); size_t amount_winners = som_get_winner_number(network); ASSERT_LE(0U, amount_winners); size_t network_size = som_get_size(network); ASSERT_EQ(3U, network_size); pyclustering_package * weights = som_get_weights(network); CHECK_FREE_PACKAGE(weights, 3); pyclustering_package * objects = som_get_capture_objects(network); CHECK_FREE_PACKAGE(objects, 3); pyclustering_package * awards = som_get_awards(network); CHECK_FREE_PACKAGE(awards, 3); pyclustering_package * neighbors = som_get_neighbors(network); CHECK_FREE_PACKAGE(neighbors, 3); /* get network dump and upload it again */ weights = som_get_weights(network); awards = som_get_awards(network); objects = som_get_capture_objects(network); som_load(network, weights, awards, objects); CHECK_FREE_PACKAGE(weights, 3); CHECK_FREE_PACKAGE(awards, 3); CHECK_FREE_PACKAGE(objects, 3); /* destroy network */ som_destroy(network); }pyclustering-0.10.1.2/ccore/tst/utest-interface-sync.cpp000077500000000000000000000053071375753423500231740ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering::nnet; static void CHECK_FREE_PACKAGE(pyclustering_package * package, const std::size_t size = 0) { ASSERT_NE(nullptr, package); if (size > 0) ASSERT_EQ(size, package->size); else ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_sync, sync_api) { void * network_pointer = sync_create_network(10, 1, 0, (unsigned int) connection_t::CONNECTION_ALL_TO_ALL, (unsigned int) initial_type::EQUIPARTITION); ASSERT_NE(nullptr, network_pointer); std::size_t network_size = sync_get_size(network_pointer); ASSERT_EQ(10U, network_size); void * dynamic_pointer = sync_simulate_static(network_pointer, 20, 10, (unsigned int) solve_type::FORWARD_EULER, true); ASSERT_NE(nullptr, dynamic_pointer); void * dynamic_flexi_pointer = sync_simulate_dynamic(network_pointer, 0.99, (unsigned int) solve_type::FORWARD_EULER, true, 0.1, 0.01, 0.01); ASSERT_GT(sync_dynamic_get_size(dynamic_flexi_pointer), 0U); sync_dynamic_destroy(dynamic_flexi_pointer); double order_parameter = sync_order(network_pointer); ASSERT_LT(0.9, order_parameter); double local_order_parameter = sync_local_order(network_pointer); ASSERT_LT(0.9, local_order_parameter); std::size_t dynamic_size = sync_dynamic_get_size(dynamic_pointer); ASSERT_EQ(21U, dynamic_size); pyclustering_package * package = sync_connectivity_matrix(network_pointer); CHECK_FREE_PACKAGE(package, 10); package = sync_dynamic_allocate_sync_ensembles(dynamic_pointer, 0.01, dynamic_size - 1); CHECK_FREE_PACKAGE(package, 1); package = sync_dynamic_allocate_correlation_matrix(dynamic_pointer, dynamic_size - 1); CHECK_FREE_PACKAGE(package, 10); package = sync_dynamic_get_time(dynamic_pointer); CHECK_FREE_PACKAGE(package, 21); package = sync_dynamic_get_output(dynamic_pointer); CHECK_FREE_PACKAGE(package, 21); package = sync_dynamic_calculate_order(dynamic_pointer, 0, dynamic_size); CHECK_FREE_PACKAGE(package, dynamic_size); package = sync_dynamic_calculate_local_order(dynamic_pointer, network_pointer, 0, dynamic_size); CHECK_FREE_PACKAGE(package, dynamic_size); sync_dynamic_destroy(dynamic_pointer); sync_destroy_network(network_pointer); }pyclustering-0.10.1.2/ccore/tst/utest-interface-syncnet.cpp000077500000000000000000000033121375753423500236750ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering; static void CHECK_FREE_PACKAGE(pyclustering_package * package) { ASSERT_NE(nullptr, package); ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_syncnet, syncnet_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); void * network_pointer = syncnet_create_network(sample.get(), 3, false, 0); ASSERT_NE(nullptr, network_pointer); void * analyser_pointer = syncnet_process(network_pointer, 0.995, (unsigned int) solve_type::FORWARD_EULER, true); ASSERT_NE(nullptr, analyser_pointer); pyclustering_package * package = sync_dynamic_allocate_sync_ensembles(analyser_pointer, 0.1, sync_dynamic_get_size(analyser_pointer) - 1); CHECK_FREE_PACKAGE(package); package = sync_dynamic_allocate_correlation_matrix(analyser_pointer, sync_dynamic_get_size(analyser_pointer) - 1); CHECK_FREE_PACKAGE(package); package = sync_dynamic_get_time(analyser_pointer); CHECK_FREE_PACKAGE(package); package = sync_dynamic_get_output(analyser_pointer); CHECK_FREE_PACKAGE(package); syncnet_destroy_network(network_pointer); syncnet_analyser_destroy(analyser_pointer); }pyclustering-0.10.1.2/ccore/tst/utest-interface-syncpr.cpp000077500000000000000000000036441375753423500235400ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include "utenv_utils.hpp" using namespace pyclustering; using namespace pyclustering::nnet; static void CHECK_FREE_PACKAGE(pyclustering_package * package) { ASSERT_NE(nullptr, package); ASSERT_TRUE(package->size > 0); free_pyclustering_package(package); } TEST(utest_interface_syncpr, syncpr_api) { void * network_pointer = syncpr_create(9, 5.0, 5.0); ASSERT_NE(nullptr, network_pointer); std::shared_ptr patterns = pack(std::vector({ { 1, 1, -1, 1, 1, -1, 1, 1, -1 } })); syncpr_train(network_pointer, patterns.get()); std::shared_ptr pattern = pack(syncpr_pattern({ 1, 1, -1, 1, 1, -1, 1, 1, -1 })); void * dynamic1 = syncpr_simulate_static(network_pointer, 10, 10, pattern.get(), (unsigned) solve_type::FORWARD_EULER, true); ASSERT_NE(nullptr, dynamic1); void * dynamic2 = syncpr_simulate_dynamic(network_pointer, pattern.get(), 0.95, (unsigned) solve_type::FORWARD_EULER, true, 0.1); ASSERT_NE(nullptr, dynamic2); double memory_order = syncpr_memory_order(network_pointer, pattern.get()); ASSERT_GT(memory_order, 0); pyclustering_package * package = syncpr_dynamic_allocate_sync_ensembles(dynamic1, 0.1); CHECK_FREE_PACKAGE(package); package = syncpr_dynamic_get_time(dynamic1); CHECK_FREE_PACKAGE(package); package = syncpr_dynamic_get_output(dynamic1); CHECK_FREE_PACKAGE(package); syncpr_destroy(network_pointer); syncpr_dynamic_destroy(dynamic1); syncpr_dynamic_destroy(dynamic2); }pyclustering-0.10.1.2/ccore/tst/utest-interface-ttsas.cpp000077500000000000000000000015101375753423500233460ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_ttsas, ttsas_api) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * ttsas_result = ttsas_algorithm(sample.get(), 1.0, 5.0, &metric); ASSERT_NE(nullptr, ttsas_result); delete ttsas_result; }pyclustering-0.10.1.2/ccore/tst/utest-interface-xmeans.cpp000077500000000000000000000024551375753423500235140ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "utenv_utils.hpp" #include using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_interface_xmeans, xmeans_algorithm) { std::shared_ptr sample = pack(dataset({ { 1 }, { 2 }, { 3 }, { 10 }, { 11 }, { 12 } })); std::shared_ptr centers = pack(dataset({ { 1 }, { 2 } })); distance_metric metric = distance_metric_factory::euclidean_square(); pyclustering_package * result = xmeans_algorithm(sample.get(), centers.get(), 5, 0.01, 0, 0.9, 0.9, 1, -1, &metric); ASSERT_EQ(3U, result->size); pyclustering_package * obtained_clusters = ((pyclustering_package **) result->data)[0]; ASSERT_EQ(2U, obtained_clusters->size); pyclustering_package * obtained_centers = ((pyclustering_package **) result->data)[1]; ASSERT_EQ(2U, obtained_centers->size); double obtained_wce = ((double *) result->data)[0]; ASSERT_GE(obtained_wce, 0.0); delete result; } pyclustering-0.10.1.2/ccore/tst/utest-kdtree.cpp000077500000000000000000000475101375753423500215420ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include #include #include #include using namespace pyclustering; using namespace pyclustering::container; using namespace pyclustering::utils::metric; class utest_kdtree : public ::testing::Test { protected: virtual void SetUp() { } virtual void TearDown() { } protected: virtual void InitTestObject(const dataset & points) { tree = kdtree(); for (auto & point : points) { tree.insert(point); } } virtual void TemplateTestBalancedFind(const dataset & p_data) { std::vector payload; for (std::size_t i = 0; i < p_data.size(); i++) { payload.push_back((void *)i); } tree = kdtree(p_data, payload); ASSERT_NE(nullptr, tree.get_root()); ASSERT_EQ(p_data.size(), tree.get_size()); for (std::size_t i = 0; i < p_data.size(); i++) { kdnode::ptr node = tree.find_node(p_data[i], payload[i]); ASSERT_NE(nullptr, node); ASSERT_EQ(p_data[i], node->get_data()); ASSERT_EQ(payload[i], node->get_payload()); } } virtual void TemplateTestBalancedSearch(const dataset & p_data, const double p_radius_search = 10.0) { std::vector payload; for (std::size_t i = 0; i < p_data.size(); i++) { payload.push_back((void *) i); } tree = kdtree(p_data, payload); ASSERT_NE(nullptr, tree.get_root()); ASSERT_EQ(p_data.size(), tree.get_size()); for (std::size_t i = 0; i < p_data.size(); i++) { searcher = kdtree_searcher(p_data[i], tree.get_root(), p_radius_search); FindNearestNode(p_data, i); /* Find the nearest node */ FindNearestNeighbors(p_data, i); /* Find the nearest neighbors */ /* Find nearest using user-specific rule to store result */ std::vector index_points; kdtree_searcher::rule_store rule = [&i, &index_points](const kdnode::ptr node, const double distance) { if (i != (std::size_t) node->get_payload()) { index_points.push_back((std::size_t) node->get_payload()); } }; searcher.find_nearest(rule); ASSERT_EQ(tree.get_size() - 1, index_points.size()); ASSERT_TRUE(std::find(index_points.begin(), index_points.end(), i) == index_points.end()); } } virtual void TemplateTestInsertSearchRemove(const dataset & p_data, const double radius_search = 10.0) { tree = kdtree(); ASSERT_EQ(nullptr, tree.get_root()); for (std::size_t index = 0; index < p_data.size(); index++) { ASSERT_EQ(tree.get_size(), index); tree.insert(p_data[index], (void *) index); ASSERT_EQ(tree.get_size(), index + 1); searcher = kdtree_searcher(p_data[index], tree.get_root(), radius_search); /* Find the nearest node */ FindNearestNode(p_data, index); /* Find the nearest neighbors */ FindNearestNeighbors(p_data, index); /* Find nearest using user-specific rule to store result */ std::vector index_points; kdtree_searcher::rule_store rule = [&index, &index_points](const kdnode::ptr node, const double distance) { if (index != (std::size_t) node->get_payload()) { index_points.push_back((std::size_t) node->get_payload()); } }; searcher.find_nearest(rule); ASSERT_EQ(tree.get_size() - 1, index_points.size()); ASSERT_TRUE(std::find(index_points.begin(), index_points.end(), index) == index_points.end()); } for (std::size_t index = 0; index < p_data.size(); index++) { ASSERT_EQ(tree.get_size(), p_data.size() - index); tree.remove(p_data[index]); ASSERT_EQ(tree.get_size(), p_data.size() - index - 1); } ASSERT_EQ(tree.get_size(), 0U); ASSERT_EQ(tree.get_root(), nullptr); } virtual void TemplateInsertFindRemoveByCoordinatesAndPayload(const dataset & p_data, const std::vector & p_payloads) { tree = kdtree(); std::vector nodes = { }; for (std::size_t i = 0; i < p_data.size(); i++) { nodes.push_back( tree.insert(p_data[i], (void *) &(p_payloads[i])) ); } for (auto & node : nodes) { kdnode::ptr found_node = tree.find_node(node->get_data(), node->get_payload()); ASSERT_EQ(node, found_node); } for (std::size_t i = 0; i < nodes.size(); i++) { tree.remove(nodes[i]->get_data(), nodes[i]->get_payload()); kdnode::ptr found_node = tree.find_node(nodes[i]->get_data(), nodes[i]->get_payload()); ASSERT_EQ(nullptr, found_node); for (std::size_t j = i + 1; j < nodes.size(); j++) { found_node = tree.find_node(nodes[j]->get_data(), nodes[j]->get_payload()); ASSERT_EQ(nodes[j], found_node); } } } private: void FindNearestNode(const dataset & p_data, const std::size_t p_index) { kdnode::ptr nearest_node = searcher.find_nearest_node(); ASSERT_EQ(nearest_node->get_data(), p_data[p_index]); ASSERT_EQ((std::size_t) nearest_node->get_payload(), p_index); } void FindNearestNeighbors(const dataset & p_data, const std::size_t p_index) { std::vector nearest_distances; std::vector nearest_nodes; searcher.find_nearest_nodes(nearest_distances, nearest_nodes); ASSERT_EQ(tree.get_size(), nearest_distances.size()); ASSERT_EQ(tree.get_size(), nearest_nodes.size()); for (auto & found_kdnode : nearest_nodes) { ASSERT_NE(nullptr, found_kdnode); } } protected: kdtree_searcher searcher; kdtree tree; }; TEST_F(utest_kdtree, creation_without_payload) { std::vector< std::vector > test_sample_point_vector = { {4, 3}, {3, 4}, {5, 8}, {3, 3}, {3, 9}, {6, 4}, {5, 9} }; InitTestObject(test_sample_point_vector); std::vector children; tree.get_root()->get_children(children); ASSERT_NE(nullptr, children[0]); ASSERT_NE(nullptr, children[1]); for (auto & point : test_sample_point_vector) { kdnode::ptr node = tree.find_node(point); ASSERT_NE(nullptr, node); ASSERT_EQ(nullptr, node->get_payload()); ASSERT_EQ(point, node->get_data()); } } TEST_F(utest_kdtree, parent_node) { std::vector< std::vector > test_sample_point_vector = { {4, 3}, {3, 4}, {5, 8}, {3, 3}, {3, 9}, {6, 4}, {5, 9} }; InitTestObject(test_sample_point_vector); kdnode::ptr node = tree.find_node(test_sample_point_vector[0]); ASSERT_EQ(nullptr, node->get_parent()); node = tree.find_node(test_sample_point_vector[1]); ASSERT_EQ(test_sample_point_vector[0], node->get_parent()->get_data()); node = tree.find_node(test_sample_point_vector[2]); ASSERT_EQ(test_sample_point_vector[0], node->get_parent()->get_data()); node = tree.find_node(test_sample_point_vector[5]); ASSERT_EQ(test_sample_point_vector[2], node->get_parent()->get_data()); node = tree.find_node(test_sample_point_vector[3]); ASSERT_EQ(test_sample_point_vector[1], node->get_parent()->get_data()); node = tree.find_node(test_sample_point_vector[6]); ASSERT_EQ(test_sample_point_vector[2], node->get_parent()->get_data()); node = tree.find_node(test_sample_point_vector[4]); ASSERT_EQ(test_sample_point_vector[1], node->get_parent()->get_data()); } TEST_F(utest_kdtree, insert_remove_node) { std::vector< char > test_sample_payload = { 'q', 'w', 'e', 'r', 't', 'y', 'u' }; std::vector< std::vector > test_sample_point_vector = { {4, 3}, {3, 4}, {5, 8}, {3, 3}, {3, 9}, {6, 4}, {5, 9} }; for (std::size_t index = 0; index < test_sample_point_vector.size(); index++) { std::vector & point = test_sample_point_vector[index]; char * payload = (char *) &(test_sample_payload[index]); ASSERT_EQ(tree.get_size(), index); tree.insert(point, payload); ASSERT_EQ(tree.get_size(), index + 1); kdnode::ptr node = tree.find_node(point); ASSERT_NE(nullptr, node.get()); ASSERT_EQ(point, node->get_data()); ASSERT_EQ(payload, node->get_payload()); } for (std::size_t index = 0; index < test_sample_point_vector.size(); index++) { std::vector & point = test_sample_point_vector[index]; tree.remove(point); kdnode::ptr node = tree.find_node(test_sample_point_vector[index]); ASSERT_EQ(nullptr, node.get()); for (std::size_t next_index = index + 1; next_index < test_sample_point_vector.size(); next_index++) { node = tree.find_node(test_sample_point_vector[next_index]); std::vector point = test_sample_point_vector[next_index]; ASSERT_EQ(point, node->get_data()); ASSERT_EQ(&test_sample_payload[next_index], node->get_payload()); } } ASSERT_EQ(tree.get_size(), static_cast(0)); } TEST_F(utest_kdtree, find_without_insertion) { std::vector< std::vector > test_sample_point_vector = { {4, 3}, {3, 4}, {5, 8}, {3, 3}, {3, 9}, {6, 4}, {5, 9} }; for (unsigned int index = 0; index < test_sample_point_vector.size(); index++) { std::vector & point = test_sample_point_vector[index]; kdnode::ptr node = tree.find_node(point); ASSERT_EQ(nullptr, node.get()); } } TEST_F(utest_kdtree, remove_long_branch) { std::vector< std::vector > test_sample_point_vector = { {5, 5}, {6, 5}, {6, 6}, {7, 6}, {7, 7} }; InitTestObject(test_sample_point_vector); for (auto & point : test_sample_point_vector) { tree.remove(point); kdnode::ptr node = tree.find_node(point); ASSERT_EQ(nullptr, node); } } TEST_F(utest_kdtree, insert_search_remove_simple_01) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_01) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_02) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_02) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_03) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_03) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_04) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_04) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_05) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_05) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_06) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_06) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_07) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07); TemplateTestInsertSearchRemove(*sample); } TEST_F(utest_kdtree, insert_search_simple_07) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07); TemplateTestBalancedSearch(*sample); } TEST_F(utest_kdtree, insert_search_remove_simple_08) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08); const double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); TemplateTestInsertSearchRemove(*sample, search_radius); } TEST_F(utest_kdtree, insert_search_simple_08) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08); const double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); TemplateTestBalancedSearch(*sample, search_radius); } TEST_F(utest_kdtree, insert_search_remove_simple_10) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10); const double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); TemplateTestInsertSearchRemove(*sample, search_radius); } TEST_F(utest_kdtree, insert_search_simple_10) { auto sample = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10); const double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); TemplateTestBalancedSearch(*sample, search_radius); } TEST_F(utest_kdtree, insert_search_remove_hepta) { auto sample = fcps_sample_factory::create_sample(FCPS_SAMPLE::HEPTA); double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); search_radius += search_radius * 0.0000001; TemplateTestInsertSearchRemove(*sample, search_radius); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST_F(utest_kdtree, insert_search_remove_lsun) { auto sample = fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN); const double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); TemplateTestInsertSearchRemove(*sample, search_radius); } TEST_F(utest_kdtree, insert_search_remove_tetra) { auto sample = fcps_sample_factory::create_sample(FCPS_SAMPLE::TETRA); double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); search_radius += search_radius * 0.0000001; TemplateTestInsertSearchRemove(*sample, search_radius); } TEST_F(utest_kdtree, insert_search_remove_two_diamonds) { auto sample = fcps_sample_factory::create_sample(FCPS_SAMPLE::TWO_DIAMONDS); const double search_radius = farthest_distance(*sample, distance_metric_factory::euclidean()); TemplateTestInsertSearchRemove(*sample, search_radius); } #endif TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_data_1) { dataset data = { {0.1}, {0.1}, {0.1}, {0.1}, {0.2}, {0.2} }; std::vector payloads = { 0, 1, 2, 3, 4, 5 }; TemplateInsertFindRemoveByCoordinatesAndPayload(data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_data_2) { dataset data = { {0.1}, {0.1}, {0.1}, {0.1}, {0.1}, {0.1} }; std::vector payloads = { 0, 1, 2, 3, 4, 5 }; TemplateInsertFindRemoveByCoordinatesAndPayload(data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_data_3) { dataset data = { {0.1}, {0.1}, {0.1}, {0.1}, {0.2}, {0.2} }; std::vector payloads = { 0, 1, 2, 3, 4, 5 }; TemplateInsertFindRemoveByCoordinatesAndPayload(data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_data_4) { dataset data = { {1.2}, {1.2}, {1.3}, {1.3}, {1.4}, {1.4} }; std::vector payloads = { 0, 1, 2, 3, 4, 5 }; TemplateInsertFindRemoveByCoordinatesAndPayload(data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_data_5) { dataset data = { {75, 75}, {75, 75}, {75, 75}, {75, 75}, {75, 75}, {75, 75}, {75, 75}, {75, 75} }; std::vector payloads = { 0, 1, 2, 3, 4, 5, 6, 7 }; TemplateInsertFindRemoveByCoordinatesAndPayload(data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_simple_09) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09); std::vector payloads(data->size()); std::iota(payloads.begin(), payloads.end(), 0); TemplateInsertFindRemoveByCoordinatesAndPayload(*data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_simple_11) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11); std::vector payloads(data->size()); std::iota(payloads.begin(), payloads.end(), 0); TemplateInsertFindRemoveByCoordinatesAndPayload(*data, payloads); } TEST_F(utest_kdtree, insert_search_remove_with_payload_identical_simple_12) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12); std::vector payloads(data->size()); std::iota(payloads.begin(), payloads.end(), 0); TemplateInsertFindRemoveByCoordinatesAndPayload(*data, payloads); } TEST_F(utest_kdtree, balanced_tree_find_simple_01) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_02) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_03) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_04) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_05) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_06) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_07) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_08) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_09) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_10) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_11) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11); TemplateTestBalancedFind(*data); } TEST_F(utest_kdtree, balanced_tree_find_simple_12) { auto data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12); TemplateTestBalancedFind(*data); } pyclustering-0.10.1.2/ccore/tst/utest-kmeans.cpp000077500000000000000000000346031375753423500215410ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; using namespace pyclustering::utils::metric; static void template_kmeans_length_process_data_common( const dataset_ptr & p_data, const dataset & p_start_centers, const std::vector & p_expected_cluster_length, const index_sequence & p_indexes, const bool p_observe, const std::size_t p_itermax = kmeans::DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()) { kmeans_data output_result(p_observe); kmeans solver(p_start_centers, 0.0001, p_itermax, p_metric); if (p_indexes.empty()) { solver.process(*p_data, output_result); } else { solver.process(*p_data, p_indexes, output_result); } const dataset & data = *p_data; const std::size_t dimension = data[0].size(); const cluster_sequence & actual_clusters = output_result.clusters(); const dataset & centers = output_result.centers(); if (p_itermax == 0) { ASSERT_TRUE(actual_clusters.empty()); ASSERT_EQ(p_start_centers, centers); ASSERT_EQ(0.0, output_result.wce()); return; } ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length, p_indexes); for (auto center : centers) { ASSERT_EQ(dimension, center.size()); } ASSERT_EQ(centers.size(), actual_clusters.size()); ASSERT_EQ(p_observe, output_result.is_observed()); if (output_result.is_observed()) { ASSERT_LE(1U, output_result.evolution_centers().size()); ASSERT_LE(1U, output_result.evolution_clusters().size()); for (auto & cluster : output_result.evolution_clusters()) { ASSERT_CLUSTER_SIZES(data, cluster, { }, p_indexes); } } ASSERT_GT(output_result.wce(), 0.0); } static void template_kmeans_length_process_data_range( const dataset_ptr & p_data, const dataset & p_start_centers, const std::vector & p_expected_cluster_length, const index_sequence & p_indexes) { template_kmeans_length_process_data_common(p_data, p_start_centers, p_expected_cluster_length, p_indexes, false); } static void template_kmeans_length_process_data( const dataset_ptr & p_data, const dataset & p_start_centers, const std::vector & p_expected_cluster_length) { template_kmeans_length_process_data_range(p_data, p_start_centers, p_expected_cluster_length, { }); } static void template_kmeans_observer( const dataset_ptr & p_data, const dataset & p_start_centers, const index_sequence & p_indexes, const std::vector & p_expected_cluster_length) { template_kmeans_length_process_data_common(p_data, p_start_centers, p_expected_cluster_length, p_indexes, true); } static void template_kmeans_metric( const dataset_ptr & p_data, const dataset & p_start_centers, const std::vector & p_expected_cluster_length, const distance_metric & p_metric) { template_kmeans_length_process_data_common(p_data, p_start_centers, p_expected_cluster_length, { }, false, kmeans::DEFAULT_ITERMAX, p_metric); } static void template_kmeans_itermax( const dataset_ptr & p_data, const dataset & p_start_centers, const std::vector & p_expected_cluster_length, const std::size_t p_itermax) { template_kmeans_length_process_data_common(p_data, p_start_centers, p_expected_cluster_length, { }, false, p_itermax); } TEST(utest_kmeans, allocation_sample_simple_01) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length); } TEST(utest_kmeans, allocation_sample_simple_01_range) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 3, 3 }; index_sequence range = { 0, 1, 2, 5, 6, 7 }; template_kmeans_length_process_data_range(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, range); } TEST(utest_kmeans, one_cluster_allocation_sample_simple_01) { dataset start_centers = { { 1.0, 2.5 } }; std::vector expected_clusters_length = { 10 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length); } TEST(utest_kmeans, one_cluster_allocation_sample_simple_01_range) { dataset start_centers = { { 1.0, 2.5 } }; std::vector expected_clusters_length = { 6 }; index_sequence range = { 0, 1, 2, 5, 6, 7 }; template_kmeans_length_process_data_range(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, range); } TEST(utest_kmeans, allocation_sample_simpl_01_euclidean) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto metric = distance_metric_factory::euclidean(); template_kmeans_metric(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, metric); } TEST(utest_kmeans, allocation_sample_simpl_01_euclidean_square) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto metric = distance_metric_factory::euclidean_square(); template_kmeans_metric(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, metric); } TEST(utest_kmeans, allocation_sample_simpl_01_manhattan) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto metric = distance_metric_factory::manhattan(); template_kmeans_metric(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, metric); } TEST(utest_kmeans, allocation_sample_simpl_01_chebyshev) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto metric = distance_metric_factory::chebyshev(); template_kmeans_metric(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, metric); } TEST(utest_kmeans, allocation_sample_simpl_01_minkowski) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto metric = distance_metric_factory::minkowski(2.0); template_kmeans_metric(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, metric); } TEST(utest_kmeans, allocation_sample_simpl_01_user_defined) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; auto metric = distance_metric_factory::user_defined(user_metric); template_kmeans_metric(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, metric); } TEST(utest_kmeans, allocation_sample_simple_02) { dataset start_centers = { { 3.5, 4.8 },{ 6.9, 7.0 },{ 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, expected_clusters_length); } TEST(utest_kmeans, allocation_sample_simple_02_range) { dataset start_centers = { { 3.5, 4.8 },{ 6.9, 7.0 },{ 7.5, 0.5 } }; std::vector expected_clusters_length = { 5, 3, 4 }; index_sequence range = { 0, 1, 2, 3, 4, 10, 11, 12, 15, 16, 17, 18 }; template_kmeans_length_process_data_range(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, expected_clusters_length,range); } TEST(utest_kmeans, one_cluster_allocation_sample_simple_02) { dataset start_centers = { { 0.5, 0.2 } }; std::vector expected_clusters_length = { 23 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, expected_clusters_length); } TEST(utest_kmeans, allocation_sample_simple_03) { dataset start_centers = { { 0.2, 0.1 },{ 4.0, 1.0 },{ 2.0, 2.0 },{ 2.3, 3.9 } }; std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, expected_clusters_length); } TEST(utest_kmeans, large_number_centers_sample_simple_01) { dataset start_centers = { { 1.7, 2.6 },{ 3.7, 4.5 },{ 4.5, 1.6 },{ 6.4, 5.0 },{ 2.2, 2.2 } }; std::vector expected_clusters_length; /* pass empty */ template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length); } TEST(utest_kmeans, large_number_centers_sample_simple_02) { dataset start_centers = { { -1.5, 0.8 },{ -4.9, 5.0 },{ 2.3, 3.2 },{ -1.2, -0.8 },{ 2.5, 2.9 },{ 6.8, 7.9 } }; std::vector expected_clusters_length; /* pass empty */ template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, expected_clusters_length); } TEST(utest_kmeans, large_number_centers_sample_simple_03) { dataset start_centers = { { -8.1, 2.3 },{ -4.9, 5.5 },{ 1.3, 8.3 },{ -2.6, -1.7 },{ 5.3, 4.2 },{ 2.1, 0.0 },{ 1.7, 0.4 } }; std::vector expected_clusters_length; /* pass empty */ template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, expected_clusters_length); } TEST(utest_kmeans, one_dimension_sample_simple_07) { dataset start_centers = { { -2.0 },{ 4.0 } }; std::vector expected_clusters_length = { 10, 10 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_centers, expected_clusters_length); } TEST(utest_kmeans, one_dimension_sample_simple_08) { dataset start_centers = { { -4.0 },{ 3.0 },{ 6.0 },{ 10.0 } }; std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), start_centers, expected_clusters_length); } TEST(utest_kmeans, collect_evolution_sample_simple_01) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmeans_observer(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, { }, expected_clusters_length); } TEST(utest_kmeans, collect_evolution_sample_simple_01_one_cluster) { dataset start_centers = { { 1.0, 2.5 } }; std::vector expected_clusters_length = { 10 }; template_kmeans_observer(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, { }, expected_clusters_length); } TEST(utest_kmeans, collect_evolution_sample_simple_01_range) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 3, 3 }; index_sequence range = { 0, 1, 2, 5, 6, 7 }; template_kmeans_observer(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, range, expected_clusters_length); } TEST(utest_kmeans, collect_evolution_sample_simple_02) { dataset start_centers = { { 3.5, 4.8 },{ 6.9, 7.0 },{ 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_kmeans_observer(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, { }, expected_clusters_length); } TEST(utest_kmeans, itermax_0) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { }; template_kmeans_itermax(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, 0); } TEST(utest_kmeans, itermax_1) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; /* it is enough to make one step to obtain proper result */ template_kmeans_itermax(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, 1); } TEST(utest_kmeans, itermax_10_simple01) { dataset start_centers = { { 3.7, 5.5 },{ 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmeans_itermax(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, expected_clusters_length, 10); } TEST(utest_kmeans, itermax_10_simple02) { dataset start_centers = { { 3.5, 4.8 },{ 6.9, 7.0 },{ 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_kmeans_itermax(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, expected_clusters_length, 10); } #ifdef UT_PERFORMANCE_SESSION TEST(performance_kmeans, big_data) { auto points = simple_sample_factory::create_random_sample(100000, 10); auto centers = simple_sample_factory::create_random_sample(1, 10); auto start = std::chrono::system_clock::now(); const std::size_t repeat = 20; for (std::size_t i = 0; i < repeat; i++) { kmeans_data output_result(false); kmeans solver(*centers, 0.0001); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } #endifpyclustering-0.10.1.2/ccore/tst/utest-kmeans_plus_plus.cpp000077500000000000000000000476741375753423500236630ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; void template_kmeans_plus_plus_initialization(const dataset_ptr & p_data, const std::size_t p_amount, const std::size_t p_candidates) { kmeans_plus_plus initializer(p_amount, p_candidates); dataset centers; initializer.initialize(*p_data, centers); ASSERT_EQ(p_amount, centers.size()); for (auto & center : centers) { auto object = std::find(p_data->begin(), p_data->end(), center); ASSERT_NE(p_data->cend(), object); } dataset copy_data = *p_data; std::unique(copy_data.begin(), copy_data.end()); if (copy_data.size() == p_data->size()) { std::unique(centers.begin(), centers.end()); ASSERT_EQ(p_amount, centers.size()); } } TEST(utest_kmeans_plus_plus, no_center_sample_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 0, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, no_center_sample_simple_01_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 0, 1); } TEST(utest_kmeans_plus_plus, no_center_sample_simple_01_two_candidates) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 0, 2); } TEST(utest_kmeans_plus_plus, one_center_sample_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, one_center_sample_simple_01_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 1, 1); } TEST(utest_kmeans_plus_plus, one_center_sample_simple_01_two_candidates) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 1, 2); } TEST(utest_kmeans_plus_plus, two_centers_sample_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, three_center_sample_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 3, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, three_center_sample_simple_01_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 3, 1); } TEST(utest_kmeans_plus_plus, three_center_sample_simple_01_three_candidates) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, 3, 3); } TEST(utest_kmeans_plus_plus, max_centers_sample_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, data->size(), kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, max_centers_sample_simple_01_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, data->size(), 1); } TEST(utest_kmeans_plus_plus, max_centers_sample_simple_01_two_candidates) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, data->size(), 2); } TEST(utest_kmeans_plus_plus, max_centers_sample_simple_01_max_candidates) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization(data, data->size(), data->size()); } TEST(utest_kmeans_plus_plus, one_center_identical_data_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09); template_kmeans_plus_plus_initialization(data, 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, one_center_identical_data_01_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09); template_kmeans_plus_plus_initialization(data, 1, 1); } TEST(utest_kmeans_plus_plus, three_centers_identical_data_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09); template_kmeans_plus_plus_initialization(data, 3, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, max_centers_identical_data_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09); template_kmeans_plus_plus_initialization(data, data->size(), kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, one_center_identical_data_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12); template_kmeans_plus_plus_initialization(data, 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, three_centers_identical_data_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12); template_kmeans_plus_plus_initialization(data, 3, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, max_centers_identical_data_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12); template_kmeans_plus_plus_initialization(data, data->size(), kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, two_centers_two_identical_points) { dataset_ptr data = dataset_ptr( new dataset( { { 0.0 }, { 0.0 } } ) ); template_kmeans_plus_plus_initialization(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, two_centers_two_identical_points_two_candidates) { dataset_ptr data = dataset_ptr( new dataset( { { 0.0 }, { 0.0 } } ) ); template_kmeans_plus_plus_initialization(data, 2, 2); } TEST(utest_kmeans_plus_plus, one_center_totally_identical_data) { dataset_ptr data = dataset_ptr( new dataset( { { 1.4 }, { 1.4 }, { 1.4 }, { 1.4 } } ) ); template_kmeans_plus_plus_initialization(data, 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, two_centers_totally_identical_data) { dataset_ptr data = dataset_ptr( new dataset( { { 1.4 }, { 1.4 }, { 1.4 }, { 1.4 } } ) ); template_kmeans_plus_plus_initialization(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, max_centers_totally_identical_data) { dataset_ptr data = dataset_ptr( new dataset( { { 1.4 }, { 1.4 }, { 1.4 }, { 1.4 } } ) ); template_kmeans_plus_plus_initialization(data, data->size(), kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, points_less_than_centers) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); ASSERT_THROW(template_kmeans_plus_plus_initialization(data, data->size() + 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE), std::invalid_argument); } TEST(utest_kmeans_plus_plus, empty_data) { dataset_ptr data = dataset_ptr( new dataset() ); ASSERT_THROW(template_kmeans_plus_plus_initialization(data, data->size() + 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE), std::invalid_argument); } void template_kmeans_plus_plus_medoid_initialization(const dataset_ptr & p_data, const std::size_t p_amount, const std::size_t p_candidates) { kmeans_plus_plus initializer(p_amount, p_candidates); std::vector medoids; initializer.initialize(*p_data, medoids); ASSERT_EQ(p_amount, medoids.size()); for (const auto medoid : medoids) { ASSERT_LT(medoid, p_data->size()); ASSERT_EQ(1, std::count(medoids.begin(), medoids.end(), medoid)); } } TEST(utest_kmeans_plus_plus, medoids_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_medoid_initialization(data, 1, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, medoids_simple_01_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_medoid_initialization(data, 1, 1); } TEST(utest_kmeans_plus_plus, medoids_simple_01_two_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_medoid_initialization(data, 1, 2); } TEST(utest_kmeans_plus_plus, medoids_simple_01_all_range) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); for (std::size_t i = 1; i < data->size(); i++) { template_kmeans_plus_plus_medoid_initialization(data, i, 1); } } TEST(utest_kmeans_plus_plus, medoids_simple_01_all_range_farthest) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); for (std::size_t i = 1; i < data->size(); i++) { template_kmeans_plus_plus_medoid_initialization(data, i, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } } TEST(utest_kmeans_plus_plus, medoids_simple_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_kmeans_plus_plus_medoid_initialization(data, 0, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, medoids_simple_02_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_kmeans_plus_plus_medoid_initialization(data, 0, 1); } TEST(utest_kmeans_plus_plus, medoids_simple_02_all_range) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); for (std::size_t i = 1; i < data->size(); i++) { template_kmeans_plus_plus_medoid_initialization(data, i, 1); } } TEST(utest_kmeans_plus_plus, medoids_simple_03) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_kmeans_plus_plus_medoid_initialization(data, 0, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, medoids_simple_03_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_kmeans_plus_plus_medoid_initialization(data, 0, 1); } TEST(utest_kmeans_plus_plus, medoids_simple_04) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); template_kmeans_plus_plus_medoid_initialization(data, 0, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, medoids_simple_04_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); template_kmeans_plus_plus_medoid_initialization(data, 0, 1); } TEST(utest_kmeans_plus_plus, medoids_simple_05) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05); template_kmeans_plus_plus_medoid_initialization(data, 0, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, medoids_simple_05_one_candidate) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05); template_kmeans_plus_plus_medoid_initialization(data, 0, 1); } void template_initialize_kmeans(const dataset_ptr & p_data, const std::size_t p_amount, const std::size_t p_candidate, const std::vector & p_expected_cluster_length) { kmeans_plus_plus initializer(p_amount, p_candidate); dataset centers; initializer.initialize(*p_data, centers); kmeans instance(centers, 0.0001); kmeans_data output_result; instance.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_kmeans_plus_plus, allocation_sample_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_initialize_kmeans(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, { 5, 5 }); } TEST(utest_kmeans_plus_plus, allocation_sample_simple_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_initialize_kmeans(data, 3, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, { 10, 5, 8 }); } TEST(utest_kmeans_plus_plus, allocation_sample_simple_03) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_initialize_kmeans(data, 4, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, { 10, 10, 10, 30 }); } TEST(utest_kmeans_plus_plus, allocation_sample_simple_04) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); template_initialize_kmeans(data, 5, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, { 15, 15, 15, 15, 15 }); } void template_kmeans_plus_plus_metric(const dataset_ptr & p_data, const std::size_t p_amount, const std::size_t p_candidate, const kmeans_plus_plus::metric & solver) { kmeans_plus_plus initializer(p_amount, p_candidate, solver); dataset centers; initializer.initialize(*p_data, centers); ASSERT_EQ(p_amount, centers.size()); for (auto & center : centers) { auto object = std::find(p_data->begin(), p_data->end(), center); ASSERT_NE(p_data->cend(), object); } dataset copy_data = *p_data; std::unique(copy_data.begin(), copy_data.end()); if (copy_data.size() == p_data->size()) { std::unique(centers.begin(), centers.end()); ASSERT_EQ(p_amount, centers.size()); } } TEST(utest_kmeans_plus_plus, metric_manhattan) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); kmeans_plus_plus::metric metric = [](const point & p1, const point & p2) { return pyclustering::utils::metric::manhattan_distance(p1, p2); }; template_kmeans_plus_plus_metric(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, metric); } TEST(utest_kmeans_plus_plus, metric_euclidean) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); kmeans_plus_plus::metric metric = [](const point & p1, const point & p2) { return pyclustering::utils::metric::euclidean_distance(p1, p2); }; template_kmeans_plus_plus_metric(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, metric); } void template_kmeans_plus_plus_initialization_range(const dataset_ptr & p_data, const std::size_t p_amount, const std::size_t p_candidate, const index_sequence & p_indexes) { kmeans_plus_plus initializer(p_amount, p_candidate); dataset centers; initializer.initialize(*p_data, p_indexes, centers); ASSERT_EQ(p_amount, centers.size()); for (auto & center : centers) { auto iter_object = std::find(p_data->begin(), p_data->end(), center); ASSERT_NE(p_data->cend(), iter_object); std::size_t index = std::distance(p_data->begin(), iter_object); auto iter_index = std::find(p_indexes.begin(), p_indexes.end(), index); ASSERT_NE(p_indexes.cend(), iter_index); } dataset copy_data = *p_data; std::unique(copy_data.begin(), copy_data.end()); if (copy_data.size() == p_data->size()) { std::unique(centers.begin(), centers.end()); ASSERT_EQ(p_amount, centers.size()); } } TEST(utest_kmeans_plus_plus, range_sample_simple_01) { index_sequence range = { 0, 1, 2, 5, 6, 7 }; dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_initialization_range(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, range); } TEST(utest_kmeans_plus_plus, range_sample_simple_02) { index_sequence range = { 0, 1, 2, 5, 6, 7, 10, 11, 12 }; dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_kmeans_plus_plus_initialization_range(data, 3, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, range); } TEST(utest_kmeans_plus_plus, indexes_less_than_centers) { index_sequence range = { 0 }; dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); ASSERT_THROW(template_kmeans_plus_plus_initialization_range(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE, range), std::invalid_argument); } void template_kmeans_plus_plus_several_runs(const dataset_ptr & p_data, const std::size_t p_amount, const std::size_t p_candidates) { const std::size_t attempts = 10; for (std::size_t i = 0; i < attempts; i++) { index_sequence all_centers; index_sequence centers; kmeans_plus_plus(p_amount, p_candidates).initialize(*p_data, centers); all_centers.insert(std::end(all_centers), std::begin(centers), std::end(centers)); kmeans_plus_plus(p_amount, p_candidates).initialize(*p_data, centers); all_centers.insert(std::end(all_centers), std::begin(centers), std::end(centers)); kmeans_plus_plus(p_amount, p_candidates).initialize(*p_data, centers); all_centers.insert(std::end(all_centers), std::begin(centers), std::end(centers)); index_sequence unique_centers = all_centers; std::unique(unique_centers.begin(), unique_centers.end()); if (unique_centers.size() != all_centers.size()) { continue; } return; } FAIL(); } TEST(utest_kmeans_plus_plus, several_runs_simple_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_several_runs(data, 2, 1); template_kmeans_plus_plus_several_runs(data, 10, 1); } TEST(utest_kmeans_plus_plus, several_runs_simple_more_candidates_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_several_runs(data, 2, 5); template_kmeans_plus_plus_several_runs(data, 9, 10); } TEST(utest_kmeans_plus_plus, several_runs_simple_farthest_candidates_01) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_kmeans_plus_plus_several_runs(data, 2, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); template_kmeans_plus_plus_several_runs(data, 10, kmeans_plus_plus::FARTHEST_CENTER_CANDIDATE); } TEST(utest_kmeans_plus_plus, several_runs_simple_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_kmeans_plus_plus_several_runs(data, 3, 1); template_kmeans_plus_plus_several_runs(data, 23, 1); } TEST(utest_kmeans_plus_plus, several_runs_simple_more_candidates_02) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_kmeans_plus_plus_several_runs(data, 3, 3); template_kmeans_plus_plus_several_runs(data, 23, 12); } TEST(utest_kmeans_plus_plus, several_runs_simple_03) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_kmeans_plus_plus_several_runs(data, 4, 1); template_kmeans_plus_plus_several_runs(data, 8, 1); }pyclustering-0.10.1.2/ccore/tst/utest-kmedians.cpp000077500000000000000000000220031375753423500220450ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_kmedians_length_process_data(const dataset_ptr & p_data, const dataset & p_start_medians, const std::vector & p_expected_cluster_length, const std::size_t p_itermax = kmedians::DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()) { kmedians_data output_result; kmedians solver(p_start_medians, kmedians::DEFAULT_TOLERANCE, p_itermax, p_metric); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const dataset & medians = output_result.medians(); if (p_itermax == 0) { ASSERT_TRUE(actual_clusters.empty()); ASSERT_EQ(p_start_medians, medians); return; } ASSERT_EQ(actual_clusters.size(), medians.size()); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_kmedians, allocation_sample_simple_01) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length); } TEST(utest_kmedians, allocation_sample_simple_01_euclidean) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, kmedians::DEFAULT_ITERMAX, distance_metric_factory::euclidean()); } TEST(utest_kmedians, allocation_sample_simple_01_euclidean_square) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, kmedians::DEFAULT_ITERMAX, distance_metric_factory::euclidean_square()); } TEST(utest_kmedians, allocation_sample_simple_01_manhattan) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, kmedians::DEFAULT_ITERMAX, distance_metric_factory::manhattan()); } TEST(utest_kmedians, allocation_sample_simple_01_chebyshev) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, kmedians::DEFAULT_ITERMAX, distance_metric_factory::chebyshev()); } TEST(utest_kmedians, allocation_sample_simple_01_minkowski) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, kmedians::DEFAULT_ITERMAX, distance_metric_factory::minkowski(2.0)); } TEST(utest_kmedians, allocation_sample_simple_01_user_defined) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, kmedians::DEFAULT_ITERMAX, distance_metric_factory::user_defined(user_metric)); } TEST(utest_kmedians, allocation_sample_simple_02) { dataset start_medians = { { 3.5, 4.8 }, { 6.9, 7.0 }, { 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medians, expected_clusters_length); } TEST(utest_kmedians, allocation_sample_simple_03_hanging) { dataset start_medians = { { 1.80508 , 4.609467 }, { 0.926445, 0.126412 }, { 0.144706, 0.987019 } }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_medians, { }); } TEST(utest_kmedians, allocation_sample_simple_03) { dataset start_medians = { { 0.2, 0.1 }, { 4.0, 1.0 }, { 2.0, 2.0 }, { 2.3, 3.9 } }; std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_medians, expected_clusters_length); } TEST(utest_kmedians, large_number_medians_sample_simple_01) { dataset start_medians = { { 1.7, 2.6 }, { 3.7, 4.5 }, { 4.5, 1.6 }, { 6.4, 5.0 }, { 2.2, 2.2 } }; std::vector expected_clusters_length; /* pass empty */ template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length); } TEST(utest_kmedians, large_number_medians_sample_simple_02) { dataset start_medians = { { -1.5, 0.8 }, { -4.9, 5.0 }, { 2.3, 3.2 }, { -1.2, -0.8 }, { 2.5, 2.9 }, { 6.8, 7.9 } }; std::vector expected_clusters_length; /* pass empty */ template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medians, expected_clusters_length); } TEST(utest_kmedians, large_number_medians_sample_simple_03) { dataset start_medians = { { -8.1, 2.3 }, { -4.9, 5.5 }, { 1.3, 8.3 }, { -2.6, -1.7 }, { 5.3, 4.2 }, { 2.1, 0.0 }, { 1.7, 0.4 } }; std::vector expected_clusters_length; /* pass empty */ template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_medians, expected_clusters_length); } TEST(utest_kmedians, one_dimension_sample_simple_07) { dataset start_medians = { { -2.0 }, { 4.0 } }; std::vector expected_clusters_length = { 10, 10 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_medians, expected_clusters_length); } TEST(utest_kmedians, one_dimension_sample_simple_08) { dataset start_medians = { { -4.0 }, { 3.0 }, { 6.0 }, { 10.0 } }; std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), start_medians, expected_clusters_length); } TEST(utest_kmedians, rough_medians_sample_simple_10) { dataset start_medians = { { 0.0772944481804071, 0.05224990900863469 }, { 1.6021689021213712, 1.0347579135245601 }, { 2.3341008076636096, 1.280022869739064 } }; std::vector expected_clusters_length; /* pass empty */ template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), start_medians, expected_clusters_length); } TEST(utest_kmedians, itermax_0) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, 0); } TEST(utest_kmedians, itermax_1) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, 1); } TEST(utest_kmedians, itermax_10_simple01) { dataset start_medians = { { 3.7, 5.5 }, { 6.7, 7.5 } }; std::vector expected_clusters_length = { 5, 5 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medians, expected_clusters_length, 10); } TEST(utest_kmedians, itermax_10_simple02) { dataset start_medians = { { 3.5, 4.8 }, { 6.9, 7.0 }, { 7.5, 0.5 } }; std::vector expected_clusters_length = { 10, 5, 8 }; template_kmedians_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medians, expected_clusters_length, 20); }pyclustering-0.10.1.2/ccore/tst/utest-kmedoids.cpp000077500000000000000000000403711375753423500220610ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_kmedoids_length_process_data(const dataset_ptr p_data, const medoid_sequence & p_start_medoids, const std::vector & p_expected_cluster_length, const std::size_t p_itermax = kmedoids::DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()) { kmedoids_data output_result; kmedoids solver(p_start_medoids, kmedoids::DEFAULT_TOLERANCE, p_itermax, p_metric); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const medoid_sequence & medoids = output_result.medoids(); if (p_itermax == 0) { ASSERT_TRUE(actual_clusters.empty()); ASSERT_EQ(p_start_medoids, medoids); return; } ASSERT_LE(medoids.size(), p_start_medoids.size()); ASSERT_EQ(medoids.size(), actual_clusters.size()); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } static void template_kmedoids_length_process_distance_matrix(const dataset_ptr p_data, const medoid_sequence & p_start_medoids, const std::vector & p_expected_cluster_length, const std::size_t p_itermax = kmedoids::DEFAULT_ITERMAX, const distance_metric & p_metric = distance_metric_factory::euclidean_square()) { dataset matrix; distance_matrix(*p_data, matrix); kmedoids_data output_result; kmedoids solver(p_start_medoids, kmedoids::DEFAULT_TOLERANCE, p_itermax, p_metric); solver.process(matrix, kmedoids_data_t::DISTANCE_MATRIX, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const medoid_sequence & medoids = output_result.medoids(); if (p_itermax == 0) { ASSERT_TRUE(actual_clusters.empty()); ASSERT_EQ(p_start_medoids, medoids); return; } ASSERT_EQ(p_start_medoids.size(), actual_clusters.size()); ASSERT_EQ(p_start_medoids.size(), medoids.size()); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_kmedoids, allocation_sample_simple_01) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_01_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_01_euclidean) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::euclidean()); } TEST(utest_kmedoids, allocation_sample_simple_01_euclidean_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::euclidean()); } TEST(utest_kmedoids, allocation_sample_simple_01_euclidean_square) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::euclidean_square()); } TEST(utest_kmedoids, allocation_sample_simple_01_euclidean_square_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::euclidean_square()); } TEST(utest_kmedoids, allocation_sample_simple_01_manhattan) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::manhattan()); } TEST(utest_kmedoids, allocation_sample_simple_01_manhattan_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::manhattan()); } TEST(utest_kmedoids, allocation_sample_simple_01_chebyshev) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::chebyshev()); } TEST(utest_kmedoids, allocation_sample_simple_01_chebyshev_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::chebyshev()); } TEST(utest_kmedoids, allocation_sample_simple_01_minkowski) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::minkowski(2.0)); } TEST(utest_kmedoids, allocation_sample_simple_01_minkowski_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::minkowski(2.0)); } TEST(utest_kmedoids, allocation_sample_simple_01_user_defined) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::user_defined(user_metric)); } TEST(utest_kmedoids, allocation_sample_simple_01_user_defined_distance_matrix) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, kmedoids::DEFAULT_ITERMAX, distance_metric_factory::user_defined(user_metric)); } TEST(utest_kmedoids, allocation_sample_one_allocation_simple_01) { const medoid_sequence start_medoids = { 1 }; const std::vector expected_clusters_length = { 10 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_one_allocation_simple_01_distance_matrix) { const medoid_sequence start_medoids = { 1 }; const std::vector expected_clusters_length = { 10 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_02) { const medoid_sequence start_medoids = { 3, 12, 20 }; const std::vector expected_clusters_length = { 10, 5, 8 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_02_distance_matrix) { const medoid_sequence start_medoids = { 3, 12, 20 }; const std::vector expected_clusters_length = { 10, 5, 8 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_one_allocation_sample_simple_02) { const medoid_sequence start_medoids = { 10 }; const std::vector expected_clusters_length = { 23 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_one_allocation_sample_simple_02_distance_matrix) { const medoid_sequence start_medoids = { 10 }; const std::vector expected_clusters_length = { 23 }; template_kmedoids_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_03) { const medoid_sequence start_medoids = { 4, 12, 25, 37 }; const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_04) { const medoid_sequence start_medoids = { 7, 22, 37, 52, 67 }; const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_05) { const medoid_sequence start_medoids = { 7, 22, 37, 52 }; const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_07) { const medoid_sequence start_medoids = { 5, 15 }; const std::vector expected_clusters_length = { 10, 10 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_sample_simple_08) { const medoid_sequence start_medoids = { 5, 35, 50, 100 }; const std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_wrong_initial_medoids_sample_simple_03) { const medoid_sequence start_medoids = { 4, 7, 12, 20, 25, 30, 37 }; const std::vector expected_clusters_length; /* empty - just check index point existence */ template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, allocation_wrong_initial_medoids_sample_simple_04) { const medoid_sequence start_medoids = { 2, 7, 15, 22, 30, 37, 40, 52, 62, 67 }; const std::vector expected_clusters_length; /* empty - just check index point existence */ template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), start_medoids, expected_clusters_length); } TEST(utest_kmedoids, totally_similar_data) { const dataset_ptr dataset = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12); const std::vector expected_clusters_length; /* empty - just check index point existence */ medoid_sequence start_medoids = { 0, 2, 5, 7, 10, 12 }; template_kmedoids_length_process_data(dataset, start_medoids, expected_clusters_length); start_medoids = { 0, 2, 4, 5, 7, 9, 10, 12, 14 }; template_kmedoids_length_process_data(dataset, start_medoids, expected_clusters_length); start_medoids = { 0, 1, 2, 3, 4 }; template_kmedoids_length_process_data(dataset, start_medoids, expected_clusters_length); } TEST(utest_kmedoids, itermax_0) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, 0); } TEST(utest_kmedoids, itermax_1) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, 1); } TEST(utest_kmedoids, itermax_10_simple01) { const medoid_sequence start_medoids = { 1, 5 }; const std::vector expected_clusters_length = { 5, 5 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_medoids, expected_clusters_length, 10); } TEST(utest_kmedoids, itermax_10_simple02) { const medoid_sequence start_medoids = { 3, 12, 20 }; const std::vector expected_clusters_length = { 5, 8, 10 }; template_kmedoids_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_medoids, expected_clusters_length, 10); } //#define UT_PERFORMANCE_SESSION #ifdef UT_PERFORMANCE_SESSION #include TEST(performance_kmedoids, big_data) { const std::size_t cluster_length = 1000; const std::size_t amount_clusters = 10; auto points = simple_sample_factory::create_random_sample(cluster_length, amount_clusters); medoid_sequence start_medoids = { 10, cluster_length, cluster_length * 2, cluster_length * 3, cluster_length * 4, cluster_length * 5 }; auto start = std::chrono::system_clock::now(); const std::size_t repeat = 10; for (std::size_t i = 0; i < repeat; i++) { kmedoids_data output_result; kmedoids solver(start_medoids, 0.0001); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } #endif pyclustering-0.10.1.2/ccore/tst/utest-legion.cpp000077500000000000000000000045041375753423500215350ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::nnet; static void template_create_delete(const unsigned int num_osc, const connection_t type) { legion_parameters parameters; legion_network * network = new legion_network(num_osc, type, parameters); ASSERT_EQ(num_osc, network->size()); delete network; } TEST(utest_legion, create_10_oscillators_none_conn) { template_create_delete(10, connection_t::CONNECTION_NONE); } TEST(utest_legion, create_25_oscillators_grid_four_conn) { template_create_delete(25, connection_t::CONNECTION_GRID_FOUR); } TEST(utest_legion, create_25_oscillators_grid_eight_conn) { template_create_delete(25, connection_t::CONNECTION_GRID_EIGHT); } TEST(utest_legion, create_10_oscillators_bidir_conn) { template_create_delete(10, connection_t::CONNECTION_LIST_BIDIRECTIONAL); } TEST(utest_legion, create_10_oscillators_all_to_all_conn) { template_create_delete(10, connection_t::CONNECTION_ALL_TO_ALL); } static void template_simulation(const legion_stimulus & stimulus, const connection_t type, const solve_type solver, const unsigned int steps, const double time) { legion_parameters parameters; legion_network network(stimulus.size(), type, parameters); legion_dynamic output_legion_dynamic; network.simulate(steps, time, solver, true, stimulus, output_legion_dynamic); ASSERT_EQ(steps, output_legion_dynamic.size()); } TEST(utest_legion, one_unstimulated_oscillator_rk4) { template_simulation({ 0 }, connection_t::CONNECTION_NONE, solve_type::RUNGE_KUTTA_4, 10, 100); } TEST(utest_legion, one_stimulated_oscillator_rk4) { template_simulation({ 1 }, connection_t::CONNECTION_GRID_FOUR, solve_type::RUNGE_KUTTA_4, 10, 100); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_legion, dynamic_simulation_grid_four_rk4) { template_simulation({ 1, 1, 1, 0, 0, 0, 1, 1, 1 }, connection_t::CONNECTION_GRID_FOUR, solve_type::RUNGE_KUTTA_4, 10, 100); } TEST(utest_legion, dynamic_simulation_grid_eight_rk4) { template_simulation({ 1, 1, 1, 0, 0, 0, 1, 1, 1 }, connection_t::CONNECTION_GRID_EIGHT, solve_type::RUNGE_KUTTA_4, 10, 100); } #endif pyclustering-0.10.1.2/ccore/tst/utest-linalg.cpp000077500000000000000000000043541375753423500215310ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::linalg; TEST(utest_lingalg, subtract) { std::vector a = { 2, 3, 4, 5 }; std::vector b = { 1, 2, 3, 4 }; auto result = subtract(a, b); std::vector expected = { 1, 1, 1, 1 }; ASSERT_EQ(expected, result); } TEST(utest_lingalg, subtract_with_number) { std::vector a = { 2, 4, 6, 8 }; auto result = subtract(a, 2); std::vector expected = { 0, 2, 4, 6 }; ASSERT_EQ(expected, result); } TEST(utest_lingalg, multiply) { std::vector a = { 2, 3, 4, 5 }; std::vector b = { 1, 2, 3, 4 }; auto result = multiply(a, b); std::vector expected = { 2, 6, 12, 20 }; ASSERT_EQ(expected, result); } TEST(utest_lingalg, multiply_with_number) { std::vector a = { 2, 3, 4, 5 }; auto result = multiply(a, 2); std::vector expected = { 4, 6, 8, 10 }; ASSERT_EQ(expected, result); } TEST(utest_lingalg, multiply_matrix) { matrix a = { { 1, 1 }, { 2, 2 }, { 3, 3 } }; std::vector b = { 2, 2 }; auto result = multiply(a, b); matrix expected = { { 2, 2 }, { 4, 4 }, { 6, 6 } }; ASSERT_EQ(expected, result); } TEST(utest_lingalg, divide) { std::vector a = { 2, 6, 9, 16 }; std::vector b = { 2, 2, 3, 4 }; auto result = divide(a, b); std::vector expected = { 1, 3, 3, 4 }; ASSERT_EQ(expected, result); } TEST(utest_lingalg, divide_with_number) { std::vector a = { 10, 20, 30, 40 }; auto result = divide(a, 5); std::vector expected = { 2, 4, 6, 8 }; ASSERT_EQ(expected, result); } TEST(utest_linalg, sum_vector) { std::vector a = { 1, 2, 3 }; ASSERT_EQ(6, sum(a)); } TEST(utest_linalg, sum_matrix) { matrix a = { { 1, 1 }, { 2, 2 }, { 3, 3 } }; std::vector expected = { 6, 6 }; ASSERT_EQ(expected, sum(a, 0)); expected = { 2, 4, 6 }; ASSERT_EQ(expected, sum(a, 1)); }pyclustering-0.10.1.2/ccore/tst/utest-mbsas.cpp000077500000000000000000000140051375753423500213620ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_mbsas_length_process_data(const dataset_ptr p_data, const std::size_t & p_amount, const double & p_threshold, const std::vector & p_expected_cluster_length, const distance_metric & p_metric = distance_metric_factory::euclidean()) { mbsas_data output_result; mbsas solver(p_amount, p_threshold, p_metric); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const representative_sequence & actual_repr = output_result.representatives(); for (auto & repr : actual_repr) ASSERT_EQ(data[0].size(), repr.size()); ASSERT_EQ(actual_repr.size(), actual_clusters.size()); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_mbsas, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length); } TEST(utest_mbsas, allocation_sample_simple_01_euclidean) { const std::vector expected_clusters_length = { 5, 5 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::euclidean()); } TEST(utest_mbsas, allocation_sample_simple_01_euclidean_square) { const std::vector expected_clusters_length = { 5, 5 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::euclidean_square()); } TEST(utest_mbsas, allocation_sample_simple_01_manhattan) { const std::vector expected_clusters_length = { 5, 5 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::manhattan()); } TEST(utest_mbsas, allocation_sample_simple_01_chebyshev) { const std::vector expected_clusters_length = { 5, 5 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::chebyshev()); } TEST(utest_mbsas, allocation_sample_simple_01_minkowski) { const std::vector expected_clusters_length = { 5, 5 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::minkowski(2.0)); } TEST(utest_mbsas, allocation_sample_simple_01_user_defined) { const std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 1.0, expected_clusters_length, distance_metric_factory::user_defined(user_metric)); } TEST(utest_mbsas, allocation_one_allocation_sample_simple_01) { const std::vector expected_clusters_length = { 10 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 10.0, expected_clusters_length); } TEST(utest_mbsas, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 5, 8, 10 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 1.0, expected_clusters_length); } TEST(utest_mbsas, allocation_one_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 23 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, 10.0, expected_clusters_length); } TEST(utest_mbsas, allocation_one_dimension_points_1) { const std::vector expected_clusters_length = { 10, 10 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 3, 1.0, expected_clusters_length); } TEST(utest_mbsas, allocation_one_allocation_one_dimension_points_1) { const std::vector expected_clusters_length = { 20 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 3, 10.0, expected_clusters_length); } TEST(utest_mbsas, allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 10, 20 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 3, 1.0, expected_clusters_length); } TEST(utest_mbsas, allocation_one_allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 30 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 3, 10.0, expected_clusters_length); } TEST(utest_mbsas, allocation_three_dimension_points_2) { const std::vector expected_clusters_length = { 10, 10 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 1.0, expected_clusters_length); } TEST(utest_mbsas, allocation_three_allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 20 }; template_mbsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 10.0, expected_clusters_length); }pyclustering-0.10.1.2/ccore/tst/utest-optics.cpp000077500000000000000000000376431375753423500215730ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; using namespace pyclustering::utils::metric; static std::shared_ptr template_optics_length_process_data(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const size_t p_amount_clusters, const std::vector & p_expected_cluster_length) { std::shared_ptr ptr_output_result = std::make_shared(); optics solver(p_radius, p_neighbors, p_amount_clusters); solver.process(*p_data, *ptr_output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = ptr_output_result->clusters(); const optics_object_sequence & objects = ptr_output_result->optics_objects(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); if (p_amount_clusters > 0) { EXPECT_EQ(p_expected_cluster_length.size(), ordering_analyser::extract_cluster_amount(ptr_output_result->cluster_ordering(), ptr_output_result->get_radius())); } EXPECT_EQ(p_data->size(), objects.size()); for (const auto & object : objects) { EXPECT_TRUE(object.m_core_distance == optics::NONE_DISTANCE || object.m_core_distance >= 0.0); EXPECT_TRUE(object.m_reachability_distance == optics::NONE_DISTANCE || object.m_reachability_distance >= 0.0); EXPECT_TRUE(object.m_processed); } return ptr_output_result; } static std::shared_ptr template_optics_length_process_distance_matrix(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const size_t p_amount_clusters, const std::vector & p_expected_cluster_length) { std::shared_ptr ptr_output_result = std::make_shared(); optics solver(p_radius, p_neighbors, p_amount_clusters); dataset matrix; distance_matrix(*p_data, matrix); solver.process(matrix, optics_data_t::DISTANCE_MATRIX, *ptr_output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = ptr_output_result->clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); if (p_amount_clusters > 0) { EXPECT_EQ(p_expected_cluster_length.size(), ordering_analyser::extract_cluster_amount(ptr_output_result->cluster_ordering(), ptr_output_result->get_radius())); } return ptr_output_result; } TEST(utest_optics, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 0.4, 2, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_01_distance_matrix) { const std::vector expected_clusters_length = { 5, 5 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 0.4, 2, 0, expected_clusters_length); } TEST(utest_optics, allocation_one_allocation_simple_01) { const std::vector expected_clusters_length = { 10 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 1, 0, expected_clusters_length); template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 9.0, 1, 0, expected_clusters_length); template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 5.0, 1, 0, expected_clusters_length); } TEST(utest_optics, allocation_one_allocation_simple_01_distance_matrix) { const std::vector expected_clusters_length = { 10 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 1, 0, expected_clusters_length); template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 9.0, 1, 0, expected_clusters_length); template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 5.0, 1, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1.0, 2, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1.0, 2, 0, expected_clusters_length); } TEST(utest_optics, allocation_one_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 23 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 1, 0, expected_clusters_length); } TEST(utest_optics, allocation_one_allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { 23 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 1, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 0.7, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_03_distance_matrix) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 0.7, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_04) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 0.7, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_04_distance_matrix) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 0.7, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_05) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 0.7, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_05_distance_matrix) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 0.7, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_one_dimension) { const std::vector expected_clusters_length = { 10, 10 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 3.0, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_one_dimension_one_allocation) { const std::vector expected_clusters_length = { 20 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 7.0, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_lsun) { const std::vector expected_clusters_length = { 100, 101, 202 }; template_optics_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN), 0.5, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_lsun_distance_matrix) { const std::vector expected_clusters_length = { 100, 101, 202 }; template_optics_length_process_distance_matrix(fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN), 0.5, 3, 0, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_02_large_radius) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 2, 3, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_02_large_radius_distance_matrix) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 2, 3, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_03_large_radius) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 7.0, 4, 4, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_03_large_radius_distance_matrix) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_optics_length_process_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 7.0, 4, 4, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_04_large_radius) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 50.0, 5, 5, expected_clusters_length); } TEST(utest_optics, allocation_sample_simple_05_large_radius) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_optics_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 10.0, 10, 4, expected_clusters_length); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_optics, allocation_sample_lsun_large_radius_10) { const std::vector expected_clusters_length = { 99, 100, 202 }; template_optics_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN), 1.0, 3, 3, expected_clusters_length); } TEST(utest_optics, allocation_sample_lsun_large_radius_19) { const std::vector expected_clusters_length = { 99, 100, 202 }; template_optics_length_process_data(fcps_sample_factory::create_sample(FCPS_SAMPLE::LSUN), 1.9, 3, 3, expected_clusters_length); } #endif static std::shared_ptr template_optics_noise_allocation(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const size_t p_amount_clusters, const std::vector & p_expected_cluster_length, const std::size_t p_noise_length) { std::shared_ptr ptr_output_result = template_optics_length_process_data(p_data, p_radius, p_neighbors, p_amount_clusters, p_expected_cluster_length); EXPECT_EQ(p_noise_length, ptr_output_result->noise().size()); return ptr_output_result; } static std::shared_ptr template_optics_noise_allocation_distance_matrix(const std::shared_ptr & p_data, const double p_radius, const size_t p_neighbors, const size_t p_amount_clusters, const std::vector & p_expected_cluster_length, const std::size_t p_noise_length) { std::shared_ptr ptr_output_result = template_optics_length_process_distance_matrix(p_data, p_radius, p_neighbors, p_amount_clusters, p_expected_cluster_length); EXPECT_EQ(p_noise_length, ptr_output_result->noise().size()); return ptr_output_result; } TEST(utest_optics, noise_allocation_sample_simple_01) { const std::vector expected_clusters_length = { }; template_optics_noise_allocation(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 20, 0, expected_clusters_length, 10); } TEST(utest_optics, noise_allocation_sample_simple_01_distance_matrix) { const std::vector expected_clusters_length = { }; template_optics_noise_allocation_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 20, 0, expected_clusters_length, 10); } TEST(utest_optics, noise_allocation_sample_simple_02) { const std::vector expected_clusters_length = { }; template_optics_noise_allocation(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 0.5, 20, 0, expected_clusters_length, 23); } TEST(utest_optics, noise_allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { }; template_optics_noise_allocation_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 0.5, 20, 0, expected_clusters_length, 23); } TEST(utest_optics, noise_cluster_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 10 }; template_optics_noise_allocation(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2.0, 9, 0, expected_clusters_length, 13); } TEST(utest_optics, noise_cluster_allocation_sample_simple_02_distance_matrix) { const std::vector expected_clusters_length = { 10 }; template_optics_noise_allocation_distance_matrix(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2.0, 9, 0, expected_clusters_length, 13); } #ifdef UT_PERFORMANCE_SESSION #include TEST(performance_optics, big_data) { auto points = simple_sample_factory::create_random_sample(5000, 10); auto start = std::chrono::system_clock::now(); const std::size_t repeat = 1; for (std::size_t i = 0; i < repeat; i++) { optics_data output_result; optics solver(0.1, 40); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } TEST(performance_optics, engy_time) { auto points = fcps_sample_factory::create_sample(FCPS_SAMPLE::ENGY_TIME); auto start = std::chrono::system_clock::now(); const std::size_t repeat = 30; for (std::size_t i = 0; i < repeat; i++) { optics_data output_result; optics solver(0.2, 20); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } TEST(performance_optics, atom) { auto points = fcps_sample_factory::create_sample(FCPS_SAMPLE::ATOM); auto start = std::chrono::system_clock::now(); const std::size_t repeat = 20; for (std::size_t i = 0; i < repeat; i++) { optics_data output_result; optics solver(15, 3); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } TEST(performance_optics, chainlink) { auto points = fcps_sample_factory::create_sample(FCPS_SAMPLE::CHAINLINK); auto start = std::chrono::system_clock::now(); const std::size_t repeat = 20; for (std::size_t i = 0; i < repeat; i++) { optics_data output_result; optics solver(0.15, 3); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } #endif pyclustering-0.10.1.2/ccore/tst/utest-ordering_analyser.cpp000077500000000000000000000021411375753423500237620ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering::clst; TEST(utest_ordering, cluster_allocation_identical_ordering) { ordering cluster_ordering = {5.0, 5.0, 5.0, 5.0, 5.0, 5.0}; EXPECT_EQ(1U, ordering_analyser::extract_cluster_amount(cluster_ordering, 6.5)); EXPECT_EQ(0U, ordering_analyser::extract_cluster_amount(cluster_ordering, 4.5)); } TEST(utest_ordering, impossible_calculate_radius_identical_ordering) { ordering cluster_ordering = {5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0}; EXPECT_TRUE(ordering_analyser::calculate_connvectivity_radius(cluster_ordering, 2) < 0); } TEST(utest_ordering, impossible_calculate_radius_geterogeneous_ordering) { ordering cluster_ordering = {5.0, 5.0, 5.0, 5.0, 6.0, 8.0, 6.0, 5.0, 5.0, 5.0}; EXPECT_TRUE(ordering_analyser().calculate_connvectivity_radius(cluster_ordering, 3) < 0); } pyclustering-0.10.1.2/ccore/tst/utest-parallel_for.cpp000077500000000000000000000171631375753423500227270ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::parallel; static void template_parallel_square(const std::size_t p_length, const std::size_t p_step = 1, const std::size_t p_threads = -1) { std::vector values(p_length); std::iota(values.begin(), values.end(), 0); std::vector results(p_length); if (p_threads == (std::size_t) -1) { parallel_for(std::size_t(0), values.size(), p_step, [&values, &results](const std::size_t p_index) { results[p_index] = values[p_index] * values[p_index]; }); } else { parallel_for(std::size_t(0), values.size(), p_step, [&values, &results](const std::size_t p_index) { results[p_index] = values[p_index] * values[p_index]; }, p_threads); } for (std::size_t i = 0; i < p_length; i += p_step) { ASSERT_EQ(values[i] * values[i], results[i]); } } TEST(utest_parallel_for, square_1_element) { template_parallel_square(1); } TEST(utest_parallel_for, square_3_element) { template_parallel_square(3); } TEST(utest_parallel_for, square_10_elements) { template_parallel_square(10); } TEST(utest_parallel_for, square_elements_step_increase) { for (std::size_t i = 0; i < 50; i++) { template_parallel_square(i); } } TEST(utest_parallel_for, square_10000_elements) { template_parallel_square(10000); } TEST(utest_parallel_for, square_10_elements_step_2) { template_parallel_square(10, 2); } TEST(utest_parallel_for, square_10_elements_step_2_thread_1) { template_parallel_square(10, 2, 1); } TEST(utest_parallel_for, square_10_elements_step_3) { template_parallel_square(10, 3); } TEST(utest_parallel_for, square_10_elements_step_3_thread_1) { template_parallel_square(10, 3, 1); } TEST(utest_parallel_for, square_20_elements_step_2) { template_parallel_square(20, 2); } TEST(utest_parallel_for, square_20_elements_step_2_thread_1) { template_parallel_square(20, 2, 1); } TEST(utest_parallel_for, square_20_elements_step_2_thread_increase) { for (std::size_t i = 1; i < 16; i++) { template_parallel_square(20, 2, i); } } TEST(utest_parallel_for, square_20_elements_step_3) { template_parallel_square(20, 3); } TEST(utest_parallel_for, square_20_elements_step_3_thread_1) { template_parallel_square(20, 3, 1); } TEST(utest_parallel_for, square_20_elements_step_4) { template_parallel_square(20, 4); } TEST(utest_parallel_for, square_20_elements_step_4_thread_1) { template_parallel_square(20, 4, 1); } TEST(utest_parallel_for, square_100_elements_step_2) { template_parallel_square(100, 2); } TEST(utest_parallel_for, square_100_elements_step_2_thread_1) { template_parallel_square(100, 2, 1); } TEST(utest_parallel_for, square_100_elements_step_3) { template_parallel_square(100, 3); } TEST(utest_parallel_for, square_100_elements_step_3_thread_1) { template_parallel_square(100, 3, 1); } TEST(utest_parallel_for, square_100_elements_step_3_thread_2) { template_parallel_square(100, 3, 2); } TEST(utest_parallel_for, square_100_elements_step_3_thread_increase) { for (std::size_t i = 1; i < 16; i++) { template_parallel_square(100, 3, i); } } TEST(utest_parallel_for, square_100_elements_step_5) { template_parallel_square(100, 5); } TEST(utest_parallel_for, square_100_elements_step_5_thread_2) { template_parallel_square(100, 5, 2); } TEST(utest_parallel_for, square_100_elements_step_10) { template_parallel_square(100, 10); } TEST(utest_parallel_for, square_1000_elements_step_13) { template_parallel_square(1000, 13); } TEST(utest_parallel_for, square_1000_elements_step_13_thread_1) { template_parallel_square(1000, 13, 1); } TEST(utest_parallel_for, square_100_elements_step_increase) { for (std::size_t i = 1; i < 100; i++) { /* go over the limit as well */ template_parallel_square(100, i); } } static void template_parallel_for_sum(const std::size_t p_length) { std::vector values(p_length); std::iota(values.begin(), values.end(), 0); parallel_for(std::size_t(0), p_length, [&values](const std::size_t p_index) { values[p_index] = values[p_index] + values[p_index]; }); for (std::size_t i = 0; i < p_length; i++) { ASSERT_EQ(i + i, values[i]); } } TEST(utest_parallel_for, sum_1000000_elements) { template_parallel_for_sum(1000000); } static void template_parallel_foreach_square(const std::size_t p_length, const std::size_t p_thread = -1) { std::vector values(p_length); std::iota(values.begin(), values.end(), 0); if (p_thread == (std::size_t) -1) { parallel_for_each(std::begin(values), std::end(values), [](double & value) { value = value * value; }); } else { parallel_for_each(std::begin(values), std::end(values), [](double & value) { value = value * value; }, p_thread); } for (std::size_t i = 0; i < p_length; i++) { ASSERT_EQ(i * i, values[i]); } } TEST(utest_parallel_for_each, square_1_element) { template_parallel_foreach_square(1); } TEST(utest_parallel_for_each, square_1_element_thread_1) { template_parallel_foreach_square(1, 1); } TEST(utest_parallel_for_each, square_3_element) { template_parallel_foreach_square(3); } TEST(utest_parallel_for_each, square_3_element_thread_1) { template_parallel_foreach_square(3, 1); } TEST(utest_parallel_for_each, square_10_elements) { template_parallel_foreach_square(10); } TEST(utest_parallel_for_each, square_10_elements_thread_1) { template_parallel_foreach_square(10, 1); } TEST(utest_parallel_for_each, square_100_elements) { template_parallel_foreach_square(100); } TEST(utest_parallel_for_each, square_100_elements_thread_1) { template_parallel_foreach_square(100, 1); } TEST(utest_parallel_for_each, square_123_elements) { template_parallel_foreach_square(123); } TEST(utest_parallel_for_each, square_123_elements_thread_1) { template_parallel_foreach_square(123, 1); } TEST(utest_parallel_for_each, square_1000_elements) { template_parallel_foreach_square(1000); } static void template_parallel_foreach_sum(const std::size_t p_length, const std::size_t p_thread = -1) { std::vector values(p_length); std::iota(values.begin(), values.end(), 0); if (p_thread == static_cast(-1)) { parallel_for_each(std::begin(values), std::end(values), [](double & value) { value = value + value; }); } else { parallel_for_each(std::begin(values), std::end(values), [](double & value) { value = value + value; }, p_thread); } for (std::size_t i = 0; i < p_length; i++) { ASSERT_EQ(i + i, values[i]); } } TEST(utest_parallel_for_each, increase_length_to_500) { for (std::size_t i = 1; i < 500; i++) { template_parallel_foreach_sum(i); } } TEST(utest_parallel_for_each, increase_length_to_500_thread_1) { for (std::size_t i = 1; i < 500; i++) { template_parallel_foreach_sum(i, 1); } } TEST(utest_parallel_for_each, sum_1000000_elements) { template_parallel_foreach_sum(1000000); } pyclustering-0.10.1.2/ccore/tst/utest-pcnn.cpp000077500000000000000000000306701375753423500212210ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::nnet; static void template_dynamic_generation_runner( pcnn & network, const std::size_t steps, const connection_t type_conn, const pcnn_stimulus & stimulus) { pcnn_dynamic dynamic; network.simulate(steps, stimulus, dynamic); ASSERT_EQ(steps, dynamic.size()); /* check that each iteration of output dynamic has states for the same number of oscillators */ for (std::size_t index = 0; index < network.size(); index++) { ASSERT_EQ(network.size(), dynamic[index].m_output.size()); ASSERT_EQ(network.size(), dynamic.at(index).size()); } pcnn_time_signal time_signal; dynamic.allocate_time_signal(time_signal); ASSERT_EQ(steps, time_signal.size()); } static void template_dynamic_generation( const size_t num_osc, const unsigned int steps, const connection_t type_conn, const pcnn_stimulus & stimulus) { pcnn_parameters parameters; pcnn network(num_osc, type_conn, parameters); template_dynamic_generation_runner(network, steps, type_conn, stimulus); } static void template_rectangle_network_dynamic_generation( const size_t num_osc, const unsigned int steps, const connection_t type_conn, const size_t height, const size_t width, const pcnn_stimulus & stimulus) { pcnn_parameters parameters; pcnn network(num_osc, type_conn, height, width, parameters); template_dynamic_generation_runner(network, steps, type_conn, stimulus); } TEST(utest_pcnn, create_delete) { pcnn_parameters parameters; pcnn * network = new pcnn(100, connection_t::CONNECTION_ALL_TO_ALL, parameters); ASSERT_EQ(100U, network->size()); delete network; } TEST(utest_pcnn, dynamic_generation_none_connections) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_NONE, stimulus); } TEST(utest_pcnn, dynamic_generation_grid_four_connections) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_FOUR, stimulus); } TEST(utest_pcnn, dynamic_generation_grid_four_rectangle_connections) { pcnn_stimulus stimulus{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_rectangle_network_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_FOUR, 2, 8, stimulus); } TEST(utest_pcnn, dynamic_generation_grid_eight_connections) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_EIGHT, stimulus); } TEST(utest_pcnn, dynamic_generation_grid_eight_rectangle_connections) { pcnn_stimulus stimulus{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_rectangle_network_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_EIGHT, 8, 2, stimulus); } TEST(utest_pcnn, dynamic_generation_bidir_list_connections) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_LIST_BIDIRECTIONAL, stimulus); } TEST(utest_pcnn, dynamic_generation_all_to_all_connections) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_ALL_TO_ALL, stimulus); } TEST(utest_pcnn, dynamic_none_connections_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_NONE, stimulus); } TEST(utest_pcnn, dynamic_grid_four_connections_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_FOUR, stimulus); } TEST(utest_pcnn, dynamic_grid_four_connections_rectangle_stimulated) { pcnn_stimulus stimulus{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_rectangle_network_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_FOUR, 2, 8, stimulus); } TEST(utest_pcnn, dynamic_grid_eight_connections_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_EIGHT, stimulus); } TEST(utest_pcnn, dynamic_grid_eight_connections_rectangle_stimulated) { pcnn_stimulus stimulus{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_rectangle_network_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_GRID_EIGHT, 8, 2, stimulus); } TEST(utest_pcnn, dynamic_bidir_list_connections_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_LIST_BIDIRECTIONAL, stimulus); } TEST(utest_pcnn, dynamic_all_to_all_connections_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_dynamic_generation(stimulus.size(), 20, connection_t::CONNECTION_ALL_TO_ALL, stimulus); } static void template_output_activity( const size_t num_osc, const unsigned int steps, const connection_t type_conn, const pcnn_stimulus & stimulus, const bool activity_requirement, const pcnn_parameters * const params = nullptr) { pcnn_parameters parameters; if (params != nullptr) { parameters = *params; } pcnn network(num_osc, type_conn, parameters); pcnn_dynamic dynamic; network.simulate(steps, stimulus, dynamic); ensemble_data sync_ensembles; ensemble_data spike_ensembles; pcnn_time_signal time_signal; dynamic.allocate_sync_ensembles(sync_ensembles); dynamic.allocate_spike_ensembles(spike_ensembles); dynamic.allocate_time_signal(time_signal); ASSERT_EQ(steps, dynamic.size()); /* check time signal for activity */ bool output_activity = false; for (size_t i = 0; i < time_signal.size(); i++) { if (time_signal[i] > 0) { output_activity = true; break; } } ASSERT_EQ(activity_requirement, output_activity); /* if activity exists in time signal then at least one ensemble should be */ ASSERT_EQ(activity_requirement, (sync_ensembles.size() > 0)); ASSERT_EQ(activity_requirement, (spike_ensembles.size() > 0)); } TEST(utest_pcnn, no_output_activity) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_ALL_TO_ALL, stimulus, false); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_EIGHT, stimulus, false); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_FOUR, stimulus, false); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_LIST_BIDIRECTIONAL, stimulus, false); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_NONE, stimulus, false); } TEST(utest_pcnn, output_activity_full_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_ALL_TO_ALL, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_EIGHT, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_FOUR, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_LIST_BIDIRECTIONAL, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_NONE, stimulus, true); } TEST(utest_pcnn, output_activity_partial_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0 }; template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_ALL_TO_ALL, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_EIGHT, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_FOUR, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_LIST_BIDIRECTIONAL, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_NONE, stimulus, true); } TEST(utest_pcnn, output_activity_one_stimulated) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_ALL_TO_ALL, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_EIGHT, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_GRID_FOUR, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_LIST_BIDIRECTIONAL, stimulus, true); template_output_activity(stimulus.size(), 30, connection_t::CONNECTION_NONE, stimulus, true); } static void template_ensemble_allocation( const size_t num_osc, const unsigned int steps, const connection_t type_conn, const pcnn_stimulus & stimulus, const pcnn_parameters * const params = nullptr) { pcnn_parameters parameters; if (params != nullptr) { parameters = *params; } pcnn network(num_osc, type_conn, parameters); pcnn_dynamic dynamic; network.simulate(steps, stimulus, dynamic); ensemble_data sync_ensembles; ensemble_data spike_ensembles; pcnn_time_signal time_signal; dynamic.allocate_sync_ensembles(sync_ensembles); dynamic.allocate_spike_ensembles(spike_ensembles); dynamic.allocate_time_signal(time_signal); ASSERT_EQ(steps, dynamic.size()); for (ensemble_data::const_iterator iter = spike_ensembles.cbegin(); iter != spike_ensembles.cend(); iter++) { const pcnn_ensemble & ensemble = (*iter); ASSERT_NE(time_signal.cend(), std::find(time_signal.cbegin(), time_signal.cend(), ensemble.size())); } std::unordered_set traverse_oscillators; for (ensemble_data::const_iterator iter = sync_ensembles.cbegin(); iter != sync_ensembles.cend(); iter++) { const pcnn_ensemble & ensemble = (*iter); for (pcnn_ensemble::const_iterator iter_index = ensemble.cbegin(); iter_index != ensemble.cend(); iter_index++) { size_t index_oscillator = (*iter_index); ASSERT_EQ(traverse_oscillators.end(), traverse_oscillators.find(index_oscillator)); traverse_oscillators.insert(index_oscillator); } } } TEST(utest_pcnn, ensemble_allocation_all_stimulated) { pcnn_stimulus stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; template_ensemble_allocation(stimulus.size(), 20, connection_t::CONNECTION_ALL_TO_ALL, stimulus); } TEST(utest_pcnn, ensemble_allocation_partial_stimulated) { pcnn_stimulus stimulus { 1, 0, 0, 1, 1, 1, 0, 0, 1, 1 }; template_ensemble_allocation(stimulus.size(), 20, connection_t::CONNECTION_ALL_TO_ALL, stimulus); } TEST(utest_pcnn, ensemble_allocation_unstimulated) { pcnn_stimulus stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; template_ensemble_allocation(stimulus.size(), 20, connection_t::CONNECTION_ALL_TO_ALL, stimulus); } TEST(utest_pcnn, ensemble_allocation_fast_linking) { pcnn_stimulus full_stimulus { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; pcnn_stimulus partial_stimulus { 1, 0, 0, 1, 1, 1, 0, 0, 1, 1 }; pcnn_stimulus no_stimulus { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; pcnn_parameters params; params.FAST_LINKING = true; template_ensemble_allocation(full_stimulus.size(), 50, connection_t::CONNECTION_ALL_TO_ALL, full_stimulus, ¶ms); template_ensemble_allocation(partial_stimulus.size(), 50, connection_t::CONNECTION_ALL_TO_ALL, partial_stimulus, ¶ms); template_ensemble_allocation(no_stimulus.size(), 50, connection_t::CONNECTION_ALL_TO_ALL, no_stimulus, ¶ms); } pyclustering-0.10.1.2/ccore/tst/utest-random_center_initializer.cpp000077500000000000000000000033771375753423500255120ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include using namespace pyclustering::clst; static void template_random_seed( const std::size_t p_random_seed, const std::size_t p_amount, const dataset_ptr p_data, const std::size_t p_repeat = 1) { for (std::size_t i = 0; i < p_repeat; i++) { dataset centers1, centers2; random_center_initializer(p_amount, p_random_seed).initialize(*p_data, centers1); random_center_initializer(p_amount, p_random_seed).initialize(*p_data, centers2); ASSERT_EQ(centers1, centers2); } } TEST(utest_random_center_initializer, random_seed_n_1) { template_random_seed(1, 1, simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_random_center_initializer, random_seed_n_2) { template_random_seed(1, 2, simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_random_center_initializer, random_seed_n_3) { template_random_seed(1, 3, simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_random_center_initializer, random_seed_n_4) { template_random_seed(1, 4, simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_random_center_initializer, random_seed_n_5) { template_random_seed(1, 5, simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_random_center_initializer, random_seed_n_2_continuous) { template_random_seed(1, 2, simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 20); } pyclustering-0.10.1.2/ccore/tst/utest-rock.cpp000077500000000000000000000075161375753423500212240ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_length_process_data(const std::shared_ptr & p_data, const double p_radius, const size_t p_cluster_amount, const double p_threshold, const std::vector & p_expected_cluster_length) { rock_data output_result; rock solver(p_radius, p_cluster_amount, p_threshold); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_rock, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_sample_one_allocation_simple_01) { const std::vector expected_clusters_length = { 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 5.0, 1, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 10, 5, 8 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1.0, 3, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_one_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 23 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 5.0, 1, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1.0, 4, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_wrong_radius_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1.7, 4, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_sample_simple_04) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 1.0, 5, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_wrong_radius_sample_simple_04) { const std::vector expected_clusters_length = { 15, 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), 1.5, 5, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_sample_simple_05) { const std::vector expected_clusters_length = { 15, 15, 15, 15 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 1.0, 4, 0.5, expected_clusters_length); } TEST(utest_rock, allocation_sample_simple_07) { const std::vector expected_clusters_length = { 10, 10 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 1.0, 2, 0.5, expected_clusters_length); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_rock, allocation_sample_simple_08) { const std::vector expected_clusters_length = { 15, 30, 20, 80 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 1.0, 4, 0.5, expected_clusters_length); } #endif pyclustering-0.10.1.2/ccore/tst/utest-silhouette.cpp000077500000000000000000000117031375753423500224440ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "answer.hpp" #include "answer_reader.hpp" #include "samples.hpp" #include using namespace pyclustering; using namespace pyclustering::clst; void template_correct_scores(const dataset_ptr & p_data, const answer & p_answer) { silhouette_data result; silhouette().process(*p_data, p_answer.clusters(), result); ASSERT_EQ(p_data->size(), result.get_score().size()); for (const auto score : result.get_score()) { ASSERT_LE(-1.0, score); ASSERT_GE(1.0, score); } } void template_correct_score_data_types(const dataset_ptr & p_data, const answer & p_answer) { silhouette_data result_points, result_matrix; dataset matrix; distance_matrix(*p_data, distance_metric_factory::euclidean_square(), matrix); silhouette().process(*p_data, p_answer.clusters(), silhouette_data_t::POINTS, result_points); silhouette().process(matrix, p_answer.clusters(), silhouette_data_t::DISTANCE_MATRIX, result_matrix); ASSERT_EQ(p_data->size(), result_points.get_score().size()); ASSERT_EQ(p_data->size(), result_matrix.get_score().size()); const auto & scores_points = result_points.get_score(); const auto & scores_matrix = result_matrix.get_score(); ASSERT_EQ(scores_points, scores_matrix); } TEST(utest_silhouette, correct_score_simple01) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_silhouette, correct_score_simple02) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02)); } TEST(utest_silhouette, correct_score_simple03) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03)); } TEST(utest_silhouette, correct_score_simple04) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04)); } TEST(utest_silhouette, correct_score_simple05) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05)); } TEST(utest_silhouette, correct_score_simple06) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06)); } TEST(utest_silhouette, correct_score_simple07) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07)); } TEST(utest_silhouette, correct_score_simple08) { template_correct_scores(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08)); } TEST(utest_silhouette, correct_score_distance_matrix_simple01) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01)); } TEST(utest_silhouette, correct_score_distance_matrix_simple02) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02)); } TEST(utest_silhouette, correct_score_distance_matrix_simple03) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03)); } TEST(utest_silhouette, correct_score_distance_matrix_simple04) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04)); } TEST(utest_silhouette, correct_score_distance_matrix_simple05) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05)); } TEST(utest_silhouette, correct_score_distance_matrix_simple06) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06)); } TEST(utest_silhouette, correct_score_distance_matrix_simple07) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07)); } TEST(utest_silhouette, correct_score_distance_matrix_simple08) { template_correct_score_data_types(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08)); } pyclustering-0.10.1.2/ccore/tst/utest-silhouette_ksearch.cpp000077500000000000000000000176751375753423500241620ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include "answer.hpp" #include "answer_reader.hpp" #include "samples.hpp" #include using namespace pyclustering; using namespace pyclustering::clst; static void template_correct_ksearch( const dataset_ptr & p_data, const answer & p_answer, const std::size_t p_kmin, const std::size_t p_kmax, const silhouette_ksearch_allocator::ptr & p_allocator = std::make_shared()) { const std::size_t attempts = 5; bool testing_result = false; for (std::size_t i = 0; i < attempts; i++) { silhouette_ksearch_data result; silhouette_ksearch(p_kmin, p_kmax, p_allocator).process(*p_data, result); ASSERT_LE(-1.0, result.get_score()); ASSERT_GE(1.0, result.get_score()); ASSERT_EQ(p_kmax - p_kmin, result.scores().size()); const std::size_t upper_limit = p_answer.clusters().size() + 1; const std::size_t lower_limit = p_answer.clusters().size() > 1 ? p_answer.clusters().size() - 1 : 1; if ((result.get_amount() > upper_limit) || (result.get_amount() < lower_limit)) { std::this_thread::sleep_for(std::chrono::duration(25)); continue; } testing_result = true; break; } ASSERT_TRUE(testing_result); } TEST(utest_silhouette_ksearch, correct_ksearch_simple01_kmeans) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple01_kmedians) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple01_kmedoids) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple02) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple02_kmedians) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple02_kmedoids) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple03) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple05) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_05), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple06) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple07) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple08) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple10) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_10), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple11) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple12) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_12), 2, 10, std::make_shared()); } TEST(utest_silhouette_ksearch, correct_ksearch_simple13) { template_correct_ksearch(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13), answer_reader::read(SAMPLE_SIMPLE::SAMPLE_SIMPLE_13), 2, 10, std::make_shared()); } static void template_random_state( const std::size_t p_kmin, const std::size_t p_kmax, const silhouette_ksearch_allocator::ptr & p_allocator = std::make_shared(), const long long p_random_state = RANDOM_STATE_CURRENT_TIME) { dataset_ptr data = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04); silhouette_ksearch_data result_1, result_2; silhouette_ksearch(p_kmin, p_kmax, p_allocator, p_random_state).process(*data, result_1); silhouette_ksearch(p_kmin, p_kmax, p_allocator, p_random_state).process(*data, result_2); ASSERT_EQ(result_1, result_2); } TEST(utest_silhouette_ksearch, random_state_1_kmeans) { template_random_state(2, 10, std::make_shared(), 1); } TEST(utest_silhouette_ksearch, random_state_2_kmeans) { template_random_state(2, 10, std::make_shared(), 2); } TEST(utest_silhouette_ksearch, random_state_500_kmeans) { template_random_state(2, 10, std::make_shared(), 500); } TEST(utest_silhouette_ksearch, random_state_10000_kmeans) { template_random_state(2, 10, std::make_shared(), 10000); } TEST(utest_silhouette_ksearch, random_state_1_kmedians) { template_random_state(2, 10, std::make_shared(), 1); } TEST(utest_silhouette_ksearch, random_state_2_kmedians) { template_random_state(2, 10, std::make_shared(), 2); } TEST(utest_silhouette_ksearch, random_state_500_kmedians) { template_random_state(2, 10, std::make_shared(), 500); } TEST(utest_silhouette_ksearch, random_state_10000_kmedians) { template_random_state(2, 10, std::make_shared(), 10000); } TEST(utest_silhouette_ksearch, random_state_1_kmedoids) { template_random_state(2, 10, std::make_shared(), 1); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_silhouette_ksearch, random_state_2_kmedoids) { template_random_state(2, 10, std::make_shared(), 2); } TEST(utest_silhouette_ksearch, random_state_500_kmedoids) { template_random_state(2, 10, std::make_shared(), 500); } TEST(utest_silhouette_ksearch, random_state_10000_kmedoids) { template_random_state(2, 10, std::make_shared(), 10000); } #endif pyclustering-0.10.1.2/ccore/tst/utest-som.cpp000077500000000000000000000415741375753423500210660ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include #include using namespace pyclustering; using namespace pyclustering::nnet; static void template_create_delete(const unsigned int rows, const unsigned int cols, const som_conn_type conn_type, const som_init_type init_type) { som_parameters params; params.init_type = init_type; som * som_map = new som(rows, cols, conn_type, params); ASSERT_EQ(rows * cols, som_map->get_size()); delete som_map; } TEST(utest_som, create_delete_conn_func_neighbor) { template_create_delete(10, 10, som_conn_type::SOM_FUNC_NEIGHBOR, som_init_type::SOM_RANDOM); } TEST(utest_som, create_delete_conn_grid_eight) { template_create_delete(10, 10, som_conn_type::SOM_GRID_EIGHT, som_init_type::SOM_RANDOM); } TEST(utest_som, create_delete_conn_grid_four) { template_create_delete(10, 10, som_conn_type::SOM_GRID_FOUR, som_init_type::SOM_RANDOM); } TEST(utest_som, create_delete_conn_honeycomb) { template_create_delete(10, 10, som_conn_type::SOM_HONEYCOMB, som_init_type::SOM_RANDOM); } TEST(utest_som, create_delete_init_centroid) { template_create_delete(10, 10, som_conn_type::SOM_FUNC_NEIGHBOR, som_init_type::SOM_RANDOM_CENTROID); } TEST(utest_som, create_delete_init_surface) { template_create_delete(10, 10, som_conn_type::SOM_FUNC_NEIGHBOR, som_init_type::SOM_RANDOM_SURFACE); } TEST(utest_som, create_delete_init_uniform_grid) { template_create_delete(10, 10, som_conn_type::SOM_FUNC_NEIGHBOR, som_init_type::SOM_UNIFORM_GRID); } static void template_award_neurons(const std::shared_ptr & data, const unsigned int epouchs, const bool autostop, const unsigned int rows, const unsigned int cols, const som_conn_type conn_type, const std::vector & expected_result) { som_parameters params; som som_map(rows, cols, conn_type, params); som_map.train(*data.get(), epouchs, autostop); size_t winners = som_map.get_winner_number(); ASSERT_EQ(expected_result.size(), winners); som_award_sequence & awards = som_map.get_awards(); std::sort(awards.begin(), awards.end()); ASSERT_EQ(expected_result.size(), awards.size()); for (size_t i = 0; i < awards.size(); i++) { ASSERT_EQ(expected_result[i], awards[i]); } som_gain_sequence captured_objects = som_map.get_capture_objects(); size_t total_capture_points = 0; for (size_t i = 0; i < captured_objects.size(); i++) { total_capture_points += captured_objects[i].size(); } size_t expected_capture_points = std::accumulate(expected_result.begin(), expected_result.end(), (std::size_t) 0); ASSERT_EQ(expected_capture_points, total_capture_points); } TEST(utest_som, awards_two_clusters_func_neighbor) { std::vector expected_awards = {5, 5}; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, false, 1, 2, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); template_award_neurons(sample_simple_01, 100, false, 2, 1, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); } TEST(utest_som, awards_two_clusters_func_neighbor_autostop) { std::vector expected_awards = { 5, 5 }; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, true, 1, 2, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); template_award_neurons(sample_simple_01, 100, true, 2, 1, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); } TEST(utest_som, awards_two_clusters_grid_eight) { std::vector expected_awards = {5, 5}; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, false, 1, 2, som_conn_type::SOM_GRID_EIGHT, expected_awards); template_award_neurons(sample_simple_01, 100, false, 2, 1, som_conn_type::SOM_GRID_EIGHT, expected_awards); } TEST(utest_som, awards_two_clusters_grid_eight_autostop) { std::vector expected_awards = { 5, 5 }; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, true, 1, 2, som_conn_type::SOM_GRID_EIGHT, expected_awards); template_award_neurons(sample_simple_01, 100, true, 2, 1, som_conn_type::SOM_GRID_EIGHT, expected_awards); } TEST(utest_som, awards_two_clusters_grid_four) { std::vector expected_awards = {5, 5}; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, false, 1, 2, som_conn_type::SOM_GRID_FOUR, expected_awards); template_award_neurons(sample_simple_01, 100, false, 2, 1, som_conn_type::SOM_GRID_FOUR, expected_awards); } TEST(utest_som, awards_two_clusters_grid_four_autostop) { std::vector expected_awards = { 5, 5 }; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, true, 1, 2, som_conn_type::SOM_GRID_FOUR, expected_awards); template_award_neurons(sample_simple_01, 100, true, 2, 1, som_conn_type::SOM_GRID_FOUR, expected_awards); } TEST(utest_som, awards_two_clusters_honeycomb) { std::vector expected_awards = {5, 5}; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, false, 1, 2, som_conn_type::SOM_HONEYCOMB, expected_awards); template_award_neurons(sample_simple_01, 100, false, 2, 1, som_conn_type::SOM_HONEYCOMB, expected_awards); } TEST(utest_som, awards_two_clusters_honeycomb_autostop) { std::vector expected_awards = { 5, 5 }; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); template_award_neurons(sample_simple_01, 100, true, 1, 2, som_conn_type::SOM_HONEYCOMB, expected_awards); template_award_neurons(sample_simple_01, 100, true, 2, 1, som_conn_type::SOM_HONEYCOMB, expected_awards); } TEST(utest_som, awards_clusters_func_neighbor_simple_sample_02) { std::vector expected_awards = { 5, 8, 10 }; std::shared_ptr sample_simple_02 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_award_neurons(sample_simple_02, 100, false, 1, 3, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); template_award_neurons(sample_simple_02, 100, false, 3, 1, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); } TEST(utest_som, awards_clusters_grid_eight_simple_sample_02) { std::vector expected_awards = { 5, 8, 10 }; std::shared_ptr sample_simple_02 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_award_neurons(sample_simple_02, 100, false, 1, 3, som_conn_type::SOM_GRID_EIGHT, expected_awards); template_award_neurons(sample_simple_02, 100, false, 3, 1, som_conn_type::SOM_GRID_EIGHT, expected_awards); } TEST(utest_som, awards_clusters_func_grid_four_simple_sample_02) { std::vector expected_awards = { 5, 8, 10 }; std::shared_ptr sample_simple_02 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_award_neurons(sample_simple_02, 100, false, 1, 3, som_conn_type::SOM_GRID_FOUR, expected_awards); template_award_neurons(sample_simple_02, 100, false, 3, 1, som_conn_type::SOM_GRID_FOUR, expected_awards); } TEST(utest_som, awards_clusters_honeycomb_simple_sample_02) { std::vector expected_awards = { 5, 8, 10 }; std::shared_ptr sample_simple_02 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02); template_award_neurons(sample_simple_02, 100, false, 1, 3, som_conn_type::SOM_HONEYCOMB, expected_awards); template_award_neurons(sample_simple_02, 100, false, 3, 1, som_conn_type::SOM_HONEYCOMB, expected_awards); } TEST(utest_som, awards_clusters_func_neighbor_simple_sample_03) { std::vector expected_awards = { 10, 10, 10, 30 }; std::shared_ptr sample_simple_03 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_award_neurons(sample_simple_03, 100, false, 1, 4, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); template_award_neurons(sample_simple_03, 100, false, 2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, expected_awards); } TEST(utest_som, awards_clusters_grid_eight_simple_sample_03) { std::vector expected_awards = { 10, 10, 10, 30 }; std::shared_ptr sample_simple_03 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_award_neurons(sample_simple_03, 100, false, 1, 4, som_conn_type::SOM_GRID_EIGHT, expected_awards); template_award_neurons(sample_simple_03, 100, false, 2, 2, som_conn_type::SOM_GRID_EIGHT, expected_awards); } TEST(utest_som, awards_clusters_func_grid_four_simple_sample_03) { std::vector expected_awards = { 10, 10, 10, 30 }; std::shared_ptr sample_simple_03 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_award_neurons(sample_simple_03, 100, false, 1, 4, som_conn_type::SOM_GRID_FOUR, expected_awards); template_award_neurons(sample_simple_03, 100, false, 2, 2, som_conn_type::SOM_GRID_FOUR, expected_awards); } TEST(utest_som, awards_clusters_honeycomb_simple_sample_03) { std::vector expected_awards = { 10, 10, 10, 30 }; std::shared_ptr sample_simple_03 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03); template_award_neurons(sample_simple_03, 100, false, 1, 4, som_conn_type::SOM_HONEYCOMB, expected_awards); template_award_neurons(sample_simple_03, 100, false, 2, 2, som_conn_type::SOM_HONEYCOMB, expected_awards); } TEST(utest_som, double_training) { som_parameters params; som som_map(2, 2, som_conn_type::SOM_GRID_EIGHT, params); std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); som_map.train(*sample_simple_01.get(), 100, false); som_map.train(*sample_simple_01.get(), 100, false); const som_gain_sequence & captured_objects = som_map.get_capture_objects(); size_t total_capture_points = 0; for (size_t i = 0; i < captured_objects.size(); i++) { total_capture_points += captured_objects[i].size(); } ASSERT_EQ(sample_simple_01->size(), total_capture_points); const som_award_sequence & awards = som_map.get_awards(); size_t number_awards = std::accumulate(awards.cbegin(), awards.cend(), (std::size_t) 0); ASSERT_EQ(sample_simple_01->size(), number_awards); } static void template_simulate_check_winners(const som_conn_type conn_type, const bool autostop, const bool p_reload = false) { som_parameters params; std::shared_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); som som_map(1, 2, conn_type, params); som_map.train(*sample_simple_01.get(), 100, autostop); if (p_reload) { auto weights = som_map.get_weights(); auto captured_objects = som_map.get_capture_objects(); auto awards = som_map.get_awards(); som_map = som(1, 2, conn_type, params); som_map.load(weights, awards, captured_objects); } std::vector expected_winners = { 0, 1 }; for (std::size_t i = 0; i < sample_simple_01->size(); i++) { std::size_t index_winner = som_map.simulate(sample_simple_01->at(i)); if ( (i == 0) && (index_winner != 0) ) { expected_winners = { 1, 0 }; } if (i < 5) EXPECT_EQ(expected_winners[0], index_winner); else EXPECT_EQ(expected_winners[1], index_winner); } } TEST(utest_som, simulate_func_neighbors_autostop) { template_simulate_check_winners(som_conn_type::SOM_FUNC_NEIGHBOR, true); } TEST(utest_som, simulate_func_neighbors_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_FUNC_NEIGHBOR, true, true); } TEST(utest_som, simulate_grid_four_autostop) { template_simulate_check_winners(som_conn_type::SOM_GRID_FOUR, true); } TEST(utest_som, simulate_grid_four_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_GRID_FOUR, true, true); } TEST(utest_som, simulate_grid_eight_autostop) { template_simulate_check_winners(som_conn_type::SOM_GRID_EIGHT, true); } TEST(utest_som, simulate_grid_eight_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_GRID_EIGHT, true, true); } TEST(utest_som, simulate_honeycomb_autostop) { template_simulate_check_winners(som_conn_type::SOM_HONEYCOMB, true); } TEST(utest_som, simulate_honeycomb_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_HONEYCOMB, true, true); } TEST(utest_som, simulate_func_neighbors_without_autostop) { template_simulate_check_winners(som_conn_type::SOM_FUNC_NEIGHBOR, false); } TEST(utest_som, simulate_func_neighbors_without_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_FUNC_NEIGHBOR, false, true); } TEST(utest_som, simulate_grid_four_without_autostop) { template_simulate_check_winners(som_conn_type::SOM_GRID_FOUR, false); } TEST(utest_som, simulate_grid_four_without_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_GRID_FOUR, false, true); } TEST(utest_som, simulate_grid_eight_without_autostop) { template_simulate_check_winners(som_conn_type::SOM_GRID_EIGHT, false); } TEST(utest_som, simulate_grid_eight_without_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_GRID_EIGHT, false, true); } TEST(utest_som, simulate_honeycomb_without_autostop) { template_simulate_check_winners(som_conn_type::SOM_HONEYCOMB, false); } TEST(utest_som, simulate_honeycomb_without_autostop_reload) { template_simulate_check_winners(som_conn_type::SOM_HONEYCOMB, false, true); } static void template_random_state(const std::size_t rows, const std::size_t cols, const som_conn_type conn_type, const std::size_t random_state, const bool autostop) { som_parameters params; params.random_state = random_state; dataset_ptr sample_simple_01 = simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01); som som_1(rows, cols, conn_type, params); std::size_t steps_1 = som_1.train(*sample_simple_01.get(), 100, autostop); som som_2(rows, cols, conn_type, params); std::size_t steps_2 = som_2.train(*sample_simple_01.get(), 100, autostop); ASSERT_EQ(steps_1, steps_2); ASSERT_EQ(som_1.get_awards(), som_2.get_awards()); ASSERT_EQ(som_1.get_weights(), som_2.get_weights()); ASSERT_EQ(som_1.get_capture_objects(), som_2.get_capture_objects()); ASSERT_EQ(som_1.get_winner_number(), som_2.get_winner_number()); } TEST(utest_som, random_state_neighbor_2x2_rnd_1) { template_random_state(2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, 1, false); } TEST(utest_som, random_state_neighbor_2x2_rnd_2) { template_random_state(2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, 2, false); } TEST(utest_som, random_state_neighbor_2x2_rnd_3) { template_random_state(2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, 3, false); } TEST(utest_som, random_state_neighbor_2x4_rnd_2) { template_random_state(2, 4, som_conn_type::SOM_FUNC_NEIGHBOR, 2, false); } TEST(utest_som, random_state_four_grid) { template_random_state(2, 4, som_conn_type::SOM_GRID_FOUR, 2, false); } TEST(utest_som, random_state_eight_grid) { template_random_state(2, 4, som_conn_type::SOM_GRID_EIGHT, 2, false); } TEST(utest_som, random_state_honeycomb_grid) { template_random_state(2, 4, som_conn_type::SOM_HONEYCOMB, 2, false); } TEST(utest_som, random_state_autostop_rnd_1) { template_random_state(2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, 1, true); } TEST(utest_som, random_state_autostop_rnd_2) { template_random_state(2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, 2, true); } TEST(utest_som, random_state_autostop_rnd_5) { template_random_state(2, 2, som_conn_type::SOM_FUNC_NEIGHBOR, 5, true); } pyclustering-0.10.1.2/ccore/tst/utest-somsc.cpp000077500000000000000000000065721375753423500214130ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include "utenv_check.hpp" using namespace pyclustering::clst; static void template_kmeans_length_process_data(const dataset_ptr & p_data, const std::size_t p_amout_clusters, const std::vector & p_expected_cluster_length) { somsc_data output_result; somsc solver(p_amout_clusters); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_somsc, allocation_sample_simple_01) { std::vector expected_clusters_length = { 5, 5 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 2, expected_clusters_length); } TEST(utest_somsc, one_cluster_allocation_sample_simple_01) { std::vector expected_clusters_length = { 10 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1, expected_clusters_length); } TEST(utest_somsc, allocation_sample_simple_02) { std::vector expected_clusters_length = { 10, 5, 8 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 3, expected_clusters_length); } TEST(utest_somsc, one_cluster_allocation_sample_simple_02) { std::vector expected_clusters_length = { 23 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1, expected_clusters_length); } TEST(utest_somsc, allocation_sample_simple_03) { std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 4, expected_clusters_length); } TEST(utest_somsc, large_number_centers_sample_simple_01) { std::vector expected_clusters_length; /* pass empty */ template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 5, expected_clusters_length); } TEST(utest_somsc, large_number_centers_sample_simple_02) { std::vector expected_clusters_length; /* pass empty */ template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 6, expected_clusters_length); } TEST(utest_somsc, large_number_centers_sample_simple_03) { std::vector expected_clusters_length; /* pass empty */ template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 7, expected_clusters_length); } TEST(utest_somsc, one_dimension_sample_simple_07) { std::vector expected_clusters_length = { 10, 10 }; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 2, expected_clusters_length); } TEST(utest_somsc, one_dimension_sample_simple_08) { std::vector expected_clusters_length; template_kmeans_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), 4, expected_clusters_length); } pyclustering-0.10.1.2/ccore/tst/utest-spinlock.cpp000077500000000000000000000032441375753423500221020ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include using namespace pyclustering::parallel; TEST(utest_spinlock, count_value) { const std::size_t amount_count = 100000; const std::size_t amount_tasks = 50; std::vector pool; std::size_t result = 0; spinlock locker; auto task = [&result, &locker, amount_count]() { for (std::size_t i = 0; i < amount_count; i++) { locker.lock(); result++; locker.unlock(); } }; for (std::size_t i = 0; i < amount_tasks; i++) { pool.emplace_back(task); } for (std::size_t i = 0; i < amount_tasks; i++) { pool[i].join(); } ASSERT_EQ(amount_count * amount_tasks, result); } TEST(utest_spinlock, count_value_thread_pool) { const std::size_t amount_threads = 20; const std::size_t amount_count = 1000; const std::size_t amount_tasks = 1000; thread_pool pool(amount_threads); std::size_t result = 0; spinlock locker; auto task = [&result, &locker, amount_count]() { for (std::size_t i = 0; i < amount_count; i++) { locker.lock(); result++; locker.unlock(); } }; std::vector tasks(amount_tasks); for (std::size_t i = 0; i < amount_tasks; i++) { tasks[i] = pool.add_task(task); } for (std::size_t i = 0; i < amount_tasks; i++) { tasks[i]->wait_ready(); } ASSERT_EQ(amount_count * amount_tasks, result); } pyclustering-0.10.1.2/ccore/tst/utest-stats.cpp000077500000000000000000000056411375753423500214210ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::utils::stats; TEST(utest_stats, pdf) { std::vector data = {-0.80526491, -1.03631388, 1.38455957, 1.67106978, -0.00618697, -2.44026332, 1.12861732, -0.16200512, -1.41740669, -1.27725788}; std::sort(std::begin(data), std::end(data)); auto result = pdf(data); ASSERT_EQ(data.size(), result.size()); std::vector expected = { 0.0203153, 0.14610067, 0.17646506, 0.23318766, 0.28846996, 0.39374123, 0.39893464, 0.21101479, 0.15298106, 0.09874884 }; for (std::size_t i = 0; i < result.size(); ++i) { ASSERT_NEAR(expected[i], result[i], 0.000001); } } TEST(utest_stats, cdf) { std::vector data = {-0.80526491, -1.03631388, 1.38455957, 1.67106978, -0.00618697, -2.44026332, 1.12861732, -0.16200512, -1.41740669, -1.27725788}; std::sort(std::begin(data), std::end(data)); auto result = cdf(data); ASSERT_EQ(data.size(), result.size()); std::vector expected = { 0.00733828, 0.07818203, 0.10075561, 0.15002787, 0.21033341, 0.43565091, 0.49753177, 0.87047035, 0.91690641, 0.95264605 }; for (std::size_t i = 0; i < result.size(); ++i) { ASSERT_NEAR(expected[i], result[i], 0.000001); } } TEST(utest_stats, mean) { std::vector data = {-0.80526491, -1.03631388, 1.38455957, 1.67106978, -0.00618697, -2.44026332, 1.12861732, -0.16200512, -1.41740669, -1.27725788}; const double result = mean(data); ASSERT_NEAR(-0.2960452, result, 0.0000001); } TEST(utest_stats, var) { std::vector data = {-0.80526491, -1.03631388, 1.38455957, 1.67106978, -0.00618697, -2.44026332, 1.12861732, -0.16200512, -1.41740669, -1.27725788}; const double result = var(data); ASSERT_NEAR(1.827869, result, 0.000001); } TEST(utest_stats, std) { std::vector data = {-0.80526491, -1.03631388, 1.38455957, 1.67106978, -0.00618697, -2.44026332, 1.12861732, -0.16200512, -1.41740669, -1.27725788}; const double result = pyclustering::utils::stats::std(data); ASSERT_NEAR(1.351987, result, 0.000001); } TEST(utest_stats, anderson) { std::vector data = { 1.20051687, -0.11498334, -0.06660842, 0.65981179, -0.8188606, -1.48766638, -0.76268192, 0.89156879, 0.5011937, 0.85737694 }; const double result = anderson(data); ASSERT_NEAR(0.319009, result, 0.000001); } TEST(utest_stats, critical_values) { std::vector expected = { 0.50086957, 0.57043478, 0.68434783, 0.79826087, 0.94956522 }; std::vector actual = critical_values(10); ASSERT_EQ(expected.size(), actual.size()); for (std::size_t i = 0; i < expected.size(); ++i) { ASSERT_NEAR(expected[i], actual[i], 0.000001); } }pyclustering-0.10.1.2/ccore/tst/utest-sync.cpp000077500000000000000000000314711375753423500212370ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::nnet; static void template_create_delete(const connection_t type, const initial_type initial) { sync_network * network = new sync_network(25, 1, 1, type, initial); ASSERT_EQ(25U, network->size()); delete network; } TEST(utest_sync, create_delete_all_to_all_equipatition) { template_create_delete(connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, create_delete_all_to_all_gaussian) { template_create_delete(connection_t::CONNECTION_ALL_TO_ALL, initial_type::RANDOM_GAUSSIAN); } TEST(utest_sync, create_delete_list_bidir_equipatition) { template_create_delete(connection_t::CONNECTION_LIST_BIDIRECTIONAL, initial_type::EQUIPARTITION); } TEST(utest_sync, create_delete_list_bidir_gaussian) { template_create_delete(connection_t::CONNECTION_LIST_BIDIRECTIONAL, initial_type::RANDOM_GAUSSIAN); } TEST(utest_sync, create_delete_grid_four_equipatition) { template_create_delete(connection_t::CONNECTION_GRID_FOUR, initial_type::EQUIPARTITION); } TEST(utest_sync, create_delete_grid_four_gaussian) { template_create_delete(connection_t::CONNECTION_GRID_FOUR, initial_type::RANDOM_GAUSSIAN); } TEST(utest_sync, create_delete_grid_eight_equipatition) { template_create_delete(connection_t::CONNECTION_GRID_EIGHT, initial_type::EQUIPARTITION); } TEST(utest_sync, create_delete_grid_eight_gaussian) { template_create_delete(connection_t::CONNECTION_GRID_EIGHT, initial_type::RANDOM_GAUSSIAN); } TEST(utest_sync, create_delete_none_equipatition) { template_create_delete(connection_t::CONNECTION_NONE, initial_type::EQUIPARTITION); } TEST(utest_sync, create_delete_none_gaussian) { template_create_delete(connection_t::CONNECTION_NONE, initial_type::RANDOM_GAUSSIAN); } static void template_dynamic_convergence(const unsigned int number_oscillators, const solve_type solver, const connection_t type, const initial_type initial) { sync_network network(number_oscillators, 1, 0, type, initial); sync_dynamic output_dynamic; network.simulate_dynamic(0.998, 0.1, solver, false, output_dynamic); ensemble_data ensembles; output_dynamic.allocate_sync_ensembles(0.1, ensembles); ASSERT_EQ(1U, ensembles.size()); } TEST(utest_sync, dynamic_convergance_10_oscillators_all_to_all) { template_dynamic_convergence(10, solve_type::FORWARD_EULER, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, dynamic_convergance_20_oscillators_all_to_all) { template_dynamic_convergence(10, solve_type::FORWARD_EULER, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, dynamic_convergance_16_oscillators_grid_four) { template_dynamic_convergence(16, solve_type::FORWARD_EULER, connection_t::CONNECTION_GRID_FOUR, initial_type::EQUIPARTITION); } TEST(utest_sync, dynamic_convergance_16_oscillators_grid_eight) { template_dynamic_convergence(16, solve_type::FORWARD_EULER, connection_t::CONNECTION_GRID_EIGHT, initial_type::EQUIPARTITION); } TEST(utest_sync, dynamic_convergance_5_oscillators_list_bidir) { template_dynamic_convergence(5, solve_type::FORWARD_EULER, connection_t::CONNECTION_LIST_BIDIRECTIONAL, initial_type::EQUIPARTITION); } static void template_static_convergence(const unsigned int number_oscillators, const solve_type solver, const connection_t type, const initial_type initial) { sync_network network(number_oscillators, 1.0, 0, type, initial); sync_dynamic output_dynamic; network.simulate_static(50, 10, solver, false, output_dynamic); ensemble_data ensembles; output_dynamic.allocate_sync_ensembles(0.1, ensembles); ASSERT_EQ(1U, ensembles.size()); } TEST(utest_sync, static_convergance_10_oscillators_all_to_all) { template_static_convergence(10, solve_type::FORWARD_EULER, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, static_convergance_20_oscillators_all_to_all) { template_static_convergence(10, solve_type::FORWARD_EULER, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, static_convergance_9_oscillators_grid_four) { template_static_convergence(9, solve_type::FORWARD_EULER, connection_t::CONNECTION_GRID_FOUR, initial_type::EQUIPARTITION); } TEST(utest_sync, static_convergance_9_oscillators_grid_eight) { template_static_convergence(9, solve_type::FORWARD_EULER, connection_t::CONNECTION_GRID_EIGHT, initial_type::EQUIPARTITION); } TEST(utest_sync, static_convergance_3_oscillators_list_bidir) { template_static_convergence(3, solve_type::FORWARD_EULER, connection_t::CONNECTION_LIST_BIDIRECTIONAL, initial_type::EQUIPARTITION); } TEST(utest_sync, static_simulation_runge_kutta_4) { template_static_convergence(2, solve_type::RUNGE_KUTTA_4, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, static_simulation_runge_kutta_fehlberg_45) { template_static_convergence(2, solve_type::RUNGE_KUTTA_FEHLBERG_45, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, dynamic_simulation_runge_kutta_4) { template_dynamic_convergence(2, solve_type::RUNGE_KUTTA_4, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } TEST(utest_sync, dynamic_simulation_runge_kutta_fehlberg_45) { template_dynamic_convergence(2, solve_type::RUNGE_KUTTA_FEHLBERG_45, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); } static void template_static_collecting_dynamic(const unsigned int steps) { sync_network network(10, 1, 0, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); sync_dynamic output_dynamic; network.simulate_static(steps, 0.1, solve_type::FORWARD_EULER, true, output_dynamic); ASSERT_EQ(10U, output_dynamic.oscillators()); ASSERT_EQ(steps + 1, output_dynamic.size()); } TEST(utest_sync, static_collecting_dynamic_25_oscillators) { template_static_collecting_dynamic(25); } TEST(utest_sync, static_collecting_dynamic_100_oscillators) { template_static_collecting_dynamic(100); } TEST(utest_sync, dynamic_collecting_dynamic) { sync_network network(10, 1, 0, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); sync_dynamic output_dynamic; network.simulate_dynamic(0.998, 0.1, solve_type::FORWARD_EULER, true, output_dynamic); ASSERT_EQ(10U, output_dynamic.oscillators()); ASSERT_GT(output_dynamic.size(), (std::size_t) 1); } TEST(utest_sync, dynamic_around_zero) { sync_dynamic output_dynamic; output_dynamic.push_back(sync_network_state(10.0, { 0.01, 0.02, 0.03, 6.25, 6.26, 6.27 })); ensemble_data ensembles; output_dynamic.allocate_sync_ensembles(0.1, ensembles); ASSERT_EQ(1U, ensembles.size()); output_dynamic.allocate_sync_ensembles(0.2, ensembles); ASSERT_EQ(1U, ensembles.size()); output_dynamic.clear(); output_dynamic.push_back(sync_network_state(20.0, { 1.02, 1.05, 1.52, 5.87, 5.98, 5.14 })); output_dynamic.allocate_sync_ensembles(2.0, ensembles); ASSERT_EQ(1U, ensembles.size()); } static void template_correlation_matrix(const sync_network_state p_state) { sync_dynamic output_dynamic; output_dynamic.push_back(p_state); sync_corr_matrix corr_matrix; output_dynamic.allocate_correlation_matrix(corr_matrix); ASSERT_EQ(p_state.size(), corr_matrix.size()); ASSERT_EQ(p_state.size(), corr_matrix[0].size()); for (size_t i = 0; i < p_state.size(); i++) { for (size_t j = 0; j < p_state.size(); j++) { double expected_value = std::abs((double) std::sin(p_state.m_phase[i] - p_state.m_phase[j])); ASSERT_NEAR(expected_value, corr_matrix[i][j], 0.00001); } } } TEST(utest_sync, correlation_matrix_similar) { template_correlation_matrix(sync_network_state(0, {0.0, 0.0, 0.0})); } TEST(utest_sync, correlation_matrix_not_similar_1) { template_correlation_matrix(sync_network_state(0, {1.0, 2.0, 3.0})); } TEST(utest_sync, correlation_matrix_not_similar_2) { template_correlation_matrix(sync_network_state(0, {1.0, 2.0, 3.0, 4.0, 5.0, 6.0})); } TEST(utest_sync, correlation_matrix_one_oscillator) { template_correlation_matrix(sync_network_state(0, {1.0})); } static void template_sync_ordering(const std::size_t p_size, const std::size_t p_steps, const double p_time) { sync_network network(p_size, 1, 0, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); sync_dynamic output_dynamic; network.simulate_static(p_steps, p_time, solve_type::FORWARD_EULER, true, output_dynamic); double order_parameter = sync_ordering::calculate_sync_order(output_dynamic[0].m_phase); double local_order_parameter = sync_ordering::calculate_local_sync_order(network.connections(), output_dynamic[0].m_phase); ASSERT_GT(0.8, order_parameter); ASSERT_GT(0.8, local_order_parameter); order_parameter = sync_ordering::calculate_sync_order(output_dynamic.back().m_phase); local_order_parameter = sync_ordering::calculate_local_sync_order(network.connections(), output_dynamic.back().m_phase); ASSERT_LT(0.9, order_parameter); ASSERT_LT(0.9, local_order_parameter); } TEST(utest_sync, sync_ordering_20_steps) { template_sync_ordering(10, 20, 5.0); } TEST(utest_sync, sync_ordering_50_steps) { template_sync_ordering(10, 50, 5.0); } static void template_sync_order_sequence( const std::size_t p_size, const std::size_t p_steps, const double p_time, const std::size_t p_start, const std::size_t p_stop, const bool p_check_result) { sync_network network(p_size, 1, 0, connection_t::CONNECTION_ALL_TO_ALL, initial_type::EQUIPARTITION); sync_dynamic output_dynamic; network.simulate_static(p_steps, p_time, solve_type::FORWARD_EULER, true, output_dynamic); std::vector order_sequence; std::vector local_order_sequence; output_dynamic.calculate_order_parameter(p_start, p_stop, order_sequence); output_dynamic.calculate_local_order_parameter(network.connections(), p_start, p_stop, local_order_sequence); ASSERT_EQ(p_stop - p_start, order_sequence.size()); ASSERT_EQ(p_stop - p_start, local_order_sequence.size()); ASSERT_EQ(p_steps + 1, output_dynamic.size()); ASSERT_GE(output_dynamic.size(), order_sequence.size()); if (p_check_result) { ASSERT_GT(0.8, order_sequence.front()); ASSERT_GT(0.8, local_order_sequence.front()); ASSERT_LT(0.9, order_sequence.back()); ASSERT_LT(0.9, local_order_sequence.back()); } } TEST(utest_sync, sync_sequence_ordering_10_steps_full) { template_sync_order_sequence(10, 10, 5.0, 0, 11 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_10_steps_20_size_full) { template_sync_order_sequence(20, 10, 5.0, 0, 11 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_10_steps_100_size_full) { template_sync_order_sequence(100, 10, 5.0, 0, 11 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_30_steps_200_size_full) { template_sync_order_sequence(200, 30, 5.0, 0, 11 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_20_steps_full) { template_sync_order_sequence(10, 20, 5.0, 0, 21 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_50_steps_full) { template_sync_order_sequence(10, 50, 5.0, 0, 51 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_200_steps_full) { template_sync_order_sequence(10, 200, 5.0, 0, 201 /* the initial state of the network */, true); } TEST(utest_sync, sync_sequence_ordering_10_oscillators_partial) { template_sync_order_sequence(10, 20, 5.0, 10, 15, false); } TEST(utest_sync, sync_sequence_ordering_20_oscillators_partial) { template_sync_order_sequence(20, 20, 5.0, 10, 15, false); } TEST(utest_sync, sync_sequence_ordering_40_oscillators_partial) { template_sync_order_sequence(40, 20, 5.0, 10, 15, false); } TEST(utest_sync, sync_sequence_ordering_one_back) { template_sync_order_sequence(10, 20, 5.0, 10, 11, false); } TEST(utest_sync, sync_sequence_ordering_one_front) { template_sync_order_sequence(10, 20, 5.0, 0, 1, false); } TEST(utest_sync, sync_sequence_ordering_one_middle) { template_sync_order_sequence(10, 20, 5.0, 5, 6, false); } pyclustering-0.10.1.2/ccore/tst/utest-syncnet.cpp000077500000000000000000000072261375753423500217470ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include using namespace pyclustering::clst; static void template_create_delete(const unsigned int size) { std::vector > sample; for (unsigned int i = 0; i < size; i++) { sample.push_back( { 0.0 + (double) i } ); } syncnet * network = new syncnet(&sample, 2.0, false, initial_type::EQUIPARTITION); ASSERT_EQ(size, network->size()); delete network; } TEST(utest_syncnet, create_delete_network_1) { template_create_delete(1); } TEST(utest_syncnet, create_delete_network_10) { template_create_delete(10); } TEST(utest_syncnet, create_delete_network_100) { template_create_delete(100); } TEST(utest_syncnet, one_cluster) { bool result_testing = false; for (std::size_t attempt = 0; attempt < 3; attempt++) { std::vector > sample; sample.push_back( { 0.1, 0.1 } ); sample.push_back( { 0.2, 0.1 } ); sample.push_back( { 0.0, 0.0 } ); syncnet network(&sample, 0.5, false, initial_type::EQUIPARTITION); syncnet_analyser analyser; network.process(0.998, solve_type::FORWARD_EULER, true, analyser); syncnet_cluster_data clusters; analyser.allocate_clusters(0.1, clusters); if (1 != clusters.size()) { continue; } result_testing = true; } ASSERT_TRUE(result_testing); } static void template_two_cluster_allocation(const solve_type solver, const bool collect_dynamic, const bool ena_conn_weight) { bool result_testing = false; for (std::size_t attempt = 0; attempt < 3; attempt++) { std::vector > sample; sample.push_back( { 0.1, 0.1 } ); sample.push_back( { 0.2, 0.1 } ); sample.push_back( { 0.0, 0.0 } ); sample.push_back( { 2.2, 2.1 } ); sample.push_back( { 2.3, 2.0 } ); sample.push_back( { 2.1, 2.4 } ); syncnet network(&sample, 0.5, ena_conn_weight, initial_type::EQUIPARTITION); syncnet_analyser analyser; network.process(0.995, solver, true, analyser); ensemble_data ensembles; analyser.allocate_clusters(0.1, ensembles); if (2 != ensembles.size()) { continue; } result_testing = true; } ASSERT_TRUE(result_testing); } TEST(utest_syncnet, two_clusters_fast_solver_with_collection) { template_two_cluster_allocation(solve_type::FORWARD_EULER, true, false); } TEST(utest_syncnet, two_clusters_rk4_solver_with_collection) { template_two_cluster_allocation(solve_type::RUNGE_KUTTA_4, true, false); } TEST(utest_syncnet, two_clusters_rkf45_solver_with_collection) { template_two_cluster_allocation(solve_type::RUNGE_KUTTA_FEHLBERG_45, true, false); } TEST(utest_syncnet, two_clusters_fast_solver_without_collection) { template_two_cluster_allocation(solve_type::FORWARD_EULER, false, false); } TEST(utest_syncnet, two_clusters_rk4_solver_without_collection) { template_two_cluster_allocation(solve_type::RUNGE_KUTTA_4, false, false); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_syncnet, two_clusters_rkf45_solver_without_collection) { template_two_cluster_allocation(solve_type::RUNGE_KUTTA_FEHLBERG_45, false, false); } TEST(utest_syncnet, two_clusters_fast_solver_conn_weight) { template_two_cluster_allocation(solve_type::FORWARD_EULER, false, true); } #endif pyclustering-0.10.1.2/ccore/tst/utest-syncpr.cpp000077500000000000000000000134011375753423500215720ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include using namespace pyclustering::nnet; static void template_syncpr_create_delete(const unsigned int size) { syncpr * network = new syncpr(size, 0.5, 0.5); ASSERT_EQ(size, network->size()); delete network; } TEST(utest_syncpr, create_delete_10_oscillators) { template_syncpr_create_delete(10); } TEST(utest_syncpr, create_delete_50_oscillators) { template_syncpr_create_delete(50); } TEST(utest_syncpr, create_delete_100_oscillators) { template_syncpr_create_delete(100); } static void template_simulation_static(const unsigned int steps, const solve_type solver, const bool collect_flag) { syncpr network(5, 0.3, 0.3); syncpr_dynamic output_dynamic; syncpr_pattern pattern = { 1, 1, 1, -1, -1 }; network.simulate_static(steps, 10, pattern, solver, collect_flag, output_dynamic); if (collect_flag) { ASSERT_TRUE(output_dynamic.size() > steps); } else { ASSERT_EQ(1U, output_dynamic.size()); } } TEST(utest_syncpr, static_simulation_10_FAST) { template_simulation_static(10, solve_type::FORWARD_EULER, true); } TEST(utest_syncpr, static_simulation_100_FAST) { template_simulation_static(100, solve_type::FORWARD_EULER, true); } TEST(utest_syncpr, static_simulation_5_RK4) { template_simulation_static(5, solve_type::RUNGE_KUTTA_4, true); } TEST(utest_syncpr, static_simulation_6_RKF45) { template_simulation_static(6, solve_type::RUNGE_KUTTA_FEHLBERG_45, true); } TEST(utest_syncpr, static_simulation_FAST_no_collecting) { template_simulation_static(5, solve_type::FORWARD_EULER, false); } TEST(utest_syncpr, static_simulation_RK4_no_collecting) { template_simulation_static(5, solve_type::RUNGE_KUTTA_4, false); } TEST(utest_syncpr, static_simulation_RKF45_no_collecting) { template_simulation_static(5, solve_type::RUNGE_KUTTA_FEHLBERG_45, false); } static void template_simulation_dynamic(const solve_type solver, const bool collect_flag) { syncpr network(5, 0.3, 0.3); syncpr_dynamic output_dynamic; syncpr_pattern pattern = { 1, 1, 1, -1, -1 }; network.simulate_dynamic(pattern, 0.95, 1, solver, collect_flag, output_dynamic); if (collect_flag) { ASSERT_TRUE(output_dynamic.size() > 1); } else { ASSERT_EQ(1U, output_dynamic.size()); } } TEST(utest_syncpr, dynamic_simulation_FAST) { template_simulation_dynamic(solve_type::FORWARD_EULER, true); } TEST(utest_syncpr, dynamic_simulation_RK4) { template_simulation_dynamic(solve_type::RUNGE_KUTTA_4, true); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_syncpr, dynamic_simulation_RKF45) { template_simulation_dynamic(solve_type::RUNGE_KUTTA_FEHLBERG_45, true); } #endif TEST(utest_syncpr, dynamic_simulation_FAST_no_collecting) { template_simulation_dynamic(solve_type::FORWARD_EULER, false); } TEST(utest_syncpr, dynamic_simulation_RK4_no_collecting) { template_simulation_dynamic(solve_type::RUNGE_KUTTA_4, false); } #ifndef VALGRIND_ANALYSIS_SHOCK TEST(utest_syncpr, dynamic_simulation_RKF45_no_collecting) { template_simulation_dynamic(solve_type::RUNGE_KUTTA_FEHLBERG_45, false); } #endif TEST(utest_syncpr, train_and_recognize_pattern) { syncpr network(10, 0.1, 0.1); syncpr_dynamic output_dynamic; std::vector patterns = { { 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, 1, 1, 1, 1, 1 } }; double memory_order1 = network.memory_order(patterns[0]); double memory_order2 = network.memory_order(patterns[1]); ASSERT_TRUE(memory_order1 < 0.9); ASSERT_TRUE(memory_order2 < 0.9); network.train(patterns); /* recognize it */ for (size_t i = 0; i < patterns.size(); i++) { syncpr_dynamic output_dynamic; network.simulate_static(20, 10, patterns[i], solve_type::RUNGE_KUTTA_4, true, output_dynamic); double memory_order = network.memory_order(patterns[i]); ASSERT_TRUE(memory_order > 0.995); ensemble_data sync_ensembles; output_dynamic.allocate_sync_ensembles(0.1, sync_ensembles); ASSERT_EQ(2U, sync_ensembles.size()); for (sync_ensemble & ensemble : sync_ensembles) { std::sort(ensemble.begin(), ensemble.end()); } sync_ensemble expected_ensemble1 = { 0, 1, 2, 3, 4 }; sync_ensemble expected_ensemble2 = { 5, 6, 7, 8, 9 }; ASSERT_TRUE( (expected_ensemble1 == sync_ensembles[0]) || (expected_ensemble2 == sync_ensembles[0]) ); ASSERT_TRUE( (expected_ensemble1 == sync_ensembles[1]) || (expected_ensemble2 == sync_ensembles[1])); } } TEST(utest_syncpr, sync_local_order) { syncpr network(10, 0.1, 0.1); double local_order = network.sync_local_order(); ASSERT_TRUE((local_order > 0.0) && (local_order < 1.0)); std::vector patterns = { { 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, 1, 1, 1, 1, 1 } }; network.train(patterns); local_order = network.sync_local_order(); ASSERT_TRUE((local_order > 0.0) && (local_order < 1.0)); } TEST(utest_syncpr, sync_global_order) { syncpr network(10, 0.1, 0.1); double global_order = network.sync_order(); ASSERT_TRUE((global_order > 0.0) && (global_order < 1.0)); std::vector patterns = { { 1, 1, 1, 1, 1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1, 1, 1, 1, 1, 1 } }; network.train(patterns); global_order = network.sync_order(); ASSERT_TRUE((global_order > 0.0) && (global_order < 1.0)); } pyclustering-0.10.1.2/ccore/tst/utest-thread_pool.cpp000077500000000000000000000116221375753423500225570ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include #include #include #include using namespace pyclustering; using namespace pyclustering::parallel; std::size_t AUTO_POOL_SIZE = std::numeric_limits::max(); static void template_create_delete_test(const std::size_t p_size) { thread_pool * pool = nullptr; std::size_t expected_size = p_size; if (p_size == AUTO_POOL_SIZE) { pool = new thread_pool(); expected_size = thread_pool::DEFAULT_POOL_SIZE; } else { pool = new thread_pool(p_size); } ASSERT_EQ(expected_size, pool->size()); delete pool; } TEST(utest_thread_pool, create_delete_size_1) { template_create_delete_test(1); } TEST(utest_thread_pool, create_delete_size_5) { template_create_delete_test(5); } TEST(utest_thread_pool, create_delete_size_20) { template_create_delete_test(20); } TEST(utest_thread_pool, auto_size_pool) { template_create_delete_test(AUTO_POOL_SIZE); } static void template_add_task_test(const std::size_t p_pool_size, const std::size_t p_task_amount) { std::unique_ptr pool = nullptr; if (p_pool_size == AUTO_POOL_SIZE) { pool = std::unique_ptr(new thread_pool()); } else { pool = std::unique_ptr(new thread_pool(p_pool_size)); } std::vector results(p_task_amount, 0.0); double expected_basic_result = 1.0; std::vector expected_results(p_task_amount, 0.0); for (std::size_t i = 0; i < p_task_amount; i++) { expected_results[i] = expected_basic_result + i; } std::vector task_storage; for (std::size_t task_index = 0; task_index < p_task_amount; task_index++) { task::proc user_proc = [task_index, &results](){ results[task_index] = task_index + 1.0; }; task::ptr client_task = pool->add_task(user_proc); ASSERT_NE(nullptr, client_task); ASSERT_EQ(std::find(task_storage.cbegin(), task_storage.cend(), client_task), task_storage.cend()); task_storage.push_back(client_task); } ASSERT_EQ(p_task_amount, task_storage.size()); for (std::size_t i = 0; i < p_task_amount; i++) { task_storage[i]->wait_ready(); double obtained_result = results[i]; double expected_result = expected_results[i]; ASSERT_EQ(expected_result, obtained_result); } } TEST(utest_thread_pool, pool_bigger_task_amount) { template_add_task_test(10, 5); } TEST(utest_thread_pool, pool_equal_task_amount) { template_add_task_test(5, 5); } TEST(utest_thread_pool, pool_less_task_amount) { template_add_task_test(5, 20); } TEST(utest_thread_pool, pool_1_thread_20_tasks) { template_add_task_test(1, 20); } TEST(utest_thread_pool, pool_1_thread_1_task) { template_add_task_test(1, 1); } TEST(utest_thread_pool, pool_1_thread_2_tasks) { template_add_task_test(1, 2); } TEST(utest_thread_pool, pool_1_thread_3_tasks) { template_add_task_test(1, 3); } TEST(utest_thread_pool, pool_2_threads_1_tasks) { template_add_task_test(2, 4); } TEST(utest_thread_pool, pool_2_threads_2_tasks) { template_add_task_test(2, 4); } TEST(utest_thread_pool, pool_2_threads_3_tasks) { template_add_task_test(2, 4); } TEST(utest_thread_pool, pool_2_threads_4_tasks) { template_add_task_test(2, 4); } TEST(utest_thread_pool, pool_10_threads_1_tasks) { template_add_task_test(10, 1); } TEST(utest_thread_pool, pool_10_threads_100_tasks) { template_add_task_test(10, 100); } TEST(utest_thread_pool, pool_10_threads_200_tasks) { template_add_task_test(10, 200); } TEST(utest_thread_pool, pool_20_threads_200_tasks) { template_add_task_test(20, 100); } TEST(utest_thread_pool, pool_30_threads_300_tasks) { template_add_task_test(30, 300); } TEST(utest_thread_pool, pool_5_threads_5000_tasks) { template_add_task_test(5, 5000); } TEST(utest_thread_pool, continious_pool_5_threads_50_tasks) { for (std::size_t i = 0; i < 100; i++) { template_add_task_test(5, 50); } } TEST(utest_thread_pool, pool_auto_size_1_tasks) { template_add_task_test(AUTO_POOL_SIZE, 20); } TEST(utest_thread_pool, pool_auto_size_10_tasks) { template_add_task_test(AUTO_POOL_SIZE, 10); } TEST(utest_thread_pool, pool_auto_size_20_tasks) { template_add_task_test(AUTO_POOL_SIZE, 20); } TEST(utest_thread_pool, pool_auto_size_50_tasks) { template_add_task_test(AUTO_POOL_SIZE, 20); } TEST(utest_thread_pool, pool_auto_size_100_tasks) { template_add_task_test(AUTO_POOL_SIZE, 20); }pyclustering-0.10.1.2/ccore/tst/utest-ttsas.cpp000077500000000000000000000145121375753423500214160ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "samples.hpp" #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::clst; static void template_ttsas_length_process_data(const dataset_ptr p_data, const double & p_threshold1, const double & p_threshold2, const std::vector & p_expected_cluster_length, const distance_metric & p_metric = distance_metric_factory::euclidean()) { ttsas_data output_result; ttsas solver(p_threshold1, p_threshold2, p_metric); solver.process(*p_data, output_result); const dataset & data = *p_data; const cluster_sequence & actual_clusters = output_result.clusters(); const representative_sequence & actual_repr = output_result.representatives(); for (auto & repr : actual_repr) ASSERT_EQ(data[0].size(), repr.size()); ASSERT_EQ(actual_repr.size(), actual_clusters.size()); ASSERT_CLUSTER_SIZES(data, actual_clusters, p_expected_cluster_length); } TEST(utest_ttsas, allocation_sample_simple_01) { const std::vector expected_clusters_length = { 5, 5 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length); } TEST(utest_ttsas, allocation_sample_simple_01_euclidean) { const std::vector expected_clusters_length = { 5, 5 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length, distance_metric_factory::euclidean()); } TEST(utest_ttsas, allocation_sample_simple_01_euclidean_square) { const std::vector expected_clusters_length = { 5, 5 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length, distance_metric_factory::euclidean_square()); } TEST(utest_ttsas, allocation_sample_simple_01_manhattan) { const std::vector expected_clusters_length = { 5, 5 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length, distance_metric_factory::manhattan()); } TEST(utest_ttsas, allocation_sample_simple_01_chebyshev) { const std::vector expected_clusters_length = { 5, 5 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length, distance_metric_factory::chebyshev()); } TEST(utest_ttsas, allocation_sample_simple_01_minkowski) { const std::vector expected_clusters_length = { 5, 5 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length, distance_metric_factory::minkowski(2.0)); } TEST(utest_ttsas, allocation_sample_simple_01_user_defined) { const std::vector expected_clusters_length = { 5, 5 }; auto user_metric = [](const point & p1, const point & p2) { return euclidean_distance(p1, p2); }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 1.0, 2.0, expected_clusters_length, distance_metric_factory::user_defined(user_metric)); } TEST(utest_ttsas, allocation_one_allocation_sample_simple_01) { const std::vector expected_clusters_length = { 10 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), 10.0, 20.0, expected_clusters_length); } TEST(utest_ttsas, allocation_sample_simple_02) { const std::vector expected_clusters_length = { 5, 8, 10 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 1.0, 2.0, expected_clusters_length); } TEST(utest_ttsas, allocation_one_allocation_sample_simple_02) { const std::vector expected_clusters_length = { 23 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), 10.0, 20.0, expected_clusters_length); } TEST(utest_ttsas, allocation_sample_simple_03) { const std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), 1.0, 2.0, expected_clusters_length); } TEST(utest_ttsas, allocation_one_dimension_points_1) { const std::vector expected_clusters_length = { 10, 10 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 1.0, 2.0, expected_clusters_length); } TEST(utest_ttsas, allocation_one_allocation_one_dimension_points_1) { const std::vector expected_clusters_length = { 20 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), 10.0, 20.0, expected_clusters_length); } TEST(utest_ttsas, allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 10, 20 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 1.0, 2.0, expected_clusters_length); } TEST(utest_ttsas, allocation_one_allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 30 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), 10.0, 20.0, expected_clusters_length); } TEST(utest_ttsas, allocation_three_dimension_points_2) { const std::vector expected_clusters_length = { 10, 10 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 1.0, 2.0, expected_clusters_length); } TEST(utest_ttsas, allocation_three_allocation_one_dimension_points_2) { const std::vector expected_clusters_length = { 20 }; template_ttsas_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_11), 10.0, 20.0, expected_clusters_length); }pyclustering-0.10.1.2/ccore/tst/utest-utils-algorithm.cpp000077500000000000000000000016771375753423500234140ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include using namespace pyclustering::utils::algorithm; TEST(utest_algorithm, find_left_element_valid_input) { std::vector values = { 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4 }; std::vector answer = { 0, 0, 2, 2, 2, 5, 5, 5, 5, 9, 9, 9, 12 }; for (std::size_t i = 0; i < values.size(); i++) { auto iter = find_left_element(values.begin(), values.begin() + i + 1); auto actual_index = std::distance(values.begin(), iter); auto expected_index = answer[i]; ASSERT_EQ(expected_index, actual_index); } } TEST(utest_algorithm, find_left_element_invalid_input) { std::vector values = { 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4 }; auto iter = find_left_element(values.begin(), values.begin()); ASSERT_EQ(values.begin(), iter); }pyclustering-0.10.1.2/ccore/tst/utest-utils-metric.cpp000077500000000000000000000061121375753423500226760ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include #include #include "utenv_check.hpp" using namespace pyclustering; using namespace pyclustering::utils::metric; TEST(utest_metric, metric_factory_euclidean) { distance_metric metric = distance_metric_factory::euclidean(); ASSERT_EQ(1.0, metric({0.0, 0.0}, {1.0, 0.0})); ASSERT_EQ(3.0, metric({-1.0, -2.0}, {-1.0, -5.0})); } TEST(utest_metric, metric_factory_euclidean_square) { distance_metric metric = distance_metric_factory::euclidean_square(); ASSERT_EQ(1.0, metric({0.0, 0.0}, {1.0, 0.0})); ASSERT_EQ(9.0, metric({-1.0, -2.0}, {-1.0, -5.0})); } TEST(utest_metric, metric_factory_manhattan) { distance_metric metric = distance_metric_factory::manhattan(); ASSERT_EQ(1.0, metric({0.0, 0.0}, {1.0, 0.0})); ASSERT_EQ(3.0, metric({0.0, 0.0}, {1.0, 2.0})); } TEST(utest_metric, metric_factory_chebyshev) { distance_metric metric = distance_metric_factory::chebyshev(); ASSERT_EQ(1.0, metric({0.0, 0.0}, {1.0, 0.0})); ASSERT_EQ(2.0, metric({0.0, 0.0}, {1.0, 2.0})); } TEST(utest_metric, metric_factory_minkowski) { distance_metric metric = distance_metric_factory::minkowski(2); ASSERT_EQ(1.0, metric({0.0, 0.0}, {1.0, 0.0})); ASSERT_EQ(3.0, metric({-1.0, -2.0}, {-1.0, -5.0})); } TEST(utest_metric, metric_factory_canberra) { distance_metric metric = distance_metric_factory::canberra(); ASSERT_EQ(0.0, metric({0.0, 0.0}, {0.0, 0.0})); ASSERT_EQ(2.0, metric({0.0, 0.0}, {1.0, 1.0})); ASSERT_EQ(1.0, metric({0.75, 0.75}, {0.25, 0.25})); } TEST(utest_metric, metric_factory_cchi_square) { distance_metric metric = distance_metric_factory::chi_square(); ASSERT_EQ(0.0, metric({0.0, 0.0}, {0.0, 0.0})); ASSERT_EQ(2.0, metric({0.0, 0.0}, {1.0, 1.0})); ASSERT_EQ(0.5, metric({0.75, 0.75}, {0.25, 0.25})); } TEST(utest_metric, metric_factory_gower) { distance_metric metric = distance_metric_factory::gower({0.0, 0.0}); ASSERT_EQ(0.0, metric({0.0, 0.0}, {0.0, 0.0})); metric = distance_metric_factory::gower({1.0, 1.0}); ASSERT_EQ(1.0, metric({1.0, 1.0}, {2.0, 2.0})); metric = distance_metric_factory::gower({0.5, 0.5}); ASSERT_EQ(1.0, metric({0.75, 0.75}, {0.25, 0.25})); } TEST(utest_metric, metric_factory_user_defined) { distance_metric metric = distance_metric_factory::user_defined([](const point & p1, const point & p2) { return -5.0; } ); ASSERT_EQ(-5.0, metric({0.0, 0.0}, {1.0, 0.0})); ASSERT_EQ(-5.0, metric({0.0, 0.0}, {0.0, 0.0})); } TEST(utest_metric, calculate_distance_matrix_01) { dataset points = { {0}, {2}, {4} }; dataset distance_matrix; pyclustering::utils::metric::distance_matrix(points, distance_matrix); dataset distance_matrix_expected = { { 0.0, 2.0, 4.0 }, { 2.0, 0.0, 2.0 }, { 4.0, 2.0, 0.0 } }; ASSERT_EQ(distance_matrix, distance_matrix_expected); }pyclustering-0.10.1.2/ccore/tst/utest-xmeans.cpp000077500000000000000000000372471375753423500215650ustar00rootroot00000000000000/*! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause */ #include #include "samples.hpp" #include #include using namespace pyclustering; using namespace pyclustering::clst; const double WCE_CHECK_DISABLED = std::numeric_limits::max(); void template_length_process_data(const std::shared_ptr & data, const dataset & start_centers, const unsigned int kmax, const std::vector & expected_cluster_length, const splitting_type criterion, const double expected_wce = WCE_CHECK_DISABLED, const long long random_state = RANDOM_STATE_CURRENT_TIME, const double alpha = 0.9, const double beta = 0.9) { xmeans solver(start_centers, kmax, 0.0001, criterion, 1, random_state); solver.set_mndl_alpha_bound(alpha); solver.set_mndl_beta_bound(beta); xmeans_data output_result; solver.process(*data.get(), output_result); cluster_sequence & results = output_result.clusters(); /* Check number of clusters */ if (!expected_cluster_length.empty()) { ASSERT_EQ(expected_cluster_length.size(), results.size()); } /* Check cluster sizes */ std::vector obtained_cluster_length; std::size_t total_size = 0; for (size_t i = 0; i < results.size(); i++) { obtained_cluster_length.push_back(results[i].size()); total_size += results[i].size(); } ASSERT_EQ(data->size(), total_size); ASSERT_EQ(output_result.centers().size(), output_result.clusters().size()); ASSERT_GE(kmax, output_result.centers().size()); if (!expected_cluster_length.empty()) { std::sort(obtained_cluster_length.begin(), obtained_cluster_length.end()); std::vector sorted_expected_cluster_length(expected_cluster_length); std::sort(sorted_expected_cluster_length.begin(), sorted_expected_cluster_length.end()); for (size_t i = 0; i < obtained_cluster_length.size(); i++) { ASSERT_EQ(obtained_cluster_length[i], sorted_expected_cluster_length[i]); } } if (expected_wce != WCE_CHECK_DISABLED) { ASSERT_EQ(output_result.wce(), expected_wce); } } void template_length_mndl_process_data(const std::shared_ptr & data, const dataset & start_centers, const unsigned int kmax, const std::vector & expected_cluster_length, const splitting_type criterion, const double alpha = 0.9, const double beta = 0.9, const double expected_wce = WCE_CHECK_DISABLED, const long long random_state = RANDOM_STATE_CURRENT_TIME) { template_length_process_data(data, start_centers, kmax, expected_cluster_length, criterion, expected_wce, random_state, alpha, beta); } TEST(utest_xmeans, allocation_bic_sample_simple_01) { dataset start_centers = { {3.7, 5.5}, {6.7, 7.5} }; std::vector expected_clusters_length = {5, 5}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_01) { dataset start_centers = { {3.7, 5.5}, {6.7, 7.5} }; std::vector expected_clusters_length = {5, 5}; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_01), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.1, 0.1); } TEST(utest_xmeans, allocation_bic_sample_simple_02) { dataset start_centers = { {3.5, 4.8}, {6.9, 7.0}, {7.5, 0.5} }; std::vector expected_clusters_length = {10, 5, 8}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_02) { dataset start_centers = { {3.5, 4.8}, {6.9, 7.0}, {7.5, 0.5} }; std::vector expected_clusters_length = {10, 5, 8}; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.1, 0.1); } TEST(utest_xmeans, allocation_wrong_initial_bic_sample_simple_02) { dataset start_centers = { {3.5, 4.8}, {6.9, 7.0} }; std::vector expected_clusters_length = {10, 5, 8}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_02), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION, WCE_CHECK_DISABLED, 1000); } TEST(utest_xmeans, allocation_bic_sample_simple_03) { dataset start_centers = { {0.2, 0.1}, {4.0, 1.0}, {2.0, 2.0}, {2.3, 3.9} }; std::vector expected_clusters_length = {10, 10, 10, 30}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_wrong_initial_bic_sample_simple_03) { dataset start_centers = { {4.0, 1.0}, {2.0, 2.0}, {2.3, 3.9} }; std::vector expected_clusters_length = {10, 10, 10, 30}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_kmax_less_real_bic_sample_simple_03) { dataset start_centers = { {4.0, 1.0}, {2.0, 2.0}, {2.3, 3.9} }; std::vector expected_clusters_length = { }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 3, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_one_cluster_bic_sample_simple_03) { dataset start_centers = { {2.0, 2.0} }; std::vector expected_clusters_length = { 60 }; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 1, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_03) { dataset start_centers = { {0.2, 0.1}, {4.0, 1.0}, {2.0, 2.0}, {2.3, 3.9} }; std::vector expected_clusters_length = {10, 10, 10, 30}; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.2, 0.2); } TEST(utest_xmeans, allocation_wrong_initial_mndl_sample_simple_03) { dataset start_centers = { { 4.0, 1.0 },{ 2.0, 2.0 },{ 2.3, 3.9 } }; std::vector expected_clusters_length = { 10, 10, 10, 30 }; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.2, 0.2); } TEST(utest_xmeans, allocation_kmax_less_real_mndl_sample_simple_03) { dataset start_centers = { { 4.0, 1.0 },{ 2.0, 2.0 },{ 2.3, 3.9 } }; std::vector expected_clusters_length = {}; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 3, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.2, 0.2); } TEST(utest_xmeans, allocation_one_cluster_mndl_sample_simple_03) { dataset start_centers = { { 2.0, 2.0 } }; std::vector expected_clusters_length = { 60 }; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_03), start_centers, 1, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.2, 0.2); } TEST(utest_xmeans, allocation_bic_sample_simple_04) { dataset start_centers = { {1.5, 0.0}, {1.5, 2.0}, {1.5, 4.0}, {1.5, 6.0}, {1.5, 8.0} }; std::vector expected_clusters_length = {15, 15, 15, 15, 15}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_04) { dataset start_centers = { {1.5, 0.0}, {1.5, 2.0}, {1.5, 4.0}, {1.5, 6.0}, {1.5, 8.0} }; std::vector expected_clusters_length = {15, 15, 15, 15, 15}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_04), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH); } TEST(utest_xmeans, allocation_bic_sample_simple_06) { dataset start_centers = { {3.5, 3.5}, {3.7, 3.7} }; std::vector expected_clusters_length = {20, 21}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_06) { dataset start_centers = { {3.5, 3.5}, {3.7, 3.7} }; std::vector expected_clusters_length = {20, 21}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_06), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH); } TEST(utest_xmeans, allocation_bic_sample_simple_07) { dataset start_centers = { {1.0}, {2.0} }; std::vector expected_clusters_length = {10, 10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_07) { dataset start_centers = { {-2.0}, {4.0} }; std::vector expected_clusters_length = {10, 10}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_07), start_centers, 2, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH); } TEST(utest_xmeans, allocation_bic_sample_simple_08) { dataset start_centers = { {-2.0}, {3.0}, {6.0}, {12.0} }; std::vector expected_clusters_length = {15, 30, 20, 80}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_08) { dataset start_centers = { {-2.0}, {3.0}, {6.0}, {12.0} }; std::vector expected_clusters_length = {15, 30, 20, 80}; template_length_mndl_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_08), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.2, 0.2); } TEST(utest_xmeans, allocation_bic_sample_simple_09) { dataset start_centers = { {3.0}, {6.0} }; std::vector expected_clusters_length = {10, 20}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_sample_simple_09) { dataset start_centers = { {3.0}, {6.0} }; std::vector expected_clusters_length = {10, 20}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH); } TEST(utest_xmeans, same_size_data_and_centers_bic) { dataset_ptr data = dataset_ptr( new dataset({ {1.0}, {2.0}, {3.0}, {4.0} }) ); dataset start_centers = { {1.0}, {2.0}, {3.0}, {4.0} }; template_length_process_data(data, start_centers, 20, { 1, 1, 1, 1 }, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, same_size_data_and_centers_mndl) { dataset_ptr data = dataset_ptr( new dataset({ {1.0}, {2.0}, {3.0}, {4.0} }) ); dataset start_centers = { {1.0}, {2.0}, {3.0}, {4.0} }; template_length_process_data(data, start_centers, 20, { 1, 1, 1, 1 }, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH); } TEST(utest_xmeans, allocation_bic_identical_data_01) { dataset start_centers = { {3.0}, {6.0} }; std::vector expected_clusters_length = {10, 20}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, allocation_mndl_identical_data_01) { dataset start_centers = { {3.0}, {6.0} }; std::vector expected_clusters_length = {10, 20}; template_length_process_data(simple_sample_factory::create_sample(SAMPLE_SIMPLE::SAMPLE_SIMPLE_09), start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH); } TEST(utest_xmeans, custom_allocation_bic_01) { dataset_ptr data = dataset_ptr(new dataset({{0.0, 0.0}, {0.1363766466758196, 1.1783713695419944}, {3.214688621356828, 1.476853479793315}, {2.138463480518565, 4.081574609797002}, {0.7396242774728039, 2.87928051726698}, {4.392971847058702, 9.373294690055928}, {0.9201540078170818, 1.58388176369988}, {4.314084965826241, 1.2011928104209428}, {11.734694885255871, 7.357322102302481}, {3.536693195144401, 7.985381380225232}})); dataset start_centers = {{0.5370863032832184, 0.11587434446400902}, {0.88032361344512, 0.1499414823211892}, {0.32937175324286194, 0.1591103849511586}}; std::vector expected_clusters_length = { }; template_length_process_data(data, start_centers, 5, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION); } TEST(utest_xmeans, math_error_domain_bic) { dataset_ptr data = dataset_ptr(new dataset({ {0}, {0}, {10}, {10}, {20}, {20} })); dataset start_centers = { {5}, {20} }; std::vector expected_clusters_length = {2, 2, 2}; template_length_process_data(data, start_centers, 20, expected_clusters_length, splitting_type::BAYESIAN_INFORMATION_CRITERION, 0.0); } TEST(utest_xmeans, math_error_domain_mndl) { dataset_ptr data = dataset_ptr(new dataset({ {0}, {0}, {10}, {10}, {20}, {20} })); dataset start_centers = { {5}, {20} }; std::vector expected_clusters_length = {2, 2, 2}; template_length_process_data(data, start_centers, 20, expected_clusters_length, splitting_type::MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 0.0); } #ifdef UT_PERFORMANCE_SESSION TEST(performance_xmeans, big_data) { auto points = simple_sample_factory::create_random_sample(20000, 10); dataset centers = { {0, 0}, {5, 5}, {10, 10}, {15, 15}, {20, 20} }; auto start = std::chrono::system_clock::now(); const std::size_t repeat = 10; for (std::size_t i = 0; i < repeat; i++) { xmeans_data output_result(false); xmeans solver(centers, 20, 0.0001, splitting_type::BAYESIAN_INFORMATION_CRITERION); solver.process(*points, output_result); } auto end = std::chrono::system_clock::now(); std::chrono::duration difference = end - start; std::cout << "Clustering time: '" << difference.count() / repeat << "' sec." << std::endl; } #endifpyclustering-0.10.1.2/ccore/utcore.mk000077500000000000000000000057231375753423500174360ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # # Tools CC = g++ -c LD = g++ RM = rm -rf MKDIR = mkdir -p # C++ standard depending on operating system UNAME = $(shell uname -s | tr '[:upper:]' '[:lower:]') ifeq ($(findstring cygwin, $(UNAME)), cygwin) CPLUS_STANDARD = gnu++14 PIC_FLAG = else CPLUS_STANDARD = c++14 PIC_FLAG = -fPIC endif # Warnings. WARNING_FLAGS = -Wall -Wpedantic # Toolchain arguments ifeq ($(CONFIG), valgrind) CFLAGS = -MMD -MP -std=$(CPLUS_STANDARD) $(PIC_FLAG) -g LFLAGS = -pthread else ifeq ($(CONFIG), debug) CFLAGS = -Og -MMD -MP -std=$(CPLUS_STANDARD) $(PIC_FLAG) -g3 -ggdb3 LFLAGS = -pthread else CFLAGS = -O2 -MMD -MP -std=$(CPLUS_STANDARD) $(PIC_FLAG) -fprofile-arcs -ftest-coverage $(WARNING_FLAGS) LFLAGS = -pthread -fprofile-arcs -ftest-coverage endif # Build specific flags (VALGRIND_ANALYSIS_SHOCK - for valgrind shock checking) ifeq ($(BUILD_VERSION), valgrind_shock) CFLAGS += -DVALGRIND_ANALYSIS_SHOCK endif # Output name of executable file EXECUTABLE_DIRECTORY = tst EXECUTABLE = $(EXECUTABLE_DIRECTORY)/utcore # Environment PROJECT_DIRECTORY = . INCLUDE_DIRECTORY = $(PROJECT_DIRECTORY)/include/ SOURCES_DIRECTORY = src UTEST_DIRECTORY = tst EXTERNAL_INCLUDE_DIRECTORY = external/include EXTERNAL_SOURCES_DIRECTORY = external/src # Project sources SOURCES_MODULES = . cluster container differential interface nnet parallel utils UTEST_MODULES = . GTEST_MODULES = gtest SOURCES_DIRECTORIES = $(addprefix $(SOURCES_DIRECTORY)/, $(SOURCES_MODULES)) SOURCES_DIRECTORIES += $(addprefix $(UTEST_DIRECTORY)/, $(UTEST_MODULES)) SOURCES_DIRECTORIES += $(addprefix $(EXTERNAL_SOURCES_DIRECTORY)/, $(GTEST_MODULES)) SOURCES = $(foreach SUBDIR, $(SOURCES_DIRECTORIES), $(wildcard $(SUBDIR)/*.cpp)) INCLUDES = -I$(INCLUDE_DIRECTORY) -I$(UTEST_DIRECTORY) -I$(EXTERNAL_INCLUDE_DIRECTORY) # Project objects OBJECTS_DIRECTORY = obj/ut OBJECTS_DIRECTORIES = $(addprefix $(OBJECTS_DIRECTORY)/$(SOURCES_DIRECTORY)/, $(SOURCES_MODULES)) OBJECTS_DIRECTORIES += $(addprefix $(OBJECTS_DIRECTORY)/$(UTEST_DIRECTORY)/, $(UTEST_MODULES)) OBJECTS_DIRECTORIES += $(addprefix $(OBJECTS_DIRECTORY)/$(EXTERNAL_SOURCES_DIRECTORY)/, $(GTEST_MODULES)) OBJECTS = $(patsubst %.cpp, $(OBJECTS_DIRECTORY)/%.o, $(SOURCES)) # The dependency file names DEPENDENCIES = $(OBJECTS:.o=.d) # Targets .PHONY: ut ut: mkdirs $(EXECUTABLE) .PHONY: mkdirs mkdirs: $(OBJECTS_DIRECTORIES) .PHONY: clean clean: $(RM) $(EXECUTABLE) $(OBJECTS_DIRECTORY) # Build targets $(EXECUTABLE): $(OBJECTS) $(LD) $(LFLAGS) $^ -o $@ $(OBJECTS_DIRECTORIES): $(MKDIR) $@ vpath %.cpp $(SOURCES_DIRECTORIES) define make-objects $1/%.o: %.cpp $(CC) $(CFLAGS) $(INCLUDES) $$< -o $$@ endef $(foreach OBJDIR, $(OBJECTS_DIRECTORIES), $(eval $(call make-objects, $(OBJDIR)))) # Include dependencies -include $(DEPENDENCIES) pyclustering-0.10.1.2/ci/000077500000000000000000000000001375753423500150725ustar00rootroot00000000000000pyclustering-0.10.1.2/ci/appveyor-ci.ps1000077500000000000000000000305641375753423500177700ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # $env:CCORE_64BIT_BINARY_PATH = "pyclustering\core\64-bit\win\pyclustering.dll" $env:CCORE_32BIT_BINARY_PATH = "pyclustering\core\32-bit\win\pyclustering.dll" $env:RESULT_SUCCESS = "Success"; $env:RESULT_FAILURE = "Failure"; function build_ccore_library($target, $platform, $configuration) { Write-Host "[CI] Build C++ pyclustering library (target: '$target') '$configuration' for Windows platform '$platform'." -ForegroundColor Green; msbuild ccore\ccore.sln /t:$target /p:configuration=$configuration /p:platform=$platform; if ($LastExitCode -ne 0) { Write-Error -Message "[CI] Build process for C++ pyclustering library (target: '$target') '$configuration' for Windows ($platform) is failed." -Category InvalidResult; $env:TESTING_RESULT = $env:RESULT_FAILURE; } Write-Host "[CI] C++ pyclustering library (target: '$target') '$configuration' for WINDOWS platform ($platform) is successfully built." -ForegroundColor Green; } function bvt_ccore_library($target, $platform, $configuration) { Write-Host "[CI] Run BVT for C++ pyclustering library '$target' ('$configuration', '$platform')." -ForegroundColor Green; msbuild ccore\ccore.sln /t:$target /p:configuration=$configuration /p:platform=$platform if ($LastExitCode -ne 0) { Write-Error -Message "[CI] Build process for C++ pyclustering library BVT '$target' is failed." -Category InvalidResult; Exit 1; } $smoke_test = "ccore\x64\$target.exe"; & $smoke_test if ($LastExitCode -ne 0) { Write-Error -Message "[CI] The BVT for '$target' failed with code '$LastExitCode'."; Exit 1; } } function ut_ccore_library($target, $platform, $configuration) { Write-Host "[CI] Run UT for C++ pyclustering library '$target' ('$configuration', '$platform')." -ForegroundColor Green; msbuild ccore\ccore.sln /t:$target /p:configuration=$configuration /p:platform=$platform if ($LastExitCode -ne 0) { Write-Error -Message "[CI] Build process for C++ pyclustering library UT '$target' is failed." -Category InvalidResult; Exit 1; } cd ccore\tst; & $env:PYTHON_INTERPRETER ut-runner.py $target.exe if ($LastExitCode -ne 0) { Write-Error -Message "[CI] The UT for '$target' failed with code '$LastExitCode'."; Exit 1; } cd ..\..\; } function job_build_windows_ccore($platform_version) { Write-Host "[CI] Build C++ pyclustering library." -ForegroundColor Green; build_ccore_library pyclustering-shared x86 "Release"; build_ccore_library pyclustering-shared x64 "Release"; Write-Host "[CI] C++ pyclustering library is successfully built for Windows." -ForegroundColor Green; bvt_ccore_library bvt\bvt-shared x64 "Release" bvt_ccore_library bvt\bvt-static x64 "Release" if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -Message "[CI] Binaries are not uploaded in case of Pull Requests." -ForegroundColor Green; Exit 0; } Write-Host "[CI] Upload C++ pyclustering library binaries to the cloud." -ForegroundColor Green; upload_binary 32-bit $env:CCORE_32BIT_BINARY_PATH; upload_binary 64-bit $env:CCORE_64BIT_BINARY_PATH; Write-Host "[CI] Binaries are sucessfully uploaded." -ForegroundColor Green; } function job_ut_windows_ccore() { Write-Host "[CI] Build and run unit-tests for C++ pyclustering library." -ForegroundColor Green; ut_ccore_library ut\ut-static x64 "Release" ut_ccore_library ut\ut-shared x64 "Release" Write-Host "[CI] Build and run unit-tests for C++ pyclustering library: SUCCESS." -ForegroundColor Green; } function job_build_cygwin_ccore() { Write-Host "[CI] C++ pyclustering library build for Cygwin." -ForegroundColor Green; & $env:CYGWIN_PATH -lc "cygcheck -dc cygwin"; & $env:CYGWIN_PATH -lc "cd '$env:APPVEYOR_BUILD_FOLDER'; cd ccore; make ccore_64bit"; if ($LastExitCode -ne 0) { Write-Error -Message "[CI] C++ pyclustering library build for Cygwin: FAILURE." -Category InvalidResult; $env:TESTING_RESULT = $env:RESULT_FAILURE; Exit 1; } Write-Host "[CI] C++ pyclustering library build for Cygwin: SUCCESS." -ForegroundColor Green; } function job_pyclustering_windows($platform_version) { Write-Host "[CI] Testing interaction between pyclustering and CCORE on Windows platform $platform_version." -ForegroundColor Green; if ($env:APPVEYOR_PULL_REQUEST_NUMBER) { Write-Host -Message "[CI] Integration tests are disabled for Pull Requests." -ForegroundColor Green; exit 0 } install_miniconda $platform_version; Write-Host "[CI] Set path '$env:APPVEYOR_BUILD_FOLDER' to tested pyclustering library." -ForegroundColor Green; $env:PYTHONPATH = "$env:APPVEYOR_BUILD_FOLDER;$env:PYTHONPATH"; Write-Host "[CI] Download built binary for platform '$platform_version'." -ForegroundColor Green; if ($platform_version -eq "x86") { download_binary 32-bit $env:CCORE_32BIT_BINARY_PATH } elseif ($platform_version -eq "x64") { download_binary 64-bit $env:CCORE_64BIT_BINARY_PATH } Write-Host "[CI] Starting integration testing using interpreter '$env:PYTHON_INTERPRETER'." -ForegroundColor Green; & $env:PYTHON_INTERPRETER pyclustering\tests\__main__.py --integration if ($LastExitCode -ne 0) { Write-Error -Message "[CI Job] Integration testing pyclustering <-> ccore for WINDOWS platform: FAILURE." -Category InvalidResult; $env:TESTING_RESULT = $env:RESULT_FAILURE; exit 1; } Write-Host "[CI] Integration testing pyclustering <-> ccore for WINDOWS platform: SUCCESS." -ForegroundColor Green;; } function download_miniconda($platform_version) { Write-Host "[CI] Download Miniconda." -ForegroundColor Green; $webclient = New-Object System.Net.WebClient; $filename = ""; if ($platform_version -eq "x86") { $filename = "Miniconda3-4.3.27-Windows-x86.exe"; } elseif ($platform_version -eq "x64") { $filename = "Miniconda3-4.3.27-Windows-x86_64.exe"; } else { Write-Error -Message "[CI] Unknown platform of Miniconda is specified '$platform_version'." -Category InvalidArgument; Exit 1; } $filepath = $pwd.Path + "\" + $filename $url = "https://repo.continuum.io/miniconda/" + $filename; Write-Host "[CI] Start downloading process from link '$url' to '$filepath'." -ForegroundColor Green; $retry_attempts = 3 for($i = 0; $i -lt $retry_attempts; $i++){ try { $webclient.DownloadFile($url, $filepath); break; } Catch [Exception]{ Start-Sleep 1; } } if (Test-Path $filepath) { Write-Host "[CI] Installation file has been download to '$filepath'." -ForegroundColor Green; } else { Write-Error -Message "[CI] Miniconda has not been downloaded." -Category ResourceUnavailable; Exit 1; } Write-Host "[CI] Start installing process using '$filepath'." -ForegroundColor Green; $env:MINICONDA_PATH = "C:\Specific-Miniconda"; $args = "/InstallationType=AllUsers /S /AddToPath=1 /RegisterPython=1 /D=$env:MINICONDA_PATH"; Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru; if (Test-Path $env:MINICONDA_PATH) { Write-Host "[CI] Miniconda has been successfully installed to '$env:MINICONDA_PATH'." -ForegroundColor Green; Remove-Item $filepath; } else { Write-Host "[CI] Miniconda has not been installed." -ForegroundColor Green; Exit 1; } Write-Host "[CI] Set miniconda to PATH variable." -ForegroundColor Green; $env:PATH = "$env:PATH;$env:MINICONDA_PATH\Scripts"; } function install_miniconda($platform_version) { Write-Host "[CI] Starting process of installation of miniconda." -ForegroundColor Green; download_miniconda $platform_version; conda config --set always_yes true; conda install -q conda; conda create -q -n test-environment python=3.5; conda install -q -n test-environment mkl numpy scipy matplotlib pillow; # Download pillow from the channel because of troubles on default channel. # conda install --channel conda-forge pillow=5.2.0; Write-Host "[CI] Activating environment for powershell manually (activate does not work)." -ForegroundColor Green; activate test-environment; $env:PYTHON_INTERPRETER = "$env:MINICONDA_PATH\envs\test-environment\python.exe"; $env:PYTHONPATH = "$env:MINICONDA_PATH\envs\test-environment"; $env:PATH = "$env:MINICONDA_PATH\envs\test-environment;$env:PATH"; $env:PATH = "$env:MINICONDA_PATH\envs\test-environment\Scripts;$env:PATH"; $env:PATH = "$env:MINICONDA_PATH\envs\test-environment\Library\bin;$env:PATH"; Write-Host "[CI] Miniconda environment information after installation of miniconda:" -ForegroundColor Green; conda info -a; Write-Host "[CI] Python interpreter information after installation of miniconda:" -ForegroundColor Green; & $env:PYTHON_INTERPRETER --version; } function download_binary($platform_version, $binary_path) { Write-Host "[CI]: Download binary file" -ForegroundColor Green; # Obtain link for download $env:BUILD_FOLDER = "windows"; $env:BINARY_FOLDER = $env:APPVEYOR_BUILD_NUMBER; $env:BINARY_FILEPATH = "/$env:APPVEYOR_REPO_BRANCH/$env:BUILD_FOLDER/$platform_version/$env:BINARY_FOLDER/pyclustering.dll"; & $env:PYTHON ci/cloud $env:YANDEX_DISK_TOKEN download $env:BINARY_FILEPATH $binary_path if ($LastExitCode -ne 0) { Write-Error -Message "[CI] Impossible to download C++ pyclustering binary (platform '$platform_version') to '$binary_path'." -Category InvalidResult; $env:TESTING_RESULT = $env:RESULT_FAILURE; exit 1; } } function upload_binary($platform_version, $binary_path) { Write-Host "[CI]: Upload binary files (platform: '$platform_version', binary: '$binary_path') to the storage." -ForegroundColor Green; $env:BUILD_FOLDER = "windows"; $env:BINARY_FOLDER = $env:APPVEYOR_BUILD_NUMBER; # Create folder for uploaded binary file & $env:PYTHON ci/cloud $env:YANDEX_DISK_TOKEN mkdir "/$env:APPVEYOR_REPO_BRANCH" & $env:PYTHON ci/cloud $env:YANDEX_DISK_TOKEN mkdir "/$env:APPVEYOR_REPO_BRANCH/$env:BUILD_FOLDER" & $env:PYTHON ci/cloud $env:YANDEX_DISK_TOKEN mkdir "/$env:APPVEYOR_REPO_BRANCH/$env:BUILD_FOLDER/$platform_version" & $env:PYTHON ci/cloud $env:YANDEX_DISK_TOKEN mkdir "/$env:APPVEYOR_REPO_BRANCH/$env:BUILD_FOLDER/$platform_version/$env:BINARY_FOLDER" # Upload binary file $env:BINARY_FILEPATH = "/$env:APPVEYOR_REPO_BRANCH/$env:BUILD_FOLDER/$platform_version/$env:BINARY_FOLDER/pyclustering.dll"; & $env:PYTHON ci/cloud $env:YANDEX_DISK_TOKEN upload $binary_path $env:BINARY_FILEPATH } if ($env:APPVEYOR_REPO_COMMIT_MESSAGE -Match "\[no-build\]") { Write-Host "Option '[no-build]' is detected, sources will not be built, checked, verified and published." -ForegroundColor Green; Exit 0; } if ($env:APPVEYOR_REPO_COMMIT_MESSAGE -Match "\[build-only-osx\]") { Write-Host "Option '[build-only-osx]' is detected, sources will not be built, checked, verified and published." -ForegroundColor Green; Exit 0; } if ($env:APPVEYOR_REPO_COMMIT_MESSAGE -Match "\[build-only-docs\]") { Write-Host "Option '[build-only-docs]' is detected, sources will not be built, checked, verified and published." -ForegroundColor Green; Exit 0; } switch ($env:CI_JOB) { "BUILD_WINDOWS_CCORE" { job_build_windows_ccore; break; } "UT_WINDOWS_CCORE" { job_ut_windows_ccore; break; } "BUILD_CYGWIN_CCORE" { job_build_cygwin_ccore; break; } "PYCLUSTERING_WINDOWS_X64" { job_pyclustering_windows x64; break; } "PYCLUSTERING_WINDOWS_X86" { job_pyclustering_windows x86; break; } default { Write-Error -Message "[CI] Unknown target is specified '$CI_JOB'" -Category InvalidArgument; exit 1; } } pyclustering-0.10.1.2/ci/cloud/000077500000000000000000000000001375753423500162005ustar00rootroot00000000000000pyclustering-0.10.1.2/ci/cloud/__init__.py000077500000000000000000000003671375753423500203220ustar00rootroot00000000000000"""! @brief Cloud Tool for Yandex Disk service. @details The tool has been implemented to support CI infrastructure of pyclustering library. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ pyclustering-0.10.1.2/ci/cloud/__main__.py000077500000000000000000000017061375753423500203010ustar00rootroot00000000000000"""! @brief Cloud Tool for Yandex Disk service. @details Cloud Tool is used for storing binaries of pyclustering library. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import sys from cloud.task import task from cloud.task_handler import task_handler def run(): if len(sys.argv) == 2: client_task = task(sys.argv[1], []) token = "" elif len(sys.argv) < 3: raise SyntaxError("ERROR: Incorrect amount of arguments '%d' " "(please, see 'python3 ci/cloud --help')." % len(sys.argv)) else: token = sys.argv[1] action = sys.argv[2] params = sys.argv[3:] client_task = task(action, params) task_handler(token).process(client_task) if __name__ == '__main__': try: run() exit(0) except Exception as error: print(error) exit(-1) pyclustering-0.10.1.2/ci/cloud/cloud/000077500000000000000000000000001375753423500173065ustar00rootroot00000000000000pyclustering-0.10.1.2/ci/cloud/cloud/__init__.py000077500000000000000000000003421375753423500214210ustar00rootroot00000000000000"""! @brief Cloud Tool for Yandex Disk service. @details Cloud Tool is used for storing binaries of pyclustering library. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/ci/cloud/cloud/task.py000077500000000000000000000063531375753423500206340ustar00rootroot00000000000000"""! @brief Cloud Tool for Yandex Disk service. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ class task: def __init__(self, action, params): self.__action = action.lower() self.__params = self.__parse_arguments(params) def __parse_arguments(self, params): action_params = {} if self.__action == 'upload' or self.__action == 'download': if len(params) != 2: raise ValueError("ERROR: Incorrect amount of arguments ('%d' instead of '2')." % len(params)) action_params['from'] = params[0] action_params['to'] = params[1] elif self.__action == 'mkdir': if len(params) != 1: raise ValueError("ERROR: Incorrect amount of arguments ('%d' instead of '1')." % len(params)) action_params['folder'] = params[0] elif self.__action == 'rm': if len(params) != 1: raise ValueError("ERROR: Incorrect amount of arguments ('%d' instead of '1')." % len(params)) action_params['path'] = params[0] elif self.__action == 'get_bin': if len(params) != 3: raise ValueError("ERROR: Incorrect amount of arguments ('%d' instead of '3')." % len(params)) action_params['branch'] = params[0] action_params['os'] = params[1] action_params['platform'] = params[2] if action_params['os'] not in ['windows', 'linux', 'macos']: raise ValueError("ERROR: Unsupported operating system '%s' (available: 'linux', 'windows')." % action_params['os']) if action_params['platform'] not in ['32-bit', '64-bit']: raise ValueError("ERROR: Unsupported platform '%s' (available: '32-bit', '64-bit')." % action_params['platform']) elif self.__action == 'get_third_party': if len(params) != 2 and len(params) != 3: raise ValueError("ERROR: Incorrect amount of arguments ('%d' instead of '2' or '3')." % len(params)) action_params['os'] = params[0] action_params['platform'] = params[1] action_params['to'] = None if len(params) > 2: action_params['to'] = params[2] if action_params['os'] not in ['windows', 'linux', 'macos']: raise ValueError("ERROR: Unsupported operating system '%s' (available: 'linux', 'windows')." % action_params['os']) if action_params['platform'] not in ['32-bit', '64-bit']: raise ValueError("ERROR: Unsupported platform '%s' (available: '32-bit', '64-bit')." % action_params['platform']) elif self.__action in ['-h', '--help', 'help']: self.__action = 'help' else: raise ValueError("ERROR: Unknown action is specified '%s'." % self.__action) return action_params def get_action(self): return self.__action def get_param(self, name): if name not in self.__params: raise IndexError("ERROR: Action '%s' does not have parameter '%s'" % (self.__action, len(self.__params))) return self.__params[name]pyclustering-0.10.1.2/ci/cloud/cloud/task_handler.py000077500000000000000000000216661375753423500223350ustar00rootroot00000000000000"""! @brief Cloud Tool for Yandex Disk service. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import os import zipfile from cloud.yandex_disk import yandex_disk class task_handler: __LOCAL_PATH_THIRD_PARTIES_LIBS = "ccore/external/libs" __LOCAL_PATH_THIRD_PARTIES_INCLUDE = "ccore/external/include" __LOCAL_OS_NAMES = {"windows": "win", "linux": "linux", "macos": "macos"} def __init__(self, token): self.__token = token def process(self, task): action = task.get_action() if action == 'upload': self.__upload(task.get_param('from'), task.get_param('to')) elif action == 'download': self.__download(task.get_param('from'), task.get_param('to')) elif action == 'mkdir': self.__mkdir(task.get_param('folder')) elif action == 'rm': self.__rm(task.get_param('path')) elif action == 'get_bin': self.__get_bin(task.get_param('branch'), task.get_param('os'), task.get_param('platform')) elif action == 'get_third_party': self.__third_party(task.get_param('os'), task.get_param('platform'), task.get_param('to')) elif action == 'help': self.__help() else: raise RuntimeError("ERROR: Unknown action is specified '%s'." % action) def __upload(self, from_path, to_path): if not os.path.isfile(from_path): raise FileExistsError("ERROR: File '%s' on local machine does not exist." % from_path) disk_client = yandex_disk(self.__token) if disk_client.file_exist(to_path): print("WARNING: File '%s' already exists on the cloud and it will be overwritten." % to_path) if not disk_client.delete(to_path): raise RuntimeError("ERROR: Impossible to remove file '%s'." % to_path) if disk_client.upload(from_path, to_path) is True: print("INFO: File '%s' is successfully uploaded to '%s'." % (from_path, to_path)) def __download(self, from_path, to_path): if os.path.isfile(to_path): print("WARNING: File '%s' already exists on the local machine and it will be overwritten." % to_path) os.remove(to_path) disk_client = yandex_disk(self.__token) if disk_client.file_exist(from_path) is False: raise FileExistsError("ERROR: File '%s' does not exist on the cloud." % from_path) if disk_client.download(from_path, to_path) is True: print("INFO: File '%s' is successfully downloaded to '%s'." % (from_path, to_path)) def __mkdir(self, folder): disk_client = yandex_disk(self.__token) if disk_client.file_exist(folder): print("INFO: Folder '%s' already exists." % folder) return if disk_client.create_folder(folder) is True: print("INFO: Folder '%s' is successfully created." % folder) def __rm(self, path): disk_client = yandex_disk(self.__token) if disk_client.file_exist(path) or disk_client.directory_exist(path): disk_client.delete(path) print("INFO: '%s' is successfully removed." % path) else: print("WARNING: File or folder '%s' is not found." % path) def __get_bin(self, branch, osys, platform): dict_prefix = {"macos": "lib", "linux": "lib", "windows": ""} dict_extension = {"macos": "so", "linux": "so", "windows": "dll"} dict_os = {"macos": "macos", "linux": "linux", "windows": "win"} disk_client = yandex_disk(self.__token) remote_path_builds = "/%s/%s/%s" % (branch, osys, platform) builds = disk_client.folder_content(remote_path_builds) if len(builds) == 0: print("WARNING: No builds for system '%s' on platform '%s' (branch '%s')." % (osys, platform, branch)) return sorted_builds = sorted(builds) latest_build = sorted_builds[-1] remote_path_binary = "%s/%s/%spyclustering.%s" % (remote_path_builds, latest_build, dict_prefix[osys], dict_extension[osys]) script_path = os.path.dirname(os.path.realpath(__file__)) local_path_binary = "%s/../../../pyclustering/core/%s/%s/%spyclustering.%s" % (script_path, platform, dict_os[osys], dict_prefix[osys], dict_extension[osys]) local_path_binary = os.path.realpath(local_path_binary) self.__download(remote_path_binary, local_path_binary) print("Latest build for '%s' '%s' on branch '%s' is '%s'" % (osys, platform, branch, builds[-1])) def __third_party_libs(self, operating_system, platform, to_path): disk_client = yandex_disk(self.__token) remote_path_libs = "/third_party/" + operating_system + "/" + platform if not disk_client.directory_exist(remote_path_libs): raise FileExistsError("ERROR: Third party folder '%s' is not found on the cloud." % remote_path_libs) lib_files = disk_client.folder_content(remote_path_libs) if lib_files is None: raise FileExistsError("ERROR: Impossible to get content of third party folder '%s'." % remote_path_libs) if len(lib_files) == 0: print("WARNING: No third parties for system '%s' on platform '%s'." % (operating_system, platform)) return if to_path is None: script_path = os.path.dirname(os.path.realpath(__file__)) local_binary_folder = script_path + "/../../../" + task_handler.__LOCAL_PATH_THIRD_PARTIES_LIBS + "/" + operating_system + "/" + platform else: local_binary_folder = to_path for file in lib_files: remote_file_path = remote_path_libs + "/" + file local_file_path = local_binary_folder + "/" + file self.__download(remote_file_path, local_file_path) def __third_party_include(self, to_path): disk_client = yandex_disk(self.__token) remote_path_inc = "/third_party/include" if not disk_client.directory_exist(remote_path_inc): raise FileExistsError("ERROR: Third party folder '%s' is not found on the cloud." % remote_path_inc) inc_files = disk_client.folder_content(remote_path_inc) if inc_files is None: raise FileExistsError("ERROR: Impossible to get content of third party folder '%s'." % remote_path_inc) if len(inc_files) == 0: print("WARNING: No include third parties.") return if to_path is None: script_path = os.path.dirname(os.path.realpath(__file__)) local_include_folder = script_path + "/../../../" + task_handler.__LOCAL_PATH_THIRD_PARTIES_INCLUDE else: local_include_folder = to_path for file in inc_files: include_library_name = os.path.splitext(file)[0] include_library_path = local_include_folder + "/" + include_library_name if os.path.isdir(include_library_path): print("WARNING: Include library folder already exists.") continue remote_file_path = remote_path_inc + "/" + file local_file_path = local_include_folder + "/" + file if os.path.isfile(local_file_path) is True: os.remove(local_file_path) self.__download(remote_file_path, local_file_path) zip_archive = zipfile.ZipFile(local_file_path, 'r') zip_archive.extractall(local_include_folder) zip_archive.close() os.remove(local_file_path) def __third_party(self, operating_system, platform, to_path): self.__third_party_libs(operating_system, platform, to_path) self.__third_party_include(to_path) def __help(self): print("Following commands are supported by the tool:") print(" upload - upload file or folder from local machine path to remote path on clound.") print(" download - download file or folder from remote path on cloud to local machine.") print(" rm - remove file or folder on cloud.") print(" mkdir - create folder on cloud.") print(" get_third_party - download third party from cloud for specific system (linux, windows, macos) and platform (32-bit, 64-bit)\n" " to specific folder on local machine.") print(" get_bin - download latest binary file for particular branch, system (linux, windows, macos) and platform (32-bit, 64-bit).") print("") print("Example:") print(" python3 ci/cloud $CLOUD_TOKEN get_third_party windows 64-bit") pyclustering-0.10.1.2/ci/cloud/cloud/yandex_disk.py000077500000000000000000000164221375753423500221720ustar00rootroot00000000000000"""! @brief Cloud Tool for Yandex Disk service. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import http.client import json import os.path import urllib.request from urllib.parse import urlparse class file_type: FILE = 'file' DIRECTORY = 'dir' class yandex_disk: __REQUEST_ATTEMPTS = 3 __SERVICE_ADDRESS = "cloud-api.yandex.net:443" __HTTP_DISK = "/v1/disk" __HTTP_RESOURCES = "/v1/disk/resources" __HTTP_RESOURCES_UPLOAD = "/v1/disk/resources/upload" __HTTP_RESOURCES_DOWNLOAD = "/v1/disk/resources/download" def __init__(self, token): self.__token = token def get_free_space(self): result, response_content = self.__send_request("GET", yandex_disk.__HTTP_DISK) if result != 200: print("ERROR: Impossible to obtain information about disk.") return None json_content = json.loads(response_content) total_space = int(json_content['total_space']) used_space = int(json_content['used_space']) free_space = (total_space - used_space) / 1000000 return free_space def folder_content(self, path): result, response_content = self.__send_request("GET", yandex_disk.__HTTP_RESOURCES, {"path": path}) if result != 200: print("ERROR: Impossible to list content of folder '%s'." % path) return None json_content = json.loads(response_content) if json_content['type'] != file_type.DIRECTORY: print("ERROR: Specified path '%s' is not folder." % path) return None folder_content = json_content['_embedded']['items'] result = [] for file_info in folder_content: result.append(file_info['name']) return result def upload(self, local_path, remote_path): if not os.path.isfile(local_path): print("ERROR: Impossible to upload non-existed file '%s'." % local_path) return False file_descriptor = open(local_path, "rb") binary_file = file_descriptor.read() file_descriptor.close() result, response_content = self.__send_request("GET", yandex_disk.__HTTP_RESOURCES_UPLOAD, {"path": remote_path}) if result != 200: print("ERROR: Impossible to obtain link to upload file to '%s' (code: '%d', description: '%s')" % (remote_path, result, response_content)) return False json_content = json.loads(response_content) upload_link = json_content['href'] result = self.__upload_request(binary_file, upload_link) if result != 201: print("ERROR: Impossible to upload file using link '%s' (code: '%d')." % (upload_link, result)) return False return True def download(self, remote_path, local_path): if os.path.isfile(local_path): print("ERROR: Impossible to download file to path '%s' because file with such name already exists" % local_path) return False result, response_content = self.__send_request("GET", yandex_disk.__HTTP_RESOURCES_DOWNLOAD, {"path": remote_path}) if result != 200: print("ERROR: Impossible to obtain link to download file from '%s' (code: '%d', description: '%s')" % (remote_path, result, response_content)) return False json_content = json.loads(response_content) download_link = json_content['href'] status, content = self.__download_request(download_link) if status != 200: print("ERROR: Impossible to download file using link '%s' (code: '%d')." % (download_link, status)) return False file_descriptor = open(local_path, "wb") file_descriptor.write(content) file_descriptor.close() return True def delete(self, path): result, response_content = self.__send_request("DELETE", yandex_disk.__HTTP_RESOURCES, {"path": path}) if result not in [202, 204]: print("ERROR: Impossible to delete folder (code: '%d', description: '%s')" % (result, response_content)) return False return True def create_folder(self, path): result, response_content = self.__send_request("PUT", yandex_disk.__HTTP_RESOURCES, {"path": path}) if result != 201 and result != 409: print("ERROR: Impossible to create folder (code: '%d', description: '%s')" % (result, response_content)) return False return True def file_exist(self, path): result, response_content = self.__send_request("GET", yandex_disk.__HTTP_RESOURCES, {"path": path}) if result != 200: if result == 401: raise PermissionError("ERROR: Impossible to obtain information about file '%s' " "(unauthorized request)." % path) return False json_content = json.loads(response_content) if json_content['type'] != file_type.FILE: return False return True def directory_exist(self, path): result, response_content = self.__send_request("GET", yandex_disk.__HTTP_RESOURCES, {"path": path}) if result != 200: if result == 401: raise PermissionError("ERROR: Impossible to obtain information about directory '%s' " "(unauthorized request)." % path) return False json_content = json.loads(response_content) if json_content['type'] != file_type.DIRECTORY: return False return True def __upload_request(self, binary_file, upload_link): parse_result = urlparse(upload_link) connection = http.client.HTTPSConnection(parse_result.netloc) connection.request("PUT", parse_result.path, binary_file, {'Authorization': "OAuth " + self.__token}) response_status = connection.getresponse().status connection.close() return response_status def __download_request(self, download_link): with urllib.request.urlopen(download_link) as url: response_status = url.getcode() response_content = url.read() return response_status, response_content def __send_request(self, method, url, params=None): connection = http.client.HTTPSConnection(self.__SERVICE_ADDRESS) attempt_counter = 0 response_status, response_content = None, None while ((response_status is None) or ((response_status >= 500) and (response_status < 600))) and (attempt_counter < self.__REQUEST_ATTEMPTS): url_complete = url url_params = params or {} for key, value in url_params.items(): url_complete += ("?%s=%s" % (str(key), str(value))) connection.request(method, url_complete, headers={'Authorization': "OAuth " + self.__token}) response = connection.getresponse() response_status = response.status response_content = response.read().decode('utf-8') attempt_counter += 1 connection.close() return response_status, response_content pyclustering-0.10.1.2/ci/cloud/tests/000077500000000000000000000000001375753423500173425ustar00rootroot00000000000000pyclustering-0.10.1.2/ci/cloud/tests/__init__.py000077500000000000000000000002111375753423500214500ustar00rootroot00000000000000"""! @brief Tests for Cloud Tool. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/ci/cloud/tests/test_cloud.py000077500000000000000000000117101375753423500220640ustar00rootroot00000000000000"""! @brief Tests for Cloud Tool. @details In case of running unit-tests make sure that environment variable with name 'CLOUD_TOKEN' exists. This variable should contains token for authorization. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import os import unittest from cloud.task import task from cloud.task_handler import task_handler from cloud.yandex_disk import yandex_disk class cloud_unit_test(unittest.TestCase): def setUp(self): token = os.environ.get('CLOUD_TOKEN') self.assertIsNotNone(token) self.__token = token self.__disk_client = yandex_disk(token) def test_get_info(self): free_space = self.__disk_client.get_free_space() self.assertGreater(free_space, 0) def test_get_content_folder(self): self.assertIsNotNone(self.__disk_client.folder_content("/")) def test_create_delete_folder(self): folder_name = "/test_folder1" self.assertTrue(self.__disk_client.create_folder(folder_name)) self.assertTrue(self.__disk_client.directory_exist(folder_name)) content = self.__disk_client.folder_content(folder_name) self.assertEqual(len(content), 0) self.assertTrue(self.__disk_client.delete(folder_name)) self.assertFalse(self.__disk_client.directory_exist(folder_name)) def test_upload_file(self): folder_name = "/test_folder2" file_name = "test_file1.txt" file_path = folder_name + "/" + file_name file_descriptor = open(file_name, "w+") file_descriptor.write('Hello World! Hello PyClustering!') file_descriptor.close() self.assertTrue(self.__disk_client.create_folder(folder_name)) self.assertFalse(self.__disk_client.file_exist(file_path)) self.assertTrue(self.__disk_client.upload(file_name, file_path)) self.assertTrue(self.__disk_client.file_exist(file_path)) self.assertTrue(self.__disk_client.delete(file_path)) self.assertFalse(self.__disk_client.file_exist(file_path)) self.assertTrue(self.__disk_client.delete(folder_name)) os.remove(file_name) def test_upload_download(self): folder_name = "/test_folder3" file_name1 = "test_file2.txt" file_name2 = "test_file3.txt" file_path = folder_name + "/" + file_name1 file_descriptor = open(file_name1, "w+") content_file1 = "Hello World! Hello PyClustering! Hello PyClustering!" file_descriptor.write(content_file1) file_descriptor.close() self.assertTrue(self.__disk_client.create_folder(folder_name)) self.assertFalse(self.__disk_client.file_exist(file_path)) self.assertTrue(self.__disk_client.upload(file_name1, file_path)) self.assertTrue(self.__disk_client.file_exist(file_path)) self.assertTrue(self.__disk_client.download(file_path, file_name2)) self.assertTrue(os.path.isfile(file_name2)) file_descriptor = open(file_name2, "r") content_file2 = file_descriptor.read() file_descriptor.close() self.assertEqual(content_file1, content_file2) self.assertTrue(self.__disk_client.delete(folder_name)) os.remove(file_name1) os.remove(file_name2) def test_command_create(self): folder_name = "/test_folder4" client_task = task("mkdir", [folder_name]) task_handler(self.__token).process(client_task) self.assertTrue(self.__disk_client.directory_exist(folder_name)) self.assertTrue(self.__disk_client.delete(folder_name)) def test_command_upload_download(self): folder_name = "/test_folder5" file_name1 = "test_file4.txt" file_name2 = "test_file5.txt" file_path = folder_name + "/" + file_name1 file_descriptor = open(file_name1, "w+") content_file1 = "Hello PyClustering! Hello PyClustering! Hello PyClustering!" file_descriptor.write(content_file1) file_descriptor.close() client_task = task("mkdir", [folder_name]) task_handler(self.__token).process(client_task) self.assertTrue(self.__disk_client.directory_exist(folder_name)) client_task = task("upload", [file_name1, file_path]) task_handler(self.__token).process(client_task) self.assertTrue(self.__disk_client.file_exist(file_path)) client_task = task("download", [file_path, file_name2]) task_handler(self.__token).process(client_task) self.assertTrue(os.path.isfile(file_name2)) file_descriptor = open(file_name2, "r") content_file2 = file_descriptor.read() file_descriptor.close() self.assertEqual(content_file1, content_file2) self.assertTrue(self.__disk_client.delete(folder_name)) os.remove(file_name1) os.remove(file_name2) pyclustering-0.10.1.2/ci/github-ci.sh000077500000000000000000000053511375753423500173100ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # print_error() { echo "[PYCLUSTERING CI] ERROR: $1" } print_info() { echo "[PYCLUSTERING CI] INFO: $1" } check_failure() { if [ $? -ne 0 ] ; then if [ -z $1 ] ; then print_error $1 else print_error "Failure exit code is detected." fi exit 1 fi } run_pypi_install_job() { print_info "PyPi Installer Testing." print_info "- Download and install the library using pip3." print_info "- Run tests for the library." print_info "Install 'setuptools' for pip3." sudo apt-get install -qq python3-pip sudo apt-get install -qq python3-setuptools print_info "Install 'pyclustering' from PyPi." PYPI_SOURCE=$1 if [[ $PYPI_SOURCE == "testpypi" ]]; then pip3 install --extra-index-url https://testpypi.python.org/pypi pyclustering else pip3 install pyclustering fi print_info "Navigate to the system root directory to run tests for installed version" cd / print_info "Run tests for 'pyclustering' package." python3 -m pyclustering.tests print_info "Navigate to the repository folder." cd - } run_cmake_pyclustering_build() { print_info "C++ pyclustering build using CMake." print_info "- Build C++ static and shared pyclustering library using CMake." print_info "- Run build verification test for the static library." print_info "- Run build verification test for the shared library." print_info "Create a build folder." mkdir ccore/build print_info "Navigate to the build folder." cd ccore/build print_info "Run CMake to generate makefiles to build pyclustering library." cmake .. print_info "Build C++ pyclustering shared library and build verification test for it." make -j8 bvt-shared print_info "Build C++ pyclustering static library and build verification test for it." make -j8 bvt-static print_info "Run build verification test for the C++ pyclustering shared library." ./bvt-shared check_failure "Build verification test failed for the C++ pyclustering shared library." print_info "Run build verification test for the C++ pyclustering static library." ./bvt-static check_failure "Build verification test failed for the C++ pyclustering static library." print_info "Navigate to the repository folder." cd - } set -e set -x case $1 in PYPI_INSTALLER) run_pypi_install_job ;; TESTPYPI_INSTALLER) run_pypi_install_job testpypi ;; TEST_CMAKE_PYCLUSTERING_BUILD) run_cmake_pyclustering_build ;; *) print_error "Unknown target is specified: '$1'" exit 1 ;; esac pyclustering-0.10.1.2/ci/travis-ci.sh000077500000000000000000000327431375753423500173430ustar00rootroot00000000000000# # @authors Andrei Novikov (pyclustering@yandex.ru) # @date 2014-2020 # @copyright BSD-3-Clause # CCORE_64BIT_BINARY_FOLDER=pyclustering/core/64-bit/linux CCORE_32BIT_BINARY_FOLDER=pyclustering/core/32-bit/linux CCORE_BINARY_NAME=libpyclustering.so DOXYGEN_FILTER=( "warning: Unexpected new line character" ) print_error() { echo "[PYCLUSTERING CI] ERROR: $1" } print_info() { echo "[PYCLUSTERING CI] INFO: $1" } check_failure() { if [ $? -ne 0 ] ; then if [ -z $1 ] ; then print_error $1 else print_error "Failure exit code is detected." fi exit 1 fi } check_error_log_file() { problems_amount=$(cat $1 | wc -l) printf "Total amount of errors and warnings: '%d'\n" "$problems_amount" if [ $problems_amount -ne 0 ] ; then print_info "List of warnings and errors:" cat $1 print_error $2 exit 1 fi } filter_content() { file_name=$1 output_file_name=$2 if [ ${#DOXYGEN_FILTER[@]} -eq 0 ]; then cat $file_name return fi while read line do for string_filter in "${DOXYGEN_FILTER[@]}" do if [[ "$line" != *"$string_filter"* ]] then echo -e "$line" >> $output_file_name fi done done < $file_name } build_ccore() { cd $TRAVIS_BUILD_DIR/ccore/ [ -f stderr.log ] && rm stderr.log [ -f stdout.log ] && rm stdout.log if [ "$1" == "64-bit" ]; then make ccore_64bit > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) check_error_log_file stderr.log "Building shared pyclustering (64-bit): FAILURE." make ccore_64bit_static > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) check_error_log_file stderr.log "Building static pyclustering (64-bit): FAILURE." elif [ "$1" == "32-bit" ]; then make ccore_32bit > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) check_error_log_file stderr.log "Building shared pyclustering (32-bit): FAILURE." make ccore_32bit_static > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) check_error_log_file stderr.log "Building static pyclustering (32-bit): FAILURE." else print_error "Unknown platform is specified to build pyclustering library." exit 1 fi cd - } run_build_ccore_job() { print_info "CCORE (C++ code building):" print_info "- Build shared pyclustering library for 64-bit platform." print_info "- Build static pyclustering library for 64-bit platform." print_info "- Build shared pyclustering library for 32-bit platform." print_info "- Build static pyclustering library for 32-bit platform." #install requirement for the job print_info "Install requirement for CCORE building." sudo apt-get install -qq g++-multilib # show info g++ --version gcc --version # build ccore library build_ccore 64-bit build_ccore 32-bit print_info "Upload ccore 64-bit binary." upload_binary 64-bit linux print_info "Upload ccore 32-bit binary." upload_binary 32-bit linux } run_analyse_ccore_job() { print_info "ANALYSE CCORE (C/C++ static analysis):" print_info "- Code checking using 'cppcheck'." # install requirement for the job print_info "Install requirement for static analysis of CCORE." sudo apt-get install -qq cppcheck sudo apt-get install -qq clang # analyse source code cd ccore/ make cppcheck check_failure "C/C++ static analysis (tool: 'cppcheck'): FAILURE." print_info "- Code checking using 'scan-build clang++'." make clang > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) check_error_log_file stderr.log "C/C++ static analysis (tool: 'scan-build clang++'): FAILURE." } run_ut_ccore_job() { print_info "UT CCORE (C++ code unit-testing of CCORE library):" print_info "- Build C++ unit-test project for CCORE library." print_info "- Run CCORE library unit-tests." # install requirements for the job sudo apt-get install python sudo -H pip install cpp-coveralls==0.3.12 # build unit-test project cd ccore/ make ut > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) check_error_log_file stderr.log "Building CCORE unit-tests: FAILURE." # run unit-tests and obtain code coverage make utrun check_failure "CCORE unit-testing status: FAILURE." # step back to have full path to files in coverage reports coveralls --root ../ --build-root . --exclude ccore/tst/ --exclude ccore/external/ --exclude ccore/bvt/ --gcov-options '\-lp' } run_valgrind_ccore_job() { print_info "VALGRIND CCORE (C++ code valgrind shock checking):" print_info "- Run unit-tests of pyclustering." print_info "- Shock memory leakage detection by valgrind." # install requirements for the job sudo apt-get install -qq valgrind # build and run unit-test project under valgrind to check memory leakage cd ccore/ make valgrind_shock check_failure "CCORE shock memory leakage status: FAILURE." } run_test_pyclustering_job() { print_info "TEST PYCLUSTERING (unit and integration testing):" print_info "- Download CCORE library." print_info "- Run unit and integration tests of pyclustering." print_info "- Measure code coverage for python code." # install requirements for the job install_miniconda 64-bit pip install coveralls # set path to the tested library PYTHONPATH=`pwd` export PYTHONPATH=${PYTHONPATH} # build ccore library build_ccore 64-bit # run unit and integration tests and obtain coverage results coverage run --source=pyclustering --omit='pyclustering/*/tests/*,pyclustering/*/examples/*,pyclustering/tests/*' pyclustering/tests/__main__.py coveralls } run_integration_test_job() { print_info "INTEGRATION TESTING ('ccore' <-> 'pyclustering' for platform '$1')." print_info "- Build CCORE library." print_info "- Run integration tests of pyclustering." PLATFORM_TARGET=$1 # install requirements for the job install_miniconda $PLATFORM_TARGET sudo apt-get install -qq g++-multilib # build ccore library build_ccore $PLATFORM_TARGET # run integration tests python pyclustering/tests/__main__.py --integration } run_build_test_ccore_macos_job() { print_info "BUILD AND TEST CCORE FOR MACOS." print_info "- Build CCORE library." print_info "- Run integration tests of pyclustering." print_info "- Upload binary to cloud." # set path to the tested library PYTHONPATH=`pwd` export PYTHONPATH=${PYTHONPATH} # build ccore library build_ccore 64-bit # install corresponding packages pip3 install numpy matplotlib scipy Pillow # run integration tests python3 pyclustering/tests/__main__.py --integration # upload binaries to cloud upload_binary 64-bit macos } run_doxygen_job() { print_info "DOXYGEN (documentation generation)." print_info "- Generate documentation and check for warnings." print_info "Install doxygen" sudo apt-get install doxygen print_info "Install requirements for doxygen." sudo apt-get install graphviz sudo apt-get install texlive print_info "Prepare log files." report_file=doxygen_problems.log report_file_filtered=doxygen_problems_filtered.log rm -f $report_file rm -f $report_file_filtered print_info "Generate documentation." doxygen --version doxygen docs/doxygen_conf_pyclustering > /dev/null 2> $report_file filter_content $report_file $report_file_filtered check_error_log_file $report_file_filtered "Building doxygen documentation: FAILURE." print_info "Building doxygen documentation: SUCCESS." } run_deploy_job() { print_info "Deploy (upload linux binary file to github)" if [[ $TRAVIS_COMMIT_MESSAGE != *"[publish]"* ]]; then print_info "Binary files will not be published to github repository (keyword '[publish]' is not specified)." exit 0 fi git config --global user.email "pyclustering@yandex.ru" git config --global user.name "Travis-CI" git config credential.helper "store --file=.git/credentials" echo "https://${GH_TOKEN}:@github.com" > .git/credentials git config credential.helper "store --file=.git/credentials" print_info "Prepare copy for pushing (reset, checkout, pull)" git reset --hard git checkout $TRAVIS_BRANCH git pull print_info "Prepare binary folder" [ ! -d $CCORE_64BIT_BINARY_FOLDER ] && mkdir $CCORE_64BIT_BINARY_FOLDER [ ! -d $CCORE_32BIT_BINARY_FOLDER ] && mkdir $CCORE_32BIT_BINARY_FOLDER download_binary 64-bit download_binary 32-bit print_info "Add changes for commit" echo "linux ccore $PLATFORM_TARGET build version: '$TRAVIS_BUILD_NUMBER'" > $CCORE_64BIT_BINARY_FOLDER/.linux.info echo "linux ccore $PLATFORM_TARGET build version: '$TRAVIS_BUILD_NUMBER'" > $CCORE_32BIT_BINARY_FOLDER/.linux.info git add $CCORE_64BIT_BINARY_FOLDER/.linux.info git add $CCORE_32BIT_BINARY_FOLDER/.linux.info git add $CCORE_64BIT_BINARY_FOLDER/$CCORE_BINARY_NAME git add $CCORE_32BIT_BINARY_FOLDER/$CCORE_BINARY_NAME print_info "Display status and changes" git status print_info "Push changes to github repository" git commit . -m "[travis-ci][ci skip] push new ccore version '$TRAVIS_BUILD_NUMBER'" git push } install_miniconda() { print_info "Start downloading process of Miniconda." PLATFORM_TARGET=$1 if [ "$PLATFORM_TARGET" == "64-bit" ]; then print_info "Download Miniconda for platform '$PLATFORM_TARGET'." wget https://repo.continuum.io/miniconda/Miniconda3-4.6.14-Linux-x86_64.sh -O miniconda.sh elif [ "$PLATFORM_TARGET" == "32-bit" ]; then print_info "Download Miniconda for platform '$PLATFORM_TARGET'" wget https://repo.continuum.io/miniconda/Miniconda3-4.5.12-Linux-x86.sh -O miniconda.sh else print_error "Unknown platform '$PLATFORM_TARGET' is specified for Miniconda." exit 1 fi print_info "Installing Miniconda." bash miniconda.sh -b -p $HOME/miniconda export PATH="$HOME/miniconda/bin:$PATH" hash -r print_info "Configuring Miniconda." conda config --set always_yes yes conda install -q libgfortran conda create -q -n test-environment python=3.5 numpy scipy matplotlib Pillow source activate test-environment } upload_binary() { print_info "Upload binary files (platform: '$1', os: '$2') to storage." if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then print_info "Upload CCORE library is disabled in case of Pull Request." return fi BUILD_PLATFORM=$1 BUILD_OS=$2 BINARY_FOLDER=$TRAVIS_BUILD_NUMBER LOCAL_BINARY_PATH=pyclustering/core/$BUILD_PLATFORM/$BUILD_OS/$CCORE_BINARY_NAME # Create folder for uploaded binary file python3 ci/cloud $YANDEX_DISK_TOKEN mkdir /$TRAVIS_BRANCH python3 ci/cloud $YANDEX_DISK_TOKEN mkdir /$TRAVIS_BRANCH/$BUILD_OS python3 ci/cloud $YANDEX_DISK_TOKEN mkdir /$TRAVIS_BRANCH/$BUILD_OS/$BUILD_PLATFORM python3 ci/cloud $YANDEX_DISK_TOKEN mkdir /$TRAVIS_BRANCH/$BUILD_OS/$BUILD_PLATFORM/$BINARY_FOLDER # Upload binary file REMOTE_BINARY_FILEPATH=/$TRAVIS_BRANCH/$BUILD_OS/$BUILD_PLATFORM/$BINARY_FOLDER/$CCORE_BINARY_NAME python3 ci/cloud $YANDEX_DISK_TOKEN upload $LOCAL_BINARY_PATH $REMOTE_BINARY_FILEPATH } download_binary() { print_info "Download CCORE binary (platform: '$1', os: '$2') file from cloud." if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then print_info "Download CCORE library is disabled in case of Pull Request." return fi BUILD_PLATFORM=$1 BUILD_OS=$2 LOCAL_BINARY_PATH=pyclustering/core/$BUILD_PLATFORM/$BUILD_OS/$CCORE_BINARY_NAME # Download binary file BINARY_FOLDER=$TRAVIS_BUILD_NUMBER BINARY_FILEPATH=/$TRAVIS_BRANCH/$BUILD_OS/$BUILD_PLATFORM/$BINARY_FOLDER/$CCORE_BINARY_NAME python3 ci/cloud $YANDEX_DISK_TOKEN download $BINARY_FILEPATH $LOCAL_BINARY_PATH print_info "Content of the binary folder." ls $LOCAL_BINARY_PATH -la } set -e set -x if [[ $TRAVIS_COMMIT_MESSAGE == *"[no-build]"* ]]; then print_info "Option '[no-build]' is detected, sources will not be built, checked, verified and published." exit 0 fi if [[ $TRAVIS_COMMIT_MESSAGE == *"[build-only-osx]"* ]]; then if [[ $1 == BUILD_TEST_CCORE_MACOS ]]; then print_info "Option '[build-only-osx]' is detected, MAC OS build will be started." else print_info "Option '[build-only-osx]' is detected, job '$1' is going to be skipped." exit 0 fi fi if [[ $TRAVIS_COMMIT_MESSAGE == *"[build-only-docs]"* ]]; then if [[ $1 == DOCUMENTATION ]]; then print_info "Option '[build-only-docs]' is detected, documentation build will be started." else print_info "Option '[build-only-docs]' is detected, job '$1' is going to be skipped." exit 0 fi fi case $1 in BUILD_CCORE) run_build_ccore_job ;; ANALYSE_CCORE) run_analyse_ccore_job ;; UT_CCORE) run_ut_ccore_job ;; VALGRIND_CCORE) run_valgrind_ccore_job ;; TEST_PYCLUSTERING) run_test_pyclustering_job ;; IT_CCORE_X86) run_integration_test_job 32-bit ;; IT_CCORE_X64) run_integration_test_job 64-bit ;; BUILD_TEST_CCORE_MACOS) run_build_test_ccore_macos_job ;; DOCUMENTATION) run_doxygen_job ;; DEPLOY) run_deploy_job ;; *) print_error "Unknown target is specified: '$1'" exit 1 ;; esac pyclustering-0.10.1.2/docs/000077500000000000000000000000001375753423500154275ustar00rootroot00000000000000pyclustering-0.10.1.2/docs/citation.bib000077500000000000000000000632141375753423500177300ustar00rootroot00000000000000@inproceedings{inproceedings::bang::1, author = "Schikuta, Erich and Erhart, Martin", editor = "Amin, Adnan and Dori, Dov and Pudil, Pavel and Freeman, Herbert", title = "BANG-Clustering: A novel grid-clustering algorithm for huge data sets", booktitle = "Advances in Pattern Recognition", year = "1998", publisher = "Springer Berlin Heidelberg", address = "Berlin, Heidelberg", pages = "867--874", isbn = "978-3-540-68526-5" } @article{article::birch::1, author = {Zhang, Tian and Ramakrishnan, Raghu and Livny, Miron}, title = {BIRCH: An Efficient Data Clustering Method for Very Large Databases}, journal = {SIGMOD Rec.}, issue_date = {June 1996}, volume = {25}, number = {2}, month = jun, year = {1996}, issn = {0163-5808}, pages = {103--114}, numpages = {12}, url = {http://doi.acm.org/10.1145/235968.233324}, doi = {10.1145/235968.233324}, acmid = {233324}, publisher = {ACM}, address = {New York, NY, USA}, } @book{book::pattern_recognition::2009, Title = {Pattern Recognition, fourth edition}, Annote = {SIGNATUR = 2011-10411}, Author = {Sergios Theodoridis and Konstantinos Koutroumbas}, Keywords = {PATTERN RECOGNITION}, Publisher = {Elsevier}, Year = {2009}, Aquired = {2011}, Place = {Favoritenstrasse 9/4th Floor/1863} } @inproceedings{article::kmeans++::1, author = {David Arthur and Sergei Vassilvitskii}, title = {K-means++: the advantages of careful seeding}, booktitle = {In Proceedings of the 18th Annual ACM-SIAM Symposium on Discrete Algorithms}, year = {2007} } @article{article::clarans::1, author = {Ng, Raymond T. and Han, Jiawei}, journal = {IEEE Transactions on Knowledge and Data Engineering}, number = 5, pages = {1003--1016}, publisher = {IEEE Computer Society}, title = {CLARANS: A Method for Clustering Objects for Spatial Data Mining}, volume = 14, year = 2002 } @article{article::cure::1, author = {Guha, Sudipto and Rastogi, Rajeev and Shim, Kyuseok}, title = {CURE: An Efficient Clustering Algorithm for Large Databases}, journal = {SIGMOD Rec.}, issue_date = {June 1998}, volume = {27}, number = {2}, month = jun, year = {1998}, issn = {0163-5808}, pages = {73--84}, numpages = {12}, url = {http://doi.acm.org/10.1145/276305.276312}, doi = {10.1145/276305.276312}, acmid = {276312}, publisher = {ACM}, address = {New York, NY, USA}, } @inproceedings{inproceedings::dbscan::1, author = {Ester, Martin and Kriegel, Hans-Peter and Sander, Jorg and Xu, Xiaowei}, title = {A Density-based Algorithm for Discovering Clusters a Density-based Algorithm for Discovering Clusters in Large Spatial Databases with Noise}, booktitle = {Proceedings of the Second International Conference on Knowledge Discovery and Data Mining}, series = {KDD'96}, year = {1996}, location = {Portland, Oregon}, pages = {226--231}, numpages = {6}, url = {http://dl.acm.org/citation.cfm?id=3001460.3001507}, acmid = {3001507}, publisher = {AAAI Press}, } @article{article::ema::1, author = {Gupta, Maya R. and Chen, Yihua}, title = {Theory and Use of the EM Algorithm}, journal = {Found. Trends Signal Process.}, issue_date = {March 2011}, volume = {4}, number = {3}, month = mar, year = {2011}, issn = {1932-8346}, pages = {223--296}, numpages = {74}, url = {http://dx.doi.org/10.1561/2000000034}, doi = {10.1561/2000000034}, acmid = {1969853}, publisher = {Now Publishers Inc.}, address = {Hanover, MA, USA}, } @article{article::ga::1, title = "Genetic algorithm-based clustering technique", journal = "Pattern Recognition", volume = "33", number = "9", pages = "1455 - 1465", year = "2000", issn = "0031-3203", doi = "https://doi.org/10.1016/S0031-3203(99)00137-5", url = "http://www.sciencedirect.com/science/article/pii/S0031320399001375", author = "Ujjwal Maulik and Sanghamitra Bandyopadhyay", keywords = "Genetic algorithms, Clustering metric, K-means algorithm, Real encoding, Euclidean distance" } @article{article::ga::2, title = "A genetic algorithm approach to cluster analysis", journal = "Computers & Mathematics with Applications", volume = "37", number = "7", pages = "99 - 108", year = "1999", issn = "0898-1221", doi = "https://doi.org/10.1016/S0898-1221(99)00090-5", url = "http://www.sciencedirect.com/science/article/pii/S0898122199000905", author = "M.C. Cowgill and R.J. Harvey and L.T. Watson", keywords = "Cluster analysis, Data clustering, Genetic algorithm, Global optimization, Variance-ratio maximization" } @article{artcile::hsyncnet::1, author = {J. Shao and X. He and C. Böhm and Q. Yang and C. Plant}, journal = {IEEE Transactions on Knowledge and Data Engineering}, title = {Synchronization-Inspired Partitioning and Hierarchical Clustering}, year = {2013}, volume = {25}, number = {4}, pages = {893-905}, doi = {10.1109/TKDE.2012.32}, ISSN = {1041-4347}, month = {April}, } @inproceedings{inproceedings::kmeans::1, author = {J. Macqueen}, title = {Some methods for classification and analysis of multivariate observations}, booktitle = {In 5-th Berkeley Symposium on Mathematical Statistics and Probability}, year = {1967}, pages = {281--297} } @book{book::algorithms_for_clustering_data, author = {Jain, Anil K. and Dubes, Richard C.}, title = {Algorithms for Clustering Data}, year = {1988}, isbn = {0-13-022278-X}, publisher = {Prentice-Hall, Inc.}, address = {Upper Saddle River, NJ, USA}, } @book{book::finding_groups_in_data, author = {Kaufman, L. and Rousseeuw, P.J.}, description = {Dissertation}, interhash = {119bf8c432712ad3bbc1612759e0b7b4}, intrahash = {54cc9fb0fc88d6057dc9b1ce3feb1293}, keywords = {clustering kdd17}, publisher = {Wiley}, title = {Finding Groups in Data: an introduction to cluster analysis}, year = 1990 } @article{article::optics::1, author = {Ankerst, Mihael and Breunig, Markus M. and Kriegel, Hans-Peter and Sander, Jorg}, title = {OPTICS: Ordering Points to Identify the Clustering Structure}, journal = {SIGMOD Rec.}, issue_date = {June 1999}, volume = {28}, number = {2}, month = jun, year = {1999}, issn = {0163-5808}, pages = {49--60}, numpages = {12}, url = {http://doi.acm.org/10.1145/304181.304187}, doi = {10.1145/304181.304187}, acmid = {304187}, publisher = {ACM}, address = {New York, NY, USA}, keywords = {cluster analysis, database mining, visualization}, } @inproceedings{inproceedings::rock::1, author = {S. {Guha} and R. {Rastogi} and K. {Shim}}, title = {ROCK: A Robust Clustering Algorithm for Categorical Attributes}, booktitle = {Proceedings of the 15th International Conference on Data Engineering}, series = {ICDE '99}, year = {1999}, isbn = {0-7695-0071-4}, pages = {512--}, url = {http://dl.acm.org/citation.cfm?id=846218.847264}, acmid = {847264}, publisher = {IEEE Computer Society}, address = {Washington, DC, USA}, } @article{article::syncnet::1, author = {Novikov, A. V. and Benderskaya, E. N.}, title = {Oscillatory Neural Networks Based on the Kuramoto Model for Cluster Analysis}, journal = {Pattern Recognit. Image Anal.}, issue_date = {September 2014}, volume = {24}, number = {3}, month = sep, year = {2014}, issn = {1054-6618}, pages = {365--371}, numpages = {7}, url = {http://dx.doi.org/10.1134/S1054661814030146}, doi = {10.1134/S1054661814030146}, acmid = {2670644}, publisher = {Springer-Verlag New York, Inc.}, address = {Secaucus, NJ, USA}, } @inproceedings{article::syncsom::1, author = {Novikov, A. V. and Benderskaya, E. N.}, title = {SYNC-SOM Double-layer Oscillatory Network for Cluster Analysis}, booktitle = {Proceedings of the 3rd International Conference on Pattern Recognition Applications and Methods}, series = {ICPRAM 2014}, year = {2014}, isbn = {978-989-758-018-5}, location = {ESEO, Angers, Loire Valley, France}, pages = {305--309}, numpages = {5}, url = {http://dx.doi.org/10.5220/0004906703050309}, doi = {10.5220/0004906703050309}, acmid = {2971006}, publisher = {SCITEPRESS - Science and Technology Publications, Lda}, address = {Portugal}, keywords = {Cluster analysis, Kuramoto model, oscillatory network, self-organized feature map}, } @inproceedings{article::xmeans::1, author = {Pelleg, Dan and Moore, Andrew W.}, title = {X-means: Extending K-means with Efficient Estimation of the Number of Clusters}, booktitle = {Proceedings of the Seventeenth International Conference on Machine Learning}, series = {ICML '00}, year = {2000}, isbn = {1-55860-707-2}, pages = {727--734}, numpages = {8}, url = {http://dl.acm.org/citation.cfm?id=645529.657808}, acmid = {657808}, publisher = {Morgan Kaufmann Publishers Inc.}, address = {San Francisco, CA, USA}, } @inproceedings{article::xmeans::mndl, author = {M. Shahbaba and S. Beheshti}, booktitle = {2012 11th International Conference on Information Science, Signal Processing and their Applications (ISSPA)}, title = {Improving X-means clustering with MNDL}, year = {2012}, doi = {10.1109/ISSPA.2012.6310493}, pages = {1298-1302} } @book{book::the_design_and_analysis, author = {Samet, Hanan}, title = {The Design and Analysis of Spatial Data Structures}, year = {1990}, isbn = {0-201-50255-0}, publisher = {Addison-Wesley Longman Publishing Co., Inc.}, address = {Boston, MA, USA}, } @article{article::nnet::sync::1, title = "Synchronization in complex networks", author = "Alex Arenas and Albert Diaz-Guilera and Jurgen Kurths and Yamir Moreno and Changsong Zhou", year = "2008", month = "12", doi = "10.1016/j.physrep.2008.09.002", volume = "469", pages = "93--153", journal = "Physics Reports", issn = "0370-1573", publisher = "Elsevier", number = "3", } @inproceedings{inproceedings::net::sync::1, author = {X. B. Lu and B. Z. Qin}, booktitle = {2009 International Conference on Information Engineering and Computer Science}, title = {Adaptive Cluster Synchronization in Coupled Phase Oscillators}, year = {2009}, pages = {1-4}, doi = {10.1109/ICIECS.2009.5363490}, ISSN = {2156-7379}, month = {Dec}, } @article{article::nnet::cnn::1, author = "Benderskaya, E. N. and Zhukova, S. V.", title = "Large-dimension image clustering by means of fragmentary synchronization in chaotic systems", journal = "Pattern Recognition and Image Analysis", year = "2009", month = "Jun", day = "01", volume = "19", number = "2", pages = "306--314", issn = "1555-6212", doi = "10.1134/S1054661809020151", url = "https://doi.org/10.1134/S1054661809020151" } @inproceedings{inproceedings::nnet::cnn::1, author = "Benderskaya, Elena N. and Zhukova, Sofya V.", editor = "Corchado, Emilio and Abraham, Ajith and Pedrycz, Witold", title = "Clustering by Chaotic Neural Networks with Mean Field Calculated Via Delaunay Triangulation", booktitle = "Hybrid Artificial Intelligence Systems", year = "2008", publisher = "Springer Berlin Heidelberg", address = "Berlin, Heidelberg", pages = "408--416", isbn = "978-3-540-87656-4" } @book{book::chemical_oscillatorions_waves, author = {Kuramoto, Yoshiki}, isbn = {978-0-486-42881-9}, keywords = {oscillations reaction-diffusion networks turbulence waves synchronization}, note = {originally published: Springer Berlin, New York, Heidelberg, 1984}, publisher = {Dover Publications}, series = {Chemistry Series}, title = {Chemical oscillations, waves, and turbulence}, year = 2003 } @article{article::nnet::hnn::1, title = "Selective attention model with spiking elements", journal = "Neural Networks", volume = "22", number = "7", pages = "890 - 900", year = "2009", issn = "0893-6080", doi = "https://doi.org/10.1016/j.neunet.2009.02.002", author = "David Chik and Roman Borisyuk and Yakov Kazanovich", keywords = "Hodgkin–Huxley neurons, Synchronization, Attention model, Sequential selection" } @article{article::nnet::hysteresis::1, author = "Jin'no, Kenya", editor = "In, Visarath and Longhini, Patrick and Palacios, Antonio", title = "Dynamical Hysteresis Neural Networks for Graph Coloring Problem", bookTitle = "Applications of Nonlinear Dynamics: Model and Design of Complex Systems", year = "2009", publisher = "Springer Berlin Heidelberg", address = "Berlin, Heidelberg", pages = "331--340", isbn = "978-3-540-85632-0", doi = "10.1007/978-3-540-85632-0_27", url = "https://doi.org/10.1007/978-3-540-85632-0_27" } @article{article::legion::1, author = {Wang, DeLiang and Terman, David}, title = {Image Segmentation Based on Oscillatory Correlation}, journal = {Neural Comput.}, issue_date = {May 15, 1997}, volume = {9}, number = {4}, month = may, year = {1997}, issn = {0899-7667}, pages = {805--836}, numpages = {32}, url = {http://dx.doi.org/10.1162/neco.1997.9.4.805}, doi = {10.1162/neco.1997.9.4.805}, publisher = {MIT Press}, address = {Cambridge, MA, USA}, } @article{article::legion::2, author = {DeLiang Wang and D. Terman}, journal = {IEEE Transactions on Neural Networks}, title = {Locally excitatory globally inhibitory oscillator networks}, year = {1995}, volume = {6}, number = {1}, pages = {283-286}, doi = {10.1109/72.363423}, issn = {1045-9227}, month = {Jan}, } @book{book::image_processing_using_pcnn, author = {Lindblad, Thomas and Kinser, Jason M.}, title = {Image Processing using Pulse-Coupled Neural Networks}, year = {2013}, isbn = {978-3-642-36877-6}, doi = {10.1007/978-3-642-36877-6}, edition = {3rd}, publisher = {Springer-Verlag}, address = {Berlin, Heidelberg}, } @inproceedings{article::nnet::som::1, author = {T. Kohonen}, journal = {Proceedings of the IEEE}, title = {The self-organizing map}, year = {1990}, volume = {78}, number = {9}, pages = {1464-1480}, doi = {10.1109/5.58325}, issn = {0018-9219}, month = {Sep}, } @article{article::nnet::som::2, author = {T. Kohonen and E. Oja and O. Simula and A. Visa and J. Kangas}, journal = {Proceedings of the IEEE}, title = {Engineering applications of the self-organizing map}, year = {1996}, volume = {84}, number = {10}, pages = {1358-1384}, doi = {10.1109/5.537105}, issn = {0018-9219}, month = {Oct}, } @article{article::nnet::syncpr::1, author = {R. Follmann and E. E. N. Macau and E. Rosa and J. R. C. Piqueira}, journal = {IEEE Transactions on Neural Networks and Learning Systems}, title = {Phase Oscillatory Network and Visual Pattern Recognition}, year = {2015}, volume = {26}, number = {7}, pages = {1539-1544}, doi = {10.1109/TNNLS.2014.2345572}, issn = {2162-237X}, month = {July}, } @inproceedings{inproceedings::nnet::syncsegm::1, author = {Novikov, Andrei and Benderskaya, Elena}, title = {Oscillatory Network Based on Kuramoto Model for Image Segmentation}, booktitle = {Proceedings of the 13th International Conference on Parallel Computing Technologies - Volume 9251}, year = {2015}, isbn = {978-3-319-21908-0}, pages = {210--221}, numpages = {12}, url = {http://dx.doi.org/10.1007/978-3-319-21909-7_20}, doi = {10.1007/978-3-319-21909-7_20}, acmid = {2958474}, publisher = {Springer-Verlag New York, Inc.}, address = {New York, NY, USA}, keywords = {Image segmentation, Kuramoto model, Oscillatory network, Phase oscillator, Synchronization}, } @article{article::gcolor::dsatur::1, author = {Brelaz, Daniel}, title = {New Methods to Color the Vertices of a Graph}, journal = {Commun. ACM}, issue_date = {April 1979}, volume = {22}, number = {4}, month = apr, year = {1979}, issn = {0001-0782}, pages = {251--256}, numpages = {6}, doi = {10.1145/359094.359101}, acmid = {359101}, publisher = {ACM}, address = {New York, NY, USA}, } @article{article::gcolor::hysteresis::1, author = {Jinnno, Kenya}, year = {2009}, month = {02}, pages = {331-340}, title = {Dynamical Hysteresis Neural Networks for Graph Coloring Problem}, volume = {2009}, booktitle = {Understanding Complex Systems} } @article{article::gcolor::sync::1, title = "Clustering dynamics of nonlinear oscillator network: Application to graph coloring problem", journal = "Physica D: Nonlinear Phenomena", volume = "240", number = "24", pages = "1972 - 1978", year = "2011", issn = "0167-2789", doi = "https://doi.org/10.1016/j.physd.2011.09.010", author = "Jianshe Wu and Licheng Jiao and Rui Li and Weisheng Chen", keywords = "Clustering, Graph coloring, Phase oscillator, Complement graph, Kuramoto model" } @article{article::cluster::elbow::1, author = "Thorndike, Robert L.", title = "Who belongs in the family?", journal = "Psychometrika", year = "1953", month = "Dec", day = "01", volume = "18", number = "4", pages = "267--276", issn = "1860-0980", doi = "10.1007/BF02289263", url = "https://doi.org/10.1007/BF02289263" } @article{article::cluster::silhouette::1, author = {Rousseeuw, Peter}, title = {Silhouettes: A Graphical Aid to the Interpretation and Validation of Cluster Analysis}, journal = {J. Comput. Appl. Math.}, issue_date = {November 1987}, volume = {20}, number = {1}, month = Nov, year = {1987}, issn = {0377-0427}, pages = {53--65}, numpages = {13}, url = {http://dx.doi.org/10.1016/0377-0427(87)90125-7}, doi = {10.1016/0377-0427(87)90125-7}, publisher = {Elsevier Science Publishers B. V.}, } @article{article::clique::1, author = "Agrawal, Rakeshand Gehrke, Johannes and Gunopulos, Dimitrios and Raghavan, Prabhakar", title = "Automatic Subspace Clustering of High Dimensional Data", journal = "Data Mining and Knowledge Discovery", year = "2005", month = "Jul", day = "01", volume = "11", number = "1", pages = "5--33", issn = "1573-756X", doi = "10.1007/s10618-005-1396-1", url = "https://doi.org/10.1007/s10618-005-1396-1" } @book{book::pattern_recognition_with_fuzzy, author = {Bezdek, James C.}, title = {Pattern Recognition with Fuzzy Objective Function Algorithms}, year = {1981}, isbn = {0306406713}, publisher = {Kluwer Academic Publishers}, address = {Norwell, MA, USA}, } @article{article::utils::sampling::1, author = {Vitter, Jeffrey S.}, title = {Random Sampling with a Reservoir}, journal = {ACM Trans. Math. Softw.}, issue_date = {March 1985}, volume = {11}, number = {1}, month = mar, year = {1985}, issn = {0098-3500}, pages = {37--57}, numpages = {21}, url = {http://doi.acm.org/10.1145/3147.3165}, doi = {10.1145/3147.3165}, acmid = {3165}, publisher = {ACM}, address = {New York, NY, USA}, } @article{article::utils::metric::gower, author = {Gower, J. C.}, journal = {Biometrics}, keywords = {similarity}, month = {December}, number = 4, pages = {857--871}, timestamp = {2007-11-22T17:01:35.000+0100}, title = {A General Coefficient of Similarity and Some of Its Properties}, volume = 27, year = 1971, issn = {0006341X, 15410420}, doi = {10.2307/2528823} } @inproceedings{inproceedings::cluster::gmeans::1, author = {Hamerly, Greg and Elkan, Charles}, title = {Learning the K in K-means}, booktitle = {Proceedings of the 16th International Conference on Neural Information Processing Systems}, series = {NIPS'03}, year = {2003}, location = {Whistler, British Columbia, Canada}, pages = {281--288}, numpages = {8}, acmid = {2981381}, publisher = {MIT Press}, address = {Cambridge, MA, USA} } @inproceedings{inproceedings::cluster::kmedoids::1, author = {Schubert, Erich and Rousseeuw, Peter J.}, title = {Faster k-Medoids Clustering: Improving the PAM, CLARA, and CLARANS Algorithms}, booktitle = {Similarity Search and Applications}, year = {2019}, publisher = {Springer International Publishing}, address = {Cham}, pages = {171--187}, isbn = {978-3-030-32047-8}, doi = {10.1007/978-3-030-32047-8_16} } pyclustering-0.10.1.2/docs/doxygen_conf_ccore000077500000000000000000000257521375753423500212250ustar00rootroot00000000000000# Doxyfile 1.8.7 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "" PROJECT_NUMBER = PROJECT_BRIEF = PROJECT_LOGO = docs/logo/pyclustering_logo_01_small.png OUTPUT_DIRECTORY = doxygen_cpp_docs CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 TOC_INCLUDE_HEADINGS = 10 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = docs/citation.bib #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text " WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ccore/include/ \ docs/page/cpp_pyclustering_intro.md INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c, *.cpp, *.h, *.hpp RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = docs/img/ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = docs/page/cpp_pyclustering_intro.md #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_DYNAMIC_SECTIONS = YES HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = YES DOCSET_FEEDNAME = "Doxygen docs" DOCSET_BUNDLE_ID = org.doxygen.Doxygen DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = YES ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = YES MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = SEARCHENGINE = YES SERVER_BASED_SEARCH = YES EXTERNAL_SEARCH = NO SEARCHENGINE_URL = SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO MSCGEN_PATH = DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = svg INTERACTIVE_SVG = YES DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = NO pyclustering-0.10.1.2/docs/doxygen_conf_pyclustering000077500000000000000000000333311375753423500226520ustar00rootroot00000000000000# Doxyfile 1.8.7 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "pyclustering" PROJECT_NUMBER = 0.10.1 PROJECT_BRIEF = "pyclustring is a Python, C++ data mining library." PROJECT_LOGO = docs/logo/pyclustering_logo_02.png OUTPUT_DIRECTORY = doxygen_python_docs CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = docs/citation.bib #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text " WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = pyclustering/__init__.py \ pyclustering/cluster/__init__.py \ pyclustering/cluster/agglomerative.py \ pyclustering/cluster/bang.py \ pyclustering/cluster/birch.py \ pyclustering/cluster/bsas.py \ pyclustering/cluster/center_initializer.py \ pyclustering/cluster/clarans.py \ pyclustering/cluster/clique.py \ pyclustering/cluster/cure.py \ pyclustering/cluster/dbscan.py \ pyclustering/cluster/elbow.py \ pyclustering/cluster/encoder.py \ pyclustering/cluster/ema.py \ pyclustering/cluster/fcm.py \ pyclustering/cluster/ga.py \ pyclustering/cluster/generator.py \ pyclustering/cluster/gmeans.py \ pyclustering/cluster/hsyncnet.py \ pyclustering/cluster/kmeans.py \ pyclustering/cluster/kmedians.py \ pyclustering/cluster/kmedoids.py \ pyclustering/cluster/mbsas.py \ pyclustering/cluster/optics.py \ pyclustering/cluster/rock.py \ pyclustering/cluster/silhouette.py \ pyclustering/cluster/somsc.py \ pyclustering/cluster/syncnet.py \ pyclustering/cluster/syncsom.py \ pyclustering/cluster/ttsas.py \ pyclustering/cluster/xmeans.py \ pyclustering/container/__init__.py \ pyclustering/container/cftree.py \ pyclustering/container/kdtree.py \ pyclustering/gcolor/__init__.py \ pyclustering/gcolor/dsatur.py \ pyclustering/gcolor/hysteresis.py \ pyclustering/gcolor/sync.py \ pyclustering/nnet/__init__.py \ pyclustering/nnet/cnn.py \ pyclustering/nnet/dynamic_visualizer.py \ pyclustering/nnet/fsync.py \ pyclustering/nnet/hhn.py \ pyclustering/nnet/hysteresis.py \ pyclustering/nnet/legion.py \ pyclustering/nnet/pcnn.py \ pyclustering/nnet/som.py \ pyclustering/nnet/sync.py \ pyclustering/nnet/syncpr.py \ pyclustering/nnet/syncsegm.py \ pyclustering/samples/__init__.py \ pyclustering/utils/__init__.py \ pyclustering/utils/color.py \ pyclustering/utils/graph.py \ pyclustering/utils/metric.py \ pyclustering/utils/sampling.py INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = docs/img/ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_DYNAMIC_SECTIONS = YES HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = YES DOCSET_FEEDNAME = "Doxygen docs" DOCSET_BUNDLE_ID = org.doxygen.Doxygen DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = YES GENERATE_TREEVIEW = YES ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = YES MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = SEARCHENGINE = NO SERVER_BASED_SEARCH = YES EXTERNAL_SEARCH = NO SEARCHENGINE_URL = SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = NO MSCGEN_PATH = DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = YES DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = YES INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = svg INTERACTIVE_SVG = YES DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = NO pyclustering-0.10.1.2/docs/img/000077500000000000000000000000001375753423500162035ustar00rootroot00000000000000pyclustering-0.10.1.2/docs/img/agglomerative_lsun_clustering_single_link.png000077500000000000000000001003621375753423500274220ustar00rootroot00000000000000‰PNG  IHDRXéøoI%sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+€wIDATx^í ¼G}ßç>$d½e¬Â¸A~?$#Y6Ʋ$KN¢´ ¥M„IPx"Hƒ“¦ ~‘4A‚´$bp±›Ò´.NcË’lcG~`K~‘ØDÙ±l]IXH–t·ûÝÿ½sæÌž³{Ξ׽ÿ¯>£½ûš™ýÙÿÎügÖD-â¹çž‹Œ1Ñ_þå_¦[ò#ç®_¿>Ý¢Ôãšk®±e–ŽãøñD/ëñ]ïz— ­¤™ò‹hýU>'žxbtå•W¦kJª½±C|3 sã7š¾¾>óÈ#¤[z‡_|Ñ|ò“Ÿ4§žzª™'œp‚mr¹ýöÛí›"ÍðS§N5?÷s?gžzê©toBžñ 3oÞ<›N®M ®t?Õ«;a¬i´Û´'ðò‡aóž÷¼ÇüÒ/ý’Ë¿ÇhsÅŠéÚ(¤Î¸ÇèùôÓO·÷žýùÈG̾}ûÒ#¨ßÈ3ÏcžƒÜã¯|å+vËK.¹ÄÖ™lGïña÷¹pý«¯¾ÚüÔOý”}žsº!n^n]öîÝkÖ­[7¢Éùóç›õë×Ûr,JË ¬,ÈèÊ•+íð3ŸùŒýQÓÌ*sØ×¿þu{“ñ1ÝcìC…P~pTüópÓM7Yƒ !óƒ§uáé§Ÿ6^x¡ý¸ÔË?„ÿößþ›ý›·Pâ&¸ù8zô¨¡Ç»ßýn»o3ð`~í×~Í ›tÔó¹@8ú§j.½ôRÛ…0a›'e”NéÃjçÎM5³sO¹>•ìïüÎ[·Væ€î>ö±ÙŠäÿøí •UC›—‰óÏ?ß<óÌ3æ?þÇÿh˅ʉó¹îx¤Wê/  * +ÒG}‚‘F]päÈ‘ô¨(?ÿó?o )4ÂC…á_ýÕ_Ù%/}h ®àÀôÌQ¨£xØRGqü† ìC½týQ~ÿý¿ÿwó¾÷½ÏžsÁX-ÓJõêÎñ¤ÑNiO ÅjéÒ¥#†:¸í¶ÛÒ½ ÿîßý;s÷Ýw›—^z)Ý’€¡Žÿ k`}à°÷Œ:‰{å•WÚt®ZµÊ>]xöR·‘Ž=ûì³ív^"N:é$óŸþÓ²e‚Þ?ô¡Y­»üÖoý–ùô§?=¢q^8‰Ëo Cã´ßrË-6=\ }qþUW]•U€Ø*+ £8õá‡N·T Á¶]ýõé–„… F±eš®UŽ„ˆ+ƒ(¾iQ\¹D7nL%~PÙP™3gFçœsNºV›X8ÑŒ3¢Ø˜I·$¼ð ÑôéÓ+¶çÍS,8{\hôžÄ‹-Ý’ðÚk¯E±ÁÅo˜Q,„tkýÍßü=>¶ÈÓ-Õ£·mÛf×ÿý¿ÿ÷é–„+®¸"3½J/êñÉ'Ÿ´qï‚ ¢ø?ºõÖ[£øž1J\‘VŒ"Œ+0{Þi§>|8ÝEŸÿüçíö'žx®³/®Œ£Å‹Ût ±Ñnsã •O\ùFguV?8Ó-Q¿uFïxÇ;¢ø­.ÝÒ{ŒõúëŸÿùŸ£‰'F±1ÅØtk}ñ‹_´éúêW¿šnI´Å¶›o¾9ÝEñ›½ÝÖßßÅF{º5²ég»[&RïüÂ/üBº%z‡íÛ·oO·T"ŒxQl Eÿ÷ŸnI Œ_(£ú§²ëµêÎ^Óh/jbã(Œ¾üå/§["[Æÿò_þËt-!6xíõc£8Ý’ÛÑ´iÓFî“Ôa±o×y¶¹Ûßô¦7Ùm›7oN·Œéé_£ ‰“O>9]‹¢þð‡VOñËAº%áw÷wm¼±¡—nIô|ÜqÇEßÿþ÷Ó- ñK¬Í?q¡í-X€ß€ ì?þã?¦k£Ä†mŽŒ ÝŽ^àíˇÖ$¿E)Äþýûm7Y6mÚd[‡p>Þ³gÏH   Ý'ožjAó¨ #MâÊÒÄ••mþh…¢)öÿý¿ÿ—n©†òš:]hŽW*é„iÊŽ`ÛÝËñ±qdߺéêÁ¿&Œ@¤Ù_ Ý iG?/¿ü²mõÄGOàM0~`§ka^yåÛºFËoªò >ÞüvìØQÕM=^èöú‹n<®Ío=6’Ò­Æê€.<¿Þ •ÞmY +0~Á4±oë;Aþå•Ö2—_ÿõ_·K©‡Bàú@Ù¡E·ž]¾|¹my¹÷Þ{Ó#ÃŒGvB{ð?þÇÿ°Z’žàùH·- Ý}t9Óú)ÐE¯KlŒÙÖQàÞÓ¥KW{ïqaˆ ªg,Ýt¡Ö6ŽèZ$º½c£Ýˆ3¿ôÄsÔE4êBº8úôéé¢Û“|à^Q„¶X Ò§.ðso’@ssüVoýòø‹Ô‚Š%Ô´‚&póI«Í…ÑãR$OYð¤Çå?ø]Ráù``ÉþìãÁ.¡¸Æ3Ò#ÄoY¶»ƒ0>0ÿå¿ü«ºV|_—oyË[Ò¿Äh’´‹>ðkqጪ¾\ñ ˜íwõOˆßòì1þï`<Ð õWV½1N׈_oPïàóã¶A(¯<]¨w¨j=À©gï¸ãŽ*}a`A=}7v²®¢ãã•r',\¸Ðr%.tb¿ð v}Ë–-¶Žc»À½Ç@öï.2tÛù÷nÀ<<§é楀8Ј/WV=ȵü—Ò…Qê§ ƒŠê©íV‘‘dŠ‚£ÏÔw¦+  V-‚¨‡8Xòð£5ËŒ¤p)’§,°ìÝ·M¥=tJ.¤á¬³Î²¾'â7’g„NVÚyè4‹üðï ý~…5è…ú«(YyjF_¾ÁÑ2ÒÁm- 1Þ4Ú)íat0EÈý÷ßo i øƒ_WÑʽ‘ ÆÁt[ÑØÃyèžÄ@Ü–*߯8½M8ËÓ2˹Òk#ú(ÚÆÌOzŠÐÕOtœË°ÂxàÛÜé;¾aõêÕÖ2þë¿þëtK6Òêƒ…Ë ôC#oy*ŸÓfßûÞ÷ìÒ…m²?û˜?J$—’2õ˜# €yfšEôÁÛ¦ é®×5@K00"ô äí²¯tªþʪ70Ξ{õF£H«¿€æ¨jµ”RÏ2UIH[i¡Íª;U£Ù”©= (ʘnBZ«ÜÀhQZ‘Ü©e0jÏ=÷\ÛMxäÈ‘çzâ¸÷´jÑźoâÄ^ ~ iZœplgpçÒÒç’UÒå· £)ºýôHð[uëÑõM&dŠKS2¯ùViÞ¡¦ô]c1ÿæoþ¦µ|}(læ#¬šäé²A >þ‰<0üêüsáa‹‘÷¥/}ÉN¹ Ðïͨ™Z#/»ì2»d„ £ •Æ)KTJ!m‰ÏJ]¹è‡Gøt¹,f¨[ÁÝñ"Áhœ±×Èo`<Ò‰ú‹kÒÈoßmmbH;Ý&­IÌT ._øÂìRê¡øN1ÜÆÓ-£POŠf³êNÕhmÊÒõ†]|Œ"uƒŒ¬cÔ Ç~ç;ß1_ýêWm]ãv÷žúif|ØîOÕBZô\s­¯}íkéZåÀ±Œ8tº.êfº5}ˆ»¨¡:êùÚ7Ï«¶Lh–ûË¿üK;”ÃÇ‚)ŽoõÞÈi¢Ä’ÆÊ]°`u.~ûÛßn÷=úè£V ?ó3?c×¹Cƒ%–8MžôÃb¥Ó ÉPbfÞ.Mœ8bÕã{ƒƒ΀„,°ø™"âW~åWì\œ êŠC4o†Ìq•yäxD…XßñŽwXÑøVüX¢—ôÈ}ýîw¿kßìäm 2Lm”1‡,ÃõqæÄOʃt‘vÞ ëµªòФ€îK¤y»C<™æaûöí鑽ÉX­¿¨«ènfÞ(º;˜ÿŽÖ,ê‚Å‹Ûsˆ–1®ÃõÐ>;W\q…9çœsÒ#ªááL+SD0•ù¡õà‰'ž°ÝK” óþÕª;{U£½¢½|Ð>3˜ê%Ä›Þô&ûŒÄûíßþítkb¨°Î=FÔ?.\›i˜:ýbáJK(-chµ^w !<#yaàÞÓÅ”L#¦n ý2ˆ®J&ëÅŸ-¹õ ifê ^ xîâgF+«h’Aøzå&¶þ ß0;¼1+ìܹ3s¨é”)SÒµQɱ‚;ÔÔ%.t»!“‰†šÂ~ô£(6Lì0Î×½îuQüvd‡É3ü5~CJJ`(i|íÔ ?”¢¸"ˆyä‘ôˆüy‚xÀ©e5û8²â²ÊpÜI“&E± ¢÷¾÷½Q\y¤{B×cj‡uëÖÙ¡úÄ¿zõj{oÜkzQñÛ]ôÑ~ÔNÁ¾âŠ"zË[Þbõ¿U¦G%dMÓWDé–„PaÆ 6MègÑ¢EQü†fu? Ó#²Ï%-qåÅ•–M#C¦ãbW6é½G/êE(R1-é§žjïÛ 'œ}ä#‰â·ðtoº:ãŒ3ÒµQHSüàJ×F!ýèV¼?ýôÓvüÔ©Sí”ñ­bj NÊÐ%~(F±1½ímo³õblPÙáÿŸùÌgì45BVÝ ½¤Ñ^Ó^ürfÏóë$—ø%ÎãNÉK–,±Û?üá§[*޾ô¥/E±f§’ˆ À(~ÙŒb#'Ú½{wzT2Mƒ?„pë­·Ú:”ºí¤“N²º‰,{]ÊR8zôhôŸÿó¶¿®µtéÒè™gž±u/ZuÙ¿¿MÏ{ôˆÑ\}ö³Ÿ­˜î&}ü'FQ”q]¼UÒz–wJE A )-etÇÑÚ¤(½>`ÔƒL¢ë¶¾•‰[S”1 #ˆüw(º!"]ÆðmEQ”n‡">âÜÊzP ,EÃðù|$°ÿ£mø„þ+Œ.REëÜ|óÍÖlýúõÖ¿ ¿jìñit'Ó-5°e Ã`†3¢ gwæpÃá•8Á+Š¢Œul3;ƒ‹@Äô|ï’9ºZ‰ú`)Š¢(Š¢”Œ¶`)Š¢(Š¢”ŒXŠ¢(Š¢(%£–¢(Š¢(JÉTù`1GÎ~ô#û §F¾Ÿ§ô>H‚Yq™·• V­oTgJ;P)íÂ×Z•ÅçŠ~ÐP›ìܹӼùÍoN×ÊGµ¦€êLiª3¥]ˆÖª ,¾[Ç·v8€o_ä»=|ÇoÿŒ54•ìß¿ßV|\uúôééÖòoZSU¢:kú;EuÖ:Tg•Ti Ë% —] |Šoþ¸ß†Khþ* i Œ7­å¼AÑü©ÎZÇXÎ_Ѽ©ÎZÇXÎ_#yó5 N(Š¢(%£–¢(Š¢(Jɨ¥(Š¢(ŠR2j`)Š¢(Š¢”LwX/¾hÌe—3s¦1Ço̬YÉ:Û¥D^Üÿ¢¹ìO/33?>ÓÿÇ›YŸe×Ù®(e¡:SÚê¬;é.ëýï7fÓ&c††ŒÙ³Ç˜½{“u¶+J‰¼ÿ«ï7›žÙd†™=?ÞcöÜk×Ù®(e¡:SÚê¬;é.롇Œ9v,]Iaýá‡ÓE)‡‡žÈ®Ôëÿ@µ¦”‡êLiª³î¤» ¬óÎ3f` ]Ia}ñâtÅAºgÏÖnD¥0ç½õ<3Ð_©5ÖŸX©5izŸý‰ÙÚä®Fu¦´ƒ¼:ÕZûè.ëÆY±"ñÁš3'ñÁbí>ÒøÊ+ÉòòËÕàRrsã¯ÞhVœ¶ÂÌœ<ÓÌ9nŽ™5y–]g»‹4½¿òê+vyù_\®•“’›Fuƺ>•¼äÕhÖ>:g`…Z N8Á˜ÛoOŒ¦—^2æå—“u¶ûlÝ:ÚÈò¾û* .õÛRb²R'L;ÁÜþ‰ÛÍ+Ÿżô¹—ÌËŸÙ®³Ýeës[GšÞY޷㾪¡¢@HkêìÁç ]ŠÒŒÎ@ë´öÑ9Ëo*j ¦¤`d¹—úm)1Í>¤û+uF…äVNêã ÍhÍ×Ý;®_jM´Në:g`¹í,·l)Ö½'ç \â¿•å·¥Œ;ü‡Ô–g·j —s…ÁÁ_‡,e|ÒŒÖ| WøÕ¨ÖAë´Þ¡s–ïÐ~ôh±Ö¬%KFÏgyá…‰¿FZ–ß–2îð?;ZèÍoÉIK**Ÿ ßv¡õm˜}ÜìLe|ÒŒÖ|wÒy#~5ª5ÅEë´Þ¡s–8´cM˜`LÄG¨còvï¹ç³¼å–Ä_‹ù³²ü¶”q‡ûš00ÁDñ?à-.OS¸ÿ»åƒ·X߆=ŸÛ“éã ŒOšÑš¯3ÖůFµ¦¸hÖ;tÎÀ‡v ¢eË*[£òtï¹ç«A¥dà>¤–º¬âÍ-OS¸>䔼4£5Õ™’—ftªµöÑ9ËÅoÊÛ½‰¨(„Z òµ£(µhDkª3¥(Z§u7Ýa`5ÚåD<óL5¶”L}sóGíœyÍ™Z1)5iDkª3¥(eÔiŸÚhæ]5OuÖÚo`•ÙêäDÄ@Óy°”˜2ßÐüQ;|뫈S©2vQ)í L«5|¸Ž Qµ€þÇ›ýû÷W8räHEmk$ _y¥‰ÒV'–¬ìßµË ¯Ze¢ØøbÉzp›Äµx±‰Rß­ÔE>!6¶¢‡7G€Ðö±Šæ¯´SkW~åÊ‘74–¬Ë¾]/ï2«>·ÊVV,Ym“ãñk?*¨‡ŸW¹¡hþZA·èŒPDkeꌡíc!Í[+èUBZSU‡FòæÒwÍ5×D×]w]º:ÊÍ7ßl&Ožœ®•ÇekÖ˜‰¤kƼvÜqfïÉ'›™;v˜¨¯ÏLˆ÷õG‘îï7/-X`9~Û6Ó?<<²mëÕWÛ퓆†Ì ÌŒø\8WŽSŠqðàAsÅW˜}ûö™iÓ¦¥[›çÚk¯5íÒÚškÌ#£:;nÂqæä'›C;L_ü}¼¹õ÷õ›smÛ³Í GÃ#Û®^’ègèðÙ°mCæ¹rœRŒ±®³ù3æÛ–§^yªBWÒšê¬5ŒEM0Õ|áâ/ÔÔ Ô«Ó¶ïÙnŽEIK–ê¬y|­õ:t(°ÂçÍ›göìÙ3"F¬²M›6™+V˜ L©Ð«W›¾Í›M­L´>ñÝÁ½{“õx_r˜…V+¦oè£Û/…mGwïN×^|Ñ ¬]kúyÄD‹™c7ÜÛ—«Ìüu#Eó‡æÌ™Sz…„ÎÚ¥µÕ_\m6?»Ù¾•ñ¦6óõ3ÍÞŸìiw™=e¶­˜x;ض{}µÎhš_ûõµæ‘}z…¹ÐßþíßšŸýÙŸm¾ñ¹Â?й®Î>;ù† “Œú`|ųę´>V² Gø)5]HÑü…4Ð Z©5*ü ˜æì7m¿·ut¸ZgTVŒ¾šÞ¥cN£e¢:«d¬éŒn—¿ûÇ¿3û~²/ÝkìuÝS#ºÊÒšêL ÒÅýß¿?Ý;ÊYo:KuÖe´×Àòç­Â˜òÙ»7ÙWoš?.–AI¡)Ýqã=hÑb_žaÉ~|yÎQÆ>!]àlì£:Sš!¨‹ Çž„{wÜ«:ë2Úk`ùóV V?ø,ì«÷=B?®<ß/TÆþ|BÃÃöù܇}y¾ÝåÇ—çeìÒÅ…ó/´ë.ª3¥Tg½K{ ¬óÎKÕå…±HV­Jºùð½r÷Õû¡Wžï*ã÷kó,Ï;é<óäuOšUg¬²NÇÒÊÀ>º ëáÇ—çeìÒÎU)e¢:ë]Úk`ùë·Ü2ê_õä“ÅœÙÕù]É äÜ)þ;ÿx§YyÆÊBŽŸ¡øEu¦´ÕYïÒ^KÖŸz*Y?ýôQuöa$ÑE÷>Uy×+g™P”‘ʇO8ýêÓGœ9kí Áv|hVçMO*7E-áDŒ.Љ8ƒêL)ƒ2uæâÍФ´€öXB–ƒz=Çuwä v¾óNurW2¡"Êr欵¨ ¨¨æýÖ÷ êL)fu†QÅGÄ™üTk­¥3–ë 4Ub8±­–ãºk˜¹¨“»Àuæ>!olõ=ÝŠLP‡P%‹,­±Mu¦”E™:ÕZkéŒ%ê}Μ1N„ZŽëþÈAÖwEqÀ_'Nwn"yc“}YŽžnEÆùŒÖQ‡P%‹,­TgJY”¡3–þ¬ïJkèŒ%Îî+WVLK–ŒŽ*tgmÄ0£Š‘‡YÇ*ãqe”[¹ðÆæ:޲ôŠ¥"£â|F넎SÈÒÚ’“–¨Î”Ò(Cg,™¶&ëX¥<:c`ë|‰¼?NR¼è¢Ä€’}¡Ïàˆa¦F•’ü­=lúûúmëÀEó/ycs?Å7KŠL+!%/#Z‹ÿ¹ZS)e’¥3ÙÒšê¬3tÎÀÂaýÞ{ùduâ¬>iÒ¨ÁTo4¡¢ä+>!1Ž|øY*×ñS|³¥QF´6\©5Õ™R&Y:“}ªµî¡sV­OÝø£ 96«UKQjàºqGÌø#oz.ÖYL­EÉ"Kkª3¥LŠÖiª³ÎÑ9«Ö§nd»@7¢¶j) à;wº#fd»ÐÎbô-Pi„,­©Î”2)Z§©Î:Gû ,·ê’KŒ9p 1œ|ÿ+8z4ý#EZ±²Z¼ÅAÞØf}|–}ƒ“ÑY®¯®Ô™¼ùÕzCTÁm¸ä3—˜‡}ýTgJ3äÕ„´¦:ëí3°Ü¨{î1æ;ß û_ÁùçǦxj‰ËèBý¸³’ycÛ{p¯yåà+¶Òñ}àü“ίxd$ÔzCTÁm¸ç{÷˜ïüÃw‚¾~ª3¥òê BZSuŽöXn ”û ¤Pk”?ëë×3sf2w-_< ¾XJ÷M½¹ñæç]f·EFèÐê%ÿXW¿ÅÇÕ> ¾ÖjéLF‚MÝt³õ¹­ê#£T‘WgÒÚú÷¬73'Ï´u-_ü㪳6Ñ>Ëmr' µF…¦c¸ê*cöîMŒ3Z¾öïW_,%ˆûÆ&„ÞÜxóó‡.ó¶ÈZ½¨ÌX²®~ Š«3^‚¯µZ:c$ØÑcGmKëÐÁ!õ‘QªÈ«3iíªo^e[ó©ÏhùÚÿ“ýª³6Ñ>Ëm•ºøbc–.5fÖ¬¤UjëÖú­Q¡Ïä¨/–@ÞâfMžeg,žñúö .O AÞÖ/Eq[ .>åbsÁO_`[£h%¨×êY¤UBß4£3Ð:­s´ÏÀr[¥îºË˜[nIºúXªßå¿ÜÖ/ÆAI‘·¸—?ÿ²±xp`Ð~à4O A½Ö/*3q8ÕföñÛZp×'ï2'ÚÖ(Z ð•¹ü/.O¬¦^«„êLšÑhÖ9Úg`ù`La\ Ò•e(I ­^|ƒ–/ñÏ׉^»•Œ)Œ+Á}s U,~ë-_âËÄ'§ÚÌ®¸ÜÿýûGZ£X²µt&­KOYZá7£:S²(¢3Ð:­stÎÀ¢Ëχ֨,CIZÀ^~Ù˜—^Jö‹FØ–-‰‘Úu¨¤Ð<î#on¡ŠÅmýzés/™W>ÿʈ/Ö–g¶Œ4·k3»RÁhO_µt&­ñ›Õ™’IÖi£s]~é„{Z¥hr}­Xb8ÕëöÃóçÎÒi”šÇñUxƒ“77×7寧6V¼ùùPaùóÌøN¦ÊøåÂù¦%\ø¶dÝ×Ù–g·ÔìŽQ)µ(Kg Zk-3°0¦.½41žV­2æÉ'“Ö(´!#ëuûa”¹S?0y©t*㌩KO¿Ôv¿¬:c•õÉâÍ |ßšÛÝ7?*0išMÅXS”[>x‹Õ˜huðý­ð©Õ£:SjQ–Î@µÖZ:c`Ñ…±„aDKÆÆð·Œ6L¶A­n?ÒeËFãSÆ-¼µQ±P‰ðVFÅ!ưŽ/‚ëdÌ›_V¹[±\v겊ø”ñK-­‰Îx öÖiYZS)Y”©3P­µ–ÎXY~V ¾V8Àc(¹#™ûÊï*äïÇ“îÆÐgw”q QÈ'A "Áaå+G*`ž¿Y¿íÄŸ¨PÆ7µ´&:ÃÇjÙiËjjMu¦Ô¢L±ÎÇ¡qz÷ß•rèŒåûYeµLIk†“túß{oögw”q oy®OBÖ[œ¼ùñ@“¦u¿òâo;1d¼/ô‰ e|S–ÖTgJ-ÊÔëL@Jà“:âø®”Gg ,N+Œ'¿UŠ–ªÓOOÖ§Lõ±ò ²¼Æš2îp›¿ŠFÞà@ÞâN¿:ÑÙ”ISFüüÊ+oŦŒOÎyó9V_Àòì7mÿÑÇ<ØxøM}ÝÔ ÖTgJ-Tg½EÿáÇÍþýû+9r¤"„¶»v™áU«LôÀ&No{l;½òоòÊ‘ãø;J»YFƒƒ&J 2–Ë»xqæ¾"BÛÇJ(š¿VÐ.­ízy—Yõ¹Uö›[ôj¦Ð¬~åWFuÆß¼ÅIsû`ßàˆAÆrÑ[Fµ„¿CÖ¾"BÛÇJ(š¿VÐnÍüøLsßßß7ò cÅ/„rœ¯3Ö³ôT–ÎÚ>BѼµ‚v>;ÑÚÒõKÍÝß»[uÖÆÐHÞ\ú®¹æšèºë®KWG¹ùæ›Íäɓӵr8ÿúëÍñÛ¶™þÔ¸u-ŽÅ:uª¹ã¦›ìß—­Yc&8`ÿ†×Ž;Îì=ùd3cÇ34¾ylÝ:sxÆ »oÒÐY¸aCpŸÒ4W\q…Ù·oŸ™6mZºµy®½öZÓ­]ÿàõfÛžm¶‹Ågꄩ榕‰ÎÖl\cÕÙqŽ3'Ï8ÙìÚaæÏ˜oÖ-XgfLJ´4txÈlض!¸OiŒñª3ö}áâ/õ¤:+Ÿ^× µG_z4]EuÖ]øZë;tèP„%.`…Ï›7ÏìÙ³gDŒXe›6m2+V¬0ð‡jÁ¹sMŽí[ÑÊ•æØm·ÙõÕ«MßæÍ¦ïØ1Û*-_>²¯”•¿n¥hþÐÀœ9sJ¯ÐY;´6÷ª¹ö-.ÄÊÓWšÛ>–hiõW›ÍÏn¶Mä¼Å-?uùȾV :«DuÖ:Æ²ÖÆ›Î Kkª³ÖÑHÞª´yÄ;¬½ÃRxíµ×¢[o½Õ.›bÕ*<©ªÃœ9Qô éA1üͱ³g'Kw_ (-]JÑü…4Ð Z¥µUŸ[™µ±Ýî…9Ÿ˜½°oTKüͱ³?1Û.Ý}­ Œ¼u3Eó§:keä¯[)š·^ׄ´Ö·¶OuÖBÉ›¯ö:¹3*o º°.“Œ üͱ̑…;#q|çwý ³Rœ;ùî– ëî$£Àß‹?NŸ8†â(ê:‹²d]Q|TgJ»@?3^_Ù…÷ŽŸ~G•Î øÔuOÙuTk¡½†Ó9ç;jX²šV!4WVh›]ŠÍ9ó*GÛ°îVF‚ WÇPÖCÛ´‚R|TgJ»@S ß²°Bk'Ú¿}TkÝCû§iØ¾ÝØŽA`ùøãa#)4ýBh[ÈèRÆ=Ûwm7îh›Çøx°B Wm UPŠÒøZcBGÕ™Ò Z§õí7°üÏÚÐ 2’BÇ…¶é˜¢„*4?^Fzõy(Œê¬kS:ÕZ×Ò¬ÖTg§õ–?ÇÕ–-Å 7dLujrÑPZ”®ÀŸf˳[l…R„P…æÇÛÕY×âëaãSG^yéj­ki¶NSužÖXŒôsa¤_‘ S¡y³ÚA§ ;¥.ŒŒqad JB•Ohž™–£:ëZüX8ËÃ+/]£3P­u-ÍÖiª³ÎÓz _(Fø Œô+R¸þT û÷sø°1]”47¶ÓߪS†R|#ðà+úvæ?<÷ÿd¿ñ˜™Û꣠:ëZ¸ÿè@fÀyxå¥ktªµ®¥Ù:MuÖyZo`á ÕÌ?q^ÇHë‹+µ#GŒ¹÷^c&Mj­¿Uu¤ïZðhvDŒ<<©Ôx€9vÄÎxÌÌÇ-÷QpQu-Üt°òŒ• k­ktªµ®¥Ù:MuÖyZo`[¸´<ÑÅßyœÝÄy}êÔÎÏsÕGz¥a¤BáíL¾·UdŽ<<§¾nª}[„¢­¥ :ëzšÑZ×è Tk]ꬷiå.-O´@uvó» iÍk#ÆéH‹² …·3ùÞV##pÎyó9öXžý¦³íßc ÕZS”¡5¿ ­qbî TgM¡:ËI—ê¬=–@¦E؈³­`|ÌYÀ@k#ÆéH‹²¡òØòÌû¶¼µÉŸ,ǪµRhFk´NðAgg‘ž@uV ª³:t©ÎÚk`‘iFºäõÇ¢Ìý°3µ‘:¢§¨<ŽW꬈ïÂö]ÛÓ¿ÿáãé_cÕZ)4£5Z'Ü;ówGºoZ‰ê¬TguèRµ×À¢Ä p\/â5ÖG"舞R`x²Ûò„“gß·I½¨ciÏ Z+ÕZTg¥ :«C—ꬽ–_Ó§óÇë#ÆzþÚ„_™LýôB¾ ®c)KÖǪµRP­ÕAuV ª³:t©ÎÚk`ù…@wa­f=ßq ÆòH„q:Ò¢lüÊ„¦õZ¾ ¼ýñ(oƒ Ž¥,ibs¨ÖJAµVÕY)¨ÎêÐ¥:k¯åÂùçW¶hùÍz]ê¸fÉ;j!t\Þs•† òp+“óO:¿âíÏoçí·À¼oƒm'¯^üãž|2ßyJÃŒ)­5ª3Öóž«4„ê,=.ï¹]B{ ,·E+4?V7;Hæ5þBÇå=×§ÇÄÕ-¸o¡¹dBŸ”è*òêÅ?néÒ|çù¨ÎF´Æ¨-ƒÏ=8¢3èj­5ª3Öóžë¢:kÕYo謳–Û¢š«›$ó>XyçÕ:—V‡ãïL|kX².4".¥âí/4—L×;€æÑ•†?ÊË/gŸ§:k ¢µ%'-1{îµÁmAèj­5ª3ŽË:WuÖƼΠȳ]^r‰1'&¿Åê Î:k`¹„ ®K×,y?9F ¢©u.­œŒ¶dɺW˜J&¡7;ß¿õ®"Ö¨4øŒ”ÀD¼ünTg!«¡«µÖ¨Î8.ë\ÕYK³:9F¨õìD—÷Ü“h“p÷Ý£†TuÖ=V¨àºÔqÍ’ÇøÃ‚JWR¸ÁµÎ¥ÕÁÅ]Ï+L%“ЛïßÀzWQOkÒªà28˜T2ª³ŽÕ‚ÐÕZ«§3غ5ý#}p\Ö¹ª³–2fuVôÙ‰åNbHuPgÝc`Õ*t »ÛúêóXÐb9 K–TŸ ’?Œ.lj•‘’‹zovþèñiè(õ´†Îü |ùÀú™gVŸ'¿%ÕY©ŒI_?͘‘çŸ ª³–3fuVôÙyà@ò·‹RÔYä±oß>Ì@»^{íµèÖ[oµË–ò Q´jUÍš•,YþÀ>M–¬7‹\kæÌhxΜèð”)ѱ•+G¯Ù~úã¸mšÝ°tiõ5ÜüúúF—S§&û›HWÑûÒ@+è”Ö^Ø÷B´ês«¢YŸe—¬ ¬|p 2k]²Þ­Ð¸Z›0aT;B:_kØ–uNNTg•tDgè!¾Ç.¾8:×¥×iÓ§WêíÑÙŒI½ÈþÓ¥:«¤­:ÑD7>;% K´ÚF¯¾C‡E‡½—²ÿ~3oÞ¼Ø@Üc¦M›f·9rÄlÚ´)6þV˜ ̾Þ"V¯6}›7›¾Ør ÍDË—›c·ÝfçÎ5}8¨¥D±%zt÷ît­1*®¯ói_÷šà§ß~;qï޺רÊ_ì±²l2]Eï˜3gމE2¢2@gÝ µÕ_\m6?»Ùú,Ь¾üÔåæ¶%e;÷ª¹Ö^˜=e¶Ù½¾q­µBgP/~0qµ’G3YZâ‰.½TuVÓ™«‡&µ¬Óâr¬§™VÖiª³JÚ©3hEÔY‡ŸÜ;_k}×\sMtÝu×¥»G¹ùæ›ÍäɓӵöpÙš5f¢ÓÔ÷ÚqÇ™½'ŸlŽß¾Ý46Üßo^Z°Àl½úêä ñ¯%Äo}掛nJ׊áÇ[öfè”SÌ}Ô¦]ð¯qþõ×›ã·m3ýÃÃ#Âði&]E9xð ¹âŠ+J¯®½öZÓ Z[³q9pdô>MœbN™yŠÙ1´#.û>óã£?¶ßëêïë7 æ,0W/i\k­ÐøñljüF„Ð5êiMuV¾ÎŽ›pœ9yÆÉmÕ4sOCuÚ„C‡L¬5¡A»´6Þt6uÂTó…‹¿`6lÛ`¶ïÙnŽEɽ*CgЊ:-¤³±ðìl} Ö‹/šµkMßÛhñbsì†Â}®1õ¬Øøâ&ºä’šqä¥V¸+NëàÂ…#o}U× |bqõ}ç;Éz,†øî”š®ñòƇÁÚ¯¯µ#ipö¼á}7;ý7¾™¯Ÿiöþd¯]§š5yV\ö‘Ytâ¢Ì8òÒ AHkqáš¾oÛÐÁl[Þõ.sìÎ;“äwÈÐgühâó¬ÃgŽÖˆ¼Œ½hÌÚµæá‡ûÌâÅ‘¹á†cÁê¨c:ka V]A‹ë4ÕY%¡,mÀ· /9å’¦u­¨ÓB:ëô³³‘{W¥5ÛQèï måõ#»}¤,YÏBúagÏN–ô×sž¶—…ÓçK?ò¡<ýÈÎ9véë§_ÖûûGó_kä<–¬Ë>ñƒáú Ù—u­½! ´‚²µ–×ß@|fb¶]Î\7Óž#í¥!(Sg ǸZC;¢%ër¬¯3÷ü!‡ŒÅE—§Jóu6cÝŒÖë =Ä÷¬Cy|°ä¼"uZ-q Z?ÒÔiª³J|±Ž?V˵Vf&ûó<;e_—é | Ä)«¤l‘ØLJ(À¼P8yÖ$¯íܽpî¹Ñp½’7="âCYùçwŸ¿¿$ŠÞ¿ZAÙZk´R¡R*Ý4@KuÆÒw -±ÏÝîî+‘q£³«´vé ]ðÀ;œÇÀÊ£µ":“¸BûKBuVŸž¬Óz\gàk õÓ443E›†WÒuB?®u–ÛTc¦×¼–q>ñßgR>?ÿÄçÓÆ9:ÆÎ^\o¨sY´TgwÜaÌœh \­©ÎJ¥Ñ*­]:Ct·àÓÂ2SgGkEt&q E H© ©Gg/ÖicPg­5°èD¦šXéÃä{ƒë×›‘9ŸXrLþœMú]eNrÿæ“>I¯ ~gŸ®x„@þÅH”8}GÁ9s*÷ç)#ed®¾Ç%ßæ¢RYÿžõ¹æ€Á'¡“òåÖ¿‚€ÖBðu†1ߢ¼ÈoMuV R\¸±QÌ·˜ëc»t†.ðC»ôfî}wɪÓêéL´äj¤Î+Rç+Ѝ©Gg·Õi.­ÒY7Öi¶Ë¡ÔfÎP³`h[‡¡ý˜ôõúirÓëñ=ðáÿX·ùÒ“nD¶I󪻿„2*zÿBhei-«9¼]ÍäyÉ­3–n×2ç„4À69F‚ꬊÒt–Q\%cóÄ Nd—~‚Üû!T§q¼œßãÇ)þ2þ¾Pz 2Öu¡"+¹K¡Ôg'ÇûÇѸû›,¤Fî¯Ï,×"ëÖß¶qcÇ-MF+0õC|3G-aÁ·ª]<ýÃói%pÙ¿4Ÿ¡8ù3oÏšþ˜ª’IÖ÷¸üí[žÝÒÑ™Œs댥;3;oˆ! ÕÙqÇ%ËSOM>¼ËoOu–ÿIqùÛ;^¥Åº`äÃÓYVè BõªÓêé ü8÷íS5AHk]§³˜RŸÍê¬ Ÿ­5°BÈî6ÀÖ¬ÕwÛN8ÁΫe'/õ»"ÝôÒ´)Ôëó=묤éRΡ¹Sòé—S¾»DWè޽ɱr^½ë¸ BÄØ-Í£m"Ë÷Ší.GùÚ|GÈ«3–ÜCw=¤Îç{ƒn¥”¥3–ö‰Öøí Y×ÈbjÍ/N).ÿçÜñ*-ÖÃÒ™ûÇOwun‚óÔiõt~œìW5LHk]§3ˆµQÚ³³Yuá³³µ)V-‰ëV¶¹^ÄÒl÷ÎÍÃÅ'_ƒwóÃõ/¹Ä˜‰“Àß—_n̽÷&7Û­\È'6>1ҹΜDî1ÛÝëä"Æz‡cŒ,‡N–Ìÿ"0ç´nåA|»êùp•‚«3–þ‡šqÀðu†ö®º*©X\B:Ƀí~‹EtãPkþ-’â’í½R¥UdįÓÑǸŽiþ÷ ÕYnBZS:cß“O&-OÔQ,Y/CgÝôì´…eö#פѾÒûX…¦òÇõI‹dnŽzôÓ‡,ùq·7’¯Œq½EóÒ@+h‡ÖšñÃ*Û‡«©¼…t†vòhMôDh¡ÖŠæo,é Üâ-R¬žW‹†óÇÅIˆTg¹P]‘ î¼Vµ‚$ÞÍ¿¯(%è | ´¶«®u[ÄÒ uN· L~¬hZ¤e€aÐ>Ü¢<~ùÇ"§i”~ä"åájWç43\9Ë·«-ð6Çoƒ×U´Ò™ßý’…üNä7§Zk ½X¥•®3ZTg-¥'uƳó ¡5ÿòËéοÇ'‹ÒYç ,ú[™‚Á-ðàZ ͆÷Ü“øL!–®3r#,X,Ý¢EÆ<ýtRP´=·Ñ_Þ¦™áÊøpñIïǵÍIžætš«A´Ö ‹F¿Ô²K–$V*8ÕZi4S¥ñܨ ÚQYÊÖ‰Wµ”žÔšà“6b@¡¹<ÆT=¢³ÎXE €¤À˜q ÷àZ 7³QQVúŠ·oO&UCp a$!ùdY´O¸Ñ_žbñ}®˜GkÖ”ø­(eïÁ½ís’÷ßîš¡–Îø]á3¨Zk+~•6cFº#”vTg–ft&>¤.$^tÆ÷ Ñ–dTë´¶Ó5:ãÙÙ(!1zPtÆòÝïîJõ†EIá<>iRòaG1vÚÕÞÉ+@ÈPªç¬\Y©n`;yÈ7˜m,³ÚsÝ_ Ë<ºRŒ§MÏl2¯¼úŠ]^õÍ«Ìp”N¢ÓÖnBîmˆZúcߪUIS¹ úÉÒ•Ó}÷…µ¦:k~•æÎëÿÜ[J–ÎêÁCoçNcü'»/ L/Â` yjÖvºFg<;!Kg¢#Ö±.ÔY÷XnA„æ¶p» ÛÕ7O³!£!|kº´É’úŒNêBë[üü¹¿šZzZ†ƒsçšó¯¿^+­n«Õ–g¶Tù\5úù¦áÁäJè K{ìCg¼)òvçR¯Õ•ßTè·¤:+ ·:cÉ´wn•¡[ÐrB: ÁƒN(F>­Sh£üLÐÚÀêÕæ²5kìRµV«5ÿÑ ÑÏÎ .¨ý‚èC§O7æ´ÓzWgÖÕÝ¡]#!êâŽpGÈ(ù0$#åd½AjæO®# ”ë<ñÄèèö ަQÛØçtȈ?”?Ä£/Bùç¼ôÚ̶k?üšƒZA7hÍ)Ø·¶Ï.ÝQƒ¡/Õ7JÓ:c9ujå½—wN( S®ékMuVNÙ%·Ò]gbëÐ-h”¦µFÂü€NÜ}è­„:­æ,õƓ΀"m¹·¨+uÆ>I¬¸ÿì“Y⋆è | ÄW¨¤[D,ˆ²TáQ3\Oà4JuÓç§WBÈðÊHV>Iƒ_¹…à¥i˜òËAH­ ´6ëã³FŒ*„M(Ř ÑR5ÐQè³ :+ ÿ¶±NQ¶¨J+Gk4ãë†Ð‚:Í`Æ“ÎÀ/¢>:ËÑ t× V¡íyB‡t¾ÚÛEè¶]²¬Õìæw.[–ô­¶ÛÑ‘.·Uúsï¿?Y Œf¤݇s$Ypž;Ô?FEd哿V¿«(Ô™î”áp¿‰¥8(2A¨ß¸ìÔe­ÿoˆ¼:É"¤3—¬fxÎã·ÇÈ1™ôßÀ[nIðPÕ¤™êŒõŽùnçÕZ=²tF]†®ZT§Åkû§]¶­«sÑøZëÔ£3·ÎB®2òiÉHÔiè ¡·.ÓY{ ¬¬þÏ‚(ˆnžë«5« ©l˜çÇsH¿ˆ äCÃ/€2yé¥Ñ¡¦µ~ ìãœzéJË0¶¾í÷¢ønÔxÀwV—‘!ë™y²J%¯Î ¤3@_ü^ð ùÕHM{×]I¨WëªÎjÒ‹Õ™¥H¢žÎˆ]µ¨N«ùÅ1H–Π«µÖ¬Î¨çÈ ½T'šA_èŒê6Ùv,‡–6sf5»e5%Öƒf@Ž•ööÛ?kæO®á·±ÒÌ)M,Y5±³Í%Ô~ÛHº³Ò èý i ´Jk~·]~àú[™™]ü°ˆ·™®ÃšykVg~³¸êl„–é¬;«3KÍüeÝS_k\PÝMãë¨,AVº<ŠÞ»±ª3 ˜ŠjMй§uÆy&>+]Ü;_ímÁʲh³šëQË´/ ,^¬byÛ^¶mK^¤9œn–ÇKö»pœ¼Z€_XÓµ,n÷u…¼bUw¤í·»Éù×èÌìY-b¥Ò¬Î˜ M¨ÎÚF/VgWkÜ[.ĽZ¥ø­}éKÉãÌ…îœVèŒ%¸¿Õš%KgЈÖ:¢3–ªÓþú¯™<9Ù/ »ÓOOŽG'~!p^t¨Nk%™cl2…J“ŸÛvYKAµh´&kQ'³´˜EVnR¨ûc8^&Ücº†žr,S80û›TV~…#Û…¶ý2zéÜúÜV3sòL3kò¬Šn¿F§\èÈ'sŠêŒ)@Tgmƒ"£H)Zz/˜û¸«³Š{-s ʃ‡ïJ‚\DRtñHP•J-A#ZëˆÎ@îw¨Nó»ya]P§ÕÒt«Öl;–CKš9i†«ÕŽ™³É®Šzñæ¤Pþjµ×ΜY¹¯V&RÒM“)iw›ICù©uí½! ´‚²µV¯ °Ñ)êÅ›—BykµÎÜíª³ÂPdÅãa‡«3KîüÕº×þ>7ˆ~ü 'Ót[ûÛ]Tgu©§‰F´V/Î"Ê_YuA.Ђ:­‘{çk =-X¾Ȩ́:\+ K¶h“¦|»½ù²^È‹lÏ·(FU`U»£)B¯¾ü–¦Om¬EØèw ;âßj¹ÛUg…ñ«4&tìÅê¬æ½>çœô¢Ñ-€ :kˆZ:ƒF´ÖAYu¸:ëâ:­=–›9  Êh¦k´&k†,u’šæPù ´ û"èØ/£7p»!Šÿ•á3ÕÌ£¦–Îh^o„ÎB•ê¬.TiôTâšÔ ¨ÎêÞk7“yaʚ͛ÓÕYaƌΠë~7Z§‰Îº¸Nk%™s•²2{,uòª!sw@hX©À7 Ýý¡·AüÔ|tì—ÑHKS_üOh›ÏTÙÔÒ™[¡ÔÒM=á©:+ Eæ»ÂõbuVó^óð¬–*êuwº¬Œyt¨:+̘ÑdÝï"uš»/¤3´2 :¤µöX’9<ÿ¥%+de† ù°–óZ+häš~$£v JþFLð¸pa"ŽZP±µIciiZyÆÊÂÎì¡9²ÚBQ­ÕÓc¹ŠÎ?¿¾Îx)P†"Ë3NˆFª—¦iä¢~σ‹«³ÇOŽ­Å”)ª³w:cYëÙ™5 ÀÀž6Põh%`Um¦£ùîÄvzÿ7rM?o<¸Ü·?Þð^{-™à‘7Ãzäý)U4â3Õ–©BÕZ=ñÕy¶1ñÞ3Ϥk@W´ÒTgÐHõÒ4\ÔÍ Ûr®ÎÎ<3i…¨Ehä«’‹q¥3–Í<;»¬>koj°*‹6Óù^~nûh«LôZ×ÌÂÏ­Y¯X쵄€Åž÷W¤TшÏT­©ZÚºUTkeê äÚJa©Î ë–·ª:³4[§ÕkF©§5ÕYÃŒ+±l¦NÃ/«‹h¯Õ~ó¡[Ø­2Ñk]3/µ^;øûÒK“}4±ûð¶—÷W$ýÕ´ôWÖ{Ôš#«¥­[Íj­sÑAuÖ4Y·¼UÕ™¥•:Wkn÷ŽÐjj­‚žÔÔÒš«³PÒ^-Z­3;YƒC+æò¨‰ÌcÁ<2¯… ëÌßÃ<þ–cœGŧ*’¦"“‹È9YùÈ‚ãü|Ç¢pÍŒÉM‚÷¯Æñ! ´‚vj­ÞçnX_º~i4áC¢ œ`ÿ–c²>½S”`ÞŠj­¹ój}u> ®©:«I½[Äz¨J+©:³TåOÕjr3BEήYDgqŽê¬‹urNQ­…2C&‹ÀõJÒøhm VK¯ž9MK³ Ó/‹Ã.³ Ë1eXË!i“môµ€¸Ÿ~:ù 8åÄ’Ï¡¥hÓl#M¹]Jž.¼z­Pt#Nœd†£asdøˆ¹wǽ#Ç4:|.Šj­ñ•yWgµ¾:ŸÅ8Ö´²JkUufi—΀úËÕõ[«uc©N/:ƒFµFÜÍ>;[¬³ÖXy .Ob³Ž©Õ”ØNP?3ÀÕËGY¢Ìó+ŠþjZú+k/yºðò|î&똎L4BuÖqZY¥uKuÖ“:ƒ±T§¡&¯—‘,šÕZ‹uÖøða³ÿþŠGb“× ¡mõBäÝÝ(.8ÿ˜á8qQšX–Ë%ûví2ñEÅõ÷‡™5Ëùַ̑ݻ“%ëNÜE„¶ç ÃW^i¢x)D}}£iÌœü²´ëÄ›þÊX²<—ðå/›áåË“óã%ëî~p×ó_6­ÒZ•aô|µÎhur[¡½%¹?»^ÞeV}n•mýêÿ…Ž™õúYæ[ý–ÙýÇ»í’u7î"BÛóÕY>ZY§=ôPä= ¢ªc/Žë]z ¨#³hѰٵëHü‚=×÷‘]ž}võ1³f1ßúÖ³{w²dÝ»H€Ðöz¡'uF¨qN+èF±ÝÕZÔÝ:CSB'T<ßó†f´V²Î.}×\sMtÝu×¥«£Ü|óÍf²ÿ…난ýõæømÛLÿð°-@ ï¥sÎ1­[g3Ùf̤¡!³pÃ3cÇ34þÈ>÷Üáø~„¹1â±ÿ­oµçMþy³×9¾ÝHºgÆé¢}æ”SöÚcݸډhí >êLÕ«:Ë¢uÆ~÷ܾ¾a3uêk¤u»ÎÐÉ?Ÿ{nágz7?;û:a‰ XáóæÍ3{öì#VÙ¦Ø \±bE\)xó¡ÔâÅÍÀÚµ¦ù+â8lÄw9Š­¾c·Ý–“Áàܹ¦öѬţ»w›Õ«MßæÍöÇj[µ˜‰nñbsì†F› ÐHþ*ÒÁÈ…¸")’?‹”M¢{÷û©Ê”(NGtÉ%yͯGÑü¡9sæ”^!¡³Vh Ÿ«µ__kîúÞ]æÈ±ä ‚¨å§.7·}¬vyͽj®íZfO™mv¯ßmVqµÙüìfÛ"F\3_?ÓĦ¾m »á}74ô¹œ®ÐY\éôÅé¬âƒþTgu¡§aáÂAÛ#¿ŸÚ‚+"sÛm£†oˆ¹sã—iî\­ »w5«W˜Í›û샆´:3‹G憎5RYšÖZ¼®:«M7ê BZ[´(ªÐÙ;ßYÿ¬‡îkJkÑ´áÙÙHÞª´f]Ý⤴ܑE‡-0:Àñ«kÄSßKB¬×›¿¹óçŽv`X†{}ÖÉûóŽ‚àXÒíÆãÆ'׫¯›¦ŒcŠÞ¿ZAÙZkd´£ÝsX?. °£!wÞÜ{Z¶Îä‹ónàKö£:Ë…_Õ«ÎÀX'ƒü¸$4QYråÏ¿§èÀMZɸ×A8VuÖQQ\¡G§Ոܪf´–+þ=mVgÀñ’?”ôìläÞùhÏnÿvãšsÜÓߗ謈áÖ0­ÖÙÅmΧêl· Ê[|îw“Yòù>pãjwuVuO E3æ¢:+•FtæWòèôãÂqoUKµV¶Î Gží1°òX“.~á¹w_âzê)cÎ:+ÙOÿèE5v£Šà§«‘Ö_õÌKT4¾Ze5Îhä9Y­^n\wòn3kÊ,ÛÂ5sòL³þ=ëí1-£Õ:£"®"qªÎF*¨Œâsãºûî¤Å—p|±Ö·XfU‰ÊÓÂT ÕY©´Jgò˜Ä˜oË£³lA<;Ûc`Å/¼Ðݧ9ïÞ{“.¼BñØkäF!OºŠàª¾,¡5›¦qFžV¯«¾y•Ù{p¯mábÉzKQ9òßU±¬èÞ¡Õ%ë-¥ì{ª:ë8yНíÎVÜÓÑZk ,†B0ɯeÇŸ¼–Õ›`ò^'š’˸©eÓij3îLî—|æjÍêî’§Õ+Ï$¥¥¢:ëJ¤:£>¾ä’$ðwÏViÝxO»1M`L=:»õž¶!]­5°0•ï¼3y#CCÆÜq‡1óæåS‹[ÃѾ) °cq*=3·ßùôvº…»¿w· ü}ÇSw˜3¯9³®‘åãl,Ïyó9#>X@WaÑ8•ÞGª3|béÎ#ð7UÚ™g6W±<çœÊ*®B­ÎÆ'—_žèÊt6¢3pµ¦Îöás ÀT¦ Ò‡¶ÉF -j8ñúGy˜÷t"Sg‹F4«nUréÐÂ$“Œúìùñ3ï·æåjÍüOï>XÝ„¡ÏñtÕYKɪ΀‡ ¿"EïVg,*M ŠëÆêLuÖzî¿?ýãAO>:Ç€ÎZk`áDV‹¢wÖoÛÄY!á}d[7Ž:ñkÒ®¬5{ÕkÁä£Yß( áw 2²Ð5àÚÒMت³–R¯:ãáW¤èýꌑ…®׭ՙꬳÕôä£s 謵Nc Ÿ¬w–»Ÿ‡×F4¯î®¬5{Ó™J¡E=—Og¡‘…αÕVTg-%Ouy«´^­ÎTg­‡ih]ªE^AOjm 謵Nc Ÿ”¹P–.M‚¯·C¸âõÇáÁù^A2Δø[4 iz¢Öì]pLòº'ͪ3VÙÑ€KOYjƒ;q(ôçÔ™Œ,œ5y––aës[ÍᣇÍEó/*4ÇVÛQµ”¬êŒ¿ý/i䑚Tgt×PmÝÚÕ™ê¬õ0ÃS:•¡3èI­µÖÀ×SŸo¦OOw¦ˆ•Z‰‹y4èH&0Þ”q¦ÄßM#\DÝ]]kö6îhÀ»>y— Ó'WêLºýê!qwÒyÖßjèà¹wǽfÒà¤BslµÕYË Ugü=eJz@Jž*Mââ9BU†#s/Tgª³ÖS¦Î 'µ6tÖz+ÄùçWZ¦LyÁÑmË–QeõBÓ¡ûkéÚZsìqþIçWtë-9)¿Îpˆßòì– _¬®ô»rQuŒF«´^¬ÎTgc\=:Ç€Î:c`5c™âè†s¼@w£6Q+òL"šñ8Ç t7v¥ß•Ò4Z¥iu¦A½Eg ¬f,Sß«ï´Q™2np» ‹vë1’Ðep`°;ý®”® Ñ*M«3¥úèì-:c`5ƒïøÆwÚŠ¨LQrà\vê²îô»Rz­Î”v¡Zk?½g`5ÓFª(9i¦{QQò¢Õ™Ò.Tkí§÷ ¬fÚH%'Ít/*J^´:SÚ…j­ýôž¥(Š¢(ŠÒ娥(Š¢(ŠR2j`)Š¢(Š¢”ŒXŠ¢(Š¢(%£–¢(Š¢(Jɨ¥(Š¢(ŠR2j`)Š¢(Š¢”ŒXŠ¢(Š¢(%£–¢(Š¢(Jɨ¥(Š¢(ŠR2j`)Š¢(Š¢”ŒXŠ¢(Š¢(%ÓrëÅý/šËþô23û³í’õ^¤ùpã¼ä3—ØÐëåÔI^Œ‹ì²Ë’¯Å³d½×hEÜ8/¹$ ½\F¦÷¨”ž?Â'Ÿ,ùã‹ÒïO§(;#~|]¬³þÇ›ýû÷W8räHEmË®üÊ•fÓ3›Ì+¯¾b—¬‡Žsî—w™UŸ[e –¬ç9î±ç3K×/5?<ÑLüÐDû7Ç䉯^þBùÈo­àÆy÷÷î6÷|ïžBåDÈ›†zùóC+h¹Ö®6›6Eæ•WŒ]²:N®]G̪UÃñï2²KÖó÷ØcGÌÒ¥ÃfâÄÈþæ˜<ñÕË[(yâ­Ü8ï¾;2÷Ü“¿Œ$äMC½üù¡¨Î’P/~>~é—†sÅ›†¯¼ÒD›6"d-]Z±ÎþÐyUa×.3¼j•‰â&KÖýcêåÍ­ ÛtFÈ£ ÿtÆræÌÈ|d—îöfuæëÂê Ç=Πݬ3‚Kß5×\]wÝuéê(7ß|³™ú†x¤µ’ze$ä-«"tJgÐT6t~>ŽÅ×î«HçﯻÃ,ܰÁÌܱÃì?ß<¶.©ÏÜmOÅ´3¾ö5ó†G­Pµ²»~xêTsÇMõë´ó¯¿Þ¿m›é6Ãýýæ¥ ÌÖ«¯ÓƋΠÖÜc¸K}ñMŠì#”»•Ü5Îíë‹Fô׌Î.[³ÆL<0úìDC±nü{Œ¶Bºòµwé>`ú>ç»Egàk­ïСC–¸€>oÞ<³gÏž1þÜÏõÇôè‚¿ôÒÈÜv[¥1bõW›ÍÏn6dž™þ³üÔåæ¶Ý–î5¶+lí×ך‡ð°9ûMgÛmßþûoÇ…–M0{Êl³{ýnû·{üCÌ‘cÅßNÜø«ó›óMó]ß0ßý§ïšÅ'.67¼ïs´Ò#Âù ´8 Ä»èÄEUÇ»mæëgš½?Ùk×]bÛ|Ëyn9e1÷ª¹UipóäoSlÙ¯X±ÂL˜0!Ýš ˜3gNé:«¥µÕ«ÌÆh¬¸Î€ó7oî‹+…¾øa™åËGÏ¥ÕxíÚóðÃ}fñâÈüÁ3K– Æe3úÓäMm÷î£éÚè9wÞß—øÁ3Šÿ“6q¹Fq\ü•ŸÕÙ7ï5ßøÆ óÝïöÛtÜpÃ1s¨̂y ͯ¼Rï¢EQÕqàn›9Ó˜½{]M³T¨ÕeT‹¹s«Òàæ zEgÐTÖå:ƒF´?cªÒùÏ‹.3}›7›¾ø ˜hyRŸ¹ÛDhv}q¨Úžž{ì¶úuÚàܹ¦f›ZŽî®¬¯UgÕ:ûߩ֫leQ©¿Fu6°zu•†ú~¸êG‹eë*=úî¼Óô%¡Ma|s»BgP¥µÈ#ÞAšíR˜5k8ÞFŽFC\Ø™¼°ï…hÕçVE³>>+Zº~© ³?1ÛncŸ Û>«g­‰úÖÆê‹—n`Çîñ?>xíµ×¢sçÜ‘xCÇHžÜ|¸i‘sȳ{=Ž÷·ùùd½^9eá§aÎ'æØë¹q¿[o½Õ.óÒ@+ð¯3kV¥Æ5ugoU|›8åO$KÎaÉ~õ¸’²q²œ3'®bì¯t4pŒ‹{N½?øª¶ùñYûBgò{"nÿÉ“›7rŽ_VïoóóÇúÒ¥I•Q-ü4P~RîG¯è ŠÔirzEgЈÖÐ…›v{|£BãäZU Žuâ‰Mu–¬ûE$ëXç8Á=§‘àÆ%äÑY•Ðd]#'ÕÓUH{ü ºDgàk ޹’HV®<oŠü~@ÊÊIWÐðÈÂ7>Ü€áÁ¹OìzÂ.9vðƒƒUÇÈßý¿ÖÍZ7+šð¡ 6ð7Ûä8¶¹†‡@NýÈÔ‘x:õÈktùÛ0‚ücÅMñJ~Ýx‹ %¤Và_ýdé |­Ôûíò;%~¹ÆŒÕÇHèïOâã‚-’¿Uâr±:›z¸"®¬ÊÖEÒT¯~ò·¹•®Ó(nˆ—2ðãíA‘:­•:ãøÁÁÊc$4ª3hDkî=fiãå?óþ¶2…nBbSÕ×™\Gl,Éy,ÑÅ=sfe±ÊÔ™%$6–n„tåÃz£”¬3ð5ÇVIH$;w¾uÖ?Ç7`ØÞ„ .HÄÀM •A¨Gƒ@ZYhµcÃ5–Ä@àx ÙîŒ(10äxaäZñ1Ä1cÝŒ‘–"þfÛÌu3£•²2:ë·Ïª0z8ÆžëµÕC®é¦Çß6b0:éòͺn­ýYåÞ+z¿øâc±ŽŽZ­¹:CW~„ù[‚ûÖßNÖ¹¾nÙÏq~œnà·>pa88ŸÀßR¹a¬qîŒÃÑ´i‡âë¾íÉu%~¼YHþÜôøÛÜÊ5¹~õ±µ®›u ën¹H¹÷ŠÎÀ­Óxð',äÓ×J™:“rd»§¸^3:#<ØÉŸ«5öÕºßA$ƒ°Í-œøš½ª3îW­gg»u&q…´ÆßmÕH&}]¹ ”c¤Ek®åX÷\ÿ¶¹…Ó€ÎÀ×@S%!‘ø"mr3ý`Ë"~ð»Æ ë‚»O‚´.]ð‡Tu“±tõÔ2,|îAû·àæ…%Žö.8Ê»Ë^ÆÕ™,ј,/¼Ð˜+p¾L–7ŽÊÌlÝ:z¿þÆ9˜¿qüþ£?2æöÛÙ³'Ynß>z|ˆeËŒuÜ|,«MɈ`»d]ð\Ï“Ÿiຓ&%ñ»eK’ŸzÓ¹°/ïÔ/÷ߟäX²î—-×õãðy8•åµ1Óð ŽZÏ[§½5]‹ïCÀ¨;zìhÐxó©eèU‘êå߻%¾¡ä–KF< Ûvn«0ض†ÆÕY¨ºå–êJEÌ–Yð·å^ˇßtnܘý%Žz0Ü™€ª Wv>µ*Æ<œsNúG •§‡_þ¼< ûö¥Ąʳ—h•Î T.µ´6}z¢µæu™·¾5™—)„<“ri§±5#4þƒôñÇ“¿{7«þ³³:c€Þoÿvb‡Œ ùF:»üòt%%Kg°m[¥Îxã.Üóy0l1PP'Þdï¾»Rµ Q1‚B¸Æ‚ආ-=e© ’!“ßù‡ïØI:Űßð Ž9ÇÅJÎÀ=0b˜SJÀÈ‘cB­F.´8¹††_VKÖ…óãšÜá·]höªëÃÎ+AL­ÖAßíçÜc æiaZWgT6TV@©³l™Uý¶€y¨.]šFærm~oßùN¢sù ‚qPaf™©SØaÌÀïݽEr-ð+;ÿeìŽ;Ð-ƒÁÅ_üë¹eÂRÞ¨©÷¨¿Òí—g·ÓA¨\¤\©;Ñ O® <[ÐZs:«<²îy=Y|°Rl¡ÖP¡Uáê í`Ô 1²RäÙY¶Î¸&õE­âíZ¡w¼c4sƹK–Î@ /¡¬g§í(tÈêGv‡bJ×'!ÔÝévè•>Þ¥ö‡ÂËõ›ª…ïÌí|™ðK’¸Ä7 _-®:‡À(Békåü—8~“шµü¢\BùYçàìÎñ¤™%ë\Ï=—4ägy÷\ñO+Ú—Ò@+]‡¾üþ~FÞÔ×™Û¥NÀG ä¨ìâd¿ëk…ëOà‡P<üíkßS§ÕY|G‡+'bƒ¬V¯u·¬3{~¼'¶†"»d=Ôªµ|»dß«‡^éR¤,Ä?­—`â¼d†áú: ùàduöZò’âÎÇKÊÊ•£o‹>þÛãia™YBñðÂ}ï½Iºy™ò_¨â=ÍéœK´d‘nº9—4û/X>ìó» 87ô–Èȼ±²Ÿ%ë~ëoªÄ™õ ²Ée*þi½D3:£.£ååË/'-¾ÎV­2æ®»òéŒ^´¬æÆtF|‘ý€Àùøü æ7Î,Ó'$´«®J E„F3°Ÿ¹q&4Wgh½ˆ–BZËzvRœ´²Ñ¸ÅÌmÈÒY¨x}qí3*Ó¯µ_g$ìÛßN*|ÂO$Û³ZP³´æn§2¥€%je`Í,‡Ž—Õ‚Åߊšbýú†¤8KzéϾ`[³µç¶8…`¿Û‚4ã×+[j2 Ï'4uߒŹ7þÕ–jÖ”õ ­Äçž+­j‚´ª¹Ç¤}~¹ð·”s]Ñâ%#&É·ì“xÜs‹Zâ! ´‚Ðu²ZB:ãoÙï‡Å/7wtMìwß.ý— ÄŠÇCtÓŸ„dÄüóHkòížG .¤ÓOåÈvŽõËÅ/^*IÛ)GÙ'ñ¸çŽG8§qCufã:ã¾ G7Þx{ŽhTg¹…Ê…±% ­Wu&Ùt³Æº{CE(ûL =çHK}H.n1s~H+´œ‡â éÅO___‰:ã¾»'ØæB"C…$`™Wk,e84KÖs‹ê | Ä1W   ×ç÷æ"AÄ*§Pp7bX`4`0Ä€ «KŒ‡¬€ÑÁ±>ls3Öýn8 º™¦!dÐÈyy ›Ï7°Äpܸýã²ð ¾Zx¤ì¸nQ¡„4Ð B×aÞŒùÙ³‡­ŽÐš_)ˆÎüíî … Å¿Ñ/ñø›mY•H‹ÿ›ˆÃÿûçcdñ;"‚ëõà|â@òéÆ Äå#Çeú]g⑲㺪³Ñ² ðwHg<ýóÜu ÍèŒù#Ÿ‚ë¹ð º™{Œ„¬§kBëU‘|¦Sðï·«î¹»/+ˆ6¡ˆÖB!¯ÎX¯Öj‰: ò~âˆÌ?†PËŠË«µ&u¾âX+ ‰Ä¿[€~HÓf—ä¹^ÞäøF‡)lÃÊ7ZBÁ7d@ 7·Eã-t¾kH…ÎËÇúñ’v—ÁÈ1¤+ â e~pËIòST(! ´‚¼Zsõ"í Zó ?Œè,®vå¡Ê6*­,]»ß¡Tn.®îYŠKÊè¹2_RÙ þy¡¸}8n4Þ$â©®³+T ÞÝ®?uÝS#¾Y·|ð³êŒUÖ§ÊõÇâZ2ïÇÉTø\ollÙ)!üíûBAhŠ®1ñCÍÄO´çúS/°Žïéò!~ÎÙüÌf3<<\sš âñóSkÄc/šÊ¤k^´¶kWÅ·Ö– ü¢€mL=€ï@=pÀ Ün|¶ág€îIÓ™góä“Iº’ûŽ/#i$O=•¬ŸK–>ßm@• n'&s¥ìŽʆáà>ÄÏ9›7'eàúzøˆ?†[v!W‰^"¯Îv3Îqç-·¬˜Ã(Î8GF«çÕ™ë…ïÏCnhDgßÉ‹õãOzX¾ûÝÕB«åxCbå!âÇíÂ>×Ñp -Kg’µZÏNŽç~ÕªÓÄ%®®Î@´†>½&ÒFÝÒÙ]wõhÇÍÃí7¾hNxŽŠh…!™B °ÿ¨ÎÐÿƒ#!Y:ãn¥æ;­fQ¢Î2°Üé$\Øæu ›ò¡,øíÙôú¸V]f†.›gÉ]|#$awcyÁõ³&uÅ„~Ö±;\Ü:Í=6/Ø#yê4ÒêÆE}aMúb?Rљ݀Îü ™]¸°²R«5Ú/T©ù?L ðÉx t–ËÀZ»vÀlÛv|œÿ>k|2W†bò[£k…|f’ ­@L—ðÊÁ=æèÀ‰^X_å“caúë§›í»¶ÛÖ¦)p'ýÌ Ý…B­–Œר9ï¤øÃßM^Z×Üx%î4 C}~Å3íuÓFŒ ‹æ_d=<ÒåøäŸ´KYµˆ›wj ·u.«U¬›ñµöž÷$/=ü6ÐÛùç×ÑYúÂÄ9ü^ååŇÛÂCC…—Z£äw[÷YÃùY/>ü>’„°äMÖÇoéøñ’G·.‚€ÌÌ´i£u/DüMEÏ1KY÷[Ä€¼QF’&–òì$ÈÛu­ûÑ­dé òè ¸´þdi̧¹øzpIt–üÝß?kª:ayuf3è?ÁɨߔX y„ÆÃ”¿kABƈÐjÕg<7y ¬—5©Ó8>d¡:-ÔZV×ÞÍÒiMGë´ &}±iA¨R õu‡*YÒA'…×å*~.ŒO×0eɧ$_!üV ,#,킃KO¿tÄ È‹´sXeµä°}ù©ËÍÔ SÍ;ßöÎ cGü«ÜV!f’ÇÛÞa[Öø¬ Çs\(?ˆ!¿)1‚˜oëÞ÷Žäwég–Ú¥¬ó¹›Á¾êóÉiÀ@ëµVªZÔ›7¦®Î/L!xÓ#ŒÊ äw[äÍÏ}°ÒŠ›õâÃöåË™Éý°yç;£Šgä…c$ ´†391i¡’äx9Î1*S¿µ ¤Îà…ˆ9m$¿ÄÏRÖ©”CçÓxÁõIõYI/v§Y÷!a<´šÑ™K=%ñGæŒ3^Î¥3Z<°ˆß±‘cCBãÁÈÛ¾oÑSy„ƃŒIêüÌKAŽ1¡•¥39§¡:íÒKÃ/_õàvp+ÐI-­Õ«ÓFƸ0˜°}¡ÑŸJ Uj¼ép¼dž~NªÔ M:Kî|/ŽìÛˆñé¦Üò…1¢Ö7]hyC…åã?|Ü#´Ò¸çc\¸ë`üØÉê–s[†Äx¢…‡<ß´ò¦*cGü«ÜV!>FÍG©eRŽç8?¤£ Çõå§-ÙÇÒm%s 3–/ÿøåŠuüFGmÞ|HiîµVªZøZã[Hg¦´:¸û»MÞÌ’}.l“ç¿{ÿ·+Ïê ¿¢á…ˆ¢ÞtÓUÏ É ÇH˜<·[ZSx8s¼GÝ7Sê-œO—/M7K÷έ¤Yú=i‘Ö8©ÓX²ë“Ò]Ò‹]ÇiVg@ùyxÕÓÚr׉;?iã> -_k¢¡Ý»Æñ ›ûîë««3yááŒA=rlHh<0’p‘IJ”‰zBã¢ô=#(âs3 cLheéÌ/¦Yuš{« ¯Îhç|h´N;^z)iö…ÖˆÎÀÕšT¾À6ú9I_© mÒY.‹o§-XðRlxF#Ƨ|¿Ë…|ûac¤È÷©š5yV…ñA+‘»ŽaQDK­5ìgࣟzÔÆÇùÌÎ>}òtk„íZ¿«Ê ¡Oºð|ãÉ*׸ÉòÛò"Žs[¹HßÎ?Þ9ÒEçîcé¶8ùovóï"-V®¡Åµk}ë°Ak¼yO˜@ÅdÌI'ÔYúÂĹC>üNÝŠŽëðû“ C÷ ŸÀß¼ðÐRDÜüîßùÎÑ8ä·O}A½QUÑ8ðV+õB­¼øÏ*9Ž<òfJšháÇuÉ;Ûý7O·’öóïƒáÈ~×€äúµ> Ökøu/»nµî P¾´þ¸u7qøvƒìg[–θ>š¬»/ûè ý¹÷Nž1õ´æ~}£^^‚ZËd‰-¯Ð¸sÝdÛš¯3^VŠÔg Eí×gÔCYEM‘bǶCg·N ­«5WC²M®Tf¾Îò46‹¬Á¡Ö\ÌuÁœš[ƒ}µ¦£~©»Ÿ½»â{|¬Ë~Ö™@ÔÓÉ…¸8ÆŸ÷)4‡•?Q§;gÖHþþdåÈ\S¡ë lÏsœ‹¤ÉÔÝ.ie¢RYåŸ ×–P/ Eçói di‰ëä«_kytî|,29.q1gþÉ>w^¢¬¸‰Ëkˆã˜Fâ`É1þÜ5Lí"óÀ„~GµòÂö<ÇùH¾I‹¤K¶IZ™;IÖÉ—Lhì^‡¥äƒ óådÑk:óï…ò–¹[¶h­qß üͶZåìB\ytþ”@ÜoÁÿÕË û¤òæ{$ãmZ¯ë̯Ïêý®·h}±.EͺÄu/‰+¯ÎʬÓìŽ\:HÆ]¹Û¥@’xþö¯Cmj¤¡¨ÎÀ×@|…Jj‰d֬чžD$äY&¾cKy˜ùå®Áà ¾Q„Ñá±îþÐ1Çú“•ʵ$;÷ì´Û˜Øã†'³.ÆàEþþ—•Ï,BÆ“‘ú3Ѳò E…Ò@+ÈÒÚÔ©‡+´å††u¯û¿7Á¯@øúp¼{L­ãH{œ\kDg;_³Û¸.éf¢lÖÝôël÷+¼zplV^Cø×‘Šštùy åYè5ÕªÓ\A^­ñw;t¤Ã=ŽuüÉ×7êé | „Ž©‚; ´±¤3‚k°t£Î8Ö¿=r=ÉŸÔi³g‹VÍy(zaÆ)ÉA¾| øûCp\ £Ëµ>%dd¼¨ÎÀ×@{%µDrñÅÉ7•BA ÈPúÙ–)†FT=£Ä?—e¸`¬ø†‰\Ë/Èz×m„zÆb=H¿ÛZGƒ‘4bx‘N¿… Š %¤V¥5¾×gÒYÏÝÀ¼aÕ¨t8.ë<Á?Ÿ:ŽßµŸ6¹V•Îr\·òT°µ |ý •@ÙG:ý zMg |³ÏÍ£É'­D¾!CÈÒZ»tþlH«àÞ‹<×mˆV DÊCÒÛXÒYE_ݬ³"uZ®‹¥Y‘¿pEw¤1£R+ª3ð5ËËÅíÆ¤oG~ú˜}Øæw» ¾’;‚ï»´þ=ë+Õ™ÂÀÂ_,׿É_¨¬I8ñ_ºþÁëÍÜ«æÚx™Í=/p®¤ÉåÝý›ý§Í=-=#áÔN­È‹øP¹ñ¹ÛñÛóã=öo—R6 >fL¶zæ5gŽœÛ‹„t&>A éÌs q}%CÝütËÓ=Ï6–LcòÃôÁuÀu^v¯Eœîœ8ÌÕ••^?=2ú? &9ÆŸB¶»é¤ rž¸øñÉvÀ?”ÚGó) &&ÄÕ=·—ذa¡õ·õ‘úŒ|²¿lŸ,­µKg€¿°{-™ˆ8W¯0kÖ\f—Etiºä°yñ’Ë“w(ÆÌqyŒ¾a ~Ú³òŠ4ÜspÒÇ'K`¿{ŽÈ÷¹¿snÏTH®sn^ñ)¤³4.ΓcÝm\ÓŸ8³Îþýæ]üº8.Ozý:@ê?øÛýuɇAÒìÔžucÜ}nàžqïÆŠÎä~ú¡HÒ‹»­5:«Œ³ˆÎÀ?¶y©rC(yÕ‰ifüL²µ„$ÖÝŸ†á8ã/œ;vê³2t¾fÄÅõ¢:ÖëimØ¿çÍTjY!o¥–¥3ÒážÃv G`¿{^Šê | 8„õaÈ©4=2¬ÓýÜÍ‹þ0RÖé²`(³Ì»"ÇgšNA¶É|VÀtûî·ÝhÌ~N—]cþ4 ¡)|è*”®FºÌ[`ÿŽËÇ.kávq†æªÜéX2ù©ËÙo:Û.‰Ï‡4Ó=J— @^®úæUéZ\þ¿z£í" Á±;†v¤kÝϺuÙ ì²tF·˜MÞ…tzìn“éSšóÑ2­Ç´"»çAÖ” .þœ8 ™Ù_s=B£ßC°Ý?Îï2¤õ›ø|H3ûžy&ÝÂǣʟî„L °cÇŒt­û©§3é=paH;ÓùäÕZ't–h%Ë":ƒ ­õ3‹MF7‰¦ÏÈÿ]†YÔdˆ­/ÎøŒc§>CgR”BCÏNOkî¯!q ˜“Ù 8†%ëB­Eñ}– †%ZàDô@æj%Øø… ø•ýª.µtÌSáÏ9Ãçh„ê¬EYeÝlþöo"ýÇR1¸dù±Üòì–*ƒ(4K:Æ}bL1û¹ëŸ$ç~Z®á³ïྊk ï»Á,˜³ÀÌžRíÏäk!\?1¾ŸÈLï!îþäÝþd§ýÔi#érÓçJ~€S|,Z`’Q×XÄÇìÉëž´spq âp ºù3æÛ¿{3Û ì²tw*¬®z÷ ôRy¸ #÷÷ND…Eš9x¶¸ÇóY ÷š sâÄ/\U]ÿîC4„TÄä…%“‡ð?©ÅºkâëÁuü:…º‘:‘}¤Ç… ÊŸŠŸéj¸qŒÖ}‘™?ßùn]—SOglóq?Ë'´Sgþ3‰¹Ž¸¿îu¹·2Ã6KÈ«3¨ÐÚÅG̓¿–îqàÅÓ_„ÆI ™q3Åäq.¬×¸bÃâHãŒâš?vê³Î2Ÿ´æÎñÒñ»np,Ýz4Ovì†ÌK±‘ „HÓˆÐ=z áWjødåÕ`LQ “ŒºÖb+ufÛ±²š9óxÓÓ¤ioÓë_ˆÌÊU‘Y33êûåêéø;Ôm‡”ß½Å>ÿx4 ßÝF  ó.øƒ ªö¹×?~7]ž®H´ë>y®AW%ç² MÍ þY!$âí5¬zZËhÑi–Viþ¦i›},YºæýsÙçï·8û-ÓŽá<¿·ƒà^ªtæµKK·P«ùF~oi`=DÖuÜø9—Qi~ž ìËjé—8ˆ³×|°òÔi¡{îOwÀß­Ö÷€ûDœþý$ÔÒZÖý\°¬º×lt# îÅ„¬ Éd¨Ë&„Ök>XytFÖÝ¢ PÌy´Æ>ÿ|Îe[-q{BÚ®ÓšZŒŸÖ}ŠèLÖÝã ì]_âh@gàk ¾R%!‘0ÇýÈød• ЭioÆÕ¯&‘ù@b `Ô\ð‡T1.0ŠÜíN ®±ÀCÌ5¸ˆSœÔÝ2Æ$¸ÿ#ànü¬ µö øF‘&ÒÏÒõ•ÜxH;ÇùF›{LȈ̺¾Ÿ¿z„4Ð ÕÛüߘ*B¡‡›üC• q:¿-»$·‚â7)þœnU^Ü:¦Jgñ5ÜøYw©·ßŸ3Çu+pqã!V¶IÙºû‰KŽ“ºvˆ±¦3=dR&”¹_feëŒxÜýƒƒ£ûÜ¥5®ážÏºK½ý6Á$’„ø;T`nD„ZB …àÅ«‹:yvf :Dþ>Ñ¿¸ˆ“}Y:“mþ¹²?+=Y:³úp©·òTjn<üP8Î5Úüë°_Ö%d]ß¡¨ÎÀ×@®.Bÿ‹àY-ø п<áÓŸ¶M¦-xtÛ=ðýª¦ ûjdj’æ€Ï]_ù K¾ïÇgsøt ]h§œpŠy×Éï²]cî§xl·b|}ß7Šuw:zwê‡<>]g¾éLÛ]ǧ{èÊ£{ÏŸ2Á½Æ¬)³*>pò£K4ô©œÐõ{™ÃuèB;åcÞõ®¤¥Ú½¶4û­ÕPëšPÑãô²õ| ø½Ñ²_­Þ´„»Í÷‚\GZ¿i-wËÖï²rZÉ-¡k÷:yë´¿þëlQ&ôlPf.èŒûƒk ûCo ÓkqÜq•:¿]è6̺n³:³ &‘ŒÕç™|Ã-D¡Á8Zágg†Öx ²ÛäžS¬>Ü*⬥3fT4\JÖ´Ðb˜sfÑ¢$,Y÷q¯ê–ô¯Càøh-—å¼Ö§¢ø-.;»úÃά»Nê‚kÀ\8¿²•*û† `pñ‘cûÁåcGÌÖç¶Úu °e§VÎuuáÛ.¬úø3†›k4¹p= ŒŒ0ŽãzB­y»\Ä1?ËË5ÉGÈhó¯EÞÜ^׺~¯òàƒ•Z U`uæ},üu‡›üÞý®zž!=s ž%/<+ø'ëTXþ¼0ÄéúQ‚{M®'uÇq=— gãxªØˆƒz¥–ÛñRÁ’O1ÜúÅ¿yÃh«wí^¦ Q&ø¹ø4¢3îóXñ¬À×…%ë²Ý½~Zxn„žgP–ÎThQøÙ™¡5߈¹ç«?…okú×ñuFà{È¥Ôi¨ÐH4•3 ¢5ÿ:òCê„Ö:d›³$ìܹ“[íÙ³Ç6V¬8os‡˜[ Ùï>9ƒßõ!úxâCÄ:s?¹]\ìóÏc›ÛÆyî1ª|˜>>Ûn—k³ÎRÖ¥«-端¾j›YÖ;6¿»_BVúB!ëš¡kå½¾Üü…öû{¤™³,òhmölt&ZcŸáŠ´¹æwt8sfrKÖ“/Œêµ¯¯R¯œ—̬œÃê,=ûS+>¶ËµYg)ë2;g…ÎêK]Ã?&+}¡uÍÐuò\ÛãMglwuäÇãïϺÏòj }×ÓŽÜ êîzÇúñ³îãÇž]Ÿá»Âw{\¼dÝî‹ïƒÝŸk·ÅëÁm^|~è%~v¦÷Â×Z¢ ‰§Zg3a°­ë8¦–ÖZQ§]±"|ÏÝã^ÑÁÆç_7ë:9®ï†¢:#øZë»æšk¢ë®».ÞVÉÍ7ßl&Ožlÿšd>ðKcqÔLf„ÊM7Ý‘®åãû`>õwŸ2ûì7Ó&L3Ÿþ™O›§˜îMX³q9pä@º_gÂTsÓʛҵQ˜y}Ûžm±Ô†m7!£¯^ruº·’¡ÃCfö vªFÓ­[°Î̘Nž÷úõhUúÚÁÁƒÍW\¿Iï3Ó¦MK·6ϵ×^kêií½ï½Ì¼úêèpí)S›o|£˜ÎÐëg?ûvóôÓ Ÿë3§Ÿþ²ùÍßü®Í#0Ëõ£×ÉÒ33¯ÓÄÏ[(S,0 ðê«·¦{+áºÌÚÌTŒ¦cx¶{M—¼×¯G«Ò×z]gðƒL5ŸúÔfÿþ‰q^3Ÿþôw̉'ŽÖEîsÞ{Ù 1[÷ñÛ¶™þáa;,Ÿ‘c[¯×g“††Ì ìwFa=¶n9Ìü¢“:+íÙYGgÐÉ:í²5kÌÄ£é9ÚZÅñŠŸd+¯“E§¯?Þ¡¼UgJ;hÛ³³“÷Z…$·¥(Š¢(Š¢äC ,EQEQ”’QKQEQ¥dÔÀREQE)™><ÝÓ¿-ûöí33fÌ0;wî¬jzçwšK/½4÷pÅ^BóW‰ 72Ó§OO·–ÏxÓšê¬ÕYëÐßÑ(ª³Ö¡:«Ä×Z•µk×.{€¢PQ¼ùÍoN×ÊGµ¦€êLiª3¥]ˆÖª ¬ááaó£ýÈL:Õô¥G«ÌµÌÇš¿JÄÌßøFÓï~äªdÆ›ÖTg•¨ÎZ‡þŽFQµÕY%¾Öª ¬\ˆæ.š@ǪH4ÝÁX¾ª³îAïEï¢:ëTgµQ'wEQEQ”’QKQEQ¥d®å“à90_|±L·Œ-4ÝÃX¾ª³îAïEï¢:ëTgÙäòÁREQEQò£]„Š¢(Š¢(¥bÌÿIÖÉÑuŠIEND®B`‚pyclustering-0.10.1.2/docs/img/bang_blocks_chainlink.png000066400000000000000000000730601375753423500232030ustar00rootroot00000000000000‰PNG  IHDRFì‘ÅiÍbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEâ “Zý IDATxÚìwxTUúÇ?÷é’B&D$Á†!@°‘5XpÕ]4àÂÏB,è* ÐEEHBVEÄ‚ TXÈJ¤$ !…’ ™{L2d2} “9Ÿç™2÷Î̽çž÷œïyÏ{Þ#©ªªÒ P…cÇŽ„$I<UU)//§sçÎȲìñå!lC ìC؇ÀqÛhÓZnèØ±cDEE‰'+0rôèQ´Z­Ç—ƒ° °aÇi5Â(((ÈhìÁÁÁâÉz0eeeDEEë„§#lC ìC؇ÀqÛh5¨Þ,*·À¤Nˆr¶!ö!ìCà(b‚Y @#@ !Œ@ ,ÒFA+D§ƒ-[ ÿ4Äʰ ÈÉØXa°5›Qk¨„YY†23¡K9ÒðêÒÅðž@à©dfBt4 bøwÚ´óö"š¯š?ßÔÖÜ´ïÂÈÝü.] •0* î½ƃ†9;U’“EG ðÜ;9Åð·¢ï.] 5ÕtP!š6ð˜6ÍÔÖÆ‡mÛÜî–ZÄTÚœ9søôÓOÙ¿?~~~ 4ˆyóæqÅW4ÏM¶iƒRÿ°."MK* ø[=‰ž#›*Û5k,Ÿ¬($D]Áf‡÷9àŒËW}±—˲Lmm­hœ<Ê6üo‡ÎL –,K€:}: žÂŸ6ìÍÀY ÂmlCØGÓ¹üòË©ªªºè¿[XXèr}±m[^6º}ɦ]Er–X ‰üºž'…<Π±~1(ýû3o–áÕà»bQ|—-{®Áº§IªivÛhÂhóæÍLœ8‘¸¸8jkkyúé§¹õÖ[ùý÷ß hò÷+ŠrII’\î$)‚¸¸«Ço9±ùÏ‘}—‰ž÷@ëo¾÷ý÷CPÕ*—ï÷b—³»miðý÷ß“ššÊŽ;(((`Íš5Ü}÷Ý6?³iÓ&&OžÌÞ½{‰ŠŠâÙgŸeìØ±Ír=îim0à´ÍsªuDÍÁG_‰š3ÉJ7 R©"Àÿ_¼í?Õêw–”„¡ªåncÂ>šNUUÇ¿$öáj}±e[²ȧŸZ÷÷ÜÓŽ'ž8eñØ€=™Œøn@•d¶ŽKçÏ›“è¸7 ÍËCl×A †¿ùg:h¹<+“þK“‘TU’§úõüI«Ÿÿ׿ÂHM-¶xlÚ´`ål³ÛF‹°šuëÖ1vìX®¹æzõêÅòåË9rä;vìCkþ¤ÚŽ pí±õ¢ÐZ•••ôêÕ‹E‹9tþ¡C‡¸ãŽ;¸ùæ›ÙµkO<ñãÆcýzñ<­1¼(“ÏvEóöþ!Ì·"Š,ÙȬª§ˆÐ‹i5a‚†„”ë¸C²Ñ+$© q™)øÐóÝbÞ´Bs²éöíbúgŒCRãw¥QIpY˲»¹*­´´€öíÛ‹Zi…²6Wƨ<²5…ß:'rÒ_¬È¹”ÜvÛmÜvÛmŸ¿dɺvíÊ‚ ¸êª«øñÇyýõ×ILLÚˆ°j3%£©›>Ó8ñY ]õ¹h„ûmêt²jê½’=w~E—Ÿ?rhà¡®c$’Õh2—²à–cw-ÎϪ( O<ñ×_==zô°z^uu5eee&/Oâ· A8ãhÕ¨zÂËs…•»ÙÙÙ :Ôä½ÄÄD²³³EáX êlŽQ9‹™CšQˆÂ> (n‹"™JEÖàwú˜C¢HÁà‘•¬ø–j€Ê¢å5jqÂhâĉìÙ³‡U«VÙÚF“m ¥î؈GòÄ¿£é³³e,ïoQÂhÒ¤I|õÕWdee¡µ“jæÌ™”––_Gõ¸Jüa§ÇQpl傸ÔV Ë÷¶š-Wr*ª'Ňœ²1kýR½¥ÊªÂð¯RZ„ç¨E#UU™4ikÖ¬aãÆtíÚÕîg|||Œ»!{ê®ÈK×;\$ ƒÄ4»Ñ©S' MÞ+,,$88???1h°À—“¸»wŸtœ`bÖ†*°Úçá-öá±ø–èHçŒ1–HVîßbâ9Jä׿9ŠÞIâ¬þÜðæH3›r6Á@ãóeUOû“—>ä£E_Oœ8‘•+WòùçŸd\bµr{:ktÌ<<^dèlåÄÇÇóõ×_›¼÷í·ßosÐàãããÑåVì£eCûûù[чçÕÿaŽÿl!Ž„}x$9f dUOô±lªüC©ö ä ªT×ÃN ÆëÒ‡|´ˆ~uñâÅ”––’@DD„ñõᇊkC©êăV‰)‰—šŠŠ víÚÅ®]»Ãrã]»vqäÈãhö¡‡2ž?aÂþüóO¦OŸÎþýûyûí·Y½z5O>ù¤(L;8oÔ•®z±8A؇‡–{D,úFï)HŒY7ЉŸ á‰UìZ’‚ùü…½¿- R¼Ï–ï_v(‹à2‘è‰ÊÍ"ðôÅ›bk£¦eÁõLú•n@½€Ê]paؾ};7ß|³ñïÉ“'0fÌ–/_NAA±èÚµ+k×®åÉ'ŸdáÂ…hµZ–.]*–"Û¡>Á㊈™Œ-xÙ¡F]¬HöáIø–è,È¡""–ð]ëMúɰ’¬~j͆¤Q$ ª^,–jŒç׋ ©Á¿Xø ©ßÖE\½ÿSdUAEâ Tä´!(’Ì7÷¥³§Ò/Im%ª¤¬¬ŒJKKÍâdYvÃì¾í1l}`N$zò(t*G‹ DF¾ÝOAUO_ôûuKÏÖV]ðDZŸmØÎ|=¼(Ó˜ËÈÑÁƒ‰>íŽØœJ3d¾.vÛöÑtûèÔ©Ó%Ë|íº}ØÏ|ý]&½ß®Ë>]'W¤Fý…CKñ% ÛÆ¥1#ã ²œØ.GEâäe½iø³ß±õÛ 2éÏäQÑÖ`§Ó¦£ªeÍnm´PÚлw¾eoQyš?†8õm*Ч÷N"½mÇPlÝ!Š^àÖž¢† õ¨jê¦ÒDŒ‘ÀšKI¨ôß<Ÿ<*!³ù“B aäA ;ùkDÃ/h½ûhù<,Ù¥ÏjЋ•i‚Ö?°þaU“¿CŠ»_oö¾®Ë óíC$™°ç¯ÏX\¥Ö”D€”Ð5o¿&„‘²;`ï?l1&XFF¬L´nQ¤*ôx÷©&¯f>Ñ5ŽS1qfï—‡h Sj’¦Niøjx:ãÞ‘³Ù5úU£pR$¹yVUëõÛ¼|í†yky)*ƒçŽ&#;9ÇyVŒˆ­—°j-Nsiü¢ÿ\|-hÕÄ£w(¾¨±m4^±¶ýáEVÏßÕ7‰?bi2—“íc(ÑÂÓØ?|yƒFT˜Ë9ïŸèôõ˜¡Ñ@Lóh„0rcTfgÛÕ‹‚´Z Á×Î#GåhQ€‚ÖKf&Pã’m4ÌItèÆ1½E )Ñ‘ÎtЃ¶·ŽK§_Æ8—l@hÒÒ@Û¼1•æ†t¬ÑñÜÑñNe¾®çˆowQ€‚V‹«Á×A«F§ƒäd—ˆ¼…ë_ÜÊÏ.o¶Ëúóæ$FãÚ ñƒ¤æOø(„‘Ò«r‹ÍL¤Ö+liw§(@A«¥ØGËÜ®NÇà)Hl÷Š(hä䀉\÷.Фa.þv=E®°/³€mK×`é*{Šåú‚¦òßöÿ È[ÄPZ7_vLâÙnέ¼Yä;EÄ Z/±± ;.>$h$­aõ-iä_ ¹Ì—w6ØFb[ß l¿.Å®xI§/nöUibK ˆ$5Å¥ XÞz U¤Réô„Áóð"AvÎ:”º|ÕbKaÞ6_›g¶Í9åÐÔ LßøÛ9ó,8±íÁ¥¶ aM·÷Ü$À¬ïx„j2¨2J(:Yù=0@PÉES'Šj°½Ë™·«²õYo"QˆAoü½Hò(uȆ`<þ,3ë3«*‡mRl r‘p½r1aB‘Ùûm+t¼ü~4’“_«þËâŸá¶]¡o¿Ò¤=z‚ o¡$$Ø^Dp{A&Òñ8â—€yR5¥‰8éoÝkôé§Â6î€?~ÒøWH¹Žç—u1ñ÷H6D€æÕWÙ6m𓼲 "ÐÊ€cþ|ÔiÓì:d C:K×ä”·á B­^—-›SinFÇÒ‡÷£i,ŒÊÄ>h‚ÖOèY“$;‡§QõDTŠT‚ÖÇeÇœŒI}æpB]P¦Ne:^ŠʪÂõ;6ËÏ aäf…ÄZ TsäA‡•І_ÐúÑžq~¿4™‚‘ÜQк°'“1ëG;÷¡^½ZÔ=,¼øvérj§ï¼m!åM7ÂÈÍ8¨åý›ÒÑ;ùèô@qˆhø­_¬Sö¡ïö˜gsM p7BÊuŒÜ˜ìÒ CKãl¨–ßǦ²yÞÿlú¾dT®ßÑt¯‘FnÈ–«’XuÃ[N}&¿}ONІ_Ðú)ñÕòÚéèÌÚ²9ê|Ñ}ª(8A«"ì´å° ›“j’ñ-7mEi÷8öŽIµyƒw¼Þd¯‘FnJÔ‰ÝNyò7ÚVˆ džÁ×IŒx˜ç¯Zj'>a{Ä_E ZÕ^(ºøZ`ÍŒ­|?z±™]¨óæ5{éææLX›-«z:œjZ؈FnHÛ 7ìËpê3Tc$ð(J|µ|>‚%—¿ju„©aU‡Ea ZödòäêÈ(&u_ÚçÿʾÁØü`Š\¿Ù«Ì4¼ZNеº|›I¿¶c¦IÉvM ÂÈ éXšãôæ±*PÝ&@žÀã8ìw¥ÕcðÀÞ™´¯ÞTAë Å$¶HjÔáßô~ §t¸>‰•/æ‹'³XùJ læ!ºôø–èèýv²Ù¦³ =cФáã[ÓL–컂Ècä†Ô¯Ls&¨N:”æHxœ(@Çp{A&SŒ·éz¯_ª/‚¯­g8c³o=ÁE¹T¶Ó_î@`AŽ™(ªgíà¹èÂã¨ñ Àç\!åº&‰#á1rCNjY3`ª( À*ÝK·1Å|F*ÐíÔvQ`÷'5• ÔØ­ïayÛÜîÖ*"b-.×—;6?ETávþoå@&¬ÂÓéÑÄý–éòo Q‹åK–Xß¾c?µü͉oS€¾I&ÿ›G8S pon/Èdòñ%¶“€÷<ÅÚQÂk$p_t:˜>Ý¢wTåü”š øl&Ävo–ìïúg:½™ÛµŒÊ›§#Õ½/« ÷}“B¤äÒo aÔbQY·®ÜêQŸbêCÑV]‹–šÿGþÍ®{ñ7:ˆ¢¸5õ™¯5NøTe1&po¶l±Ò“˜ïRÖp:Í8ò—$:ü–E—ïß·ÐÃ5Kªžúb*ÍM©Ó²÷ñt»K‘*êË ²EÁ Z="óµ@и~7ú[ÖPÖÑýê»o‰Ž¨ïW:vÏ’L®‹G#7&X»g®røü±ëîgàÞLQp‚V+™¯7wyPx‹îÍÇ[|[ª{© êûÁþ¸·ê°õ« ‰œÂÈ9}õ »ûÇ4|Ø#7¦4Ë^2AKå|ækÇìBùX²/p_¶mƒ>²YÇÆußú§Ü¯¾[ ÀVmôwK¨4Ä^ aäYT‡i9ðÈ\‡£)dU/= Z=_G$ñCÇ3Z˨\qRL5 Ü”~p®ã¯‹1r7ê°ëSÖ‡"YíÿÚä:ŸB¹)>Å:ÚïΧX‡Ïé"# °Äf²‚Öά=#|bSŸ ¬>! NàžÜx£S§»kŒ°¿M?Ì/eqm©ñ°ÚÿÕÄ8ŸbUš¹.“k2€ª&³Ç–©_• H>Òô¬ AK¦{é6J>vx°PO…X‘)pSââ`ÌX±Â¡Áñ÷ÿHsË£zΆj9ª%™üŽ}¸2ï[‹çeàã.ìý&ÿüsÞ{ï=EaРAè¬Ì›WWWSVVfòò4мµür‡CçÞql)¡g…Mx‚m´&û8‹âdîêòõ–LE[-? Ÿg·ÿSd åáŽÝ»FnN§µ™\7q áY«{ànšØË“‰ç¡‡¢wïÞ <˜O?ý”°°0ÒÒÒ,ž?gÎBBBŒ¯¨¨(+³áÅ™ÜPú•CçjÐyFØ„'ØFk²_- ¯IwJ½Žh[_º–â.}m®?S$ ÙcÒ¨jïØ½ aäÆxéè><’R¿tß>îœØ«5ŠF£¡°°ÐäýÂÂB:uêäÐwxyyѧOr­dt9s&¥¥¥Æ×Ñ£G=ªŒ;ÖèxúP²Ã› ŸÚ Q9=À6Z›}¬×&ñÐà>>›¼<‰¨³9Èvº‰†jjPyù×áLý}¬¨ ­Ü6Z£}<”ó,#ϳؙ« Úþ#ÓÈ—Zg—ï]SaÕ1 H2%±Î¥(ÂÈ]+B‘íê×:WŽ\ÈÊW·ªÄ^îÊäÉ“ÉÈÈ`ÅŠìÛ·G}”ÊÊJ~øaCC÷ÐC&¨/¾ø"ß|ó þù';wîä //qãÆ‰Â´ÀQ_û±’… Vнt›(@anC÷ÒmüåØ «¢@dV?™Íïñ­·í?‹b¡T`߉O¡Õ#¶qSüóOô(Úý߉Bk!Œ9’ââbfÍšÅñãÇéÝ»7ëÖ­39rÄdµÝ©S§?~<ǧ]»vôíÛ—-[¶põÕW‹Â´@‘·–¯C䎒N录€¥?q0$N¢° ·`tî‹v브‚WMëN^ZÑVË/7O¡oÖ|3›¾jÃ[œîÒË©©4!ŒÜ”ÀÛ{ 9B}е˜FkLš4‰I“&Y<¶iÓ&“¿_ýu^ýuQhÒ±FÇm%ﺴ-ÈžëE Ûp BÏêP²ÖîyФ¡4¬õÇ•êbs]Ö|3»—Q‰_žÂ±kEðukÆ»HÇåé3œjøIA× êlœË=£ë#Æo‘Àmè\™c7O—‚ÄÆ‘iT´mýâvÅ­ö‰²ª§Ç³þ.á1rC‚÷l1®Ds´Ñ?zÕ­¢à!ÆHr(¹c½}<ÓóK¶†Ý) Oà6òÙ®ç›F¼Ýªc‹LÊãòm΢\¹)ŠŽ1ü~ûT!Œ.-dÙÏêÑHU%…dòÍ2Ôú‘`¾²âªHǹ„dýû:¢fF1ÞÀ°Éb,zrÐßÈq(Ë.Þ¯—xä·$ºj?[ÂHà>”øjYuùÓŒþóe‹b@¼ªË=¦<Š¢ãÈéu±»?¶ºoZ¿ÕÓ9Š_ƒ'pNøDÚ\‘vý—3Éé;Ú#¦ÒöÜøOºïþ؆­«æÚF-&ƨ²²’^½z±hÑ¢Vÿð¼‹tFQ ) ]ç¦à]dšÆþ¯'2Y»7šôÜ!¬ÝÍèâ…NÇNX{è²Qº)LÏM!¬Úô·ýNèè¸7 ¿b«{qEåvT§mBÙ¯nG»³¶ëµª'¤Øsêµµeûõ(Hm Òb†ßîº1“¸Œd$UA•d¶OçБÿHÐòéX£cÒÑN¯HÓ£!ßO,N¸µ§mÆÕxÊŠ´z*Újùé®yÜðÅt³2Qƒ É;ÜwÞðlT,j£]áUIÆëT‘ÑkK­™wHƒŠhî=ºõÈè|cê™bE’ªÐoiŠð ÜWV¤éÑðúUibMàV„žÕq×Ñ·¬Š"øiø\™F«ç—[¦ñã]©&ýdýÿ¯Ü”Æß¦D³9³u #wÞ°¦£–C3ÒQeM(’•ØgGÒûîh¾È$‡6è­Ty©™¯GB¡ÿéõÜIYâHYÑx\L3Z>G}c­Ú5Þ¸â-ÖuQ{ѹ2a²uéç‘e“Ówjƒv@jÐoʪBüŠ"m  ÜV¹ÛF€ÞE:‚wd=BÅw%±ë³Ãœ½Œ{žIŠB×9Éôâ?ßѬנڨÓs“™»÷c,®H2·F·o Ï‘ ESä­å­¨yNyU˽:ˆ‚¸†åú¶ÛûsÞž¹ ¦m±í²¢'ÆÆq·]®ïããƒ{ìl²M’(=…“CïGs¦ ÕÌC#© _q©ì«f½[ãh ןþÚ⼬¤*\ùß…†¿—ý“ÝÿHåÀðó¹ üNè:žcS ‹•Ó˜xô)»Ój ¿‡Ä‹B¸·Yb³M— ÕobÓa±(’ŒleÛ,EÖ«X/=‘ùº9Ñé +Ëðof+ÐT•Î+çsÍ#ý¹jâbžU7•済Q/Ðå[Ëý 5ú»×ûÓèþE*`Ô>)š›_Bg!3SÔÁ%çýˆ©ÜÝ;9Ñ‹­J#ø&â![$p;þvh>£½l³Ÿð´Àë†T´Õ²}èL‹}¥"ÉdI3Ëß×"…QEE»víb×®]:tˆ]»vqäÈ÷x™™ C†þ­–V 5!õShªäØ£P/ 0rF@õú`ír·™jkRRL„¡@p©Pºžéy­6rð—‚÷=+ê«À}ˆDOÒÁévÏž³ˆ5δ·XF»ïzÎ-Fmß¾>}úЧO&OžLŸ>}˜5kVË:$'C½RHN&…Z¤3•v…Œ¤ªI™mÑsd©1¿ÍQÑ%« ]~\i6 ˆ^¹"P[piéX£cæ¡d»Siô"‘À­ˆ§ÆnSU’9rU¢Ç–Qàiz/?³RRü^öcw%UUÕÖPeee„„„PZZJpp°éMJMYÇØTï#8ÃëVÄûL¥ IDAT¶é°•c¨%Œ´ýókëŽ;“˨þ;k ¼I¦ÆêçõÀWh¸½Ýß°t­*0oÒð>¿Ý‰])w8㺘kT…mÕOĶm®Æê)€Ÿ«ã9ÀÛÅÏVÛýl5dqÊ!Û˜F tðw½šp¿RÊÙÇå²RÕ2a.ÛGÀßÊ'«êž5j°ƫةÃ5VŒ@a5Uvï+6›ý¾­ß­¶3ì–m”Å;ea»wU†H’¯ÙýtëVâÒ'ÿøCK÷î®MC<Åõ×»¶’ô§Ÿ´ôìiûwÛÔèÐï¶ë1’€yœaÛåû(ô²=ípà@·ÜRàÒ5oØÐ‰{ï=îÒg?ý4ŒÐÐb—>[R&ªx“ð'(Èr=-/âî»­×áÏ>kǘ1–ÅùŠ¡<ú¨u»[¼8”7Þ°||ÞcíQ8câ52²†‰óðp£­/ÆŽ ã±Ç,×¥7Þå‰'¬_Ó¿ÿÝ™>}ŽY<öË/‘<ôP¾ÕÏþç?!f"¤yÚð*+Ïžÿ®|¾WF#)–û(˜óÈ—¹¹Ú,}z-pªC …]âØróÓ.ÝSÃé>YU¸ý³d"tÛD¥\4мµü»“cËö5è‰>'¦ÓîA>fuÊ0ËÓÓ°Íßqß\»ûµF¤\Ë1½FÁ(i8ÕÁ~@ºF.p{A&oÿÒßlž×YÝ«{F½bx­ÈÒÖ(†6^7œÈNž¯èëãžuhq|äV·žBP©a¤]¢eÿµ#øúî Ic¬4)øö~6›ý=îkr°·ŒÂÃéé½C¬X\<öù÷uÈ&õhÈóÛ܇>=­Å%àDWÏLì¨ÆXØUÂäÅè ¨¹¢l[Ýô™ƒʪ(’Øž¼”S1qlŸŽR—[‘5l—Æv¼ÍÄPCNjÙØ{ªsEÕÓî„éȸÞ{ôî#Y¼5õ0ËÅ2|ùàG¬½ï¦‹£FÂL ¸ÐäyÇ¢wÀ>¿ ¼Çî4š@Ð’¸®ê«¢¿Ú(µU £H-5o¥[]È$£:4ƒ!„‘Ü^Éâ_ÚLÃn*~,{‘TIâ»Ù?7f=4$‰¯Þ<ÌÆç²øêÍÃoغ©×ã6w6»+nÄò-G.O <Ärçð{ÜXö\7Æx×®Š$YÕÓþd.A¥:¢ÿÌ"IpA¹¾b=’û€[+>%üœ¨‹÷a§ÿ6w2èüÛz-eh"H–§ å£06m Øpo#ª˜}ªu\Sº…)ÇÛ]&i>"•L˜U`÷ß_åTLœÉyg:h9ÓÁùQ«£²HAæë¿¦Y?öøïÈå쌟ˆ6ï'ü*KˆÏzÅf`¶ea&‘¿¼s ²ª H2o'*˜ ÙéX£ã9]²CöªA!ú\®ð ܆=~qüâ;ˆ>g·X 0Ž_‘±kEœ‘ÕAºBÕ†T;Z­FÎò•dü/Ù…í.d Þ!É(vžËÁáS›åÚÂNç8!Nšž•¡°K…] ‚n×À tÎË&úôÚš¬êQ°î‚Tmý'2䛯4í²ªpËúi¼ˆ¨h‚f%º&ÇzDŒ‘ÀÝ?§£×Ùl«cYÑT˜ë‘¨>ÎÈž8j†œ{„‘˜J³…NG§]EFõª*d?¶Ê0MöVïšÖl—×]·Áñ„Œ¨ÍãSÑVËÁ^#øöÞÅ,™q˜’³@ Õë‘€j¿vf{×HÀ3TÃüù¢¾ š C|‘ýæMÌ OÞ" ë­¿"kDœ‘FcßU`Õ©!°"ŠHOwº€T ôD÷xНIpiªÌm+t ÛñŠS+á,_7—H:Ú-í´aíÝKQ¬loræ—L–˜6GL›&¶4†ø"Õ®­Î ‡OÚ&‰¸§t$PC•hu¸^ dIóHo‘qÀ3&‰³û³/›ƒuV¯ÂÈaê÷={é%§EQvû;Œ9£kíãÒšUÕÓµ`‹ó1>Èåph »ú&ñæ”<²¯Ÿjf¸²½Þ¾úJÔ=A“éX£c–Î~<  xÙ]·&´ ®ÎÎdì ÑdQƇyý-Š ž»{y Éœ³íŸi£N4ªûþ'uæPnzM!å:ÂNçPÜ6–Ò ÖW¤Üûý¸¢XŒ3òa´cG¾CgúlÉB3jˆK¿¢W<üG:•ͳۢ*•®=T©IIǬ¿õ×ù¨Û¦95•Ö;áM½Ê¶œZ¼¸=ŠrÒÅk`ùrÃgû®š†¼n¾Sew_ž߼Ȩþýé¸ÞöõN˜$Zê&2¢,“—‹ÇÛÿ;õŸŽá©ðåFÑtÙ¹{Öúÿ¦’ôC†m7ŒÛÖ 1?tËÚO3NŽ ¦°jÚ39èüb)öѺX?WƒžÞg²Yï5¢Éå8ìX&“÷%#£  óÚUé¬ëœT7PÐÓ£8‹c±œôw½úÇÙLT6ÇÕ#3%0^‰&B©÷¹m 8÷?{ÝÈw¢z7+ÿW=Ÿ—j¦#£¢ÎdÃeIt8£ãŽÜ…üõȨ(Ȩø nÊÉdlv²±][ŸÎwè鞟EQH,§µ´­Ðѱ4ÇøwcÚç˜ÅgZBä61›3‰_nømU’™‚/ç€{3¹ñü5}8$7ñZUn£OÅüx#¿ĵèg¥Æò˜iõ3&̓,CLŒ§zŒ§¶«cí Y~¹v Ç"/|eiW©ã¾íO9%Š$`ôæ~J´š4²¹ð?©ãêu œEÐcÓ›&™ºoz/ÝÕ‰T¶£â E$zf7EõuåÞŠ¼2‘+k~ev±¡#Vê6¾‘ëà†[¿HF¡¡2½d:AúR¼©æáS Р¢Gf~è<öúöå°W,-ˆ¡+*vðhÞSÆNÿÕ˜tÖ†;?%°ËÍ’y½`$©çòx§ƒë«ECÏ꘼ïüôŒÂä}ÉloŸH¿“ëYO š† ["ïç‹Ø©üÑ>ŽöU::WæXLõÇ~FO{½Ž[k¾äÕʉÆßРðZÅxÔºr×#qP¾š+•½Æ-Š–‹ŸÍæ%šV=›GjÓÔuøç®ñ\S’Å`ÝJ/¥ŒB:gÈ<¸œ±Ù ê…ª0vËxÆ ¢ùb ?_ñ¾k)+§óz"fq:Ì0ñ«(F•d$âH~õ@Dõ~:íËâœO Qa!P*U¬ßò ·î˜k²:xä†d6ãK¯«9ÒŸsfž¤eœfìÁþƺµÛ3º~L‘wËlŸÕH-)ø‘.ÕVMK2¨2ÿYéç…0j¬¸#´œš›N»éãÚvW8Ù¶cï¸(¢ c©c£³Ñ±ª'¬4÷‚ £à§ò=Iþ¥8ê±q!?ÿ-UTÌ D,ŠEw³$T®eÒé—ŒËÞ>Sçùè©—Mž§…é%Óê¼J2É„p¸£0“鹿1kP˜ž›ÂÖ¶‰V½HktD×äçÛ¨v|÷B•é%Ó•w:8çé =«ãêÓ[¸ªÔ|úNFáoy ø›îó{7䝿úüÕä†ô£[éÎ:“Ä—±SøªÛãœô×r×Áù<¸ç)dž8eQè™>•«”½&%0–jض ââDewÙK”Ê‹5Ó-Öy•›uï[ñFÂøì‡-äRMþ?ðÀ “áß7g4*š· ÂI¤:û°×Žö©þ™­€4oˆE!%·nŸc±®.¡ þ;Òh‡ ›®›Â®î÷smÎÇ åŒI[Ý»êgþ»7еmÿÁ¿¨!îÐjªOPéÛ‮øê+( rmê°¹X&yÓsêAâ¶,dàOó-÷éÙÙ0b„F+qŽ6‡r¨íëðgd ×ž•,x,²à‹÷ð‹BbQ$ÙD©ØOö¨—4‡\ø%œeáæ×ç*=¿{=C^£ åÝk0 ÖXôßTùµÃ¹€¬‰]KïiPHãÊ·ñTî83¯ÓùŽEÏ}Ç2êØkF/ÒâËæâE5mjt\_±žçtç§•^Ò¦³¦}Ñ59N'b•€©%3ø:x47T®çÅÂóß»¼ÝdþÓîq4úŒaêÌv÷Ý¿­þ^Léöó"*Í™ÏðœùüÞá&®9ñ}ƒc®#¬]+„‘‹L¡ŒÙ5Ó‘šRþNžÓX89ó]&MÕ²mË!Ö>/£2dç|nÞ9ßæ¹wž~Ÿ;金fý‘"ɼ30ÿ\âç8`ËkέàvôÄ}ûöqùå—·Êʰ*“ˆøh:ŽBD|4ížïp!Ê(´?yqwæ> %»Ûƒ&[t8âÝúlÀÜ î-¨j¯%{ìùýßÌRHŠƒUOVõ5oùîÞ½›Ù³góöÛoSRRb*êÊÊxä‘G<£ÕÏÌäK*¬Š˜>ç¶9üUΦmŒ9ò¢ÍZ £ŽÍ7Š3 O'‹Öíf–n¼É±çt)t¬Ñ9œÃÈ|„¯0¸â+£(ª/éÔ|6þÙ…)TÐëd¡gut/ÝfW¹ÒiÊ@¢¨Yðñ¶á Û¶1²æ}ÉÉ÷›KÜ5ô€=œL? ê‹ö'l̰HÄÇ».ŒjjjÈËËk•ž¢v3’1E’¢ ©Ž7v 2'Û_ÜDZí*uÄÿñ®Õ)(k÷HÇ‹·ãrîà$>™˜uOe±ýþWM6ÉÍ›Á׳þg1§‘¥Î1r_ó…~óÍ7ôïߟU«V1oÞ<®¼òJ²²²ŒÇÏœ9Ê+.xù,Z´ˆË.» ___ ÀÖ­[mžÿÑGqå•Wâëë˵×^Ë×_Ý´ Ðé`üøfË×álçQ \ú+»ß©±áuj,J4èéR“˰ӫœNeQÏóEÿ´è%Ó ’J ~ÂÊŸ¢xk{ÿ&‰¢‹JLŒ°  àÒêd¹óàTAê¥ ‰¨ñtiàÀäÉ“mžX\\Ü*Z›C9Z×wÒj5© ñùéu \‹1Rè¢mäD&\´ë¬j¯¥ª½–«8IVV–ÅWFFFëS±u×eg¢6L~"AÙ¤§Q%T$ Gµñì½z¿_3â¢{Šê¹ò˜k#b a¥¹-¢ìËÂcQœ¸‹žß½FÀ©¦oâããÃéÓ¦bõïÿ;K—.eäÈ‘¬Y³æ‚ÞwMM ;vì`èС Ú ™¡C‡’mñ3ÙÙÙ&ç$&&Z=ß!´ZÈÈ@¹DÏß™¸gâ$ZŠiQq)z½aT,lCp©©O¨Ø=ÏèìW$ ŸßžvÉÄPCJý#\k‘/ʪ4G¨j¯å÷aSh¨J³a÷îÝÛ$n¢žQ£F±téR{ì± zß%%%èõzÂÃÃMÞçøñã?süøq§Î¯®®¦¬¬Ìäe‘“'Ý:°TàÄ(Ý8#O° ‡ìcР粄 œkŽyk.Nv0„+Àü Érž4cŒÑ‚ ¨®®¶úå½zõBQw}tér>Cr$ yTÙ‘JªÂø—Ÿ%_bЫÊä¯k§8ñ»5H.X ™™¡–…ÕÜî´(‚düXön¯ xÍ^ŒàðÙ†çàX I-ðÏ×ï!ß,ÂÃ9±þè£òý÷ß[<6zôhTUu{ïèœ9sø×¿þeû$¦OÂÈSFéë×[í<É6²­^}Õ°±µ Ù¨Rôz–EEYt¼¸ìä°õÌ«©×1ÉB?Q`#[‘ñH§NÈÊÊâæ›o¶xrZZ)))nøH¼X²ä|JçYh^·ß2~Ü»|’™„N)séW›6wÈØ±%µ«Ô¡|ÔÅ©U12C¯{Ú¶ßþóŸ&\³„ªÖ8÷¡ÔTT;´ ì¾v ݹÜB#×Þ©Ÿ»çž{¸çž{¬Öó¿ÿýï”——_°šŠF£¡°°ÐäýÂÂB£ 6¦S§NN?sæL“ÅeeeD5nŒ.-µ'‘’‰‰§ <É6¶©SáçŸQ?þX š‰6‹“9a™ÍÚOJ¨6"IRgžˆû7ò¶‘úC‡b ÚšJ«gذaL›6sçÎ+—””0|øp‹ÁoîHiÇX³ø!³AEÝâ[äõŸ в|sñ!*£vNcØž–EzÚ4¦ágH×nõÚ¡Ïž÷.Ó5ÛÏ^ªzîííMß¾}Ù°aCƒ½Â† ˆ·\ßâããMÎøöÛo­žïããCpp°ÉËÌ[ôÚk¢¥n\°`ãŒZ»m8dõ6òé§­FyêúºHôD•ï±xì*!:ÚšÁž0ÊÊÊbÍš5ÄÅÅñû￳víZzôèAYY»víj…UÙNËÎÄ™V+‹ŠÄ÷f´èlË{"q6ÄSîß9ƒv•ºu/¯Iþ¬K˜gÓxeUO‡SÍ´g­ž—––^ðz>yòd222X±bûöíãÑG¥²²’‡~€‡zˆ™3gÏüñÇY·n ,`ÿþý¼ð lß¾I“&¹v99V÷j¹;u ¬#v"¶Ã£mÃÍlä’×+gèÐáâþ^f&y1rÿKÖÛE1xSu¦}¢Ù$Û AƒØµk&Làºë®CQ^zé%¦OŸÞ¤yÀ–†F_m±²l¿ãyöß0®ÅoA1ô÷….%˜Ó ^ž{I÷¯1SõªžÛ²lO§)’†íš/hïRÖó‘#GR\\̬Y³8~ü8½{÷fݺuÆ Ò#GŽ Ë²Éµ®\¹’gŸ}–§Ÿ~šØØX>ûì3×ó´ÄÆr]hø/æ2ô=½ ÷ª»hw2—›Ö?m2Šsæ:Ü©ÕÒ##;µ^ÓÖwIhP ¢ÈÊêa6l¤™D¹ÔÂìÊø›’*.'Cuºvï6Û“ì‚¡ÓAr²1~ÕfÙÖ{S؇Å裃²}ûv´Z-ÇŽãÀTUU@k à”Žžß™O%(H¹öŽ/ŠÚUê¶wKŸÕK ƒbZÔýLíè–ÇÔàŒfòSXޝD-æÎkpçµGH ˆÿLÜÊg_MVâ+ks¯Ÿ3*5¸¸KbɌìŸÅetâmÿ©|é;‚§‚s]ûÃ<ðÚ¹z=2éaÏ ¯{êÑ8]NŽúåf_ó9Á}]Á/xÚäS0¦`.¹ÈNwDoõkù/úý¬YlG±!xl{…dþœÊÁiKMrõI´=ò+%ÝÙ·m¾F@½x9ŒbcO¹ XÒX¸p!Ÿ}öo¾ù&¾¾¾ôèу­[·rï½÷’Ð*êü9Ÿ@Ó„Ž DU¸éý”fI&x¡( ޵¬lÅ7­âûؤ×iìŒ4îûo}wg\¦ãò¼¬f Âö„zîˆçh3>h´lòIt¨©Uq-fGòü®¤È[K‘·–Íxq<*Ž=G°õæ™l½qª…ÆI¡mÉù†´ÌÊNާìPyñ²wÌÊLµà-ú=$Ÿù¸ö„•ŒJ™W3¹¦AOŒ )<…mp~ºÙE$N"5i?=‰ÍWM`æ?޲ô–]ò2ý>kºQS9g“*©*ý–V˜oŸîR∠ÙóÌ´ 6³Òøí·ß¸í¶ÛLÞóòò"55•o¾ùÆíëû?er÷¼67Š••æßѽ99 ey|:zIãøÈèP‘×" { ȪÂ=_ã©EQŒ[9„éoGÓwwÓ¼z­½ž;K×Ú»²BAbJðRþðŒÓͽ G}¬7Š;nxÜ< ›¤át¨c iFË”ÀtjqÜ&ž§6ðe„=MÒåY »ò0kÚ1çM‘·–;=ŽÞB·¤ZV¯tMç¿Dz“ã{‚™x¡^¿2_-%¾Z^¿2ÝäØt|mz©ôhØxƒ™ Ò£1xŒ„m¸4h =ݤmRø°Ý‹Ï¾q=ȼbÙx™ ÅBÝT9?ªH²®La!ÌüÇ>¸i1§µüÙiÓâE•5”]cX矟ƒÔh–DVôÏåÐ$¾{é8³Ñ‹jÓÖe¾î8ƤÎêÁ0}¯½H³Îì)If‚Í,Æ(44ÔêçìÖu=à”ŽÁëªV$ ecZô½üÐ=‰=‘‰ô;ôß>Ù¡ûÈ_fðs×Q-k*M«%…Ò¥³ÈªÞƨ¸‘Púo 9]]þÙÖ\Ï]áP›ØóÁºò9¯p¸M ;¼ã)ÐÔí)$…ðlÅt4˜Çà4ÞãL†W¢Ó(ò¶^ïÊC´¬ÿ[†1ŽH‘4¬¿7òÇëêJ¿$ö¶éÉúÓ‘ð”¨@zØ3l J•€¿ZÉï›×Y/’ætÍ`æ¡4èÑ#³²Ód6´¿?¥’3r~J%:ßóßõAlíû=JbOÈõ ‰#ô¬ŽÈ3¹äûÅPâ{þ7ÿÛ9‰míÇVoéI»®o1ãP2”º;3x#ôh˜Û5ýAqÌíšÎ ã5ÞÏ?4E؆«$%=n*#£Ò‘$ØíO‘·–}ýxNW_οµ½‰kOÿˆ= 2Ë®˜Ç§]§’`ËãÓ“‚FÕ£—4¬ˆO£CùŸÜùÛ+hêÃ'q¯²­Ûh:–åRé-ïÿœ”{ZžÔòÞMéüc³¡X¸€ŠŒUÖppJ5 ßQ‹*Ë&{‚*²†ŠN†~îTLÉø‘.Õ ©³?TÅ¢ÇKAfQ—¹x_F¿² üµ( zdVužÌǧØGËÒ.³¹¦,I‚wLD—tg+œY`2eŠ™`kãIø[š¿ÿuè“->»Þs$«µ‡Êª¾Å­HX&ù2ä¯ËøûgŽ6÷ò}O§@£eZp©eãâHAbjpø›7hK§‘Q‘ÊÝWWöŸS×8jx3r.ûúQ%à¯TrÔǾØCѡ-ÉåthŒS¢¨ž@µÂaQ´²ý$ÞŽ˜íRy}–ÄÏ!‰hÏæš [ ‰ã`Hœñïz‘%û²cÿ I$ªIÅ}1 IDAT:×èy«ÿ±Öâ9Å>ZpA Γ†ïÚ™v¯iŸÄO‰œÛ Q {)ñÕzVGDe.¦"·~ÛPôLüím¿}É{öÚå-W&q¶MÉFZ¬ÏoF½ÊwFS¾ëZæ¬úÍ(Šj:j98%n©ãhS'жKãL‡óç,Û {^žKaP ×[ÏØÿ¥…ÒUƒ.æ=öÅë\Vè–G>KÙ/½h×o·ñ}€b-›Â e—ోûàê<~µã ÷kµÔhàñÇÍÞöatŽG &Y­á/vά†»˜üïÒ ÎÙLÎÍÈòå¶ó>ô£–LÊUßÜÆðµSU=ËôÏ&0Ƕ¡n¤õ¯•÷5š‡ü“Øä“HßC€mC‘µNcGP;‚ø4l‚±CvD$Øò¹"ˆêùScˆÑÑØG°±íßšT^õñR‹b­YÇcïÁ…¡È[˯x3¬NÙ¹§´f¢' "œ¯ß¡·ÐNJ@ûsEykÙŠ·‰(ªçøI MÄŠçþKE§QdéZ¿Mâ·Î‰F¡´ð“^ a±Îý®oiõ.)‰ËÆ=Íãqo1eÛýfýd-ÐÆJ F*¿>þ:×,L6›Ud ’¢G•5ì,¥ÃÎo»Íÿ]³C‡ž°ztX~&OîçTÌ“Îqâ–NøY®Ä_~Ùî¢ß©$I¤¾’íY™Äe¦ +zTIFU‹÷§Iá­{žåžÿ»R´ÒÍì9úÊÏù¥Ï[$غþ)é̯H¡¨ Pþ-ÛÄC¸ §µŸ|ŸËÉ·Qïó%™âk¯ó–DÛ ÓK-A5%û‘Ñ„ð‘½Md[3‘¨\³0Ù,øLö>±”’¾‰øË¥ªs Õa-¿„žÕñä¾d—ÖàhT=•¹V…Ñ¥äÏ›“(è™HPa.ç¼,>Dç_Òõ§÷ÌØiÄdeðˆgÍ `¥_YÞ‰ô;—MFùýíDÆ¿BVðÝü' Mà6, ‡ü¯¡gÕÿLÞ—yÿd:³6“ãw$yn!efBr2Y(¨»ÿivX†l¼­~Ü#z•XT3QdheJú&R¦u AdzU9ÅQXBLA@Ë ,?ÓAKįëé¿Ô dU$3QTÿ·¤*¤Qcu#@çR Ñ²x·›#ïÿÑŸµK«Ï‚–?Ð×Ó£êg«Çe û‚NÆ%ZœRkõÔe½®¼–,Œô$Rm³ [=9H¨ŠGRü¹_ïM ËÙ1>ï6¹Ez‹êñ;¡3Š"CVmÞk¸xIÃnÅåzû‰Peà9] kt¢Àn2Яµ[¯%E_¾‡¶‹d½–4ÊÌöHó(a”Ä$óMJUYCUç·»?}…KY~õÈ|Ùõñ}oAÇÍómØÜ6ZnÒ0Á%¥Brl¡AO—!®î?ŠÝz­J2g"=´]t09§­Aµì)e•7bŒzÆè9Re ‡ïyÒ=…ž¬ÓÛ¨ÀG13[´·ê²’[¸vk÷4/1&°H êØB†#ÞB\ ܃îvRLªÀŸ)óKoÃf%¿YMÖ®Y±Ú_ïW¬÷Y®ÊIò6»ŸHTâÑó!µ&ÖjèûÂô}U¨j©ÅºÐ¢<.Z´ˆÔÔTŽ?N¯^½xóÍ7éß¿¿k_faw]Óø¢úåIú¿¦ñh?óXƒçžk‹¢T¹øÐ¤&<ðPz÷.¶xÌ»F‡þ÷(—º$ Ð;à*Ú$X<^ZªEUO^Ôû•åÌšu~û“à2Êë]¬ÆQIÀãTóÕ†ä÷™™$âD\£U=}ѵi¶À¼yöëh—?²Ð¤ÛéÑ:`7ÙÙëéûï;¡ªÇ/úý6µœM)¿J¥üÔq럕åúõ™;Í3:îñ÷¤òÊê‹I‹‡ ñ·ÚŸ~³ê’Ü«ëhøì³ó"°Ë·™ô~;ÙbèŒXÿü"Jn6ly”`]˜¶˜yˆ?üÉ“'óüóϳsçNzõêEbb"EEE®}aÝîºh4F$*;âRødäjÞ™°•wÉâ­©‡ÙÝÏ}:Ö"o- #^ui¼­GßrË^šÜ-w½Ýj©Aegüx«‰ºžËɱ(’í&N¾éø€ØxUàV”{[Þ`|Ôž§ÉâGEÓi­gÅÎù–謊¢z®~q¤CåÒb„Ñk¯½Æøñãyøá‡¹úê«Y²d þþþ,[¶Ìõ/MJ‚ìlô :R•>Û2ÈïO6Ž#—'4i7ïKÅ>ÿ~.­ÇzËûIŽÉ-÷~ƒËt ÿ*ÉÙ§ª-æÖ¦T´Õ²yØ\›5In-z°j!¬îCNØ ‹¹ìê;tIQ¸âµ·YPÔäØE’ªÒ}A ÞEº–/ŒjjjرcC‡žÏ³#Ë2C‡%»©^E…Ù”“ŒÂ]=àÖ•àˆó+ÓôH¤ù´ìÌ×íOä «.ì·q£h-fFÙ@hÐyFd¾¸'ýµdÄeØLõèiÛ‚TD˜§zÑ[)—à½Ù-_•”” ×ë 7y?<<œãÿßÞ™ÇGU^ÿ{ïÄì Æ„ „ÄAYƒU#RãúÖª,n/”°h¡?)‹JK­Š,¶´Ö%Aì«\Ðj[(¥·Á0a ƒ$,‘„$$!sŸß“2dÖ 3s¾ŸÏý@æÞ;É}î9Ïsžóœçœ2çkúõõõTUU9NÉÌtÚ8i{×s÷›wSµ^ýM»öwËNÉÏ—å4Á©ÎuŸ¯›‚ª,H]B Û~™¡[]!†nâ .@9)rùÓÃíÔ2hG†Qk˜={6qqqö£k×®.¯]ó„—m_ɯæ¥Òk³ÿ­ÅÞøO>½< øÖÔ«Ý?WUl Þ‘¡Š ó Ãb²‚ËIk£Hg~fžÄ ~G|­™›v/t!ó;'ç9 ÀdJšËšü½|úûÖäïe&ÌC'·0Ž4¥ÈÃÒ¾‹È&$$`2™(//wø¼¼¼œääd§÷LŸ>ÊÊJû±ÿþ–5%xì¦èž†â¶Æû•ç¨cƒ™ÿ!`…{ë5¹¼–[ˆæ}•É$Åd…–ƒÇÑb·ÜÓ—-ãŸdG£à$/FwPñÝ“Ë)»=8åº.!…£=³é¸u5{©£ëòùNó¶û"²¡¡¡ôéÓ‡µk×6s¬]»–¬¬,§÷„……ëp8pZ‚Gw¬®,\xÔ¼ ©õŘ|Œ0² S’å7ÏÚPí}ÙMƒ¼<)&+´ â"×—'´®>V ÁׂßQ“‰ád·UWduÛØv¨™ì–žc¿(";yòd.\ÈÒ¥KÙ¾};<ò555üâ¿hÝ:©—â C3ñãEþãm( ËÄâëSÀ¬ðçÛ}|Q‹í´X#·fRNŽô”‚ècfRwðåçqŠ9ßÝÉ‚¯³|c·”Ò ‚ý‘)¼ÕkN‹~QÒ_úuP·MRч-v¨i`ÎVº‰ñ˜\N¦ÛM‚ÇáÇsøðafΜIYY½{÷fÕªU-²½ÆI‚GWFÃÆkýKˆ…¦ðL×|fìÉMYsØjêçWÏh‹5ºó£ñèÊ‚Bs½…_)«KTý?Ï8bÝVÜ=·Ô³m[‚˳ۀ…Äðÿ¨c2u„`u ê´t6Ûjî£Ò«\ÙµçüI•ªç©§žëB,YœdÕ®ÿzM“ø"°zŠlFøæ·mÛÃHðâkÍÜ´+ߥÁŸ²b>Ûg.ª6‰û¾ˆÔ‚¥-ŒEì»ÿqª/óÎP èVÊÍ…«®Âèßße©Û;EÈ×jˆ¹û[~Œ:Õ1þõ¯Éçé¯F)/SÑ›ÍPRBHF¬^e̘SF„¦²p!f/Kfœš¦óúë‡]žOÞ^€iŽ›ÒãÆ‰·H°­Íƒ…lÛü kðµk:¬`÷#/Õδ„íŸ8õk@c\¢×ßø¥É×­ózg“IYH:î‡[¾SR ;Ûúon.i+VXÒR¿¯#v2,Úe­0c†ô’à>ØÚ Èëþ¼x‹¿Á|í&Á#xLdhït±Ó€ T^y­F€Õ“òøã^w“tÊcüÆx`èPëáçž”Œõ‹¸í÷ÑQv·ýkh&ÆêWÏXQQÁ<@ll,:t 77—êêj·÷dgg£išÃñðÃËÈà„ê)¬¿uŽÏu5`gL_i@Ñ ÿi¯È¶'\çöšËŸFú+Ó‚¢4H•ó8ûgNw tør½F€ugšW]>ÙaM8¿DV˜ÉZr*^Ķ«`í¤Yõxï¾°—Å\àWÏôÀðí·ß²fÍ>úè#>þøcÆçñ¾±cÇrðàAû1wî\eOcÝmó|ò)à„%'ºá7Äך¹ìÈÇ þÔó8<°‹ÊöX9+–N³ïDsžž÷¸Çi6;ÆÈËik.{¡ý[Þ2^DSI;Öóňy~÷<Û·ogÕªUÑ·¯Õ;ñâ‹/rÛm·1þ|:wîìÚHŒŒt™ìTpbÝ0•†Ð(rÞÿ¥W×k@„Q# 'ºá?ÃÛáϽölhÊZT¶‹º àÚ!üˆ™+–z^Ò”AÄ:zv~¶Ç¨igZ£×]£Ðž¨JÊD9y/W¬úiWYá_îáÂÂB:tè`ïø† ‚®ëlܸÑí½o¾ù& \yå•LŸ>ÚÚZœˆ¼Èëk-hx-ºáWøºOF3,d`\;D,vÊ¥¾ÔŽ xéÉÍ¥Û˜ÇÈ»|4·~÷‚ËlÊ:IÇKd)­Ya&ý³7ˆß»åÄ4Ò1È~e8†¦3ÚD¸¬¬ŒŽ;:*`Hñññ.‹%Üÿý¤¥¥Ñ¹sg¾úê+üqvîÜÉ{ï½çôúúúzêëëO˜® ,8•vGy9åYÞeŠ^n’~Šò^¾m†A‰x¾êN™(Mo‘Ðñôgÿ~JžWÞ"ëÀÄšËukU* Û‘"é¡Î3ëqïä®ôy÷·tßòž[Õ•A . ž+žx≠§;vìhõ÷7ŽœœzöìÉ<Ào¼ÁÊ•+Ùµk—Óë})°È„¬öjа`â½YFÝ$ýoô,ߪ™a°sr´À\)ùŸÉöJ ªÙs7¥Ã§²aÙ^ŸjÇ…‹‚*yÃcÜá_<ÎŽ¤lö&_¶Ðöâ)´d¬O‹šöB€çqgÚ”)S5j”ÛkÒÓÓINNæÐ¡CŸ766RQQáSŒÄ€¬AI =zôhq~úôéLž<ÙaFŒÆ‘më¾»š{LÌÏÌoQèF 釭VšîfyLJ&ü‘Ã7ÜkÍgô¯J¾FÓÈÍcÓДÒtÊ{çÐqÛjû¢'R/õÚST†Ñbªúåo=^§£˜õ¯þ,Îz3¥âö¹æ²ÿ ÍÍ.BkÁDDz‰`MlyILL$1Ñsò°¬¬,Ž;Æ–-[èÓ§ÿýï1 ÃÞ¡{ömÛèÔ©“sOIXaaa"P¸^fPÀ =^aCÂb‘n’~TD¦°°_>c6Ǥ,XÐÑNë•n:ef3ù4¢5 š2Œ"›atñüqTôËñÍ8RBee¥Tee¥ã‰M›”aÝ´ïõqT$+ˆ³yæä8kG¤êB¬jtóN, ¦®F¡N6{O£ õ^Ú·Ür‹ºúê«ÕÆÕ§Ÿ~ª233Õ}÷Ýg?o6›Õ%—\¢6nܨ”Rª¤¤D=ýôÓjóæÍjÏž=êƒ>Péééêúë¯?sÝPÊOå%FA¢Ç#›8·z~/ªlT’tñâ¸Ð/ÛË_ôã|è†êG¬‚$ûÑ…uª¾\¨^&ÜÞžlê3‡©î%Bu!VA¤›ã‚vú¼a ¢[Ù„{=¦ß@ˆ‚ÐÓ“KY|Ñ'Ÿø¼ß,wã ¶'e³lY"J©VýjMÓZ}ïÍ’ýì÷êz<¿ö.¦åƒÝxó`®v’çÞË\à¢K8za‹_¹ÊÎñæ›o2qâDnºé&t]çž{îáÏþ³ýüÉ“'Ù¹s§}gMhh(ÿùÏX°`555tíÚ•{m”í[Ó4 Ãð+Õ´D®¹æÇëÂÌߤ:]JSÀr~DÇšØõÉä|ÞíàÞK¼cG'¿ë t]Ý8’’’ÜŸýÐõªtô‚ýß"¢'µ{Ü àëŒ{™Wò®=¶Ö Ž±Dpýçi)FŠB©†VËYkûOº¡ëqÌ™SÙâóècf,Ïuu¨¡é,]iÿÚ¹ÕÅÑc¥»µ›ë®ó)rß&T±õ‡ˆ¯ ül¡í…†Ðhë庲pÑ%ìNͦ2Æ?]Ãñññ¼õÖ[.ÏwëÖÍ¡“èÚµ+ëׯi5Î;\­YŸ`Âੲñ|•Cù²¬&ºá_è?˜‰ž2Î! Az—¼sÚ²’"ZVV˜©÷9¯îÂ8âȧ·ã¼þŸÕXFzø»Òúõc ¡>•ЀIŸçÅ¿§1š:é±Î2£U=þo :†Û÷dh&Ž^(¹fïH­/öºƒ3a!µ¡DMð;L»‹Ñœxk4ž˜òÀ‘óÅD1¬ÿ^ÞK~Ä¥Q¤)Eè¯Æ£ðÞÑÛõGÃŒŸn¢øÂ¾õ¶”ÃÈÚ8ùTŸ÷íàÙLµe?\Eïåäù­§H8÷”†ebñÒWlA£4TŒnÁÿ°¤g¢¼Ü†ßO <9ßÕÓí¤Z³XÐvyoÍvýÝõcfNéG‹¸øðgœ4…1f‹çr&€ÂBkAV¡í).vX#>ìêz=+îxSŒ"Ák:6˜I­/fyÂî;òÏåPü¤fµÇ8#Aðgþ@IñÑF33—J¦lJCǰaØŠÈ6×ye2¡zxo†›`쾨»/êGúÑ"Ÿc„³@f&›êtÀ‚tógÄT䢊bŽÆgŠ$¸ågGñÛÒq˜š–f½Ñq$ÎHðKL»‹Ý¦9i>É|›P&À3÷Ü´ˆ›ßã°ä¥Ÿ6nØt_™L4¼˜×"øZ #'x“5°ÚYY¢}g‹”'‚yœp8§,Lø«5ÉÐtÞËɧè*™Ù -éØ`¶Eø8ñ±Å‰a$ø¶¥4OÆ‘D¡ˆ¬0[^LUR¦_aG3só;c=ÆiMãwCA!ªoI›õ`¦ºhÙ x‘0(.–8£³Å¢EÌqcÙÞƒm·š® î^=ž¸ãò>„–¤ÖÛ"ŸLg$øFçjfÎñ8žèôŽSÒÈ™3˜{§¤‘±~‘ß=o罟»Ífï8Ù­¦Æçß´†‘7# x”z<ÒÒ`Ñ"ѶÄl†±cÝÆ9›õÛ¶í ÂéX®}ïÖðBâlñ þ9ÑŸ8š'ç¡Üä­Ú•œÅ\NØ‹­jÊ`Ð’qDVøÏ$3ú˜™„òo¼¾¾|Š- zÃÈZgƳ£Ý~…aÀøñâ9j+ŠŠà¡‡¬yI}!ɶ}Á‡BSøGüCø*UðM¸ÔHüÙ8šÊ[÷1 çåN2Ë>k1àkÊ ±¤Ð/ž¯ç¦EŒ.•k×þÞ+ý6ÐOœO±E6‚$ƨžeË:¶ø4‚æQë}‚ÅÂ]3Y¯yÛl™j^€®Çx¼j™:ÁP¯7RŸšÑkM3€ñ*ŒÅ¯\Õtæ¤ôˆ‚Ž fn¯ø«Ï›*d»¾Sx0ž¤ÁžñÚcߪÚÿsŠ+RŽ 7̺t9‹wLâÅVü¾ 1Œ4æÍs^B`ÿf0ð¿ÏzÕІ¦óäÃK9œ9È« µQ£¢‚Î0zýõãn¯èýî ®úðYŸ¢Ò÷²ëæ T'gpóE)ÜÜtnĈ`kcÁ­1Ò@¶ë Át–YȰÿŒõ‹chG2Ûÿæ"_⊬oc[ÿ\z° Ñg·>öã<EXsd¿2œ{ü4hí|Ya檟kUŠ„ò^·pøŠlN\$1 ‚kJü["oÙ*ž*OÒIY*üŸi9^M8¿º}:±åÅ~gäÍsåu{žÃa­+t!Ø8äwšîqFiÛ©+ƒ¬¥ãJ˜Î±åÅ^»wOoû¾¯'⨴·àž¬ªÕ­¾WÊ‚Bâ±b èõÑlræ æž)iŒ¦±Ý>ÏÝ¡¼œðhÀŽ˜3‹Ãk1ºß›ï6­z‹Q†…Ä’B’·ˆä%UI™(­u"§¢ËdÐ\cËa¤Óº  œÐeiVðwÈô8Ù·Žk§&ûy4´ÛÍEÕRX}ïB¯É-˜8qfñ‚b5±÷â‡ÊÍ;QMçú—‡Û­mYZóLm| ›‡:Ï·á1‡n¢:Y‚cלI#Ûä'¨‘†üžÊ˜VÜ”ï“6„”´ïɧ'Ÿ‘Æü̼3ZFèÖà.ïg–(Ã>3•¥5ïùî¶©|wÓ¯ZBš£hó˜<‰/ÜâKÑXWªìL…Wæ²`Ä&¯# @Tûô˜&•‘óî8¯ìlº0猟FM„×õÉju¶´S.K=§Yan±ÜX›ØÍ«áKiŸ=º‚^ÜËžÁ²[HpÏ¡ÐÞì8å,ÎGÁ¿ØŸÜÍ—ôªÊƒ `àÀv—Èx´jàÁ¿ °'¦toÐt9qæãpˆˆŽ•ºÈ‹Îè~C3q%7äR~ñu‹{*M§hl>次Ҡ‚׬¹pšß*GÇZiB@wÜLßõªÊƒu kJdœ“)í@Ìfò¨óÚƒÓñEb5ã‡nƒ0ÐZ¸ùmίý² _[“±~YKÆ¡+ÇÊæ¶åÆzzvsÀ~¿3$±à£QnT·Úï#µÒ„@#ñX1ºò1îÎb±Æµè¸ØcɨSã†Þ&ñEÖI’4íLº£©I t¤ô.õ¸¦³ãæGƒ¾ »`Ø"‡YˆMØ Å…$}ÿ‰ÛÁKBê%VðÖÆh<™œ'Þ"! ðvwZ˱V¬°çs§Zf¦5öÉ x5í9†ößÇ?’Û&äBSÊ‚{¦ªªŠ¸¸8*++‰u|H-õzpÏÀ ØÀ ÖªG‹ £ ™X(ÆÄt ZÂÒtœk¼n«æm–‰Á%4òª‡àEBy”—ÃW#Ðð¦6ôÄI”jðZ‚wí¡ë:†aœó¿IÓÎ$ž§îòìªxŒZŸµ-Žp«ñ'€c­þ«ÏGWëìýŠ~x¯ÉÉÉ”••µCýpw>‚æå¨FÓ@'i’so<0F3¯‰Œ%ŠÅ„4Ψkº7½º;ÓÆõâÕê™G£Û'Î&žõNÿ¶Z Êåï=]'m²4µÒ”ªóí–‚<Ø 6Ñãáïùhû߸uÝcèM³Ï÷nYÈÐUSÙ°¡†ÐCfÂ÷S×5“†ŽÞÍH³²"0ŒÆV+Uk;a]cÁ‚J¯¯¿¼pƒ—ŸZ:s&òÍÚv£ÈvNÙ:¥Àd"$/snnu B{¥µ2ªiHN>èòü2‹™©‡S}Z73ãþ—¹ ó\^³kWüüÍ"§Â¹Ò'ý¿Ù %%üöÆž§Áó8pÚÿju¬Vqý}åN¯ÿÛß¿±™IDAT’™;×µùØcq¼ÿ¾óqå®»bX²Äu)©¥£"ÑÜV&ëö~éóÒŸ®ë^=¿ÐœÌLÐ=7®,<°ònnk2Ьª¸{ÕXº`ø÷Eô¾+Ë& ¦÷]i$þ=pòuÜWÄàec].) ¤ó .ç:Z“yQPZj5F÷î…\Ù&´žƒ¦~=×çhÁÜÊ?Ü()7„$%²³ilUíë8—qŽ3cGV˜IÛ¸‚‹±´H¾l{†F€¼¼6‡ÃÈ åçÛEÁ0¥•µŒ§Aq; t~Z“+[3 º??žÐCþßù^^¸ˆáèvV®?|ì¶v•Ž¢Í®¸í"àOð{^žÊÓÑs}JpgÂ í¤¤Ü³™9Ô·js‚¡™(9Ë LÍS»d¬_Ä=“SÉ~e8¯Ò »q¤t‡§Íeÿt#ä¬L¤eWšÛ)d.ÝÇLaƈ÷é÷åk\³ýMŸnEvcÁ°¶¿Äë%µöFô13ö|Îàåã¼Ê+¡¡ØŸp5]luX>sP8eYÚœâË|ºÞ‚ξ dWš¨ áý/£åW?O泉¯5SÙöc—ÃnfMG)ÃÁk£¡PšÎ‘G~GÍwP•uÇò³”{L¹ à\€:m9NQÛ‹ü²-./\ĨYiܺd¸O[@mFœŠ)²E+nÊã€&b(´- Žâ¯Çîô)›ýÜøç) ¥ x±Ãët°ýoÄÓ( ‚?Fö®¶ éK#ƒšïf>Í(:åT0HxùiR‡$öí³’"#’—TƤðî-¯ah¦Ó„Æ9_]2Œƒèùé}×j@êËÓýj9-ú˜™Œ­+â‰|AsòóÊëÿÈÓ£÷²ñJ‰'Ú–^ E «[êÓ\R¡QeŠ—Æ—”Æî6´ÁY¿­;üß ·h<ñµÖñ+¾ÖÌååtiåêÔ5‹Ø@W«Í ¤¤™ã );{c¨,¥ù@ÑU¹|ß=‡‹~,!këËôÜù¶SSÀÑ 3)eúê7¼Ø–Ëi­Ù¹v6 ¡‡‹i&sÛ ®.øC« "WšÎ—™÷R#³s¡íùi݇>;ØuÏÏ'‘9â5–ÅZ(}SLç}…„×%}Ç?ÉØþ¡OßaRrvþ‰ƒ±—2fÓ8t ¦k6-âëþÞOtØéýò¸V-†i†… ö½x@1Œ|¤2&…ʘv§f“r°ˆ»W¥óá/í/WÛÓoçÆ Ï¹tÇY—Ó6s¼O6‰_dÒVºÎž'òÏÛóV Œš•Ö"sµç·w×*àÃkçˆQ$œ5ê´ðVÝgÂBÚÉ1Œ„€¦ºC ßw°–ZÚ}ù¤?û¡ÏKG·í˜Ö¬R„ ¸ùÝñì¹8‡êÞéOôÁb§ž"gcÉéŸ)ÝÄÉ´³(KigÀñèNt:òµÃ Ó€KwÿÃãn­Ô¿L#îÓ=dvºs­‹³<¾g!uvŸ«ï**²Ö¥q±ýÞ­ï¥Qôï~¿e]ß©"<ÂÙ›¼è¶ê> & ¾‚ÎHú÷Ð×¼^^;5‰ Å§+ ÷Òµ¤€ècŽcK ¾. üȩϫ;e¢œÄ—j.ÆÛµJ7QþtÉgo##Oƒ¹ªgÞ<ç±Ùê$¿q²!X÷ƒ¢—L½“Õ„¢ÑrçZ"д$¦PÃj0aË´Ãb"šÎÒ,Û¶mÏA,š–ÈhêȧºÙ}Ñ->[L¸Ãµg¥g cææ—aóË-ÚXÚŠcºï¡-èÌHÌo‘t|Ó?—ÃÉWqÿ‹ýϨÿ7€;ßa/þï{òùº.=7-bÕ˜~7¥élûe>¥?Í¥.!…oÿw—-æñ÷*àÀ+ "£9™–qV"Û.¸3`´“ìÛWáôxëïÿuéj¾ûÊq”CC‹ë,š‰¢6¬œw.ü&£Èf©çkµ<|ÇÞ¸j¥üHÇ(åG^éûÆ•L±•…Z­ã}Ô°ð´ïZ¨`éÀ§YHíY5ŠN>;É5uTWW´84-8 £gŸ}–AƒI‡¼4Ì3gΤS§NDDD0dÈŠ‹‹E1ÝpGÝÛ>'±›”´Œ·ce#€èGpRžÚljäLŠÖh`_mЕÁÍïŽ'©´ˆœwÆÚÇMô~i,áG̤®YÄKójÜÑ͉ÙgÝ(j7†Qk¢= ×V{ô yóµӌˆw2'“F†}5ƒ»w<×â{LÊÂÏ¿{†¿š†ÞämÒ1»åÔnŽ•-«*›PNÝŸÿ»á—öïi #ÈágM£îãM4N’峆††Ê#<âõ=sçÎåÏþ3¯¾ú*7n$**ŠœœêêêZÒ«¡ˆ;ëßñqG˜CºIã‰~5/ɲkæ9,«)t¨E’ceáÒ­oµÈµ­¡¸øo³èýÒ¯ópŸí˜¢Ó iO ‘••Å¢EþS2£±{&J×[$qt%(ÞZÝC‹Ÿc8 v<ëô; t†ìÎsj0 Üÿ6b!íÈ–Vÿ gniÖ„\ºNÃ_òQ}úI¯<õÔS,Y²ÄëÙð‚ ˜1c?ûÙÏxã7HJJâý÷ßgĈÒ¨§1 áŸe^®¬ßÂ×á"§¢ÁÍ¿®˜Ê†n#È8\Àÿ|õ{R+¿¦5%mmã€3º¯õ<ÎÛÆ¯FàÈYŽ)j—£§žzŠ_ÿú×ôìÙÓ¯„ÈÒ)…ŸÏG™s)]?#ƒDw+lPëôÅ)`ä—“Ùdž=v^Œ" 89}&uÿ* nÇ>,#ey¢µìÙ³‡²²2† bÿ,..ŽPXX( ä„]!·j9àé#0§|”4 èGÐócT E݆R’˜EW/Œ"w¦MU‡TŸôÑžüW7±yØCjFäRwC!{K0"¢ÐOÔ`DD‘t×@§ž¤¶0}:•••öcÿþýAó>šR˜›Oc+öX*`¯ä1ý¬ÎSäGšÓIµ#@ñ cλ1Ôœ³©£Fr{MkÂ&Ü“'O¶ÿ\UUÕ˜ø&!›o²ùw÷GèTSB)ŠpK £28qJ–^>—Qß=ÖbYÊ“òL¬ÝÝk ñÜÕïp$Üú7~×- 9t®-á‡È ûç¶sßÇõcóÎ烮óHLL$11ñ¬|w÷îÝINNfíÚµôîÝÛ.ç7nt»s',,Œ°°° íÐÿ™Ëº°ú4òjå0¯M$ 8¡Gˈ(ú!Žï2ÎÕ×ä¿F“Fé&~øs:¾gÍw¤›o„p}|ûÊâ áÂ}4"ÅÁ:2§#¿{ E#P?ˆK*>w(7⬠kk ¢u—<Ìg—Œ&õð,ü¥Ã6~,ºxŽƒñp$<¥Åg‚÷”––RQQAii)‹…mÛ¶‘‘At´u@¾ôÒK™={6?ÿùÏÑ4I“&ñÌ3Ï™™I÷îÝùÝï~Gçι뮻¤A=xŽ>ŠÊ?ê†rgýÛ^é‰d¾ýN±3ñº–¥8Za)›Q„Æ·Íf×ϧ~ÄLÔÁj:e°xÌe\ßΞ=Ä_"ø s*Ÿ¦Œ SM K>»k‡|FúÑ"®þá OfO|ž];Ð!çŽvZBwO‚«€^ý[~ŒJaob? Ó<ôÙxLÊ‚X|ñ<Þí.y‡Úš™3g²téRûÏW_}5dgg[;£;©¬¬´_óØcQSSøqã8vì?ùÉOXµjáááÒ žf¼3wÔ¿ë¥Q$™¯E?„æìMìÇ'é#¹n÷Rû’ØWÉ9ô*[íÑ‹dû¹ùçŠËÿ:×ÝG]B u íW×4¥Ôyý5j”ƒBØh®ž¨ªª"..ŽÊÊJbccR;“ë­ÅІ¦Ò¾SïÔnÍ ò¨&ëÚì‰`'Z\÷$á̤Îå2B6±¬çûÏ]°A ŠD¶òo>o¥«õœ.Âîd!q×!!!ƹp;³n'Î+½Ê¦ž~ôê‡Å;„z¸ª¨i}O¢ûº®ÓØØ(úÑJýHOO§¶¶öœÿMååå­–÷º.å\5w¤/'¹–F>Cã áìã¨Ã¸b§ãÌ_01‹½¼€õw(>šFp…k iF›ëF»0ŒÎ¶pf3””@F“Û?- šn&ìÝ «WÃøñ`9M8mçSsv,¿´‡]ON× «…Í»½×‘i6eÑ¢SãŠÉ³gÃO´ƒ aà@çcS;Õ5›,H­4$%²³­ÿ¦¤@~¾Uàl‚——gý<7×*„S§‚®·ožMf¢ò|¢gC?Dž[?$óµ ‚ BscYš@AÁŠiÖ¬Y³‚î¡M&²³³ ‘ç“gD7äùyßÒ^v&øZAáL‘¥4AA1ŒAAÄ0AAÃHAA #<ûì³ 4ˆÈÈH:tèà÷ÏóÒK/Ñ­[7ÂÃÃ0`›6m ˜wõñÇsçwÒ¹sg4Mãý÷ßíÝÝÝZY¦Û’Ù³gÓ¯_?bbbèØ±#wÝu;wîÃÈ :”GyÄïŸeùòåLž<™'Ÿ|’/¾ø‚^½z‘““áC‡â]ÕÔÔЫW/^zé%ÑtÑ Ñ Ñ &Ðeº-Y¿~=&L`Æ ¬Y³†“'OróÍ7SSSãú&%¨×_]ÅÅÅùõ3ôïß_M˜0Áþ³ÅbQ;wV³gϸ÷¨•+WŠàŠnˆnˆn%Á$ÓmÍ¡C‡ Ö¯_ïò‰1 Ùý–-[2dÈ)W ®3dÈ ¥Ñ Ñ AdZ*++ˆwyFÀ‘#G°X,$%%9|ž””DYY™4 º!º!ˆL=†a0iÒ$®½öZ®¼òÊà1Œžxâ 4Ms{ìØ±C$D:D7Af&L˜À7ß|òeËÜ^pV¦L™Â¨Q£Ü^“žžPÏœ€Éd¢¼¼Üáóòòr’““EÑ Ñ Ad:¨™8q"}ôü1)))Áe%&&’˜˜T/<44”>}ú°víZîºë.Àê2\»v-'ND7D7‘é D)ů~õ+V®\ɺuëèÞ½»Ç{‚º$oii)”––b±XضmDGGûÕ³Lž<™‘#GÒ·o_ú÷ïÏ‚ ¨©©á¿øE@¼«êêjJJJì?ïÙ³‡mÛ¶Ojjªh¿è†è†èFÐè2Ý–L˜0·Þz‹>ø€˜˜{V\\.­© eäÈ‘ hqøåó¼øâ‹*55U…††ªþýû« 6Ì»*((pú®FŽ)ûOE7D7D7‚Ž@–é¶Naáìxýõ×]Þ£5Ý(‚ ‚ôÈv}AA1ŒAAÄ0AAÃHAA #AA1ŒAAÄ0AAÃHAA #ÁuëÖqÍ5×FFFK–,‘FÑ ApÊÁƒ¹ÿþû¹øâ‹ÑuI“&‰a${öìáöÛoçÆodÛ¶mLš4‰1cưzõjiAtCtCZP__Obb"3fÌ W¯^AݦY³fÍ‘ð/>L=hhhàºë®àóÏ?§G 4ˆåË—søða>øàéß¿?ß}÷ëÖ­ãÁ”D7D7Ñ ݸæšk¸õÖ[éÕ«Ë–-#99™[n¹%(ÛJ}Ôý÷߯¶nݪ¾ýöÛ k'1Œü‚‚¢>ùäûg{öìQ±±±êå—_¶_Ó»woªÒÓÓÕ믿. 'ˆnˆn¢.uhq¤¥¥][iM!‚ ‚ôHðµ ‚ Bÿ,NP¯N&¯IEND®B`‚pyclustering-0.10.1.2/docs/img/bang_clustering_chainlink.png000066400000000000000000001074531375753423500241110ustar00rootroot00000000000000‰PNG  IHDR.ƺH bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEâ êÏ” IDATxÚì½ip×™.ütc#’€”(J¤¨Õ¶,Ë’Y’¥Çu/#å=Î2©8ž853wêÎäf’›ÄIÕTjn¾Ê$“ÕËdõز#ç~ö̺_eó"ÇŽ,Ú²%qßI‰ÄBì;}¾Óì@ ŒS¥" ¡ÞÎÓÏûžç}^†BÐÑq ¶q £1£\ÑÑ àjŒÆhŒÆh×e=xžG#mÙ—ûÐ7NÁå1!Èd2H&“H§Ó0 ÐétÐét`Y,Ë‚a˜Æ‰jŒp5F}ÏóH§Óâï<Ï#•J"‚˲ÐétÐëõâï 0kŒKu0 9Ä¥ X„¤Óiðé?ú^ `Rf¦Óé`Ö àjŒêžçE€"„ȘÇqà8N®b '2B8ŽƒßïÇúõëó­Øç5Fc4BÅÆ( 8RÀbFü'}OɧUÎ6t»x<ŽÉÉI8N¤Óiñ= Ãdf vÖ àjŒ‚€•ÉdpñâEØl6ƪƒýô¡•\ÍSº©•€‚‹/bll f³Y1UI~¬VŒ«œÏ´X,°X,èêê5‘Hˆ`æõz1== Žã`±XD “²Ùz¹þ•†¼‚ópÕE«Òþ…JŒKšÇÚ±cº»» Y¯†²½ÖßÁ0 Ìf3Ìf3œN§øÉdR3ŸÏ‡X,†‘‘ÌÍÍå-”ûÀXMÆ¥Ì(«—œ+É3>È+š àR‘Ç*äÜP  àCYÇèè(<6oÞŒ¾¾¾¢¡’àªwwˆbßÝÔÔ„¦¦&8ÀéÓ§ÑÝݦ¦&„ÃaÌÏÏ#™LÂl6ç™Á`¸¤€«Ø5È]Ñ”2~iÁ¹ßïs$0kWT©õWîP pQª?>>ŽÙÙÙ²ôXZ5`õ¸ÊF£èìì_K¥R"3 …B¸pቚššòÀÌh4Vm_”’ó«êô§´íÌÌÌ ··Wd Ò*—óŠf¸nÎR‰÷Jð„,--–——qýõ×ËôR•æÇªÅœê±V±˜utt ££C|-N‹`‡±¸¸ˆx<“É$²ÖÖÖŠÁ¬žV9¥¬_¯×‹lSiESz_.+š à’Ü”¥Z•ÊU~¿ÃÃÃâÍ´wïÞ²'Ðå’ãªÅ0 hooG{{» ̤õ™.— ±X F£QV@™™çŒz›ä<ÏËÂÊJW4/µ‚s}°òïjòj+‹allLÌcmܸ¿ûÝï*NìÓÚÇZ>ÅëihÙ'ƒÁ€¶¶6´µµ‰¯q'3êœAm€¤eMRç )s©7à*µO•®hÖ³FFFJ¥°sçNtuuUÜô¢ÐõA[U\+@Èu΀·Þz ëׯ‡N§C8ÆÜÜ¢Ñ(†Q,6_}¯µwZ)y†’…6eif³¹fçú `åæ±èòqnr³àÊÍc•ÒcUª€_P±žXW=.477Ëxž—›çÚÕÒ9ƒŠ W;ïVÊBÛëõbff×^{­,SMy†þr¬BR ,•Ã0H§ÓËËcÕŠ9Õºä§Á¸J…’M¦ÜTD­3¤¹Ùz¹VôáJ%µ*8×_΀U¬õ½Ø™L¦lÅ5 9GFFÐÒÒ’—Ǫ}ÐW=ÞWj»1©qÎÏóy`ÖÜܬ Œê ¸èÈd2"¨TžÁó<~ûÛßâŽ;îP” ]vÀ¥Ö¹¾^.ó¡y¬D"žž\qÅUKì×pÕ㪷PQ‹Ž«Î—pcfÅÀÌívãØ±cˆD"—7p•+ -@b±FGGáõz100ŸÏ‡æææª4½h0®K'çVMÐâœÑÒÒR·Ê÷RÀ¥Ìâñ8 CÁÔ‹þr¬J¤¸J :9ŽÃää$fgg±~ýzÜ|óÍ0™Lƒ¯ðia\¤UÅˉq•sÕ8gÌÎΊ9£óçϯ¹sF.pi݇P(T4dÖ_Ê€¥E@ @Œ¥ }þÂÂÆÇÇaµZqã7ʖƵvëi0®K3 ±VEÖ¹Îàõz144‹Å"sΰX,² €ÕpÎÐʸrG8–-x\ÀEkrrétÛ¶m«š   GFFÀq®¸â E=–àªtÛÆªâåϸÊtE®¿¿_|Mêœ ±°° :gäÖgÖ Ìh'u-#‰MÅè/EÀ¢y,žç‘L&+¾™rCÅܵ yžÇôô4¦¦¦`6›ÇEÝ}ªí…x)ºC¬ˆÖÓ žZÕ¼ÑhTt·Ã" ---!‹åÙµ´´”œ µ ¥©™K ¸¤R¥Ö_ZÀƒÇãÁÐК››óòXå°µÕb\JÛ¹ÝnŒŒŒ@§ÓáÚk¯…ÕjÃ0b/DÚ¥zttTVžBMZk×XU, õv~´”û(Ùq'ó4“Ú)Y¡s‘Éd4< /)àR›x×étƒÇòò2Âá0b±®¼òJ8βnJ–eEOðµb\Ñh###غu+z{{E…²T7DEÒÆ®´Ö.‰@§Ó‰@FÃïz‹ê‰ùÑ}¹\€K ôzU6@±X z½>̨ Ð2T,§õW%ÀF1:: ŸÏ³ÙŒžžQC³¬I˶49/µÌéééÁ¡C‡ÄÜ%àQjìÊó¼ÌÒ%“ÉàìÙ³0 ²³’árb\õ \µnçVÊHêœA€ñx¡P‹¥bçŒH$riÒJóRO“r€+Ncrrsssâd®x×"ÇEãäÉ“hjj*XjT[bYVtAèééÏçÃÎ;¡ÓéDfæv»óòRçеŸÀ@ Øí@­RP—rŽ«ÚCÉHú ƒp»Ý˜•Õr–㜇±aÆú®Z H !˜ŸŸÇÄÄš››±ÿ~ɵ„š«Í¸Âá0FGG‘J¥°k×.¬_¿¾f}Y–Í»1¥ùšÌÇãâ2»д„ RR,xÀ —‹…ÃÁãùçãØ·Ï3­àöAµ épbb»ví‚Ùl®Ø9#‰ÔgržV"‘én5¤45<< žçóXkî•»m:ÆÄÄæççát:‘L&ÑÓÓ³ê¹%¥ü]™ …B…BXXX¹ÌLMH#¡®.ý׸ê*¦ ¸µ¶ÇŽ™áó ïñxXÜr‹?øA_ÿºIüœÇOâñÇWþ~òÉ8æË°Ë-9_ëyMË‘Ô8g„Ãa‚eP*•Âàà b±,K}])ôz½8wî>\Ñ Qˆ1IóXØ´i“â^‹•Aµ¡"uRCKK nºé&d2ø|¾ºÉ))­L¥R)1Ä ˜››C*•‹†)å ó<ðÀfx<Â÷»\ ¾üåëñïdð ìÝ+œëÓ§YÜ¿‹Ž>›sÞ<öØJ}›Û-üMO·ËÅàèQ+œNÑÏU3!ë±QF=XÓ¹YhÞsÎxçwð /`dd¿ÿýïñÌ3Ï`ïÞ½xì±ÇpõÕW¯ på&Þ 2™LÅ7D.påæ±n¾ùæ¢9NWñÊ`-W0ÄÐÐ’ɤL¹ …jÚ¶ãR;rû ÒUN f^¯““Ó8FØíe26¸\Òdì ‹zà3ÆÆ¢8}šÅ­·ZÀóL–Qš´Œ È”þÏífÄÏUsÊê±QF5dµ˜ãÅ€«Ð=KWÀo»í6ÜvÛm¸ñÆñØc¡³³ƒƒƒyóeU€KêÜ@ŸÔÌO«€”~öÅ‹1>>ŽÖÖVY«žòT¥W*•ÂØØ.^¼ˆþþ~lÞ¼9¯õT-û*Ö"b&“ ‡‡ƒƒ,>óš“âðíoObãFNò€aºÆåbà÷÷ÝgA«Ä'/"²ÜÏ Iô{É1®Õ¬AT38ŽSµ°Vê\G£QìØ±·Ür î¿ÿþÕ  )Þé  ×ëEûÙJCExóÍ7AÁ®]»àp8TÖZ&ç¥LçyÌÏÏc||ííí8xð b|©ûq冃ËË:üÝßmÅÈÈzÜwŸµ(ø|éK,/·¨…˿ˇÃÁC²Ê߫ī!ÑXW9Rz°å®DQñ%¬[·NìÖS/ážZÆåóù044žç±{÷nYõ¿Òvµ¶µ©åä —‹•L<õÌÍÉ_WŸgŸí.ÀžHQp*ô>–%xê©8ªPq­œ!JíS­u\kµO«¾ªX®€”ÒKµÀ%]e£:õë×WôäY«ä/u)‰H=†‡‡‘Éd`·Û±{÷îŠ@¥ÖOÿZãÞ½àÁÍ*AKšóxÊ™¼Ê9±ááaôöZ Ú×kŽër®RŽô•íı´´„ÉÉIÜtÓMš´X´>±Pk×®]õXZ½j„ŠÅžÄ™LSSS˜žž}¾ŒF#æçç+v‡¨5p­ÆçK‡T-_Ð0 Ó¹’s» èKØ3°ÙxƒLö=v{ÝÝfÌÍE@È<ÒiAý/-2×¢7lWùÀUJΤ/÷DIï4ÌÓrA¥Œ‹Ê&&&Të±Ö2T,BBàr¹022“É”W ­Å‹ž§K™qÑÁq‚6kyY 8¹9.åUÄÜü˜~ Ï=Ç–-<Μaq×]Ò0Røü`w: ¾þõ4>ò‘+Å’ _þ2„-[ü…Bðù|˜™™A:˲–©ÿ×8.Wà¢ÎÅîEUÀU¨õ—VR)ðx<ŒŽŽ‚‚«¯¾ª&‘VàÒ²­Ò͉D044„H$‚mÛ¶¡§§'ï8*]\äüj1®ÁA÷ÝgÎ ó”@ "38O?Ãáü,?¦”7»ùf6A0Ef6ó‰bçN«¨-óx|üã­ÓÉÔÿ ¸páŒF£¬ÿ¡ÔaVkgêJ@âr+f\¥œôz}^˜WɘžžF2™ÄÀÀ€b«VÀ¥5T”²ixÛÛÛ‹={öT5ke\jÊ~*ŸZ2.Zm±÷ܓ˴y„\ÏÈòbßúVŸù §¨»ÊÍ› ²¸÷^s–]A‘ÉÅã žžUÔ–Iõô!m4100 ^ÚÌ•ºeŒWl—}91.­jþŠCÅrH+YqI¥R˜œœ„ßï‡ÝnÇõ×__‘·ÓZ:<Ð Em‘smsªý½—jŽ‹çW_eñÙÏÒ\Q ;:2‚@€ê¼xtvüæ71lÚ¤ÞŽ†çå®År^Ÿûœ5Ùµ·“ŸOì ]좮ãRÚ–6Ö…ÝnÇþýûA“½Rq$½am6›¬ûp¥Œ B!”Q]8\s: ž>.¶Ó2”CXú]ÅÃÅOÚŒññ(¤ó¯ÞЬ‹­„çÚeÓkšH$Ä|™ÛíÆÄÄ„(˜•23«ÕZѱRi‘à¢÷­¦P±Ô‰›››ƒÏçƒÅb)šÇZ-à©øÒé4ÆÇÇÅbèC‡©êÚ¬¸* ?rCÅp8ŒóçÏ#‘Hˆ–?ét<ÏÃb±ÀétŠ7D4ŸÂ³³³ˆD"â<ýW  ÚíÈ.WúäfðoÿÅwðy!Z¥`Á²ÀsÏÅqË-–f§ì?/ýÝëe°m›/¼°’ïª7[›r%< ÃÀl6Ãl6Ëî Úu:·UX®ÆL`¶T‡ŸrBŪYÓƒ¥z,–eÑÑÑ›ÍVh­u¨HKšÎ;‹Å‚믿^Öj¼VÀ¥ÅW‹ÇqÇüü<6mÚ„èõú‚ÀC›pJ¯“t ^ºjE»S0S“)~¥›W8 ­j,@lÞÌWÀ‰^Ò.@õ\ZBªþ§òú€£ÌLÚÄ•‚´\¶^-àªz¨‡122‚P(„­[·bÆ Õœ\_‹ä|$Áðð0‰zzzpå•W–}cja\•<5éðù|"ØVÊté¹Ë]‚ï½÷`2™`2™DgŽãóeô|(±r'¼ÏáVúî»Ïœu ])±QÓi§&ètòY¬úÜ›0å5‹„ºR©×ªÜGú€“ªÿ¥l]*˜•®d Í~Òé4‰DuBÅ\=Ö5×\#æ±ôz=‰„fàÑÒé§àâ8˜››Coo/xž‡Ýn¯P/´ºö4Ñhñxóóóعs'Ö¯__uÀ²,, 6nÜ(ËPV–['0²V´µYà÷³B`OccBÞè׿^ÑXuu)릴†Š4\|þùxNÝ" 0¿Q,-ø– Q/¥Wµ‡RGêL&#‚Y(ÂÔԢѨøð“†™å”ó©±m.ɸhkbbmmm8pà¬Vy)­Éuºd_)õU«œ'„àâÅ‹ƒÕj‹¡•šMjI”—øÔn›Éd0==©©)èõzlݺUT\×â‰[(7B‹‰iý]0KV8ncQ3?ôõ¶¡É½^Õ{÷ò˜šŠâ•WX<ü°‘H©&²ÂÏÎN9 ^ê9®jN'²o:–——144„ööv„B!¸\.QýŸ[ÊTh/ƒeÙ<œQ \~¿ï¾û.X–Å5×\#.µÖ"Ô£“³à¢:¬b7V0ÃÂ;v »»[|ïZtú)‡qy½^ A¯×ã†nÀÈÈHÑ󤦯T È—:nNôôôÀçÂaS‰¼`·‡ÀóÍÙR1Ô$<,ļ>ô! Ñì¾V+°eK‹â¾:ccQY±x½W=zq‚4£··WáÐ|]H$0›Í2 £vÙápX•D£ p™L&ôõõaÆ ŽŸ5zrÑÏæ8®"‡êð tc¥R)ŒãÂ… èëëÃæÍ›óD™kÑ釂K1€H$×ëÅÖ­[±qãFUÛU›q©Í%¯ d`2qx÷Ý32y+VÅüªª , tv ÿ8Yÿ/@Þº ¢$#ÌëUÇUO`šûP-¤þ— fççç‘L&ñ‹_ü~¿mmmøãÿˆ={ö(6F. \V«UÌs” õ´„Š´™ÖBiéˆ"v†¶ÛíŠ!®Vð©Õ¶4<‡ÓéÌ“f¬FoÅJ>¿Ô³+™Ô㓟ü(ž{Î |…B¢öŒæP¤ÉÿZOÊ`9¦…ôØ ÔGÉÏ¥\jöÉ`0 ££C&ìN&“ˆF£x饗ðÞ{ïáî»ïÆòò2n¿ýv¼ôÒKåå¸Ô‡VT-à'5ô3 ðûý¢Uή]»DÍŠÖYµKã~œ@ IDAT €è¾ó<_P±_k[›JÜ!¦¦€P¨ô 0øä'Û0>n—ߥ+VÒ$/eßóóó°ÛíŠw*Ô#l%Œ]‘j´µå;C4€K=pUzL&î¼óNÑ`ôí·ßÆÂ–––Êc\Õ싨ü´€Ã0ˆÇãƒËåÂæÍ›Ñ××§*g¦õ»Óé´fУþ^‹‹‹Ø¼y3úûû‹ª¢ÕX7¯ã*Ý¡'?dt»å^WÒ+ºàÀqü~?Ξ=+æE’ɤX®BÿUR®Bmx¤6:Òý €Ó§Y\wŸ—›Žk5BÅrG8Fkk+†Aoo¯,_VUÆU ßy-àAo¨Ó§OÃápààÁƒEIÖ |*a6™L b©Î ÆôÒï,,ZBIµ“3ׇ+¿±…ô÷•÷8ÊŒ&÷ž¢Ú²+¯¼:ÉdRde´YÏóyú²R ïüF&/T¼õV ~ûÛöíãŒk €K.Q3ã¢Ém-'²ÒpÓëõbxx„lß¾›6mZu¶§%lÇq¸êª«àt:knû\MÆU ººž{.ŽHøÔ§V4TííB-b%ó_©öNj‰¼°° v@–Y®ŽˆÖ0zü>ö1«¤¶’(æºxžA @ÐÞ^yA|#ÇUãÚ¼ysí«ÆT xÐbèP(„mÛ¶aÆ û;ÖãâySSS¢]ŽÔs¿Ræ´Ú«Š”aµ¶Ê“ñn7ƒÏ^ê+„[ #$à?ó™••;ij…Š•¿Ÿß¯SÌÍI…a€³gOÂnµ ª'¨ÇP±.r\j'—Ö•E%Æ&-†Þ°aƒ¬°»š¬©VÊyi©N.CÔ˜µn–! )Ãr8xx<¬ÜEŸ«öv‚'žˆã®»¬2ö’Ûº¡¢ºãSõ.ôõíË õ˜©T çÏŸÇÔÔ”,_¶vÈ´PQÓª¢Và)w{*I „`qq£££°X,ª:Cke\Õdk…Juªò­VŽ+Wîàõ Ž ˆ¤,KØ/¥,/ «ÛÛyIGjå–_kÁ¸ò[—(É6‚ Z¡Ó Oÿ`0ˆ­[·‚eY„B!™å’¾¬Öaåå*V…q­F¨H·…BB<ÇöíÛ±nÝ:Uû°Ve;RðÉ-Õ9xð`ÑVä•2§Z‡ŠR-©Ü2,†!Ša!˜×ËÀn&¿ËÅÀá(n]³šŒ‹¶.»ï> ÊŒbÈèñ°Ø±Ã*ææ!0 °ÛíbEC®òÒÒÆÆÆòL÷*éR½ì¦ÞBEBˆ(@]µ—Vj À[o½…M›6aß¾}e­¶i µ2®@ €óçÏ#“Ém®Q-Ƶ¬så° ;Š2²ÐÐçc0=˶®Y«Amu¶o·ÂëeŽ)?7§”œW²C¦–?T’AM÷ ƒ ÈŠY»4×*W¥¡"-†ž˜˜Ë²E‹¡k >•Þ<Édo¿ývÉRj2®Z¯* bKAî@ ÿÔuðYIÐ;ííÚ«–á–^/¸@Ü?e^ÊBTš›S+@•Zþ¬_¿^œÐ”•Q3ÆD"!öB´Ùlb¾Líýs¹æ¸ª¦ãªU¨è÷û1<<Œt:7ÂëõVZ¸*í†] pÑ®:### „ààÁƒ%Kuª˜jK~´„ZtÛ½{y G±m›^/« ´(+ã8‚W^aqø0JæW­óxƒƒ,|Ð ‡…ÕÊ#e©½]`ŸZä:v»]¶@CÛ‡…B!,//‹íÊYd×3pÑê-ÀÅqb±˜vàªãJ&“•Cû|>¸Ýn y Vóª¢Ú3‹y¸-[¶`ll¬lÐR›«ªæv•²œP*@KÊÆóù=j…ÓÉãùç×FÃ%ŸX+bXžî»ÏŒåeaŸc±bõ•+³š P©b!‹ìÜ&“ÉTwÀUFÔ¶YÚ¡æ9®X,V‘ggg111ÎÎNY1t5t`Z’ójh®Tž±iÓ&ìÝ»WáÕ QW[9Ÿ_ÚêÔ#°úÑpIeíí|Ää …ŽÁç[ kº²ÈV²ü1™Là8‹‹‹èì쬪åÏZW$ÛÚ\³¢Z¡"-†fF1y½–-ʤ~^J'ªö‡‡‡a6›eòŒt:­©?b­’ó^¯Ñhv»½lë—Üãx÷]éôŠ¢¹™  c§Ôr»å¬v¨˜+ë7Í %óv,K09É®‰r¾åO(™3gÄŠ jù#]É,'_V-à¢SZ—Úý®i¨Ç122"CoܸQq§Ö¸(X)A,Ãðð0¶oߎžžÙ…QËÖ*ÍU•˸‰†††à÷ûaµZ155Bˆ,̰Ùl% aéçÓI¬0­H¤Ô)geZ4\ÕÅml <ø ?þ1ê"4“ZþìܹF£ÉdRLþ{½^LMMUdù£¸ªÕVÍ>ÖDQ¨ºT¨WiÜ®¸¨»¸xž»ê¬[·‡RôÃ× \•ì3 @'ø‹•Ë„ÌÍÍall ]]]Ø¿¿ØßކÁ`ÓÓÓb¨AW²èÒ<ÝéMSxÒöÛ€—^Šá‘G„âëJ4\Õ •],Ô–”1F£†º©U¤÷*½ÿhLi¾Œv¨¦M]ÕXþÔp©uy©j¨˜[ ½oß>™I~)ÖSiý•V_,)ˆ,//ãüùóÐétŠ¥:…€k5rUÌéÓèÿó?ÇV¤»é'Úº#o½…˜^kûúÐ10€ !H¥R+Í=-¬oj¶oÇóâ 0;;+®fÙl6$“I1üµÛ™ U‹ÿ~Í5<ÆÆŠ·[­P1WÖ!t¥.¶Cv;A($Wý[­éº.¥{+·CµËi·µ®H$‚æææÕc\:©T ƒƒƒƒ‹¡ÕW%¢¼j„š‰DSSSp»Ýb©N)-·?¢&°åyî¹X^þv»ÁÞ~;šYý~–Ãó ÝÝH¾ð°k—ð=ƒƒ0?ðX— |WâÇ£}ï^Ñ-®fщ¡PÉd'OžDkk+¾ñuøË¿P 7èê""X­Vû±RƒÊ:¶o·by™jÒ å·üⱬ³…ÀŸy&Œhu\åvŒV²ü¡ù2ÊÈçææJ¥*²È®¦m³fÆ¥fp‡……¤R)X,™B9'U«¤¡Òm…º<gΜÃáÀ¡C‡Š–ê” 3Áó€Ï'üÞÞ^Јª ã’®ÛK·õùÀH0<}0t», Cbx`˜xŒÇ#lãñÀüÀˆŽ‰4ˆ!æxf§ÝÝÝ0ˆD"èííÅo¤ð¥/mP}.ÛÛ+ k*Ò AV$ž›‹“ïáÃò†µé4‡“'Q7òƒjI!ôz½Ìò@žEöÄÄ!y%LMMM²ësÉ„ŠÒbhš¿Ú¹s§&‘ÞjW ;mÙ²êD91§OÃpô(˜,+"H¿ôȾ}ªsê ÷ÜÆíq:‘>qdß>0¿ÿ= ñ²iFæVÚ1<ÆãAk?âÏ<Öå’ãr.ñ山瞃ÞhÌÖÚÙð7c•%æ‹å…^ÿáÿ‡mÇö!7JÓo%Ï_­CŹ®üP—eÇOfÃIé?Ru ­àRÅ,²C¡æææ‰D ×ëe@–J¥V­ÜGãRbT„‹Å°}ûv´··ã•W^ѤœÕâ0AÙšÚ%ët:±±1\¼xýýýày^Q­Ëœ>-ÉÒ’˜SÊ!€x†»ï^ å„„ wßÔô4 ÓÉ&qîyeN‚áÈ0Ýnš›Ád…y²i–ݾ¬0á0ÌŸþ4x‡Œ× ††éì̵x>Y>üaìäy¤ÚÛáúéKp¹ÈeÉ¿‘AÃ÷2îü‡Ã›Ðޞ¸€#Ö!8>óY˜ÊïÝ»&“‚ÒŠ‡Éc]<|ùË&lßÎãÁWLþóô¸”æ®Ev&“‘åË\.b±t:Î;§¸è£–q©QÍ—*¦ÓiŒcaaAaJ5\Zè¢*ýÎRÀEÉ­­­bWÇ“Ÿo¢9%ªèw»a¸ç„r$<σyå09ꆆnýýàþñ¡ÿÊWD4ÿûXÎÞà8î¾[-q{B@$ •û(+ °Âüèþ2 XÖmÛòÉ<6F‡ÁçC×'îBg§;k¨œ ’ŽGcÿ6ÕðÙÏnÀ»E`4Ýw|gÏ¢IiY^™U×MxüqSý™\pzß}+ ><Ÿø„ O>Y?Uâkm"¨Óé`³Ùd ÷±±1Äb1X­VÑ";N—eù‡ea«fà"„`aaccc°Ùl¸é¦›d±(žqWñòjµ»Y+ʯ¸â tuu‰'Pñ»¼œ––«¤dY|*Ã'?™Çzˆ¼ôŸýìŠjÓíÆúÏ}s/¾(°º»ïãõ%ᡌÜÀþ¦«Q,wß ÒÚ „ByßqûðgÁ—á«ò»ty{ üJNÎãÁàï~´µÉteöñq4ìc+ÌìÙg§s%oW…Qª-™tHKœxžÛ­C Ü÷ƒ\¥ÒD¢®0ÇògnnÀË/¿Œááa<ù䓨¶mž~úi:tH9gYj‡®¹ælÙ²¥äNÕÂw¾Üíiž*‹áwÞÁ¹sç°eËÜpà ùI?ŽÂ7Žý£ SIƒ4T!Ìùó0nÞ Óúõ0nÞ æ·¿…!Í÷Ðt8À=ù$U2çýg'‹H@M й¯Ù@7Á £á6fpœ¿¬ß·òŠß/;8ëöíhéëƒõúëÁ·¶B)õÄò< ^/zöíCûÖ­0ö÷cæW¿ÂÂÂB¡PY:¸@ðùX(;ž2xýõ0FF¢Ø»—ggËâê«“?U®Bó¶¿¿ÿóþO455á?ø<¾óï`ëÖ­·+yôjOVàÑÊØX–E:Æää$Þxã ˜L&:t¨ –ùÿ#Y•c²!óïÿ.‚“áÈ19ϸݰQ†äv‹…Ü‘úýïÁß~;ÒÇçaY¤fgÁíÞ«¾òyµ2à õÊ+HÎσtt A@º»‘¹ùf¶6ùg´¶‚/àÎÊwv"ñýïƒo³ãeüºàV€¸b{ÄeÏcN{޼$‡B`¾ÿ~ «%£«™¬× V²æ¯,óc €_ø¼μóÞü?ÿƒo¿ññq¸Ýn$‰‚2 *‡ ¾ùô›†€e jÁŽVœ>ÍŠ2<ÚÀ¶[“Õ›m³V!DTÎwvvâ£ý¨¨ú¯89¿À£Uýï¿ÿ¾ºR#Žƒá¯þ*¿ÊŽa`ø«¿sNy«|ÒßyX^X$$ÃÀøáƒq¹dlJüêÿÐéÀ†B0ù|òÏçy`Û6áórfŲJâß]]H¾ð˜P¬äó…9s-×\“Ç;¢§Oíí˜=|×ÜtÂ=xGðþ n¬+* à„n¬C\øÓS|7ëñ e`@uЩ”—3,/ãº_ÿÆãÇÁº\àŒ}ë[˜Ù°‘HF£Q¬Ã´Ùlâ’¼réÑV?üa xž‘õ‚Të~Ú`\Ú¨j¼¸T1®r€k-’óÉdï½÷’É$:;;±ÿþ Åó`~ÿ{ûûÁx £.Þzë-ØÚÚðÎ×¾&¬TÒÏ;qBA–Eú§?-ЪTFº;ï”hüøqª€v8?~Ðé”_g€ç±á±Ç Ïº†kÔcÃG®(=,2èÇ ÚXÙçœëP¸ŸNûŽ far… 3<ÖíFK?ì]]ذgvÞ|3ö=ŠCÙE™M›6eYÌÏ_ÀÃ7‹aa…Q9üæYÕw?­HÔ#pi13¤Eà5 ÖKr> âüùóà8»wï†ÃáÀ©S§ “R&T„µ–$§é_ý ˆD`ø‹¿€ñ¶ÛpmG.üð‡ÀÑ£@¶ÈY&¡ÈN.¾³oùËHøýØ¿?2™ Þ]^Fjj J6 äÈ®.ÀåZ g¼ÝßÐ\Õò2ÐÕµzÒÃÞ»ÑÑѼÏ/ô:è³a2b‡ÝíÁÜù0€VųÂ0ÀÓ–¿•‡¬¹àÍwt€Y^V4ÆÉf†µg Ë ç…MuÄÏ‘JNü~A«6=¦®.tuuÁçüþ&8Ι®øˆy½ ÆUkÆUŽmsÕW­“óétçÏŸÇŸþô'8N8p@¬©*jßœ“ª ™`ÄáCËʾføô§E4øýØðùÏ “&+¡²¨èo~ƒÁßüÿ÷_ÿùn¼ñF´´´¬” ±ìJX>s~ñE › $N'Ò¯½†àØþï³Ï"µ°€Ôü<’‹‹HMO+ÖCŠÌ§Àçç½n·ƒs8pй=¸€øÐÃ.bÊ£|3=ñD~÷ýǽÈf÷“ooÏ Eãÿú¯y„Bz|*¡` ÃóˆÿÃ?ܶ“c°¬[·"ò‡Að¼Žø‹/æ…¢ü‘#ù¹µöö|ÉËŠïá³ Ç}á òmUæÉ€x—£bç#†ÿcÏý2Œ[ZOázàC'ÜpÂ.øÐEvþôý×13¹s~9bE:†ËåB$Áo¼sçÎannÁ`PóbÒå\´ÙŒ–P1Ãb±¨fmu**Ý‘HçÏŸW,Õ)µ=sú4 ÇŽ ŽEÛ¹¯ï¸¤½Äfݤun€×+†ƒ\{»LQÇq~bÑhW]u•Øü@Ž*ý¸(8Ip¥>÷j†·–ÈÊ24O +Éd^ò’ý,ŠÆ¤.—lé´|Ye‘øþ÷aúú×Á¸\HÛíà$y9ºm±õÍÜÿÓ`–0ïµ@÷0 \‹fX!<á;°²zë$.8¿чÆ]3ZZ¡äââ¢X_È€q5ì‘븪ÕáG­m³*àZ­P1wû’¥:¥€+•‚á®»*/§‘H DUz¶ì'ý«_Ápï½ÀÒ¸övLýó?£/ëËE-Ÿ{zzpíµ×Üg-Í2( ­ÅimåÑÞžD `,š¢y ÉIûöñ%7Ðx-Ùº6郻ývp=„Àì,F––pc¶ÜGÜÖçCó–-“Fáêú“ƒ°BÊfk&YØV†bBÀÐ"ôãÇÁ +¼Y9„Ô»*×€‘Ú#Kí^( U»O½é¸è¼Ó¦åxqUqU+Tt»ÝBSSn¼ñFU=RCKy EºŠ<£³S´¶¡IõqÉT ~¿çÏŸÃ0%-Ÿ¥¹\Ò⺪î:0øÇ<‡Çß—‹)1„Feµ£€Æó໺YJ–¹‡Cdh¼Í&”ZånÛÙ‰Ä~€¦Ï^ôÝO|÷»à®¹-’òº;~´Ã!aUJ‡°c¼^Xn½UXTéê‚é{ßÛÕ%<ÌhaºÝ.¶£BI©ÝK0Äââ"‰„Ì!Áf³uH¸T—N§ÓtLtE±jŒkµBEºýàà`Á®:¥€/™L ¥<´tGá \2'¢tC3 àp 53³²ÌŸ€ÄãÏçÃââ"Ð××§ºU{%OO)ãªÕBÑÜŒ ÒY¬¬õ=¹¡£(Ë(q|ÜÇ>†Èý÷ ÀÆÂµÈB†AÊ։ݺ9Ì/[Á‚/Y>ÅH˜=ŒÇƒ Ÿý,Ö3 Œ‹l™¿XÖ’Gg·‹v/½½½äŽ¢.— Yf+ï¼TŽ«J½—–QŽWÝ„Š<ÏãÂ… àyF£±`WUŒmvVÆ´ÊÑå¸ðt WäÒºBBàr¹0;; N'z{Õ€j \™ ƒ/}i‚A¹äAùëœÎÊ[”e¨¹÷ôz@j’ „N'¸ãÇ1¼' ßS?@ç¨ÄB’NÅ}Áð<ôÀÊb]”É–.ÅŸ{æ,h–˜ë(šÛäurrRlZ!Uüë/x¹WÕCE5+`•†ŠËËËÿ¾âŠ+*: ¢;ĦMB.*GUvˆÈ0@S’ÃÃy+wñxCCCp:à8®,ÐÊe\õ\ƒƒ,î¹g½ìŒ¬|U¾òíé§cÚ5ra‡P @øî ‹þŸÏÂC>ƒ‡mÿŽ =†n²T´ÃÇÜaÖÛ|ÿýby–’§¿ÒuÏmòšN§E óù|˜žžF&“AKK‹,ñO}Þ/Gà*Ƕ¹&¡¢Úœ m_ïr¹°eËlذ¿ûÝïÀq\ÅUæ™LÐëÁ=ñô<¢éxžr, # _fgg1>>.ö‹\ZZ‚;Çùt5W1Àã8>ŸÍÍͪÐæ¯~¡4w~u¤Ó)4–¨U¸ª¥]¬yèñLø..³'«6 кjš{L<Ï  ¡¢ •륖{_ä<}OÿååüÇMû"J}Þi·jŸÏ‡¹¹9LNNʺUÛl6X,–UWùW¸B¡Põ—ÚP±pÑRt:-–êH¿C«ï¼l[£é—_¬i*Y]Ìr™Œ(ËèëëÃÀÀ€ì"i®J$t»Üë‘N§122‚¥¥%lÛ¶ N§<Ï## ÊZ³Ó›œ‚™Ñh,ÒñY™w¿KþÆ IDAT¼óN““,¶nµÂãaen õ2”Ž)–Ð…n¸ ³-ju]"¥ÀÄã@<¾RÁIJ±hsÉ* ºN§ ívÌÍÍa×®]0™Lbˆ¹¸¸ˆ±±11•æË*éUºŒkÆ Õ.µ9–eÁqœÌ•N*Úd£¿¿›7oV<Ðj·(#[¶”-‰ S4õî»ðd2Êz{)9¨j.ºm%!Q.p---axx­­­8xð L&R©T^ߟ;wîĺu늲8©u®41  ÑÙ9 –íð „E<tvf°¼¬“­*†Ã î¿ß,¨¢AQ£PqpŃšáñ°p8xÄb@4ÊâmÜ€ýø#^ÆŸ¡nð`¡_±93¡Æ>Ÿ¬—ú ù|%ö•[ Ç'MüKIÕ•IY7mXAÁLm.´jåt±.+TT› §à‰D044„h4Š;w¢»»»äçhí­˜7aC!ÕŒ‹>u3øÓ¿!8xð`É ª¸Ô„à…†ËåÂÌÌ :::D–UÉ„7 èììDgg§¢{‚׫ϛ¦„ Û¶,7ºæµ¦wªÈJVó°¼LWG…+ý6nÀz\„AÑŠM˜Á¶jûÒ@¬B‹º¼„}…Mr)(gUQ)ñO¼ƒAÌÌÌ ‰Àd2ÉreåôD¼¤W)p¥R)Œaff½½½EË^Š_U—ÝÒÞ.{i‹£_ü".îÝ‹+víéw­XS¥ÛÆãqð<™™™‚u•²»p88,/³ày6Ûá†Àã¡“^n,#ä°™ì±Éújå…µ†ŠJ‰ùü‡•~aô 6Ët`Y I[¢ƒƒð}ë[Øô£•Lè[?ò‘¼D>@$µ¬ìÛo ÝÃ=žŠšäÒóRi¨§Ôà•ã81ñ 1??t:—ø/T‡ÉqÌf³¦k½f%?”2ž?‹Eu©NµCE™ƒe‘þ—ñá‡K?™b1ìúêWq¥Ó îÄ ½^Õ±Ò<½‰Ô]Ã0ؽ{7:³Í8ª—§ž~ÚƒO}ª~¿ Áã'ñ÷oB$’¿âHÛnOâK_z <ÏatÔ&&þ©îh-BÅÜÄ<ËEðêìZ–ñ<‹Û™ÿÄËÌQtñK YPA{;Ö?^:/*ÐPå7¤RÂù=}Z,%„>冑bY[sTz½mmm¢s0­Ã¤‰ÿ .`tt,ËÊte­­­0 Uc\j½¸ª*Æãq #‹¡»»W_}uE7]5z+æÆÛä®» šÖ)%_·†Ã‡#»®.¤_|±°×Õ*%ç£Ñ(Î;‡D"={öàܹs5+²½æš4ž}öU\qÅ~´¶;vX‰0k¡ÙÄôt éô²‚ãááaQwD¬Ü–앆ˆ4 {üñ$>ÿù•Ð×jåÊSïÉ$`·ø| fû0üì,[ü+J~ŸFIû´\–ÅHÔø" 冊‘ôO<Ó7¿)¯ê ¤lÝW-€Ki¾Ó:LÊè©C)½Æ´Ób±ˆ^\ápV«µ¢}[U Y&''ÑÝÝÎÎN´¶¶Vü¤Ô\ôdå¡¿^î©§DAj)Y¥ÌIÓå‚áÎ;‘ZX L8­9®bÛJÏï† D‡ -¹1uûEÐÖ&Ô˵]y0B€ùy ¯OXá¢7:ÕÑÄ? ?r—ê å+9¾ÁA6Û Cg¤R+JžGh IaSSattPâÓ&£n©Ž|¾•‘9ö;ÄéI§ÁøýŽM_ø‚²7Àœ_äᘛOÒÊF+_”e­ÉB¡FGG‰DðÎ;玑«2PºÖ«\>ŸO,Õ¡]uΞ=»f½¥Œ+>þq¤|Ìw¿ ÃW¾"Óu•da~?Œ}}Hÿïÿ­È¼jŸ¨à5“Éäu-ª%pI'„Ý47ó9a¢œw0ŒPç¬t=¨îH~P ›“”‘åÖè•39s“ñn÷JŒâWšÁò2ƒn°â…th,‹‘ú'ìüâaðzÁ;B^jß>p=$–±¯¼ëÑ£%½Â ‡ùÁU‡‹41_VÒF£˜ššB?:;;Å:Ì`0ˆ©©)D£QñKë0¥ä"‰€RÛP1·T‡6"К\׺½R7kY8›LÂòío¯0¬Â•ÃùÃãáž{šž–ß\<]0’›[ÓÀ¸xžÇää$¦§§¯åæÆ´$ÆWXJÁfhªO¡4ü 604) Å=ºT¯×ë‘N§‘J¥TÜ¿ú*+c‡rÐRs‰;fÆôt¾-²s'Æÿðô¶¶Ê‹Á¥åE‡ *úœîQ²kk2I&óÚÜ•.ֳ߼R§jŽãÄ\™’ãòò²8gk²ª˜[ªsðàÁ¼•N‡T6Y)kÒº}ž5[_8óÎ;ø¯’^…LŒ…„F°’›‹9}†{îii ÿÕf^z ¸ñFMŒ+àìÙ³ÐétE7Š1.êŽ*­¥OèR7¼bEB:7Wäe@ssr£-IáX,†`0ˆ¥¥%$ œdj€ëRîb˼ô£áá‡Æ'>ñ |èCŸþô'œ:uª:Àe4át:Ñ××Wt׺›µ&&&077'+1JŸ8!´)[ZÊï@†ƒ4ao´Û ¿‡!‘¿¸¨ú&dFôdjÊöT£eÉe\”eQ bF¬O£!%4úy¨Éâlb~(4‱±(~ðƒ{¬©`Høýï'P @OI@IËZ‚Á &&& ÅÐÜüQD"”g)áÖV¢HªJÏ >`Ù™šo'j£cce‰PëqÑ£0M¥RhnnÆßþíßV×Õ`0` Dët­ÉõjmïóùpöìY455ᦛn’h¹ì÷øk—ÌW¾¼ ¢Àë˜?üäC*ùét‘H>ŸÛ·o—u*¸(Q ¢LJ æÒŸôæ—²³ÜÕCžgár~?LaËGZ‹åCúí·s«:QrË–Y|îsæìB1áK®,4ß±¾NšzÎX‰Í´ZÈL~ãe+çë±Ã{•Žrm›…Gm™ÉùZ%×µnŸL&‘H$0==Í›7ã†nPf/,+èo|¾’½ùÔ– ä?ö±’k·Û“'O‚çyôõõaÓ¦Me]4šœçy™L™LF–ËRÃLu:ŒFcÖ¡Ó öþŸ «‹‡ÕÊ!•âpß}fäg„÷ԲħԱЕĕò#µWOùÊû|,í2—Ÿã*¶/v»Ð>Z©<>Ó×¾¦~uC–]®~ÊŠ®ªyµjQVŠªÎÏÏãäÉ“`[·n-Í^ìvîî•F¯…òZ(¯‡ tP†‚`‘Râ3gÎàìٳضmÚÛÛ+2‚cF,Ê´5_àðÍoÁf’ÇÁóÏ'`4ðúëFøý¬bHƒƒµY–W#÷ e=å® Òa³%óÀZ ˆK†ŠYÛhBËÄ$ý‹Á(ëvƒ}õÕKšq­E‡Ÿ²€KÍĨvr] şχóçσeYÜpà 2µmÙŒ¶»î:Œüæ7ØùáCõgÔk^¢ý*9Ñ$7³á¿ý7ÙÔ1ùýèþÔ§dåC, -³ý –´¨a#• P¡õÕ p¹\Ã0°Ùl"Ùl6èt:x< ¡µµû÷ï/Xvc· EÈÅÀËáàápÀ0†¼¤îê¥ÄJM>µ€¾w/ÑÑ(ü~à½÷X<ú¨¹D?H»ˆ ù )#óå–-={Ñhï¿ÿ>8ޤV+ºOŸF×ãCçñÈýbý~Xn¹¥`ÃZZ+°z¾+ Õ¸Ô”™¨õ/|…ü†(CX\\ÌSìW#TÕ™LÿçÆÎ/~Q›:`$ÞJŒBþ+wJ)õ+{–ýüç@s3®úó?‡ay¹`17š.–Ë’újÑ<‰  `aaÉdƒÇ¡§§}}}%ýƾó~¸© s9q"%’³²û@*½È`5¬LíÃïÝwWjNßøF_ýª¹àãÅïWgxHË–t:`·Û[¡ŸþÝ_ú’X`](õwRÍí%ùAf\´šbÍ—⩬ûˆø¤›¥ÖÄÅúj-ÒïÜ)†hm…q`@Q°Ê”‹ÆÛn“ç>\. N6Á !3£–*oriQìÆE–e2™ÐÜÜŒ`0(ªÒ¥áess3†Áà ‹{ï5feD¾-`Ͼè>H¯+xÒcSbeåäþrk=?ÞTäj”ß ’F ÃÀb4¢ùË_^i[î¢C°¢o¿×öN-pÕ“u-z*–͸Լ§…Ò™LƒAì_ ±cÇÑš¸ØDI§ÓOC¶ì£X&X¥…¿Ùn.JMgiýc±îÙÙX £Ó‰Ôþ'2{ö€÷ùÀ´µAæ L÷Þ Öíït"uâø={V4hííb'gb‹xê%&Íemß¾]v9ŽÃKǃññq@K‹ ÷Üs#|>FzXyG[¶4áĉ”ê&¹a¢”•Ñßi #!étZÆÆrÙF®a !LÑ\7íNTôvÎq(•é¸ff+/ÔJ^3ÍÍðÿìg0µµU”NiôT¬ãÒÊzè šN§±¸¸ˆ‰‰ ¬[·TUh[õf9 |ý÷Ša$q»åÊ{†ÁÙS§°mr¦¿ù¡'c™76Âxä mm`}>ð]]@,&þßí†ñŽ;½^lÆ@ÚÛ‘úæ7aøêWÁº\²ñƒÍÍÍŠ¹,½^Ÿ§JD"˜™ Áë5ÈÀ ÐðzÜ{¯““‰ŠÜOsYY,ÃÐÐâñ8vîÜ)îW¡¤¿ÝÎÊ †ˆû±Ò­ˆAGŸü$Ž#GxåýÌ‚;5•×™Z¬ù„ùd×3·a¬"ÃjkÃâÏ~K |,‹P8 ¼öZ^·%5Ýxxž¯‹^Š—pi]YdYgΜ!{÷î‹3k šÃI_ #ív°Ï<ý£ 7<Ã`áßÀö]»€]»ºã7o<ž•VW*Ý(BD6Ÿ\ù¦t¡<Ìôù`üÜçä0 röO~o½…õ==ªsKK ®¼²EÁ=T90âùê4É )‘‘8N\sÍ5âUJús`ÍÆá™gx<üp \._ûZ_ÿº ƒ®.‚§žŠáða¾ °R@b].±Œžó±c ?ÿ9B„²§¬4eÓ=Gb]37ß,+[r¹\ˆÇã°X,²br¥‰õ(@½äCE-ÀEë 9îÿoïˣ㨯¬ouk_Zj٭ŲlYÖ®nÉ;Þd;ð I8ÀG àØ²Œ ðA8ld’If2™@&f¶`ì$À0É 966Þ„m$µö­µ¯]Õ-õÞ]õý!ýÊU­ÞU-µ¡ß9>9Á¶ÜU]¿[ïÝwß}Ndff¢¢¢"è"ù– / ær¹Ð²~=zEIRÆ““±XèQo4Î&ö9öÿüOÄîÚå?óòÃ¥Í*3=”­Ç!¦‘›œ4"“µµöŽk „CÌX¤ƒƒtP2 -ÍŽŽŽ‹P*Óù.f0»üìv;š››Á0 ***fùý»ge.;w&ð†Náí·¨©Q`lL†‡NÇQP©X:dÆúõœØizœf^Љ;wò€$t ¡0½¥Gn4Bf4úëñ9d$«f÷mKv»wLæw$ }¬ Å®T$Y~0^\S*ŽA«Õ"11‘ßÞÊÍðåÇrÆåÐjµˆÅæmÛ’’úÊñßQæbŸlÅæn» ÎW^AÌxíHú³™öôf÷d#ÌÓJnÂB{áÀ¼ÅÚµ,::¬˜˜˜>ç_ûZFF(¬ÃE¼[‘ƒa !÷*ŽâéI@¶j1˜©)^¸™œœ,"ýE‹ÒøŒ¼%-- ›6mòK °ì4h Éøš]IHv0˜`ÈüæÕ2v×®$hµ4d2 ±W® ùÎ;E;mÏ>;k3§Ã…lzúô~?îÖ[„„«ñÿöŽ;pËÍH†œÇ¿ÿ®,î¹~¿ù`)vì`sù*ø¤ÈdXâáQ‡Eûöá¯o¼¤ÄD,’Ë‘š›‹‚o~“÷·¢ÆÆwç0·wbçΫàöGF3‹lŒð™W;Š1>¦DQQj,Æ–¬,QÃ#Å)‰>êYþ “KObc§fdeÁrð ïË%3r¡(åg—ÊWu\„#‡ÞÝ]´··SSS|¶+ܶ$O6×fÁäLÇ|AG~|•ŠB/uá|a°ÀNà"W(zMOO÷»ÑÚ›¼»ZÜ£ú}¦ŒãÉá™Cjíì„ý•W¦;†3<™ã‘Gsè¨ÑQØSS!£(ÄÎt©9²Y×m0€›7jd û÷ƒÛ¿¬™ð4x›që-âþÅôXo5eezžÊßx†Áõ…Ľ{36[z:äâËNwO`ddß x{=ºleaç±€!dá#ÆßßYˆ+?ù1â|`–x”òÑ¡fÊx|ÈõΨÞÙÕ«¯všgÊrþóddÀöÓŸ"þG?š·”òžÎ‘7 ðäëïr¹xYâùîr¹šš*’cøÛÄ.Ž‹,L ößK©hµZEÿÌÊåòYó…áΚ‚åǬV+šššÀ0 ÊÊÊøácÿ®;X Û÷äÏxü9î&t‚å ®={`ùÖ·¦÷-_Ž šFÓ7BÁq(Þ°‰ `ÿ{Ä=ö] ˆq»ÿÞÈ}w‚9oØßh‹ ãøÿ©ã“ƒóJT‹ÀO©Dòþý fæBã ‘à—¥(ØÓÒðYçedddaâÆ2¢²ÕÛçÉÆÎ`3äc¸‡dü}òtàƒ?$‹0¸ÌL_yÎmÛ¦KC— 2…”Ë…äo}kzÂa&#Cl,œ»wùk—ˆ2˜KÛU”Ëå³|ý- _^öôô`jjJäë¯P(DÛ–ÂY*)D°¥lXKÅ@æ CáÈü^¨w8ŽÃéÓ§¡R©½º¦·,Ëk̘ÐQcc|RTNÄÄÀ™—‡ö™ûXTT„¥K—N_Ë"öç?¿ªØ§(ÈÁY­~=@}ýv3=?PÒgJÌ@ù9ÖéäøFÇÁ‘’†Ø)d³AŽœT¼öÚ(öïÏ‚~"ÃÈD6Fýþ| ”—µtþ®‹U©`íìŒF° dbJ—ËЦ½¾€ TÎMä6àòôœ'%%ñÝ{Òx"YÙøø8ºººÀ²ì,¬§ó0׌+ WØ€‹(ß™/ô>¡núñ¶Í:‚°¡¡ V«ƒø$Àp–åÆƒÙkk§ËÅ™rÂ^[Ë¿™I¶š˜˜ˆ7Šï£{¶ÆqM{í|QÓ4dF“|ñg¾üœ§ß—¹uPI÷-vÊÀÿwG#ÿ{5PÓmèº8Š3Út<}óÏðî i¯O @ÌÉd°=:íè¡Tòvî{<]‹y|Ù“’ s:çdï#%py;³î›xȶ%âëo6›‘˜˜8kÛ’À¬msXJE—˃Á€ÉÉÉ€K-÷›h±Xæ\ÞL²º¬½½ÙÙÙ i:(¥¾;p'‡`IÙµkaíè•D;88ˆÂÂBäååÍþ™²5ÊÌ‘É*\ï¾ ùwn6gL ä‚L—ML„ÜbñêÔL¶æë÷½ê¡X1Yì0lË ‘ÌŒb²±¶9,#ójlfæt7ÓÇ–i~†2>~Ö Ètèd‚¡yáY teœÔdx gÝ›m’ÑhÄèè(:::øÏ344‡ÃðØ’;Ç,1tÆåËÚ†eYär9ª««ƒ¾)8.r3¹a°ÛíX³f 2220004GFÊR½^ææfžOðgã)ó"åÙ?;Ëò“­qÇ´H’_ ÁLt[k×Âzá’–/ñN1N'.]‚©½£YYè°à?k¬xß:ëòêÒ<9·;P!†™î4fbr°!ý›~ÿNf&lo¼vûöà,gÜ^@rŠ‚³í}ÈKNx®<­Œóô¬-”rÞ›mY[ØÖÖÆ …%¦§±%Oׂ”ŠƒZ­.— ÅÅÅÐét!Ö\Ëß6krû»»ÑÙÙ‰eË–¡¨¨HÔ^ôßrYYYYˆåWËkµZÄÇÇC©TäF*|›¶··ûβüÙ¥Kâ²óȰ……bb8#ÃcY£,.†²¤KT­áð¨*CcÓ<’¿²‘ÀbÆÑ8)•àh:°Í xôP!Wç h¹@‰šþš>ï¿B‰ÿw$ÞtbB|~…/ ÷_UÛß IDATª»½pö2¬LHA,t3K(--Ell,?¶D”þ±%¡@VHæ/p‘E¦}}}(((@AA&''ù¥¡×\퟽eMƒà86l@º›ž&Ю¤;—‹ììlÑjy¡ikk+oJG~) ÑHÓ4x>³,?‡ÅSÙ,¯6})Ôsáá[ÿ€£ÌW"úýç–Ë—‘¸zµ×e"ž~î0²ñÿÒÞÆ[º°C®E X8!%\T ²¸‘鮟Ó9íäAÀxñâi±±€L>5…ô‡Â__)©©¢ï+!!ARg ö>îYÙ\ö9„#Ü7üø[€Ífã²uuu ?9/,GGGÑÔÔ„ÄÄDÑþÂ…^ ëéï»\.ttt@§Óñëé­åodÈ“²§‡ÙÝ.†(œ†MÓèééËåâßB&“ z½………AíW æ­¯ækײøÕåÍZ‘LŒð™ hd`1&x qB†Q¨@âË8Ù?ãFy-ÞµTåЂ1dàG½f<Áýoâ6ä`£ÈÄÿÅ{¸ï·ì½U?} /!þ®;!€1€øÛn›µCÓcÙʲˆ§il«¬CQ`½½½Ðjµˆ‹‹Ù`K)âô”•¹/òu¹\æÏ ÝnŸ³§¿Àå¾ÇÓýšÜÇ–¬V+ŒF#ÆÇÇqàÀ´µµ!66 Ã`óæÍøÆ7¾¢¢"é3.«ÕŠ––Ñ|¡ðƒÇÄĈv()‹¦i444 66›6mò™–ú*Cê ~.I——/_ÎwmÐßßσáÐÐ,‹è-æ|ß/Àe,–áåŸñ&}ÛÌ<`&nÅø ë°'p5ÈÁÈ ¼ü6 ä`aSf@÷òˈµ9°L•ùø(îª ÕS7s3a¤Ò!£8TV&¸¹@ `€BïXìù¶—.ÉpçÎ-D‘ŠÆïßMÂÚµÓ?Ñ¢Ó4 G]ï»qÃÕQ7ƒHN¥B|V²(Jä=O²½^ÏË…âˆ(`KK hšFUUbcc./à \Ánø!¾þ™™™8þ<î¿ÿ~ÄÄÄ ²²gÏžEYY™ôÀEf/^ŒêêjjWòÆp:! _J•q9N´µµa``………ÈÏÏHH:kæ0À,+˜`Yýýýèïïç³,›ÍƒÁÀgd“““¢­=J¥Ò/Ñ.l{äUȽY p7 ƒ³þ;RQÁà/çhœ?çÀc×å¢@ÿl£3¼•'>jœÊÄÿåÞ(¡£)n¦D$1:*ƒ^ÜygÆÆ(p Ð1‘;ï⮚Êdu¹Ð””„Åý+Jsr“‘uv"î®»¼–Ìä™r— ˜L&~< GŒÃh4¢¾¾ž—ÃÏœT¤ÿ\k.a2™°iÓ&<ñÄá+9ŽCUU_ÃzŽ@;{á.™L†aÐÜÜÌ—±„D –›K–å-†ámq6nÜÈ6÷ 3N§St0Üy2¥R)y¹â-¶og¡ÊFGÓá.Žp’éß¹úß&ØEèëOÁSOÅa(\Äz°)0€¥Pá*o5 *ЄØEiøõKÔÔxo ÈdÓCÔ€Ø1Bhn¨P¸ø=‰DžA³€]·Î?'è2!~ZK—.ŸŽÞxMg­¯¯ííí(((ðøâõGú -YÙB¹Ÿ \Ë–-ó *RøÎ‡ª~·Ûí°X,0(-- ¨+ç©T G–Ex¶þþ~¬\¹Rd‹ã­dvo?Fþpy2Ò½LKK“ÜÖ—ã8ŒŒ ã‘GÆðÜs½‚ˆw ¦pà ñ¢?/¶[ñ¾ ›æ­dãjjâ}0RÀâÅjkíP*1˱U¥â —O¢®®I$&&†\2û‹¸8#®®6sÿ¾ …¨¼ôT•8~ך5køqp‘þ¾<ýç¸LáéÐI±0#˜C8<<Œ¦¦&@AA–-[R¶&\mî,+ØÏFÞܞʕÁÁA¾c#”a„:MØl6466Âb±`ýúõAeÞ†…R »ÝÎg›R‹™ÇÆÆÐØØˆœœó÷ÜSyéôÕ¶9bKEáßgY===èììÄÒ¥K½Z>’qI¥Ë¢(ŠeòYYY°X,hmm…Õjuø”Jåœ;DR¿ñ{{{ÑÑÑeË–aåÊ•üC˜˜˜È›Ì9þP ðú$!q\ bbdxõU;î¿?<טžÎ">3‹ü@‹ââh4ꀬˆ|a‘ÑÂ' ¼Ôß™^¯GCC”J%*++笶ŽÕN:)/‰Ãéää$ïpJ®+P‡SáóÒÙÙ‰ÞÞ^”——Ïò¬ó¦)óEúÓ4˜˜˜@•â8Ž æÃbò×ÚÚ —Ë…òòò¾Œºº:äåå!%%p¹\P«ÕéYt:&&&°fÍš9eYþ‚eYtuuA§ÓaÅŠ|Ê,LƒišæÆÔÔ”HYM¬o¢T±X,üšûŠŠŠ tB²™¦i p'8é é445ÅâÑGãfx¯`MfÄ™›LÆáÄ Ö¬aÑÝ­G__”Êt”——K6fãÎ'1 3K®J“Føó»ººÐÓÓƒ’’¯‹W¡ò¿Ó«¸¼ô–Øív444Àf³¡²²2d D˜™L&ÜsÏ=8~ü8o½àÀE+++CºÀ .ðW+V¬eþ¢¿¿CCCX¿~½(Ë"6ʾ†B £Ñ­V Š¢PQQPªK2fF£qqq¢Œ,Üœ‹ûšû’’’9 VIK[xmv»}& HGss6<##2¤§s`ß«n33Yüä'üð‡±‘!3“Em­kÖL;‘ Ìêv†+„rrè…]Ù@§¬V+ùƒJi$õs ,/†á+÷òÒ`0 ¾¾ééÓ/ )Ψ©©Ajj*jkkyyHØ€‹Ôçþ¢§§4McõêÕ!uY.^¼ˆ˜˜¬]»6èŽÃÐÐt:®»î:Qš:YV0Aw…YY8Gzˆ˜”¦i”——ÏZ 'å¡ Ä8¹¶ÉI€4dg§`󿵂lêjf•™Éâ7ìØ¾ÅŒ>ÏŸ™Í&ÞZ[£Ñ„$à•"„Ó $Û$Ó ÂÌE˜NLL ¡¡‹/Fii©ä“ RYkFžÅÉÉI^­R©ŸŸÔÈ’·gã/ù þþïÿ555øÕ¯~r)4pÙívøû+îYO él{{;úûû‘””„ÌÌÌ€¦Ä݃tZp-d–졘œœMÓüJHK?òX(&-//Ÿw®M8Çwøp<~ñ‹R¸~úÓ!ÜqG rs“!“Q³ô´µµ!///¨Ì{¾2áôÃ0°X,¼ß”Ífƒ^¯Ÿ÷ÒPŠÒR«Õ‚¦idffÂf³a˜99b¸\.üã?þ#^~ùe8p{÷îÓý p ¡§§›6m ê`%$$@­VC§ÓA.—£¤¤$èi||—/_Fvv6222B³Qv”îînôôôÌëø9B #%˜P ïëÁñ%&]ȰÙ\hjšDjªFãôÊKH™ÒÖÖ†a V«½v‘#-l6ÆÆÆÐÕՇÎã'*Á‚%Æç3¦¦¦P__øøxh4þ%ç ¤…¼­7«f½^ûî»ííí¨­­ñÏ\ccchmmÅÖ­[ýò>---Fqq1o¢ ¹O¸,—Ë…‰‰ QÊ› j7299‰ÆÆFÓÛ’› %1š¦a6›E"KaÛ›a466">>jµ:¢UäBy Ã0Ðëõp8üºùE‹Iîw®ƒV«…J¥Bii)ÌâÉ„™t¸†ãC 2ïKºÌþΈ0“&¼-qÄ iš/£÷íÛ‡ââbùäÜxãüÍæ8Ž_›‘‘òòr¯Ã¢½½½Å:/ûìܳ¬¹t )®×ë188³Ù Š¢x~ŒŒóDrÖâMLꮹòÄ%¥¥¥-赑aùÖÖVäææ¢¨¨(àÕﮬÁ`EQ¢Ã>×F*‡ììlK¢¼Žõk ‡ÊŸt/£!¾­›šš`6›g™ÎùUêíí…ÓéœEøÏßâp8x‰Fee%?ÆH¸Û) G_ܯMxà¥âÉ„åUyy¹hЮái¬GJ•¿pN²´´4$•§8{ö,öîÝ‹;vàµ×^ ë¬nЗÓéô;Îãr¹ðÑGá+_ù ?–’’’€nîÈÈ:;;±yóæYe!ù¸RHÈ8Qww7–/_îqû1€#@FÓtÐݽpe*s“ ¯MØ)JMM û¨MÓhllDJJ ***$ÿ7Üû†53„Ó Á2¦( F’ò*Øk Uåïp8ÐØØ“É„ÊÊJI¨–eñꫯâ…^À‹/¾ˆï}ï{áß¶àâ8ÿó?ÿÃkY***&ü€iyDSS¶mÛæ5ËškMÖ,Ë¢¢¢"à uawx³Ù\é¼SÖÎGxRù~“T Ç¡±±ÉÉÉP«Õ’¼lÍf3yä?~‡ÆŽ;æåzƒ.²AÇ׃©Óéø,K­V Ð4+W®`ÇŽaɲt:ººº°lÙ2̹ìsWŠ çI©&U—h¾Å¤RŽ*™Íf¾y Ñh|ôE8Ã'œ^Ò„ßt¹\hmmÅÈÈ***Â6y UŸP>ãr¹x× Ò½œ xuuua÷îÝHIIÁ»ï¾Ë;ñ^sÀEtON§‡«W¯j€—„ÑhħŸ~ŠíÛ·K6®C²,­V —ËT–ÊÛÏý° -”ƒÑ’ ï{$ˆICUBKK rrrPTT1¡ûKMÈ%‘Þ’’‹Å‚ØØØˆ˜5 öûjiiÁèè(?‰â®òvc7©¨î½÷^|ë[߯ýkÉ]Yç¸X–Egg'Ïâܹs()) ªDr§OŸFrr²HojvŽ,+Ø7»È ¯¦ö¦%F$‹I=*±,+²††^¯š2Xè $vgg'’““ár¹x0^WR‡Ð𯲲rÖçôT:»«üSSSEÏ¥ËåÂ?ýÓ?á_ÿõ_ñoÿöo¸ûî»ä4p±,Ë›æ EQP«Õ|sîÜ9äçç‹„xþ!—EZÂä@òKd <ɲœN'***"by‚¯¬…\[jj*o…¢Óé$_¶ÎÃNF•FGG¡×ëL›Å‰Éµ ‚'™ÊØØÔj5ßá#‡ýêyd9«’ðføÈs)3P(xï½÷ V«qøða´µµ¡¶¶Ö«\)¢Ëår¡½½½½½X¹rå,uù… ““PÝHÇPX~"!=ñHÇA§Ó¡³³“ÐÄò„ÜSw½¹r¹EEEÈÎÎŽx¼ðÞwww£»»+W®Dff¦¨üò5ª Aæõbcc¡Ñh|~6¡³*ɦjq¯°úéëëóhøì÷855…¡¡!<ú裨¯¯Ã0¨ªªÂŽ;p÷ÝwcÕªU×p!©V«E\\ÔjµG½ÆåË—¡T*‘ŸŸp– —%$išñHIIIṬHYQèýÕétèèè€R©„\.Ã0"-Ù\œ"‹°ÛíÐh4ÛíÂ…¼„æºUIª{OÜ(¥,à¸/î~w‘žphå¤2üs¿'µµµxøá‡ñðÃã¾ûîÃùóçqæÌÜ~ûí§c"¸ŒF#N:…¢¢"Ÿ¥K}}=’’’PXXè3Ë’Êz†lÑét i/RÀKˆ/Ä¡'bR¡ã«p2ß“–LŠ‘1<<Œææfdee¡¤¤$``ΓŸ+w{hw®%h¡2²úúzþ€›L¦Õ[…úù½þ ÷ºY s÷ºç8ûÛß°oß>Üu×]x饗æ}tg^Ë›™ ;—åÞùr8!i‘„YVyyyDðîË,hš†Óéôx}ĉ‚ã¸÷®æú!>::ÊKLÒÒÒ°hÑ¢ˆÖ’yÊrššŠŠŠ ÄÆÆúUФë ÅðOØ™%¿OVWW‡¥K—¢¡¡/½ô^zé%|ç;ß¹f¶I \BÀòÄeyóµJKKãµVîŠ{–UXX±¥‰·ëKHH€ÅbAVVÊÊÊ®‰…Âk"ÓùùùÈÊʹ ¸kÉæÓ„0ÐÏO………ü2–@^D­J¬e>¿?áÂ\ ÿ„^÷Ï<ó >þøc0 ƒòòr|ík_ÃÍ7ßrqİ--- &“ 6›-¢º0l6a6›¡ÑhfµÚ…fv‘ %óDg?° „`·*Iá0ü¦õ•»ví²eËð‹_ü---8}ú4òóóñôÓO9€Ë_–ìƒB€l``F£‘/MˆEïµPšø“Z,–Y¢Qw ‹„ŒŒ¬ØZ´hJKKþL¾´dó9“¨×ëÑØØÈËL¤º§ó5ªD±Rþq‡cǎᡇÂC=„_|1b_ša-N§äº,‹Å­V ‹Å‚²²2$%%ñ‡@¯×ó™d¸Þò---Ðëõ‰IÝ9@òFº(ÌgÆB燆†PZZ°³‡¯ûáKK6W7U_¥Uqq1–.]ö1!©G•ÐÒÒ"©6ÎápàùçŸÇ[o½…×_·ß~û5ÅgI\Çá®»îByy9¶mÛ†5kÖ̹AÌíííü¶÷·ÉÈ"Ȥ“Úl6™L&Qi¨•O(199‰††ÄÄÄ@­V‡ÅGÝݪH覨u²¿Ò–hËb­Ü\F•„6:F²YÉ‘‘Ü}÷ÝDZcÇPVV†/B„´žì·¿ý-Nœ8O>ù‡7nDuu5¶mÛ†Õ«W•Ú ‹ËËËþÂüyP dá“Úív E•RYB gݼ- ç½ó¦% &c™˜˜@cc#222PVV1%P £Jv»Ý§á_¨ñé§ŸbÏž=ظq#^ýõkjGhXJEáƒwåÊ|üñÇøøãqúôi¸\.lÚ´‰²U«Vy|„"Þ²¬P8²ù²ù“:y*½‚ù v»Z­SSS"7Š… Ó Bxò绺ºÐÛÛ» vÖÁ<£žF•€i£Åüü|dddÌ™à8¯¿þ:ž~úi¼ð xòÉ'¯)¡mØËSÍùòe|üñÇ8yò$NŸ> Žã°yófÈ*++ÑÝÝ3gΠ  åååAíÓ Èhš†Íf“È"EL*’Ò+>>~yúl¤´U*•+Ó ‹ûÂ"¦œ˜˜Çq¨ªª ë¿ptgg'z{{‘›› Žã$Ùªd±XðØcá¿ÿû¿qøða\ýõ×<Ÿvàòd—.]‰'x #\×_=žyæTUUÍ /EÚÛBùE(@ÉbR¡§»•#ëììÄÀÀÀ5‘¥¸‡&“ }}}EQ¢áãH—˜3]o†ÞF•™)Õét¨©©\.ÇÑ£G±|ùr|Q#¬À%Œááa|ûÛ߯•+WpóÍ7cppgÏž…\.ÇÖ­[±uëVlß¾ dÞÖÜGr¸[ù1¹\޼¼Xs“ú²ùêx™L&444€×Õqs¹çž<ɤ^›622‚¦¦¦ –™J úsuÂþ©Õjɶw;üð‡?Äo¼ßÿþ÷øæ7¿ù…”:|¡Ë;w޲O?ý‹/™7ex8Ĥî:2«Õ6  zsssçÅÝÓ“'™»çZ0< yq £¼¼YYY þ\±,+k²'Ñ=ë$×èÏðo.<ß=÷܃¡¡!üñ-¡‰×(ˆJùìÙ³<]¸pYYY" [²d ~õ«_aݺu(..«˜4\@F?0 #éNÀPï¹°«hÖi2™Dc/ ei=°ŽÇøø8T*ÊËË%kÜ\¸p{öìÁºuëðæ›oF„Ǹæù;sæ Ï‘]¸p …ÉÉÉøÞ÷¾‡›nºi^UðR±p!îž‘¤Yò´ÿ‘謄×8>>Žææf~ñɵ4žBÀº½½ãã㈉‰ÓéiÉ”JeH“ ÇáÍ7ßÄSO=…çž{ßÿþ÷¿p£;Qà 28€'Ÿ|_ÿú×±|ùrœ>}Ÿ}öòòòDò ©lJ d±£ù°p‘*„@¦×ëùY=•J…%K–Dœ`4l×ÝðOx ÃðZ2¡úÝŸ–ÌjµâñÇÇ|€ƒâÆoüÒòYQàÄ¡C‡——‡êêjþíf4ñÉ'Ÿð³–—/_ƲeËøÒrÛ¶m!w褲ÔÔT¤¦¦B¯×óeÕµ6§\• Èåräääðå—ð“_‘ dF£Ÿþ9RRR|þ—¡¡p#ûp|oo/jjj@Qjkk±bÅŠ(RE+ð4Ý`0àÔ©S<]¹r+V¬YNNμYww7!—Ëár¹šš*ÄFzkœã8 ¢µµyyy³F§4Mó‹ŽU*òóóE :æ—.]BMM V­Z…·ÞzK2_®(pEcÁ¢¶¶===xüñÇ!“Éx×R!ÙßÕÕ…ªª*ÞæzóæÍP( dD[ÕÛÛ‘£GÁ”pZ­4M#;;›¿^ŽãDY°@ÆqÞ~ûm<ñÄxöÙgñÌ3ÏDGw¢Àõå)-{{{E@¦Óé°jÕ*È6mÚ4¯Ž¥ä`÷ööÂh4dóÒµ”*¦¦¦ðùçŸ#!!AdøçÍÊÇȼñV«O>ù$þüç?ãàÁƒøêW¿å³¢Àõå2NÇŒŸ#»îºë¼.Œõõs{zzÐÕÕô¶dä—ÉdZ0 þUUUI6èr¹ðÓŸþ~ø!’““1<<Œþþ~<ðÀøÍo~}0£À`³‹ÎÎN?~œ/-ÇÇDZ~ýzÈ6lØàs\Æf³¡±±‹…·p™K,MLL ¡¡™™™Ao ò“““xðÁqþüy¼ûî»Ø²e €éE­ƒ•••Ñ1 \ј+µ··‹€Œ¦ilذw¿Ø°aâããAQZZZ022¥R)©®i>Œ”Ó===())Ann®dŸ½­­ »wï†J¥Â‘#G$SØG# \Ñðd­­­" 3ذaqæÌ|ôÑGÐh4óÖód)))¼Ž, þUUUI2BEÀð¿þë¿pÿý÷ãž{îÁ?ÿó?GGw¢À…²“'ObÿþýCvv6z{{qÝu×ñ#JëÖ­›×QžP,Pÿ`ÃétâÅ_Ä+¯¼‚W_}»víŠJ¢À…޽{÷‚¢(8pIIIÐjµ|FvêÔ)X,\wÝuü⑵k×ΫðÔf³a¾k)tO%{-ÇÆÆÐÚÚ*ùøÑÄÄöíÛN‡cÇŽEù«(pE#RÂjµzõœr¹\hhhàud§N‚ÝnÇÆy [³fͼ–Mž€Œ¢(¨T*äääHægùòeìÞ½•••xûí·¯‰Ñ¦(pE#^€ìóÏ?ç•ý§OŸ†ÃáÀ¦M›x [µjÕ¼1ü£( ¹¹¹0™LÐëõ³2²`Œã8¼óÎ;xüñÇñÔSOá?øAØœ;¢®h,]¾|Ydlj€¬ªªJòî¤/Ã?¡Ÿ½;ù[Ìa³ÙðÔSOáØ±cøÃþ€›nº)ÊgE+_ôp:¸tédgΜEQؼy3¯ì¯¬¬ 9ƒ ÅðÏÓb!%&&B¡P```{öìÍfÃÑ£GQXXýB£À/+]¼x‘²³gÏB.—cË–-<©ÕꀀL*Ã?w ûÎw¾Š¢`6›QVV†·Þz ùùùÑ// \шÆUÐp²¸¸8lÙ²…_çi­=Ã0¨¯¯‡R©DYY™d¥'˲øå/‰ÚÚZ¨T*~cøwÜÚÚÚè®hDÃsuáÂÞêúܹsHLLä3²êêjüéOÇqØ·oŸ¤ǧ¦¦ðÐCáÌ™38rä¿4x||ƒƒƒQéC¸¢À¬®®'OžÄßþö7ÈvìØíÛ·cÛ¶m(--³A_{{;jjj T*qäÈ,Y²$zó£ÀhÌ-pà 7`É’%xä‘GpåÊœ݉W4¢h„7¢ËÝ¢hD+шF4¢ÀhD#nñÿ²Ó;{ösüIEND®B`‚pyclustering-0.10.1.2/docs/img/bang_dendrogram_chainlink.png000066400000000000000000000146351375753423500240530ustar00rootroot00000000000000‰PNG  IHDR+±œ.›%bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEâ 1×ü{(*IDATxÚíÝ}TSçðox‹€°ߨõ |™/4"§2r6‹;S¦Ö9S;­Öi¶:¬gÓN[çf;µëŽíN=ºéì*Zk¥P_PQGÅ©A%QgIð¥Hà·?œW"A$àû9çͽϽÏÍó$?î}ž›çQ‰ˆ »|ù2t:ˆÈ3•””À‡Å)¢ÑhX DÂjµB§Ó!((ˆÁ T*@£Ñ0XyèwÔ‹Å@D­ƒ1X1XƒU»Ì2h •êþBÄ`ED VDD VDD VDÄ`EDÄ`EDÄ`ED VDD V­„ô¸êhj•°J]W– VDÄ++"¢v¬<ˆï~÷»ˆŠŠ‚J¥Â?ÿùO»í"‚_ÿú׈ŒŒ„¿¿?qîÜ9»47oÞDzz:4 BBB0mÚ4ܺuË.ÍÉ“'1räHtèÐ:+W®dÍ1X5ÜíÛ·1pà@¼óÎ;·¯\¹üã±~ýzäåå!00ÉÉÉøæ›o”4ééé8}ú4²²²ðÉ'ŸààÁƒ˜1c†²Ýjµ")) ݺuÃÑ£G±jÕ*,]ºï¾û.k—¨-‘f@¶oß®¼®®®­V+«V­RÖ•••‰Z­–>úHDDΜ9#äË/¿TÒìÚµKT*•\¹rEDDþô§?Ihh¨TTT(i-Z$½{÷nð¹Y, –ÆGó£g<¢,\q¬RϨRå»i±H‹µY]¸p&“ ‰‰‰Êºàà`ÄÅÅ!77››‹ :TI“˜˜///äåå)iâããáç秤INNFQQ¾þúk‡yWTTÀjµÚ-DÔŽoÇd2"""ìÖGDD(ÛL&ÂÃÃí¶ûøø S§Nvi£fZ±b‚ƒƒ•…Óp1Xy$ƒÁ‹Å¢,%%%ü$1X9¦Õjf³Ùn½ÙlV¶iµZ\»vÍn»ÍfÃÍ›7íÒ8:FÍ<¥V«•i·Zýô[íåéÅv4 )«ÔÂU= Õj‘­¬³Z­ÈË˃^¯èõz”••áèÑ£Jš}ûö¡ººqqqJšƒ¢²²RI“••…Þ½{#44”ŽˆÚ w¶ä———ËñãÇåøñã@V¯^-Ç—K—.‰ˆÈo¼!!!!²cÇ9yò¤Œ;Vzôè!wïÞUŽ1fÌËÊ++""+"b°""b°""b°""+""+"¢†«ýû÷7[æÝ»w‡J¥ªµÌž=PkÛÌ™3íŽa4‘ššŠ€€„‡‡cáÂ…°Ùl¬Y¢6¦ÖC¡cÆŒÁ“O>‰©S§bÊ”)ÐétnËüË/¿DUU•òº°°ßùÎwðâ‹/*ë¦OŸŽeË–)¯”ÿWUU!55Z­‡Fii)&Ož ___,_¾¼}×lÍyŽ}Ò±!ó*¹s¦¦äãIóT5ãÛ®«J=±(ÜV¥N*xýúuY½zµ 8P|||$))I6oÞ,nŸPqîܹ-ÕÕÕ""2jÔ(™;wné333ÅËËKL&“²nݺu¢Ñhœ:ß69ÉiÍ$üß™+3»¥;óqâ¸M™˜ÓÙÓwÇŸÎTisMrÚRUZs’ÓZ·aaaxå•WPPP€¼¼<<ýôÓ˜5k¢¢¢ðóŸÿ'NœpK4¾wï>üðCüøÇ?†ªÆ•À¦M›†˜˜ ܹsGÙ–››‹ØØXDDD(ë’““aµZqúôé:󪨨€Õjµ[ˆÈÃÕý®\¹"¢V«%00P¼½½eĈRXXèÒ¾yófñöö–+W®(ë6lØ »wï–“'Oʇ~(]ºt‘´´4eûôéÓ%))Éî8·oß’™™Yg^§µç•¯¬xeÕŠ®¬ ²²ÿûßñüóÏ£[·nøôÓOñöÛoÃl6£¸¸ݺu³kWr…¿üå/HIIATT”²nÆŒHNNFll,ÒÓÓñ׿þÛ·oÇùóç›”—Á`€ÅbQ–’’þÕ"jm ì/¿ü2>úè#ˆ&Mš„•+W"&&FÙˆ7ß|Ó.¨4Õ¥K—°wï^lÛ¶í±éâââÅÅÅˆŽŽ†V«E~~¾]³Ù ÐjµuG­VC­V³ö‰Z‘ZWVgΜÁÚµkqõêU¬Y³Æ.PÕl×rå#7nDxx8RSS›®   Ðëõ8uê®]»¦¤ÉÊÊ‚F£A¿~ýX»Dm¹Í*''G*++kÝ;VVVJNNŽËªª¤k×®²hÑ"»õÅÅŲlÙ29räˆ\¸pAvìØ!={ö”øøx%Íf“˜˜IJJ’‚‚Ù½{·tîÜY ƒSçÀÞ@¶Y±ÍÊóÛ¬j%óòò³Ù\k§7nˆ———Ë ãÓO?RTTd·Þh4J||¼têÔIÔjµ<õÔS²páB±X,vé.^¼()))âïï/aaa²`Á‡Á–ÁŠÁŠÁªu+ÕýjÜzyÁl6£sçÎvW`_}õ†Ú&»ù­V+‚ƒƒa ¹¹éÜZòAźòn‰‡BÝ™OÍcד¶)L:‘M“«­®~õ«_ÙØÙ¶¯7UÍ3xCói®óqæOlSöqô~šòì˹ßÝ^lõUiÍí®®’ZÁª°°ÇlÙ²±±±8|ø06mÚ„÷ߟ5LDžqeUYY©4¶ïÝ»ßûÞ÷}úôAii)KŒˆ<#XõïßëׯÇgŸ}†¬¬,Œ3põêU<ñÄ,1"òŒ`õ»ßý6l@BB&L˜€>þøcåöˆ¨¹9|t¡ªª V«¡¡¡Êº‹/*sóµ5µ]xÀÝÓC9ÛÇÛ’ýÜ yŽZS]unõõsרÆG^¥Î{CªÔ‘ÆVi£.Ôäíím¨€û¿$"ò˜Û@³ÙŒI“&!** >>>ðöö¶[ˆˆZB­+«—^z F£K–,Addäc'H.ºÍså­¥;óqõ4ÀMy®ÊÝ÷iÌÚEÔš~PáÊr}ôãQ+X:tŸ}ö Ä`CDž{¨ÓéÀŸ ‘Ç«5kÖ`ñâŸxñ"K‡ˆ<7X?@tt4‚‚‚ЩS'»Å•–.] •Je·ôéÓGÙþÍ7ß`öìÙxâ‰'бcG|ÿûßW&1}Àh4"55Uy¬báÂ…°Ùl¬Y¢6ÆÇÑ•Usêß¿?öîÝûð„|žÒ+¯¼‚;wbëÖ­Æœ9s0nÜ8|þùçî?–šš ­V‹Ã‡£´´“'O†¯¯/–/_ÎÚ%jK¤eddÈÀn+++___Ùºu«²îìÙ³@rssED$33S¼¼¼Äd2)iÖ­['F***7o`c&ŽkÈDoM™<ÎU“Ì9:NCϽ!åòh>õ»¡éë;ö#ëÜ9o`Sª´±Uß¾«ôá¼^ŽØùóçñÚk¯a„ ÊÔì»víÂéÓ§],Ï;‡¨¨(ôìÙééé0€£G¢²²‰‰‰JÚ>}ú k×®ÈÍÍäææ"66JšäädX­V·œ+yP›UNNbcc‘——‡mÛ¶áÖ­[€'N ##Ã¥™ÇÅÅáý÷ßÇîÝ»±nÝ:\¸p#GŽDyy9L&üüüb·ODDL&€ûãmÕ T¶?ØV—ŠŠ X­V»…ˆZY°Z¼x1~ó›ß ++ ~~~Êúçž{_|ñ…K3OIIÁ‹/¾ˆ 99™™™(++Ö-[Üú¦W¬Xàà`eÑétŽ:3zXÍÑÇ ,×®­±éÜqŽÍ¨©cò5¥J7¾ ;Æ[ôä*uÕ±j«S§N!--­VÂððpܸqí®<ýôÓ(..†V«Å½{÷PVVf—Æl6C«Õ´Zm­ÞÁ¯¤qÄ`0Àb±(KII ÿlµ¶+«‡ƒì?~]ºtqëÉܺu çÏŸGdd$† ___dgg+Û‹ŠŠ`4¡×ëz½§NRÚÕ ++ ýúõ«3µZ Fc·‘‡{´…~Á‚2bÄ)--•   9wîœ:tHzöì)K—.uioà‚ äÀráÂùüóÏ%11QÂÂÂäÚµk""2sæLéÚµ«ìÛ·OŽ9"z½^ôz½²¿Íf“˜˜IJJ’‚‚Ù½{·tîÜY ƒSçQgo ³];îÓ”®%gºaœí:ªkŸÆt54Ÿè llÇîãNÍٷ択µÖ^¥ùˆ;ê ¬u˜ŠŠ ùÉO~">>>¢R©Ä××WT*•üèG?›ÍæÒ`5~üx‰ŒŒ???éÒ¥‹Œ?^Š‹‹•íwïÞ•Y³fIhh¨HZZš”––ÚãâÅ‹’’’"þþþ& ,ÊÊJ++«6¬êœ7°¤¤§N­[·0xð`ôêÕ«Í^]Ö9øÞÃËOç[!­¾ÑÔzLGé ÷¸‘Új«!#½=z>Ž~__> mqmÌ(pu ¾çL6ôÔZ¥+*g‹§µWic>â·YÔ|oþüùͨf/àêÕ«yïLDÍÎçAãyMÇŽƒÍfCïÞ½_}õ¼½½1dÈ–µ\°z0©éƒ+§   |ðÁÊÐÆ_ý5¦NŠ‘#G²Äˆ¨EÔj³êÒ¥ öìÙƒþýûÛ%,,,DRR®^½Úæ ¡ÅÛ¬ÚÀñø›ûÆ7p<îÜ›ÚÀј÷ÖÐ}Ú@›•£ã4¤êÛO•>l³òrôŽ~ýz­ƒ\¿~ååå ïDÔ"j«´´4L:Û¶mÃåË—qùòeüãÿÀ´iÓ0nÜ8–µˆZãY­_¿¯¾ú*&NœˆÊÊÊû‰||0mÚ4¬ZµŠ%FD-¢Îç¬nß¾óçÏ¢££Øf mVm¦ƒmVh»mV>u400 `8'"àÅ" "+""+"jO|X P_«j}û8“OSïŠQJ=eäÏúÊÉótçŒóõý½¡ý3îœ[¸fQ9*¶æšr¾)UÊ++"âm ƒ1X1X1Xƒƒ‘«+V`ذa Bxx8^xáÙ¥IHH€J¥²[fΜi—Æh4"55ÇÂ… a³ÙÜsÒM}`²¾9Ä=m:ö†Îî®svqy<:%¼+§hoj•:“®=jÑ'Øsrr0{öl 6 6› ¿üå/‘””„3gÎØ I3}út,[¶Ly ü¿ªª ©©©Ðjµ8|ø0JKK1yòdøúúbùòåüsDÔVˆ¹víšœœeݨQ£dîܹuî“™™)^^^b2™”uëÖ­F#®™ä´¾Ù§¡y¸{iêù8»¿³åÕ„ójì[qvß¶^¥ÎÌGë¾ó|8É©GµYY,@§NìÖoÚ´ aaaˆ‰‰Á`À;w”m¹¹¹ˆEDD„².99V«§OŸv˜OEE¬V«ÝBD¼ lêêjÌ›7ßþö·£¬Ÿ8q"ºu놨¨(œùäìß¿O>ùäcÓÆÅÅŠ‹‹Z­f³Ù.̓×Z­Öá1Ôj54ÝBD VuÌ™3Û·oǾ}ûУGz÷)((DFFôz=N:…k×®)i²²² ÑhЯ_?Ö0Q[Ñ’½?ûÙÏ$88X8 ¥¥¥ÊrçÎ)..–eË–É‘#GäÂ… ²cÇéÙ³§ÄÇÇ+ǰÙl#IIIRPP »wï–Î;‹Á`hðy°7½ì ôüÞÀ V.7n£Ñ(ñññÒ©S'Q«ÕòÔSOÉÂ… Åb±ØçâÅ‹’’’"þþþ& ,ÊÊJ÷«Æ”º§}²›û›áÁÁª±ÕÃ*mŽ2x¬êœ7°=©wÞÀº/KïÿÛGŠIÛ:.É{?™d®‘çÕ˜Ã7¦zX¥ÍQ¥ç äo‰ˆ ìDD VDÄ`EDÄ`EDÄ`ED VDD-ˆÓÇ7E{²±1ï½¹æ'§6ûqæ•ñ6ˆˆÁŠˆ¬ˆˆ¬ˆˆ¬ˆˆÁŠˆˆÁŠˆèñøPhsiÏ6g¨T¸?à¬ûO­½Wis¿^Yo‰ˆ¬ˆˆÁŠˆˆÁÊMÞyçtïÞ:t@\\òóóY»D VžeóæÍ˜?>222pìØ1 8ÉÉÉv³4QëÖ&æ Œ‹‹Ã°aÃðöÛoª««¡ÓéðòË/cñâÅõîßèyÉ3?Ôà¸YmÇÃy[ýsV÷îÝÃÑ£Ga0^.zy!11¹¹¹÷©¨¨@EE…òÚb±(ÅBmåNm©.E¤õ«7n ªª vë#""ðïÿÛá>+V¬À믿^k½ŽŸŒ6"˜EÐÆ”——·Ï'Ø æÏŸ¯¼®®®Æ¥K—0hÐ ”””@£áÍ`£þZ­Ðét,C–¡ËˆÊËËÕúƒUXX¼½½a6›íÖ›ÍfhµZ‡û¨Õj¨Õj»u^^÷û4 ?$MÄ2dºô:9øþ•r«ï ôóóÃ!Cmw¥” ½^Ïš&j#ÚÄmàüùó1eÊ :ÇÇš5kpûömL:•5LÔFx/]ºtik111 Áoû[¼ù曀M›6¡wïÞΆ·7àãÃÁ(ýb² ݤMøàøøø ??øÃ°zõj¼÷Þ{µÒUWWcìØ±¸yó&rrr••…ÿüç??~¼’fçÎHKKÃóÏ?ãÇ#;;Çw˜ïÊ•+±xñbìÙ³£GfEx!ò £F’¾}ûJuuµ²nÑ¢EÒ·o_éÖ­›üþ÷¿‘={öˆ···F%íéÓ§€äç狈ˆ^¯—ôôô:ó{p¼_üâ)………¬Å++ò8Ï<ó T*•òZ¯×ãܹs¨ªª²KwöìYèt:èt§úèׯBBBpöìY@AAA½WIo½õþüç?ãСCèß¿?+€·DÍÏßß¿Þ4#GŽDUU¶lÙÂc°"j¸¼¼<»×_|ñzõêooo»õ}ûöEII JJJ”ugΜAYYúõë0`@½åÇÇ®]»°|ùre¤Yò<7•<ŽÑhÄüùóñÓŸþÇŽÃÚµkñÖ[oÕJ—˜˜ˆØØX¤§§cÍš5°Ùl˜5kF…¡C‡2220zôhDGGã‡?ü!l6233±hÑ"»c=ûì³ÈÌÌDJJ |||û`*ñÊŠ0yòdܽ{ÇÇìÙ³1wî\̘1£V:•J…;v 44ñññHLLDÏž=±yóf%MBB¶nÝŠ?þƒ ÂsÏ=‡üü|‡ùŽ1;wîÄk¯½†µkײ"< Ç`'¢VásÒ{ãRN`IEND®B`‚pyclustering-0.10.1.2/docs/img/birch_cf_encoding_lsun.png000077500000000000000000000470621375753423500233730ustar00rootroot00000000000000‰PNG  IHDR÷ã*žsBIT|dˆsRGB®ÎégAMA± üa pHYsttÞfx9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æðMrIDATx^í ¼Å}Çç¾$A/\.W%Q|Di|ÁEE­ È‹mjÒVRÄ’Æ&bµIÚÈ+m’Ä„¤M‰Ui°‰yXi§5 ˆFTHL±Æ0\à†r¹p·û›³sÏœ¹ûÎîÌîÌüfþóŸÙËFB!$74:kɽ÷Þ+<—ÇÜ93] \q‡oÞ¼yòšårÙe—É¥>ýéO‹‡zÈÙŠSN9EüÉŸü‰³•,ûöíÿüÏÿ,Æ'† " $ïã7ŠŸýìgÎYþiî¶ÛnsΪï>jZª4½la¦Û7¼á bĈâòË/ŸùÌgÄïÿ{çÌèüüç?—ééÕW_uöTÄ÷O‚ró‰N‰¸+þýßÿ]üô§?°¼ýíowÎ I’”¸W‹ÿýßÿçž{®øìg?+ »x@¬ZµJÌŸ?_¼öÚkâïx‡Ø»w¯sv·47{ölçhõ@áƒpF-|fÍš%ÃLê •nW¯^-þå_þEŒ;V|îsŸgžy¦X³fsV4 îHƒµ÷$)7‘踊ûèÑ£Å\0`A Œ?Ž9"ÞùÎwŠ®®.Yè-\¸P\}õÕâÿøÅÌ™3ÅøC±|ùrÑÒÒâü¢€[š;餓œ£é…8ñÄe˜I}¡Òí%—\"®½öZq×]w‰^xA}ôÑâÏÿüÏee–$Ooo¯8|ø°³E€«¸‡¦›}èCbÉ’%²–:xð`1fÌñßÿýßÎE^zé%qÝu׉ã?^šgQh_ýõ¢§§Ç9CˆM›6‰?ýÓ?Æ “&.Ô€ï»ï>çh\«³³SÞ¯££C|àû÷ïwŽ–‚šóĉe¥çO˜0A¬]»Ö9Z‚ƒû!l§žzªøüç?ï . wÞy§8ùä“e¸aÝxä‘Gœ£E<(n½õVyŸ¡C‡Šöövqá…Šÿú¯ÿrÎ(€çú‡?üAÆ]™ü”yçÎâïþîïÄYg%Ž9æqÜqlj+®¸B<ùä“òxX~ðƒˆsÎ9G†÷-oy‹X´h‘sDˆ×_]´µµ‰¿ýÛ¿uöAK¢©©I ¶°8¼øâ‹âŸø„,øÜ¸êª«äûˆ‹oûÛòY¢@Ås™2eŠxî¹çœ£n¸áyìå—_S§N•9R¾•¿c=VþÖ…zþø-P¦wt+¼ë]ï’iõ´ÓN+9f&l¯¼òŠø«¿ú+ñæ7¿Y¦Aä¤Û7:g,òí _ø‚,—þíßþÍÙ+Ä3Ï<#ß3º§ÞøÆ7Ê5ÊÅ_ÿú×Îsÿ»ßýnù7¬^* b?€…å$*“È¿§Ÿ~ºÌ«¨L‡¡»»[¦yä{¤5”!È(W½ðJÛªkB·0<ú裲¼>|¸Œ#ž*=¨å/°eË1}út.„Ú‹ˆZýø´q9á„ä¹ÈÛ¸ºóPŽãù œE× ¬‡õ†«¸£õ…Z¾`Ÿ Dñ«_ýªX°`øÞ÷¾'$Zm(¬Ï?ÿ¼8ï¼óĺuëäy>ôI¡@=tè<ç—¿ü¥¸è¢‹ÄæÍ›¥Ð|ÿûß—†—áT Œ *ÿú¯ÿ*_.Ä• “ÿøÿW^y¥våw¾ó>®ºÀãod–ÖÖVñŸÿùŸR¸p.Ìma@"ýØÇ>&&Ož,…í¦›nï{ßûdœtßÝ»wË„‡óØ.¾øbY»¿ÿþû³„lí"S Ãáo,ˆ+ÀïÁܹså³G‘I‘™Âš¹ þð‡ÅG>ò)òxî·ÜrK…„~ño}ë[LçÇQG%{ó;ø³?û3¹‹[š º0P@"½à½!M PEK æMÔæ)œ¨T!hiÁŒ Þô¦7‰+VÈ¿ßûÞ÷ö?ÿ;î¸CîSà¡P}ðÁÅ׿þugï@† ïúÙgŸ•i…÷×¾ö5Ù­‚˜d¼ST„Ÿxâ gO¡òøÖ·¾U|éK_+W®”énûöí²|Tâ +Ò €¨©4ˆý]^¨," ¯Í™3G¬_¿^–%Hß~ íáúÑÊgƒßà^Ès¨,íÚµËùUoy…-ðœw]ì„êœUû솵oß>geíØ±Ãjll´lñvöX–ݲ´ì– õûßÿÞÙ3»6kÙ5/Ë~QΞv ϲ[x–]ÈÉm[D-»ÆfÙ%·¶°Êð<öØcrÛnùZ¶[Ó¦M“Û [@¬1cÆX矾³Ç²ÆoÙ-&ëÿþïÿœ=–Œ~kú±gÏË®Zv…ÆÙSàÇ?þ±ü­]qö Ä/ËÎŒ–È-» wö°3ƒ5sæLgËu [¬„Á“O>ÙóùÙ• ùÜ€]€È÷h ŸÜx>vmܲ g;2îtöøã—æ7?^š››­›o¾ÙÙSÀ.Ĭ#FXñáì±äóÄ5m‘uö° aË.p-ËÚ¹s§<Ï®@9{Š`ŽÙª³§ˆ:¦6»P—¿³ |¹M²J·6lpö å£Ýòt¶‚ük7Nd~ÿò—¿ììµ,»Ò(¯­Ê3/úúúd±[þò|»ÂêqÇn\Éóì ¤³Çœ£§3m+Ô3øÕ¯~%·¿ûÝïÊm³|ÑñË_vÃË:ñÄ-»Qáì)`7Þd9k7nä6ž ®q饗ÊmÑ£G[vÃÂÙªo\[îhIÚ‰¶dAíÐf#´x0'¢ö¤ÌL0‘üèG?vAÖoŽq¦´¦`&ÕAË×@íØ/Uœ}öÙÒü¯3ŽÎO~òÙÊE¯jb±3ƒ4é#>0}cÁßh‰Á„£@œìгå Âsû{ÞógO´†a¦7AK]hÛ¿ìwþæ7¿)~ñ‹_8gƒZ*Lÿ¯º¬a¯áõüàÝ®¼Øa €W=Zêv‘û–.]*k¿nV’8pKsˆÀ{Óߣ²"¡õƒmtñèÇñl`á1­0å™ïݺY4 036l°&Á´‹Ñ¿øEi²G|IöQyG+#¬|°ú mcAY€r(lþ…>º"QVªü¯Êš kÀjŠVú¤I“œ=ñ‚.G´Úßÿþ÷Kk©nÁ å(Ê1X~Ñe§çXApÖ_·|h7ÜdÑøDå]„(Ëê²ê€‹~§mÛ¶9{ÜA%Á­Ïçw¿û\Ãqà¼;vÈ¿uÌ}ê|$Õ 4Xà…Â5Ì5ÝP•›0¿‡ ÃÉ;Ó[èÖüÇt0ìFu[„Áëù¡+Âl•£õˆB Ž+¨ )/^?àœˆ N“(ŒÜ@«E ! ¼Šõw§$€ŠL“p2ÒëKTÔó k ñ¢Ü°ÁlúÉO~R>C}²’àäÇYŒŠQ£Nwa14óïâÅ‹8+{¥AUv˜×Ð=òýÀ(•ÿùŸÿ‘emÿÊ¿2BƇòtWiÙ+n(çQ¾£[ ]enù%l%F2 •8µ¢Ò¥ÌÉv‚ëG9H`m Æ€EwŠÃyvKÎÙ*§-Ý ÎÇsŒõ–·¼ÅúÆ7¾aÙ Ëzà,û÷;ãÙµ,ËË.Ø,»uj-_¾ÜzÏ{Þ#ïqçwÊs€Ýº·ìÚ§u 'È0ªóFŽ)ÏÕP–,Y"Âþò/ÿR:¨üèG?’wÜq‡õ|À9˲V­Z%Ï»øâ‹­üàò»6ÜÍ ì‚XžǸ+VXwß}· ߈#Jêî¹çyÞM7Ýd­]»Öº÷Þ{­ÓN;Í5jÔ€ûàwÇwœõðÃK‡<G.;ƒË5®a·îä}p<÷ pÂvÒI'Éð<òÈ#ýÏùsŸûœsV;3H':G<ÃòòË/Ë÷÷n·>å{Âó·+kÖ5×\#ã œ$Ã8&ùñéOZ:®Ù…¨|?þ¸õíoÛºõÖ[Kß&á¸dâæ,„ç';»"Ã¥†Ô¹p 2q»N˜°Ù-ËníX‹-’ïïõÿñešü‡øyIfYùä“OZßûÞ÷,»•jÙ¢.rQÖéÀ ûQFÀ© yêMoz“t8ÖËÌW^yE^Ža¸.Ò Ý8²:ÔŸ×í ¹,oP£ÜÄùnNj:(oÏ>ûl™/ÿéŸþI–}pÂûèG?ZVóZppC¸í §LǶ¨[×^{­uê©§ÊsUþ°[É–Ýe®‡|ÿ®w½Kžƒ¼¤ðÊ_vÃò[ðÒáÏå9ÊÀ/~ñ‹–-üò êP®›à·p|衇d™óõ¯]–a^x¡sFýà*î^ ¥ÛaÄØ-hùÒñíÖ«»FUâQýâ‹/Jïvd œ¯v„Çׂw·Ýb– ¢ŠŠðèâðr¯¾újy^KK‹6l›‰ È®-ö‡í³Ÿý¬kaíF__Ÿ€Ê~ë ñC uq¸®] –#àE‹çévTˆ&L˜ G à˜ºNOOe·d<»¥-1ž7ž{8ñG™áExy¼À{‚@mÛ¶ÍÙˆ÷§>õ)F&xþx¶ý×-G(Tš+WÜž2?<þñlO*kÖ¬qΈ&îøF0àZ8¦Ò³:7¬¸ƒ °½öÚkòŸqÆ2|xVHC©pøðayIfY‰¼„ 9ò**un£ƒ‡ Š04f0²dÓ¦M®e&FO@<1J ×We¡*ÿð{\å*Ffà¤Á 0Âç–[n‘yyaF™ ÀíZO?ý´uÑEÉ4ŠòÇ/^,ÏUâŒJFí >Hë(ïñò‘ÈÊQ½ÁÇO06&9ŒýÎw¾ãì%„’vís'Ù^µO=õ”ô̇×7€!„dŠ;œèàõŠñ¢ðÚþF!$]Ð,O!„ä ¶Ü !„œAq'„BrÅBÉúÜ11fŠÃŒejF$BHõ@–Ä,‰˜—¼±1;õo–„Ô½ì î˜{Øü:!¤úlݺ5Ñ}Ä ËBÒÊŽ⎠ÿ1/;2ÄÙ[¤··W¬ZµJ~_ìÉ"ŒC:`ÜÁçw!’ÝÝÝr~ò¬À²#0é é²cÀ|™˜GØ>gÀó˜ßSjbU‡tÀ8¸”Ó ËŽlÀ8¤ƒ$â çA:ÔB!9ƒâN!„ä Š;!„’3(î„BHΠ¸B!9ƒâ’×ö½&®úÒUbø‡‡Ë5¶ !õGwO·˜öÕi, Hª¡¸‡ä†{n«±ZìþÃn¹Æ6!¤>P•û·³Ÿ-Ö¼´†eI5÷<ýêÓâHßù7Ö~½AþMÉ?zå~_ï>–$õPÜCrþ)狦Æ&ù7Öç|žü›’ôʽË’V(î!¹÷Æ{Åä3'‹áÇ —klBê½rß`ÿë8ºƒeI5÷?äxñȇ]wuÉ5¶ !õAåþèáâÜcÏÏÝñ\YeŸc®ß1B¢Bq'„Ô-aUUî·/Ü.挟Svåþºo\'Vl^!ûî±Æ¶‚N»$N(¥Ú‚úÔ–§œ¿ <õrq›N»$N(¥ê‚Úà¬] Ó.‰“Æžžù X}øÖ¬×t< ㎅qp_HuðÔ¤ú¿/>ýbé°Æ¶‚N»$NæÎkÍŸ?ßÙ,²téR1xð`g‹R-8 ¦OŸ.öîÝ+† âìM?h :Ô3ܨ´,_¾\L:U´´´8{k D¦x´Ø!ìTô§CÐa¦Gk¢±EŸ{¥qðº_5Iã{ˆ ãàŽž˜ãë/ÿüåUoOòOîÄÝÌ4Ì$„$C‡ÑÎüæÌ’òÛnçù-nqضk›è¼«SV°Æ¶y޾˜ãëw½¾«t¼ý«\×ÜögiaÜEƒeãü-ѽí²èñŠÌåæåª“ö8„qHIÄ!(¦…y󿉬 £±r†Øß»ßÙ¢µ¥U,™²ÄÙr§»§[,Ú¸HléÞ"Fµ³ÇÎmƒÚœ£¬_ 6vm}VŸhlhc;ÆÊij½0Ï?¦ùñúá×Cÿž7ôa´¹w˜ÚP#7ǧêPTÒãàNVÄ-÷¬ £öÕibÍKkúˇIgLË>´Lƒ‰~Öý³úÇ /¾~±ìk73føñä'Ÿ,‰ÃˆÛG”6*Ž.ç¡÷BÝë™_?#ÆpØ !ù¦’<ŽËxA«©5wÂ:ÙBÒÙ’ÞôÛMr½þWëŰÁÃä&¿ðÛœ¿ ˜Û ZýH­¡¸û@oWBòÙ’¾üó—Ëõž{䂯À…ÉãhÙ76ŠM¿–>­~¤ÖPÜ !¹ÇlIïz}WY-ëÅ×/c;ÆŠáGû[óhõ#µ†âNÉ=fK¢[NË-û9ãçˆí ·{¶ôÑK*¸îÂw/”Ût®#Õ„âNÉ=fKú±ÛK¬eíÕ@ç:RM(î„ÜcúÏŒ>atÿ6„=Ζu\]„TÅR·@ÈGÏ-Vl^[˺Ü.Ó£Ÿæ{R wBHÝ!ïz½ËÙòoYCl§}uš˜±r†\{‰o¹]¦9Ÿæ{R wBHݺ‰WËb»æ¥5bï~¹ö_¿.¬M'<Õb_¹y%Í÷$6(&t5ntÓáÙ²v›˜&Sºj±ë3ÞEñà'Ä Š;!¤n_yÖ•ÒdÞyv§Ø4“ëð6à61M¦t½Ò0g}Üü¤þhìééûöí+Y@oo¯çt< ㎅qp_Hò • 1VãÑ!¦^Âp|Ò“DkK«\cÛ­5³Ò0åì)®æ{B¢Ð0wî\kþüùÎf‘¥K—ŠÁƒ;[饻§[,Ú¸HléÞ"Fµ³ÇÎmƒÚœ£„dˆéÓ§‹½{÷Š!C†8{ÓC‡õ 7*-Ë—/S§N---ÎÞÚ3:ZÛeˆ*ZËU?Ì8˜×¸tÔ¥bPó )úm¿ ƒª\¬ûÕ:ÑÜØ,úúúÄù§úÿ&ÒöÊqpGσ ´ÐzWààÈ‘#EWW—g]½zµ˜´Ì9êNÚâPŒC:H"ȃ÷„A?9Ìé ˜æáôæ‡%Ðh±£õßs¸G<±å‰P†r*q¶÷PŒƒ;zl4ḧúp3¯%èx5d*d€õ3¿yÆõô¨ … AVžðÏo{¾¤<ò3ÓÇaÒ'Ä‹Ì;ÔÅ‘A !õæ|ǧ^áÀ†5¶ƒ@K}ÁúbÄí#\½ã£”G,»H’d^ÜÑ?sVЄxÉš3î¶]ÛDç]ÒõÍKo–Ÿ{Å4¬oûÎm®¿Ó—ï»QlìÚØï?ó›3KŽß=ãnÙ5ˆ¯Æamý¸¾D97ï!®…qp_ –ó·D·Ùg¡ß¬‡tÀ8¸”Ó¼yóD–œqÑâ†0÷Y}ΞRà¿dÊgËÌN‡Ila~CHµÐq)îŒCÍ`ÜÉŠ¸£åž%g\˜Òu:˜æ1Þ=È÷ê¯\-Ö¾´VV`JãÀ›6jýâ€qpyP9ãrBHYdÍWïã6inj÷½÷>×ßéË=3ïc;ÆJS:ºÃü& pÛŸ¥…qp_wBH] üsZšŠ bâC-Ç9sÆÏÛn—Þñ~¿³œîø•7R (@ [ûÙ?íƒÛå>˜ã'œ6!²#náŽcjZBÊ…âN©+nðv±÷à^ùwcc£h}Ck¨V»Î¬ûg w˜qìlÝ“¤ ¸BêŠ8Dל<ËíaƱ³uO’‚âN©+â]ü&èaæàà,u$)(î  ì‡è.¾~qà5T¿ššV™þõrß’ª$R÷ЄFHöñ] Ö}˜kx¡—#X0õ-gØ$qCqMh„ÔaZ÷増#˜ Óß–SI ÄŠ{ø¡BêƒJZæAx•#ìö#qBq@’µyBH}àUްÛÄ Å=IÖæ !õW9Ân?'wBIìö#qBq'„äŽ4ö_…‰Ý~$N(î„ÜQ‹þë ñ Sæºý^³ãwÕUB ^Xc›¤Š;!$w˜ý×+7¯L¼$Þ¹ëS¿ÁŽßêÕBìÞ]Xc›¤Š;!$wèý×cÉ“nÁ‰wîúÔŸ~ÚŽh!¾r½€i‚âNɪÿŸtU$ÝZÖÅÓÊâÞº‰>w}êçŸo×Rœ ÖçÑ0MPÜIö¡‘œ ú¯§œ=¥j­e]¼Ûn{ì)1Ñg®O=ˆ{íÊÉäÉ…òkl“Ô@q'E؇FrF5[˺xcZÙ\õ¯»q¼]9yä!ºº kl“Ô@q'E؇Fr†[k9È«=8fÔŠ;)Â>4RyµÇ,—ŽºT´4µØ…l£è9Ü“¨§>  »)î¤ûÐHŽQ-v ‹KÚd Á æAÒ<ßÛ×+žØòD¢žú$€:ìr¤¸“"ìC#9FµØ1,N‘¤Éœsŧˆ:ìr¤¸Bê]l†ª%édÇ~÷Q‡]ŽwBH]`Š-†É%édWMO}@v9RÜ !uŸØ&ádçæ©OjDv9RÜ !uŸØ–Û?žD‹Ÿ8 ¸BêžrûÇ“hñgž¸†\gPw·hš6­®†·EâNÒG\…!!q3Ù‡i•Ó#Þ…¸†\çÜE‹DÚ5É oËx9”+q§‰,'ÄU87“}˜V9=â]¨tؙՕ+}¯3lËÑö>¸æWqÔQ…‰uÆË¡\‰;Md9Óà’¦Uîç¤W·T:ìL‰ªUœÀí:{FVØûàš?.Dooayì±`±Îx9”+q§‰,'p\’´Êýœôê–J‡é¢ \¯óÜìÙš4)Ü}pM½²‚Ä:ãåPcOOØ·o_ÉzíÚ×t¼V 2ŸžÇ4Îõ<,Àm––ÜÆáî»EŸi-;Óbíç¤hqC… ©=l•—I¥ÃÎÆŒqþp¸ì2×ëô´µ‰#Ë–¹ßÇì/Ç5QIÐ ëJ+)5¦aîܹÖüùóÍ"K—.ƒv¶²AwO·X´q‘ØÒ½EŒj%f-Úµ9G ÉÓ§O{÷îC† qö¦4 †ênTZ–/_.¦N*ZZZœ½Ù"(ðóAw ¬ˆhù£B¶Ö|*ÞÄfq´¨ÑB†p*qF8L誥ÝÞ^XkçÆ‚Ó>,hu_ziaÿSO qøpaßøñ…þ÷矆*Ä{Ðó`ÃÁƒ-´Þ88räH»2Ôå™AWÛm²]“Érejãàò`GGÅ=˜b}÷Œ»Å³O=ë8òÂßÝ‚°¢Ås}Í0EtáBÑwÛmâðO~"š/ºH4Þw_U­S|íü#[ß-e8±™hç¦%óØF _¿/@k•3 U ‰üP"î–³_’Ç j’«8¼ã¢å}ïs¯§¦%w‚ò`Z@£ ï ƒi_&Ö¼´¦_¬¯xë⃧}Ð3#n!zÃ.¶/ÜîlUŒÇp1x•Kç³aÄس§}ÖÒ´]ešGŒ šø¢ îðöÂs* ³½­ÓÕyAiÉŒ·Š§y_= Õ ‰ü€<¨÷ŒÇaÚ×¾&1Ö5ÑÔ>+iɬˆû¼yóD^ºô¼˜±r†Øß»ßÙ¢µ¥U,™²ÄÙØˆÏ»nÞ½Y~êµ±¡QŒí+挟ãœ]}®š1Cµ¿~S,{Z[ÅŠ%ÅøT‹ ,ÇnÜ(ûúD_c£Ø9v¬X7§ðœ09 ư·mÙ"[Ö-¯¿îzžú5ºG’Îwè£×ï«„Ï#ʵӌޥGqÏx®¹ñÆÒš¨2?e¦%w²"îin¹Ãœ>ëþYrÄ m_¿¸¬¾ï –»yü’Ó/‘ßqæ×ψq'+û¾q‘Ö–;º šfÍ Ï<#¬qãđŋÝ-Žçy¦%uþ† Â:ï¼×Õ¯÷¶·É] /¾è†„H"? ª–»€¸ëØ;!öríÆ¡C‡¬‡zH®³JžâpdÊËΤ¨¡ÖÎé‡iÉ <˜VÒTvtÞÕi5½¿É³l ³×Ø.‡{wÈßÿðp¹ÞÚµµ$í·´Ë{¨祊; eÂp;\X¿ø¢,3¶¶Ê/uíööº’k¹ás}Ï´„ó2R&‘ô<Èég3ެmÂ;Ö®AHÄ5çEÐ8öÔÏP‡–(ºé`ÍÃzôhÙR‡)^¶Ø+i©ªÉf`9Ä:hR7àð§Yö"ÊõÕufµ«'(îYÇ̼U4+’Vª%º™ o !úžá\6@P£ O6S®ú x”ë«ëè½Ì膨㠰(î„Ü ¾/±þWëŰÁÃä’¤èµìÓúœáT&}u‚ZÄ~`t”+¤¦€£å­*Q®¯_xÌj'Q­|7kAŽ ¸Brƒú¾Äž{ä2þÔñ®¢«*õø‘)8›Á[\Ô"V¸ "„“ÃÀ¬Ñ–8WFJ]ÀZÞªÂëût9–|ò÷Çp½)S¼-™~Ö‚Aq'„䆰}íúG¦Vý|•=wtÝ=¼È1ôK¶Åí&ˆÎAƒ„@E¡·Wˆ'žˆ.”JÀõ©aU…# Ë±ä“¯{öf²ó¨”GwB ¸BrCؾv½€1é]¯wÕÍ×$á„‹1ݘ´%P^‚X©P*GK[µàQñ€ØëV|ò­~TT2ð{Le‹E¿VÝ €âNÉ aÜôJ€N%žõ™ÁTLÖ"gc ë„ë%ˆq%&}ˆ:Lümm…–x€ÙÜ󓯺•ŸvÅ<õúµ”µ Jå&*ˆ“ÙQe(î„ÜÖÁM¯tÓ‘¨g}.ú÷½1H(!jh9ã-Xð·)t\˜ôaÚ‡‰3êé-rÝÉÎMxú7Úç[—\2ðÞ¦sò Ç¾æþXÐ+>”$¡¸“ð8«–µQBâ@¯lš¿)Tk¿\ôþýÌšý½1H(!jh=C¸± m iÚÇWÛtt';G4áé?|óæBŸ¿yoÓIOõç—kY(‡ôëSÜIxœŒUËÚ(!q¶µ_.qM¨“J6mâØc &u¬±­‘ÓPCèô†~«ÄB¬ZÚ:H\kíÚ~Ñ„Ç?¦‘€nM¸üòÂ÷à½, I‘‚~}Š; O j£„dÔÏbW O´œ•3Û9ç”Zõ r:oÞPص« ðºÇ¼ çh­zT0'ütk£/ËBRuWTŠ; O j£„d Õ¿¯&ÕÁ;¹raÖQ&ôÑ£ ÂG¹  ŽrÍÍ…׬__Ò—¿Ék,º½££(vw€3œ~[á×mèvÌïüJ ꮨwž¸k£vfŠeLBR‚›óœ2ûcB5¹Nn†Ü¡,0hCÔÐ*‡£\k«‡ 1i’øZ<áÍ~uTT3¿È .èo\@â{>Zþ-AÙ ÅŠ…û®ZUÚmèÖ¥è¶/GPÜIxb®Æ6 &!)ÁÏy.—}ïp–CëÚ ½û-v½µŽÖaÙÿÂäå¤Ë—j•_U#êHÝ$Њ×g¯Ã×ÔE}îšÐ6_y¥ðÝÒç·¡E:ã#h2)î]BHf >ÖaœØ’._rW~EiÑUçü­ÿ^É­0^Å@”Ñ  í®]þ³[ê­nó·aE:J¼RH&ÅB‚Ð[È0É+ó|fœØ²BXg;Ñ…à*ð•8œoÎ^~ê©Ãê„Ö¾—ïì–z«['ŠHG‰W ¡¸Br‰ÞB†Y ÈŒ[Vˆâ=ÑÕé Þ8_Ÿ½ëñã ë`Ø›#´‡W­*Îny饅™ðð·êS7­ðÜoo&ÒQâ•B(î„ÜÑ/Ðû«£8 …ÁËÔ±ïhÅCÀ±ÆöÅŽ)0ÄN íèÑrkܸB ³âé}êp\GV<îA‘.Š;!$÷$íĖɉi¼Ðû«£8 …ÁËÔ±ïøÎ;ZòXcCêÔ—æ°Æ¶>º‚¯Èin•ù"ŽyíÏ<³0½ÂœÞ¶ ¸BrOÒNl™œ˜Æ‹$½Ä½LÝn÷ 0‹Û²E~|¥´ü!öª¢ “1‡¸J¡¸“t‘¤I„ˆ:1Mª[úµð/ãž{F’_éýêæzD?cq•Bq'é"I“`-a¥%×DíÓOuKßËtž$eÜSö¹OšT4Ûã‹p'+ :ý¤ûÚ“Êãe^—âN’T" CÆ'Žð$¯•–œQn‹Zõé·n—ÃîÖýjïïS=m€9¼lüÊ•2àã+%¿Q•óÃ4¦s^$•Ç˼.Å $©D†Z˜«A^+-)£Rsw¹-jÕ§þ©ç‹=öˆîݾ¿¯Kïýj”+ª’€V¼3^"$•Ç˼.Å ¤–BT “`5Èk¥%eTjî®´Eö÷I{ï§’j–+a-qZ)“Êãe^·±§§GìÛ·¯d½½½žKÐñ,,Œƒ÷Òg'娂u߸q®çű€’}íí¢÷á‡Eïöí…5¶õã)\ÄÁm¹ûnÑ7i’œtkl»žç,Y eÇq}uƒëy^ ZÐz‹zÜIÓ>ضk›è¼«SZ°ÆvØßcic»xøƒ‹íwn—kl»—ÔÜö'²lÛ&úìÖ³µáûë6q”+Àmÿ¢î‹°ÛÙ+Äð£‡‹í ·;[ETx`ž+ •’ô{hš6MN.ƒ1èÒh kƒ}OZ ‡·|VQ‡æ# _s°ìó¿òJ‰‰Þ +¼ï¥“^Hºì–½SV®°vãСCÖC=$×Y…qHŒƒ;Ay0­¤­ì輫Ójz“%fÙå¶½Æv¥¨8Lùâ”P×ö ÃŽ½;äßí·´Ë5¶«EâÓÇ—–ËÎÂßXwÆ÷úã°Ã~~¸.îµÚÖÃÑÐ0ðÞê¼áË¿«I¼=Ò¡Ž8jHjHj¸Lï=‡{¤9¾¥©E\:êRO‡8¯0TêøWsüòŒé†ahvë4Q'Y7O|ÜGoCâM'¾°Žw^¤¸ì ¸R!:¤ê$5Ü }êO¾ü¤è=Ò+ûÜ5ò4µ{…!©ŠGÕðË3æˆ C«D@Ãàæ‰ûè“Ú`÷(•—™÷JdzÒO-‡þ‘ÄHj¸œå ³W2?ÎÝ/ÏTÚ.¯ábI­MqÙ‘YqϼY‹¤ŽAÏ%jb™¸?/ø°Â솤*U#myÆKÄ“®h¤¸ìȬ¸gÞ¬EÒCÒµ{’+0¼mÒ“ÊfXÑA†Š~WÅ£j¤-ÏÔÂZR\vdVÜërúF’ µ*H&Á¸õeZV¶E VGæ™)~™÷Z˜µØÏOHº1óè¦ßnJ]ž5­Žk_ZË2…ÄNfÅÝ«/+IØÏOHºAž\õóU2®Ø¼B¼ýSoïß^¹y¥yûȪ‰¨YÑP÷Ô­Žàð‘Ã,SHìdVÜkûù I7È£ž¦PÃÕ€eÿëíë•"zÝ7®sÞ8ñj èVGŒ“G¸Ëƒ!Ï÷°ŸŸtƒ<Dô©—ŸrÞ8ñj èVljgLd™âEŠÇgŠ{jÑÏO òdÇ1Ζ-˜ Mr-d…S]xÑïwë=Lc€eŠœ¢"(î¨E??!$<È“›æogwó¬Ér{ë[‹ûl½øô‹EƒýOó}Ü­w]¸1E-¦¬5»X¦øÀù'*‚âNÉn‚iî{àýˆæÆfçâîïÖï‰)jŸØòç¢â1äY€âN©; ¼ϬN7Zé0û»õ¿8–¾"(¤ZýÝh¥Ãì¯@wçHÒPÜ !u‰›ù> à5¯ÓÜÔLÇ9’8wBIÓkÃß’ªH¢ ¸BH‚TËüOˆÅB¤ZæBt(î„BHΠ¸B!9ƒâN!„ä Š;!„’3(î„BHΠ¸B!9ƒâN!„ä Š;!„’3(î„BHΠ¸B!9ƒâN!„ä Š;!„’3(î„BHΠ¸B!9ƒâN!„ä Š;!$w¼öšW]%Äðá…5¶I|dåùÖs: ¸BÊ¢§§GìÛ·¯d½½½žKÐñ¸–™3ûÄêՖؽ[È5¶Ý΋ºlÛÖ+,¸@ŒÑ,:;ûä¶Ûyå.¸®;|¸•ÈõÕRé{HêùFYô8x=·4„ÓoÑã×¢h°lœ¿%È C‡{÷îC† qöÁ—/_.¦N*ZZZœ½Ù‚qHŒƒ;Ay0-Ì›7OÌŸ?ßÙ*²téR1xð`g«6̘q•Ø¿ÿ(gKˆÖÖ±dÉ g«| ì7+úúEccŸ;v§˜3gs4Ý݃ĢEçŠ-[†‰SNÙ+÷½úêP1jÔ;=5ŠÍ›‡÷_ÿ˜cz…e5Èc³g?'ÚÚzúÿË_MM–8r¤A¼õ­ÅãÕ èùêqÔîtN˜k(¼ÞKRé@%ŒÕàÀbúôé²ìh8xð …¸ËÈ‘#EWW—§¸¯^½ZLž<9Ó2ãP{w;::R/î(7¢–>ø„¸çžÉâ§?- 'L°ìÂöˆ8þx¹Ó¦5‰5k¤ðA'M²Ä²eGœ£îÀd;kV“ذ¡Aœwž%/.†K[µªAŠ­-ÅíÛ;[áÐÃ&„%쮉p6Ú¥··x}·Û`%q0oBO³»w·xÆÙ çæùWr •–¾õ­ÉâÙgm/}n꽄 G%Trý¤Ëކ¹sçZi­}Rèµï4‹»IÅ…Ùì?ûÙqöV¡ †°M™"Ä#ÈÍÈ@to¸Aˆ§Ÿâüó…¸÷^!ÅIíß°AØ¢UÜïúdí²Ö.¨…]P »Ð-†K?VÔÒs¼0øÎnèww; PÆ÷õ©û”‚~c»Þ$×03›¨ãAà=(kÓ5×´xÆÙ çk†Ñ-lAçøWiéùç“ÂZ¨ Žéñ('DÁ+Œ^éRGqŠ»Êƒl¹35ƒqpG¯}çMÜÑ¢ÒͤÀ,Ôu‚ I?AŽŠŸ˜˜Ç,»RÒ0 B^eGTñÕÔzß¾b¡¯`_”ƉþŽŽâ6†·aÛ«‚¢ðªàx¡ßSç19ì1:ç§EÔSÞGÔÊGq^Ï|xæ:xVú>¼ë(÷ ªdšD}—I«¸G}„Ê-;¢¶þž¾(âX«Øb¥qb†µ}å•…m\…>á4ë‚©0÷W÷T•Ä ئ6<õ1–ÝSQ1Á½â,óz°6„}&feÆ|¯?,:Q⥒‰°ëÏ/jZŠ‹XÅ=‰Z6IfA5óE¡š÷"Õ3zaâ¯w«·žÃàÕúóJCzkW AS ð¿üòÂo¢T0€Yö]º ³¬ çªU…ã#GLé*ì@¯ Ý_Ýó¨8)°=tè@ÑC|ƒÊeÜ<;®çµò®§WLz{ËoÅ_pAiØÌ®ÄC M’]„ñP B%-ÅE¬âNò‹W!šÕ¼©.˜ª3z™ï¶ÜwîÖúƒ{]…¬ÐææÂ>„æÑG“iœèá„Èà3޽ðBi… èþªƒþfÄb QÆ6â®W^ ²ª4 "?&ÜÁ3Q*ap«ÌEiQ+>ö±bkkl›xY$*ŬHâ}è‰0ª$ ¸;xÕô«E­ïDÜ&9?ªy/R]07fú»-÷£À6[×]WêP¦_O tâÄx[¢~yØ“rî¯*0`,^(ÄÎBìÚU³¥Š r¢ˆ™ùN¢V>‚@‰å<‹w¿»XYÂÛ&ˆ;,x?BlÚ䇨e±Y‘DøãLWåBqwðªéW‹Zß?Ýœ™t‚­æ½HuÁÇ5šš Í5ýݚpEm¶ÀŸzj 9÷1 í… ãm‰úåaÜKÅÏá/çþ~"³Ò0ó]AN:âúf…>a+!z*:¨à˜è;¿Ê‰×{ô}ó=`‰ÛÂQÎð¸~*«šÜâucÜD½µßƒƒvý9¨E¯y4ÔÚÚSò;/¯IcÂb>7l¯w¨ž­þ¼®¡“tÙA³¼L'µ4¥Ôúþ„ÔݼibšuLsë¸ç%Ý̬ãum7³7>Šo†ëû¸LÊ0-ÃÜŒïqÁt ³®×¸s€cAÝqn&á 3³Y¦ ¼*>ˆÃ£6ô›–kž¯ ºܺP܉oáÛb.ÿÆï.»¬àg¿ŒFˆŠº§rPÄ¢§Hµx¦8¦¿¿.“jAqwÊ(ISëûRkLñÕûŒ£ôùzå%]ìà)­÷'ë}üp´ÂßW¨ûã›çO5=L³êï‡S×OD³¡éÂñWCîð·:æ'^ýÀ~˜ÏÁ¦†¸…ÅMpÝö…ç™ýíJ ñž. D|1\ÏÑíÚêÙy oXpmÜ÷RŠx^zúñú@£[ÚLÚ_! wBH*ÐÅÞÌðÎÆÛz **J€Î:«Ðš>眂°¡e¦S áÅ Á«ûc˜±cwÚa²J¤Ä¿ÑŪ  ú‹/.8·ak«sÀŽ`G%ÄW”ŠY-A„qQXVC¤ë¸U0Üö…çA@¨lmß^Š1E|uoô}XÔŒ`q½/à5ù Öj–<,ø[?VøMqv7=¬å„Ïï~Šâ}KêcN΃gæu.óÊ!®ë„ÁŒƒÂëyEÝo¢ÎÃ{Š+MzÅ¡ô^`¦çk¯- ­‚Ykx6+¢¤ý¨æéJÓî§¹(Ç$®LÈê¹(æu½›×‚Y¿œ²B¿Žþ¾âÀìz0ãñÆ\˜s@Ÿw KeHÍÅ=jŸ ‰N¥}ryi-=  Ô‡Á»Þàès†ÈaŸþŽp¾iÌ$¦f/CzþÉO ¿XóY%íG-¸Ã¤'=ܦXâ~:çrÄB‰*œÓ„aÀp> ë3ÃwYás¿šÐí9áoó¾ºC£×=*ñÆ\HX07ö½ó$ÂR6Nk¾Ÿ¨¦µ,RoqˆÓ”'õö”ÓJ”²¦UÝó»JŸXÌ4ªŸ´àZŠ(i?ŒY9êû6ã‰m®Ôç…0á~¿‰»¬ðŠ¿¹_ÿ¨~ÀߪŸ[-ˆƒWZÒ«åy›ÏK˜g¡‡ âåu¨i) z¬yË$O–LI¤>0MàÀ/êçëà\ !Óg³"JÚ¯Ô¬ìÖjó3õãúðЇw¼î!·{… ¿ßÇoâ.+¼âoî×gÔÏ8R©€UÓ+üž±ZÞh«Ö¸9  N¹V=,ï÷p{_ICq¯˜ ©&¦ˆ@ýÒ¨y¾«Ž1é§Ÿ^ü & ÁWáq¥}U8{ÍPPˆ›&í(bEÜî¯ß€¸Ë ¯ø›ûuÐU£‡ÉÚ"–œ¡ÎÄϤí—Ì~Zó2>Mëg¦W&c¬ñ‹xÊ£ròl”î7ð;s;ˆ°aëãàõ>üºTtÜ|âîîŽLÊÉõFؾ0B¢€‚}ìJܘ‡cÜÃMØü‹ß£Ò ÓÔÔWâÐ¥p+Ô~yA?Ô0@à%Øø²ÚkœGyTNžRQrŽmøÞ'ÖØŽB%åŒ[ÅD¿Âÿô¹¯__^åø¥¤ ¸—I% ª^¨Em•¤¿ï¹‡#Z]Û·„P‘Ãw/¡Á½ÔÄ$S¯ðË¿ø½Þjoh°Ä˜1]‘ g¿¼ ƒCàÖ­Ð? k ¶Y!Щ¤<*'ÏVÚÐÁ¼;wœ#±ÆvÌ0ÃñÍl/Ü*&úõ0wÀ%—Ò –r*/5Ã1Õ÷S­~³ZGÜúUª ßC:H"Ay0­„);àÈe·|íó ý•:™}™ûÆmp®~ Î÷Ë¿fÿ~KKŸuï½Tô¾UÙÔ?nÆ Û u ·þj¿k‚¸Ó¬_8Ãö™(üâ%<æûuëWsN9Äý€žËj¹ÇQûÎ:µ0³’uôï¹5¸\ÌV›þõ.³‹¦‰úħWþuk!/ZtnEež[kÑ ¿V´*ÌYéü>¡êâ¶µkâΰ„}&aˆbIcͪ•¶,qGâ^³¦!–AÉ&===bß¾}% èííõ\ð=w»a!ÏSlØ`¹žfioï?Ü+¶o/¬ï¿¿WLšÔg %×wß]<÷¼ó0¶»xo˜ØÇë+¹ž¹à÷¸ŽÝ—ç÷ö6ˆ7ÞØ8àܰËÓO[†ø¸Çߌ¶ÍsTøÜâë·}{æÌ>»,·œ2Ý’Ûúq¿%L8ƒ–°ÏD_€Û~¼g»Å.cí÷ŽÃ<¿rŸq˜¸í¯dQÈAÎßdСC‡ »Yo×jíj­~ŒHîß”³§PcC <+ Ë—/S§Nµ3­Öi—!‡tD‚ò`Z˜7ož˜?¾³UdéÒ¥bðàÁÎV)°úÍž}¹G” ¶`ö‰sÏÝ)æÌYW8!Apï/|áâç?Ç”v ⬳v‰[o}V´µõNðaÆŒ«JʼÖÖ±dÉ g+˜Ì‡ÉdÆŽ­Nüýˆ3~åç3Á{FtË–6»2Ùm§·çB½ã¹ïIEND®B`‚pyclustering-0.10.1.2/docs/img/birch_clustering_old_faithful.png000077500000000000000000000221121375753423500247600ustar00rootroot00000000000000‰PNG  IHDRó3%çêÿsBIT|dˆsRGB®ÎégAMA± üa pHYsttÞfx9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æð#ŠIDATx^íÝ_‹ÜÖýÇñ3qÖùá²ëµ½iÁ°—L¡Ôí]hÜÚŽp ½4z_š»^?…ô  ¾^jH‚×­ÓÛ6¥”¤IK.CR;õþ¡Æ»[[?}%Xsv4:Òœ##½_j5#?ši¾™ÝÏM’”*È;;;jwwW-//«ÉdR<B"5[êõéÓ§ÕT1—B~üøñb„îË/¿œ.æòãW_}¥Ö×׳'WVVŠg¦¨;w/ª¥¥¥âÑñ`þÌŸù3æÏüûž¿|—z½µµ5]Ì…þt¾½½=·˜¿ÿþûê­·Þí‹Éü™?ógþÌŸù÷©\¯_(‘¢˜9Š9‘£˜9Š9‘£˜9Š9‘£˜9Š9‘£˜àË¿ÿ­ÔåËJ:•oeߊ9¾üò—Jmn*õŸÿä[Ù÷€b€/ú“ROŸæ?ËöÏÎvŒb€/?þ±RGŽä?ËöG?ÊvŒb€/ï½§Ô… ùßÌe+ûPÌðå{ßSꃔzø0ßʾs"G1 rs"G1 rs@ü:Zi-Ts@ü:Zi-Ts@ü:Zi-Ts@ü:Zi-Ts@ü:Zi-Tsðaä¬C|_ŽVZ Å|y 뮇Wsðaä¬C¸^QÌÀ‡‘²ázxE1FÈ:„ëáÅ|=Õu@oä5ß(æ0FÒ…bcD mP(æ0FÒ…bcD mP(æÐ¥®ƒgU¤ źDð PÌ KÏàźDð PÌ KÏàźDð PÌ`ˆš¤æÍc?ýÔþܶlÆWwŒM#1yòäI²··Wì*µ³³£Ö××Óÿh|¨VVVŠG§¨ÍÍMuáµ´´T<:ÌŸù3æúü\¹¢&wïªÉÓ§*9rD%çÏ«§·oÏN3U'N(õèÑÌs]Íßf|uÇ4™£+!½þR¯×ÖÖÔöö¶š\¿~=¹qãFñÔs·nÝRÇŽ+ö1¹|íš:º»[ì)µ·¼¬>¼y³Ø›f›¤ÿLò3óÎmËf|uÇ4™ã=~üX]½z5/æ|2oŽù3æÏüCŸ?ŸÌýéõ/2W‰!}Pþ£,ÛVÙßßO666²í1æÏü™ðó¿?I.]J’S§ò­ìW1ýä“ÊsÍßf|uÇØ´áXH¯¹^€€*CX%òïûfÂþÌÿ‰{›TÝ16mTXxŽbUb^z•ecçØõ¡˜@•˜—^eÙØùv}(æP%æ¥WY6v¾]Š9T‰yéU–o`ׇbU XÕñÀ2Ç.ú|µ™§ïk#f½¶uý¦ûòu8ù~»l½Œ«%Š9ô¡ëV_¯6ý†:Öt_¾×. Õȶ³qY ˜@º`õøjÓo¨cMŸ—jD¶íj\(æÐ‡®X}¾ÚôêXÓç³òRÙ¶«qY ˜@º`õøjÓo¨cM÷eÉXY^¶ËÅ€½€@Ññ®›e^ò:ú œµ™g›s\¨ë7Ý—µßåf.Ùð]ËÅ€½€@X€¼Ž}Îà Å€½€@X@_38C1`/àÐWà ÎPÌØ 8„ÈëØGà ÎPÌØ 8Ô —ÀY¡³YuA^Ç>g]hrM?ýT©—_N+cZe+û‘ ˜€-—ÀY¡³Ya1M®é¹sùÐÈ=àe+û‘ ˜€-—ÀY¡3‚hî5¹¦ß|SüP0÷F1[.€³BgÑÜkrMåWñeæ~À(æ`ËepVèlÖcXL“kzïžRkkJM&ùVö#A1àW_¡.ÒÕ/nVèÌGÍçõŸ×¶~îäÉ>®¥0ûÿè£Ùý¤ó˜üå/ùßÌÓmƼnm®¥yŽô)äV¤¶lûmòމŚЂ@>î=´°“í||\Kaöñâì~Šþ³µé]öoòùúúl»Gs`hB ™÷„6÷ÛZØÉv>>®¥0û?8ÈÖt?éVßd&ÛºêßäóõÚ{§@1†&´ ü:³ÌÜocha'Ûùø¸–Âìi)ÿYÓý¤[ý‹ïl몓Ï×whïŚЂ@>î=´°“í||\KaöçÎì~Šþ³BÏ××gÛ=¢˜CÓ&€ä“{DÛ̱‹ “«>l_3}-ÿõ/¥ÎžUê'?©îWM¯@·º:½-ß_Üìÿ7f¿féyɨ$Ížn3Mç¯Ç5ïÛëQfÓ®Ðmÿýïùþk¯Ù=`sÃÔEЩ¯0•M¿ú½Ýööô¶ÍýÅÓckW€«£Çåúš5m××8zB10L]ú SÙô[>¦JÓ1§mÖ®WÇ×5kÚ®¯qô„b`˜º:õ¦²é·|L•¦cNÛ¬]®Ž¯kÖ´]_ãè ÅÀ0utê+LeÓ¯>F¯@'+/oåñ¦cN­]®Ž—ëkÖ´]_ãè Å@8lCL6ǵ Q5UîCŠüݵjLóÆ\7så7 ¥UÍM·õê«J}üqþ˜„åþñü<¹{›låoÅ-¯‹þ®y6–ªqhæÜ¤oÑdu·&lÛ-¿v-¯CPÃöö¶\‰l[e?ÙØØÈ¶cÄü™?ó÷4ÿK—’äÈù×q¾•ýYló rþucš÷|ݹkkùsúÙ¯RnKÿ3«Í6Ò6žmg[›6Ëã‘­Œ½¼ïb\ÂìÇU»¯ïÿ†ÊõšOæÂaJ 1¼T7¦yÏ×k®´6oåµr[Ú¬6ÛHÛž ÀÙ´iέMhÎFÝ58Š9€p؆’B /ÕiÞóuçʯ¨ËÌý²r[Ú¬6ÛHÛN?õf?f[›6Í¹ÉØËû.Æ%ê®áÀQÌ„Ã6”bx©nLóž¯;·XyÍjå7Ý–[¯¦mLàlÚÔãÑskš³aöãªÝHPÌ„Ã6”4︺0™Kå¾$ü&¤jìóÆ<ï9Ñd=Ý–ÜäØÏ>Ëw±ÒYÚöÓÛ·Õ½ßþ6ß·iÓœ›„æ„üu»J›×ÐìGæ^ ºº]l &OžvIÞgÿÙ°¶¦þ÷õ×òÓBBzÿK½^Kçµ½½­&ׯ_OnܸQ<õÜ­[·Ô±cÇŠ=ˆÃåkײåF5ù•ð‡7o{nuÙW[>ƸH›6çºóÏß~ûùWèRR籑ï ÄãÇÕÕ«WóbÎ'óæ˜?ógþáΟOæÓød>ŽOæªøºÚ·Êß[«Ò÷ìúÀü™?óxþ÷ïçß1>u*ßʾCSó÷Ü—ŽÇ(óþà½÷’§o¾Ù®M›ñ¸ó'ŸäßiŸLò­ì;Òû¿\¯ Àð«M˜ÉÔ¤ 3%ûMÙöפ¯&s¨b¶!¡®º6mƨە仄ÅÊ·G-K÷åSóOýë|_n#ªÛ4Ç6k,Âf<6ÇÔiŠ9¿\ÜjÒEMøèÏE›fmnA:‹nW–z•Zu{Ôt_~ý-Ï–íÔóº®^#L¡˜ðËÅÊ\]¯îå£?×ÁÕjjåvµYí¥ÇÉß±E¶-?ïãšÁÅ€_.Væêzu/ýù¸ò+íEÛåvµYí¥ÇI MdÛòó>®¬QÌøåbe®®W÷òÑŸ‹6Í6\­¦¦Û•¿™ËªqU·GM÷%Y._“íÔóº®^#L™H"®ø9#Q÷ãÇgQ÷y_M{ÿý÷Õ[o½5Ú¯æ0æÏü™?ógþ}*×k>™8Ì6™2=‡º„vé¹’æ–EMd;·-Ý¿Í54­K©7i» íšmØ$c_~~ÞsC–}Y­¤ü½µ*!}Ϯ̟ù~þòÝÞŠ{CG3ÿòô?‹Þç:=×ú~Þåþ›[wÏï&m7aÑníëo¶asÿò¦ç˜Ç—ŸŸ÷œ!½ÿËõšOæB2Ù6¡Ýļ4·©É54­K©ûz}\´Ût.Âåü}]›ÀQÌ6„d²mB»‰yinS“kh+¿"žw®¯×ÇE»Mç"\Îß×µ ÅÀaCH&ë9Ô%´›HÏ­Ls›tÿ6×Ð<¶.¥Þ¤í&\´k¶a“¸ozŽy|ùùyÏ ÅÀa.–Ó웞ƒüÊV–ó”•ÉšÎÅ SI;©òݸ*5¹†æ±²ôè¬sõxä>ââ£ò­Í}Å%TVwos¢<ÿ&a²ƒ¥~ÿ{¥¾ÿ}¥>þ8ky.e¶ó×Ìãgµ)5÷Í|4¹>ŽQÌ Š¹Dé¹sÕË™vaÆx¦öçGŽ•â'EN¶²_ÇìÏf¾úœ¼ 7éÏ…6cn«Ë¾jPÌ ÊŒ`–u·6á2MŽ-3÷gi&+ŸSfÓŸ ]àºì«ÅªÌfYà|h.ÓäØ2s–6a²ò9e6ý¹Ðe®Ë¾jPÌ Š¦ºwÏ>çÃŒñLíÏ+AÀÉ$ßÊ~³?›ùêsŽWJVHkÒŸ mÆÜV—}Õ ˜›Ð’>FÍô}»ÏœQOoßVÞ¼™mg¯´º~lÆ¡ÍOeÌl_BoMïïm43ésþùO¥~ö³ü[gÏæýûTulÆÜÖ¬ëÓäuuˆb`\lBK.‚Mum4é£É±Z›s\êºÿ¾ç«õ4Š9€q± -¹6յѤ6ãq1‡EtÝßóÕzÅÀ¸Ø„–\›êÚhÒG›ñ¸˜Ã"ºî¿ïùj=ƒb`\lBK.‚Mum4é£É±Z›s\êºÿ¾ç«õ4Š9€x4 U;+´d²9¦NUz\¯¾š¯Œ&´:mÆÓæœ*¥k)·~}ik«xbýK˜N‚t²Doù5-ëbå·y\λŠ9€x4 õDª¥Ç%Qþ…ÿèQX㛥t-e廼ûnñDGl®YiŒÁ_O(æâÑ$\J ÊT—Òøf)YV¾[ýâ‹ìçÎØ\³P_ïŽPÌÄ£I¸(”@”©<.-¤ñÍR³¬|·õÊ+Ùϱ¹f¡¾Þ¡˜ˆG“pQOA¤Zz\ò÷_YMþþÒøf)]KYùî¯ï¼S<Ñ›kVcð×ÓŠ90T¥ÐReX(6mÂE}¢Lzò·]Y‰Mn@"…GþÆëãµZä} Ï-­ª&+ßí­®æû‹´ÝĬkf¾þmÞB1†jä ¨æïs¬‹´]wî"mÃ)Š90T#E5Ÿc]¤íºsÇþ Ū‘‚¢š¿Ï±.Òvݹc„b ÕÈAQÍßçXi»îÜEÚ†Ss`¨ú uŠªÓü]ŒµªßEÚ6Ï}ð@½xú´úùÛog[õùçùq®C†m®áÈQ̸5öPT_óï¢ßsç²Â>‘Ÿ¥À_¼è§Ï¾®aÄ(æÜ{(ª¯ùwÑï7ßä…<•müôI°®1Š9·ÆŠêkþ]ô{ê”Ò¿P϶KK~ú$X×Å€[cEõ5ÿ.ú½w/[-+ä²Û;~úìëFŒbÀ-a®˜õ5ÿ.ú=sFýïë¯Õï66²­zã ?}öu #F1€! >jsà£F1€! >jsà£F1€! >jó1"(Ÿ\¾¿ºz¯Úö“>~äÊuùÚµlëmžœ?¯ö–—³­·ñ QÌLj  |rùþêú½jy_n}ç°¹t¨îäI¥^~Y©'ü†ø0j“'Ož${{{Å®R;;;j}}=ýÿÎCµ²²R<:íàà@mnn¦ÿ{A-É]sF†ù3æ?¬ùK2]mòwpùõ¹|ê~zûvñìs¶Ç‰©cÓ}ù€ºsbÀû?œùK½^[[SÛÛÛjrýúõäÆÅSÏݺuK;v¬Ø€á’¯šIB]“_£xóf±÷œíqÂ]Ï:N¿þ¯½–ïö™Rä ÒtâÃ(QÌ×lWÃ0ñú£sÀ5VØ7^ô€b¸Æ {ãÆëPÌ×lWÃ0ñú£sÀ5Û0•oñúÊëQ¡˜CE  Š90T±€Ñ ˜CE  Š90T±€Ñ ˜÷€\:A  ŠyÈ%\¢˜÷€\À%ŠyÈ%\¢˜÷€\À%ŠyÈ%\¢˜#áâ[rΕ+GÔµk—³-ßÄÂ@1FÂÅ·(䜻w'jw÷h¶å›@(æÀH¸øEÞÆ$ûY¶|Å ߢÈÛH²ŸeË71€0PÌ‘pñ- 9çüùD-/ïe[¾‰„bî‹ Qúg,×gh\|‹Bι}û©ºyóÃlË71€0PÌ=p4êB_ãŒåú@,(æIJ\k_ãd9[p‹bîA,˵ö5N–³·(æ¸u¡¯qÆr} Aó¡¢\\¨»®}3”ëƒç†öÿA1Ä9U‚(æ¢üàºÂÖß+¼ÿ1&AsQ~p]akˆïÞÿ“ Š9(?¸®°5Ä÷ ïŒIÅœ@”\WØâ{…÷?Æ$ˆbî+5öŒy] çH=7ÄPâçT ¢˜ûBf×c×ÀP º˜€™Æõ˜Æõ0ƒ.æ`¦q=¦q= Å ‹9˜i\i\C]1oZr€)÷{åʵµõRñL¿ºº¡Î.ßЧèŠy_¡¥r¿wïNÔ»ïþ x¦_]]P爰˜÷Zšîw¢¾øb5ßéYW×#Ôù",æ}…–¦ûMÔ+¯lå;=ëêz„:@„ż¯ÐR¹ßóçõÎ;-žéWW×#Ôù",æ}…–ÊýÞ¾ýT­®îÏô««ëêüs0b@ä(æDŽb@ä(æDnżÉ§mÉr¦²¬©MmÆcžóé§ùöÄ ¥^~Y©“'íÛ ÛäÉ“'ÉÞÞó¯íìì¨õõuõðáCµ²²R<:íàà@mnnª .¨¥¥¥âÑpH‘•%Ge¥2YàD¾-_§rEæÿúë»êoû®UmÆcž#EüÑ£|õ5¥’ô?s³úëïógþÌŸù‡0©×kkkj{{[M®_¿žÜ¸q£xê¹[·n©cÇŽ{q¹ví²ÚÝ=Zì)µ¼¼§nÞü°Øs£ImÆcž£ ¸ÉÇÜá{üø±ºzõj^Ìùdޜ̟Oæü—9ógþÌŸù÷©üÉ\%†ôA©Ù¶Êþþ~²±±‘mCtÿ~’\º”$§Nå[ÙwIæýÞ{$o¾ùÔª6ã1Ïùä“|{âD’¬­%ÉÉ“öm¹úëïógþÌŸù‡0ÿr½6×&4fzöL©?VêÕW‹éñHðìôéÕ¯~õÓìñ¿ÿ½~Õ6K®šçHèMLÒægÏ*õÙg‡ÛrqÍñ ¶˜/rŸn}®üZZŠáÖÖâ÷ú6Ûüïf¿_¤Í&tÿó®‡Í1€á ¶˜/rŸîò¹Ú¢÷úžn3¢É߯û¹Ÿúì¹,rÍñ ¶˜/rŸîò¹Ú¢÷úžnSþL!ûIO÷SŸ=—E® ^ÁóEîÓ­Ï•¿o¯­å ­4mÃd¶ùïìeIòEÚlB÷?ïzØž`‹yUhÌ&ä¥Ïý楮 º˜7 ËU1Cl}¤Ô•+GÔµk—³í¼Õã$h'+ÐÉ­Xe+ûðÇfu@¢AsÌÛÅ‹¬ª¾ÐŠy 3´vpÀ p¡â°ÆŠb^à ­--±\¨¸,€±¢˜×0Clwî°\¨ú<@_FYÌ›¥$ôvöl~OtÙJAÏù¹ªíØšÌa,l\;C3ÊbÞ$(e+8Ÿ8۱هøv†f”żIPjöíSýàlÇFØ«=®€¡e1o”š}ûT8Û±öjk`hFYÌ›¥Ìc%ç3g;6Ûãp×ÀÐDSÌuhI‚hJ;yòpxÉ 6Éjmr¬$ÑUju5\Vc²L3T%«¸ÙÞµ ÝŸÜ®UÈí[Íy Û°—-óÚ™ý ‰ëk}‹¦˜ëÐÒÖVþ/áG‡—Ì`“¬Ö&Ç Yìe{;\BlåãB @™sñ=Æ®û¸M1/‡–43¼d›¤€›äñ<Äö|?ÄT×!-Ba¯hŠy9´¤™á%3Ø$«µ™äqùUrù¸P]‡´…@¼¢)æ:´$3—…[äoæfxÉ 6Éjmz‘)ìò7sy\BlåãB @™sñ=Æ®û¸M1ס%ù›®ØäWåfxÉ 6½ñF~¬Ýö÷ó¿³Ëãb+bÊœ‹ï1vÝÀhй óÞã²_æ#±mÓ¦~]èz\¡^ˆÝ Š¹yïqÙ/󑨶iÓG¿.t=®P¯ÄnPÅܼ÷¸¹ï#±mÓf¨Iqó0 ƒ*æòëÛ2sßGbÛ¦ÍP“â$æ`UÌÍ{Ë~™Ä¶M›>úu¡ëq…z vsŸÁ§rÛ¿ùMz{ö,O±Kj½Ì&±m;Ö­­—Ô•+G²åV…,¿ZÕf]¿>¯Ï<6×Ã¥®û€±è¤˜û >¹nÛ¶½wßýAv?sýºž`\:)æ>ƒO®Û¶mï‹/N¤Ïëûš/Ö/Á0À":)æ>ƒO®Û¶mï•W¥Ïëûš/Ö/Á0À":)æ>ƒO®Û¶mïwþšÝÏÜE¿®ç—NйÏàS¹m)‚ò÷f)г‚d:h6ïžèº½ºû‰¯®îe÷3¯;ÎF“ë£çP5GÀøtRÌ»R$ÓÏÏ»'ºV×–f{œ+]÷ß Šy]¬ü¼V8³ ¥u^#,0 ª˜×ÉÊÏkU3ÛPZ×á5ÂrÓ Šy]L??ïžèZ][šíq®tÝ |ƒ*æuA2Yîãó¿™‹?þ±:pfJ³=®-3ð&êúk’#Xñšù$IÖÖ’d2É·²ßF—ó¿?I.]J’S§ò­ì×ñ}N¬¯¿+ÌŸù3æÂüËõzP¸:²êÛÙ³yš]¶²/Êᯟþ4ÿ§.¦oj[$\Ö&`×Õ9€0Œª˜W­žV~üÞ=¥>ú¨~…µ&·@­êFUÌ«VO3W†Kò›¡Mcjr TVmø4ªb^µzš¹2ܤ¼Ï[a­É-PYµ àÓ¨ŠyÕêiåÇÏSê7cjr Ôª~p!ºb¾H˜LÓ¿F×Êá¯?ü!ÿ§.¦oj« —¹˜`¼¢+æ‹„ÉB ¢…:.@¢+æ‹„ÉB ¢,"ºb¾H˜,Ô 9À"¢+æ‹„ÉB ¢…:.@¢+æua²y9×§PLjCtÅüÓOóeX_HG.[Ù·5ÖÔ8iy¶èй|\>ÁÊ×Ëd+û¶Æš'-Ã]1ÿæ›â‡‚¹?ÏXSã¤å`Ø¢+æò«â2sž±¦ÆIËÀ°EWÌå®fkkùú鲕}[cM“–€a‹®˜Ÿ9£ÔƒJ={–o%g†»tàkuU©£GóÂ/ÇÉñ!¥Æ» ¦‘–€a‹®˜›f…»ôcÛÛJäÇ5 Ëu`À…è‹ù¬pWù±²&a¹.L¸}1Ÿî*?VÖ$,ׂi¢/æ³Â]ú1ù›ùÒR~\Ó°\¦\ˆ¾˜Ï wéÇ=Rj?_`¦*,'º ¢™æÓú >Ñó&ªg!ÑB L£*æU³ƒh„ã¶FUÌ«g!ÑÇlª˜WÎB ¢…8&@˜FUÌ«gó‚h} qL€0ª˜0Ds"G1 rs"G1·T^‘íÊ•#jkë¥âúE1·T^‘íî݉z÷ÝÏÐ/й¥éÙ&ê‹/VózF1·4½"[¢^ye+ß gsKåÙΟOÔ;ïüµx€~QÌ-•Wd»}û©Z]Ý+ž _s"G1 rs"G1 rs"G1 rs"G1 rs"7IRÅÏJ~üꫯÔúúºúòË/ÕÊÊJñÌ´ƒƒuçÎuñâEµ´´T<:ÌŸù3æÏü™ßóßÙÙÉêõÖÖÖt1—'Ž?^ì€ÐɇïCŸÌ¥ ïîîªååe5™LŠg¦éÿ˜÷é}Ș?ógþÌŸù3ÿ¾ç/5[êõéÓ§§‹¹-™Œ|‚ßÞÞí‹Éü™?ógþÌŸù‡‚‘£˜5¥þÐf£䨒xIEND®B`‚pyclustering-0.10.1.2/docs/img/clique_clustering_target.png000077500000000000000000000550421375753423500240110ustar00rootroot00000000000000‰PNG  IHDRðܵósBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 2.2.2, http://matplotlib.org/†ŸÔ YbIDATx^í|eúÇŸôBB'!€pŠ"(DšRôNOÿêq¢¨wtTPQQN ŠØûÁ‰gål „&Õ G @ $„ôÿüÞwóîììf“l¶>_>ÃÌ;;;™ö{Ÿò¾oH…ù9åååtìØ1JHH }-Ã0®€WÀÙ³g©Y³fª¯­ü 2LÝc|VBÀ³³³)--M/1 SŽ9B©©©z©zð3È0žC>«!àgΜ¡¤¤$ñ£õµ øB^^žßÓ§OS½zõôµÕÃßžÁ’’Z±b 4ˆ"""ôµÁŸÿ;Æg5 ? ?/p†©îx~üíÄ‹û‹/¾ k¯½6¨Å‹ÏãsV³€Ã0 Ã0^…œa†aüàðìl¢ÌLËœa¾Ï&` >Ç‹lÊ¢ôt¢,óÅ‹õ&@ðƒû¼<¿œÎ.9K§çœs”&Øø½˜èšŸ‰RÖ[æ(»Jð¸|¡¡©Ëœ9h¸jYù˜1l¡0ÜçR¸ÏÌ;C¥ûK©¢°‚J”RÁgú øHáNÛ@ôu.Qn)ÑJm~×n}Ž,tX£GW¾ÌLx¸GOÚÙ ^ªš]»vRûöíõRíØ¹“÷U‚a_;vT_¦{~Þî¼Vwz¿~zÁ‚§²Ð!ÜéÒƒÚ›ÊäQ ‰ ¡¤ÉIz©ná l>À[çâÝ~+QN‰¾B!%\[ß[/0>g/à°8à>t"ÞaaT¶/‹¨X¤¦6¡ß~ûM/ÕŽ&Mx_Õ!Xö•]}i÷yØéâä>'í>§,ûûÜS«–6™½qBˆÂ[‡S°}EÝÂâÅçxëÀòþJ³¶hO( L&ú²ƒ¥lÄøœ¾ }ïÞ*Å»üÕÕo†ñ5Böí­Z¼x÷>/;Vf.ÞÚ[âw}œ¾‚a›-yú‚B„V‰…x¿u‘¾Â_ÀÛ¶Õ~¥ýϬ ¡²& Ë»âï#ôµ ãŸT´iKîó[_`±¼Gx÷>k¦U"ÔnÒ!Ü„S½‰õ„åø¯#†Ý-Ö¶¤füéi±¼Gê+] ðŸX Z, aqOÒ„ûÀaªx6ƒ-o&0Ðîãòù Åý Ôûü­‹/ö‰û6,mĺY¸™`V6¬mÄ»‡hó]«'Ü’àxr`yhÕ`q—Ïbáfx’p—}“é“÷9„‚D5n&˜XÃÚF²Zu­n•ày‚´™È2gáfíþ®èÛïs† ¸ Ì0 Ã0~ 8Ã0 Ãø!,à Ã0 ㇰ€3 Ã0ŒÂÎ0 Ã0~ 8Ã0 Ãø!,à Ã0 ㇰ€3 Ã0ŒÂÎ0 Ã0~HpŒ®ÓªUk*,<§—jGNN5¨ÆøáÎðå}¥¤¸g_'Oºw_Ápîݵ¯˜˜X:xð€^²ÇSÉú<”&ŸàoçÀøœ•€_ýõôÙgŸé¥Ú cR7nÜT{ñ×Kµ£U«¦tà€{öÕºuúý÷À>÷îÜWU÷= 8‹Ÿÿpv¡3 Ã0ŒÂÎ0 Ã0~ 8Ã0 Ãø!,à Ã0 ㇰ€3 Ã0ŒâþÌ3ÏP×®])!!5jD7ÜpíÙ³Gÿ”a†a#>!àkÖ¬¡»ï¾›6mÚD+W®¤ÒÒR4hè[0 Ã0 £âþÕW_Ñ]wÝE—\r uìØ‘Þ|óM:|ø0ýðÃú Ã0 èød ÔArr²˜)** ÚÕ‰©[BŽfSèšL17+›a¶+ßc|GÏ :Æð—Éߎ·.&>þwT|®'6Οÿüg:uê­[·N_kËã?N3fÌÐK•pOlîÝ—ì‰-ìíÅy÷(Ü,TA!TvãÍöé‡R^N¡¡TüòB*¿z0…ìÛKmÚREóTËwîmÝæ¸xš5ëyмW_BÅ“¦ò~W[¿£"„~Óíïi÷D^âs¬ÃßèyÇ_h[Πˆµ$®c]ôÄæè\²d ÅÆÆê%¦®8]tš^Üö"í=½—Ú&µ¥ —Mëë’¢’ÄzIM¿ÇøçΣaÆYŸUŸpÄÂ?ÿüsZ¿~=¥¦Ú¾Ô%¨ýc’à”––Æ®áÎ}AÀ³Öo¥è [ñ–`)IJ(€“6YýÉYùØC¢,)Ó¦Plc²ŸŠ|çY*½o²X.ÄßRaØé°;(|é»bŸØWØë¯!>¯ ÁpëBÀ=ƒèÃÝÕ}xX2È·8p _v#zÝË×ÑÊ_WRy…å‹ ®-»Òæ¬ÍTV^Fa¡ate›+)*<жÚJ]Ó»Òëw¼N#ßIßìþƺMÇ”Ž”Ò …VíY%ÖðÐpJŠI¢ÒŠRêÞ²»ø^ãÄÆâ³ßó~§áo §ïö'à+Ú\AÏßò<=üñÃ6GnïëøÛ}€ç c$ø¤€ß{ï½ôÉ'ŸÐÚµk©U«VúÚªqõÄ^= à‡æÌ£è;†êk\"®Š·+à&,ž9›Ên¹•bÚ¥Û}_н•°0¢¬,ÒjyúŠš ×±.܈;öáIðâöç~ÀSîK¡Ü‚\½dNDX„x)ÖÛ ¤-Y[l¾—‘@‘÷¥U¹©ß…ýhÕäU¢|Í ×Ð×»¾ÖžÇJÙh߀N;eów¾¼ïKýS߯ßîãsæ1pÔ!î¹çúè£hÕªUÕo¦ÈÎ&Ê̤ŽÅÅúËN}¥ëK\³ªUP·wVS„8GN׬öMLÅßF¼A™¶Ç}ûôÃÝZvÓ—là)V5æ°ñ=ùæp™whÞÁú=#êõûÖë%U¼AN~ŽÍßÙrp‹XfêŸp¸Íß{ï=?C[pX˜ õ-˜:Ck1‹¥§ @_ŸÎ¥ÈYO:^|&\è °ÀK¦³ þjŸÐ±}+EmYGEÝ4K£cW}­-]º4¥#GÜsîÓÓ9Î^5VÔ,_Üİ”—Ž^*¿`iK±†Õl·vFrl29F|?4$”’ã´ò¹3Bd!úØ'VƬ]•7‚ãýj×WzÉŽ¿KV@|9¡càŒOþÓV«xÌQŽ\±Ü.Ö ‘¬™|[ö+ÿ†ÄX® üýØ¿ ¥øöéþí×Tzã-T2b,Ÿñ¬ÝqYö’-ÄZ%eÜ_¨ÉõÝ(yæ$1G9ìx6EmÈs†ñïÌ=™Âú-)+˰²ÄZ +æßîþ–Ξ?+Êg.ìÜs¹Öï# ñiüùd㳓ù']okî{ˆ5**h!Ø 8T8P‘¿ËÈΣ;©áý )tT¨˜£ÌTðGµ¾,A9üçMcÍøLŠ¥u®Õäk"ìfßqe?åèûÆX;{)¿¼‹“W–eû&îAqÿZ,ʉ³§QìX¿ƒ9ÊÍz¤Qã[P³^éÖmÆÓËÛÌ€šdJËJ…ÈC´‘UkYáˆaõæ^Õû©SO/Y@³1ì“Yåß‘ ëÚÁÃ)+ ªøcÂr‡Ç;ˆÊ*˜wz¢“ˆí;ª(0æ°€8å›êK¶Ä.YL…7w(ây3æÒ ¤:óI&þz2S,*TWÔ±}ñ˜{]ñ²2 =`É2/¿ m•‰m!šµ‘üÈa‰×{åi»w Êr°Úµma‰7ÕþNÈj%‰aêÁË+ÌÂ…ø´L2ƒ`KËóĘDáÊÆ”37GÄ¥{´î¡íÎv‡hÖ…ïš!÷güâæ/Þú¢ø»*êvdYÑP1V:TŒâ/ãùò8$ðÀQ•åÎØÂ@Àb½¢¸ˆBUŠQñ ë´GÅþ4˜˜ߣÓo}jŸEFE×ÝLÛ#"©äŠ~Z/DÏHñàëô%sŒåÈE¯X x”ÍŽ¡¼uËróT:?oaeV»øßˆ~ÔÖõ&¿ÖlÿÆ<ú1÷E@‘H§Ð7Ù*gêļ@è \H.CjôU]eFÌ‘EnÄØ¬ ½sÆNJˆNÐרs¦ðŒÍwÇßî?§¿M¬XûUƒšÙnt§K¤ø«!GàóÍ7[­u¶ÊÃîçˆ.G×dRØ }Q:}|&W$§Ek6(o–JyÏ/np#±ˆMk4E¬|˜±TxÓíbYVÊZÛ[ÀÚÃ|nÒcUZÆFP0öâ{'U ´6?ÿ›îUKîAù;²èüÔéZT<ºövé˜ð;αfÈã¸ÂïÖ8ã6 Ö†\2Äbe‡VZÊRää÷6Ø(Ñ`#ñ Ö¹ÕúÅ¢·¶3«âm´Àñ·—=»l‡c•âŒ9ÄÚþž¬t8z8¥ø;;.l#­u¶ÊÃî§@¸Ã™"º9¾V³ §=hµ’1Oœ2Æj‰Ÿ6‚r¿ØdoåjIÜüçlž9,#É­Aç¢2PÿòtŠXõ5å?§XÀÚ<ÿ¹TvyWÛõâçàošYÛÅc' .øO¦˜C° ±-*c¦^²ûÍ}zÈ6GV:ÊÎÀØ…V†;}?wÃÔ £`#YÍL€TÁ»ª½•íVü²BXʰÌ!¤Ø,dce@µ~U­Ê*6Š8þ6¶5‹z¬˜‹˜· ò·« w¨|ÀŠW­ªã’ öoLè3sß;,à~ µ9o޵y•™…¿Q/Ybác5+W·N!šcî·kž„¸Éýj•øI£©ô’têÇ,Ǽèv‹ÀbŽrþ“ÏÛƒüÍóóÐùUŠ>ÖéÖ6¦²+ûÙXÞTX¢'ZBQÁQž6†ŽmÐÄ_oJ†9ÊgFO¶VŒ¿e³ŠDEl…|°LLl3®kÿö¢IÄݮ޳ºJ2`—j ™Qî¬2  ¬ºÞу™›Dv¢”8ËßΜœiw,®"­eT8$h†}ªÇ¦×/OþRé‰0ÄìÑ!Ñ»`æ¾vXÀý ™å«*’ÆþU¸Ò1Á­?ŽXŸ?n2ålÍ¢ÂQíDÌ ü­¤ÁÝ…%Ž˜8Üò*(_‹µr`ëG$Ô³ZÖÒîÌÚ6º¯éoÆÑÇÿkE¯ùÚ²Bá|ÿké·O7Sîcö• ”óFM"ÙÄ»ìÖÛ)²OwŠ>Ô2µmÁqqÆ% `X ,\üSÅ+-gi±^<ýbQÞ5c—Uä \Î@eÀ˜Ýí 3·5ÊX?½ût:žq\üíöÍÛ[ÅU‹«˜Å¶q>à5pt|ª˜ÇEÙöªˆ}+7! S=rL$EŽËUýö@‡ÜÏÀpš®ˆ7Àv‰“ÇPâ¤QÖï`·p®X†ðæO|ØðšÁËÇXäñÚ¾Ô9±/w:ÊX¿<:ÆÆ²vfm›!2ÑMâø¿Im Ž&bh*†&cMnèAû÷ØU.Äqý}"uNnHÅ_gRñ²O(ì½·m<X¿›ãâLÕ@Àª§HËYZ¬fñ]\Ï*°Pá’–ÀÅlö]3¤Âeý"žŽ2F sŽbÛqõødÅÅXù@qªµÝ½UwÇ ~jûyx8ªúí ¸Ÿ!ÆÎv!IK¢Õdnr¸×Ãî–yü‹³„5j\íáAOmfC~ÏÒ.šž­Øbçn¯ ú¢'ì;t‘@ÄÑ<1ãQJ~¨ÒCyÂ’Z  Ü¦RxyYÓTÑ kÈýyóŸí¬t ÎÇÅ™*Ý–:Cu£;ŠïBÐ JX'Ånæû‘]<Èên–Ö½ú]GH!<9ï$˜{BtsZ] »*d%Á¬ù R¬ñÛÔŠ Âó¢Ò"êÓ¶©û^Š>ö£‚sìqqp?BVò¤c!3â(i ±ÞÄÉŠÐa½&Ú¹Ÿo¤³/¾¥Í7‰þÌUð½²V–¦]Ž€%7;ÜÌÜíµ¡xÂd:ÿÄl»ã’ -x½—Ÿs#ø}²¢rfÜCTÚ¢µhÞ±¤˜ÂÇkçÁä;@œ¿ œÿf†qX–2Žë(¾+Ö:&X¢[Õ½íJó2O#+ Gf±ó@h¥XC„ÕŠ‹Œëò^·wø-oµr!ωYH"Øãâ,à~bàèTÅÌZê-Žå›o§¼çl“Æò2PˆIÛn”CΈåRM€'Å׳ù^þœnäšP2q uJn¬'¨™x ô¹#ð9D^ôÈÖ³…qͱx‡Ré+šõ^Ë1Ç™Àg{öv}Éôtʵç YÚ°(¥Åj´8]ɼvô]_‹vèð¨YîR¬"¬‚öèȾ—V¹yM} ,}´Q÷¥ßî XÀýˆv؇Ë(bÂXKöùÓ>ª€a9æßïQq¿Á"i-÷ÃL1G³2Ó¶Ý {IL¬iæ¹·ÛûÌ´ úíS4«þ-,ÏB f߯¹-~q>ÿ÷•ÿÍ7~3ã{H×.ÄFO‘£uA¼¾Ûÿ°(¥ÅjLsd™«8ú®¯ oð%ƒ­¿ÅUÔl{ĸa™«¢Jº|-~­XôHçk¿ÝÓ°€û8¢ÉØ…-(ꎡ±X³œ—·+ †‹ædaö q–4æyslÛvÃ27ZØ(»Ûî.D›ïYÕk‡î*!ùgm-ïìlîr•¢-2¡ÇFR“IM¬ÍÆ :®â,nëËÖuuQ ÜêÎ*9f˜YëX‡áQqí=LÉúîx๔œl?†7úéFWŸÕ«ÃÚ‚‹‹ œPp‹Ã²–ào´*+¥ƒaávãjçæš-^NžÄ˜çîÚ×)›ó%âÙÓÏuz¾p.\©üà\uJn(ÎɰÂsô\¾eÜtTŸžˆ‹§Wcã±™ –±ÅÝóy<𺥦ÃHÊd*g®àª¸¢Í”• Üå°¸!tÞ°$=9”&ž㹃+çã•ÃM‹]u kÛÑy†‹V>û®ÉùäñÀ}W_îüøqwÞœ6o>ª—*‰Þ˜IMo —ܬբÝY.Åu[¶ôÍñ­›4q2†÷Ö­~e›ø>Beó^!­Aôóv ›ýŒøÉ}Æ }•ÓÏΧ°ßŽQü ¶‰qøFþ}й‡ž²¬ÐéС ýþ;Èw9,nW@ì;1:Q ¯©‚õÒ­Á‚•*ÅÈ“xC¼PBBškão—b /E‡æhÝ×Qi…ì­¡Xõ!uŸÖ>â𮈸¿ 8»Ð}˜rÍÊs¥£ÛT{ÐLŽòtíJeómC¢U„{¾ŠŽm˜ÀÀØ>;ï|žXV0c;ã!‚E+ƒ{ y\È{WcµAAµfc¸çÐ8×ÁàÙ`÷A"wü`* *B¤«È?σ&àÅï-£¢=‡4ñž"Ö#={¹œO?kwѶ×ËõÛhnÖìŽ <à>W›@a9Ää^‚¥÷¯ãVˆ£?oG.ä`§w›ÞÚ3æøÅgK ”k‚ÊY×­ØݲƒgƒÜÇ€ûF,« [¿¤c휚ÃñïàAuŸˆ¹±i˜ Ü·è¯ÜØ/¸ÌžfÌàÂ+‘‘- 2Ì€L~U¨UW:Z˜,%p£¤%†Í¬J®må<½ˆŽ|w˜^ŽŽµŠÄ»ôeîËÛí\”ÏÊBŽ,õNÉèÜýÚsœ»’²ŒÌ¦¯SÁ:ŽÆ‘Æ· ±tL"›GAd¿à#™=Í8G ¹fpÔŬÈF¿°¿XV¹¨ñEúR`Ãè;†Ç|"!QÄ»1Æ5:l)»‹ûò6Erd©£§µÈÕ†a 51/}¿XÆÈlg^xÓô•ú»ƒÎd˜€ÃYlVãTchL‰™1ÕñnœSx0PARãÛ8ŸèÝØ*à×ã¿êK ¸øwÜç˪LN3‚WKƒicÄ÷°2ûT6¡bƒnXŰªê9×–ãçÏ¡]ÒŘ顱LÿH‚rÄ–ï,& ÁHcάn#„#Ú { œËµ{׊Êš’í8ºƒ.ž~±5™ ¨9 ÀXTXÀ}tÜ’ve:¥<íx¤1g`Ð’ˆC“­.­ËJMsÄ\[Ÿ8e •µþƒÝ5A¹¤Û–pÈŽ[äHca!•±˜%§©@ì9YÍ}›ð!›Ùþ2™ ›”9kbH°€{“­ÚCþüótUQ¡]Ç-ÕñŠÐ0*Iç˜lu9nš™.A2/´‰…cŽ2ÆLgB ƒmH "ÎFׂ»“Õ܇ÿVQ“ÙФLv’ƒ9ÊÁ ¸·¸K«9vïF!“'Ñ’¼S­@W@›äœ§ˆ8S=·VUüoKÒ˜¿RI+)÷Ë-”7c.~g9ל»Q `m‹!BÇDŠaB±Œ.S¥Õ·miYeÛn”˵ç59Î6î ñ€uÞïÂ~œ¬æFp.eÿéjÅ ç[¶ o˜ÐNÌ=Aå‹ÊÅMÌ‚poËû·­"mfq£l&&Fp•;õYÊÊÉj5åü°”³5‹r?̤³ÓgÛYäÌ$qÒh*oÜT«ö—PÒ×Sòͬ1rÆ¿µ¹'S´1Fœ1ìPëm“Õ,èn­º !7‚æchÏÌÉjîCMDV?²ùÕvá¢ý¨KÔð‡'DBx<ðšñšSRj6^ó˜‚z¢ _/U‚ ¡ZÞ(ã×êÿx¥˜Õ¸ðYçäÆÂšÌÍ=áÆq·OjçÓ¾ÏçêÒL³dšœ=E¿%Ô§c&®°ê’—‡±²ê¥Úa6ûç hN}W™Ë#¢èO%E6×ÈrîYÏ=îÉ6™ÒD¸ÉU sX ¸ÇaJ7»´ÔÄÝ8D¦¯âoCiªÀS¢^\¯â׊…Xc$29È ¬u¾£ëáïÉ•€»s<ðÆš5vð`Íš…|ùоù:;±VË’óãî§ŠÔ4*éÞ›Âù™b•«ä/ϤÒÞýè Ý7&uròhìØÿê%×IÌ˦G7P̹“”~ô;ºlFýª ríaZ=äY:“ÔBüÖ£é½èl½ê»ýgÏÖ^¸¹îù7£_~9¦—,D|¼ŒG ÕK•8ºFçîžL…32¨]»¦tø°{š–¹s,vÜõÅ}ý+׋AG$pÍÂâ†u§.¬@ Ä" PÍR7nç“”þNåGï¤Òü ß‹B›¿Mî?^„;Œ×ííÑÜ Þˆ;:Õ1óŠðxàLµ{{1EÿåÏBä#yñÀ?*¯ (G½öÅL{€õëήØ$bÞ*ÞT‚ÝúP&5?¶•†¬šB¾’FÃ>J7®OvýSˆ7­(§þ_N¡—¥´iü¬4ê÷Åjrd+µØŸI g|#¦\Öݼßt3ñ1óçVÆÃ³³)töÑæŒosºè4]÷òu"Þ-ºë µtŠ6\äF:4ï`ãš°ìÐý§ê^÷É6M°éð¢ÝšHíÖîä}M(¤ðkŠ ;«ÍWí¿X[i™°¶÷a0D«TÂþ0‚ü™­h°€{£Ùy}¶ù=ñ‰t~îkbÙ>ßõ]Ѥ)ÎS’®´yáÜTÑÜ; l·/Ö»\2€Æ¿Ýúlžãô¦REË=ÖÍ¡;_íFÃ^@ãfµ‚îm!Ç%ECï°«P9MøBì£a…ç(êÂtŠ2@ÌÃÞâø¸/óâ¶é›ÝßX‡½ªÝU ‹ŽA"Ã5!S…ÈÌtµ “šd%{aó:à#Z%cO}¢ÿ6Ô[{?œƒeZ™Œ'ŸÅê*B€E«MØÛã{ø>öãc‚þâ­/І³öúj³¾@‹³€{}æýœ¿”ŸGQsfÚˆ°+CÄ›D%SÞö,á6Ǽx¸çØ`uwûa>ÝøÅH«…m<^W‘ßÃ~ è°Ì»­£¯õ<°¦£–½ëòïA%ª"6ŽžÓ®£µr¦ÍÃïmIXd|’=§öXãטóë7ÖûOG~ë%!¡!´íÈ6›í¿ýõ[!j’æ>‘ÀvìV¢‚¯´›ó´V#…;¿R¸]CÛßÃ÷±Ÿš…þߟsŒê樳Ùs zEdÞ‚¬„|g¤Xﯰ€{Šøx“ú¡å"D½¥YÑ–¢³m#Ÿ½´E¬úZļ½ayÃꞪYÝ7¬_'7;¸Ú»­É°¬ð0¡û]]c ý}áØû)ôÐA‘l¨‚}DõíΖ¸¢vÎ0 (^ìpÅعÅeY‚lêäTß±äÎï´XÍp‘ kÛ”k:&ˆùÑ›ô•ÞÃ8ÀŒJxX¸ˆyËq×U¯ˆ±S˜¿¬ '6?á·–8 ¸ ÉÏ×ë„öÈõË<Ôñ¶sÿá’÷4°¼oür´vlfÕ ÷ßÞï«E|ÜÓ”_ÐÖiç.¢¯ôg_¦ó7ß®m\N±¯Ì¡„Ñ5=#¸Vá÷Œá˜¸R&Æ¢3ÎõcëÛ€Ù8ߥ¥6ît¯r¸¿Åj®k 7è ÞÃQç.ãŠK¯È®»Ä:t½ŠöýƇîõm9ÛüÖg÷ mœ DëÜâ¥Â5.’Õ,«MAaÞβEö‘Œæ p¦ï°Õ³,bàÏ›wî"—ãOQÿ~ÏZ‘P;¬pi× 1rÆ·¸0éB‡"ðrWÝâ=ZYIÀ’ó‰®SËOê uvÏï÷j²›Ì;@n&´€Û#“!>¯HòÄdJ{0MxTàYAvºÙ0°hÏÿý¡ïõ’ÁîAàî.~Ùq¯_X_Úµ§p—wîJçg̶ÛF‚m=y×ù­ŸÚ7¯ªK ŠC>éñĶ¢ÛGЙ/7 kÛ(ÌÖÄBñÕ`<&»ï1á² tõEW +/~uD+´6f“C4Ôm$ÒÅî5¤ëÜáÛ¢.(³¸é{Çó -l´@"¼#â¨ð(‡W1rc[~G\ÚüR}É¿`÷0åW¦¢7—Pѻ˨øÁG¬9Ù˜M^4a • ªl^f›l[× ‰Ø_ŒrY´Ü ÎPçïæY $¤ ß*Ö’ý~“&iŒ÷IŠJ¢å÷,V62Ïyò§cwC4Ö<¸ÆÚç6,¾z1õ¼Ÿy~¨¯g\çf|ëÕ¤6cLžgññ@ƒ܃ˆ6à¥SôC)òοµlMçw¢êÕ7Í&z1ƒ"V|n Ì!øg¿ÞèÑÌsXÞãÞî®Ý,ž¬áÛÒmÝs·ÂÍbá59Hfcºo¤%$/¡6™„&­:GÙ䨦ÿœþ¢—/¸×añõlÝÓt[ ›Š‰&`Þ¢ÔkV8PcáÒâ,>î Qê¸$à¿þú«è†´.yõÕW©U«VM;w¦uëÖéŸvmÀµ9Ê`Cd”5í£Ÿjgñ 1(,ÐKuHZÓ,ooŠ7Àß÷´n !Ž^Ö3aœ;ßcºo¤%$/Ût;ÛÈ.:×cß²©˜WÑîþ‚•^…ËdÃŒ[2DolèË„<Œˆ âäf \Ò%½‹^ò/\ðââb:tè^r?ï¿ÿ>Ýwß}4mÚ4úé§ŸèÊ+¯¤k®¹†>¬oáÿ˜¶×Êᯚ‹RØm{ƒûÀ"ôdì]¢z[¼%ݽ`…#~ú§,:óI¦ˆ‰‡ÿ°ÉÎ#’÷Ïå-u!ú// Jõ|s?Æ1^9 „Ý¡VÕ ®Y#^}Ÿ[¯/Ô ÷=Õe^…K¯ âßk÷®Müp}#Ï—+B$W·»Új™C´ I‰K¡Ë\F¯ßñºXïoˆ·Î<àtš3§n;ÕxþùçiĈ4räHj×®½ð ”––FóçÏ×·ðDºI,4üŹÔcN(kmî¾-üdzžmûíÚ-@Æw³Cõ’ç€%ŽÄB7©„¡²unú,kWB´ŸžMÅ_gRÑî,*»‹GŠó5 ¼rXJ—xU–8\³êw ^}×òá´Õ‚ÂÍú‚w1‹‰KTk9ÙìxÆqšÞ}ºwB n@ÜóæÍ£5kÖë×lÚ½{·Ø¸.€uÿÃ?РAƒô5PÞ°Áûí ÝD·l€ío膳KI1…¯Ë´i×í _PÜ·š˜#+½xÂdQö§’Zù’†Sô9O5•±ÇQL<þ±(ö‰‡hf\|¥hß?…ÊûôcËÛGyæÆg(><^/Y¨Ê%À‹€d7€W_ü¡¶Çï]ªs®+Œ1qµÿzTÎp }ªÇ¼Z"ÞFmÛ¶¥û￟233M§E‹‰ë ›X¦Y ÛžL”ÆTTT$FeQ'_â–¹R/UXtö Å_?€;¤S仕mžÑejÁ¢%Tðæ2ÊûùÈJ÷4õÏtoM½–œuÏp5Á¬}¸Õ®Yâjºˆuh;z1º“?LS?šJù¥&Cú–Wˆ—ý¹C(ûd¶Íw’c’é³»?£ã³‹9Êêç ³µc=­uípG½‚ÊÌÓÃÓ¢á‹,MãRăm³"sî\|§Ýw€q/O*!Nô¶Ûn£FÑܹsõÕ¶lß¾.¿ür*7¸ÝÁ±cǨyóæÂÚîÙ³§¾–è©§ž¢wß}×ÔúüñÇiÆŒz©’ª†2tïxà'«5øÅEôÑió¾{Uà†íœÜúkÛ£omHB“âiIL,6qJn.Æ‘vÈ8QDφTÐä²3úï‚Mßèæô]q5l˜dYYK0xýúÕw!ë‹ iæ¹³úšJnLªOÃÂ…Wâ¾5"RŒ^]Nžtßu¬‹ñÀ=ƒK–,Ï×þõp:[bý$p•#6 ÷*ÀÈeüdïé½Ô6©­hCŽfhÞ¢WêcÔ v‡O´PDªÎÿ :Ѧ£–såK¯sBD½;ø]½ä@¿† f}V…€ÃÒE:==]ßÌsÀ…Žþƒ> o¼Q_K4qâDÚ¶m›píÁ±b’à„˜yU/ wŽÞ¤IÊήÆxÍÙš~Aº] Õ Xܱ#þj³-¬¾³?gUÿþÃÜ;øê†—R‡ÿ~¤¯ñ>Ïý)“f®ÿ+:åžßبQªVy¬^b\ØñlŠÿøj0wšw­²§2(âÑ­ ˆÈ{(~e•ÝY½8x«Vu1¸£g5W÷áMþøÒéÛÝßZÙÌ€‡)À°£¹ nv¸faÝ¡ ¹·ß§Ý{®uRR×àN/Mý‘(ª½e…€„ÄËŸ¼œr ,-P)C  kÃßNßíÿNüEõ/¢Oïû”RS|ßs†ç¬AƒÖgU¸Ð!Fïo¾ùFldÆ‚ ô%÷)š­\ië^F¹W¯^zÉ–¨¨(qðêäó¤¦RùüJ÷«#ÄçÚËß.YJ³ú">ùÀãýŸkÚY_ò>xQ…ÇY b³)SÌA‹©eŸ4jho€²*ÞË‘wòøu«k=ƒ~1½qçÂÂFS#‰ÚçDºkË®ÖíW“£¾?ü½Íþ<=ù€ámEÜ÷§1=NOO¹…¹4xÞ`н'–ÒÒ*”ºxƒä¸dz{ÄÛ4êÝQ´æ¿kD/mÈVßqr[:Ît¾8©Ødäüñ¤I“& «XrâÄ ºîºëèá‡Ö׸dº¿þúëôÆoˆ6çˆÇ£ ÙØ±cõ-ƒŠ¿ ²}YTöÀdk2”èfS,YÄ=¬•uïeš,3íJ¸4"Þñ\ßàÛ/u}\ìº/Š”³Y–‚bÝ/š æõÍ¡FÓ÷F‡+¦Š·ë5d¼˜à?ðÔkïký.ì'Ú Ë6Åj†¹19 bïÕ1¥c{ë µÇ-Ï÷yÏ·‡Çy— jò: QmõžÕ¦Ïœ)<#5ç­TVí^åëXKlTbíÚµ´|ùrêÚµ+íÚµ‹>ÿüsjß¾=åçç‹8x]1tèPÑtì‰'ž Ë.»LÇ_|á—~£YâÏfPÙþCTöM&•8LRZ0ù9‹JîaŸ®MR4`™{r$²¼ÄTÚØù^ŸqO‹»Ñ£¶ï4Ȱµ®«š š¨íˆÑV“Y–²Ú ƒ )ª:À¸fKµ·wõr7ák>ÚóíáqÞÕ5”ÑŒÌ(ÎXÜØÖ¬t¾W®c-±ðîÝ»‹fc:tnmĤa‘¯ZµJÄ·ê’ñãÇSVV–ˆ«¡YYŸ>}ôOy_K3#$9•]i;¶7„‚^øÔóv˜§G·úåÂÝó×’rí(4®Lt¬K"™t¼£‰wM+2h.²Ÿ»SõWT¡GÜ\íÆ+½±…k•‹Ö;±`){“d¢¦žoolóÎxÔvúÕO¶W®c-±ûµ{öì¡­[·jº’Jááá" Ü]™ÛŒëÀZ Ý¿—J{ô6u§‡ýè¹›ídr[«›ß›¬ì0‰NÇ{&Ѥ8Ý|èךVdàM©¸€»S Œ}mÃî÷+D<îj½àE.øÅr,Æx ÂÌUìr¼Ù«^ ±yCÍš5K4å8p íܹS¹´È7nô|XÁ b܈u£mxüÀTrÝMB´%¸í¢ŸxØ£nô­—Yúm÷¨@¬j?ÑRðeMSé3RE kô*ïâ—<;zã>Œ±Vô· 7ºnY¯¹_½`ùÚ¢½¼ Þ@†5T!†%®–ÁG#š–¡Ušóà/ؼÐ#Û'Ÿ|B/½ô’Tä’K.¡-[¶ÐÿýßÿQ¿~ýô­·M!«3Å\¢sŸmì5bù‡v·¤§Ýè«{?fS‰ð$ø»uÏð˜õmƒ“fFUQ¡ÕêÏ¿³ŒÎÿšUífdŒï`Œµ¢¿mµù–½æ~…x†ÚQî1šý[_ð¤DŠ6殺`u¸p€hŽ&þØ3›€ïرC "¢‚´õŒŒ Z±b…¾†©-!o,mÂÃóa…•! ¸Ííb¯ZÙØ:¬:OŽp+ü«qü½/.{„Vvôl²‘Û·R£iZEJ/W¸ßKžœEå7Ý–·c–ÉlĬmcVºWݯ-ÐW†báH\Kü?½àydÅ MÁ¤5íhÄ1#ØV¶ ÷gl ÄÑ·o_}‰©šÅ:ÎÖÂÎ8›gu‡›ö·­‰õùÇŸµ®‡˜»_,{’õ=&ÓWýg{,Ž¿ó¡fyÖí)Ë QÿùG)íænbb}»Zž“ǦŠ1àßÊ3™˜‰µš•nlræq¢ÛµÑÞ±ýµBM«œÕAûø[©ÞëÈ-4“+“HWµ»J/9§´Ì¾™™?b«Lc6¬(êŒa[,9vMÈ ÞÓŸ¡ÿÓ º|hóè—çx¼M8Xßs eÜs„–ܸŒö§õ­‹ûÜÝ´/=<ìˆÇ-ïÆ÷ÞBÉóŸ2} "^×#®s佞kòÇTc-f®pgbï|è{j÷X;‡¼G€+½Å*MÈסGXö¿¿å…Ø7Îï€9¨é¤¦6ÍÁà:—+µsGÀbG… 8†ÜÈaEM²›ÑuªcÙ„ mÃÏÿcEÏxH¶lƒ,M„'Û„KàNßÕîzcøjš×ú¥Íun³ÊÑTìåÁËiîu«=ó†Û<þ«›¾ú Þg†Ž2½vÎ@®7ó]ðÒ—Ö5È+̳bÙ„l׌]¢ŒÎ@Úÿ£=­øe>wšròsDö³# Þ£¨B7D³ R´·<<«µtíü`_{M¸%8¿™{2…«„‡… ñƵºê¢«lš“9Jj“•/†ÜÓÈ.U B Š1¦°Í(tϯýøT;‹]ÅÓÉlFŽ6ëJÿüËgÂ*_Û}r„\>Še!aô^ŸE´3ýOúÏóÃ:sñÿ•SÒ¿hsíÕ¡¿äq[_›Ìr¸ù˜ï‚(¬jXmxÑês$Ä2æ w;DÛØº# Þ+@dÓ¾$j›ci/7Xÿ :h–lH’öÝ>ínùfônÓ[\ä2•Qß?ô-0f;\ë˜Ë²é’ÞE,û+,à^]ª–¿·T/U1ŽÊ˜I —¤QÜ߇RìäñNÅ "àÉd6GÀ*ÿúª zM³È]qß¶× ‹ƒ”Ù–Xйp­W"ïuû{^“…6¿Y,î OY¾ëE«[ùf¬ûï:Ñ‘ *Wk÷®¥¨ð(êÞª»ðŒ  UÌQÆîj8$ ’ØÏQÑÓ¤¿sM"ßZ`†ªÀƒ'’Û|H `‘ríëÂ.1{Q` jó‡|&,îÿ6ëçfb*±á©j°±KUT´â´uh.†fcç¿Ìäæc~„1Q­Có•ž6%M¸lÝobc¬ÖW“Ùªݯ ÇqkSh²f­ÆQET/±,îl¸Û[n÷Á6‚6øf”V”jïË3‰JÜ è²Â%+ejzÆîrýí=dxù!®‡èÞñÀ1^síú"¾µ°2´cGn3ƒ³.&lƒí_ˆŽ¥Yñ¶¿÷Ô)÷#“s^;ŸôRõhV^B]JÎSHH Šü<¢¸$JÓ^„ð2o ¡cÚúšpöì!í7ÖÓKµ#'ç´u<ðËJŠiÅ™.‰¸ä´^NçkyOH|}vŒ]¹Œï£f™cBÖr•mе›ÀgeêqŸ¶}Äu‘MŰ1m³^Ød»}õÚRE‹Ü[ìÝko‰j]›Á0 <Ê)O=@i½[PâBóÆuBNçj'µò,ãšÄþóu;QÇ÷M£’vìZ  REû¸í·¿¡v™ —,’¢îâà*ågåù;ŽîI…˜§ ŸwÛÞb.éak¢šYw¸ ¸·hÛV;û¶§ƒ_¸âFW‘[Ch’g=HãÏèk˜êz,›žœjW‰ÂXÞ熮l¦]·³ÓgSY‹V”4îV±NEl׆Û~ûf]¦ªëŒtoÝ]$±©®ÛÜsë‰Vèì…Eܽ@¬Ñ_1ÞrÐÒ6|éè¥4ä’!ÂŽ9Ê2,r¶ð¬õ:Ék°€{ $:-\¨ÝMº(hóœ§PÎÓ‹Š8ÖšbŸM/ȧǧ‹ä8¦z„Øk e‰}wåO›E¹fRÎ÷‡¨è†[)qreŸö/m[ÙÏW«ÚFe¹Î Ƕ#Û„¥n„&P\µ¾‚YG.hã ‘Æ&bÒu®x"¯m ÀîMFŒ ÊÊ¢ê¥Ð‘µY6ÙäŽ0UT‚ öÔ“Ö«…þ_ÕA$±éËF0°IüSQY«6"V.ÄÞ Þ‚¥ÿ²\WÆïÀ ß(΀ ÖœÚm§´EJ ïoH;îÔ×25¥cjG}©³£¸¶ê:è•Í•kë/°€{ÍRÛEeM5Q8žM 0„¥+ÀÊ®JİÖß}›-ñêâ$„ØvØAKlÛ,c]ŒoÔ³§XfiÁ9âçx?lålͲÄŵù’˜±ž ಕÉO˜_Ñæ k¢]{ª.t FÂ]«ª˜‰:S=`QÛ{£Â„¦eè=ÏØ ºaƒÜÇV´6I‰]ý…Íí‹õ¹΢¼ñSþÿÝiq!ÞÃï$êX.£Záž:…ÂZ· °èÇÜÿQÌ«¢6`i^ùXˆó¨Mòœã$N-2Ö,ñ’+ú‰9˜À.çöm o~ýF4Û|p³p‹«–5ÚŽK+/sr¦qæ(3U#3ÇÍšãáÜ¢óˆ6&4ûñ±EÓ2ôYlê°€ûÂ…îÀ…k}.A¹´y:Eo̤S“fÒ ¤úT6g.•mØBåoh/ÝÒ úŽETá~¾rlu8ÀžxPt¡Ú KºX—ûÅ&Ê`:~v>åÍzÕþœW”SÄ÷õÈ]¶ñÒòRÑ\ ÙψmKX–V^ûæíéÄÜT¾¨\ÌQf#…;íÁ4Ñ bŒ1×ÑOŠ9X5y¿V,&,Où`Š]Ó²`éP‡܇.t.\GÀåÞhâ_©ém(íÊtº¤´Œ*&Þ',ï7SØéÂÒÄå`ÄzáV±µ®G 7yüóOP½‡ï¦ˆ­æ9æÕ,&ÐpÖܶ“£˜9êÌÅ™u¬…[ù ùgiYߺðV»ógÖ´,Ð’ÕÁîC ƒ“¸*âRDdâæs0ê¬mm WÙNs”ƒ.+Ýpª¯ž³˜ÿ)–UPi*íÂÙæÁ€L‚‚»ÖøÛ#W®Ìj6W¯3ä91Ùj–µ±ïyXçgÏŸÕ·°àóúºpmÁ¬;D§GMvØ¡‹ŠÑ¢DoÀ!û÷QÈ>ûŒv”îènn‰ÃÅ€®v³ó R•%m¼¸&yÏ-â˜w “ ŽÌ>"â­Ž„âƒ$*tì"³ÖÍ\¹Æ.=1nu°[áŽ2ýq®!ÆÒ"çêùƒuŽs<lÃ3v\²š#´÷¿ƒ «áêP†¾6¸$'ç%'Ûï Ò·ДÂ|}=¸xªÈ -rg}_?ææˆ¯ÈÙåÚ6Çõ&Pà é9ÍrG ƤøD‘Q›{’RRÜ“9‹ñ­SRÜ5VöIí|9>.œ·®%ÅÚRh'çŸygLkªGFÑÆ’zº¢Ü:&;¶sVm‘DˣͳÍssO¸q,v÷Ý_<¸=µFî[X€f@D¤% ÁUŽ €n_tî¢ÆÍ!RFѨÃ2…¸Á‹ÒÝ¢ä+CiâœÇøÆyD¥ à< "·øÙ¢³"‘P=dù#Û¼:øûp¢A%à>9¸F“&MéÈ‘ãzÉ€f‡·IwjEJp!M ñk¡ðƒ{)|û”øÔƒ¦qßÜ×–QÑõ·ˆlêFÝl÷6ÍÿÛœEí‡t£;-ce×–K/mª‰ˆƒßXMZ·nNÛ¶ÕKð;ð›#~¶ýÍø‚,ç”óÍ >¯Î¦^zêKaï¶=Údóí¼”îÍrØÖ;-Í7ÇOçñÀí©Í‹‚÷­™Õ¨âH˜Ó¦¤‰®=U`9…^þ ³Š€;ð†x¡7:™¹N1‘1Ô¹EgÚ~d»H ”˜;0`Αmn¤¦çÈßœ]辎&eó+; qĦ¡fMBSn@‰OO¥s7ض¤w>òû v•ô8žeéq ˆ&V²Ù”·9šMak3ż£f]Ç-xžÂ²¸'c—.¦ÆÝÓ©Á_´ß¬kðÇn47ÿŒÕšÅ<ñ‘ùé2SkÜ]–zļ9ÛNkM´QŽš`+ÐRˆ1ùüÓß`†Q Ø <¦øxªèÛ-oƆÚ&ù—'¡ABŽ]6Ü$Ä sÕš†XÁ=,{tÃw¤õ(O&faÌq ¸.ÖÚñENŸZåqšYιl·vÎŒž #¨ìT\Àãz3®!-ón­º ðés§…¸A„Ua‚XÉmÖ£*xB,Ká‚("KµTñY§':™Zäf‚[Sð]4Ù’¬àwA¼eĹ¢Üë‚^Âû ³ÆëÅÔîotI‹,~TV°]£önÓÛú]3`}£Õ­Âîç„`üo%æ«ñ>óì±,bÝ9ÿËp×;T,×ü=ô^ûêaq«ãbcž8eŒX_«îò(ˆµ^–`U -Ûà7ç=:›N=3ŸòîŸN'ßZNùÃÇŠÏlö¢½(ò¦=kALìPöÔ³ly3ÕÆhu–k÷0DÊY¬‰­S§ô5׺1°cèÑD¼¼Äj‘Cd¥PÝ×(×| ~âòh60¢ 1–¿ýÃñZ{§ƒ×âô‹§Åù€µŽä4TH°ï¨ð(Z:z©õ¼AôÕ¿ƒr°[߀ÜÏ©hcß{ÊÈ2Ïùl#…ïÛMº¤ ÁNÖ&,×›<ÒN(Í«ŽÁ÷ãgN¥ð­æIp1‹æÙXåà 7ß ÝoÞ,~KѤ‡Ÿø-ÚwóoC¿oÊ¢Š¤dJšv7%Î}‚Rþv=Ž·À¤b Y6»Rçä†"Æ]öLFe8Bû›"<1i²(3Lu0Z°È¥µ ÑÖŸX_¸Ä“'& ë [0U 1L)ÜñÕ"+…Ú,NµÊ¯{ù::]tZ|^Ø—xð{ §Šß‚ß„~ÊwÍØeõ4¨Ç »Z9€‡Ǫz)r@¨blm½Áîïh¢š¥‹òÌì…šŸG ®ëAñ¯Í±/,Å `]…é'Žp‡ÀmR@–¸j•£‡8™”fFùö#± 4aCÇ4zÑøWÁߌں¾Êßïæ=2˾75äpÂSK‰ „Kµ4„ˆÉQ`uªñ`™õŽáMc—„…Tf¬›U$ŒVùÞÓ{Ų3pÜ[T.VïY-Ú´CÜÕŠþžµœñŒÉiìwð@AX”èФ:â º¥—w¥ówŽ¥¼i³mr޲*ë(çO³ˆ :.vî6RÉe]í¬r<®å­'„9r¡Kä1y,Æ­ÅúS'íþ¶ >C.ãØÂf<‹™Ú2S1,#³]áƒk>!*ÁÆ®W9œ©YEÂh•·Mj+–ã6ZÙ".ãï869AQÁPA{o™H§ƒ ¾ÃîñêÁ€”¶ªÞ¨fØ™ê’ÒŽmĘ•K:v±t"¿ùœ’¯í.2ÕáúV-y,…}óµ¥`BE\|•ÉjøÛÈ­DÙ²(@9á•YTxÍMvâ.9õê¿4ñæØ6ãy — >‡ˆ¡yš*bXVETƉâ Q5ŠŸs†Û»GëB,Cµ`|î ãq]äøûø»Ý[u!3…gÄ:XÒø;Ø¢.éq®VF$‰1‰ì¯&,à¬bÄÁ­nmg©&ˆç†ÒKÌ*vÖ®¶ï²V‹Z6#‹Ÿ_9\§˜+5ö5qŒiµÄ è!¾#¿aü{Çd´Òm_%Z t_|h·à˜Ñ ÃxXÆÒ¥ ‘†`QcæFÌbÚfë$R¸ÕñµÑëÙžßö…xïÊÝE#ß©ÃùýÍ7[­kt\ï€jaË¿ktãiNˆNs¹•Ž K'Ø…ŒÇθ x€‚¶ÞèÏm¿s–o2d$­A‘¥Ý¨k Ѽ D­Ö,eE(±¤ "Êg§=#* Æfd*fâjŒƒ‡þ°•¢îµí¨Çz~Ùr*þû«Uñ-š1ËÎJ¯[ -„üûCß‹e#òû°ª1Á†gz¡C%D¯wLíˆ7Šø.æݬ‚aì8«¸0Ža` VŽú‰Ø¶E.\Ñ•ò!¯7e4E¿=_›²±tí„X›f>$,ï°®ÇÛñ÷e–xä´)Ó¯›àbaß­¡ˆ·‰ã¨Ð^PÅšx—ÝbÞ¯»¬œ`ÿHN3sÅc š1Œ¯ Zä˜)˜°PeG0RL°ža5Ct·eo³öz>W|NXÀØNºÄU‹Øÿ.é¶¡0€}`¨Sù}i=K«üâé‹õjó0 ­m97þF!Ò†Çv× ð AµÈO½ºÔF %Òú7ýÌD6qò Ý·Ûκ7ÍÛŠæ- Šæ©Ö¾Í#_´mâ&G¼ø\¥U®Wä?¢ÐÍìŽ ßÇvø,l$§¡ƒã/€¸£ÙÃø F‹|{öv;ÁEB K[Scæ6ʲYD8йC\Q} Ë\F¯ßñºX/űr4wSÿ¶‡õ,­rãß8~43zô°¦Zê(35C{ºð¶®#²²²èÉ'Ÿ¤U«V‰¡›5kF·ß~;M›6"##õ­ªÆÕ¡ }wúG²Ü÷Fð7%êßq&ÌyçòlŽ[z_‚ǯC† ¡7ß|“ $¬c¼h&OžL}ô‘¾SgŒA”uˆ*Þ_F¯štÞ¢ &,Þó{‹©øáéú'æ@¼û0[8“ySñÖ^f¥/[Æâ.»k„fe7°·Áucb-hC̹cÆ.õ“óNŠÎ[rçåÒUí®²ºÁ1‡xcd‚Ë>ÅëÅÖŸ‘–´ü¾# 𰜱ÜÂ/›A´å? DÝÓÖQCÆãæ óºÁ«njÉÉÕëÿ—©!¶[n!;–há"‹jˆùk hytŒˆYc*ûÛ(§ï”LyDyÄ#D\&žU?ÇçE«7 á–ÀE.Ž{mp8fk&0M3УU}É'âËø„XEµªÄ“ü[èwªÀoDz ÖŽ\ß®7S{¼êB7²ÿ~êÔ©=÷Üs4r¤yÛDPTT$& Ü iiiìB×pÙ…n†ÁåܤIS:xð¸þ¡öBÀpŸÓ4<ú‘-~y!•Ý9²ÍcYˀѵ±-ÊÜH¡…TGQ}»›ºß±ßÒW´ý*â ÒÓ•óå‚›ÜìB¯™ûÛÑ3ˆØ½¿¸ÐW®\Ijâæ®SgÀu}ù“—SNA¥‹1ë  jYlƒöÞh2vióKÅ6ßíûÎêæ†Ø_}ÑÕ´üžå¢,Á€'_ÿbÛö}àé^‹[»»ðœ!7F>«u"à?þ8͘1C/™³uëVêÒ¥²ù±cǨoß¾bzýuKV¤#퟼–nÀ(à ü…9ñ˜eŒî í¡/p?•ŽŸ(¬t šˆ…ìßgK;ìÕyª}qkˆ7Üáª(‡ÍÍ ðGl+Òò¦®ö®7¯%,à5pGÏà’%KDÒãY0ª&AßæèuÂe()*IÿÔW¾ƒm&¬ž@y%y¢ ×:2×§wwRcê$a6¬nµpLÎhÙ²%EGG‹eˆwÿþý©{÷îôÖ[o‰g°p  ´*ÜÎèÕ¢mY²ÌÒÜÄR›« ü£zÅÀDäUXÀ«[àö’^S\=ªõŽ6ãҪد%Gâݹsgzï½÷(LiVW_@,àÕрׄV­šÒ¡CUì+;[ôÔæHä%,àÕ£.܈;öáIðâö§ì㺀ÏÿãsæÕ$6XÞýúõ5w4;qâ„xi¹ëÅÅøšh—÷á¬q†aW𪀯X±‚öíÛ':rIÕ^ÚM›6µN Ã0 Ã8Æ«~×]w<øfÃ0 Ã0Žñª€3 Ã0 S3XÀ†aÆag†a?„œa†aüp†a†ñC¼Þ‘‹;pµ ßÜ÷…±Åݳ¯“'sܺ/÷áø×‘Ç·‡;1ásü½#— ðë®»ž>þØ==±¥¦~^¼¯êáî}eg»g_7Þx=-_Î=±©°xñ9þ.àìBg†a?„œa†aüp†a†ñCXÀ†aÆag†a?„œa†aüp†a†ñCXÀ†aÆag†a?$x<;›BVgŠ9Ã,Úý}iNßç €Ÿ€k/²Ð©S(ì‚t 8@ÌCÞX¬È0‚rŸ?½i#Qz:Ñb»ÏÿèškˆRR,s”&ȨÍc<®½ÐþöË/Ö*BŸŸC!ååb5æ¡ãǰ…ÂÚ}á6Üç„ù¹Ïå+-è믉rs‰V®$ºë.}† |Üñ‡€ÃòÐ,ÿ;°ŸBôU*!ee²Ÿ^bÿž$áY‚pëëlÐîsÚçÅû\}c}õF’ ’c)áØ¶nµ,3L€ƒG¡}ûÚ?/à°8F¶X ¨ £Š Úè%†ñC´û§6^¼ÏaZÀÄÀËŽ­kW½À0 ¤¦©îcøÃ‰ff  ìÑ*<ôJ‡Ž´²E Ë Ùµk§VƒÒªPn`çNÞWu†}íØQ½}!QMĺ7ÂD#Fè+*ñØp¢òÁOhÃ8^uÑ[o5n¬¯¬[x(M>À[çÀìQpå1°{Î àþŽöcP s;Ž©¨ E-Åv Ñê.“'[>g§÷¹ÓçÇE\ÚÇ!aa•ÇaY÷Ûoúž£¸¸¸â“O>ó`…Ï÷Îú(`jÐÀµÇÀøœ¾ =5•háB‹0Ÿ<™èða¢Œ Ëç ãïøÃ}Óbà@‹ù1x0Ñ‘#D_~é1«›a|õQ2Þ»š=Á‘Ä·aV–ÅŽ9 7ˆøú}Ž7Á?n&ˆq×£<ÍÈð"ë×…› lø>g˜ !xœa†ap†a†ñC¢Ù™3g())‰Ž9Rãf0 ¬ iJZZ>}Z4Q© þö ¢ùЊ+hРAAÝ„ŠÏ㳞-~Ã05â›ZÃØ9?ƒ ã9ä³^^^NÇŽ£„„ 1íDÒ'µ§`óðïöíßWÀÙ³g©Y³fZ³¨š¿<ƒ’`½'Uøøß90>«!àþn–Úöxåðï®ßíðµásüýpÃ0 Ãø!,à Ã0 ㇄=®¡/3 ,,ŒúõëGáááúšà€wpýn€¯ ŸàÏç€cà Ã0 ㇰ a†aüp†a†ñCXÀ†aÆag†a?„Ü deeш#¨U«VC\pýãÿ ââb}‹ÀáÕW_¿3::š:wîLëÖ­Ó? \žyæêÚµ«è•¬Q£Ftà 7О={ôO†aÜ ¸ؽ{·èzrÁ‚´k×.š;w.½öÚkôÈ#è[ï¿ÿ>Ýwß}4mÚ4úé§ŸèÊ+¯¤k®¹†>¬o˜¬Y³†î¾ûnÚ´i­\¹’JKKÅ` ú Ã0µ‡›‘ù4þ|:pà€¾ÆÿéÞ½;uêÔIü.I»ví„E +5X8qâ„°Ä!ì}úôÑ×2 ÃÔ¶À}ôÅ›œœ¬—ü„~øáayª ¼aýàÚ‚@º¾ Ãxp`ÿþýôÒK/ÑØ±cõ5þONN•••QãÆõ5Pþí·ßôRà×<@½{÷¦öíÛëk†aj ¸A¯´JÑÙôý÷ßë[[ÀŒC† ¡[n¹…FŽ©¯ ð›U hÆuÌ=÷ÜC?ÿü3-]ºT_Ã0 ã8îF`ubrFË–-EF6€x÷ïß_ÄŠßzë­Åì‹À…K|ðÝxãúZ¢‰'Ò¶mÛD<8й÷Þ{é“O>¡µk׊L|†awÂî%Ž=*ÄM«Þ{ï=Ñ¡~ Š ~š’I.¾øbúóŸÿÐIlx¤ Þü1­^½šÚ¶m«Â0 ã>XÀ½,ï¾}ûR‹-èwÞ±ï&MšèKþš‘ >\4‘ëÙ³'-\¸-Z$šÎ¥§§ë[ãǧ%K–ЧŸ~J^x¡¾–¨^½z¢Ý?Ã0Œ;`÷p—ÿíoÓK¶Úå€õ={öl:~ü¸HâB›÷@oJå(Æÿæ›oÒ]wÝ¥—†aj 8Ã0 Ãø!œ…Î0 Ã0~ 8Ã0 Ãø!,à Ã0 ㇰ€3 Ã0ŒÂÎ0 Ã0~ 8Ã0 Ãø!,à Ã0 ㇰ€3 Ã0ŒÂÎ0 Ã0~ 8ã107Áhl­[·}¤3 Ã05ƒœñ¤k¯½–®¼òJúé§Ÿè‘G¡ &Ї~¨oÁ0 ÃTî q 'Nœ K/½Tˆ2ÄlÞ¼YöþóúöÛoé³Ï>£_ýU|ÆŽKÛ·o§7êk†aWa œq 6¤7Þxƒüqúþûï)??Ÿn¿ýv1´æ Aƒ„Hc®2xð`±mII‰¾†a†qpÆmÀE>jÔ(ºí¶Û„uX÷¬Y³Äg¿ýö5nÜX,KP.--¥œœ} Ã0 ã*,àŒ[™3gŽåeË–Ñ?ÿùO!âã8Ù2zãhül†aÆ1,àŒ[9pà;vŒÊËËéСCúZ¢&Mš+\åÿû…‡‡SJJо†a†qpÆm ÷ùСCiæÌ™4bÄúý÷ßÅg={ö¤•+WŠeÉŠ+¨K—.¡¯a†a\…³Ð·1eÊú÷¿ÿ-2Ëããã©ÿþ” ²ÐÑŒ¬}ûö4fÌ'GRâäK—.¥›nºIßÃ0 ã*,àŒ[X½z5 8233©wïÞbÝáÇ©C‡ôÌ3ÏиqãDG.÷ß?íÚµ‹š5kFS§N"Î0 ÃTp†a†ñC8Î0 Ã0~Ñÿmímí$ÞIEND®B`‚pyclustering-0.10.1.2/docs/img/clique_clustering_with_noise.png000077500000000000000000000550061375753423500246730ustar00rootroot00000000000000‰PNG  IHDRæÜ¥°sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 2.2.2, http://matplotlib.org/†ŸÔ YFIDATx^í |EöÇßdr@H8Â@e]O@@E! º*¨»º¬¬®úG¼PQ‚ ÅkE@•îêéét÷tõ¯Þ«WU.M@qŽ×ë¥]»vQff&¹\.c+Ã0á€WÀ¡C‡¨M›6”””dl­:\¦ú˜ËaBóÎ;©]»vFŽa˜ê°cÇjÛ¶­‘«:\¦æ &„0çuG˜Õ‹ Ý9¦OG§K};–C‡:΢`˜jáÐçÜú¢9Ì‘ëH+6® I—O¢q—“Ÿ1L<©ç¼nDeÃR¸ù抗” ÷õèIß5kfä*gÆï¨sçÎF®f|÷«*Ô…c­__õcõݾnûö›Ðµm¸µ{÷62:ÑˆÊÆË /&¼”€zi)R“S©df‰‘«]8:™¯»¶¨Ésn.?‰/̰àÆ !ÊšÛMžM[‰ª0¸BÛ¶­h÷îÝF®f´jÅǪ uåX;wVáXâ9w—M®Ï9‰çœ¶>çÑf ^Zx9•–—[õ—òѲ˜Y øºk“ê>çæò“ø®ìŸ~ªT”½Ï̪’(3ŒÓpmú©rQžÛç/#ëË ÑŽïDZçüÍŽÇé–òàØ>çx™_Vh{S/*€u×#×&^‰ÄsžøÂ aölÝbH y¤ä-ÛI›šÇ–2“ˆçØ;s¶|¾ù9ñ¤“bþœ+÷^ïzËÒò—ËÏÔ‹ –Æ„Ü]Љ_"õœ'¾0X Âb@€,dïd&ñ€çÏ·çƒ|Ç=çx!áÅ”?*_¾˜X™D#RÏyÝf ^P2êš™IdÄó­ßÛqÏ9^Hx1™aAfH=çuG˜†a&`af†aÁÂÌ0 Ã0‚…™a†a 3Ã0 Ã8f†a†q,Ì Ã0 ã X˜†aÆA°03 Ã0Œƒ¨ó1tèÐ‘Š‹¹šQPP@ͪ0s(œ|¬¦M#s¬½{#{¬ºpï#u¬úõÓé矷¹@¢5í£Sàéùºˆ¹üÔ)a0`-Z´ÈÈÕŒº0'pË–­Å ýW#W3:thM[¶DæX;¶¢ß~Kì{ÉcUöܳ0× øºãG˜Ù•Í0 Ã0‚…™a†a 3Ã0 Ã8f†a†q,Ì Ã0 ã !Ì<òuëÖ233©E‹tÅWÐÆO†a¦îàa^¹r%Ýzë­´fÍZ¶l•——S¿~ý¨¨¨È؃a†aêŽæÿþ÷¿tà 7ÐÉ'ŸL§v½ð ´}ûvúâ‹/Œ=†a¦nàÈ6ft°YYYri¥¤¤DvÆ6'¦vqý²“’VæË¥]Þ»}Âù+‡ÐÁé)^Î3Ò‰¯ÛÙIḑ¿p:—_~9íß¿Ÿ>þøcc«?&L ‰'¹ xä¯ÈKüå~i.¥Þ: iä"Ï•W‘{á›äòzIKJ¢Ò§g“÷‹ȵé'ÒŽïDÚ1mõïÜv³oŸ»dД)QêíÆ6—‹JGÝGÞÞú¾cF øšUâÿ‰g¢ÇÙòslÃÿèù¿Ò×{ôkH]økkä¯`åpÞ¼y”žžnä˜H‘vàñä“Ôä§Ÿh§N´áúëéä—^ò忺ã*iÜØØ[Çúì¬Û¬ßc¢Ï‘#GhРA²:N˜ÑÖüî»ïÒ'Ÿ|BmÛú¿¬¨©#)ðbi×® ³ ’Ç‚0oýd-Õ;¡½eÖ\úª"K"ù„:w ¥Ž»Wæ‘’°Íq4¾3•Êï%·'KQ×+Ç/ôJ~íeyLËýÜsDƒËÏkB]økK˜ƒ•CŒóíô!9ËÒ·o߸šÒݯ¹V¬ÐË 6$'‹QUöxHs»IëÕK(q¹Ö®%­[7òˆ2â¾é&r}ðoŸßO;š5mJI~¨—W÷ AÒºw—ß[‰~ûÜ×]G®O?•YíœsÈóØcä¾ï>¿ÿáÛß¡ÄËïòƒññQa¡:†Ûn»Mb¬mÙ²ÅØâBð|Ée(ú÷ïo¬Õœ–-[k5Ç©ÇjÑ¢•Vü¯×!UJÞ¤$Ûí¡’píèäiZÑÆ¶ßÇç~ÛÜnMÛ±Ã8ÓêS~ÇÊžûpËOeDê8µMii©¶`Á¹Œ+RRüË€5ás” ¬cyñÅš–•å·ÏÑÌLÍkÙæ—š5Ó´Ý»õÿ‡ï»dõØÿsëÿp8ñò{›Ë#Ú˜Å9‘ezë­·hùòåÔ¡Cã&&ìÜI”ŸO§•–RÒ÷ßÃGwUû?Z°rñÔV@êxae¯Yågi+̺DX´i“‘a˜:ް†%(j)¬Z:ë,ßgBHé@§N¤zªÌÛRP@tà úúçŸã嬯+ð¹ù`&â8B˜á¾~å•WdÛú2Ã…‡T\\lìÁÔ†Ë%˜;—(;›('‡–ØG©SrC ª¬âÁ•mîì²Ñ÷ÉÌÃ…-–âj‚ìûâûaÑ ±Â0 Æo¿ýéODMš5oŽHØàÏ;Ê_ß¾Dçž[!ÐXvëFôâ‹úgM›JWwRY¹>ùDß'tQ·”íÂ-«L•pD3^Æv ÛºQUF¸md;v” ì‘ ÒsïFn®â½âXM\°~{ˆB¹&%…¾IM•Û‰ŠÏôC…„¢Œ:pnƒ WtXæÃ~9eߢˆªm8Þ;©itYiIØÇÃqÎlÚœúˆï<*Ϋ²"ÿ€8ßÅiõèWõ2ªûö%þ|ÌÄÚ²…çcV ÍÑQÓB„ñžƒõ 1„˜"¿lY…u <'ð2všžÿæ]0Ëˉzô ÊË#=š´?ÄÅWZA¦>}ˆ–/×Ïëškˆ”C*pL3¨8ìÛgdœ‰ã~ï ˜ËÜÈq|òâº*mÛrj3Úr‹Š´ˆ¤æÍ[Ë&"s*úëõ¾6Z,‘ÿýËÀ¶\¯µ=© ÇUÿü͜¯,áÿ½ðºVøý™Š^œ¯yl¦íyù®G\CÁÔç´mÛ´€´kÑçÚÞ•K»Ï‘š7o¥=ªE$q3·1‡dýz½Ï3–È´ÓVÒ62©rŒïöé£[}†mævápŽaÎ˺/Î Ÿ©¶i‡ÁmÌŒãHþj-ÕŸÿ’¯–Œ%ò©K´åBþðdT×Z¯´fnÿ?ýÆ”Ñ9›’?\BåW^Meƒ‡ÑщSÎËw=â²î»™R¾1ÜoM‡ÿ•Z 8‹²&”KäݿUùrÉ0Qçüóõ6ZH–ÈXÊævÛ%Kt‹×ê&æVVåß…u‹c+°mïÞð,oޝ\é°š°ä­cKÀZF‚uoçÝüî;ÝkÁy¦RX˜)Àƺùäo¿´mËÅgJ}KWRµÛî;áb[ïΡ¾AH¼gt )òØ¿Õå=¨Á¿çÊ|Ãic)ý½7*Ä[$äÛôhG-¯É¡6ggûöe˜¨auùª¼)@KáÞ¿_A¸ŠáªÆzïÞz»q0 ÜeƒTøhÔÈXÑËŸ†nVpWciEÃNlCu‹R ³˜cyæ™þ•äsrì…ŸñÁœàx[¶6ÖüIŸ7—Нº.¨8NœAý7¥ƒ òéÀ’5µwA8"kû—½= äÈ«mÒÊûÂrn-þk…)øaj ;‹â„6`h™?‡ÐAÌ {öèV/Ú}!hÖã@¸ÑvŠýÃíÿ¯½F„~Ïæcáf±Æ9¨@0…µaÿß,æXZ+ È#Ø4”•Ͱ0'°0Ï)-¡¤]"SÚ¯¿ÂÀ‚Kl­ÿæ+tàÅ…QÕ¢à•ô¿Š¾II¥²szSRÑa)fVJ/êo¬Ùcý¯È§Îù§ž1׉Ý9x;¯¯Ó–Ž>1»"Ê[þ bž¶ö›« ûf<ÿ}¹o¥^œC©Ȧ¤ØŠfj‘³Ï6VL@œF&zÿ}¢‹. Œª¶bíÂ1…{83ÓØ`‚‰ dÙ€(*A4 QÝ\úLQÞnm`óʺRaßÏ>Ó­fTPØŠöÁÂçÈ¡+Wæ“ûñ<ª÷Çlzûà>jÖ5›ê ‹xÛ´¥ÂÇæHw´ˆSÊš•~…kŹV®+‘÷t ´Xµ$79®RKÖ ÞN°KoY!¼byôñY~Ãt–ýc0^¿•ŽŽTxe…¢Û¹a®³áì龈qœWòmCÙrfjF(‘yóM¢‹/›é VB†ýªh/†û–´³ÅŠ%„.æÊ,Yò¿ã"zÛÌ·ßú /–È›ÁÿB%ÂÜŽmç Äçdµî­`TPAa+º# ,® 74‘¢²üo‡V2b”/bYE)«äu»e䵊Ì.xÿó€èfo’;hijï¸IIZáŒçdÂ1å6±D~ÏÍ»HêÁ’Ýÿ”Ç3"±¿“/—ø)­éÈSâÙŒ &!Ž«¢³±DÞn¿ÊRÉ’|ÛˆëpGe×Ѩl0IÎÈXØfÝ ys:眊ãb© 3Ö›6­ØÌÛƒDt«ò)Ë+öEªì\íPÿË:òØn=§P#–5nx¾¸†ÂQÙLTÀ°ŽSŸ˜îOÚZ/…5œ¼nµ‘ÓÛš‹† «Ô°&EA¤¢¡wù¾oÇòWÔà3FÞLå'ŸJû¿Ü*Ûœ±,¹V§Käç>Ô’Uà}b}RXðFí^n3¬c$O¯Þ~–²žz#ô 0Ìà, J»Vm¥¢¿éç„%òoås‘[¯y;÷¹–Þ€\oÌ—‰­g&$Ê:n×s×ê,IXÁ@YÃVì¬R;·ïªU–¤ÙbÅRdUfÉ‚”*ÉÌ$í õÿY™u eáªöc”#“íØaNØOþµ1Ú´­^€Pnuæ8¥fmªŒÆÃþ&]ÚHpogÌœ.·>Š Ön¥â!#ÄÉü¯Æu§”åKd›3Üãf/puP2¶Îl$]ÑpI+·tÑ;ù¾m•‘´ù'ÛkÆÙgü{Õ[¹Dß`âhŸKh÷ÂÏh߸ÀJò…CF’.¢ì¹æZJ=¯;¥^7POÚs»3«@ÙQXXáÒVB~ÒIúg6TÄÉ *Çf‘·F=ÃέJgNý÷å—ɳx±þ?ÍbnÔÊ0wï8Ot±Âý°;7óÿ±Ž^†ãX+pá#r!!a½²kN0X˜ã L{Ž(ì×pÔPj8rˆï;X6˜=C®CP¸ÏÖš´ :CËXfFëÑÀ-ä±}q½ú~–p(ëØ™mÓNpMæ¾Ìè ….QèÕꊔ²yc@¥Až×ÿ .YÍ©tI>•Î_@îW^òó `=ùVnwf‚`(; ÚÊÚUBn×– q²S!oX<›ÖïÙ¡„ßGÄ6º\‰¼œ *ØU"ÌשP®ªP`$2uMXvïXA@0"·qL¤+*¿æƒ…9Îs‡ܤpy=îj¸¹Ý?o’–tÆ“S¤õèÒ$7ÿõzÛÿ¡¾ åÖ–]¬–~àö® ð’I( ÎèËÜ0ïʺ·Â£€eæ¼YBÙ)îå}Ï"Oë¶r8O×–Í”zÕå¶®xyÿ6ódŒ v–©o¸´ÍB®¶„åT )\¿+Wêköj™¿ %tèb…®V¨TÅ"® ?ÎÓ ÎÍlÕãšTEÛáòÇ4¡çgï>WBŽ}Íà¾TvÍ  sœ*Ë .PV ´ÁÚRŽ2 ¶ 1Þ÷îj:ôä‹b¹FŽwmßótл0–3ÜÝž3ºÙº½kBé£èè¤iç¥@_æFO?$—Vp}òE:8ü^*oßQöc>­¬”’o÷Áæ;@Þ¿ãB_3SG¨@Dí@™S¢%ÚMƒµ¥*à"H°"!¤;ëËpºQE<ºh¡ò€6cóûEYõ8w¬ªˆ`;¬_X°€1Ã² îƒÅǯcíÎ,Ìq† K¨©(øa~¤±^|ÕµTø¨°UaÞ,rÙôMFÞu¤H®— a™ÑÈï{‡§ÏЍÐV‡²£é̬–F`—Uo,ƒÏ!Þr°žíå ZÁE9‰Êÿ)¬í¶±½fÆ¡@T,eÈ9“Jÿ·¼7:ãšan;µ”!f+í¦J̬ÁVÁ,iE°ï9unf«>\p=¸7° !Ôf!‡Ð#Ò»´TñÌI×X˜ŽìuB{JûÇ@J™+,]“ë9ÐFŠnSî-?IÑU/–…ÓMÁZb KÚj#i—t¤(;­í›Rùˆ`ÕÁuø¿¥¼s'ÝY—«HáV­ü»G…C¨6R'ZÄUÅ| hVa±ÃβÆ6 €‚û^FƒÝ]‰/â>æ}”•%h ÇCFV±ê~\$Ôáឆ%¬Àÿèà)§ŸÝÉóïÛg?·suØ»sNGêXûýî—º´?r(äý½§Rƒ{ufVsyO¡GëóV£Z4©A=“žÝüÐçvŽÌ5ò|̵GµæçUAIÕ}]"Bó%Cl`!CÈ¢lFm^bøe½_æÿ‰!D1T(< °ŽƒÝW´cÃ"ê¸pýWáò|Ì1#¥ˆëªtÄ¡HüåõjIÍ›·Ñ¶lÑÒ®W—ãqh¨?Å?íЊ‹µJ“SG²jÙ²•†A|lÓ§ŸŒ†|ÙS3µ²yóµ²{Çú>·õÌœöO©Þ5Nìg9žH…wÞ/62§-xä¯H§¶©ÖHPAFÓªVªÊ([$ê#`áƒ,¦FÃ(_˜ÿ999ð>!™G3 £¬á8•õë®&æòîlãVY8€˜±„N€.OjÖ¦„¤[7òÌôwÑËüÐaD‡„Õ;õaÙ€à½æš ÷ Ÿ73œ2gä‡áÉxüaJF°…©ÀB ·,ªîNÁö‡•XºÿsÑ›-_´§c¦+ŒFfñØIwøÿX1Ÿ³58 Í K@w7 ³CÉx}.µùK ‘°Ãn;^ÁöøR³6%*Úƒ©ü§­T¾,_.‘GÛ°{Øy?î“{Þ˘<&è€+L‚€—>ÜØkÖØw³bäða}‰hb«Ø(êB÷5­‰ ±¯KÄr`D¯ã~ÂÝŒõ~ýˆ~øAÿ¾²“­à3ˆ|‚ÁÂì@п¶ÙXÿ>Æv]t¥ÿOÕjóËmå“§Öî?âµóŋѸV×êU>Q6ƒ»§î –¨¸¹éŽ ÷Ü ~ŸP®0 €ê[{à€Þ&jµ‚1Öó÷ßWôéè¯ ÁA{2Ó°¶k"v@Yu ßi¦¼œèÓOu¡FÅ{¯gO]Ìѯ»2ÐûÀÂì@R¶V>ì&$¦ÁÒB@‚‹ >QÖŸì“ûð4òÜ5Jæ{pß½ÍZ­Ø˜‘nòJ\aâkckåyX€ØÏ „"„yŽÑõ.]8ç¨cݪ„ÙÕo0j®Á#‘€Þf’ºþ [a0#Å×εcB>¾â!.}e>•lÜ&Dy´Ü^Ñzžv{}Æ”±TÚUìoäæo£ÿ´]÷2&€m› ¬ÃB6kýp!ÂX·ëù£ˆÒÒ]ºuTTB•E|¦&ÿxãÀá?Õ{žx$ÐûÀÂì0àÆÎš6Æ_ŒT¤åà‰ºà¾…¸~ϳsU, ~êWŸÑ‘A!?na¸±Í®ÔƉìº)¡ÀÒNpêJ°W¸ Ø ’X+9h«‡Øâ>¢Bƒ&„©Sõñ¾íî+Þm¨ð$`E‡…Ùaع±ñHÚ<–~À´¶7¸[=Ø+\dPئmä¹{”O á¤¹œôC:[o²Ú 'žXaÉaií .¸@Èæ ¯êc˜Ãèh+T†ÐîŒI,0Ê079˜Û ¦›2Öã–XÍÇÜ´©Mø~ -*¢IEÆ@÷&ðC˜ëâÈÃŽÆ+c A.ìjRø¬KVKiýíÛ·GœWdÚ]öîÝ+î§% ²´ñz¨Õ¡ý´;³ íVJM),Ä\Å¢æìæÂþÇ‘"š^$^ȧ¤Ñee%~¿‘~ï[øî=ÏÇgó1·j%E¹T<–©¢’MHNB!P nVT¨áªFä0‚”T{(€`ÃÚƒ°8”x™—ØÔTÿßç®h°”!àiˆx{ó1×)a0`-Z´ÈÈÕŒ–Âzúùçêu—q½ÿÕ»ª€›óŠ£Ãï"­m;*ë~.%ÿ-Õ¿³¢-ÚÌáÅùT~no:á„V¢ò¸ÛØZ3²²þ@ÆýÏÈ…OÃÂÔþ—UTÿÈ^ÊþåS:}fqÒÈëJ¢O¥ƒÛËký%ûl:Ô¨êî÷iÓZ ŒÌ5¶lÙ†¾ÿ~—‘ÓIy{>52ÐÈUì7:rë(*ž˜' «Ö´}{dºP{l+Ú½;2×XÙs_—…yÊßO’–2Dâ zÜ6ëVš®Ts™ƒu†¦(XpæýP!Vbá0pÊ×_ï¥U«Êé쳓饗’âø· 3@…ÕzŸ•`Û\T< 3»²£Œû¥¹Tﯗ˼*ÒX–ö½Ô—W ŸöìãTìݔٯ‡ÜvhéÙ¦l&Ö“)@ˆ;n˧cv­¥‹—¦{þÙŽ-HW.½…ÎÜðªe¤y©Ïû£éÊ×Ò"Ý2¥õ~o4µÚ±–ÚoΧ̃Îh³õt·WÛN”Aý™3*Ú›w•ùú¨FŒcI;p€1Dîë’…Y>·vnÏzÆ^âeéç6°Î0¬$,e€¥ƒ¿ Ä99º^áQnÕ õ:”JË–¹d/$hös¬'ãj[±«ü`œòêªÆÂE\¿ì¤ÔÛ£¯oËhHGg<+·YQýkñXËZ«ÖTü„)XI,‹gÌ"í˜Ø~uùf®âötÓ¼ºå¥³è¼Ï¦‡|¨Ìâ†õO§ëŸ9‹=—Cç´—BkÆÄ%ÿPQ ºª%mÙDƒŠPÚ Ù”zqŽ\º_äög§rÆ“O’gËfš´ŽhÜšéª7ÿ'štù$ò4·iB@—k×s°RŒG÷‚°¢Î€ r54>–ýçÕÐKŸ×ë’—C ûa|ßwT“­ø¤…\xOªÈmu3â¸ý™…9Џ6ÙƒýÔáBJ›>ÙO´@@âumt-N´1=f?èˆZϸçJûÏ+¾ Њ”ø­ÐÍ8‡ý'œàû}øö[õÙgX€UæŠÕ«•Z–3b°bbpªv|tYC‚•Œˆ¶sŒáp± ~wœ$j¨©`i!IT ]ëÖ9çÃÂEàv.}:ø(SØ^Þ­§tQ{»t££§gìíHl¸°¯Yب6Ø]üÖMQ+¹v0|µ´Ž­‚ë È“+Çà9±ÅWwÜAÚ…ú¹ Pq¶FWC¬³”ãDb+6š¾£Å§ŸÆÈrVíø°œqÁðT ™iãF½/9ÚŸÃp Äj§œ¢gâæ(ã½ð"*ya•¼<ŸJï¹ßgACh­ÑÕ%wŒ¦²~ݨ|K›}kt…ºò½!a‹Q$Áêòéz&ЏŠûDXQ­ëW*Œc(iܘ<‹ëÖ•yîd Ta®†8¬\Y1F3„]¨b‰­\ØÑæƒbØLkàbïÞŠ|ÂÂEdæ?fS½ ¤ÔëÿFtlG:úã6º¢QÛèê´'ó(eé»>1ÀB~hÉê¨FbÃRþRwñ°ø‹T49ëãG£n5Ûµ5Wç Œ]ÙB¨ ‚’ѹ\À캶FWCúôÑ?GE [ÏžöûÖ"8 œ.ÈcŒÕ˜µ7›Ûš±D%JåÃïN¦‘ŒÂæ~øAgY›<óÌ3Ô¡CªW¯uéÒ…>þøcã“Ä  ³X"V¥¦X¿Ø¿Þ„1š|É[ºsÔ"2ØKXʱe€ÿm«9 ­Y,Ë»]á¹°,ƒï±+Û9 Á@.£;M¥jƒÏUPˆQÛ²êeqâDÜ®˜Xͪ­Yä½ñ†Þ ¡<ë•'»qÌ^QÁÖºv5rÎ',a.--¥mÛ¶¹Èóúë¯ÓwÞIcÇŽ¥¯¾úŠzõê%j†¢íÛ·{Ä?¶}˜E>ù{±qoûÛ”@XpÑl[ÆÐš±eE÷XÍhk>ðÕV:¸ _¶9'±&ÀƒQøêâ –µó§géÝkGࢊ` DVõKܨVbжüÉ'ÆJµ©y9ÆíRóHDÕÖ¬¼S§êíËʃѣÑòåDˆP–4Êd³f¤ 1ßsúéäyî9}{ ß&wß}wÈ4}zíöðØcÑàÁƒé&Q“=ñÄéñǧvíÚÑÌ™3=â‘mÓÖ˜üä jmÓVâéhïF-~pjtû.;C“%ˆ€n³-J¡¨&`9# O¶9ÛT®P‰:2~ŠœÐH1~x•.ɧ’·’çžùËIhBTýëÊ|´p£šË"Úšcж\sK9ðýSáÌ´¶9+†Ù²F¼ÀwßQù¯¿Òšñã£ÚìPSäÓöÄOÐÊ•+¥µj—~üñG¹smkü‹/¾÷PÜDȯZµÊÈÅ?SOŽÿ5 çØµ¬”’?Î÷ë—Œý‹7¹QÅ‹QÚ¥wŒ’ùh±¿q'i3Õ;²×X‹>ÁÚœ3ÆÝMé“î¥É 2*Äø®Ñä=¯7[ÊÄóÈ#4áL¢ÜÓ P<ñbÏ}'—&,š`l4—=ÞOxÙ#H SÆà%Ÿ‘a¬Ä;"úXÛœaôà÷A ¿W°x8A¾e:uêDwÝuåççÛ¦9sæÈkLoç¿tKË D>Øì:%%%r&sr:]wþ2#W^ìs¤Œ9ÔðÔlJ}¹¢Ï.†Þ,š3Š^˜O…ßn“QÚѦÉÁŸ#TÏŽ GÓEá‹vý›Õ½åü€°¨e[rã`å³ù89%Cn/Ñø®º8ãwœt^&_8ž’¦N#¯ß²;+¾“•Ee‹Q™°¼äyÓñ¢• q¦‘¢úÇr»5Ûó‹jšä½ðBé¦Öš4! ñ"iË–‘÷úëöÖmNL ¦}üûßÿN-Z´ 3f›ýùæ›oèŒ3Î ¯Å víÚEÇsŒ´Ž{"ÒÑࡇ¢—_~ÙÖZŸ0aMœ8ÑÈUPÙts‘y¯¨ …1¸ºÁ9¥%ôÖc¾ÀÚ%«9õûcìeH*¨#3Ò¼úéØ%$ûöaßȈמ=%4Õ¥Ñ(O;L†¯’óëCŸ–Póæõ5ó17iþïÐô0 ¤˜&9dl©àÊÆMègw²ô‚@´×¦¤Ê¹š«ÊÞ½‘ûkk>æ`åpÞ¼yò:•?]w¥:$E⬦|œø…‹Æ¥É@!´IÂý‰Y¨0áE“Ÿ~¢ý€AÿgtµŠW\1@üu5Y–{)½òÊ|ìQ¿§¢$3“þ+´#Þ€6 4H–C)̰LQûÍÎÎ6v‰pe£¿ñÆtå•W[‰FŒA_ýµt±[Á¹")ðbA›te/–HÎÇܪU+Ú¹³ ó劸û¸ì€6J;`!§þ›ß¾°Ò}»µÒöå?ü!²ó1¯h~ ú¿·Œ-±çÑËòiò'£ýû#s-Z´•ª”¹ÝIoÿ‹šÍë÷šDÊóP¥

üP€¥Ý¨‹2Ĺäc,1´Mºû÷'×ÈÑÛP1(‰ìÿRSq{ÿU£Fš¨´«ˆŠØãî×\+VÈ;ƒR§õîM!Ìn!Ø.ŒŒ"(øã©ÁÂ…”â`oÊO³fÍd9”®lˆ Dùô ¬Y³ŒµÈ’šš*»G-C¾ äÏ2^ZZš,øæäxÄáYá †ü\¼Ô‚ŒÄ‹!eÁQ{Wë.ÆZìA¡+In g¢D¸þš|¹™oÌ¥cÏkGÍ-¢ 7‹2Àzê­C¢þ»Eƒ`å“Ñ;9yŸ^Zēή¯‹²;U.sÏ4~QQ]ݺÉ}“Ö®•eÈ¡U×­ 8^´’D¸Ý.Ûó‹jÚ·Rúô¡ñ &¢ \¢"œ$RÊ!”$Œ:WY™LÍÖ¯§zÇÛËAIáÉr©¨IŽ9RZ±Š={öPQk¼ï¾ûŒ-‘‘ßÏ=÷=/ úL£½]¥† fì‘hÿ7˜<›¶’çîQ¾ "9\£\ÓE#zɉúm‚Œê½›2Oɦ”EoìèoN ^âÚ…¯é¡­z& HîMÇ\—#—æL§cƒ~†_Ì,Ê l Ö-މ-[Ò];<©Xο\òl Mºà¦F¹B¬ýFô dƒ™¥bÐCËaØE5²Šù¾#È Ö°µ¼!/„Zv3}†2ëBwª˜t®:~oÿ>úˆ/^,€n´aÃz÷Ýw©sçÎtøðaÙÎ\[ 8Pv‘š4i.j²8÷Þ{/&®õZGXÎÚÔ<òlÞFžòɳe;Ù´¹>qÅ·[©ìƒ#²EòÕ…%Í™¥ ¶¥Õ]nwŒ8G XÈ-ð¦Yž¿5\Ð-.­æxÅ«yéÁˤq—“ùq›*EÚ3æÿh^s÷ haÅbf)xÐQ/ˆ5Q?ÜgÜoó}·ë[®@5RùˆéÐeUÃO˜»wï.»Gzê©Ò½Œ6_XÐËEMmGµÉ-·ÜB[·n•mVè>uÞyçŸ$(èóõî4òôòŸ[ ¡.~è± -Ú³}•A­Ähâg±¥eE€`m’ºÍf@Qà«[AA·8×f–Ó)\sÂ54ö’±FN"=a€¥»Z lçA=poGyô/œJdZíjVÍÆLSQÅÚgc’Z<Šá +ÕQþͪKÀÕmܸQœûZ¡m)99YFEG*’™ XW˜°¿¼Ç¹¶nm÷—Ñ{Àöfuò¹ÛcɲSGÒŒèo”fÛOÑYÝ Š :އåŒkÌnmÓ1Ê®QSÇ•Pýj6šA_{ÍÈD ë}‡ÀbÔ¯p¿‘ª†H¤SÚ*ÁïÍ3eÊÙe©oß¾ôÝwßIVôêhMþÉÈ6d´%£osFßTÖÿ/~u\«z“;{íéú¸Þ±ƒåGè™(àiÝ–~Ÿ<›4WÕkæVðB(}*º³1ÀÚ¶™—§»³p­FÙ5 Ïz,ÝÙ\Páåª9Á|ᰜùqQ›@*9ͧŠp8~oŒ¶`Ázê©§äd'Ÿ|2}þùçôç?ÿ™z÷îmìÅD„;ɵ"_.Í@lëßéß¶™²øÍ€:n´ÝÙ+ÎWCXõÁÿ}«{^Ô¬e?´êû ´$7ý×|:úÃÖ*w—bj—×6¾F½÷‘Ó ùËÚ¶9zt…+`=îìX½ŠÑ5=¦º† *”c Ñ­ xªrrd¿fÙÍ-굊êá'ÌëׯCQ34îÍî¾9r9¨¸¢©î뀶M‘·Ž³ +,š3ÁjþoN^ÔÅÿï½Óï§e§Ew(ÒÔoÖR‹±¢‚dä« Üàe¹SÈû—«ÙRv I®$šøÎD)ÆKŒüå•)vã1[£´cà…+92mÍáQÆ51Ñ5UAB@—aû¹¶ƒý„¥O“W(ü„›ƒqþùçkLrÒp‹8ïP¡Ï-m;³xN˜êÛ‘.~—\&ŸôEÿí3-jíÍø?o KyÑYþ–MmÓ䱨ÝUg‘ËÆZ·b"=ãÆÈ9¸ç1ðeT6Ä8mxš\"*[EiKìDØ¥e LHˆãÿþ§Ïrí©mðb"ʪ)Á^ª‚P+ wô5Q¹Â4ŸÁ-žðW¦Ö±›þãù¸?×ÛðºJA”Ç?B®=¿‹Œ! bYïééQïÓ >é9šònÛAó®œO›Û_+4Žùcëóé¾A;¢n)·¼ýjÊšù­¥ŒöæªXÐøSo^×6¦j *–siy)¥&§úDÙçÒ%ŠuëˆN<±¢omH¢[.†œX¿£ôDØi86þOÔE… 'ujUA2 u0Ð=jß>9r†U'X˜£ŒœþÑ&ÚCp*‘U]¥Ð·ùèƒS¨ÞÄ{¥«>´JðâfŸfÜÚN¼šž¿nͼásúþøþ³¢Ñ%êé‹ÓŒþ+¢Þ¦ ÷uÆÿT”bûÛ…±ÜMÊ™ ý™Ä‚ìçÒ†©®Re¸T•XÀÃvD«¾µ1¢sgŒ­N„90ùUM­hh޳g~ì˜3ÝÚÍyª‚Ô½{…7ÃS4Ê`ãŸ~’ëñ s´QCsZ^ðf‘Er¶Š’6þ@õ&Œ °°ÍD;ÌÊ/mºÑ«]$­èºª–@«ú°Çå¦WΛCße_fl‰.õ¿øØ^”å/5þ÷,YØU¤¶:oßù‹d ÀݤœÇëÿ{]¶1Ã} ȶ.m`nç´ëÍýcU=bÇ]X« âyèýAMÃŠŠˆ?é$ ÔN„±.° ¦}£Fúy\<"ä áF<Щ“\X˜c†æô¾Ø"›–7™2OnG þo ¥º%¤(|4ƒÀ‚+zÉyô¬° ÃgÚ×íûK “SÜÍVúô±‹^.=ö>‘5©Ur+½B¤!À¾m"áw¸¸q–œ°ÂÜ Áݤœ‰yä/$¸²,e)ÊpMçä`0=ap0Ô?V 4ŒN¬UIˆ1¬m¸Åá0|3m'o¢ä?úƒµë–3¶<¨/‘Ç BÎh†@7)Ì O°0Ç­§ÍxØâeŸúâ,[«Í/æ ?,è—<']Ò »×ÖØ5óâEÒBþ_›Þ±ée&½AX÷ûX‡æDªØ†nQèuôý|î&å`Ì#Á}­Ú™=^åþ{ŒîÃÍÏ×-d$´WZ¼!>`©ÅÜÄ Ú¤ÄО^"—j>Ç̺1b+õê+&Ìe•$Œ‡m 3{.LÍè&«©:«‹x¿XÞ0qH¸ÓÖEv>fÌ—+ d ¸¦¸˜òĹ£nˆG Å>TM ?öÁþ×K§)þ×»äæñ-(8*îg #W5Úx˨kÙQñ.Óh{R i‡ ‰4¦vž2ù~[›\Ÿv‰íÕáСm⹚QPp€Ô|̧—•ÒÒƒ{®™Á$xÇ%%ÓÑ>Šx˜ÙJ¤ŽSÛ`BzŒÅÉ%—Д%SüÜתyÒ:¢q__P(a†»A_P4©í8e Ä|Ýæ™ŒIóæz~U€§ V2ÙD¼\·¹üˆJHü#.Dj–¡èß¿¿±VsZ¶li¬ÕÏ?ׯ6h¨ý>ñé$­,y…ÒyÕzR’öû#Ïi[¶h¾Ô¼yK­¬L‹HŠØ5 "},»ó­NjÞ¼µ¶{7æ$×´½ÿYp¿ÃIø ÇçiW4j¢y·ïм^­Æ)’÷«²ç>ÜòS‘:NmSZZª-X°@.\ø 6iñ$ãIg××<Óþ·–ÉíÖ´>}4íâ‹5-+K_âr8æëv<ûßóädMåÌo›)á÷štõñ~¿~Wü¾ñrÝæòîìX2w.Q4¹¨šM¸5 pȸPÕ^pŸ6{`¨o®`¦fx:Úô!¿‰u›|~øŽ{)còzûà~¢c³õß•‰ 0iŸn7û ½9.­Mø:Ä«.ÓO>ñ,†QÙ ‰x/ú¢®±ìÕ‹¨_?Ýÿnƒû¸ãi|£M”»v¶ÌûE×Ç!,̱CqÞ,^Fp—j³Ôÿ†Æ¼÷‹sð¶iK…Ó1>¶éÈ߇kþà·*q?e<9Ť'—Æ µÊ8q­D„Ó1Ø®m“‰ h@Ô5„XUŒ±-3S_7Ó¬{êÙ1:`LÁÂ+ЯÎx™+ÌÖ°ÒÏ¡¯ú@¾éCwS»sÛSÃÙyúF¦Ú¸ˆ—³QIøMÒ_}.@¬¥(ß9–ÊN<5 r•%ÚÄ}—ãëЛß~P6ý@Ä0F3ƒgFMvåÁFŒn¢‚ï… î»Ùƒ…˜ FÒ²¥/ºÞ:`L<ÂÂ+ЯÎê6Mr‡åÎ6ãsk‹CÖ”{è–#EƦª$íÚI™¹c*G˜KùÈu7Wtƒ¿Û¡ñÓÈÓ¾5~ÜfFîw<÷]Žì†Þ4o³’‘¡w¡2—UXÛHè΃ˆnçš6¡Â„ ¬f¸´Q Beˆ2¢ÜsÒuQvëâ wv¼ÂÂ+Ú¶%š=ÛWøñ2/xh<<'¨8c«ý':øl|ÑarMÏ®µjàÞò“¯IÁJúËsèðØ)´ïÍ|*X·J®¸†Žªó\!Û£Ÿ¥ÿ¾L|€—½ÑçÕ7º†Úfצ‰Q¿¾þZüØÏJïK‰.è&ÅÔæ|Á£Pï<ž¯J@„­ Ÿ2î+~ˆ¶êp-¶åþ¾„ÆŸTL“¾tQɶŸ[;^Å™…9– L´u+]Ѩ)íøh+XyŸW{Ù¨?¨û¡\rŸ}%ý_ÅË©üe¬[A,|ÆC÷’§Ãñ²-ZЏ»óµë¿+?˜ú¼ú^ö ô_¶j‹Ç ¸Å#±ü!Æ©ÈÂ(âŒ~éñ s¬–ÕªÔ491?¸šaªÁ V€U\™8i]¿ü[ÎU%DSÚŽÝ?ëmÇvÜòÞ³§\gâ¼ü!ÁÊ"\«6b ]ÏÙ%ĹE9¹†¸¤(çü1‡>ù¡±S#p߭ﴳ΢ ߸õ~çª)BqFÔ}<ÂÂì R¶±ÂL@ B¹³ÍHq^õ©ža*%”+àÞké äº/‚ÛÔ1 ƒ½° ;10„YÁoŽ¡­enï¦MéC¯ÿ@Õ,ÊÕà›oŒ &áõa×ç°0;ˆ²c…fý«¤Âp伋,fíõpàv¤³ÏÑ3Œ?;w’kE>µ6½|í¬`î%*MY—ö zóô~ÊG ¦‚µ[õvg±œW¿¾ÜÎ$p¥ª²ˆå9¢!ØH½üóòü]ÙŒ .îð .,56êÀÍøƒi5­í¿ÈËé6‚ï¬Þ+T|0êÚš5þÑ"âf‡#­^‘”0¤¯xÏÏbÆö}÷L¡Â[î£Ã¾Þ'ÎR”¯»ÞQƒë;ò˜ÑäîØžÜ}sèË}¿Sýgò(å“|ù±Þ¹¢XÈû(’ºçø ޼YFpXÎeçô–K&ÁPÞ,W­Ò'²ÀúgŸéƒL›g@‚`KMµ)Ã}­ÍÑäyg%ÈhsWÁYH}¦÷ñV/fˆ‚#á~C¬qÏ|‡1²¯ ì‘(°0;éÊâJõ ƒ±T _~L6Õ[OûGN¦~›gú ò¬úœ¼Ï‹‡Û° ëü€fA~¬bnk¼2'ÝCYWåP³®ÙrÛ¾÷ÖÐá»ÇÓ©3©pÊ3÷\óRʺÕFŽIH¬®T.[Z†X"_ñÝ“ ›ñ·†‡HwuÆc“¨Ñ}·RÊZû6úÀ£0 E¨~ÌV°ß©§JAY1e=}øAªÏÍ !ú¹àgºàDÝb†8ùY†u³ «®Lð$(R5{ëg½âƒ ;XÃh4˜ÝÖufÈ삇f‡-ÎJTÀ–Ó1‹¬c‘’†Wô³Åù:¥m¹•á6ß³úo¾*×Í 2TÞ•£¯Pd×Ù >Ç~À<¬§Ñ¥GuÛ%ÂP‘ÕÅ|&/xÐØª#Gëri”{ŠáU@܇u,r Úb­TŸ{®±’x°0; ôeÞññ6:0dTÐFÌX-@L!éÚ¼‰\›#¼‘wŸÓÝÞr†«7]Þv÷ÁLe–¯õÀoRøènSNtT@ÑŽ“Ûá"KJôGT ¡¥KDÉ7T$,Cå®­cV ¼âú!Âf¸ôéÆß•(÷t±Ay*Ì÷MjNlüÄÃ„Ó Šx¯ÛøöâŒxYQP°Ÿ²²…ˆák‹‹htñacK øñÌâ¾´]Œc}¹¯@¶¡ZL!öùÕ(ƒŠ‹éQai#‡¢02£¡Œ0Þ·o/5…+)`~á¦M#5Wñ^q¿‚Ÿî[·2Dƺ¨HÜœW ÚÖ@ßNM£ÕâÅú°æõ͉ýBU‡g6¦Åõ죯÷íÛ±9”#ù|ñ|ÌþT{~^”Xpvà8i€r+Â.Pîk%Jr ŒoÄS†à&´* Ô°´Ñ– W:¬öFÇz^bu9¿ˆ[p°¾>b×÷½õyvýBR{èmüÁî5~u˜ð|Ì1óWŠëªtXGÎÇ,hÙ²•†©BmÓ–r¾_q•&!¸ÚøôLm÷ºZÁ˵äÉù›íöÝûì|m×.Mîk=¾×í–Û›5«˜«¸¦©yóVÚ¡CZDRóæm´_~ÑüÒ¯kwh{æ^3î‰yiÞŽ}OÍj®•½úºVöÔÌÀû`Z—yq_ð{ØþN"9uþjžÙŸjÏÏ‹y—1³é™°MÍšé½sÓM¤Ïùœ’¢M:]Ô¥‘Käý0Kä#HTç%ÆõcÎj\cr²œã×Ýûr±~†«â>œ“®Mzí9o²\·¹,â*_ûÕë®æòîl§Ó¶-yfV d XzÍ…œ´8+›š^C CG®°ïR ¼ä©ëVº¼…Å™¼Uá ݂ЕHuŠ®_v’û£|¹ˆ¤Úûqÿ=ÏðØušpÛÕó÷§?‘gÊÃz´1æ|`t*XÌ»7¯yP,ã-¿ ØB›p~¾îE(/'ÏQa‹ëÎ_ì¥qß%Wܱ}Üìµ4aæg^«WûÞ’ž^1qî?~‡DÇë¸&Üšz\ZÌ* K­üîQ¶Ö //>+·n5M«ÕŒ<,âýÓŸ³µÆ±í÷w?×Fd4ò}Ë=çgW%UÅb>üãíÈ»Ëåùâ§+Î׬®Ë¢K¯¶½†ê¤€û)RéÛ‹µ²eù!-e•ØbNp‹YZYƒHYYõ‹ï ¯òêxøÇRŸ™-Cõ9þ–ÈWƒˆ\·:sÎÑ—x?ÀC°~½þ™ºæPÉò>’×­¾‡ûhýǯ5¾î(a.?l1Ç ÂRóNÉ£òÍÛ©|Þ|™p´0ä÷=;Ÿ ­¦äM?R‹®í¤g‰„õF£n @{i¾Ÿ1y %¯µ«?ç ?+zPqènjI›í‡#ŵ”Œ¼/äùÉkß=|íPúmÍVÒgQã±·RÓ¨é¨Á+³lßCe§u£.YÍ©|Y>yÉ«hÿS6Œ%ó f‹KcR ÕmJŠpjªž°ŽÑ­`›ŸûÊˬàøJ€í‚ÇLV´»Jƒ WŽc?ÒfªK ®×áݰ¡âšÍ<®×,øxoàÍž„ᆱô‚»yåY¨C°0Ç;¢3GmÃ<8m6%.¤fý{PƳÓýD ëV‘ئÙ~² .a›Š¢¦ÍV4F$ƒU ïq3kIDwcÀ# |Þ`ÞJúíW¿¶sˆ}0Á/?öxÙ—mÈáòŸ¶J‘.ß´M60L•PQÛe%+al×®"J ëHV23Chb‡ru[+S“íúà:ãÉ'õÏC™µ¬ÀF¹òa-³æŠ‚éË¥ÝØÖÖIv‚¹ûë,Ì €vã`Ÿ¨tÉjI%½/ Ø UÁ»ŸI°U •¬Yå •²®=æ%.zwÀÿÆI[ô.XU¢šòöüÀÿm,Íভý¤ÒëÆw ïŸ8zÚï9Ћ©.v¢¢ÄIvUÄU–ÁbTB Ö¸Å\>•»ŠÉІ'«ñO?Éõ*³b…^¹@%\–ø_VTEÁjÁ[ïAuS‡ s¢`ˆ ,ÀäŸCCiÄ´üŒntôúaT8všŸðá5€¼Y®‘?Щ“\‰uf-€² a…õ‹ÿ©¶Y­{œ<f Þ ö¯Ãnêp`aN@Ê;Tm–*ì‹ÈmEùi]üDØåËNëªg R?x—².é.#·QÍ–7ÖÜ,Ñ36h 2* ò§ØGí%óúªùÌN¡â?ý%@´ûŸù·en;f¢D0q²‚}.¼Ð_¨°n®`cATæmL«¸™Ú•¥ ºG] E9O‚ª`±`„:güoüÏîÝõ 5 ‰mfqÆvx òòü+ XýuØM,Ì ¬X´3ûÜË¡,H!tG 1r:vÂn:ÛÓA·€Uw©Œ™Ó*Ê¥±p´´CmÛ™“_šKõszÈï¨oXÿÀ9Y­j«”ËÀ³÷Þ ØpÎ¥]xV(&ŠÀšUîeX‰ 2 ñR®g+f‘ÄÇ1çÍm´æölÕÕ飈6n”âé¢ÜtÃrßt“ñ êûŸ}¦ŸS£Fº»Ù,ºêZÝÔæîaÈÃ=z´~fð^±¶+3°0'(è«üûg[eßå‚Åkl…Á^:D-·èÖ^v£i+„ek@¬™…ùCc‘kw)3v¢imgNúb-¥Ýî?€ÎõèüÅTúC}V4Dµd┫Ú_¦õïª~Ðf°_á}ú93LÔ€Uhv/Ãz5 +&²8ýt}@*¢µ•E‹%,^”]¸¹†¨j”äÑ5É,ævíÙIXÙ†ˆ&A ×­“ë¨ïÃâEê)*±{öè3l¡Ran»F€˜*‹ªra¾.%ÞÖ÷¢ºí* Œ,Ì D¨ôìÞ²í8À‚…Ée’5t£Ñ7S½—fŠå?ËÔ_ õ|æä{¥¥ìÞ~{6þ¿jg†åœ:v4Õï}V€âxîOWRÊ‹säyh®$*¢ì¹Ú~ÜoUéÀñÔeçÇtb˜˜b¶ ±¬b:á”2ÊÝŸ¯ $Ë܃+äv)¬jà”M,åŒ}•‡ÑžíeEëêßå³”—ˆ ¹ú>–ª»þŽ ±Åù+´8 gåž&ÎçÄ}וûç4ẓukß Î]Ø•ÂÂ\G0[ÐûŸyÍOxÈ&÷Ýbû™ˆgÃQC)iÓÖ¸pt•<1‹´cÚJ×5†ÛL}Ò¿+—šòä£V´8¯Ô磻ÏVœ¾ýðXÄêÂÀ!Ö+€h£{ÃÄ«@+ã™v‹Ç]ÎI\¸R汦&·›=X>`ÃÂUB¬mßåCKI¡=Â:÷<÷œ¾] 2,uˆ²ùà8bÿCuyRÿËó³ö¥¼žÜGÐøF›Èݰ‘.âæ©KÕ1™Jï9»_<:lݺ•rssiùòå´{÷njÓ¦ ]{íµ4vìXJEôa˜Äÿ|Ì8Vs#W3 0‡rèca¾â/öþf;WsuPön(yF=üÙúé´0­½`_ÐÿêX7‰Â>«ð`ÐïBü»6m)#Ó‡¦qEúÓØ>:³ͫ߻ù±wo$çPƱ"ùLDæX<³?ŽšŸWYªÆk8÷t]èR“S©´¼”&}é¢q_êÂj+Î×7·ê KÚìÎ6@åõ÷3Π¬… )]ñ¿!¶V+ÿ .vkÞüaé£Raúnî™.Yðóå“hÜeãôý•Å ëÛjqG ž¹Š¼ÿþûÚ 7Ü -Y²DÛ¼y³¶páB­E‹ÚÈ‘#=³qˆëªtVçÎ.Ùcy½ZåiŽýÌRÖ„Y¥¬³SÙ¥pöAÂk»]¥`Ÿc.äâŸvh¥3ŸÓÄ+Çv$ïòüŠkܾCÏci¾vSròï)xv)5Ûu¦*±ž:4UÎUŒ¥œ±©iS}ÌèdžÊšÔŒT˜õÉîs‘P¾¼8ökÒ$p”c|ެ3E©ã«óVç&–¾s&ÎÙaðìRUäâ‹/¦^xúõë'­ÙШQ£è­·Þ2ö`jÁƒ‰¶n#íõù¤=c3¨ˆ°:a¡ݸ]¦ÒûÆŸØY¶Ãì§/vG€«¼üi}.dÏ ƒ…UÜL?o‹ çLÇ›ÜÕ° PóçC§ëÑ4SUîÝ}¨ÔSª[Ÿb™{ëÙº…Š}` c?kd·Bµ Ûµí |!:[Z»(/H e•ãsüO³%ÏÌ‘ã&—<ÎÑwÎÂbÎ}'W߇©61f;Dm²‚ÇÊDÖÕW F4{Ž.l¹|v-®W_¶ #ynRxñ²Ñ÷‡]Žâ ت¤}Ÿ—¬X#YWµ<ïYþ#ŽáœY„™x‚6~áxé .™Y"—È"»í@Pîbk3ˆµìBt‘T ¢®Ñ=Ê÷¢‹t!¶¸¡Ã>g¦J8J˜7oÞLO=õ”Ð }6 `”””H¼915ôÏ[I[ž/—2oâ\:90¨ @ŽSþÏÙÁF*9g¦v VѦçôäÄó,-+¥/{î½è^™Çyl÷ÛwލD áUeKvy/¼P~V& ›²¯¾"¯SMˆ®·woòž¾ÜÇ÷Q½Â².[´ˆÊ~ýU.½Ý»”o”MßqÍç`¤°Ï9Æ ØmwZRÔJðׄ hâĉFΞµk×RWSØþ®]»è|ñð =§¢ƒìø°¶CÀU¾H<€‘ U«V2`-DúX¿þ©cµ¦ŸþÕÈé$?>RÆés$kIn*¿ã.*¿e„nºB¹6oòÍeì~æ JßÃxÙx!À-m¶€Ý3ò(ùþ{üÜØÊR¶åììÈݯ֭û;FêX•=÷Ôêm+‡óæÍ“gLíY¢0!ƾÆ0›_Ýq•sqTö|ÞGlKÏÊ"ºV!Š{ÍøÐÍXLd@`ò Aƒd9¬aFD)R(Ž=öXªW¯ž\‡(÷éÓ‡º‹Û‹/¾HI†Å ÔÔ‘x±´k׎…YPÛ ÌÂkäPœÝ¾}>o¾ÞÙÆÝìž!„ûCðmÄÛ sÕ¨-aVQö•½lÙ2êÛ·¯££t#MX×ýÛord0 B‚þβkU”£¨#M¼üÞ(?è‰QkÂ\~ùå)Ê]ºt¡W^y…ÜhϨ"á¾XX˜«F0a®:´¦mÛ*9ÖÎrd°`â­`a®µ%ÌV"uœÚ/êxè>iøºã§»TLÛ˜a)÷îÝ[Ö²§OŸN{öì‘/£H½˜8Cˆ±÷<Ž¢f¦nSa^ºt)mÚ´I0ÒV¼Œ[·níK Ã0 S‰©0ßpà Oº]b†a˜ºHL…™a†aX˜†aÆA°03 Ã0Œƒ`af†aÁÂÌ0 Ã0"æŒD‚p6èС#;u>f' s;GæX{÷DôX‘›C9ñGžÙhƒ¯Û‰˜ËOæþýÐÛoGf䯶mÄ(>VÕˆô±vîŒÌ±®¼r-^Ì#)X øºˆ¹ü°+›a†a 3Ã0 Ã8f†a†q,Ì Ã0 ã X˜†aÆA°03 Ã0Œƒ`af†aÁÂÌ0 Ã0‚…™a†aDÝæ;ɵ"_.&aÏ÷)Ž{Î',š@¹ïä9ä±a…ê>çuO˜Å *iÌhr—Mî¾9réz~®ñ!Ã$¦çüá5«‰²³‰æÆþ9W/*w’›Æ//בúLï#óØÎ0ñNMŸóº#ÌâEuã÷ß“»C;Jzl:¹¼^¹ˤ[†:΢`˜j!žcÙòœ–Cc÷œ[_T ç9riÅÆ4éòI4î²qò3†‰G"õœ× a†¥ ,†?oÙL.c“—ÇC®Í›ŒÃÄ'ðüHOÙØæ‡xÎiSlžsó‹ /&¬/ÿq¹ÌƒÔäTe&î‰ÔsžøÂ áæ›u‹!šÛMÚqÇ9†‰CÄsž4üæ ÙñœÓñ±yÎñ2R/ªÉïN6¶êàeUZ^*- †‰g"õœ'þ´ùùD99F&aCÐ?O=–µo¯o“ï¾ûŽN9¥³‘«8VçÎ|¬p© ÇZ¿¾jÇB€—lKDyÖ,¢Áƒ DsÚÇ´áiòåd/2€—ÖkÛræéùºk›ê<çæò“øÂ ‹/VKÂå"9’hÄL®lld˜8¥Ïy´„–^J ´½õ>¡·ïE<^MP»‘Ù,P|ݵIuŸssùI|W6^F³gëÀrÔ(¢íÛ‰òòX”™ÄÀáϹzYá…—’j{Ã:^T° j[”¦6‰Ôsžø³_ÐÆÆbÌ$*ÕxΣa1#Z1f÷^bѰ­°åÈ×][Ôä97—Ÿº#Ì ÃØ av,P|ÝNÄ\~êÞ# Ã0 ã`X˜†aÆA$„+¦ãÆiÇŽìÊf˜*Z»víèÀÒ•V]⥵¹téRêׯ_séòu;Û•­ÊaBóÎ;å1 S} ¨mkÉåajÊaB³×ë¥]»vQff&¹ÐoÓ¡¨Q]³ìùº}Ýx:tˆÚ´iCIIÕoÝârèløºã§&„0Ç x@êbô8_7÷pü<òu;þb†aÁÂÌ0 Ã0Â=A`¬3QÀívSïÞ½)99ÙØR7àë®[×ítøyäëv2ÜÆÌ0 Ã0‚]Ù Ã0 ã X˜†aÆA°03 Ã0Œƒ`af†aÁ¶nÝJƒ¦:Pýúõé¸ãŽ£|JKK=‡gžyF^g½zõ¨K—.ôñÇŸ$.<òuëÖMŽ€Õ¢E ºâŠ+hãÆÆ§ Ã0¡aaŽ?þø£¾pÖ¬Y´aÚ1c=ûì³tÿý÷{$¯¿þ:Ýyç4vìXúꫯ¨W¯^ô§?ý‰¶oßn쑘¬\¹’n½õVZ³f -[¶ŒÊËËåúEEEÆ Ã0ÁáîR!//fΜI[¶l1¶Ä?Ý»w§3Ïï¼óŒ­ Ã0ö°Åì0ŽkVV–‘‹à–ÿâ‹/¤¥hùU«V¹º~[H¿/Ã0µ ³ؼy3=õÔS4lØ0cKüSPP@‡Z¶lilÑA~÷îÝF.ñCêî»ï¦sÏ=—:wîlle†  sÁ覘î.TZ·n±·¦É»øâ‹éꫯ¦›nºÉØš8àšÍ@¨¬Û™Ûn»¾ýö[zíµ×Œ- Ã0¡á6æ+)Ç{¬ŒPå>}úȶØ_|±Fsá: ¸²ÓÓÓé7Þ +¯¼ÒØJ4bÄúúë¯e{k¢sûí·Ó‚ è£>’‘é Ã0áÀÂ#~ùå)ÊèBôÊ+¯ÈAÖ T8p}è2¥8餓èòË/Oèà/)ˆòÛo¿M+V¬ N:Ÿ0 ÃT s €¥|þùçSûöíé_ÿú—Ÿ(·jÕÊX‹Ð]êºë®“]ÁzöìI³gϦ9sæÈ.bÙÙÙÆ^‰Ç-·ÜBóæÍ£… Ò 'œ`l%9Y;ú­3 Ä‚…9Àm}ã79í瀵ûì3)Äï¼ó}øá‡´hÑ"úá‡äg`ذaôÍ7ßÐêÕ«- Ã0 [ÌLDhÞ¼9=ÿüó4aÂZ·n>|˜®½öZ9b¿~ý¤øbi梋.’û–••[†af&bÀU=dÈúûßÿ.­a´%O™2E~¶{÷njÙ²¥\W _^^NƆa†…™‰(Ó§O—b;þ|zõÕW¥8+¬ó«V”`ó3 ÃÔEX˜™ˆ²eËÚµky½^Ú¶m›±•¨U«VÒj6óûï¿Srr25mÚÔØÂ0 ð03£´´Tº±H“'O¦ÁƒÓo¿ý&?ëÙ³'-[¶L®+–.]J]»v¥””c Ã0 ÃQÙLÄ=z4ýç?ÿ‘‘ÖÔ§OÊÌÌ”QÙè.Õ¹sg:t¨l‡F0Ú¡_{í5úË_þba†aaf"Š+¨oß¾”ŸŸOçž{®Ü¶}ûv:õÔSé‘G¡áÇËFîºë.Ú°aµiӆƌ#Å™a†©€…™a†a·13 Ã0Œc úÜSAr²®ãŠIEND®B`‚pyclustering-0.10.1.2/docs/img/elbow_example_simple_03.png000077500000000000000000000453411375753423500234210ustar00rootroot00000000000000‰PNG  IHDR)ÓDƒH/zTXtRaw profile type exifxÚ­šgr$9’Fÿã{(‡8Âlo°Çßçˆ`UÙÎ,Ù•L# \|ÙnÿÏ÷_|å,Íe©­ôR<_¹çoš¾žŸÁçûz¿b÷ñ½úåº[é}(rÉÞ¿¿—ýü ƒëò÷šßëúõº«ó§½½ø0Ù̶†÷¾ö”âs=¼¿»þ>7ò§í¼ÿb½‹·ÙŸÉ¾ýž+ÁXÂx)º¸SHž×l³$VZví¾fn²ëö^xÍ©þ;÷çí·à•ð{ìüxïH_Cá|yo(ßbô^ò{ìn„>¯(|¼_ÿ ùãÉŸ±;gµsö³»‘ ‘*îÝ”‡¸ï¸‘pæt+|Wþ ïëýî|7¶8ÉØ"›Ê÷t¡‡HdOÈa…NØ÷ç “%æ¸cågŒ3¦{­¥{œ7)پÉ5õ´9Ši’µÄåøg-áÎÛï|34f^;c`°À?¾Ýoÿï?c¥‚³ñÙ=EïC]¹…Å„DX^’ÀkŒ5âØÈÏ`呲W2Dâ î›” ÉiÑææ™î½Qâsh!’Jª¤¦§A²€ ê§æF I’ˆ©Ò¤Ë(©ä"¥”Z £FM5W©¥ÖÚj¯£¥–›´Òjk­·ÑcO@˜ôÒ«ë­÷>“†<=¸c š4«hѪM»ŽIùÌvÖ%H÷EZH˸‹Eµ3ºì¬ì9ÆÐ[{,"f@™Î˜%lBf#¤›Y_'=X`|×°UXBÓ˜dÇÔæP©´1š¶]ÅÁœ)†6¤ß¶•Ìñ«]K§Il-–“zO{iÚiZ,–}vÚ&“ܶ]×S X˜â‰¸Z˜2«[bÝC5Ÿ¤Îz¯Ö£-2S\UðÀS§Hwõìz ·õtqJ›¿SÆgÏsz¬H Ûh(,S'\`'þø¾[>îÔÒífý2&Ò)±wDþÝwÐ̨qq­“ÎIGÓÙÙuk¢•b& ‚°™&JÂPÏZCÉá\‡²<‹JØ•²_½0G'JçÄ É¹XÚ;´UÃü®Ñ‰´í0nž=¤ä•çbZVÌØºc¢ínÄß-°/FÑŸss'’Œ ÕL8É&À–»Ë‘B&D䪦¥AÅØ=‘jñdR¬5 tmÃ÷¾£Pa–Üvr¶)™9Ü?…¹,{·r¬+Ò¨u~½³µK¿®¬É¦bè]*ÝKˆÖ$–€¥4hè²JEhÔµ&°™}kµêðQz¦»gÉ«öáhd­i÷J°ÝS¥+èàURVÐ…ˆƒo4ÅÔrzE[vº~È4%g°‚vÛÅQÎ}:½fÑÆ¡)×”-´YtážcP…«í™ÚÖ·ß›Á#ÊhÌf0 .8Øc‰¶´Cmgn„ÇØ–ífÙHÖh_ØxÍS~ôËÞô®ï§!z¾•Ó©äÑ‚ÃË]ìç'záír™—¹Úùº5(Ù o¡Èi™(#î‰ ®£.‚µIýÃMÝ‘Žb½e3¨yÑÚuNÚ”Kj{Ræë\<ßdÄ$ÊÍâ€Ï(+Hqe—%@ SÒj.Æ.%P`LË64[ÓÔíΘòºq> ³ÑR"ؤî Ú¬t¨^"rùT<é °V;µ¥2ÑjÐ j6d-—Zƒâ¿H—”j&kW«è4n¡¢P%˜¨ OQe )v[›6°b$y©ÓR0Kp†‰÷¢ö½‰Öå&<Õíiµè“¬¬iyÿDJÝó«9Ë'ŽV‡¼ÁÖªq~Š5[‚Sá/SÖ;¤ ûü¡®v½åÞyïãÚBÓ$^£¯ I»µ@­D1] w刈h³Bc´òò—¥Û0ÿm ’FO“ ¾à!b;g²b´­ÈÒ fÀ†h‘eh[ˆNÕÄÍLí«•/rPWik#wYÆš™É{ qxyø‘¦_Ë!zƒ ™ L¶Ç.U † 7yEÈBlv±Þ—Ý'Ó"ú‘åhè…4eð"¨åˆØÉþe‹ïq·fL¿PÆèòz *„:@í±(Ñ xÔeÛ¡€iGšlT J[̶ڧ0WâD¤ä®¬§–üc¡Ld²¦Æ‹(£˜%Ì›M«Gõ¥†v@¤Ó×ÐË(úêÁKôÇ_н¬ƒÇãLà)ò”²S[ë3xÙ³?…°3ãÞ–-bñA‡ùð‡±Õ0àÛº]a>þÔÛÝ“ö¸ÕWFÿ4â;‹!6]6Õ ÜF[ÚbÜ—ÕpS_•옄6à;H¼Eö¬\`@«þŒU®}«;–@†'(h|»ÀÇAš h„Né+Oë© Qv²ûrÿ> ³=Ú£”|÷‘® "}©{èú-__>ñz¢ßñ$nN0;ŠÙ†t£>©GZ]®—Òâ67…Ÿqr‹¨—f¤]êÐd·ñ 8°'´NžÃÏÛr¤hS2¯ X™>\ÄòË}âòÞW: ÔžT±Í  %g@µã¬ŠA§¹¸ŠúT°Ð‡šáúxsŽÏ ÍŒß*ø~ÆA|Ç­Zz¬`CÁR6‚¾È¨Cµ¶²ó?ä®bë|qZ£÷º:¼ˆ[Âj™YMÆ]t6a4ÑHû [l¾ñÐÓÛÑbÄÌ’X+èÕX¤Ž}‰ß·¼!/X—ùUhY_m;K³’ù|÷7¬\ƒ‰Q‘ÌuÃÚ¾ÒjpÐÁ¤pÌñD˜.C\ã9+&jÌîIRS¯– @ÙÌJ² ŒÐ#n|˜ïçÝŽµÝÍÙìøà*×=%Á^S‡¿³ {æêhn©èŒ[–.Ì0±Yr® ²GôK€+áä]dÚ߃´Âwz³š³&–Ø0Ñ9!œmªDYô -A×”H*(W;éãn¨ x<„&a4f@P÷dx×A^ŒSÞ`” !6·Si@>ƒÒìˆv2Qi‚œ %«l¨8DÒ&ÁcAW¯<^ç¾›8ÁÀ”ÁÈ‹Uà"bF¥æ!)\ÐnƸà,’ÐÒyè-¤EÃ&kEn ÇÈ!Lú=mVÚǺ?˜Å‡åXå2>ã\öo°ô ¨_ D*#Ø©ƒñìÑ`ôè[½;P3¼Q*àÛÝĘšWE!"©Î>ì`†f€&ïtô~aB×-BLˆ}”áú­¿QlŒ½ëóÉtj·54ü»®~Z ý²ò•fÍû'\WS£üÉ 1óeÞ$=‚‘t]iµ6ûÐK;óÒIÉŽn€C­x—›$‹Ç¿#,ï˜ÛjX#L.h¸ìhý¶ö™>4~X¡W`…".›¯‰ñÁÛáJxPí;"ßÓ2lç¸ÃÓ ¶_ƒ ïyª,.”d_m•Š-W2«‹ÀMô:Á6ã¼í¤°·Žë1OÔ)V„u²Ú¼G^°ð¶èë¥[Ø@,Ö½Ð>2¶’5¼–õ,Ø”½úÝCBo{J$ÛéÈ¢@1Z‹ ¤©G€á»ñ‰2íu@~ÀZ%¤í¶³ë€$øxˆÆŽÆ¸¬ QÔ7¢‚}"Åt°DžT¤6Ç,Q;ZNš ‚ ’VÙ¶Ou¤o탸nõi¾žî³á…2AŽ«X¢Ã:5Ð¥“l%hgU¤ô <èHšXº™TÖK¯˜ÿ`Ñ /"FÀš‚ÓL·µFÖQüÔ’hB¸];$¤Ü2 m_·èš®ó`K´úf!ôî¥eèÊ©»Øçr°Œ‘¥·å`[¼>®¤SêIÈø^N$¯ž+=Bg€ÅT`!òÃÎHÌ?ø:0O‰@±rä õˆ´“em!tgÖês¢ŽF&@je$;¨[ÞØ l¦b$@G›Ù¤ç)š[ž§# á[æ@qWv3î¨á%ÒªJ3§+ Má¬&£Ø‡kv*@3a®¼U•#1A%ÙϼGJšŠÚI)î †Ê´Ñ…$M5we» ØhО½àÏ×£˜ ¥ÈDZcRûœ– šcÒ•à e{7ašïÄ(åŽóÌÇ8ÊF»Úç&t!€ >“Jö‘ë‡Eˆ7zšy¾à¤ç‘úå¡£7n¶”p/¿5üÃ`ŸûlŒß~Ž\0*5âÌÔØ‡|…Ñ 4}È/Q¹Ÿ´{önÖ»|?3\ëq;Žô[°,íŒwdk4æHžjÁ¿»jŽÖüìz´–—ŸT€A+—p@jÀ¸‘p[ñÀ7ê¹ ïüô…nšë˜šÂ…˜4ÉÊUˆ]KìäýÐî«\&ÂW¾,E4lû(>Eº§™¬ ^ÇÀ ¤Ò …5P`i·6—Ç! ³…[wu s –ý/¶1´91÷ÅÀƒ‚ðvº m;*5²BëP3h‰n™˜€åêòù,¯þýŸî?à?ùw¹ÿa­h ‘éûbKGDÍèÆ— pHYsaa¨?§itIMEâ 1à­yU IDATxÚíÝwxTeÚÇñïd I Īˆ"E¥*½GP\vAaC|)Š(«ìººÊ ê²X@Wd•U¤&t‘)Ò{ ’™óþñ0“L „’0I~ŸëÊ5%gʹϔ{î§Ù,˲ñ2> ˆˆˆ(IQ’""""ù™oAßA§ÓÉ‘#G Âf³éˆ‹ä#–eqáÂ"##ñññÑ{]¤½× |’räÈÊ•+§W€H>vðàAÊ–-«÷ºH!{¯ø$%((ȽãÁÁÁ^ó¼RRRˆ%::??¿ó‚ºo:fy/!!råʹßÇ7û^/ÈÇN¯))qÏî½^à“WÙ788Øë’”€€‚ƒƒ ä^AÜ7³;ÿ>¾Ù÷zA>vzMIAŠ{Æ÷º:ΊˆˆˆWR’’ΡC°t©9%)^aòd¨PZ¶4§“'+&""O8N»±í(5¸íƶãxÂqE”¤ä¦C‡ o_p:Íe§úõSEED$£˜OcˆÛÇ™¤3Äm#æÓE”¤ä¦]»Ò‡vïVlDDÒ[»o-§Ã|N:¬Ý»V•Q’’›ªTŒóDÙípÏ=ŠˆHz÷EÜ—ö9écÇÇLJØm±ª¬ˆ’”ÜR¶,Lœ®‘O6L˜`®ãä…“8œBC±a£d@I’’“pZ¦íp:X·%JRn·Þ½aáBs¾HøãÉ?r»Ckª#•ÞŸ÷ÆÏîǹ‹ç°°8tÚ|‘ØÌW‰ÝÇN½ õt0DIJnhÝ*U‚ädˆU$§&kD(IÉ+ BXœ= +W*"â=®ÕïdJ¯)´¹¿ ¥Š—¢å}-ñµû²qÿÆ%!íþÕŽøñ™þw:ñ4C¦aÂ3xú“§Ùt`ÿéõÊ„”ÁátâLaÅ®Ñ#JRòН/<ñ„9¯&ñ&éûÄn‹õH"‚#ÜÍ.‹_^ÌÌþ36ck÷®½æ}~»ñ[l]ÀŒM3<®w8ôþ¼7ÿxêôú¼;Žíà»ßqOø=,Ù¹D#zDIÊ’¾_Še)"âÒ÷;qZNVí^ErJ2¹ÊrÅq…éý¦óúì×Y½{u¶÷ùýæï=N]þ:ó¯t|°#¯|ó GÏeñK‹Ùyl'¿÷;j•«ånZÒˆQ’’ÇÚ´€8pâãñéûøØ|¨Pªí?lÏk3_ãþÈÂm =ª,!!Lï7·æ½ÅŠ_Wdº¿ã ÇÙ|h3ñã9‘p€é릓˜œÈ„¸œz™Yfñ—aéÎ¥|ÚóSŠàƒ~v?šViª=¢$%/+>jΫÉGD¼Eú~'ÑÕ¢YüÒb¾èýqÛâXöë2¬«¥_§ådÕžU8N‚Š1½ßtÆ,Ã’íK<îoáÖ…ž—YÈ–C[øô‡OY¾s9ÁÅ‚y¥í+ôœÒ“Þ{ónçwéùiO–í\FŠ3Å]Õ‰ù4FÓâ‹’”¼¤¡È"âmÒ÷;q ÷íùYOÖï_ŸiÛÀ"´ùgæþ<—€"|Ý÷k>Xò±¿¤M5wË\weÆ×Ç—™›f2`Ú~=þ+U"ªU"ŠvÿÀ÷¿ÇátÐmR7VïY…I†N+w­Ô´ø’k|‚¬=þ¸Y¿ççŸá·ßàî»ñ>éû©¸4½§)OÕ}Šéë¦óÊ·¯Ðmb7R©ÔŒªÉ›sÞdûÑí4®Ò˜[¸ Lu¦2{ólBŠ…P%¼ ‹·/&Õ‘JéÒ,Ù±„Ë>È‹­_ädÂIÏŽ³–Ã]ÁQ'ZQ’’GJ•‚¦MaéR˜5 ^|Q1ïS¿b}â¶Çáp:ð±ùP#²ïªÈÜŸçràÌž=èÞö§}?°j÷*lØ<îËátp&é ?íýÉ}Ýo§~`ãÌÞ<›G*?½÷rôüQ©ôWWX±k§ChEIJ^êÔÉ$)ß}§$ED¼Ó”^Sˆù4†uû×Q¯B=¦ôšBDp–eñ^ì{ ýfh¶·u5ÛäDñ¢Åù¸ÛÇü¡þ<®?žp<Óã‹(IÉ; /ÀªUpò$Üu—b""ÞÅÕO%#›ÍÆË¾Ì¼-óXºsé-=FxP8[Fl!<8<Ç/r;¨ãì5T¨µjÓ sæ("’¿¤:Ry·ó»îUŠo” –}ŸGüœe‚"’ÛTI¹ŽN`Ó&ÓäÓ³§â!"yëxÂqºNìʪ]«ÀïiÌûþ—R¥8zþ(ÏäÐÙCì9¹‡mG·±çÄÎ^<ËÅ+¹œr?»~v?’S“oø±K–$ªdÿZô/jDÕ FT ?Q’â-IÊë¯Cl,$%A` b""y'æÓ暥;—rï_ï%ªd)ŽŽœ;BrJ2ÁÅ‚yìÇh~_s’’“Øz?—S/ãëãËÎã;Ùwj–eÊÉÄ“9zì3IgØsb/¶~‘]'vñäÇOrðìAJ+Á#•¡vùÚÔˆªAõÈê ¦Ïç}X»o-õ+ÖgR÷I:xrËÔÜs5kB¥Jpù2,\¨xˆHÞZ»/óÚ;NËÉ'=>¡\Ér\ºr ‡åàìųÄn5s T‰¨Bª3• û7°÷Ô^^hù—Æ]bϨ=\J¹tC¿ëÄ.ÿàq^øêöžÚKŠ#…3ÏpéÊ%Ú?ОÄˉL^5™ÚoÖfÁ/ Üó¥ôùO<ñÞ$eÔ¨QÔ«W   ÂÃÃéÔ©;wîôØ&99™AƒF`` :tàСCÛ8p€'žx‚ÀÀ@ÂÂÂxþùç¹råJžÈfÓÄn"rçÔ¯Xßó3 ïiLåðʬڽÊc„NÂå>[ýïžG­òµøííßøå_Øj Ëv.£Çä$&'ÞÐã;-'WWHq¤xLâ¶éà&êV¬KL£Þíü.©ÎT÷mNG–̉xM’²|ùr Àš5kˆ‹‹#55•èèh’’’ÜÛ <˜™3gòÕW_±jÕ*iß¾=‡™\Èápðøã“””ĪU«øê«¯øöÛoy饗ò4H®$eÎHIÑ‹FDòΔ^Shq_ wß’æ÷5w;Nqx~ ÝUü.Öÿu={ÿ±—7;½IP± ,Ëâùï0iå$N'žöØÞîc§D@ †·NH±Ì?Ò2Ì£’^Â¥iðÓ¯+d÷±S·B]<ñÞ$eÁ‚ÄÄÄP½zu|ðA>ûì38À† 8þ<“'Oæ½÷Þ£uëÖÔªU‹©S§²eË-Z@ll,Û¶mcêÔ©ÔªU‹Ö­[óÞ{ï1iÒ$ò,HAXœ= +WêE#"y'"8‚%//áà胴ªÚŠøƒñ<ö¯ÇX¼c±Çv~v?Öÿm=Q%£<‰n“ºèÈù‹çùåè/·éð`v¾¹“‘GòëߥVùZîäÄÇæC‰b%2%5®Ä%Å‘â1 ~úu…ÚÜ߆Oz|¢ƒ'·,Ï:Ξ?€ÐÐP6lØ@JJ ÑÑÑîm"##©Q£«W¯æÑGåǤFDFFº·yôÑGINNfÆ ´hÑ"Óã$''“œœÖ‹Ý•̤¤¤r eöííL™âÃŒš4qÞr<\Ï%¥–f ê¾é˜Ý¹ç%¦íÂ_baqîà9J+AÂå÷L¯­ª¶""8½ýŽ£;0mot|ƒF÷4bø¬á÷WÜ¿83úÏp_gí_ÖRëÍZDFFðõ×É´n‡Ív{bW`_\ußtÌòÎÅ‹õ)}ÕÚ}kÝ}B,ˆ6÷·ñ˜éÕ5ûëªÝ«(êW”Å/-æ²p<á8¶tZ>6ßÓ8ó‚Ý—·:½Åê=«ùõø¯ì;µyƒçaY}>ïÚßÖЪj+b·Åâ´œØl6jDÖ ÝØvîQ=®oEòM’2pà@~þùgV­Z•£„&ý›É–E6q›ô† Æ!C<*)åÊ•#::šààà›Þ‡-`ìX‹S§ˆŒ|ŒZµnýb\\mÚ´ÁÏϯÀý*/ˆû¦c–÷ò²Y×Û¥_£Çîc§~¥ú™fzm7¶ ·-IJ,.^¹È+ß¼ÂüÁó‰ù4†³IgÝÛ…†f;}}ýJõéóyRœ)<\ña.^¹HDp_õýŠ7ç¼IDH­«¶fýõD†D²ùÐf.%à´œîæÍ@+ù&I4h³gÏfÅŠ”-[Ö}}éÒ¥¹rå gÏžõ¨¦œ8q‚† º·ùé§Ÿ<îïìÙ³¤¤¤dª°¸øûûãïŸy¢!??¿[úðõóƒ¶maÆ ˜3ÇúõoO|nõyy³‚ºo:fyû|ÄÈjž,«-WW$vZNwSLú* ˜5{²«vôü¬'§“Nã´œ,Ú±Ètøøøðz‡×™?‹ Ë'°|èr†þo([lußV« Ëí–kg-ËbàÀ̘1ƒ%K–P©R%ÿשS???òòÑ£GÙºu«;IiР[·nåèÑ£îmbccñ÷÷§N:y, E‘;ÅÕçãÔ?O1ðü,“ŒŒ#l\+gw}VÖî[‹Órf›tt|¨#ïv~—fcš»-ÖãZYòM%eÀ€L›6Y³fäîCB±bÅ ¡wïÞ¼ôÒK”*UŠÐÐP^~ùejÖ¬IëÖ­ˆŽŽ¦ZµjtïÞ1cÆpæÌ^~ùež}öÙ[jº¹Y?v;lÙ{ö@åÊz‰Ü)7ÒI¾ wzNoR÷IôùOÖï_OÝ u™Ô})))Ù^Ÿ•zê±hÇ"w³RÝòu3m[å®*8-§;™3"¨uÕÖîû.,1÷6ù5îÙ=ß\KRÆ@óæÍ=®ÿì³Ïˆ‰‰àŸÿü'¾¾¾téÒ…K—.ѪU+¦L™‚Ý~5ã·Û™;w.ýû÷§Q£F+VŒnݺñî»ïÞ‘ ††B³f°d Ìš麾ˆH»™Nò¹Ó³ËÿÝýp·9¿aÕ†ë^ŸQר®œ}º"–Š,""r“” púôi÷?BBBøí·ßÜ—Ï;G×®]±xüqÓ‰vËسGñ¹¥$%cåÄÊ¢×§¥ž 9 Íš™ó³f)""7,õ8l¿–2§©Ç“œ¤ä„ÍfSÄrHM>""·ˆ¤Xpž¤8sY”¤Èíѱ£9ýá8qBñÉäh $-Ì:¹´p^½à€Ëë¯BÈ7ý…mÛ¶qìØ1À4íìØ±ƒÄ«Kúž:uJѺåËCíÚ°q£™&¿W/ÅDDÄÃ¥µ€•u"R¬¾I\pv(ZOñ*ìIJ«V­<ú´oß0Í<–e©¹çuêd’”ï¾S’""’‰G"bóLDÊL¹ZiY þuÁº—ã¡èCŠ[aLRöîÝ«häB’2|8ÄÆBb"/®˜ˆˆdJD.­ŸbÜ-Ý·S”›Ç>pî#¸0CIJaMR*T¨ hÜf5jÀÝwÃo¿ÁÂ…ðÔSЉˆH¦DÀ™ ‡Ÿ„¢µÀ¿FÚ6þÕáô»æ|â÷p׊[!âî8»k×.ºvíJBBB¦ÎŸ?O·nÝ<æM‘ë³Ù4ÊGD$gßFþPæs8þ<¤¦mà[R¯Vú“ã=ÿ'…'I3f åÊ•#888ÓF!!!”+WŽ1cÆ(b7È•¤Ì™))ЇˆH¶|LPÊ3,ùð3žÛ$-Tœ c’²bÅ :wîœí†]ºtaÉ’%ŠØ jØÂÂàÜ9X±Bñ¹&ÿPr ìox5!¹˜>‹Ä¹ŠQaÊ[]göïßOxxx¶†……qðàAEìÙíС|ú©iòiÕJ1qK9 Ž ³Éú–†ÔS¤ OvI…¤ùpyÍhS{øEåüñS§uÞ-VßtæõÐqñ¶$%$$„={ödÛv÷îÝY6Éõuê”–¤|ðé«"""ÀÑpñªôÎ °¯nöÿhååð¾.Ãá.piàL›PÎÕ™W¼'IiÚ´)~ø!-[¶ÌrÃ>ø€&Mš(b7¡uk€C‡Ì¼)uê(&"Rˆ¥¯^ø•ŸpžÏᯱ†œO é Žóz4íÏq,ÝùtãS.ý„f¶ÍIʰaÃhР¿ÿýïùóŸÿÌ}÷ÝÀŽ;=z4 .dõêÕŠØM(V Ú¶…3L5EIŠˆj®uypBòYð- ¾‘peûÍß§½4ø×„„/ i¶d/mNýkAàcæ¼O°g9û`;Íl›’”ZµjñÍ7ßЫW/fΜé±Q©R¥˜>}:µk×VÄnR§NiIÊ›o*"Rˆy¬Ëc™&œ¨ÿÁ…Ypö_`]Ìáù€-Jƒgn&”»¼Î$(e¦èøxc’²{÷nÚ·oÏþýûY¸p!»ví²,î½÷^¢££ P´nÁã›N´[·ÂîÝ ¹óD¤ÐÈØ9µèƒpqÅÕê…™°íÒ0ÕLOàÊõï·H5ˆœEkÞ·`„ú ä‡$åÞ{ï%**Š-ZТE :wîLÅŠ¡Û$4š7‡Å‹aÖ,xþyÅDD ‰£1iM*I±P¤ªiâI=öàÿœÿR“VaÉÇ)8>lE!  ï`š|4:¡ÀpÏ“²|ùrúõëÇ‘#G8p •+W¦R¥JôîÝ›©S§røðaEëiöY)”.­5 ˜$$å”[÷]†*' ôGpeß%(ö» è÷@ ¤ì‡sÿ†ƒÂ±A&)²®˜*ÎÁvðk)sšz\Ç#?&)Mš4áµ×^cÑ¢Eœ;wŽ¥K—Ò³gOöîÝKß¾})_¾¼»3­ÜœŽÍé?À Íì,"…E±ú€Ý•Y@@cð¿l>àL‚Óï€Ížþ+)[†Ó«®là.Pn=©ÇÀ¯´4+&úì}ÈL ç<“6ÄXò_’’žŸŸM›6eèС 6ŒþýûS¼xqvïÞ­ˆÝ‚råÌÈË‚¹sUŽ‘B¢ÌlöRæ´Ì³ à™áPð»*m…ÀhÓÖ³\b†(—nNÝÉÎUI M²S¼-”¥^KËàâ2éŽK¤ [Öã|¤\¾|™%K–ð·¿ý&MšP²dIžþy?~<PÄn‘«ÉgÖ,CD WçÔ*§ ì÷8=ö’P.‚Ÿ¿Òf›â_ýjºúC®x¸{'Ü5ÒœïpõNmf»ÄyžUä^ˆøD~ŽàcO»/ 1οIJ³fÍ å…^àÌ™3 4ˆýû÷³}ûvþýïÓ­[7¢¢¢±Û”¤,^lãÒ%»""…ƒå„„ÿš>#8 Ü3lØ–îsÐJ…¤€ÓTM"¿6Õß«K¶ø†›Ë‘__­ª8Í4ù–#óãÙƒÌ@•¶‚m ˆ™n¿ä‹:ù1IY½z5aaa´hÑ‚V­ZѲeK""n~ý‚+VðÄO‰Ífã» ½E-ËbĈDFFR¬X1š7oÎ/¿üâ±ÍÙ³géÞ½;!!!„„„н{wÎ;—¯^½:T® ÉÉ66m ×+PD ¦Ôã<õ¾¿EÀÞÚp ¹é´Zv.”è 6¿Ì·q^¿»¡ø“¦jÜ%ëûîrµªò$øUç5æUñ+•ÖCÕd(¿’æÁÁÇ á+°´4}¾IRÎ;Çĉ àwÞ!**Šš5k2pà@¾ùæNžÈG}”åÿGÍûï¿ÏG}ĺuë(]º4mÚ´áÂ… îmºuëF||< ,`Á‚ÄÇÇÓ½{÷|p›-­š²`AEÒ‹PD û‰>ܸ ›u’ãÁ桃ÍTôÙÞ(*®÷¬ždÇUU©¸ÎÜ.'ŠTˆ±¦ã8mFûœú;\Þª@^Ê=OJ`` mÛ¶¥mÛ¶\¸pU«V±téRFÍÓO?M•*UغukŽî¸]»v´k×.ËÿY–ÅØ±cùë_ÿÊï~÷;>ÿüs"""˜6mýúõcûöí,X°€5kÖððÃ0iÒ$4hÀÎ;óõH#ß«Qÿùçpî¹ÇbâDèÝ[/F)8lÉë°Ù\V-HÞ”ÃÞ`3¸í&šÍíAPr”èÁÁÖ¦ÿ –ôÖ$%£ÀÀ@BCC ¥dÉ’øúú²}ûöÛò {÷î娱cDGG»¯ó÷÷§Y³f¬^½š~ýúñã?âNPyäBBBX½zu¶IJrr2ÉÉÉîË ¤¤¤’rçK{‡Á˜1¾¸:r96úõ³hÙ2•²e Æ‹Êgoˆ·ö+ï[AŒuaaù×ú‡Í‰×vXµÙÌh#+òò$Åét²~ýz–-[ÆÒ¥Kùá‡HJJrÏBûñÇÓ¢E‹Ûò ÇŽÈÔç%""‚ýû÷»· Ï\î wß>+£FbäÈ‘™®õŠ©ý·l ÃéläqÃaãË/¢fÍÓêÅW ß4u¿¼qß.^¼ˆäOŽðO8óKGƒ÷c+æåk⫯E½=I)Q¢III”)S†æÍ›óþûïÓ¢E *W®œ‹I¬ç\!–ey\gËbjãŒÛd4lØ0† âQI)W®ÑÑÑßñ€?ð¼þº…Ó™~,ºty˜J• ίò¸¸8Ú´iƒŸŸ_ª6Äýòæ}sUB³r#UÓ‚\óÚהʚÃÃiSíêkʼ5þa“°;û`K^å_GØ$ï}®9x/çÇ×zvÏפŒ3†-Zpï½÷æú“)]º´»ZR¦L÷õ'NœpWWJ—.Íñã™;/¤¼%æÚ¯ü»o×z.7S5-ÈU0o•bþéÎoPÜóXvUSw’Ò¯_¿<ü¢®DéÒ¥‰‹‹£V­Z\¹r…åË—óÎ;ïРAΟ?ÏÚµk©_¿>?ýôçÏŸ§aÆùúÅÓ»7´l™Ê—_þD©Rп¿/ï¼=MšèCM$'n¤jZ«`ÞüËX1/¼q?~úô±³nzõ,>ùÄÁµf5É®jê›[O011Ñcý½{÷Ohh(åË—gðàÁ¼ýöÛT©R…*UªðöÛo@·nݸÿþûiÛ¶-Ï>û,&L oß¾´oß¾@¬!T¶,Ô¬yšÇ³X»¦LîÝáçŸÁ Z¥D¼ÞÍTM rÌ[)æ…3îÏ> ‹Ã‹ÙxöYæÏ¿öóÍJ®Í;~ýzjժ宔 2„Zµj1|øpþüç?3xð`ú÷ïOݺu9|ø0±±±¥wÿòË/©Y³&ÑÑÑDGGóÀðÅ_¸Ó¿þ+Âþýðüózs‰ˆHþ¶fIPÀœ®»ÉS¹VIiÞ¼9–eeû›Íƈ#1bD¶Û„††2uêÔ0ƒƒá‹/ Y3øüsxâ xê)½ÈED$ÿY°||ÌŸÓ v;Ô»ÉSZåÎK4n ¯¼bÎ÷í GŽ(&""rgÄÇC»væ4§¡˜?Ö¯g|ê'IDAT‡èh(U Ú´1]”¤äs#F@íÚpæ ôê×(D‰ˆˆÜ’­[á®»LÅã®»Ìe—o¿5‘3rv_+WB‡ðûß›. •*™dåÔ)sz³K*Iñ"EŠÀÔ©P´(,\¬˜ˆˆHîhÑÂ$–eNÓÏ×úý÷ž§Ù¹|†…ÿüfÎ4‹è¶kg*(íÚ™Q>·BIŠ—¹ÿ~=Úœ:nÓJ"""NŸÎúòñã°y³9'Nd}û  }{hÚ&M‚ˆ‰¸8Ó"g.+I)` 0my—/Ã3ÏÀ•+ЉˆˆÜ^¥Jy^vM±p¡çõ/§¤ÀÈ‘ðþûðÕWf°ÀÑ£°|ùíÕ£$Å‹ùøÀgŸAh(lÜhúªˆˆˆÜNK—BX˜Yg1 Àü> sçš9¾¾¦Š« §IÓöÞ{M÷„  øæ3"õå—¡Z5ó·6ªÇÅW‡É;EFšéóÿ{ܳÑ6n¬¸ˆˆÈ­9|8­¯Hú*É[o™¤âÔ©´jHjªIZRSÍåU«Ì§ºv…L“ϤIæ‡õñ㦉gÝ:s_7;ªGIJ>ðÔSð§?™¹Sºw7m„šVDDnE°dIηw%(.7š®.𗿘ó\sfÙ¥æ/÷Áf6Ú}ûà…¹5Ï=%JÜžû*Qrsé?%)^.8Ø í²ÙLÙ,§cÖED¤p:wΟ'ž°g; ¸sgعÓÌkr3l6sú䓿~:wν}QsO>Ф‰™öÿ0³Ñ6heÊ(.""’ÙÔbÓ&–e&d«Yy$óvþþf9–Ìù(R»Ýt–0ºtÉý}Q’’OŒi:8mÚdf£7/-›qÙµ«$–•öátÂìÙÙoâDEeî{’•èhSÕÏ›}QsO>‘~6Ú `Ü8ÅDDD2«Rå,v»YW%'ÀÃáB…ë߯Ýuëæ]‚¢$%Ÿ©VÍ G3}ÇÅDDD<=ÿü&Z·¶nhq¿¢E¯¿Ãqýiò•¤ršf£‘¬”(‘Ì÷ß;r¼¸ß–-ðË/9»ïøø[_GIJæš¶dI³nÂo(&""róž~Úó²Í~~Ш/ž6û¬KÆiò•¤ˆ‡¨(Ó³`Ô(X½Z1‘›“±ë€¯¯Y¹wo3W—k¨²Íf~(Ï›§$E®£sg3 ­ÓiN/\PLDD䯤¦šï› Zµ2ƒ5*T€³gÍü\_mV9v:M’kÚ|%)’­?4/¢ß~ƒÁƒ¹1—.AÕªfÄNÉ’ðè£im]³ƒ™eçN3[åÊpñbÞ×´) jÎ?û,;¦˜ˆˆHÎ¥O8Ž7¶ÍŸ;Bbâµ·W’"×õÆðÐCfyí^½À²¹q11°l™™Þ".ÎTYî$%)€¿¿™Ößßd¿ÿþ·b"""7níÚ´Ž´‡ùñ[²dÖ *I‘«^=m6Ú—^2œDä:Ž7Ÿ¾Ù-+RÈÔ¯ïÙœcYpªÄÄ(I‘[0h´nmzk?ó ¤¤(&"×±±pæÌíýVò#ùÔ”)fVóR¥Ì„n.¬[§$Enå`ú˜XÉ’°~=¼ù¦b"rMkÛ·ëS8·’‘\aº œ:eæKqUUr²P¡’¹®¨¨´>)o½¥ÙhE®)}mÛf3s€ßŽ™s+ùÉCé«*9]¨PIŠ\W—.¦¹G³ÑŠÜÀ§ð£Â˜1f²¡ï¾óÜ.'Í7ññæññfÉr›íÎþ¹Eé«*9Y¨PIŠäØGAùòf6Ú_TW?.m6 õÜöøñ´Y¯6o†5 gÏkW_4HDIJavèùltq:¡o_ϵDäZŸ>fçåË¡LSeiÙÚ·‡Q£Ò¶[¸Ðóvׯ¾üáæv$¢$¥0ÚµËs nW¢ò‡?À‘#ŠHŽU¯n²þ¹sÍ›¨Q#HJJKTæÎõ%´q£YëÞU}qužMJ‚/¾0‹¢üøcÚ$¢$¥°©R%í32½4Ÿ¹_|¡u~Dräða“x”(aÆöÇÆš7ÒæÍ0p é0ëp˜m-ËôGyî9xøaÓ\tß}&¹i×öìÑ£MEæNOB!âå|‚‚«lY˜8úõK[Z{øpÓ¯oÃèѦO‡  2RñÉV°dIηOI1o]¶m3+WªUðå—¦‰gÝ:“ hH&ª¤p½{þ}°t©9>Ö¬·ß6Õè9sTU¹®çž3U”Û¡D óËÁ&¡Q’"wZٲм¹9ðõ…aÃL5¥n]³xTСÃë«b³ÙøîêZûöíÃf³¯ƒ'Þ¡sg³jç“Oº^°7ú7§O>iî§sgÅTDIŠ\K¦Y=cUå?ÿ¹ýU•˜˜l6[¦¿¶mÛê@Hþ O?ug¯ìØíf⢯¿6½…‡+–"JR$'²ªªüéO¹SUiÛ¶-Gõøûïÿ«ƒ w^Vs–XìØû›™=6"Âô9wÞ{ÏÌ$›ÑѦzÒ¥‹â,¢$EnF^TUüýý)]º´Ç_É’%³Ý~ÇŽ4lØ¢E‹R½zu–-[æñÿåË—S¿~}üýý)S¦ ¯¾ú*©©©|ÿý÷”(QçÕ1ØñññØl6†ê¾}¿~ýèÚµ«¾Ïiï.„{îÒ¥Íÿw쀡Caÿ~3 yÎxá3rÇ5:çZêÖUõDDIŠäVUå‰'îL_•¡C‡òÒK/±iÓ&6lH‡8}ú4‡æ±Ç£^½zlÞ¼™ñãÇ3yòdþþ÷¿дiS.\¸À¦M›Ü MXXË—/wßÿ²eËhÖ¬™|ac&O;sÆ$&ÃâÅi“ Y–éC²?ìÝ ÿûŸéCR´¨çý|ÿ}Ú°ãk3w%)’U•¹sMUåóÏo­ª2gΊ/îñ÷æ›of»ýÀyê©§¸ÿþû?~>ÞãoÀ€Ùnß AƒtÏÇ—ºuë²}ûv¶oßNƒ °¥ûBhÔ¨‰‰‰ºº’bóæÍY¶l–e±råJ:vìH5XµjK—.%""‚ªU«ê`6õë{&$ švÍ6mr¾jqÆið]c‡7§›ž}Ö4ýóŸŠ¿ˆ’¹]ªW¿}U•ÀÀ@î¹ç¿ÐŒ µ]‡+)±,Ë#Aq]—~›æÍ›³råJ6oތժU£Y³f,_¾\M=…Ù”)™’³dÞ<3ÂÇõìÐÁtŽ9ÒœvèVUññ1MGÛ·ÃG™L?ãz"¢$EnUåðáÜ{Ü5kָϧ¦¦²aÃwå£Zµj¬^½Ú˜¬^½š   ¢¢¢€´~)cÇŽ¥Y³fØl6š5kƲeË”¤f·:‰Zjª™ßéÌzhqx¸¹üõ׿ÿN§yœR¥Ì‚Z~~p÷Ýpô¨Ž…ˆ’ñ–ªJrr2ÇŽóø;uêT¶ÛüñÇÌœ9“;v0`ÀΞ=K¯^½èß¿?dРAìØ±ƒY³fñúë¯3dÈ|®Îaáê—2uêTwß“¦M›²qãFõG‘›wé’I2\³e7´¸K—´ à*W†‹MUeÆ xé%óæ™?_ñ¹Öd…@n¦ªÒ¡ƒ©¦¬_oN§O7ëE]܅ϤIÔY³Ÿ~0mñUª°`ÁÊ”)ãq÷Ýw;vìÈò±þñðÎ;ï°iÓ&*W®Ì¬Y³  **Šyóæ1tèP|ðABCCéÝ»7¯½öšÇ}´hÑ‚7º’’%KR­Z5Ž9Âý÷߯*7.(ȼðs2üØUUq-žå2hé Ó¶-ôé“¶š²ˆ(I‘ÛWUy÷]xýuÓDÿv•Ïøðr||lD:-l«W›I¯&OfÊ”)L¹FgÄôÍ6+Vt_¾Ö<&Íš5cÆŒµìÚeò ×´ÿé½ûûî»×iº}¹e9IP®·}:ðÛof$ÑŠf­"E[%)r»ª*¯¾jú¦ ﺋ¶ôÁ'8Àà  WoV:s¥ü=ØíævO³ºîzÛ|ú)ôíkšü}|L%§wïÜÛßC‡`Ë–0x*UÒñ—Û (~þÙ¼+T€åËáÞ{%)r»T¯ÿk÷)ÖVÛÕ¬$ HµlüÐ{2!÷JÚN§©šÿë_¦bPù+^<í|N.d½,ËäÉз¯/Ng#^ÝÊõ„È•]«J$ÈĉðÕWfxt… æàׯŸ6òHDIŠÈÍó9°ËfeJRL¢bQ«Ä>(oF8æ4ýùkÞˆ-[nm?l6 ôLbŠ3ÐÈv5!²ñì³f´SXøû›mŠI;Ÿñ4§ÿ+RÄ<“Ì*‘’¯lüñ0n¬\i.ÇÆš_ê\+JR¼Û¸qã3f G¥zõêŒ;–&Mšèèy“г]¾ÞÇn£ísi{…Ë2_Ô— vmÏé&||L¿?$&Â… ž¯K91ÑÜ—e™ó‰‰×!jYæû$WÞ”¾f?3V‰Þ|ŠKkúòó»=çþfÍòŲ1|¸E׮дiÖÛæäòµ¶ùòK80ï’¯|ç—_<ü¢E¦4¨ªŠ(IñN_ý5ƒfܸq4jÔˆ &Ю];¶mÛFùòåu½E¯^ØFÆr×®~™6˺éo"›Íô?ÉØï°dIóׯ_ÚÀ‰ ÌZC7òÌÈÒ¬’˜}ûÌkúaÖ6ôêe¢+W 99ëÓœ\—±Z”>AIoÿþÜ<€®IòlL›Ó¦åþKÆé4ÇïÑGUQq«_߬+äzQ¤¦š5†ââTU%)Þèý÷ß§wïÞôéÓ€±cDzpáBÆÏ( ÛóUªÀäÉØz÷Ʋٰœ6›IP&O6«ÊÞf½{›/¸Ý»ÍÝßÊÍfú£dýcÕßúõ³p8lØí&Øn[Àန”´Äeß>xä‘ÌU¢o¿…ÐP³­«¹,5Õóòžß·fÍÊüœ7†%<'ãmoäòµö}÷n%)nS¦˜ddÝ:³(aJJZ Ö­S|DIŠ7¹rå 6làÕW_õ¸>::šÕ«Wëèy›˜hÜçĉ]³†2<‚½oß\IP\Ê–Í›/¸Þ½¡eËT¾üò'ž~úa*Uò»m÷íª¹Ö³»ë®¬«D:Ýþý:tÈ,æ›>!²Ûá¿ÿ½}qu5ÙíÛg®d|¬›}y$''“œœì¾œpu¥á””R\_îW¹.g¼Þ넆ÂìÙ&6O‘BÍš§‰ˆHÉõ]êÑZ¶„={lT®lQ¶lî„1"Æ·Ñ¿¿Ý]%7ÎAD„uÛ¯|ù¬k½?FÅÈ‘#3]K@@@–·‰‹‹Ë7¯7ÿ®]©uò$%víâ\•*lêÚ•äyóòÝû&?ż Éoq¿xñb–×Û,ëF—‰Ë;GŽ!**ŠÕ«W{¬ˆûÖ[oñÅ_d9Séˆ#²üàš6mZ¶\"…Ý©SE9z42e’ »ì5uñâEºuëÆùóç ¾î’råÊqêÔ©LÛ¦¤¤—>q–<ù!¦˜+î9•@XXX¦÷ºWWR°Û홪&'NœÈT]q6lC† ÉôÁéƒK/$í›öË»÷ÍU ͲÒàï¿¿¦ëýüü²Ý‡kýOr‡b®¸çôùfÅ«“”"EŠP§NâââxòÉ'Ý×ÇÅÅѱcÇÛöÁ¥’öMûåû¦/7‘ÂÍëG÷ 2„îÝ»S·n]4hÀĉ9pàÏ=÷\ŽnïjͺÖ/²;õËõâÅ‹$$$È_åqßtÌòžë}›“Vék½× ò±ÓkJ Bܳ{¯{}’ò‡?üÓ§OóÆopôèQjÔ¨Á¼yó¨P¡BŽnáÂÊ•+§W¯H>uáÂBBBô^)dïu¯î8{;8NŽ9BPP¶lfD½SYc¹rå8xð Wõ•Ѿé˜yÓ¾Y–Å… ˆŒŒÄ'«E•rø^/ÈÇN¯))qÏî½^à×îñññ¡¬Ï\`ßÀußtÌòÖõ*(7ò^/ÈÇN¯)ÉïqÏê½î£C)"""ÞHIŠˆˆˆx%ûˆ#F( w(øv;Í›7Ç××Wû¦ýÒ¾iÿsQÜ3(ðgEDD$Rsˆˆˆ(IQ’""""JRDDDD”¤äs£F¢^½zN§NعsgÜO›ÍÆàÁƒ Äþ>|˜gžy†R¥JÀC=Ć òõ>¥¦¦òÚk¯Q©R%Š+ÆÝwßÍo¼ÓéÔUD¼‚Æ…å±åË—3`ÀêÕ«Gjj*ýë_‰ŽŽfÛ¶mˆ}\·n'Nä(ûsöìY5jD‹-˜?>áááìÙ³‡%Jäëýzçwø÷¿ÿÍçŸNõêÕY¿~=={ö$$$„^xAoV¹ã4ù;yò$ááá,_¾œ¦M›æûýILL¤víÚŒ7Ž¿ÿýï<ôÐCŒ;6_ïÓ«¯¾Ê?üÀÊ•+ Ôk¯}ûöDDD0yòd÷uO=õ|ñÅzsŠÈ§æž;ìüù󄆆ˆý0`?þ8­[·.0ÇhöìÙÔ­[—Î;N­Zµ˜4iR¾ß¯Æ³xñb~ýõW6oÞ̪U«xì±ÇôƯ æž;Ȳ,† BãÆ©Q£F¾ßŸ¯¾úŠ 6°~ýúuœ~ûí7ÆÏ!CøË_þÂÚµkyþùçñ÷÷§Gùv¿^yåΟ?OÕªU±Ûí8Þzë-ºvíª7§ˆ(I)ìÈÏ?ÿ̪U«òý¾?ذa'Nœ N:îë+V¬à£>"99»Ýž/÷­L™2T«VÍãºû￟o¿ý6_³¡C‡òꫯòÇ?þ€š5k²ÿ~F¥$ED”¤F–e1hÐ fΜɲe˨T©RدV­Z±eËëzöìIÕªUyå•Wòm‚ШQ£LÃÄýõW*T¨¯ÙÅ‹ñññì–f·Û5YD”¤V `Ú´iÌš5‹   Ž;@HHÅŠË·û”©_M`` ¥J•Ê÷ým^|ñE6lÈÛo¿M—.]X»v-'Ndâĉùz¿žxâ Þzë-Ê—/OõêÕÙ´iï¿ÿ>½zõÒUD¼‚† çuÀm¶,¯ÿì³Ïˆ‰‰)PûÚ¼yó1`Μ9 6Œ]»vQ©R%† ³Ï>›¯÷éÂ… üíocæÌ™œ8q‚ÈÈHºvíÊðáÃ)R¤ˆÞ¬"¢$EDDD$+š'EDDD”¤ˆˆˆˆ(I%)""""JRDDDDIŠˆˆˆˆ’%)"""¢$EDDDDIŠ111têÔÉãºo¾ù†¢E‹2zôhHD¤ÐƒR |òÉ' 0€?þ˜>}ú( ""€*)’ï=š2mÚ4%(""ˆ*)’¯½úê«|üñÇÌ™3‡Ö­[+ ""JRDî¼ùóç3kÖ,/^LË–-‘FÍ=’o=ðÀT¬X‘áÇsáÂDDDIŠˆwˆŠŠbùòå=z”¶mÛ*QQ’"â=Ê—/ÏòåË9qâÑÑÑ$$$((""JRD¼CÙ²eY¶l§OŸ&::šóçÏ+(""JRD¼ƒ«éçܹs´iÓ†sçÎ)(""ùœÍ²,Kao£JŠˆˆˆ(IÉ©ÿÊ% NJæµIEND®B`‚pyclustering-0.10.1.2/docs/img/ema_old_faithful_clustering.png000077500000000000000000000640561375753423500244500ustar00rootroot00000000000000‰PNG  IHDRÂä|ÐNsBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+g³IDATx^í½ ˜\Åy¨ýõ¬ÒhG ZЂÐÆŽ ă°!Éýs“8qðOLÌ&cLˆc ä`ߨþƒ1¶Á!1d!¶“ç>÷fŒ$6` ±H€‹$B -#ÍÚ½§º¦kΜ^§÷þÞç9s朮³uŸúê«o©ŠÅ bÇŽ2}úôÄ–¢(ÕÊöíÛå¸ãŽKlU>*{¥6p²'RÉhoo—±cÇ…FØ[>º»»å±Ç“‹.ºHš››{ëƒz}vý͇öìëýû÷˘1c{+•=•ƒÊýÍó!,{"• ñ!¾R*úÃ?,—\rI]þèõøìú›íÙ+­g‹ÊžÊAeþæù®Ã ‰ýŠ¢(Š¢(E• EQEQŠ‚*Š¢(Š¢U2EQE) ªd(J5°k—ÈÅ‹Œo×l+Š¢™¡ŠU2¥¸ür‘Õ«Eöí³k¶EQŠÌPE*ŠR <û¬Ho¯ýŸõºuöEQ”"2TÑ£J†¢Tg%ÒØhÿg½d‰ý_Q¥ˆ Uô¨’¡(ÕÀˆ,_n£¬ÙVE)2C=ªd(J5pì±"<"²g]³­(ŠRd†*zTÉP”"¢I!Š¢”ƒJ‘=ªd(JѤEQÊA¥ÈU2¥ˆhRˆ¢(å Rd*JÕP æ¿\ïA“B¥úQÙ“?ªd(UC%˜ÿr½M Q”êGeOþ¨’¡T •`þËõ4)DQª•=ù£J†R5Òü—¯ùSÝŠR¨ìÉU2”ª¡æ¿|ÍŸ•b‚T¥t[öôôˆ:d­ï¼#²u«È¦M"/½$òâ‹"7ŠÜx£ÈÒ¥"cÇÚõ—¿,òÊ+"¯¿.òÖ[ö8ÎyäˆH<ž¸X J†R5äcþ£²=*ÒÞ.òþû";vˆlÛ&²fÍ@ÓãÚµ"o¿m?£²rƒEº»mG¥˜ E)…ª÷(È_ö ‹P"^}ÕÊ íÛ­œz÷]+‹X³tvŠÜt“È?þ£È×¾f·ùœ²,÷æ›V9ùõ¯íy†ìëë³×+ªd(5ÊÄÖôHE}í5ÛذAäå—­¶ï”*ã‰'š—?ñö³>á»ß-î/¼¬°o¼a+õÞ½"]]öXEQ”T —¶JÂæÍV™X° éö@öÌ™c•¬Î2 B–a™øà+Û°tttØ5Û|¶s§=KÇ¡¨ð?ûYWìþy‘-[¬ì*µÂ¡J†R•P?ö1‘cŽ9ï<‘ÿüO[‰P¨t®@EcŸQQÐö/»Ldñb‘‘#íšm*'ŸQ)©ìTz*;çà\ü’B9®ƒ©$ó¤¢(Å#SLÖOsd J²Ä—#ÈšE‹’²çª«lÃ?b„ȤI"Ó§[ŃŽŸyóDæÎµûf϶k¶ùlþ|ûùñÇÛ㸧æf«Œ¼÷ž•a,Né@vÑqâ~°ð–U2”ª†JÄïÿ¾U,ÐòŸzJä+_±•늂³8P‘šš¬sÊ‘™3m…<õT‘{ïµ>Ñûî9í4»ßUV*;•è9 H¨˜TX”îJË!BÅ¥s?Ϊ(JíSœqÖ ' ØFnð?¶)‡ úîwE}TäþûEÎ"rõÕ"¿ü¥ýÜ8ëÖ ›TE©NHõSI造XÐpÓX¯…¢QÇ¥<ºõV+ò‘=aÜqN–qÝtÛî|(ÈHd¡Xf‘«Ü7Ùb¸PbqCgg§°88`zlÓÆ³GFØ[>ºM—põêÕ²|ùrÓë4ÝÎ:¢Ÿâ;ïôÈ£®•3ÎX*‡5¦I4myx^×;ïl”Í›c²`A\n¹¥7°0¤â†eݺ˜éyÄŒ`ˆA—»îê°_„ÀŠŸ§"|>î WN__Ì(?ñ BólóùÙgÇå?þ£7è½d¢¿9ux‚‘$íF’TBN…ʞʥ^Ÿ=ÕsSŸiiÄ︣Q6mŠ™ÎN\>ó™Þ ÑF±3fp§²wHªíTçË‚‹—ߦ¦yã'åw÷#“=’±råJ¹ýöÛE’<ôÐCFXi©(% ³³Á¼ôÃMen2 ÁT”f9|ؾèmmÝF¹è2• ¿Ë[o=Çœ7YiÚÚºŒ xfÐ~‡û<ƒ³B"ÉÀmîÿŽ;ž6ÏÐm*à‘ ò“#/½ôÒŠW2Tö(•Œk6 g«éå7öË%dˆaÃzeĈ.><µRP~Ù“þ|ÝÝÈÝaF)iq㎚ò=FF5JSRùÏ…°ìQKF…SÏŽ…ß Ù+WÚ¬Y}rÎ9/ÈÅÏ7/|Ó ÞA®\{m£lØ@Åc‰Ëé§Çå?(MoËÆ¢EqYµÊöx°f`BýÂì9¸Öý÷÷öçÞâ7WKFaPÙSÏŽ;óÊ+m}<ãŒ>ùÔ§VË|XvïnÜÔezüd’á¦ÅjÁ‚ å”=QçÃz±j••³ Z+0n]dð¾}½²mÛ¹è¢ÓdæÌ¦¼Æ‰´d$>ë‡BcÆŒ©ÅËþðÃË%—\R—½–ŸÊ@€¾À+llJ ó¼yûäÁGcèÏ͹ׯOlˆè&»„ GGšà'„\'$rÛm6À3î8¾HGÃ÷y÷ÝQÛqY8?.ׯ8*ñî^‰õõÊ” =rÓ7FÉÚç[úÁòwÊ#?=hÝòðc é7¯´:œ-*{*‡zzvRQ>Ôêã 'ì•ÿxŒ9Òl 랥s@cÌk™KÀfùdÝŸÏÝ€`Ä”0z(åá½÷ºåñÇ7Ê…ž"“'7Y/ÍçB¸«’QáÔê³ó։͂¯“õWX¥Ã™ï‰'bQ2‚2¯s?æõR` ƒbA[bÃÓüvÆ” ÈHÙÝ$‡Ìó^û—ÇËÁޤyfü˜nÙc*·ÄbÒm >µfœ{á…ÒŒT£–çøÛ«’QTöÔdzÓ÷åÀ½ù·ËwÐlþ·U0_ï]QeO¤»Ÿž~óu2{ö™:µ9ø^^Å:’-á:œƒ>¦(…ó#)^D4ÓK ­;µ—éÓMÏ> hôhåá(ê(üsfÏLÇ„ ®÷ù¸\ðQ,]²÷å÷‚t—½Ïn‘ë¯í‘ þŸrýW†ËÞ­Ø1rÅx@4¨;¤é·dúÑ-2åÈ[rüøÒsú}\Ú6ÈÅWL‘—þküöŠ™ò;_½J~ûòce×Fs Òk0÷ )ŠRPèÑ“æäVÔ‰;‚¾)ë.õÓ§,²'âz¹Ü‡#ÕýЊ+æÛß^"wßÝdññ}|Gù¢J†RRèä3¦þM‚¡R§@E¾ãkºC³ÆøÉO¾’8*L†˜ýÐÊY³ L†œÛÅv`UÈtLIyï=¹ýËözb²vC³Üþ­áqû÷&ÈÚ—Ú¤ýP“Y”Ûï›’tàbÍÀJN\Ó%;ûùúŠrÒœCÒhZp™¾FYýÒ9ÿŽÈã/L’GÚäñ ÇÈå_™l¥,ŒôƒF¦(JAÀz[ÉÆ ûâÅqùƒ?x%H“OÕƒ/‰ìñHu½\îÑê~pëëAPéÆ1ùë¿¶AŒ³¤èæ‹*JÉ@ÁÀ‚A›MÇœ—ŸJãP`šÃ7ˆéŽ@%21Òpp6k¶SáÎíFñ„ÈczÌ5©±ïí´Iä¨ó‰A:^ÞÒ,½}i™cÍúå7Œâ°g¼üöH³m«Ro¼A^~ï;"Ý Ó‰žâÆ%©eºESg4ËnÙ!ÇáNqçl½[’ç2ëuoy í(XF¸=hÔ¢±hÊÒØ`c,°@,šmÇ^4¯«ß"Ñ¿? Mí;iΑÀ–ŒÜÔܳæsâα2ó[`ÍÈGäÄ4»¤²)׳Ӧñb9Øæ%Ë Ì’¹*D9?õÔÓrî¹ç˜²C|n^qn„›`áÿDFȺXÚ½mƘ öŸß\o»6,NÕ/2½}F·ÙÙ$£7鈼õúZùƒßY,Íá/ŠnR‰n¦ |MhvIaPÙS½²Çe‚y…¨þT!” 7¯G¸ŠTö¤ UÙAc_άˆzv §|_d™;‡µ'š]¢dÅYg%+kÆëÏLB ¨Ø²U0 J&³ÃÍb¶Ëôþ‘VÔ4óÙ¢iûº:æi„úŽõ¢D à:™ql—¹í˜¼»§Ym‘ÝD|Q4¼8PÉ4Ù¿?±SQj‡BȪ ýÑP"‡Ø&LŠJKXÅ1WG)Aä ˉcÏG䨒¡DòÀ"Ë—Û^k¶sm!&J‹l ¼¤R1|.ëT¾JöãËLN0dã+ön2] b)p-P8‹m‰ml~Ôœ©Sä¶ë÷åíêÈ•½írý·¦ËŸ¬Ù~}{‹\xí;/#nBÐ~IÃû T‚µkãA„3HK—Æ‚hè0~9#RÌbÊ7˜ò ÊÝ×¼lbì¤8iœ±N´™uc)L)ƒA±XûÒ!3%¸O£Ôlzs˜ì?HwÆ>ÃØQ½òÀÊ×eÝs[åâΔi“â2kj(¬ k ¶^ü#PwIaPÙSÏN 9îD@&÷ˆOn²g`ƒËyQ¢Ê—ÿ~Ý}bÝñ-dØ?úh´«9Îw9gŽu›ð]¦BÝ%JÑáEÆ;ÁKI寇—­‚6-ËöàYJËJ¸B^~±¯¿œm¤Mù µÔ¨ÞÔzü“ÌÅ1¡`¥f”IÁîk` ì0iïW0 lOGtU\öìo’½íMr´Ó}nàÙéŽñl¹Dª)JàÍÈ!Ö“'gçÉ({Ør‰l§*_nüûu÷it€„·}߀?|¿¹ J†’Ù¤—Á‹Èes˜FY s˜$þ¥{B<v½íÛeÑÌä`V®<)¦‹ŽïH*#FÚì C”»"~ùwÎ+î˜!Ë.Ÿo–ƒíLLJ!µu@ü‡Ù3ŠšŸ|¶‰Ï=âˆì?Ô(ÝFŸØ¹ÇëE¢`JFõ¬•ú&ÙsäH2Uƒ÷†¿lH){Bøñ¶SÅUD¹+Òá—g,¦\X¶Ì.lg:>LTünŸð¶¢E1œ ªd(9‘)½Œ—°>§=d,ª!ÃYo½iíŸïÉÂÉß}Wn»äYY:g·ŒÞ%cGö˜†™¸Š¹í³F‰Hv¿ýGSw…™sD°¿üúÍm²qK›ô˜ÞMOoC°éø0Q©®÷~õíÀE35Û0ª …ħZ19ãw<¬]5‹rOäâ²àÒ¸`Ðj’Ö ‡ÍüÕ6ÐÍâÜ/IE#·å¢ÉÅ…ÒÒ—xg—ô8,Ýã&Y‡ó´i‰O¥:(€è {h¯ºÊ*È_Á€(WAØeE ðJº=‹ï²ð¯ ÷÷ÈšíT¸{$hÕY ¢¬„`‘Åâߣ{–(EÃ~^¶£¾—lpcòì.Ó$[tÄÏ § ÏN7‚Zî`›Z›TdÿáÅÊÁðDuáYsÜè^¹àB—JÖü1mÝòŸ_}Ün`ë¤æ°öC—ôôöÈóÏ?/§žzªQ(R÷Ú±ÐX;h̲ †ƒôP²7¢Eºã!êpɤ"SyÿÙ»»›ä­írüä#2ãÔñ2ý¬)™g(2舟…AeOaž½¢gìŸý̦©ú ÐS§!uÐÐf;ùX¶¤E]ËJX>†3ðáã£Hw<äúœ™Ê§zv7ö#7ÏŸo-G©Ð?ë™Ì<„pðqÛX2H~ˆí”áûí¤d‹f%{ù±¾`2²@-Ü!FÁ§¡`äB”;"j€«T¤ryd{JØ‚áˆrš¨kÐhû„·}üãS‘îxÈõ9s-ïÀÚâúƒ¬sA•Œz"]jH–N;ÇËÆšmT÷î=íÒ½u[0HVóAÓE1Ý–Û~k}à \# Êõ—·Ëõ}’\pÝ‚Œ±pàð0¹á;3ÓÆ.D¹#Њ1&œ¢0sJg—Á(K?mã.ˆ×àÒCO›ß!#†÷.¬#‡÷IC,©h0I™ýpLÅõŸÜ5èá²lóùi'Z·ßcWO,òÙ¤³Kâ%cD›ÄZ›%6mê•2E)=òïÿnû(TŒï~7õ8çšîzœ?êÙ|(CL÷¾¿lPwI…SÑÏΛ‡Ís÷nÙüZ£¼³­Wvmï’ùãwÛÏG™7r”y’€F–bèÁÓ “å.ƒ+n;F^Ù>5«òaÂ×e”ŽäDd>q9ûäçõµŠÆÀëçò©Ê¦;Gà.Ùðk9uÒ$éék–7ûfÉñ‹GÈô%“ƒô¼lPwIaPÙSÏŽ¨qz‘IB' ¯a?4²Ä ó@ž™,(p|úÓŒrpŒ)oêg†òaÂ×B!â¾£8ûìçõuø×Ïå9R•MwŽ(w ã¨KP)ò‡y`Ò¡îeèàaÞä_´‘Wï¿/}ÛvHß®÷Í›Ûc³È%o$×ÕÈ5ó­]ãs*ï¾ÖÀ‰È|Ÿ×?Öã_?|îðñ>©Êf:G+‰ï¦Â÷ì9¬Uš¦N zŠR01ï¾k{Ó¹(k:çöí£M¹DýÌ¢¼OøZ¦­MIø¼þ±ÿúás‡÷IU6—s€Ñ‰S˜rE• %;0x¡Ž3ûÐæÍVµeþ_¶ÍzßÑ6¹ùÿž%+î_"×ß·Höjä* µ“^;°Î»0ëØ½ýå±(0(çÁõáλâ37ˆ»ÆúMôÕöC(öØs·=Á÷1o:)¨Éë÷Á~® Ô–&|.W6m\ƃ҈D5ݵ£2L&£¥¡(s0(J¥ƒØaAÜÓµûD¹Âûè…ÓHëL±Ó§0å\½µ® Î㊠„Å]ƒºH[õ• \ éÜ áûðSPܯK— §¸F•w„?sÛ¹Äeà*¡O‰;†¬’tŸ©P%CIª.©#¨»[·Úÿ±^ð?µ‰ù3æÎ•›ÿåTÙ°e”2ŠnÒ2Ã©š´µ¸¢b¢øôEÏÈ’EƒØ Å”ó’êÎ˨ŸLVæ®qÝ_Îà!Æ‚ø k5°ûl£7{_;è>\±”ã~ÙÏ5œ¢ŸÐæÂŸ%¶¹fäwr±o¯ôkºlGÇN–ᣭ5(Ÿ ®(Õ â+†=Lõa‹^TZfxà ±díÇ.DñÉO¾Œøé®EŠ)çA©pçE©`q׸îºnbðø9«;ñ™îƒrÜ/p¨så ×Ìö»àyP’xŽ|cÎUÉP¢!Ue—µå yª|Fv3êLšLÖõâëɼÀ™ÿÃ.FÈ$î Óˆ›ŽÑ#ŽÊ]_|[F GÉHž×G²¡güÌua±kuäöµs탯#w†ïcË6Á“çÙÖÜ/û^×®mùhÂçre#GE’a!j&]£FJ|ì1ÒÑ8*°` lrÍOW”jçw¬Þ7IT˜N”ù?¼ƒ+q™FÜtŒÕŒøé+öœ…Âׇ}n¬ ŸÁ¶qGa H4|ܧÏÌýFð áò>áÏÜ6×Ìæ»àÞy^îù“é;K…*Ê@°Ça¥`x=j86Bœ¡¼iÄZÌ™c-žl gþÇ5ùßw ­fïgYdÂe—0o‡µ>˜[0ç#¥Ô×îO~F†ˆÛfMYëŠpûÀÞKª{ ¼u¯@²¬ÿ<þ5fM<ê¨#| nœÈQH‰e!ïtâDé5šEÇÈI`Áš/TQª” âÊY¨©£Ìÿþ>ªT {vÝüç ,ß{ÅvÕ:LÆ<Ü4ª³fIOcƒ<öدeæÌÓM¢1aPŸ\PKFaPÙSžg'ü‹00¬¤«"b\Ï|Ó¦˜,\h{÷á8¨2I €©Ÿ–Œð17ÝÔ)_úRÒ’á“éÜç/½ÄqVÔ.ZDëÆïco½µ1ØÈžSâò…/ôÊç>—´d²'aE‰zb6ðp§z6øØÇž/“%ã™gÖšï|™éÜ4™< #ž‹¾iÉH|Ö…t@œÊ  ÏÎO£†rÁ[Ï›G­àlaÔ–L61.Ì™ZDx2ÑC†Ý4ÉÛ;[dêª2yëÓÒÐ×+ñ†F9°øC²öê¿ ²M%Nl ?à’X—¹áêß]ösùßk>¸EücÂeÉÎ xÒáN¥¢rQŽ‘=[šâî{zæž™²`'Ccþ“¾¸;’×rǹó0âçÝ?96å³A0âè7fA«Ä‰0*éܶwM—ÁH¤(ÒMbøpÓèvË¿üËF9ï¼SLƒÛøVs ú¬´:œ-*{*‡r=»içä…¬…»+FÑÓOT²'0– J]bÛW ÂÇ,YÒgæ_™†øC²ysÀc2݃ÿ¹ƒrŒ²ÉAþ=pOÏ„ŒŒhjª@ ª}R= ×ãú©ž ܈£|—(œòFÁ`\ÿú¯ëMçæL³4¢iöìćY®ÃªdT8yvÞxº,æ|ÁÛ†å‚ÿiÜpvf; =Fïà­M̰Ãe6n.‹¯>GZ:’¹\=#ÇÊÆ¦754i{úzúÿëÊŠœ -ª¬?ÁXøsG¸D•%í•Æ£ˆ:G^0[ß#ßýèQ"ÇM·¿…aûönùÅ/6ÊïýÞ)2mZsÜ•+ªd•=¥vú@ŒêI6âK¤=ýdS&Ìàc°üwäi™ÎþܑͽÆãÁ-²%›g*ííÝòoÿ¶Q>þñSÌ÷n;8¹þôá:œ§—K© èâÌØÉb ¢‡hB²Eœ‚UÕ˜·Ÿ5ÛaxëP«5Û Ø¤ß1g±ôÅl,¸L ©}ÌûÆŸÈi—Ÿ,óî¼<ØX°€8‹Ø‡¾3S\¶k¬Y: e©˜ç_sBµqþ5ó‚íX0÷$Ëq0vŸ+ vrw/ö³äÿdºp-îà æ_Ûßï²MÂÛ{ß:h¥Ë1ãlÚÈ”©ý ¦O>3¦3¨ÜSSϯ(5ŠÅÅÛ^øïÿ¾Í”§ÓBÏÞ‘Fôô“ª ¢ŒÞü²evá'Þüc\ܱd—¸2N4úÙ&” dÏù6kƒµ•=‰ (—ê^à ܽ„áÚ\ƒûpƒ‚ù×ö÷;ÞŽé¬'XZ[û‚ï}Ú´ü3J|Ô’QáäõìX(¨µ¸FP4È¡çL­å÷¤&GÙßy 3Ù#yKÓØ‰{xeÃ!™|Ï×dôÛ/ÉÑ9‹äík1dî·®–Ñ/<å9&Ì»vò¹òú—~(ÎA%uî ç¢ÀBí»Aˆ“` ‹® › ‚R‘3ú@~ú7¹1¸î'¾<[¦fÛ²§ÌcÂ4ëVa„Î×¶µøœ5÷…2rÐì»eüýQÛLw÷ oØ® Ý4b` |íDÔ76v˶mOËýÑ9FÉÈï}WKFaPÙSšgGÁX½:)zN>Yäæ›mЦ#ƒè HUÑvM¸yCücÙsÀÆqã°ti,(ã‹F N‚~y]¸6P(X»ìŸþ4ú^?ñ {Ç)§X5÷¯½6ðsàûA!cÆÝ„÷GmG‰t Æž=Ýfý+ùÍßü,^\Ù“ÐÛ”š€Ø ÎÂr˪,Ê5ç]ãT~Þl÷Ö²f; 5…·»ëPÍiiŽË¸™cå­/ß'ÿçæõòäÿ8P0`Ä/Í´ƒÿG¼ñRð?¿œ µ×* æ6Le§±Ö¶A‡X0H—_ÖžÑnå¶YS.¬`ûlÏ#Yö­ÉAì+ü9pƒ¼?jûå‰Äs‚= PÉX[µµõþPE©ž}ÖÔ Oô8W‰OѪL”(sûücyâꪑ!®Œ/EÀ–MìHÀ¶_Ù“â^ÃV·ÞJÞ ±áÏócí _'¼?j;ê{F+ /ŠHjnîË9Ð<ªdÔDçc_d-\!X1P.ˆ» 7ÈàY´\©æEv ú£îë({^LØ-ÃZã2eBWàÚØ—pwž}RÐßwð¿s¥øø®ÖÎ͵ßßgÏh?óìreSu^Ÿl®‘îÚŒ.êo/šc~/~oà ~2z,TrtÀ‰;Ÿ(JísÖY¦n$D–úC™bÐs!J”¥Ú‡X»2v¿ý߉FŸƒm”£pÙTD×'›k8Âû£¶£îŨŠÅ…Ù“fH¤œQ%£šáí × å‚·„å×o !ÄV5Ml‹ØÓx3](sð23 æÈ¶¸ŒÝ#ïÐÄ2¼uõrpáRékl –ƒ Î ö9ˆÏÀ¥ò³-§Ê…±Çe¼ì‘´­•UŸ´Ö²6Âó}¸}£Gô.‘Qm=Áè£3ÍõmÃoÓèꉮâ#ˆŸXrÙüþ‘7ýsàÚxñõa6v"¡‘=2|Ý+|X/žÓdˆ„¯Í¶ÛÜç¢CòÍË^”QúÌmX×ÉõŸ7çá÷IÀÏÆOÆOÅWÏtʇ·ÈoÿvcÐÛÁ”Œ¢(µÊØØÞÿSO¹öÚÌ}¢\@”1Wn›:P¼áºÀ%²q£³ØôPöA”htûèÇQqME¶``æüˆfžqÉ’äÈ›þ98#4פ<ð8&±é—aå_›m·ßÝç7¿i?ã™X»çqàÖ!\¥ùCz__CAeÆdT8‘Ïδx´LØ·ˆ¿àÄÞÅ›„ù25©Ìl¯Yvík–í»šåHgƒÌœÜX8RÄl¼ô+‰‘új¶©ë.–¸l Çnp&,4ü›ÞæM fc5ÿÍñså],HTš«;.%T­÷ß—ëï[(k·NLžw™õó‚û©àül¨1cºeÙ²}Fà1¬8¾a‘åËEyÄ“ “QTö”îÙ‰ Øt¬Ô‰RA㛌¹HÈ /&#[žÇBý¥Áß´iàj(?nÿ÷så¹.û£Ò\Ýq™Hu^@<‘ÅC_•Î;{v·|èC…•=jɨ&/FýuS­ã¡FbgGÅr#¿ 8îØî 1>nRw0>Åö]-A`h*‚˜ £`€+Ŷ‹ÛÈ–pì±f?ñÞÙÛÿ8WìÚ‹„ZÍot䈼üî1Ï›ð‹F)üŒ°e˸ ’§Z·.øWQj¼¾4|ô›rf¨ Œ¹põ.YW³%»l³ŸøÛ?Ε‡¨ë‡Ï“ŽTçBö诒E‚µ¯:ýÔBËU2ª€&æ!ê•Wì›ÁÄe¤!ïˆRrAë„ÚYAðÂΞÖÌí1}rWñ±í½éî1Ï”pœòÙëaÛ_“¸9€>ô¯C)°ácüm>gY[/â»í™\ª«ÝJ^…ø GªØ »vÇ€u{¤„ÉÎÐ :ÊÞáÓ$Ô2w" ZýÃ…fEï ˜7ïósÚc¸oôHu›(µ J ŠF1 'Î5â§yRÇ’$d€“uŒ¿Íç,Ïc¡Î²Ç!\ŽT±Q1¸=²!|?܇;r-“h»œ÷Zö¨’QÉðë¾úªŒ@© CçÊJ©¨ž8Îx{*nmÎq2ª­OfEƒ üæ;­2ý‡7®‘¦CíÁú„o\nþ?ô!x½ãMr¤µMÚ-ëÛ˜õ£›ãoó9Ëßú]Y.«eœì•ñæ³=¢Cª«©6Á¹¸ Vâ'Q1nÿÈ6”Ф”8~*1à€}×h„™Ož"·ÿŸkÄg>c{#(˜(Q0ÂÑç×_ÿk¹ðÂxPñ]Ë/OP”³=Õ †tU\ÔAÖŒ™¨u`>¼+¢ÛÅmDãoó9Kø${_ß'+~¼T–Ýt,»b±¬øÖ™uüÀß ¥ÂY1ñ7LF$~jk"Ó¥V¡!„¡ˆ¸°kù2Ü>ÎíúgÔ)}¿Ž1m{ßÁ±áþg¥syDíußÍñ” hžŽ€¬5O} ªï¢ S(Ù£JF%€z‰zŠêéb.HMeÿÔ©Òár«A¹p„í‹f»ñë·ËˆÖî–#íÒ3r´t¶“sΑç®ÿ{9°èCÁ<'d“0skÜ&|FŽÅz1à1ß_†µsµ¤r…„ »d؆´Ç·›šûþn¹ýÿœ*ë·Ž“ž¾†`´ÑõÏ5Þ-Úðƒ.XÝ̆¤öÝM†5ÛŠ¢¤&Bô ؇ k¢sM„Ó>™í4ŒïÎàXgÅðIçòˆÚ&ê¾!›ã)»~½µ±ð?Mˆû‹1Õ§P²GSXË ¿:2 _X/P5Q±a™ß Û¼ÍO?õ”œsî¹Ò\!Y#Y:NmqPCÀÛ×3j¬løÞ3²k_S0IYKs_àšÀ•ÑÛ×#Ï?ÿ|äi€¥EÀ'›‰Ø2>oÚsRuö™.ăÁó]póÒȉÙ|°\¸J* ñ¾»Ç o„ø*{*‡R?;bÂΊ>ñÄÁÖ‚lÉBôûpMDÁL¤O=õtäi>?¤;_¶DÝw¶çŒº'ª¨_=©NO>iƒ<±dDQ Ù£–Œr€£ å‚A´üá¿yK°_Ó-’Ê&Wh¢l|Ø=O˜+“Žé‘©{äø©G¥Õ(;÷4ËÖ­ÁXéÚ¯¨ÑC ¹pî(R¹BlÈpásÎÈòteÞße§jç73ÚÃüwoþ×€ ²Vøå/Ù¯l(J&ÈN KžqT¶mšk×èsåK¢gÐv.D¹+¨éDi&±Ë¶_•øŸ%[1uO(NQcÍ ^®i)%ªd”ZM²DP.PÙùŸ Þ lX¼4XùªðÙÊ&Wh²°ñQ‰=aÆQ™8®WŽ;Ö*ÃZzå½½ÍòΞ±²ï@ã€à%nF ” ³P?ÉNqî(R¹Bl7ö2\ƒs*‹î14“&IGËhÙŸ&—}¦5HOE°atbTÁŸüD䣭]w‡*J¶@–™ QÙ Œ:é²J†¢ddã^ œºíƒ &(Í$vÙædÛÙŠiwOÈ–ÓO·Ìt’U6ˆÓxðAû”U2J!½Ä\0n” TyBxQ.È'*…;„{pEÖlZÕp¸4Ù2>‰íQ#úä„™râÌ£2é§ltÊð–y_s0 êŽ]Íuq²å¦¤wä˜dÎGœ¬•Ôw…³SÂeíçV£áœ1óýôg¼¸ò‡Kß;ïÊÁ£Mò^ë,yýƒñòvßLélrR‘?ôé§E>þq‘dz?9£æñ3×NÑPeCIGx´p¶ñJX2x3#_r=yÁùˆãðlÄF:QšIì²íw¦(㶣ʇq÷´fÈ¿ÿ»È¾`Ý"ìûÅ/D}t`6K)Q%£Ø0V.#tˆÅ‚5.ÔvÞB}Kàïì'Ê–˜ ÜûPÝ,®Í´íóftÊüY(=2~Ì¡`Œ‰ãz¤qÿ™ÿWWɩמ-ÓV­ö·÷ËÑÎXÊl‡ï" Ü +QTÙçJüµk»½âÙ¶ù¼¶o¢ìˆÍC±‘2òÄ©2{ÂùØw/–ó~o¼,þó‹å¤I»ä¸ãŠ›ë_i h¨UCIG¦lÍš,~G DOZR]?Ó9ýã¨Î@UÖ?„]Å©Ü;þ5®»ÎÎ}‚Ü¥§b Ǻꧣ–U2Šãµ¢.3?oÙ#¤¤ò&‘;D+Tê±s!_[b&{_6dym¦pG¹˜uì>™<¾Û,=òÿú%™ºõii=²_&½þ´Ìð+òæ»­òÄo~GvÍ;GºFŒ•=óÏ–—/û¦tve"QI} ®ž£ež8Þ¼êNÙ¿Ð(# ÛH¸¹ìé4Ÿ˜{Ÿ4w´ÌYÔ*s?…øt=ÿŠžHR]?Ó9ýãp}à¶HUÖ+×jã_KÑ]wÙÁµÈ`#“ä„JÛ‡B³K v>RPqð?j%Ö —»¾-Ý==•‘]‚ªÌ›ì ¶ 5œ: áçŽô‰H^¿Û( ¿úÿ~%GR!ÒÕÓÌ‹ïpËT®¦¸üÎ×ÏÖŽä¬D(#}ýÙ o>/?ãôw÷Ø>uë£` ªÒ=bŒ¼pﯤeÚD3gBðÐCh˜h¤&ŽfRÿHžTKv E:~ã7~Ã|ǃ¿Çt¨ì©ÊñìôßÄÁÓHRÇJ,ze—ä{ý|ŽÃºUeRu Ü#ôcó©>š]Rɘ'ˆ·ÀyF¶8æ ¤¶àÉQÁ¨(2Ù‹Llqòúq³Ž/Xd¥`é †cö´.™?«3Y”iÞ§Lè †ß?ý$éK¸@Xï›vr`éè2?WOÂïÙØÐ”å˜“;¥gä˜n’`mŽí[¸X]4MN:B0° :0VÁˆYκP¨%Ô}¢ä ™´mŒ–éôö2‹ž¼¯ŸÏqÈ”0©Ž¥É¡YñÝ0'ŸlÇà©ý¼U2† 6=b,ÈA± 5• N¬X.êŒzsªL¶Ábã]?fÖ-_¿MæNï”SO<"§Ìëâ8fåbú±Fé˜Ô( S&tËžOQzGŒ \ ¬÷^þ™5µ;XfNé6J…UR(;ÍÇñ|ë~‰m j®‘x±³?$­ÿò ›Q{ 5jM‘qq…Z²r¹(&J}ƒe˜ ’ìèŸ!F+Hôät}b%x^}Ölg‚@M7z†k”­ð5é¹Ü«¯¶Y%ÜÛ‡?,ò³Ÿ•ß=FÝ%ùÂ/+¥‚”FÔnb/ø:ilˆ¼qjì¨wI‰)ÔsÇ?ojö³kƒL, }g.•®ï|/¨Äna˜ðþŸŠß¥醤cP4j=öÇüžÙP “%|¶ŠA±ÈÆ}¢²§r(׳cþÇ]òöÛ¶Çè”ÔÓR‘i0®lA© ^‚g@t ,í2˜x›&‡,;šDžx¾£Bwª»¤@H¢LàÁèTJÖ¨“ä Ñ0•¨ARÒÛôr `ÿ›uã+/ËðaqÖ—Ö–¸´4{ †ÞšL`.¿#®.¬Qú{gÕP”t F±fîM•BxSY¡‰Hˆž`) 5„÷Ñܰ‹RÁ÷ÃŒ¸R ¡` U22 Cçc4´ •†ˆ7ŸtT\$Ôœcüâµjmðs¥X³E¶åQåÍÒxà rέ·ëŒçHG¶ŽQ ~W,X-°^ \b¬ uŸxä"{ê Ò/É6¡§NîÚkK&zä†åÖ[Ï Ö™Î‘ŽlEO:º»mCSƒ¢1mšèŒï…Ø 2I*½ÿ£JF¦aè€_—7”TÞ:#B JÉ/_ëƒ"¤Êã “m9GTy³ÄÖ­“掎`ñéÈäPÅ2…Û‹.c—ð{¢`0²k¥à h¨UÃì©Sè·aD¤1ý›¿±Ü•HôȺu1éèh֙ΑŽ|c9Ëù.¼«}ôQD©©(aÕ€*醡sþùM›lC„b£P'Q#i˜êlm¹Ú£Ê›ÅwqdMC‹(†tâ J”¤#ª¼ÝgßI֙ΑŽt¢'»sAÝ“cP.Oxp™UM¨’‘*ýÐ î&0ãMg„Ìç˜Ó û­'²µýåj#Œš¹È,.<0X»2(+VØøYø?_{&ÝRŒ‰ Â6K-Æ"¥ñ%¥®Ý'Uú\nðBŸrJòk"]“^|=†¤ô)†è ƒ1O<ýD’‹9'¼E,:((].]µš²K:;;…ÅAtètÓKß³gOÅDx¯^½Z–/_^ø(ç]»¤ñÊ+%¶~½Äψ£<ÇÙ×'ãÆI9¶ËÔè#tJ¬<›ó=]zé¥U¡d \„©+Ù£dwÉîÝm¦—ßlú~ͦqn5®>;¶Ó4Îù5ôw{áhkë2m<†ƒ}wÜñÌ ²à>Ë•ÎÎÆàŽi ”š¶¶n9²Û4ê}F¡è3õµÓ(]U+’Éžº·d¸”Tâ-\¾ª%×AU.snÐK†ùÑ+Á¦M_¸0£• ¬ëÖõcO˜ŒÃûxÖ&óââæHö%Ì’%ÃýÆü¶tp‹\îb0*Œz²d `pŽº’=Žÿìûö5Ë•W6ÁK–Äåþû{Ëbt¡ £}äˆ52À.ЍÎ5Œ ëÏCìEccë‡Bu1 ¿:Có`·"¸»=[Ÿ p€ ”Šù{ ƒæy3 1ºK¹¡ñÇŠFü NÔDvŸY÷¼ð‚4|²4¸°oæ1v`ÀPwñé-j4 $Òˆrü¶(ޏG*4#¨ï{¸W¢’58WÝÈž*Àöÿñ?šMã“=¦ ’GI,1(Ä/ ¾‰_ÀûI5ÇëIÃÍkƒ… )DY÷É /ôÈÉ'7™Ïò=ôÙRAóÂkÎëÃÌnAÑ@¡\TŠ(*†ì©ÏÀOÞHÒP_yņðò?Ž?ÞRÿøå+1ÂÆ†>ÛÿY%ô¹R –†C°Í‚u7H`¥`Ïê×rTÆàMUËÁ¼ìA‚9ÎO¬Ôf¢¨ˆ«õ”ã å"JÁP*—JJ„AL“F?êÈÆ8‰bAœ>™ˆswÏQpl„è ¬¸AX³èAĸ>F+Eì/ˆX ä$oÀåœtR}Œ~P_JB µ—·†5o"á¼¼A4BäUro%×ðéZ"—gç÷ä·Å‚A0§ûâÄ­’‘M7G) N¹P£º¨ÄDŒÍˆD7î’ÄhÌQ°ìØaú4þ«1hú C6„E}Ü6(4œûµ×ìupã h`¥`tÊqooºÄ52eØ‚R™"ùP?J½ZÆ»àMÀ-BJ*ûp,VPfAZ†2º‹a.ÃâU Ù>;R„nD{»í2 8b™Z¸°ºgÁ­ÔzQ½b@úu…à”†E€Æ›*O£NƒŽåñŽ[‚Æßõ)_}Õ*ˆ Ü.(#|†"â–}û†JŸ]q…M!E|pOÚÀ áà ²ã”ßZ‚ØafT QoÔ~LÎ1ÞÔXœd¼ÙìãÇŽUáÀ|‚4‹*ˆëÈë¹é^¸àN,¬©é¾]³ (VLF¡É6Æå²Q04&£r(ô³£X”"®K®úô5\NûùŸ÷ ÷ÂÚY7xE{{»åùç-§Ÿ~ZðÜ(2ĉó¸µ/’P4ظá•%ä«Z• ÉÈÞTQ\#X.P4òäÁrªYá FQàûpŽJÖlW;H º$üÎt+\·nD•)Å‚¾K¶¨{Dq”*®Á—, ªå<âX胰ð?â‚&w ë‰;‚ýîš Êò¿sË ^N;ÍÆV8×H½Z+ÒQýJF” ÎÖ‰OÞ¹FIæ­"â&×\§Z"ì`d»š¡Ë‚ÝÛ%µÛ)È0ºJY@¹¨y÷H1ìÿ5L¹â:ècaÀu‚øG4   ° ˆ 00៱ž1ã` )wê©6–‚Ï8w Y, ÖK\ÅP¨þ¯(<ÉÐ'>ab Xc>§wë"‚êBÄuTXªpžb¡"Qžîݺt94¸³lÔõB'8ˉBÄuç Aa@ŒšÇÿ ŠÅ~\!j™Õ¯d„mp/¼`Ý"4>¼!4>ônõM±PÃÃy[ÕÁDpgC·Âî,óàiõNÍ[/|t‚³œÀ’@ ý>ÖåÌK)=Õ¯d`ïr j)3Lç8ä0Ÿ«É<šLY&•˜…BãÅ}7†¥%‰ßœÐîzŒ±©êÂ=†™|û?vwÞM×É!eE¸»Û–Q2y™Ô U[T¯’"Á¨'þç"gœaó‹¨ä_ýªuhºbzÆŽ,¯Y³í“éóRƒõ‚àNF¸Á!Š‚Á*V ¥lÔ…{÷œm‰¯E¾øÅ¤ë…ƒm” ÒäQ4X(‹uõ¥—¬’˜;§žÉäeR/TmQ}J‚Œ††ÀNzµt~þó"ÿð"÷ÝgÈ5'3™²L2}^*ø½±¯" ¹"¯°³â&!«žƒx+€š·^åv8Áã( °€A@9Ê#>]w37³F!ç=Å•G<#4±8«ÇñJçq¹•uF&/“z¡j‹êjQ(ž~ZäþO‘óιúj[y]nQžy½Cr åØr’)ˤ²P°V!´ýà]¬ŒÜÉï­Áe¥¦ YÀRºi“´’­†¢±aƒÈ•WŠüæoZ *ûy/qÍúy,lóŽbå ÅšŽ çÄþïÒëýk‘MÖ„¡2×ÀPŽ-'ÔàtY&™>/X«èñ¡Þ…òèÇ^`±RW˜R  Yââ~XóvtH'Š6ãE_ádO®u«ù‘ŒÕƒK ŠË‹/”¹øªÔ¯)ËD³Pj‹ÂJìBšïÜ(Ž 2¿¿ŒÀJ¥¤GàÛÒò1ãsßÅA¥Ï÷œàV2áïƒíbî:oÞÜ#dÓûëB¸;ë=@EIE¾²‡÷Ž˜ ¬¤tdˆ¥`«Jíœ9ÒíÆ‰.D]çÿ³?ù£?²±(ÑNqvçÌÖBT~…B6é(Õu”ÁVÉ(”ùÎØÉ›@ÌŶmÒGEÄìxçC7ã‡]ï9ËéV(¥rù¤ºtôùÝ™O†ßyÜ89ˆO›žŸÆ^(™ÈGöàöؼÙq:ëEBÁ ,iþ»Wˆºî×,¤ØŸ~ºu¹0þ5Ùq¾Å$5àW(T“‘‰R]GLa•Œ¡šïÈ'§‚Ñ›àm`MÖ±ÇÊ|›ø:©PC5ã‡]ø_ó=g!î§Ü”Êåu<ž½:” ”‹ùó¥OÇ8Q²%Ùã¬d‹8ëò†ø ” †|Œ¢X²‡Xÿø›‹»{¢—‰ð+”Êã£+声JÆPÌw˜©€Té^TvYÂ'_HjÁÅQHJõ}ø×q–)+B8ò?~jFí$=U­J.d+{ÈXÂ5‚…K)9åQpQ2ŠýÞ¥ªkÄk¥‚U@S:°é—Êã£+声JF.æ;ßIöá‹<÷œU4èUPÑ\Zj1FqtfOÌ¡ø[ ¾*f,B:¸f)â!ÒQ*—ç¥vó3pÚ 7X%áÎoM¼Ž{¡äC6²¹‚‚bAúûþ¡Èw¿k]¥²š¥“=(Ô‚ÝélÑÑÂ¥S,|\¦@…\šŒ¡Pªë(ƒ)¬’‘‹ùÎw’=óŒÈW¾b{T4ÆCjZj:xÓ0wÒÐQ¡YŠ‹ŽTq ¥Ä}ÅvùÐ…`à4Mû«¿²Sr-¬¼+j½Pò%“ìÁíŠ{„º~ÓMv@,pÆ©¸ãŽD¡Iö ð tód¼àJ,Vªp*äÒd …R]GLa•Œla¤;ƺðdø&1bÁ(ÕQ1¥¦î¡Øð{Ó{D‰¤÷†‰°ÅDMfÆ^(Å—ãR hð%µP¤«÷(Xô¨/Äh”Z 4PA)ÅW2Â&9³!!¡]êkzµáA–®„¦‹.’“þú¯‡æJˆrK¤‹Eˆ*_ ÒÝCµã7"s„”d#"[„nÏI †¢ dÏ…ÚxŸ+lCŽŒAÖdªs‰ú_Ùƒeá[߹⠑Ï~ÖÊL§  TPJ@ñ•Œ°IîšklÃsÙe¶²ãY¶LdåÊÄ WBÌô@ÆmÙ"«V%>ȃ(·DºX„¨òÅ Ý=T3nP-~k7$8k,}1U)6Ÿú”Èý—­ÃÄ|ýÍßXK)²&S+·ìY¿ÞºsÊü–[lV¡Ñ@¥_É›ät¢‡ÁØþ?ú‘ÈO¤ŽðLŠ }}#§=_¢Ì“Î?‹U¾¤»‡j„ï ˆYÚe`¹À‚AìE1cmÅA' µ«Ã¸Gp“÷“M«ÙÃ}³²^èØ TPJ@q• ÒÅ|³ =ZÌæ¤)ºý©ðŽe0®8#?æK:ód¹–W¬Ï›ì pZ*®1\)¸æP(|—l®uØ«ÿe•=NfòLÅÌ4Q”"Q<©Ož7±d¸x‹ÓNùæ7mI6$LŠñ1cäƒyó¤³a¾¤3OF‘kùzæèQk¹ðÇ6qi©z\)ôö]üŸü‰E3Ÿ:œ¨ÿe—=gœag~EÉ@yW”*#˜Jñ€é‘Ž1/x{{»ŒÎÕ¼yoûvk‚£gK„4Z9æò<›nSÁž~ê)9çÜs¥¹Î|ùýì>~gÊ–k½@™D8b­b_žtwwËÃ?,—\r‰4ç;…•RˆgR.#C¾ïmÛ’C„3‚0LC¨7e¯¸Mȼ£n±Ða+õZUöVöÖ’Aïß%•傞-V *º¯`DE[§Ã|N„7‘ÞýåÓÃ}vþù"ý¨í\J„¹_NÉôR73Ál ùîÒR™­’e †¢ä ïîÝ6æ ëZÔ`~éäFæó²Ê:hÈNÆÓÀýŒŒU”*"°dtvv ‹Mdúôé¦Îîɾ7AÅf8\² P.èåwA¯6Dã 7HlÝ:‰-=n*Q|Éé½ë®Ä§ƒiøÓ? Ê€åÊCªs 8?傽¦md1>ݵ*ó=®]³F–šûnªKBŽßš÷…w—ÙRéih@-4êÕ«WËòåËë²71Ôg§O˜0¡â-‘=ÀÀUÌØLï'²gìØÄ‡IªRö¸!ÆÉÌ"¶ «p ¨×:¨²§°²'P2V®\)·G¤h>ôÐCF‰Nï∙F°íý÷¥É4>-FÛn1'î37wÄôjã)Åsn½Uš=¼Ë\ã™4£îE•§ò¦:G¸¼O¦k)Ñ 4[÷ï—&£Döµ´H§à½fÍ4Øé~k¥s÷àà^x\î?ê¾*²ž‘2ǘ¸¾øÞ™†!ÀùÉ)â\#¼ì|¥ŸáÝdDLêåólñïƒõ½÷ÜæsÅÒÞnM²Ä_à qsðŸx¢ÁP”J¥‚11HU¥Óƒu†¸Ve*J•’YÉ8pÀŽÜIåCÉÀM‚o’!£SMÑí›1·ÿú×'âsWé¨ä˜ÿ¸ñ®Œ;.S&0WÒsá¼ÙâßkÆoð·ù¼Þq£u¸ëFëD`»3 E©4Gšã²E¹ÎN­Ê_É@qR”*!½’¿¦sAF.7'@&ð=:bØéæˆ(C¤6kÿ3%Xh~WÜ$¸Bp`ÅÀ”«s(• n=dò(*FÈ—/r¥ªduë ‹‹íP”* }+â‚;±` fM蹦,†}“ÎIO$J0øeÀüOšk>Ãusá…" ŒÃšm%;R(¸Fèá1€.,n´ÎT*E©ÈzB¹Àµ‡õÀó(jIö ä hpߥTé• Æÿw3jbÁÈçåû&/³$fJç5j°¿ÒüO:Ù£íñihÜ &k¶•Ì`^ÆrâˆÙŸÈ Êo¤(•V “yŸ£bµ${P2œÂ¤J†RE¤W2¨Hnºî| û&/Ó£oöÃÿù䓃ý•æºa¤¼`À>£îÞVB ®/”FzCX.œh|â.R™›¥Òà]¦qÇG£›n,Z’=(N¹P%C©"Ò+3gZ7I1 çì4sgŠôqfÉ3Ï”¦sÏ•s¾öµ`4½ÀÔîqWCœû&:=Û‰™ q¸¼pÐëC±pJ##(u6ØŒRå®JƒKãNz>Êq5Êž¡X2_l•$Öl+J‰H¯d3ð/•)ÓáÌ’`Ëæ£GƒázS'ÑáNÀ°f»Òᾉ^G8úQìÅ€^Âå‚ï—ˆs 8Ο_´áÀ¥h`Ye”a\¼ãé\%é¨FÙC‡!_%ãòËEV¯¶1,¬ÙV”QD-"hÕQ¦L‡g†t}•þo‚\„ŠÏšíJ‡ûæþÁ=G¡ñƒ:Q2‚(¸E\J*ІºF”j™€»„Æ’Š|­pÕ({œ%ƒ%×úûì³e÷®(%¢|J†O”+!’À4É5Ó§#ê\QûJM”‰¶÷…`D¹ ¨3ʱ,(¤¤ºë+J5‚͸.}¢@‚¨:Xi²‡ÎÊJU>ñLêæË‚XÕ…¢”ˆÊP2¢\ Ä äCÔ¹¢ö•š(m!î‹t>2FL‹ÔS¾7¬X/ ÷ˆÆ](µnÞwܸ(Ò… ªVšìA©BÑ >.Ÿç~à‘åË­BÁšmu¡(%¢2”Œ(W£P&è7Yò'j‚#Ÿ¨sEí+5Q&Ú¡Üã-Â&˜OQ&H3f´Nb.Ó¤XA»ŠRj\&.%ƒ†¶P.¿¨:Xi²‡ºÎóæ«d0Á#X*k¶Õ…¢”ˆÊP2¢\ Þ¾~“¥û,ÎÕ¿¯Èç¾èÕ0ó-‚á€bAƱ˜sO8¡p½ùøAó9¦˜0=š­[¥…^Š…KGEØœt’¿¨ACQ€‹K– zôÙU«Qö`Å ŽcÁPK¥R…WɈò?f²Œ`Œ8®Ùô@‚Q÷œIÑ™>£LŒ¹úA9Öo¬SÜà 2™9óýñ†xÈ–ä¡¢\à"!•5÷¨(õ -ä¢dÔŠìÁò‚‚Á~_ÉÐT¥J(nK…ÿ¿'fFþì)Âo9ÿ'?±£îÑÁ´ˆ•µÛöSÃ8“c:?¨ÇXæHqƒ(Dzšå³0^Ä\£3/‚'ßI꥚éî¶=|¬{--‰¨Ùƒ«ÅŠú<ð³Å4U©Š«d e3ìîš5vá×+I‚€ãBŒÞ¾ÝŽº¬©à©LŒO3Õˆ~a8ÖŸ0)Å= "™3HÏ#[„¬ü`r23*î ä)gÙ WE©5p•¸z欙¨ÙƒE‰Td¦ *UÂДŒ\Ü®l¸7A%òÍ‹¤a†ÏiŽê?Ó!=…°Y2—ûñÉÕÄéÈ÷8=ƹ`¼ ¾,3fX!ÃfyekV”Z%JÉÈ¥®»²Õ${x^”¬ì++š‚ªT CS2rq¸²>T {îh^„Ð9W­’¦#GúÆ LŠôLÂfÉ\îÇ'W§#ßãP.°Z5NPœX/ÜDf:™¢$ñ• È¥®»²>•.{p¡ 1 AßN¡ph ªR% -…­Jå ¢`&Œ"Û²å¸Å˜ï·ÌáØ”÷Sð¯ÒÃ!ö·J÷Èpण"LBÙ"šF¦idùPS)¬¯¾j•rb•PÀ©#µ.{ˆÍÂEŠÛ”éÊ`ÑTÙ£²' ›Âš‹»À/ øG1+©íšƒÎƒIÒaJ|Þ<éó_þ2GFÝO¾fÌBBÌŶm6îËÙ!nêu\$Ü'=’‚¡(ŠÁY2 ®ŽDÕõTøe¡Òeò9ƒNžºL•*fhJF.îWÖ™;˜©äë×Ûmz ~EgÛTþSÑúM.ì‹2GFÝO¾fÌBÀø(Ä\ðl¸EP.â"ö‚±.êôŸWQ”8%ÃWjYö Œ`Å`dÓpÀ§¢TCkÝè}gIíÊúC»à¦0Îÿ }}Ûº5ð‰ö÷'ˆÆŽÊ䈺ŸBe€ä‚S.êLž¤£"0˜È å‚q/T¹P”Ì`= ®`ipÔªìAv° +0WcÍP”*¦ô­\ج5½¯L|Á90}º¤(±/­yœ©ÒO[㸨rÈ×´é@ÒËÁ—ê” \!L^†À`Í=×è0àŠR4èÕc…ÀÚà+¹Ré²ç£ùÓ?Å1nL霨¬Pªœ ð³³³SXnL7kÑÊGGUÄ¡`*۱͛ƒ C»?x0è)âÃTÆž”Æ{îé/ÓyÓM²á¹çdÙ£JÃ+¯ûzo¹%mï…ú@‡üöà¼FHŧ«Kb7Úý‘%K¤÷®»–÷ögÄ) &Dbt> Ö žCü‘ìy qV¯^-Ë—/¯»à«z|n(ijS‡'˜÷°Ò?SÊž={’÷½u«È;ïØàOÒºÛ#WªAö44e{ÿöo³›£¥ˆ¨ìQÙ“aÙ(+W®”Û#ü…ÿþõ¯Ë”¹"pÞ7&M‘*åûÛvcœsë­ÒLU‚.Óè?sÇ9ïO‰Q.(ßb¾P„C¯ùžºÌÚkz]ütÜ8é)´‚¦(YÒaÞÍK/½´â•ŒT²ç¡‡2zºqtøîÝ2Ü(Ãwí’Ž‰¥l¬Pɲçç?þqÁžSQJIXö”Þ’¢éc |£ý½‰1c¤çç?ç¿~zzzdíš5²tÙ2Ó)È®“Ê2‘ëþAà“e$>†óÅ|Kô7– ”1¾+,êÚ›ÐÞD>Ô”%ƒÔU\dƒ<͘ ¢dϳÏJÌÈ–`ÿ9çHïã'ÎV>Tö¨ìɇHKFâ³~(”Õ8…€èî뮳 ¶©`Aöq pê©"ñÁt˾ð9Æ›„¹Hrz@˜<ñ‘²Ï7a⾈ú<×ý” ¦™F¹0B"P$øœÞÿ£\á»âG×\õú«è…ÎU¯"ïÛ(A†Ö+¯Øl¬BCVŠì!½}åJ,NPøÏ~fÇÍ)3*{TöäC¸—_É à‰ô.î(Î>Û´ï¦7š~k„)bàŽsûˆê.4œß)\ß|/` ÿQ.ŠhíÑŠ®=jJÉ0ûdËkÉ@1+q!¨Ùc~ë@¹ ³BZ;â¾ÂRFTö¨ìɇp.%Z}ªJæóئM¶’e9Æ?Îí+$ôn˜jÁFO GO¥‚Þ£ð„¦qŠR\ˆÍ pƒôÎBQnÙÃy håÙ°\àªCQ Eñ• L„Qi[ÒºÒ±h‘ÄMƒÞçÆ” ç€©‘…ÿý}™®• (»vYå‚ãÉ A™@¹ ÅuóBGáS”Ò@,  =æþɆJ—=ï½gŸ…TU)䊢ÔÅW2ðAbZlÏrÔ; B……´¯Ûn RÆ>0!Ž{¦ÇÂÿþ¾\¯åCe'À å‚ÀNz((N¹À”YälEQ"@ÙÇjHƒŸ­5£’eîWÊÒyAÁJj®¢T0ÅW22™ñµúÐ3X³Æ.ÌvHco–¯ºÊF~»ÑôX 5ÂẄÊÿdŠPáq‰`Â$Ø‹Q:5LQʇkE€ ³¡Reræý÷턈(*t^Ô2ªÔ(ÅW2¨@>áí°É2“ 3QfÌ(ð…E~Å"¿õ["Œ‡…"¬\LŸn<E)/ÔCzüÄ-`uÄm’‰J”= Ø·y³Èw¾#ré¥"_ú’ݧ(5Jñ• ,>áíBeÆô!Þ‚.‘¯]äÅm¯‚5cb¸IËð‘ÖYT±¢T®Œ¢(Õ :tï¾›ø Å=ÿܬÉPa>”|D䯭ƒõùƒ‚‘î>¥)]«ëG_3Ð •“ èƒ)“%•éÑAúšËa-„çäÜË–Ù1-8äÉ'5z[Qj ä£c’ÒŠ¢A†£g¦¢²'ŒnÖ£>û¬½§—^ùÁ¬å…ŽPøšŠR”NÉÀšà¢¯ñ•>ø ª¦rF6=ÂáÃÖüè²DÜ|"Rá×dÿ/iÝ%¾ S£·¥¶ ƆW8ò •¢QÙ“ wîGµ– dËZc,BR”:¥üþƒT¦Löñ=ƒ½{¥ ²}»¸†ìÌ’þÇ=²`AÒ%rÖYM˜½­(µ  ‚;¢ŒÈ”ÚêÈ${²W ×ep?d'ú²Y¤(uLù•Œ°)Ó¹=N?]䪫lÏ`÷né#X“81“úY"®7ãƒUC£·¥ö!Ô)ȲMH[ÇꙉT²‡}|–7Éb£äžo~SäüóUö(J‚ò+¾)“Q7W®ùámœCy=ož¥ÊJÊ=—T£rj戢Ô(X6Q4hè‘ ŒKUƒQ6SáËÜ(,©Órp>” :?ÈâB¸&ò9óዬ^­²GQ”_ÉH¸Cs#ƒf‘Wް@™ ý”J:mš$ ·C k•¢(>XpU HW'M…¹Â8 Ìçb%r!—Ü ¸DP\82ÊM¤H¼2 ÙÄu£Ü/ŠRÇ”GÉÀI¥§§‘p‡!˜;݈œô 0]þùŸKÓé§ËY˜!wíJœ@Q% {:'X" GŽ oOãµ×¬+9‚üq­ÑÑaá2C^}5p×6]x¡œrß}öX”ÎçöCÁ`"E¶Ã.[EQJ«dà/ÅÔH…uƒèÐ ÀÔIÏåA¶&ÈÏ>0=Æö퓉Ï?/W^™8‘¢(J P0Ü,ÊÈd –QþGÁüÁrJ'‡9KXøKŸ¿üK‘%vø°Œ6ÛÿôOÉý8/2Š5#EQRR|%ùC¢AǤé»CâD(Ð Á éLŽä›'RQL/"F»¢(J&È2C¶ WÜ(›X!Xcy cƒüAQ@þ°ð?., ÞŠ1d–ùóíù8¯ºE%+Š£d XàÃÄJwȰa¶S¹;„Êï†úŽêx©¨}FhĉþVEÉÈQHK=å«d8¥"¬d¸YãËd£Œj<˜¢äDᔌ°bß“ ‰2á»C¨ìÎBåOG"5>~¼ì>õTé½ÿþÄŠ¢(yÀÜ'Äz!EXTQ:Xœu…ãÿQe¢€¡)é *-!éÜ!™àØG‘ž;eÍ­·ÚmEQ”b£²GQ BîJØÙ*¤”¡\¤r‡(Š¢(ŠR³dV2Hÿêè°’yMv6ŠæH¦bVEQ¥.I¯d0…2é¦X-˜àM”b,œbA”*Š¢(Š¢„ˆÅ ‰ÿûi7 ÅØ±ceû}÷ÉhrÎhˆ°ft=‚§J¤PtwwËc=&]t‘4§J¼F©×g×ß|hÏ~àÀ£ÿO—ýû÷›ªjêj•Ð/{¶o7bÆÈ™2£ï¡Êžz¢²'RÉØ±cGPHQ”ê†Æú8ܘU‚ÊE© œì‰T2úúúäÝwß•Q£FI¬òÂfT)½›RR¯Ï®¿ùОj}ðàA™:uª400U• ²§rPÙ£¿y>„eO¤’Qiðà˜]0¥Öã^Ï®¿y}>{¥¡ï¡Êžz¢Ï^=]EQEQª U2EQE) + ‰ÿ+šÆÆFùÈG>"M \gÔë³ëo^ŸÏ^iè{¨²§ž(ô³WEL†¢(Š¢(Õ†ÈÿQg—‡IEND®B`‚pyclustering-0.10.1.2/docs/img/example_cluster_place.png000066400000000000000000001036511375753423500232570ustar00rootroot00000000000000‰PNG  IHDR¼Ša9sRGB®ÎégAMA± üa pHYsÃÃÇo¨d‡>IDATx^í½ te¾ç_0† C =u;éÌlh‡Eç 4בa1Øv ,7lîÞs{$¬ÊˆŽf˜0=jÄíÜÏIÃAò¿—„dØ€ i£è$rÓ‘aEЬtÖlB&é B‚æ­ÿÏ[UW×[wÞ:]•ßçôéð«×›ˆaÔ–ÇGµ€qÁ:¤ ŒqìoÄ ì~ôó'$Ü1í‡ÓQ‰8‹j©™Œ«_ì)þ†¥@7€àÒƃ§¡®®î7Þ`Èr×­ËÁL&ü.ÊÒZ%î{ø¹¿mÞþä;ldR_¹¸Ä]²Ø„Y\ÒLVLܬšÖ£RZN Öb‚¢´Ø:\œ§ÀÂo)m oµa*CY¡’(Ù@í„Û’º`1 #@ðh+¼颭@ºBÐiøôÓO7nܸÿ~–Wa``èú•ŽŽ¶íßþµ­Ã×Ò.΢Zf§À¢Œ?|øì¼{gû“yYQ(ž‚\Y ð9¹‚Ü’æÔüÂ<×Q¦5÷QW^a~*>þøú²B”Úi¥:îâk ol/ Ôäq6'ÚoéÞ ´TÃídRò4¥£.Höx³ˆYž§ ˜IÖÂ.ãª\ÄÐ x²^€tÉ ݉9 H…›6mzðÁiVË—ëÚgÎJþå/¾ü¿7ºëÞ?ò)*üã¿oü°e/~åmn¿½ù±ÙÔX™ôœGfq͇—¿lÎ2r +Ðãõqœ=‹W¢ûh“ó¤ŽæãU"ȱ¤Û\eß²ùRRòdÙ–)oÜFöMúÃ5]B¡mù2ÜYüÐ x¼Né‚t'ì4*DG„–ªq¹®híZ®î@J/ϱÿÝ?d¢ÄkGj×mž¾ðÞOÐë× {ß~óçÄVÎÕ/ö<ùÎö׸ìŸýà CË”Á!Ø_p6!¿²¹dg“’@“šß€Ì\ôÑB×Ç(y̳E„÷„ƒ‚Ç€àuHÒP↡ÂËuèÝ4·ž¦¼ð§ýpºe.öU/T¾—¶®nÞâ¤y÷sU(®g!R ¾óp +’á©:NÜLâ¢fQß03›«*.®â˜QÞæâ—§$ O•÷AÝGÅËPH>§¸"RÓ¬œZSá@Ûò‹_è$%/‚gÙa‚@º,;,@ºcMÜéÓ§ûûûÏœ9óa-òNU@®ë’µKPbms`…›k"྇ŸÓ Åfõb7Ó„/AñÎdj~¡Õå² «\HT5V¶P%qHñâ“ËA*ŽrlÊÍnŠAM’&ìYyÂÍ5öR|AŽ5¥èܪc/­aûÊå²aÉKG€à©^w€t©Hw‚a >áhiùÓŸÞ}<ø=Ùäñwÿ8*i<ð‡ýÿ%0ô}SqJ_ç…€'5p(¥ö7)l›áÁßö"UˆV¦bäÇv‚WÛ€tU鎑>§w]ëÊEYzµìëÚw{®©ý,gŒÀ—ÈØm,±‰»¸ÀcK·°`@ðj€àc® Ý1!b§á2z#×É~]Æá4&·ü›oÚ¾c™±‡üºÖR•MoÓ-ø_þâ›yójà©e† ^7€tCéŽ1‘>Fº®®èr]ݰ,ÒåKäjY ûÒº»¸ÀÊB–”Úí¥Bð¼¥{ƒÐR ÇGbõ4¥—Aw€²téÒ#GŽ\»våÕÁ1HFë4!ÞY^…Ë—ëÚgÎJþå/¾ü¿7ºëÞ?ò)*üã¿oü°e/~åmn¿æÝôœGfq͇dË_$ »5<–t›Ë!ø´!4_j¢ž,Âáâã½ÛXxxด””•+W>|Øç£òPÄ ]`L•Ó x èÀ±".×Ñ`k(½<Çþwÿ‰¯©]·yúÂ{?A¯_/ì}ûÍŸ[9W¿Øóä;Û_ã²?|ö/ü -1©ù @‡ƒÁ+-c‰§‚à (a6›×¬YSQQÑÝÝÍŠd€à¤ Œž‘; Ãð.“ksëiúÇ ÿqÚ§[æb_õBå{iëêæ-Nšw?'„Q ©Jð‡SXQ©™Ù6¿<%yª¼ê>ê")H>§­éRèV©iVN­)`øýþÊÊÊœœœäädV ˆM@ºÀè¹Ópúôéþþþ3gÎ|AX‹¼SøøîÜÚ"æÀ 7×DÀ}?§"AU•-TIÒÔüÂ<—ƒTåòh™{É›,V²PfÏÊn®±—úœß”¢s Lr:;;«««W¯^m±¨ÆåÁ1HÆýáNÈ]¥B4™v#.Y[Ô^òâWÞuo—]Øuò^ï¸ôwåÆG \Æ?w°Í ö¨¨¨ˆ‹‹[¶l™ÙlfE2@ð@ ÒÆŠ1øõ„6¼ëZøS.ÊÒ«e_×¾ÛsMãg9‹Ì™3gÅŠÃ.Ä ]`¬§á2z#×É~]Æá4&·ü›oÚ¾cÐ 6›-11‘eTÁ1H+ÆýòD]]Ñ庺`Y¤Ë– ÈÕ²@÷y†pOMFN:·Kô Ð) ] ¢° ]3î—'0à4à4úsÂ<öbÐ- S@º€ÜY÷OÅ}ŒÆzÎ÷í/,3X†ã†¦.ùÝ–‰QÜL;Ó} ‘j €þtËb‚P'; ]@8 Ÿ½dýñ“[~ðƒ)(}ýJÇW _<öT†½ù¿üêõ&b³€Ó0‰IÝ‚ð€t tpybh(€ôú£Ÿÿ8!áŽi?œŽJÄYTKÍd\ýb,6+ŒÇÓÓÓÃ2áݱH+&Øi¨««{ã7XF…²Nvëò_ð>zŠ¥µJÜ÷ðsÛ¼ýÉwþ¨þ Ôæ’ÅÁ€'8Ãb·#§–¤Ð_ ˆB*Ül+¶ úb  >d y –imm=vìXWWËk2Žº•Ë&X ‰H±„)˜—³ÃÅ !Tä5+ß– Ý-6Û°•ñûb.Hw¬˜H§áÓO?ݸqãþýûY^…¡ëW::Únt´û×¶_K»8‹j™‹2þðá³óþííO~¤ÊÕ½_ `j¸%‰ÀVìF宆,ƒÙKIm &/…ÕS°“+£eS.I¢´oj€ƒ°å ¢%HöØÌ¹‹ ¬,(ŸøÐJAšDÊüªá *Ô1Õíñ*O‰̃u•—E%¢:›óR¢O òm«p¾`3v 1H—nÒ%ã4:ˆ¬H…ËuE4ØJ/ϱÿÝ?d¢ÄkGj×mž¾ðÞOÐë× {ß~óçÄVÎÕ/ö<ùÎö׸ìŸýà CËBÈcÓ|„ÜãDn1òpÏiceÃKUFèSó2.}°L¦Ìfóš5k***º»»Y‘Œ·O¶ß;#þ±§2hÇA·cÁHä­y¾1HÒà4 Ãc¸LB®Í­§é/üÇi?œn™‹Ü •省«›·8iÞýœF%$_ªÝwNaE!¤¦Y9ÉÚ¹0¨áä?¸Ïë±¥[P;Ȥ>"jà2þ¹ƒm6Á /~LlX***âââ–-[f6›Y‘:ÿò÷?µ®zÿbÍdúk[Glë08 ]`¬˜È_OhÃ/3Ôþ”‹²ôΆ¯kßí¹¦ñ{GæÌ™³bÅŠH†]ÄOÓï:WýΩ²7Oxt L, ]`¬ˆa§á2z#÷4üºŒÃiLnù7ß´}Ç2]l6[bb"Ë„ÃVø’«ðÝH+b÷òD]]Ñ庺`YäC<°AîlôqŸg7ãdä¤s‹°{1 èÐ) ]€G±'ˆb÷ò1ÅdtÊ_ÝÄRDŒ‘/Oüç‚_²á…ûïžžò“Û½ß}ÓÜžþàœþ¾þï»[mû„U ‰ÁW.-¬|ëχ_ÿ·?¾}ú3ïû©#Ëüó¿Mœ•†)é }?Èì`œ ó¸~ˆU@º€ƒ¯4 _!.Ž=ѬñŸÿqÖ/~u«ûæé†/—d>ö]Ïw9õÇ%ÿô­§MåñMÚµÀd¢îŸŠû.EøœïÛ_Xf° Ç %L]ò»3,±HÐÀàNCÙÎÆooε|ëý_/Ìîû3~ü³ë×ÿzíÚ_æÏÿi`(ÐyñDÆË‡~òï° Æx4ädç³—¬?~rË~0¥¯_éøªá‹ÇžÊ²7ÿ÷_½®Ð &. Á/OLŸ~Çö}—7um­È˜67õÞ¥kíK2CÃÿÍñЯ¾ûGæññcâñxzzzX&CCqÔT"΢Zj&ãê{d1…`t€t±Âø¿ž¸Ñ+Îìÿì×o×Ûßu©ý»žïðÃ¥öÛ=ß÷÷`•ŽÁ´˜ÄK#‰qŠñµèÝá¢܇…lë.Yl°e‚ {&ˆÖÖÖcÇŽuuu±¼&d}WõGÈÒZ%î{ø¹¿mÞþä;Ôxv/…É#X ËeÃTL d[“ .0VÜi@NqÏOÎsƒS¦Å%ôÛúéþwêŽþ϶ó5”í®û—·Rÿ=ÿ¼Éâ)ðf5yž‚b‘ í¥¨ˆ³9}ÃÝî)ØÉ•¡qL¶Ü’æÔüÂ<>p,ç>êʃP˜ÍÒ¥K9ríÚ5–Wg``èú•ŽŽ¶íßþµ­Ã×Ò.΢Zf§À¢Œ?|øì¼{gû“)„ Fƒ(¾q é˽‡T%y3Pp-=MéHMÈð[Ôp#xrÒÆƒ; ½½=3®Åõ'|r¦ëºíðþôªóþƒãw•‹7•~ô£äùë+˜Ý±áHÚ{V×ti ôls–·{ ¯´Ì¼÷Q·˜XRRRV®\yøðaŸU6?6»¹ýöW _4~Xßè®{ÿȧ¨ðÿzœf/~åEµanJOÏyd×|H¶ÞÛ|¼Êê=6_jâò²¨6å`lÙ™Ä u/„Ã%T“ .0&Üi˜6-îÓÔÇmܸ;é¥úÍYŸÜ3p«æÉ›µ™¸ï ׸„ÙÅø\!Ø_p6!ÿº¹dg;€ Æl6¯Y³¦¢¢¢»»›Éxûdû½3â{*cy޽þî2QákGj×mž¾ðÞOÐë× {ß~óçÔXÆÕ/ö<ùÎö׸ìŸýà CËFKÎa†·ú.0z î4Äõ÷#5n þ½_ü?=º•\¨|/m]ݼÅIóîç„ø+ŠøVOÕq’".9uÀS3³¹ªââ*|†Áï÷WVVæää$''³"%ú‡Ä·YæâÉYòCÃ.sßy8……€as…¬Ó¦¦Y9þ*ò.]üÔM€ÀÒ.ÒFÁ†Á©ñ½·Lñ=ÉwMñƒ¸i¬4سò†{#$Âfõæâ…8|wªSó ­.—ngˆ :;;«««W¯^m±XX‘ ø6[ÉÝdpßÃÏ©Œ¹ŒÔü†+[±¥ú²—âëÁ$/˧cØ€ã7ûÉ&' ]`L0þs¾ïý¾ûÛ¾Y3ú§Çý þ®û¿|Ç¥§¸+7>jà2þ¹ƒYOîó á.žŒœtnQMÀ¸òt Hà™dN#Åà÷40V€Ó@DùòÄÆ¢Ìåsç×¶œ½=sË4ÿ.šNzdþ«öטcd§á÷Ë;žØ‰SúñwööâèlùûO"bwÑqbQß‚~²e@?€t1_ip~À2<O$/Üzfïøø ªhwX¹ÿqæÄ}?Q§îŸŠû.EøœïÛ_Xf° Ç %L]ò»3,=&Ñ÷Œ. ‘ïiX>w>zïè8qƲåÊùëƒCÜ] ìÈc@åÈ¥ VºH|ÜŠÔü†œQ1D\Oߟx>õ©­èõÃÿ˜xï"qÕ2;ˆ1@º€:s<OOOË„£¶å,zß¾ïò¦®­Û®¼ùôÅ~öì­d“³ðƒÜUEÔ"gXò ˆ£þ qÕR3W¿Ø#‹) Q¤ h 3§¡µµõرc]]],¯Éí™[Ðûþ[qfãã»O-Ù“Ö¶l[›ÎÒ Â‚æï á)ÏÍ%‹IÁâ’’àä^±P€¯EðÍ…7+G…‚IpãàVt#¼É† ¨ gC;†r 6ϲ¨¼=ÝCËPBÚ¬Œœa]â[Ý5_¡õYB øBÒ.©uQÞ¶ Úð=ŒÃ’ßYß•Dý²´V‰û~îo›·?ùÎÕŸÝËU¡Â“}ÁÉWJP¨Å_¥ 6ÀÔÕÕ½ñÆ,£HÐ@—'–.]zäÈ‘k×®±¼:Óü»Ð{ÏOÎsƒShÉS³Sw“ƒØK„š<”Õ½‡ÄEe\•‹) k8Œ›pzx vre¨µí0å’$J{ ЉÖÑVUÙ>\¨áø€°ž¦td†ãU…v åjò8›ÙƒY¥ææñ±f9÷QWŽŽ©Ø¬‰G‚Ñ¡.¹78¸rÑCö ´?‹ÈÇ©Ë Ý­¬Kîbþû’‡æ’´£ø£Däòº~¥££íFGû·mëðµ´‹³¨–Ù)°(ã>;ïßÞÙþäG !ˆƒÒ £ÂJ¿À Y¨)jµA±ÆãÓO?ݸqãþýûY^. þœ†”””•+W>|Øçó±"%._®û%×sõêg5ksãúêÏuW|ÜYz¾~vÜÝÌBä¶bÐ<žÐ|©ÉÆBFáÿW¤L¹PÕr|lx\íñ²ÎÚœeä?œ= ý¿ÏÎ$ÿìpºé’>ÞŠ¬óÛðfIÇA­±ÿ¨î£4Ò•r³" ì¥5œÃ„\þ$TصægÁð!ßA¾GKºÍ%xdíÈ?c´ˆP~››ÝÜ~û«†/?¬ot×½äSTøÇ=N³¿ò¢ZdC•IÏyd×|H¶Þ‹¾:5¯ò„úNøVT AµV$6ÀX aÓ¦M>ø ˫ҴÑåf³yÍš5ÝÝݬHÆåº¢µk¹ºøÞ…Çmܸ;é¥úÍYŸÜ3ðµsöÍÚÌg¦Ÿæ—Pãã‹þWR?ÖÆÊ¢Hõ¡1§9ÒŽÙ_p6¡¹;ŽŽ<Ô›ehŒö;Á'ºŒÐ=â9Ñü#פµÂ(´£ø£D$ò{ûdû½3â{*cy޽þîð]·¯©]·yúÂ{?A¯_/ì}ûÍŸScW¿Øóä;Û_ã²?|ö/ü -€Q x èübE*€tmté4øýþÊÊÊœœœäädVÊåË8˜Šin=M_üUÅ©îCÙ •省«›·8iÞýœ%Ÿ×cK· vIIjš•_sGÿ¥ØT[±PÕrü :®æ]cmÈVJ—òŽ©š™ÍUWY™ÿ®Ý,BÁ€\˜Ôpò<â]‡â©:NÚ$“‰o@¥KÈs@^ Y©À)ùz…vøÏÈEzV~”þÁ!ñíc–¹xr^~xØ¥cî;§°¢ÐW§ ÆÌl[è÷I¾aUjׯ"rÒ4ПÓÐÙÙY]]½zõj‹ÿSär]Ñ’µxam[lhË‘…ó\¯•ͪí¥ä²=.ã²ù+Š…öR|½ ךð;åÙ½ ¼Ý9F2ãVêXVžp#¤üÕå² g“f³‰AIÉbYõÇz|Í@aב`³zñÊ _ƒ”|².±ËØVv‹‚R;©ù…Vô£x;!ùQðÝ3’»É"྇ŸSsŠÂCîV•ÿ>ÉÖV v-`(NŸ>ÝßßæÌ™/k×®e*€t töp§ŠŠŠ¸¸¸eË–™ÍfV$ãòå:ê4˜L;ǑϰdmÑ}÷ý UM20Ú¨ðø®o¡d_±p²ƒ¼€1y‹j;¨âhVT¿ôHä'ð/ÿSëªgð/ÖL¦¿¶u\üÊ»îí²ÑÊO@º€:[i˜3gΊ+´‡l~™¡.ð§\”¥w64zЋŒwq[¨¡XÃð“z†Âʃh.ÙÝ[ ‘ÈOà§éw«~çTÙ›§¼ñuí»=×Ô‡6Rô&<@€t tæ4Øl¶ÄÄD–QáòeôFîiøu‡Ó˜Êê×ûŸg™aƒ¼böÖáÊ£?AT)ÔüÏ'ºsöÉ7o©Ê¦?©ˆ"‘ÈOÀVøEnù7Âë›¶ïXÅhѯð}Ò40`쉺º¢Ëuu<À²È‡x` ‚ÜÙèã>ÏîâÉÈIça÷¢ÈÐ) ]€ÇÈ«Ctù“K¢8 D„‘/Ol,Ê\>w~mËÙÛ3·Lóï¢é¤Gæ¿jY1Fv^q¿¼ã‰(1e /go/ŽÎ–¿ÿ$r v'&%6?6ûí“í,“м!1øJƒ³ð–áq,|"yáÖ3{Õý¥§ 5ÓHla$4VO4bª3“Žºz(î»`ás¾oa™Á27”0uÉïΰ ‚˜×< ‰c€‘ïiX>w>zïè8qƲåÊùëƒCÜ] ìÈc@åÈ¥ V‘Ã)Ô€a×Ó÷ã'žO}j+zýpÁ?&Þ»HœEµÌ.ª AS%’(Œš˜Ô<0ÆèÌiðx<===,ŽÚ–³è}û¾Ë›º¶n»òæÓw<úÙ³·’MÎÂrW 3  “¡¡€8ê*gQ-5“qõ‹=²˜Â Fªy@OèÌihmm=vìXWWËkr{æô~£ÿVœÙßøøîSKö¤µ-ÛÖæD…³Âañ±g—ñó2aІ6 Júôåà3΂Oc–n+#d#œa–üNÐ_k”T¸ÙVlBH÷x…ýJ»©ÔmŒ¼l´á{8É©««{ã7XF…²L+‰ú#di­÷=üÜß6oò?ª=»—ƒ&‘H %ÇÙ8\œR„3Çxj>–‡D@Šþ.O,]ºôÈ‘#×®]cyu¦ùw¡÷žŸœç§Ð’§f=™·ë)ØÉ•‰1W¦7OS:ª,µcá;!‚3¿mMV‚{ƒ°Q ·³„#AÞ%‰FM®ðÏy®É ÆŒ 6ër˜rI2t}–ì±?ùÝZCòò‡HKÚIÍ/Ìã#Ñr¼hÇ•Œ9>ýôÓ7îß¿ŸåUº~¥££íFGû·mëðµ´‹³¨–Ù)°(ã>;ïßÞÙþäGŠ!ˆÑ1òfáƒ'€´PrÜ-¥¨Ž³9Q Ä †Ã8k>ƇD ý9 )))+W®<|ø°ÏçcEJ\¾\÷K®çêÕÏjÖæÆõ'ÔŸë®ø¸³ô|ý츻™…6'k€ÿcz¼Òýز3ÉÿÍæãUùÿP~[{V×tIêp ­.5!5ÓH°iÝ^ZÃ9LèüàåÊüj4/7Ëw dê}–ïÑ’nsá×Ì Y;h/ÌkpzŒ¨Xž›6mzðÁY^…ÍÍnn¿ýUÃÖ7ºëÞ?ò)*üã¿§Ù‹_yQ-²¡ÆÊ¤ç<2‹k>¤x©ÂƃD’B¥À°wÍÇú„ Ë!Ífóš5k***º»»Y‘ŒËuE4¾%J8nÛàÆÝI/ÕoÎú䞯³oÖf>3ý4׸„«ƒÅ5ä1Ÿ!wk›K£“×ùœ6V6ûºG|_g ŒËE§ŒúZœÐŽýgrÆq\IvjNR„Ñ}o¬H…·O¶ß;#þ±§2–çØÑëïþßuûÚ‘Úu›§/¼÷ôúõÂÞ·ßü95–qõ‹=O¾³ý5.ûÃgÿðÂßв¢©4G´4¯‹!ÀèÒiðûý•••999ÉÉɬ(”Ë—I”˹õ4}ñW§lX¸e/T¾—¶®nÞâ¤y÷sBüžªãÄå$k Yjƒmjf¶-¸X)©iVN²Y… ךÈÕçeAcñÞI}D¨÷Yatš S¸åäú«Wh}P®ª¸¸Š›Ì>Cä£'¥pH|˜e.žcE ?ä1Pwá‡SXÑQ9î!QÒ|,‰€*ús:;;«««W¯^m±¨Fc¿\W´d-^EX[ƉÍêÅ.§ÉR`ÖÇ@«±²E®ÈýS{)¾ÆÆ¶2m(A^4YõÇz¼@†þÒê\¯unµFŸ%{$·Ä­üòŠB;©ù…V—Kn;™8}útÿ™3g¾ ¬]»–U¨00€ïž‘Ü÷=üܨ݆ì¸ãÕ[²*±XÉL´4ãC"‚ÎîTQQ·lÙ2³ÙÌŠd\¾\G“iG ð8ò–¬-ºï¾_¡ª©S.캹½w\zŠ»rã£.ãŸ;èV:I~LZ¢Úª8š+ÜÃà_þþ§ÖUÏàž™Lmë¸ø•wÝÛe•`bIóc5$Rt¶Ò0gΜ+Vhx ~™¡.ð§\”¥w64zЋDÞƒeèsЇog˜ì·@—Ÿ¦ßu®úSeož:ðÆ×µïö\Sû %Ðüd@gNƒÍfKLLd._Fo䞆_—q8©¬~ݹÿy–‰*üo…º›«“Ÿ/[ª²é}È@ÄØ ¿È-ÿFx}Óö«ƒšŸ 0öD]]Ñ庺`YäC<°AîlôqŸg7ãdä¤s‹°{ÑäL6@ó†ÃÈ«Ctù“K¢8 @,Rþê&–b#_žØX”¹|îüÚ–³·gn™æßEÓIÌÕþ³&šÿ\ðK–"¼pÿÝÓS~r»÷»ošÛÓœÓß×ÿ}wë¢mŸ°j`B1²ÓðŠûåOìD‰)}ø;{{qµüý'‘±»è81€Xgóc³ß>ÙÎ2`DÓppiáTÇ¢cuSÙË\ÕÖtÕ{úÜÒµö®KíW>-[ü;¸ƒ2&0ò剧ÎÒÄàÔø¡¡@BÂôÊJ:ñÖCë7áç¢GŒ[ô”eÃ`Èeêþé¡Ï^ù…ðú›{ÄYTËì& P0öįxjêÔ8SBB\œ©çæwÈc¸Õ}óúõ¿¢Ä·Ý·úû4¢Âª€-®.TíZ@#; ËçÎGïÝ'ÎøO¶\9½cpˆ»k}뙽¨|˜~D‰¸ž¾?ñ|êS[Ñë‡ þ1ñÞEâ,ªev` z{þß_ú>üsçÛ/®ki¹î=}ît×׮ý¥éÔYß¹ÿÓ|ùú•‹_2ÓÁ1¨ÔŸ¬'xxèÌiðx<===,ŽÚ¼Ò°}ßåM][·]yóé‹;ýìÙ[É&gṫF¢ÁÐP@õ•ˆ³¨–š€‘˜>ý:VWdL››zïÒµö%™ÍŸÿÓ'þ›ã¡_=|÷Ì?ùw ˜)0¡èÌihmm=vìXWWËkr{æô~£ÿVœÙßøøîSKö¤µ-ÛÖæD…³ÂÄR!ATzìsð¡Ð¬{©6 kœW¬-)a¥¼7«Ú8#¤^´ˆÆ;ÄÊ{q³­Ø6~! Nµ´Gj=”·ƒ-ƒ6|5êêêÞxã –Qaß{#ú#di­2!Ç gØÑà úË`Ç,䀲müa”ñP¤J‘æ rèXýÙ¯ßþ®·¿ëRûw=߆—Úo÷|ßß7_YHB:ÓZôîpqÃâ&?/°òƒ {6"ú»<±téÒ#GŽ\»våÕ™æß…Þ{~ržœBKžšõX5tø-UÙ¾A×ä«zšÒ˨¡bm7‹–y б¨ÜÅVÉ]é™Òî ÂÎk¸% ¤‰6$±bÉršò^vr¨¸ÌaÊ%ÉàÅ8¶[n¨œ%{lÖ졤ÔüÂ<×Q¶÷QWDˆSçÓO?ݸqãþýûY^…¡ëW::Únt´û×¶_K»8‹j™”WhFf:VO‹Kèÿ¶õÓýïÔýŸmç?j(Û]÷/o¥þ{þ¿#D63Ð9Q“ÇÙœHÆÃ“ìä õç4¤¤¤¬\¹òðáÃ>Ÿ©@ïiè™q-®?¡þ\wÅÇ¥çëgÇÝMkU!Á×U8r!1È9°egòÆJµ,Г=+#Ú-é6÷Jje4_jBr¤![.}F{i ç0¡Ÿµâ^hl¼¾?Â1¼Ö6iU@¾G­ÊÚA{açŠû(µRy ›6mzðÁY^…ÍÍnn¿ýUÃÖ7ºëÞ?ò)*üã¿§Ù‹_yQ-²¡Æ!ĺr@‹ÞÞ:Vr¦ëºíðþôªóþƒãw•‹7•~ô£äùë+˜Ý‘ãeòŽ„º¼Òl6¯Y³¦¢¢¢»»›)Aïi¸Ã45ÀqÛ7îNz©~sÖ'÷ |íœ}³6ó™é§¹Æ%Ô2RšK£û«>§<¬»v­¾'PÆá@ï*ëayl²†;¿îE<ÒËÝcø"„vpÌ{4ËÄ0ƒÞ‚à1 ¯”©ðöÉö{gÄ?öTÆò;zýÝ?àÛu_;R»nóô…÷~‚^¿^Øûö›?§Æ2t¡P`Ú´8ùX}«æI4Vÿá¾+ë£Ç¤ ué4øýþÊÊÊœœœäädV¤½§_qñ§lX¸e/T¾—¶®nÞâ¤y÷sB•R3³mÁÕÛ|^-Ý‚x5‚‰Ð® ®häVðxSÓ¬œdïdy9€æŒdÎ^DxªŽ“6É:J–øŠÂ1¢Š/Ð)´ƒ¾0®ª¸¸ŠŸA‘È=JÿàøÎGË\¼®ncP9)qýýt¬~ïÿãOîA%á5m`$ÄèÏièì쬮®^½zµÅ‚@ è= ½·Lñ=Z¾… 4èÕXÙªkè„ ¹’©ÈõZås5íZ¶Dl²X•.‚ØKñE2¶wÓ†4=$k]ØÅ+¿îEŠÍêÅó?¼Wa±š!Ù#¾N“J=Tj'5¿Ðêr)~€ãNŸ>ÝßßæÌ™/k×®e* àÛn$7BF@Œ+´œOÇê»¦ÎøAÜ4V ìYyý1yGB=²¢¢"..nÙ²ef³™©óAÙËöÿºó†¿·ûÛ¾¸ •L2pa×}È{½ãÒSÜ•5pÿÜA Ëw¦ûÔ²)ªí Š£Yü‘Pá_þþ§ÖUÏà[šLmë¸ø•wÝÛe¤Û±RhñŸ ~Y¶³ñûÞïÑX=kF_bâô¸ÄÇðX=©GB­4Ì™3gÅŠ‘x ˆÚ–³Þoû—m½P½XE 4&fx¾n¬€/âÁ-cÆOÓï:WýΩ²7OxãëÚw{®5² 0._~ó9«¿j÷5ü߈žã:xJÁX*%DÐàä uæ4Øl¶ÄÄD– Çí™[*«_G¯ê×£wçþçYE ÁÿŽ¡;µÿTÙR•Mo$Æ[á¹å߯oÚ¾c`\Ðø,~±RMBO #K%£±í'ÑHhä€U ú¸Ï3„{j2rÒ¹Eˆy@·Àd4«L2§€‘¢ËŸ\}ÀiƒSþê&–F¾<±±(sùÜùµ-goÏÜ2Í¿‹¦“™ÿªý5fâ?ü’¥/Ü÷ô”ŸÜîýî›æöôçô÷õßݺhÛ'¬b«u„‘†WÜ/ïxb'JLè ÄßÙÛ‹ãæï?‰D¹»è81〜†ƒK §:þ|SÙË\ÕÖtÕ{úÜÒµö®KíW>-[ü;¸› ˆ9`¬ÖF¾ý*øŠŒisSï]ºÖ¾$ó±ùóúÄs<ô«‡ïþ‘ù'ÿn3€ñÆj£¢3§¡µµõرc]]],¯ ry£ÿVœÙßøøîSKö¤µ-ÛÖæD…³Â„"÷ >;Tì™ iœØ°ÙÉrB D«º|{è/ƒ5@*Ül+¶ ïJˆÐ¿ Ò.©uQÞ¶ Úð=tüg¿~û»Þþ®Kíßõ| t^j¿Ýó}ßn`?I”0™†ˆ°½;\Üp£þmAx%Jc5?ª-.¹ÄJdÒç%Z‹LHãDpl—Ò<ΰíù­Ñ_ÛšTh$×ß剥K—9räÚµk,¯rÙó“óÜàZòԬdž†ÂŽ›è‹¶TeûÍg‡zšÒˈ‰{ƒ°E §V[bÀ‘@šÅ8, ƒ«!ë»ü#Lkò‚ц=;9´\æ0å’$J{ð†¡8Ø`nène]rXkH^þ¡$í¤æ湎²¸ºò d¡N@ò¦‚Ÿ—Ðÿmë§ûß©;ú?ÛÎÔP¶»î_ÞJý÷0»â)ðfa…ˆÄ[“ÇÙœHoÃ{z/ÏÈŒÿXF96ª•qU.V&èB‡Öµ*Œí`$סӒ’²råÊÇû|>V¤½NÖ3ãZ\Bý¹îŠ;KÏ×ÏŽ»›ÖªBâ£GöÝÚXÜôæKMèhÑÁ—Ç+똂½´†s˜ÐøãÎTä ØœôIæö,¤r¶/œnºÄTÅ`m„îV¾GKºÍ…#$3ƒdí ½0­¹B0*ýÐÛ;@ÿÉ™®ë¶ÃûÓ_¨ÎûŽßU.ÞTúђ篯`v#ÄÆ¤"ÂÑÂ32ã?V_jâ%‰DÊ:…¡5,üx+FrÞi6›×¬YSQQÑÝÝÍŠ” ×Éî0MEþê¶Á»“^ªßœõÉ=_;g߬Í|fúi®q µ ò˜ï‡Pv`5 šK#Õá:ŸÓÆÊ†V–ŒÐ=â{Ö?ŽcÀ‡.j‰Ú±¿àlB^-Û¦|ö±È´iqrÁߪy þ÷]SÁ- _J W`èû¦â”¾Î OjàPJíoR˜©.áoç-ªí  Ѻë¬ÊøæÍ>*øo¯· ÞºÛ‚á«#Fg#¹ÎVæÌ™³bÅ ³ÙÌòšÔ¶œmô6xÛ¿lë½€èÅ*ÆÞd oò+à‹`p'šÎøò›Ï©à¿j÷5ü߈žãªU #®Dü"h„gt2Vk#¹:sl6[bb"Ë„ãöÌ-•Õ¯£Wõ‹ëÑ»sÿó¬bÜátÃ,7Å>ø×½&KU6½ÐHäâ+Õ$T«F ]‰ø%h7Â3:«µ‘\#¬R ÐÇ}ž!ÜS“‘“Î-‚ø=€qÁ:¤«L2§€‘¢ËŸ\}Ài "Œ|ybcQæò¹ók[ÎÞž¹ešM'=2ÿUûkÌ Ð) ]ad§á÷Ë;žØ‰Súñwöö tþþ“H”»‹Ž0 x@§€tu„‘/OÜ8…ŸgŽœ?4HH˜‚^YI'Þzh=rliU8Üü:…„‘0䇚¼Œ…àõH×PŒTº-ü“ƘÒa4¾#; ËIä´Žîgü'[®œ¿Þ18ÄݵÀ¾õÌ^Tn¸a˜ì€à]éŽÝV;ŠÄÞLèÌiðx<===,ŽZ9mû¾Ë›º¶n»òæÓw<úÙ³·’MÎÂrWQˆe@ð€Né9 ­­­ÇŽëêêbyMn“Èi7úoÅ™ýï>µdOZÛ²mmNT8ËD,Ô ÏÑB,.¹ÄJ(>¡œº©¼]ðù¢ÒäÓ2˜qrKX©ª»ÒŒh Œw‘•›u³­Ø6~! û•v\šç‘·ƒ-ƒ6|1!J‚—nr¥*U,”ÒÎ0K^è/ƒ‰†T€t G´¤+–©X¨ÈáâDÁÕ¤zÁÛlØ€ÊHVZ+É ¢‘ÚI ©Ç¦5¾ô—Á¶'±y^tEyyyGGÇÞ½{¯^½ÊŠÔyî÷ŽþþAû»~æÉ¢APÖ¶§7®B‰ÖsFµÌNJMÀœDD§!@p!KâR’’†*ä¡DH;t«à~$Æ8)Ú}#Xâ¶äI’»)Þœm’8… »¦ØŽÈXu;`DDEðrÝ’£ŽHBÒB ¨"TH¸YÒw1‚%nKž$iÑ~i)HW?Dm¬ @ù1•Z”ç5#N+*’Ôª5%-— k‡m ßL°D ñGã·Çiº‰¨4ºç…þîiHIIY¹råáÇ}>]z¬gƵ¸þ„úsÝw–ž¯Ÿw7­U¥ùR“…÷ÀaSIÁæ¤OðÆ¥$»%ÝæÂÑPi5 a.?ÊHäÛ ð­Û³ò8]êu„ÉvdOöÒÎarpB´SÅfi÷p³6:=d²þ È÷(ùh!ÈÚA{q%Ž©û(„kÆ_ðJºUV)Hã.]ŒXà4F¾<±±(sùÜùµ-goÏÜ2Í¿‹¦“™ÿªý5f讎0²ÓðŠûåOìD‰)}ø;{{P:ÿI$ÊÝElj < S@º:ÂÈ—'nœÂÏ3G N $$LA¯¬¤o=´9¶´*nþY›BàÁ?Ìï$†©àµû‚‡SÒ8ŒÅX­Gt©a#; ËIä´Žîgü'[®œ¿Þ18ÄݵÀ¾õÌ^Tnh-Žm‹jSó ð ÷Øè®ŽÐ™ÓàñxzzzX&µ$rÚö}—7umÝvåͧ/îxô³go%›œ…ä®*¢6Ë€àÒ5*:sZ[[;ÖÕÕÅòšÜ&‘Ónôߊ3ûß}jÉž´¶eÛÚœ¨p–‰X¨Ažˆ…X\r‰•P|B9kóvÁ'…JKÐÄœÁ,ÈL½„•ªÌèeͪE›!-»Y9²6 îE¡w’Π‡‹b'&¡ý—Ô’Í¥ßkZ©q1¤–ï-©ÅMðÛ†´=™‰’àRm¤…ÚÇ”'Df8Ã,ùcŠþ2ØñÛ†²ßµ„²G…<¼l´á{Œž¨HW| %ù£ X5…ð„Ôã Û–WúË`Û“ŠI¢á€®(//ïèèØ»wïÕ«WY‘:ÏýÞÑß?h÷ÀÏEÉIMÔ/;’ê…Á¤â!Bt3œWú.F°ÄmÉ“$-Ú/- ˜$“8… »¦ØŽÈXu;`øDCº’¦p(Ñ_¹bƒR™†*ŠµÇ·D°Ä­Ë“$Ü=+Õ¹†õwOCJJÊÊ•+>ìóùX‘ ô:YÏŒkqý õçº+>î,=_?;înZ«Jó¥& Ô‘š_ˆÃæ¤ÏâÆ¥/Ú¹%ÝæÂqMi5 F.$ÊÂ|'` ŒÃ‘ÈCWxšK#™aç û„‘¢Ð¬ÈwUô“a¶3²þþû$Ñåw–4ãøjìœ0-øá¢)³ÑŠJP‹˜Ð=†=11 ºh0¾Ò•è1<” aUté4øýþÊÊÊœœœäädV¤½N†¾ô¸øS 6,܇²*ßK[W7oqÒ¼û9!J©iVOA19NèˆIOÕqâ÷G•M¬‰n‘p°3™š™ms¡#Ç*>¯Ç–nA ¼ -ŠQ³iV.´YÕj"o',öŸ´L]Ò¡à—#C|ÁMáûD_!WU\\ÅÁè-f|?¶(È̽°h¦FF¿žÊgFEØÁ3T7qDAº¢Ù¡”Ô@ÚèÏièì쬮®^½zµÅ‚šÓü»Ð{ï-S|–^eØKkò\$`S.—-^ü·z±ßg²Xé"[¡Âd± â+[c"î!òÿ8’ÏõZ#wH¥ÍÚK}¬ iW¥‡ÚÈÛQÄž•GÊBÿEµApËM¤?8 ªOî™+"û>©ù…V—‹~n€0þ‚[$2+A“2²bŠ'Cx½ud'…¢Z2aKÏ 1 ºè1îҕ舥l –Ö„­‡è„òòòC‡!-²¼&ïømÿ`çõ›>_½¹&0ô}SqJ_ç…€'5p(¥ö7)ÌT¿ GT¼®¥D7þ„…ytž ª–aª‹%ÝX=”ÆÑ°ÎVæÌ™³bÅ ³ÙÌòšÔ¶œmô6xÛ¿lë½€èÅ*b Þ¥d(9¾ê¸‹ ØB™1ÀåÆýFó‚•zcPÝ801ÒÉ¡ 9 6›-11‘eÂq{æ–Êê×Ñ«úÅõèݹÿyV[ØK™G‘,[)‚˜Kq¸òj òTFò¡,UÙôÆ`€ó‚zc PÝxuéŽøP‚†‡‡‘V)èã>Ïî©ÉÈIçÕÑ4< S@º±Ê$s)ºüÉ%Ñœ"ÂÈ—'6e.Ÿ;¿¶åìí™[¦ùwÑtÒ#ó_µ¿Æ,À@€àoŒì4¼â~yÇ;QbÊ@_ þÎÞÞ”Îß§»‹Ž0 xÆ#_ž¸q ?Ï185~h(0½²’N¼õÐz4'£U{üã˜j3áÆŒ‘ ~¢5€2S"„“T1²Ó@#§utœ8ã?ÙråüõŽÁ!î®ö­gö¢ò˜ñ`lˆ®àÇî?kj~CÀ ã3§Áãñôôô°L8jIä´íû.oêÚºíÊ›O_ÜñègÏÞJ69 ?È]UDm –ÁSèÌihmm=vìXWWËkr›DN»Ñ+Îìo||÷©%{ÒÚ–mks¢ÂY&b¡yÄbqIIp:ÅòÏ%3-TOι”Ì6l@e8‹2Œ°Ï* iG´€ËOðdM‘ 7ÛŠmCàûbì°€´çÒ<¼l´á{Œž( á {@Åz@E' ]& ÞF½¬V’#µ“R3Lh|è/ƒmO*ऀ1$ +ÊËË;::öîÝ{õêUV¤Îs¿wô÷Úß=ð3O ‚r°¶=½qJ´žû3ªevRjòøØæ8‹" R“GR،ٷP6ã‹3‘}Ší ]Ðw1â¦DvŠÓÁ^²RüÁSI'q HvÅPjGd¬º0|¢&ø  èÑ“PéqEy^0â´‚ìeµjMIË%ÈÚaÈ7,QBüÑøíqšn"*…“"@÷4¤¤¤¬\¹òðáÃ>Ÿ©@/ñö̸ןP®»âãÎÒóõ³ãª4_j²±È©ù…x,@ B:¯B8\/Ý5ogÏÊãHÐs³`Œs6B³4MÚ±—Öp“ƒb¡*4esÒÇãþð;ú†á ðã{G‘ïÑ’nsá0°Ì Y;h/®£dZå> ±Æ”qE²FûoÌR•MïÆŽ¨^N,P8) 1rÀ*}ÜçÂí`9éÜ¢:š‚`L™dN#E—?¹ ú€Ó@DùòÄÆ¢Ìåsç×¶œ½=sË4ÿ.šNzdþ«öט<㑆WÜ/ïxb'JLè ÄßÙÛ;€ÒùûO¢ñtwÑqbÆÀxcäË7NáGñ#§Æ ¦ WVÒ‰·Zæd´J 7D±%À÷ 3¢$xü[B½4 cŒ‘ô¯£{àÄÿÉ–+ç¯w qw-°o=³•k£ vÀ°‰’àSóÑxz 1ˆÎœÇÓÓÓÃ2á¨%Aÿ¶ï»¼©kë¶+o>}qÇ£Ÿ={+Ùä,ü wUµ€X@L¡3§¡µµõرc]]],¯ úw£ÿVœÙßøøîSKö¤µ-ÛÖæD…³LÄB{,$?ß>&rƒ§ƒOµe‹äO {ô­h•@¼!ʪ˜…X!‡‹òW|xnˆ1ΰvøå ô—Á6'n¶Û†Àw Ä@Ôyɇåyäí`Ë  ßC B¢'xŠüÀò%Dµôà‰ŽbÐ^Ø€Ô*œ¡„ìg˜%ß6úË`í’ Ð0L8]Q^^ÞÑѱwïÞ«W¯²"užû½£¿ÐþîŸy²hüžƒµíé«P¢õÜŸQ-³“Rƒ#[Òè38IÂÍHÂΈ²|’lE …­HÀ«Ð86Šf(Å[Õä‘”¨DŠ¢1j‡¾‹,QBü‰øíq:ØVì²xs¶Jâ*슡ԎÈXu;@…h ^å@ãvÈðñ”škCe#W¸¡œäw„,é»Á·%O’tpg¬4 ã†þîiHIIY¹råáÇ}>+R^âí™q-®?¡þ\wÅÇ¥çëgÇÝMk5±9éãíYy‰›oI·¹pô]ZË]GÉÜÃ}4ÆÆRÂV$²¾<„®ÌìR]W@8\¯æçR0¶—Öp“ƒò²išÃE³ñ'²±èþB0¼Aj~a^hä{”|!ÈÚQþ®€H‰Šà òJxµâãI¬‚`û¼,z@Cd#S¸Ð0è]Þi6›×¬YSQQÑÝÝÍŠ” —xï0M pܶÁ»“^ªßœõÉ=_;g߬Í|fúi®q µ ¾ù+PÆáxùd¡‡ðßYÒŒƒØ±Ñk”ˆf/áCóh7—,Fc/®#“ÃaƒÇW¡{”~ŠíŒùw5éˆ¢à‡¥ÃÑ]¢K§Áï÷WVVæää$''³"%è%^4(Ä ÄŸZp°aá>”½Pù^Úººy‹“æÝÏ |"3h £óšÔÌl®ª¸¸ŠÓC‘Í…Æ–U#5ÍÊE`FQ0voÀ#,š©‘ÑÏçeá¼ñ:©OÕqÒ&YaÓGŠJ÷D߆ø2¯B;}W€:Q¼ü@£OA1ùŸŠþ_Š&ýbO'à¤:T6€†@·èÏièì쬮®^½zµÅ‚G ¦ùw¡÷Þ[¦ø­¡6"Øb©ÉR`e—Ró ­.ŸS J5V¶*ª1¡±—úœoFììYyd5Ua‰q š”‘S<Âë­è/­ÎõZ‡1K³Y½xÖ…?¡°DÌuOþmQj'¢ï P&Š‚WÐaiMžËs¹\¶ôò±o"µ8´/ò¥ Ð0è¶^§ÊËË:„†Q–×äý¿íïì¼~Óçë¢÷…†¾o*Néë¼ð¤¥Ôþ&…™ŽÝ…> ›Ø¨Pmn1$x|¡ –!h¢ÎVæÌ™³bÅ ³ÙÌòšÔ¶œmô6xÛ¿lë½€èÅ*Æ|y3 ·Dñ"†ÂʃˆÒwe@bGðîâvÉ`Ø€†À8èÌi°Ùl‰‰‰,ŽÛ3·TV¿Ž^Õ/®GïÎýϳŠÑB~ám©Ê¦·X/öRæÞQ"_Ž¢ù]‰<9|‡+¯f„Ï €q0rÀ*}ÜçÂí`9éÜ¢:š‚`L™dN#E—?¹ ú€Ó@DùòÄÆ¢Ìåsç×¶œ½=sË4ÿ.šNzdþ«öט<㑆WÜ/ïxb'JLè ÄßÙÛ;€ÒùûO¢ñtwÑqbÆÀxcäË7NáGñ#§Æ ¦ WVÒ‰·Zæd´J ÷ä‹}; ?²‰’àñ/'‡Z&Ï'€ˆ1²Ó@ƒþutœ8ã?ÙråüõŽÁ!î®ö­gö¢rÍaôG”C=ð‰ ±¶“$ªÕý'€±GgNƒÇãéééa™pÔ’ Û÷]ÞÔµuÛ•7Ÿ¾¸ãÑÏž½•lr~»ªˆÚ@,‚ ¦Ð™ÓÐÚÚzìØ±®®.–ׄý»Ñ+Îìo||÷©%{ÒÚ–mks¢ÂY&b4ç ½%“7{8*ž“œ°Çž’K6& —”°R~CÙfBêE«¥ütHy/Z] 1ö_@Ú#µÊÛÁ–A¾‡Àhˆ®à•Ž6_B´K¨èÐí… H­Tçd»‰|¿Ã; åA%Œ‡ò œ•Ô’ÍGøII-œ €áÐß剥K—9räÚµk,¯ ú×ó“óÜàZòԬdž†"¼ñá$¤?{è­§`'WÀQk\S.I¢47ؽGùÃeŽFà埋6Bòz ¼Y´Œmè..°²8Jו4Ë‘˜™hCG˜¬›*ïE««"÷/7tÜ’}­JÚIÍ/Ìã#%s<ˆ8DKð¹ŒQ ;þe\•44¶¨i€„§¤å2KŠ*òýû4”u1|H*²ïÐ3HZË3²O '`@ôç4¤¤¤¬\¹òðáÃ>Ÿ©@/ñö̸ןP®»âãÎÒóõ³ãÚTåâáG4nØœôÉóö,4¦°˜ú8Mbñ7_jB»ëpy¼¤ch&Aó8C±±ˆ7†–t›+8IQhÖ^ZÃ9LÈe໦¸®bx<ˆ±Î2ä{Ôꡬ´6(ºBtŸ1":‚ÇÈ>*á5‹2± ‚íó²èQÑ’Lç$¢Æ~‡†íŒÂ$c„ŸNÀ€èòFH³Ù¼fÍšŠŠŠîînV¤½Ä{‡i*šjmܸ;é¥úÍYŸÜ3ðµsöÍÚÌg¦Ÿæ—PKt Cdˆ¢æ¢èü:žeؘ…øN+4—ÂÁûƒë–!„6+!½¨‚ÇB¡{ ßC„ÐŽýgš¯áˆ€lDÆ€ñ¼€¦ÞÆ QÕ~‡ÙÎhÏ 0ºtü~eeeNNNrr2+R‚^âESÜ@ü©îCÙ •省«›·8iÞýœÈG†-»¬MéU×$¤¦Y¹àåŒÏËâ7¯Bˆ&hE#–Â$HÞ,šá1u ¶ÃÙ‹OÕqÒ&ÞŠŸ?QöˆõP|%V¡ÔÌl®ª¸¸Šƒ!q ÁäG•ðËîèÿœt.NìÙr;®ÕR8‚¢î~Õ·–Ï a|R8Aƒ£?§¡³³³ººzõêÕK˜àþôoï-S|ÖP«†½Ô—]e‰ìf%dëäØÂ(™=¡Íçz­3¶4j²X•®oJš-AÓ"²¨‰ç+Ø£‰p/RlV/žäá½ —9²¢ÕC¥vRó ­.—â§FDÔ¯pôQ ¹{‘ËeK/Oû&R‹#G‹¯æi#Õp÷«†¼EìYyä*†òy*ª 2²O '`DÈBžn(//?tèFY^“÷ü¶¿°óúMŸ¯ %Ð+0ô}SqJ_ç…€'5p(¥ö7)ÌtÁßç5ZTÛA¢5b`TÄàñúýD؉Úïh0&:[i˜3gΊ+Ìf3ËkRÛr¶ÑÛàmÿ²­÷J «ˆQøùCu¢Ó૵p‡×˜;‚w°•üa3*ab¿1 œ €ÎÑ™Ó`³ÙY&·gn©¬~½ª_\ÞûŸg1 ÿã/FÄ‹½±þ:^¼¥wŒcÁD žS‚ÕGå;|F ì1Ùo¬'`Œ°J@÷y†p;XFN:·¨Ž¦À€€àS&™ÓÀHÑåO.ˆ>à4F¾<±±(sùÜùµ-goÏÜ2Í¿‹¦“™ÿªý5fÀxcd§á÷Ë;žØ‰Súñwöö tþþ“h<Ý]tœ˜€qÁ0ÞùòÄSøQüˆÁ©ñCC„„)è••tâ­‡Ö£9­R 1k‡þ)|cÏHoàÌ€qÇÈN ú×Ñ=pâŒÿdË•ó×;‡¸»Ø·žÙ‹Ê'Ç0:´‡`Q-Ž?dŸÒë<ãΜÇÓÓÓÃ2á¨%Aÿ¶ï»¼©kë¶+o>}qÇ£Ÿ={+Ùä,ü wUµ€X@L¡3§¡µµõرc]]],¯ úw£ÿVœÙßøøîSKö¤µ-ÛÖæD…³LÄ" äñ·ø¡·dVíf©CÂóê‚3ñà#ìØSrÉÆ„`Áâ’VÊo(Û,Y­Üœ/!MÓVGÐ[yßP‰ÃÅ#÷„~I-Ù\úXÓJ‹!µ|oI-n‚ß6¤íIHT/?‰J£öÁå i g˜%pÑ_;ð!]bÛBö«ÐgIßeyy;Ø2hÃ÷F@W”——wttìÝ»÷êÕ«¬Hç~ïèï´¿{àgž,¿ç`m{zã*”h=÷gTËì¤ÐH3â89¨„cÑgDI’¦&tœBÉÐ05BÙR0§)”Ј]#­šÂI’"a}ä]%E¶Êí+åfA„Bq­¸ï2îP°PÖ¸©¥†Â&¨Œ·%'#ѼìˆR<ÄLz %  ¾¥ Þ%}#Xâ¶äI’í—–†(M’ÀIœBŠ]SlGd¬ºLVôwOCJJÊÊ•+>ìóùX‘ ôoÏŒkqý õçº+>î,=_?;înZ«MU®$®ÍIŸoÏBã‹…ÓM—ðääRv#.—tŒÍžÐŒ\ÀÆ"ÕZÒm.ãšÔÊÔÊ÷‚Jø&Só ñðÇ~oå}“ ðqdà–ó²è—†;Ä·¦q¾·Â&ÈÌu”LöÜG'}tŸ¨^všWyòäÁЕŽc8å(èÍ^ZÃ9LN­x²hh#ë³€|Z'Ȇ.o„4›ÍkÖ¬©¨¨èîîfEJÐK¼w˜¦8nÛàÆÝI/ÕoÎú䞯³oÖf>3ý4׸„ZÊð ¡$t ‹hB‚FÂæ’ÅhHÄ<QßB(ãpÐýÐUS‚Bmè^FÎ0Û‰ðãŒ<Øì/8›v–4㈀ìߍfü/ ‚±ESo£U—bŸC÷¨}¢1@~]: ~¿¿²²2'''99™)A/ñ¢a"n þÔ‚ƒ ÷¡ì…Ê÷ÒÖÕÍ[œ4ï~Nä#Ö]Ö€æB‘^ÍLM³r.4ʰ,Âçeñ|ñŒ©‚44X*ÍÑ0ÁZù^P‰§ ˜ ‚h€ÓZ#o',~Ò2£‘ñ« ˆ¯{ªŽ“™ÝÒMR3³¹ªââ*mÄø ^vа S$j(èͽ{ è #ÿÁ‡s²ˆP CEᢠä#DNCggguuõêÕ«-–0Aö§ùw¡÷Þ[¦ø­¡V {©/»ÊÙmPÈÖɱõP2—AsšÏõZ5&OlUÖd)°Ê–‚åµ²½àeÞ<—çr¹lÑå mäí(bÏÊ#k¼ÊGT·ÜDúƒC‹/ïha³zñNa½:5¿Ðêr)}+“¨^~ÐØ+/UD„Do%%‹dÕOè±cáÉ"EI6 ™ÂµN4 ¶‚§ÊËË:„†Q–×äý¿íïì¼~Óçë¢÷…†¾o*Néë¼ð¤¥Ôþ&…™¼²+Z’Õ ¢{ÖB{ÐQ¼ê!ˆaÆªÏ ?:[i˜3gΊ+Ìf3ËkRÛr¶ÑÛàmÿ²­÷J «ˆQøÙcx³;wq[ã5øz2܃¦GÁJƱÈTЙÓ`³ÙY&·gn©¬~½ª_\ÞûŸg1н”yr”HÖöƒ¿>w¸òj òTFò¡,UÙôžöÉ?Ç ?ÐÂÈ«ôqŸg·ƒeä¤s‹êh €1e’9 Œ]þä€èNaäË‹2—Ï_ÛrööÌ-Óü»h:é‘ù¯Ú_c` @ðŒ7Fv^q¿¼ã‰(1e /goïJçï?‰ÆÓÝElj <ã‘/OÜ8…Åœ?4HH˜‚^YI'Þzh=š“Ñ*%Üc —oÿ˜kl[Žcþ…ãÂHôzz@T1²Ó@ƒþutœ8ã?ÙråüõŽÁ!î®ö­gö¢ò FqÔƒ†7Àý&­ È÷¨ÕCY;h/®£dêå> Ñ€"&*‚—¬æãUž”½Pù^Úººy‹“æÝÏ |dزËФ=Ò«©iVÎ…F–E OA1"Ñ!Öø¼,Œ5žÏÑ"UЋF8…I“|§h…ÇDÔq28g/"îó áv°ŒœtnQM€Á0¦L2§€‘¢ËŸ\}Ài "Œ|ybcQæò¹ók[ÎÞž¹ešM'=2ÿUûkÌ €ñÆÈNÃ+î—w<±%¦ ôâïìí@éüý'Ñxº»è81ã‚`¼1òå‰§ð£øƒS㇆ SÐ++éÄ[­Gs2Z¥„{¬£Øj6ˆ™%¯ó>Œ’Xë ÀH¯k@™UŒì4РÝ'ÎøO¶\9½cpˆ»k}뙽¨¾ûÔ’=im˶µ9Qá,±ƒ??—,ºÙcëPð»àÂhð¡vüssù’Å%—h&h&؉ÖW6‘·JH=ΰ¶øVÉg °íÃ~–ƒàöH­‡òv°eІï! AT/;‚Ááx…•ŒVq†YòÇýe°}„ÝEˆÂ~Cö¨ç‘·ƒ-ƒ6|£¿ËK—.=räȵk×X^ô¯ç'ç¹Á)´ä©Y Exã'GHì}ö\OÁN®,€ãϸ¦\’Di>¢¯{ކ‡Ë5 ׋J ¬$PMWÅGû p=ÉȤ´‰»˜ß@ñy¼’ýr$2!ꉑM.zðõEýÂk‘Ž"˜+ëdè'ÕꡤÔüÂ<>ä0ç>êʃà0î‚—A5•†•P&ý9 )))+W®<|ø°ÏçcE*ÐK¼=3®Åõ'ÔŸë®ø¸³ô|ý츻i­6U¹x56'}†¼=+³±èø8Ýt \Í—šÐ0Dƒô:\¯—ØX < á¿ÔŒÍK±aÅM,é6—Ô¹"ß/Šk8‡ Ì|ßÙ„ÎÁ;.ÍÏ‚á ;)Ù£Veí ½°±Ù}ùDƸ ^rUUV6"@™`Pty#¤Ùl^³fMEEEww7+R‚^â½Ã4Mµ¶ nÜôRýæ¬OîøÚ9ûfmæ3ÓOsK¨¥ VBǤ°ˆâßÊæ5#ß&(ãpœþÐ%VÍýòË%xJeceÃÄ2B÷¾‡¡û Î&4 ÄÁÿØÿ <ã+øˆŽàe€Ñ¥Óà÷û+++srr’““Y‘ô/2ââO-8ذpÊ^¨|/m]ݼÅIóîç„@>2lÙe h^¤:Å—šfå‚k¬TÂ/ª¢aˆÍ¥ˆ[Å¥ü|Ž¢¸ ~hdU˜ÐÉ÷K—¨ïdœôyY áæãUÈŠOÕqÒ&ÞJÖIé1¢Š/+´“š™ÍUWq02GÎø ^tµU! L0(ús:;;«««W¯^m±„ »O/ñöÞ2Å÷h µjØK}ÙU–Èn‰B¶NŽ­Òy½”\—EärÙìZ1k"…8f®øêFi¶„k²X•.³Jö[‚¦odmO›°ËƒþÒê\¯uó9›Õ‹çgx¯Âb2CöIµz¨ÔNj~¡ÕåRü4€ã.xéÔVi„€2À °Õ_J W`èû¦â”¾Î OjàPJíoR˜)¤&³9é e£BµT!ZG´Á‹eÀÄ£³•†9sæ¬X±Âl6³¼&µ-g½ Þö/Ûz/ z± ½ÂOd™Wwà‹Æp£Y¤èDð L˜,èÌi°Ùl‰‰‰,ŽÛ3·TV¿Ž^Õ/®GïÎýϳ ½ÂÿH1²uã „ünÞR•Mo\"@'‚eÀdÁÈ«ôqŸg·ƒeä¤s‹êh €1e’9 Œ]þä€èNaäË‹2—Ï_ÛrööÌ-Óü»h:é‘ù¯Ú_c` @ðŒ7Fv^q¿¼ã‰(1e /goïJçï?‰ÆÓÝElj <ã‘/OÜ8…Åœ?4HH˜‚^YI'Þzh=š“Ѫ1ÿh+¢‡GNnˆøkl¢*ø˜BñìÓÁ) úÃÈN ú×Ñ=pâŒÿdË•ó×;‡¸»Ø·žÙ‹ÊÇbýÆÑqHÄ_˜ Æ_ð±JðìƒSÆ9 §§§‡eÂQK‚þmßwyS×ÖmWÞ|úâŽG?{öV²ÉYøAîª"j± €˜BgNCkkë±cǺººX^ôïFÿ­8³¿ññݧ–ìIk[¶­Í‰ g™ˆ…äqþ‰¸dãfåd.ƒJ.‰ÿƒÛ“Í%Y!õ¢EU¾Iô—Á¶é Û†À÷ Ä@èViÔz(o[møãDT/;úÁáX‡•œl¿a²! (è+’ —”ðR#=A9VN÷N…ˆÞUNI…ÆÛ µ |¡¿ËK—.=räȵk×X^ô¯ç'ç¹Á)´ä©Y …½ñÓ½Ǿ `p¸?alðìäÊH!W[Òl/"ß„<6 .88 ÙžÔ¸‹ù柯‹vÇ›×p;K¸ü†+‘MB “åUþ!½5yÁØ¿|gH`Ì\’Di>¶¶È€õ–•${lÖ졤ÔüÂ<>p2ç>êʃ €ã̸ ^zôÃé_UrŸ©@/ñö̸ןP®»âãÎÒóõ³ãª4_jâøPýx ðxÙ~lNúhúB$BÈxbI·¹‚•¼;27B8\¤]{i ç0!—ùд†VÓ,†ïŒ= ’Ù™dw8Ýt‰íG½·ò=jõPÖÚ ;ÝG!ÀÏø3î‚—ý°úW•œÞF®7ù9¢¸SThcÃe¤’À—jí]„Æ'Òj” èòFH³Ù¼fÍšŠŠŠîînV¤½Ä{‡i*šjmܸ;é¥úÍYŸÜ3ðµsöÍÚÌg¦Ÿæ—PËa‚¡a€oÈBS%¿?¸¼‚(oÈ ‰€feÈÀu>§• ÅÞ†î1|B;öœMh¾ˆƒ² Àø2¾‚èèM…Ç: |¢K§Áï÷WVVæää$''³"%è%^4Æ ÄŸZp°aá>”½Pù^Úººy‹“æÝÏ |BHM³rü2$\ü…óT'“2Oâ e¤ffÛ‚WÐÈŒþç+L‹ÈîBíÉ…‰@ ç c¸Ïë±¥[Pï—ÔG„zoöˆõP|ÁV¡ô¹ªââ*FÎè0¾‚'¾ªþGŠ\oòsDq§¨¿l€ËHåHÆ'å@ôç4tvvVWW¯^½ÚbÁÿI5 —x{o™â{´†ZöR|á½$Z®O˜Ù¬^<3á룴О•'Üu%€†ß+[%5ìâÞNé2(ÞÇÛ›6””,vµO<­Á«Æè/­ÎõZ‡±Ò ï­€døö šTê¡R;©ù…V—KñÓc͸ ^zôÕô?bdz“Ÿ#Ê;µ—’û'¹\¶èò„ЧäÈ>(”`k†:¡¼¼üСCheyMÞ?ðÛþþÁÎë7}¾.”@¯ÀÐ÷MÅ)}žÔÀ¡”Úߤ0Óðð7X郱ê­j;¨B´â Œ'ø_š‹¦â@ù ŒÎVæÌ™³bÅ ³ÙÌòšÔ¶œmô6xÛ¿lë½€èÅ*&~ZÇ™醿’p#XTЉàÇ]Õîâv‘nbå“9 6›-11‘eÂq{æ–Êê×Ñ«úÅõèݹÿyV1‘ð?ŸdŒ~í7ʼ[ª²éåÀ8£Á“ª‰ØWýùñÄÊŒ‘V)èã>ÏnËÈIçÕÑ4<cÊ$s)ºüÉ%Ñœ"ÂÈ—'6e.Ÿ;¿¶åìí™[¦ùwÑtÒ#ó_µ¿Æ,À@€àoŒì4¼â~yÇ;QbÊ@_ þÎÞÞ”Îß§»‹Ž0 xÆ#_ž¸q ?Š185~h(0½²’N¼õÐz4'£Uc„;fåÆNO€hEÁÇ yˆFvhпŽîgü'[®œ¿Þ18ÄݵÀ¾õÌ^Tnèa˜Œ€àotæ4x<žžž– G- ú·}ßåM][·]yóé‹;ýìÙ[É&gá¹«Š¨ Ä2 xb 9 ­­­ÇŽëêêbyMhпý·âÌþÆÇwŸZ²'­mÙ¶6'*œe"ÊàÕÎ ³§áŸJ'~:n°4ô‘¹äyºŠOÑ ÙgØŠ*¿¶J¶$°ÍI…›mŶ!ðK±! ë³Ò>jôYÒ¶ Úð=¢OT/†â¡'J˜@EZPSOH=ΰmyE¡¿ ¶=©Í@,Ðååå{÷î½zõ*+Rç¹ß;úûíïø™'‹Æï9XÛžÞ¸ %ZÏýÕ2;)5yœ¬§Y|2‡S<4¼FPQü›š<’¢oè»Á%ø~ˆ’$M7•{$Þœm’8… ”;§ÔŽÈXu;`ü‰†à%XáУ¿bÑÑ”ü,€LCÈÚã[ "XâÖåI’îž•‚æ`"Ðß= )))+W®<|ø°ÏçcE*ÐK¼=3®Åõ'ÔŸë®ø¸³ô|ý츻i­&6/¿ùRÇGßOÍ/ÌóxÑ>I|}ypܪ\õ°»¸±áp‘Vì¥5œÃäà„¨»lÚåpÑ,Ææ¤º·g¡Ñu §›.±Io ôM@¾GKºÍ…Cm3ƒdí ½¸Ž’y—û(Dè™PÆ]ða(zK òS9 ‚€æÀˆèòFH³Ù¼fÍšŠŠŠîînV¤½Ä{‡ij€ã¶ nÜôRýæ¬OîøÚ9ûfmæ3ÓOsK¨åXàAÃPè&A4u‘{Í%‹ÑXŠëðÄgøàñRFèSó2.¨¡Kµb„vì/8›v–4ã¨~lä&Œñ¼TcxèAó`4té4øýþÊÊÊœœœäädV¤½Ä‹Æ‹¸øS 6,܇²*ßK[W7oqÒ¼û9!*©iVŽÍ>зÓEVR3³m.4¸R[vYšG)OkH;¡›¸7àmAF3Ÿ—EþÅ8Ržªã¤M2íc+"…=bÐ(ŠFh2k_¶Uh}J®ª¸¸Šƒñs‰‚àEˆìÐ+Ÿ"@ó`Dôç4tvvVWW¯^½Úb ^šzï½eŠïÑj5±—úœM4“¨¸ìâ…j¬l4dƒ¬³«,J·Páv8~Ó†4É"+ xrƒ ô—Vçz­Ã˜uÙ¬^<‹2Y ¬Â’/C²G7¿Œme«ÊJí¤æZ].¹-]Æ]ðraDtèUÏÐ<¶”§ÊËË:„†Q–×äý¿íïì¼~Óçë¢÷…†¾o*Néë¼ð¤¥Ôþ&…™êÑm_£Bµ¸l™(ÁÇê¡ÍÀ£³•†9sæ¬X±Âl6³¼&µ-g½ Þö/Ûz/ z±Šq‡Ÿà0”¦a±¾´ ·ƒM0#ø‘zÐ<L tæ4Øl¶ÄÄD– Çí™[*«_G¯ê×£wçþçYŸc/e>E²ˆû_·[ª²éíåÀÄuÁøÐƒæ`R`ä€U ú¸Ï3„ÛÁ2rÒ¹Eu4 À˜2ÉœFŠ.r @ô§€ˆ0òå‰E™Ëçίm9{{æ–iþ]4ôÈüWí¯1 0 xÆ#; ¯¸_ÞñÄN”˜2Ј¿³·w¥ó÷ŸDãéî¢ãÄŒ€ñÆÈ—'nœÂâG N $$LA¯¬¤o=´ÍÉh@pC$`‚Wä c†‘ô¯£{àÄÿÉ–+ç¯w qw-°o=³•ÇÌ0 #06èDðè9 §§§‡eÂQK‚þmßwyS×ÖmWÞ|úâŽG?{öV²ÉYøAîª"j± €˜BgNCkkë±cǺººX^ôïFÿ­8³¿ññݧ–ìIk[¶­Í‰ g™ˆ…2äÙpìY¸8|".[ JØcsE«â QVÅ,Ä Ù8\œÙQ|ðnˆ1ΰvøå ô—Á6'n¶Û†Àw Ä@Ôyɇåyäí`Ë  ßC`4èOðRiá PY¨|(! à ÛŠúË`[‡ì‚mCïä ãH@W”——wttìÝ»÷êÕ«¬Hç~ïèï´¿{àgž,¿ç`m{zã*”h=÷gTËì$HBÖˆ²|ýå÷ã$Mùœ6I E3”â­jòHJT"EѵCßÅ–(ÁÉ“$ì + vY¼9Û%q HvÅPjGd¬º0ô'x‰$Ha¨™ªâk@Þ ôwOCJJÊÊ•+>ìóùX‘ ôoÏŒkqý õçº+>î,=_?;înZ«Š%ÝæÂ‘{YÖž•ç:J&î£Á`66–Bµ‰ÔO¢òËÃïÊÌ.5Ñu„Ãåñj~c{i ç098!˜/›‹9\4‹±9éóóñNmÙ™¤KB0¼Aj~a^hä{”|!ÈÚQþ®€Q¡3Á+H‹¡7è]Þi6›×¬YSQQÑÝÝÍŠ” —xï0M pܶÁ»“^ªßœõÉ=_;g߬Í|fúi®q µ !5¿!(ãp¬}²‰Ãÿï,iÆð”¿á"š¢„ë£iÜ\² °¸φ†De„îQúm("´3æß€Ñ¡à¥%ä :C—Nƒßﯬ¬ÌÉÉINNfEJÐK¼h8ˆˆ?µà`ÃÂ}({¡ò½´uuó'Í»ŸùÈAƒ ¨èä%53›«*.®â´ dds¡…eÕHM³r˜QŒÝð0Цcdˆóy=¶t Jài©OÕqÒ&™,f‰Çj• ñµ\…v"ú®€a¢Á«KKÈtˆþœ†ÎÎÎêêêÕ«W[,x<Ñ`šzï½eŠïÑj¥°Q“¥ÀÊV_Só ­.ŸS<5V¶ô©1k±—úœoFììYydÉTa‰q šy‘eQ<ãÁ‹ªè/­ÎõZ‡1³Y½xj…?¡°ÌuOþmQj'¢ï º¼†´ä€¼@‡°•:P^^~èÐ!4Œ²¼&ïømÿ`çõ›>_½/,0ô}SqJ_ç…€'5p(¥ö7)Ì4ºï }þ^°Q¡ÚÜ#6†èJðc%­Ñò€ñEg+ sæÌY±b…ÙlfyMj[Î6z¼í_¶õ^@ ôbÃ_ÃŒÂ}Oü¬‡¡°ò ¢ô]M $x79 6›-11‘eÂq{æ–Êê×Ñ«úÅõèݹÿyV1 Èϸ-UÙô>êñÅ^Ê<9JØÕÝX#šßÕdÁ@‚y€0rÀ*}ÜçÂí`9éÜ¢:š‚`L™dN#E—?¹ ú€Ó@DùòÄÆ¢Ìåsç×¶œ½=sË4ÿ.šNzdþ«öט<㑆WÜ/ïxb'JLè ÄßÙÛ;€ÒùûO¢ñtwÑqbÆÀxcäË7NáGñ#§Æ ¦ WVÒ‰·Zæd´ PÁ ¡u~LS0²Ó@ƒþutœ8ã?ÙråüõŽÁ!î®ö­gö¢rFƒ‚`¼Ñ™ÓàñxzzzX&µ$èßö}—7umÝvåͧ/îxô³go%›œ…ä®*¢6Ë€àˆ)tæ4´¶¶;v¬««‹å5¡Aÿnôߊ3ûß}jÉž´¶eÛÚœ¨p–‰X(CýÆu‹ÓÁÞ²Kò§„=W´‚)ÞPžm’¦Ü¬ &ª £!­â ³äSÑ_ÛGØ]„(ì7d yy;Ø2hÃ÷ˆ£žo’/!ÍÑ–Bdƒì„TÅÒ,Î0K^`è/ƒí6ì.B ö²G…<¼l´á{:& +ÊËË;::öîÝ{õêUV¤Îs¿wô÷Úß=ð3Oßs°¶=½qJ´žû3ªev$iDY>‰þòqùq’¦pÈÿ7’vD¦"[Ò”,)¶ Uð;©É#)T‚,é»Á·¥¹ QiHÇ$ œÄ)T Ø5ÅvDƪÛêè\ð¡Ê‘lÌjI㲤ÈV‚b³È’¾‹,q[š»•Â)šèÏi@ïN§óÒ¥K´P ôïWÿëÕWÿ_N|ÑùÿÕ\ÿÕ[•KOý÷0c¨h<#g:¢H‰PϧñV¡‚¤P¾Q¥¦¤i¤Í |¿„$†d ´…°»âLHÇä{”|® jíð½TÚÐFç‚A•¬ÚTj\š!olဨ Ë!Ífóš5k***º»»Y‘ô囹ŽÛ6¸qwÒKõ›³>¹gàkç웵™ÏL?Í5.¡–!¤æ7e¥OÖqtÿ%Í8¾]væ0bÕHÛ+‚c£BПæ’ÅŽH†ºi¾ÔÄR"B÷ÑçÚ鷈Эà5µ:rà€ C—Nƒßﯬ¬ÌÉÉINNfEJÐK¼èÄŽˆ?µà`ÃÂ}({¡ò½´uuó'Í»ŸùÈAÃrš.áë©™Ù\Uqq§uÊ##› ,Ël'5ÍʹŽÒ!®¼¬Œ¢¤‘н¸7à!²†sáËçõØÒ-(Ñ|¼ÊCê#ÂSuœ´‰· í˜Â1¢ïG|V¡ˆ¾=@ý >Ä•x ŠÉ)€ÏR6là€ ENCggguuõêÕ«-<2h0Í¿ ½÷Þ2Å÷h µRÐ@°X iÜÔüB«ËÅçT@cHµÀB·Å£—´{©ÏÙä EUÙ¾‘ͼp#¿Ó†4«"ñýñlÆ.ô—Vçz­Ã˜fÙ¬^D9¨¤&ÏEN\.[¸„0Là€ …­¹é„òòòC‡¡a”å5¡—x;¯ßôùºP½Cß7§ôu^xR‡Rj“ÂLÃ!\–4"!bGj;†þöÆà MÒcHp @¤èl¥aΜ9+V¬0›Í,¯ImËÙFoƒ·ýË¶Þ (^¬b¸à«‘x.uø OÖôÇ„}{FÀ¨‚w°‹a€Sb 9 6›-11‘eÂq{æ–Êê×Ñ«úÅõèݹÿyV1 Ȳ-UÙe²²h/e¾edW4&‰ýöŒ€±O'8\y5 ‘ìNˆ-Œ°J@÷y†p;XFN:·¨Ž¦À€€àS&™ÓÀHÑåO.ˆ>à4F¾<±±(sùÜùµ-goÏÜ2Í¿‹¦“™ÿªý5f@ÄÙixÅýòŽ'v¢Ä”¾@ü½½(¿ÿ$r v'&DŠ‘/OÜ8…Åœ?4HH˜‚^YI'ÞzhýÆ¢LZŒ ø‡fÀhÙiX>w>zïè8qƲåÊùëƒCÜ] ì[ÏìEåà7 ·èûrDµ©ù ˆ~†è9 §§§‡eÂAƒþmßwyS×ÖmWÞ|úâŽG?{öV²ÉYøAîª"j@„èÌihmm=vìXWWËkBƒþÝè¿gö7>¾ûÔ’=im˶µ9Qá,±P&øÜº nœ>º–ͥɟö|[ÑÔ[¼¡<+.Ú$M¹Y9*LTfômòMò%¤‹´™ö"mGþQ‰ÃÅypàb‚ò œ•Ô’ÍiÛÁ–YÓJ‹!µ|oI-n‚ß6¤m ªtEyyyGGÇÞ½{¯^½ÊŠÔyî÷ŽþþAû»~æÉ¢ñ{Ö¶§7®B‰ÖsFµÌN‚$¶Œ(Ë'Ñ_>Â>NÒŽÀ¬FÒŽÈTdKš’%Ŷ!(´Éï³&¤‚[âDºåv‚•r³ B¡¸V\ÈwYò©¥ Zj(l‚Êx+Qˆ*ú»§!%%eåÊ•‡öù|¬HzOCÏŒkqý õçº+>î,=_?;înZ«Š%ÝæÂ!vYÖž•ç:Jf¹î£Á¨36–Bµ ©OÂç‡Ä¾•´Ó|©‰ããô§ææy¼¬û6'}.=nÊÆ"î ÍJPh“Lîn•ð]Ã;!VͽÈÛÁÈ>£4ã§°¼ŸZ«q¾·Â&ÈLá(QE—7BšÍæ5kÖTTTtww³"%è= w˜¦8nÛàÆÝI/ÕoÎú䞯³oÖf>3ý4׸„Z†€oâ ”q8(>YÇqúw–4ãHuìŸmdHÛ ÚͺGÍg˜í4—,vpd²¢1^`§ƒ0Ò£Œºtü~eeeNNNrr2+R‚ÞÓ€þ¿Æ ÄŸZp°aá>”½Pù^Úººy‹“æÝÏ |ä ÿÎèŸ!§ffsUÅÅUœÖ+dds¡ÿj,Ël'5ÍʱÉ2ú»ÓÅÏ¿‡¤Í¢OA1Ù Þ ) ¼°ø¼,´1^b¡EJ ãS‹oUðT')²~C7‰è(ã‰þœ†ÎÎÎêêêÕ«W[,aÂñOóïBï½·Lñ=Z¾…¶ên²XÙå†ÔüB«ËÅçT@ÿÊk¬l‰Ÿ,HÛ±—úœMZT•íѲ€R›¿S²W{iMž‹ì%—Ë]žÐFÞŽ"ö¬<þVG4ó§äz­l¥ATddŸÚfõâÕü9køM": À8¢³'BVTTÄÅÅ-[¶Ìl6³"u>({Ùþ_wÞð÷vÛ÷Àw¡’©S.ìº/m]Ý—žâ®Üø¨Ëøçj¬ úg}4KoÁü›K[¼…zë5ù²w¦ûó Ë£` t¶Ò0gΜ+VDâ1 j[Î6z¼í_¶õ^@ ôbÃ_HŸ›ïø…†ê €"îâvÁLØQ:sl6[bb"Ë„ãöÌ-•Õ¯£Wõ‹ëÑ»sÿó¬b‡ Xª²éÍüÑÆ^Šï4ˆdŽ|*‚ÕWc§2NìQFX¥@ û6ç>êʃh”†CNCJJÊÊ•+>ìóùX‘ ôž†ž×âúêÏuW|ÜYz¾~vÜÝ´V{i ç0¡ÿÌÂ?J›“F=°gåq¶ìLòß§›.¡ºÍ—šÐPVÚáòxI¯Ø"€Ã…3‹¶$lhI·¹ªr…feSÜ‹FW1¼þ/Ï:ËïQ«‡²vÐ^˜×à> ‘¥Œˆ.o„4›ÍkÖ¬©¨¨èîîfEJÐ{î0M pܶÁ»“^ªßœõÉ=_;g߬Í|fúi®q µ5yl>Ž@ÿЛK£ÿì8ãsÚ˜…©ù @—‹þG‡.þ „6+!½¨‚}¡{ ßC„ÐŽýgÓÎ’f’y+€¡Ð¥Óà÷û+++srr’““Y‘ôžô/n þÔ‚ƒ ÷¡ì…Ê÷ÒÖÕÍ[œ4ï~Nˆ\ Yÿ I½ú?J1©iV.xyãó²˜ÔÍÇ«<´HôýÏÖ‚È›•tl8{á©:NÚÄ[åe‰]…=bD=ߪ ÐNjf6WU\\ÅÏ`Hôç4tvvVWW¯^½ÚbÁÿ15 ÷4ôÞ2Å÷hùÐü,®ãy³úÅ1öR|]Ÿ.ë“)9Ú”æs½V5vqÁd)°*Ý i¶DÚ±÷"Åfõ╼×àõŠìƒhõP©ÔüB«Ë¥øiý£³'BVTTÄÅÅ-[¶Ìl6³"u>({Ùþ_wÞð÷vÛ÷Àw¡’©S.ìº/m]Ý—žâ®Üø¨Ëøçj<9@^ÀÎt»½s¨¶ƒ*Žf)Þ× è­4Ì™3gÅŠ‘x ˆÚ–³Þoû—m½P½XE,ÂOê‘]‰5ðí p $€aÑ™Ó`³ÙY&·gn©¬~½ª_\ÞûŸg±ÿóI†îæê䉖ªlú“ Àˆ9`•>îó áþÇŒœtnQM Í$s)ºüÉ%цãþü÷þtPN±"IEND®B`‚pyclustering-0.10.1.2/docs/img/fcm_segmentation_stpetersburg.png000077500000000000000000003505231375753423500250570ustar00rootroot00000000000000‰PNG  IHDR‹q‚é„ôgÇzTXtRaw profile type exifxÚ¬½Y–$9–m÷/£¨! ‚F†ƒv-΀ÃçÞPì*³Þã##2Ý=ÌÍTEÛœsÛkýßÿ×¾þë¿þ+>¡ÔëM¥æ/ç›Þïýbãõþýóû=Üïùõ÷¥þçO៿~•ðç‘ß~~‘×ï÷Ðøzúû”÷Ï×û?ý*ã÷‡Xÿ¼ÐŸ¿øëß(ò‡?ßWÿ¼Ð_þûúþü\{ÿáãüù,çá}÷ß›ýË¿…؉×{âמ›__ßåá žïiüþòkx¢ßô<üù}òùúóïÏîúÛÿåðÖþó„ÿrvwûóÏ?Åuç?ßÿåŒþ|=¤vç„þñ‰Âý·[û§¿(oúëøþÛÙí=ëÞë÷éÚ›9©|ýùP÷Ÿ—8â9Î÷w™ ÿOü¹œ?þ­|ÄÁMn³óï¸Â"§½Ãfha‡u~aðˆo\±ð{Œñõkõ)ñ‹ã\Êë¿aÇÂõÌë©ÜÊàÖ¾ÿö,á¼ïwÞo„Ê;ÏÀwÆÀ‹q—ÿýßëß}ñÿäß¿½ÐÞŠn&W~•iÛóW¾‹ ûÏ™¦s¾çßëo×ú÷¼Ø‡Lç˜+°Ýý÷=…¿ËÖsîùáûÒý^?¡¿C™^€#â½nàÎáI!‡»ÄXBà+÷Óxòø¼±s!¥8õ¹›çÉ\N¾7?SÂùÞ˜âï˘."¡"…«A¸¬÷MÈOy+2ÔÒ“Þ+¥”SI5}©å'¿9åœKÖFµò”·¤’K)µ|¥Õ§¾5Õ\K­õ«í‹ßƒ K_þÊõÕïûZãM/ÝøéÆw´ÖcúÛSϽôÚ¿Þâ3Þ‘FeÔñ6ã|&ê?ó,׬ó›m……(­w¥•WYu}«mdm?ûÝiç]vÝßn»µ?·úÏ·þåæþç[ nÍ{Ï÷•¿ß_.寗š“äqcñ Üxñ4NÞÙ]ÃûFoÎ;»?ÍUŠÜZH^Î Þ7ø®Ó»»¿ßÜÿxoWzÿ_Ý[üO7wyuÿÜÜåÕý¹¹ÿ~oÿæÖf;å9¤z¦÷³1l;åú[füúËëž¿ž1{=óž“Æ §°f*}wÌз·¦;§¯ì¹kâ?Ûºp«gßµ4xöo÷‡göð˽ÒäCÉ+|©÷üF¹ŸVWé©p_Š}ŽY¯ÖŸ6FÃxñÙr¨™káAÖÓwâ¤JjÏSò‹ çyï——Ù 7|ªµGô÷šÞx&òin?OñËe¾9ö4¿öÛê7qŒ!µ‰Éüx‚\RÓì÷=½òƒ¶|>ÏÀ”òI¾üì•Ãç+þõz/jpá•§|"Ùùöè羟/ D}®~Ï‹û[¸´É!¶?‡89Í¿1ûµן·èÿð“ŸmÖö¦ü|×m¾ÈÙùG¡òOß?¿\ x¯|­¿¯ç›Ç}ÕvóŠ{)Zçëï“ýý[ó;#h!¯‡Û䔟½Ó8õn­Æ½8–ëë£!¶õC=kLé⇷¢¢M[Ÿ„ÎûôXõ(>^òùý.ûÏߥtÃ$s³=ú¨%¾•«ì_ ­èÏ\£æÙ_®itlÀ^;/„!”K/×îi£3£ÛhÛâ›ZïÆ–LþPb_èXV8ž¨g> –©mç0ÊÜ£¸ÀܵIøí9Joɱ1¤ùªÃ(êʳJÚ³Éép°èõudgŸ"Æ™9÷¶ÛD‘öýL faÔwàã6¯7×A™/¿¼uŒÒ3ªÓ0™W«7bôF¼q­ ‡ÉMbæº?w£Ç|¼Ë31à„2æÅ³ÿ€hôz¥ ’á=_LÜVçENGæüž¿Ûo /@8qˆo/ß“îžßÞËüò˜(Í÷õ®4ßÞëÒÿ^Ÿ17?ä­‡8ç;úýäUß§ƒx>lxGï>\ÉÃg»w»‘¶«}+`Ö*ï³9ìªý~BÃl²Î>RyN¬J…ØÜbâfæ3ÔìÉgÀו>úÁgãÝ€„¼Óâ”QpBmÑ?üãï¹ßˆKBR[Ä#¼sƼ¯¶1e³ÆÞ¹©ÞNë[8Å$p¬ÀêUÑÂŽlĈÓ}â;KoÏÂÌðjD÷“úõ Îßð#¿% nx}߾dzî]gÑP·`;qqƒcÇT¾µ^Â=E”~\èߨWOQÇ1HcçÓŽA•º¼Úñ/`Ó×”:êzn¬è¾Õ'Ü ÅÏ5¼bFRÑýb.Â\Ücô"x9M¬Nᇿg­{–œ:nd$ªšŒ­Ð.ß ‘o£3¼Y¨)­=¼vÝð‚€DàÎ2¾ ÛYÛXàø¯œ5V/¬·À•ð]xB`+güð2ò ã#sØOˆù·ï ³H¸`„n¡šããè¿ýp¥¨'8l\œÊx1IëÃJq<‰µ`€à.R~Ü%%°˜7þ1NdãÞ×W@i .ÀU ±õÊ«‡]¼õœ‘W.½w¾µ‡–$ŽæænVâ~ð›·ËOÒÂÒ] Ítš´–1i)‚FÁϤ½Þwò±žT‘÷Ä—ùù’ÃŒeÇ„÷Cez=دÏôÅ5óÆb$÷É1bÒZà¾æ([Gn°$ +©9%!3ŠÎ@Å 'U¡«<ØzoÜ–Xƒ¹Ç–¼sÃ1µ²>ÀPÇÆï ?WA5Ü"&\÷ƒ‡-‹[Å"`æ–6ÓøñpóØ©Â3|àH~(>s Ë_ènÁ ;ò½ÁS%ïïr‚kò´ÃãÝ Î2¬ÔÖÂVb³s7NþŠS–Û;Ÿ5–‡Ãá>ŸuhÖ4JH#á†ÑÖ«T"ÚS^îw‡]BD;ˆ ÀÙ•ˆrw¥7“á<°à&  òFúsÃÉåGC0ñ6ü ï‘Á'ôëk8Ø€RšLÆXkŠÒa4¶’〺û¸¨SŸåèB<9à.}ÀÊ !=—Ä|‚Œñ;ÈÈŽ€ Í¸Áñ“ÖápÓ°ëw¢TQ]a_D§x—x_S¡ÇYéVÄì…,™gEóîå ÏÒöB@óûÇÇ÷(àÜůb{@ R „âl8|ÜDY7†¼¹En%·–§¼̓gCˆK#w|ÔÐW´û^8‘%òn—DbÏ ’KMÏSˆjåÄKNñXoUáöÃ…‚fKº4;8IÌ:S±;hgþ0мJÇp½†Ú„™ÞU&?¹àpE^>îþ¾KQ®;gˆ¯‡Â•q¬¨''‰’¡Ã÷….Ô‘“æ”Q}ÁË;T4¹A¼\â (3æsËMƒ-@5ãäãn¹48#~Âû¾êâ@‰Ç±>o“a€±üqG8-¾ªbZ{ó€7xøÕî&ð®”æÓ8F@`FG«¾sšúXp1”¼r,áB³ ]«Qì0³v‡¸±$@Q±7ç ê¨À¡jÐ…¸Ñ]0Àa!¸î°øLóâ²D,¹<5ï¼àI¬,AÝîZsrœ½Í-ÊŒ.ß.]Úw¾°F|R,FE€ËÓ5£èïý¦‘ \4Ÿ°¼cã1å¸È*S݇]c¤qkx‚+ÁXV¯8”]`—•þ Åð@õ0ÄOx·'øusA©k2´t/->¾ªcx{ oøôOƒ %é+ˆdÐ^!·ÞEX}U±ú³ĺð¿Ï±•Ö!ö@"L7 oذç‘oy\B™µ&tǬð‚8Œë]—¦8Ã2Ò…¥ªB9€U¨7Í£-«~P"¼_:‰çà7L\@qA”ˆbz¾)¶rã¸. [P öŸQ7öÄ€YÇppñ/Èaظ'1ÏË!âi9­ŽYGãŒ3ìOšu´‡^2;N„µ"ýèôˇQ½E‘Ž?)ÌׇÅz0ìІŒôÌ õ`ðÂÖ•ÏfÐZ¶„ï¨þ 8·Y•/ðâxÄ^ÍNo˜¯ ¦ŠçÇœ#²¸¥UÇý=Ï;aN |7z;Ò ˜Ü€ T7 ,èþ> c¨6fJ[õç¼ §ˆ”+Ç6mUjV+Œü˜¢g*gY¯²®Õ"Ö¡o€¹ôpç/r]t“¸Ë{dÅ ãþWXÁnÀ„’S˜9¦]¨ zI( h…ÿê\l*ƒpå#œò†pˆ!|¾u)ÀP|Fà|ǵSÂ2 Í)"lDÆhá:Ÿ >+eMÓDÞ± €ä÷Çb"±àްø˜‚DB0¾þü¨†¢˜d>ÝøŒòsíº¾âWÑš¤Í)¼ÅõoŒ08?cbë0¬;‰oÉ-ø¥ ?±0x.`/ lòú[Õá—/_ãBo£G9`ȹÄc“ÑìŒÛòÃ&1= €“Grëç›÷^à}H—°Y‘ŸÄ™«&å|p¦˜ßyyG© 8¥¡¯\´zËo¹$éx¶W¹@±¨€áŠ“k@Z0€‰”€¡Ú)Ç oØlp,`aïoã“ ÅÀ^%£üÏÃA|æQ…aÜfÐQ S<¡W~ðÆÓ¢ Ï ×žâ&ÃwàyÆÆCp‡ÒÜ 47ø$f­Ë¾±&ö(\mú0|wƒ+`¿×ylìÀ>YÒ0À¦Ë ÂåH¡T¬)„ e6q]9ä¨Å‰åñæÀF2v7f±´R`Lô˜y03^”ïÇœF³–ç\q@².x@áæ£qM\6ïÎß} wQ`FIŠ iå2@ÉD_˜@?áhjèŽrÂcB;ðå8u¤šP oÅ7bKƒ±3¬jßc˜E|¡ò‹×npâèåò…^mTÔ3õ ÍÙ6F $ªýû¤x#-£œC¬öè^øXü¤;\ŸF ‹€[6óC¿7 ónºnÙÀàð‹1,{D °¦ú C{ÿ»¢±fAÓcÈ·¢: «büÓ¼*2yÃYo³ßüAüN`uYSç…a$ \¯¯¤ýS@`‡†gÏ;k@áD³~K Êÿa@Ó+Cб-+'±ÿ«ðìQíF 5ø`íÏà÷ôÖ õE@?àn«°Á°#,zAdZ‡IÑAAã/¬âæ¾ Í Ó@áÞS ÁGñÝø*~ª¦µ0qpeC±íõŽÃOðv0ÏkbjðÖ¦¾ãÿ:Þ¥‹cfíqœìŠrÃB¬Uïó1*È5c†çe®£ím’ÙZ ‡Ï¨0 õ: €ÖȲm<6øÈüFìþŠÁ LâäPc¸v ãmY`Øž·S½YäÂÂEÜ("œŽÅž"Þ‡HõŒ6xÕHŠ ÌÁã§9ÁœVÜ3- •‘+äk‡c[£9Ú%à=ï†û;uïo¼a®X†ñÇ:æ‚™Þ G¹àA€±ÀjÜÎmÀ(Lj%Å 2øźŠîwñEÐܨãúf#ÊÜÞ+—“y½fü)𺕃솸up°¥—[ËpÔx™,0<ÁsÀœ×,'Z ^ZµˆÂ6i–ÀÈ’“:æ‚åÙ‘ ¸’‘‚!ð¨™ñ[ ³Ô-þ†8Ù„$ˆr`¿¦Z‹&¯÷ãæ1þÅÀ‚…K!_ìÚ2¹…d~ä‘7ª8kÜ)W‚³5à³±0‰…· ×3q¥aÅŒ `g¬b2”€ìi’qvØëgb×Sæ8¡3ßWã?7ÈnH5ú"AË ”*[|˜oŽç6õT^èæPàO3¤Š0ÃÔÂ…f}µþrŸò Áv#!ý`‚öš&˜ •pcäšåFÏšV¢¹€ÞZN'– Ãä‡RcY˜ü‘Áàžçƒ§‚æaû –]@ÖÈ_Ç ±®*·(ÝÄ‹#æ#W<‘ðß ‰À/³Áð@ÐnýhõÛÍçë÷UMµˆ´Ó®+ZÚÁÏ"°Vìø îÜò H¢4€<±m­KŽ“¾‡kFšæ^|u¾‚Š~ø\úy@œ3ÍH†®ùCÌ"økœÜtyö%lA³ Êüá ^L:Ðo#Æè±ô±—áw<±•Ó4°=~¬BA€Æ®„¾ Ö Eò=©\À–ÑV^P±ŒÎGÓ"7˜ZG6BD)!&ãêòà×c„^Û1Ë SÔ1Z›c\áߎžÿ ó‚,ïp"ùÉöEÜ2ø П–à-ßä’ÈQ0š+‚78 @ØS´±wÆšÞ¢@ÎýèØ·²_eä3XNâ4r‡hØæéß0 ý†‚Àµž: ]à¡Âý<†‹ëÂä'W‡ÂH`—@ϤÔ7½Ð´ Š N:R¯t¼ïk2›ƒ™j¯P Ü,¿ ¢V¼p6ún0zóaM?BÐ}¼$%bXš5)áÃDçš%‚¹ßrC ° ^…‡1f»‹Õ$Ü,& “¤\ ·gz9ÕùµPArìô”ëÁZ Ad¦¨ Èkn9b€±Ø ¸88HþÃûáyÚ:àªÚg.£>èK›ß™ `ãÌMŽ´I)8në%'?âÛ?®K‚Œ"ýJ@êWxëÇj%ìÝCkql|vFBëñ©b:9xÜçç„UAŒ[N ‹mÐ'¡y›°J¾j«n€.•¯=-˜>ÃÚ{Àìrq2ãt¼:>¨#rÜ6ÚÀ¾¸3/LE ·UÓ>¬p¦!ü0Ol l|˜)Ë@2Žjݯ¾W†s"D—YÒ€¿yŒšùÆò!ꉯ¡5¤ 0ªÈC©QÔŠ‘QFÃÁýÆÔVþSé6/,o70»aHÄ:⻹ŠŸïeÉI‚ ¼k0Γ.l©–7²³±ì?ú¢f@Œaòà{˜V¬ÇJfµG‡›zLHèxÛ\äÈ„ýh[íï ß_–u€]ǃ/©·•m³p]„d1ØÇ츭Wæã€Úk¸ ºú€ =nhŸ­—”õõÉçVšÐéƒÑ»@hT彬Aû8xŒÿw`­‘Ĉ÷i¿Sé‡ÍKÙ¥¿(×-5±tÈ"‹oàõÛ\Ü2± ÍÚ‡ðƒÑŸb|Õd”“ô@MJÆ™󚌲Ô<þ { >_1°ø¤ ±Ð†q€ª•£SÛW Ä¥KBânàmC€^½'W1-†ÄËTo•£ ›=äÖ^lD3Ü‹®ß°JÙ"hGòÍg‚”Ó‘¯£nX:uä#‚Sƒ7˜€í]ǦóéËIÊ£¸–= b¾}ç…C{Á.íà­·&¾‚)ÇE™¾í&?.}Ü0ZÀSš‘ŒâT‹+¸uë±æ§ügA-ì|<Ê0ͼž {Ô`\Êžâù©‘oSì¤HûÈiY1Ä6Møo10ë ŒK²ä§M¼2ÎõYm[*™^á:Ò9Í÷¨ŸJ·~yä±4ZÐÑC>v¾6Þ1¦ÒãeB´€œ|±Ûk­h6±m¸ŽKÂanÉ8Ö^É· ìÄb^èù5^Èþæë;pEø6jŒÊ €’gÿ¬CEGNâxañý%®c7›}µ˜ÕU°cÀF“@N\ ,¼øŽꈊ<œâçc'¬ì~0ܼtˆ×Æö‰#Aà]w+ é¶í6‚á¿÷Úíz0j¼™ÉAÈw·º8æ–‘íÜÎ…4ômKð" {ÚäúÙä6¸pY7¯e>E⻄å0£´…ÀÉ`k÷ØÀº£Ñ=x/ci nµ}=x-æîZJ4T]ç®n¬Yu0®õì²…:Œ¯–Œüþ‘Y€×xW˜Í©d ³zÆ?Tpa›‚RÞfÜ P]œ(° /-e›{î' «D.s*À>VxÍŒOÙdS¾¡$ò /á{9gÀV+à:aÒðñÏ 0yÃÅQO¬hW+ñ_˜Ð礭q··³N[ˇûoOë¯þø(¯ÑKòî9$ˆ„+Œ¹Ä!®YÆÀÍ ´ë}wë †”Lx¬#ÆÏD‚U S$‹ ujDmO;a_t‘÷~j\1¢'™ÜÙ:ùœ‡=CFaÛ¥€0È·)ìÒ.àõš–Ñ?ÝP9ÍÇæ®_0l %æqÑ™éë™™Æ~ÏAÙ!ðÑæi1(o¹ ‡Va &)ŒÅÅQÓgC0·rŸ‰3æ ­t€H‚{“M[œJßÀø A‰o[` Rñ`W©1ÕCÀHòÉ+áÆ’³j¹EH…1ØWÝhµï+Òýqü[Ã)lëu²uY(^ñûªÆÁ.{ú$É :lÊòk9àêâ^-µ·Z¤ᨾSk”Ew@FØÀ2 ¤Æ½ÂÀ °2ÎØ Ö +t7¬ÌdÍþ µHP<ë3ƾÏÞŒ"·…8ýjЋ•d¥àq°š€W5m óŸ±f;ö«Â@Íü<œ&]ãÛ¬eЧr¹¼Â&Ô3§~ùìK€§6n¿œÌ³ÚÀ‹¿?aR>VÂ1ÙÛÒ%]@øç¤ßV@j„  õVÉà'‡ Ljêµ#BTÚ'  ôÈn:=–§ÒBgÜ"¿F¸ü%òS.–ÓI!±-:©Rx¸PDÄ:/¹ lSu³P³U“–§à¢¬÷½Bó`HV ø}›c{Ê›öÖ·ÎÀRM¤”ô˾¤Ýwà×9¬Î²—î®÷ÄiÀ2Û¼°üãÄFÁèÿÅ}&ì2kŒÜáËë Þ6Þ¿ÖkPÃ’yÿªØd‡_Å&#j}dƒ™ý¶6®çë†Å%_:ó~9Y~[¸¤Ù††nœTž©˜ªœ`H,©i$»š¾™ èm¡ÌOšh)¶ýqâmÛ'_Ž_D=4–În»€¦åiP9œ/€ #ùÀŽøØÖ!B†f·/—pHï Aç»AeA™cÛ׋©µŒÄ,5 æ2„ÿ7j>~ÝT"çe›læŠ ãÀmï­âþ €¬®Úíþ5FakWøþjª­ÏOOáqNÑÂkjpËm²!¯Ó6ˆ¶Çj»kÿBF­¬5§ÆùÅ& Â•Ì iç‡l¢ýCXj– %7íûŠ«Ÿ˜f0–é70P—_à“–® öq®)K«›w5ˆÿTÎ,ÀœøþÀ #Ÿ±Ë~[jì 3Êý§žǘð_Ù¨)Âf)WHøPî$‰¢þÕË~€5¸ÉVoPïAAPж¬!(` -±´€²Ý¦ú7Å”{¶¦#bݾkñeHÁäDžj™i»Ý> ` eI–ŸÝ#ñ¦uó_+\­ …Óœ¦SKqcJu†Ô&†ŒÇ.Y6e“æ¶[j”/“JCÖº¨ß ’ÿdÅ8OŽô÷>B›‘4Ø„”±p§Õ8+(& äå`Sí7k´åÓâÉ;cå,¥Ø–, É @à×3€Ýx„ÏÈ©,í8µ9LªLG°)ÆìºŽøæ(% Ãv̧ÛSfÍÊ8à ¢ ”µW´»"Œ·õyèxÊ&¶'<}¿W·îa%¯’;¸MѾWàx·)ÍÊAHQ6‡¾¬°k~Ú Î'…ªßï›dGGuðÎÀ†•“¹8@–ÔMÂè'ãoyïf¼µZ‚S'Sý½p¢ÉÞVR}ÅoÞ‚¯Ö ñƒô }æ2:›×©bÖ5bî€Ã< >+À“å»íúLnr°Ü3b 1Øœ‹²Ç­™EÍ!º|ðiâ´àE‡UMغw/,¸°û J‰í&a¹¶iCÅ~—îÛíž|Q— }‚Š ¶°ñÖbÔa÷"gdJ òR^Y*<ŽuÁ'Ö2«ŒÅé‹g?f)ØxÄwoQc_.PSzŸS6&„Õ}èÓ  EžñN¯Ý9IäÄT{RÀŠ@³Zzñ€®9ÅŠ¼6–â ë´µ9û°íÁÚl\m:ƒ(/”ßoòèN¶wÄ뱺zÉö6˜O…}‚×ü9- Ê‰!­\×g^ñ¶ìú[¿f6ÃÐtpt>µÇçiХРãlÌË·¢ènF3hÉ»1_ö@ëÆB6aø!˜ZÜé.ZPÑŸ¨³7¬ü5ø‰Ò.."$iØ 3àkP œÉ´\cɪíxOBƒÅ²j- EëÖ­=öµܧHÃzèÏÒ¸„O»LkåÍÊ=/ž­Ûˆ©® v'Ö!¤š·ÏXв‡Ü(p‡Ašº…ùߘËWC¼^ŒÉgØ,bª¡zk„Q«bÙÙk*P‰¹Wj˜ôeÅqAÛùÀXÏŒ{Ll/P©a!Ãm îO4ˆ!†ÇT @u¯µ÷˜l’ kü;Ž¡Â7~Ý6”ù‚¡–­ a ½ƒ§Èh¦Ç@:/U@ø¶Ó?νxí€ü lߪÀt@¿¬}ÊÖ–€+'gôY¡ËSðÃRE‹ºögÜ¡Û3ÖmK‘%Ð:lŒïàmť͜v»õ«œ&ÉhÝÎøêÏæÂm¦Š«ÅÌíff$ùPº¦ž¹`f­Ç¸±Ð¶]-hÍðð >8‚Â'zNoí ßËGol-:™BÃH@Á¦Nì"œÖ‰†‚à"p7C‘¯ ðCǹPû,o¸[¹¸gðÀÍ^7cĨçr&øÖeƆ'¼_ë´‚àÿYOn6Nã·yî¨bÏìUþÞÐíæ„8rhÛÝ„ª…K§xz¬&Uï ªhI‰½Eèá, Ü)@GkÒ&˜Pß±H¼¹3®Éƃ rIdž¼À§ABÍùÇ! ºû†¥Dœ°fí[A²ñNï˜~0iLJ$Û^°è|hdþt˜xñÆ}Ì„¢ÐbæfC8² ¹q´ñ‘ˆcu@·ðp<²Ö98¹—“ÿºnˆß!:nåÎõ1Ï (ãO—½EÏñÖöv «EŒÁ¹ÿð;ªU1"˜Rü´Í–ã€nmDî{¯Òl¦¢ì¸+Úõn?5`ì½c8ó5ªq$ï„ĵHoq Èú5/[?-;ǃñGÃ3⧆ªÀ…ÉjøìS~ä Æ^ö©[ÌÖ•œaßëuʬ€aÒÔ93/ÖwÔ?ëŸpÆQŒ‚É€Ú‚ÃÀauשº½D=ušµ@Á­"h÷' ˜@ü°”iJÏy1j„`¥«±Âº\³TÓ‹6þ" *©¤lP¾%õÊÌÚke¼ux&ô·³ÂâþE0.£Ó¾`³€)_¯33˶ãa7ö×’ |ØÊjT˜f…p¾_¸ºýÝ0Ì„6 _NðJ€nƒñЈ~já kÙ΂\r‚39wb|™w½þÇSøûÓ <Ï‘ÿõðOg^~gXôºòÆ: ‹"· [H8bÜÿ=‘ý$þ£êä‘°¯9Ž=¹ #r¶ &»qûe#Èã”!!`9ßÌ·ü/žædPÿ~œ×¯ ~ÿ9O¥%œÓ-Mµ“ 7¥³±¹5ÐWÇÀà Ö}9¥é´`ß3}9Q€YêsåmÔ`)åF?±¯é3>í)¼ÚÿøL×ïŽÿå™Î\ŠøfVé˸@©ÿ>  Aã‡y¿qöè;.øZv‡c‰Mn¿"´O`Vš±æa}fÔçÛ·÷ð†NÎ'†ã²D•ïÞ\ûïZþ$âv- ó´íBGÿ§ÕN‚³ÝgHE|0ãÔG‡ø˜P²·ö‰¿§âøÝ@fˆØ™îœÄb[’iqžÝl·i½ðm~‘ÆâØ£òâ¶õE³4ž Ç _7P7V›E«Â' ¶ðE˶H–Õ”f j[ÎÍóÌúƒ—Ó=Vι”ÏôªáxÉß=þ˵q¿‹óÚÀ =¬ÇÓògý¯àÖ@ó¨4™«²hÛüøn9Œ ï ßPÜRïʇëû^@÷ ˜/V£Ê£ýŸUá?Ùõë ;gÜÀùÚc¢ Îj¿qwM§ßš—I=ó=†­çÆdg}F‡¢õçÏI]ñH&Êì—É–TÙ‹†ÈšîGöxu˜×XðŽf-?2;±p—zšÏˆ£û­Æõt“fa߆2[rïìw¨ZÖÃþÍ&!Ž<íFRv鲎ÅÔ ¶¾B¥Añ åá'M†y  Ÿ ð[Ö´ÅrùrrMÅÇZ×`+0[' à Ê“äjãmÛXU00 åîýv˜û/!¹þ”ðÔéœ ø$5ÜVûYtàvæ˜9ò×dÌc3Ô©LG²7·’Ù'ܺI/|Ülß`{í.…²5y`¤͵þ±¥4orýgÿ¿2»J_®<øWX00Å™Wšúrò…A,Îø˜o7Dû éýÎŒ3åÙðμç߀ÏõäóA•à ®@"ɧ[×­ß Ö‚=]` pEÔ.ÿÞ¶ýïy–ë?é“P6Õ~2™Ñ?íü1ÂE°™o‚œÂüî €º¶öŒ†¬ÒÓ`ߎR¡KÆã‘~‡û8&À§ém¬°¥ÂY¹ ÖôÁÙ‡]ÿ ºžDËŒ6tÅ!Y Á׃›>­YïdwÍ™l0Nš]Ó¾ˆ•#–MÂB®=Ríœè™ß ‰È–Óë ›¹·;‰rÇÿb_T mxè>u2Ök›¯çg{ÄF[²®Ó6¿å =3¢‘b>¹ý”0hÕ2sЦU Õ)g™í*[§¦ÀZ¾ð82†Ï¾:+`q_ÑæCø^˜ÏqBÙ!&‰‡³ƒ¾;Q©_°ñiäè‚©»Û`>öM§yjbliw×óBI-]H1¾§õ0哸v¸_‚¢ífÒk:Å„ãÔܱ‡xÛÇd'•å]î;Ù³¼xlS2ƒ3²êÌôˆ›KCĢà ç44¯AŠ…ç P Üdum¿)r%ᦢ¡z+ZϤ’󻃟`"Ái:bí5ú·«¥—3¥>:¢W¼œ·™!#!ñ%xéwH¨íä6žiï¡}4Nw±þÆy#ÏÉõ(£ÄÏaÞ¨fÄÐ<ö"Ù2.0‰÷¾ìÀµuî ×Nðdü ÂŒlRe6ìT·|\TsäSå/xñ· ½›iâ»¶k[7nž±> Îo²'æªüaWÊö£FèòþVnÔ_)»£íîzz R—sJ²Š®ôM˸-Fï¶9½Û\•|}ÊOJƒ›Ý°È-š¬×Gt !‡}†…aŽ67íÚÙú8µ…mT+ЬôØA»5Òaˆ&C¸ŒíÔ™Ç>õë’“Ý EP‴fgÁß0§f9…ÅÉQÀ K… ìÜVÇ¥ÔÊõñkÉq±É¢ù±ÛÈ_=³g!çÎäÚ1ãÏ ó¶twYšñA.²Ã¡0&6¼Üí±ŸÖÖûDœi0ÏP׈ઢýŠÝi<duT°‹u0ˆš£ T‘ù´¯µ1K·¥·Á»iH§ÏÛ@M±Ì;B”Qá8Î’—C`¸ÈŽÜ;ƒú,<×þµûÝ'&l†ÿÎД„W­ÓwðaM[_¦z›åÎW=^%˜‘äÔJkD hiƒ²ó‡ Úoµá=B¹°”Àk“)x.«m„&d™¾ªŠrôá°¦y}ŽñùŠé›1WuŒæé™·¬ØŠÄòg:døë÷d7Á™ls}îy}}^ÆQdaàMÇrÜ Í Ã©…öuÛŽ¸ìIឃù6RbùÁ]8YãåD)gæxy¡FE´öæî,£´¹IÔ½Y^:í~/äà¶»¤Ùç´}ñÒH劦Ç#ãhK0w¾t‹ÀúƒÈ†(ËðK v6„¬£qF½‚cû>`ÅŽgZ»Ý)õÔSßhŸëÀ?@àc½EÁžØï…Ë:í0zžCy9$ñ4R?šª¢µ²¾î«“zœ ^nQùÎvüÚ>CWðÁ–Ixˆ¢\Žo6#bÊÀUÁ©ã=5¾wÂ@úu¡Ë~Ū‡„Ê-CÁtÞÆóšâQó·lE]Ñ3|I½aNÁK7:Òí[N•ìüNð(ÇÈ»Š»^z)ýg^ øÎì¦Ê\¬ß! ËúΚßò؆†ù6ã‘¿Ó­>Dê>Syïebû9ÿç [9o´l8ì¯ÝTsY¯ð™Ë9Œ¨¯£Þªì\w|HÅX^F@-×õ‹½"º[ïã‡Xûýýª%F¯¯ ‘C¼/å±ÉqÚ#Û ³P/2ZÎÜ,È›4Ÿ˜®oœ±ÉxŽGÃÏɘ~%ZѲÅû:Qòzøò€@(ŒxÕiVÙRå"Y² ;7»1»zŠW^øïÓÉ 4ÁÔaÖ…Y˟ð9sÓóöh'€ã2öhE£]´\’-„Æ;€ñ³A´•25—P„±y¢DtðÍÜG@BVÜóùÁ㎤>3ò‰©•©nØtœ¨ä¤4Ï× ÕU¬˜ˆwKÂyCµFäÏàþØ·A]§ ÔÉÙ¡¯íç–œ%?0?ð¶9/®¼O•Ñô÷À9ÏÇ¡'ßúRøåGᤠiµÅÊ&[<Þºí Ž,hßÅçR­O$èq’øœ¿Kw¨/P2z¼|t‡Yã¸[à?díû~­"…+ÿë$YÐúZް9á™ÖµÌåPQ”ð62_Óf¼Ã/è"šw¸pÌŽ6b¬ŽÚúl°°(ÇÄ™ùãÂÅñ›dê$C 7çà#«Ä Ø!£¿3Âñ¼v‰ô÷¶¢¹UMXùеŠá‡Ì:´îÙõ[ãùÛ–kò~X xvRgœß¬BFg2‰Å}cå¯ñ$Çcœy~k«íiä˜ãÕðãbüÕÖƒ.Àüe[ívZÚ©ø±èÇÂ÷{;u¥›\ÂN9o̹¬õC¢‘§:»X½älÎvùá_|¹-ötGÈÜàû,·™€S¹UÖÌ Í¾†¡"üZ6xÁ_e[½¹ÁLÖì 1Ó×é=ƒß$ Ö*@ <¯ãá/›Ó/;tu;ÑéZøÇølq/¡:«û’…ý3:¦Å"ü.ŸË8",»:¨â×Î1¦à`-[D±¨!TÜš•ÔE³uf—|Û. ¾httºä—YÇöƒf]³ìè'Œú/CXœ|j·½L˜´PÚyÙóÊ¿Q'¶(–'{×O»Ý˜ÙÎ0×™µÃþk9t(k>Ð\Ät,98íš3å#ÛáÍ¥í”y.«‡q´ÚáÜ·5O‘ÞþŠ]ÁYaØìRCœïÇušÛ­DQX.‚4Ùé´A«V“u w²7{KU’0výBé€ô¨ˆ@è+8œXŽà¾Ç™ÔÉÔ#¦ÓNÉ Mç>ŸþSŸ‘{´€"ÿ‹óÀËä_Àá,@E,8[QÅàÓŠc•?‡‘:R×ùP6ŠtFånéJ·œâûV¥fQFpeÅÙRÝ!*½9Y1ý¨b1‹%φÿá´É6šÕ¶‡3Íž‰¸´Ž.1Üð,l1çYãl›S€§—{ѳËÂìÀIÕŠ²xÖÝz¶iÍL¶…9À‰Ìp5‡•pãF¥[ZŒi¹z‡yÕáQÙœÉí„î ‚¬¨ã2õBÚöÐðÑá2­8F…GÓ;­êÂÿ:©ßš~éQxV^É^Òqsü‡7_ ’?¤»¦Çɵ¡ÅKßœQt¯úrÜ8 ø 0V¶XÕ37"Üûk­ŸÀh|‚ï ÅaÂ2 ]q©\'¾æÓÁàš×âõìÀ 샃ǮŽt(-òÜgÏÁÂ,!vb"|Jcƒ\¼KŒdvßWZ= ð0:6äKܾ1­«Lg¸u´O'X}ìëúfqsvü†‡Q¢3uù0–œ‡Ú"ÎuÎ=Rèåá5ñ’²Ê-¼gDXDÁ»ß“›Aeß.-óB?˜ü:i×í<8i7¶Mç[*¶iBæ`û/$ÖôƒÕ¼³œF™Pï¤÷#oÀi„ü±G) .iøâÏAW ¢qîö…!"V|aÕ«» ,å‚¢V¶yƒÈàÌ’ºt!oÜ ÔÔýå¤wCØAg/ÿKN?rÈÖ+r^°`7›q‡ác%Û°Œ.9ÀÀéùr©ÕíV‹í¸ºÏÈ)–ÐÜ–]·(ìáZÏb “mr§6ç¶sÅNýé<ñ®Ë†>;.²õ¥;(±½gæÎk‹×8#Kûæ£ÞÎ=óQ.qJ—.Ùì‰mÊ8,³%x©éÐÚlÆÇr£&ýÁv[séGâYépU»æ-Ntã`ÚwxÉî[¨h Ž3ñðÓùAN‰À®Î … Zÿ†­Z`îT#GLc£w2—oÝûêȉ㩜ŒAr2v;=Ÿyv‰ÄdÝŠCfNׂ:º?âR+†Úíí[‘ð‹d‰w0yêðÍÓo{µs,lÑiòÓÆó´¢r-§þ‰²{ȉkx“fp@DVmý³çîtôa" ‹!4€££Dû‡êtK„µr=½zܤ%"ÓòdÂÖé6Îh0¨À‚âó’Pûçzêi7Hî—‚LHÇ~݆c$ǶjÞ :ÄÕÃN¹êÛYöMjf™–6·vÝÝ—õZl,úl”]#œ8ÊÓ ÷>¤³`⼫\µ<Õ^—H@N¯pªÁ?>¥”#Ø;µ·sšÏ¸µ3AÖ¯‘Ù¦§>'çzÛh]KŽ4â5ö8çÅqMå¸AU\4V±¼ÎTmŽÓ²1ðôH°. w1öµlÖú֣?Ø.ä+\Å–ÉÇe-gªÆY«WìYH®²X pMYl€iἿév…fçôAçr¢7nXç¾'ë|ë{ê¡Ë¦óè²Ô]Nkp@ß9­~&š¢;Â,Õ|ëPóÑöYà,´µap¥À¶BwžÙã\ä\jsˆp¥×@à cû±áä t¬Q>lWŸíà¨bcÆJ:¦&Më¬mžÍÎYqÑ@§e¼àÓÁG†EŒ$kappM3Ôìlºj>‹Q7÷º k˜×jDÄŒ[t <$[êYµÞŽCn0³»k¤ÏªU»–³3Ò‹]½øÖn;®˜¯o~g|ùvDØg‡W6RÂm:H“ñ¢1–: =†þ‚EO–˜å•´[ŸžŸ˜_½*.¹Ø´2i\­Ð~åSR,fÄA-vTr¤ðhÓ^îªù/èC@¤¯7:NËÆFêm r­a6/1Ì|¢æ|)œ¢þ,¯“Ùr*çr vòå^€VÊ\¹AL\5$^¶äðʧßA²zéÎ0çVÀØí(±®:?–ß¡oåL£—ãiJúç¨zsçÖ_ñù?Ñy«¸\n’]éaã;N‰£â§_NÙ™,0šK ²è7;.Å8%òg ìYF`ÖezÂ’D8ay­1@ñ¹² * ¼@=“IªîLå/¸rÚÁ¥Ÿ˜ÙIùÜVÕ:ËB¬®7iôñn&É ¤y%¼”_šÐ¼7î'].vq€P0¨õÔgõ“×à ;G%ë{½l—´ŸÊfta`Ͷ譀·i« Ø æàü3Æ|{»£°¡+Ú õÚúW’Cæp«ÉlË8p%9}b퓌’¸Žoó4­º­gšEv„:fýœy„ÒŽåŽS„<ÂHΟò<Òƒý ­:H489 œ~ÈžKÂèY7xU¼ÃQ]X,ëQNÇúú6pF«^ž3ÑHŽÛ[Î.°):T¢N—[TÚ#X¬~ùÉ'>ÞÝñúÛÞG´áyÃÙíýÁ žÎTLÚôM‘£ÐË{»¤,Ùü†ÿoe9 ‹|—ܶ%.((FÙ\Š&ËÂþæ3w_í“·.øuÚñŒ¦ÊxW+sí¨šÕå!ÙWGvfM޳'$¸ø'»é…¾GèFE‚;w ;X–åR>ãì§Ãñг…»¨ñ7é]¿Îç}’Ü †ï6ßœAÜ‚\=äÙP¿0F"Ÿ³U£EE($pßg €=Ñ2¾jz\bÃâ…¶ZÄÎ]Îhunjµ„תg“Ë<¢cñ–²™îè?¦‡£‡^\_´Tí4(Œäí !êÏú:§rk‰²×ÍŸÇ:gÆPYP¬µTzX¹0Ί«¡5¿M€fÃÅ<ƒIŸàÚ—qh¤³OÎÙëÓi ˜‰aÅÌ÷Øx†¼„ÕaZÆbÎë]íeÅw ¯g,[w_ß:½W¸ÿ\_õòÍî…Ò!]ÊÆÌŸªÏ6‡¾¯Ûùަògb¹Ÿø^Ðj; ±v ‹:€Ó\õYµažU`÷Lh‹•- ÚY_kÖvþµÜ9ÉÙãÖà˜JƒW9BÄŒÅ92Ð$¾Ô2¦è(NŒÂ,—ÍVÃqƒ³h•zà²×çgohjOî$™ÏÏðlG Œ(æ÷f5»¸×{ÛÚn·Ö€^\JZ[`̹Xmß,Á·8¥™Ìš¿´HǯÆ_2 ]t= ÞNw³#¯¡üK¤â¬7¾‚ÇîãZŽÓw‡[w€Š¡·)“ÛÑLÆh.›ßtÛU,gêy^ÛìD»3¬æs²üËŠôÏ)( ,°P—¬ lI"þ9CÀFÅ•­9ÀŸ\ÉÎ üe´qãv3ПæØÉfÄÑæÍ 쳓¸Îv–a>Ú%‚/NHÈépéû+n+œAìp­åü¦ã í?°`)JðZÑt›å;vg^ÏÙS]ÍJN[°öHfKŒq\9:Buþ\~ÊEDS§Ôñ9kX¬±¿=¨Œ­èÖ6|„.´ÆŠæï.¿y¬ÝϱYÉ®p.Îa0^¼qººs 8+Ö «®¡q|¢ÃϑĮ¨šÆÈAÓçf%küÎð€å ¼ v#í¸.'·?©;á=ø¹µM69@ªÅj ,ªÎ5:ëÌo³/„¸/ÕÓœ³qmâKÙ1ì9š¯Â€H•7ÔèŸÜWfÞP€Ú²jý›Ã]ÏülîÙ±Úv8¤u7fn z «Èo)jÓVá:ÍaÌ5›‰ªìü³µÊƸˑTЦOŒ~"Éö8ÜДØZ¸Ë_öcçãçz ¨%ïk-¥K(‚Cþ/£o€ŸÏ޽Å€mfÖò¾nô¹å¨ïéoíåjVF€ ^ÂM͹ñ|‚KnãÔD42k7)fƒôx^h5 wëx<šSyÒɵBË f‚»n$»Ž3ÐÅ KÎ&Üÿ^þàx‚ío—¥VûÉláó{òO¡Åz¶{[†zY¿‹‡å•Œìœ‰¶ÿÄ?føv¢û¸÷ìf€‰“³‚éŒÊz²å¨—_Â*bZOqÜ\5œgw ^ÇY—ø*ö©Õ¹¹Å‰u]qutY×JÖ…9òÏŒ—>n„H0«¸S…Åħ£9ÑcÁ¦eàp6›é^Ó•N©µ±|ˆØÁMä…Û´°1€xfu$— €ÎìâÕ&ÇÖ¿»óí6ü]xømvS?3„?£N‡bwªÈrïØRŠæî2·:R ò<2;Kò…º8·XíÂÌÜM…'gÉe÷Õll̲PÐ7d¶ t·«{ÂÙÝtz« ÇÏwªãL'$€Â,³£Öít0¸å J¶ÝÊXÌéU‘Ÿ…T+ºÈºŒÍ–#Zì‚iGƒªT-,?ù0T#^OŽãTµ.…D™ìÜî÷Y÷^r sôÝUà©Ç’"S°¡Pm_­Ž…sÙñχñË,WµS»èw3ñ©9â Ê{:ÎÄ%Öû9àÏòº\´Åp*Ò{Öû4ìðx¬ÐŒ³¸ÝåQéÓéúŸgjòvì¨k÷©ZýõWxšŽÇƘòÇæXÒ—ªÅ–ºáýN`¯úˆX;~âsÊøÊ&7qŸÍõVÉ}ûs{ ôpBè2ÚƳºÅ~Ž%þ*FÖÅP§  7ܽX¿<*äÀP̉3Z6T›W°³"ìxUˆë­=ÅßC\êç‚ KàºqP»WÝÒ͵§Óæ¢L$ðÝ:Xˆ=³N(¸*—WµØÂn.øl*³žjæì«x7¢__Àéœ,†}hΉèCv{›µ  åÀ ÙZ<ó:jnšä Ê…NžÒá‚§¹ña$æýí`AVÀ·Æóﳡ!‰gêìŠøÀlÝšg[_ÀR]u앃9±€ XÓPÉ$Š´ÒÉÅV>„×Lmø’ãBn·&#OÏÉÌ–" !Â~Ó_NŸ.ð³‹J8áêŒç¢þp^6¾ên½GŒùÍ×ûÊoîåkËÎç°aŽZ²‹yp[^³R#¤¬·Ú#öžºs·,[ÌÀC'š™µ~ÀRæÚ&GQE×¢9”|>MþÛõ6ÎÒšßÛ.{G¢†Õ¨žqpN`‹¨v®sŽVç:]Ò®¸´øw ýZq†;fÃIdv—Â}Ñ olWtÉú‰Ïw\D0@Y¶ÛÔÀdzèhG;ø–Øñ„­¿¨N:tµsyÆ¥ã›ø6õ™b1•eáNѲÞáÒËj`°ºSkÚïUòÁ±-<â¥Ã›µ?¢;a3Ñ‘*¶†Õðg¶ht;P l»Ok¼L}ãD¬±?ßuaÅìtÀ^Ýí²½êµü\ÙÕ[±v>ãÔ\DІO½v3:Î19qRtÁý?WºMgÀDŸØMXðQ7£»´|XNmÿ‘+ì¬5qãϰÑs¹ã¯ã6 x\Ù NôÌɨx îö°Ôèû:¯¢œnÛ0O/ÙÙZgIæ2È,á±¶ ¤_v!ŸN;¸æ²„+º»Ömf®QÖ ÛQ~ÝüN€öqÒ’,œ“U¡¹_f¥>3±À7³+Ñ’){ã:ã/ñ˜Ž¾³NWô>î ½fݸ#Ìã:vúúª.ë1êeAƒì©Ö³ÿ0²ö÷Œø‰½á„`ÛᙎÀK8­{Ú¼ŒŒX-nYG²òý~ܬ 6:v»Kí,âzm­OÉŸñü6/•ÀÝÍïk`Ϙ¸[‚O¡“H,wNV¸ÙÛôN¼]?|¢Ã<áQ˜2îÖ áJ§S÷qò}Ëf¿’£`! S^ë2h·d:"ܱ9BhHç6*‡·¶³Íc:Hopà•å–e D|ãôe­ß㲯}FâBŒQ-Yæ±pˆ®–Ö6Ûcz¦Ðƒ¨ìQ|^3“ùÓ†]Îtèí¬fÚL•ð{u3ÕJÍ·†S¬gcô)×v¯•³‡Ü/ï¶ôi̺]hrŒ'rnQ¥ã}]x• ò‚Ô»rñ&îÓâ/ zÃjÚÁæ¶íšœÇæ42^8 Ÿ˜Þûrb`V,m³Í—ÓDR=‹©·J™Úv¦i°`6;l É6å•0ŒÈØÙÕêY Uwtd‹›ÃgÔe`x]¬)¿qG­ëM¡\®…E@² u`ÞüNA;´ÕBµ^Ñ~8œS#þ7ßÑÉtˆŒtº>1X&¼3¾Íʼn½Æ ¬4tÔ´›¼r?L¢-Äê¿ç´zwYŒÖÍQíÙ»`iÙ~·9‚á~Eð½NïcÜXòɳrë»»œÓÆÿe}j¨§úΚñjصÁ¢ùsþìvÁÅ9þï1™öëÚt3©wiÌw—¬6QuhÖàY\‹€³Í1Ö“„/Ñn“åÊL7zÚbhÆÛ° Ÿ‚å†úì†ìbÜâéá¾ʩ­±ñØ&µõ›= igÑwLàiçÿ #˜tâÃWדýÂf\æõ°Y»´¿òOÎóà‚ò):Jçå!iÅMJeÈ‘ç´7÷çaà8ók¢Káàê€L÷s4”bIÍG‘–†»£Kù† Ó¨lpÎë"G t}™6?lØÝêÌñþù*Pœ‹Ò0ðn-?ÀL…M9‡-øâû“Áîës¯¯;1îžå7Ɇ?‰VœÜ`=±áŸ)I²Gvd‡€)MðÊváiÎà†æ„Ÿ&ŸŸs]9§扭\µ âqÞìsŸÒ+Wrž¥Åæ¼ ƒ|ýæå´&ðP¶t\¾wÆ6ñÁqÝÙCY]—`}ºI¨™?›ŒÝ8ƒuÙòðéܧH¼¸´ÎÙýé6½ÑYE£Öà­ï½/ûÞO˜¼âK1í}9Ñ~<®³B÷»qh'n2Î%ÃI¯Åþ(›UëåÄŠC…ž;Òk÷sœ.þî³FÙ=²{dxog*˶1g¸·£µáš-ž q¹üY\ë@Æd3 Ÿ|›µ¤ð0¤ã°%œ)ÜvKšg;+G`l×ÉlžgmQÊÙ†~*„ Æ†Ïœgë®T‡LCUõ¡cñÛ·îD†½¾>÷{¸¯!glÇ ê?œa«!Ϧß'²òš?ƒN·ú¸”“u§Wýªƒ­ºP/bñÜì›ö•^÷æõ…ºƒ“¢íuͱ½¢!WGì÷œ‘›DñÒ~çJ ³õÁýfÙaà.a¶ð9ý¦@Ààj[?³[`òçl HÛñ.Ûq½ö©X¥®Ì(鋵¶¶OñYÁìš«ûÌp€¡‚éïæà |n¹ J«N?£r½qz$TZ£bàÔLP”Û¨Ìþ3œÛ¾û (pËÇY h…&Çå.^ýäÜ®ù9¥]…x¼Ž’ÄT~:©ænÐSmèhJpÜã` Ç'§tI˲•»£=µÖôYéÜ™7rêl'Óš'‘b6s+g+¸ Ô~Ùl­ˆån›7ߥIåôŸ¹`Öè¹uëׂg «eÎܬ»ršC"J L6Ìøk*=ëÝtÞ{§¸,ÛåÎwƳý 4-®á]Îö‡ˆdå•.Ðñ§ut4GýžFÜwCÇ=9wþfØé.C>Fµö㛿±Ó˜’æŒþš.Ù72}[€æd·qÖiA8Ò)LÁržA+Ïyg¢ÍG/‰€ÆáŠÛ–ÚüBjÞêHdhjvÉ—#ª¼ÚzÈÛª€ð½Ï²%¡••7?Á%Xú8òˆÖk"nÌ´­ès—ÙÉ¿½°Æz²s5m¨Gͭʤ»#ewzsþ®øtÛ—ŽÄŽ]Éjk»ÖźAs-ÛÂ*¢¦Ã0Éš8St—Wœ‚w¢~Ž)[¸˜ÀïÔ½Ž–µ¹”ÇJrôâ;sñþ÷›û§þÃ?tØåI—ݱü-ØI¿ Òçe‹ŸkH¢Í±Zq‹ùáªëZYoh‘3pÂüa¯N¿Íqº 0ÌŽ~ôסYô½fP\¾¬¬³A û?@zP©{ЍÓÓ“Î^-7òž¹­£{ÏÈë_OL$Cr×® ̇ÞgòI6ï¯z®Ëì]v°iW%×å6'Îß®ö@iÇ™Ü÷J³íÂÝ'*û˜ûM:Ð]N¦-KÅÁÒ`mŽél¹SSm’s&‹`[ó3çÙ¿8²¹Öu–`[§g†?áæ«{Ww´8I$9ØÕPh\…+‰à´¶pð-ÕM$-:ß™šÖ¦W·î9sL\Ù·âé†xá™Í¼êl:NŒp¼Úq½_Ф߲v¯ÑQˆ¡‹­ü¡ºp6”Çu8šCv¿Ótš RÔËá#y9'騱ôºÂøà˜öñÞgLŠÝ؈ÅÖœ!ÄË ß˜»B´›UIFé¶àÜI_ôqTé_ €ïÿsÙ¦ù]L½Uz¶á+P8¸ð¶u¿\ó70Åå ¸ètVi;qêvF½£@Ag};X ÿw·«ö¹ ü[îVÀ`\°ùÅabI@„§‡ÈÞåÏ\HTŸ q…ÈÃÛGç«@àîøßDÜÄõXM6 kð@\œ3Îl‹@BÜ›€Z]EÎ=œÚŠq†Ž@Ÿ>{¸’-‚XΫ[.?–$Qñ‹k©‡iw+ºï 8Z–ü·4ƽ“8mœÚ™ùiÌ uFb$V<«‹*.ŽN—f4 öÜ¥’äEÕäì©r33ÓIö`^R%б…ÒZ.Ë4ÃÊS'»ûnÓ}­°–ò9 Ï0WÒÀ»»vˆëä…àöà^T¥í2Áææ1xD}¬ä‰ìèt—d'šýÝNY77®ß"1˜Ú…nŸ*KæŒ1[)§‰+˜ÁÏŠ#'íøÉ–1@ë\aÙ=ÈçÔÏl+¶¥çµ> Óàh÷~¿ãiø'[n°$¸m°“í£-þîS)ÙÓZN…pÈÇ2«2®æüSaàt‰¶™Š †æ‡*X/kvæÐïmPR>›¸(•ÚøÇ1änÍC#*FˆKµß“nEìÖMÜP:„D¤ŠY,,ÇY›¾‘Jvøì¼Â:KŠ–ù] tñµoœ2õ–±W6N[ `Ðètê[ò7ŒB —þ@ñóé ê—£VIÛ}"–r¼Bžõ†Ÿá4ØŸé•,5ü²ö™’vHD5á5<àk:89càôœ0]rɸ“—¹Ün±2ÒéÈ!>ÞtÁÛé²Ð,Ú¼ñD =×°f¶¹ìcâ(>éå{[± þ^V¯OTÍù2÷s`nÓvÖøb·Ýo…o±Bó]κuA¤Jo€59Ÿµv Î ·ÅÕWÓ0ú³ªÄfËuƒ-'<=QZWavX¯hò ˹;Ïi…Ï€ã.‹(ðÈëãˆë[¥«X:Wl8ZÞú/¦ðžÊ½`CþYûê¾o»´N ª»¿l4å•#ÄÜÎâu®AS¼ˆXΰ5“ge%'@ H'F¯;ã"‘› …ÏØo4xuÊsÃ^XÈÿ§¥{K’T‰aúÏj y/ØÿZÇÕ÷câÆLwQ™Ø²-K‹¶àW ?I©! e–Xìž—f"Éna×nÕÆ3oßAÇæ¾rï‚“×n’„†s¿–Z6E#”À_n\‹1ÔÏt줠Ð~NçÈ'é’¢ÞVË”èä»`çt½yo2Z\ùYÿnŸnlªÃ‘¼ÍžLO jÂÈ›$3š=Ÿ“mÅݺq©htÍ‚9†9ÏQü–@;­Ü]ÆÃÿŸé§Àc¿Š áç2¸è´+¬ ?Ð q.ì·Ï½NÐÙJwØj±‘;‘§N²Xy~^¿w-[]^¶òÉà%ÝóµN¦MÖF,læ^Øf×lÖ4;La¦mÀk¦=jÊJx$ì옵Z¬Ì?&a’ËÙóU sàçG†}'„¸ÝN¶*àØ‘k}®FëéÀzÏùvzm«!sJ£\ö ç?9ß²'´_ã:gÓj‘Ë'ŽÎ†³{«eRÓ›Äx¾¦ÛHbóNB4M;žHۘ߉®_>ê1äb°á¼ŸJ¾\¬t¿“!yŸBË@lÖI·Dãì}ñ9é©•ÕIBVÏI <ñ: n§nžû‚šâß§dÜk‘+I†.En>©ÉqïùyçÍMÝSåä:(É^Ü’÷[þ—–XSËiÒ©DZLJ€+EoX‘Êu³x~ú°Zg?Ë ¨©‚æo:7œéö[IÊ+º÷¼ëgí—~ö4˜E=½¬ës¡œ5_)½ÓG>m)~Ë!– H°‹F֞ȉ2qòîXò±Ë[ÿp×xš‚!‰ÄL¢÷$AÆN3éJˆ`º^VvSï„0rUsþä󹞶§„¿‘žæ@Òá´_–Šî&°ÿ: ¾c¬Ñ×ÊD.r^{‹áJøÔæÉRbÜeTÝ««—·r8tÒÆ’Hžð'{™}š†Žêþ­4_ŰŸZŸ¤²8ùó>ŽrúâG fd,İdX‹ªýPŽJFMähO ž”é³tÔŠ¡‡/@Eq?ïZn–¸¥ÒɨŽ9ó=É>È&mr:Ï_£E™œƒ‹\ÄkžÚƒApF3Þ%ø|M4nt ú}üoX#ŸÕ6ÚÊY1¿xLªƒÅö.ahÝS÷/Ú7µ…›”opŒÉ·æËÅ_4¯D·Æ=˜a˜ÕëW2ç÷h:ºæ1vJtL-ëà×&š¼ÂÜl¿GŠ‘Ï·óµp b{Y›¥~¶#·r'±ôm½¾m¥aBs-§×-j¥:Xlsð|ê©’®CƒÒL±t°© á§¾LöFxDÖ=¦Ù‘úÊeH‚)[+ôí«¦J ’"Ÿ¾y—“Ÿ8@~FêM@Õ)ƒž 9Å= *Ø,É —$ùæGä"ܨžÈþ¼¥ýu¾Wò:š¼F’Ä&ÔŠ>½è:ŠÊ' £}öº>~ßøGTQ–%/Ž^áÃQ+ï +Oòóº[¾»óuŒùÍz8àÂØïZØZ` ²~KIÀ~$É‹=¡”Ù¹uý°Ü“ú5™hçzHXÏP)K5ñhi袙‚Ñ( Ät½ÉúËAºl™E<~çôÏ ˜‚ܘ{x›‰áU›÷¼­yièÖhËn‡ ¤Ê}Ëåøqçì\|š¿K®váðùÝ2mη'IkHY2§6¼RgNÅ*±‡—×(ØŽRbÖ•‚“Ù›ú•æ’–õÂîŠçI@o òsº‡§æÑš‹%¤äSä£7ÔÍg©ïwÌ–œyF²3Á³™F·lP”½²IJ»²ež~Äþ9s ›ù_Ù¿¶j¿ZAH\È‚ON¶™K™Î´+y­´$Èœc®OŠ…¼¿ywÂ;GÊü”5çkU£úß)ô:ã[ŸF[®â:Xƹ2³–|ü”_`7#)bÙŸ3Âì¼[°UçÐGá ©°­Cꔺè¥ÆuK&#xú5ÑXKp}Ï_ÍÛ.šóHÍó ‚Z¹$ÚëÆ©ÃF'n%ŽW ¿ ìànqêçay"› .'g G¹ç›*”³™´MÏ`HárZ s ®ðÚ¹y‹a†ýÒíqȰífâ©GS„OÔ縅oÂjòY.²õIÌÆü߯*µÈVy8o–Mº¼tË~3Ô{ˆ+Ô )10¯é5å¡]ÈéA;vf7‚,Ô‡{¾£1Míÿß¾ÉÉ iF–êUŸI\©@zŸ\Y^Tà\û‚»¶¹Ù3{ÑÏÖ9‹@ro¹ç‚úןÚQí¶æž#YÄ2ÙÔ‰|Üû¡ý$›ÒùKŠÛy@­‰ ©ºî¦u†•(ÀH@eõóµ¡?õ]ÎGËz¾–w°‘ß¼*¬…©uu܃ñl%¡“†¶œ|Gær _ó•àŒþ°ªcâÌaæ#@Ãñ½yõ¨¿åšîVª‰]gðu»Å£/­óS„o„©O¹Î%„ÓÅo–)N›hYažãÈÇëS‘}»Q¬a—¼Æènùèù99…»s2B.$Ï*ß~J:ëä s ÈÔGµ»*)ˆ2ݼµŠ†«„sŽõ-2n.ÝÚœk’î­;—LªŠµt Mz>ËÎÚÖŒÁÇSû‚ŠÐ9ŠÉðIÁ6Vô/že]n&óÞ‡ü¥\‡=ŸE ]:%òe4§Ë5s|[$ͱVŠï7^VÐö+È£.ׯÔý=}«t=NÔÊ.’Œ@n·üõ±îdjM`÷"BïóÒ)2Ái–ŠS¯é>%>¯@ ³ÈÃp—ÎÕAIi]®ŠdŒÔ‰ËAn¥“vy¾ør¨ÄØÔ]‰iÓ/ü½”­ÐÒ˜qæiü%ŸÐ-×Ï¢z±ñþI˜ó7Ð%ø¸ ¢_V_)ut>Åa7lÞ)|Ë<¤wmûŠjG345¬µ‘ܦü ñµÒžX«*7 iÝôr Û$ü“PBAàï§ÝÚLõvwEÌs˜“7ä09q¢Ešò*9Œ¡Í£…ô¼;‚óâÞ䨌\P=¾íÀO°ëå2#ž¤íäǯ̼4˜îceüÈ×#ïbr2óIk¢¿öÖ”ÐÍL=µˆ¹&3³Ë—?o¤§1œw2r z¿MBRwí'žtóD.£á[ðÔ3@b¼¦€¢ Nöœ9¾às‘=J¸r±4L™¨uèáòZŠã k2bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEã .js‰Î IDATxÚì½w”$×uæù{ï…K_¾ª«»«ºÑ¦4Ž Ð{/RZ.9r#¤³šÝ3š³;»Í93iÎjÄ!EÊP¤DQ¤$J@¢I @o@{´C›êê2™•&Ì{oÿˆô]UÝp$@ÕÃ)²3322âEÄýÞýî½ß€em¬µÁ±cÇØ°aCûõñãÇÙ¸qãÚĬµ8Oî{ŠB¡°âFÖžOú·Yí;½ŸÉôµHß·F`­Ec‘ÍÏtž™ækaÁÓü^ï¾…Q$¶Š±.ž€® ŒÂ ˆX±*ýžµXÑûÆt½%;ûn§°«œ{s{!IJç/Äùç³û»ÖÚöëî÷ûÿ-„@4'¢õºaÎù¬{ÿ’æï Âömkz¾'»ßöMakN–9†þã:çJ#ªóï~ýÏyV{&ÖÆÚøi‹‹‹=¯K¥Rûýr¹ÌÆS°( ‹Åóúî÷ûÍ3™–²6ƒí‹tÑkЗ+‚… ÈF(/„À@)K½QkHr¹¾8,ZçÔzßZ‹­}ÊÎqu­Î±ÚsÀbEãˆYLZF·ß@XÞà !ØUAÅJ»:uí;Ýg/`´€.ý­ â@£û½ôgú€Oöž»Å ZàfClb)NŒ&G”#øîßàÓŸþ 6ºì¸dšõ“cx™ÙB–!¥*qf&ÆÖ~m·gfZ¿%zæ¹},,!;ÐÖù3Ý{Æ´ç¿ñÒûfÙ{a¹ûÁö{­y¤›à¡T€•‚F¬1EÈ&x˜îÏLJÔ,C õÛíUçm™Ï-ç‚q÷_Ï| Ñ=5íï Hç¤ 4m#½ ¶œGÔsN¦?HE9e‘]×LC{u¿ÜýÐ}½Eد ¨Íy’ˆ Zá×c‰ã ­qeÌ?þͧø§[þ†kwngû–iáy>ÕDk×É"lHi/X³kc (.,ÎçY¬hPÎ3d×Út%k*›Æ^·©ÅŠ{no1}Æ:5HºÇH»JÒcŠÙ"ÕòY{ø(årÅ®×S,¨G¦ëÜL×ÑÒæÂm—¦åxX‘p˦¿Ù7?r¹94çx+®ªWð¾VóìZÛj­—¥ º½±þÝv__ÕóÝVŒB¦À!›äèºv€îLÓ2ÞBçøÔyî¡–ß"{ÞëŠK¬,^FP­ÇX[ç3ŸúsîüÊ­¼l×¥ìØ¾™D‡F©°N¡âXã»™L†r½¾f<.àž[ÿrâY{Ë=¬âU¬ºMßÍ*ºhÑE»¤œ}º—=ÞDoP92”G­Y®Úu%FƒçyÔ BÊsi’¾•p7`XÓ9ΖgÐŒþ˜Ä3»0ýjO|¦Û;h-õM/P¬”\ÐO¦±ÞD÷BAéµt»®¸Ù ›.À2ç¹OZÉ«Ý-Ò4¯q”»œÌ^´m*®ÇWùøŸ}ûîú&¯½áj¶NMR"Š##Ô#Åb#bp¬H¾XÀèa¤jÒ™ÿÂÇH¬ÅùîçùBç:dÓ»èY ÷üÛ.›5Óæ°û³v”4ac…1 <a6‰ûŒ­E4ƒÞÝàÕ Á91Š•h±Âêÿ‚/¤Xþ¢-·º>'Þeøì2°²ùAÛúvOÆê>°Hc²®V4 tÓ´buèñ ̪çÕã•,s?ž»]‡¶¬ÍŸáwÿûæäñ½¼áÕ/gr°ˆµ–áq*‰FEah7“¥^¯ã9×z½ŠãûkVdm¬ÅyœÀ•.& ‘®ƒ ±¢¨#2hSÇÒl °aðýÖÆ(§ÉA¬l-ÎÉäé^ÍÒÀ±Å‚’mš¢õ¹cÓÕ®i)RXÐ);ÙJ>^ u ®"2gq¼A¹ÿKÕy^~Ó&„»€±Ù ¤D¶&Û‰4m£±MúD¦651 Œc‘"m´Œ¶µº™Vë4÷×2|¢=ÖZÌ*Ýnz§ímÑ÷z•,"œo›ôsc̲7‰l{[u!,ÖŠfÐÞ Œ‡Hy!,¦y–€”ìv d;(ÝC?Ûž'k-HÓ<Õ¾.R¤qPJÐkd Y°Ab®røÿþwð9›oØÌäxá–Pù”bòU‚Aúì!ŠÅl$ u.ˆ$Y3$k4ÔP\ Uo,Q˜`©^Ú×õ©‡5J¥"q¨ñÝq¨q=…ç%)“lõš&ðä»3J_7sJˆfàU ¥ìi!Û†Ûs|ªIcÀ¸ä²Ë‘"&“ÍP­/â)µâ*]ô¬[»ƒ¹€sû˜lw°YÒòV¢¨ÒϺ/Ü2ÑÊgu3œonŸ %¶¼W”·À6=ZÕ AèÞ”[±jöS ¸ÓThƒ1©7#„HR¢ãNÁK•ùBi-÷ßwZ?ÉM7¿šbÆÇHA¾äRiD¸n %2…€Å™E<ëS("‹­Õp=5g†Z‰µq!4””Š(ÑäsEÂ0BJÉ@±D­Z#NjòC$I‚ã8©aÆâ¸Jy`’gmœ– ¬/GÛØïÑe€¤(a‘ÒbL3û‡XÔU¤ãRÈk1žç¡‡zMãgЍDtj(º ôzŽ©Ÿïïÿ|Ùó”+Ç2ºâ1¬J³üäVçÆ;úÀlyçÔ`ôŸïÊ4Ó²€"-XÓ—ÛJíµ¸žÅ˜„(Ñ(×Ãhøö·¾ÊGþð÷ù_ß{)9Ïe`p/+8³TÁ2ÄÈèz’¤Lyá,›£I3Ÿ¬®#UŒï¸ØdMÄ`müËô(ÎG“ !Ú{Nkm›®À-I’ %4×õ ²)c/A7„”‚8®#HüçõàWÊÌZÎøÊffOû„E3ß‹ïû$Í*d­#\'¥µ’X#…›fú´Î]šÅË€í*òþcëN =èuˆêòVz¾e»h«ÕæM,?—生ÅÍqxYÙ¯–e¤EbQ”Ri†Õ ÇÜ}Þ+ÍQ&W++NˆÞ9R5"\/Àoý{>þÑÿk®¼ˆ‰ÁõácUÄB]à{”òëhÔæ©TâÈ"ãcƒ3ËüÂ|ó·’$A­¸×ÆPtÑé½v¤\.wÀ"“ó‰¢4通A ‡$r©ÖÊ”J´èØá` HÇo Õ*ð—Mëíª|—«Tµ÷ƒ¨Xå>è†K)ÖœïJbp8lðÅ[ÿžÏ~æãÜtã•ìÚ1ÕCdK.‹µž7ÎðÀaã qí®Ø86Ž´ ,T¡qpT ’Ðà:k1‹µ±çûްP>ÉèÈ8=~§fޱëªëØ0¾•z5$±O?…çH)QŽE)‰´>Idpý¬ø|ÔKšY$è_‚[kÑÚ eseÛäÌ»#Ñ!Öº(Àõ³'O€Þˆ«J@Ç·hVi[‹¦ÉÄ·¼‰.´µ‚¶äDo…¹íduU’÷‘;+iÛEÑôg÷ÐSº|îj¼«ˆðyºqº‡ngÙ62öèAõxX¢WšÄžçwew–[ äE§øOÈvöUkî”RHÕô6Œ"‰êü埄ۿô¼õ-¯dËÆQò##œ-/00¸‰bvjå)ê•=$2ëÑÕ“Ì-ž â$™ÒÀ“¦RWëÕçeѳ6ÖÆK•zºáÜò…OóÖ·¾‘GŸøgöî{”jõiÞúÆŸ§]vÏ"Ý%ry—8)3»°ŸZ½ÌÆu»°vô9ÌrEeçœXÓ0Ê–ÑnjA IœÖ !¡]@–RJ™Œˆ%q’˜êÒ<ƒŽHPÊ¡P@b,ƘžTÍ60ôÉqØnÝ%»Œ‘o[ÂŽfÕù NkÕ¼RÍÄóyã¬dèú)®þÚ‹îïÑ[¸×ý})ä3òRú ¢YðhL³]J„LçRkMei‰ýñ²ç‘»ù¹w¿–|F…u¦§/ff±JP&?P¤6[?Ê€2W^ Ñ©/$h“€ÒPUL¡”‡ëºX½ºñ_\\¤T*­(ï²6ÖÆK(η}OÌâ†ënÄ÷²ÜtÝ›¸rûfn»íËäs>¯~í»ùÊ×>Mµ¬©4îb~î4_ûƒLL–Xlàúk_Ã{ßþA’$B…ÆØ&`»¤9úN¤•í#ºULm—JÓ- 1AÕŒ©èf-„±‚ÈÆíß“6U\M¯¤‘XHb|¡ˆ<‡Fy–¬£ð§±É T Hk±Ö!±†$H®j页&N ¦™æ«£LÓs1=ÞO¯6”é¡ÒÒmTRÒ•²l õõÐ-¬éÏ–’]´˜i«½ŠZlù•B…&º¿Õ½èý¹®½Ó¹FRJœö¿Óm´¶§žê¥‘ºk±¥MaÜu]RJ<ÏAÇqšê,%:VøCÔXÂóʵ æƒú#Çåu¯ßÉåo¿†|n€\vˆr­J%r™šáÀá#,•Ï0=œ#_€X“YçS ëøÕ„†Èqðl•¨¾@"BüŒƒ#¤Xõi)pöƒú…þ¤öyóë‰ñ±k@Å„ç57¾—G*lš 8uòVçXÿ²W’q7b ‰¢£eŸá¢]ñÛ¡YúNN˜s,Ë?dÝý: ‘mÑI}mª¢¶W~Z·EïŒM0:&ðÖ]q‚´²W‹²#A y®ÜiKv³¬2m?å´l}IW Ã6ÿ?­#¸° ¼Òªö|´Rÿ¿¥$¿Ò{RÊöµ56i{!Z§T‘0+Á6‹…mµ^cb¢("›Íâ8aEIûZ†ÑnP`¾b°Žd÷CóÑ?ør,ñ¦›®&›)14\@xа×]Ç`i#V/à9.ãcÃè°ÌÙ™c¨ð,*YÂQs}j"$ŠÀõ]‚L¥\„Ç•¾<ïÃÒ’j^‚µñRŠç -ÏBLLLF‡ óßüÑï2_9F­a¦Ä­Ÿ»];ÞÃåÛ߯Sû ïyûox%u”³åC$qŒ ¥œæÊÞ4%£U×ÊS4Ó\Å* °ü‰vâ½²šG´9í”IÓ€µ6`²µè$J9qc:IT=ÆÐâ‰r$Ž«š¿i:M§±\Š­]ÕÍ[IE¶h„]^eµ?¾‘VP›ž¿4¯û¨½þ›J®˜ µ¬ºí2Û˜D§êÀÆ‚Xm”hm{ÿ¬Áh‹Ñ©¶Vêi Â0¦Ñh´½+ÇqÉå2ˆLŽÈje¸çŸ¿Åû‹@ÔyÕM×PÈ; m aªT¢%\w”á¡õ8fŽ…“2VTøÉaù(I¼€•1 S5µ(¦iêI‚Õ6M6c%ˆ“úsz8W«5Ykã…‰ Šçí‰Y<þà&‡¦À;Îâ’%PŸçu¯~/3§022Âî½·³õâ1Þû¾7'†=‡ïâá=ÏÙ¹ãüû_ù:R¸Mù‡¤¤4ÄÑ$$DoMtk¨®€n~µìswêdG5‹µ²mlE·1#ÀA4WÁ I‚Í MŒƒE)ÕIÙiE©´@ÑZIM§`-ÆöÑP-zì™^k-Buvuýëè[Kq­ÔÌ(Õ~r“zQ=ž‰zVêÂýžF¬“T:\J´I3á¤cJ¦¢¯Ö Œ0¨æ>´IÒ€²Mëyü¦&S…$‰ÄæLTæŸþáÓ|åsŸá5×ì`zÓ:_Q$6óÄQ†ÁÒvò¹AêK‡ˆÆ©-ÒXšåä¬&Š«8DK‡XÎ.ÔÈx.žç¸BºÍž$ ›<óì²åtº–£&×Àcmü¸½‰çƒzZn8¹Á3lÝ1Ìõ×þ^)Ï£ïào¾ð›„ ²Þ»?ÀÅÛ^ÁØäð©oqráææŽòÖ7¿åtœ`ByÇ•6¶§+5•NL#+ˆ-Ó2býT‹¤]÷Њ!H)zh¨ÔËèPVRª6 æ…«,"Ö$QLL’D(OÓÓ*ÕÒ¥®šÚjÏwSÐ!iÆdšt¶ùZœ³"_©©ÏJï¶+"èöZDÝ´:¾œ9²¤€!šF{¹cY­po9¯Àó‚žzm°îꦢãFØž k-™L04j5<Ï#› 8UYäsý1îûΗxã«v1:˜G(Kv`„r(¢ÊØèdüQ!“§Ì”$2u°Žc#æjœ^¨¡¥GÆ÷Áh²™¹lDˆ#Z’5R¸ø~æÅ+ÎçA¾”и­ÅJ4”à†é©aÆ_FM68ðÄ]<¾g/ѼËoþÛëùÑ=ò¡ÿod —^¶‰;¾y;[·Lq÷}Ÿç’õ¿Œµ^3a0B£Ú¼vo º÷„:F¬mt—˜¦BS(¬0tgY+Ò•´í–#TèO¬Iˆ£Æ$(“ŠT"¤ßˆwŒ€ëzXk‰µI¤KvÙÌjƼïü[ºGÖÚ®Ì&Ñ®îNηXN½³­i Šž@~«©Swšïj7ÕJç‘XƒNtsŽÊuš…’%m€l-dz½'Óô*¢4J§zcٜǙ3§ùÄÿö?ñ0¯¹ùe ”«]ÏbhÈfJLN^JmIsâô(QfýÈE%À9E£|W ¼|‘ÅšÁq%¹|‘ÀßÇñqµ¥²t†È*L²Dl2Ä:äå!^kãÇŸx¡îE pìèq¾üå¯òÄ¡¿E¨ƒCö?y–ÑqEƒcì¸ôZæÊœ8õ4c¥›ùµ÷ÿ5Õ™­Ü§ÅØß÷ð¼TŒMëTúÛqœ>¥Ù^éë–HÜjYEË­È{þ¤M»¸ueåt÷ˆ6´ øR"CKm»\¤ì=.)è9ÆÎ¶ïj<âj¢ûV¦­}«5–ÄÊñ‹¾c[ÎXYn?«}göìYÎÌÎ27?Oµ^#1:-TT²=­9²#ö(¥$ C\×ÅuÝf¼BËexê©CüÞïý7Nî{„·¼öFò…,Aq€ÒØ$‹\¶À`¾H\“Ìœ>FÆwØzÑNŒv8zj‹á~¶€äñÜJe(†Åw=JßqˆÂ*å…3„á"Ò·ø“.´^„µñ’÷(^húÓ¸|Ç;ùÁ½ß$Ï\o!®Ïòî·ïb~¡Ì‡>ü)v^9EFùì4âøeûù¥÷ÿ®»öfŽg‰M¸V#°†¬*‘h@†xÊ'JB #=ŒqJ€õFOäšµ©þ0Ýåm¥ú*»[A-Z£¹:oÆR *5ºŽ1(ÇÅdò £4~£BXPxʶ5ˆŒI0­lšÃƒ2©šª'FY,†ÄÐSdmMZ$˜*±ªÔ@"H´é¥eH;ì›J ;M¯"I¬R(aAJ,RÈT«¨].Òß¡•²«°²)ýÝœ+Ù•&šsB+Û˦ץbù–¦–MÍ/ƒI"„Ù<Õzƒz#æ®/~šãdzný$¡N˜]Xäò—½-$Û¦.£P ( ÉæPJ‘õ|ÇDu”Ê#½ôú%”ñ9ðä~>ú?ÿ3®SæuoÙEÍãzE2¹1*‘DùJãä'݉/]¦Ö_™ljâ„g cC¤ -õš&N4¥ŒBÙ%Œ£HD{æG”3²PÊnA‡ IT#£bæ”y^Ú5*gͨ?Ÿ÷Å3õ(žoª'uömoû>|»î¼‡}OZ¶mº”D×Èg®çæëÞÈ÷~ðY\FF¶sóM¿Èb¸ì0c“<¹÷~6NQžÕŒOÓˆ–Èç"S­8¸nF-$Èê¡FZMØÈ¦Ý׺WËtQ-fÕvɆ·çdÿ>:1 €0މãˆ$IH’!í9B~½©°©Ì‡Ö:õ„ÄŠÔÔö{GV€Ô²ÙŸ#5Ò‚4ÐÛú¯E»‰fOŒÞßìÐjÐÊ2=r÷¹I™ö-­>ÜVôÄÎõJRiŸ[_'¼sn3ÃR#d±–Z—Òà8cë&˜Þ´™‰b‘l!Ka Ïøø8=|?Ÿø“¨:¯¸öjêK CC›) å96sŒ±‰mLŽmņ§9ôÔ-d4èºåÔ᥅³d©¬UÄåˆÐ4ˆ¥ÁÍ™€ŒqT™SÇ"gê()Éx>ŸG¹YT¨0ZbŒ8/gûlúͯ¹@±ÜbìÙp>êé…ò€€?ùÓdJ¬Ëmc~ö4Ï些Ǹë;ßàª+_Ë[ßðólß²…¿»õ?òùoÿ70Zz=#ÃÛyô‰ïqÏÃgÚÁ;Þüë8^–z­”Yr‰°éŠÏu3éê_$hà¸>V6­'ݦ ¢-aú:­u´”šX‚’¢íQ¤+þ¦¡iÿf#,aT'ÑÚD$º]ÑmKÓpÓ¹ĘžjìÔ¨ë¦H*h$mÚtÉXÙ[±½ ­£» ¶íÍfZŒ]À» PôIqtF+{«5‡ Ñia%J/SGÑõoÏ÷I’„L&G­¥©²îÿÑ?sp÷ƒüìû†-›67B†K²A@Á ðýœ²—³EÇ4–°qƒ$ލWCt"¨8ÄcOU˜™™#Œ-÷?‰ŽË¬+pÃÕW#…ed|KµÓ˜š¡TÚÈèðógP=û%O “”+0å*2¬ƒVÌÌ-Ј…<ƨL†DB>ã`–æ8yäAŠ™:–€Là*a$´S¬-R:ç]Y=[ƒq!’kã§(–{ý|%G¼O+-–Ú`ñæ·¾ -ëüÙ}‚ë¯ø9î{àk<òà"±vpÝyû{öeù•_þUffj9¾Ÿ#OÝÁžÝŸg¨áå7^‚µg8rì‡,-ÂØÄ4“›‰â€$ž›”“ßWÄZ`èòì9•ÒÝ+ëþ nÒîNð…NF••šŒF£†1Â’($¶¯Ñ5]^…!I4±6]W­ßìæ¶;ÙSB´‚ù©aïÈŽ,_“‘j(é•V‹ÁÕ²'þÐíí¤°bP]йéè4 ÔtÔ M[‰W¶Á3#Ùs, ûtDQƒ ›c©^C)Ai°Èçÿá3|÷[_åÿüwÿ;“£ãÔ+u\×!È Áh‰Z­Nɱ8Æ#ÔŠj<‹—•ˆlžDø,Vˆ,—lÙÌ÷?ÊKs\³ë".»t#õr•±‘õœ)!È(·Ää†+8qüå¹=\»m²SW»›•ß1‚F&'?„Êyø^Ú«"@ea 3ÊI+‘®D>¦±4khRñ‚µñÓϤ~ì¹Þ?. è¶½@-<ÀÙ¥=ÜxóNNßG~¸ÎÓGFÜͼç]¯ä»ßÿ·í˼ïï§V[BËîþÞCLŒO±{÷#ì¼bs‹‡9vвnôjÐE¬ Éf=ŒÖáH‰1 cÀQªƒ½‚|i0\öLÌJÕ:ƶOœOÊ&×oh„U¤WY¬ŽPÖ`…³ìÄô§Â¦»Ta6ýÿîþ4Mxp‡çñ»µ„µ©ÄHë|1m%[­uû¼Záþc’çô_P©$:î®BªŠtwÿ“Èf}I+ ØöeG9EŸ0làg’8ä‹·ÝÆ÷p'¿ð‹`p°@ÃH²#(×iÖ\(WRòd©-Ö 4§OíG˜y O{Lsœ`ÞÿÞó07¿ü*¦§‡ˆj‹Œ ŽÐcŒ2 •612:ÍCá:†]W¼Œò©CäœE²¹!ŒŽ°:$ j³ XÏ#?XÀËæI’o˜?õµù#Œä ¼N¢Q®‹5Ž—Ex.N –¸²/2£²6^Ú1Šjœ+ôÂCOÌbÛÔYz²Jué4±á)½ IDAT ›ùÆmg9;«ÞÄEc¿ÀcÅ“<ü£‡9yÔ²sçNNœÚÏkÞ<Ê]ß8ÉÜì<—]|…B†×¾nWê=ØY\¯ÄBå(RF|õ«_çæ—¿ž¡¡ d³´±M©ÀþìžÖE0¨¾Õù9…PJ!úVÆ­ µ"Mé7ê#°è(› ¤Û6¢Öö>ÈJ)¤ì¼ÖŒip›°Ç©‘±Ö’XÓ“œúÞªõVÌY ‰n)ݶÒJ­ìÓŽ2}ž”íÊà¢'ã«Õ{¼UÝã1´ã(çÒT-!Àþû,Œê8®BÇ îþÁwøú—nå×þõ/²iz(ƒ|Ÿ(Š(å𤃮5B0«K먞¬àzPt õÊ"ƒ¥QÊá)¾ùí‡xüÑ'yÕ«^ÅæãÔª‹ŒŒ¬CH—ĶO¾‚|^r`ï]Ôª^~ýÌÍœ`nn?eç,J—À„ø®G E¾T¢TÈ…†|&âÌñû0K3ŒçŠi3$ß%1Ò H¬‡5 +¼´²\¤ œÎ—8{¾˜Å3y`Wëe²"?=ÔÓO Pœ³h,Ö9u¼Ìĺ,A®Æàð»·,P­ÖùĹûÙ²k–ýG4<ú8ö‰¸r˜ƒ‡5›¶Ëà¸&Çv⨠„ P"àôÙ£zênö¸‡ë¯}9ã“9LÒ„pÛò©q–Ha0-ξI¥t÷~è_?Žëx¡Eµ/hÌbÇ•cÇÞÁù¯¿Íú‰Íxj7‹õEF'6sÛȾ™ílܰ•Ç<ÄŽ‹_É¥ïb0s&ÚŒ Àw=–Ê–/~á{Ü|ÓkÉ—ªdLŽ|Áãkߺ•WÜ´™o÷êeÉÎËÞŠÖ1Ɔ¨¦Qíx­â4VŒStOšmzbßb›…uJ¦=0¤˜$Â$1:NHLˆ´,#ÙÒF²Õ™µ+hÞñ@°i0]zMq<®Né£$IÐV`pÚBo€¼o%)Ótß–ú¬1 ÂHLW½D«6¤T¶}Ãçoûƒ%É–u?‡ð<Œ!–&•ƒmÒ7 ´èé4·\à I_ê˜èÔ^DIƒœW I4h†L¦€ŠJ¸ÕÔ0jJ}4e1R°IµúbímÚ¦%_¢Z ·V‚ç µ¤!,66(ŒH+¦)nØL‘ED[T/ÛM9w¡$(fyÙc Qdpú [²à©²­Ešf7%ŽuÚ1ŠXÆøA@F¾Ÿþ†´D:ᓟü8w~ýK¼ã-71:è05žc¸´. ºÛ×ÍÅKc¨‡ujõ:FÌᣳ,Ìž`éÔIŽÎíçûñ8Ì/Ìòte€ƒ‡ðæ7½Æ÷U–g댯¿ˆÒÐ0§fˆê ¶ î`ÑìC;1¾ž`©r?“P5fæ ùb£ ˜À¸1…@AcžÚÂSäó’(‰ñ2%2™ R7hHuTA¦ÚöÎ,:l‹˜ú±áÚó>,-ÕÙ盺XNMxm¼4â…¢…~œ ±Üý×ãYÜòO_dãô•ìº~'ÒÝÏS‡Oájµw}k?ÅL‰­SS\}Íåx™,—lsg¿Ãñãóœž;Ê[^÷KœÿµßåoضõF'ƒ6Ýõé ݃0¶§ßÃ3íî4{X4³–ŒmRK£cPÁó²ÂjKˆÉ”ÓÖàXKl5ÒŠ0¬lÊ5½›‚T«x·HáJÆE{ŽNÑ9^˜´tŠæ;1l6K£á*Õ”º0Xó©O}œo|å‹ÜtÍ”²‚Êâ zØ#Š4ITc TböÌ®'Ú4`>'(\6lX¬Ã/gßÓqxïã4ª 5iˆªu®¿z™ F¥–'SÈҨƬŸšbdp”ãÇOP*¹xÛED³»Éx–H§~R6›Exß·ŒŒdÈæ3ä‹ %`þúý(^A’Ä©\ ¯¤¸R¡õrj¯]GŠ®ÆnB½U‡Z’©Uv_ˆ´k’ê2övÓψ‡¨6R‘f é&½ Dˆ4¾7{=¤¿Ó:VÛlÈÔ-Án¡K~¢Õ6¶»“TýàÑW‡ÑEYÝMóIL¢Éx>Ês‰ã„æ¯þâϸóޝrÝ®‹™ZŸ#`t`œ¥ZƒÁR‘‘‘ tXcÓÆuD‰×޵$IB½V I|†¼1Z*P9n.”Ë–éaÉF P©W¡˜“ØóŽLoç©=÷bj‡P²DHë`èF‚Ñ’b!‡ &tɺ:9Mya/ž¨2<:†Æ@!B7 Bbªcpâ&âÐçÐÁS¬Û¼…áѱô&Š(Jp]çÇjxÎ÷à¯ÆK(^ÈßýI¤É.7€K/zöÁï1½µH®X啯¼Ž½Od¶>ËôôÛ.v˜X¯Y7¹™[¾pÓÛ†ÝPt®ãÔ™}¼þ]ãTàôS̼ÄÊ'a)ªP>sÑô%<õx•ÀŒ16t1:‘(O ”$ÚÒìI¡ÛHR:+òýçs¡ZÅÑR¤½¤8Íf7:Ž ÙIOtí¯-néɽ·Ë4<²-KN/UåZ…’*-ãhRJZ¤zT¦IéD`…l‹ “6jjý†6ÝÞ„m‚E'Æà¨å›3M éôÊhÕƒ´(+GºhÕzéZþêÆ·ßÆ+®»‚Éñ!ò)|ÊuM. ?x)JJ„­GšZ<ßκ’ÍyRŽ—öq2õˆ‰‰IÎÛÏðø&‚¨AÍæÙwä ÕÅyüŒ1Kœ>ñ8>žÔì{üiâ°Š+,Z$8Žƒ±&†8¤‹¸™àKIeqqí rAÀÀÚ ›€¡{xÃRMø»˜ž~O9IL™uO344†±’Ä&,Ö+HÏÇÆÉOÔÍ6Û¬õôBË +y+‚E\\¶cš§!ëŒñý;gldÑȱgïìÜ9M©8ÂØÈ¼â†!Î,ìafþ쾓‹¶V™/ïxË{øÂ?Åï~ø]lÝžÇQãァܵ|ë¡ÇÈgøíÿøŸQ× iÔëØØâ)Þj\”v0K³vŒ0Í8D_ã VœÕ+%Ó‚+I…øV§2V’Ä!N¦¿7õ3å›é[ý· éR`PÍ´V+$‰4È®Œ–-cÞò*Z+ÿ¦GÒש/çM±ÃÞú’þsï”9¶<’&X4³Ê´ÖHG DÂÇþä¹ç‡wòšWßÈ@Ö!ð™I*壃LŒN’ÅW’Œ+ÑaQCÌ :NÃF…8j@,(1žÀ>•¬¶H%pÝAÂÄea¾ÊÔ† ¾¥2ô¥2Ø„Šñ™_XÂõ³8ÍÖ«®›!“ñÑ¶Š¯NŸý®9Í@ µr5^àâÙQên…ªcXH6°aë+‘Þû§00HnÔ'çR¯yäóEÂD²i÷çAuöùR®ÄKߣX-áÅ6.(zb/ýWÕ üà[à ¯~ãcC—ré†×¾óW4ª@”áþûòÄž£?~аV'ÆÇ¶ñÍ;oçéÓû°‰b`X1²!¡>;Éá½ÇyË[®â†—g( ×ñ— Ÿáßý×\ý4#Å·ShI‹ƒ”×MƒÍFضjìJ©§+Ë7e3LšfšÄ!Y‘\a 6‰ÑMÉÀþ jI3œ”=ßÃÛÝ\(6”©%况\+PÈvU¹U^ÜvZ+Tý¦Ï9_Ѫ¹@ô¤â†~å]Ò#²p–z£Êg>ó î¿ûN^qÃ.F‹²>Ùl–¹Š¤PaãºQÎÎáäÓ‘ FGäóYlXÀu]<ÏÃó<¤tp¼ nvÝä\‡‘QÃðäzŽž<ÉpN3»x“L¡µÃøÔŠ^‘¬ ‡5%ëUê¡¡ pü¬G.ððÝO%4ÂNžÚG>«qd‚N,ùÜB¸DZc¥%VCÈÌ4£ã׳HÏexÝ4¾Ú€u=L¨Ðµ/切KÅb‘£s'_:éÙ‹µâ½—†Gq¡J݉ ?îÚˆçB;µŽ½'fqff‰\ÁpéU.…ÜÕ…!(¬g`ÔPÓgyrïAÞ÷sïçôƒ‡H8̦éal¬¸öš1îüþ &Ǯ㟿ýo}÷$Û/ÄÏrâ™—qÕŽwV®¦4¾Èw~ÅÊãœ8qÍ“ï`óúžï"eJɤ¸ÅZI"¤ã­zá¤](lËà G’Dš8Ž›«}›‚¦‡N=æöÂZÓìÎ×=é­ ­¶·Ñº©0MßZõ÷Knˆ¾«õ¹ÁÚn/"=n³B‘b›J³S*Ñ 7Âò©OýßÿîíÜ|Ã.ŠùW‚ HjÇgãøó'÷Q_8ŠÐe–*®ïqb>ÄG¦*½mYªELŒ_ÌôÔV7K}±FŸ~ž3•ãYÈ8K„,!5 —˜›m`sùœ 4)|ò…,uÊ ”rds%œ "ðA׫TNR¯%«ɉ ‚`KƒFâºE”ã²àA©ðjFG®ætý)Ê9F†w)L!<‹®yxr/7Ç|‰ñŸ%靖­¸?ÙÕÝ‹yõ¹Ïm‘п¿Ÿô5¾o¢D¬µ”ËåŽgñèý5¬¬00à0£f0QÈ™“CÌœ¾‹{xš³³gøÈ}’z=ä†W^ÊcîÆCRÊŒqvþ ¶\2ÏäÆ~ðÏ3ìÙ-)ÏY´=ÆD¦ÎM×Inxå+<Í@]qâè1Ö_L.ŸÁX•f-Ñ+˜çº.‰±+P@byëι*ŒZkâ8Ī„´Ñ˜D÷Êsœç"®„À¶ù™ìZ5t(õ6<êw˜¶.VZ»Ñ¿]ëRZ«³¿¦Ç!d_¯^Ýî ðX¤Ûhþæ3Ëc>ÌÎ+wPÌ äÉdX,×É—FX71ÆÜÉCT玓S ’¤†ãx4j "–øŽF[ƒt%Zª™x å'ˆd…ÑÉ1Ë‹­,?ÊÉã3½e”“‡ãç7 Íi ÇÌ™Nœ¨ˆ4˜…1;ˆ«\⨂špi‘¤~OTÖá8i_ åf) dˆM™F˜e|Ë¿¥®Oslá^2Þf¶®»™ñ©Êˆj C2fæÔ=œ<üM¦§¶àç$gÅÌ ºQ{AŒÊ ÛX/~ x±, ú=¡ U¸mym°Ø0‘eÓ¥.Ã%>Ë# Œqß}òͯßÎÏÿÂÛØ³WRIøÁ÷wcË“|ôƒ¿ÇíwýõÌiês1¢:ÏýíÿÂã{òÝ{¾È‰ã³l»hš×Ý´“ùÆßsæ”àØ¾MLoOØžŸ¤¬GØsà1¼ÅEën © |ߊ%âÄëâ*…±–$²¾ƒPÐk¸^ÓcH ØV7¼.cÛ<_7‘„6BRAø%Jâ ((i`VÕ,àÓi÷=aº¸k‰«?°¢ ÈL{ÙêL׳–§Ð!°Lç3ºÒ±šÞ„¤£œK%×ù~ ªE} Ûne£q‰#%I#„JÆ1_ùò׸㫟㊗°qÝ(§ÈG˜_¬‘^G±4¡}S 昊1èì •FOIæNÏSÏyìܲŽ$®²hkè³u’ŃÜßbᨘJ¹ÒCOPOØ”•̉:µÙS̆9\7íu‹¡b*•E²™a¤i pq…aþôèäùŒïäI²´KV  „ƒŽ—¨Ègìæ+ŒÊ‘Éo"?4…ÎÔ¢l3,KÌ>ñ ˜„ùáæ=6„ÊÍSOjDR¿ æs1NkQ?=@ñbð(.Ä›XéýÏBˆ ‡Ÿô9}ªÊÔú«ˆê#?ù 6 ïäñGN3=½‹'÷?Ä5W¾žòµ¯‰Ý{O‚¨³~ÃeØÏÍðòWnâL­ÀÓ‡ÎÉ*ÆÖû|÷žÏ°uûEüù_„z5C¤O£œˆÝÿ×ìoyó#l˜GÔF¨Tù¡ù`k‡ðý Cb,™vã†(4Yéþl„nÛ+ ÚÄh‹˜DÇ'u¼s&H>'îø™TçVÙ¶ù?- °Íªv–“ YæúzÍ…Q˜ ÇQkøÎ·¿Ág?ûI®¸xš­›Öã*ÅÐÐ3³s 28\bß=L Pp9å--QO" %­-‘=CÖFˆÙÀC› c#9éQ3!Ž­.-Ñ0aš°`„aBÀà 6šÄXªK œ+“‹Ÿñ) (ŠØØÇõöÒ¨ŸÄwbUÄÁ#ë•°qe3D*Ä/h*õiÆÆßAfxœ™hž‘Ñ‹ÈYhT+1ƒ^‘°ú8‡ö~’¼#(å|ß%Bcâ×‘ä‚ Õºó‚gÓòr-vñÓ?é±R;æ 9÷s<‹ÒDW¿~'ß¿k/>:ÃüÜA¶_¼‰Ãûa©²Ìð¾¼×Üø¯ùÀ~ƒ¿úÔÇÙ¸%Ãà°bÇ®¸^ŽýÕïpåu[)—˼ëÝocï¾oòÔñGغé]z¤Ì®kÈ|t©.æyÓßN” ñÿó?pÓÍÓã8›83;Ïú‰Í¼ñ5ïcp` ÏÏa­ƒÕá8©B¨pp\§'屇’iéF!ÀDLH’ˆÄ†È¤žë‰å:¤É {øY¹wÁy]AEÑÙFÇi¯/ð¨Ö#„’<ôà=üùŸ~ˆË.Ýζ‹ÖGuF×obn±Âæ‹¶âù’ÇwßÏE›6 ØÙÙYfs¸ÒMé&QmT©ÄÊB­£¥<Ì26’Å‹jШ¡TL-”Ä1àh<_ШºÄ¡DTcŽ\v8›c®\Ås2dü,Ò*ã!Eƒ¥ÊiÊ‹OለÒÀ0¾“E¥²j íWI‚!fk[˜ÚúF"`fö“¿ŒØÔY¨.’͔ԙ9xÓßcƒ?‡Í¬'ˆ-QÔ@R€Žcâ("ŠôóúP>ß+ËÕÀgm¼8ÀäÅ~ìϦ±Rÿpö8ÍRý»Ü÷ý†J×Erùe×1”Ÿ@&cü_ÿÏ›(ǰRðÿÇ[©ÄSüݧÿ‰¹“%ŠÅ23OWyúè)ffO346Džå¹{Í £}¬ß0Á±Ù _ýâ!¦6\Âûö·Ø8=ÊÝ?ÈðÀî¿{?¯¼é22™.¹ä*î½÷{|ì/ÿ¿ù+eb¼€äH´%ѦÙßÛ˜&Coº]½mÒö:j ã:ÆMÐ&Ę:&^ê +›¯/<…RÓ§KÕµÌWç»]=2:׫ º/ìÊ­7–¾ç£%Ñ‚ ð¸÷¾òÑÿ.½d [6­C(ɺñ TÄÁá1Â0¤ºx–’[ciæ –ÊšB¬qɹYNÏÎrzî ¥‘I–¢³ó³ d ™'äQJj8>‹Êû =*q…Pƒ+Ç1 T³øGã{¾ï"Ý€b!´Õê< »:¦˜ËRÈ C,®!_È"¤fÉ$h=‰M¶±uÇž=MCF¬ß´ ­<”HÈIKýôAN¹?ÆD1$k3,%„ˆc?•§w$G \åþôO>B.ë²óŠK1qÂÈ$‹µ˜Á¡Q<%iTÎ`k³8ÑŽnËf(—ç #Íœfîì"¥á,ù¡1ju‰›q¨ÖgY\œAe¶d&@jÏC9†Ä40:Á3 žJˆ¥Cµ.‰Âë<ˆBW3ó¨4êÔ«u’¸Fµ|Ë<9?KÆËâH…¥ðbåÐhxèâ&KWR¼ˆ'î¡8¾‹Ö¿‘ ¶AIåȃ̸“’7G6Ÿ$C݆Høn@#ÉR©itÇqz²Ñ^ @±š7±–1µÏåÞ|.çëär9ÂÚIF׹ܰírœ@sË-_àšëßÄ­ÿøeþÅJCl ×]{óÉýLŒ1>:̉ù=lÚºŽÃûæpAA’`¡²ˆ§â©#0XšfÃä%LŽfyúéãŒláË_¹íÛw²u[Ͷ­áù–õ8þô7^óÆÇÇÈårÄ‘FX‰£Ú¦‰§nSêÈN mOv’’(‘Vk[­S°Q‘$4Ú1NÏQ ˜çÕÕ[‘’hÖ;t¶ï-ìnH´ZÆ×²O3˜~ìÈA>ôÿRÎáÊË/!‰#þöÞ;JÎë<óüÝ{¿X¹ª«s7@#ƒ ÀœEЍV^{œ=¶çŒwm¯Ój<3Ζ<²lËkgå±åõ±G¶gdZ)R¢Ä Š™ AäÜ tî®\_þîþQ‚` I¿súTªê»÷¾Ï}ßç¾ÏS­ÑRúúû± ƒÅ™ãŒ äˆär}ø­eZ:¦TÎqtjžF'`pd˜J_ž•–‡²ò äQóûðü)òÎ(¦™'2 ´ì ‰h4¡â6B¤¸J¢-\×ÄÒÔG¦†+.ñÜõÚ2aÔ& Ú T3dìbOWØy…§%^§XÜŒ=v©8º8Ïšõ7c»U„H ÃÇ_âèÁûP§)EXRÆšD˜h – V_f®nÐô;Ä(4 AèDÑw}Ày3‹x(¾ÙÄóÀ"Ÿq¸æš,ïxïföíõøò³nífN.äêë&Y¿u‡¦°4çòù¸Aˆ¥ÉüÉ:8B™MFÖ‚«cxóì¸*Çì¢Áh¥ÌòìÙs7ÕÒ0ï{ÿ;º_þÅwaÈ2:ChÅÓ;¿‰íh¤rÙ%·ñøcÇùʽÃýÞÍÏþÌ/°võf”0éïD¡ˆüË0 HN¹Ö= â”éQJè»]B¿‹.hâ8& <’vâ`geò,×¾óßä3YÀYÞœU;õŸ¯˜Dz%?ûì÷Ÿõ´8ý{'øÌýÍ¥\±}#®cRí H4ÊÊ3ž·Y^š%UCeE·1KEøZ‚êÇ bæj $iޱñq2¶$I»©Y³z’¼»›ü½”K9ŒìÒˆ’)òB3ëï&íÎ!cCð"ÉRÍ$ŽCÔˆ¤¿:ÄôÑ'H…Cs¥A”€´ —5"Å´c²Ù„)Ê<ùä×9p஼ô*>tÛÏñ{ÿ÷#UÌb½Å“;ïejú)rnžw½ý1A%éÆ ò,ràÙrÍiÔðQ¢®ÐgØxQ‹0ˆ–ô"eŒÖ&)`H‰N#Œ4A˜~œ` õ, œÂ’äÔMOÑgܺ´+w IDATí8/ÆéNmɳå%ųçœå9]gWAzŸ#}ž;àÙJAè{Øv†8ŒH” J0»°Ä'ÿà·‰ÚSì¸h 7«ÉGhG6¦™ÏêÓ;‘I@˜v ëiš’h‰jº^DµèâRÍf ý9D¦JpâEËÆÌ*:9‡J7‡hÛ‘%PlåEd剠`A+•50¼˜B&eaIs¬eR,/0+r²Ó&Tàè B†„2"«Ë¤±E#vpú73²þzêž„¦`lôtÚ]ƒ‚чך…`Çž¹“Ç«€mÙh¥‚KöT‹£T VÐF¹6}Å4k˘:D’!:I¾ë‚Ù ™óùº¿™}|wgJ1öõþ¬ÀÿûŸe©v„ÒÀ <üe®»þ:žÉƒÝGÕbhmõA¸ŠÖbÀøH…Ë.çäâQî»×Íáµû˜?ùR™¼ðȺ s'±M‹ã'÷36žçÄTwÜòC c<¶ó^î¼ç„\âÐÞ#|ø½?K«Ñ塇ä#úI¤.áäçXZZÃã“÷üèG0”‹FHeá8Šðà„†IFt»mâ8F§½E†!aÜîõI(}F ¶ )NYª¾È}–<«v{î õ:¶Ÿ?`çå:ž/o²Gq„P&a” ¤BÍÒâø‰ß%¨Ïséöm8fJµ2ÊRË#_Êcp|ê$k*e:­ZÏ%.í5¸ÍÌ-Ðlh úÊÄÚ¡ÄTŠÔj‹8*Á°Ll«áZ8Y‡°í  ‰å:¤Øf#m¢”‰ŠÁ2ÚHÀ#c5u/Äïd)g] ¿…)!Ò*(åÒ” ±ŽUC×Ñ?>ÂÜJ ;?J©˜@5±â5¸t —К‚ú샌ä [ôî‡ÖÛ´°ŒžñS”F$±yÊðIJã”¶ÖËß=ŸÖƹ;ÄWÚñjâû‰¹På }O/Pœ‹b¾B>_&_Ú@ß­køÊ—¿ŠsŒ÷sÏÝßÀ)7yË­W°eM‰ÃÁ,+‹ؼå-”+WòÄÃ÷püp at°Ý2–Q¥ë‡ Øö&ûWÑl.²zM–±Ñ¾úõ;ñ[En¼ñ=|èÖŸã÷?ýSÄQÈÑc;¹í¶kiày]„’4ê>3'd²ƒD±iØiL·ãáXî —r’žExÄIH§Ó¡Û…4ñ0DˆNC¤2{rá┈ßY2àç»ÕJˆ3ÙÅùHé3Ïõó¹‡çp+â%â9Òëç<:Ò(Ó@©žrîòü Ÿúäï4—¹|Û:J…"Õê‹õÕ~¤„V½Æ¥Û.¡1÷$†m É‚Ž†Â°,29E&[@EƲqìF†ÖÐõ à˜dÜ<®UÁpüD#í2n>O*!6"ÎbÛ¦á S×!cP`X¾“R÷aqAï"° E"í¢'w5ë¶]D*–ë‚Á+ÈTª4‚%œœ íÂ;ÆÂá»qã¬/kd‘HMˆ"ˆB ÝËÊÂX LÓ4J"Óžeîé¯3è¯Â?ûõoŠ ~g€âÛ ôzl.H<,+5Ýù -fNLS)X·¶Ê¾cr鵓LÏ=D_ÿ .¾,ÃÂ,tÚ“ÜýåÝìk¹åÆwÓõZ<öäƒDq—ÅÚúúòÚ»B”¸4»¢¹0Leòf>ù\t‰Åíwý>®äê«×°<çqóM7pààÓ ÷_L§•’/&t|“\®Ê/ýÒ$M]”Êâ‡!Òä³Y¢(}Á›–¦)RâÐ' ºxI›$²ÑÄDÚ'‰B +sʈôôD9å§:£Öz:NŸîV§mHÏ3`/Å=¤§ú?ôKq¼x3–’&†’´»Ê2ùä'~¿³Â–ÉqòE“\¾H­Sª Òi/âw–Ù¸f-Ë'ÒíÖQJEaäÓhµÐBbÚ Ã¶°eJ =Ê•I´ÈQÌf(*á:XÝ!²H5HÇ×X;SD¤âpa:d0@t$„R`' Ðl ¤«¨È ‹Ë>m/ÂÊMPêfrË¥,y>}ýÔŠë¦KÇ["ïd‰VL‚ÚW™›þ#…6&!tò³ˆ°""eaeLrŽEFx^€Ò N"ª—õœ=kÙçvЯíÀß×.£¸PRàß‹@q,\×ahx€_ÿOrõå—“ÏäXÅú‰ËèžçÚòG˜šÚÃüÉ”DôSk€´<ÜÊ!Z‹#ÜpýÍœœ¡Ù=„ÖЪÅ¢B"#V–Xžïðž·_ËìÌ Q˜²ÿ~šÍ:¾\dÓöqª•"wÜñÏÜô¶«1MðHR äºkoÂ÷C,+K§" Ë’Ô›+dÝ ¦æ†THFâØÇtM²9—(T´-â0ÀÎ$§ìJŸí”>Ÿº­Ö=ßkÎê„TZœ9}un 9/>AžO¢Ÿóþ_€z sJDIZí33ǸáªKé+pËê Ÿ\nË1H£ˆTט?º™HbšV«…Ö íŽ‡å8ÄqJ%é¾ïcŽ] †M_>‡›4Ã7 Pv‘U[Éè¡¶‰¥¤ÕZAªˆ(õIÍ,ÍN–4öH•Di°²8²CÑ·YœM™^ªQ-õ²B'7ÀðšKY5¹_G‹(T7Ë”Ÿ 6ª¹ÈÌ¡G0üÙ<^!ì¤nLi(R »,Rʬ®°Mz  $JJ „T>Ç,*I’çø¿y½y}¯øw(΀ÅÞ½ûÈö•¸þ†yêÉûh4¦¸üÊÍl^{+Ÿùó?âÏþä—˜›þqRãî{î'c¯cÍøålÜ0Ê@uSG„Hè´bW¤Õ 0-)!ˆr¹iü\uÄçô'¤)R¤˜Ø–"—q°”¦…]ÐÉ™f¼Óò§õΛ1œå¡¡eÜ>-õlK=½-½Æ½jµ?ßß?Ó3ò\yþQ’$¯SãÿùÌsåå;p]'ãÒêDT‰â”å…iúr †mÐm,£SA#Hi4´;Šå2h‰4 ¡Ñ(üÆ,†rp‡|¥L§f"D ÌÜb/‘Ívƒb±D>WFY6ʰq,Qš@#“ëÃÎH “®/(Ùã«[¨ûÏìÚEµœeýúmDGöìÁq—ÐiH¡ÏMI R Ã&_(RÊK²Ö «»WRY=Ïáý{éM Ó£¹hRÊTŸÀtKtÂ&y§€Ñ­qhÿ]8ìa´ÒE™S ·§ñE "ËÁéºÑïšæª­ƒ¬îwñ ˆ“af0 %$qõlpO]I’ åéMAúŠƒÃÙ‹ÿµ^°oÅ…¹¯(Ÿ¯ÑöŹ¼š¿¡¸³óf™¼ÍgÿûŸrðÐQZ+>£;8¸ï(«Æ&¸xËåèd#ï¸å=`šüÚúEZí£\}éÍl+¾¶)÷Wxfÿïró[ÞÅ7ïßɉ©iŠ}1c×3utŠji”©#‹Üg~‰+®]E£ÓdaF°ww̵7 âù lÞt#üé¿`ç®g™à£ü…(˜ Ë2 "ËDQÜ“/R/ÜgYí¦G«Õ <”Ê‘ê¡câ³\ëN›•<œžG^ ^ôxã‹Y¿ŠÓY„~ößÏ—˜,añ×û9víz’›o¼Û4ØR¹+Õ4»ËŒ0wbЏíá§ ÂÉáy ’$BA±\B(Ãt@K å q”â-;ä2%”%UÙÂYKÒ0ùÊ7€ ÃUWH˜|éÎ{h,ÎP(çq E._¦²v„L¶ J"¥öA×ÇiS!̈Z#Gž&ƒýEâÔ! šNÕl†ÚÂã,¹Ÿþ¬ÆÕá;d\MÝkP.eHÈ4t9rØC;Ù}xž‡wbÓª*Ž›C&]Ò8Á6$D’Ðó§z)N;Ž$I‚8%FùrÝËéÜ?÷ç.D0zózõ€ûZ“Ù/¦÷öFÈ: €¸ýoøÀûßKgÅá±'ãÐñxúð£(+Ë“µk/â7>þ{dòþü“ŸãŸþùïÙqÉ;šÜ€œÞÉäøEüÞøC¾xû×Ù¶y –áPî+3uôi:í€ 6R«/P(VùÊO³nÝ:æ—OHÅSψ°²¤¾MÁöÞZm'%†Ž”I #"„ñ\ã¥3áT…8=1ÎÚµH{à£5êÜ=Ŝݽ}º±îL9JJÒ8Aè!%HƒF·‹“ÍÐòBþú/?Ãcßú*7\³Ë0I’<}Õ"‘ðhÌÍ`™Óœ<´I0j²rµ›ƒ©ÙžÙÿ0‹K38®2$˜¦‰Šj‘ÂjVOztædì,Êèͱ´‰Ó]¢1õ(…ÇÈ ©HU„¡2$i¼cgaJE$«7\Æ»Nrüäu?ƒëºˆ4 IŽ[!=•‘Æn#Ìéi¤ÑéùŒ">ñKH‚5 çˆó•/¹ùæõÉÌ.tð¾Ð@ñ¼¦¼#‡Ÿæ+ñ?ûã¿Æö?ÌüÂ[YYZæð¾~âGÞO4»+”ú‹LL¬âc¿ðKt;:ɰzä:ª…5”/ÚNÖÞÂC¸ç÷±\?‰¡ò¹*•Ò0…B?‡ìa`h-Ì2¿0K&7BÇŸãê«ú)‡¸ÅI¶•¯çÉÇö°}›ÉPÿVºÝ vÖ#Ml %1¬”NÓÄvcx‘£¡¯°eB„4mF\b?E&š0 Éf R E’˜J` @˜Ï•Üø6èyÏÄŸçûÏËbd°â$&ôºd2~àñ_ÿü3<ú/ríuWSÈç[E’šD:$Š#2Y‹ZÛ'ô¼NH‚G­±„aÉm¬L†T'T*cÛû ÃE‹|!ƒåfHÃ,…jŽz·KÉÈ“ÏóÈ“Òn-²vUÏ<ó vd1ïe‘‘Gcy¡%®QÃqmòî0C}#lß¼ž ˆ˜™™Å³Ä”z½Ážñη¾“( éë+“Ë€%1X!íz9t/»Ã`Å!kçèzʶ0M¯ãa+ã ÷`ÂÎ’Ïɸy„hž Ò©<«pÊ<*ÑML#mÒj¶0­S'¢ Sû/;ý?wœ^ªçáÜñ}­Ko^&˜¾\~âVF|>g14Éò‰÷Üu?ïûÀ0<°Š‰±µ\±C†5&–íÐõZ8ŽEúd2y e°mëu½àëZ¬_Wæð±FÇÇÒçÖ·ÜÊ?üÃçY½z I,€ µúß@b_Óndyâ!h¬[àɧîâÝï~}ë)~éç¾I2‡0Ó0Â.‰ÉçJ€Arš³xŽä÷©”É„výÈ*UE.ÒPÉ»Þ2µú¹¾9ÇFK§½^‹˜ž†¡_ö„|ÞÂ/žžŠ— ,¤ $‰aHn‹Ïýõgyôþ{¸òÒŒö# —ãS3 Œ”QB020Hg¶F^d‘…¡oÓî,ã>¦åbÙdÌèð:b]dlt q†dò9‚fmT蚤Pìç‹wÞE¾œÃš¥Ùã\yé&¶¯]M>c"tØ$¡Þi€¶èt<4ß÷©öµ°LÍÔÑøÝy¶®ß†ßnÑlÖÉäctš†+´æžæÐôÕR€…G[ÄÂìe$ªç˜u\÷N¬IÄÀ´]J¥> Å>„1H‰Rœ!¯­"üÀÇ ML³HœjŒÔÆUÖ« ÒoìïoŽâåJÇ¿QÀøúŠ-\<ùnŠ¥a¢ Æ0{e–0аŒ2~Ð;1äº)¶m£$„~*Æ0È”LÖâŠ+®$[øe>õGŸä©ûxÛ-ïâ#þ!,»È¾½‡)ñ»øË›ê²²ÿüOŸç_þ×ÿ保cl¨m*Rí044Áôô4"èvêøAB;jÑ ëø]MÆ-âùm²ù ¦°é´—Q›DS,–©wL #‡mºd‹EBgŒoí<Œ•+ƒN8~üï¹íTûÊìÞó4Ýc÷"„& ††Æ°L—Î’Ùó 1|ºq"4d29¢0aaaÇÍ¢u›Z}­$iìÓmµ)岦 hÍãæúht[H7G[ÌÏϳ~r€\Ö¥Ýjã佌!M4iÚkP4m¥q¢ÏèuqÊÕ=MSR ßÀ‹²x¾Çñã{±ìÛhù]"„)/è¢;7 ¼šàðzkB}/•º^Ê÷ãµ,;½Ø¿ÆWßÍ Ö9Ìg>ûÓ¬[ý6Þ÷_ ÝMRÓ×—CQÆqM4Š ˆ°-ß!Á0c Â@“qŠ@JLH1Ÿçmo½•+®Ø@à'tÚ1o{ÛMÜsÿüëÿ‰ÉukÛ)k7ÝÈäº ^£F7hv†QÄ_ü·?Á*,3PÙFµ0ÈŽ‹ÞEÖ5Au”­_¸¡* —Ù·ÿqß ŸÍ1><€2ºÔ–;,/´ÈéƒtVfP…I$Cõ¼³ÓT“¢Ÿ#ø£zÞ…újvç^¦ã¤1Ièñõ¯ÞÁçþú³Üzó YP’›±±1N?Ì`5O˜8˜BÒNj( üF€––kQBê"9§HgvK‡¬E˜&F.a»ý„B03¿H£3Oip˜Û¯ààÞ½XcC öUØ»ÿ :ÝÍ@aš ?ÒˆF„©$iØ@ŠˆTú¤Q›¡r†ù™ãœl·YnúH«H*'N£¯ØÏ£ñ}e¤‰ Ýõ1,—v´ˆÌ˜^‘ÔWcÚƒÔš'¨äó$i§z#¤ìñH”àØ¤T=Ý'mÀiP9å•îøÚ—î¦Ó©qÉõ“(‘ssQ›”—ræµÌ0Î Ìߎ¿ó«y_o„ æåd¯Çk ßÙ pôÈ&WcZŸù³?gÇ•Ûxê™{Ù¼q5#¥k¹ô²«PÒÁ¶³D1˜vJ7žcniЉþM˜"‡×ÑØ® §Qm²™2Ë‹³4_ýÚÄÌqÅåkÙ°n;A+eÍÚQV­™çº·^ÂÞ§W8zØ Ô›‡©×Qlšôç5_ÿÆ?ãwJ¥µTÇìÄ Û˜Ò>µó~`_XÞÉìÌNú̘¾’ÍàpeIÆ&ªÌLµp‰ÑÞ 2}t£„T›¤‰ÆÐ`›’$y }}þ…úíÖMO«Ö !øâ¿~?û̧xëÍ7aZ’B¹„2,úªeæN@é6Õr‘é¥Ó1±ŠÜnB¡PAcagL)¶ÊÐ_!ŒçÉÅ&H“X)€£ÿ7d¤)æN¨Wœ^+ðøvƒÍ÷#éýzd/gÍžÛüb€õ†ã, ;ƒ×ÍRr&ùØÿñãt’ŽßÍ=_}œýÌb©<©VèÒ4&1jœ˜˜ÿïóŸfÓÐÅ|àý¿H>»†4S½îh¶cdx‚ý‘Ÿä|ž½Žséå[Ù²îR&F.åÈÔNž~â^¶mb¸´ž÷þûwðÈÓ±gßà \NÑÜpýÕds† I —‘Š.¦•‡4êÅìÓ·x¶ &Žº¬_¿žpa‰Åù½ˆ¸‰•ëb(—¹1ù,Lí¢0z Rô‚…! Ò(@=‹?Lúì×ñ‚„û¿q7õÙÿÆÕW^Fµ”§Ríà ú+KsÄá:ªs`÷il3·²ŒŸ¶¾íX -„Ð,.Î160„iºd3yŒvÇÍC.‡áU(Y{æ8Ma±mófFÊ#:²“åù=X²ÁžgÐmtXYé²yÝv\k’þÜ–)1H1âÙ•¸¶“í`[MNÌ>#š=½) œ˜màTʔƲ¬Y½‘D§èÖAJnJ¦!žÖx¤B³ëÀ=Þ– “€Œ!PR¡…Öñ).¨g«TO.>Žcâ8F’ …ÑÓýÒš„”íÛ7sd÷ Íå}lžt!è` “$ ˜¯8#x%çø_jÞ¼X0úNÖ³¿›è;¡|¾qù~òG7zü_–±Õ3-KË-–çÚ¬™¬Pêë™Å¡FZMŽÏ>N"æyà‘/3=ug‚={w²qSLÖC¤.‰H… ]2yŽàýïÿ &žã ÿò;Ø¢Åæ5o!S̳~ýϲ8pÃÕï#ï–ÈÚ[èüè[.¾†½;ïáŠË€¥•ýäìR5±Zâ%12ò1¬|ï“ÄBj¦OÎð•¯ÝÃGï¢Õè1Rd)d-*…QrY—V§Í3³B=Ê­j=“[¯AÇJ²l„ì’böÈÔ3)„|N7¦TÏ/Iž(/4©Îtü ÕHqJ ](R A’¢•â‘ûäO?ý‡lÚ<Ή –aÓi¥Œ®gfnšñÁ!,êDmÅÔ¼:++mrÅ·ØPvv‚åéûuºTTeW±„L¶@,"\+,®å±cG0ûäqâÙüŸ8¶¦”t[+x~—(JiûM¼ ÉШÀI´D& "‰­Güv‘d±l‘iJ£=‡ÔëP2&ŽÚ,µêXÚ%I<¼$Â0 2ÚÇIûÙ<Îìþ€öÂ>ÆÒÒqªeAµIe L¢F Ó°©”K¤ID.—ÇÍõãÆ8á r¥Ú4‘îFf™bus5æ–¤]X89E6Q,ÇLc´+x­eZ­Íf“ ì2²m3SÂÉÚä26–©0´F{Y‚ AdÛÄ­%l§'›¢‰±dJlIrŽCµZ¥T*¡Û~ÇôJIJ ¤&›ÍR©d©ôõ“+yH+AKE’`¤ÝÀR22ÑÚFkI§Ó¢Ýn##P‰E6cÓõ=Â(ı-¢NÃ0°¥‰i!¤~U<Ä«é ~9Aý…šý^iÉ啾΅æj¾²Šo§|ôb}7ßë`cÜù/3\~}?^xœïÿ<ù\?3sSØf…¥ÅõÎ~ún …ßüæN–<æ}¼`…“Gr¤Ñ“|mô¿rëM?F6ÛGטžÝ#,ÖN^F»±ar3÷ Þvã‡9xü_©{÷ð…/ÜËw® „ÍTë[hûQŽ-I–³tE6­ááfjîS33|ãþˆ-ë È’F-"¤t0MZ“Éåù‰Ÿþw|ê3†/,¬bž LH4d3ùŒïût¼”Úþ.Êá!…4%:õˆbÑóÈH@ègÝÓz¥®”y† •gï8àEy‹sw‚RB§ÓÁq³H% Â)á[ßü:ùçŸfûö FƪØn¥²d3æfOE34ó¸b€X¯ÇšÀOÐ,Ë& 4…LˆßŒè+ºÆð—êhS ?­°zâ"ö®1ךÃóëÚõW\|1[6m&5Bd¦Cľ‰ëäé´ ¤t9|ø ×ÞúS(¥QR ’‘ĤQ'h–Ñ$=×A™`HM¥èyÊý%òù"ÙLÏn)uÖÝÓh#€l¾L®XÅÉuвI*%Z'(¡Ú@A‚© âËÍ÷¤N,ß\!‰ x„ ŠÈl’ØÇ²©H1…i›D†ÙÓä:¥&ßVàz9å¡—ŒWÂ{};Äê÷ºHá…ŠW*áó}•Y?q”Ò~ÍÈêqˆƒûÜ@Ìa‚ Çí_¸‹(¬SªæXX2øúý·³ª|ÿö'ÓÎQ«gqÑfó†kØ·+â[OãÀ~Áå—æ˜=¹Ÿ~øzö|Ñ‘u¤q›¥å‡xÛMBœŒqðóÓlÞz)ëׯ¥R-2¿p„Çžú·Ýò“$€ø(¥è†W^u£·¯ÅuòÔ]æW¬V™FŠ„“'Oâd²4ëEòE—÷½÷=¼åúË‘ÑóœH…8sJæÙ‰’¢ÏˆH=Ÿì~©@ ÎúÝl6‹Å$ böï{†ßúͳní##CT*UºÝ”ÉÉÕ9|˜u}Ô––h5Qg /nRë$¾fÕØ†ÌFMjsGèØB.Sfyþ0•Ê(:ã rYÆ×^ξc³¢@èO±4w”wÜz cÃCÔVZœœ›ÇïÌ’„)f‡(J¨Õ|¼0%Š$Ó'çq2’$ Ž’0A$)R+Â0z~2Ƶ¤H­h'H“^IÓ4mLÓ„ôtIOôîv¬±LÛÉáé6©V¤hL!”ñ‚:vNÑö:HËbe¥‹©,n»q3·^;†¥–MµÊJk‰8ôÊÕÓë¹äqÆüÈÐsqýØëQß~±Ì÷µÈÞ¨ÅË);½ ç‹ëß2Á‰¹#ô{[¹÷ëñȃSü›ü}ùK™›½ƒ½ÏtOɳ$~Ó’\ÿ¶AªÅ1w­ µ‚Àã‘Gv£í:×\s-»9Æ—ïþ,ýÃ}üÝßÿ-##ë¸å¦S,Ó® 2\­FƆײ{ggø¸ˆÄ`ûE[98ûW:”bæ²ÜÿÍ'™?q-k‡ÞÐyV^Õƒ3L,«×›Íf©ûå¾>Ú -r–dÆ_byf…‚´ÂÐ2¶2®–˜]…cæAK,¼0Â0$2•§ýÒs&Îs5¡Î'x¾Ôýìçq”`XË4ðBŸ½{žæ?ýÆÇÙ´a=ë&'0­ Q(Ù´q’ƒŸbÃä*Úõy:&å1:Æ q«‹ô%ÅRÇ6)æª$²‚7{ŒŒíÏ÷ÑlVA™+ÏJ³ÁÉKD2bó†ud\ÁÆÕcT‹63³‡¨wê4Â&A+B¤‚ޝ CX®xž‡0NKMRHS)¦’( IèÓp1MSAÖH4I׃4‰z.ƒÂDJšœ¶¾6•R%M§'=Ò»gê”R¬Dë”DË Ñí 3Ã,¯ÀôÔAw‘«/ΰ8ûý«û0T†ùùY²ËÈú @¤¤h‘œ•åItš~ÏÀ—:‰óF¹^o©ñs×íë!?ÿ½:À­Ô¢N/á.Ù¾…ÿþÙOÑíÞF³Yã¢kÙ°¥ÄC=Ä—¿tÛ.ÞÀÉ£S¬¹n€~ôö>^çÄì Ë÷Ñ—»Œ§[bÃÆV¯¾†cÓûÈ•%Å’ÃÜü¾|çßP-màí·¼‡zðÜÎG?ð“8æ:&6ì`ïþ= –†h,Eìju9|t‰w¾ãßpݵoeádÀÂòÓ<ùø1Þ÷‘÷ô,QÓSø~­,,eP«Õ°KEæš'YjÖêë'5$­Ð§Öi1P,Ð\>Á`Á¢Ónù1Ø©Ó2IS-ìÓ' = g÷WœO¾ã|‹õyg²eo·Æ‡íå·ó?²zb”‰‰q ËÄ´ ôspÿn¢`…ý{gqM…ŽcŽO-mC’qóئEÔi’( l§[¢Ü7ˆ—$ÈL?ÙÜ uŽ;LN”™X»‘4ªÓiL³fã:fNNá—jÊclÜ~1žçÑj´{œE'dyeŠ4Èçó˜†DÄ¢gN%@¤)i‘&1:NIÓÄ(S£ØÊÀŽL,ÓÅPBH@Ç)¡‘$)BH„P¤§‚·¥$q`Y½{k(­c¤Ž!5†]aqIóÐΧèaËú%s‘¾¡F!¨d\¤öÉf³¤‰ SÇÂ:(ÛD§‘j„êÛ:éIÜ¿\ó£ï¼š#µof¯þþ¿T£Ý+å•Þ™Åýwx å’[1LÉÈZ¿+ùÓß{†ú÷Ã|íK3̈^•áäT–k.þ÷}ó‹¬_—CÃüØþ'N.sôøÖoÜÈÿÐÏsðÀ,†^å2>_bËÖMìyæ0ï»í¸ï›_`tÂbßþíL®³øÐ;~ŽBþíDfO,1RÙJA–Xôx×{ò͇î`næIp—_»~ô·)•v S‰aHLe‘&QœàØíF“¸+ñ1a+Ef ¢VJ·¶ŠY‹D•ðSƒNšàãƒ!1…$‰Sléâ“ 8»ùæì “žÚ!¿|¢ñìc·A¢Ùùä#|ú¿ÃE[7‘ÏÚô•‹h¡ÈŠì?ô›6¯§6;M)›§•vÈÐ ŽMÍÐW]¶‰ad¬°-àÚ”]Ä sD–ƒ™u™™YF†&s ËÔOž¤¶g†Fû8å|@Ô­áµ Š ‹‡5š’¦MjME§&1HM¡’§ß¯23=O·ÛEšŠžÃ` ˆ5aœ’ÄiÒ#ŒM³WŒtˆiÚØ¶‹›-œ*ùœm$Oùb›½ N(¤X†D§! Iš$èTiŠ-djâ(ƒu“0µð8kÆûé·ò(lG„$ c K“/¸t;>­ÅóúqzÝàò»2êQ 8ß¼z-¹Š7"P¼œ†Ø×ó}½!NC:&Ø{°ÅØX–驽ÜrÓ« ¿ö+[1ï¼e’‡ž&_$JñO_ü/¬žE&&7^ñaŽ[FZXiíæÐaÉòÊ;®p8xäiÒ´k¦ìzâú !RŦ —3<šgÇŽw2Ð?F¶4LÇX2Kä%ìÚÿ(]¯N¹¸ŠUCWP.…ÌMÏóöÛ¶‘$Er™õèØF¦aO^V'H­1SE³£itBj‹3žO±P¥Þj2<’ÛCÚ!S³Ç©¦)5j R_!„!ÂtâS[Ï6æ‘€g‚]˜hlãYqÀÓV¬Ï.ÞÓ4 ÃmÙ¤iB˜$(¥Ø¹k/ŸøÄï³f´Lµì0Ô_¥ãÅ ¯ZÅôì¢3ÃÞÇæ°¬H:m‹ˆaA®ÜO#Méójw™0]GµÃ@JÓš`hl#'¢ÝJ9~ä(:¨qÕH½ejM›f+¡š,7æ‰âiç™\·å–(9x…,~;Çܼ"(%´Z1Õa‡þÁaHRâ8&‰cD’ âSô´š8Uû·,‹41-è&]²®…HR„²Ð*$HÚdryÕFD8F3 ‘‘Í’rйÝÕødÑf ÙµHU„V!Èê„-#£Zö¤ÆUŒ=í(´iôN*(iA”˜¦9,D*“@zˆØ|ÝØ·³›|)ºêéy(^º,üjû`^,ÃûnϤ^°8°ß'ëV¨-%”+›Ø d`h5GNìgÜ*‘0=Ýâcú8µúç˜;y’+w\Ãg?û'äÝ‹Y¬ÕÙ½ÿAâ$¤¶³*DKi.?€Ö’(ªá¸š|)á-7]EõGe[ÊA`㇆2ȸ6oºÓøž¦^7}}“€ä#þal;˜hL" Ñ=ufq޾ñqš&× _h³võ>ò8[7_Žå¸Ô‡r<½ûù5"£iEO-PÈ: TóÈþöÞ_°¡Óß ‘ÊC M3nSËÒ«V²\ÐqTJaU1Ïs‹t_iŒ’Xi2Ç9EfcÚùr˜ßû½ßã¦-« Yï0¢ ÖmÜÁèùÓ¬¨5/R-ûTÂ+z˜›§ÝrøžÀÓ–Ÿ¡¡U̶&(U«x^ÑÕGª A¥‡Sçgð¼ G_:Àž]{¸ùÆÌ6&Ø÷üÓ„¾"k¶Iób^ÓNõF›ù¶ezz†4©}”ç£<–‘~€Ë$iŽ1–…í°…$!®r1-T¼JI”»œ,\n:ÆECñXÒ“i1ÎÒÈší9l»ÍP9àø•5+B?%O qËÂðÊ!¥Bá^WpâêϵùA˜!½ÕB…oÇÊúJ^Ì÷Ûùý8­Ôj€Z_›ù&@‰,óPª›ZW ©&™Ÿ1=Üfë®]D¥=vc2öܼ–ž3ß¹±¨j7OóÓlÙ¼ž›o™—£¥‡s`]g*@)t…¦“鬿KÇbW±áÈm1ŸÈó„Äó<ÖoØÀomÙ±ùÂçþ†õ#dK¼s÷FÆÆÎRw }=4sÌ5§èÖe‡ûèë¤1]ç⥋xZPî¡#¬ø´L‹úxD=MY°eÝ=üÉü)N4ö33=NnKôôoeͺ8Û`rršÙÙYÊå2&ËÉ$iš.Ê ¡:Dh¡½ÂȘ%ÚB’è$Îÿdaµ€‡lGÒÄaÁW„ë,H¤ðЪŒÉsâXñ‡ž¢hMk3ºJ“ U+T#ŸJ)¢4ð…ZÒÙ\]àíÕ†Á—/FócI²ú~·y~Ø:®kuß õã|B‚ùwÞr÷èCœ??J»•rà…£<ûäA¶lÚÃÞ›¡»¯Æª•ë¹pþ1´JUíx’Á®mÌÌÌ9S—æ¹ù†{¨뙼8Êð¦•Ü´ç8¡J" ]i‚À'Ml1Üt×1ª‘² _9YfО@‰bã)‰ Ci Ö‰D p9BX‚’fhÍ0vv”úä$;v úF¸gÛ¬Pb²n˜žg°¿›ª×´çÈšóô¯Ù¡sµPY-ºA(EæÀt·Z-àããø•oÕqmó}vœš”J¹Dî,q’°jãNÞý¾ŸfúÜT$iÎ×éï¤ÒUÃiA;;O©&ЦQŸ ÒUÊA?]]]ôôucƒ^8„ô^9 ’tј>Çþ§å±úEû*˜deœä6§´²D%*1YŸg¶337Ï|+%IsòÜ ….ü«;«Å!”F«‚@W©T–%‹WºÈ¯ô©^ú=¡äbBÑŒR(¥0yF–nÚ¾Ë,èqVöV‘yƒ@ gAtþ£Óñ½ž- )%BÚÅ6Ðu†µùËüÖPüúñÆTýW[‰½rÖvýø“Å{Þÿ^æç§xö¹ƒ<óä3ì½åNæëðÏë7)Gàò{Y¹r„×óóú×¼pài¦‡.°y㇬püø1<ÑÃôTƒ¯å!°÷PÖò+?ÿ¿ ¼ç,Zû€ ÍÁ×+ëHWÁó¬)””ê\Ë’B†:×øž&˄ʋa©Õhé7-a©ÉÙŸ§¢ÛŒÏOàÑ@¤cô”R¦‡´ šYNC®à¯¿ø zð\˜.Ѩ·˜=ôÿæ·×RMŽá†lé «=Èè¯3Òw?sá:ºzû(U{±Z“™¶íÀ³hŽ´”½½À¶YNx´ÓBä0Š"2k ›O-)g–ÛöÜIzÓœ<;ÊðŠU”|SÊ‘¢ÙŠyö¹8ñâ.?¬Fôî$µ£Tzziv;äünÚYÀ¡ÃGéÓ‚];V2U™ijæ›3̶ '¦0V`\™û>~Q¹¯Q*usnô,‹´ÇŸD ‡v‚ÔTÇüia­4OcÊQ‰©ÉñÅ »8Øv®ê¸‚¬è¬+$5¤ÀÓ" ºŠ1 ƒÃÚçæPj$t÷ Pãéˆjy-Rr8ƒ3‚@ë¢y eçµK¬k¯% ×yŽB“÷…¿m¡ z3ªö×£øa‚6Þj.Çë±#½VÒx=¯ÅuyWI/ìû'|Ïçä‰ó¼ëž-ì¾Qòk¿òèx±ô"wÝ~|ûï96ú6oYÃÊÍwªÂç¿øçüÎoÿö¿xŽû»¿Ëmwmçè™'Ù¿ÿ¹ï£ŒMM18¼ _c‹5ÒŽškèu_Æeg|ùÊF)2, 0|WˆÏµmÊŸü·¿äÖáI^<úe?¤,$ƒ5Å–5RB­R#TeÚIJ’•Éò„Z ‚z‚î’”ÖlÇ6-«FAŽ“Yˆfs6èŒñsÿ•¨v'is/þê»p]¥c0 e€“Ây‹°“Ãbg ùq©©±‹i¡Z€–мœLf˜8‘‘þ~P!:Ð$J~ÀÆíwrüpÌŠÞ ^Lâu“•·áU8w<¦Z*Ñ]+‘Ælºe=ûž|“Y&¦/â%æ05!qÄIŒ± ¼2¾ç"!*• £ aT¥RéE 1Î’[²X0h&x¾À|âÜ ÂjÇû¡}Yb]]¡v‚\¤é#d?–Ó(!¤¤±@– ~Þ@©^>qÞ&p ©‹Åàù5<ícE 2G…ƒCÉâü"dVŠÿK';[WjqH½À߸ŠÏ3ãáéãy8áã§1ž #”³ßwP{Y²¼'«ƒÏ›ùûÞÀWê^ ^úa þo—çzµLlßz+ã—`÷ w±ï…ý9ºŸ¹Æ9¬¼Èm·¼“C/Œ²÷†³sÓ»øô_|ŠG¿ý5æ“Ãô¤<ðÅ?Áé üÂ/ü4­z“J¹‡SgÎU+ -Ê),•Uˆã”×"ÇãœA ‰q†@䯑å?(1<<—ø:‘‘.£Ï’åó´²Y.Ngzn’©™I¤””u™[·ÜÌɧް¥¶ŽuÞJ<ž Pé[MÔ½çõ©*VÔÈó ¾;ËÌÅo£í)|2\*qF_³:‘¯AÁ4³¡¾ïÌíRi|c¬Fv’‡ }d¨ ÖðüþSØlžž®—Õé.{œ>yœ¹Æ0}|èÿˆï9þæ×ùã?ÿsÆÎÕùµßø©T"Z­Q©Dž§„aØ ¯þ"J¥°ÖâK…Ã!¥ÆâÈrÃ=÷ÜÃÄsß,¤ªm‹ñÉQ^ü)¶nÜÀϼ¯ÄúU9Òµ˜o âD EŒ/Y3‡rFµ õ©ç©ˆ.üÊ ™ í)¬¹"P:Çk­Oì–gyÁvV’,3xR`òb)ðjHÏÇØaw?2ð8yjœ 4Lk~‚ñsMlÒ$kMqrv‚žžaÖïÜI¹\ez¶Áää$å°F}nk%Q¨Å ®T1´^¸ó"‡çyˆXàŒÁåÅ0: CºkU¢¨¼ìâ»r}¶˜{ʲÖ!Ý-©î—^€J)¤•H,Æ.'˜-OªH‚eëÊ—ïwåE}åïZ²ê»  %¶“`„/{Ø·*9[å÷ IDATx¾™F?îPÊ[éÍýãòšh€O}ú³8'øwÿî_ó™OýWÚMAµ´•v³Æ”¿ŽíÇ&vîÜÉØ¹{é®pêÂ78uþ2`ËÆ]<ûôAN¼t‘‘MÜsϹ8q–ÃGñØcß⃼Ÿ0 q¸ÎÜÁ’¦y‡Kñj‡]~3yaŸ)œ@8‹M _yô©AkMèGxôrb\‘&-„׃²-òt'ƱºL¹ÚM–+²“SLžoqà»óTiS­øÌ×gh'9ÆxÔ[…rêÄÄg§i4 y"ÐB“šyŒhƒÔØÃOнâ$»nÙKÿ¦9z†ÈH¤"Nb|¯t9²dm:lÁåšRKû !ÎÁÖ“ª³2ì.;¸ KµR"Ï•Úf¼0¢=’é¹³Üõνô—=ΜEG!_–;ÿ´ÈŠ%.cŠláÞ6ìzwqzÛ'‹zc”æ\wÜý<ùÔW¹÷½wóµ¯>ÄÁŸäî»îå]ßàÏʼnµl»¡‡³g÷sþl›Zu€¡9¿õ/>Áèè,GEëŒ]žç-.ÁÓR ª|a?ífÁnæfÇØ²~Óžãô™c¤¹#nÆT{†¹pñ–!lg`žáàû%‚°Œu¥}˃y×—Ô"Ç¢Hdf±»(…>&Ö8›"l­Ý+l—Âq‹²ß¢ðÇÚÅß{YåÕ^¾9ƒ5ÙbXx~8YÀQt’…Ë’ÆåïË%³ ·zZR‚ë0ÍMŽÍ³Îór“¿©ç­Þˆúq ‚?è ÿãtæææèêê*’Åïáé§ç—7}ˆ‹¶søÈV¯^Ͷ­Éy‘ßÿƒÿ \†¯‘"¢…œ:v‰m;5}ûZqÞ{˜˜Hñ|ÁôÌ8ůýÒÿ@³ÙÄó<Œ1ø¾é(¯j-® C¹xÇišg“311F%ò©DÔºˆ<–íEf,™IZ…±‰b°§‚–’4O¼J°_d(m©æ.sÌZÃ\<—+Ú2§5Ñž÷Ù¶s'=Õ ižîìö_í³#½º÷€–…ù³Ž,IIóŒ0±6!8qâÕj„ĽªL…èè6]Nr±º»˜„tÇ~U"QB’:W0Ý—‚IN^‘8^%IˆkË},µ¿]€Û¬1‹Ÿ¿™Áùz{=1þÈt+W—X¹n3>üŒ îáÒK¥Rbó–5ij«ùø}·óÒ‰I’\ÑÎ[œ¿8ÀñKˉ‹¸çŽU|öo¾ÀÌÌŸóû>À û÷ÑnÌb“ ƒãø‰clÛº‡Þ¾a²4%Úí˜À–¹Î]íP¬räªT Ïáì¹ â¸Åí7¼+ÇPA@Ò†Àï&Oh#Â~’8ÆóùyŽ;ÍÙÑ ŒUD¥ ëFY¿~=~ÉgÞ¦„lµé 4Fu!]•î5}Ô“Yn¼ýH]AÙCˆ“ไ(´”,AÀ¹Ø9û2¼}iËͶ/Ð8B)䘼Ûh7.ñì¡Gˆ“ƒÏÀÔÔ qœ¢¥ÇHïâÌ1ш™­·ìÃ׃Á.TôºXU2À¢‘Z!¤Awº…ÀS>žÒýª“%XWæV„„ì<×N2t®Ð7)wÂuºaÑJ» ? %¡´Ø\Cž¢\Hà]¥PM’¸ ^Dx "ÓtÁ_‘©R$ªàVªe ³Åù,\ÒÓY/¢ÐZ;ëÌ™lâ™2&Ñ$jéÅH42d2ýU—? þ?ˆçÿV'‰ë«´‹åg¸íÎ~7ÿýë_¥õÑl4™™½ÄÏ}ø¦«²‡ŸùéU8´¿ùEnß{ ;¶nçé§ãÒÙ³lÝ|3·Þ¾—®žn³ŠÝÛof°g=7ìeäýÈR³AàÇ-‚ DJ=˜_‰š ŒÂš?Ðä²4¡¿·Æ/þÒÏóìÓOQëêcv~ŽflQ"$Î-ãӬ酬°Ô|â;Orèè ºzÖrèÅ \š˜§ÖÓÇÄê³|ç»ßå]w¿ƒ-[×133E­R¡•µÈMŠ %ŽŒîž.¼( ‰Sü0 NÁ |Ò,Á÷}<ïrõÇ1¾^û¤+A–edINµ«á"‰Rh^:~œ‡zˆ¾ÞC]Œž=Aœ´Aä6#K3º{úèï@úBO3wi”(¬¾ÌÄg$´¬ú_*öwùV½Ëü†Ëk¶Å \\ãµîŠßƒZöû8Þ;Rj¤Ð—»…n¢ÓE¸NÑ™c_µ«¹Ú¶ÔÕ‚w»•Rõöáw1~qŠG¿óþm„pô÷÷7šS©T˜™n LŒ_¤·o7si²Éº « úV0>—RFèÍ0Ý’ô¬ØB3+ó§ù%nÝ»‡µkÒ'‰-Â9snŠRUT{ /D‡W ñ÷ŸûkV®bëÖÍ4›mr‚ÁÊZ´¬²~í.޽8Cšy\8ßdÿøc´ÃÑÇù¹_¸ŸûžäÑÇç§>ðZí)ÂPàð±hÚÍøh%–ç\í«ábB9yê,“ÓslÙ² ¥<ÒÜPzúk 5A­M­\aźÍfƒîM}쌹iE~³Å¯ßònÎŽŽ2SŸ£Ï!ò2Qïü.Î:Ù¹)úúú˜˜¸H½‘±q˃Ãûh43zú+ ô¯§ÒUâ‰'žâ‘Geß¾}h%øøÇ?N¹\fbbâš'=Ë3|? ËLGÊ\’f Žœ‡þ'ZÓ§¤V«±ië œ;wŽÖ\›Ä¤ò‹5W¡PÒCJ…T ¥}¤ò€xYp^„®"EqµÎâj«¤B(œ(yÅžº¸JÒê²äËg7 ›VΉÎFœëtZƘřˆ[è.¤,¼D^!9½–@´À_ ´s ÇÇ811AËO¹õ®îÚL®œ¾_âÞ TôF$Š×A]?Þ„d†eþþï`ûöm|ð'?ʾðê³)ÞêØÍðžwý:7ß´ƒñóMžÛÿ-¬ìB™-4§vñð7¾AµÒ‡Ò>±F#ãæ½wrÃÎ]<ð¹ÿÆûïý6oîÆó"Y§™u &U’ÇE`I3öïž$mqæô9òÜ„%&'ÇÙµû&Zq­}fÂÙ ÉsšÙ%ô<Ôª%b’á"jå!B¯‡jw@}®ÅÐÀ§OŸF‰œîž*åžy†‡Éå)úWÕàkßx”jµ†ÐsõGˆÓ)^?E¥RáÂ…‹|ìc÷#D”¯yÒ=í‘$ ~-:æy̧þò/X»n%&mðÀq×»ÞOšf ®¤Vë!n S #„,x*NH”§ ì_ÊE¤+»‹ÅÎÁ¾¼¢]¦¾*‹áp!~e%Ü!꽊֑[`jw’ÊBS@N–<+f ÝŽï{ø¾¿8YJø38äb°€CoÑGãr¦ZHâçB”´œ=ÅøxAIâ+ÈI‹žîÚ›6³¸ÚׯfÈóÃØU\_ þ1J÷ä#ø¥Äæ1ÍÖ,[·îäÉï ì0>¯HZ/ÑÓòøãÓlµ¹ãŽ;(o¯òÿüþ¿âŽ[îã†Ý7Džzî)<Äìôn»ekVod|l†Í›4ÆB³Ù¢R+‘vìI¹ï6Ð!i–ò­‡â…gŸ¤·§‡þ=›h·Û䯱j(D«Œ¨"•`ffß X¿v-õVá_=;9ÆÜô{vïenfš £ç¹41ÎÐp/«W¯e||Œîž*/Žb0Hé3zaŠvšÀ ›ØÄÃ:¿$˜›ËPžO¹,Ù°a#SSS|èC¢Z-ûÈÕöþIb‚ˆvãœãìÙ|ñ>Ƕ-ëyú©'˜Ÿ>ÎÝ︡‘tõ­¦ÑJ˜š¤=ß R«â~Î’çæ·t8a¯ê7qµ!÷ÕÖy_>_eççR½úÅŒ\„È–O[¨ s(¥‹ÉÂÇó5R ¤¼"QÐÙvê<-%^nvtå¬âÊ¡÷âGÍVÁ¡>úW¬ääDÎóÏãh|¥Þð`&ÄÕÍ™®¼ß‘0ÞîAôÍì(®²ßâdñÉO~’\Írëm»9wá%6oÚÉm7ßÃ@Ï Öéˆ#‡Ÿâ©§ŸaÓÆ[h·{ö¼‡©Æ¿üËÿ~õ3\?Eß@7‡âþ|‚‘á>¶m¼…³gp×÷ E€‚rµTبêbáñZ n6‡<Î8rø¾„³'Ñ××CX©–#‚ÞÊïAêbÓÊß²²ƒ±k†‘ÑŽEÅ,4­8¦§/ gp5Â*Æ.ŽÒÓÓMcnšV{ލä.}" WΞ#"e¨z íŒù†`ôâ)Ö¬âðáÃ´Û årk;ƒ {í7mÄqŠs‚ãÇó­Gb릵üÝg?Ãð`;¶o! ëÖ®fªnÉ3‹AA!¬èûËŒŠ ¦¥­Ú•ƒìÅsº¤Ú_`Q/­è¯Tu½rþš¡˜+ "kÌbÒZdp»è|v9 ‹»âýñJÓËÝ•ÏèªU˜œ¹@TõX³fµ“Žf³Í©3‡9yêÔž(^ $ó£°6ûƒì(®Ÿ»·æXFÊûåÿ*3ÍKœ=ΖMë±V04²’$W„¹âþŸüENœ=Í—ÿñ«ÜzÇ>ü;vì`׿Í<ìœ?uŽÛvÝʯì7¡ZêÆå‚;n\¸ìÁæ8!(È»ŠOBžЄïi²Üç9aàH G^<ŒÎ3ÎŽž Ö±aMI2ƒ¦…3)²q’v’BÑÂa³Jä´d ¥<Œk%¥¨ŠçøÆR+×ÈðYÑ¢e†ìaåP¿à©Óv8ßç¦Íw1_oÏ_ûÔmõ6;6÷a“æ1!ýœ?w–µkWʱ^€´‚ÜZr£•Gn-žô@nr%i&)_ÿ—"¡»ªøÛÏ~’ÝÛ7S‹Êt×60Tvô–JÌäª1FÅS´ÊUð5ÖATëŽtF&ñƒ¨±E ­%Ïó“Lž;œ,˜Íƒò$JÁ[kMnÁ™kÁt„˜œMÑLšP*õtmÇiÁÉ`1ƒ(QÂY)sR“ $x^ˆó%6ncm€õAe>ˆ£=DnÉÚ‚¾¾â´1M¼²Wˆšg«UGÚ.|ß’&M|¯§ ·L¶ÎÂ>Ûw¯Â 2\j©Ã÷Ýèô]µ>Z qßû×pîÈ´³˜æTë ©š¯å£p-Ë×ëÇuØéí6×rÎQ¯×/w,fbÚñ‘ûƒoûAFVt‘§ å°? Y¹j˜r-⦛ö`œe¶>ÏWÿñótuuÑÛÝÃôèy¾ò•¯pã7²rõr›¡”¿¼Kàå²ynð´ÂØBv\ÊBÔ9hµZäÆñíï|‹F»…ôv﹃®î ή€<Á‹šôTj´Û G’´ ýBTN$ RJ’¸…šÜ:ò,Á¯jÚí (̶ñ‚f+¦R«R?×Àú%’VFL©,¥H-˜kÎãôE9y¹ŒT9#«Ö222ˆ ½ `f‹)¡ôÁ):ÖÓÄ&£•Ôyà³óôßäÃ÷ÝÅÁžæøñcìÞ±Z±mÓzTÎ]dföÆ ”"lÖFEè•‹ ݱDÅU_6YvI7a—½è¯4o¸šê•?{ÙÆÔUyÕ¯Å¡Â¥ÐØÒÇ´¼šíŸ0êAãH³! "0ø2$ ív ¥ÁIE+3LLLrx´I«¬ì0¶…‹}¦gz©VË4³ÓÔô,Õª"‹zxî¹ã<ð¹/q~æyËÿž.âW þ×qüëÓ{²ºòuÐöWÆÎíwrôØY¶lÝAšÖiÎ7py@.cΜ>N­»‹J©Šô4&O¨T|ffƘçC÷}˜žÞ.FÏãð‘ãüìG?†Ôû²•D±LÕ-ñXPÿ4Æ¢•¤R.ñâñÃ\˜¸ÀÔ¥‹lÚ¸vS%QXB(ùjâ´‹Ak‡çJa™f³IXñȲy<â8&Ià›”ªMº5’4Mˆ|²,¦:žŽp¹C’&1’cºM„##nO‘Ò&µCtõ”Y9BxdÆ’¤IÁä–> Ö@’ô0R¡<Ï|ús}æ%Þû®›øÆ×þAÊM»w1Ð;H%’×`ræ"¢1KwÚD•$ÂóhÊ)"¿„î`ì 0Æ—âj²ËyW'µ½–D±Œó*o²…ŽÆ908„P¯p?‰PºãQ"ÉEhƒ#'òkØ\Y„$f™j¢ ŒïÁ|ÜàÄÉ“ŒÍ¶h[ǙɧF§¸m7Ü^ªÒ®k>û/`<Éý?»‚žjŽöHÍøOˆ ±yó ¼{ëøòçüž‚Øë]ýA8Ì]ËšôõX^O?Þ˜Ÿ?ÍWpfÔcß 3ÄqÌÞ›îd¸W1==G£ÑàÈKÇøÅ_úzzzèíaÅà#ÃýLŒOÑl6¹a×.žÝ÷<›¶n¡Þ˜£·»°Ï¼ü¦í„ª%ÏCJ‰íTÈR LgïÝXG»ÝæÁ¯}…ÙéiÊ¥*«V¯ãä©ó ¯`br–C/<Ï¡#OòÁ~”j%âÔɃœ:ù+GÖ°{÷m̸nj%ÇùSG©V»Ø´u7ífJ9ò)+Ôj#ÔVô0ß#( <`¬ÄU-ñÒg,Ú“¤.a˜ŸžÆïT³&Õj›6ï)`cˆ¢¨8ÙàIâ¬IùÐ1lúê$oYÞ÷¾|áÏ02ÜKoo/•r½}]O1×c¦Þ¢K)|/¤-=2WtIÚ“—õ§Ü‚‘(ÔcµÂŠ«C!Rr䯆Ÿ¿Ö„±¬CW%µÐ-ll‡(”t8̲ܒŠ[˜i@ž§‚Œ<Ïñ|-ù_þ/<ó(7줧\eåªMØ÷8_~à/X·q7÷¼çcøQ•v|‰/}îo¨”úùÄ?ûUæ“J‡?z­Ö¯ÛÀÚ5ë¸mï:ÀÙ"5HwùF§Ö\¼uˆZ Ý ÁH)E©Tbfj–U#«Ái&¦&Ù}Ó”ËÖ¥t×"B?Ç‘"hÑÝ%è®X¢À…’’ö™Ÿš¤?ÔLŸ;C—_fýªõ}á0ÏcòÂA™p×í7òÝǿƥ‹‡¹pæFOðŽ»÷²ÿ™/ðè7?Å#ýÎöÓ÷0=¥øÿôKŒŽçܰ÷]ÜÿñŸãËÿøEþèÿ ?õÁ{é®~ÿrׂz~X°êïõ{×á§½¹Å•¯³a‰áß IDAT¸4Ùfp°ßá#÷¿Ÿ?úã¿ã£?ýAnÞµ‰°Z㮹=½z{FÈRC–eôôô‘$1çÎç½ï~/iš“9A’ÅT¢‚qæå™iipq—p<­ð:QZkvìØÁÿù»ÿ7_þâ8vä(›6oG{>õF‡äà‹ÇX5¦)­ú$ž²ôu—ñÂn¤Ô4Ó&ÕnÚ¹õðË‚–ià•sJÝ–4q%1B¢£€žþ>†z7¡K]ä:@¤Ž¡îa¿JW©—õ«60=ös“uV ô“š„Áávܰ}Q€¯Z­b2‹Q6M™Ÿ™ä»ß~œ#‡qôð>ÊUغc#›7lņÆÜ(óóLM_bëúµt‡!Ys™Žá¹ ZfxZš¢:×ZS‰JËpyfÁÕy œgÅ5f\5a¼Þ ³Ðg*à¼uZg-ÒØeU¨1[ÇÇ"u 6÷IÛ’™–¤Qo mFoÿq6‹Jž —EJGdÒ'Ô%œ ð…‚Ì[KàB'Y=¸‚Ì z‡†ÙsË­ô ÝÄc‡.òõ/~Š}Ï=… ,;6ï}Ã;Š·rùį'‰·_’x¥k^>5ÉÉ—&(WofÏ­’[o½¾ž^ªa‰“Nјk2>>ÁÞ›KhUÂóCå¡RÍoÿËI ”òƒX‚%v• Cí¥~Pàü +³Išøyžã{yX)Èô ¡Ã2FxÌÖcJån´„Üø(¯BwµŸÆìž® eßÖðm™žh€VÒúDºB),SŽJôD’HyØ8£¯Ö͸ö‘™dÕà²fNw_?c—¦Zsirœ±éI&ç¦X5Àà@QEaeB–·‰ü iœãœ ð}šFsöÄI¾õà_Ó˜8ÉØ¹“¬ê@–»Y¿qš6­öcçOÓ×7Àº¡-˜vÎlc”j¹M­â9A)L»lŠRÅ Š.Â-©ä¥”p…nÓ÷Š7_ E½žÄ!¥Ä]AʳŒ0¸Fáóì±ú¼ïÝ»hÍ5ñdF—ì¦Ùl~ÏÖÕ¤Òß.ÒÛ9©¼‰âúûÍ= [ÕÖ,½¶ÌŸ}€fÓUrº{W°eãOcsA‰#ÇŽ±sëOe)N€ß`×ç'éªuaɘ™›, ç¡t°HsWHF/~~͉Š`hhˆ Ú…‚$IH›-â8¦R©PÊÅpÜä”+1Žr¹ @–·ÂëZªLŽ–­Â%D¡¥~PTÂQâŒ%OSß'Œ|j]J¥ ¨Ô*8룜¡Z-#”éH2C’6yæÙ'™™©óÄÓγqóJ|é³zå6JÕI&fŽã9AXÎqö"B´9zxŒçœæ7~i/k‡JÄžB µÌÝM‡T Ôe[Ò… cé¼çjÕÿ2¹î+:„+»k-®óØWúd_+ÈH.û_H¥ Ú¥~˜ÅÙ…ë|,,p‹ÄµqÃV.$$GÏ31>CB^%JIžgh¿è¦$j‘µn\!ãÛ1´¨ÐH³¶(ˆ^…ž.Á¯þâ½Ä3-.œšcf¢ÍÀp•  CÃ}äYŒPîûÐo—ÙÄC°¼Ðˆ“EGÄmøà½÷ñ¯~Ž»×bdÌÓÎrï¶³uË6޽tˆ,oãÉž'-”öùã?ûlÛ¶ ÖóÂ瘛斛ogËæmt•Ö¿úvtÑÕÕņM›HL!YÄMZõ9Ò4%ð#‚ ËÿöÞ3Ʋó>óü½á„›oÝÊ]ÝÕ™lv3K¢DeÉVp<’ì™õŒ¡ÙGžY`3üa˜Å;À»Øý¶†glìB¶aå±g,É”eÓ ,‘sèÈ•sÝxÂöùU]Ýì&e‰”D¹_ ÁªË[瞪sÎÿyÿáyƒ5†R©„Ë q’ç)a…›X²$EKhÔʈ¤DžJŒÉйþ($ C‘ánªÕ2•J‰‘‘Q ” Ñhàl• Tgßþò$¥ÛïW"z½-ùÚÃ8×çKžf¹N¹\g}í GfÇYZxÕõ Zc-uXÚ¼H© QX¢V›áìù1®U!a¡ex G¡àSŒì¢Üçnȳ¸Þ&t§ýJ@q3 Ø;¥TñÙÃÔðê/öÿ®ml³3ë Â9¼ð8,È«?/=Há‘ÂÓlL’š}ÔkWÈÍ:2É­Ø=žg¯º÷y¹ÉÈó”†Rlw ÞÆ”êû¸pq—®,réâ2ÛÔ¢:åZJ½Š—’ÖØ }ë©5ZL>óCg¯´£½Ñèìk *? ð'l·@âg,œ ¸ãÄ=Ü{÷=´Z1«[˼ý]ïgläöùÿ#‡¦YßXåñÇãmoù`!kúÔG—çNówß}„ÙÙý4 –––Ð"æ¾»¿ì†¾æ¡yµ{G@$½l×»»Z­Èi*õÒ©¢„†…™P¨PJbm¢Ðy JÈ &ÏI’ksr›Q*b]Ž1QEµJ%%RŠ"›õ®TFšg„¥˜0Ž)U*ø\099!s ó|ÿ»ßdc}Ž¿ûæW˜>8ÊìÄ Çìç¥,-ÍãMŸ#‡oC)IÞ]¥[´rÔ* Íùø?frfn"ƒIB!…GHp^íÊsì æ7kÝù~/XÜH êÆYÈË…wãe"x×FÑ‹ÀzÀÙ€p?̆*…» ¬C8Ož J•ÍÖ4a0dáÑ(­q.G°3"\ˆzáqÞA¹RC‹€í­O>s‘íî(^OѨ[JQ©§n¿A’ÒlMpìø ¬‡Ó§Ï¼&eW ¯µxà¡ ó“`´ßZ¯ýõÛÞÞÞS†,óÕ¯ÿÇMñ‹ú5굃È0ficްÔaqyÀ kX][$’ÔcðåG?ÇüÒ<·ßvŠùùyÖV·øàÏÿ S‡)E5®¡kÿ7q–Á`@š¤*Õ*Õ’$ÐÔ„¥˜‘JD†äa¸køE: p©D(…óëA©F\iá3E–[Òl€Ãµ“,ý~Ÿ4EùCIvƒm…$x É ¬®lâ½çÌéçX\¸ÂÅsOqò¶ÃÌì?ŠÒ].^zœÞ`e„‘ôÛ TëšR i”ªEÖ!Ñ*â*NY¸ŠA ‡¦C×âüµ#²{ËK;ç¸{EûŠÆ8?ÜÇîôÒpÙ 0ˆaVpƒÆ·ÜÃàÞ™†;Z€wCM)®¾g7#q!´ŠÑ*Äy…V1b‡2¼FzE«„]ÇÁDÆFb„Hˆ‚œj%`­ã3“»÷ßþêóìŸÜÇí§î§V-ñ‹Ïð…¿üS–—yî¹g_—zÿëåéðƒœßOƒ‡Æß×AðÖú鈽±âm¨ýûsiñ2¿óÿ~šOúÓœ¸ívþ§ÿùáßüø Ê&Çkdùžzö/¹í¶w³º¾Å‰;ïbaq™æH‹}³“´7Û…f•àBœ7?RÐ{ÏÖÖB”JœÉÉÓ ¼¥T© lˆJ4êq¡ÿTô^©ÄTX'*5HÓ%2k©ŒŒ’PáÅ‹}¾ùÈÜì0·=X¥\o—JÄ¥*MµV£R )EeB舙³ì›ÙÏÚüYzƒ‹í ú¾ƒûJ›‹§¿G«Qæƒï¹›n{Í'H’>#µqt}iŽúˆ#é­3Zº‘VTM Qy”‰™ƒœ}f‰nÆÑò:Îvx}ao( ò ¾¦ä¼¬ e‡ð;å¨òÑ^ßÍ|¹¯/?]_Š*ÀÃ"¼–— 8‡ó›ç…B®HNâÊæèÜâsÐëÎkr§°^áÑxé‘$Œ#*• [fã ·BfÅðƒ7…”ˆÍñY†Ð¦Ø„M”®“›*——öqÛ›àαqÖùöWžd£s†ìâÇøè|è—?J¨þ·û/Ù7-yÇ;äâ¥Óœ½°ÌøÌ§NÞËÂÒY9ǎϰ²v‰Ziœ(¬þÈRé ~¦(aÈ¡À`2ØÆN‘e9iª0Þ“ç9…ŨFŠëí^—nÏ“9KWQ¥™‰ØÜê UDTª€–N¨@ïáXŒqC³žpXb)ì8'§'ØÞ^䑯ÿ Þs˜éñ/³µ½N¬#âFB·Y\nóì÷ŸãSÿüWX¸ü"WæÎsðð[ÙX_¦Rkà¥&Ž[AŽ]"U&S¤¹H¥ô¶¶Û þ;B‚/Ë®ƒ÷Þ×wį/Uݨßq½÷Þ’•”º˜˜r×}O ‰z(ßÁÕóf2*¤ÆÐé÷èºôó.ÖV‹Ï@¸Ü¡e€ÐC0“’r©Ê‡ÞwüÜ/1;Rcå¾ñÌS\Xx=è2;v;#ûîäoÏ=ûÊA½Qo† $I>ø‘ƒôÍØË?îõëÍ¢¾ÅÈ~cƒÝ+)5ü@=‹@¦h›pæé—BFš³—ŸÝGfï&/rêM–¯y‘?þÌ—xð=Ó”+Ut"8·¼Ê Ï>Å ¿Ì¹ÓO2wé"/´ÎðkÿM¢hôï…¬×ÿ¡L–1Ro2È\á‘÷ð2g||„A¯Çøx™öÆÓ£³¬µKlf%Ô KŽ¡YÖ“Œ®«b}F˜eÄyáÛDÆ#àrЖmW#ªNqæò&­ñ{9rxÀc~¿ž[¦ÞjÒšçþ;ßN)ˆ©6ÉSÉF'cúÀ>ju ¶K«f(é­Íôu Ö¯– ¼‘‚÷UÂã§áœÐÃë¹¹øQŽ] ö3Ž?ÌÊR›J¥ Ö–6Ù^{޹óÿ†ãwYD<àö“cx¹ÉW¾|–{ï|ç_xŒ•ìy —.ã¾ûÞÂÊR‡“Ç#?òè Ðx›’úX£¨6ö±¾¼H(+$V»”Ш×Pj“,é312‚SžJ¹Î¯ÿÓÿ/ºä¹!³Ö*œóˆ@‘åà£%b´1âåÙb8’*…¼¶‘-^y¬õF¯¿¢î“—…ĺçU³Š?€n×ßb§ç!NgY‹ºI¶³{í‡YR1°¡U†Z´z½ÁKD¢MŒÈýÌŒ×xâéïÒÏ·H: 'Ncfÿ2›‡!Íj™;t½OÒß ·=&F«(Q&$t)™{}¾ŸD­þeu¿–Áó–ÔOG0½—X[ïpâŽÛ0™Æ‹ÀqÛíÇ8óâ¶ûs|ë[+T«u>þñòõ¯ÿ-¡*1>²Ÿ÷?ð>ÿÕßçñ‹OsòèÏóÏ~õSDaÑѤP¯~ÓÞàþòì!:: ΢ƒˆ§Ÿyޝ|íQb àÈÝÇyáÜi²|Ñ(D9ݼƥÕ•‰ÖåÑu‚PÑÕ)ù*‰ë2ôðÕ*ZáúÛ9ä’^§Ë˜¼ÏÒ†ai=ayé4'NÜÏò%KoíßyäIî½wŠVk”r-ãùç£.Ê4ª‚¼7O}D6ª4+UR/¡y4¯cÝ€ .Ñ©5ºy¿(y©2’ $k¸,%%E¡¯íìðdÁ_¸~IYH¿[ü˼oĸ±»e¨½`±·ät•1òšã;œœCˆ¢·3/«¥_ßLs„„A„RDñYÆz¬°„z„ˆ˜$KØ\‰¥ËkÔ'ÞÄH¥Êí‡ogkm…§ ªµÞe˜d —f»RÜìÖÐÝLè÷òÜ µ"Ëü%p¿ÞõÕÆwÿ¡¹[ë5‹z-äÜÙËô¶3êµJoU¦™=æyúñˈ°ÇâbŸÏþÉæÊå>ö‹ÿ‚ÿôç_ ó>͇ßû)>ü®jµN¿ß§9RÁÚ æ`õtã“c¬£›Y^xüQ¾öðÉÓµ8~Çý$½KÆç¾ø—ØD3uø$ëí6ÿÇïý>-!¹ëž7qß[?Äù+gøwôYšõãÍü³_ÿlžãþøÏ˜=t Ü}ßûQBðÈ7ŸåÂ\—Õí¢Ê8bº[Û,\þ6q)àm÷ÍR«Çdv™ /.RVeB &_a²U¦$bÂJLžf„µ[6äÉgÎ1òvI]¸‚ WQƒ.NXâ¨DÞOÈ·×ÙÚp F Õ°ñò ³W&\ìɸ¹1Ñõ€±,^¨Ã»Ÿ7 ìר¤zƒ\{ L$½á=ÞÀ!öÈzÈôP¼/ô£Š©³hh[ø\?$* ¼¡Z„r U唬5BE—Û7M:hã’uú„Ï.E¸”N»C¿—`=”J%*¥ˆLyœp(ýúÐ׎ûï¬o&ùþvk½v×è§u‚Lh]¢ßéQ­FT*9ÍÑ*õ†åÐñ)fÅ<ñýK,¼TåÒåMœäs_üCZ­0ˆÑ%Å[ÞônrëʼnDï Ûý°«" ÅÊÆ<ßþÖWyàÔ$Ö¤´ÝÇbR¦³ÖçäɃLV5¡•$ýížâÈdŠ·èx•ų[t6ÚDyNl+g¹Ð^d 8•óâÙçP2bfzýA—ΞCþÝ÷˜ž¬r÷ǸûØíØî ÂzöM–©Õk,­/²º²HhFëeþî›/rïý¡LÕ§È )%¥Æ—–=•f‹r]àóUÒ4Å9ƒT® 9’ÑÙœ£ä7™ÅßôºÊ§p¸”ô(1däÕK"7*-í2µ½¼†gq½—ÅËXâb§ôd¯iŠ_µ!–̼ÜõÚ¸¾ñ¾÷x;p­õpl,ô9ØRjTôÚ]r[g~ã:ŽzÞF»SÔ¬mºD½– â+ë]tX£×Íéu癜âÁ»À Åj[sß}3¼tæBÛgª^¦V®±¹¶€÷ëìoÑëÌ“t7xôëÏó¶?Bµfɲ ( ¢—„ JŠ,ßFkMž2›ªðnH{¸l‹£Ž©±€R½"Xì <_0 e1qtÕÛßTðFÓR×¶½/¿2`pSÎ…wç G¼‚Ù-®÷½!hawå;Œ³(NpEÉ+ËÚh]Á9V’vBmhw»äf ´;=zE ÈsAT¯S/‡ômF¿Û%P–(rô;k\¹ðÝΩÉ_÷‡ÿVMÿÖú™(CÉ@36Vcr¢Î£lnn!•ãÀáÃl¯®ÒëôQJ³0¿N)˜etlŒ_ûøÇüÂK,//ðâ‹—yìûßãä‰7!%)ÉMޝ ¯ÄàöÞÓEòô÷¾ÉÁZÊ]’ç9Q}‚teÀD\eÛtP¦†Ï ÝíMœìaòïcåC¨°Š®T‰ÊUº¥Ý­ˆdà¨Õ ½õUî™Ý‡×1BÄq™ív·pÇH-§NÝÅ£ßyˆö1Óš`ýÊÓœ~n¥CfŽŒ ÓœÐ8ÂrÈ©;îÇŠ¯@ú åRL¨CR/¨6ê¤ù2^@£Ú V®¡„Ä‹¡^)Æ›–ÉF‘zD9qÜÀÛÙïIQÅu~Š›6²o6òº÷}W_7y}/p°'‹p»éÝãïQpD¼“¯:~»óuŽÁ¸B?ÊC˜]—=éÅ™ÂCB PJÑi þýgþŒò±qòà(>MÑÚâÃæÛd¦"¡ßÞ`}}…A ! q ðîûßÊ*~zÖÏú†@,.® 㣠<ûô3¼éã,-Í—tKœ¸k?wÝ~‚z|œ¯}ík4k‡¸÷þ7³²:ÏŸ~ö8xð ý¥¯ð‹þ÷Ü{?Rj~Ø*ÔÎðÔ¹ \8ó¼ó‡÷ð'_|„ùž¦ZjR‘ +ë\¶˜žBXJ ë ç·h¢ÊsDÓȸJ Ç¾ &¥[\2Mw£J}lŒ••UâŠau­O/s;y'O~ÿ¯9yÛ*•q¶·Ém›Ì®19zŒÎ¶a²º…ÓŽrØäÀá2*2„åˆh0Eæ¶qTÒïP᎞Áä…¸Ír´ŽÑaDe,†¼O)°Vº9Qî•–åå™ÂõÁäªkÞË=, µ¿á4Ôõ™†‡›Ïkïafã}ando.u¾·,å„UdJŹ‚¢ᵎtà¨WË#pV‘g‚0®ÑÉðèwçØ\ÝæÔÑI”ËX_»‚óÛ$½ÒÎ&R‚ÒžrP°ü•Ž >ˆŽlAýV†qk½¡Ábfß½^—ÇŸXd|¬Ã©;ï¦ÝÞfs«Ï¯ä¿âÿâ иïÀûyäÙÓ<øöò¯?Ì¿ýßãŸüâGÙ·–DZ¼øw<ü·F¹ 'ŽÂŠWî¦Gor„ŽÉŒÅ ‰Rá2.?üuî™cß¡ žyaPNP ¶(•ÚZrÇþ2­ò&ëí-~Ìpîü"Ê *AÀ2ÈT,HÝ.ɨ¨)šµ1.ϦŽqòŽ;éó̳ÏsêîSœ:yŒŠÙb°y‘“ÇOP«\\–ÞÖ€C­}l•%O<ù¿ò¶ãè°B,ëŒEô¶5ÕÉyØ%¢’뫈Õ&yÓ Õ”\{Tš)I?ÏÐq Ää¾JêZ»wïð)•PZ€Èq"N*åp|6¯Ù¡Þhâé•JM¯f`ä±ð²ÿ/_±–øòžÈÕž†šÍ÷½ý±Kð+yž£‡6»RJ¤†J¶Î9ÄQ„ÒšÔõ¦OT(¥èö¶˜™hŽ“'O2Xi"Ò,AêR½%$J_Í®‚ÀÊ×ìz5ñ¼×šM} 04> IDAT0n­+X¬¯m²µ½Ò0;»Ÿnw•,÷tºm>ýGÿ‘Swÿo}ëðûÕ¿¡Õ9ó=Ã'ÿõo1ÿÂÿãûÛ|ñ¯>Ï>ð¦&„1&‡W{,¼à Y JXY’±´x…3/Ó“ãˆÜ2Rnòsüý…o#EJc­Gerã t€I1JJHìkl1V«3Z! B4‚­µešÕNÕ5š­q¬Sd¬÷H›W‹:=ÂíîÞ‹]È– çñ²pË£ƒb¤ö•v»;“K…DÇÞz ¿¦4(¼Ù±®'?üýì.Xøáø¬c¬HïÁ#½Î9¬µC`°Ã¯ "ž³`†Â‰Æ;2kÈLŽÁ ‡‚L¬5Þ&˜ta#£2ƒ|›R¹InRrçÉrÇ]w¿™õ…‹diã3ŒÛ=?Ì0Ä®“£”¯Oà}=ôn¦IukÝZ¯WVZ˜˜ E«>Ê]wÞCÒ³Ì_Ù@éO•,«râØm g.çoµÊç/çâKgÙÜܦ\®Òï'H©‰£ï=Yž;ËWø¥â8&·' Ë2Ο9‹ÖšÏù?Sgn«K¹5JÇÄQHÖ¥dÎM—Q êìo5™ª Æ+–ñ°Â³96=E=j2:²ŸýûgiV™Ý7É‘cGˆbE³qÇíûiT ½~›mshfœ­uÈ=f&äÝœ€2qEòÌ ß'ªd¹ *H"pdýÔH“eç%ÒÌ´jÌ´jÔ*œ—DAÌD-¦¢$Q222ª‚•1A¹É¥ù566ÖH’äþÁN½ fÎï6¬¥‘à ¢¸°WƒÔCá¦MfwuÂéee+/wÍ®÷ξfªIìÜV²P’Žâ tq 0'ªBá Í=Ö¸BŸ, Ña„Të$¹‘%Td€tšn'g«SH§[[[“Óí÷h÷Ä•&³GŽã”@h±ë¯uH»(…HäëWg~=‚ù+wkÝZ?rf°œ>}šÃ‡b<¬,¯Q)â¬çôef´ÅÊ?Rœ[úýÄGyü»ñQ›§ž|Žgž¿‚5ðöw¼ c .ì›>L”0î•oæÁн%ñ´–ÄqÌÑ£Gyþ…géö{¬µ»¬w&f2X[+ ƒ#ic–Oþ7_¢W969à·ÿåû­§ä.Ǹ6I/kòð³Ë|ù»OÕ*œ¼mïÇ=ô:]šåˆ$Ù`i¾Ï éG#£UÖ×–xü‰9ö¿ï$Æ8Z#Ó„Q™¶sŒMŽ‚m#´ ¤ ÆÒß\ ¬’ bd+AnIÖ£^ Ð2€°F’o£ð8›3H:ªÉ2g.̱±µÍáÉ+e6V.Rn@uÈ9Øá*8ïŠ <Ô_¢˜²’ˆ¡—µ»aßâfQ¢¨½<àco ׌½¥<ÄÞà5$ààR€s®p±¸æ|û'@s¤J¨ü0`R‰#â0ºæaê%t¤9}ú4ƒMCÖu=|;½N—,É©„eB- ¢òMZÓ'˜:ôt0I9*#ó÷¨Q! ¦Gpf©rï}åŽÛÞGg=fl|’ññqLš°ºx‘jè¨ÉßÛàðø“SS”Ê-JQhzi†¥B¥4†ð9A,ðÆ¢­DÚušµc{àÒJ„Î +%5ÖÆdV@à C‡ ˘¨Â³sËüå7ãÊÆ6Fk–æp¶Ëvg‰,ïAÛ ðïvü±Í5°×ìh—ô¶“=X·»“ß«»ww¿kÃꮵcÝ {Ét7#®ïìºÙ5{M” ©yÏðæîoïUQ’rcÆ82IæHsOÛlæ«IÌ•MÏwŸ>ÏWý:Ýöe~éƒ'yðÍÓÜsj’²N•¢ZjpìДã:Zèbòi¶E‡kˆ†¯E¹é•Þs+ÀßZoøÌâÒÅkM‘eÂyÞûÞ÷òÎ÷¼ï?ñ]Òþ*Î-±Ñ>G¥ñø÷¿LæÇ8¿ñ$åò,ûNpxö8¿õ›ÿŠ8,‘ôS\%'@…¯øá6ï2‚H“æ'=+++<ôÐCdYÆÜ⽞àÔ]'ÛÕd$·ä¶‹R‚J¢bqÀVñ&@«*!eò­ FöH„¡TU=5Ρ;JŒTzì+Çåæ.Ð)0vÀåõmîª6IÔš`ieeºÔ‚Œ-m°½-Ò¬Wüø«òJJ´–ì•ãRìönÆþA‚×µבúÜÕ2Rè;$š½Ç¹öó÷4»í ØãCÀØ{žÉ C”-Þ1ôä¹)DÿÒ>WÖln÷XÛÔGËÔcŒÍÌâYÇ™E[œ‚t¼Št)阙‰/³‘¯îtevû1;@¡_/q¨ô^¯Ýì­lãÖz½3T ð>v7§ÏÎãÅ, ÿ×ÿýò‹~zlYœæs_ý]~ãcÿŸøÐ[xéâ8Óãoç…K_æâù->ù±O1ÚšÀzAT*“$}rA(‹­å+¬!išEÝn›ÏÿùŸ2èö¸pù 6«qâØ86ësöÂ&Ïò¡¶8—»5Æú cÕ“å<{¥sÖ‘ù6.׬®ÎÑ™å³P¾Ï¡ÉQ²MÉåóÑ ¶ÑÔIU‹óç.³߀XVË“”keú™¥T°YSqD> 2’¬*hø*.0ä±çÎ}MªÕ:¹’H9@– l b]%'!,§&¤ß é»wÖ÷sç1ÇåÕMžâi6ú’™£dn™f¾M½äPª‚DkEâRjBÛ2N´w³N€Í2‚,ËQ*ÄZ»«¥´ ²,C¨"óŠ]³!)RîwÖ;„ôH¹±fx±ãV‚•¥5¹³hÀZO(d¹!r%¶Ü2©èc‰pI—õ±Òã„&l’ùi1QU(Ñ'€u-2UA'ëtÖ;ç±”`<âsO/0Þ,3:>Mõ@…ñÃ1˜œ|°AÒ~%ÚT#Cµä)—«TkBHr‡ñžS§NòÍoyHˆŒÉóœPÅ8Ÿ ÷š>|×øÌ¿ÆíŸ¤²ì9(Þ*W½F™E«UeîÊ"YÒÂzÃÔ¾qžþE¶ÖR´ ¸ïþ£<õÌ·›Î™=¼Ÿõg8ö,+‹Šñ‰ÖJQ ï=Q)FˆbfþÕF…cˆ¢ˆ^¯Çg>óžxâ{´·6É’ÕJˆW•f“v¿ÇãO=Ïøh!=}Ûñ#4å¿ðaM·×æàÁ;IÚ[œ?¿Áö¦¥çY²É/ýò;¸2¿F«1}°E»}–Ëç/±fœÈæT4tRA½^gieòt‰JP«ÕðÛiá#-=Â+|> ¥HŸcDˆŒÊt»=¦§Ñnw‰¢˜ÜzÆÕ›¤Bañt{ ý­.›«—ˆB(©Í*侄¸m–í4¢53ŠÙ¶4rP¦³Ûоf÷íÜ5îtÒƒ»ûºàN@ÜyÝÍìl!«±·ÜdíP1–—ˈ;w5{J¢„Â[S¸V¥håQ®˜Vê¨6¾dè÷ ¾RØ©OÚQ1FUÙÎ3.¬$l³Œ—V6RŽ©ràà!öM×ñ¦‹MRLÚÁu7éš6ø‘¶4J!¥8¤®c¼ðh:…0|ˆÖEV791ÃÂÂÂð¾¤é€(°Ö ^Ó`ðz†[€pký$³ °27Îúb0*D)™Ù 9RaóÒÞûž¼ýݘ­³µ•Ò¨O°¸òA©ÃZû~ëk¼ãïÃØëT1åjtâ_…»Ssïv»ôû}p&GKAµYGeúý”'Ÿ:M:¬mÃãOÐ9÷ÞsˆJ©Æüå3,¯=ÃäĦ·ÉXS26Ò nއcèü<:¨àäp6ßF¥ï$‰#é®2RÍ ³¶¸LÖm322‚3­Fër¼ÒM- ««\Z˜CÈ€‡ŽÒ-3¿Õ%m¦š!øœ$NÙn'ÕÀ@),áE‚ºi UXUúÛûa ªƒõE­èe=‰]±;€`¯éIXk¯)%õ{C>ÇÎûòÜ’¦)Z©aí¿°I•J!Fàè¥IÁÑpŽÜ–Xé•ZÐÍBê„tºòÜ—ËEÆ“CjCRQe3‰Œ VÓ<€ïáÌ<«Ÿ‡Ì …¦µ °- ¢H!QPFQWNäÚœë›À¡”aöÀQÖV·06ÁcÐÄZƒ” oüëöðݼµ~VÊ„`sð ïýÐþëç¨È&Ý협Fƒ·½í0ýí-^xî"Á›¶)5Fø‹¿ú KËL6ßÏHå^<}w¿ûà B¥É2Cj "™zµÔb¨*Õ*¥R‰OýÖoòû¿û;œyþLž0³/ Þ¨’™˜Ü­s÷½Ç8||†(ŠXßX¥×ÕÜ}¨L»ÝÆ™ kë–¥¹Œ z˜w| ÂÈTƒJ3Á™M[Ž]ŽLïçù瘙l0:;†t‚0(“&}Êå2Q©L…„¹bç¤yF =Õr@gTÅ€‹ç3úÝmB鋹wo)W›l¬-seù W–ÖA•°¹å‘o?ÊÑ1Ïd5Äç)QPF:C­¬ e#_Ãû.Zëëæèw8×O$Ù¡×…Ûý~Gyvg øz'{°W r{2‡ÝlAJ²$)€Éä¸áû¤ÔCœ Ã"ëq…Bì³<Í=AP# ØÀry«ÌÙó52ŸÄ9auPF( X¬I±&¡YopôÈ8ûŽŒÒoo2h¯Ð[ï©„rP7CÂP£(…1a£Uˆ’¥Jƒu}üÎäÎõ°”S8oi5§™œØÇÜÂy‚@ E1¢ëlÑX#ìþoõ%Þ¸ë§íºÝŒ@úª`ñÒiC?kÓï@£R£ÝîqþÜÛc}F+SìŸyÏ<ù(Q xü±ycpø¾CüêÇßÅÒ¥€Í>q•Š.tŒð()±¯R VJŠn¯K¹¦4å˜4éqìÐLß1>;I$™£Zkâ…dssѱ:k›)atœ@5ŒÒœŸ¿ÈÞÁ¾VF¼É™ï}ƒV©ÌäT•5Ôâ&d%Êq “”â:η‘2Ä:C¯¿Å`s€5 cb$JŽ Ôªp霣IÐÍrtX"óŠím¢jƒfš’{Ϲù.η™œœDkHÒ6+¾„ G¥j KoЧÓ0Ö ‘Éu¾\gHä÷Hr\Ç›7q¹Û™xÚûÚÎ1f(?"wYÔì’ÉŠžÆ Ÿ°µµÒ$Ê;\ž"ˆá¶Öš­v<·ŒŒŒòŽw½+,Ëë–$w rGf /(ô„Êazë¬\Ú$é Z G9 h5ëÔJ5¥A$Ae4‚©kèBÊœTh©ÁkŒˆp.#‘.2ÌÎaaéA ôÛT*5YVŒæþŒÖÊo­[ÙÝkuj€jSqé¹UNž:ÊêÚqÙÒëÖ^H©DÛ´&ÆÐ¥ .]xšf³Å]wÜKÖ(…#<ðÀIðº`F»¢žîœCÈWß­cÐ:¤T*!… Z­°¶¶Ìý÷Ý…ÏS¶·xö™GXY[Ã{Á[Þú6‚+s1.ei–»„²Î ûͱ §î?Äþv¦GưIÆ…_b¬5Êêå³>tdöà8Ú¢ƒä¦ÆYj(…Vä˜ÎÕ¨IF’¤„P‰ªD¥2Îdx)Q™RóØãqìèA7¨T¹³(ÝD©€²Ê)û” ”C•Ó¨ØÑŠœÍ­U/uHºË}ë4"׌¬ q#}'·‡Ëàw]é®ZŸú‚£àÖ]>º¾´µv7‹Ø1,rø¡f’5ž$ɲ‡ÍŠŒ#Ђ!ß#"¸„I`¥½ý]2“2èÅêã»Ra¹³dÆ`„Áe ‘Ð*ž¬ ñ*C{’!A£B‡!e`·†d=…R^j¬‹ð.5H¼K±fï4Jäh½“]•©UëÌì;Àüây´é÷û:"Ïò[QãÖúU†Ú{>?(˜j€4hÖ§™=p; étW¨7êÌ_^&m¬ó…/}ž±I8r¸E½Ycy>ç={¥…M6VŸâÈ‘ãhUBÉçŠYvçä. ëfË w°&7äÞòøcßç(ÇsK—éô3â¸Ì‰ÛïáâKs,Í·‰¢ËsmÂP¢JŠ£wŽsæô‹üÂ'>„äÜs÷ýLŒî§³ü}¶Û[Ô«žX l&èw,•Ñ­Ñ:K ýÌRŠëhR*WQ^·¤I—ãû' ´G’#|…¸ ´ # Bd\'KR^¸8ÏÅÕ—¨†½öY'&)É”‰f.$É‘J(¹rá·! &Ï1YJ©$m5ÙJ$¦#\xM¯àªDǰ¹ìjOvà±…ô‡·0Ü!‹ë$Æ÷fÖZ”º*™žç9B´Ö8çÈÒ´ gñ¾(S…aH¥R¡^¯ÓhÔØÞÚ6†_Ç!™àTJ¨ :_C¸ ›Òw)å^ŠÍ,ÖI¬,ád‰¾…$Í*@ú0R„¡DJ…!J—x"Y‚Р‚J• QÇ,Dˆ ¡®á]P<ÆàÅû©R¼’x'°®hb9|œ•Õ%¤Èɳ>2b—»r+«¸U*û‡Vû{Ξ9{;Oà‘G¿Èûß÷aªµÛyä_£ÞJèõ*¤¨”CV,I{é±)¾÷½'8|tŠÛo»|‚@cr‡’…We)n¶‚ Ë3Tð‹gxè¡/Ðj5YX¸„5:‚æhsçÏ0»ÿ(RD(2Òl±¼²Ä©ÛNø˜3íçhǽÜF)èqéù¿Å³ F@#A:I{³G­Õ$ ëèx ƒ,y–ÒtiÔ‹,Ç“Q«VÑá`X×8—arJ¡tLbO¾x,ª²°2ÇHYá:+HÓ émS®kj±d%ë3=>C·³MÖÍúý ÂZ‰0p@N < ‰t…@Ää{.è^s¡ë rWaØŸÀî R{ßsõgvÀB)µ«Ñ¤µ& C²,+~ïñyFj²¡†“C)µ;µ677G{sáË ³‚s†8u ‚-zÝl$ä’r¹Š¤ôÃe’n‰ÍÕMÚYÅ•mªc‚ÌE¤>ÀÉ€ÜÖ.ǹ‚Ùj°B"}ˆò)&ñyDž–2FkT)Nvðþyáðo5 ¾‰÷!ÖV°F!1¤Vk0=5ÃK^¤Ñ¬Óén"…zÝÆ[â·úopß›]Üìü5@9 ¸xf‰fyŒ 2Oml†|ð>~è)rÛ¥–˜Þ7Æáƒ >úËŸàäñŸcfßm,¯Ìa]·Ø#•&7† P…­ª|å]Æ@Hr—³záø{ÿž‰‘ ›+ t:Û„‘¤OqåÂ*i¯„É`¤î˜žªR &¨U+˜gS4xë{ÞÍÁ£ûñvƒ…åy*¥AÒãùÓUî?p¥3–dˆtmŒê¢Ô$B*¤o!ó”¼½Íx+A玼Ÿ u_Êé§š† Eëú¾DPÉÑVçOóŽ»ñÜÅË`bFFúYŸ‘°AÆ ’žJØe¥ÓÃô%+uòÁ*:ªúë=BVоO³Ùbmk LOÍ[˜¯“¢0ÆP’ynÀ;*åc 0°ÎalŠRŠ,³QŒm:R8¯ˆœÀ8N ´¤zšµ“wQA„ôž<)”`%EÚ>@1QŽùö×¾ÊC=Äæê ÝöAdTÂëmœÎis÷ñ f§§ynq™þYº½‹ü§‡rÒÞ÷Î*MÝà±ç ý‡ÒÎãeçG°¶‰Ó£8]Ãé2. HõZé lŠ"G{Æ[O7KÈUXðvdˆÍ ’VK¤‹±¶ >~ôvæ®\b0HÃNgðSŸU¼QÐ?ôó|£úÞMÍÔàŽ« oy`ŠR5g~ñõ¼Êãß=ËÉS‡Ñ/nR¯ð[Ÿü×´··X½¢©Ü9†Iªå,«"ˆ(êÙˆÄÎ÷Êåt{[üÞïþ±ö,ÎÏÑmoG!q±º¹Áå…+<ðæûô–9ûÂEB˜‰‘1öOŒ(ÏÃÿ wÝuƒN›+WžgÿD•Z=FÊ‘V©Q¹F¹êi…RX%O,í~L©€jY£|•¥s¨ÛÇêö±PŒ´ö‘$)+[Û¬õ·9·¸Á‰Ã3lõÖ T„ŽÑfÉq(•rdµN8W”Kœ’$IÆüæ<¡0»ÏS*U®ac„÷Ã^Fk]î†|¯ ú£££¬¬,±±¶‚—)<G*râÒÿÏÞ›ÅZvžgzÏ?¬ygŸ¹ªNU±ŠÅY)‘’(·Ùnw'–y€à @ßd@ß$¹Í]n‚¹4‚¤‘`§í8Ýî¶-;²,[–(‘¥âÌ"kÎ|Î>{Þküÿ?ëT‘’(Ën‰²†ZÀ¾8ãÞ{m¬ï]ß÷~ïû&L² IñÕ«ï²·³Ëç>÷ËháS9’—©#þäÏþ‚Ó§ˆƒñ»ÿš¯|ýÖW׸{ç6®ª×iÃÐgšÎ‘f†Q$¸ÒqiºÇoôÙíçä"!3%ž‘h™àXe>÷è÷ eÞ@Šeªì“„ÍÀ!R„Êz„óÊÑ6Â:\Y§ú‰Zœx˜œŽ¨„GjÒk`ÊœªÐøa‚”³ÙŒFS”ðÐÙó\»þ6Ö‚ÿ]rÏà㲟†÷ÿþ››¿é¼ÔEР"R^üÒ]>öÜœPŸâ·®ðÉç~‘K¯\d{s‹ßúÍÊÞö»›[œ?–f¸ÈQ>F‰k¡²Z×ûë¾Þ „qÎqëêþåÿùàª9“tÆÞî6ž´šKô÷†¤UÊGŸ}‚ÕÕŸüøóüÉüot㌵VÆt>ÅÑàÌF‡·_»È›_òñÇ684;œÛè´zÌÅ*À@gعÆùhÀxtDU®b\E  ËŽn8J[YK7HØÝé4ZlÍæ1/½z‰G–}ª|J1Ÿ!lA{háQBe«šLõè&Š”‡ßC»êÖIþ1·c”’øA½¹ó6÷<Ÿ ÇÙc EQ ”`6›±ÒY`0¢µæðð<Ój5ðÄŠF{ÍÍmü0DIËsÏ>ǯ¿F¨^úúEÆ£>U £Ñ”Ù|Îõ›¼så:Íf“…î2ýèG í­-º ‹hO‘fAÞ ªfTV3Is”ìR ˜M R°¸¡K°¥¤·¸ˆÖÖB¶ðT+obeH=xËk®Â)”uxF@:@H Ba¥ÆŸÂ)æyÅ(k3JSöYiOxöÉOÒT!E™Qe3‚Hƒ{ÏnääÉSììÞe6?¸¤¼@ñ“3*ú ÍÌOÒûÿ Ô÷ì,¦ãï¾1à¿ùoÿ²|†÷…?à?üÇŸçæõ„A¿àóŸÿ<ý;¼øÿßý¿ÿ/†ƒ»üÚ¯þ&¿üK¿Íêêà Ež¡¼:3$EnQúoF®wÞx‹ç?ö<øoŸùtJVVt—V¸{wg?¶F¯×å3/|œááuN,·h„–"ëÓIš¼{ç€~@šYìÜ’¥–…– ð-JFA¶…@ Z±å‰óhk¦"ð}°–(i’ÍØøä{3‚V“+W/óðC§Ø¥\¼|(J@B§! }‰—Ï÷ç%0FúÇä´saÌÊJ@£/‰u‰cʼÀÚZ9†1…(ÑÞqr›Q1fá IDATòêd<÷­<…¸*d Ï‹_¿È×^ºÈö­›öqV1™Žh5C:Ý¿þù_f2œP•Gܾ}ƒ ¨˜¥¸¹¨ÇŽ&Ã’QT÷<¦4¹d¶BjA#Öµþ’étÆ|Öd0“Îvi\!nB7œâ‘¢,øž ôB$Ž*…Ì ¼8¡4‚yÓ¹ãh’2ìÍxçVŸ¸Ónû$I„óÚå 3Ê"@kIž§H)‰ü€óg/pçÎ ²ƒÃ¥}¿àñ(~ðÅñÛ?›ïåü“úY| õ÷zŸÀ!ÿàgÏ2Þâ¡G þÙ¹ÿ’Ñ`È…ÓŸgwø½Å_þÒ»dßx‘ç>ý ö÷–IÍœ?ý‹ÃÏ}æs¬,ŸDë)%Æ8”ò°Fà\õ-Ô½xo—ÿs¿ö¤yNwõ$gOŸâ+_þÿâŸÿ/œ9±ÆãæÓOaõÄ:Û»›´Â:'£4deeá¼d6ù—ß`6IyöÂ2ºpâÌ:BGx®‹ÂшæyJ§i¨Šªœ…NƒEÕ% %“¼ÄêÍF“ƒþ×É„Wolóê•]>ÝeIxæ¤`©»H¾ºŒ òé.RO1•ÂSšùx@¡Câ®EYÕÏÝêFxÑÊ!ÂY”0˜2ÅÐi,"Íxt‹HkŠ,Ó<Þ\²Èãœì{k¡ª Ò¢À§ÂaµàâÅ‹<ÿ©8qjã81\U‡J}êùO†>ö§_äÏÿüË ·™ÌS²<§,æ|äÉÇø­ò[ܹÃÍ›×&dEI•Ï8yb™ßú_¢™H•ÒY”,u>ÉW ÃÖõMBy8SÒ›¤¹aX iDõ¶U†h­MGéðƒòaŸ ðØèµé·OY nß9àhc ¨Yi™eŽñ´¤,%žqæágXXèrâä Kg»,ÇE9e4ØgãÆF“1˜‚$`**çðTƒ4/Qºî(¼cb?ËËKk¬®¬±½{|õC/P?¨ úïcœò“8¶ùIƒ$Wñ-`ñÈ“MöÞduÝÃ÷Û¼qù« †»þñçyóõWÙÙÚâ©ÇåäR“GZdo0bR®]›ÇYGkW)Ê"áQJŸÊÕ6‹+¬Èj × ¯fT¥¡Hž”,¶û’Ào!•O)¦2\ÙÚãhr‡‡ÖzTÅŒ…XòôÃëìä,v:øÙŒÂZ´ôYXZe{o“é`ŸÅ8`ž•8Qây-œÍȲ”Fb‘žÆ ¢z-7JrŽ”P™„EkÍÑhÊÂÚb ¤8¢(ªUïÇÖÝ÷ÏÕñF”tuàÑ}ž¢,QZóÈ£ˆü€"ËMÆL†u‡ñÍ—¿A³óÚk¯ñò7_%Š[ ÷÷9 ÐZÓiE¬.µøÓ?üWQÌÉÅ„½ýmfó9®2×%î¶q.ãÝÛ7Q–xî“Ï BMšUܹ½Él:¦2µÚ=N<„pX[2ÍR@h­$S|¿"P•I1@V:Fƒœa@ÐxˆN§M··@w¡Ë™å‹Ë=º‹Z­.Ÿ0ŸÏ9ìsåÍ·˜ÍúTåAŽ49S[‘T-|]ಒÒJ¬TháP¨ûÉ|ˆúÌs¡æÓ Å:/¾ø"­Ö£LÓ#fcCw8÷ÐC¬¯>Á~ÿ€ËW¿Âé³ëìof¤cÁÎÎË~kRhŒ) …uÖ”HþÍ-Ž0Çá3>ýÈÓ¼óÚEÜlµ7/¿ÊÎDðó¿ðYÒÒ„!yžÖ6e† ¤°¥ë±ƒT%žçÑmµq¹ Õh–%Z„a“0ðé[– Ê LâqõÆ ö'G“”áþ]V´e!d¶àüjV‚×AÄ]&F³tú —Þz…ÅP ´O·H‡ïÕêo(¥(KC˜„4›mŠñqøOQ µúùžRz8Ò^îb]…Ã’$ žç¿ïnÎ}à‡›$ “´ïû”eÎÊÊ eYò;¿ó;\¹r…­­mª¬¢(3.\x˜Ïÿú¯ÅÞzû ¦—£cŸµÕ~ág_`½›0ðª⤨- X‡:öÄ¢ªðýºË1)(Q`™SV?‰)Sð•&˲z¡à8]0Ífß²ñà®û‡w~ØÑ°>£ïïÐÍd•;7&DÑÃ<÷ܧ¹µõ&£ƒMn^>bóZŸô‹O³¼tžÎÇ ÚÆ|äÄ“lïÝápö6¿ÿÇÿ¿ø™ÿŒ“K?‡öjáSQ(t °Hò<# |õN¿§êµZk+<Ó ’VNОãSŸzŒ·ã>×ßÙæµËI¢(2´_ÖÛ@e žß¨WH•GQŒ±E†MO¡ò£Á.“Ö:Î/õˆ‚³²ߣ ƒÑ·Óí¶a4ðÔù‡øú¥kX+‘IRÓôhwna«vTóaÒ# KœqzŸ Éfò2¼A =diÑ®·Ùb€òž$gD*ÑÃR"LE5Ï SbíœÙþcãæõË|í¥—¹½µ‹³š­[ÛSÑjxœZëð—ö”F‘OúdyÅàà3k«,÷zô–xâÙgˆš1GÃ>ƒQÉ­Û×xùâ×°.㑇Ïðü'& }\•±»{›VÜç¸2Æ…M(ò ë8VƒŸ¼oRhLm+âû>­DÒ –Èì”×¾ù.+Ë3Y±ÚóÑÑ„AÛW¶IG‡ =R㨬Ãw¯RdJ᪋'¥ãTN;ñ‰GÐÐd™¥€«*<àÊ•‚•)ÊÖ NP™z±àû-"dKþwUÇþ¤‚Òß&EðÃ"nŒá>° 8»ö8q/'l°°ä1\µ|æ“¿„53Þºú§èLYÑ餜ޘqáüg9mžäààw¹xñ"'ùIœŒ˜g–(l“›]y$:¤*Á!©ŒÄT‚ ðꌾÒx>Yaðü€V²ÌáAEÐ^„ø[̦”Ìçsʪ¢, ², šîñ3Ï=Œ–ì`(:C#ôQÇy žçÕ¢3ßÃHÅî~Ÿt^ñÖ^Ÿßñø#g8¹¾D>õÙ©,óù„¢( *Iš!f éyQHmà]ßfÙ_ B?ÀPZàäYI–¦dEÔ‚¸› ¡-qk´X )Ræx®¤Ät¼&»a@£Û&Íf˜\àÉ„tâ˜e3Læó?þÏÿ+ï^¹Æõ[·‘ÎòÛ¿ùküìÇÿ_œþ%ûã)íVƒsgøÙŸyŽfSáXg6/Èf9 §Y\èðÈùÓœ;s‚ùtÄK¯|•·®“çíVƒ$‰xøü¾/ Ãáþ5ò¬M¹ñ2kK>›y1GÈQd(¥k¡Þqˆ’`„AI…'<ÊyÎîáGé˜ÙtÂdš²½s›+ý/àÅS¢ &ÒLŠPl§ŽÓ¼…¤­”åO z Kd¹Bêívg,ÚW‘¢<ŸòØ0Ñ KEpï% Ö£=‹u?¸bõÝœfÿ.Û&?ícŽï·h˜Ù互c°8ò›ÿñ§°jÎïýîÿCVÌç»LŽþÿÅþ_±²v—_ùkîÞ¾ÍGOñÍK/r8ØâÙü'|ú™ÿ”…EŸYzˆ”]âh…²TH£Õ¤‡r¡}„rH©IËk-±¸2Fƒ)™O2^ó6íÞÖ³l¬¯sòÔ*kK’ȯólUÛ:é8³š0Ì5ÖV4×0f†³m´RHâÐ &Sîìî°tzƒ²²¬8ÁW®¾‹8ZmMäÁÆ©5n\!¥EJç+¤ÔTÖ¢dÝ-EQD¥}‚0¦¨fTÖ`lA6>B{µÂ}’Y *‡¥¢, ´§ˆbD·1#òi†×ñÒ2MG¨ÐgÍÕU}âÐ^—o~ñ@TžRžD xJQƒ@¼O³òm–)ö§³øöQÔÃîãÇuDòïóšš7˜~$À" › GSNm¬³Ð™N§Üºy…Å•6†!§N=Ã;oßem-ãÏ|šO?÷Û¼õö%^{ý2O?š³»=b¡wŠÅ¥G1¦I(Œ#@{}B? ŸÏ°&§˜:Žúì–’+o\a´w_pöÔ)â®ß¸N^Œi¬õÂøw_ˆfmíAU)Éd4"l4)­ÄèÂ\¾¶ÅHj‚ÛG¨r³O„a:f!.(g}Úºd¢5ž„Ð IZ xÒ§Ù ü˜ÖÂ:ïlõ‘D[+…ÓÙ”¸Û:ÎlVáPJPQà‘D1ó(!˜OÇ­¨ò /jQåÒi–O3Û¹†¿¸B*6l°¿=äö«lŽf;·/â%'ÈBaLI‘M¹pî?|ŽÍ;øB¡¬­­²zb•…ÕÂnŒFô&cöw7™e%···é¶4Û&]Šbå—žÄÚŒ¢Ê(ç3Œ­è÷0iŽç‡A@¬"ŒQ‚ï)’0¢MIà.'Pµ–fš§(BK¬´÷3»­«»@[‹Ð‚8¤Ó9EâLƒ«¥Gsù$qû,‰Ÿ0Ÿn¡E­ö¶G9a¨±æø9Ó 9Ž7n3ߦÛR HM#ÐJ"Œ#qeô}Ì·dtHö˜?³?°â÷Aàðý€ÆBAüv0ún® lÀ ÀÂó-Û·4ëk– çK˧¹|õ-¤lbÓÏæWùìg–y÷ú%þø _â7~µÇÃO®óÛ­ÿž½Ão0™oòê+;$ŸZeiù<Ž’"¯}z.¾ô2óñ„8¹}ãE:ÁS–>õ N¬?É­·_çæ×8w¦‡ö=º‹MN+Yêu”$Ïs<ÏCû!EeHÓ-=2!dˆu•SŒSC<Ãw^qëö Nu#œ-9±¾†Þ"ñ­Øgëî‘ß QÒ«3´Ë!¦,ïOIʬDKÈæ3X|¥ ü w’S¥x*Á÷CÍÈ9I³…±–Ò:¤ø~Œ’>B¤™áòþÍþ½ý’FÐE áþT6ÂöšTÂçõ·.6%~rª9{ö!––Vi/ôøÜ?z†Ïÿꯗ%£á>—^¿„ÅÐ]Z¦Vh=D«’"˸u}„Ãà{àÈ)F‡8g™Óé)Zkšq©¥.ZE…8<ÒZ×6$Æ¢¥"òJ¬íSíÀYõæV®TËBî-)ÝËâð=SUxÚ#Ô!ÝF‡$>" ¾³¸ü'מdyiwßþ#¦ƒë ,Ý…Öƒ¤rT¥#M)Éœ¢÷ɆâeIa-Æ–µ}¼±PS''ïwõ˜L Þ7—úAlC}PÑüÛÝDÊþ(Þ$€= £ÌÀbcc‰ÍÍ[ü?Žfã:Uù6yrÁ äW>û[¼sýkœ»ðyìügqeÈÝí~èc¬./Ew |Í©õ'ëLc›"Eå<^{å5Þ~õ ½N7n]£Ój1ŽŠ?ÿ«7Øßÿ‰¼Š¥vÀúÊyü`ÇŸêáÄ0:è39¼ƒï{˜rJ†x^€§} Æór¯AYfèPa¬dcãÖîa­¡·ËMM+ñ´GfyéˆÛm‚x@ÜT-BF#Æ–}œ«È‹B8´§0¥ÀZlYâ+I„ÿÞLÚ:¤§Q2 ÝZ€R‘Ù˜8ñ£%ÇC®ÜºÁM×çDçJ9´™ÐkKö÷fH€¶líîáÊ5âð<ífÁ…'Îs4)X\_çÜ™slœXe8‹'Oñ…?ù ¯‘Ä-FãMž~úaîÜÝbtD³Ý`g°—hÅÚÉÓ$Á*—^¹ÃÖÞš‘A—–åXâk4¯7[¦Ó)EQa­#g¸¨IFDa„pŽÛ·orzM„!+í[HmȦCV—W¸¹w¨Ù%q JßÁ <†£#â…ŠÊ%E9ÇNGh­QÔVÞ¶2”¶Äu>¸çîYsÔ?÷„Fk8èRÌ+æ6fûÎ>ýÁ.;“=¶§¬u6Pì»Ù¿ÂÒòÃVŽRsáÉg9·ñqZk+<·¬Ø9Ð鶘æ†K¯½Ä›oVt:>i1¡Õ«ˆÚŽ,Ûgÿp•˜L&xO9ÍpdS;©Æ~ƒn·CØ ‰.¸w«Çæ9¾¦Vf».¾öȬBE ûý}âÐǗƾк`6­h/G4[« æ)žW`æ%A¡/1Õœ¢œaŠœv£CÚß!ð[Œ&9Êæt;ŠÝaASÌ«1JL~HVU4S‡¬ÁÊò£,®…¼òî~ï«WQUJœ„4bŸ<›°Ð*(‹餠¬ òq½V\U‘#\‰j h‡ß ðý%´öñ”ÆóJ×Jq[UÇáGµšYûÒ‰ºøk‡s’8jáH8”¯Q<U Å',"ּŊñžK ¥ÄTމCFöÆIÂÂQJˤš±Ðì±Ø4ÜM™åK”ÖãhLYFà-2mÑí. ýÓW2™ÝÅ 8—xž“†H—xdTóŠ0ލ)Õ±£ÃØ aë×c­«“?®â‡Q ÜÇ,↤ª"tàð¢ŠÃþg'ŸàìÒ?æô',+½O“犅‚Ðãí×¯Ò C&ÃUõd‰·®ß`=u4Û'Ù>˜R)Át’±´¸ÁÒÊ:Àg~”2è°rbÏüÌÏ!œeóî.·ï\ø‚F[SYM;¥œ9Â(a41÷i´äý„7°T¦d:?`4t{=¦GsLh)Š9F-d‹â¥5Bi¬' 4•)Q.A‡OYJs”ʰ¸²B{ÍÅSLiâµ#&…¤, ‡þþàwn0ÎE>ãäzm'ôÒ)¡Hå3ÕšS Vz â°À–†A¬0„y è4ÖhuNpvy…42¼x)gL)£ƒŒl>EICU¦gñ”Dsœ`§$¦•$h¯ÞºÂÖ e-=„PÇPmQ ¤B+¯>Ç‚4uLØ q¼õ…ÀY‰s÷  aï}œèz ²ö¢râ8þU|‹º{न·ÙŽÓ´òÑÚ¯Ç]YÁ`ÊÊI%}¬‘x>ÄÀ¸ f±Ð?*QvH7¦¼±ß¤´>N)|ßg6™ç%¡ç#¨M¿£À¾ÿ{âß³ø^ÄOÛ8èÃ®ÝØXx¡# 4‡ûŽ“Gxá7yëµ^ø‡ÿumí1H÷yíõ—xãÒÞ~å%:-ž^Ž,ÛÇkž!N  ‘Sƒ7™ƒô¢ƒqÅæp›»wq¥å‘Ç–È3Ãå×Þ¥µÐÀº‚ÍíË„‘G¤ë4¼…µu.~ý-ÂFÂdâÇLçRÖqä(Éh¸Gå,{w†hÑÀ¢8¢2ëåa°”eŽukrÊ"¥pŠ$ðÁNð¤@ A’Dä Ràœ ðC²Â “ˆÛ¸0âöö!ï^¾ÂùeMáõYŠOcÝ€l¢Ùºuƒó½gñ„ Ñ•D:À¹%×xô±„ÓÄæI*8wâXèõX[š1MK–Öq<æg?v‚†xˆ?ø£ß'Ë2”t`+š­ ´T‡tµi£§JIÂÀCÊ:¬HèÚzE YwB %(!ŽIhw ºú}‚±{$´C)}L5¨û¿ÖµÜ+*{,h“ÜË ?p¸ûÝD}qß+Dï|‡ãûè(>LíÆOÓ8èƒìqý#NïQša´ÁÂÚŒµ Ët~ ”&Ë>ÇþAU¼õÎ7xé忦d<²¿»ÍÙžÅH嵃½»D2boëN`Ê’ñ$c1Y¡Ó5ÜÌ_%t _iv¶¶i„ï¼õ6V–Üݺ†pË‹+ úI<`qi…ÒTŒ&C:ú.T+²4¨¦ t íNLVÍJ`*G }„+ŽwìëG‘§„Z€-Ñ¢$Ï'4ÚšùxFV͘æ)NXÑÑCkÃÜ’Îçx~ÎÎöó2dž>û‡„Vs"š·3’ÊbZh±Ac¡t’©;GÔê±Ô]aaå!.<£èµ5;׿Ƶù;´Ã%°õXd–MQ£)WnìQ”’££ ¯AÃiĦÌH§®Þ\zÏ2Ê!xºV&k!ï¯ !PÔã¥{^TB8°â¸;«ÇFîýE÷xéãBÇ@Q{„Â8Aå@:‹qê¸ðÊã­"y(ê®BÜߊʋ+)KÇd2­#X­&"¤“•ûŒ3‰%F()4Â&¸Ò’zMªJ0ÍÑé”Ô…¡èÛ‚_z—ÓMÚQESǵ•‡´gdBVÕ[nR¸oÙ>¶~< ýý¼¯ʺùnëÇŽ°8sN’æ†8è bp$H‡š“+‚—¿ù?áª5^zåefù˜ÞrùèˆñÔçÌéÇ8¿Ñ %@1§Ð$Ý. ™¢á`IÏè­Ÿamã,U~‡Ë K'=ÍÁÁ±p(ih¶ºt»Ïш4'VWø×ÿößÑ^Š`^±¹¹Ia ‚¨ÅÎî>R8º­ˆyVp4ÎAD¡baÕ„`*ï·‘®S¢äé”°ÙÄš%`> §ˆÅî:Œ1øTÂcïhÌÕ[‡ìg3†ÃÎoDt`:èáù™“-ß ‰{]VN|†Vc‰Ð—4““K=Â@c­¡ÈÈÇûŒû;LƇüÅ»WPAÈõÛwÁ‹Ñ^Zw Êpêü2NŸdxÔÇ$Ù|‚V)ÒQÄ{Öï8Œc IDAT‹ö5žªW]Eeq®v_ò=àD]Ìï™Öã'yÿ"5÷çFGÌT_¼ï›Ý„zìdŽoÐíñïÝï,¸{ÿÏIÂ8Àå9Â)Â@Òíô(ç{‡9Y6G˘½ƒ}¬LØHÒù”#¦xR!´fœîÑL4mð²Ô㯿öuÓŠ›oÞ⟜þa¨I‚&eiˆbÔŠ2¯°”õö•|õî ÆU[>ˆ˜êoÝýMçôPüEYXV–:íèï4¼€F3`8ÞDªËTù9vvú”®¢È+¯ÇúÚ ¦©åÚë»ôP¾Av¸só ©êÒßÞAöÚœXY¡ÕY`Ø¿C«¥9±Úcgë6¯Ý¸Â“g×QÂãh8 #éñܳÏñ—ýJ;§œÌ‡Ä‘¢( FÃ9­f‚µ(‹ðÖ»[à9"²ôðbm^—+\U"îA,X!‘ÊG‡ •É õ 2v Ɔ½;W¸üÖëtü!½ES*ç±·ÈzÇqöä A£Á¡‘¬oœCÙ9aç1מ♞aý¡§ð<ÍÎæUÖ–kÅ<Ÿ³{8à ?¥?š1›î÷Û`é.6(uIžo1Ùëãò TZâ Î?Å«—ö)«Œ h­Žu?TH÷~B¶Î½°P‡& 5Á¬$÷»ˆ{ !…_wÇ6èî}!KwLúÞÍÜ©¼ÿ¢}oôdîý=5ôÞø‰û¿ç¬¸ßc¨ GiJªŠã‘˜ÄØ’ùxÀú⓼úÆeö¿rƒáá€ÿèçÏóð©6¡V ÆCÚQA¤*3§Ì}Nõ.p°<Ç |ü ¡ªXY’Š ÏYŠ¢ÄéêXr|¸×™÷uV?úÅøïcóý>ßßf[ìÁñcgh7O²wó2–“YHfz'S†ýe®^0›KPk*¡%ï8z­6 ±Å©‡"ŒZ]N™1çâµ6Mü…˜Å…Vú4ân§rJx\¸prtÄ´Ji-¯°ÐlsçêFGz½%¶‡Ο:}ì^Z1+k'1EÉÑ`ÊÚJ —\~÷#áäJ‡ÇÏ9¼HQåFHTb¥Eú “ÌRº€Ì†LKÅë_ÿ:k=CyŒó€í­»4OúHgi5†œ?÷~Ó"ë4––Y^9Á]bçÆ4£Š¥µel@:q{ÿ+ï¼ÉE“sXt@–Hjk)Kž)ì"qÜ~û ÜV%qS3Ï3¿çâÍcN=±Áå·ÞÄVà÷Èéš`–ÎÖ"³û ëM¦c00EÍ> iA „RÇ YÆÔÀ ¥@¨÷ŠÏ½’”î»’‹÷¸‡{: w/–‘{Äö·Ë·‚Œ+О"eAUÕ´~ 0¡ ½°Bs¼ÏödÌöá.ãYÎhbˆº4› i6¤ÅøTÌ ‡’‹‹Ëô§?ì2™ÏPù!,NH¬0XJûT"¿®âØä½sø÷ ?IÈw'=…Ÿ°xùk[œ»°ÇÙÇ V—ÈÓ‚Ýí-öÇËܸ>gW±¸Ô¦Ñ)R‹É ѹë«'XÐ3gX\Zgr§ÇtPpé­«ÄçO°²! (k¢±*²ã jÅx6e=nóøcRhËõwßf<=àòÛo²µ¹GétÛâбºÖ%Žcf³çÊìí±S M5ÍΤÇlžá\…U–Òj¦©!ª`gpÄîєͽ·wlnÞ òœh®s¢·Î­v‡f¨Q.¤D¼ðñs´—ç`x‡'Ï?Fa$!"‹)Ó‚KwìŒ5ï\¿‚ˆ;Ì‹4(¤‡5‡ †{Ì&GPæøÂ"ÓœD[¾GKVÌKK"—XXY¥²ŠV»Ád|@ÕŽiÅ=’ K¥f8WaŠ?ð‘RcŒ!ô4îž"ÙXœ“ @HÔ{ìcuÐ6Çq¬Â Ò¼@H‡Ö’ ¬u"ŽZ8‡“ÇB9÷jâûy½Õ{c&ëêçvßÇ áÞ#·ʲ r¯ ÁÔ﬋xÔt,¬ÆÄcƒ ¡CòlÊð('-2*¿ÉdRR•SüfH7¨fÑðqÂ#VÉ‹z#Lk\YaŒCx¢Ðo)nõ˜ü!ìõ£ïç=}/ÁáòXìÁñw‹¬ðÙÚŸ!¼ˆk+H=æ#çÖyû­1q§‚=ËááãqJ —ÖÒ]Ù ½¼†Ù¿I»Pe3æ…@OøÌyæ‰ÿ1JoJ!A‹O4)´ÁO|ÖÝ:wß~‡dm[Û›œ\8Á‘Øä‰G7xéÕ—Ée/Ìʲ²¸‚çK’&“)vL#Ttª xÁ‹H/!g¼ŒÈèb˜pÔ¯8Ø?D‰Š3•äðÎ-´.0úˆÕ `²¼J³Ý£Ó;ÃêéÇ8³ñ›ï¾Å…g>Æ ×PN1J6ûìȲ9;›7™O¹ygQ~’LLÙ¼q aKL9Ca©ÒÊLýA‹ NÈÍ>nD€æ´—sû0£Ýnù:Jè®.3 kB‘ø!§ÖÖ¹³}ƒÊÄIHQ(eñ•D‘Ó/"Â|3Ĺ6ÎË©¦GUBj=z^ÉbX¢¢ˆ4¡„Ï^Õà›oíqç0ãŸïðt ©¬#9Õ\ #}ã '5ósuþˆ°ŽÊ¦(S¦Cσ²í9lUwRÔüˆ± Ǫn‡E U›ê……XSš}(Z8;¡!OÒö¶hE]ŽöOY$íÑkµq=¥²’h™Hv±•¡çP~IC9B&Ð))ÔØ6…ʼn¬%ð:äeA%çøÚC©Óq­¼k’ø‡Ù1ü°áÁñ#ÆÎéït!é>éóõ¯~ëïtÚMŽú3–WzdiE:룜3>‚ã|a|G³­Yu ’˜¢°8+‘Z“%EQЈ\³³;$KáÈ£ÕòY^ê°¼ÔæÂ¹SŒ%û»#ºM]›ÉU×bêJ”ˆ‘B㙘S+Œf9ÕÜà*q?Cs ÙQÆÒJ“$j¡×6Ž ‚ö,žåÙ¥Ç(gGN¤"+UZòÉç>ÂÁ`„«¦Jx!JXÖ–|Â`¡>ò8‹5^~õ¯x䩟a>[dFA::äÍ+ïp}s‡r6`çöeúӻبÊA‰ ÌœtZgj'\•Qå9¡!µ#l,°ºz–éd‚­faDe ¥E¬‘„ñ"‡C’XâlN³‘€›¡¤cx´Oøa“(öèÄ!Jפtoy B((Ë'4R[Ép®¹|}D(ƒÆCÉK'zì_½*Æ Iš¦xJ`ÀE·ðüв*ê.ÀAUY¤s¤óíç…¨÷tÎÖSžT˜"'Ï |žVXc0(\n»hŒ«]kÁŸ[!¤Â˜Šª²©5± ªÚxQ!YQR–Á0c–ú(ÓÁUŽù&UÛ”¤qÃÃ…U)“ù„Ãñ> J4ðE›@ÏÑá2Jùàyšâ…9IRœÄKš?ÕÝÄwë€Àƒã;À¢öX^ñœÀåCºI—*›óÜó'íQTðò‹Ì&ÐímòèGZ„É_·±Çªj)5ÎÖ Ýª(q(?Ç“‚A:§ð}f+aš ”ÖD•åE¶v¯PV˜¦9 ‹Kܸs•*/Ã6Aà‘‰9E9%/§”¥¢ÝhÓøÿÙ{Ï`Ëó³ÎïóÏùässè{;÷L÷ôôôDif„($‹1. ÊxÁeïºÖ.Û¬]6Þ²ßØûÊe¶X—½µ‹¯! $F£É¡g¦óíts>9ÿsð‹3Ò’A 4ôSu_œsêî©ÿy~Ï÷<éûÍ[lµë(zJ¤‚Œ]´É‚ Åα4YÄOË&He¶ö›do]g{'£éÝÁQc’$b%„ýy¹O¯[Ãë Ì 5CLLÓ$C ì üÉ­Cú~Œî”8ܯ‘³MtCCH=tU!Gˆ²F¿ÛÅ44D"Ó ×èPÊÉLU:~€©) ÂMÏ®<î/ȲŒã8ô†íqƒ6NALÇ\U¢‚hQÍYd]C<ü "tEa’TЉRa¬¿! H¢€*¨±€ªÚ(ª?–˜Txw²I•U¤,"vÓo+Ê ²@–f' ¤’@!W¤6¨¿»ˆ'e’ ÅñxÄõÝÝŒ4NIâ1­,ŸO¿Õëxw¼6ŽSÒtœaxƒþhˆ¬8(’„"Dˆ;Ð2 ™ÈÉÛ:¢“$)9§ˆ—)ÈYÀÔd•|)Ã)ºèxîIÛÓ$È¢(@Ór¨²F’$±™Mg’{O3‹ïÆ´Ñß„âß÷;Àݳ÷,£E"Á3Ïgذ|¢È~ãEÏ3QZâÚ•{ yŽ1;ïS)O!‘:BÌÆÚÚI&¥2Q GY¤`2º¡`I"Ù@Â|’ÄDe‚ `zjÇ™D•›loÕˆc/6ht|ëCÈFÃZ+¤ßï!©^k€i˜ }™˜Œ0KÐ È(T+ Ë^à :’ Ö¶žÇ4öïR¬à¹©àáN6É[2akÀdÅÁ—5œ\CÎPÇ,¨©D)Áh¼TæûX†Co8$Í4]BrE,PÔq"bÙEêÍŽ%c&ØÈé…>ÃÐGΗÆ÷ 7I§¾‹j¨@Š"J9²ÌÕk­1ón}»aÅq& Û9ÂÈ'MBDTu\´")£1’˜G)²šú‚ #‰*¦)àXQ!f%{’XˆÐÄñ½TdYS«„aH–Žù§ 9 ¿{À°Ý$H"Ò dEFÈ¢p¼ÿñ­l2!R9"Ë2‚,ARÆÛãaÐí“q™ A"‰c‚ÈC•eâpˆeM’ = eQ€ÀÛð+HšE¯#áû!‘#Š!$:²4A¯çâ˜2’šàŽZ˜¦F0JÐ •4 QD,U c #·ÄÚ½U^|ó÷4³øë¾ï††ø}»o‘_޹b“h˜x05]DÕRæçŽpõŸfcÈ}úýll×xé7Y»SæîŸÿî—]¿D㉣(‘cÐÅñöq·Ó"ÑK膂Œ¬™ˆbžQcÀÆN‡vÿ.7ÞÚÂóö ~áÿ+P sEÒh·¾ø¥7YZ"JBB\ŠÆÈ¡‘¤¢( ª2")aèÇc °M UÒIâôÛ|[¾ ¿;ŠšÄcåCI’AÇSɸßñ­Û8e<}…€,+dÙxJkL{.šê@¦¡ê9Ü F’24eŽnOAPe‚tˆ®®Qœ²P'rÈ_R)åžæKŸÛd~!àÑGªvJ„H¢ƒ,„a†ï‡¨†ŽnLpwgÈo}í*_ùæ›ïÙüNy¤îöûö½ôÍ?‘YXކ(º¼}éçÏ–Y­FD¦¦ ȤCüÈ#E„ÀÇvLb<œb×w9rô8ª˜c†¸aB·7„T@Sd:½Ö&Õ¤‡eÈ¥Œœ^$É4P´'pG~¿YJt»Ý±À’(ú#ŒŠ‚š%ÅHãŠ*Œ7A³‹æäbC·éuú¨å 9£Bì%är9‚XIJlî­mP̋ȉ†"Ë„á?‰ E³‘ s¼d˜JèfžÈÈDE‘):Eöö·uY0,‹4“É’Ò“Çq¢˜«a¤³sÙE%–ç8{ªD&ÄÈB†¢ZÔßß% B,Ý"gåð#YPÉ„YMIˆ8 “YÞÕƒxwT‰8ÉHÕ$‰0ŒPMIÖ „1(’@&ʤQé8 Š’Lœ$„Q4öYFe2â(akÍÑú(=×GPuêí‚j6A& ™[9y<¦Tm¤øÁ)žý踱έ •ë››<ö¾Cª—(È2B&2õ°Ô<™¨ ê*=_ÿ/ñ…?¸N;ß³RÉ}u¹¿:ÀÞ/E½e¨åå2Aátv ¼öRƒÂ¤ÉúÝ&o¼œÒlÊ8e™Ê„‡$ÑTYõÐÍ!­ýˆˆŒ8Mˆ³˜( IÈHoè¡+:R*!J&I"qé­›\¹¾M’h49³pŠæA—rn™Ãþ²¥…Þ˜ˆ>J±[Ûæä©sõŠ)Qoï¢Q’Ð÷}ý™ýý€GÎÍcj&“Å I¢›B?"!£à¨hjLœH$ÑxqÍ6 "/FLc2É#H:Á>º¡#Šå\VÏÅ’-ê^Qˆ²8Œqƒ”À IƒŒn§¦«ã{‘* €aÚ8yÓ”ÈF>%GÃPöšMLÛ&–tr9…vÃ@Õ E!IDAàÈâ"aª˜–Êää–>K|wD³ßezr’‰œˆlKD©†±²I&Xºƒ©åy4]D5D!Æ4M$iLSž¦é»½áÛÍhIÈ¢˜8 ‘AJß%ñË–f² Š‚¤IHš‚íhLOVI•¬V§ß’d"B<–ÖM… IÆ#´iJ– A„ ‰È’JÞÉ#! "VÞ&SªóN\È‘wòØ ÍÚÆ)FÓ%‚  Vß䨙"çž<Ç?ýoþ'ê= IÙ>Œyñ•m>ôøDs€¦Z¤©)aÌúö>Ï¿ú Í‘JlæîG‚°òÈ}{Àâ±Çr †&W^oÓí1©i7Žðâ‹Û¬EÌD£$Nr{k¬Š'g"‰¯"ë%FYJ0ò™ U!G#ÒˆÃ&z:VIˆGÂnÀêæ:·kܾˆ *Œ5Ê…2²Ã™°±{‰é™Y1²()"–äàu]’0%o¥ô„^;ÄQª¸O–F˜z•(n#Ë!…’Jè¾+ÐSrˆ³6–¡Ç*n€©åH¢ ш1!P¶R’Ñ 5¦þf#(ÓJÊó3Ø‹gyã¹ßæÈ¤ˆ/˜Ÿ¶ˆÕË‹¹µ¶3»D»ÈÌ| ;;†›m2l ä¬B5æ %“i ’¢ ¨’-0WÀõWivwÁœ@Õ¦°Œ5fòÇÇ2²ªH…L”òäyU•QTÈ’€L¬ %ò‚CQÉÏ!hR*ã8³øÁˆ4Èaª†º=$H*8ê*Q`㪊H}\/B¢ˆ‚D¢e¬5n©CŽŸžcw‡4L°îÐ%šó°æ§P¬”òDTÒH2¸/£ḋµ]òyUÊÖmâh„Ó‹xC’lˆß‰ ÓÉ-噪È서{d‘Xl‘Ÿ ˜>®ñÈ“üx+_BŸ,SÛk£«ZMŸRÙ¦×WÙ¸]$ñbÞ|þ%7‡È²eêzƉS‹üÎW^ç?vy)&‡$©‰(j¬íº¬×!É\”þˆðû(ÝÿA¯m¯2‹ûYÅ{7Ö{ðS‹ÔÍsûwûÔ›ëÄQ‘œœ`™ÛÛ›è9™4Ɉã ÔY[yõ­Á ¤Ó|Ñ`M5° Â~L½ñ¹Ï}ŽÕÍwV·ˆC©©<ª¥RP§‰ãFºQ“êB‘aÒg”ô°K9Fíaáä TUB5LYCQ}¢¤EuÂä°–Ðîî!£?Vôé‘’*»$¾N›dRLš¨²™ã1ßÔ&U$9Æ)NÐ:ìaÚËÇ’*CòÅš~È©Sï£çªÌMŸáüé9Üä%'!If)ŠØÖ’žGÎTLEa¶<¬?€|41a¶YÛ xàô %ÖÖ=Da©©xþ$*¾&&1²°€SIÅIT‘STLÐ,•Ñh™Ž®ˆœ²* ë‰Ú'ÁK Œ$#Ák’Yb©LoàÑî(åNáúP™½Ë©§Œ:=å.aäѪµÐÍi|Di™0 h);öéd.Ã~Ê‘%ƒÛ·PÓ \zÄqÆc'£Ù½Ë̼Á1]âàžGã_ÿÛ+Ò<Ï~¬ÏC'ÞO¡”¡%ÏӨñ9â/X\Zfæ„Ï«ßP8¬ï£Oì°tÊf·¶ÅÒ) AŒÙ[·© ÍÒ {[íþ6›%DÀt ü(ã_ïòæ›"2¼øÙ×iÔ9uì)ªêã|åËßà‰‡/R™–©ä Bw@ûà!QIe…XJ! ÞøÛß)h|·ÆsïÆ÷äe€AM…âtƒœU êÏSïÊš‰*ŽðQ K·ÉO•¹³ò6ÓΈ7^z‹ÄOÐ$‘$îñÐSD#‘R>ÇÅ 1·(OÄ,Ì*€¢Â¥+]ú£†£ç]Æš¬RÛÞDÉçpƒ±ð‘ß“2tÚmדIQȲ€á¨…®% ¸®O.g'}oEê&ES–‰h "²¢1;sQja”Y¬N€è¡sÜâݽŽSE5bü8evþn胒âGude޼5Ëd!ÇÊÆÉ?l!Õj‘VSdn¦‚­itÝ>‰—"È2‰"# :ÞKl[ô» š¤2êE´{]úƒ¢T&JMS¥Éå%‚(FHU]!Š‡èŽ€,I^Œf‡£çDÌÉ>»ƒ!ªÓô1Ë.Ìi¸òu®®%"“e“Té’[PY,ÞFÓB5‘[Û%n¼Ýgv©HÚŒ ¨L‘(cçO±\X#×ÉUf@‹)ÎZhÙ4ÇòpëÖ-^{çÎ<¸Ès_]GÈl2A£T9ÜÛägþƒ÷ñÕ/½Á䌉Pø]Ú¾C&™ &ؽ–0÷°I±ÒƥǞ!- ó;µ«7‹ÌÌ,ðû¯Þäñ‹?ÂåË·ùÜo¬2±xˆahl¾A£1@×m Ë¢Ùl“ )†nÏOÑo ôÚ>Õ¢Î}ô"o^®±QëóÄÃSÛðö¼ÌƒDDÕMüð~ðønå?~ÝwSÄè>H|ï34àÎåç› Ÿ‹±Õ"YÇ"§Œ•>ƒA€èXº‰ƨ¡ÂCd¾â vùÐ Q¨x.¢PÁ÷êHBžN‡½– ÅSFL[Ä¢ AŒ¢¦¨‚bÂÈ÷Ø88DÏ;x~Jìû$ñB¾DÐ̱fB”Š †>†¡!aÒqkŒF¹Ü4i’EQP% Š,â$buÈé a³°4ÉÌB•Qà357Ãüä,¾Û%TæççÑ“‰2Š4 W¶pý ³ÿÛMZ&?ò‹óçNc(%ºi»8Íמ»Aäjà/âEV®Õ ^¤ÙRëúå~Óë s¸zmÅ#Ó”+s î:žŸÒîv¸rÝeuíq:6‡žÏxìüûßü­Kìµ¶yð™ ]ùÿð܈ÌõîGŽ¿d_àÏ .jñ?oñï¿÷ý¬áû¯*Ù‘y-&Ky*Î ’$Ñè6©5\Œi™4˜¬äPãöA G³˜/ŠüâÏ|ˆƒµ—E2I¢ÝqÕuêûSô‚]~öÓ¿Ä‘#‹Ü¾õÛ{oâ{ ’q”««ûôâ¦lðÄ3§yá…«xžÁÀ;À2‹,Î/Pš6`an–(ô™®èö¶ðÝ¡g1]¹HßÛ%Viî–ÏÍãH IDAT)—«œz(ÆÐD&*S„É-2u„Ÿt¢<ó,’"J1ÞÈFH«hIJ>_¦·é6aè1;3A3ZGbͺLØSˆÕ9§DoWäö¾@­qîŒõõ€D4X^\À²Zû»1í!ùRåãe¢ì:º¬púLžj~–ƒ­õæÛ-—zËe¦4ÃÌQ8òÕÏw9=û,íÁƒÁ€ÅÅTU&"|ßãܹÙÜܤ׽A&Û¸J§“171EßÝ`zAgg}ˆ#õ¹ðt…­- ·1EDÈæv¡¯qö1 ÏóP•*‚,Ð:ÌñÂË—ñýaâ£È&ª¶ÃÅ‹çX>ñòK—øÄgÎrùR—^¸‡£Z¨šA¡Teàì×tû ƒA©©Ÿþ÷¦yøÜ£ôzCZ->ÿ¹ì«\xGW0ô›wS!äøi'WBQan°¹ê1êæp½++‡ˆ‚Ƈ>ü~Þxã*Ï~ø‡; ®^¾Ã°«ã»cRÅå£3ܽ{—ã‹yã•K„DÌ9Ëã§‹ü³ò$?æÖê6ÝŽ‡¬º?6¹„9ñtþ4îQX8@,‡”™íÄÀ–%ôB‡Ð@´2!Oeê€óÏåúµCŽŸ:O«ÝÇv"ÔB !‘‘Å6$%½–yÈB¦* ì®n£§›ÄŒøØ>CiøQ“v£Cct—$nÅ9Z=“ù™|íëkäm IqY8rŠaø6Ù0"Þ±PK’ÚÇQ ¶º‡´ãm„Ažz¿HÚ·è…ÄÔ`pñ»/¿Ê'?5‰¤K}`šÞ(¡Ñ”¹u³ÎÆÎ{û>{÷öÉ—M~zòXÅIñ©w;Ô=êûw×Û\»QÄõž~_Ba^çå/hî,sÛ[cî舓K9$¹M«$yîÝÙgoÏ#Œ†ÌÍ!ð#jmöö‡d† E ܾ#òȉYcvw$öV|öÚ¼qysS')qxãÅæž|Æ¢Û½)ÛÜ[osñé,ǧ׭‹Cƒ˜Q,óOþñ=æf—˜š>ÅÞN‡Þ®ÀðJ ݆8Å*±wÈÜÔ4?^Ä ž£X˜¢¶ß£WyꉧpƒM")`zÚâ#}ŠüÔ&õöu?cf©O»SçìW¿Ñ`õ–M¾P¦Ýnð¥/ÿ–ápëò>a˜²·ðÈ…óܾ{Yéö–—ø D)EmFí„ ?Dg€*†œ;6E&–Ñ­>™ÛFŠ šŒ”ecº1¹îÛ}ûË”¡ô‰£œ<±@.×`ºZejnmcZW¤YßäÓýbÑŒw1÷Ÿ{Š ç¡éµÙ÷ "­šÈ¿ø—_äüã'øÿé?Ç´Uòjˆ^€êÜ$ï¼³Ne¢r“cVÉä ¿ËÅ'Y¿[§ÛÔðÝaˆ¤œ8o’Žº­”—ž»ÌÍ•&ÿð=K¯½Éå7ÖÙ[Sxæ‡U íëÛwHb…ýõ™>z@Þ6x雇ˆÊk·wp{>C'àì#ÓÜX½„Y(Q1ªÔë)‘+3tcèºx£kÖ¢±æÑ ûø­2Å&ò%Jâz”ë—ïröÁgð|Õõm÷l i’·_¿ÁöA<ñAŒò>zy€nZ\{e€~þ1ºý‰8à QäÞN›ýÝ™*šøw®½Äg~fž{·Þ!œb§Õ¤ïÕPd‹À1U:ÆÄ”ÅÚæeÚƒœ¼;J´u¤å”úÀÖ .ü¸ÀÑ‚Du!cm3¢ÝŽéÇ!o¾u‡ü²HœÙ¼üÂ]ªå‹4ö,v¶7qýk}~â“G«‹\¾ñ&Ápµ­|ÿO#5¾ùHíI†ì“è`XGؼÓGÌöQUxîµMœepì|õ+*K§M>ðÙ‡¸so›ï3‘*¼òb +÷Š.³“Gi¯°xlލs–ë7ؼ9¤uPB2 ÛÂÈ4D¡…ïwé|,§È—®pöá9‚¨*;tš5ʹe„4O”Ä``ê:JÚGö$4]'ñ=41‡d8øÙM“ðâ=Ñpÿ†Ê8÷K)÷íoXœ9âóñOLc:áÛNøÈ±“t»]йs “„AƯýêkŒ†!~µ{múý>¿ÿ\ƒéÙ*µú@á7þß-¶ê-z×gPó1¾ïqâxý}ÓjF¥û ) û·]¼På¹çÞ —·ÙÜ» 0s´Í«/Häó›·C^y¹M©¢±±WÃ)ÈÔ$Þ¹ÜA´U}ÌeëšËö]‡Ù#ë[·xT>Ž]jÒìÚœz(â`7àêÎ]ÌñòkÝVŸåó«mµ›.½o‰Åé%úf“Ûß<¤0,sgÅÅrº,.•ñü„ƒQ̮ߥÞjòõ¯¤øƒ«<óÃ'Ù½Ûbko‡Fã1jÑA«¿ËÒ´Ä ÛãËŸ[gzâ4¿ûâ[(RŽn·KH†JŽéœ€ëŠüþsoáä-š»1¦Lj…œ¼à“‰)aož7^Þej¾‹Yn°¤IŒúsëÚeÜCèP¥QRçØ…ç%ãÞjŸË/©µºÈ’ɬ“Çx,â܉ ®§sïî6ß|mH¡P åF$RÀ±Åxë퀀+ì tûœ9ó?õó¶Åõ›E6kM¼žÁÌô®ÛDµÚ±ˆn³ï+ò™Ÿ–ÙØ8‚,—yý¥-ŽÕ0R…,)#yb™ÂþÆ"Ó‹§Ëã 2Þxm…/|é·±8±¸\ÄШµëÈZ•Ko÷9{:ÏìLÊhÐbØÏMÒ¨µ|ùãGyU¾…œÊ„Þ€îÀ¦Ÿ%§÷‘Ó”B" ˜ O"D'o¤ ú2¡¤@ôÝ?\÷â¾ý­‹ja–Ï~úçqr*¦¥Óï 1 UÕ cŸÀ ÐT‹ô³l¬ïpëÖ-êíñdÊý_üÏ4[5Ði|øCPÉ]çÊ›M:®ÇLuS6yú‰³rûmNŸ;à>dàyÄ®Á[o¬²³ÑæÑ'‰b—Ý&óËøCÍí6;k>~jÓè¬Ü0=gqéõMn^ ©Î½¹å.ýaÆ­[7‰¢c¼õZH·¹ÂÑs%Vïè„i̵Ë{´U*“yd nÝ< dNÒªÙÜ|¥GÞ°"o`•c2;ÏÊN“Ë+DC™É‰<ýQ‡Ÿ8ÁõÛ—i¶GXú"™2@Rú£!wWF¸CƒNL{‰ïìc¨ÇYwb¯ÊÁ–Ìɳ'Hc7¾Ðr·èÖ`j*å©g/rù­ Μ9Ç¢ëµiÖ:쓼öòMv6V¹øä$¢ÚasÕäêÛ>­þ—xðôy¾ò…×1”Y: F~¹ùIÖVÛèz‰{÷lò!Å©ÿÏÿq‡=Âg¶DÐÑmÖyo¾ùÏ<û×aØJøÊÖ˜š,pþÉ“\{çEtQ&oG|íko€ÖI888 TUá?ýÿs’Ôgàv¸}¼® j›œÜcuý&qœ!%¾òù,Îåæk8Æ£ÚÇNÌ6¶;}ÊÊEe%¨ñêïx~ÂÿÜÃT¦ª¼ze³r–{÷.¡ê ܸ¹ÂÔô¬\»‚ël®î ‹%’ŠËµ«7KOÌ‘F%úÝÁžÊol¡VÊÄAÀAmE‘¹~u“(‘É—4Êù˜SgÎréÒMÈ š6’hQœ´ ¤A„nÈÌÎ;ÔöÖVz ¼ ry‹ƒzŸ,] ‰[|â³K¨¥+…î¤Ü[‰QŸn»‰¨ˆ\zåI’9{Öd/fbb‚z­ÎsÏ=O!_QÄõ#¶w¶¸s·…(U9÷ô4‹G2Ú5U/01¡ðò«Ûx£ $hu}D1äþ'ÿ;ûÔ)ê>Qdsìik#VonS¬ÐoYœè"«klï¬òø“cëK¼òÚ«4cúý˜sOž£PyÐ>οü¿¿JuzŽÖÁ€æA Q±Ùín£Šÿð‡øïù—™(8H€×©ÑïǤ¨è–‚ï·éøôã S›âÖî!Aà¢Ê)N^F× üäO|ÝvØ­ïý…`ñW9„Öã? <îË}û›ƒ?ìwR&ùúÝŸ6êüGÀâÇ?ý#ÌL”pòQ˜‘ )¶£“!2i’3-d2’ ]'KRlÓA F£QR)VɈùð3'bâDaÌ2*kÞpˆ¦i ÜAàE)Ýþ6ýÀ[Û·ÙÝÛafzž(­Ñi…üÜ/ä]Ò4¥ÑÚæÞÚvv¶Ø¼³In&ÇòÆFâ)Ã:‡ë;<ö€Èñù:3G?K4šæ×þÏ·9Ü¹Žª ìîQ*)Jl]=äÌü£|måMFÃוyã­î¬ô)Ζé7ûøƒº9ã(I¤0™yúýG8ñÀ<ÍáC×§Z ÙèÒ©HŠˆ˜ ,,g«)Aè’+Άn0äÉÌsóòÔši°¹RÅ”:ùBØäáON3;WbiYâÉ÷ÇÔÚ+línÑsÛô\°¤ úý…óË<9s„¯qÙ¹øÆ×¯röôyN<$ã% Ž.Ÿà¥o\%ŒSRd³.3ò"¢X@7l SÁÎILT«Ü»³†eрəVwðŽÁÂì2k›[¤ˆJâ!ªb JaÒë (Wl$i‚¯~yÏ ™[*1»dÑh´È—ÊG½ÕäË_ýO>³ÈäœN­±IMÜâÔÙ2W.WYÛn#¤ s y^xþ&²¤Óm iÖˆ¢CËøÐG>ÈOýÄóÑ|„Šc‘%!D– ó'rŒ†I’ kÕwµÅë›·…-þÛÿáïqåò5^~~ÇWé|¼hÄÑ3yÖ7¶¹½RgrÒ¦<¡0Tyçò=êÍ>îÐd§v›¹¹9._Úf0ª#ˆ^r‡O~´ÄÉjxÝœ8v²ˆ(ÌH² YRh¶ú(‚‚nØÄAH"ËŒz!»í…ü4^/ä 3œ87Í+”ì¸ôÚÍN«¨!«*aÑô:øAˆ$(ø¡j)¤YÆÀ8óPž³ç¦xûR›­Õ.š^Â‰ä »ÛVmB ¹¯¿¶Êö†ˆc« $|å+¿ÍóÏíAd"H!¡Ÿ01iñc?Ê/ýý_DEº7oÐŒÒ4ED %•8а Í48¬5ˆâ ÝÌ!…,Ë"C& TÝDÕ5 KŰìï¨ÿðiOÿM€¿(Sùßï>°ü݉?ï»ÿ«\Ê¿ùo~‡ÝƒaèE ss3äòÓ3U¦Ë=l+‡ªêäòER Ûé#**†aе)Ë´Ûm` $¾ï¢é2‚êS¯× âˆ\ÁÁ÷}Çbvf ;—Ãs‡¾„eÛŒ\ÐÐUƒÐ˘(UˆËÓL/-#É)Aà‘e®ë¢(®7"cFk³3"½NŸ§ÎÙ޺ũÊÇ9ö“`YUl;Çç?€ (ò˜â»qØ £ø¼õæ êw¶¸q} S9fŠWê×ø?û¡òæ«·82ó #/"B6¶7Qô<-7a"Y2ˆÓ”ÍHb™Àqáá“,©ríí†a1·hqså2ù|ž¥åˆým~ýWŸ'ôLb¿ŒiZôš6ÍfD«™‰™St›s 󬬼EìO3=y”ÝCd%!"#ˆzÄŨg`™,½€&N -²±²²‹$äÑRw ¡šÂò9‹~w@ŤZ†"i ûŠ<âÕZ\z³†¦Ê¬$Ï#Kº£Óïw°Ã,Ịb é2¡/1 pJy]BÞ ¾?`ÔS!Ó(Uj{äY+Ók:”'<‘K¯½E!w„É…7™æH¼Ç¿H·%píívÞ ä”™¨J”Ë Ÿÿâo/è´{D ÌÌÍÓív±dK×H¢˜0ò14ÉUUÉåu¢ O ¸AŒi;tzm %ÊÒ¿Rãú§ñ߯¿"ÿ´ºôýÒ×ß^ûË~—ß ÍÙ³Mƒíý=!£˜+âù1¢ñö¥È" ‚ xw{¶G·ß£Z¤R© è"¾ërdñ(¦Šc™x^L§=qœ( ç8w0dskwx—(RÌÍ33;…¡©ª†?"¢#„TA’ÃBOHS Ë!‹rN4Q˜zpQñ]5™å3³»Û¤*z¸®Ëpà¡iv Ï¡Ê2Õ2K–À3ÿþ#8Î ¸C’Â(èóÔÊ QºË?36é [ôüÅó»[žç•oÞÆó=CÄy@ŠªP͈QÔç`× 5DuQ ÐM~ÈÕw¶hÔ}:í.Ó#ÞÿCn¯¿DuúS¼þê=žý¡âz=Vïݦ¶wÛVX^Îe]|WdÔ-¡ :õÚ$ Ñ4ƒ0i²½óúKµ¢4`åÖ6²8ãÒ<ì [ m/Ðiô9vò4›ëwÉ;ž7Àw}YÀd覌ºD^Â/ýgŸ Pí³»×ç•›Ì/ËlÞmƒƒ$P,Ø\m É#7ñ¦‘;׺ìm}“OýÄ“ÌL0­ˆuŸ¥“mª“U®¯¼À­›C&& uŽŸœ#oÍ ø½ z]YVé„}…B©Š#©$QF¯Îh8"ŒS¶.‚ Q{ÄYL¯ß!ð#$IA×u„,"N|*º…ª™tz#RQÂ04£!ª¬àùÑ÷䀾—Àòge%ßég½,wm¬gQÐð“I'>A% Žã@¦Ä#LÇ¢4Qeéø TUŲ &&&PUÃÐ!S˜š¨`ÚÂX†4Ò ÉD(ŽÑ-“ ÐŒ§O#"D©C§™Ñ8<… ¢ÛòQd‹¹Õш҈¨ïc™8Ö玄Eˆ”2q ¢" ª&'—Ž"q⣙nYMH¢‰ŒÀ 9lïE{‡«¸î6†8ÍúÝ5²$crZ ðuŠE‡åòJYEÍ; ýCw05Ó3½^‡Hj3eÖî²±y‹Úþï¼µËÔÔÇâÑ*ŠbðêׯpúÁi$1`o«FíPc¿¶C¥˜vRq‚Z³¦«L”Kì¬#g6·®Ÿ©å.Q S¯'ô‚!‘§!‹d5æÄòqîÞZ¥~¸M–%$qŠ$i8ŽÂ'>þIêû./½þ{œÂâé-27=bý^‡gŸý ‰ðÍfêLŽ%³Êë¯_!DÉ@S¼à]Ý üËÔÙÝßF•‹¤iƒý©c4›uV®¸¢Bª" )qš¡˜:‹úiAàèßöyä}Ï%1I’à ;¸îv¯K§Þ¡gŸQo€ï‰Ãˆœ¥£È*ù|žŸýÈC ÊŠIÓ”HÛ¶IÒ” Š ’˜Ãf‹ù̧qÈÕ+ì×Vxäñi:ý â&?ñì9º]“¯= ¯1$­LÒŒ¨Õ&&'ÙZ¿‡c;HRL»5BÊräM(å\žzü}¼véDIå¡'D¥ÊþA„ D¤<~·ªêhºÈt9Á_(±½W§²X@S-ü~Š­&lí¼†3©ð~å1æ…Tê´»;,igY»»ÆT¹ÇäÝq÷n“#‹yv6†@x¾‹­•ñ½„O?sI‘¸³²Çìô1~ôS Ä£„G.”™˜Ìøê¿½Áឈdí!,óÐ…Ji—͘Õ²bu%LUDˆÒÐgл>iš ç ÒpHúĺŽ;’+ñ}EHF¤IÂd©‚ &ã^G·‹içU;o2 @~à@àÏ›Zù^ÞwCàé>¨ü€€Å<ù,Š ú²(a9ËÆq†}’,$%4M#“DâtL &Q’0•ÍÈD‰Œ±Èηþ¾UO©¤ð­k²ŒŒQÉçóär6KKK(І7ré¶Úܽ·†; H"¶=f]œC7 ¢(Âu#Dt]'Ͳ1ñUš&@’’ðnY¿í ÿNuKQ4Dy, ”·feqüšf$QHEdqB§ßf0Ñït¹·µÏÈõ¢,Ëp÷ö¨+˜¦‰¡é ÎØy96G¾X úÐO£j#·NŽúÂH¤ßKŒbêqAÊh÷ÚìîÕX½»ËÄÑ3ˆRÂöÖ*ºÅ'>ÃìT‘‰©?òq®^¿Ny" WÌñÂKu.œ8ù ÎͲ³qˆ“K´Ë'ò\xßû‡äIN;Ïù‹sÜ[ÿN?UçêüÞoI ý:ï–¨Ì×É…c“ŸLmó¯þ¯ÿ…Çÿ!ú˜†…mæ©Õ†(šI«Õ¦PÈ#) È- •i>õ“ñÊ+op÷n™ù…ôæéÞ¡RŽ™ž6Ù:èòÅs‰fçÛ7öè52ËÖI¢p¬µ‘×ð‚‘’"£è1"I‘"†!¶iRÈ9dcÉ×,#ö=$!Ãs=âxìcßjŠ{#—$޹þþv>ŸÿÈÞ«Ê_ôÿþºÙÉ}Pù>‹_ùå_A×4EAQƀᘃ4&ñCTI&ŸÏcå]CÓ4Ìÿ¿½ký±+9êuÏœ;/=»›}d7­³›D! IH øˆ!BHü üAüˆ/Hð)¢ˆDIäIžÖŽwõÚ¾3kÏxfî½|_çø¸»ºª»ª»Ï¹UÒh×3÷žGw½»êW[Ûpyo¶6§°··{{{°¹¹ íô"‚˜ŸÂÖÖ\ºt vwwakkëñõ/*®NÏΡm/Æ€ŸŸÂ|>‡år mÛÂÖV óå6··à•×^…ƒk¯CÛÌŽŽàÖ­[pûömø—¯~>ðÒKðÆoÀÁÁìmï@ÓlÀÙñC8™Ÿ]DB“ ,¿®+žL&“9,–ÅbOŒÅd2)ll,`~úø@°™@Ó\D.“i ÓfËÍ%|ðùàÅósXÎð™ÉœŸŸÃ–Ð4 œÌ@ÛlÀƒ£‹þ€û÷îÂí{ïÁÉ;¿„ét W¶.fAÿäÇ?…½½=¸ví\Ù¿ »{[ðhyŸzù#°·¿ Í´Í­Kðèx›[°»»³û·ápxÿÀò æ‹S˜înÂéb¯¼ô5xùùÛ𓟾ôG_†ýàWð‹Ÿ¿ûè'áätÓéûð¹ßûxpü¼úÊ.|fù*|þ³_„;w¶ß†ùîMøÏÿx¾ÿ­Ëp|ÿeø³¿üCøþ·ÿþñï¯ÃÇöá­ÿ,a Ïí½ ßøú㜞.àÁâ¢øàè݇ðü‹XžL>ýéOÀ/þçð‘À_ýõÃýwásŸýøÞ÷Þ‚o|ë6üòÆ}¸üÜŠñ?-oÀ[×Átò*œÌ m¦pxç.]jáäø!Ý¿'goÂy3…öÒlïì@Ó.& 8;Ãôüv7·àÊÎ%˜Oæpv~Ï?¿'ï?€KÛ[°½9…L`wç Àd¶··áþl Ó鄆ªJ j+q ͵Ö4×§aPbßÇ ”±ü IDAT€±xçh[§[°±qa$.míB»½ ç—wàåKpx÷,NÏà–pºœÃb~~ñ°³íæ6L7[ØÞÙÝ]Øœn¬ÒLçË å}vGGGpttôX!o@³±Óé&4ͯ£‹#,–s˜Ïí4°1™ÀÉÉÉ㠟Ë/¿/¼ø"|âS¿ ï¼{Þ¾y¾óïÀí[oÇ^zÞ¼ö:|ø ØÙ»Û[ÛÍ–0åò‚aÚU´\ B®yA@sÁˆ[“­‹±£ËÇéµÉâ)£2¸X\\«mÚǑҚ¦…ãå6§hwöà•kÛðÚ‡? Ëù9œŸŸCç§ïÁÙÙ~ãó¿ ç§ ¸{÷.lLðö½·áç¿ø1l¾û_ðÂK—aÙ,ÎÞxó°½{Þ›?‚GÞ‡÷œÁë¯_ƒG' ØÞ½ ‹“ ¸¼ÙÂ_|ñÏa±Ü€?ùbGNàáW߃ãã3¸²· 'gïÀ¯îß…­S˜ŸÜ…÷Þ¹ gÇðÍo~Þ{t>ð¡9<?ûá߃Ùwáþàk_¿¯¼ò"|û[?‚ÿÚ~ës°½sf÷îÀáá1ÏacwÎÏv÷¶áäø‹sØ],Ï÷á§?<„is ×ü¿ðÛ¿¿ßûé?Ãõÿ;å|šÉópýg7á㟜¾ð¸}÷W°»y ޞܗ_z®^ý(üéW¾¯ð¸öêassNÍáäôb-OÎÂùù)¼{ûüà»ß†Ó³S¸ýþû¼·œÃ•çöáôì&‹‹(óôô šæ°„Ó³÷ááÉ#xnº‹¥[™t«AR)wtÒW¨³Çià£%ªòŸÍfpxx|—Ùlæ|?Ê}ú× ¹Ö@ŠVü?3·FFpãÆ ¸zõê“ß¼ylaŒŒ`rãÆååË—mºÑÚÒr¹„££#xíµ×.RÓb±€[·nɇ‘ÉÇL––È32222 PcK`dddd¢öæÍ›fY˜mi(##T>ì€ÛÈè1Ù·‘Y¬„ÄÒ•Ve…¾rÂÃÃC888¸€·éÐêß&Fc–•\tËo]¿k®\¹bÂ`4JâÌÂöaü›|U6|]ÿ.~omÉŒÖAŒŒŒž• ÎYœUC™¡0z‚L`d†ÂGY™¡0²õ2Cä‹,ŒFç›â32ò‚PDáû» £Ñ óÓ ­ÑzÈI YÊhT^“‘­Qš¡°4”Ѩ…À”‘‘ß@ø EHnº7ca´¶aµ‘Ñ:;Qýó WÏE÷ÿÍX ÞPXTadä7¾¼}Cr¼ìÌÂh”^ÓØîkdÄåQ,õäC+À¨±°ÞÈ N+|œØf&#£š Fè™EèbÝ9ÔFF9… TÚiª¶’®Œtå!Æ[«i}Æ#+>¥³Ï+þoCÖ„ó7##Mæ¯÷VÏà{–nÔc²bTƒÁO†W‘uÓý‡‘‘Špdcd4$C‘êè¯"‹¦ûÐC˜°­£¡è:S}X.—Ïüå4!Cêµ`G¾¼+f™ÌxÝP¬œ©®1è ªKL6Œ4e#t±âSI>l\÷Œ4„¡&þr^ûŒÄP«¦ÌÀ G60C Í{è·Ë³ëþÛ˜ÊhìÑDˆB OFFZ|GM;ISãUh?”‘Š! éžÑ0å¤ï=uÀíà ñyO& ưCíÊuuÀ×ï¯ðÉÉ…ÉFWoJ`E—7¥³?+þo±²ÂÈÅ¡r< Ù ïV vŸÓõìf(L6|ç¹.~¡Ê 'õ¤š†òõYtëÌpQ‹BÅýÊ»¡*Ø®Gç«2Ä3ýÒj¬ãŸSY§Qñ„9KOÒP!«æ2&f(b•lO\Š7W¥å£a]Üë)TgŠÊ·šO”geA”û¢ _(ed†‚z=mC‘CQû"$ÎùŸÑ8" Ɉ•ZËãœg~ª)OÊ ™¡ (Ö¼$y á€+xXjÎh¸†B‚ß\MŸ!CË71ßk\Ë “ŒÆ+’û<†rRjêÕ÷޾CÏÒ ®&Ï鼜*/”3az@r6åùWú‹ÒÍÏ…Ý:½‡MP˜²Ëì>X˜!óf|Ç\pæ®ÃÏ †É+?šàD±X4PºƒCÞÒYŠ÷áö÷ ˆ«Üh8†‚+ !Á¢ëöYPŒ ¶~¾Ô…ÉÅ0 •ß]{Måiª³&!k®ç™Íf°¿¿ÿ4 %ŸJiBÂ'ËRAõ ©NìÔÔ•†z®&UX°$Èú ,Ú»³àƒÅÁJÎ ˆp؆"e– µ9USn8Ñ‹Xé,¥YÏŒG½ÂP˾ÄD·Cyn3Ô Îá²k–ä^K4ý¹ì;è¤<ß‹bé& SÊŒDý^“†Ç’:¡+W¢>NÎ#$¤¡ê0 .Ĩ¼¡ :ǾŸîç]©FidnÚ)T¸ÎàN©åí.VWn4^C¡á9•ä—3!¸·]¨¡Fu ?úœ É–Mpd÷A9œÆŒåcë†!¥šx‡Rk“ã6ƒQ·{ØìÛséòrjÔAu仟kBá²ë¢®¶tÃõ–¡„ðà|†Z9×w‡ÿ¦Î?6D™½¢¦†BkÍìë+sîwC|Îá ‰È´¡Z)ŸÅñû%%CÅu55…÷ÒÈ·šüã+ÊÀP<û€šªõ]s°(C1¼ëk ””­Šî½‘…Ïs 5”¤(ëL–¡p)OŠPiaøk­Çþþþ3 €OÎákªWi”f($ùŸj¨g ±±1òÉ‘/ç¤<,'z°R]Ãf(ðÏKDrÏØ×P©…&›ƒ_f³+]ê‹À%¢‹,ä É…øÌ—²5PºÒ€‘©×yføQW4¼NŠ1f݈B¢>?öó¡™Óµïù*²®â ¥e1Έo(¸½?ÜRÛ~#%Žß''5’k5ÆWKñ®ÌPä19îë»Lii $Ù˜ÚMeIÃA˜¡p§‰R‹t\… Øï©F +3÷ý®59k¨uõCO=I_ cCõÒRJF9•y¥gÄ*¶¦Zï2$§ SÔ¡(ƒ[ŶÚßÛþÞ…ËùžW+3àû\«éݹ^j5 Ç?ÝP”^;Îsô½ìÔù”°?w„å“ vœ2†5ö¹ÆÅS" Ž#Ëåç§ŒóÔRí”ýUqµOW{ä å]å–‚’QPš@ÔkcÐÃçh0â®i÷LO+Jî_ß•>±J©ôˆ"†Ç\i'Ÿ§ö¨Qf®ç†Ä ñY“b‰$Ɔ:Â×9ª¨ÍxÆ ×u$'xqÔ󗘹,œœý£·d,NTì~»@#±´iè`›Sì#Á³ÜhÄ·ïMN•ZQ"1ÏË!‚‘Úà¡(Ž!Î/‘ö^]2âêsêCHp×®¯Ô†Í"í Pú8óÕ5x­´ÞzR:ûp)Ø7åÍ9¼¤qÍCcbò’š©§Ú@Ør¯A·©[åG­½çXc$Ô/#¡8]åîµ:W±ç ’†ˆ‚s'é•û¤)SÑÿLJë¹Kyû®Ï 釞z*1¡Ps=säZµ”Zw8˜¯yª?È+fÞ¸ëº}åíúÜ:ö_h rÍÜÑYš+r—âê¾Gà »¹Ÿ§”²iCM“z’ìÐ íSÍãNsíe=¨§¡è ´/¡önh'‚â”Æb3'(é§±OxlR6÷• ¥ªüà(ÆÔzâ!E9<ö!x™%ªùbÖÏ5&•¢ä±ˆœšáîkÍ)ZÉÏcUz±á5驦>ç nû„ÄW+ì³È®PÝuÀæ ëÇf×h(†ÖÈ•²ë¦i©i#—LPÀ±ŠßÁ6–Â]çÔ“¦¡Ð~žÜŽ ;²à. ¥: „\ë+•Õ0’åš¹Þ:(ƒÚ#Cn9dèÜ׈ªÛïËžo0Sª2®1ò¥œ¸À§®uÄR~)ë›û[ZOvxEw–xî(l(©yÜZŠ8/g”$÷^Ú uCË»‡†éPgtÁ±ÊÙÇ"Ñ#B‰¤G›j®Q í-¦äC9ØÜºëÎaXD!DØ zmå©5ŒX‡+*C@n( gd±ÄêŠ}9Ú{BÞÞGBqRÞµT3l HЇ*À™ÏQâ=)M{¾Ù”hD#S*+vl€”ë}%Ëõ5Œz©gjºÂ@ 1F«%Ì‹wn#hËS•Ù77ÙÕÜå+‰Í){†G½vMÎTÌ4N“w4\†Áê˜so7„.ƃ|UO®h°[S«â‰i[³NLGx" ß< Ê"ú„!#¹àB)—u2Ò83ë*@ýÈÛ·¶¾™®Š"mçÊu?ÊáñXFSº±%ß‘m ]~žJC¥æSs ¬a-4)oL8K9Þa0©|ä:Óóͱà*pmƒákXóý¸þ>„è‚z.§9c¬ÎÔŠÿÛЂûò°.¸GÃxãŒ<Åb]2¥õœÚ£fkIå–ŽzÖAWÇMÈJb“¼0F±Ô‡Œ±¯y(eã‚·}Ó‹®MéRðÌ‚2¨Äói§ÚR"(#uEl¨>Ÿöÿ_CV|À…TÇŠÓ±«Øµ EêÀ"#º~kûÂÀ±Î®ÎTÍûгI CjJNÊ;4Ê9v©ëLù¢;—rt!¸`A$ß)v.uŒ ¥ä´äÂä$3µZß§šòf³)¥RU±ä˜Vjd#±9&õÑþþ~p'µšP:‡_2⤀xJ],ÓîjÝKŠÞm8i­õrÏ”×i]<¡˜A?“ÉÄ™fŠÝ{_}Ž3¼¡öD„¾cgu:Ž/…¯—Ëå“Ⱥé{NÚ«ƤL]) ##A£áù­"oŸM}F Ï8TÚJ#¯És¡Z›¡3¡±Ø}í,b<´R æRC SmjŸ\dÂf’ŽF|…¾ô”æ>‡ õ±†;WZ-”b£ü¤8‘®ê)îùɘ•¾p"Ñþþ%UC a¡BÂ’¢8R…Ü E£“šª UC…<4íKwùîIQò¾tl¨˜¤`E]Ju°—0¸pnJ ¾Ô3P8†Æ E½Î„«‚†[¤Ðw¦8{¨™f”N!Q£Éh·¦f(òD ®u÷éÝÆ—"ѪڈeÞZò©)ßÍÝ85&Ï1û½šÒˆ!‡.gÄk$\˜Zë”b’4îÒ{øLJ*íS£’ÎÉøÜ4ErJ<ŹҰ~Äž7ÇÞ–p¨$› }}Leø DN Êàð£1œYÔ¢ü8uøën(r¯I,” Ä®Öu«)J÷ĉu8äέ—»÷k)ð:Xk*@u³¸ym3ú8_©é ßÜùR†.WN}·˜ÏqgS¬»3¥m¸±û5¦ð¿ÅL¥Ë=9Ðß‹~?‹TO1òýj!­> Ž2‰ñýƒTÛßë1ªCö#eŸ6>Æ«ÅêÕâÆŠ~˜½®ás‰=ôuP§ÉqÚq«µd…Åæð~±ó9ßÀ¨šu˘" £ À3VÕ”—\¸nMEå ÅsÍ‹Ç*æÎLÉÆYØh̳™ÁÐÝ›þ~t£ÀÙlûûûOG)•(CÁmÒ†OÇÂ<£rûØ7Üýåkæ¬î¢L“4fÔ¨€ÓÏTkfA;"(e}Ð*]ì´&…)×!\K½Öäb¤Ãð®µ×@ î;5”Es*Šr 5£€“Ö†OU›ƒ«©«|Íx.j¨JNgg¨¢Êq6ß" ]!£ngßá`ÿY¤å„kSß‹Gq¦rÈo rW2åæë_á(4Ô›`Þñª¸iØïb ôw oÞå»uK`„”7 å½ksðÖ9’ê¬4œA!çPŒlF%må~ëÂS£_JE{f»Ï8a HR1Y¹øø Q›Â¹abÆBº¬iÊ8ÈXü›u40ëöÞ®ª9(îXaœ¯ü;52 y¼ë¦¬}ï]ëz´1›èÂÏ¹ÐØ9%Jý'Ç3|ìŠuì†Â·g.eœó98ÕQ)¨œ²ðT3Fƒ’#âËf,°šèœÃw×ïSš K*·1*ÖÚ `ªPb¥´9 ÇCM™1QR‰1ò¨Ý®xöðððÙ>‹¾„„aL˜-v1N/Íõ¹”C¾Ðd¹þ}´y+÷À.£aêNšÝW$ÒÆ C.ë£tMKm¢n×½f!Èki¡£4éiÏ¿]›Ò5-ÙgF¥Þ5K9«u ÎË ¡# ”ê*ÉÔ—Ñð=áþ!¶«¸BKf$ùZâ~>‰u1 Cr&cž³I¹p©0§Ç¨=!ÊBøñ{t«îð#lû(žýj(I>ë_S) 7LŽQy÷úYÁ}´”/QÒçô9ÕK¾úó\‡á& e='Í9-X£S×`H{¡Ô§z k"Ì‘Z1gªläMMÛ¶œ —˜=,q? oÎh˜†Cóúýó5Í> Ésæ<£úe‚›j¸Âã9Ôš‚0aÈïÅŒùý|FCë~9‘lÍ™®3#E-õE\¡´v”Á…ô ¥¡8›j¸22cÔå×á®&'­EI1ÄD)¡†]ã½ñ#ò™Eÿ¦®0F3'»nV܈Ç#%q¡\†Â%7’F£¤ƒf4¼ˆEb_ÑIyÏ!‡–°’È¥ÖÏAWd©µã)ÏA‰<5æi¸"|‰Ôp͇ҡ‰{FxQƒ/#ÄYǖ¹A%kÓ©ß-¥ ]àŒën(¨ØF®Üz çÅ•ªÕJÑúú|´+—J)h8cì(ÜÚiþsÉŠd!D Of¬j)bMﱟ¿õ!;Öª€mJmï}Æ!Ǻíïï³fyç4!ï1d¼¤¢’<±îÑD¨Úçh†f”P×µ}ÈR)Š÷é2(Cð>Œ€Íèµ=#vv‘#ECñ>]%§g¼®Š^c ¹ÃÜR¨YyN¥B*jˆU&¡Ö0tLJ?f¦sîT§Ã[Ó8`P’ʨ„^8û˜÷çî)(³ÿ9Êú·)/kƒ±éc¾ß§Î—ÐN¬SØ,1Ë`¨©‚Üg|”Î\‰ùµ{ÜCAŠ¢–ÀÆ“’­–ËŒÚÐÏ¡†&ÜQX)†¡¦ÂrwÆçX %0C¡…âŠ)W_Q«´jšÎFM…•‡ Áƒ”TaNëëXʳ4¥”@ì}cùBÍuÃ×iMJU´Qî«-»Z½™È®I @[ÛËÇz8R0ÌëÈÈ9q¾Ö¥—$wET*ª¬ÜšKxû¹"½n9r(zkkÙxª¡p•–œ·Q:ŒªGºÎPŒf¯ …Ÿ]BO1 Íµ9š¸ZR §9*8Æ©y ­£–ðùò¯ý¿•8€›¬ Š7&#QÃÚøð©\[瑬œfD®ó:„µô=7¶.ͱ멅JÌrTVh)ºZKSPHs+ì’ϪQP¨ÿçB`Ðô†sC©»ŒkÿGkß5ù3ÔÈLŠ,\­õÝE+1Ï‚;óØ<_^äÐß÷”Ïäãsï¿Kúò"y&Ãm–+}2„("6ëÀJÍ¥9©CN±ÅÙn1¥œ €Zþ'U—ÌezNž8—¢¤~/¢û›tóW Ì5V6šC úKÚ`øäÏe¸¨] CгöR<“RüгžÒÍÃ1c°¶ŸãÊ,°ƒ1Ÿ hvªj2tQv:µ\2˜MbRrÆ¥QO}ÎK³,—áÒ–É”ÙÒ‡±©ßãF`Ü5•Ú‡”†<輕¼±F”‘Ó{rº)´> lΧS{K8!~iªá±NìÜÈ©ND©F;,b£Êï%ÒRÔs…\ûÞbXº«ØHf½brœT%$1ž¶”CòÜÝCMߟ´·_âÌP;u¤QºËí–N­2ÓJûqe1»±ºw½Ž†¡[á9ø2×`¡¡:”tP¿áÉœ=ãš{* yñý¿cÐðcÌr´¡PŠÐ'éh.Òм3ÍÈ3 XžÚwˆ‹¼J SînWJMº+¢æ1nš†rŠI)ÕéÅ>†C‡¥b±µ£Ìe×pÆ4ÐZŽç„… ,GIäžö§JûcÌ$@LsAÝB‡ŸZSÂR•ƒ¦w§1tËg€|F‹sÿFH"ê sâÞkXä" û1.KF»Ñ^+Á¼¹ÂÌ1„r©k)ÍíRÞ…šj dé=”ðì4K3©|…EP¹²Rל¨¢tƒ‚ªúޤЦ(ízb©dH©&lý5Ö(Å@Ht¬S )rõ¹¤¤£|ÏB9èvE’T†ùŒ½®t¤ÈI£Rû°$×RùC¢cm”«Ï¥Íq7ŒÚg*j4Áé›ÈYIäãɾ Ÿ`g%¹ÎÕ|¥‘XŠ3”Žòy~X:!tNBQ69ÓM±J,¶iÓçôæ8o )v©õ 5b3b÷½)É<\F ¾ÖhRŒdûÇUé‘ÚïÐWêûÿRk•#jŠñBCŠ »o.œ!îý¨% 1NH)¹ 6^bräk†”Ãëƒòý Ì5µ©!=žÃµ‰! ç!f‰("ôÞ˜ éôQ©3ÄG.Ï)7Ò07_`¼îS@xþ!µƒÚ=¯™>*Ü‹Ý;'“Dn$-¶s3Åc¬ Uc‚Ÿäûi+Ó\ƒs\‘¥óVë™|^kêá¯/q¼i <5ÒQÔ½—L•ˆ$ŸÝ§CbŸ§}À¾—¨qÆŸ‹vÔ‰IDATjþkޤCÇ!g•„¤%åŽ}eÏ©€+­­äs)JN‰xêž×ºÔþ®VÿQË}ÈP÷"y3Öª—2(”f¶!| в¤*uÉqx|PÿTÜ©ô°¦‚¥4³ùÞŠ0P»ÐPÔ©ú@¢¦åxL¡‡¢F¡ëpqükPˆ’ Ê¥TJ­= äÿ1p6W˜c}|^>%åú/w©i(mÅÇmŠ4|<Û€7'Îõ~¡k.OФ¡bó¦1ñCê‡Ð`j)l-k”{¡Ï/ÑFÝ j\ß)ÁŠÔêÉÍ‘c{’‰Z Eîi„¾LÅØˆ‹X¯›Êؾù®±%ÒKZ›®Ý‰:$¢(Š…YƒóõPR´¡ù2¥f»P&ó¥`‚i# ‰¨Pê>~‘N‘µR/"™â)•bÒÂh‘4"ëHfŠ¢vCklr;î³ä †þyÉ  ©¨ÕšI‚Á¶ÒÊ‹[ÝQ"ŠfÞ% ÉP8³¦†îßÒÆ@óÀ¹/µPpÒÏ1©3Ê™•ft/q\ƒ>Óà—Fúf1‹$]CM9@”ª¡4ɸº£SŸ!Ô´5FÏ«¦Ô\ì!sªÖmFL}vJs¦+âêf¦~ße|ד@%ˆ}÷¡GàÔÔ$˜R8G± ‘R‚Áe ™Arß3µÌº&xm)pò‰Urõ'vRª1¸Œ±9¹šðb"À”gkJ.¢D'·ô&P»±»?ˆ cð¾K¡œ8VR{A”tŠ(+O‘Û#óîCp®j’í#ÝøJc“CÓì3±‹¡kÍ«‰ñJxNÔý‰YÓýý}ö3r1„°µ£(},­"…Ý­DtýÔšW“l–ˆ¼©ûD8›ÍÂi¨\µÝ!4ÎÔ ¥$æ2¤~OZ‡ À# )Ýô‡˜ÚŠ%‘§þPÚHÂ¥~OÚ‰*cŒ3 Ó “jä^¹Œ«ú‹G…x–ލ´ŠÖ¹LÍ”âR‚)†Ù-p™XèjtºÆzÅDMÔu—Œ4‡êLIêß½ÚÜ %¥Ê*uúUIFH™Z&™~Ð[«5™û^šå‹ÚãCS#!zÕœ©—”Îí”4º&2³Öd>î{Å覛“ •­ˆ¥fÇåýbyoj©&çàÖw8,¹æÜ3ÜŽ¯JÏŠæDÞ1ëUs”ìËž`禃I)Yö¥§Ry®‘¬šC*ïYRƨ赕VUšE*Ô"ˆ˜ÃgÅ:S¡tI‰¢ ig*¦©´ôY¡ßKœù΋0Â"ê„ÄÐú»þÖJ-l¨ò#wý{-áµEÊ”·Øgã\ƒº¯mvtÌ…šÓrñi ¾”TÊS2U™Òç"»"áLq®AÝÇçćë%í$p U¿)1%…ã›×AAÀäRªÇƒž'p§z¤œÈ‚;ü…2‹7G˜ê+-æx‹>/Ê {×ç°ïb÷”èŒêÉõ¯ÊU­Ã–ãSx…;<Œ2˺7±Á5-d(|ïâó¨):»?†˜KmäbÛ¹Œ™;'ùîÙæÀT¥®‰ëIs½ L(BÊÞÅDÜ`îØÅý%…£¤R>—Ò7Ròð<6ÍærC½4²jèÌ(d r:5:W¨±å1HÜÀS¡›±q‹œ¹œÕBÙåz¡Éd)}ÏØõ辇ϰq<ň?1øtÎÁ¢ïóùŒÌßäð=—·(‘-—§9ö±ëÑ}Ÿaãd²‹”C O†âaQFbÊÊåyh iáÐP^7·bÉ÷†Öš«Øj‹ b)§Dè”Ñ£˜²rñplßKè=8ƒù/¡XcGÆbkÍuŒ‹E± sp¨%ÀÅÀ×RT±a!Ɖ½wŽ%T*ÍüÚ³R:åS*ô4ÊK¹å®547ryÓŠž8ΖF«+*ÃÎ^\÷o56¿EЇû]éñ…>#ÇíÎ-5[i‚åŸS0“¸çg‡‡‡¢wX4A+­¬S<ÔØïJ¿õ9.º)!·qôÍšO5j˜1p™z#‹ÒÜ–94XÚXix°X…UÎh-wÈ3r4'íïï‹Þ3¶Û?9qÏB4# ÃXLÙåŒÖrèÂèß籈’rýD±`c¥”gè°0T:˜;ÂÒØ¯c­=á0u/K5|† 8%ÏÜŠŸÜò:ïIgQƒÁˆ­¶¢¼sõOè¾íÊsŠåM Y¥<ð°ÍÚg %%ö™Pã—«yK“gg³\¹rUε9QX^šêL•œyÂ9ÿÊýl9ߘ³•~5^lƒcÿ3-U ±TÏ ×Й™¢ô‡T~û¹:½CFØw¤öûððpcad´NtãÆ ¸zõê“ß¼ylaŒŒàÿÌŸG×ðÿíäIEND®B`‚pyclustering-0.10.1.2/docs/img/fcps_cluster_analysis.png000066400000000000000000003320161375753423500233150ustar00rootroot00000000000000‰PNG  IHDR¡hg­"¿sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+ÿ•IDATx^ì½ ¼eGUç¿;ét'Ýé¿s×Y·jï}Ωsî¾·÷ïöê½ëµjÕªUUk×~œ5XØ»woñøÇ?¾8ꨣŠ=–÷Ýw_ñ¥/}©xá _XlÞ¼¹¸óÎ;‹Þ>{t ½öè2zûìÑexû,Þ÷¾÷-„øžzêa— ·ÏžºJ½öÔeêí³§.“ìsÍ'?ùÉ…sÏ=g´ø®ïú®69®¸âŠâú믄&G.> k2õ:ªÇþýû‹×¼æ5E°Ëâ™Ï|fñ©O}ªÈeŸ9õr󇢌 ë힥N-ë>Pï|gqŽ÷×oØP—^Z¯~õ q|äÔ].^¹ù ²]»Šâß(ŠG=ª(^ÿúñTÖ5ÍkMé6œsÎõIÚr‡V™ºº¦£YÚ§GLojƒMóù¾ðÂÊL­¹Ú4Ï[i›7We*ú®2,"eÓ+Z³¦:~øÂÂYg-,œ|r<êS]¶þ‘þ‰ehƒºr.mêúêʸ´,mkoÁ÷χ‡~xp6rñ]“©×Q7[ÖY´ýP”¬„vÏ SËzãEq÷ÝEÉ%ËðÈ©»\¼fÁ‡ ãÛn«Žã¢‹:šbz»ó·‹3ΨÎI×^[·ß^ßùÎÅràž{ª£@Úe—ž}£e”F¹«¯.Š“O®âÖ¬y¸¸ÿ~ê-Šo~³(Þýîªl•VÉûªWÅé§Å 7Å—¿\_ûZ•f+zå•£2Ú¶ôO,CÔ•siS×G^”É< % ¹ëšYÐ'=éIƒ³é‹èšL½ŽºÜ²Î¢í‡¢Œ`%´{V˜ZVœ°â–\Xy OœºËÅkµò9y-ðsþùŸŸ4â<âÿÈáã¨ë"Òöì©?`¯™|™Ÿø‰¢8ûì¢tnå žw^Q¬]KŽ'•e~Ôg?»XÞäyË[Šâƒ¬ü*€Óš¼®¹fp˜wÿL]ÊòW ,—íeuB{ôèÑ£Ç2A+>«3ƱòÎa'c5ÕxbE5ëtà¼=ð@u.‡sp]TÂ^‘f7ß?|1Í–p.åK]tQµÛùÐC‹Nl /yu”K½rZSøú×W‰xožpÇÕ ýÁüÁÁÙtÈÅtM¦^GÝ@nYgÑöCQF°Ú=+L,++¦v<Âêüƒ¬Ò8 Äkõ9u—‹Wn>¨†[°ÜÎ…t;¶-º¨£å:«v«6lÚT9“˜!×CÜ ·×EÖÑÄ}Å+Ó8r-¾ÔÍ7/úVª/…|t3ð¬³*Ùê€cÛ8œwÿ”õ!ĤcØ*™#OðúA^Bšb®˜9Z曣9‹èšL½Žêáí1§}ZäÔÈÍŠ2‚®·{–6:±¬7²néÀžP½T ·/xƒ·5ÆDNÝå╃ªy ߿0ª+iíÚöïdtMG³´Ï:,êñ@yä%¡&Hÿ1]¾|´H¼<Ä‹E˜tWÕ#^vò|¨/ÅÛy-röumã8ðÖ·.ŽaŽmÒBõ0þS¼ÂùOœ®ž–ðö˜Õ ݲeËàl:äâº&S¯£zx{ÌiŸ9õr󇢌 ë힥N$«xýú…-gžY-<6žU{ÌÅ%§îrñš–*¨Öâ-åõ•¨ j»wMG³´Ï:x½NãÇPVoÍLj´uëôÆû–%釶ø¦ü¢\‹×b6ðR9ñ€pv-²õµ FY[6lÈ{ÅãÀÏ–W8ß’JË oYÐ\Fž‹èšL½ŽêyL ]çEA×Û ¿YÙèD<ض õ[*ù°°-nU4æâ’£MB.^ÓòY\‹é·*œÚk£®®éó˜CcÀäN9å–”OÕ‹}T‘>¯ä gôÈ#o1s}êÉÇS<”QÎc6ÀвˆêÐ2j ßÀ„¡Ýòæ7·rV[²)^áü–G=*O= ðö˜Õ íÑcZx{ìí³G×Ð9õ;¡lëh!M+ôŒ—•T ]6ë(NsfV:gŸ Ë¶¾šíÝ~ÇIô}Á3g“§R(ëëò&<½Þ/„à[ ˜¤;+Ô¤å¦E¯œõÔÀÛcÿv|=z¬dðí™^OÖ[°¤ñaDÿVH%8xpp2Àúõ½ºrw]ìËA©w_ˆçݘO|bñ3Jxj_øBõmÐë®+ ~n\/é]ޔ痗Ž>º*ÛT<}š#¾ ŸZ´}ûÜ+ÄÞÖŠ´\ßì¬ã•³ž1Ð;¡=zôè±Ò±cÇâʬג‹ £^SîQªCŸèÑ7!ñ pbìÇÍqzzLLðŠ+š}5ë§ñýP}ê ÐO”Á„ù©MœQùoö» ?ô¡Ñ0u_pÁÒ7â½ð–_xÓMEù3 ðoŸkÜyP‘JY§¯kÈꄾ›Ÿ*È€\|@×dêuÔ ä–um?e+¡Ý³B.Yßý—¹t÷…ð˜È©»lm›’Ï¢ßðî¡ÿ ÿ€2}ܼ­oÐEÍ ˜”ýªÇ“O~wy„øî*Ÿ¼â{žÖÁ÷_ âhUûýP ë*òi§Tø×ÿúÝKL êþð‡«Un(/r°szÄÕwGõ U—d#ýCÎ$ß’ò;š¾°uVà®»F ®Ü’ú¼@B*mŒ2­ëÊŒ¬Nè§?ýéÁÙtÈÅtM¦^GÝ@nYgÑöCQF°Ú=+L,+‹¡ÙÞûôþa|÷eLäÔ].^ÓòÁOÀ_8öØO—GûøÇW·Eu4àŸØk9Žÿïÿ}ºt<õíU™¥||6û“œüÒå—W΢źu•ÓÈíwv>êc·Såÿûÿtí/ êfgõ°àñ¼ð…•Ïø˜ÇÅÿüŸ‹NªQàÛ&_lØ?6Á«f|+,££1ÅXÆ R.Z_‹rµñ ’Öª®Y +-÷è¼=ööÙ£kè¤ò2Ñ!×cÔaß±/¾¬duÍË>ѺE>Ò0BÒ©/WGäRåšêõ¤oÀúröMx_—•£„Ï`_þóoAÕ5b–i“”uiàí±&´G=Vذ·Ë´ÓÂ[MìÊpÏ’ûšì¾ÔÝ*<à›ÌÑnö *îj×În‚êjÿ8$?iw”uÛ›£5A[Ž_J²à–½Ê‘‡¼ç±ü¼@Æ®©@“ Žz @`ç“>?óÌAÄúyOú[HÉQÂ7BÏè΃Òb˜WÚ$e@]Ú,0««¤IpÓŸÞ´púÏœ^íyCÞ»dŸ=z€e·Q¶qR;œ6Md¿5TWv•"Öd¿Ù£,}KRùV¢ºæiŸÒ¥ôbÃ>ÍBi|Iú¥×ñ Ý~3T™ÇÄù<›ä±e8oËA6̨>ÉOʉÏà!#QZ¬ð<Ó&)êÒ¦„·ÇÎ8¡8›'_qòBñúbaÓ¶M ›~|SyN\ïˆ:ðöØûìÑCXveqõ ‰°àÓD¬¦±t[v•"ÖdÖVëüØtÝ®M•í:–Û>Çõ_Rùñíü'n!=2áJL²Ž©åɹú„íŽ(¿Ì£°Ý}«SW×t4Kûlz*н¥þ éÍê£ÕqìnvÅg‘èâéÅaÞÇËùb}ždú¶~ê‹åõ¤›S÷O¬aÕp‡‰êóunœv\os¿ŸrM«ËgA:·ïu_ù9Ê©íoé¯x{œ…}ÆnóôXøo—_¾ðþ3Ï\xÿ¿ü— :ï¼,Žè-±#:-fm£µ`¨[`”[­}þCuê>=æ45ñè–Õ>Ð|ŽèM¤x«Otn@ÎqD†(çyyÂiõÏtz‚/¤ú&ÔiȈOë~ö j*è+k[΂¼Rf ±tÎSrÖ¥e†·Ç¹:¡)Çg´Í®g )'toÙÃÛ£Â'‡±eË–:çœsöìÙS渥@šÇ¶mÛ.¾x—[›á½eá­o=0ÈU᪫®ZرcÇ TáŽ;î(ùîß¿SaçÎ Û·o„*ä×ó£ œ?úU‰›ãÈT‡®ñ]’ÉÛcNûg{Ê#Wäì!7Ï• #ÈÁ“Oí~^qÊ)å‘ј¥6¶½å´çѶÆÞ˜?…œý›‹×8|êÔÕ†ù师˧-rðš¥}¶oºbîµ:³H阹ٗ³›ˆô'áG?zÏ0÷¥¬“é/&,û¬©'k7Ñþ!1ed1Œ‘?ZŸo$á6¨«7œï©°m׆)àí1«ÊBpí®glw´  ÏÓb\^)¬V> K2y{ÌiŸv ®Y³5› rö‡›çJäàÉŽ'Ï€â|>í˜c²9 `–6šl;ƫٞ .nëÙg/®ì¬¶‡6zÅ¥ü±•Þ gÿæâÕ–O]9?úè­Ñf«œŽ¨Ð“Ý íšŽfiŸm0nR:&ÞÃç%l룯u€£7y “€áaÞ$K²mÖhÚ eþh}”I9“M¨©·œ3ÆiÄðö8÷“nÞEÌÝ>§„Õy“9úþñy˜ÛIÙ;Ý5$ümz{ ß×p1Y–´B2oËî„‚ºÌ¶ð>Á~ ýëÕïý ðA>NÞyEqXðlp#­§ GýÆ<ýwõÕÕo;Ü{oÑGV2Eáa1‹4pÄÕÑ#U®Žß¤i¹1ë«$v"sÜn¯ÛÙ$Þ>WºöG׎„Iï±2àíqÖö٣ǸXe‹'µÕDœ½·¨<*c·—„º´U5QMã‰R/%ûráº]¸®`^ö‰´ëhI/üØ[ëö±LTæjo©sT|Œüs›ð§Œ/Ç­õºÛëù‘I2Ö‘•q"Ô ŸaiVXŽ„…T¹:~“¦e€·Ç¡šã8ÏxÆ3¡ ðÞpú†…â5£¡>¹bK>¹ræÓÏ\8õGO]xÚ Ÿ6àP}rå¹[Ÿ;âȾãßQÊ OÇP¾Lv±pä¿{ô˜s³Q¿ÃâIN&G»;¢~×0¶ªEŽ|~\Á  ݆ijLaïìX"Í—¶Ž®`nö™ú°º#Ü^—¶ÏÆr #€W#ª4.<vä«_½ðB“2ÈoÇ`lL®2x{Ìú‰¦O~ò“ƒ³ 7~ìÆâkw­<çH8†~°üœÒ¾¿ÝW\ö¼ËгÖ5Hi‡ºz¼L“bµò]”iÖÈ-ë,Ú~(ÊVB»g…¡¬|åþû«s°víàd€Ã/Ї®¾5ôŠWÅ?X•á;5{÷Ÿä;D_ùÊb¾[ÃwpÈÃwtøžNÈWÜsOQlÞ\oyKÅWiCÞœºËÅ+ÆÇ6k úð³?`ÏžJàka©¸1,⣲öÓM|ÂGŸó¤‰¯°Xç'—¤MŠœú^.|ÿ÷rÉg®Ú@ý%3µ}†WÆÀLI·h£³Ï~¶â}þÔ§VÃð9§}û?Ïe‘¬‹ŒÀ°¬!W§ òc€ãÍ7„?¹cGu>,›íå¼JòoÔ¥v(9nÚVýÞûš×¯îˆBì„ÆÞÌ«CÝN踼RX­|@—dòö˜Ó>-rêäæEA×Û=KÊêwP´=Öœ˜4»£ˆ·^—ä‰ñ…´ãٵɩ»\¼b|"¢áÓØõ¢¹âãÓQ1ªÖíxKq¾ÕØ6mRäÐÑ,í³ hƒÌiÒ<ß'ìˆÆx·aÖÆKâÍðXB”õuöHö­Àï`ržΗs;¡[ÎMHÕ3 ¯V+Ð%™¼=æ´O‹œú¹ùCQFÐõvÏÒF‡²úÅÉ. þ6=a·‚òi.WݢݗÔâãêÌ©»\¼b|êÔŹu(Qqâ+ëÔ9’&,–;¸$mRäÐÑ,í³ Æmƒô×íÒ§M«ÿ6·ë‰g¨øk8•¡ŽºG6@²mÞ`·Y˜p{¾Rªo`hüA}³ªN‰àíq.oÇ )GQñÓ<:I¹݃·ÇyÚgm0e`Å„ü‚@X^GÂâìJ«•5EvÑáè=‚‚:ѽßî}_‡Äûê)G¨kêš‹}fzKùEÒ-zé˜8õ%âñhâ IŽ”Ó[ k0Çf`:àSõø9Bi3€·Ç¹9¡8ˆ©[æ )݃t9®ã”ëÑmx{œ—}öèÑ3·Q»"ú•Yˆ-TŠc´+jlçÂQ9¹+V51•X•Ú¼Äyu¥º¢k˜¹}f„×3a ëÛézKà\}*ò}ës ⨳é"¥u Q%1<Ú=)R¼½ìÌ9ëuðö87'‡GQÄòv÷Ò§NÁ:¬‡¿áðÖåztÞçeŸ=z´ÅÌm´nA³`¡ÐâfÏ}y>çsDYyWh¾ÖYœm‡C#ù¼vM6ÍRª+º„™ÛgF¤ú€£w !o²ô©6ñü¦vxp„d|ÍÚŠäh ¤‹O!&tNP¿ X½goYߎÓ›Þ48[ Þz?ySõ–ئõ›Šû¸¿|#þÚ?¸¶x矽s$}Ãg6”áìÛð/<\¾æðòœò¾\Lã`µò]”iÖÈ-ë,Ú~(ÊVB»g…RVÿFíYgÅg¤^Í.Š+¯¬H¯†}t1l1¯þ¾øÅEñªWUç¼Uxýûê««sxyþäÔ].^u|ìËÆwß] Ž7¤õö5ø¹Ÿ{“}¹,+‡7±ycUØËͨìøãßSÝDXI¶šÂ8mžO?}ñÍw™6o©7>}øáª>Þ¤',0ldîðŽ?ýÓ‹öÁ‡(y¤êo½‘C²m±†ÿö»5²ÜØÓi§Uç¹€\v€ìo:¸á†êKsDV'ôÔSOœ-ťϹ´xË÷¿¥8ýÄÓ‹õG¬/î~ ê}}Rɦ¿äé/)Ã)X‡•ã+¾çe9Êûru2ƒÕÊtQ¦Y#·¬³hû¡(#X ížJYí‚Æ§•ø^Œýö¨ó¶>ÿùbØbö7X™YXvî Wø hÅ÷üÈ©»\¼êøØ5ç1å@ÒÌ<µÖÁ¤ðÓׯ_üŠ•]»¥º»î:5¦º‰°’l5…qÛ€N­_dMÛã‚ 'Ðg›6Uõáhâxú‚a#‡’ãç>·È—ã}÷UçðÀùMõgmÛ|C€s*—™e3{êË^6H˜1B½§þÂ/ŒÊ>/,ÇV½½{Ž“°½UC›<=V¼=.‡}öèQ‡™Ù(·Å¸ßév™¿=§û‘ö÷õ‹Jœs;ÍÞ^;묊¿¿™Š¨ÃߺëRâ)5xuÎuë5öX¬-ïï¤*cLu6}¹03ûŒ ®½“¦¡wÝb§Ÿè#û\¨ï/›_w“áMØ“øÐŸäÓû{²›—pm_Ö5¦ù|>l‘;m’2 .mJx{œ»*ç1õ&<áþE£CÞçmŸ=z4a&6Êd/Ï✸T¼Ê°P°š*ÒíÊlWpåó«°ˆ8ñö<;„&ñ{RðΆœ¥ù*'õ‰(§4ê´ª#lËú:牙Øgu:ž$#:V¿Ö9”¶œOW9ÕáÓ¨ƒ²µ![†°Òl]Ca3‹©Oó…Û¦åà9IP—–Þçþ‰¦&ÇT/A„=(×ï‚®Nx{Tøä0øP°¥sÎ9gaÏž=e>aïÞ½Ñ oÛ¶ma×®]ƒPx“÷Àƒ˜ W]uÕÂŽ;¡ wÜqG™wÿþýƒ˜ ;wî\ؾ}û To»‘wß¾}ƒ˜ »wï^¸ä’K¡ElݺuâvÜô §üæ- g>oËÂ[ÿç…Óÿ²ŠjaÅ_óWw,l8wËÂÏþùÒv<÷Ƕ”Ÿg;@ûƒ<”ÅÖdƒçŸ~~ +é¶ÀcW À¬¢Wê$x;\üˆN«ðøHýþSOùmù¶ÎË…-ä?øŽw,lÙ°aaŸâ´;´¡Ô ùLüÖ C—úvQ¼ƒ¶,{ìhßnÚ´;Ä_2È3löÂÙgo i{†ñí T}p~”¶çtWyÎZ\ÕI_“÷@/:ꨫN8aÇHÜi§ÍÞFeŸl4eŸ çÂÀì†DX7Íú=> ç0ö^xRÖ_0¨œ³i€£ç3™rzùË á C4a|š-YµBœÒ´BkQ²ðégµÈÇ’/˹¶{ [ç`ò!<%rõ|¼“`ÅóÍÂAQàhTáýÃ<–äÐ(/k0#Hµ—6Ôé"–æýž¦4tOŸ“N}ô“í7ž@ñŽ©ÊIÊxçVé6#a0ì2©–d,¾BÛ´•ãoRže¤¶á R&Ú6Ë/¼=fuB¹³ð;–8”ú¤RíNè©iGµ#káeš«•è’LÞsÚ§ENýÜü@OœD9žžp$í±¤glY<7„cºyßÒø2ía×8¢ËÑîq‘›ßÌl4LöìzWW ÂZŒb°ék×.ýÙÎTYâ¨Ï×ÉyX¸J>~›¹ú>ñʦq´Î"GÛtOÊÇÏ={ìhŽ‹åå!þu~晋í²é“ ‡ŽffŸÄÚ«6Ôé§q”ßCZsôilò«ï‰—þÅ“þó(ŽdЧ'x@>ŒôL`j Q•HUhÑ”fx–óò5•óiœ[Ù|9WfIÛRuM oYPn£~ÇÒ~TGÔïp ”Ûüo6ËyGÕó9²V¦i°Zù€.Éäí1§}ZäÔÈͤxâ′[s=ÉÝø»w,Imü¸sX á ¦0ÏvOŠÜüfi£Yd «0·æƒP£Û8ã",@wœvZyÌ\ý >Z'iž Ž1'Äî’©9/yI&ÄúƒêŠ©ÂËËÓ9t4KûlƒIÛP§?›ÆÑöÙñÇ/ÖG:¿NkÓ!ïƒy–°(¶mŒ­3jlˆ_ ;®¹f9|#á™Rp@Ûko3ûD“ý–'Ç›?sóÈ·=?û÷æƒ^|béꋯN~r P~óÑ›‹óþÅye=|g4…\Ÿ¼X­|@eš5rË:‹¶[žïürQœñWEqÑç‹âÚàaÜþí¢øŸ‰gm,Š“¨Î9¾bsQl^[ž˜–ñ¨Ã«|ƒÏêྚïæÍºÝ90 ³ƒïÁœqFqêG>2ˆhÀ ÿÈwd.º¨(ލ:þT}«æ©Oï»–/ŸmùÒ—²}¶%W?ˆbñE¾@e?½Cø¯XüF$Ÿa:òÈÑÏ,Ѽ½{Gå!¿>jAÞš¯X•ò4åi‹a« ˜´ êϘ¹Ù´ê³Lƒ„€‡ªô¯>xè¡ê“¸|ÁÌ~¢Ó~9ɃO;}üã•ç8êû£Ñ¶!ߨ´ŸIkúh j߉ yê£5H˜¶‘(Œ¡ÖèrÙ^V'ÔÂËóåg¿|$\÷1zÏÛ®»m‰гÉÇíï¼çÎâþï/ö~nïÈï{ôX-ÀÙ<"L„q@åxî sÓ׬ò æÈ°îÞœÆÇ¬ ñàÜÿHQRâ‰EqöÙEñáW+ð‡>Tû÷Wy¿úÕf~¸rt±O1âwóÝmOp0\°É)øþ£ä8®1È~·2å_´ÉÓ#è#¾Ý*ÈÁ´}€ãxX˜ÈRß…‡>Çyá…E±6\¤ âámª1#œ9 É6…åp’g€™9¡8úø<ÇþÛ–Gv0ï¹ÿžâšÿzÍØŽ£Ý]½ûþ»—|ðÞþg\yFï öXQÀñüPp6ƒ;Qú‹ÁÆŽ'ë¦.òÝÅ~ ÒqV?]œÔƒÁù„ÇÝáX‡›CÍKO ãŒ9Ë0‡Ï•W¥ ÖIî1%Æ]xl~vMتÑÖ `×ïŠ+Ú9”ãÊÑh­õ¿vC¼ß ºæšêÜú 8§8"© ã˜:íFt.¤G;°cíõíûó½îºÅß| ¬þâH˜2ôûõ×–…¿ü7íž×Â:|­ $Ûƒ-d«0 ^wJ,¼QÏ Yз½ímƒ³ ±M~®óàËÝÌ+ïʨƒø²7¼,ê<ÚÝU~úsÓºê2'¶³JYvHoÿXžRß¶IÑ5> ‹2͹eÍÉï÷‚OQâ·+ž8’›ÌH="8ˆÜ^Õà6{k øÅ€ÃËn«ÑMf×Ü÷+n¯ÒÏþã$ßô¶â”¿s×_Ui9Ðå¾É Mú,ƒâmü¶ »(ØsÒíýȆ-æ¾$»£vgS¼¸}oË—cèÎÊ0rôUoÞü¶¨øÝøãlÛ&Ù]³o}«Jcm~ÚÓÞVú ì˜>ëYõMùÅÉÅ™Á‘Õ¯¤rܸ±j—÷Aà5®º:k«-A[Sý3 ¤CoªÖç£ Û8õ„ ؃×öíUø'~¢ §ÊúÇjû'V`\PÖò6¶ðsáž{ªùcF!¶“ÂùÛ~æg–å.HV'ôÞ{ïœÅÁn¥v/»™~gñO?÷§ÑÛìvwõºW^W\÷ªë¢ÏŽRæŠ\Q횆ù7µS:šÚÖ]ãº(Ó¬‘[ÖœüŽÒ.ä·yÚÌŠâ¸à|rûüêÇźA|# ¿Øm½qàHÂ×:¾§óÊ/V»¬Cž_y Ú}õ»¥“¢Ë}“ LòºõÍ‚€wž{Ï=·Zˆl:žŽ¼âÞýîjA±`qyÜãªcðº†-Öî¨vDYqÅ—Û÷ ‹ÎPwVžšüu˜¶$Â׿~ïìï€sÔŽ'Ц0x تÒÎ:ëÞÒg©¦©Nœ[øìÝ[Ûºhy€|•W]´Õ–P›cý3 ¬½©BÚɤ•Ÿ8®éì®'çvƒ^Ö&xz…¼m|ȱú¦þ*$çaÉbÔ…âphí|€b„p~¯æŸ6kÌóÍ9Þdß´mSùf;´éÇ7-y»Ý‚ióå›Ë¸¦·àûö<ß娿-úÝ€·ÇyÚçrBo¼s„üêöíu¾ç©Ï&Õ}¦©-Åø¾1ºÆäkCÈÙæû¢+YlÔ¿¹Jðæ*ç¼ÉjÓÛå<_½®W}ýkã¢XYÂB]Úœ•©y"Ô|›&Ô5-V>Eöåã:ž³Fûœ¹Ûìù‰Ð³¾†€9óæ::WœlA/©Û´:óÏ [iLŽNÅÄÏ1EJ&!&ïŒàíqfÏ„¦°~Ýúbãºå³¡ìfÚLào¹sû~œ—ìs£ áoíak—ì”öèÑ%°{¨8‚ 7W/v$yÈ^»­].’O©Î/ Gû&<å¶°w××…òºÝ®·çO?²(ÞrÚ"_ðñ»C£@«Þ‚—˜ÔŽ\·çW%ØÂñÏ~iÇ‚-¶jì­qÛ·k,ÄÃóåmÞº`yö¡I½Bœ*KX¨K›¬ö±66mÔ<@³ô–;yÔL°nÝbš6¥ÌÓ¥šï v¯*[§íËæV?]Ǧµå¹Lêš ÐïÅAmÛ,½KÇ)XÝ[SÚÙÄœ÷ì©vÂ'[І‹ÜhÀfÈoÏÄ[YÛÊW *–@ÄÇ!ø¸[å“À‚Ÿ98÷Ï#Ì óºJ²;”M;“¤±ûÉ.¨vD¡¦]QâÉÃk¿º2áíq^ö9o°SÈ÷7¡ŸÓ¦ÙMd'Qy8}HÞÿÚ‘Ý}ä¸ÖågG“]JxÅÊxχêUžÝR[–óõŸ­Ã“Ú±ÚÍFÙm°;!~ÇÂn­)/»'Ú±`[çq«>Œ¨Ï—£ÊØQ~V&Æß–µPžXÚœ€xj‚¾ý©yÍR^í|Q†œKt[†#yQwìScjRyê°¿#ÁË–›'²Ùgh—ôq^g>€x«wåã+§xËò;š~'²ü)kÓlɎǘ|c#ÆÈÆù à¬à?˺ZÀÛcV'Ôÿ.°…¿ÍN8ñÁ”ãÊmü:çÒçÅ%®N¦q°Zù€.Éäí1§}ZäÔ‡Ÿwð,áØÉÑ{žÇòB8‡Ü6÷ Œÿø<üÚÒ–…|=Ôñ¨ÿz`aÝ £~T?г*çµ-–³oÚ ‹² iUÂùO EÝ ¨²Örù—´™4ÿo-F¤Y>fÅÏ©»¼pîìﶈ¬u]M¨[ç9·|WqñüVýßúÖ¹‰ß!Ww(¿ÂuÈ¡£,öÙ^_qumðeÛ¾Â!”_[æ°ÃFÇŸ‹ ¯o.LlÑÀÐP?ÙxÂcõO¬ãGc×"Ëøƒwª.ÉŽYêjo3ýÙN ë$6íPZ>ä‹íŠz'6åäÖÉ4V+Ð%™¼=æ´O‹œúãð‹9x"v,‡¿÷þŒ-Ãç4ë~ g3æäÁÇ>ïyæóÚËsbm=q.ýOGû¨Û:Ú8§1cXξiƒ©m´fQØræ™Õ*Üf%®Y1£mNÕëùo®”‡|ƒ…jäè‡ÊÙ 67•0ðMðþ6;eV|Î×­«ø  |xÅvB-ˆó*¤]í® åëó×!‡Ž¦¶Ï–ðmÖŽb]H·ú°Î¤%«+Ž1óSücæÉÇìAe´‹*yÔ&µÇ¢Uÿ¤öh‘/‡=”ˆÕŹQ\9ÖçoYÐ9‘!œIíR¦ðæw½yXFà¼Î‰M¥çhX­|@—d‚Ç<&Ðåä‡3–Ú …†·Ò=´=uÛœÛ釅0©wS·¾)§òã¶GÒÖiWS;ž’’à ùÇ ”Œ+¡¯§²QƒH„¸åÍoYF ·ˆØ¼IYÈ[Œ´òºûš·w\{yÐZ?5 ú Ð÷¨“ÀÑŠi hýú¥¢¿ùÍ·”ާý-rŽuþ¬ëÔ.Êxg'µùœBÁcs(@ÏìúÚGTaoj€0:YýX"Í:©êWÏ“úkwSc¤!ŸåM^Énã­-`3ÞFtH‚†s"‚S‰G¬œàÒÊúgïò- uñ®ñ·œrÊ 1 U.h“µÇ™>jÃu?¶®<®ÿ·ë“Ž$H9“€sïœZ4¥÷è>¼=ÎÒ>—1¹0GÆÉ#Îîr7 P}CžÇRoÌ“×ÊeiœÐ®cjeb·“è™ø‰®Ã$‹…/ÃQ+/«³Î‘Í{ MòÌVd/¾àã›D'Ÿº!•Ïó´e8z§(–nÃÊ7KLmŸ-aÛêý-¯Ûn›†©Éܸþ±»¢˜¢»&qHá¡¶ùäˆÚº|OýÑSGòn~þæ…íÛ·rU8xð`™wß¾}ƒ˜ »wï^¸ä’K¡Elݺuªv #òúg&®ºêª…;v BÔŽýû÷b*ìܹ³oÇj锃°5lðüóÏ1P٧«8cìhzGM„#Gí`r´éÚQ´yf‰ò¶»©?E1甸qŸ í:¼MNd£LìÖ{fµ¨¾Ø‚EláÒv]|ñ¢áˆdl–G¬#€ã7ajŒ?Ú6_.¼=fuBÙ®GQÏ‚rôŽ#aël‡ó˜³I>9³a‹¯X­|@—dòö˜Ó>-rê4ñ‹½¨ÓDG¼<Œƒ)œNm:£ƒ“Ö¼lÛÂã>æ?'»%òCú®hÓó¡óî›q1±2©‡|Ql÷q‹­ ³8haóN¤{téÃ6§ê„glµå†ò6ñKHé5·|U¨ˆæÂǧYuù5¢©Kw½¶•G+zªyõ´­¬ß—µ|I·iVÕ9lubûœÞ_É=Þê@ÇæÉAÝL}Í‘°@>ÙIŠR}’m³J°•`Œ2Hë¶Ä¶cNd Ô_K̫߼=Îôv¼Pç8Žël¦òƒº´+ÞçaŸóÀ¸;¡"œ·.ÂïjêR8£Ö!]O}GÔè_©˜ØFín…_œ¸ȹÈß ¶»ðÑ" Û…Î.ˆžüö ]}ýBŠ<¤ÛºÆÜ V_E, Ñ´ù4Ž:S|=Ù.óÝG¹˜LBìÖþ¬0±}®p o|/tku-ßPGìÓ×5ØâŽvÕ§ä±ù[C…¼–HÚTBš7H÷el>o|ƒ·Ç¹ül§ý)NŽ„û3› ƒT~~“Ÿá<ýÄÓG~Ž“Ÿô¼âWDyõ豜àç+?{Ï ?Æè~ °Óàç=o;§:^ôùоƒUò‘0G…ùG¿d‰ç–ßùEqÍ5ÕO¯Žõ‹š)8Zaôû 6]%2*ŒNx ̨ŸøÄ 0€7>Âm@½úÝÕV æu•Ä®¤½M.Ôí^¦ÊxXk^¿¦ß ]Áðö8/ûœØ)ÔK=±Ái'‘ç/ën[w©G h7ß6¥AzË¥a"eÇ#ä’Ý~÷D»ŽÚÚ³ œÚÊóðy ÛÝŽu»1^nÙêÊL ØŽ»©ãÅDDÏj+¶—µ)ÜfØ–—úEÈ6KLdŸsÀ8ú·ð}+ëÕåÓêÈ÷DùFÔ !¬à>S%ƒÇu†DxZ ¶ó!mÏÞçæ„Ö¡­³™‚¿u¿öG×F_jêÑ}x{TxŸƒ7ygùÉ*­¡ãõ–Ý Å‹.qÄÊÏ]°u¡øÅ=Ã8·ÇÞ°7ú GËÕ ÿYŽá£®Ð1ïØ»p˜ûU%è¨Wlyñ ,w;û)4}bDŸá|¢Ïˆ1¹k%e²g‘²¾]8Z¯Ç®¼–+&ùï:ÎýªÚ´ØyÀÃ.TÜ TØÊ•ã®Ï1¼º ¯’q`Ë{™D)‡Òç·×“ÊÓÞ[ÙgFÄôιðº$ìQÇŸó˜sÙ†ZËZ' l•Ò”Ø2ŒóÔƒ®“Â+Š)73¼=fuB™ s`\>v'”#¨Â랸.‹#º\mK!Ð%™¼=æ´O‹œú)~8h±ïgÖ‘ž—ŒÓ@-rê¤øì„Fˆ[Ö8dúô‘½?/§å©—•ìÏŠ¦nÉ×ÝŠïz»§²Ñ†Õx(ë`*ópdá!/G¯ÅÄñ,ùX¬¨¼“Zdl^<+x†¸%º³ùT¿âS êmûuN¨å3ͺ¼mÛÞ&‘G &ú—Œø(z Êß–?h«£:LeŸS‚öÅÞ¡nt3›¶°/šùò謮e+|ÊIiŠä¨Æê•RIJ©Ã  ªo]¦ h cÛ°ÁK‡{WËÛñÖ\.P·Ý]NYzŒo¹ísÞÀ1þκ#í*ŽÙJx´ Þñfg—·äm»Wr;DzQ¿:²j”³GœÍ#hÕd¶+8ñ”SY-(âiùùEGå}}ä‘Ï qîËsŽ–ï˜ (M¶bP• 8"†œŽ¨ÉŠeaË)ìUÚ¶,y}¶)çÑ”>)ƲÏÌ -V¯¶mmÚËùúYDôT‚ÍãÉó®«k"´ÐÖ±FMj4–§¥©8¼=fuBgéüÁ+æÜŽߣÛðö˜Ó>—¥ê?ðnˆ]ÂÕÿ;£þv}Ýíø®£µÚIŸ#ދ¬tº¦U4-.¶¬ß¶aAJ¥±«¡4ñc‘±yTFéœHOÖÛR•¼KxØ&‹P jóéý¦D^<_ްW‰¨©¬ïB«ž¦:-šÒ§AkûœhK[?Éæ…¼N ßÏèxÁ÷%aT‹ì'›,Yû‹AbõñmóYÇXÒ¸«ƒmSBnãkoYPœ¾ámð@¼ ”à „G̹MÅwuÖ# o9ísÞÀmó‘ú•ìÅàwBÙùô¿•^V*ZÛ¨Ÿôý_Œ(+kGïôÕ¥iþ!ÍÆÛt_W’œÀ¯Þ:¡)1T•OÇß–ÿîÉŠçËnR‰àËÖu!ò±:-šÒ§Akû\fØ>ˆ™.Ž¡|.KVÏÀîLþ:å8*§XÝ–’}c€ 0AŽmœE[Þæã(ὡXjc4–äå%nÎðö˜õ;¡yÁðÛžkÂßC‚Éw ò$>‚ÙÔ11lU‹é7—Ç;ªO•Æ>ª2ÀòU*Ù²åæ%ߥÙueéB¾:Šª]|JUŸ[ŒÕi¼ê›¾l¶:!h«ÿ~§ÚKˆ»âŠÑÏÝÞwߢNßò¼ûîA`tÏ7_Åóû½ß»¹üü.6sÏ=Õ'4íÒK¾9û”§,òçHðùÍb}ZAù„‘þტj‚òÝ}¨:JpÒ©ÜBбå•a/¿|(üÍ” ‰Ìƈ)›s}ð”#зDùF1ã”:eFÚã7+ä¼JâÓ&ìF²jwDÙ!ð±°;ž›¶mZØ|ùæ2®ÍN¨ç5)Ææã¯`W-Ë&O º$“·Çœöi‘S@üØÕd—¯îû˜žR;¡³’1'Rû9ãŽ\­ðö8 ûœp®ì³:ÇñÒs¡þsM|À~µ‚Çb¿­ä—°V„úù‡E«í|Y —,¦qZ­Sy:T‘r^=ÈgÕ¢fû8òÅ@u/^åÀ¼ìÓë¶cœ4ôáý%ºÕ]ãX9¶$óõflåH•§N^gË•ðÂÔ‘-ìËÑ8âb Dx¥O«ã©4¯TEZ¬®6ü2ÁÛãL~¶3öӚܒ?ãÊ3ƾ5/À㸣Ž+î¾¿ÚæÖíwâo»î¶áÏwv“þŒV n«3ºsKþ; ¦pdQ¼jsQl2£nýáŪýùJ~ÒÜ?PÄÝÅ¿P—ß^·»z\áúéNaš[]mËr›ÍÞê«ûiO øîÙSý¼¨÷½?øÁAÀ€8ÝOå™#&Q-ª¸í¶¥*/½ÍÎ­Ú /,Š;«_7ý:£å¹=ÌO‹ þvïJ‚Õ…oó8i×_?ú„‰}"“âv9}ãËÙ§[(ÃÝj@O¨Ð'G†9WýâuMù6l¨õ°uYùKXa$0Gûû¬ÀöÏaèñ`y’‡FÈ(}ãá3JŽª¥ªñ#j¿Ømù7Ôo³¶ÏœÀÁäYPÎcÝ·AíÇÛqVõ{òsß–¶Žç7~!B׎!ýîÞ½p×MwÍÌ9¥mu¿™¯óC+åýT6ÊÄΘi¢U[Hê@ùq['( ž·2fÂ$¢zÄT;hjê6®%ß|«9ª±v—â;®¬u˜Ê>ç«7骳ƒX@ßÉÿ‹ÝN·duMy?¬D2ýZX|çâ Ú†xõ¤†ÇháùإІïœàí1ëíø×½îuƒ³ ÜzçíxÞ’çmyÀÛó—=¯~{×ó±HÝ–O¡Ž×8Xq|üí8ÿ†žA×Ú6ä–õœ­¯+®übQd”‡ðCüg ››_{°(>~WQ¼å´êö½££¥¦7ÄÁ¸2–; ~×ÓÐo\øÑxK쌎ƒ&ÙÙLýbÄN°¿e.s"w_'môÍoŽ9;µ]ãwo¾î&sâbåHc›Çn·Ù|ßÝdz˜À»<Ö•S<¤•ò xŽä­ Û:‰ðõI~I;¤‰ Ä9qðˆWÆ« ›Ÿ»¡J,–Ý=LkÚ¤ò$Yª:wë²D7IFÒcy +ë1ÇTm›Iû„g6ã­ÒÛR]Xò|¾ çÄQægwB “Žö\ð}ûX=|,–´Í3¦€g"Ǹϯ0‚ÚÛöF£†„ü»_ûÚŠ/°„Èk4%Úô[x{œéíø”³8Ž™e:ùV|—àÈ €·ÇYÚgNÄž}äùPâSi9o=—莸c9.å¼5ï?\¯¶ó¹&ôÂã þv½ýýü."i£§œ0X Æð«Oþž Ò»þ¹3»¨iŒÛôº×†!VoêKÕ +ŸF8–_¤rÀçSÓä0Z²ªö·x½“iÓ Ô/:5‘•u$ísîêú ’i[ÄúÍ 3ôŽc ¶ÏUŸïckKàP±ÂÖ#3ˆFxgã!Îé¾!~Œ^ðö8“·ãnû·äA›Ì ©·ê;ûV|üý™6H•iâÅ–{ìµÏÙqõã‹b»íÌH;Žow‡4Gš´3¾~ÿ¿¿(Ì7çÁ}̽ü<àÃõ'1 ðÔÁ,ï-Š;ª_ðbs‹>§n憋/^¼go“qô÷ûÛÛhöõ`[–±ËëÃJã6Ÿîë~$ymÙÔGñÝ3¾?ØŒÒlÀËL^ ù¤mž¯ƒe{!ØŠ@Ó¹£ |õ„m\ž/êà6/ßó÷o¹#î`¾øÅ• ½Á†uç¶,ÇïþîÑüºƒª8Ékë´²®V¤úŠ#zŒÝ1¶e8úßDxÖ³Šâña®åØð÷w¨y+ÞöC!…»u^> 0n"ŒŽ0“£|©‚tãáÞ?GtòY0ƬñØ×û›|.c9®’üNè…ïº0º«éó­ø]ÏØ¥WRe&á•e¹B›†G&x{\ûœìÞ±³§7äíKGÜ~Ÿån_®]PѸ·åë@Ûí‡ëc'XÒ÷D»ŠZM%¿ëè·q;©­øQ†W}ÅÃßʳõÚ°v^lYåScßËL>‹º:}Z ê²çîPóÅÊÙ¸X: Û¥ïX9Î5ÝZò›Ò¶¬WŸTMwØ£/7-jí³C°mnÛ~峺S¼úÇÚȸ œúTŽ%|¥d´á˜¨œß:g,ÛçHW#8ª±ÔñÚ[ñm½Šï(¼=fuB÷íÛ78k%Ž'¨w4ÅÇ?SJx\Œ#S²ð †´OFaXMH,ûø¼C$~ 0Úº{Á`÷|ÅcJΡ#o9íÓ"—]—xßðínÈ¿ém?ßıÍ3¡me¾íÞ@ý7Ƨ¨ ÚÈ»%_GGÝ´/«š»¯'²Ñ¦…b^ΩqÈ']ó̶ÙÖËÂÆâ¥0UÒ†se˜‹êò7`Ò~ðÍ~ÜãFù yÚˆF©£(öð…ä(z^^>L«Èãó¶~†õ)êÃV'²ÏŒÈ=Þ-rõ'(wúþèàЉâ… ¿ˆCÚf§¯ŒÉoFèËoùr4>I¿Ø¼ÚV´=°Œ#ŠØÞ88·tÒǶÒO[äìk0‘¦Æª@|›Æ¡ø°Zjq±4¸M7ló€o™ÆÑ–««g€’õÙ:Ç Ù8úzCØöb´ôƒ—TÏ“Är4ü)Ñ"Õ/‰?é¤`gQ)—â%(Ÿx ïxÇÁ%uA±¸Xy‹¶:‘}fÄ4mˆéÍÇÓ÷òéˆCÿÊC*Íç«Ó;Àum‡ohïx µm#³:Øžs„iо¢JÁ*!mUÎÖgáë&œ@ÛkoËòL¨& oú¤iÒ±êÔYÁ×ÇQÆñ<#¬IÒe´öˆ[ø±6žg[kàí± öÙ&û"ÿ¼'çÚ Äms+¾-¢ÎcFÊ ïã°Û]RÂ9ÐY •Ú1Ù…$5Îl‹ºxxzòuØòm^ÂM \“ü>OGÇ:j7‚šQËÚSÊÑðÍ´ë¼ygß–{àêV¥§`ߨ£Œ~Püã?Æ¿Ìký[ôƒ²?òÈ àßî&]§¿áô¢øà™ƒ„0or®Ø·å7 ¾Ó|Þ±•n®{bQ8·Ò׊†Ï|lš7bí[´zÝ–|v^ñãx¾Òû‚7Gøðº¸}PÇWÄù"‹}™°eü\G9^æµåÔWÜýWÄ}•Ù|9žYG^*lõ:ªÞNg€)’·ÎyÙ·ÛQ åì›Ô¨‡ï†óA|¦r¯f@ÊÂÃÏÛÊäAÜ]w-ª”:½J?ñ‰ÑáËšø¦ÒV ÝÿЀj_Ê`y 2XÀ¸¶¼©ÄÊ 4,Vƒ·÷9.'ºp•{.TÐî'»¤©<Ùá/§f} ëëÓU®`ƹDóW>~GBTÇcáí± öÙvîüß¼%?½Øîe6º>ÿN(@/ìxê¶|ì9Ú.#i£|¬øñ ù?Ný¼bÓ-ù¹#/9À_o¿×í²Ní¤x¾ã¤‰§å !/Û€ƒ²7múé…u‡?0Ì i'ÔV ±Tu¾Ÿ¦²6Î?BÇTJ¼E¬¬Ð6›N<ýk‹ºC„ F%µ|}Z$ísž9fJ«k»ÊÙ2 n7Ùò¤œnÖ•!M}CÿYyc?ë>[!GÛ¡)Š]˸mZÛ¹$lã9ž¼=Гƒ<˜jéœsÎYسgO™QØ»woôÖmÛ¶-¼ð…/,Ïå8¾ù]o.ó8p Œ®ºêª…;v BUþÍÿ&8™§ '¼ö„…çn}î0~Ó›Ч ›¶mþ^üI—ž´pæÓÏ\ò6_ü¿ä’K¡ Û·o_غuëXíØuñÅ‹,ø–püÎ@çÍ·ÜqÇ%ßýû÷b*ìܹ³”xƒ¼þ 8~%¡lFC}ƒ_YØÒ÷{l/>#íPþ`PÛB¾²Æi/>8ñÄ*~€§?ýéc·ÃBíøøAL…Xõ锃°5lðüóÏ1Мö¹k×®A¨² x“·É>A>Ž»xûBñê@rBy>ô[Žÿ•ê-oˆÛЯ½©^´ã;¿ó;¡EØv襤?ÿ·^¾ttÛOÝ6âD¾é‚7-\ýü«‡áKŸyéÂÿú÷ÿ«ÌûW?ñW#yw¼dG™nã¾ü¾\¶¹nœY[gœûÊm Åö]Cá”·ë–ò¯ó~dÛ W…IÆ™Åe—]ÖØ ÛÙ¨ì“ó¤†ÉœyJ «cíœ@{1þtO¸Ô‰á Œ[;‡–ã8ÄÇ,yǃ1~Uï "oÀ×\³°%Ȱ?Äm7i#:ðåÙSø–_ÙB¿t å V¹­G½ØŽAÚ°oÛ±°pÚiÕ˜=õÔE}@ô«úb±í|A¸êW°h»]RæQ?Qö裷†¸=e¼Òh/-)Nñ´ãâ‹w }°Šn a^T;P†m¦j‡­«œ{Âøeœ 2•Œw†uzû(ÓÅqÆW& cqœ æ„!­\㉇B˜ú¢óE(·í¼óªþð„Êù"ä-ûÃÄ—óÅ 'Tõ€Pþò*ÛÂꃺ5~Ü9´}fÝ ExÇIÞh—ãÊ>€°Ýýd7TyÚB¼Æ† fp…³“ŽÒ ÓâaÊ$å‰ä-A˜z©Ÿ‘1¸báC.ýt)çåoÊFê˜XG9øx{ÌiŸ¹Ú p2×_H9¡†ì3ãîø5ÉøÍ·sÄil"ÍX|’®mÞ DèÀÿJ’ýzºGOMÈÙ× i£Œ=žÿbaáÂÑ>““×&m(«M÷ÛlµØqT<”KÎW‰zKDÒ¢ò´(7‚A:2±zò¦{F²Bv ²ªS«Ù¹¤šÅ´¥"PVN…M£mœû©“®£ Gë\Ê—óªÎq•‚ŸåéÓT6ÆW2¥êlƒ¤}³†Ú`ÛϹÚQ×¾Xš“ÙÛru:ã(98Ò§,ôq–ü{¼)›)«0Æ”J‰·©œm ‚Y£ðŒÖgü€¤ÙFÆêð‚ònÖ5cx{Ì~;Þ;Ž„'ŤmvÐyˆ5¦&Ô@ÈgEÎá!"laë©Ë·Bàí1·}Î 8M8œÜ†··™‰“sfW4‡“õ·GÇÌ”´Um†Ö5|¬"W‘´Q<Æ^Œðl<üX÷ >²0µšb|¯•Xé6êÜçó¨K&Ýg¥‰¶98>Žü€2©©X|}ó€Ò|œ¦Nùùl »µ9ZVàšÃÊI=OûNŠ_êøÖ¥5!iŸƒð¼€ì©¾B¯rô=|Û½-P.¦_p.ýCº¸!Î^èpŽ,²Ž1;­0VQ¬á€8?WÈã…‡-ÇQu PÌ3樺9*Øòu0Cx{Ìê„â$²[É­ó\Ž#åÇÝýÌ:ÐZg¬C=èxò‹7ÁÖ£«¦º}=±|œ§ ±cðö˜Ó>çït ßþþo2>9Î7B'¢·Nï„ÚösÄI—£YG9¿ I•÷#&ûI›GÇ©EGðcžclññZy9Æò „3Í)ÞÉЧqbÕ§â…¦t ¯Ú©Ûàã›Ë¹º¢û­cɟȤªVHÚç ¼Ü@M}(}AVÇœËD}¹êú˜¾‰—­»TÀ1á:PNJc)’—mópôuP/ðT|Gáí1›Š“¨]KžÝôŸ[ê„39)Æéd¥Äýöy ¾ÊÉIãhAô ’Q€skÈžGÇàí1—}.'ä”ú]Ñ»}Ü2:¨ÍÇê›@m›ÛÒŠÜ }îs·Ñ,ÇNhl 7!6~!;æ™[÷û±2~n! |¼È·CùAŒÿ ¸uÞhqÛ²O­Ã‚oŽO·€¯š#T€jm>Û\_—ºÀÇÕ!ÖÆi‘´ÏAx¹Q×G^×^Ÿ\ ÄúÂCz¥ÿ¼Ŗʱa…ÅX´^'˜…Òò˜1)Ÿ­ÃÊaã; oÙ>ÑtãÇn,¾öÕ' î¾ÿî⸣Ž+.}Nõ9ÿy¥‹~í¢âŒ+ÏH~féÖ[oœM,¼.»¬¸õ„ªóØ78> O³ìÛWyLõ­>‘@8¤×Ê_ò ”ãÛ|†4óy…[ùÜuñÙ&À'^øÂ¢8î¸*¬O6øO§è“¹ô³ßfܲ¶áwÊúÅ/*q<ëèê<…6ÿ<šC9®í§Vó|7> 3†ígZ>üáj€øœSó·ú1o¿qcç0ŽúŽKÚš5E©9?çÁ¯aN‰!Õ4‰/Åúò ñþ‹Ußúgû !ÕÌž÷¼[‡Ÿ~’ (çyP÷SŸZŸýlz ]¬ëÖòxõÕ‰GÂ)Ð-2‹¹Ùê Ñ8'Ôô‘7-`ó¦;ߪý1tøâôºwoµ¤ê+fôÉÆÕyÓÅϦ´Í Ëxᓈ±O!¥ ÿà«2|À€ïˆß1‘ÏCŒc,~L,›íåºJb‡sÝ×EoÃûçDÃáÑ|oRåB.^åÏ×5]²úK<ÿÜGHo”‡«"] ±= w…³äm9{•D•³ç‰«¤±tDù„rèÚÛc.ûôÈic ÅÏÞŽ÷§;ÛÊÈ/Åv2=û³mÐFFtÐøS†xC>'r÷õX6Ê8ñ[1ŒŸBÞ%?ë i\ÇâbÛt´5"ŒÔÕy1X sÍÈrFE2pøðÉë\ú‘e‰´Cl­#Ê»öXäе·Çœöi‘Ë.„?;ZŽh›gBÛÊØöÙP>Ï‹Ñ]¿~×€{=ÚÈH;yÁþªTŠÐË55Ÿ¾™µ6ʘ°csÆ‹ˆ1íǼâùlÊ0/e}yÍÌ-8‘¬ÊÖƒƒBŸkÊáe¢¬[ìÅ®ˆ0|N;-.+qÈ¢¶ø:|8 Õ°°U‹%ÅUlóñé£Ê1©«Ò‡-ˆã“A©4¿`Iì jqRclÿ’<6¯òÓ¾k®™ÞVkís˜v¼Y=k®ý“-ÔGXºL‘ì*¦wê°KÛ¢­UÕ5D¬R˜K°Ià?¬pÍÚ[ÂçñŠ•1˜¶ßÚÂÛcö·ãSÃxá».:¤©Ð6°Ží4|²ƒŽ¶#ćçv$Èp¡ºÙ|Ö°kdA6^ü[_køAG83¼=ÎË>s@Ï~Zç’sûb/Üø<9p÷ïŽ:“QÆÔÓ^9Þ¼”ÅïÅ[§ÓS—_H’6ÊÇêý¤oÇ%+hl‡Ø•²s‚Ʋâý⪬tåo[^ñ±9†4­ÆŒë¦Œ°Ò)«:ˆk*k`Å+š£ ^©Dl•×;y¶L“Vôº4ÕM=ªËÊcËï¸X"ÍÖéóÖñIû„W¼¹ö@g±›–ÐqJᆲï¯hŸXc±¤u‘t¿ö7!U†¸X¾q^q±2ËossB-äNã8R¾iGµ`6ä>—í2,oPµú:Ò¨Yòœ2æi¯Æ‘9¼=.‡}NïlzGTŽ'Ä® dóä@¹#:å‹J8³¹@û¼“Ùä„zÝuI=å”ÐˆÈØd`ܦÆ.ã(¶ M‹KŒÄÛ—%Œ<6N¤ù‚<þ£‰â'¶é–ÆXü<ùè1’x}³<Õ‰àë¬KƒuB)ž’‰)Þ¦«»™*cÝ ©Ôw½•g$ís^I@·V¯èóõP>«s.Lü³^ï kiS¿rL‚Do´|ç‹xu° –±=§a^¡. Và Îý•™/³Lðö¸,¿Ï K·]wÛðÅ¥IpÙó.+NÞT=±¼iݦâ®ûîšíïÉOžþЇªç÷cùñb~H—'ßõô:à©éûî[|È9ÊØO&¬§ºyzš¥ ó`2Ä9qz²:ö¤õ8Èôôj¿ÿµ«sŽWÜÔ<øýx~ m®ùRQ¼1ÄßùPEÛ¿°˜'x‘èøŸ=¾8â»Ì[mLrG_Øð¶Ôøé/N 6„zÌ«wK€îìïî¯(\|ñÒ7.kùˆ–†* (0FýWëUÍù±tÿ#êÌ'â/Bèí A?–Í‹M¼±Áœ%XYÂj«—8ùË—ê!ÏæÁÁò¦Þå@=*gßå4Ie^[gSÚõ×/Ns¼óéyÒ=z æ°°šZ5ðŽš¦J+/GûŽÉ+^1šfåYmg ’nY:éOúb¾6ßÑaúâÝ ÞáûêWG‡à¥7xy½Ó_G¹ø^°Ëi$Ú±¾ò•ôÛlÖ`kÎyÁPó€/ËͤaìzAÑ‚¼zY  ¨+Óä¼Jò?­7)R|ü*Çò»¤ƒŸóŒÝ–ŸµLµˆìX”?µÇU W6öÒÍ^¢y"žKgs9]òá Ä®’|aŽ6Ï˪#o9íÓ"W›…—þÌŽáN¨vûtûoc¦vÙMaZý³¢ö'<-ñËK“~Ž©NÆX{!nËó‹I‡:ë¯+èyQt†.s"w_×Ú(ãÊnŸÄ¶ì´½&p>›;ìV‰/çæ‹Ô!”¶*ÃQõZÞÌԉܖW 숪Œñ”¡¬¯Ci¦lª”5¦*6s›!ªE•äQSh¾^$BxÚ²q'œPý\¨‡äQGÛ –'ùìÏS’æå<_ ¥½ô¥ÓÛj­}Îuý,=rŒéÁ¢Òí"Ž~ôù|Y‘^è3™/r‘ž’3Ú6 ØJ ˜Æ˜¤óĘ eÊúÚ(þ¶>êo*ãê·Üðö˜u'ôÞ{ïœM‡ÿ™'Âì¤ò)(> ¾v÷×ÊOEYÌR¦F°#àPrá*‡oð 'LèÍ~/„#;Äsé ñ‡€’Ÿ„8ûì¢Ø³gô ê§ziÜÍ7WG…u•0Ò6®º&Ü-Í¥ëy ·¬gqoñ–ÓB÷„óA–»zº³údŃiedgÔîŠÞû ã·¦(ŽzÑQÅqÛkõ9¦êdLíÕÝ.Ò±Lö¾LøêÇÅuO(ŠÓƒè]æÄ\í’Ýû]!¶sìöà|°-v/ŸYÓVcTc–ùáþûGw;,˜'ØÞÙ¹³,?l3¼¯»®Jã¨zMÅ 7Tu²í£¹„ó{_ð‚QY-ˆ§­ÿø¢\‘[i¦lª”Õïnò…«Ï|f©:á£Í¡‡ª6|Øè¡)|Ñ5DÑëü”¿ÿñ{Gøjê¶Nß ðT*Û¸±j—v8mYñä¦|R;kÄQæh«3BªŸ­Ýºj³Cü}ßwï’|¶¬Ý)g¹eéÐ;ý)óE.6$SrFÛÆØá.‚@…§œR­¿þ“MV0Æš]ëuNy¶iî}ÛÛ*Þ¾ðgèSnv0¥Ê8¤úmæ˜÷UR[ø]ÏÔ3 ¤wò%«$vü“ô\¹¦PˆgI¸b!^G{u»âŠ‘å i§Ãò²—w‚½šR™6 òÆxŽ o]µÏxžQ;¢MÄŽà<ž,_Zâ3No­Þzç¹ÑœÏ~¦°qðëPMÔô©ª®¡µ2Ø‘Ð3c~¦ v£ôR&fËÙsŸfAØ›­òÖ=©rö±Nv×eҵˠ*C2ª"QlÌ¦Ž–‡„ᎇ½ëÐäõ *k¤øù2‚ÊŽ›6%¼=vÒ 9–uÎ&çÖa]64u†d_R"/FãI3•OÜÞ/É; ÒŽ¢&ù|}”MåH×ÌâGøðöØEûlŽeÝw1×}¼º½ÞŸÜfµß·á»þ"’G+µãB΢Æý8 ¿³ ÛE‰óŒc°5¨Ç/ºÈ3cP­Ögˆs«ëàø)p Mùà/¿¡-3ý¦Ì.•Æ‘öÛë§6å@*#gœ*ûœcŠV›àÓ€¶é·òSÄó²³ødÕ,ÑÊFý¸1FÇ“1øy¹ÂÖ1ål ߯6­à«¥ù>N*ðªJ‰W—/•Æ‘zl^ âcÓ;òέì3R:uiÞ\­>Æ-gûÆ’ô^·œùºêÈ–+”;™6ÎÂ’'Ö5 f,é¾ë½ÿ‚…M³¾†È6"&¿P—–Þ³>z§~Br€ØsœÄùŸðü7ß÷o†o¾säMxP÷V}Œð2MŠF>M¼¾ûîbÈ…‡Px8…g?ìC+<ç¡ç¶8òì Ï{„ü%ž/<óÁ³`zöKyýÃT ÛF^+O›gIÌ3.wòæ‹gOº€\v!ˆo»_{G?T÷?R>v™Dӛ೒1'êxòU€>ªzNö¬q]"oÿv¥3})`%´»f\Œ€q¯¹A š‡Gd¤—ðsÍ׿¾ø<užuVq矸´œâ \Z­<¶ÌE¼^\ƒ6ýà«ϳ•ßøÆ#Íåñ7D±×iÒÊ£yzD^ðòÄ᱑G/9_vÙ¥\1x•ðö<ò‚X[—ÅV'„í~ŽÒ9mði<ÖëWOÊéY_pÕ7£:cùR_sL-gœËfê@y•ö&ÿ÷Õ[ñ)ÜuWe,üî¬5^ ãBX­é Ë (iŸñ¸‡þ­|@ù rb¿AZ´m¾Ü,ó*ÉÿìSjGS`G3v‹½ü®1v=S|@®Ÿ¢jäc/Éìå²@8\l©ÌgtG„]K{?€{¾¼0¸JòáQ*oK,iü¨§-ßAþò'Ʀ„·Çœöi‘Ë.ñcW/¶ãgIoʯÿxµ˜úfè¬d̉:ž´‰6ª­<~ QtÀòÒ ¤gC»ÞîÖ6êÇ5¤qEæ‹¡¬‰ô)¾ì– î–”óƒ/êøFÒFäÑ8R¯ÒbuÐÔ‹‰fã«fo6׿‰‰lyËWò4•UijƒÄnmY² ̹ê„H÷òÖÉ4 ZÛg ·_*¬^isìñÆ”¾AŒç¨¾ þëÖU?ã /ƒ!PÆ©>ÏO ¿å±üjxÑo”FúG ´b cñãTñò¢0v9Ãù’úb»ŸÔáŸO)%ÖxâŒb–Ô•RÚ”ðö˜Õ µŸ”rRÇ•¥ÎÙÍÑ.ЊOªãŒã–ãŽ[j¤a0"¥{^œŒþòah6}B”¿ô’ÁàrÙÐ<&ÐYñÃñÒ‹IÜŽÝŽö¿!Åžìz›AOÿbaÚˆ³iRßþ®·~­lÔëÁÂRÆ3ŽmqC¾,ù5F}šˆøAZ9?(Ηµé™†òø4ÂB¢-KôãÍÇú­&U¤Ò$O]Ó|YÖ{ºZ¼{Ú,D× M2MxÌcMAõ #ùB–h«Ì˜cX^òë´ü½ùÍ·,áUÇߦA1Íæ±X¢Co<"}[,–&#le ÇrmH³oPAÚÆ‰W¬5˜§}X{œÉ3¡vgrÓ¶M¥3êP`óŜԶÈÅg&pF5 f',ŽöÃw*cù`x\-iĤ@Z“!Z¾)ùæo³°ÏYCŽGœ-ëˆÕ/3yGt%#ömTµÏï×}/µkhm£~lù ˆs¿ÝlY›×ó¦LÓx&,^•nã}ð óh*7(ÝÆ[5$ÖîaYP—êšFšêQ' ~9¢±:m‘òp¬“i´¶Ï=©Ý¢iÚJ9xªßmÿ·ELïâ;Ÿ°¶1`,Âa<6ÝÆ@|*Ÿ7TêRÚñ©†Ö¥e†·Ç™8¡~grí®M:†Ä“ZÇ1Ÿì¨3*!f\6ŒQÛ0T7ûQƒ a¶‘oŽðö8 ûœp¸Ú~®I´ßOÑûöée,«›•ö‚ÖX6j'w?Öשq TÆÏÄ1¾5Op$,pžz•žZ­Ãèe£N òé–D\,û/vørcBM–X‚âi’ŽšÞhÕÇJ•÷ñ€8»Á?ËßÞUU]âSÇõˆ§Èvs]Ùi0–}δaÞÖÔbý2)à£þ‰ Ð7eD„'†g©Á2˜Ø-ù:ë†-]-òÕSߺ´ÀÛãÌwB×¼~M7w(ç…¦&,Ã…0Z;Ùk‘²äã4’l]žR£­I¾9ÃÛã,ìs^H=ʳº%Û-\I»‚uH}¢IÏ~âxjÇx%abõcÍ/*ãŒQ_–p*¯…_8U'^—KŽ„åÉ«S¤r±úfß ˆiTS)S$M°â×Á7-æ[Câß¶©È`ù@Rù¬0±}f:ñËzËm¾ÿÛê9ê†ÇX°Ì¼£YG[)À7f´„ýÕRÛÔ)lReNoYÐ]»v ΂n‚ÃɨݵÏjÖÁò™¹xMÅÇÕ>ÞRŸ]°Œx×1ÇTç?WDªÃç…FÛ®‹/Ê7 rèÚÛ£Â'‡6ðà´¥sÎ9gaÏž=e>aïÞ½£X°mÛ¶ù8‡7y80ˆ­pÕUW-ù ³;̻ÿþAL…;w.lß¾}„÷Áƒ˼—xßègšÞ²{á°]²ô#îl](~qÏ0ŒóF;žúÔ§8.·´måšÚa¡vìÛ7êïÞ½{á’K.)Ï­,gÿÖ…GïØ3t*K'ô—ö.ÏØ2lÎ7(Ôµãúë¯ÄT˜¤?,~åW~¥±[·nÚy(‹­ÉÏ?ÿü¨*\ 3”¤El0F½N†ðåü¢ÇJsÀ.Ŷ°u²ˆ1wÈÃR•CÿÂCì¢jñ‚d²mc>¶)BEuN£•ÇòãHSm˜ôj‡ÔvñÅõíò¼½9täíq,ûœ•Žv•myœô‰6ø­N9¦²‡Ôo6='Ô¥%ýCÆ6k¶% ‡FxD*_R_lœ¶‡ý˜ðùö˜c¼Û¾ó;ã!fÛØýŸ‹ÃÌu4¼=æ´O‹\mbüpÆš^LÂIµ/ép”7§…xÒµ‹6à€Úvù6×í~v½ÝYmÔͲÚùÂc æ€m>Þ,fvW’é…(äò˜obNhË™Iú¶~z5CŽ&G;%zòëõyçmá­º˜bíѦÇTÄÛ†yRï¦|9l5«}Ž Ú‡>¤›–¦ÑúÂ/ƒÒ)ýéê/™´â}¿ª¿cù-–ô™d€cªSÊ8¢lCåÑúš„LAuÅÊ„¸mÇ;¿ áíq&·ã-&u-(;‰3;sÐa“„å¬q`šìáËB¢K@ü¤[ò „Fë ‚·ÇYÛç,‘ºoI·ÞqÊtkÚž¯ §u2E<ëÉs¡¼půDÙ4µ{%bYm46î!Æ:YlŒÍK1>â¡üœû<1"ß €~z…ü:jãìÔ‰o ?Û;CœÇx[§Vñ„ý­zˆú»‚eµÏéÑšR×÷­ÓyooââmûÝú~~ùlÕ§¾ÝY°xœû >ˆ|“T^§¨o3wBs'¶é¶~gwlxleµ-І/h¯Àt™è)—Ls2|o+Á>SÀ9«{1‰]Bv ­Ãiˬ„vŸ õmÅœSèuB?©ºnŒ)Í®šm‰yÂ×ǹ?Dä¨Ë§{bñœÑ….͵UÙ5[DL]R×îš½ ¯oKð±€y­Oay«n[—P—–SÙç2ؾõ:lðP,ŸEŒ'ú·<¼s+_°‰÷¶ AcŠ#F¢Ï²‘UIo„6­Uå+Þ—Õ më8’^·Ú”>3XœÔp(ãg¦¶|‰Ç! Ý_MN•må©eZÌÀÞ—Ó>s' ‡+æ¨á y‡ÓïžvÙYCÞ‘g^¤Ô§PûÈÁJÄÄ6Šík‘‚¼÷’c>MÞ+³óuäùÆVvÉD© [ˆzg¼hZ8²†{RÕöªAeÀ7M¾‚Í ‘‡¼<Õ ¤QŽ©WuÛt/S]ZnLlŸË絛ŸžÊçžÉ#}û~ }XKjë>R%²ÂY…1yt¤ dçkPâÉq•ÁÛcV'ç¯ín与#é|o4öÍÑ6;¥3Ã4ÆB;,Iøbà2|Ž„s9à)"<êÚéàí1§}.'p&c™%íˆê9J‡N›œÔ®8p±6'9cŸhZ ßBØFý8‚4–êÆX]cÉzT–¼Ù²±{œ a¬¬Í/¸–o&øfS¥¦/ž¯Þ—…˜Q—/+õÅÔhùzžð±S™O¯+kÓrcbû\F¤–ŽèоSºú©a)IB<}¡˜­€Œ‘ŒÎ3£¶Bo’3äíí1›Šc¸î‰ëZ;•uŽ#o zÀ/å´Ö¥ÅxM‚™ð¡“e|á–HÊÓd<‘ôƶ‘·Å Hò£ÞsÙ§G®þšøáx5Ýš—s6|{~ðV¹»ioÓOÛfê”sÉÎn¹ÓiÞ|çsS<^ ¼¾½måžwߌ‹‰m”qÓ°ý¹M[ΖœGœÆ-„YISYÏ—tïy‘Ç,ŒÃŸ‰ĹkÀ¸ý«Ú°aˈS«ž°w6™vF§¢êç-¡Ž”ºR<Õ.ÒS2Õ¥Yä°Õ‰ísÐt`ÛcõA}åóÄÊùü¾ cšlÒO„¯Ïò©x@×i¶ÜHÿXÆPê…$o4TfË©‘3yËñGÞX}^9J³°e<\Ú°m„SóMx{Ìæ„–Nå‹ÚïFÖ9Ž|žÅ;Æß浯i1>Ž C£³kåqÆ5ak¸ƒôVmKñ4HòIÔƒ·Ç\öé‘«?…6üpÀø­x똉ìâ0Ÿ7¤oó“´Y2á\FèŒ"œiä…lü8; ËÑ7ã`*ÅöíªgÂ{ûØh|tQà¨qE<÷«/FìµoÕ’/5v™ƒXi¹5¯<†ï^xÃ3¶ÈÕñ`"û‹T!>MÕǦWH*;ì°½e³¶yR|c­²Ë^.ÜrÊ)e}•Æ…Ó~‡±Í÷$‡íGµCß`„ôÆ©¾Á¸B€CÇN¢ÞgG‘ÝE9y8rJÓ)eôŒ%Ïaâä=îSU˜²¹AÔ¡ç;cÕÅžýäƒü6¬ÒÕo“3³Q¿( Æmy´ñÓ.fŒŽœ¯¤ÄÅû8ލ²qäaú´G╦¼]CÊ>skT¿›ÏŽò2,uÔU!nG k¢w”»Ø§žº$~óæÅ5¥â  ´%øZûÊ0~R5 vº¤ŒƒTçÑGo á=#ñ´ƒú§xµc±.¨jÇžp ì×Å'Uªv¨P®6,ì_,\ÒÎ@Û]ÜÁ@[‚ã¹ï¨£Fâwº„s1³5ÐâEA˜²?B}ø•k<çÆy½%Ðp7ñWÚq U] ÔwGˆ#oÙÓÀá¢s¤Añ­ÖxƒqÖøìÏ„â|ò{ñ8‹~‡sÄv>áÅÑ:¤ªCi“Ö7`ÝŒ&:Ö_õX+vVó¨‡xåSýß!x{ÌiŸ]ƒu,½#§ÝOœA(º iˆòmwcÓ ¥v=cŽ(»¶8Á1GÔ|W æb£v¬²óa?odzvU|Ú¸°õutnHÁ‹nÆ6ˆ•WX»a±]±(‹Ãq¹0û ðz³z©ÆQRžºr>Í;ÿ)s÷åšâçãòÂfÐó:C…S·é-c޾¬5"[Ÿ%›÷'DŠç˜âçȹc•’ Þ³:¡ æ,rƒU9§îrñ‚âjꌭ¿"6¡*YÉc›Î~ Ç?Áú¯}ÅÇ;¯„­œmCG³´Ï6°zµm÷zn«“&ÔéÌË`Q—–Â’º` ‡7jdÊ(!ŒÌA¬‚Bž=GY…18 šœpÌm˜r Û†l3¼šòö˜Õ å9€“8Í­ñ£¿ëè¤S)Ø:¼Sjë•LÓbl>Þ8¿õì³ã4&†òÀ'6²9¶¬'Ù¶DRÈ¡ko9íÓ"—]“ò“3'' çm¸‹ÈoÊë| b—Ò†µÃºþ9[£Î uÚüuä\/£Ýñômk‹®ôM Ùl42FGdeòga7Âq[Öó Ç­G½öðùÂìäh u•ó•ÒX`Îé$ÈÑT½nÝÖ¡ÈÑßÅô„ÊP¥o²•GªÖzËQ>DÝf´fMW/eìÚ]· •Be³Ï ‘júG"L)Rõ¡o;l¬ ø´6}–ÔcQ* ƒq`°¾BÂþ¶}ÈÏ3¢Ã°Æ^lì Ä[y¬ ’/¡oâå``d„·Çì·ãs Î©LÝÒµ?ºvÉ®é²ÁCMçO x×椘gðöØEûœpÖšž­ä…%víKM6]¿E/'ѧãzgó@u/$y'W4îŽçJEm[>½í Ú”ÆB&¯Íî®Îc»®ÄËë‹•›¨RM—¬3hUéùJe¤Ûò|š/u(Nåà­ë†˜*ç,ö9 Ÿyš‘ïCk ›6UßÈ`|cûÛó"ŒDù9ZÅ@„}YÂ2TÒS„ÄYy|8ÒÄÛ^ÕaàuFx{Ìþb’Ýœf7tœòä×i Út~×1ç6x{ÌiŸ]GÌ´Äõ8yžÃL={IÎqX•W»˜)çW¼y@çäã™Pû(éÔu(8  ‹2¦B™!¶¨KŸ$Í.2–ìv”/˪M9¿bC¶Î9Á‹×Dr½3èRü›N=)uÉw€bå„”*ç,ö9!h£ôçAœßd³:Ë êSzÀ¤•Æ1{ߨÊ=ù+o,L9§r:}¾\Â{px1ðÌ(ðöxXdÁ;ÿìŵpmqûÛ‹ŸüíŸ,Þø»o,ϯü½+‹¯8±L—>çÒâ¶ën+ð:ãÊ3†f_ç Æ>~*xg—0€Ï„ú´:^ã`Ùø`£Í%è’Ž¼=æ²Oœú9ù Ã]R:ƒz>"Ì-uŽÖ„p)»­_ÞNüàKˆÛû6N®ˆtê‰9¥#xÂ''ºÜ7`f6€òÖ"yI,8c.:KÚLï„ö¼Ü|sÉi§„ÛÔB®~xÚÓ.‰®•„ëÖÒl¾ÓN ãaЦY>1y&AÍÌ>@û+}Vzµú Otqû1Cìaš~´PŸ¦xDÇ• @V‰Ãè¿ñkˉ¸KbcÄòO‰Üód ޳ݎç¶ù÷û}Åákªû%›Öo*6®ÛXlZWm3¯  áÜ}ÿÝÅ5ÿõšò<†¼àƒ³¥¸ìy—'oª¶9žuêYå­ypý«¯I#o¯q°l|ì¶¾ÙzÏ%蚎æÜ²æäÇmí·œløé/(Ö‡z5lJÜýHQ|èÎêèq0Ľñö¢øêýaü™Û–kÁbÍÿ÷‚â¼c˨âÊ/…e±nMUÏa WqŸ½§ºý¨[i§Ygmd<x¾róà<ºÜ73Åea¾:æ˜êœ[rGes?xýúÐwWñÌׄ¹“[öö~§CÙfÝÚçȼ!a+ÏÍ7/øö·³Ý·ÌÕ—]ö‚èB„‰ç"¢Ú[éﺫR…ò½õ­/˜¸iº½Ì­ç;îxAôô$X1¶úC'Ÿ\éÕêó³ŸÅ «Î9Î…/}é±%rlØ>MõåHÿøŒK+ȇ?\oÙ²xK¥@ÜþFЋ.*ŠO ò•£x¿€1zùåU> xd~LnÙl/÷U;’ö–»Â·mÙ¥äÛž“B<¹½»5oë_ñàJ'×eÞ €·ÇÜö¹ÒÀŽdlÒ¿äɾLd‰]ÎäN©!ò”u›Wä °KªÖj˜©2¾ýí6»µG¼M‹Íâaw`,ÿb„aåKñ_A*šT6.Ø„‚Ÿ'â—3µÏ áÍ s̵‘çyOÊÓ÷ic_úš±„ñY¡¬À±gGàëysW$‡²:oÙvBÿB‘Â;^µc¸+Êñê-W—瓞ìrÞü™›G^Hâ%_ÿŠW:“^®÷Xñ`Wôº'Åæµf÷1€QÌ'»’1ð²y<¾þPQÍ‹fäÃ׿e•—¤¨›X—¡x‰ |ðÌ¢xð‚êØ##ßÇ7ºóɶÑyç…=Îv´MóÛ>Ú¹óÎÅŠÈÿñ/Î#¯zUz>YEó ªzêTfA™†Mæö=Žy½h³’aÍ SÞ·¯~Çqä2YÛ§¼Lfߌ‚ ê|Ž„ ‘Æy`|Öè8׎).¦…Œ²oáñ6]á®`dwBSÀ)¼îU×§ŸxzyœÆIÔ›ø=òPy›èöûª£ªCýÎàs‹bg˜dõö<ÇëCø3ßW7…#·Ó-ÖrQ%˜ò>w°(^ø¨Ê±%ŸwVׇ‚zÓ·ím8§=fy@,nZ 9Þ»·z›7VuÙz=*ko Z|ýëÕQ÷«5ŸÄ¼.Í7 G¶Lˆ‰.p÷ò'²rt¾õ­¥*‹•姈2±; @å€ëÓƒ«,;bz|šÌŠk*™hê:ª-O…ý /_Η±°iȇ©/(0ä¸S+W‚ ;9‘ ã]{ð8§_ýê¢ójÁ§@ á•~9¢š(&áXçm•iQ—–9·ê÷íÛ78›M|¸ÝnoíóBRêöû¼dj‹®ñ]’ÉÛcNû´È©?›ˆñäv¸n•[p›ÝÞN'l_,*iç¾á¹Þ½‰ïy§êój÷4ÈÍo&6:¸E–°êV½_Ém>âE¼a«4S¶LÜ®/ùx"½¥gË%Ò†òØ´ ‘«àÓ$º¿ËiU¶XvßHÙ¦; ‹åFëT»Réã ‡ŽfbŸÔé£N˜vê%¥ºr>mñ “}2û%åÆáGØÛ€/7ì"T!ŧ"Œ/VÆ“}n„cÈ¿ïòË+¡h¬¯OBÅd!£ñ#mK•ËoYÐ-[¶ ΦCNÿ,h ó’©-ºÆtI&o Ÿü-sÎ9K~ËwïÞ½Q9¶mÛ¶°k×®A¨’Þ80ˆ­pÕUW-ìØ±cªpÇw”y÷ïß?ˆ©°sçÎ…íÛ·ÔyðàÁ2ì”Ý»wGß@ä§àbí Í¾€vœù¼- 'þÁÒ‰Ôð´ã¥?³£t ùüRñŒ- Åïܱ°î™[~öÏ«vਖσþÄÎ…âÕÛË|B›vØv§Úaó©v÷/xÁ ¦Â$ýañ⿸±¶ä¡,¶&<ÿüóóÛhXh¶O ˜U R@©“uë(~6¢“ÁÊyG -ösä{E,\k×.ì áíʲä (ûvÆQg5¤ u2à ?Žü è´}‹~rµxøî–…Ç=n±o+_`w Ky†ê,ûvÓ¦=ƒø0Âñ±­ÚÁZ;úÙ¦m '´ØŽªNúšr¤Ê²,í8ᄃrvZ{ÕX{Æ3ž1ˆ©Ðd£²OH6š²O…sa±*²úH¥\i‹?Põ£%•‡aëù4@ÛJøÂXª°ŒÏ—dp”ÃYµi¡\²¾Az28OXˆ¤%ë²å2ÀÛcV'””mø´}iž2µA×ø€.Éäí1§}ZäÔÈ͌˳nǼãoFÓ§yɨ ínBn~3±Q°M›>Yz§ÃÆ vñl1<é¤*Þ¦qÄ1eQi™VÊCá)‘«àãE—x4ÁΫi¥JX¯NÒ­_`Ó|âùŽwTíJÉ4rèh&öAª½uýr¥¡ÿ*\õ£úÕ–‡Ÿ-ƒã7ì_Ø…ýg™TÆþ$&D˜üªÔ¦…ðH}H$ÞÔi^ñP¬ ’–l›-—Þ³¿ߣÇ4ðöØÛg®af6ê!5…@b Ä/n –WÙÅU{qqi“ƱƒðâqÝɬˆu^ë·OGåuÍVZL]6=Vv^˜™}FP×Þy¤Ù°ORñ`Ò´Ê3âøav7Å€£ÿÝR[’¡Ê‘´ 쯰0`ÕMš­p>“ÆOo½Ú£SðöØÛg®af6Ê„ï³qÐTžE…4a¡.m…À7!E©N@>Mªï²ºffŸFÛ~ãämo 8†r&!έ£êIH„P”‡b'>ßYí’!&àíqnoÇ÷èÑ£GðznÓ·fêÞZm*Ϻö­{½± xóÖ¾‰kÓVlóxù˜—’oÆÛ·ãyé8¦"Tª·ã›>T§ÊóÅ8ý6NÞÖðÆôM0ÀùÍ7~–ɨ5 Æ!ŸX‹ ˆÁò©6áù¬PCÌꄾéMoœM‡\|@×dêuÔ ä–um?e+¡Ý³Â›î¸céçØXˆp<ùfPÓ J¹P¾äãAZÌI…Ÿ–á»4,€|&f–Sw¹xÕñ¹çžj}ç³Iÿñ?VM}á «uš_P¢ÙúBÕwŒò±ŸoŒ}:ȪòÌ3ß4Tå´XI¶šÂóž÷¦¹}ÝüÜϽ©u¿Õõ±†YÜÑþ±Æ ï„®ããwàd¾ü壎*jóNÀ7ýÜÏUçÂ}å+ƒÀ8¢vL·iHËe{YÐSO=up6rñ]“©×Q7[ÖY´ýP”¬„vÏ Kde!‘ã¹gOzuH¶™EÊ;¹váÃ5¿©˜Sw¹xÅø &~ùðààÍ®|¤Šgcÿš%mô žßÐjÚT’*_ö²îéh¹ÀuÒŸýÙ©Ñë¤ }£F<ïy§¶î·TÛa–úF,HöÆ3W=|÷“+~®S¿%+g‘1¦ÝRû1{xhÛ>8©§ò]`«°Ø˜Ç¡Õ˜¶ I]¨&°l¶w(#°þ>˜0KßÈòÆ/‹ùfm€¼rDÇ–ÑŸJ²N©¥:æ¶1ºøŒå¯3ZònÛ€qóO oYŸ ½õÖ[gÓ!Ð5™zu¹eEÛEÁJh÷¬0”Õ>¼ffÔ³›©‡àåJ.±‡Þøýy!Q¶Ä -§îrñŠñ±¢£.“Óc¯W_½¤Y%Þò–[ËgýOõ+•Ýuxä®»ªøÑ´[—¼à<)V’­z ow<õÔ[‹n¨ƒ”fߟɅ·¿ýÖá°àñJ=jY÷Ø4ýçŸOE^䮓1Ù?Þy–S‚xÔ fŒøVžÓô 4¿?/ð&F,×?÷¼ÏÞúó??ªy!çUÒðgŸ¦D.> k2õ:ª‡·Çœöi‘S 7?p(ʺÞîYÚ般ڡ`‹F»#u›Ší^„8~’s$Íïœ@v«JPƒ²9u—‹WŠ}>ãºuÕÏ=J¥¾¬W™Ý˜ÝÝR†s ‡ŽfiŸmÓfÚàÌ3· ‡G›Pâ”?•'…%m£° Çn¥Æ¾*BÀ–•Fë“ð–a#/¢wR>cÀÛcV'”ßüÍ\|@×dêuTo9íÓ"§þ@n~àP”t½Ý³´Ñ¤¬Zì¼CJ¼Ò̶„i<ô–Sw¹xåàS­½wÔª•IÕ^u8JÛ¼ù«ú©£m³´Ï6Èi3m@}vØóª¾_$ß÷uåGÚFÿh|‘—Ûõ©‹Hƒ%ºôÂCš@ð1˜6ÜÑBžðö8“gBÇÕÃjÄrë`¥ö·ÇYØgÓ`YmÔ/BÖjZŒìNÍ»ÊSç1µy¨,ïƒis‹#ªŒñíæiŸu:ÈFsOùJuålÑOns¦q”qÞ¶\*>æ³ù~öå† Â ÔDu;¥º0„Ÿx§+5@{Ë>& yTÖò&Þ©4®¸fx±êíqè„®YsrùŒ ÏWðtÎ9ç,ìÙ³§Ì(ìÝ»7úÌǶmÛvíÚå:ñ–… ¶,8p`«ÂUW]µ°cÇŽA¨ÛÎðýÙŸÝ?ÔM¥« Û·oäªpðàÁ2ï¾}ûÊðb?í^X»ö’R÷VÇk×n :Þ3¢ËsÏÝÒŸ RšÚaލ¯m;hsQì/yCèdçÎ Ï}îö‘¶½ãKÛAÞ×¾v÷Â%—\RÆÅŸ}öÖ‘þ þ˜cö{mGÕÛíÖÆm‡úƒòÒíhêa÷îÑv[·Ví r¶vrhÀùçŸd^¦¾Gð69wÕ çÙI…pÌ1õ°¯iiãÆ…mG¹°ë裫[ûƒø[‘÷À‰'ŽÌWÚ18/iíÚ…;‘¼íŸå?tB+cªâIŽÌ8ƒ•4:Wy8V_5ÞTÞϹyËKò@‹éÕÕ䤩NŽ)ÓåRmK•IÅ¿ô¥;†ñ–$[¬L Þb| TûS|ÆAjU8rÈj‘›8e]o÷,m4)kÝÀ#ŽIâê;LâÇ 8[–£6锋ñ È©»\¼Úò¡I¬Ïö…"5•¬YSÍÅ65Iuaª°åaùÚòV¿–*}V¼D”‡l\=Ó6[§—̓4¯Î7nŒ·ÍËD¸.¾ºÒM³=Ð_gÔ†Xš0IáØE@S}©x0nÚHÿà¿»ë Ç’| ãsÎfI4 ƒ«Œ³4²«^ô¢ª,iº¥+«8ê°s®FØóHÚUÇ?êˆ!‡@Fx{Lî„:ù†rÙÁ—Š÷ Þw&aʉ|_¶ù}]ô‰Í/ãT?“ýù8øX^uz&Ÿ•ÛËLx\xž‚•Ir¶§}´Si“‚òV6[G¯óIÚßo >Ü£Çrcî6Ú4ñøt‘&G^&<gÓV b*a®×‹•#LZ쑾®ªkîöy(ƒ+DʱÞ°ˆ‡äœØE\F*£T˜q«£Ê©¬M³e'¯?3¼=Ð㎻eDmœޱx ÏK:òϾoóùö{,Ñ÷””ƒ¿í ÅYžœÃSm”7&‹ó¼'EŠW›ø6yê@ºo›âmvÌ(ONxõá=–s·QZlp 6Ý’&7_–íóZOl€¦ØuZ¤¹L*ñ›1uÅÖž.«kîö9C ã6ëײÉ9žë×WG Pcò†8¦¶ØA]9ïÀ uª,ŸÁÛãÐ µêç(Ú™ÒC,ÞÂ󒎤s; P>fp„cŠ%Ê mä²yà@ªGrŠÄŸr’R~ŽŠ‹µ¡ &-›²=Žj£Õs Ô«¶Bj¯ü|{sÃÛcÌ>³á'í¨+ 7ýéM §ÿÌéå1æf£1{µqÝ®³ÔæSX²Wñ«43µ¾{•Xg×wŽR•¨ËêZûœнÖ/Ûw³u´^R·â‡Ö™ð e¬ñŸr6ç©4‹&>‚·Ç¨J{|çC±Î±ñþ­k€¾c –¼®<ÒcåDÞ@Gó¾µ'4ñ´Þšóð“vçõæÓ oSY ñ!_Êö|É—’©MýžŸ×kªmãÀÛcÌ>§F0Ê<¼M#Ú(»r´Ý#7Ï• #ÈÉóÂw]¸pضP¼¾X8ùŠ“³8¢³´ÑÖm·–íÞ¾-í»Î®513iÕäËÙ¹xˇæ1WùfZ>6dçBT%"æ¯wMG³´Ï& »'<¡ZO<¬ŽÛ i½êt6Nä±ý+3R†`´äT¿“GYóN„[¤¼õ­õBnÁ§ rÚq¼=FP€Ž¼ÓƒtÀ1öYÒ¬n<Åôêù®~`2ЄÀs-2JÎéÅ<[–ð–gŒä8Ó—ðŒµÍ÷»üòxÄø¯§¦5D||9k{ÈmÓ :™¤ÃT½ð“^b“qªmãÀÛcÊ>'Æ@)#Ÿ¼ˆ)eLäh»Gnž+AF‹'(Îgqj ŽØ³´ÑÖm÷ßQíOðÙÉ/6äìß\¼róñêðó:ẹ±k:š¥}ÖaQÕÏhZ]yÇôèѶLJgãÖé‡Tlø,©Ë>j‰xUŽ3âj¥éö½]T6°åÌ3«8œ1xZ#´ ô-“Wð)gÃä´ã:x{:¡o~ó-C¹ 6gó¡Óç>·bJ|Œ—ô.B¯1Þ±ÁâyZG“£Îå$&íJ¾Å6¬\©ÐS2Ùz­Ý¥ôã,/á >^ë"·ågT‹”Lža‹¶|êØšåw_<ìl¾§6ü¦W›¼é?•¢oÜíß¿SAßMµmŸô›j´ƒï©yLó[ò5µÃ¢M;l»S퀇G];>ö± b*LÒìxþ†Ã+çóû+Gô°-‡ì„¶é}çN߸ã|–ß²m̓ì'TC·Ô]Å6 dƒmrñš”ê ©R‹øxuØ[øPÝ< º¦#xÌÊ>ë°¨Gê5+¯c›Vßg1ÄÚE~¿ÙT'e&Z¿Éh+‚ä4bHÖÉ䘷Z ¡Á¢~ |ìÏQÂy¥ZÂù‘l¶Q8‰FÎÚ>oC'ôQª ¹ü•`ªó¼Ð!z—ŽÕF髦ý•©Ó¿(%7€d¡™xh72Êf”V''ùm{ [9Ç×;T×@=ÖF©_°mDF›&§I^å¡ü¤ý×Þ@}x*Є·SJv<µû)bg4fj£ãÛµ“½%_7q?ëÜ1xUÙ&[u 6ͧ–´¦¯,—}Ö™USÚ¤kf ¶.ë÷µ™ê'’…Ì1£Qå–p*íBê‰28#±4KZeÔÔ{&ܯy1Ï|¢FOoC'Ô~'”'ÑÂ1ùˆ“RDYÛ¾X{cqÄ{†bý.R¾¨Ïæ' ¼#ˆ=Ô!Åg ¯Õ§ì(Ò¼MQÞ–á<¥[âbz%?ö­£Í£ø¿ðêÃSÁ6¸í¬ÔcE‚OžÅùdG4— fj£máªÂض(å9‘—´ÔľÊ@½?€ª”Æ9›'Ì¥©õß_àwËiŸÒg̬biœû5hZøa ÊÅ RzbwKpL•‹9¯–hˆÝíÓZæ)Û*˜|uá™(hÞ£;¡ÈlÜÑ‘srFÉguÁQ„.å(¦Ê{†¬±ú¾" b·Î‘¹‘«±zïG&%+‹GŠÏ$À®lÝ„S°õz’~šàõJÛ½cïûTº¨ÓÉ4ðêÃSc–Â÷èpDs¾/ÌÜF›`¿t˜ôˆ1Az;·ö´Ö ŸÓY—h¶U£Ö}æ?ÍÞ@m+A]ËnŸcÀ¯A„§…íרú•vLYŠ‘_{ÚìzZÒNjjaŽÍ m½6ÌÑó™1¼=6>êɶMP[¾÷{wt~L¿¾¼×Æ1ÇT¿y®¼VøÒÄÕ]0¨¬îŒ8ÛN œË†˜Ã'¤]e½1Äø¤àå(k凰·ï“NªtäÉë·ä«ôZõ[j<ÈÞɃª2KëJµmxõá\È!«En~àP”t½Ý³´ÑV²úI“00ÞÖ.Ÿ¬±Å«9u—‹×¸|b 5‡’µ¤Öz®éh–öÙã´aq Zºž´E¬>ø¨§åo±¤.Ûëœø[”žó³‚pô»i8ƒ¼»à)'Dåh˜ÍOËO ç¨øHÈ¿ë˜cšóg€·ÇÃB Ä«_]·ÝV—^Z7ÞX_ûÚ ÁxÒ-(CÙ§=íÓÅ[ÞR§Ÿ^7ÜP;vÅÉ'2 @ùk®)Š3Î(Šw¾³(Î:«(?¼JSÞo}ëÓåÑÖuÏ=E±fMQ<üpQìÛW?ýÓU¤ zÞøÆO—õŽ×^[·ß^Ú,p~ÝuUŽ9¦(î¾»Š_Xøt±gOÅÃCíçHºÚ|øÓŸ®Úæáu ÎQwÝU{÷VŽÃ•Wʼn'Ž6B ~(fóæâÓ<0H Í7~VWzÊ)·Œ8ÓrîÙm´;‚Ö‰où¸ª¤|ìv‡=·ª›£½’I¼y&Ÿ£½Ñ†dö„ë@™6WÂBì’!âý.$íñòBðã¶Åv™º‘ÁïÄ^°õmLµiRø«$îÑc¹Ñ eà1èíäÜîªØgÐ缚pÄÔ*bé U¶«˜—}¢ÔZЕ´qÊØõÚú&¾\ [X‹©2ú–çêˆCc•E—4(v+ÒŽg‘„•QB^O¾¶Œo¬U„/—ÞG^L²õ!‡0É5Î@´m´z‰éT$þô‹ú†¸X^KôêJ‘xÖV^ue¼¬~Gžt«'Ÿ—4ï&Þ–“\Ê ±¸ØxÐV釣-cã™ Þ@}¸GåF§m”IŽ,Ò@Õq–ƒ·G'0/ûÄŒ¼© ]I§Ll]Ùr%b…5¦<#ÂÀMNQÊyd'(_×Ù2)Y /ÿ’ÆOoÃÛñÀÞ^eWYwnˆ¿ùæjÙog§íRÓáÁoXÇ.3·Ÿï¼sñuú[&¤uÔb]1À›mø‚Í›Ûß¶f;ŸG ÚÜ.°²r|ùËÃÈÀ.¹/cõ$PFºÖN»@ŸP†4{ØG ¨ŠÅ­__å·@†¼JC?<’Òñþ1†=z,Ôš.¸`q¢äxôÑ£“èo ðëa¡+i6Þ¯Á¾Œ_¯!`ù á _ý☂‘ƒ„}.Ä‚ÛàÖIpˆ^ùÊ¥Ž♺#Ž¨Æ¸çK˜[û±F Ýâ<*`óYEØr³‚¼R¿ÊQ»b"›Þòi§ÎN¸w¶‰ó½pxqnw‰‘2¤¥êÒn·wú½c/þ›`ëŠéÃóâHý©XÎcm²h³K¤‹û8x«.]|igšºS2Îþ*ɇ{ôXntÊFíÂÑOv3ÞÕX­@­v_I˜§}Öé©+i„Sk°/£¼PãÝ__؂Œ=Ž@y Ü۷(ET¼¸­¯úˆ³»§çrz$“êå¨sÒUR~ÛÎo#Ï„Ò.+oLG¤§àEí°Ÿ´’^!;wŽÆ-þìÔF7„Ñ¥œ+=çˆL}]‚MCFÙŒ‡ÚFÝäÕéC-³eIdˆµÉÂç‰éÚ·ÑÇyÛ¿ ¶,IæUW[x™&7PÎ…²ZäæEA×Û=K[ÖÑÉ¥äa°—?ÛÉ gB³“À˜ƒ:§îrñš5?o6©¬k:š¥}¶AN}´A›úü0!CSßOÔ6ËÔ:'¿ ïÂ[phìÂ/ø‹KK±ÆY;Nóê7o#Ÿh²Ê÷N‰â½.q´{Û¶½ƒ˜¥P•çHåÉùc»·vqðgweÆ@NÝå╃ªaA%~òkógº¦£YÚgäÔG¤ê£?›Ö>ò«ß!ß÷µm³Zx¦HŽ G{ÑÂ{:ª:'Ž4ñçÜ:¬±Ï?Yx0r'ë¼úÍÛãÈN¨•g]»—èFƒBv郣աڤ|¦C—à ,|Þ¦üu«mË©mÖ&š 2mò¦@Ù6z«CLÚ¡Ý~Õ¤‹ÜðêÃ=z,7:g£ `Mb~bÈ1i¬2X•X’ õLq+Me³Ïe@Ì졦58V® aÊäÜ;WÒ­` û«!ñàH,Ø„õö}]㈻a³·Ç¡úÜçÞ2âXëYAµØv(¯-ÉY­k/º²eÔu|8÷ý6éäQ7‡ ±úêÚØ„¿º0ˆ]¡ÇòY4¥küÀ#öÜVç³€7PîÑc¹Ñ9eP2`EöYŸFø‡W‰%ÿ22sîJÃrÚgÝ‘sýhâåû˜p[Œ%§]@-yÃñùR q”…(£ÅØ;±ð’ÓÛÖÙ«a³ƒ·ÇäN¨%u ïØ¡;ŸOåtÐÖ‹é-Už£úÏætËׇ-ˆóõ5µ±žŸµµX˜üw²cù,l=öbÂÂï|jýªÓ¹xÅòM o >Ü£Çr£s6j§:M6Mq‡8¬J<1·iž]©êZ.û¬3µº´qцWÎújáP‘hë@ÜbNý®8éÚýéE#òÇœ]y¦õç^Ð#ðö}&ýÅ"Gå±$'ýÈ#÷”yl¾”k/áG?ºâcaós´õöP¾×¿~Ï f¤5ÉgQÕ·g¤¾qy{öìY"ÊŽEä÷e6mZʇ°…O§Ÿ¼œØ¶m[llÏ‹ñàm„¶M o >œ 9dµÈÍŠ2‚®·{–6:±¬ @3‘ìᨠ4ÎÛNR9u—‹W>¨‚u¦šÿF ?auuMG³´Ï:,®Õz"ó‹ii³cx^ôc S˜}Kú'f@"ë4âL’×; ’´ˆ“YŽc9´ÞAµ4Š ¡üž#¬xãÐLoC'”£ôauãe!L{åxBq§vÎ Wº|È[õÑ9#zXŒ¯Ž¶/µ+gAXò­]{ÎK²C„ë@yø×ÊE=´Ý×_‡sΩäIµÇöG~_]Û¸˜H·ýù¶R}“†S&†/Kð¥mÓ¨çBY-r󇢌 ë힥N%«™Ιf•7È©»\¼róaí *Ò¸ëy×t4Kû¬Ã¢ù®ßÀ˜æ’Íúqayq´~Ǭí®ZÆRl×2ö¬‡’ stn.0—Plá& Ȧqn3ކuAMNÑðö8ò±zûr{nAø¸ãF‚ø¡‡Šâ¾ûŠâ»¿ûÄAL¼¼ý¦r üÖ{õáöË£>œo?èΑéós§|Ð9ø-yñäÈo¼K¾‡:qÈG°ß™…ßz­“‹6<ùÉ'.ù`=õÒv[ ¤‰ÿ‰'žX–·šçƒøùiX>O~_]—Ò ½î·É‹®Ð7à›¹^W‚çÅ·mýwpiÛJAnYgÑöCQF°Ú=+L%«™$N|ò“«ð”È©»\¼róñ¿-OxtQG˙߆ '–Gk~JcÃËvÆÌË£õ;fhÿìØ±ôƒò|DÞÇñ«:ö#ð@ŽMemúà½Êxø_Ÿaaç7ãùuˆsâ ÿë5ƹ¶Ì; 3ƈÚÈçõ{ï½Eñ?þGÚ™‹µß‚ÿýëƒ@“ôÀÑöaÿ‹N2fŽÖAüð€• #¶Î¼Rr Ox¨Smú®v0ùvÿÝßUñð±ü8ò£ š Ÿ}Òƒàñ H)]¥`yñ‹JøZ™zôè±L` 2A~ñ‹éɬÇP™æ²º_ŠëÑ t÷ÜçÆuHkœ_Ë'¼b›dË„ذa€Ç>vÀQÄYµÞ3‹»vuêðªW-îTQÖ/Òwß=ºðsNœ tÈ;-Ö¹B–q~N2†NèË^Ö~ÎB>ôbÁÕÍW¿ºÔ™ãÈÅmM9mäaGNWH@;€€£í;ÂVw8kú9.¯ÓcŽ©v½\ÖybN\ ¶žºÁäûµ!ÚÅ$ˆ4ýt¦àåð7€X‡˜¼*+4íêŠG{Þ£G€ÁËàfWÀNx=jÑÏeóúõkùª¦ÝA_ùÊ¢“ÉOcÆpä‘Kwô<žõ¬ê(#ýÌgŠâ¦›Òç~7‹8ï,¶ò]ßU̽S†Nè—¿\—_^íH¶Žù….êØ:ôræ˜ÿ´+üÈ#ƒÄ¯3òz‡Ÿ@¶þ¥ég Ps.NÙµãv¹uådR¿•¶r5™›.|¿?ñ‰Õy ðá‰GÚ@z ½ìîÆnÁ;Ä8┵cÀê¨G+ ~÷ƒ¹˜+Swñz¤Q§·Tkë"¦9®¾'©¯®LËÙ 4Š]#96ìFþäOV 4çÛ·ÅÁƒU:¿óŽCÅQ ²ŽZÌ}}Zø9+,»xð‚t»>Uà\q»W°uÍk>ùÉO.œ{î¹áô}¾«8,¸¥èæÕ¯.ÓñÅîÝEñ¤'ÅŸýÙKŠ……zTQ¼þõU<έŽÞß8Ê»vÅ7¾1ˆ(^x|´äÑ$;¸¶ŽSN)ŠßÿýA à‚ ^RqÄGKÞ’K<ßüæ¢øó?¯dÚýìgÅ/ýR•æñ’—¼¤øèG?Zž[y=Ϥ£‹/.Š÷¼g‘O my[y„&]¤x×éhÄdû÷ï/^óš×Á.‹g>ó™Å§>õ©û|ßûÞ.Ô•Z&äÕ"7?p(ʺÞîYÚèÔ²2©ý韆´(J.ÜMMj-Sw¹xåæ3î|îÑ5ÍkMé6¼öµMêtR}ORß,ê*û'•a0þƆv9á9Àp³+EžXC¬,z,€;!ö¼®Ì í%ïyO}Û2ÁÛ'†Y¾©ÔSO]"ìôöÙSW©·ÑžºL½}öÔe’}®9pà¿Z<þñ/Žâí­=–÷Ýw_ñ¥/}©xá _XlÞ¼¹¸óÎ;‹Þ>{t ½öè2zûìÑexû\ƒ':HëÑ£G=zôèÑc.¾˜Ô£G=zôèѣǼÐ;¡=zôèÑ£G=æŽÞ íÑ£G=zôè1wôNh=zôèÑ£G¹£wB{ôèÑ£G=z̽ڣG=zôèÑcîèÐ=zôèÑ£GsGï„öèÑ£G=zô˜;z'´G=zôèÑ£ÇÜÑ;¡=zôèÑ£G=æŽÞ íÑ£G=zôè1wôNh=zôèÑ£G¹£wBŠGydêÑ£{À>±Ó=ºˆ~íÑe`Ÿ?üð Ôc¹±&tH¿š €*î¿ÿþ’Ö¯__¬]»¶8üðË5kÖ rôè±|Ðäyï½÷–¶yÄG”öyØaýµdnçóÛßþvi§ëÖ­+íûìçÐ]sèC=TΡ¬ñÌŸØhoŸË‡Þ €ÉóàÁƒÅ®’,d¬š09bœäõ ~ÜÐäÉQ“!Wòš0 còÉa=òÈ#‡*Gl´·Ï9ÝaoÚ¡ÇVe§Ø¢€ÝiAç\s/¶i}êçÐ9iNdÞÔÝgáíOçØfÑ4;²N¨5jÂݰaCY–2ä…‡.˜ ñìÑcÈ>!PæHì Ûâˆnܸ±œ5‡j¹!sæJÎ!ì‘ySó§øôè1 °/lNó!ë<6†ÝuÔQ¥ÍòÜ2¶&…v§5\6¨y¿@s¨l·Çä8$P M“'†‰¡²`s$ ãÂh1T Q@U¤+ŸT'#Æ@)+Õ¡BäéµGhòäÖ&8ú裇¶CZ['”råäB”Å&YðeŸØmm`çPv—°)ìÛšë°SkƒTYÎÊØ9’#<±Ïþ§ãÛÁƘG±OÎq6˜pBµi$Pû„(K`{:'¿lQs(Gl´·ÏñqÈ9¡ÆÇô2&J ‰ ÃØd¨œÇ€Ú4¡Š€ ÓN˜ S‡]ð{ƒíá]1abO÷ÜsOi#›6m¤VémPv¡byà!ûåHÛÔ„ ¥ø÷8t½`›ØvÈ­0‡räÂIsé)„‡v¢ÄSN)åáEš7áAœŸC{ôðÀް=9 ØvˆÃ‰Í±ñ”rB=´ÆÃ‹#Àe£œË¾‰Ã6E„c¶ßc‡Œj'OŒE#aǘN(ée“êAYøAþ J&qÖ€µàSGo¬=4yrÄFpBAn'ÔžÔ©1¹&glSöÛÛè¡ ìƒ¹Â°1œHkgã:¡önüµØC„µ?KئæP(VOCšÇxÁ`ŸØHZÇe¿ºßä„ZèyRlMó$Ðz.û“}ççÐKqH8¡4‘…™ NÏwk€Ó8¡ÚÀ¨Š¡Ú+(@ˆtÒÈO˜zDý‚hA“'¶ÇQýÏn=iÇsÌ g•7·joˆIÚO²Zð±ÑÞ>-È>µˆl„9ÒÚÂ4N¨v®[û^ÄQ‡æPÂZðeŸ±z{¬N`#¬§Ø¨cÂp@± õŸµšÇï8Žã„Z»Ø6¨u^}äÑs§È£9êí³ÂªwÍ1&CŒIMÎer‡&E –‰˜#a92Z0r1(¸ŠÃùà™5ùöXÐä‰MpŽÝÈþ–s’b’Ô¢ŽȈM²;‹j,a¿ÈÝcõ‚>ÖÊ"4§ÍÊFá a‡8 ÔǼMXòÈö8B8 Ø%ö‰"+2÷ö¹ºAÿÒÏEì„M&ë€æ†ÖxìRãA—H ûÄf±OÖwl”ù”8ÖøCÙFWµJÇÓÙLFLJ„¹2Òn¥Ç´jÊ4™R/*„ñ9 ,è-2r”ÌšPI'o?¡®h²¢_u@SÀ>d+ó¸@Aä²WñÈ Zð™T™üç%Sù€~ÖüÙçè5Í Ô‹ ²àk•ƒÝiL ¯æPùo~ó›Å]wÝÕ_4­R0ßЯØ'ë$G€3Ø4—‚\¶@]ÌÔ«‹&Î2ú5bï/šV©j'OG&#Œ„Ûš2Œ:´1ÞiÀä‰Á®žürCšP9ÇX¹Íðo|cxÕO¨+š<écìM jès&,Ù6v Å•¸yØ‚&[í’"7vÈ8ÃIÁ>‘qž2õÈ;i±¤Ï™«ê@9ì¾W874^°CεKŠ=Æ|d± ~Ñ´ò!;£¯!œ8ú’5~Öëw ö´ù$Ç»Ã>‘Û¤Äa“Ø's¨æuÒVûºêœP?y&,ŒSŽ_—€Qú+(ÛI*KceÐ1™ÊWP+ô+ô¶Ù4iÒ¯êsíÉNì"K>øÏÈüÚ%å;„ûdRí/šVäÈÑô¶…óiŸ¯‹õ#ýKY <6 ?âfÑÿZðí&Î5®4orDŽOŒC¨¿hZ9 Ô§š÷˜=öØ¡ã×¥~Ô<ÉÏ8J]4ÉFm»…‹¦U優Cí䉰@jB²èâ„£ ÕÞvÒ” ö1áCj+*{(]A­4Ðô—l”>ŠÙ¥ >—s‰M0ïíD»é€‰ `˱¸² /õjBí/šºì~Ânè+ú çûª³Uò1ÿúž9È&±yìQó2¶?+`wÔÏØÈaoÈá|d’}Ú‹&tÑÛh·@¨¿82/rÁaŸÿ¬³SaýšªCswì¢Ik¼ì“0GÚ)ûd\.Ǽ>+¬'”΢㘠íä)ô¨3Ò.u*rÚ+( W¬öbŒ´•I£<”® V°+ú>u6(PFýŒóÉd+GœvÓ­3Û%×â*ÛEŽÄ!‹GÑÔ- {ú†¾Ð"Ø]’=¥@æúXý,;¥ïýî}ÊÎÊ&ÅOs(ãÇßiÒ¼HÛ Cví/šºÍ…ÌcšËÔ§²·&´Í7O`Ÿ'ºx㈽ÑF­ñ´_cû\-M+Þ EéL <|®I´™g=†rcE;¡(Y“'G:„Iešç?ᩉ˜Žìòbˆa² 31Ví‚Ñ« "#õWP¤­ƒ]iÞ9Ò_šdê@¿Ñ?ä•ã6)Ä»ð;RØ7¶ŽMhg!‡´i#y£Ø/² #²Ðní’öM³‡æ æO9{¡O<Ô·Ì‹ê]èÄú=ÕoâmRì€q"›¤,áºù©­¥@YYR»µ´¶BV6쳿Ó4{ÐïZãé lNý¦]CÒRö¢xÙ9}Jߥò[ÀwÞP;±KƘÖx€^Ð‰Ú ›ekÇV‰#­M—+Ö E¡š<™è:,v ¾òé$:hÑgñÓ:i]^ i;‹:ª+( WGƒ˜6ÐV½1¨1XŽ LôÙÕ6®$ CMžœc“~óz&Œ­1qÐL>¾ ˆÅµe±o]iCšÔ4ž¶0/{G&釣. ‘]ø‹¦¶‹Fz GÍ è}3oÐM6F~Êi7ÊæoSÞ‚¼²Iê·6©yоŸµMÆäàHWØ2æˆlØ&o4c§]_'VÐ!6 ɰ hûè39ŸZã±/øB]é»TÛˆ×o/šäïhG_Zãi¯Öx=’Ž.º‚é„úÉåcT±…>Ö¡Š“±Ñ)L$‚®°èlu2uÑ¡Ô×ÅŽô Ò »‚²ÆÊ9ƒåö“&TÒú uÈCürÚçŠrBQJÅPüä©Ý“q@YxÁ‡ÎT êdŒ”–#G9:Ï^AÍV¾¶ Lì J»ŸP9g‘ׂ~V‚ãÝ ?9GèÉ¡ ”aR`2hó&ò¬`åÅFü.)6€½Ó¾YM\¾Ý’ ûeÁàHœ&TìÕB….ç1W*4wAZpÑ)s(óˆÙåÈOÿlc’9×£©¯Es³lR󴜻&›Œµg\ÀƒöR72 çØ&6ì‚¡cÍ¡g9nVкbÎa|£KvÜ5/Bãè>ôåàaAœì‹~õs¶¥¹¥«’ [ÔÅöÉ‘¶‘n×xÚÁ‘vA±‹¦ybÅ8¡(ãDYÔ~ò22 ſθI£> ÔOBšX,mµT=³²[Øç'v+;í✣]ð9bÐjw ô?“'/1 ¯÷Ð7:ز&ÀiЦÞ6À¶S.´“1¨‰‹¸im¡MyÚ†\È1&)‡=¢wÐï/šâ@Oè„ Æ0:bÜÛÏÛÄ@9õµì³ÎÆÈ?+½Û…–¾GŽ”Mæ”Á·—°vÑ @ cìQs¤Ö½<¢õ‹ôãfµ= /lS6Šžc;îM€¤u »…·s«{êŠÍyØ™ÖBžËá¬Ú‚ÜŒo9×òW°OìÈ>!ì»Ô?¯‹¦á„¢'åö“'J)+/ãAÁD>¨-È«Iˆ&Œ,ÔEg2B9'šIx´)ƒÜšØÑÆ (Ë`£ Ò=DÆ»‚ÊÑΕÚŒ-¡ƒqÚ.Ñ!úf‚”Þ—±q@\êÂ…v31c'`—@ýè ûÕ¸F¯Z|4¡"Û<åêÐ :Ð8…ìÜç!=‘¥y™#ê 9‚ùhîPßärC)›dœ#CªïcíƱ;‡ÊyÑ|‰íô@œftÛ_4Uz¦ýê+€>'™éOø¡_ôª>±ý\×çy˜ó´Æ#‡Ê!'ëž.&º>·h§-è‚vé6¨Ø Ú§5žv‡íængçP¢É“Å%`Þ¨Ú‚ò(0aAÓ9 :cE6ø¦ƒt"O×'µ…G[4±Ó ”~±¢KM¨èôë_ÿzññ¼øÀ>0à¶ú¡A¬‰³MR½aL ©(xuubÓ¤æ]€`ïº8¡­ój:c‚E6ÉCß 6ÊnÔÏüÌÏ ûkµC¶F?hº ˆA6Ìg¢<Î@Ý\I=è›V(žù[€8Ÿ•=x›Ô®­ÖyÙ¤Ú/çE Àî…#2@è™5‚Ý?^pzï{ß[üõ_ÿu™ÿPýCŸ ú}€ÔO\]ß‘¦µ*õxÓ¸}Oyósué¢b¹.&bzJAm䯨-Ø#ö Ñ.ÚAœÖxìó3ŸùLñ®w½kÀmztÖ ÅHh¼õ©âÿð¥W74yÒvú]A Õ§”a0s$/:ÖÞ–È/Ç`#ŒSâÑ36¯‹°:{Ï© x1Æ‘ BßÌ#o{ÛÛV¼ÎÛ=k1Ö"‰> Ùi ÌKš+íÏ! ¶eÓÌâ¯9P²ô?öYÍê{ ¹+f“Ôü9dˆÙq´Y8ׂ>5 7ô‚,,ò¿û»¿[ü¯ÿõ¿V7h3:€›Ø«Öø˜>›@yÙNºñ˜¶¿‘>Œ­‹Zãs`\û·Ý¹ÛIoÞ>9~ö³Ÿ-~û·»LÏN:¡¾#5y2jró@‘±Î #€F޲1Îyú‘EçjB–¡©}›èI¡º¦…Ú‚ª-.qÈÍ.è/üÂ/”GzžÑ[­ÐäÉ›l£c&Hí,á°åê—®@¶‹>hŸv 8jÑe\cïºÓ‚¦±}•Mé”xä¢~l75¬ æ]ãt1ïh×=¥kâé'l•qÎ\iuåõKÿɦáM?{PF²Öò¥ì!'R6I]P“ ucµ¼ÊêÕzqŽ|èý—ù—Ëùó?ý§ÿTüçÿüŸË2«èCHúØ›.fÛèÕ>Ø"@Ç1[œèÓØº¨q£91ˆ½ÓÏ]@̦‰CnÚ¢±B[Ð%rÿßÿû‹7¼á Åßþíß?ÿó?_|å+_”œ›‰1kÊÏ<­Eß:u=h§[€ˆ—=0ÿÍÒ¬MrĽ ²IÚ8KP7zÃ&‘墋.*Î<óÌR¯ï~÷»¹VèSôŠ®µ Ú ¡ƒ&È&e±l»‚—òx¤âs‚:A6NßrŽœŒKdÕÏZbmÜžÏmëQ[´ãä“O.¶mÛVÆÝxãÃñ? :µÚÉ“ÎZ¸&1ø©“™P=Ÿ¦Ž˜‡Ah2T;9gbbúÉyæ1ˆ&i7r=æ1)Ž?þøâ~àŠ;ï¼³¼pXM@/ôƒ&ÚìûCaé£ ÛN´90I?ÎvÑeLrµ­‹0ÀxÕ=ÉEXÓøÚ”o%]¡3ž-D‡Ì„‡´Y í^¯äcAÁ¶é#l´NGäã<ùb6íÇA ä£ÿý¥ìzh kBŽ‹òb2È&©`“Ú¤P§O@úSžò”²În¸¡øÄ'>1HY=@§Ì…ØýÊÚ†mÆ~d¦ è ­‘ê¿&=Ï´‹¹Ÿõùh/qÌur™—°õYÙV ëûãÿøâ¼óÎ+8P<ùÉO¤NŽN8¡4ŽÁÍà£#èMB©ÃwylŒ¡G‡ãÜYÄx*Îóž3µ@3r¤]³œ'…daP1ØXHVÐ=vI?`'ôŬ,Ð nl‚äØÔ±u–£­ØgêÂv¥=hQ§}„q S»î´]ºcþ°;šu eÐ?ÐÎάõˆ\Øv¾GnŽØc“ã, ö1§l½ƒ\ã¶ÑÖÕt¢5Bo{ÃŽÆ…úÄ^8Y>Ö¾—M2 'ö­±„}é‚}1–Ys8bc9m|ý¨Lî5~YPÅ ¦QçtHÓÕxàƒ#ËDŸI&ÉIê5ЇŒV“!²&CŒý1Èíd8I[&-ƒ|L 9 t9A›4yª}m(3éDkìš>†ú•£ÆâˆmÈ‘ ¨Ür`’1ç![×EX¬­± º©îÕdŸ@ãŸ>Gœ£#tW§ lCszmÚÑdNÑE`~ñ'Þ¹m¾Ìwr± ÉKÛi‡Ú¯]Ò624å±éÈ`mâ\zMbcÞi€OL_ªkµÍ¡è‚>Ò:¥~C—1HO©¾‘ ‡ù»múcÞ@Úa[Øó=²¢;lâ<×Ï$ÈmŸËæ„jò´Š¥aL0tFÊ@𠔉€z’Ä%&³Ywö¸2ʤ&C»œµcžÆJ½È³ÒΘì4á¡[¨I—ÒyÓÙ†—ÀÄMŸ2>Ð-eGœ9¤¤SŸøRÂ&oó´ƒI¡¶yÄÚj'héþ’ƒô¸ÒAû˜›è[ÚŒ¶/p¦@YͿؓæ\ «?øÛ]§:ÀB.@ÙYØžkù± æDú[@’úgêÆ&åLaW„¥[»¶Ñþ6: (C›V:dØ€æ"ú šèOú“€ò1fêæ‹å6aWÌq£¬ñ´WúÔϤ²×Íu îœküÜPf'O“'ƒ¸n2LcÒ"„rüBãáã‘ å&_ÛÙÈÛFžyC“!úÓ„¬]R€Ü ^tN;Û´a¥ zZ鋼&Ol“6¡ß&} Sì=&q'È…~x]˜@@vLyäÒ>«Iwžã”U[í­¶Z'„±‹íkt°Òí]ÑNú•þÔ#L8ˆèó”>ÿèø–kcð½€ã_ñV>䜥í!+Ä|G[°úW({˜µí#ƒÆŸlÒ: Ø Öo“«aÕ¾uA€NÐæÅ¦~°éœëùzúvHÿ@›ÄÕÍóFJ'Øc×Z@Y)£q†·Yã›ÒcP™Üö9W'TÊò“§œ( âë …ÀOWé`AŠL¶³‘YŽmÌMz!ù5ÂÄ#3 ù1$Ú“’6©ÌJŸ@éSõ­w>9醼úX7:'Ÿ-7 ìE΂Ëq ûeÒÒ… }Þ¥I7еœÚ É ¡O°wˆéK_ZÑöI›°O;–égë ¦@ÍsèÌϹÔoì]6í°¢gÆ€l_s(v!›µ=òƒØxš²dÖ˜áÙc¶Oý©6Y´ÉcA~ô+§02x›ä\NÄX$Ns÷Jm@¯´{Ã&ˆÃ>ÛÎa^×èG‚°ûÙćòÔi!šë°Oú[IÍÈ߯¡›7hrÛ5ž0íAGØ66Ž­ËÆsºáŸs›Š"Pˆ”D'3H!otu°y5©7©Ră´<à ÙΆ8'žrv"¡}]3VÉ£f—&ä\½Àk%N ´›Eоd¢Rÿ7A“Gí,Q®Iuy#ð´ O ꂇì85éªíÓØÀrƒ¶bï´¶Êæßûöí+þÃøÅüÁ/}éK‹;î¸cPje€¾aÌâLË‘£/ý£GÞ¶8gÎå¢_vPòk~мaù[ÛAøúùœsꤼíÙß,üTýÔÍ‘ñÆy¬þ¶ò¤ôHƒ°AÙ$º"Ìœ#§ºþäOþ¤Ø¼ys)çJƒtÉ'Âp>icÔÎaÒUÝj.$/|è»qaçSôo,~¾Pß`“ôÍç>÷¹âÇüÇ‹ .¸ xö³Ÿ]üÄOüDqÛm· 8,?d[Ø8òc;ŒC]Ðh÷6®~h •C'^Ó`.N(ÊÐVº”¢ôLGÌ› ^ðDÙ'|Rˆñ Ž `@:õ!»7 >ð£ƒé Œž6×!Õ®:LRÆjB~ ‰sâ5àè0®3¢¼ôKN>ƒý ÄY 3&\â±lcZ ?&púi ²¦&]Ú ä <­Í‹˜ÞÇ/OXNÈ–-[ŠŸú©Ÿ*žúÔ§–v~ ' ruô ö&%Ìü‰ÔéŒþcbl£ï°z0î™Ï@ñÆVȇ=Õñ&M¶‡,€1ƒíÙù~·ÞzkyÁÀ/°åZðmý²}Å£WêW{Ʊý¶ù¤Ž´ ºC&ô޳Ã7–¿ç{¾§øÀ>Pæ_ @²Ol;b^Ñú8žàÇ\HŸYGVémôޝayp¬ƒíìãË_þrñ¢ç?¿øÈ{ß[ÜúþOñÅ@xÏ{ŠóžñŒòWƒ°Í«¯¾º$٩⮹æšâ _øB7kXÛ¢èÛ‚ìü.§Æ]ã÷\˜¹ªÉg †ÖfòlÆ›T½Rcu(²ÈØl¾6r‘G‹›&_:ÞÈF[!õÑ% oÌ©èF‹ý×Ö`1Pø¬Ð&ÚI?©›úŸ2èÅ^ÙÉòãö7ùe3LMÎB.P‡tÕú dºjÇ \ô-tÎ9çûØÇJw´‹ÅýCô ¿p\býчìQ޾Õ<•cž‹*Ê¢§`yÛù\üëêJÇÞd{ð`NeqγŸ]¼ï7~£xϯýZñ¬óÏ/ã<ÚÚbJÉKªŸ±`mŸ#h;ÿ¥*Kýè]#»ô\}ï÷~o)ÏJ€ô…ý0WÆ~ÐiL÷ŠKéDñðD/“8²ðÃ•âƒø‹¿ø‹#¤ròéG†5íûB˜m%.ϸðí Û«_ýêâ™O{Zñ¾;‹÷zv°SæŽï¿é¦â½žìø²Ë.Ëv!C]Òf;¿ËÆóù8ó;ièdÅ8¡l'OÛNn4*Öð˜¡bÜ(  ;©êØxè9}lbV1¹b @ÿu¶?©Ý âGÿ¢OÚË##]2£ le]Å‘¡ “êžè ‡”#[x`›ÌWø –‡Žú§Z<ûYÏ*~#8ŠïºþúâéáÂôío{ñœç<§$œIáÀïÏ‘­öbùR3é?';=-´ùÔ@k‚Ü×^{mé´þQˆ¿?ÈpX8þî{ÞSœî¹­Ñim)øÊÆ9§ŸtîçwúÓÛ¸{‰Šð~ò4%LŒ]“*Àa xpd²MÉ’R~[¨ƒý>²Kè¨=³À4íÐb¤AL[hºS0ZŒ—6PíÖÀï2U“'²#wPŽü”C' Ķe=T~Ø$ö€C‹ž»l;n²d— ,7šú¹»nŸ@v†nµ0Ø‹ž:]S"ß±Ç[;W‡>lûX’æ-@ÞIæá&ðÌ+6&Ðêa¾fÜÊöÔΔ.¦±GÙ>ÚÌMh²MÏ.Í)Ð^lâÂûAgØýT§éÁçA·š ºé,UÐ*¯µ×ó`ô‡/¾¸8:Ø®¹×†2×þâ/Ÿÿÿ£¸-ÐE¯|eñÚ×¾¶øæ7¿Yð4©jbµ†!yuô‹º'ÈóÿðÅÝA†×†0ßëáƒfüxõý¡_o oÚØQPz±ó;GlÒ§Ø8s6NߨLî94»Jb“'š2¨˜â•—4øaœÄ¥n¡Ùüâ<ðLžÊo‹›·ß~{ù\Óu×]WüÅ_üEñK¿ôKÅ«^õªâ´ÓN+¾ã;¾£xB¸Ò?å”SŠ“N:©|È^-R}qrÕ$çK»ô ýL¹÷¾÷½Åã÷¸Òº ÙĹì2Ön 9­ûA)´á'`“ä…§tZxÏÂN›`m@;E’W»ÉÒ©&¬I0iÛÚÖ—{ПæPŽÌ{M=è@ý°©˜C)ŒS9SZˆêø£;v»vÐvCAÏÈ¥n{Úôßú­ß*v¿ÿýÅÁ0Þ®s'ô`hÃüÈ”ë:@VlöB±År´±9Újç?êDúažˆÕßV&ÆR×í“¶`c´ÛA÷m.`ê?;N9±ð OSsôïüÎïG…ú~$œCxŒ˜ãQ3=EÜGöì)vÿæo†³j”Ù_·ã±Îé©? ´%à÷Ôׄúo笂¿‹çÞàýÑ?÷s?7“[óml¸”—k~çœxlœ~F¿ùÈGŠãŽ;®<Ï…¬N(†¤ÉÀOžgÝ@L¥é*Ëy¯b'Ëc\`lçŸÿìbçÎ÷7ÜðÞ╯¼(½øË¿üëÁ„¹>\i}+ œû¶!8¬ò\X|ô£-usæ¦5¶ è-\,èò7À兂'?ùÉÅ[ßúÖAîîÑ+=ÒŽ6úÄuáŒM &p€ Ødžó‚tçm@ºdÂbü³(£ï6ãlÖcQ`~êê"äÐ3?0ï‡} k={}Ö#²%õG ̉ÔCÿ¡›ßòç™ ÔÂ.WàYÎ Î?¿ø/¿ú«%qna.Ò•þŸåWŠŸ¼ôÒâˆPþšpq~î±Ç~½úÕÅgœQæGFæoôÁ;ô‹%rR›…Òë± ¨Óî i¡>ê•c<±9<ÉA9ß]m¤}´#öÊúŽ$3Ç:½*ŸòÀîϲßqú†yF›LØFJØÞÿñw…óÿè·Q çgòâ@ÌÌ<€§3ú¨@X’¤3ûãï ô¯í¤tÊ2ÃàÔþ` vE©ã¯}­|NôéO{Z±mÛ¶bÿþýåø¨»@kÂ$ö+ÔÙ˜·qÍï7ß|sù•‘½èEÅ¿ûwÿn{:dsBQ†Œ ã$ì'Ïêà)E·)¿2`œ9ìÃÉãð™ÔýØ… ñˆ0pÿ8ÈòšËàb>6½c®˜ý“1Ö•Kk1Ò‚ÄàŸÔà&ikÛ2äcÒ@¯¿ÿû¿_žóVë÷}rw èç™mû8é–8ô=c?M °âˆg¡¡i²É&íwlrš /Ù€Æ+ 0íD9ì¸ð´}šN‹fW# ¡3¿([X¢S`æ:ì)uS ? àïíÚ–¥9·r6Rö ?úèBŸ»#‡¹ÞþøÇ—txï{ßûÊ4ðþ÷¿¿Œ#ç?7„r…:ÆÛ3ƒJýŸÿüç“öЬ~±D_ëÙÇqÇtE{Ѥ5:5Úbû-9¡]mbÇ&бý,ݸ@Ò6Øö$Õ%]ÊïÐxáÓ36ôŒà~é _(DL,„Þâøì@8“< A˜ÕøïáœR#£#ñô5`å.wpX!¼ʱúǨçôÞ`ƒ<ðGa ðÓ³Î=·xÏ7¿~à ås©ög<}:[4Ù úfLqäYe>!öó?ÿóå'«r › äðaH~ò¤±Æ{ƒL¸8ƒRùRð|8ÂC2194ñÈŒÐ[nùßAÌùü@¿ˆúQ¹L˜aÀŽ‹À_âzéáâÿüŸýÅ?þã?–]2ð™œ+ÔÆÚäñ˜¤  “=ðW\Q<ïyϤtô?úôv@Ø·Ôâk/‚¦u0éÒ—,œ Žç¤õÅÊ•6yÁ³‹›~óý%qþ[¿õ[Ññ§i'eY°]-Êœ/;Fèµ­ç„ú³«ƒÈ¼—Z”mÿh=ꢟô”^étàspÆ€un‘)úRr9brFÒᇠ{<â¶ýßÿ[\ýwWÚëg>S<-\Ôb¯u Ý´{c¼jŒQõawN zNéÈBy¬ÎS ýEÛ­S,ÐnÖ$ÆçÖ)V=ôMž—rìi+ö&[ÔÙ.i+¤yÂ급 }'öúë¯/ }CˆsÉe š¦V^Fq8pÁá¶ú{±eÄÝ8þQ ¶(Këå€"=eáMåÀ¿ D)åÈÃ3¤GY íÇ4´åè`¯û‘)wG±¦ö/°ß×½îuå×r «ªA…AychcT#ç3!âå'Ij/ÊêVÆ ¬Ï\éß?·¨?B˜2“>'s …^xë¹0IL˜s™8Æ·¡|ˆ™΄¤É Ð6®&3Úh'³åD×'Pl °@± b‹,¾º‚&d“,€ô§ìr^(mrí‘ÅCï½­¤û__\zéOÿão¿XÒ+/¼(ËóÈ^¿Ì©*kÇvq›mÊRWWPlKöåe Ù!ú³;@~®´¶Ê9mçÂJNQÝ‚M~ïܦÀ‚‰ÈEÿZ¹Ï;ï¼âÛÇ¿ÿŠíÁ©|8ØÂýЕeÀE]T<ä&í_übqo°‹r6 <ؽáôÓ‹ë—^ziù²HÛ|µÏÚqغÀö@[‡t\ 9ÅBÔÅ<àb §¬«œèÒ_`x¤t*§ÙIEoè‹þMìä-oyKIó7SÆÙ\Ì:X¢FΟzz œKz[í¿lwbåf5‡àGyʰ›jŸýç@?žrN—b¬˜Xsé¨Û|×»ÞU¶ ûÄ>Xã›ltý[†ú!dÊi£ÙœP4‰`R„&Æ9 Xìá!÷s0IIáÓƒ‡yò´ ×P˜íÿD<¦ŒYòdÉYúXWìÝ»w8Ñ¢#µƒI =kQÐ>«É,‡Üã¨êÓ?®q/7Wm`qÄ~@jñmÒ¯åèk“,JÒѸ}E~dœ¶Ÿy$Øßº`{»ÃÔ}lùòÜ,A›µ(ãX;–S‚ aǃmÑ6/üsN 9Á¼Ç‚ êÚCúaÜ£K¿äÇùåìÃ_Nxª]ÔÂ'æÜ•¥¯p@ÉC^[7o!¿î’KÊÛ|ææ¾@¿õÞ÷ÿê_ý«aü‹ñ/Š?sÝ÷g”{=‡…òƒsóÜãYœ¨ÎpóÍůÞxcqî3žQüûÿïËG—šRd’íÑ~êFÚÅc,³àÇàun!^ô‘æo]ˆÊ)¦^~ÁkÏž=å\ñÿþßÿ+Ët È êÚ[—¦ @_ÄvR…T(½ÙMìâ™çœSüÖ 7”ô·û÷—Nß7< fú›ÞùÎ⇂Þìã¢æþ$«4µ”[G›7CÚ߇:p*y˜„í"¬"/#†OFÊ3Ýlø”pñ„\ÏažhÖ=OžE%LÝÔð“žOà3ŸùLi#Z'° Æ.ö9ÉÜè1MYd¡¼æÈæ„M„±F¢ÌºÆkW„AÊd¦«¬T/#„€GÇäQ˜NÖq’NÍk^êFž‹D'L¸˜î³á|~.æ OLÓd×Tqÿ\üÓ?}³¼¥›`5™aºÂG_ȉ±¢ô©vH7m0N;=¨;§qæFh·v–´ ú+ýqô(x§¶Î&›€ŒLDȉ]ʱ Ž¦~Ã&×?ôíâð>=\=¡(î ¶vv—ãÚŽµc&\Åa·š8Ò¾»ýêã®:¡@sh èA$g¦Î.ɇM³xÈñ¯Ë/ÛØkLÊËé#úgÀóå-äPqñÌà$?ûØcËޏÐaNS^ÆÚw÷w—ÇÂódz Þ<ÊKI¼y ƒ¡,%Ž ò¬e‘ñ»w¿ñ«¿Z>K7Î.>u3¶esØ`jÁocwãÚ= .æ9ÅÈÀ§©þéŸþ©øøÇ?^<úÑnt®—²‡º6«o}l [Ô¼ZgëâáÁÜ`XôæAYê~Ï{ÞSÞò¾-”Ž q‡ êf€Ö…~ç‡~ù—¹øÁú¡â¸ÇŽ$šçrðÀë‡ø‡‹¿øïÿ½xí¥—/Ù²¥ØÆ…À®'Ïzb%©4&€[Bù›& :—Ž(˜r©±‰W´<ÀD޹qÍ„Yóó]tŽ&i˜fNÂ\'‡“Âñ·C}ëGâ¾ý„1 Mfèù™ãÏ(. õ?}=\—ló×¶‡‡+úõa ½ïžâyÏyv'^&£ µcµ6§ì¸l´«HÙíæYyÒé嫃l¿ïËR—.p¤ë°EãEs¶ÿ{ÙÞq<9ÈñíÐ8Z|Eƒ– mžùäÙOˆ|'…¾?ï¸ãJÇôÈ~‚s¸Ñ3ì/ÊPþ^ýê©wi‹]ðå£#ô£µÆ/øuýÑÆ6•ûäg;ð°–çr¡LÊC›°k[M›Ly¬ÞëØ3ýÁ| l:ýþôý¯‹ß|Ç;Š÷Ýxcñâç?¿xÖ³žU:…g„2·ÔžÂâ%PµlägÇò;toˆ_pPŸøÄ'.íÃ0±ƒ‰ÓÈ‹F|o”-¦¼øÅÅñdz†/bmàųь æXŽ>;f„Œ¾§Úê|h0Vd×èÅÎýr‰g}À~XwÐá%rÄâÚþª3ÆóÖZ"ÖHoT,úb Á.ÔªxARø¤Š¡,ƒ„IšNõ .DMJ&i&¤Ï}îså³I<£ôÊW¾*¤Ð&6âùX¦zj 'ªn·~øÅ>ð;ådS™1ì×ñT Ž)æ\=ÖÌUˆé´ Ò!òÚ+|&OÚ-gÚ^áOR¯.ï2y`ƒ8wj;{Z ?9FØdÛI·ô2âLÄddRÂ~UŸò ߜ奣Ïÿý?®× ÷}áÂïÈ`ëïÎÂo‡ëïÇ–»÷¼ðaw¨æ‰:»Sû°­”sŽŽÔ—)?6λo+è…q¥9J·ÈSú"žñ ÐQÓãœsŠ]7ÝTüæ»ÞU¼øE/*íˆZûº¿†óúèKû÷—¿ ÿÜç<§¼ íÛý•ïS¡®µÁ– íþ›pή趿ýÛâ'C}쪮z°Xâø$T. “›Áöh3ú· >:G7u6ܳXäs}´ikmµåA9þè>v— û»øâ‹‹uAw_ù¡uaœ¿ño,žlñÔ³Î*žœCê"¤#'óP¬ïS¨Ó)P:G{1„Ig8\ôúO-øuõ(/}G¿u´£N·j'NÀïÄ·:„‡.ѹ×áŸüÉŸßû=ßS|þs¼g1Š/§ñ÷?üá⋟þt±÷þ¨Øúå°­Æ^%ÛDâWîÆÝÿIHÿÑжµáÈGí©“þƱ|ñ ^Pün¸ÈúR°×o…tžÕêÍ+Çð=6È¼ïæ›ËUü…Á1~~¯¸ðÂ’¿œHŽÿ{÷gYQ¦ üL€! Á, bV‚Â"A Œˆˆ ë6»ßîºFD” ‚’³ˆ”  ˆ¨ˆ˜3Š" a&|õ¯ÛïPs8çÞs{º¥ú™_ͽ}n o=õÖ[™Qy\ê´Ýø£åyO«\9ï SxÂ5EÇ9Õ—æAYò¢n–m¼ïfÁÏÑb<ô瘄¶4žG#¡á ø¢ÁìGê&¨¬*~}t¨K8üDÏ5 «Nî.ðÎ 'œ*Ér)<ç€24‰Ô>ÏrDÉý ³ò!¯sæÌYlXF%Mß’“ný Ë6Hn•êQ2’:ön¹!TT4ÏÈ”“Êß6¤ß%ˉ y‘7²—ÿr¤¨k>›üE#Mq wŸâ÷¶8£cdiì£Pzën¸aõÇ[SçÆ¤ƒS¿úw#œô÷½‰k{&ZzOâß#Y-Z~¥TæóªÏ|&%™øû$#<öÆHqx ¾OT/bIƒ!½¥ŽòYç Þé”ã t~‘[½ƒSçftØÂoüÞkÚ\QlcÒ‘GUí™:ÛO}Ö³ªåS¹Øù¸YØÊŨèÌôÎßÒ÷;’³Îó3k¯]ýËSŸZÍOùyï{ß›G‡O×§t0:¥‡ñj„tÙî´Ä#Ndº |’ÏX‚ ð,yôÝó²ÁW¸ØޙȤ.#‡|JýZ¢‰Ãu›²kdò¾eFÛm»m¾ Á½Vvõä?ò]KìùkSÙ3*qÀñJJÃôùùÉ-ŸÒJWºè¾ôûâëSÚN<î¸Åë1O>ùäÞ&§Ž‘V[“öLiÊø»2ý¾BJ“4ºúók)gŒf†Ák³Ô·’_­¾¡8þïN²b°×³0Å+M£¡mP?„U¶ñÊ"Úxz1tã úe¥^ OZÇ cj„J×D®z&¥KFêaX<+•gW¡„²ö©JrF°¦’.dtš†'N#Ÿ”ˆ%Ë¦á ¶{~{^—ÆóýùRMn**£Ó´¼~ÐŒ|TÃ0¤«£©š ßäHÑcõIFÒ[öð—L{ñ·²íÚ>y–ƒ6¿ÑHû=”nWÙ×á=ŠA:£,†I#¾8ˆþì‹/ëM¿S. ’JÆ;6™ŽOF§¿ï¾#õy?WJœýR2P¿”¸¶âÊù:¹Ñ¤´y.1L^ëPŸƒÇŒ6eÌ8.<Þ45{ÜãªøÃÕ~䘴‰‡È¿ú†¯ø†NÂ`õ©c/ÏmYY ŸÜÚ ®0Þq±î׬¥…x@úÛt9Ãòç?üa5çÈ#«7ì³O^kwT2F§¥r¹4é^F£ÑËÞtS6L–‡¬µV6.­uœÓu‰ÿÿ/ýžëCúnÇ|@ –M~×~Á ªÝ’ѹOŠã-ïxGuñ7¿Y=ç9ÏYl´‡ñ#¿¥Q:¬ _ù‰ß•[Sƒ†ˆ»­ÁŽ0B7MdHg“\< ý òÑ[m ³(#œkâ³Ùš=vݵZ•Ÿô7³JÍ!9-ïZU-ó ÉѤ Sc‰~gh28-ë¸öê««ë¾ûÝꯩ\˜ÏS´Îóéï}Äqi*±æsŸ[í¼×^Õ½)ŸG%™”†#£Ñÿò©Ìcw~Óh¦­g+'ž¬µþúy³Ò…_\]œŒÍ=§ïN|zz’Ÿ©úÛR>vÍ5ù$ˆw$®k(³Ð¡Oð•ŒÛêGƃŸÃ3d)™T&BÙÆgS¦ã·€0€˜M=¬~ŽPÖ d4¤áõ¨®¢0@õ…8þF8{Ä•—÷¿ÿýY 12T47L›Æ*ƒ-”öŒ×CÕw»u™Œ5"|D¥È¹²‡/íAVy(Ëm2(P €žuW6¡žç²‘–“%„K¶dLYŒF–”ÜÜ™IÍZëiúý©c#½÷ÍK ~Êç ©Ósø•UõÊ}³²Èƒðžýìg/1‚ØÔhŽ5ºÊ¾ õ÷•©² ' uعü|úÓŸÎke'"bIúWYe•¬§êð[äW~z:èþiÏ6>¿ÂHˆz݆¨ë¸X_ `„(Öž–8GØ€ÁGÞŒ´æšÕÇ“aéX¦=gÏÎa\|É%Õ»ï^=+гV]5–¥öÝù Þ?ô·¿ÍG49’‰c,8ªÉô»ç³’ú}ìcYGÖ7zÐíÊ_šµ9òêYèßÐa°´Ü«CœegH™€xÄ)Þà+ïLTÈW—#ñ]ôVSz Ã&þƒQö•’ì´´Ì1!•­¯á¥«U•š;R\3’ ?ÞÁU-·–ÚZPš›äÃ@ŸÂg|‚ôJ†q¾¯Ÿ Gºä’K/­vÞ{ï¼ñ‰ÁFãOo¸¡®Z3ŒÖ—¦æ'ž™:l8¼Vª3NEÀéãO:©š‘:ÍÒxrr‹´]‰¿çÌ™ó€5¢Ò×á7tc[ýÀÅzmÓXbÌÐ:¹BIƳ¨]á=ŽP4Œ!¬6”qCœ0KeMAÕýŽ¿ùÍoÒÿh®·[ßw'¯ ìÞ|ô†Cš£—,·Ùfÿ~—.y’Óñ1=?óA±) -ÊŒb‰´S 䉤ʄâ`ˆqYÊK[Ϻ J¹à޼ã%N–t½4!ü†?ŸäG‰“!WÆ7 %åY}áß{Î(袅‰‰ «m¶Ù¦š6?9[U[íUM_nùjî¼ô·Qg‡î¾F5Ã(i¯ý뜦²ÑTÎýzÉêû+^ñŠÜXþñ¬Þþö·ü2±èˆ6(õOÃ/oƒ:@MF ~µqÑ÷¦;ßÿ!Í[ÔvËÁ´·à¸O8¡úMj<ï¼í¶¼¾ÓqLFE9Sëk§¸LçÃ^˜êÕûžúÔj¹ä÷®Ä=þgÊgªÃvwôÒadƒ tXÈZ>—¶ÃÕ&KÏ£C‡65øô©3B}v1â&ÊÁ#ñò7àstè•O›L~ÒÚ& —[Üz©1>¡¯NŽëlÙ·|øQê}Óó¥ÊŸ‘ÓSO>9{v¼¯œÊÌ()gôR´¹HÇÿÀ¬vg\¦x„õä‘~¿#ý”îIœu.(ó)©Î<îYϪ^™:h}ó›Øû!Î}öÚ«º#é*løfr, é3Ý£ª£ÑÅõwúÕhãà ½å–[Ƽo×r£„ E&UîP’m ¢5 3ÂBLBhRˆ%ÚžA†ÒOY‹'=éIé}'…É£õœ¦ám4R5f¥]&Ÿ1Ò¨€# ùÈGòß÷W#Ÿñ}~6\a4d ô“Ký≴S2ÊYtÞ1²dšó”SNÉyUfM²ˆgƒdþTÎÒ`Tq‡‘q£Ä5JM럆£@²Qyþœž3Ý>ÿ¾ê}ï}ouîùT‹f%•æùþTÓ“Á¹ÈTüg’Ê|ERóîNÊ{zuâW/¨¶ÜêÕï~÷»%Ír$<”ÒÒ𲎥‘! z_šq–ÂmÓG6"]]d i°Æ»Q6Œz8Œ„àWSÙá¢pAZ†å¢Cæm,bTƨ¥”;gNuBrÖæaÚïñÏ¥4ä³@ÓwSñŸúío³1ê†í÷R=ûoÓòéoÆçî{ï]½é€òÔ»N|?4ålè^r c¯§{핼s¾G‡kiyYBXM ¾x>ô¡åƒê]edl¢BB¶1ȃFâK”aøŒ=¹ÐøÜö>í¼ÔÞ0u!c§»±}s‡F!±ƒ­ü>797!YêáúLþ²Ÿÿ‚‘roþ1&÷ÉØ3zy_JÛñ‰;ǧ÷îMíÕZÏXï)½6ÏýgzÏ|¦™vݵÚãï¨vKÞÏ}t¾þ¸/~±úýu×ewZ £ âdhZ3jš_>ËéþI÷Ú,5ÖP.Q?Ô.m,/xÏ{ÞS]vÙeù䦱À˜¡%ù ±d T’MÄ* YÂ3$/g~Ûü7!¦·Tt•¤TÖcSf÷÷¡¬$1ú©Rê‹-›*å¼êä“OjÜå.«õ{ŒOÕDš{Äm"¡‡EWÒŽ¬Ê—3Êddâ±}l^Ä ~¢Aºëˆg]åÅc€• zº„¨Ïú(m[ºšò°x}Æ*êMÅs+®RMK ýßÿ%Å™Êdäù´•V­ÖxÚÓR¼)ì'&•¹ORŽmÚn¿jÁ±?Ë÷ÌS„âŠFóøCõ)·Þ8®$zÉ1Š4ž|„.qKk¿òšè§'ÁóÐiêØ žâ—÷ÂHh~¡Ÿ_;ßãÎwŽáyY2t?öûßç[hæ¥4ÙÅnw»Ãæ—OͲþ$µ+¤ðW}ÌcrÃý™¤?™t¤5¢;è¹™é=†éË6Û,ûÄ ‹SCò²Œ>ã5™¨›m®¶r*~êåäïhðµOvúž`ŒNTH7™¨ÿ:7ѶÆÀÊ0 ›af€ ŽcZNy¤¿­5ö.æç½ð…Õí©ì h}Âh{ÍvÛå)ïW¦têÈ0J_µ×^ù Pë9¤_Lþ±¾3RÕ0Wiðíüo|£Úåmo«f'£’q™¤OéˆõžÒ]N³û¾ß~ûUüàóÑNßùÎwªEÉŸ¥a-,HsJŽO«ƒ1{QïkU•6Î(íYgœQ}#¥i´è'瀺müóŸÿüêï|gÞ`m°©Ÿ~ck‘€0cÔ¡®$»TZ¢ó_oœÛ žß'CX: Ø~ˆß»¦œuÚëw¡¬k9Ñ?ªÅÕI'?ðp†C½Õ,FQoInÕêèÔ{" •4@ãÝàw!g iÑ8(# Ä 7Ü0*…4Ñùí× #?å_x1"³ô(âŸ1³Z´í~Õüi¦WîçŒ8i„éo‰k»'µÆÝ•:O[/x (7Ý|ñˆ#ªc:ªzåÖ[ç‘ReNø©¾’ŽFÝíŠñäs€.ÐÈMt(›&y„‘–çÚJ‡:M®1JeQïpá÷XBO}êSsäõ€Ç[™8ñòàê#—(O~ÚÀÊ/yv™¢ƒ6Xýêúþ0O¥ómêœAgÈõ›Û¿îuÙø4J‚+'îáêeW\Qí}ÐAÕ>¸úÆEUŸøÄ'ò1‰ç%®î•žo·Ï>Õ¶éÝÕŸûÜêoéÆ*£µ<ãÓÈ{\È`zÞ]–p¾{fj‘Ê]âi­ÇZëNY ¿þÞ÷ªWl¹åâ¥wÚ{<“Å['73qqTXFh¯LÎÜ«Ñs™wA¿réºÓ Û[l‘Ï•îs¾ôS#”râd©¢C?!ù­ŒF,"¥0lã,, ƒâbSHPOSTН|ÅNv ›ÑL†²*ÕbƈÙ¿ü%ÿìÁïÿû\ø‘iÒà‡BŒ¿ Ãæ{PžûAzÊ2Ÿ,ˆôöË;9ëõƒ<.­‘MñåmDu¬Œv s¹ùs«i³“ò³ÎÓQL ËO68=Kná·V fÎJ”M¼âgî]†e«ïÛ¦š±×3ò=ó¡|Á¨hyd"aõ¶ddPFåGV(W)Õ¥áÕ D؃xú`"ó³-ma$ÊkÒm2çd¯“Ð6]à/–M1VK¿%„KïÐ7üµ3uÌÜj«­òÍ.ïŒOøçþçjã7^"<šÊ}62/.üÆ7ª»Òg¬ uLŽ®‘U;í9£ ŽvbÈZ:-ñëäãŽË¡W¤x5ÞäÓ&6ôóOFä!í>É<BÈ+øë]Еs£Ê>ê3C=ê}žõ“¯pÂVhdjzßuœ÷$Ùã#´l1Ý˦éŽ:[s—ä—F2ñ”cFؾÓs§ŸrJuYêHý醪Yém÷Ú+’Më5Á²§ÛSúç¤ïœïžñ7"Õ¯]"luÚ89V–ßOGEvÚié¯/ñÊ'£“sÁÃ_ÿjpªÊË ÀsgA/͹Î]ò6~LЀJÛD*¨«•°\œÜ„~÷œBUˆ aSMè%£‚¨(ý < ó‚ŽXB%·ÕÑ­ z½yF¦êedé9ß{i Ek5"_Ñàk"݃d<ÖŸ4*;}(AÞT¼àdôãz„§¼@ƒÓÖè”àÅ~£Úã5[WË̽³š‘êÐŒ÷lU-rKÒò+õÖ~réû"wÈ/·bUö‡ª:ãOyêþYOx\õÂ5žTí¼ã‹oQ²èÞ¡Ð÷¤ÆÇÑ9§ÝrK57ñ,îדùV÷5Nòå» /¢SØÏX¹Ô“ÉÀOr(eÔÕHïÉ'Пõ™¨%›ŒÕü†^•Ž(ïØ-o¤ÒMH›o¶Yn-ÑqãÑ»ÒwF¦µŸ{¯¶Z5õnçû&Ãò±Éß^’òç zILßÛ¼$–:gl€b:ß&)2’ù‘Æ~z{Xȧü’þiLÛã7à6×ÔáªÿÝÂþd@[Û:Ê'äÖu¿œ¹iŽ‘‘©µ\¼4•ϼ‘zí|ÎZ5=ßudóšLN8iP6nÙŠs;9aÕ¬Ÿ¸PÂàÒ£#.ßëNõr–ûâ¿´êê«WÓSúš€g RÓýHaXz_Jߢ¿ü%w9üñÅÉù¾ éâWm½õÐ3£Õµa„Ž%ÆÔE¦ºñÙBiP"(r3 G#(äbˆQ¨eZº( B{Gz¸· Çñ ‹©LäõR¢Zp·§|,³ÄhRz£œ*´ü:¶6öàõF“K„Bd…B,ühTäe´éÒ4Fi&*šòÏê²òw4ldŒ“KƒàS„ýdÝ–®Aå£nÃÛ·/»¬:ð¯¯Öyæšy7q"Ioí'7=}_”êy=ƒ¦§úk­ç/®»®:=5ì;í°CuÈ'>QÍùÂòâLpG¾9²³Ù‘'©bäÎX é£ äð_Õñ6ca4<âk: ?ò¾Fb/È2 E ÿúq…¿àbi¬ÖîQØÐ«tMå­Ia5ÅüÕsÏ­žñ‚äöâ«SRÃéœO£¡6'Áÿø<í~EŠÇ4½ßã^x”îJþ±Ži2Jj=Hn•#•òEnÑáYšŽyÓ{ä#Nr‹zŒïâ¡wƒßâ~‚x„;Ñ9ŠòÜWà÷ºìü-:ô ׄò}†ãßøÆjå$K3ÒÐÞ–üm»ï¾yºlr‹óÓGxºqêÍ9äì|×9~Ä¡œÒ—ì· Òàjn#©aÈ–2(¿÷CÔr‹sÎ9§º7q6Öšz7ÒifA™Ã ÓAøyt7¥Qþͱbºï¿H2a@s]m½\†~u?¦F(DÁÖ…Ôô›g ( ” †BìVý¹÷UxÏõ®bÔ*âíïPZa„z7zû”¿0Baówýõ×ç3=ö¸äÛ²{×LÇS8þþkzzu ǵö¤ Òö| ýo95jùŒAþ;«ßÿþ‹Ißa´5ø”"HwÙà÷C“¼»@:Èo24òm(óNVÑ ã#ÙÊ#7y§¾?ž i ®÷cTo>ï˜_”¸fͧ[’8»æ—I|›{WžºŸ±×Ó«÷ü-w…ÎyÔøch(Á¦«®š¿3æ¥zg £ä¥.©G‘ïA c Ca´²qõÃdâ§<áK¤9øñYÊŠüJC±Oã9¿%·›@¯Æ2áÒ-Maû»)>þ9‡È/H|qþçŒô~ð ·þã—¿¬þ/=÷ö}‹–ÉÓõ¥¦2bDÞ8Ï5Bª3ôÎÄ9Ó²o<7rOVòzBo“¥üÔÓÙ–÷.ˆwÀ!Ë0†Õuñv5†ý&­Â˜Èh*ÿAàŸ,äO[…]@¯0¯»êªÅÇv¡Ÿ)g}ùË‹ox;ù„òMGǤïvÌça¡Ûo_b”s¹Ä#m&½$/¦ëïI|)RÚe—]sEì~?)ÅãÚNßéÔú&¤.N%vØyç|¯ýƯ}mΛ›•N9âˆj«Í7_"|á7añzÔÄ+iíÚÆQÞã¡CÇÅmB<¯“7T®Ëâä&~¬!¥šzêmž9Œ¸#­>U–Pl~w,Â[l• ÐSRš‰ÓOá|7µðÎôî#;­£/zÑóÓ7S´äã3–¯’{Nu¹5AzË_E ” >å8H!ƒ‡‚™,|‰:gë zM]Qç:n OcÔ㦼ÝêÃùÞåÈ8Æ×®eI9.3-)'Sï/ߣçVL|6½zÞsŸ[ô†½ª÷Ù³š½ûnÙ@`óSSZ—”Îý îŒZ™–·Y¤ËÚ$»zòLú¹¨‹MÆÂÒb2ð3¸ƒ+Ái®s´¡ÿÊx‚‹À_?n+\w¿iSaî¸ãŽ‹ï‰çLÁÛ\[m¹eu¶3’ßz‰ÊÎYÞQM£CmÈ<,Ÿ šyºñFó¾yméJ)þØE¯347ñÃhיɸ8&±4DzåMz}Ç1ßÕÜŠ‘Jù[ZÔ9ŠËÚ àwWcØwåH–Ý ô«Ÿò¿ËÑUa¨‡LúÁûFØŽqTQÌ3:þ„“NÊk‘?Óè´¦Xó´}’ñ™gœ‘yHËm·Ý¶DüÚÌ“Ñù”uÖ©¶™=»ºà «§=íi‹¹ò…/|!§Á•£öËÉøu'<#òUI¿¶­mBµ_ýÒ—ª__{muÎW¾R­†r VúÎvˆMN¯Øn»êo)½yéAræ[ÍuÄP•Ú¼æšk.nã¥yP»ÐEþuxg‘ÐÆ…ò+OòŠŸ>Ë}üÞ†RæÊ%Ž*ÒºÒÎ[¿êUÙP+×yBy‡»ÍI+¥woM.ŒW7yÚi‹×Pê$•¡ß”Y+%æ§ðÜ+ï›RÛì»Qø®ÀÑrtvzr%·ÉÊR?zÛÂç—oc)½(9>1DëÓóÎv„^èÒz»ƒ~roC¼#̱nãÇÜ…~™ŒßTzÊ ¡UÌ’t] F‡ØmkHãY=Mñ·Âv´«·ÔN6T0åí°B(Š}§”§»òµœƒO„œ;WµÙ59á)’%×–ŽežÉAåBÒ0¸›¢ôÖe5ü _8½‘oã™ç*jSƒ>,"á•-y—¸ñÆ«—mö²êéN;#ñIñ£Á¬ƒ²Fˆ’ýá˜w;’ÃŽHõFY†²T¶Q–Êp;ÊÒ1aW^~yõº—¿¬Z}…e«ç=çÙÕ駺Äña”žãuž÷âçÉË¥üÿ$…%»“ïxÒ“ªXuÕl ÎËùÈ|ôN>Xü{ßËáŒäÆ1C+êzS¿+_Éf¬èXC¹’®ÔùRY¨·äÔÏP„Rßâ¢Ï&¹yFN þ~áâWÉo×½j4Ï:óÌê¬d€~ñ¨£ª³Î:k‰xŒzn˜gãÒ&³òIDATüêÌàÓžúÔju }þÕäú?$.Í­M\üô3Ÿ™—‡ü÷ýWuÛŸÿœ¯ît>çýa5r #Jƒ¨m©+·¢Î7AdHžâŒÑÀ0pÄïJƶÝÚºtºl ’<àøAG £éÎþ\-}ß$9-¯R³ Þôx¬ó|ÙË^–§¯ëw¸ó«a©¹E7ÙðG`é(-1]Ÿ¾k“K®ì»ï¾ÕܤkcºþΔžG$~ü<¹óÈ …·ÓN;U_OºsTHahå£rÒ|rËØ¼¤ƒÜÈØdˆö¢ÅXLiù›™Ò.Ý8Vo”CèŠÑ¶ññhãÇÜ áÕ3Y>—‘½Dζ ìy“°<‹p„ÀÛÂh¿^9ôŒŒ Y„Ü4½HÉNŸë7¿œh 7¦_‚.oß²zÊSžÒÚx–ùZ´ˆ!{jrQ}4ïhé0‡ùŽÚ±Y©`M ‘“Ni¦˜ë ~? øD7B› *¦F•Lú5¼mœlö3h)À¹‹æVówLåŽ65Ürë-Õ§?÷éjƒ 7¨6þ‡«Ã>¼úÔ៪6Ø`ƒÅ‡7•eð™ŠGYjàL[Ù|ôío{ ”¡k'¼»¿{õÕy×ò&«¬’ï·¦÷…÷ùÔÛ¾ìöÛ³â°&´ÄOò“Æ:3?NâÓ0£øýà z"CYvm¬•iȧ®ÿJžÒ=¥¾mã6ÿ!W óz¸00êüÖÚ”däs“TÜTc´“áhS‘#×èè%¿žÿ߯GD˜½ ç$wœ÷¦òÕÁyù£•yøÒÄGÎA÷ë®»n¹ÏM7eçœaÖåEÞ¢î4"…nhãXWîÕüV_Åí‘ãú^ò’—dãc¢"äÖ/ï~#Ç:?%?ÛàwåàÌNF—רµÅj+¦°óôxúd8^rÉ%ysÒ+wØ!äÎh5„ƒÉùÝßýs‹ÃAçÜÔø®ûß}öìœ6 CPø«&Žì±ë®ÕO’”/-דZº²Ä• é»ÝùpÝu×e£S\1ê¹ïÈwV‡K¿åÑi%È—ÌqÇ¢‡à³º^·KúA˜ãÑÆ›Ú†èqªð1zÙ…0øWy $âìŽw£÷åhƒ†Øq'¦†øØä6Ùxãê¥/}i5gΜÜ@s°Ùf¥¬=òè¥Åùž¡Øê§‚" 䌌Z}6k@F!ˇ݃3ò4i`|GƒR! y}*«2Ím ~<ãWž'¤] ò2XôIÂ5† d˜gñšýmœï¯Mn×Ć ª{çÝ[-œŸ83cQußôûªÝ÷Ø}‰i¨€¸ÂˆÁ=J¢Þq¾—ŠG8ÖÓYWwÊñÇW‹R9ÛµüídlrùzÅì34黿݆c´ÔNyƒbÙä±c å!OòuŠlåÁF“¿˳ü)߉ yåšêÈã”m©ÿê†òæŸß¶Ù"ˆz ž’Qè.eRç·MBw'þüϯ~•ó²©Èh'ÃÑÍIre$}Ãô·)÷èèÌrZC&ý ÕÝ ægƒ•qj“¸TÉ^šøÈY‹üÖ·¾5ÜÎUž]×åÕA.M£H€WÑ™£Çûq¬ mr(W"®¶ÚjÕ…^˜GÖ&*úå/È‰Ìø4Bßa„=õÔSóÈåçÒwf:Ó¬_7ò‚sÏ­âÃ`Ã8nìºOIåFŸMHn]#­]6á•ë¨Mÿ;²Î­KåYŸÜJ‰÷Öâ ]ÓÆ“0jãPûO:©ZÒ˜¯MÎíN‘†¸¶»Dï´ÐHIihÁÔ½¦6¢ÇkßÃuíÔÇ3~ÇZ‡Ž›ZÏHüœ2Á•dnʸßËçÞ5]ªpý lÇ®vŠëÕ¯~uõÞ÷¾wñ¨‚‹uy3Saü[ŠçÎäÕäÜïúÎ¨ŽøÄ'ª/zhµáT]dP\ˉ]¿I®œ>7zyo.PëNB±•§‚Eþä'?¹Zc§¦w@?íÐäôwxéÏ,eÜâDÖzšå©TÆeÙˆÇïÞ›,P:$ò"Ïò9H^uN–ð<]SxÖzŹæ×T‹æ¦°’Ñ9ãÛ3z£´ mK»éD©¶9¦óg,¹þ­ âÖFYª/òYï\èdÅñ:›'Œ>™fçì`6FoJÞÆÎwIb$00 ޏõc4${àG9ÉKèC?C&?ë|õ ‘ï6D•纾õ=d£ЫêCµM¯òuêF-=zò‰'æQ§[’Ÿß%n™6ÿЯ[}+މ|™3¦ÆÒhºww|ìc³›žƒAþ»’ŸYÕ])‹FM%hí±SšÐ&.šw›:.Â@¨ÞeÀß1Šä»:£HêKɱ6C£D›¾¨CY)§Í6Û¬zâŸ8òtâ!äUÏ—¿£} g¸ºlmaKŽëp0É™>Œ½Ë’‹×¡ G;Üó&¦T>?Oað÷ÈôÛÚë¯_]~å•Õɹ1‰;7éßàŠÙ¡Ò ôbЩɨcDŸ Ç{SþJ0x¥_äCýƒ¦öR±ߌ”xÝ1¿ó~ûU_¿øâÅ)ï¼”¿°.äۺק$§¶¼&9CjÖ¾Z£j}k›! {.ìúAºÉûu¸‚£c‰q3BK„ò$ó%ÚˆZB CAv5>åd]Ýù矟׎ÜqÕõ×\S•Þ-Segx®¿Î:Õaýhõ“þ0÷2HΉÑÃaZewGÊÇ )=ré%ë—ý:9#˜¦å{Óçðûÿ8Â:dvÛƒ©–häŒ4#«´ —2FVÊØßR#îXt¬\ >‘LQ.¼¼#IÁï&^ãä;îG3³¡™ Ëi ¦Uë=o½êÌ3ά–™™x¥VjçÆõfêR$#Ÿ IŒ|kG™i‰º $.üqŠE!1=©¡ÎynÔhéG’‘ÀàpÏh0ÙËSt?Ãp¨ÚvÄú>ŒPé¯ËCƒ:Ôè´É §é\Ÿ Eynâ"„nö©„±U‡¸ÈLCwÕÃŒ³BI ¼MHHþPù® «yÓ¦W/Nx[ÆaÔ¼ÑN£ž¾›Rd¦®8cQžzïáÉéÉŒl2FœO›³O¿X΢üñ7OŸ%Ÿ—‘ÏEªwæÂ ÷}iã•ö~e5Qé+óŠkŒGr £¨“àäbèPk=û—¬ÔJjŸµ’k¾øÅyžÑæ½”(^2œœ`ÇÚzNXqcR‰Ò íöqŸúTvmFÃÑ(m\­ùô×¼”æ½÷Þ{q{Iß9•í%‘W i`#X÷_v¦<ßy÷ݳu±frÆGMÐêÁù)nVÈMÉ•kZ!ÊÐgt¸”›t7u¸È6thÝ~[ZŒ›U1ÃxTq¹:¼ÓTyã¹B†wû­i*ÃAœ8¤ÖÙ[{í±G5/…“nHޝå“`ÝL`Ý0-Íã¿·î~xoûÞ×ùŒt ÍýÆ×ËS?}ïö´¤°­1‚zdJÇF)=ŒRé §ÐŸð„'¤·T«ÙÉ™ƒE^–‡Q©™²OHWž!+‚J3 ¾ õÊW¾2¯cQ‘®½öÚ‘·&&‚OÒî.\ Ó÷.rnò Xƒ¤ÑJÚž†Ú(fÞ|dT“®Nâv,“ãF^ûÚTþ^S~ù=jïF¦ëÎ]Ø;ÿsy–Nå¸Ï>û,>^磿û]µ\*×{“·ÜpŒËÕÒï÷¦ÏØÕl‡¨/I5RuOÊër©u~îƒzâcAþä“:üðë³Ï>;ß®Ãý½ëÔ0¨sLc€_êýׯ†¢¾6Ax~Ëpý‘ŸPéÀ—h\ëh’i„õÌg>£ºå–[ò;Õ1K Q‡ÐÛäæÖ¤Í“þðûûžbpAµRú¾âŒý{{0•oÔ=EVý:u|äQš”¹tÉS¤d!Mõ?ДÞAŸ²32«Âõ‘¯CÂ_¡u~ç|ê E»Ðõ0ÂN\T®`­§VÐè§V:FM?+ƒÏþóÙPÃÍvØ¡wÞg*ˆãt†ðW^™Ý¶I·ºjöU¯zU^òÐ\ÓF%íö6Ûl“ß H Q°»ç÷<ðÀ<š)-yäêí¥ö'Œ;éžöƒ¼îr¼o·ýöÕ>ï|gµFêô·Ý¼Ô†~qÑ¡M.ïì·ß~Y¹å›##Æcq5BëÆcü6,º,ª˜*× ¿â¯ÈF`&S*d ™‰^oÂÑòÌfž1.…jÄ3F?=ÓÄǸdÀV¤žO¡ý%¹¨|y>½R<Ÿ÷„BLÊèÖ¿FzAú¾ÓŽ;>`ÝÍ7ßœþG-§~kCøw¥|ß×E{Y—]Ã/|xßûÞ—Ë×èÄÅ_œŸMDPôÃðiJ,¼¶F¿ÄôiEœIÜ3Ó?ÓIçž{nÞMœ!˜Ø)oØ'Š zTè|m?(³µ×^»º$)Çëìõ–·T_ÿÆ7ª‹’òß6u Ì0ì’§HY ¦âMË›®7õ¹Ô ŒvJtiÐÄYùb P¢€í“Ò¶º)Jt´ºèïH›|i¨6òQ®¯ã§žï²!—÷~Üf˜ñÏOÙè×,º<:XM²ãžÒ™‰Ž ®ôÖtZ ucõ‹_84ç~h<åÁȨòSõ®õd¬UÅ?–ãÁŒº9ÅKª¤Gú£¬¹¨‡!CN¤³‰/£xCÆâ¤ Å+Æ…r3rÜ5N~'“ å=Ñ«ÐÄÏ6Ôíe¹ÇF¾¿.9­¬ùÆÇ=þñùœNz›wÈÚé Ç¥öç©ë¬S=é…/¬žðä'gV{nM©’úóOZÝtÍ5Õî»ìÒ©’ǃ1p”Þ3‹êûzë­Wm±Åùh¦Ee€üŠ©ü8 ä-ÚËè {F~1cCMöˆñXÎwƒ'ÖÞ”øïØ©°BŒÌ6­i ”4G·7EÚíe0 ñ‰uåf ÞèwUÀÄ—_Q½~·×W3ͬ¦-7­:ó«gV;î´c5ÚÈ4=‚#SïÓçOϽÐÔ¤fctú²Ó«–YaÌz¼m “²¡¦,f&)ß™µÆbi1Z®B¼;ˆ·aÐq‘k[ÓYòU¾¢Ãßo72ÿê)½Z?™ÑáÞ&½S»á†W‡rluøá'W[oýª\¶ÞzëôiQ“M–ô¢ÆU÷¿·–ÕÈ'Ç|cmú2ɰ\5wl¬#ÕÙqÃ)üÞtSiu¦ Q#¨óRÝaÜΛ×Ó¥m¿èxÆ”42 £}‘ϦN}ýï&´ù!ÛˆbdZœÊ€AªÜÊxƒŸ‘^rkã\ÉÏ&ÄodAŸ4 €™•Í·Ür RWÈ9qƒÑò)ÚÈ9sæôn6J2õ\×Çö¼íc騧3nBZ-u\WI\Ù ?å‡[¸8-‹W+œ|õÕ?¨.¸à[Õ}ó²r5/Q~™”3ƒý ŸÑfF»‰+êÖË7ß¼:>š7^sM>pŸQÌý-ÉÚþ’ã-Hi7EFrf âh§~èW.ýÀîÀߨGc…±mI(8 ÐA½÷@IØè}SÀQ(uD˜¥0?‘zD3Ò»¤=/9+4žÛ$‡0ˆó…äL†LŽ9é®Y&¥Ð¾$ þ¹Ò´ðÝ®´žR5)à kaÉiy0Œ ‘Âødû]ØŠñÚD`g’¦\%Çìe0w…Ë4î!ò¬Ò#ÙúN”¹Ç~×~£!g¼FèCÊAeìÒè·!ª'»h™EÕ‚W,¨Ì_P-šVÈ^ŸF›ˆb¤ôä“NÎSÈßO½û|×?V½ý êâ‹îßA9^`äZjjÕ1LŒ„e“4J:#ÕM£V1õº 5¸Ž;Á½Ñðèï¼z3‘Avê´>’uÔûA~ßù‹zªá ¿u0ŒÒ Q,asÌ1I¦Ë¥úð³ìæÍ[®:öØc3fÍš—â`€Ò‰Lqûl`2(9+þ35¦óŠï¯ù·›¾õ¼oQ[ÝrÄN·Ž_@ºå…¬ð ë®ú¥eDþÒñr6v:c²ÉØŸhÀ#Ö’s]A¶Ú,d'0Æ.ª­ßäÓ†ÈÅw§”ºG=à¢W¤ÑÓ_ò’j­g>3·õ÷·ÒUõîw¿;ýßËôÜpà yTÕîFSrýõYÇ9 'iëä§Ó÷éíq/¢v|zn¯ÕÕ¤Ó“ù;7µá®•!r5Ý͸fLÿ2åc•ÄŸÇ®½vu{ò³BzvéYgU S=e§UC¢?^Ê,ôÒX 0æFh(ù¦ÊÊ« *e9ýÓµB"ê—¾øÅlxê3$ƒŠeèšä‚€üê)1s«LJýt†jo\Uý09~×LéÖñýÏ~X ƃ„ð×DÏE9\†¯ÉIÔTÝüÊ€enzƒØú- Á!8«TW'B1U219†jëTIç6‹RÓ@‘7§2“o9åÁX+Ô&L–^|qü#õF¿D<ëÞâßhšMßFF?c‹ºë]zà1ëŸLçë´ü=Ö^2rÝÏì(vht"]>6Ä{ï³Oõ¬uÖ©v˜=»ºð¢‹ò®Sò)óÑvˆ†ES9” ou"ôÓD…|Dç»ßèzpQã: Müê4ñFýÑÄÏáéè—~K¸IÎ:M£?_üâç«·½m×ê¹Ï}|úEã,m?Êÿ|Ÿžø´Ö3z£¥ejzßÉáÊêîË.>7ôþu¦g&÷×”Æi£jxÉ*äE&äWïÔG£Û$§ƒ¸W‚ßùŠrcº%éˆ#ŽÈ²3CfÚs¢"ô¼t·åÝó&¹ÑÚø…Žv« F7?Dêrk¿ïKÜÅи;ÝދЇžóÇùî¨+›h~ðƒT§'Ãíië®›µ£qï¼|¨Kùˆ§ÔŽIuÒ#R¸÷¦Ö9F>c0ëŽÄÜÒ§ƒø´á\æru׈±ê ÏÛs:uÈFB.fžÈÝr>Fé/Ò§x×|¾ú5¯é<01 gÑÆ;è2cn„†áØVq›ž‡@(?¿›Þìj€‚5ˆÓi´ã¯Na™qB@ÅÒ3ëz§{ªBÔ‹Æuz궯{].dÆhÙSâ_:^³÷ÞÕP}ìCªy3)Æ›¼PÄbòÌa" ÿªZ0lŸœ£XøTº]_‚ýØT´4yîS .{üã—Mè¢L¬~Š)¤A(TR…A=½0 a´ïhÞ 7 9yÊc¿F„µóÎ;§rN ø§)Œ(ÇÅF¯Å³ô“5Eqµ'·áFæN×h`Cܳžõ¬jÕUWÍë=®‚ —_qEµ2<ß”ê@Îzè¡y—éa‡¶øh&<,óèu¡_yvApt¢#F?ÛòEŽáb³Pdé}~èU¾Ž}¸MP^±>¯_Y1rì{è—]ö®dTј«¥ºq[uÕU×UŸþôÑÕî»ÏÎ}ؽ:Ï.­œ |þ,p›™üÚ´D_ŠÓMs_ýêW³{ÚÓž–;óxì”…è ,  }I¤Z•ÔtJGúNs¾/›Zù2M›n¶ÙŽƒê ë/ïHé㟬SuÜ”}.FcË“MÖa¯œÿµ¯åºÙ•“ÃÀ;ã¥?ÇÜ 4e´©"ãTÈr}]‘¡|þÿ÷Õå—^š3bÔúOcBèõµz„4ú¨ß³\zwç?¿ÚsŸ}ªÝ“ñzIz×-/ߺì²jï}÷­VOé£R¯jíô¹kêa;‚Á`„µ®G/Ó䔹ïû¸GäÞØ3Ÿ÷¼êΔ~ëÈÁð´IIš4ÁalŽ teP·1Ñw†«^Î~ÿû¼³i¤i‘sd£2YÈ2zzH¤‡ï³iÊ©©Ì!Þ1j "Ot´qÐó¶ükÈ£÷>¨´…ç™°Œn^pþÕì]gW3&egS¼Ìôžà‘ad&vî¹ùjOnÞ¢yyÊsX0@wÜa‡¼x_~4¨8ÝÅÕÈ—;@û¡lÌ54јGC>ÚÆ|,€÷ÑøMdôã¹ÅH¥zkÈ”_åݯcÏŸúK7(¯úú¼õ-¶Øª:âˆSªN8/½+½´œ/IÃÍJZ7¹ù î­öÚëõ¹ŸžO¢wꈤÿM³ß“¾,ÌÚÐ4½ L«¦f&csQr Ówº•V¤E·NŽá¹JµÞz/Húð-©s~Iuä‘GæÃê•k[»K]­‡É* vß=SÿÉ)8ܵS?†ðíº6ú'¾‰ŒaåJVå Ó ¾%Ápt{á/®¹&ïþÖv—Ú²Ë/?r¤áa–ÈmCs’?Ç+¯Þ»é»ßÍG5Z· :b7ÞxcÞ4äîyÇ7š‚·“Ý&(wÄ3üz†+â¯ÙÀ£õb0«‡ÁùwÇh ßg¯½ªR=±ðÁÝùÿ“윯Ÿw^^jô×:U¶ ¼ßhîx-+QÏ t¦NõØ3=ئêÏUf(¿a*Ÿ›gþãßÿ=«7…ÅÐ4ÊìO''GM~+¹™©q<þøãó(Ž]üã³’yÑ‹^”Ït'÷Éðt|ÃG?úÑ4º½ôÛoOÊ«É{®·AÅ¡ø§ÞÛ«íêKM“gÔõ¾ôýmûS½ÈŒè¦èc{S|ž›#•!úo»:;ë„d(«”屃@ÞäI™2 H£FÈXN› g2Œ2µ¡‰›¾ÏPž£­ØdaQ†Ï|æ3óZæ½÷Ú;oPÊ›’ž™»"ŽgJD®Ç'œa@ –oõB³ÏùÞ[<> Su«>BßÔ˜/-Bïôƒ8¥e¢#òR/_rÿãa¿<ãˆ÷ùijô=÷;§B6ôDS¸üñcè¼yË'ÿ,•›u ¾ ûù#¼MeÉ¥ï ’1©=×­`yq’ò)‹f%ç*âK“£ï}šÀÝp9³„æ¦Ùÿ’:Ó6.ªŽ:ê¨ö+«€ð&CG‚?mˆüò£Š·Ê ɳü½ :ÚÖD^äk÷·n—5‘—^~yõö·¿}qûÙ3«|ªØ¾ìc[­šÂ7"iM¥)vË"nƒN —÷H¿}Íï)›Û´õÎúÔvßžø¶ s2¥19SðÒÐKíUÙÕÓ@Ÿ²âï'=éIéÿá!-³Rš™Òö‡$ŸU¿\ºBâuŒ´ÊßÚÏ~vù]|'~zFßjãÉ5Úxõ;f¢BÞ]øˆw„3ús\ŒÐ.”1™"¤Põ÷ÚˆÏ?øÁæ£Þ%‰=¢ZNgxœ*“9> ˆ3è^ð’—,¾]A¡€Bkëù×ãí­=B/ý2æ¢ïBïÑÎ10`ÞñÖÉí}ÀÕ›<0OizvÊé§Wk>ïyÕ¢Ÿ·9#Tºÿ_ròeŸ:vÆÙìDH‡ñ<ÈŸ £T\Œ¢ «² A¾ëyoCøóîdhà¡ÌwôÞ¡©!„2¬0f)‚úzgÓH3òÝÙ H$ž6?§ÍÌnÖ´Yùœ: í0Ó¬`|©œ2+Ôùb$£¼úÿȯ­1ß5æMè꟬&C#ߤ÷ÔQ#èê0þðÓ–oº-ô¿Þi‚÷c­(¹¨¿w¾Ï0Tï¯:Ãÿž~»+9Æch² ª?þñöô;nö¶qL›¶JrüÏ¡GÑØºçºìÒêÓXÖ>ÉÍJúúéÕ¾~ñÒ$>Nz"íõvˆeÝ(y©Cù킈¯ìÔÇû8ÜTÛʨDø™l:´KÞ”E,ñ C‡d²áhóôi÷·öûÆTvFÖÿéÝï®VNá`ŒQÂOqDž^7âù•9sª;þøÇja-mÊLÜÊÿ´“NÊ#ŠÇ§çÂM€_f>×\S›NGO«¦Vxnµwr+¦ï´&“ïé‰Ý«T·&¾ÞšZk`ÎÏK’Ãbgyv…t¹èE릛nÊÜ ¸$Ä3ËQbÊmPFÍóáüé{Ü{¿×^{-ÑÆË7ŽÒê0øÙ¥üJà'½=Ös#dº)ƒñœSa£ÒEƺ %üù õB Œ_4·BdbÉ ‚[ Äú$Sæ "”´‚ EÒ xÏ6#±õ÷‚|Û È“†Ö:9=4¹›B¯ƒô­s¹ô²ËªWo»mz¯‡‘ ­¬Ê·ào³³žíÜáÉ©X'w\&lW´åM…,ÓSOF©O•¡K¹L–šdR†ŒF xô !8<exƒŒYÓHŒKFæô_$N¡X±AéRô¶ƒªÞ|@uî×ÎÍë:Õ™(³(¯àuÙèþ½ AÏ{Þ“/‰0êºÉ&/KÊü¸ì6Ýtó%8K6ec^Öÿ¶Æ|iA.¸<8Zr‡LÈ‚LÔWF¥º[çk€ü4úÁ×~¾°É¸i]©)AË/Ì9•ÇÈîMozSJÇ])‘륖ýä’)0 aSù–¼ÍêUÜÌNÓ¼qÒ7 «|äC)ýVçkï?_¹ªž–\fGkËãym©€ú¬T€,ä·l|}ü‰ºqýõ×/q%cÛ9Žu4É:â$_Ÿeœe}$_èªC'ƒ*ïmü«CžÔóú@O|o“ b·7MÉ5å<=éÑ|àyäò¦T®®xytòC÷äMEé¹MEßJaÒ¶¦Õh¦ØÝ ü="ýŽa4’ðë»Êé*aÎH$îm4º7}ÿbú…a¨eŽñOßñ÷;ù›.ÃV˜´Œµ÷] >¼<á°Ãòò€s¾ò•œþUͶÁ_þ’ gÓðkÈS’évÛm—÷³8˜ÿ•³g?àÆ&ܬÏD…^ÀKü¤/ºvüCt-û®h×PK‰¶Ly®G¯Q j#dÓsß Þÿþ÷gZ+5ç»>4uƇ¿½ùœu×­.¸è¢Å¨÷Ca4¡-ízH½ØP̧՛bó}zõ†7¼yqc+íu …|«˜znÖööè÷¦èÄ^ûØAï¹ÐåKl a-1ÂÔmù¨#ÒF Ù +rJk²ú½ÞMVÈKôޣѯ£«lUöúTT€Ü…Cq8;”¡ù®ÞUqøÕK^ø’ìN<áĬ íŽw ¸ŽÍï~÷»< àd‡4G'BxøõCyE'¢vÐÉ Ú4v5XoºÁVÇw|õÝïþ¼:óÌso–MñÇ”ír¹î”#£i™„ÑÔ˜÷3®åO8ý ŒPÊ‘ù ƒ<ôHüæ³ä ï!+õ°Ÿ~.Ù~×ý*Ÿ—oõòêÓŸÿtuȇT[l¹Eõ‡?ü!‡‹«»ì²ÓýËG8¯+Âí’3H”Ùr³èºMYs«$Ž.J”-³Q»ÖZMÑj½]Í=m}]rQÆŒPÍï#«/}髹SãT†’?eþK(gyò‰[Q7ppÙ$Ÿ|Ždr¦{O8á„‘·ˆ¶ð›qF9Eœa„â/™·uêùUoñ2 Î¿ž‡™a ïÓW;ïºknV2îa7üèGùò‚úñL%0ÊHéSÖY'_©³Ÿ2%ΜÝ}=–øÝtø¢EËæ–}ÉY£°*hNõG‹£¢+UM!3…g w—]vÉydä‰/ЉÜ2É Ù¨ªZ"îÓûÒaþ Ï~vµÅV[å‹y¾–øë`þ3Ü`DþÑñ\õ7>*«Ä×zZãïÐ-cq1BÛ™‘qÊ/Ò• ”'V¡‚CÞ– Éîô }hÙ2ãMõ7lm Èšk®™Ö|Ä]‡´´¥Ç¢ü%ܯdU]¢s—É„ª# Ã õÌM½"8lñÆ$;ŠûÛ’}Ÿ¦ì/U~œÒqô'?™{Oƒ ÑÑ ÒJN”j¬Å k”©ßø¬ˆ2†?š–i´q£þð_>ƒ¦¢(AF%§×îXn³Í6Ëá„`€nºÉ¦ÕqŸ?®:ö³ÇVo´qõÎw¾3O×DF…÷¢qÊ)§d¦iâ©PÎw;ÛG¼cXó·Ë.»¥¸¨MŽáËä~ÌŸ_5gÎqÕ¡‡~©qd´D[c®—¨Ãmy‚ŸýÊ`¢ Ò¨ì䛤½{äˆ:ËEu‘[ŒÊC“Qn´h^ú·`ÇÙÝ›þ•Æšå#r40Ò–÷ÒʈŒ Ä^§âÌ3Ï©Ž=öKÕÏnËhh9ª¤ëMË­–œCpèÕ_¦4ÿ×G=Ÿ¬þh£ÕWh“O½®¿Áeﻣ|VòW)€dzÃ?NúàŒ3ÎÈw¶Ûa‡j«Tž{¤Žñ×Î?ñÙ¡%†çãÕ®ûï_íöö·W_=ï¼ì_b©Æßû^J˼Ü2‡‰éûýÃ\ŒÂQ&:óÝ]ô†¾åk-c†G™ÒcêT”9¾Å@ŽúTÐó“ÿãO:©zUz¾f²9îJ|qL“uŸŽmZ!ñÅýcò/yãu ûW_Ó?Ìà”rÎà'ç;(u"ÒêìÚñà瘡’|2€\A¼(œ®Px”g(åhdÅAHúõT¦>Ѝ¶À—AMòÛ4õ4 ô˜fÎdhºcÉZPô¤Ò(XJ}ÞkKÚ€ ïz—Û¤…‹öæ±B:.ûÒÏr˵gòÆùMLÔø=)OƒŽhªì£…ÞSIV ™ðÏ>ûìêC©Ž;VE›LÀ+ ä«_Cò,ù]"8铼ú³ž÷ ‡²ò©¾´Uþ™ÓgV¯_¯·¦´nØ ¿׉r½ÆÛáÍî:¶Ññ0$”‹¹ŸLþ¾â—ä¨ër¼Ë.‹ÁXÝ_qu‰»ž—²1W~Ѩ‡b¯C™x·­,&¢þHoèº&Èg4úuÝù YhPøÅ%~c$³.+ç žpâ Õ";ÚGÖw.³h™<‚ПwîyÕ[÷ykµÎsÖI¤¦P|¢”„˜¦þHÖ/MNCíx»è¬ÐhÌB3BêŸzgä4f—Ê‘R¼êmnZ¸pQ>ŵ†N ijxq4nœqð¸Ð´qÞ¤ØvJ‹¼¨ó%ŸÂP ³±‚òàÈ¿©Sï¨A3 j{&2"/%wèm´gMëÞ›P†m|Ë+$ž*…è8ä³½G¸øÒ±ÇVǦöç¼ã¯Î>óÌêo|cßó9ý¦r/{øÃ—XSjGþrÓUÓRìö¸5{Aåd¦'±¡Nk|ÿé8=†-ʳKÎ{…²Ì£ÝŒ2»è/¸ðÂlï¼ß~ym§£ÇNI†è?úQ5-¥é¶ŽuŸÏxÖ³rLR~krø­†JìöïéjB´ñêŽJ·gN ²$Ì©Aïz×»ª[n¹eä¥Ç¸¡e šòCÊhHKòBøo{®&r+àxKßyãä,!F™›ŸÈ½ÏÞ{ç3>›z=NhzÖf›ýCúf/"jd¥éÎ|ÜS Á÷CïX©Óq²é—“›‘Ò¿J2c_ŸÔíÌêMéI¤ÖçºÉyC¬Ty¨é¶´¶=ï‚6‚–@Lòä¶ß~û<¢ ÿ Ò~£, ”^tp ‹òl™S*1òVYÖ!kR5‚ÂÁñ@žNZxOµî!ëVë|bjîü¹Õ./Øeä×vH‡ô„2ljt}Š{8î8­õÍmòX¥zô£‘¥ûRÝ×|øÍ<Œ ÍÈš) Í·€u…¼”ŠÝßä¤ C±Gï=ÊUÞBÿLtPþÐ;QN½ØÏX•÷ú禰ŸûÜçªû¦§Ævd}ç´…ÓªÝwÛ} ½F®o“½y4sÙÄ™g¥¯,©È%k“ïëÉ%CrÖa=7Mcþ¥ÔàÑ[§4ià½ÐƒéЧ?}­ôÉø¤ÿi=<JÊó_«ë®ûyµbJ/³kÃ+tgFB˜—òÿµ¯}­Úb‹-ò±|%ŸðDCÜÁ¥:ŸJ *§6(ñ¨‡Œ¢ç=ïy9þË/7ô0ñy#:T~bÝ{Ȥ_þ¥ÆÏàr¥N17µYcygzþéÏ|&o42*hÔðŽçJ80âðÀr°¹ˆáÄ•”zyñg Þîóo¤¿­A•ÒíZLš··9éúô]^ŒÚ3Y¸Yv’¦rüçj£6ÊuÃ(½3IKD™+gÎw°Öf NÁ™—8gù9‚E)-Ò½þúë瘤B¬jÆý—{F—òˆ/Úø—¼ä%yÙ×ꫯžGžÇR—Ž›ŠP*®Aå.§$» ¹¡$7”áì¿ÿþù{PB³Ç—‘BËâù¼/‘‹¡Äo1¨C˜*…ô×ÓéÝk¯½6}úÕÉ1")%TX”I5Â8ë,sVgã¶T£”ú›A{vÊËŠ¹¿uOJ£¼($=x1‰Ù…nî —‡G>Ò“±Á0 xG£©ŒLí:¸M¶ Ñ{‡høÉ ÃþÃ1ä1àNî«3Máˆë®ûîªn»ç¶ÄïiÕ.Çí’±ïjØÉC½Ñ¥hÄÍá4ºMòÏ2ËàÙzË\ÔÞQ¤±T}ëèϱ)ôKùû‡¤ïžž\¦u¯ƒÅ;õÔS’1f–iÍ”†µRÞ3RŽt#g½æX¤†Z‹¼$Y•òÂÑXû÷ô$Omƒd`&-ëúC;ŽÝ¾Ó;äÙ2.‰›Ì Œ¢àG^MmDÚäÂи“¿ÍSŸýìgG~™¸½D&ôáâ0zLÂïÇ €ßttŽ™3§zúzëUk%ýµÛn› FWnÎ~Ç;ò¨áŽ»ì’oFªÃlÏ–›mVÍ9äìßm?y+;úŸ?£èñiÇô»8¥–öгbЧw'ãO’ÃEdï•.³Ìô<ÊΈi}KA, ‰xë +<£µ‘wÜúá˜Wžµç|W·M2À85…Öå^žòß飚–¦“ß„h+Œð2¬é’±ÂèZÊ>@ž(d €%Þó¶ŠÏË Üu €6r»ñÅ4cŒ½QÌ2¤ù`rÑoµžÁÕ^/I=‰6Rˆ?ÒÎA(œŸþô§yÜŸÿlŠ4¬ßì}ͦâ ÎÓ[_´(ò¢Gõ’æè¤RNÏÓqž0mõ;l¸¢–½m,U/Дª4’— ]Êðï‰ij+㉆htñª­!ï \ã@O_£ôCÝpÚ¦WoM5-œ¿°úÚ¾V}ã­ß¨î]xo5s¥™Õæ|aT†4È{(òठ§šF{nõSychÜãõƒ’rÖ#?6šl‘ø13R´¥s´Ü)eXWìòå÷rç;ßÉÇ[]u•æ'6Úd~èÃø¬#d©ƒ¾k€—F`ìXgH¸>rÁÜÔ¸êO$·pÞÂêªï]U}ì“«Ö]wÝêœsÎÉþ¼»É?lR]õÃ$K4Õ—þª€“c£jŸÑEµ2€»è 5 [{;Í(üŒ¬þ,³Œ™£¦Öš;RéW:3túôIžœ4å¢ÅãPw§4….T·0ç^pAµõ{T·'~/ŸòkQ€öN ËÈç+še¨ïÀù-ùDvâ—ô©¯mº·éY„I‡ÖËi¢B¾èƒ¦A&ˆïýòï7rÄá&Œcûî½w¾õèwÉ(;ë´Óª£?ñ‰jön»U³gÏΣ†®ì^<2:b€)G‡ÓÇ=ð1RN÷ˆSYI;þŒ¨ãƒÖ¸¿ôË‹2{ЉÒñ6SN뙵$dÐ=Wä¬á§9íuá|wþ%—\’×Áê–qJï­™êå)§Ÿ^½>q—q^?ª© £áXØscÍÏf ¶P°±ÆL¥-Ý•˜2ä†A™¶K>ŒP#¡tóÎе¼!†RvKMÒM¹ƒJÊ]Ü*Š›BæÎEQË€­ 1Z+}÷ä#tºÚ†Ó?iï´÷´,·Ç=îq¹§cÒß'Ý­‰çCêžð¤'e\Z 1ê)Œ5aš Ž èd@9=½÷.Ü„º?rf€â°„9”á”SR .âFnTýüºŸWËÍX®zÕç_U½ýŒ·W÷ο·úÓͪvÛu·<šÃŸFÔ®P££yP„\Â8…[e~ï½ Ï·%]>Îè€Ú§™W—¬ýëu£¦M»«:î¸9ÊqÌG eEŽk¯½võ™Ï|&ß²ãNæÞÑhÒ^ÊÅ÷ЋÊD5ž×áŽM žl½ÍÖù¦O}öSÕÖ¯Ü:Ãd]âŒå“¦Œu©ø-Hói‹ªûÞ—5S—o£ï‹vNñ‡©ø/儾’VOžß‡m$ñö¼®]C}ß}+¦¿ÿ\ܤzR Ü#úîÎêIßë1oTèiOz–‹|†¸Ækäú43µGOK2Ñ-rÁro¼©‡X° ÉõkgœQû…/T_<ôÐ<šõ'd|"Om[”8êºw4œ†:7Ñ!oÚ ‹~†s›ÈÉotMèà:Nr¨ûì]í»ïëó:VM ŸbQü‘‡0¨ áS†¡õ¦5!Ê":ƒP–]WÄ;“Ey4õÞ‡| §i* šxÛ¼‹P=SÖí±ÇÕ2 —©®9èšê´½O«î[p_uóßn®VY.1yÃVÜɰ\¸ÌÂj×ÝvÍ÷@*nýÑ †26 î„§X+U"ýýÀzbæ¶ÔÊgLJ>"–¯~õ«²Æuˆ9¦‰êç×]—Ÿ/ÏÍ5’vêÈí8H~¼ckÍW’%“^ ݺiâ÷}É(uùÈEYFò@QÔSíƒrñ7¹+':X]„àïx5òã(3ùnâK?½ò ¶ùmEÁí£+Žâ l÷Ýwïí8OáÇéN;í”õ€w¤ƒn4ºŠ13/Õ—Ï'w÷·½­Úmöìj³-·¬þ:mzjíg¥vØÒ¥e«ÓÒ;ÖlÖ >ázòÉù®ûà×Ý)¼úÔ81eß¶›=ߢ7bÓ€ï}ìcóñ}åS¾ïºë®Ûø¥AŒÔ5ÆÜ%¬6ã3ÈÖ&,=X†•ŒªŒ]ɉÏzö³óP:•»SrõÐÌ*mÁ-·T¬¿~>WËt”uŒ”·xë#PHK‘ õ¬Y÷¤4ÙMg:èÄÈõÄèNúADÖ=ö0 …Ö;¹qÁˆÕØ“ÅÇG~æ39­h¨h¼‰ÉJñzNñZˆ M)„Áò…<¡ǃ¬âödQ ŒÏzC>ˆ›ðGŽ1-Êp,Æ0P> YáÖᘶzùVÕ‰_8±úÙ ÷+©“prµòr+Wß;ø{Ù1DŸñؤ SÒçÝ;¯Zi™•²S&½ –ÑSÆoxÃ×4éG%ç:ê€éDõÎÜ«ÃÕÇ”íß Œ¸ÉÂO\àp‘3zz‘‹ß¡äktf|â74ñÙ³ºq´(u*Œ‚ɱ~Æi3ª§&.2-G¦Õm\¢3ùË·|šô¢Bƒ8‡1J ±Õ(,j’“IÖŽ<³<‚Áhžgúô5RÞŽLßÁ– V¬)Pîö<’Ý4J$Ê{“Ž3 a³”ss¤­œòª d{ÌÉa|A}^reX Q]%L¹ï¬öN†ˆKý ,è^:7Ú.u…Œ£3 .jKšÊøÕþE¹MdÈo—ºø^v¦‚ÃmXlH&È £i°ÀNqÊúÁrŒ¯_|qÝëï¬Îûú×ó’²·DgaªWZ_»3¿ÃÎ;ç[ßpèãÿx¡ÿæ7/©Þþö7U0»ºà‚s~~WLeìXÅÜ¢§ðUª°Ä”}r¾—SöäÂp—dF´ïf!Ìê\ü­oåc¨v?à€|Ä”#(£'Û~< ’}‰k¼:I=ëiŒqÿ¨a3êÒƒŠÈ@@Ð@È,…ó¾0ë;*‹~ó¯g´kž²¡nQŠËˆè¡‡RmºÉ&yÓ’#\íF¡0L‹ºü¸áè¼ó¾Z=ç9\¡ê8ÁÁõê®òÈ¥JÖÏØÓ÷©ïMgôÔ§#TŒ{ó}°Ö˜P”¤H÷G%a`»W„Ì€nù„1#Y*^i¶‘urBYãAÐñ@¿<6•Yä—Œñ¤ïƒÂ Þ{×êá˜ö^nÚrùLЯ¾á«Õsï¨ÖýĺÕ1WS-X¸ úÐEÊÎ÷yóçåðVžµruÕ;¯ÊÎw Üq1â Pªï{Ÿ)(µM÷H]èÍô–¨àô}IÎFwÕ>JXVZBÙÖ1,÷J zïK½2Ñ!?Ê,Ö×õb 8¦Œùõw}4½„µí– ecsa26OIzâøTrsTW_wu5ç¤Þhè;ìQí·ï~ÕG?òѤ‡/K*§b¾þ†ë«{çÝ[­ñ„5R7|$]¢¼)¹ß&‡ÊÖâ©÷äÂî¥úPG‘%íúëR}ùË—¦ü®’êÀ]Õk^óò¤·¬ Ý"é¿»R'|nv3’Uûå/ù£D`A°¿¿îº|.¨Ñ%ÓüuV°•…œënªo˜ºä¶º^RcöL›ñ?ÿó?éÿnPnÂf2(ÃàQ.:¥î:é7ü„ÉÂÑÐUƒt\€?y/;Smz3°Ø<øàjÓí·Ïœ^)Éצ²}’A¦ãÒ¿rð¾Y$|×~‹3d­“rÚÉ'çQPk.Ím.Lï¨;¡/¥Oœ ?Óæ® KoúµñÑ¢¯”Þ/7kû…c9Ë ¹Ñ±ÖvZãéh&Æ1Ý) vÆ¥—^Z]vÙeù.}m¼¼ùnÏ`P¼ý ϓƅ¦Ì65S‘„Ø6}ÔqDÏÊñóSÅE£I¤¦8Jǘ#P4N¬S,Œß¤pœ'úéO~2÷´‘Î"|‹Ô8e‚œŽÐXguÒ T ›[o!5â2¦X¬´É&›VW_ýƒä[ â¼'¦tÜžG<rùåÕIyR]b X)¢’Ðág&ç-†j½‡Õé ¥•¿‰¬zá%Y‡…0&C/šxØô¬ ä”ñí½Aá 'ÂêgÈ–PfvÅ3:ï¼÷Îê¤kOÊÎ÷Ÿýùg‰ÇKŽn5tÞÃAñ…‚]Z8Þæþn]4×`™Ê_ç¦'…mXLo*õ¢$“fÃHúF‹®ïâ'îOD™)+ü¨ëÅ’_šú¨|ü^Êç'?ùIµáK7¬>sôgªÏ<1ÿ6mþH8)ø…;-¬æï8¿š»hnŽ×ƳEÖÓNŸŸø©woZÝà^ò¿`æ‚êg?ÿYu÷}Ê8!úÕ&‹îo{{ Šß—þ[`ˆ  îEîºëíA^¸ðܤ;gä]÷Çó¹jÕU§=€aW_}õâQ"xÓž†ع‹oOú×õœŒò6¸PRƒê1Þi㵃ø)ÿ.ú“lPøÀgz:OÕfLÇ/Õb’.uÈ5Úau)K”sÜKÏ´RsüοzçÓßf¬ÿ´Ù3ÎýôÜ(·ÏÛ9ÙNdØmÿý«=8 ßÌĈ„r þ—Éÿ*)?O]gìfgL†±7}%k˜ «yé½eR$ÈxVðþ[gU½l“MóϤ­Î3ò™ø”îaôðxéÐfµ”èB.½ ääWGÙá 9ŒéÈ&£43“°,ìvºQsz”a'Ô&„‘¾yVDŒAŽ1xw¼ÝgÖc(äÞz…é½…ùwŸUåìÐÛó¢;¤^ÊÖ[o]m³Í6ù!S9ÿû¿ÿ›×'é}õbuàýºéÝùÉ]ÍQ¡œeÆ…¥Ce£Ń:úTÒ(­ý¦5»¢NÖ¨è½'S²Fg`2›òéY¨„ÁµAo +:$”qtšàÝ,÷ôÏHÓüXÛŽG­ð¨jÕWÍ»œÿvïßò;®ôÜc·=òˆ¾i©˜º¡8£¾QòÊÛç0i¯aÖDkª£¹Ž1$K?p¦×š6íîjöìmª /¼ O‹… |Š·INÃbPyLʇ+ß&È—2­ !à] :*€öb ƒ1Ñ`ÁôÕ^¯ß«:æ„còÐÌ ËðUY\¾›BOÓ7aÅÙÄ0¥hƒºó5›½JÎúœ1ãž”fcNÎ8$-wAJóy)_ ò±zÖnZõØäDãlÏ;¬zýž{æÃÌÝ.t_*WÇ“6òkÚö{ɸ1émúÔ„·Õ’&Ù÷%þ•Y‰¤û¤ƒoO2ü¿~´Ú06ä¬Í ®‚ò Ý Fñ<;üðÃózÛ‰ŽàÚ yÐ-¸ƒŸ±4¡DÛûžwÉÈî¦ïæV0Å4úo®½¶Úmç«™©Ëõ•N²'ƒÎMT {KàÌj~èCÊËîÜ7gÊŠ2Ý´³FFup ÊǨü«S{~òGäs?_¾Ùfù¶®R_–©ézGžÅ€ÈGÎ65ëZßÜ”Œ1Vã¦/id¨J#sÕ{“ÃÕÅKõ?m–ª£ä™6^—qºk/œñÒ¡ãb„ê™’ˆé£A½÷@Žïåô}ÙGø Å+®¼²Úû o¨V{æ3ó=ÙâQ |S… …è^ÏÝTuy6…475˜§Ÿ~zõ¢½¨:@Ï$AÆÄ¼ËˆŒ¦âÒo}«ºþškª_$÷\}Q&)MßWH•…Ñ9#Oª= ‰\3Jâ}]B:)P÷*I÷rä5§,°÷½+Yý>Yùa ¯±1„\"M2èþCŽd+¬àkü’3…¸ÂŒªÿã«óß|~uǼ;ò(çñ×_Ý>÷ö|cg­è'^û‰|…'Å»ÒÌ•ªÞsCuíÁצN˲¹3äŒ\JÏï”’zÓdú䤅Ãûdʃ™(¹Ü™êô‚‘|1Ö{ê}Ñ"·(=ºzÎsž“;*œ¸ÅÁ%[AÚÕ¿x& ?ɯ©ÁÈsÈŒ¿~\* Ð7½éMùzW›‰8ß—[f¹jæ©aò:åcàæÕ)މ Sy¬™äëš! îÉÛ¬ä1 VŽÝø«äBJ67²©Ü&}÷Ú·šf:?ñ ×œ:÷Ù®áÝ«ç>÷‰éo‘“Ô‰Ý4µIõÈEwWËXb}÷ô£·oLy7;+Õ%KÂ0th¤§ÌoŒpš¦wø¸Ó“£K}ç'ºQ̵Nt­õׯöKúú²Ë/ϧRàjȼiùR›ìý~®:hOƒ WFz_÷º×ü:q1(Ï¥‘6h4¿2!gŸlõÖ¦9£‡ÊÉèÃkv Z*ÿÛbM¯ã‘t^è¹W%ãñ¸d˜øéOW¯L<|ù[äÑEn¯T®›mnô~,HáÕ¯Á¦7g¥rgZ àÞö}÷Ù'´ò'Ÿ–¹0&Ý„h­i¤ÒyÙ9Ësò®öô[LÁw]'4)ÎÎO2Ã_ÕKm‰õ¬ì‘Þ^“vwØZÑÆ“¯¹Pt*„ß9D§nõÜÖJù*•¢ï@:)ÔÊñß»ªk}ŒIxŒÞ)ß º¸”_WxG% c©Y• ÿþž,#¡m2ñ¼ä ¼éðhè¬eŠi®ˆ°|’Ù©Ä\N§ïør ¬ùè5«•—_¹ZöËæóÙå˜j뵷ΨÑÒƒ¾rP^˧êp4QœkDß–ÑëŽ(MùRÅ)~ñ*ÛA#¤– \}õUÕë_¿gµÞzkW³gïV|ò‰‰;üßßš>ýþ|[½Õ°‡A£}â‹FžÌÛâ „9Yø mº-¸Fh'ã>‹!à þ+.¿¢:èmU¾õÀê‚ó.¨.»ô²êoyG5{×ÙÕò³–¯fÞ4³šq^* I±Ø´~Nrþ¾!=Z8£zÑ ^Ô+^“B®÷d%ú[’cšžKÆê…^˜7QôFŨDâÿßòT?ÝÒÓˆ¦9ýfôçž%t%2  “Ü­ýá¸Z”dñ§ç’‘’ù0-¨²!iÖÒÛt´Tî‡\”êæ‘G™ŠØ]r5=p§ _)ëv?D¯rÁ¯¦ü‘Mt|ä%êwêïû[§_x[¾kôp“ôIÒ1&‘}FHÿšÞ?ó´Óª£Ž:*¯Ã’×&ù.J®1u.®T2l¹^Š{e’]вÅçΞ|òÉÙ~÷äÃÏ#¥Ž «/§Ð–!=ç¼óò-O[íºkÞ5º_£û±®t­”_my-çvÛoŸwù‡=ámi’v{Vº@ÙqÑÆã5îù[~å»i¦ ßÙcq5BKÈHTZÄÒ¨7ùkCôèUv…?Ì»‰$…ø¦ƒª6OD¡L¨E‡)h{z›@å<>¹(t ‘ÐAyÅ™ŠÖ«EÙÚq~Ò‰'eu½ç¯WM_>ùgL2*½jô3ÁüEó{W+²õ’Ókn*ÏR‘ÌŸ‘ý_'˜ï€·ØÈ^ ªg?ûY9-M gSIjˆ£cNó16—O\<÷œsïpÞ'¹Vyô£³_&$ÿö˜dÅ,z—ÎutiŒƒ1>wyýëó3uÝZòŠ Õ <Ò‡N ÃલQGêe7ti©& êù”%§¨×m¨ç5t.=T¾£·g‘ס²vV{iðF»lˆ–Y1•‡Sn®[1…g ˆóÝnvqÊ'Þ;S>‚wºø1)ýf™–Oõ'Œ]†¯£q"ü]J&·ß~{uZê<}%½wÔ'?Ym´Áչ瞻X¿éøÄ®øW'ýOnÂ`Þ›øA¿þæW¦–„xòÚíhâ¥w¥O\ÑFI«4á%>Ÿp ùœR2kô¤9ÆÁG†}ª ¿!gø ø»M@„=«Úoòa–ÏÅ„xö³Ÿ×²YO¹_ê‘ÌJ᜛ž[ÝÆà£g)/d£À|²×A¡!¤ÕüÔoâ@)ýYJOÓ 4F6énÂgxÆvŽh©×„l¾ùæÕª‰ÒÂ="‘“M6éd€6Ér½C¾u²zÇQW ‡õ›"›¬N©tøæ;¾©£÷£W#ÊmÀñÒ•åüÍK¿Y½f§×äéw¿/¸»ççÛ¿úv6@‚ž¶×iÕ 3W¨.¹è’ê³Q]ð– ª]_´k^jǼÅ”÷­oVv‡rHUžÖPQ.Ò§lůŽid9ùç„¡>Õ Ò’;¦ê¯¸â²ê ƒöª#uÉg}1…sûb> ]~ykD×ÊnÖ¬éÕ¼TNq6$]i”Ë Á´Ä{Rºzg-¤|¦¼ÏLr±¤ÉY ’uOzO§X¾­45ú©“O×>99 ÃÅàÿÂ7(Á×Q*yÚ[äF–zÃá¯òÑæ„AZrµ Çdã§¼–ùÖáÆÍ®ƒL‘ÿà7:·|_¹¸ é‰nÌJ—±—¥dBz~ ˨¹SÝÕžÓüø‘yOü°ÔÂmIÚ_ÎwÜW¡.rÒ©§Vw¦ôÜ©ÌÓ»óÓsH~"Ýf™lf2ª~þùççQÒÓ“ñ9+éOSÿ+¥¼¯”¾[à(=Ü!CïèÜëÛß®örÖirsÒ»ï:øà\Y4˜uäÐä·‹Ži/ÛxÎ3›]{Ì&YšzMX’Ic„(åÊÞ»ßâ÷.@NÒ#g4†ƒ Þ0|ãDX*û¾û¤G&·bzæZ?LÉÍNÎ[4f‚„I!R+T¼\D¿@OQ†&’\–œõHoJŽ‘éŠ9JQoÍqz Ñ0<ù¤úD2lhªßŽPÞ•Þí)§Ç|3p{x`v8ňūÙéïo\|qî„=*•“NIQMß]L@Ç”úP§úÊ«®Êë„÷Iïó²Ëë4Æhiì2nâæ®m¶Ú*oh:åÈ#«7î³OµL2n-ÁÛûW̧j”òoz?@–œt˜atp>=ê|QK¤J'Œ¢:¾6åµÕ(n@Ƚ ¢=²D…LÌ 0ÔÇãn„–½w™h#fÓsï!(”ëG!*… "q¥àU–'<á ™ˆ†½‘Ô"tk4榆ÏÔμÔpš.jŸqÈy&U¾Sb*„µûb°M1¤·¢¨ÕÊza™6”†'#öo)þ/pB&²‘EG>ìºÿþy-‰Ûôðä%ã kÝ”ùî‚aý“5KºK÷Å©Á˜èhË#â›d¾ÕÔ§òKD:ÄIŽþVþ¦æ¿pÕò¦¥ƒÿáàjîü¹yÞM·Ýs[澺'|F¨gŒŒr ;E¥Ql­hÛ11äA6aŒr¥A ZßÛøØ„z½¯ƒL¤ôGÙÈÓ!gu 䨄É8 òTŸ*ùõ©\KC@yÕåáo~¸6h`/¾èâjg¯SM[ÒAA‰¶Õœvqê„Þ•Ê>óôߤzB ¢Âˆ˜¦/H ØÉéýØÀd]S‚¼ù±#üºë®ËzNãæ$qs6yvØaY';ZjÕUWÍ‘Ÿû\6"ÖZwÝêQ)qL•<:ôæŸÿ¼:î3ŸIé¿h‰2<~d‡#Õ8¢)ÎuT’z1Œ1ZBÞ 2ðL½ÀAõÍgÝ :Ù žG‡P~ßuþÕáý’ß¡O þ¾ÒJÉ¿'ÊÛ[Ê“Ô Y¬ÃÁ˜t|Sðˆ+y…kF8é¯H+ø&=¡÷}8gΜlèEXߥlG3i£…]îrçŒxÎMy1XÅ•öØLe„¿þH¦žª×ä+=–°Øì”Eɯó|»bPy´!ô†d'ÿŒ%F×Ê@,áQ¢õ†¸‹ VXˆY7ê…ˆWqõ_ ˜´xîoà¾ç=ïÉG*Xìk<†ÞïJaéq-›Þ¿7¥]ÏE‚²zÖë'g0à’äôJ4‡Û&ÇŸé#ŠÎ4¿ÑSë’|ª4>KÓ=yašrgqŒžIÓûßÿþL4£ÒM嘲( Ryí×÷ÃhÞJ•LCþ“!7yd€6q/F…m½zïG*7ƒª-LÊoúÌéÕ­÷ÜšwÆßz÷­½5Ÿ‡ôÖ|nñô-ªåf,Wô僪ÓgTwÍ¿«ºgQ2F–_®úô§?§u4¾(§à‹xÝGl!ÿlïV·^ÔZÑ~ 1ù„Aê»|‡Ì|Wt"CciF^}V@<¡°›y¿MF#—ȵ©Èg›!P‚?ò! ò³ ˆg¹[Þ(¨ò–åK3˜nZÊ‚šÂ^í1«U{ï¶wuÖ™gUíPõÌg:,ô~LŸ1=F͘ŸÞ7Zª8é„Ô¼EÕ5?º¦:ô¨C«-¶Ü"åXnºñÆy—³Íû½ùÍ9øY–/æ‰Â`ëZ)ýÖ}Æ -]kæŠ~e¨˜‘ê™=)/#Ÿ`³Óm7ß\Œç.)k’cWÄ»ÊM™àŸ|âj¤¡w´u“‘ŸÒ¯ý‰A¦az¡‰ßm°9Éq?¥o@'oØMn·äz+Ž»a‰QÌ·™F7¥ÇNs׆ë¯_ûÉOæ‘r<÷7Å~Ì屫2¾r³ümo{[>ª¢K<6¤;*•ïdŒ³òF]úÁâråS%¢1ŠH˜¦Òë2'†šÏ’ªP> Ì1(ÉØÈQÔ‡“O:9ãdDÔÆ¥Ù{ÎÎëìôV-ƒ‰»ãî(_aE½‰òó·ïêLø?è ƒò’ʰ_™J»0¤WCy“qùÂO|–PäP—gˆ_ùEÜþæ"^érìΑ5ÆËd=†?Ò¯SÔTŽ“Á3²ù• `ÉSòPNdMV긫;m7Ï0îtz]¹çÞ{æ³B³õ®Eã©êÌXnFîøØ]½t£œÞð3cÁŒjåG¬\ýõî¿öFGáäªzì#[Ýzç­Õ‚{|wGý~ûì—GE¥5¸ùõœjÓ0Œ:1 6|ñ‹«R¾iT#a:ô1Ëdj–Áéx½dÑjXᓦ¯ýµÎvï·&ÝF3PâW/êœr—gòlúÚtªº§ÊíÛßþv¾YÇBñíºë®9̉ éþóŸ­ºíÍö4u"äßšô©ç±n¹IGBiÐaô³´‰IöÑöbF½>ý¬³òÀ’LÀ—r3`/ƒ šÊCgÜ1rÑñ™ŸÒoÓ›‘r`¨º¯NŒòV?¢VÆQÿ" £¡ÀØ=6ÙÞýåÕWçãžÏ^• _ç—ZCºõË_ž77£Ø÷¥‘)\›¡@'R}e'‘“ ë{hcR9°·l"ô~×G‹q1BCÊh=³ÑH#n Eìh¼}ªˆˆ\1PG6<ãW¡Pd!ð&´$?A@:ÊJf'ð;ì˜ü1ËQ$H†_úß:¥o&gºrìõÕ€<|ŸW­¾úªÕ+_i`½WËŠ"ÝAn2, ri”ÏH'RpABïú-ŠÖsòàJu59• Y?_¹}÷»ßÍ=AÇaMH7¹ú”g½y ȭε:š:@ÊÿÈVÇK‘M]ÁŠS<D…nâ_”™ôA)¥&Eëè=êhÌäSâó¬4N5øgŸL½~`ÈÐ(ú«wfäY¥Q˜u^‰O~å'¾",é‘?aÆ%/ï{7âG! ëmÊb\›i˜Èþ[n¹%§—È· ŒHyæ¿É#TÙ(c²"§¨ßÞ÷îã‘ jÎXt±†]í¥ñX9`ÁqMèJ|+'~ž63õŸ<ò“Õ‚­oí ‰ùq–ž¨F™qêŒjÝç®[]sý5y*ÃQx&}Ê äEÚM…­¡¸Mï´ãŽÕŒTΘ…=a0ýœ›d³Râ™ë9·Nzö¬3ϬVIᇟ5Óï«=ûÙYüâç?ÏIeR‡ú”uÖ©6Úh£ÜØ«WÒÃEÅ/:š ãYƒtª0Œx}ô£ÍË ”™2¨ÒL4à}§]jK«¼“mÝU_é rÁq›ÂšÀù„>Æsm }‡£ “¬,MkÓ€Q®®h­ýèê/ùKž©œ•þf–k9AxÒ¨coÈ`JœÖpαÇV{¤¸µã1öœ #üã¨ôãmi€JÝlðŠ²®óW×\s?Ÿ“ ,µs™ˆ=F\Mß—¿™Å/®Ô±¡WÁsòÄϺž.‘;Š Ã¡ôý·BŽ%Æ6´)ÛÑ ã55YúÁ{a€‚Ïht» @°H$í\™va)ˆ0\,Tþîw¯®žÿüç¦_…]Šñ_«¤êóf$ô³þ£gœÒÊ&뙨=£b«­¶ª>þñgƒ \k"U|È(È‹gÒ¨áñ]Zå¹4`"ý¡4ýF¶ò~]®ƒäÜá CêÁ)e*í¸ Éhd@¶øç}FƒÏžï8Šƒ¿€ïÁ¿(Wþ£#åwe[OÎàNÉa¸f–ö“Ÿüä%â4Bˆcž W>âšFrq'1Eë9Y ‡‚kžácÔÕ:„ëwü  R^„#þÇXAøâ‘gi£Ü-½ùÓŸþ” —‰éÚ†™rùº ÂáO¹)/a– ¥ß½¯±Üp£ ³!yüÉÇçc˜–˜§¯¡5fGeBpQ9fxNUñë*Pß%“{R ò¾iÕ?þã?¦ŸgåÐr @è´H#~àšQÁÅ›3“.cLèT€‘®=SGéɉ÷ÓèÁü´y[yµÕªW§ßc½¿3K?8²öÚkW¿¹é¦<‚ª»æ¬IÇõ8oò¦k¯­N9âˆ|è¹iR\¥?¹®¼­××&Dµ[Û¹“ƒÊ~" ê|©Oê~• Ïè eíZñã=:Œ®sQì<ÿ[2šVMŸv¼ÿ[â§QÍ7¿ùÍ™ë`Ô27û¶Ií¹%¿¸êªêØÔ;.qe~Н¾Ù'\D³Í+^‘—jÈ‹z%ŸPò¡n€ÚÏÀt‰›Ÿ2Ÿ“‹%:" T‡í/F —ŒšÚøRfaxzòõÙÔÆÂ»,ò:–—‘P…Aá^Ý8уò;Å=@Ï‘Û{¨ðõÞÅ ŒLß½+.…ÄÍu p¢4ÅèJ„©!Â4|¾É&/Kþ…k;ÆÉÏ=óÉ¡õÙÉ™F[>ï Êaú”_F9”F?Hw= ¼2ßüqòç9òò㓬}&NïhØ­#¼øâ‹G~™Øn½d•”ÂeØÆµ:‚{ŒEþqšÜü²Žç #¯Tý”7H#ú”>ïÖù×ÓFL3Å!õŒK# vmzG˜•tpÂV÷BqrÊ)¹³‘öàWäA8ê\c] _ Šòé$Ÿ€wÕ•~ ·ôZÂà:DŸ¸>Ñ¡lL·7„’[è<2û&„Nòá·„ðé˜w½ë]Õ1ÇÓ›—fOšÛbRÔV®xý}âôü„ãOÈÓÈ®‹½wѽՂ{ǧ§— '9µ‡A»Cz´ÆÓóÆ8K,w‚¦iRiVw”›43\<âŒ[Ó¥F³ñØ•6|XËi bƒö]9•³ãtŒ€ÁÆmTÍKi´ô1½…dEGËgöÜ}÷%¦ã™ä/]¸`)Æ–ÉéPh™Õé)G5mµÍ6Õ9gŸ79Ù,´Ä”{rÖ[Þ—Ê|™TƸ•oãቚhÇîÉpt%(ÃÑ'¼ûÝïÎ:Ór¾—o¾ùâ©øÛÒû âýÔâ/›:Hüêðã†5È®½#ùÁOGAIk9z+o¡/}è³R_†¾=­Œ8þÈŸ¬KkÈ^ÔYüå/ÙXVKƒnš~ !!ð]& ê©ûxîPÆÈÉŸÂQ *†°Œ  «¨ÌÒYÒÉ¢©°Aéd(É—0‘Õ³’¬ex~†ßÅÛ…¬~Ÿl t´•‰ Ȇ̔¹ö +ü’ë 8ù%oþšx\ÂouNK›²0íì¸Óñ;'%§£ÄŸ)z»Ã•e‡L¶¡ž6Ÿ®({ið< Ru g}6q—Þ-G£åKòæ¹ð=ó>®Ö Ò6N– ˜L­—=y‘'Ùu7ȆN~Û•ÌÉ-§MŸV½â¯È#5Ùe BÔª[ßéüOßÍ-²üÒï ^‘ôð¼{ª}ìcù軼LØÎMzMÏh-ÜÊ¿¤ ê:Ø=[ L±º)‰ÁxÔhkØãjNl }è°þÎr2¹-Élî‘é9X52蛥쥩~8Y¢<èÜ”¨ +äÎá¦t÷¤Ý÷à.绲ü§KýïâoL$Àz~JÄoòOÿ[šÂ SœrᇌBÿ4ñG~º9$Iú CŸÑÉÀ8jÝóSRx³’îÜtûíó¨ê^ûî›×§ˆzžFpoúÕ9Sÿ·ÜpCu_ª¾š>2~È3J­ZV=\T;?éÿýÈG²EPž!Î$4J Ñé±DÓ eË ì¨‡¨#dP¶ñ>£gKù-Úp²çB_ÿ~'S2îÚÆ?Û[¹q„ŒR kžB mB„’ ÿ”© .ŒhûyUÊDÅPx¥rP(ý £þÄ// iÛm·­®¸âòê€ÈS›ÖŒØõè–¶0#Ò"mòé #Cê9uƒÙ4öwIÎ:„Y’U˜Þñ~(Lïr¡L»Õ³ÉÔÀ·!äÖVNž“3yñÛOÖr ™ö¥‘פdÛPr…ÑàÄ£GœïÖ¿â‰õf Tþð?cª^ü¡ìêðî ´ù Wð ¬[ÁÍÒ Å|b8óÓñà ¼ñ'|Ï”ƒôª7Ò6ò*Œ.ˉ‚à‹¼J?ù“¹Æo>K®’-9“‘úþê {eŽrVh^)Ä¥v¹eï¿–P-F^¬–\òcšÞt|6@Ý{NJïŒÞ [o³u/Åc8ÈýÈ©UVn\™îà—gøU/';nO<²šÞ“7E7#åS.¢»¯ñf¶’zN’ß› âs?>¯Ë»;½³ÉV[e¿ù*ÐätQ\‘ÏïeI_Û$b6 iÉ@p_ZqŠ|ÈYžÈßýÆ_äÃwÏ£}–2ð¾g“M‡ÖùWB™Ê„.¨£Ÿd)AŽmú_ïLÏÑÓ”95uÃÊÛ…¤Vб˜;[nY]pá…yÍñYgU½å-oéÅŸÒf—=Ãõ¶”ÇUÒßw'ýó„ç>·Z%=ß#ùщÁµ/%×k={ŸaK ¬þÄ'æñ«Žäï0Êo³RØâ»8ñÎ&:\æâ‘ü§úDfýÚ¿Ó™Ú¦ºAŠsáð³_/Î(_Ï–Ðcˆæœ,%d’k"¨gñœ5 !0ï r* 4D½)Î~¦w–0…¡±O4šmazÎÂõ¾–k-Vvö—ïü)Da*ä…ßý¦’†B«C˜~G¾6ƒâyð'LéŽ2ð)ÿò$ŒçMdõ)ÿÜdT Ã@¾#Ïa µ…eËÿʨ^î%ðÇïüSØ>G‹/}éK9}6$q¾®(GNjļ"åæˆ”×½îuy·q]•_ ~Å…Ïâ‰F(ê9‡k’Gø­¤â Ž “ãïã©@ÇQÇä›üKÎùò“<#wz•¼Êßx€kdHžk¬±FuþyçW³wš]­÷¼õª}^¿Ouù·ï?«ØÑIÙ²+ï„7C?+•ñ¤7¬ýÔš:R ¿h—¤ïæßS]tQjþ%×;IMO[vZÞd"~iÆ¿¤Sþ¤¿ ø#S^Üc’c\<}½õªUV_=7Úœ)öX5ðŸ#Nôˤ°Ýˆd*åÄ×3;Gò‰éÓ(Íeé*IÙ¬¢óÖåÁ…ê¿éåÐßx(_øžákèPÏ£øsüò›L:´äaò§­ î…jCÉÑxBžd8]F%ðuöž{æÍG‚–ÑÞ¸8©ÆúPÂV*|¹èë_Ïòw/ºÓj6~éK«³Rù»ßý–—Šuš7¥ï®×T^®=*=ã„¿ò#™ÖÃÓwF¤8šÑ»ŸúóOš×4©eœâœò绵¡¸€ÿ«Ò‰éY9rëøC¿CW d‡sxåÔ/òÃÑR_züô{è<åÇqnãÅÏq1BêdQ€2u4HÝD0ð.ÅEH„þBx~WPÁ!s[XàwþÅ«`…Q6š¥A*^Ÿ -ÂôÏ­YêJÊ{a†"ޏCý Ì0H…®¼sdÜÔ×i‘Oy^Sï©YÏ;ï¼¼öì³Ï·GùNF´q0dK’{ä½ ž÷ÚÊoðÕ3²ÅCrv´!«Ãñ/ò—PžŽ;QW¼sá…>à–$~F£üJȼ‘ÞB„Cuyt÷ƒŸÞ®g‘ÿºAJî8½4²}° ô]¿ô«sø©^â[“?²!²4äm£Ð!‡’ë°«3ÿøÇ/Ö!:&nÞêÍ&7BSö¯}Ík«é Ó­½¢E=­kr ç%ÙÇsj>¹™ gVo|ãë[e.=Òu*Ò4Œ |5Ò/Z…ö?™ÆÔp›ÖÔˆý*'ïKá[ChsQ·Ý~ûlc)3b–2ݺd¯Ôò£×Kà_©ëK§y*¿•:Ôæ®+®¸"wÆMÈK½¼äS»8 meZç)®Óž{×{ýAæ~§¢Ýôw¶@îMïåµ¼é"ê9R®Lεž¦¸·OÎH¹VÛ{;¥Nø~ô£¼®ôÎäîMN·•Ù£’6,Ù%®ká½h}×_ý¬ß‘Òm„U¼ÎQOtœ|¿#½¿Gò-³é{îŠ)§žzjÎ÷2ÉÅÈ-#Ö½ðΪ•ÏÑê`uY]£G‚Ÿä‹ƒ8IŽ\ð³lãáÚk¯ÍG«]}õÕyp-.+LK™ëV뇀 M‚ ƒ LQ¢ÌÖeˆßãH›@<BQØJ°ˆÆ›8UþƒœÂ!LŽ`ü•h[Á CZÅ'\{G:<Næ0ð.e&Ü@(&®”K„!Ò„XÞ'ÿdâêyôž4Èr’eü+ÂŒü ˧4èEþÇüG&*?ÎÓk“çD‚ë®»nu 'dŒõRÊ])_8«ŒñØÀÎÕÁ¿ßƒßa¨ÓäEÞó7™áG©3šøB–sæÌÉ¿édàŸþ©š–âaL?tN˜É´­cœ•¹l+1¸V[×›ø²ä¢eÄ)Rò4‹y£ß&g$t™”ï8d^øxd¤µŒÓ()#•A\¦‡Ñ·€å[–R¾Á¢î¢[‘pI‡zNŽì¤zÇ Úd*N:êMñ•¯|%——£)ëmßÒ`Ü4rÁ…0šÀ?Ä;‚d$D¤žïa€‚Ï lXúâˆ[åð]x] PàGâ&ÿò çw‰«§»¢Ð…¥¾÷)®h|¢qi‚ça D¤Qý­Ò‡¢D@y'ùG*ð]âö^¼/¥LÉXòŒœ‡zh6rŒ¦Øu=l%™È%ª¼ä?äD.õ²ñ7™xÇï\%—|¼£|šz÷]À¿rVž6P(Æ$绩*ñq›¤Æœó]ÙÖ¸%=Ò5¨ŽtC1–WÏ…UæA:Å¡œ8¿‰Ã(ƒ[häg² ^éoBðÍ'*§&Îù£!"ß½+޲î{ßß¡Cø÷¾ E‹!ŠdO0@ë ¾?gíçTë½h½|wüb¤â[fÚ2yÄ ”Žrý"^e¦lñ/ê„‘Ùs/¸ Ú6u$bó¯¹SO;-O‡®–Â[=9-†u{ S^ß’žK½±LÑûyŠÿk‰gó’îL(caËÏŠÉ¿¼—œkão¤]šåƒüp²”©÷•i´F—\ ­ƒèfœ/~ñ‹#!M|”ruV~•eï“o¯ä#,%èà3Ê / Oç¹¾÷½ïÍNë|íDg2Ý’Æ$.øtoL•s:*8cÔ6bLeszõö7½=7œ›m¾Y5oѼdg:ssVõ­o~+dzñ&WsÎÍìÌ3«SO95Ÿ "_Â~›þòÞ@þÈêu ·eà üJÉϯ}6ò®ÿáóÚ< *Ó²V}Z'¸x4*9†(Ãõ]”ò‘>rö)½ýø; ×åKù0:ÿó?ÿ3—Ëluh¿÷& BÐcä¢=P6:‘~<ã‡þô[ñ;Ž’ y+kw‘E_ÀžŒ>ý鼨Þ8;ÕïM¼Ð©¹çw¿[\ö:/jX}Ôò±©Ì® Á-±ñèšä”À?^Ygª…UãèÐÛSÇ”;]õîÕÉ1niØ0vLÕw¿›Pˆú-OQO=‹üy8I®Q'Jð' ¿i†åTÔSgKo¿ýöù“žùêW¿š—Œ%º[`C‚Ðd„ )*pÃï%Êçr‡Áßëï.O@¸Þ‰ÆÙß чéYHSƒ‚‘§zïAúœp¥W%+óé]a´))D’7Y¸âYÄ©°£iRàuˆCÞùg\ùib¸Dþ…Ù!pÞ©Êf]è¾ûñ2åAä-¯d¦¼Jð2ôÉ?þ k€âw”ã°\ûm €3Î8#Xs¾;C´5u®¨* <\¯ò–ŸÒUOGâ]ùëj€ÿ¸Oõ™\ 9J‡ýmo{[¾ýi2 ¦<ú/È!xÙ$WþðÈžLƒG8Vçt \¦|ºPƒ¹ÌÂÔ ^0­š13•ÍŒåò®z—œûµs«·îóÖj¿}öË賞õ¬Ü˜^véeÕ;÷{guðÛ®®ºòªÎ(Èߤp1t¶tqaLƒå#õõwF©Œ¼Z¯çoFˆ5£¾o’Â?ªAfžÌNjyÆ}égþ-ùïÇýa¸~…­’¥ÑzÇüõ{o"‚<”ÝS ]@ž@fä¯d",u¾kXü•v¿ñÅñtFÈi´W&G;Ú¡wÕã„{祢“¿_´Åù{É-£ q.h@MsLëc5”‘©£ct•ï2„¥Çß:CÅsæíœ‘+>ÉS= ;£¬ãe;®Nx¦ÐÍ\Ô‰ÒÎà Ҁÿ%èÛsÏ=7/ÑvŒ5¦¥›kÕR@zñB\ñ¬ñ‚Óðkxø!P¤"È.a Û'ÒqÂ$daS~ü*ÄG<œßA\n&¿ 5ˆá÷&ð'®¿`„'â¦Adˆ ˆt ¯kX!ï©äþ.óiåʲ ”røÜç>—o!¹ôÒKsÏr²A”U 뙓'‡‹MrPŽä€ÃdÂÅ;ý ü¼ÛEÉöãç;Eá7õ«ŸÚÂÇ \+ Ï=‹tø.Ýx'ζú'íÂóÛ°SÄMæò ÒmuÖ:B‡Y[.¢‘Ÿl w3 òK~ñLƒOʈ ð)FäüѱQ¯qþð¼ŸñÂl2Ë»°cêPøÊ„ß@”E]/µ…Û„Ò¯¼G™û[œÁEð›5Ðn­a$€FÞÎw›}œû¥O~rñ•‰ŽÝyò‹^T½à/¨N9ñÄjV’”ëLåMÈäŸC_Ô9~}—·Ho¯Ow™óËæd‚²0Û‰WÚé¦6MmbQ†uý:È”©°¸zXƒPê›(i4 rJâí[ÒwG*½2ñn›Ù³«SO:)ëc&ãÑt¼ïJN©+•V_½ºíæ›ó´½ à–QRìåŸ? ’ZÓö/JÎG \Só–Iï—œ¸ÍD ¸ö­äŒˆûtMè~œÐ#2íªÓå1êCÔw9ô«gM^´+—œ÷k#ŸS~Æ ãb„"#TÐÑëÈ\“êBULD!ÜèðB>a{G!^¼ÞENq)”&r«,f]Ñø,{&QaAÚ„…P Hg4Þ]!¬ †„+Ý M‘Ö¦ü´P~üÔ†ð›”{„+­eÎ9çœ|l„Q´µ×^;ûŸlß(ë™’‘¼Ç”|p§Â¸ ×àu4•O@= NŒ—òPGp¤ üE]!+ËGÉóÓµQÃ%wÛê¬3ý¾Ã;ä3PÝ~ãïɲ-P‡az4䥎%þÈ7ð.àïГMð.9‹kPV÷ Q~#så!>ßÃX6Ü6¿~ä(¨½“aÁ(¼Ž`2úÊxΛ=È!½c³Ç%©ãLoùÍŽôë®».¯¥6rh¤¡4‚=oâœïüê´öã:?a€2Žm˜s†´8&äåOúS΋iÚ¦|û­n„zo•›gôH@Y3¾„5L%å庾i*›}\5{ÞñÇWç¥g¦×ÅÆ˜T[¤”9·Šuýkþ­äƒ‰Æe¸å®†Ú°"61D_’œ”Þa|Ú£å ìüXϪ¾ŽvPð«Y”úy”48OzvªS–39…b<1.F( Ÿ Õ{é”h¬»+»xUó>Á6’í·P þ® Üsʯl¼¡IÑR k<@4 Òi‚®ä¯0þêr(ó/ÝaÊs¤•¿HƒJÚ/â“æ¼çßüæ7ymˆÆvÊmœ*÷d™Èg P # v¢ñ'ãw?™FÅ&7,‡J(gq—ÜÄŸH‡²Ê7„'ße쇦ú'_Þ'Wj”»  wË:»Ë.»äÑyg ZP¿ãŽ;Žøš\ ¿8aD¾–ò©AWÎ<Œõõ~t…0ü8œiâ­wJþ÷ÓIü*á×ýzæ÷(ß×2Î:ú…[GéW^­ ýïÿþïüÛ»ßýîjË-·Ì:[|vLþóŸÏ¿í»ï¾yÉ@„'\á÷KƒßéŒÒÈï§"\epøá‡çðxºÚjV$NNàδ¡òl=9Ò{þÖ–á­¿É+Úxr&S~„rìÇý@ÞâiJG}ßz_çßžpØaùÐyÓåΉeŒÒ~B°ÆÓ!óÖŽš~·†ØÙŸF/ÿ”œ#”„ػҡ·æÓúO#ž Ï0Zmv‹ \©ZxWÊ×Ú‰‡–‹tÐAy).±1úµ=mˆúä@Míx?¹â³òùå/™o;c¨[Ò0Þ7#4Ö0ÖGB &¦Ý $!zù¡8‚œ:¨aô~]à ÁsÂŽBÞ ¥aA¢4 Ó»*i™†¦´¶‘ƒ_r@ŽA½#qE˜ ž0ÄÑVIÛiõ¾©SXÂp6Ÿ³í4ô“ä%o ò+kò"?ylRäQ/¿RÖʇ¼ƒü {¬ PáE‡$tiÁÈ‹ø=畵ð)Þ•çAõ¬  þI Èg¤£”É0 [õÇ»]¸+n½÷0¦, ·9a2‚LÕ9rõ£3Ë2 Þ2BÉŠåQæoõ¶”gÁ[áB”OWeå(aÄ!}Ò$ñÙÄ á†_ið[øá×;u¿~+ëg‰z'¾ïF}·Ai¿ê¢¿K¹*§È'D½u¨#íâÔŠÉ e -d„’;ÝG^¡ ÉçB~tgSÙ)ƒc=~…é¹8úq±Ž!ŸÞwÏ;c’1§$›v_võÕóÕœå$çÏ:k”Z÷/ $ØškMòÉ1J·Nüóž—ËÛ@Îsžóœ¼VݼòG²ˆ:ÑÂP'}6ÕÉ&¹òr%cÏÉRÇ×ò炚I6-£Á¸¡ÑKŠ^z@%-w̉> P ÊÅs f؆Ñ{È!ô#r„ &—tG!JŸ‹²õLy5ñµ„o†ÛãÜX4-ÅSžÝɍܸµ¯­ÎÿÚ×òaòrg-(?˜j…gÄ3~óÌwsånû8ÔºÒ sù~ÊÛ | £k}þÉ3d â0ú)£²™>üá-ÓÑbÜŒPÊŠqY7B‘'Ö‰ ?ˆ¨%ἃpQ]è„÷>áŠ3 ¹IÈÄʨ©‚ø½T4¾ '”֨ žËgS«w²C¾´åM'ˆèS\! òò= ÐAeP–õ²\ìÒA­CxÒ€ô¼uäÖì±ùjN˜›žãâ‹óY£{ï¹g5#=—RµÅ§T˜šÿMr6mšœÑÑ{SšÜœtWʯÝðŽ_–ó?ë#ßòƒø&dù”ƦzX¢Îñ.²,á}2 ‹÷½ï}yÉ‚…ýÿôOÿ4âkü1îFh]tŒ6©Èþö]2Ú§AR…ÞWÙF?¨0øCø²ÐÊ6(´(d~Å…ÚEñé,‰ŸM ¸ È1äUº!&7¨Ò•ù(ÉY¦5Â0ù)åÅ/…ϯÝÅŽîq¦Ý ¸' b¤Oð-ònúÈßžC”±OFöÊ,¸æ=rÆãad(<œVƒ½&4ñ>8:šðê(óÛOòWòÏßÒü %Û5¼ÿÖûé¹[c7YΩùb„*¿úºúAVøD_‘™gdIve}®ƒ_õ›_ï £­Œ”¿ùn?þJo?´?ê wÄ!M üz]á·+/ø:Ó¤ÇýyŒ8?u¿_þB7ó7hv#Ú#|ï±ÇÕ‹^ô¢êW¿úUnä_ýêWøš¼ ú²\ZW‚œýÁ1e¨¼»Ôí&„LKˆ›^?΃4Iw eÖ׎†Ñè¤ mƒÚûpæi§U³Rw¤¼06]#ËØ<îÄ«K.¹dq¾ÕÝ2¬î‘…t×mq Ò•Ðã] Ô?0úûßÿ¾zžÓãJÛ¿ÆÍ¥ˆ¬©Õ‹N…Ð Ð3õ¬TržSQ ¬(ŒRYô3@ë ü3fïùî·Ñª´ ¯¬ ÒPÏýÒˆ|xO%Hk(Ì6@È’ÿ~½$¹•Ý ò+ežg]9\GSxKy‰F éè¢Àë(Ó7Lñ^É?‹Ûûžs]Ã3úiÞ.ãuÖYgäéC:ëŒù:ÈMG ÈJ™j\•£¿û•%>†JG4ù2è\U&xØÄ[iÆåW1èYS]‘'Ïùd¼#ŒŒ.u†_y”Ÿ¨mõ³ÔÍÂFþ5¯yMµë®»æC釭cäÆ0k2BÉ2f9•™‘un´'è¯à¸°”‰çQvÁOá×e]r£K'¢Žà§4ü⿨NL§:Š#~ô£ó¹ËÏ|æ3G|·#¸Ñ¥®Š“ £Nø›qz>š|€ppÓ§ûàéOçD7éšñƸ¡*«ª¡ €QCÈHˆ7)7Ì(a€BD:T!O¡ô+Ô:¢€½Žp›ˆÜiP¨ü—DZ}—/aF¸M޶Þ4É@XÒKüG%“átAIò¨ÌF–¬IûÁ~É©JOù­gÉ“üÉ…?e7ˆÊFÙ)—6Ù÷ã0WÆÁïX õðð&Òeé.õƒð‚kK“>áÿ„âŽ:ØOöW^ye¾êä“O®¶ÚÊ)|-Xo§Ìê#¡äD×(C²#rìÒ¨áÝ 4 l~^õ®rï_”ñ+ƒŒ ~ø>¿Ò]?ÁϨ+â)yÑœ¤Ë»p’ÉW#.òy¬×Oà×wa’›òÎn»í–wã;W¹-Í“äg#‹ND)krd€†^Q–¶ò², кüK">¿?ƒ‹Kc€BðV¾¤ÄÉ•q’E›Þ¦þÕ!ù”Ÿ žÈg[œu'ÚªãŽ;.Ÿ¥|Ùe—å#¢ Œ›JPF•Êõ"2œ¢TP BÅö©P»VR$ˆÂ/ ±ư‚œþn#r[¸Ò ¸¾FÅ3aGz!ˆd… g[%«Cœ®OðŽø–¦’QžÜ6Ûl“6ÑË5¡±(!8T‡†_?ÊgPYÛ ´Ž&‹7ê…úã·®áõƒô…njœCsÒÕ…÷ÂÓØ–kuK˜âŸ´HwÔ®, Sg OëëìˆTF“¸ˆWåWr¢'ÈC9ú;ê?(/ÏCŽ%È´_C^'ÄÃÆ2ô”2 ®D¼âĿŨfø®ð$üFÇIžÄqz/xù†“! áò_—EÄ¥ÎDýä'Ú˜GÞ£?}Úí}g-zç¡24P¡CÞdm<Ž‘ƒ2 að³OJDYuá­xK}æoþ9iYš¶o…!¿eÚ›â,õVøåG~Ö ày’!yˆOëqúÞ>Q§kfÞ9»N¾y°0îFh ÕË´ÊI8Q©! Äç°ˆ†K!Ë‚|Yøý Ú;Mƃç]HâD,~-’æG\.‹C®.•¬ QÑCAC“’îi rºgÛ zï­µž©Ë4Ãd‚ü’y~eHQù$;átmTÛ üÈ]z|H7,JHŸ:"ìA£Cü–iñ·¸KÞû;ê´QêK q…b ƒ@ÜQWJ%Ëø4“b—ñ[Þò–¼ ~iä3‘¡1§3cs'™‡áÄ‘绲 '‡~ÅE¿ùôÛÒ uàŠøð!ÐOï(îu…ß&ÞŠ³)Ÿâ•.œä,¤±ë¨&?äPÆYϧ4‡jêý»ßýnuá…æ6ð¡å`ݲ²$w²ÁY WrP†äƒsä£ÜÈÈS¹’aÇø§º”Uâ“Fi°ÄÛgÃòVœòXæÓ;òâ;;a˜|ÚxÛ'\i¯…úúýï?ïõ8ýôÓ«Í7wBꃇq3BeÔz‘8r2a”bDC7!Lä缃$ÂVزåYI¸2\¿7 uð'Üzåá±T~³,ìAðN¤5›÷…ˉ£+¢¢Ê'„Œp›fÞÎßó¦„ä/¿%M¿[»ôþ÷¿ÿﺋóïҥ“UèŽRÿ4¸Qn¡@ÙÑuýt ÿʃœîÇ7ñð«|Âè(ã ÞF½nwiÈåWþ„+ÏMˆøø #C¸üûlJ{ðÍqa†*Ídq–ù'ÒþÙÏ~vR_iÜòïÖ$r”|%+û _ƒG%çÊúÌn·£LÈSýtC?”¿I‹ÓlŒ;ì°Ãòr‘ãf„€¡z"žïf©H$…p LA^]ØüDÊXM½^~& ÂßQQø] Ð:„S/`Vi†T ˆ%Â6äéíWù¤£©wm S\>Ã/Y*“¿÷M &”%΂3Qù‘ÙÖùè7rrj‚ø)\eJ]Òè™ßÅ-ÒC‚2ZGÈFXÁϲ>uIK„©‘—×~Š5@6xHÏꫯž×)[ÏôPÙhØ•]è;² Nt)×à@ Ï lé#å‰ÓýÊ7ùUü–P®ÒÇE~»èÛax+õ\¤!â„à§ß¤Aº¤Y¾åOZÉßgÛ —x"ŸÂvJƒ)Îk®¹&ß·í8¦‡2äßÎe„“d¤ " º¬ È7dºEy K˜Êoi Ð:Úâ ¾”|íÚqjCÔŸÒ!¬ˆ“|"Î&~BOv‘g éWäÕ¨µ&y¢GÝ06¬\Çãf„Ê|œsGÈH@”‹¿ëÄ’ŒRyù[Áð Ó3ïwUPಠJHƒ°‡…0‘±CºÁwáE%êï ƒ +ü{ip›*È‚û}P#Þn„§²µvSÂ{Þóž¿ÛM &”!ßÉħ|sñ,dæïà#yS²ž);å¾4N(»¦Fº_Z¢nÔ ¹:¢®,-Ľ8#-iáºÊB~º€¿Nj°NÙrrz¨#ŒPPŽä«Lɽ‹þã¼Ç©JqþV]:áðë~üÞâï ܈Ó{õxFc€ «lOʺ"­€·ê?¦Çûå/dáÝAõ›ß0v¡:ð.öp“Y¥‡2ȇ d¤N’qW´Žà§ò¾W”_×°Ê2Ä#qJ3¿xâg<“φ…tDG¦ä‘¿ƒŸâ¿E^K}.}a'Œv_øLwš9²LDÜø‰§6ÆÍ©$Â¥ ‚\0Ĥ. ¢‘¢‹‚j‚ åÂq] XÚ„!H!]Aª&"7…éäl2"€¿A. “îÚˆ—V„+ͦ݅ùÜç>7ßiL¾„²#²&Ë&96ñp°Íì a÷3@ëhJK]…ñ!}cQ–¡Äp¯ìì4¥EüdiiBWþÄã’„ÓN;-Oq>æ1ùå¡ y¶ó˜\CžÊ•¼»tžƒüÕõmS¹?ecÙ„(;a òËOp[š•sÄé7o…3 oÛ8Y‡ºMÇqÀ_gý½2Íò'ü~ˆ4kà]æqôÑGç†ý·¿ýíCâ@ú~`l:M$xCfd1¨Lú!ä©|¼/LœTnåç}å=¬í­w}q Cž†Étà§púÕ¿Ë£x}‚¸"Ÿ¸Â¤'›€ÿÒáÓR69ê,9’ _GSFcq3B /vË(!7)ÄA<¤@ÎHjRµ ¼[6ö Øwa+ ®4¶NQ m *ˆÌE¸‘Vþ# ŸmÓö±ê«_ýꄽÒxøñÝŽ`мøÅ/®6ÜpÜy…¨pŒ¼)h•€úÁïA Ö{TÆù.œ2\…_†ë{¢M!*èAáR8ž C¬¨”ŒœP˜‘6a7¥·"/ Âí*‡€gònJøñœi†éø‡ƒ ÖÀuÔQÕÚk¯]½õ­oÍG©YÈ–Ì”y+Whã ¿ýx娓ÃBXê £SZð.â±ãß§ß›8ÑŠ/ò,ƒ”^ ~¥çñ)zÞáRÜMr©C'áMozSuüñÇ?¬ P {—D<ûÙÏ®vÚi§ê'?ùI.? ni°£q²Œ†\ÙsýÊLXâ”ß’ÏÊ­Ô+Ñ( 7øßéÀ{áwá6w| ®H‹¼È§4Fã? 'ù—néç7 Pðž|‹Kœx*Oü‚øÄ×á¹t¨sfÖ_ýûì“Ϥ:ðÀ«ßüæ7ÕSŸúÔ¼«•9 êÄ«“¢N,ï(dÏ£°ùEÄ(a–¤¤¡)ÜP‚ ×O×á]D%鈼Dz9¿…¸:‚Xˆ¨‘¥Z¦7òW· SÅñÌM ¦Þ­ YmµÕòo'¸cüo|cnà­ßúèG?ZrÈ!Õþð‡,Ç=îqYfdIî¾GcÕ„&ÞÔùï oN‚8ð\XêJÒ.¾&Npuø=û~yîax_˜¸+=d!Ï€Ÿ2-®Å3Âô‘|$—QS:ÊPv×_}ÞD`G+CÜ‘Td‡»%2Œ†Þw<ÓXú­‚Ó8 yžù]yñÏ‚ÓâôwÉ Ïúéì:ø«ó–^óçoü®ø'N–Fe‘²á7êc„uC:È/äÉIc™×¨`§ß\ߨ/އ*‚ŸøÄ'òI*Žjzç;ß™7»ueȵ”_ ϵ‹ü;×ÂÃe¦LB§á ®øÄéy?D:ñ6ò N~ÄïÝà '~ùÄý&«É^/~©×žù;dqzùŒ0œÐðÞ÷¾·:ï¼óò­]ã6?ýéOr®ÇpÆgdãçòË/¯ößÿj—]vÉG­@(ŸühjYñ2qï#F½ ‚ð"€Ø®°"½ý by¯®ý†@‘^ɹP´ýÂhBS¸AR‡};ŠéàƒÎ7%<ÿùÏyëá e{ÅWT_úÒ—ò9”Î÷3UïÎ|ƺ©Ñð§‰Ð¥‘îáâ(¾3QÒ"”VÉ ïI‡¼ù›¬ßuv†Ís(x C™ç¨K®‚´èðã;£Lÿò/ÿÒš§‡:pÇ™~k®¹f.#OF5¤–Ð8¨ß­QÊ ¢¡òÙ&³à ?mh äBtFúé«h»p;Ò1ˆ·@üŠ/qÖóÊO6]ÚŽ¶t§^wå•<¬Õ=æ˜cªoûÛ¹¡gŒ=\Q¶ñê¸7m<Ãg¯½öÊN§ Âhäȹ4@uœšP–u„zÅ3ßŃ#ø(þ:ÏÊ0ºð¶ â Ã/P浫F×tHw™WËgš½å ÐSN9¥zùË_>òÖÄĸ¡M†FïYo¾ùæl­»&Ò°3Pt q´¤eáD#‡Œe%èa„áW*3ÏëÊ©pma4¡)ÜPðA¶a ò€på_:nºé¦¼Tmºé¦‹¹¼R†Á‹àËh Ð:<¯ë+ç ¿÷„Ý%âÑ F: â”Æz^ÕÝz‡§ ]Ó!nñá±F݈Ÿ´|àÈyqMá~CýÔSOÍm<®’SÂdOîýôB?ˆc:®4Òð/‚ŸÁ—¶0º@:" a?åºèyï g4é7yõ¾¥®àTœzãZcKÎ&2Æm:¾ AC¾ÑFåk÷¶Þzë¼ëÕùUFJ QÝB°¡h ‚¡h½K±„2B:ÏR‡1ày=\a´ü*`ÏÅûшrââF…X×wázß§xÂu‘C€ß¨v2šâ{ò“ŸœGAMs>”oô-( çß™b:ûì³sy}2òô£ý(ÿ­w¯Œº øœ¤h”cW>6Ayv5(êàW<¸†—ò!¡¬# Ãr­i”oqÈs[XžË‡ø,!ßà¬Ñè), òŠ%4 QÓ–<1Žn¸á†<J‡† •)®) e>ˆ/¸ØÏï{®Üøœ=Xçаh=Âó.N…^–ǨGâõõ ›?õG˜Âî碎ÞxãyDÚ²2£~ï~÷»åópYjó¬ã¶ÏÁè6‚êÔ» šì•û>¬îÇA(”\ñ Á•¨Üh ¿^pÞ‡âäÊ:üä§Ì«ßä'‰8¡–ð˜a&sûr ¢LdüÝGBÛ@An¼ñÆYp,yŠÔ”½Í2Qh”×Vée…b¡èêÆcჄ¾ »n¼‹ñV!ÂNn ­´CÞ†éYäƒlõLFom®^iTœÑ¤ëá2ùønjTÏž3j4Ùý»nFÁÏ& â$®oJ>†k*Ÿaò.(ÓˆÒ\ …Ú…k%"ÞëÂywRƒQ†¨|áèh”òà –ÖıUÊP§É’ÓÄ6uí±Ç¹±òS¾¾·ñU9 2@üÔ&=(>º~%'ù #¢ e:ýÚ i4º*~a·Éʰ݄´çž{.¾ÒØó)~v>8íñn3—:®-b¬*#塼úé¾&Î ïã”0ðÄ\éÇ…:¢m•®Ÿ£^x'âøè9y–Ÿ~a´!t­ÿò"-e¼ î¨C‘טÞï²æYÃ.q¥±åf¦0:8‘ÄÆdËn\qJ‡jë-uÒizúÓŸžË¨I÷)³¥1@ÊS8ÂÆq<Á5èªãšÚç®~ Cž òÚÕ>KU¿öÝwß\_,éWw'&ŒÚIsÿFù‚rãðÈgãnÄJ½_½ĵ2Á;Ï4òƒÒ( ¢ÿ÷Ï·!i„¦06p” yZ+jw¬½äjÞ—½ìe‹ñ(G\€A(ðÛÏ-§à‚2#ƒ+ãò[S§¨ 6u]õ¿}–èbÜzOZ,cRŸ-suì NOa8˜BvL js(Û´KNðCùF[:¨÷¹(Ëat?ƒÚçA=©_˜ø*,áö³¡k7-™ŒWOh#´„dÚõ…¨Öç)8‚§L‘ÒïžùŽ´ÃûÈÉ!¦÷KÅåï0Hû…J‹_é(ýŠ#*Q®I‡R•dê’2\Ä ©M‹Ã„LÄ›j LÏ<óÌ|ÃÏUW]•ùôÉO~2a‚£ž(WÜ åˆÁ›ax^B¸a€âÎvAkâ/ÓB9ƒF¿ÒÔƒ·›ÖåS[ØŒhi“²P^N&aô-1%jyÎóž÷¼\~à3t`†1@ñ% Ðè8y†w8Ò†xí97ŒÚEWÊ;¿¡¡_=’6\¦Ï·ÝvÛ¼”Éh}¿8¦°t “Ê ¬É·ß¾‘(_¼Ä;e7lYàU—ÑK ~Öuœ4âEε!êÞGn©[ýÝdü#úÚíŽN¼£±&&Z1¾óïä£sUÉy‚1¤A¶~Ê4ЦT‰!AùBa– ¥%ÞA½#áR A8NN\>ƒœÃ@¸Ap=K=Ji}ÃÞïÞŽÑã)Œ/Œê}øÃÎÆžê¡š~rd† y8: ¢LñAyâLð1”Ô°JyC¢ ¸¦Fý(ÕþKÓ ô8Sð5¯yM6ŠÉ4…¿”½Û¨lqQƒõøx»ÖZkåßÃ0TŽ%_ƒ78ƒ;ý€1*ÞÔ) =ˆ?Ñá‡.:4ê„0éJñ”£«ôkèÞ¦zéöiM퓞ô¤|à°õv £‡2³?„n0…k:›o¾ùbÝe¦<éëb€–ç]\ ç]<•a1¨N@Ô‹à(Ècä×»¸»™þ÷ÿwR_i<)Ѐ5d{ï½wž^r^¥ª¡×ø;[r“2 P¨ë ¥Š<¾#B¤D8ÚáyïÙB#\¤yذSúô&íœ}Ñ‹^” !ÇÞs ã|2 m¤I™ØQO™*4Õ„§Î×T¾m­çÁ›àc(©AJ¹+ç»Büø/Mâ•gé-ÓS‡5vίûà?˜×‚ ’ÃÆî:·Œäío{•ÖðÛe¯Óô˜Ç<&û¡ç”£rÆÅ[hklK0èVþ¼ ¡_}–üðû †¼DÎM#þÂ*õ:ÜvÛmY_ZNc9˜ve4µ),=LÏÛhc@ÅL“2qlÞÚõ\´—Mº& P¿Û>´Íøì]ú ð.âÄAð^Œ^v=ƒ™ßzGMœnã™]“ýJãIm„Jºëì¬wòýöÛo_|6™QÊÔn±ØèP7îFÛ‡€!>á-MïÁ…%}È&hSÄux—!à]Uip0BýÖïÝ)ü} L]ÅÈ 5RmÔÉúQ↦ü‡âë×kÆ\ÄIó‡ãMJ92NuèñÅ(“4ŠýÍg‘i³ÆŽj£ŒÑ·)n>xPvŽ#³¡NYþêW¿Êú“£ᬬ4Þ~§‡èËСM(õY—ƶ®‡› Cñá¬8é¹aÃî CRœÂŽY$q:bÈÜÔ,҃ǎÅ?Ê'N€ÐÎÙ´lݽÑj¨ëš(SÖ-õ0ÎAÝ0¬Ûuà«0ð9ôä°ˆ08Khðšñé¶?ë¾'+&µÚYrœŽ©zÊTïƒ2u»”Xr"`Ä‹øAÆA ‚Xur†"æÂ &W7H…*…‘ †Íd¸)áá Šñ+_ùJæ§]¢Ž|Qn¦§ñ'”»röwW.õ3…·´ ¹DÉ;0á–ˆô„²fð¼ùÍoÎõц™©)Ή úGG^Yö„ƒîG§SBÿ¯p,¸ä=ÜUö¥>knôëálðYØüw?—aóßÒzØ ’z¹Á䑸«¯¾:‡1…‰åå›í´ó®ùMËqD_G»~úºKGð3 RñáKÔ~è]¿ ÃóÑ :TÖÍj+,¡±OÆYµf.&+’Fh Ù£LõœLß[7¡÷ôŒgõ©¬k¡ÖÝk£øˆ 8ülãFp?º uh§qŠ ˆSÜÀëÒ‚ë–š‚ÿÌg>3tš&*þî×v>˜PhÖ<¹ÒÊ0>‚¹ŸšÑ†,HKiù®àý^'jÓ³&ü†hHdR2…áû°½#á +*‘¿¥ó_þå_*ÅHéZ´í~ø)L>(Oœ°‘Ì‘Z.0Н|n:>.læþzáá+>z¯ä røèY¸A  ûM¡Ö¡¹$Aãn¤É‘A¦:žNab@g(ÊX™½ð…/Ìë𬗴ÁÌ%#މùñœuýúÍ{uŠ{ŒÊ®F"®y't%ÿatJðC§røÉO›~.A{Çò-k³8∩“&1”»Ûu–ûæÈ"KJì1}¯×ñ ž@Ÿ8‡Ÿ>£Ó3,„‰ÿ=) ñE¼Âç ~†þæßR&K 8š4MT<¬FB› û7ß|snäõî÷»ße£ÔwŒÒP–ž‚r޶w„€_A¹zEa1J¤ÅL”0‚J×ÑG=âk à …J™šÂv™önég†Ã-Ê´®h£á¥Èž×›Àf„«n™pŽ‘‰)<´`¤‰Î±NÍfH ¿õyÖ¬Ñm€S¾ãÃ0hŒR-°ÚÜ,|_=.á2po½õÖ¬ï]Ë âô&ðȉ6-[–÷ƒü`ñ¦å8‚¾Ã/<ÁOº³ß¹An•3EÒ£ô-ÂŽÖí úYøÀr'O'ž.(áao„– Šë¯¿~ñq:Œ:Ç?m²É&™ ˆ‰4HåïÑ(+Å µnx^'c%9ÌF#)”º°¦”èCʶ<†‰m¶Ù&7þ6ÝáO 8‚ ƒF„„‹ÛaB“rìgÔ¶ÁmRŽQ3ýîŒÔ)<ôà´§”8JGœ¡ÃdÚÞ®Ýý÷ß?/'Á¿‡ê³èIú’¾4jŽÃÑ)g<@ðY]ÀÕà3nÇh¬ð-1ƒô±}lJw>Äm'@à$®à)¾q£áÎá–¶¼m¦H:øãpÔ‡à(Ÿ;ì°¼gà¡z¥ñ”ÚdŒãtN;í´¼~”¢zË[Þ’IJ Ѻö–¢w䨭IüÃöŽbx~²ß”0…ÑCù—'@¸]DÏÞš6Ó§zûŒ¾aG샸Z*GŽÂ–0»(gi0ÂtÌ1Çä†~ /hˆA‡:ËmL³Ìp‰.lÒsÑY/G’Ú€³t"ÝØ4}Êð¥[qš_Ü5ã¥C÷ßÿýßy4L=êªÇ§ðÐ¾Ä fkb™õ¤a€F;Œ]t‰‹Þ´Ö9 ¡sq¼g€ãÓœJñP¾ÒxÊíû9眓{KvMÚPatÇúè§L” ¥ÜœŠ"ŒÑÒˆŠ¡lÁ4ÙoJ˜ÂØoâ©¿ñ‘'@Œx| åˆÂöÙ/\£ ê‹õ¬6Ë6 S˜ü ³,ΰô©s¢¡×1‰ó7K=‡o]×ã:½J_2@…ӆЯÂv£™SD¼ãjH£a¡c§ððƒOëÖLÂàs„§¸PD»ülë¬Ð‘F/q°ËR¥&ŸÍnê´©:òúЇòê‡"º‘<Œa=†µxŽ'q³©¥w½ë]ùÓZ(Gìèµ[ „ÑãPˆ…œýzGž#Åh­,JÓÑ Â7ËvÈ·ôL SÀ›u×]7+Ñ¿øÅ™/˜³GMÓ»šÑ”iÉÉ.ˆÎUÀw†).ã¢xp»®5vέ³qeÊ}¦¥»,Ïp=}ÉÝl³Í²n¥7ñÉÚ=üÒК ݈ƒ]¦÷ùgãµðÕõòAïNá¡ 7†Ù¬lÙQrËœ ò8$Ÿ^õ wð”ó. 0u¶ðj´(°„«~˜}µî߃zñPÅÔHè(AlÈÑ'°>Ó”}LE¯ ¡|RÆ£!'‚S¶6P­³Î:ÙxÅ+^‘oòˆ›$¦0p\®h`)Ë8NÇÔnº.”‚4Å 8^eòŒ’¤,*ù;F øÃsÆ…Û LÃ·Í La xä<\:Ôš7zúͱy«¬²JÖ•åèS]wÒ«Œ.›–ð4f‘¬÷·þÓ,’Ù,Ϧx:…:pæøCæ ê»óW¾ò•KlZæp‡èÉÑr —…c žŽ6 oùŠtàþh Û‰Ž)#t @‰]yå•ymI(S;ì8{J²M™B([½1SŽ˜r·±.CõS˜B?¨â:0”©“Γ‘Jšl&iRšÞaÌ24õìq·~t užéo~󛬔ÝCnÕ¦ÐÎ5rom»Qv#@Nýˆup8Šƒô¨ïÑ`Ó¯FLûO£3eÉAævñ;jj SèÒÁ×a²~ôQzTžÂw$™NßñGÓÆÓ¡ô­G„Íž=»ú·û·‡¬áYbÊcPŽvª3c1¾©ó8š¦®L!È7%PÌ–0|á§0…®PÝÝʤgÏ(¥äÜÊd„4.mœÃ½.£L€:^8ïZ¹×½îuyzk SèúÍ 0Fp4ŽÓ1yàæ3<÷¸Çe¿~ÇSz´ßò&à7:SŒG› Û¬À¦0èxÛ´l)ž™¦5×\3/7ѩѦ7éÍ.í³Î‘QzŸt±A¬£Ž:ª“}ðPÀ”:Np,Éé§ŸžÏ3*d=”8’¹]Y¹&ÂQœzð>mŽrkɧ?ýé‡ 9§0¾ LMÓkìqÕúbÆ(…¨Á·Ó~Ð(P!NjÐñ²¨ßè£âiO{Úˆ)Laxà• t˜8£Dô铞ô¤|©ÆÞ¨»ÆÞg“1³Hq¥1žâu?Ãu Sè7/º$ÆÈ.±ÞÙ:x›–cH[Ÿmm<Œ×à0zœwâ ÿL¡ãÊÏÔ¤û•‰Ø÷8NÇ"ckKìÄ‹3íêÊ´$§ÑO¿9*ÊïS˜ÂXÃh‘Ýôzô¦F­I2jd—¨uNmÀm'5˜š2:àžñ)La¬gt']ø„'ê4™ºík_›×ºO»Þ ºøâ‹óú%'5¸Ôa S/àÚÿüÏÿä†Þ†&ýYg•;L63éiÜ9 >Н–†XojtÊÂxCÏÅO:Ô¨A§Í7ß|ñ¼4ˉ¦õÙf‘ì÷x¸aÊ}a ˆ!|üò—¿œÏU´ñÈt=babP´”è¦0Þ°ÉáÝ”$ÕPžašÞÚ<¬[b Ú)úÙÏ~6otšÂÆ8Y’61™¾ÄQ»ÝéO£OFJM»;>ÏNfGïèðOa OíÔa²iY{nݨ5ÎüãóÌ‘c ,·ûüç?Ÿuëñ“4e„N–·‘è(ã”ÑÉp\ƒx¾Oõâ§ð`2µîIco$Ê.f«$ÎØ›âæLhÆ¡s衇æs­o¶v”Þ´QÎh½#æ0… ”,yro½vÝ1‹Ö*ã§e#ž=g;§v¸LXbý¨¡{=&÷Ö[ðŒ˜sžjä§ð`/ô`cÅéÆ;Œ§ Ð)Là ÑO#gÔÚ]l„é’K.É¥ÿú¯ÿñ9…)<8°ÉÓ±ö‹|ñ‹_Ìí½Q{üÔÁ¸.·› `°«8¦0…) ‡):…‰Œ)~.‰)#t S˜Â¦0…)La gTÕÿí.ã‚ÀYpIEND®B`‚pyclustering-0.10.1.2/docs/img/fsync_sync_examples.png000077500000000000000000000640671375753423500230050ustar00rootroot00000000000000‰PNG  IHDRu泚ssBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+g¼IDATx^í Ü ÕÿÇ¿ÏóX£²µP‰¬%ZD¤lY²$" ¡¬-–6EŠ"Ñj)"еBÙ%¤TZüíkdKZdŸÿ|æœá>÷™{ïÜ{gæÎò}¿^ÓœsîÕsg;ó=ß5MQ¡€³k×.ºì²Ëda¯°sçNºôÒKe‰Ïq ã}ÌÌw,Ô©>|˜òåËG[·n¥ ÈQrâÄ úâ‹/¨^½z”={v9êO‚t¬ HÇûÇPñâÅéÏ?ÿ¤óÏ?_Ž2‘ÒøÙ÷7A;Þ¸æ;unD•HõÇ+K–,‘#‘™4i’rÕUW)¹råRÊ–-«Œ?^~buƒ`«8p@Žø—ãÇ+³fÍÒö~'HÇ ‚t¼xVñÌâÙ Íš5S.¿ürÙ3Gæ8ÀϾ¿ ÚñÆ3ߥ«_tP1BÇê2Ó§O§6mÚhßW/2Õ¬Y“:tè@}ô‘üÃ0Œ?øàƒhæÌ™²Ç0 “W u§OŸ¦ñãÇÓu×]G{÷î•£Ñyúé§é®»î¢áÇSýúõiäȑԲeKzöÙgå7†a¼ÏîÝ»©GìCÈ0LD\%Ô­]»–~øaj×®Mœ8QŽFfÛ¶m´aÃjÖ¬™´hÑ‚6mÚD7n”# Ã0ÞæÁÔ,·Þz«a†ÉŒ«„º¢E‹jÂØ°aÃèœsΑ£‘Y·n¶/]º´¶×)Y²¤¶_¿~½¶g†ñ2cÆŒ¡ï¾ûŽÞzë-9Â0 “×F¿.]º”jÕªEK–,Ñü䌀ßÜ=÷Ü£iätA@0,Uª}øá‡Ôºuk9z–cÇŽi›Î_ý¥…ûïÙ³‡ ,(Gý ¢†,X@uëÖõ}ÔPŽéxûì3jܸ1­Y³F ®ÐA¿bÅŠ4wî\jР= kêìYáäÈ‘¦þWtê­¥m×\s’V§H®óÛj®L¢­[³©-…ÒÒN©/|œë4ºúê“ê=¬ÕkP4u0·B8ûé§ŸTá]Hï<ð-[¶L[¼¦§§k[8¬©³æYøå¢Þ½3è½÷N©ÂH™N;žVßMîzmzåÙ_¹2L×Î'nÏÅ‹ÓhÅŠt1â”:§É/™ Hsˆk¾ƒPçFŸ?/Zžº7jß™:uªL™2Eߺu«‰Žz¢´ïsžºÄIOÇâ@QjÖ”*iê’ck×ʇñS.£‘#ŹTW´™ÐÏñ+wSPòÔÕ¨QC;ÎH[¿~ýä7£¤9Xñ,lß®(ªð¦ìÝ+TþúKŒýóp ^xöW¬P” Ä9 åÕW套dÇ$^8^+ñ|ž:³ÀäŠ,Ëü± w̯Ŋ“#æ8 7° áÜAYºd‰TÑÏg… bÏ$NçÎb¯.P3¡Ÿã¶mÅžñ£G¦Õ«WgÚ`ÀªíŽ;Êo2VÓ«Ñ»ï]x¡P9÷\¢'Ÿ$âŒYñyªo_ñ®À9 å±Çˆvì š?_0Iá)¡&„•+WÒþýûåÑsÏ=GS§N¥.]º¨7Å|õå×Yë¿ð òæ™>=ý/s†{î{˜ÃÑ/UÞ¼bÏÄn–ˆä(¡Ÿã‹.{Æ?”)S†n¸á†Ļ9räÐÚEŠ‘ßd¬r•(!B¨Wï"R…j9ÀÄdÖ,¢úõ‰Œ,‡˜ß^~™è7䓞êà+WµjUÍ—NNãFÒìëM›6Õ|M&L˜@­Zµ’ß0ÏèÑžV\¦„ľ[7±Gwâÿ÷_±gãŠ+dÜc¸•:;†1aÿü#;L&FŽ$êÒEv xæRß;²ÃD‹QœOÝÚ`„½«¯&úúk9À$Œk¥G(êÝ$¡A ¥S§NZìÑ£Gé×_¥{ï½W~›6¥e1o1ѹà±óM±7B×$ã11È@,„ÊæÍb‰ãÇÅ^D3~Uw¢E¾šeØ0"9ÞÇÿýðÑ7ÊŠ'úýwñ]&:Ÿ|B„|Ù±¬5=z½þºì0 ê© n=ZvÓ„¢këú÷{Æ<ðEÉ[vb-ÛIüWt&üA4{¶ì0g€ß\JbEcÞ~»X˜È@K7bQ×®r ¨~‡l;\*9X¨ ¡X1…8a»yôHr#_ºp|P6ÓäË'öGŽˆ},ôïuê$ö  h‘&gíZ9ÀhL™BdÆ{ç®»ˆ¦N•Ƥ„Á= M .;LB°PB÷î§i×.¢Ã‡å•“P ™Qd@7'2±Iì>ThÜ8>ÉLtþü“èüó‰î¿ŸhìX9ÈhE‹šÓŽ#Ý´yº_1“•iÓˆZ¶” S®»A% u!Ô«§Pž'}ûŠ>#¸ürÙH‚½{eƒÉ‚Õçæ•Wdƒa$’ê@:D ÈNÀ€u¢Ný€ýêβzµÐü& eÎW?,Ô…pêQÏžgW\O¢PÇ~+Ì…pÝ zyÉÅ‹­ñ§Ó¹à‘(;è~uŸ~jÞ7€…ººuËЪ%L›F4f QÁ‚D÷Ü#Tó=&¿p’ñ;1‚+LtáÖê:8€3Œ‚Á¢ uˆnß¶MvÂáÃñÕ{DÞ¼"`Pk…);DjÍ% œåËY¨Kˆgž9E³g‹D’íÚuê$L±7ß,BÞëUáxÉ0ÂÌ`º©¼|y±g‚ χ'‹6hwQ 6À¿P/ËgxÞ‚Zɹé°`È–MXDìW·u+ u ça8x¶mKšp7w®ð@¹0ø¡¹ LÒ®U 6 #°Û¼ÀéK¨Aª‹HM+}ÀàWÔòV˜cÚÅj‚žØÁ'([jêB˜1#MË*ŽüiíÛ‹œuˆ€EÈ;B«}T~1€´l)‚´1ÌYà“cñLŒ¿1#ÔɯBA:¨YÔ` +S™„eKƒ½]¡‚ùU? u!lئiçPb Ú¹·Þ"jÖL¨ÔÿøCÜ´AŪ"óFe·"v9Y#÷㺯áÉáßjíŠûã%D¬CKTPKvâ¼Þp u ñä“§Ïh5 €æN˜\‘? ‰a!ØlÜ(>"p¶ƒ ;óÛ-Ôê~u\Áƒùï¿4í $GýN;rn.ðéµÒ ç– òûï‘ó& 4 A,†Pwýõ,ÔY&7hìàü ?J‡• G Ù…SB-Wð`̘_R;ýú«ìøTn¹ôRÙ±$ûFF@`é“PK©g‚ "ÄÍB] È "´ÇŽ-\(?º0 k|¬¤MÙ8ÑÒL0ŒU˜ê<à÷ˆäEõ « b°üqÜvÔÄÎÐ~Æͯ¶Å­7&ê×è ÅJ/^ø¤@¸ (™f| ‰®íÕQƬPs—ß}Ã~ü‘èškdÇB‚(€ØéO ©B>Á óot6 u!À¤cG‘|xÊ¢Y³HKFŒ±>}DÑgøa¼ô’üÁ‰\rµjÉFÀøðC±·2UŒï¾+L 1+Ô-J´}»ìø»4u¼Z !ø»a!`'(´€‰Ë,Ô…ðÊ+éZ…ƒ7ß$Ê—O˜^!%MÔ«—(¡î½÷ä?f^ÉÔä’÷Þ+ÁÅýƒÍ‘#±%’gdˆ„²~~`VT’'hÁx'š‰ªN¤K šô§ŸâOÏB]{ö¤QëÖ²#Ù¹S8€¢Ð?4y0ÁîÚ%? A+äv'‡‹û›x^¾W^I´nìø $tE œ]äÎ-´¢AÀ®€“pà”¤Ø ÑèlêB4HØq2 ¦×^‰ˆá°Xº´XÙáóyó´¯úäívIèØ•t×+Ø‘…ÝÆð.§OŸ¦Q£FQ… (oÞ¼tÅWÐc=FÅYÏ $³BŸÓHüò‹ˆðµ‹«®ò¯@ަW€€Aªê´c‡¨Å/®›æ¿øâ U"¯Dçœs/^œ†ª Q‘Õ›6m¢´´´,ÛÕ ¼)õìaÃÎ nï¼#¢?qãbþÔOò‹/нßiÒD6l$¨ù‡t bw”¾c¼É!C¨[·nÔ¨Q#š5kõêÕ‹&L˜@Í›7:?†cÖ§ 0»_ŸMøÓÙ$¡“™SÏuª ËnàÓ k·»§A R" W u+W®¤ÆSÙ²eiƌԦMêÓ§ ù¤úâŠÿÍ3+\&²;ïfX䬃_Ý=÷ˆèÝ÷ÁA m[Ù°‘ .€v»ÛŽS+jÆ^V­ZE/¿ü2Ý~ûí†þÃX$CúS§N«Í m~4³U¨pRóN~æö oß~B}Oœ6üÌÊ-_¾Ó´w¯ñgvl‘Ž×Îí»ïNRùò§ ?³c»òÊê;_\»T¯SÛ￟ üù3ߣfISâñ²µøÓU­Z•,X ùŒèœT—;ÙUikàÀª€âè¦ràÀU¸€.ºè"Í‘øòË/×|ëà ߇zf×00áaÓÁ„wÙe—©7èïê Z@.Qü<ƒÆŽ=•%T{Рt-„{̘tmÅwü¸·–c¸9pŽëÖ­«×hT¯Žë’Í‘cT/%)bíߊçXSAŽÎ/üé*TpæšÚÉÁƒ©páÂtøða:ï¼óäh0X¾|¹æ{ŒãÿòË/© ²²†Ñ¿zþùçeï,+®§gŸ5–¹sg^Z¸ðrºï¾_äˆ÷ùᇠÔã:Wãí-ºð@†ún>¥•ÒtŠV­2hôè£ê;Ù½ öd6,]”ªUKÜ£ñ,b]#ÔýòË/šQ¯¡~uüñ‡¶E¤WçÎåht`’EÀÅäÉ“éî»ï–£g‰4áíÙ³G R×®bC°Ä„ i4{vºzóœ¦ÿû¿4Z»6î¿ÿ´*fhydzõ:Eƒ¹âš"ž‡?G8(ªðêLD4W'-ËÆîfM]ŽˆÄIWÏ­u/K³Ç‹óœ3çIúûo9àA‚¨©Cz'd¨Y³&Íœ9“ÎÙ s¾_¯Þ!úüó|rÔÔµÜOôà1/€gaîܹ԰aÃ,ÏÂÓºè·?a.ÞÈš0r¤°‘hÇk'¸7>ûLvú˜:uNÒŸ9~¼N—'l( ú˜ï *dj¾sO]‰%Ôz†–w.½o¤qÛ¸q£*±¦?õðT‰) Ó¬9sæÔNLèpsô훆 IW_|ÙU!.»*dfS_éš²^½ õ;éêJ/åˇ.M}`³iÿÎK›~¬±6Ü… á˜?·zÃù\‹C™±wÞyGΤtPyÂyIˆ‘µzéR$D>ÈOwà b‚›:•[=ÏQÿþbï'쬋 UF×@$¬ŸQo锟"Æ;Üÿýšõ"Ò†À ³$¢ ÷“¦–'µKðòk Xuv–Z‹„¾0ñkòuÉTèp!AkÕ È]-œ„Ã'1˜Y_}õUÚºu+=zT ¸xðÁå§ñqß}â.:TÛÑË/‹r`ÐÚµlI4v,©Â£¸™CÍ®¯¿.>æåTòD~&,ˆ;e$R,šñ6‰ä)„fë O²rüú«´œJ¿–åS_Ï)›«¯¸B¡½{ãÈ¢í!’-»ÆÞ5!Ô¬‰E$†( Z£iݺÈ#¾³aƒðµ8ð¬ÙÕï~uNãå¨L3¸e…‰è<&XœsNb^~©­ uÖ ¨·’S%$éPA¡­[ýõŽØÐdJØEêà×öøãkiA  ƒ©s;l“>jÝaÈË‚#à´ˆ°th®Š'ºõVQ¥Gá_çgêÕ“ qÂÙ -(ÄoxunL´¢*Ÿ`AëuÔK¥ÍãNô©ø›~cß¾ÔV‚&kûv uÉ–°3êØ³žúFoÔ¨½÷Þ{Zté¡C‡häÈ‘ZD)Lœ~¢ï¿¦øÏA§ÎÛZráÛnƒiXL`Õ sì‚ðëÿvÒ$±÷Ÿ.:¤:(µŒ™øñúܘ¨P‡—¨‚%LÙIíþ–}¿’uæO$FU¿@žd…eC¡Ѧß}÷Vr ¥¸àÇ&L˜@—\r‰•êGfÎLÓŠõÃ%ïÍ7…À†öèÑbe‚HX÷‡¢~àp«k– Ùó ÊF À¹õ3zˆ’*>q¦HˆïðúܘŒPçõ`‰Ã‡E€›ÓäÉCôÏ?²ã’uæO–¼yQð¹>ýE²þtÀP¨Cž7”åªU«–*´œµ‡!ƒ;ÒŽ 4—ùôÓt-ÍD“&Ho"²ŽÿñÑSO‰  u.×^†°ycrD€´vßó 8þTc–Ф"Z,È\ΘÇësc¢B¢8áÛæ¤?N™2þ0]‡á#•š:#Ç)U°“Ÿ`…ÔP¨C…†ÐZª¡äÏŸ_]uølÙ!Ÿ̬0«BeޤÃ=DÔ¾½ò&zï=¢®]EZŠæÍ…ÿß°ªLW2¬^->c÷nÙp ðeÌãõ¹1Ñ@ ¸ „TVô$ˆ|M$ Þ­[Ý~;Qƒ"%вeæÍª~Lk‚y •FâŠíÙ³‰î¹GœO”Ã{¾ì¿ý&¿d’K.ù‡Ö¯—Ÿ`›¦5X‘#ΈO>ùDûÜ ºëÞ{…ðŸ9”AÁÂN¸¡¥{á˜Z„)þw¡‰‡5Ë0ŒñúܘL¦z˜.S™ê(Yâ|ݼ™è®»„; Üq0ÿÏ›'ü¬á k3©^ü Á JêxƒÚ-Áw¸#Fˆó‰°ï¿/„íŽE½Sø=š¡hÑ¿è—_âü.'Qa9C¡f„‰'jÉ|ÇŒ£™–©K“îÝ»k…õõdÀ~iL°úBªøÈÁ=¦jU”*Bú0¹¢Ò€–7¡îx‹Uœ_H¥™~~&Õþt:‰šâ‚Œ×çFøw% ’{9Fn3%KÊN `ƒÿ4Ün°ÈµÈ`‘¢òØ ô!oi4ð}?i”äoŽË·ÞÊ3DžÎüùå*ðƒ… BîO¸ÿ @,.¿üo_ u=–Ã1êî¸ãúàƒ´$À;wÖœ‘‘^£F¢-ZÈoú‹;ïšÏ¤Æò ñø}A«Í&4šãÇŸ-­ix@XÃ`)‹UYH˜_ý#ÔAXŽàÙ†Bhݺ5íØ±ƒÖ­[§9ÿþ¬^ÉÝ»w«']=ë>¥n]…æÌ!êÝ[¬*.¹„èë¯Ez˜aõJáàßø…mÛd#…èµý–´+{7³ð{Y6«ñòÜT¡®5fR™üþ»XÄ#E•™ÔÐàAXQå{-i$ð·ý¼@¨3ë÷ ‚ ÊmšÕ@A‘;(L¢ fÏ~ÚWu×­ð§…:2eÊÐM7ÝDW]u•VkÕϬZ•¦­,`÷GŽ:DV¯.Ì®¸Ñ.½T~1 ¬Zü’L6š#Q±¢lø· u:>u‘µ/ιs'(`Áðª5ÂLÒa˜¿ œÁ."ED~Íûï솿톳@¨3S5Ò‘w ‰úãÂÍ!"P1Z@ ´ ~©@4gf¢âê]w…úÔšÝüÈèÑéZ4nD8¯Y#Ì­p”}õUù¥èEÒßyGì½J´Õ¦ÓøÉd°`p#(ÇDÆOs£‘Oœþaˆå÷…ôMfØÝŽ ©E¢¿/øK'òbE &ø…áÿa´â~‰€Å;"Ô'θv@Û‰Zé‰E üÔ¡`‰ÄUW)ZT³€ÜŒ°‹3B]5Îl·Ür ýöÛoZx~õêÕ©U«VT§NUb>­¾öª‚N˜c™Oذ!ºt!êßu`Ed+Vð«@âáhÀ™@uÏ0‘àò`ÞÃOsc¨ù>fð†ïØwŠ…+\£-ìòås×ÂÏ,ðy‹&Ôá…ºtiró7´JH‚\§áø%W36RbÁÏé¿ô<®‰øš}ñ…£\9ÅÓ~ž¡ 96ž¯d9#Ô?žÆ§mH¤YY]zlÛ¶MG²ÍwÞy‡6nܨMd~ÍS—7¯¢=|ð‘ƒÀ}÷}ôÑsÏÉ/DAOà$3³“àÜûD¹‰J•dƒ‰ˆŸæÆÐyJ•G5aäàD”?¬ ˆLDZ§H9éz‹šhê…j4èH0³k2‘‡ø·ð»îÙ3«VÞ/BÌï±"ˆñ¾|ì1¢ä@àœâº@ibdf…P³¥×Ü*ÃÿÍ»êSþ„º„;'Ì«6{öìÔ£G-«ºiÞ\ÑL®ˆÂû˜ü µ3C,•´W@þ½TƒUžq[ÍÕo¾‘ Æ^Ÿ!ÔAà@õvíDJŽP äÁ•$’/„:/jFØoF .7‘>˜Y‘ oæL9 Aî1·%O„X œXˆà+ç9ܳÏ<#*<…+RÕx-[„Ïj$âIÌQ6ü#BØÉöíÛ)Ò‹ûÖ­OkQ:ð€m«®úõÍKкτWýNô(H=úÔ è¾Š^þ!n†+K˜ÇËscŸ>éšÿ„$Ï5~ÅUªûc^ôª“‘Iä…vÍ* õ{ûíÌVüm·úÔÆúHBŽA…±üϾŽÿþK´r¥À-Â+à™ŠæOׯŸ‰Ðm‰¡¸Ò¤Im5ºäcš©.?žQEæ»kìC.¼PÜ4X„c‹UG¯^òCèSˆ†ò"X¥»Ñ£eÃã¸Aû ”Âcbãõ¹ñþûOS… Â< D._ž5Úš¯EÀ"è-R~4˜ö •L&ÕK8ëQVlÜ89 A’]¯GjFÓÔAíÐÁ¿0#`‚…¶.<5 *ÀÍËD;¯¨ÄQ¤ˆù¡P7|øp*Z´(Õ¯_ŸrçÎM—\r‰¶EbMø“ Ö£|Æüùišš%À¯a¬ˆ)#öí“ ‡T&˜xU»ì4^Ÿñâ€Ù5–ï>G®0$Ž Õ0A3âµ{¾lFþtöà€o‡ŽE,ñ¡u´ñ¼^Jçìüóe'dŒ˜?Ÿ¨M9`È ?бcå€÷´×#‹#i@!À"]NïÞæÕ‘†B]>UÔ^¹r¥VËðÑGÕJâôêÕK[Λ7Ï·æ×·ßN×Ì­7ÞHZe‰DnPŽn´”m󡥆܄ÏÓOZJæFøøÜr‹HÄ ^ê^Š€”Κ%D»ÆpQŸ(3†§:ê¼,Í™nKÈa÷\‚:d¤ÕxBòzl¤41#G 9$Z%Žp"^Ô4lÔ¨‘Ý5zôh8p ÕÖ‹žú”ÝY `bÀC/¨_çeÜôNBÍ]?áÖ f¢»™³inTåVš81óK¾?^z‰¥3Aò’%¢¦·] = ´Wx§¯ u‘œùq/ §(ü0íÂ2´Ç¯¾zVtPó¥W°l´°€VòD¼®1†BÝ€bn~¤hQE‹¤ÁÊZ3eb¦ ñ¢q“ å¶HÑDqcJ(Xe3æ0š Ã7?¡¿DCK$z-X‚TxžÑQ£D–Z:h­à¯7fŒè{]¨‹ä÷…R`NÎ! ýøc<(4^€E¥£j'p€ïkÜÚOÅu%q;ÿüó•+¯¼R~Ó>|^#J•_T”›oV”Áƒå‡ €³š‘!;.ãøñãʬY³´}8ÆwCjÁoªTIvâ$Ú±:IÁ‚ΜÛdŽ¿ïÁeÇ8p@ýͤ=»Nb4'ê››çF}ŽÃy‹—Ó§¥qcEÙ³Gô7lP”Gm·ú,4j$%ÿþ«(·Þª(§NÉ9yRQjׯï}œG;HæÙ7Ë AŠòÕW²#ùö[EéÜYvdÅŠJƒ[ÎoÆÚΓ̙£(£FÉŽdÿ~qLxö@<ó¡ ˆìèáÛßÿMsçÎ¥üùóÓ›ò!‡¥Q“&BÍœl4 ×œ‰Ýœ:dõjÙð(ʆËÑ5 Ld‚87B›½®„„Vs¤Àr%ø"JÓ _R– “’Øëý&/Mrð…‚^È!ç4+*tøpŽ3Õ;àsæÕÈb# (â­Pí%M²éÛ:Ož\D›'ƒ¡Pßð­_¿~ôꫯÒúõë©i£SÈøñé¶d÷ HêèV®¹F6àZë~_?ü Ò}¥Ê—.Ao½•¹Ö®WÀyÕ…åC‡Ä¹­QCôF‹ cûöíʱcÇd/3ÿý÷Ÿ²|ùrÙóz¸áÂ*»vÉÁ$9çx©ÉŽ‹0 }GXº«~["¿Ï‰0ÿX$úÛ!Ùãuò·&KªRšxunL&¥I8k×*Ê(JÓ¦rÀ…èÏBÆ"oÉï¿+JóæZ3¥4i¢(õêÉŽ…Ø=×µo¯(ûö‰ö=÷(Ê–-¢*Â÷öÛŹEº/1t¨¢,^,ÚÏ?¯(óæ‰v8I§4)^¼8ýøã²—™o¾ù†êب~€ £R¥JtÎ9çh¿cèСxÍÈO™àì òw;pâe&6^›í |y ëö¡ÎýðgëØQ´SɃýö›ðMôpv&NU…ú×¹hA¡éòZ¬ž&UGણ/H†3BêÞÿýÚ†‰™Ñõ~èöÈ#Ðù6…$¢¦"j)–-[–f̘¡™2úôéµHöôéÓµïÕ«WTÉjÖ¬I:t B™¤Y3óEscÑ¥Kæ½›qûäêèìE¼â¯O}Á áÕ¹ÑN`ò‚?PhÁz·qàÀ9Z• ˜å–.u‡+D£Fb¾õ’SèºÁ-¾táàÚ"Û„ÛÒÂÙ»WøZŽKôÀU8Q')1cÆ(ÅŠÓ¶ôôt¥páÂgúúV¢D ¥bÅŠÊäɓ忲U0S*W®,{uâRÎ=÷\åÈ‘#r$3¥K—VZ¶l){ôK–,){±ÑMk×&ošE<²ãŒÔônüá$òûŒŽÕiœ<¯Éïºuî¿tœ4¿zun ÅJ󫦨eËdÇeàè×o¹2|øIeêTEyóMù h×NQºu“‹°s®Û¹SQ:uR”Ý»ÝaÂFÇ;dˆ¢Ô©#;Õ"P퇀ª#'NÈ HÈüú€*&nݺUÛo Òõ¾¾mÚ´‰¾ýö[ºÛ†h‚cÇŽ©«©¥Ô¬Y39"hÑ¢…–±ý+ƒ0Âm۶ц  ÿ ~ëFijÇAh’Ê ‘êÐt3xMµŽœ‡^¢lY±÷j¤±]xqnt‚;ï$zã Ùq!»wç%UðÔò†¶k']42ÈY‡%”ÐM„¯½Fôè£rÐ… m <#¼bÚþýw‘iFEdž@Ro+0ô©Ã$u-b…dË–-êÅ8N¥Ãlm%K–Ôöˆ, GOôÏ¿q;‹E[ÔÖ^‹ÌìÖM6<†Û%§¯ÌNв¥˜7àäF Ô:¥hUà/ípûäÉCôùçrÀåà5«®eè§Ÿ _º¸À”9y²p9–±Fµ‘dË’†’uµkצ#Fh>hG#M•V-Z${ÖŸ‘ªU«Ò‚ 29ŸüðCjm+_l:ýõ]vÙe´gÏ*šÚ9I격ÃI*SF¦˜'Nhç¸nݺÚy9rdS_'µ¶[É‘#Cý¯¢þNó~FÇê$â7cåèLM%+Ž7‘óœ <¨®r ÓáÇÕ¶½ol/ÎNÌqHmR¿~†*Ü)Ô½»»î< µj¦rå Ñ#d.Ãä6Ì œ9‰fδfn°s®ëÒ%]ËíW¥ŠB·ßîõb¤ãmÖ,C[dÌŸʑھÉ0bDºVM?ÿ‰'¢??ñÌwg„ºZµjÑÈ‘#µ‰ Á˜œ¢±dÉÙ²†¯¿þšªU«qâz饗èɰš$“&MÒ†# uˆŠ52‡ôïߟžþyÙ; þˆ,³ Ü\mÚ4¡ë¯ßMÏ=÷­uO=UQ]‰]B³fÍ‘#î¤iÓFêÓÕßù‰ðM›6Qÿ{RýÍsÅ€hÚQi®?ÏGT‰ 6'„:/ÎNÍq/¼p£ºÈ ~ýVP¶lî²'öï_E=?§é™g¾‘#îaàÀÊtá…GÔ{k—úîrw=ɪ¨BTºz?}ízAiüø«èÔ©4*_þU®¼WŽº“Q£*Ðo¿åQºo)oÞèIöâ™ïÎu©æ—_~¡«¯¾Z‹ì õùCe±²ÄJ¹sçÎrTðÙgŸiakÖ¬¡ëBlFèW¬XQó}iР=‹Sš:-XF†BÿýçŽ Øá+œ9ð‚Êp½¦ W¬ˆO£hçêÕ ¸ö={žü™öïO­?æ?ÿ_µ|ù„Ðäf.»LÔÏÅïDðòÈ‘ò³z‰¢ÊA†H·étEÏ„W^m7€çB&ÒAø´C¡îñÇ×Êá`5¸páB-·jnÞ¼™òçϯ¸f¼V1^Â+™Âu¼&4ë s²®ø=‰`öwÛ‘Ó ©:¯V¯›ï &N»ç¸‡IUCéÓGQ–-“A’ÙöíEûôi‘Ô7UÏ~¼¼öš¢|ñ…ìHPC·NEù÷_9`+Ž·Y³³×U«V¢íFbïâÅŠòÊ+²Â]w)ʶm²ã?®(K—ÊŽJ£F²–$(-ƒ¼KFºªÝ=¸îÅR¸˜€üÄóÏË“ ž3ƒØ_~‘ ²» RË;8ðlð¬!²‚¤'€F)ü¼ÁŤKgk—"hsrç»ùíÆHSúö%0@vA;˜jÔ}ä§³Û5ÇP¨ûñǵDšÈ»„‚ùFUªˆý¾}bŸzÒ(wnÙô n-ì?áäˆhK<7S¶¬Bp…ô"K–È€Ó9„ ü}Ó–‚$t" M›!Ç 0äL<8sV/IÔÑE~ºp*T{˜šqS¡s(ž,€ìÄP¨CÙ-}E]f½÷Þ{†S§Š½“«¯X¸¥ø6ã^Üi¼qcjÒÜóÜh ´L£‹‹RWVáþz‹S}áìe¢ ËîG¸gP«Ø* AFõ D}‡'ÊwJX6êî»ï>ÍNÁÏ©W>|ÃJ•‰=6õ¦4UÀô¾ ÉmÙ#üª¸YºT6\&âT-JxnŒL¤` €ªX¡AYdçÞÇ| 'Îõ±„( ÄÂdh•&×®]Eáþp~þYhA½´œ±j‘çða9$(ñ!ýê«å@v—;ƒÌW—‰Ü¹s+S¦L‘=ÿãDòaðÛoãåÙgå@ @²FujPzôpwRÎXˆ5‘ìDÀŠ„œñ`æ7ىǛêc2¿'==5ɇ½:7:1Ç­^­(ýúÉNxÚ4ÙI€o¾Q”»ï–0æÎU”·Þm§Ÿýd@Âd3 iß{OQúö•0â9^œÿG•zõR”_•—böxq^q~£ñå—ŠÒ¦MìïÅbÍEiÚT$6bÜ8E™:Uvâ$éäÃEŠ¡sü`TwzT$4SM*‹[ݹ~%•¦A;0ZÉ»#³‘ðÜ8€ÇÊÓˆtÈ€€†xAbá'ž 1B„áU³a´ØPî»OÔìž9}ûöU/nO“TFÀ"|ÝDóAI%v84§’X/éT\*à¹12ç'„Žh Ê‹ZTLˆÇ]fLJ"zõÕÈ ˜~½ê áã·ßd' XŒ#çé7ßÈ8@Êœw˜ã]CAÍ×hŸ{ ˜‘aNŽEçÎB0ûðC9H s÷ÝD/¿=HÎ)aÙP¨›1cmݺU}@ʪ?²V´:|c¼‰QDŽ—Iä!´¼püˆ>I…W H•+ËFŠà¹16±4N` qkÝÚ\J øPvï.J^w4B‘WsDBƒƒ¼{±@θqDýû-\(M°y3R(BK‡Å-‘½«WËFŠà¹1:—\bNãT§ŽvhÞ\˜U#m„?˜Çbig!Lº'Ã@|@ø0£QùòMŸ.4x±„èeËD-*GĪb甉Ð)â9¯ˆœÆ9‚‰‹‹¸!`Ç*[訰,}ë Ù»w¯²cÇeûöíÚ¦®P•ŸþY9r¤ü†?p*PÀqgýÐ!9à0’PE;O8ÇBLg²c@<ÎÃÉë·8]Çë†cÓÑK<ŽÃv൹ѩ9nØ0EY¸PvLðÊR³¦¢¼óŽ¢=*UNžT”éÓ¥V-sÿ?̧pv×qòÙ·‚ýû¥];Ù1 ò P”ÆeÉ’YŽW½=•öí¥Góï›Q£eÎÙq1ñ\_3A(ጯ(uꈠ’ðÀ‡}ûDÀ vvï–ƒ1øê+E8Pv é@‰µkתîÕT¸pa*V¬Ø™BÕȦ^¡Bêæ7op™4I좞*ªUÛ&[ÞÆm)ÁØÞP(>UðÜhiMŒ¸æ‘¿f)˜W‘…[½zDÛ·ÍšEtë­òËQÀßÄßö*psˆ¦±4VdÐÜìÙiôâ‹7R³fšf³aCaD¼k Ý3´Z~ÒÔhà`úŒX€fÎirp.7ã D…¤'CÀJ4Sv(Nj@ …º^½zÑ¡C‡hèСT³fMª_¿>½õÖ[êÁ©G§²Ôm‰«<œ‰•ÙÕã¥wï(I‘<„. »·—/K”Þ½eÃ%¤2H†çÆèÄ+Ô”£êÐè‹/D¥lH ó¬>_ÆÂ s!¤Å2ùqá…ˆf=M}û®¢?>¥EÏ+L³Ñ|غ՛¹þ¢à„D7£B ¸ùóE…ˆ‘#‰>ûŒhâD¢Fä—L⤰l(Ô­ZµŠ^xáõ¡zŒZµjEÿþû/uîÜY=°OÔ•@3­ 5“û÷ˆƒ¤R;hwÝ%)FO&íõ—J$¢¥?p’¯¾ûhfvÃsctŠ#Ú–C€„º%D@C2@+eV+ŽîÜj¿o«1 øjÂ'.ÑsaφþÄcÇŽQ©R¥´véÒ¥éÇ åȨ¾bÅ Ùc¼òèø‘T›]‚ðX¿¾l¤ˆÚµe#…ðÜvŸ†r«A““¬ð‘ Hµ^€Þ༚€µ <N ˆ¦hÑ¢´eË­‰ë¯¿þRW_bù•3gNúã?´6“©òKey%;Iu.µX¹¹üÌc©äÄ ÙH!<7Æf+§Ÿ‰£G³– óVh”’Áþt¥¹R鲫œ“~À†B]óæÍéÉ'Ÿ¤éÓ§kÔ‘“ 7RÅÝW_}Us f—àÐ!±w?Ô|e‚Kª ¶óÜT{AZ§€°ï¶ ©DˆUÖnü*Ô!€-•u¹¡Ì¯PAvÀP¨ëׯÝ|óÍ4a5*Ç×’n^{íµ´hÑ"êÄ,L ”@ɧyäiêœ|X¢á÷G⢋d#Å 2•ðܧ5#PœÆÊ¿æ áüçÙIk×ú£¿¹r¥N°ƒP§NŽa(ÔåRÏÀ´iÓhöìÙZ^?«büG}¤®ÀÖiÉ7íàõ×_§’%KRîܹéú믧¹á‰Á˜1c(---ËææÔˆö©¨ë§w«qiJ)ê»ÞפÒ,ô`¤H%©š½„ÓB´[åÊÉŽÇI¥ðáWŸ:J,ÞQHÝãQ]÷²‡Ô´@ù›»îºË6ó°aègÏžÔ¾}{m勿פIúJy‹À?ü@eʔєC7¤p;N®ÊžzJ6|Ê£Ê†ÃøueŽqšª²l˜”Ý„“s#üö0ŸáÿŸ'Oõž+O#FŒ Ó©ˆH0œ,ë§*©ò«ó‹ ;°è@™ °`AÙq€¨BSü§.M&BݳÏ>K 4ÐVÕ*U¢çŸ^~Ëuø^•*U2mH Êœeð`Ùð)©J×’j –Ó´k'“Š@n@Q-uÊøñãéñǧ9sæhåɺwïN”ßr°DÄ›ì5 Ô¹MèO˜éÔWšãø!%L4p^SaÕ9vì¬eÎ)\!Ô!÷ÓŸþ©åyÒ ¦Œ%K–hBŸ˜ðáþ,^Ã鬸È?Ä0ÉâRåoùþûïiþüù4räHêÚµ+Ýzë­4hÐ êØ±# 2D›Ý"QÍë·DÚšMRìvR%Ô9í÷å4H;•lÀD@ÀÓ WuðEH üëN:¥^ ã«ñ¿Õ'zõêÕš &ì' *¯ËA‰दÇoI%u.½T6RÄÍ7ˆÏÉ“G6RăÊFÀ€a.DÝþóÏ?´oß>9â. íÝ?.JŒùTsHEòf’Nú}9 Þ}Xÿ8½(uÚŸØþšGÆõQ£FEÜ`N8|ø°öÝó–[çž{®¶‡O‰0½‚­[·jé>ýôSºá†4¿¼wõS@ÿÏÐ œ8q±­zu$ÝR¨{÷S†Ÿ[½áo½ÿ¾ÞvöXíÞ¶lÇgô™ÝÇŠ¿»x±ñg©Øì<Þ#Ÿg»7üÝ#ÂÇüÆFM #‚Y³fÑ\ mnÄ)ÇtøîÉ\о -MlN (í¦SñˆvZ`N…°œ†ªþ²m »ví¢Ë.»Lö²R£F ªW¯=óÌ3ÚD-Ä[sáÂ…T·n]-ð~rá`•úÍ7ßP­Zµ4büD¤íÞ½[3ㆃ´F¾z“&M¢s¬ÊÞ´iõ¿§Õ úS1`0ƒ´iÓDý;säˆÿÀ¹lÙr µn½KŽØÏ¨Q%hþür¾>¯áàräˆz­[k ÂðÅ WÀ‚w" IFyð,²<úè£ÚB~vF`áŠM WÌÃ{öì¡‚xm#ƒÿG¥ÓÀöJ'Ó¦¥iÑ¢íÚe~á]²`Áí]ÔâzöL§‡>—°šÌñBhÚ4ƒfÏN ðlŠHäxÇOÓÌôwÞéœËÎëô駒ίyðàA*\¸°©ùÎv¡Î o¿ý¶–‚ÙØóçÏ/GI‹‚E²Ï_Õ%ß•Ðç›äµ×^Ój3b»Ø F;ÕžNޏÒitü¸½^ÅÊÛ¹3›öw¼<ÙE#G,N©Çxöv¶ûXsäÀ‚!]ý›î˜ ¸¶8Ï'M»# xNΞçx&9·bfÁ»téRÙ¼õÖ[Ô£G-ÚiTŒ­ Õ ×'ÒU¡³"=ùäj9b“'—¡J•öRÉ’Î-2ìfÑ¢Ë(W®ST­Ún9b/æRï¥2Ôµ«KòCÙÄæÍçÓÊ•…©MüT Y x#õí»JŽ$N<‹XWuºFZ7D²êÀѰºP‚'œ/¿üR+Ùsk(/½ô’öïp"r˜=Áÿÿüóϧ8*Ôév~»¯€>ïãïàÅü 6ô•PzŒ:v«ÑßL%N\ÛT³Ñß„PW¨P!O uñ€ô%½{÷ÖR?arÿý÷3Y5ÂqÃÂZŠY³ì]ðÜ}w{*‹¿§ »€ÉnúôtzáóZÎdŽwîÜ4Ú¾=:wöNT"NjǡM› úøcgáêš J§#’?¯ñ,b]á:ÓM7iæÓ?þXŽ`W4MV«F@dl‡hCHñOL~øÿàÿiF K%-Zˆ=G&Oª\‹BÖ Â£h;mÚÈF9~ü¸¦™Ósy~ðÁQ:€9“èðtjË;Nž4þ̪íèÑtÊ—Ïø3§×ªíšk²Óúõ†ŸEÛ=Þ_~ÉF+Æÿ÷R½Å{¼yófW…ÁtÃÏìØ~ù%;]wuçÕ,®ê`@rÍW^yEÓ°Í›7Z¶lIß}÷V–G投+WžYvêÔI3¯"oÓ”)S´@‰Ækþtø¹=‘« k'õëˆOIU¶ðo¾‘€Št @•c ®3gÎÔJ’ :”"™\Ýð€l„ÎeÃfVÛëÿízjÕ’ ›A=Ê 3}útm.´á›¾Àu#v uÈñé—ò`á8•„øðáàtÀ©ó Tq$%¹=]#Ô1öðÞ{²Á0âd(Xma„ ÚB6ÒæærˆÈ ¶e‹ìØ€Ÿ ù‡S±"Ñ·ßÊŽ|÷]°ü‚ê~ÿ–DÙqêRŒîË ÎÏL’8­ íÝ[6F‘"²áQR¹1.Æîè~øëÅ‘éÊS\=Ñš5²c#ð ’+I¾|D‡ÉŽÀ’“*a™…º£û&}jcþa³´¤”/¿” ›9p@ì‡ û ñÛo²a3z™© G¾z»²øCPD‰0—'8H¤„ùÎîÅ>4u ƒг<(;6ÁB]€Ñýìô}KUdhª@ýD;ñ{9³Ür‹lØ„ŸkQ\C;Ì]»w§¾æ³Ý /5rÙÉ?ÿåÍ+;1”vg-X»6uÅ,Ô¹„ýûeÃBFŽû /û °c‡lØ„ê{/`w,41Œ·±Ë‡ ¦I¿k˜ì> ;íJáp^W%_ä!"Ю"%Mª´È,Ôù˜.]d#@$[cÏ,Ný ã`)fÆÈ€(U« ‚P_7;…˜ƒ˜šÉî`‰­[…ÛAª`¡ÎÜv›l0IV*Ó6ìxQy ] l7Û·ËãIrçI‚­æ§ŸˆÊ——Ÿ‚ uëdÇ‚$¡ƒ„Õ°Øå¯˜J:ÀB ˜3Gì?ÿ\ì­Éƒ„«Wë°š¶mÅÞ¯IOÍòðÃb¯3Xþ²Ñ“J3Þ%~¢?þ‹€ ÑÏèÖ€S6•*…`ì×<±(Y’hÓ&Ù±ê˜3•%Z·{+q",ÞèÂ—ÕØ%,z»^ ˜s—•Iˆáaÿª«ì tC½q䚌£¤¨¯°Ó¯•NÊ”‘ÀB‹°r5ë×üMŒ»°K‹bÔ¬g<‚Õ>Lßœ4vKlÜì(þ*UˆV®” Ñ“²§Òçš…:Ÿb—YÌ 4n,6ñÉ'²pì^8À<Äx`VVGB„Ž]Áh‚èO§sÅöT;Á½™j—'ê\ÂSO‰½•i‚Z^Iº¬N¹ñüóbo·Ðèt³žŒÙ*ØoÑ_ Ù«•Vhý‚’Ãð’Kˆvî” ùßÿˆjÔ‚w#&¬âY¶,õç•…:—0hØ·j%öV0a‚l”Úµ­•jû÷— &Vçºb¿Eÿ{ĪJ$H˜”"ô>.¸€hß>9`ÈQ1ÈÜpƒõ¦í+ˆªV•ÁB˘5K6’¥_€]ÁÞoo'@¢M†‰ÆM7‰^²@¸ JÙCš5­MÕ„äì¨Vtj×&Z²Dv,þÅÐü¥:·&¿õ|œ@ƒŽÐªYoj½×H4o.Ã~‹þBÝ×_ËN ¾³ÝåéÜF­ZÖ 0BP :ÐÔYeÒ`np `¡ÎEtí*ö7O='Èôë'ö3f\,I¢ûÓõî-öŒàãÅþÓOÅ>YZ´{ö[ôHñ`Eð„ºêÕe'  :Á¶m²cÐúÙŸNé\PÊëÈ9$nð§,Ô¹ˆ·Þû^½Ä>Øô š0¡¢l'ûÓEçöÛe#I¦O— ÆW¤«o8¦ÿ÷ŸHä+UJvÄÅêÚ~pVÀþtgA²z«ê–/'ªVMvR u.døpÙH½|Óĉbl ò´.aPª 4 T `üÌ]º¿o">LtÞyÁŒê‡ Ö ¿:ö§Ë üê/–$€uÍ-<,ÔùŒ ñÄâÅÖ÷ÓSvX½ç7¬ª«›ç¬.)ŸƒdýêðoÝ  Ið³Â¯Žýé2S¡‚ð…K–_~!*WNvR u.£}{Ù`’F¯ Ÿ”d(\X칩1zØdØQ‰ñ/¨‡™L äV š?NÑ¢Öä«cºÌÀ-Úß?ÿ” ²p¡Ðú¹ê\ÆøñbŸŒOœQfþá4ýö[r&X<1G²¾)Š5ŠUÆ¥äÍKô￉‚¡~lùò²@`6ݾ]vç}×.ö§ B.4˜É°h uL IÀŠ•0HuòC7qÇ?«ÿMÞ Ç*£_©WO6’ÑŒAy¯Düê`@‹TÖÔL5Mš$—ÇZRÔ’e2S§ÑçŸËNÀ=¾t¹rÉÃB IÔQÜÊúŠ~á¾ûD.¤TH½Æ¤nbdŒÑ'E8t'B‰b¯›Ì‚T5‰ä DýÓ  $uë-X ; 0cÑwÊsDSoÞ,’'Ò9Yýo,Ô¹={Ä~à@±Ž4â4mØ ›qòý÷²Á˜"Ñ=;Šk3îEäñ«Ã‹ó¶Ûd' @„ù]?Ä\‚T37^à«™¨•à³Ïˆ6”ÀB ™ôí+öf¸ÿ~±çÈÁ¬Ü}wrÙœ9á°9ªÓ£‹?ø@ìÿó)êÀ·Ë,HàOljд͜);qðÓO"Ò3ˆé`Ìp×]DS¦ÈN qññãDùòÉÀBK‰×>?nœl0Y˜0Aìãu²Î–Mì¹4˜9ô” õ닽YP°´i#öŒ¿ 6ž $p+AŽ;H„¶rþ|Ù‰6½F§tia-ˆ7(æp«ü‰­‚…:—¢kÜð0š¥eKÙ` ù1q „¼3ññŲœØ98à%oJÑéåã‚NîÜ"Šxÿ~9`’+¸&x,`iˆ7 +`qüÊr)xx™‚éçŸ/ö‰¨ƒÂºubÿÊ+b ½Ök¢Î³AEw‚7½­§î9vLìÿ¡é5Þ$0½®Ys6`‰!jÚ4>쯿Š@$^ FJ‘©SeLJ ×·UèàËìb ºÏQ$þúK6˜ˆ”-+ö}úˆ},¸Ökbè…øÍæYL$uã}ÉiÆŒˆ@¥ë®cÓk(xÆ ½4›×qØ0¢îÝe‡‰_”Q3[àÿwˆ:u’áJ¡îu¹Ÿfò)>yò$=û쳪´|sÎ9tË-·Ð*Ä¿û¯ºÏ‘ï½'ö7Š=Ý7N/G ÝßÇŒ–”ÉJ·nbk1¢kMõï3Áþ“cÇÆL ¼À‰9‹úšÓR™ñKD@ ýW^)˜¨ àÐLNRGÀ…ÀMQ¯:®ê–.]J­[·–½Ø<þøãêJdõéÓ‡¦L™BÙ²e£:uêЦM›ä7¼þ0þý·Ø‡óÀb_²¤Ø3‘Ñ£XcMpzÎ!¼P˜øyóM±¶ºÖTÿ>à2‚hÖhi$P éO$Ád5¾GŒˆ-¿öÑcÉ,ä¡AŽå0mšXl¸Ñ¤íšŸô·*µ<óÌ3š@–ä×ôÎ;U©z$ :”ºw﮾ŒoW/È|*P  ]8úi:|Xì™Ø4j$ö‘"a/¾Xìu<&1ôê&‘"aõñ:|̓Ŋ£:Èïòè£B舄:­k ›^³¡ÂîâÅrÀø|Á*Á†Ì!­sg!0G‚42*Ü{¯p®êÆŽKï¾û.½ýöÛš€f†E‹iæ×fÍšÉäxËI7¦¹sçÊï£ Ù³‹=X¾œèÄ ¢ /4øc`²Àƒ‹HØpóÌ…{÷Š\Zº“z‚YD†ׄÅyÆB÷s¡Br1Åcª”³=™ .⢋DÎ:£ß»w‹ 7š·ÜÂ# Y[¡ Dišb#PŸ‘²0ƒ»×uвmÛ¶:Åáy¸nÝ::÷Üséb]½")Y²¤:)ìV/J„«â1Ö®%ºâ ‘C«Vlz9%!L|è­0³ê&@”ÓÍ…\Àßô—Í-·œ ˆ¸üò³ç~)Œy°P:u*¯‡»û€^½ˆúõËz/` 謥‹ Dwܤ¬‚ÝĉÂe‡…âøÁ¢÷%JCBq ”)Ð=ñ„p!¶ uÿþû/5*â6gÎí{%J”Ðâá°ºÜ?Ï@MAü!,ôرcÚg¡8¡^A·nÿ÷'èÅq‡áé=MmÚœP'BãïÆÚÜ~¬Vn‘Žççñ•WõšІ Ø'~NݲE:ÞTmúynÛVœç;ÊȰæ<‰C‡ÑC=DC† ¡|nJ_Ÿ$ÅŠ=ø Œ-0Åÿù'Ñ€"ñ7¢^™è¨·-ŠêCég;ø„Í›'´x,'r)Âgîî»ÏFÃ"91Ntsz˜4EE¶ma×®]Zdj$jÔ¨¡G„Ò¿u•ö¼z“Fÿi;vÔV¯ø¡Œ3F›÷ìÙ“E‹ôÿ8“&MŠ[°d¼ÏСWÑõ×ï£Úµc„k2I1jT *]ú°%çùˆ:Ó" *ÒÂÎo´mÛ–~ÿýwZ°`/^œjÖ¬Iãa2 ®Ðð8p€ ,(GÝÊXuíJ”'Q¢rB2 „~¼6lHÙCýV|ÊàÁ§hÚ´ýêûîBºðÂtÍ',ÞªD^Â©ë ŸE¤·Âù‹/’úüÉäàÁƒT¨P!SóíB]"˜êz÷îMï¼óŽv ¡ ¶gÏžÚÄŸ[Ïâ4uØt0áAð„èÆ ÏJð0àÅP·n]ßOvA:V¤ãÅ$W¸paO u°bL„,EŠ¡&MšÐÌ™3©]»vôóÏ?Óå—_®JÄê¼8ÇÁíþ¬Vh—øÙ÷7A;Þxæ;O uºFnß¾}tAHþ„.]ºhR<|ôÌàöU¬•àaÊ 6HÇ ‚t¼ñ¬\ÝŠ+Æ´iÓ¨\¹r4`ÀzN>*f„:¶F0ŒˆÇ2ái¡Q`˜àFŒAe˜V§¥J•¢Ûn»MÓâ™…:ÂBñƒPg†-ZhÇúÅ_ž`ø1 ##ãÌx(A¶F< ¬¹ò/A;Þ¸,êÜF¿~ý ÍÉÞYvîÜ©¬X±B9zô¨Q”öíÛ+9sæT^}õUå“O>QjÕª¥œ{î¹ÊÆå7b£ž(íï©Bñ/ÇWfÍš¥íýNŽéxñ¬â™Å³ëgpŒÑ¶%K–ÈoF'Hsàgßßíxã™ï\ј[«V­ª­6uF­iél¸U«VZÞ:HðXÍ2 Ãx™Õ«WgÙ°bG.N´+V¬(¿É0 ã¢|8íÝ»Ws<þßÿþG7Þx£ü”aÆ»Üpà Y6TÜ m=}Ã0 p¥OÓÀNÜO[·nÕJŒùø"À?§^½z¾÷EÒ±‚ ïü¡¥öøóÏ?}•Œ× f% ’ß0À³Àþ´þ%hÇ1 u*[¶lÑ’3 ã-6oÞLW Ü • -\/èüMÐŽ7žE, u*8Qùóç§;vø~Õ¯GÁíܹÓ×Qƒ HÇ ‚t¼RŠ-ªUZðS…»à…+Ãx3‹XêTtÓ„Õ¦×ácõ/|m™Hiá pð‚οíx1Ï™]IJP§Â/C¤c|m™Hð³àoøxýM<Çë©”& Ã0 Ã0Œ1,Ô© -J¿~ý´½ßácõ/|m†a‚MF$ 8Ù²eÓR`ïwøXý _[&()¤sÆÇëoøxaŸ:†a†aÀæW†a†aÀBÃ0 Ã0Œ¼P‡¬Ô•*U¢sÎ9GËØK—.•#‚M›6Ñí·ß®}†r+;wÖÂĽL¤c½ù曳\glß~û­ü†78}ú45Š*T¨ Ý§HºùØceºn~¼® Ã0‰h¡nåʕԸqc*[¶,͘1ƒÚ´iC}úô¡ÁƒËoø‡Ÿþ™Nž¡ ñjíÚµiïÞ½ôþûïÓK/½D}ôµlÙR~Ã{D:V,HÖ®]K?þx¦ëŒíÊ+¯”ßòC† ¡nݺQ£FhÖ¬YÔ«W/š0a5oÞ\;N?^W;ÊÂeñ ‚´€¼ˆ5ymÕ‡;°¨/E¥råʲ'P…:åÜsÏUŽ9"GüÁ»ï¾«dË–MQ'=9âN:¥Œ7N)X° R @¼­UX•Ÿ*Ê Aƒõ…¦ìß¿_Ž(Êܹsµï}õÕWrÄÄ:Ö7jc .”#ÞÇ©N\J—.]äˆ@Ú´ã[½zµ¯®«]¨Â¼¢ 9JÛ¶m•yóæ)Ï<󌢾ðU–ßð¸/pýÕÅ«vìúöÍ7ßÈoøƒ;v(ê"-ËóèÐ!å²Ë.ST!^QBÊ;ï¼£=Gõë×—ßð&‘ŽW„´÷µºˆÍt½±ýóÏ?ò[ÞÏdFF†òä“O* ,PÞ~ûmmޝS§Žvœf¯m`…:79räÈ2¹ááÇ£®nåˆ?èÚµ«rõÕWËž¿øþû9s*êªFùì³Ï²<ø5jÔÈrãŸw~º®v¤…+ðóâi xÿ"6°æW¸>~ü8•.]ZŽJ–,©íׯ_¯íý‚ú2ÔòÛÀd—'ORêÔ©ýý÷ßòÞ5ñ –6l˜fb gݺuY®3rþÀåµëëXq¡º‡©êù\¹rQÆ =wœ0/¼ñÆT­Z59"€”+WÎW×ÕŽ;¦™ªš5k&G-Z´Ðž{õE Güî¸Óø5)5\+~øaj×®Mœ8QŽžåóÏ?§[n¹E{öu0ç«B<©€ñ±Ž×\{íµÚÞ«À„zï½÷RëÖ­åˆ÷2@!³×6°Bî‹^G 'øÉÙZÞµ‡ÂÀwÜAóæÍ£gžy†&Ož¬½ðaË÷2P/½ôRÙËJ¤zy¸Ö^»Î±Ž“Ü?ÿü£oŸ9s&3†ÔÕ¬6ìÞ½[~Ë›¬ZµŠ^~ùeͧäꫯöÕuµƒ -\Ÿ¯ H XÀ‹Øø±êb 2ééþ95êæÌ™£†tíÚ•ªW¯N={ö¤‘#Gj«u¬üL´kí§ë HË–-Ó&ArmÛ¶Õ®/ ×_]~Ë{,_¾œn»í6m7nœ6¤ëšAZ¸¿/^A°€±ñ/b;óþùÚ>|§Ÿýs?€Ê‹@ÚQ…àÇÔö~×Òh¥Žkí§ë ®¹æMhQTˆ|õêuž2e Õ©SG[µ/Z´ˆ ,¨éº&B® è‹W´…/b¡×6°B]‰%4Õ%Vu¡è}¯¥ˆV,ï¾û.íØ±CŽþûï?mÁh{¿R¦L™,×ùÔ©S´uëV_]g¤¬Aj+VÈ‘³àZ{ñ:#ýÆ=÷ÜCU«V¥ÿýïT¸paùIp®k¢è‚m® è‹W´…/b³^ÛÀ u°½ãf@~:¬ðt¦OŸ® Ê•+Ë}ÇŽiôèÑrD€›‚-V8~þ5XÍíß¿_ŽˆÜ]PÛã3¿_¢çŸžz÷î-Gk֬фŸZµjÉo€ûÇ‚¼sóçÏÏòR ÊuM” -\AЯ H ^ÄF¸¶ª@XT)XËÙÔ¢E -4¸oß¾ZðàÁòþá¾ûîÓòU½ð Zøwÿþýµ”.<òˆü†?@¸;nëа÷}ûö)… RÔU¢ ñZÚƒüùó+ 4ßð&FǪNrÚØ½÷Þ«¥åÁ±ªƒrýõ×ké>¼Âž={”ܹs+ÅŠS¾üòË,9¨pMýz]­Dä•*Uªhy®tÒD•ÿýWŽøƒíÛ·k÷~x:›áÇkù¿Ö¯_/GüÑó¯.ꔀ…:†a†aÀBÃ0 Ã0Œ`¡Žñ5ÜÍ0 Ãêß‚âÞíÛ·—=†aÿ X°PÇø–aÆe©É0 ã7xËè°PÇ0 Ã0†°Œ uŒ/©Y³&-[¶LÛÒÒÒhéÒ¥ò†a†ñ'\&Œñ%¿þú+µmÛVk1‚®ºê*:ï¼ó´>Ã0Œ_а:K–,ÑÆ˜`ÂBã[ô‰µt Ãø^À2¡°ù•a†a<Š.Äa«R¥ t‡…:†a†aÀBÃ0 Ã0Œ`¡Žñ-²Å0 Ã0þ‡…:Æ·äË—6lØ@‹/¦C‡ÉQ†aÁ XF‡…:Æ·tëÖ²gÏN 4 yóæÉQ†aÁ XF‡Sš0 Ã0Œ‡Anº:Ðï¿ÿNãÆ£Ö­[ËO˜ ÁBÃ0 Ã0Œ`ó+Ã0 Ã0Œç!úþ…êˆôƒö¸IEND®B`‚pyclustering-0.10.1.2/docs/img/ga_clustering_sample_simple_04.png000066400000000000000000000757661375753423500250010ustar00rootroot00000000000000‰PNG  IHDRo)ÅßÅdbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEá  3)ð° IDATxÚìy\MùÿÇ_ç¦]éV’PÊÒB¤lÙFƒJt1È:3–ÉRYd¤TŒ},#æ‹É6(1ö!²Œ­¡š²+©±4´ •R}~Äý¹n›ºÕ½÷óñ8ºç|î9ï÷çó9ïÏû~¶7Çc ‚ ‚ eAA9oAA9oAAä¼Õ(gϞŸqãкukhjj¢iÓ¦%##ÇA(ŠÓæååáíÛ·PSS“JÛ±cÇRŸŸ––†“'O¢yóæ%öÜQ·ÈÍÍÅ£Gàää}}}…Ö…ìAð×~ÕŒã8¶hÑ"©kLCCƒyxxH]svvfæææâÏ¡¡¡L °˜˜‰t©©©Œã8¶lÙ²Reصk@tðìØµkStÈ~ÑAíW­ô¼-Z´AAAX°`üüü¤®+))ÁÕÕÀŠ+$¶ ùóÏ?1kÖ,qZggg¨ªªbûöíèÔ©“øü¶mÛ 0hРRåhÞ¼9`×®]°´´äïææ†½{÷òöW Ÿõç«î ;v¬øÝWdÉ~)J}#9ùkgAÖíW;o«V­B@@ú÷ïþýû#::Zâz—.]©vîÜ À?ü€ÜÜ\ÀÀÀßÿ½8½P(„ŸŸ,X¡PGGGÄÄÄ ((îîîeîñöa¨ÁÒÒ¶¶¶¼kȬ¬¬x©7éOe_†É~)J}#9ùkgIVuuõšwÞþøãp‡'NàĉR× æææ8wîæÎ‹áÇ£^½zèÓ§V®\)ž÷___hkkcÆ Xµj áëë ___AAÔ%jÜyûóÏ?+œ¶C‡∠åáååEá°‚ ‚¨ó( øË›7oHÒ ¨¾‘œ¼·3Šfëà-¯^½’YRRR––V£Ï|öìâããyYöu]w}}}ÓKN¶†ä$9뜬ä¼ñœcÄÖ¶ãfii‰œœœ¶oË¿.뮡¡„„ràÈÖœ$g“•œ·÷0Æx©·¼4liiiÈÉÉáí–-„lù°œ>--œ7²5$'ÉYçd%çí=ùEE” r_·l!‚ ˆÏ,È!ç ‚ rÞ‡ì÷{ËñåË—SáA¶¦:å|½x2¦ø/å'ÉJΛìÈåiÏ[m,àÉÉɸqã†Lï„:PdkäYÎ×{Ô)@Vhñ_9p¼ÍÏê”53VæN69oÕ _{Þ‚‚‚¨ð«òòPRR‚@ :”””0aÂÇqÕòüêºïÇú9r„ šP\[S^¯×'×e.gÖa (³øÿ¢LàÍa^Ùn…ic^ïEЄ³2w²«Z° ‡§ÎQ5RSSÅÿïÙ³¸wïžxõ²ºº:222x»š™ j»AFê”b§);¢øœ¶[ůË­AÅ÷.ÊB þ ºßY‡‹u–u>V7Ÿ:Ùëä^êy-X *‡øhР8ŽCÆ Åç´´´Äiãçç\¿~­[·ÆèÑ£ÅÎËÍ›7áììŒaÆáÖ­[GTT¦M›Væ=ÿùçìÛ·ÇŽÃÉ“'qíÚ5xzzНÿúë¯ð÷÷ÇÒ¥K‘˜˜ˆ%K–`Á‚عs'àçŸÆüßÿ÷îÝÃîݻѼys@ll,cرcRSS[¦,>>>˜3g®]»†nݺaРAÈÌ,nŸ>}Š K—.¸qã6n܈-[¶àÇ”¸Ço¿ýeeeÄÄÄ 88kÖ¬Á–-[¨òÔF=-¥Âä’z½J¸^-6QÛ 0Ú-SÇMîlw)Ž°Â´1ÚnHS^Qìd«ÚÈ®^§^0ǰÙÇóRWWW¹*‡¸¸8…ÍËíÛ·3¡P(uþÑ£GŒã8¶mÛ6ñ¹;wî0@ÀîÞ½Ëcì›o¾aS¦L‘øÞÅ‹™’’ËËË+ñyLYY™={öL|îĉLII‰ý÷ߌ1ƌٞ={$¾÷ã?²îÝ»3Æ›>}:ëÛ·o©:qÇ>\¦Þô[¹r¥ø\AAkÖ¬™øœ¯¯/³´´”øÞ/¿ü´µµÅŸ{÷îÍÚ´i#‘æ‡~:WÕúTêšBéòx4c `®`,Œ=]³Ï^üÌWáº./6QQl·D>Þ—ñ]¡Âå§„¬¥è"oï<Íy‡M¬ r€ÄDÙÞÓÂÐШvÑ­­­Åÿ7nÜŒ1<þ­[·F\\»Ç¹šçÌÕ¸óöæÍ,\¸ׯ_ÇÕ«W‘––†ÀÀ@,X°àÓAlÚ´ ¿þú+îß¿eee´mÛ>>>pqq‘ºopp0~ùå$%%ÁÈÈãÆƒ¯¯/êÕ+_E¾›*\4ƒÄD@Öñ8ãâ€Èeeeñÿ‘æEEE˜Ü;$$;w–¸¦¤¤èС=z„ˆˆœ>}nnnèÛ·/öíÛGN!ÓFݶ~B²‰Š!g ޲"µ1²–çô—ç¸U÷B˜ÚpÞÒÓÓ‚öíÛcÈ! )1Ýüùó±lÙ2xxx`ÅŠxûö-Ö­[‡âÀ|8† ggg¼|ù:::PVVFaß+W® GŠ{÷âââ0}útÅaÏ8 ‘þÒ¥KÐÒÒ÷º@tt´DšË—/£U«VÔëV¸º:QŸ >¥¤ùuÁy311AFF†Ø‘ûõ×_KL÷Ûo¿¡gÏžX¿~½ø\ß¾}ahhˆ;vˆ·ŒŒ ,^¼“'OÆ¢E‹½zõB~~>üýý1sæLX”Ó@ÓjSAC£FzÉdMy[…Ì;öööðòò‚»»;455qçΜ>}ëÖ­+õ{ªªªøöÛo±råJ¼zõ 3fÌÀˆ#аaCÅ{,͘1ZZZèß¿?òòòð÷ßãåË—˜9s&Ö¬YƒÆ£C‡à8{÷îEãÆÅê͛7Ç™3gЭ[7¨ªªŠÏ—Ć вeKXZZbõêÕxùò%ÆðððÀÏ?ÿŒiÓ¦ÁËË ‰‰‰ ĬY³¤œÑÙ³gcÒ¤Iˆ‹‹Ãúõë±fÍñu___ÛÙÙÁØØÞÞÞ”1!ÔDlÙÏu&©P,<~ü˜qÇ<==¥¾Ó½{w¦§§'þœ‘‘ÁÔÕÕ¥&.]º”)))±„„„r'ÿq›6±×ïÞñn²9…Ç"ê"´`AÎmÍ«ðâ°YrvHÞl"/äü8 U¢&cIÝk¯N¼ g®ÊrK®,œ8qÙÙÙxýú5àÎ;Ø¿?`À€hÒ¤ ÜÜܰiÓ&(++ÃÅÅyyyؾ};._¾,ÐZ(ÂÏÏ ,€P(„££#bbbww÷r÷xàÊë×è÷~k¾àååE¿þ‚¨9[#çCe²‰5ú¨®Øî2åüw뀷׀·Q@êÚ©Y‡á5æd/ œáÖŠó6uêT¤¤¤(ž¨¼oß>qHž¤¤$cçΰ··ÇŽ;°mÛ6(++£uëÖ ň#$îçëë mmmlذ«V­‚¡¡!|}}áëë[!ytêÕÃÅW¯xç¼9::R«BDÍÙšÚ}¾Úl¢œ8ŸŠb»Ë•SÛ­¸N¼ª¹:Q’ó­5Ž=«c]…wÞ’’’ÊM£¬¬Œ3f`ÆŒöð+ûkÄFS_½" KQÔÐîóÕ†œ;ŸT'*ตä|Ë"=œ7y£eNv½~ü¢"¨”!AÕ6’uÊùä{(ËùV°¼ä©Ðøûo¼-*B\V¯ô®Hè0BþéÙ³'|||(#Ű5Ún€Ñn¹l(˵‰5úècJX©(¶»ÂrÖTÐTìtRη¢µ‡ä¼xyé4\àÙÐiXX¾ øï¿ÿ0mÚ4´hÑjjj011H$ª3{—9s999TØD¶5’³&ÏÃ|Y¡Åß;pu*?k’2œoEkÉy”û pñåK^éN…_E’““akk‹sçÎaÕªU¸uëNœ8‡*¯+”“°mŒ1pGa°ˆ:okäNÎRöB£ü¬¢W‚ó­hí!9oîde¡{ýúˆzýEÔ@ŸÁÔ©S¡¤¤„ØØX <-[¶„¥¥%¼½½qåʱƒ'pãÆ ñ÷^½z@€ .Ο?@€ÈÈHtêÔ jjjŸµq~~><==¡££ƒ† "00PêúìٳѴiSÔ¯_ݺuÃÅ‹Å×=zWWWèêê¢~ýúh×®N:…ˆWŒiiiAII “&M*Q†-[¶ aÆ8pàZµjuuu8;;ãéÓ§é6lØ î¥´²²’øÅ[XX@€Í›7ÃÙÙhѢ̚5 óæÍí[·0aÂ|ýõ×ˆŠŠ’¸¿¿?F…ëׯcäÈ‘1b„8$Að†Ú˜cG(´Ú€ €—{ö@ÙË _½B»úõ)Sˆr¹ÿ>c077/7mE‡-Z„>}ú|¶,¦¦¦X¹r% U«V¸víÖ¬Yƒo¿ý÷îÝÃþýûñìÙ34lØ0gÎ?~Û·oG`` þý÷_Œ;VVV€æÍ›‹ï-ÿòoذ!444Ê”ãÝ»wظq#lllÛ¶mƒµµ5®]»¬Zµ îîîøî»ï³gÏÆåË—ñÓO?¡{÷îâûŒ5 ß~û-`ñâňŒŒDpp0Ö®]KàŸGNAΛ4Öõëã¯K—`7o.¾| Ï&Mx¡÷øñã±mÛ6…‘7''G*njU±°°(×!©ªCVQ8Žƒ]¥¾koo/õyÆ ŠãÓ¡E‹2ççç£iÓ¦€3fÀËË ÇGß¾}1lØ0´iÓæó©¨ˆ7hÓ¦ ´´´$$$HíÝØ½{wlÞ¼Yâ\×®]¥ôIHH cE¶†ä$9©=$ç­»Ö­ñûÕ«˜¨¥…Ý/^ˆ'h×u-ÂBbbb¥›Òˆ‹‹ƒ­­m¥¾ÛªU+p‡ÄÄD Tú\Áû½?vœÞ½{WbZMMM™ç[QQTTTpíÚ5©kõß÷2Oš4 ...8vìNž<‰%K–àçŸÆ”)SÈ@¼±5$'ÛEkÉy`ûÅØfwîàiƒHzûfêêu^ïQ£F)”¼ˆ‹‹“ù=+‹P(„““6lØ€éÓ§Cý“:óêÕ+4hÐ@;³w……Lýüy¶*%…&3ÑÜ¢ŽÔ§º8ç­Q£FÌÕÕUâèÚµ+;xð Dú“'O2WWW©ûxxx°©{»ºº²/^Hœ_°`[¶l™Ä¹äädæêê*ek×­[ÇfÏž-q.;;›¹ººJÍ/ eãÆ“’ÍÍÍô =x©Ghh¨ø}¶µµeÍš5c½zõÛ/¹uÞLMMYŸ>}ʽǮ]»˜@ `ÑÑÑçŸ={Æ8ŽcK—.ý,#¿Ôɉ`¡^^¬Óß³oîܡ֜7‚œ7zo‚›w^.,<~ü=BÛ¶m1þ|BYYmÛ¶Åo¿ý&‘ööíÛkkk‰ó†††Ð××Ç­[·>ëÙsÇXSSLX¿m””pýÍ›:;”1gÎÏ!‚l ÉÉû6FÑÚC¹tÞžâ{•…‹‹ D"‘ø:r$”ü}äàÚû¡ÓÈÈHˆD"©ï{zzJô@||í!#*Ï•+W пÊ ‚PP[Crò·Q´ö°Lç­  Ë–-C»víРA¨¨¨Hªªª•ÎØ¿?޼–¼sçöïßýû÷‹‡?.\MMM899!<<\<÷íæÍ›ÃuB¡~~~Ø´iüüüpáÂüôÓO ‚»»;,,,*%cïFAŠ IDATç!Cm"#‘]Xˆ°*n>*øøøP«"#¶lÙ‚Î;ãôéÓâ7ÕEYAê ‚l ÉIrò =,«‹ÎÇLJqÇœœœØœ9s˜ŸŸŸÔQš7oÎA‰Grr²8ÝíÛ·™««+kРÓÐÐ`ݺucÇ/ñžÁÁÁÌ‚©©©±æÍ›³… ²‚‚‚J;2%%æemÍÞ¸ÁìëàÐÄÇyMÃ?•çÍ›7LKK‹9s†õèу-Z´¨¸±¦M›²7J¤gDZ¤¤$Æc¯^½bîîîÌÀÀ€ikk³>}ú°ëׯ‹Ó2¶uëVfffÆ”””cŒ8q‚õèуéèè0===6pà@öàÁ‰gEEE1¦¦¦ÆºtéÂŽ9Â8Ž“¸ÿíÛ·™‹‹ «_¿>kÔ¨ûúë¯YZZ ›Ò°i³5$'ɩȲ~üÎ×+˱۳güýý$S‡1))©B鬬¬Ä½såáååõYá°Êƒ0ÐÊ $$à{ÌzøyEEPPW ­BdCxx85j„/¿üÿþû/‚‚‚àççŽã0jÔ(„††bòäÉâô»wïF·nÝмysÅ f6lˆ'N@[[›6mBß¾}qïÞ=èèèîß¿}ûöáÀPRRdggcÖ¬Yhß¾=²²²°`Á 2ׯ_deeA$aàÀ Crr2fΜ)’.55½{÷ÆäÉ“±víZäää`îܹ1bNŸ>M…KðÊÖœümcêÔV!éééèÝ»7o ΀aÃð¨ ú7nàc¸õILU‚€­[·bâĉ777dffâìÙ³€1cÆ ** ?þÐÓððpŒ;pöìYܾ}{÷îE‡ТE ¬X± 4Àï¿ÿ.~Æ»wï°k×.´oßmÛ¶|õÕW|???DGG#-- EEEà8)))°²²Â½{÷Ю];¨¨¨ˆ¿Ó¹sg0ÆÄŸãââpöìYh}R¯9ŽÃƒвeKªxQUÇmÊ 3ˆˆÀû_y”/Dõ9oëÖ­ÃàÁƒaffÔ«WW™£¦£ƒžzzˆºrm45—•U§ô[¾|9æÎ«0ò&æäÀ..N¦÷Œ³³ƒmò-[¶ °°Íš5“8¯¢¢‚W¯^¡Aƒ3fŒØy …“““Ø+**‚‘‘Ο?/áT™€¦¦¦Ô³„„„ÀÈÈEEEhÓ¦ òóó+,QQD"V¬X!õüÆ“…$xekªEÎÇ‹7 øïáÃUvÞxŸ$kùÎ[çΑ——‡!C†@II õë×—úuþ¹á§ž:`ÅéÓª©‰¿ë˜ó–£`‘#,44gg'ó{V–ÂÂBìܹ«W¯F¿~ý$® :»w‡F ÄÇÇcÿþýØ´i“8­­-RSS¡¤¤ôYs.222˜˜ˆ_ýÝ»w© ÍÍͱ{÷n¼{÷ÊÊÊ€˜˜‰9o¶¶¶8pàLLL ¨Có9 ²5•’36¶xxsÐ ÙõŽ TÜã–™ …ÅŸù’Ÿ ÔÆ(Z{X¦ó6`À CÏGzŠDð;}†÷ïãfƒÈ-,„z†Ùä Y/D©n4””ªÔK&kŽ=Š—/_b„ RÃŽC‡EHH<<<`bb{{{Lœ8EEEpuu§ëÛ·/ìíí1xð`,[¶ æææxòä """0dÈØÚÚ–øl¡P===lÞ¼†††HNNƼyó$Þ×Ñ£GcþüùpwwÇ?ü€ääd¬ZµJüà (Žª‚‘#GbΜ9Ð××Ç?ÿüƒððp„„„ðþý'xdköîEÐÙ³²ÞüpÇeæ*Ší.Uν{eš|lËtÞvíÚÅ{£ÓiÌ(OŸîØ1Œ…³/_b@BnuŸ­[·¢_¿~RŽÛçméÒ¥¸vílll0fÌxzzâÛo¿…šššDÚãÇcþüù˜8q"^¼xCCCôêÕ 5*õÙÇ!<<Ó§O‡µµ5ÌÍͱnÝ:‰FZZZøã?0uêTtèÐÖÖÖÀèÑ£Å24nÜQQQ˜;w.œ‘——8;;“ãFT«£$owu oJ8p4ÏíÿËžæV 5Qþ>IÝ´´ØðfÍXë+WØ„„ŠÑAû¼),»víbªªªìíÛ·¼¬O´Ï›ΘPÈPü7<\qå glôhùÑA=º8?£GSžTâ/w’KRRÆccchjjÂÄÄ'NÄ£Gxãàö¶¶ÆŸc°®.ޤ§£ ¨¨Nèõi°y¢î±sçNDEEáÑ£G8tè~øáŒ1¢ÒÑQ¢Ê¶¦¤.yÀÍ i+V£G7–ßô¡)4´øo n¢(¶»D9 *žûÈl ÛÃ2·{÷îÁÎÎaaa°´´„››,,,°{÷ntìØ÷îÝã…áðÍ7Hc ­þú iïÞ!êõë:¡×„ ¨U©ã¤¦¦bìØ±°²²Â¬Y³0bĉQ㶦´Æ[öB›pä°{wņñjÑ UÛ]¢œnnÅÎqEdÊÓ’)«‹î«¯¾bfffìÑ£Gç=zÄZ´hÁ†Ê‹a‡‚¼<Öã˜O×®LóüyöSJJ邥ႆMiØ´ÆmͧÃr2”úYyY‹2+JýU¤÷LQÞ#T$<Ö¹sçðóÏ?ÃÄÄD⼉‰ 0sæL^üjTRQÁ€-ðÇÕ«0×Ð@B‰´PÚJF‚ ˆjµ5ŸNà¯ÎÅÕe«ai]³Ý5"§Œ¿(Z{Xæ°iNNôõõK¼f`` pû¢TWWÜÉËCó¼<$ðHo‚ ˆjGNçAUÈ«è0+Q=Ž[-Í;”kç­uëÖ +ñZxx8ÌÍÍùóËqà@€ÖƒHÈɑڞ ‚¨‚$‡ó 9G^¿Ô¶óæåå…;w⫯¾ÂáǃÇcøðáØ±c¼¼¼>ûoÞ¼œœœ```@€… –û½^½zA `úôé%^†¥¥%ÔÔÔ`ff†… ¢  @feÚ«Ôàúudàù»w _ø[¶l¡—Ÿ ù°5rЋU¢œrT^QlwµË)ÃÛ*ÉZ u¤Ì9oîîîHMMÅ’%Kpø½G˃ªª*‚‚‚ðÝwß}öÓÓÓ‚öíÛcÈ! )÷;ëׯÇÇKÝ4tñâÅX°`|}}ѯ_?ÄÆÆbþüùxúô)6nÜ(/·^=Xª«#+6puEBv6}ð[‰ÇĉåFž„„jåªGuy³5–SN7”UØü”52œwXiYk«ŽTd…Czz:;zô(Û¾};;zô(ËÈÈÉʉ´´4Æq *5MRRÓÒÒb‡bDZiÓ¦Iɦ®®Î¦N*q~É’%LII‰%”±©îç®ÖúÚÌŒuÒÖfõÎc¿<~LËúdDrr2ÓÐÐ`è C&‡††KNN¦Õ¦„âm(KÿR©êjÓèêêbàû9_5»»;œœœ0¨”îЈˆäååaܸqçÇùóç‹7&•mÍÍqðáC´TSÃÍ:²âT066FBBmLÈ }}}SFU£‚ÊËe/¡8uä=RÎÛÓ§Oa``€zõêáéÓ§åÞÀÈȨڄ A\\KMsûöm€µµµÄyCCCèëëãÖ­[2“§MçÎx.yy8”–†àV­ DñeæÀQcK„\QÓÛÈÉ–)„בҜ·fÍšáòåËèܹ3š6mZnpêÂÂÂjìÉ“'˜3g~úé'”š.==ªªªPWW—º¦««‹ôôtÙ9o}ûAAh:áLf&uu©òAÔ对¦¨O{q6,ž_ÃûÈr\GJsÞ6oÞŒ-Zˆÿçj©giÊ”)èСƒ\MÊ4éÖ Í””ðpçNX|ñ~KMUhçM$áÈ‘#¼}ßø¬?ßËž ú&—r~܋Ӱ!ðÛo%¡ÊTÎò6¹­Â&¸ŠdgÍ&J9o;K•YM* ~ÿýwœÓ—Eff&TUU+õÝ'N ;;¯_¿ܹsû÷ï 0 Ì•‡Mš4AÏž=ÅŸ…B!üüü°`Á…B8::"&&AAApww‡………L]%84mŠ«ññ0QUÅßYYÙ¨ý´&‚¨iäekêÚ.¢º'—·R²–VRå#å¼]ºt .\Þ¾};NŸ>-‘&77¬´c4uêT¤¤¤8ŽÃ¾}û°oß>@RRR©ŽÇq%Î/óõõ…¶¶66lØ€U«VÁÐо¾¾ðõõ­–LëdcƒCGŽ ¿†âÞ¼QØÂ?tèÌÛÊÏgýù^öD©o2ÞZ£ÒrÖ°“#Óü,ÏA¬‚©HvFálâ§ÝrŒã8Æqâÿ?=š6mÊNŸ>ÍËa‡ ÁÁ ›väÓºp)¤þnnn¼î‚æ³þ|Õ†MëX}“ñ°ž¢¼$'?eýøç{¿Œó=ÙÙÙxóæ c022±cÇ`kk+á𩪪BGGGá ÆÇÇÃÎÎqqqR:–EöóçÐnÔ3æÎÅggÜêÔ m45éç5AÔÑwžt‘cdµÊ“ è—6ÕÔÔ„æ{GäŸþ±±1”••)×>Î#X©ªâeDTú÷ÇÙÌLrÞ‚ jƒZØ • j›2· aŒ!::ºÄkQQQxøð!o3®“±1®þóº5h€Óæ\AAÔ¦óæííßÿ½ÄkÀ÷ßÏÛŒëfo¹¹èÁqøóåKQm"‚ ¢v·ØØXôîÝ»Äk_|ñE©½r| ÷7ß €ðôid"&+Kát(ióU>Ágýù^öÕ7’“äTd›X¦óöòåKhii•xMSS™<.láà€&ž„‡£±Š Vÿû¯Âé p;J“þ¤;Aõä$9É&–í¼5iÒ±±±%^‹‰‰¡¡!o'ÀÁÄço߯š–-±?- G? õ#ïŒ5Š× Ÿõç{ÙTßHN’S‘mb™Î›H$ÂÒ¥K%6íŠ7ò]¾|9ï7ùìÝ«®æä ÏË—øRG?&'“•&‚ ¢öœ·€€ÁÁÁÖÖÖèß¿?¬­­ñÅ_ÀÈȼμ³gCÀò1càÞ¸1b²²”›KµŠ ‚ ˆÚqÞttt ???hhhàîÝ»ÐÐЀ¿¿?®\¹R'6ê­ Ú¶Å}úàç¿ÿF›Û·¡! üùs…‘ÿÒ¥K¼.?>ëÏ÷²'¨¾‘œ$§"ÛDAy ´µµ„èèh<|øÑÑÑ „¶¶6Y$ßïÙmŽCèüùpÕÓÃrÞV¬XÁë²ã³þ|/{‚êÉIr*²M€¨úú`jŠc×®a¤®gg#!;[!dß³g¯ËŽÏúó½ìë...‰D‡½½=:$‘.22"‘HêûžžžØ²e‹Ä¹øøxˆD"¤}²+ Ë—/—8—’’‘H„ÄÄD‰óÁÁÁ˜3gŽD}ËÉÉH$’êå +q«†#FÔ¨………eêñÚÖãC~V¶|8öïßÑ£G222°xñbLž<‹-§ÍÏχ¿¿?fΜ ‹jÏÈa?þ¯mÛ€å{öÀåæMœÈÈ@==¹-|ccc^7(|ÖŸïeOP}#9INE¶‰eö¼­^½?ýô®_¿^³B ŽÛ:wî ø÷£8¢ÈËËøqã$ÒŽ?EEER+Jª -## 33ïþ û7oÐZ]Çß;©òÊ´iÓxÝ ðY¾—=Aõä$9Ù&–Ùó6yòddddÀÎÎMš4Þ'½HÇ!..®Æ„=sæ 8ŽC›6mÄçnß¾ °¶¶–Hkhh}}}ܺu«Æä›Œ#bpûöèpᮽyCV› ‚ ˆšsÞ455ann.‚>yòóæÍC§N0pà@ñùôôt¨ªªB]]]ê;ºººHOO¯1-\\ðûòåèëムW¯âº™Šƒ€VAQΛ¼„‹ÈÌÌ„‹‹ 8ŽCxx¸\g¨ƒ·7´||À®\A–‰ ’Þ¾E‹Ky 11±FæÊ+|ÖŸïeOP}#9INE¶‰raáåË—èÛ·/ž={†S§NÁÄÄD⺞žòòòðöí[©ïfddH õV{†Ö«‡ àÅùó ×C§>>>¼nPø¬?ßËž úFr’œ•‘uï^`̘â¿rë¼ýõ×_åÕí¸õéÓÉÉÉ8}ú´Ä\·|˜ëvóæM‰óÿý÷ÒÒÒ¤æÂ•„¬ÃËØµh«÷îAÕÏ¥¤H¤•§p&ëׯ/S@¾Ã™T5LÎúõëë„•)Æ× =ª^†¨9>µ5$gõÊYFEž¡(ùYQY÷î¦LBC‹ÿÖªÇÊ€ã8&Ê<ªBZZã8ŽI]ËÌÌd¶¶¶LWW—ÅÇÇ—zŒŒ ¦®®Î<<<$Î/]º”)))±„„„R¿ǰ¸¸8&KvN™Â°>—/³ׯ3‚ äƒêzçIB^gL(d (þ®˜ÏGF.ÖùÃ1ztí½óeÎy;uê”Ô¹ôôt:tÑÑÑX·n]¥Æ'N ;;¯ßG!¸sçöïß0`ÀÑÑׯ_ÇÚµk‘ŸŸèèhñ÷6l333€P(„ŸŸ,X¡PGGGÄÄÄ ((îîîµ2†m7`°q# “’pÊØŒ1 •E!ìÝ > ¸¹Õ=ý23‹ÿÏÌ,þ,k=kâòÈ A@DD±ÎBañçÚ¢Lç­OŸ>%žwssäI“pæÌ±³õ9L:)ï‡9ŽÃ¾}û°oß>@RRcâ-Hf̘!õýo¿ý[·nöõõ…¶¶66lØ€U«VÁÐо¾¾ðõõ­•LmíèMõþú Ï7FJ^LÔÔÈjAÔ²ã6eJqãñ¡=#C‘˜šäC]‘ç¿Ò †ŠÐÐÐJ}7)) ………%ÆÆÆ011)õzaa¡„ãö///$$$ 77IIIð÷÷‡’’R­dª’Š :éèà¿÷=—ÑrçôÓ¹E|ƒÏúó½ì ~Ö·’zŒñ½(KN77`ãF`ôèâ¿Õá`TôŠdg**«›°{wí;ý•vÞ^¾|)c”øº·iƒ¸{÷`¢ªŠ9uÞrrrx]F|ÖŸïeOð³¾ TÜS”Üc¤(ïEyrÖ„ƒQ‘g(’Q4›È±2¢§?}úTê\^^nܸooo´jÕ 'OžTXƒ;;;ÄÅÅÁÖÖV¦÷ŽX¸.èæ ²„B\ìÐ,8AÔáwžtQ êúœ7‚ö«Ì9oM›6-q¢=c -[¶T¨eÀ5ý·ßоzç:uB~QTÊ‚ ˆZÄÍœ6Bñ)ÓyÛ¼y³”󦦦†æÍ›£k×®µ6§LÐ11AUUäEF"×ÎW^¿F/Ê‚ ‚ dë¼ùøø`úôéhÚ´)\\\```€zõêQNU‚¸xáôüý™‘!wÎ[ZZôõõy[>|ÖŸïeO(~}«ŽáOEy/HN²‰Rãx«V­ÏukÖ¬âããÉòTÖyëÙ oßâ œú°ÄIŽ˜0a¯Ë‡Ïúó½ì ù«oŸ ºvºW”÷b„ r¦©®ØE³‰RÎ›ŽŽ^¼x xnQçmäH@ÓøxÄfe!ãÝ;¹’/00×åÃgýù^ö„|Õ·ÏuÆÊÛò£®¿ݺÊO˜¦:bgÍ&J‡vîÜ'ND×®]sçÎ…ðÃÚêOà8NƬwo4À‚ʼyxó&v[ZÂT]].äãû 5>ëO« yªoŸ»cum«(ïÅÍ›¶ á@‘쌢ÙD)çí—_~ÁôéÓqãÆ p‡;wî@EE¥Tç(N @wCC\¿r¶k‡‰‰0‰g“&Xlj ZðAñÙÎXmìt/O[Œð5ÂŸÊø³7SSS=z pôèQtîÜ™Jµ’ôèÔ ß>Œ¾ººØ³r%n Ž…ÉɈÌÈ@¬9pAðžÊ8c5¹å‡¼…Õ’§0MuÉqS¤Ðien}P¿~}²† Rêv#wïÞ…ƒƒ ñûï¿cÛ¶m¸wïzöì‰ôôt‰´‹/ÆÌ™31lØ0DFFÂÓÓK–,———Üe¸¦ú5j„C.à[CCh()!øÉª‰Að®ñýœ…ò¶h€½ƒNT£óöôéSœ>}™• ÷dbb‚ŒŒ üùçŸX²dI©öýýý¡¦¦†?þøNNN¶<{†Į́µ Bn Ýü YÔ!yª7‰¦ ï!ÈÊìycŒ‰ç¤EEEA à‹/¾!--je8q¦ÊÊX1mÆ4j„m©©((*¢Œ!Bî_yßÍŸ *JEzÕäµÇ°BΛ©©)Ž?G§N ¡¡xöì„úÒeŒžž€âÞ¾OÉÈÈÇqâgëéé!//oKØn###C|¯²pqqH$’8ìíí¥æËEFF–8©ÑÓÓS* H||uwtÄOžà†‡žÞ¿ãéŒ9sæH|?''"‘—.]’8†ñãÇKÉ6bĈRõøô|eõø@JJ D"‘Ô"‘êÖ£²åqèС:¡GeÊcðàÁuB²Ê#,,Lü>ÛÙÙÁØØÞÞÞÔrÕò8÷˜ä䯜%M(IV¹þÑÂÊ`ýúõŒã8f``ÀÛºu«øÚŒ3XŸ>}XUHKKcDZ   ‰óLCCƒyxxH}ÇÙÙ™™››‹?‡††2@Àbbb$Ò¥¦¦2ŽãزeËJ}~\\ÀâââXm‘ü×_ Û5u*³eoܨ±g»¹¹1>Ãgýùª»<¼ó|ÔEQêÉÉ9ÃÃ=ºø¯¢äéÇï|™=ožžžøí·ß0tèPlÙ²EâxVV¾þúëjq(•””àêêŠ ;;[âøŸþ‰¡C‡ŠÏ9;;CUUÛ·o—¸Ç¶mÛ 0HΔÛÛ£›–öìß÷Æq<=khÓÞððp^÷ðY¾—=Aõää·œŸöª)šM,7<ÖØ±c1vìX©óŸƒ|'Nœ@vv6^¿~ ¸sçöïß0`ÔÔÔ„Î;cÀ€øá‡››‹€€àûï¿ßK(ÂÏÏ ,€P(„££#bbbwwwXXXÈ}!Œè׳Àú·o¡&`[j*ü›7'‹OA„eö¼åççKô|Ààçç‡óçÏWú¡S§N…››¾ûî;p‡}ûöÁÍÍ nnnxþü9ÀÜÜçÎƒŠŠ †Ž & uëÖ8þ¼Ô<6___¬]»û÷“6lØ___¬_¿^! a¸¿? œùñGŒ00À–gÏPTÊæÅAAð›2{ÞÆŽ uuuìØ±°aÃL›6 °téR?~NNNŸýÐÒâ“~J‡Y¡´^^^ »ñhc|¡£ƒ=GŽ híZlKMÅ©ÌL8•°U AAü¦Ìž·˜˜8;;‹?¯]»£FBZZŒ•+WRʈ‘..8›‘Ó”´ÑÐÀöÔÔjfI«ùŸõç{ÙTßHN’S‘mb™ÎÛóçÏѤIÀ£GðàÁ̘1ºººøî»ïpãÆ ²J2bX` ”„ùûÃÍÀÇÓÓ‘_Í{¾Q„а@TßHN²3ŠgËtÞÔÕÕÅ‹ .^¼MMMtìØQ|íÍ›7d•d„^«V5i‚m'OB¤«‹×……8ÿòeµ>sÔ¨Q¼Îs>ëÏ÷²'¨¾‘œ$§"ÛÄ27kkklܸ øßÿþÅ_IIIA£FÈ*Éñîî¸ùö- …‰ª*S ‚ ‚ >ÇyóóóÙ3gжm[ÄÇÇKìf[[[ÊAâ8w.rö®[‘¾>¦¥!ÂeAQQç­oß¾¸}û6ÂÂÂpóæMôìÙS|­gÏžÕ˜ž¯ÔSSƒ¨U+¼zS7ÆùùXÿäIµ=ïÓPH|ƒÏúó½ìëµÞï _ö¡¾É{¶=z(DX¼Ï•÷ð~?üðCµÖ+Yê±zõjÅ ïÇçðHò^怀Ý>|˜M¹{—é\¼ÈþHKcEEE2–««+¯ÃcñY¾êNᱨ¾‘œ$§¢ÊZáðX@ñF½[¶lÁ×_þýûãþýû€cÇŽUx¿6¢âô™9õÌš8VëÖÁBCoÞĸÄD™oÜ»gÏ^ç5Ÿõç{ÙTßHN’S‘mb™›ô¦§§£OŸ>¸qãôõõ‘žž.^}ºoß>hjjbÆ d™dˆšŽ¦ÙÛã·èhœÜ°w @l‡ø61ʇ­[£ž@ “gihhð:¯ù¬?ßËž úFr’œŠlËôæÎ‹/^ ::OŸ>û¨ççË/¿Ä¹sçÈ*UKþú ÷ÓÓa `Í÷ßãkCCl·°ÀöÔT ¹}»Ú÷#‚ BA·£GbÑ¢EèÔ©8Ž“¸Ö¤I<~ü˜r°šPÓÑÁô>}°=1ýôô`vàþ°¶FdF&ݽ+áHAAÎàÕ«WhÞ¼y‰× PPP@9Xx†„à[ <ËÎÆ×3f cØnaÿý‡ÐçÏ«|ÿOWºð >ëÏ÷²'¨¾‘œ$§"ÛÄ2·æÍ›#::ºÄkÿý7Z·nMV©i`lŒÍ 8tìž ¯©)®‰D¤§‡IIU>566æuþòY¾—=Aõä$9Ù&–é¼ýíÝy\TÕÿøñ× 0,Ê¢ ¤¸o¸kj®A.¹¢æ–f…Vš¹¤ùÉ5ô'šë75ÓÔL³ÌÝJÔ¬\Ê25Æ]ÔP 7@‘u`æþþ0çá8ˆK ÷ý|<æñÐ3w†ó>çÜÛ»œÛ‡3fa)Óh4>|˜ÿû¿ÿ£oß¾yZ¹¿þú‹Î;ãïï^¯§ZµjL:•´´4«í ­ZµÂÃÃ///ºuëV¨î„­Ø²%ËÞ}˜yð oÇÅ“žÎqqÿé{‡ªê_(jŽ_í}/d¼I=¥žö<'昼3†† BÉ’%èСÏ?ÿ<õë×gøðáyV±'Nмys.^¼È‚ ˆˆˆ wïÞL™2…>}úX¶;sæ ÁÁÁ˜L&6lØÀŠ+8{ö,Í›7'>>¾ÐL~}?ûŒŸÏÈþì3z/ά‹É’›„BUÉq©NÇ?þÈ7ß|CDD×®]£X±btìØ‘×^{ ‡<«Ø·ß~‹ÑhdãÆ”+W€   ®\¹ÂÒ¥K¹}û6E‹e„ ¸¸¸°uëVôz=õêÕ£R¥JÌž=›éÓ§šÎÒûúäãö_eF@õ##Ùtó&=}}e$ !„*ñÈôZ-}ûöeÍš5ìÚµ‹uëÖñÆoäiâàââ@Ñ¢E­Ê‹-ŠV«E§Óa2™ˆˆˆ {÷î–Ä îž»fóæÍ…®ÃÚ¿ø"{¨œ’B+//Æž?Ï匌§ú®ס6jŽ_í}/d¼åv='$oJÆxÒ(íi‡óŒ½Í‰Ú‚Z±ÐÐPŠ/ΠAƒˆ‰‰!99™­[·òùçŸ3dÈ\]]9wîiiiÔ¬YÓæóµjÕ"::£ÑHaÒqèPŒÀ·£G³¤re2…à#GHzŠ;G¥ê_(jŽ_í}/d¼åf='¤lK!ód&)ÛRr={01¼WÏg™0öyÆÞæÄ“·¬¬,f̘A­Zµ(Z´(:Îêåììœg+Uª{öìáðáÃT¨P"EŠÐ¹sgBCC™7o€åš6ooo›Ï{{{£( ‰‰‰…j,DÏÒ¥™úõ×<—™É®Úµ‰3ùðܹ'þ®… ªúŠšãW{ß o¹YOã#¤ÿûŸt0žÍ½d*»ÄpáÂ…yž0ªmž±·91ÇkÞÆϬY³hÓ¦ mÛ¶ÍÓdíAgÏž¥eË–T¨P™3gR¬X18ÀÔ©S¹sçË–-SíD8yÑ"jtêD÷J•˜0c³Ú´aÐßÓÖÛ›®Å‹?ö÷ÈR!²Tˆ2Þþ{=uUtdžË¼›À¹€®².÷’·lÀ®$oJ¶)×U×I¿«dNÌ1yûöÛo™0aaaaϼbcÇŽÅl6³sçNËõoÍš5ÃÇLJþýûóæ›oâçç@BB‚ÍçÐh4xyyº‰°ZÇŽ,ë׫WÓþ­·ˆ¹|™]Å‹Ó'*Š=ÎÎ4*RD~[!Ä3r/i2ž5¢«¬ËÕ$êa‰a^&Œ…•ñ¤ã#º*º—è>©O›ÆÇÇ”/;uê–Äíž w—©P¡®®®?~ÜæóǧbÅŠètî öíÛbõjܸ1[¶l±Únç΄„„Ø|~ðàÁ,_¾ÜªÌ`0ÂÍ›7­Ê'MšÄÇlUváÂBBBl.˜\°`ͪϩ©©„„„P©~þí7’…EýûÓáÈÜfÍbÒëÛõêÕ«@DZoß>«ò5kÖЯ_?›ºIǓƱfÍËþ\¿~}1b„üy–À¹wuÏõ¤@W]‡¾½§NèÛë-ßÿ°òÜNv ò5uOKA?ÍüD”´mÛV™7ož’Zµj¥øùù))))VåŸþ¹¢Õj•~øAQEéÕ«—R¢D %99Ù²Mll¬âì쬌7.ÇŸ©Jdd¤b¯U¯®øh4ʸ8å³K—‡Ý»•ëõÙ3f(j¦æøÕ{aØçí1–Ço'2”;ï('2d¿(õÌ8‘¡$ÌLP¦$( 3žª_ R{ÞÙxçn,ÿ¾îlºcw}ÿ>Ÿã‘·ùóç³téR¾ÿþûgþÓ#FpóæMZµjÅúõëÙ½{7áááŒ9’êÕ«Ó¶m[ÂÂÂHMM¥C‡ìرƒÍ›7Ó±cG|}}ùàƒ ý_{c–.%IQø´_?ºý{½ÛÆ7볩©©ªþKYÍñ«½ïEÁo娈½ìÏ¢ž¹qFAjO]Ü;‘—Íif{›5Š¢({ÓËË‹ŒŒ 222pppÀÝÝÝúÃMž>Å`ß¾}„‡‡sìØ1nݺEéÒ¥ a̘1Vײ>|˜Ñ£G³ÿ~iÙ²%³fͲ,îû0ƒúõëI½zõìvbT½:룢øçʺ_»FªÙ̯uëÊo ! é>_ØbIÞ”LæÉLËÿj8áÞÕ]l>º—Pß»¦.¯NÍ>ë˜òâºÄüØçs¼a¡C‡h4š|«h³fÍØ¶mÛ#·«[·.;wîTíN6vÙ2–7i§ýúÑoåJ^=uŠÉÉÔp—ÉOQð=‹‹ïï¿X(4®çYŸäáMyšœåЯºê…§¿sLÞV¯^-#Ø4nÌ[ÌúñGþ6™(©Ó±ðòeW©"#„P}¢pÿQ¤Ì3™ 2¹›0Þ÷ó…ý&;V}¬‚~Íñš·ððpâââ²}ïêÕ«„‡‡Ëè. Æ.[F’¢°ô­·x×ߟ¯®]{äS¼ÓOmÔ¿Úû^¼ñ–WwkÂ×oeÝMÜ›k¹ìe¿z>¢Ÿâ={›sLÞ&L˜ÀÅ‹³}ïòåËL˜0Af¥" qcÞ¨\™O~ü‘nîÍüvûvŽŸéß¿¿ªÛLÍñ«½ï…ºÆ›ÕÅꎀӿÿ~à­½ìRÏGôñSœz··91Çä-‡{HIIÁÉÉIf¥dÄÌ™\1›1L˜€¿NÇÞ[·rÜ~òäɪn/5ǯö¾êoVk¢…èÑwÊ~}4{Ù/¤žè㧸¹ÂÞæD›kÞNœ8Á±cÇ,ÿß¹s'ÑÑÑVÛ¤¥¥ñÕW_Q¾|y™• ê;ÓÆÇ‡O¿úŠ ¡CÙóˆäÍÞïPû¯Ô¿Úû^¨o¼Ý»~+§‹Úíe¿zæÜÇj˜m’·7Z‡¥Ñh˜8qb¶tqq±Y5]ä¿^:ñö—_ÒÛdâÛ;wHÊÊ¢ˆ££4ŒBõÔvQ»(¼l~«¿ýöÛ´mÛEQhÒ¤ Ë–-£zõêVÛ8;;S©R%ôz½´`ôæ›(_~‰Ë?`nÒ„Ÿyå V/„…6yËæ¢vIÞ„=²¹æí¹çž£Q£F¼ð üôÓOôèуFY½êÔ©#‰[U®E J98pvÓ&Z-ÊÑÑÜ~È]§j?rªæøå¨¹Pãx{ÔEíö²_H=eNÌñ†…–-[âáá!3Ñhµ°7*Š•U«’•ÅÿÎËv[ƒÁ ê¶Rsüjï{¡Îñö¨‹Úíe¿zÊœhóx¬0nÜ8Ê–-Ë€rþ°FÃ’%KìzB),—±ú "4”+WrõÔ)Ö)Âпÿæ¯úõ©'‰¸$B%rÕ£Võ"/öy›kÞ¶oßÎàÁƒضm[ŽÇÊÏGg‰‡ë`ëóÏs:5•­ññ,¸|™5tðñ‘ÆBˆ§Mžá r„Oíûi¥K §÷׬¡C‰l:y’û÷g‰“ûëÕã|£F{zÒãäIŽ&'KC !ÄSú¯«ú?iâ‘y2“”m)O¥ñs!Ѷg6ÉÛ¨Q£lޏ™Íféy;ãâéÉ–¸8 Gbú4iÂâ>}ømÚ4V•)C77·kÇåŒ Õ¶QHHˆÄ.„Œ·§®ç]Õÿi.¡]¤ßs1Ñ6ž4Ò®n;’V$ÙMbl“¼Í™3‡+W®Xþo2™prrÊ·;1öíÛG‡ðööÆÍÍÊ•+3mÚ4«m ­ZµÂÃÃ///ºuëFLLŒÌ˜€_|>|8gnßfÈš5t˜<™5j°90÷nÝ>r„„ÌLU¶Í!CT;.Ô»ñ–›õÔU×áÞÕ=OOÁ=˜x ~g°ôûSôSv‰¶ñ¤‘”ïSx»ÖÛ˜.™HùÁ>ŽlÚ$oÙ=Ï4§gœæ¥o¾ù†   ¼¼¼øê«¯Ø¾};cÆŒ±ªÏ™3gÆd2±aÃV¬XÁÙ³giÞ¼9ñññ2k=æÎ%6+‹ŒŒ VÄÚ‹Ù=dûäªÑÈ´ØXU¶K›6mT;&Ô»ñfoõ|0ñè0 ƒ´çS¶ãƒ‰¶ñŒ²à¥Š/Ý-È´Sªö¹IW®\aàÀ 4ˆ XÊ_|ñE«í&L˜€‹‹ [·nµ,\¯^=*UªÄìÙ³™>}ºÌœÿrÐéxmÑ"¶oß΄•+‰Y¸ÿ•.Í´ØX†•*Ei$!„(  œÜ¨íZEGæ™L¸·–½SÞ]»˜› ì K—.%55•Q£F=t“ÉDDDÝ»w·zâC@@ÁÁÁlÞ¼YFf6FÏžÍe³™cÆðA©Rx9:2øìÙ|;Â*„BäWR¬Ñ£-­Å¡”úNz»H’³MÞΜ9ƒÁ`°¼NŸ>mUvÿ{yá·ß~ÃÛÛ›¨¨(êÖ­‹““~~~ 4ˆ;wîpîÜ9ÒÒÒ¨Y³¦ÍçkÕªEtt4F£Ü•ó šÝºñ’—?ÿ½VËòªU‰HH`žÊ–†Ù²e‹jÇ€šc2Þ¤žRϸݞ»)Ò¯ˆÝÝÌ6y ¥Aƒ4hЀ^x€×_ÝRÖ Ažþy4hg»|ù2)))ôìÙ“Þ½{óË/¿0jÔ(V­ZE‡wÏ÷ß»¦ÍÛÛÛæóÞÞÞ(ŠBbb¢ÌœÙøðƒø;#ƒïƧƒÿ+]š‘çαô¾›U »5kÖ¨¶ÿÕ»ñ&õ”zÚûœhsÍÛŠ+ DÅÌf3„……ñá‡ТE œœœ1b»wïÆE®Ñzjm?úˆvóç3böl.EG3lÔ(Òüýpö,±ééL)Wm!‚ÆÚµkUÛÿjŽ]Èx“zJ=í}N´IÞÞ|óÍQ1¢££mîVi×®ÇÇ`0ЩS'l>Ÿ€F£ÁËËKf·˜·r%­;uâý Øõûïl¼|™FŸ?O€‹ üý¥‘„Bˆ¦ÀÞ°P»víœ+®ÕR¡B\]]9~ü¸ÍûǧbÅŠèt>ݾ}{BBB¬^7¶9_¿sçÎlmU¾`ÁËQÇ{RSS aß¾}VåkÖ¬¡_¿~6uëÕ«×Cã¨Ò®²²øüÍ7ÙÇk;âóÓO¼êëËÔØXÒM&»ˆ£°ô‡Ä‘»q¬Y³Æ²?ׯ_Ÿ€€FŒ!³¾Âþ)ÔO?ý¤h4eúôéVåsçÎU´Z­òûï¿+Š¢(½zõRJ”(¡$''[¶‰Uœ•qãÆåø3"##@‰ŒŒTÔ,ýömÅ_«U*:9)o”/¯œ¼uKÑîÞ­|rñ¢"DaR˜öy™¿„PïüU`¼µjÕŠŽ;2eʦM›Æ/¿üÂŒ3?~<:u¢I“&„……‘ššJ‡رc›7o¦cÇŽøúúòÁHvžƒ{GTœ‹aÉøñTóöfÕùó$|ý5o”(Axl,©&S¡_Í}/„Œ7©§Ì3ö7'èÓ¯_¿žádztéRÚ·oÏ’%K9r$ëׯ·lS¥JöìÙƒN§£Gôïߟʕ+³wï^|||dÖÌÁý×vœ2…-—.QR«eÓòåL,S†ø¬,f_¼ˆIQ8™’B|!{Œ–/±!òaŸ×Jsˆû½òÆÄšLÔswç÷ºu©/±!žá>/GÞTìÁ¿R]\ÿã–DE±$*ŠÏ£¢x·NfïÚÅWヒï?ÿ0¯bEVªÄ7ׯ3ÿÒ%»}&jvñ«¹ï…Pûx“zªwž±·9Q’7›9sæcm7nõj<´ZÞX²„–Ï?Ofj*}|}QªïGGSãÐ!ž9ƒÙÎ’¸Ç_Í}/„šÆ›ÔS½óŒ½Í‰’¼©Ø·ß~ûXÛùV¯Î?))üòK¢22ݼ9­ZÅœòåÙT½:MŠåó¸8V]½Z(ãWsß ¡¦ñ&õTï„]ݰ°lÙ2´Z-EбyÏ`0ЪU+<<<ðòò¢[·nÄÄÄȬ™ƒQ£Fåé÷×íÝ›‹YY¤)J¶¯ëÿüƒ˜Ý¿?.l®´›ß_IDATQƒâNNt9q‚¡ÑÑŒ>wŽf‡ÓñØ1ÒM&»Š_Í}/ē޷ž z²¸ïbú4êÃ⾋ó娛½ìRO™í&y»rå ~ø!Ï=÷œÍ{gΜ!88“ÉĆ X±bgÏž¥yóæÄÇÇËÌù .ÌןïY¦ Ú5cAd$Õ]\¨îâBˆ—IÍšQmØ0Ž;;“Ö¢ëùåÖ-ÿýw®®—ßñ«¹ï…Œ·‡%p_¿ýu¾.µ—ýBê)s¢Ýœ68p AAAxzz²qãF«÷&L˜€‹‹ [·nE¯×P¯^=*UªÄìÙ³™>}ºÌžÙ(·FZ»‡>}¸”dU¾òÈ>0€ÇŽÑÃ×—T³™ÐÓ§¹j4ò¢§'ݹñäd‚<=™X¶,þÎÎv¿šû^Èx“zJ=¥®…8y[½z5ûöíãäÉ“Œ?Þê=“ÉDDD¡¡¡–Äí^G³yófIÞ 0&ïÙcSîõÒKLß½›×–-ÃÝLJúÀ<''>1™øíæM*¹¹ÑÂË‹-7o‘ÀŽZµ¨~_ÿ !„åW «Ÿ¼]»v#F0cÆ üýýmÞ?wîiiiÔ¬YÓæ½ZµjñóÏ?c4ÑétÒÛvdÈҥ̩X‘Æï¼“íûéÎÎ|šÀä²ei{ìíŽã¯úõqÕj¹™™É¯·o£*¹º’l2ñ¼‡‰YY$dfr>= 7näéÉ‹žž8k4Ägeq;+‹ò..œJMåDJ ÞŽŽôôõå§ÄDbÓÓ ts£½&%QÑÕ_Ž¿SS‰ˆ§²›MŠÁÓÉI:OHr Lß–åWdœÙYò6xð`8p`¶ïß»¦ÍÛÛÛæ=oooE!11???Ù“ðñÇ3zôèY7ï 8¶oqQQ6ï]=wŽWfÌàóÐP¯[Ƕš5©IÀþýdü{MœÈé긚z=æÏGéÝ;ûŸïèH’ÉÄà¿ÿÆ qp ÉdÂÇÑ‘ø¬,Ü´Z\\8šŠwïœÕnn¼P¤Ï{xPÄÑ‘Úîîòˆ`Aî{Qø’{o…­žù½üJnµç³HBímN,ÐÉÛ† ˆˆˆàèÑ£2KæÔÔÔ]¿2M›R¦iÓlß{sÃþ·~=ÿ÷ïUç2eÐ7nŒçµkhïÜÁåï¿Ál&«xq4F#éÕªápëŽ h22H»t‰"NN¸8€¢Óápû6Ú´4ŒÏ=‡ãÍ›8ÇÆRÄÛ›;/½„뉸œ>{íÚ$·hAÉýûI¯V+žžø;†ß¡C|ôÉ'¤´iÃþ¤$$%±âêUÌÿÖÕËÑ­–Ê®®T×ëéíëK3OOé{a÷79°—ñVØê™ß˯äV{>‹$ÔÞæÄ›¼¥¤¤0tèP†ŠŸŸ·oßFQŒF#·o߯ÉÉ l¾#!!Fƒ——WŽ?«}ûö4lØÐªìÆŒ=š.]ºXÊvîÜÉÂ… ùþûï­¶ÓÇã…¦M¹”‘Á…Œ þØ´‰S¿þÊìÏ?§Ô¿7…lºqƒ‰ýúñzŸ>tîÒ£ÙL†ÙÌ‘={ض|9+6n$!3W­–óéé xï=ׯÏÿ2„+ü“žNrT³þßÿãÕÙ³éX¾<ÒÓ öòbîÔ©(ÎÎÔ{çJ»¸PÁÅ…˜ØX†FÿI“¨ȵÌLΧ¥ñëŠx&$0><_ޝ®]cW\Ç€#ˆ¿r…=7â¤ÕréÒ%®ß¸géÒ’qå¢ÇMÂÂÂì"žÂVÏ{ ÎwG¿£sígº1·Úóþq¦sÐQܽ¸jûþžûlÓØØXÊ•+‡F£yèò]ºtaýúõ)R„ÐÐP>ýôS«÷ÛµkGLL §OŸÎöóòlS‘’.]âõ ˆºoYšË™™4öòbÇ•+8º¸XÊMŠÂ¼‹Yã723‰IO·¼WÁÅ…óéé6§{42Ÿb7uÕjI3›ñrt$1+ ½VKŠÙœí¶÷N ?êûLŠ‚QQ,ßù J®®œOKãþo pvæBF†Í¶nÿ~ß½SÝîÔqwçHr2ɨ‹ã¿ó‚é¾ÿg) å\\¬ÚT”Ôéˆ3ï¶ëÙ³0p <Û4­;´.ß’¡ÿ΢=‹È4eâåæ•ok”}¾Ày+Q¢{²¹ qúôéüúë¯ìرèÔ©›6mbæÌ™–;N/\¸ÀîÝ»9r¤Œz‘§Š”*ÅwqqVe»çÎ¥õÈ‘x¹ºâðÏ)€»¿?æ’%Ñ^½ÊÍË—ñÐjÁÁ0•+‡¹D œþüW£ÁlEgg25B“™‰CTг3¦ÚµÑ\¿Ž6.Mj*šädh֌Ԓ%q‹ÅáÏ?ÑרÙײ²Ð&$ ILD›Éɸ—)ƒ©re0™ÐÞ¸öúu77Ìÿq5—)ƒ6+ ý©S˜¢£ÑWªt·®YYh231ûùñOPNQQ¸üóŠN‡ÆhäÖ±c¸—)ƒÙÏÍ­[h¯^EñóC{ñ"NN8 IL$38˜h¯]ÃcÛ6ÌEŠ`ö÷G“™‰æÆ 4wî -z·Þ7n xx`ª]ŒFÌþþ8ÿóñîþþàæ†â䄹LâK•ÂåÊ0áäIÒdÈ>Yböˆ‹Ä{6è)I›Ès7îÜ Ó” ÈãÓ y{˜~ýú±qãF’î[ìÌ™34lغuë2fÌÒÒÒ˜4i·nÝâðáÖS«õ/×üróæM«S¡îÚ5g†Ý» dì)F#zÞ}éöm>Ù·O޼=fâvï"ñÿz¤Ã^æ©gÁ­gnŽG{mÓû÷y;ª)RĦÜ`0(­[·VÜÝÝOOO¥[·nÊùóçsü®ÈÈHP"##5êÔ©“¢fjŽ_­±¦}>¯céóy…·±¼ú,íSèÇÛÃê¹öàZ¥Ïç}”µ×øý· Õ5·û}íÁµJŸ¥y›=ŒÑû÷y»{0ýŠ+l.f¨[·.;wî”cËO`òäÉ¿Ä.D¶róNE{oÙÕ³ ®•ö°ö̯º>ìôzn÷{^ž¢··9Ñ¡Zj¿ICÍñË :âq~QBîÜ©h/ã-»zæ÷ZiSÏ{ÉSl|ì3¯kN £=Í3ö6'jB!’À=‹ů;´Ž×–¾ÆºCë \t®Ó/·»ËMý—#yã½ä雃ßpäâô:ý®ë“È.¹yO޼ !„È7ýN¹q2/c¼?yJ1¦Ð´BSÊ+óÌ–nÉí…€å1XG޼©ØòåË%~‰]ˆ|oéÈÍÃêù_@ævŒ÷×óÁ#ƒÃZ{&GKïo›Å}Ó§Q›;@Ÿtž¹ÿ(⻫ß}¦GbímN”äMÅ ƒÄ/± ‘¯ã-·NKäýâic|Ø©Öûë™Sòô¬<,¹}ÒöÌÏDÞÞæD»[ç-·;Kž° „ìóKþRÃSž4Æu‡ÖÑÿËþ¤SÐëô|úE¡?˜×k¹¦ùK®yB‘¯Ôð”†'qþ/óI1¦w¯e›ÿË|U´ [{ ’¼ !„By;"×¼ !„̰–Ã,Ë~èuz†µ&"$y"ñKìBÈx+€õìÙ '_„~AŸF}l®w“ö”9QN›ªØ!C$~‰]o´ž;…(í)s¢yS±6mÚHü»2Þ¤žªŸgìmN”äM!„B’·ÿn×®]„††R¹reôz=¥J•¢K—.Ù.¤g0hÕªxyyÑ­[7bbb¤w…B!ÉÛ³²xñbbcc1bÛ·ogþüù\¿~^x={öX¶;sæ ÁÁÁ˜L&6lØÀŠ+8{ö,Í›7'>>^z8[¶l‘ø%v!d¼I=U?ÏØÝœ¨Pׯ_·)KNNVJ”(¡´nÝÚRÖ£GÅ××WINN¶”ÅÆÆ*:N3fLŽ?#22R”ÈÈHE^xáEÍÔ¿Zc/Lû¼=Åb/ãMê©ÞyÆêzÿ>_`¼/^ܦL¯×ÈÅ‹0™LDDDн{wôz½e»€€‚ƒƒÙ¼y³üÉû„m,ñKìB¨u¼I=Õ;ÏØÛœhW7,$%%a0¨Q£çÎ#--š5kÚl[«V-¢££12s !„¢Ð°«äí½÷Þ#55•ñãÇX®ióöö¶ÙÖÛÛEQHLL”^B!D¡a7‹ôN˜05kÖ°páBêÔ©#='„BIÞ ª°°0ÂÃà gРA–rl>“€F£ÁËËë¡ß›––@TT”*;ÿàÁƒÙ.½"ñKì…Õ½}ýÞ¾oÏìiþ²—ñ&õTïüðCÚµkÇĉmÞoÔ¨pw‘Þ† R·n]ÆŒCZZ“&MâÖ­[>|ØrjU!„¢0(°É[pp0¿þúëCß7™L–>|˜Ñ£G³ÿ~iÙ²%³fÍ¢\¹rÒÃB!„äM!„Bä­4B!„$oZJJ Çç¹çžÃÕÕ•ºuë²víÚBãÞ½{Ñjµ6/ÒÒÒ(Y²$ŽŽŽ”.]š¡C‡’˜˜h³ØküIII ËeÒïBˆÂÊQmÇÇÇS¡B›roooËû…AÑ¢E>|8AAAøøøͬY³ bÛ¶m´nÝÚë½ØlEQHLLÄÏÏÏîûüqãŒÇÙÙ9Ûë½½½ív|Ô©S‡:uêX›½{÷2wî\víÚÅ¡C‡pss³´•½ÆÿÞ{šÊøñã¥ß…’¼ ûýe}OÓ¦MéÒ¥ 5kÖdôèÑ´nÝZIEÞÿ}«ÿ·lÙ’:uêн{w–-[ưaÃì:¾ &°fÍ.\h5î…¢0RÝiSlÊï•æÇi-Z”Ž;rôèQ222,±>¬=4 ^^^…¢Ï7N222HOOÏvÛÂ4>ºvíŠ^¯çÏ?ÿ´j+{‹?,,ŒððpÂÃÃ4hô»B’·Â¦fÍšDEEa6›­Ê;†F£±ZF£0Óh4T¨PWWWŽ?nóþñãÇ©X±":Îîc}’8ï]óôà¶×®]ãæÍ›Ù^?eÏ|ÀнÅfy=Zú]!É[aÔµkW’““Ù¸q£Uù—_~‰¿¿¿å÷…Qbb"?üðuëÖE§Óáàà@§NØ´i)))–í.\¸ÀîÝ»éÖ­[¡ˆûIâlÛ¶-ÎÎÎ|ùå—Vß±bÅ ´Z-;w.4ãaýúõ¤¦¦Ò¤I»ŒêÔ©„……1qâD>úè#éw!„j8Lž|¸âïﯸ¸¸(uêÔQÖ­[W¨büøã•zõê)^^^Š“““âçç§tïÞ]‰ŒŒ´ÙÖ`0(­[·VÜÝÝOOO¥[·nÊùóçí&Ö²eË*Z­6ÛWllìSŹ`Á¥jÕªŠ‹‹‹R¶lYeÊ”)JVV–]ÆŸ˜˜¨tëÖM)_¾¼¢×ë¥J•*ÊØ±c•¤¤$»Œ?((è¡1kµÚ§ßöÔïBõÒ(^ô"„B! ,­4B!„$oB!„B’7!„BIÞ„B!„$oB!„B’7!„BIÞ„B!„$oB!„B’7!„BIÞ„xFV®\‰V«Å`0°}ûvÂÂÂò½^9Õ£\¹rôïß_:O!„$oB4åßÛ¶mcÊ”)ù^§œê±eË&L˜ '„"ß9Jˆü–W×MKKÃÕÕ5WêQ»vmé(!„‚yùª_¿~,Z´èî`ÔjÑjµ888páÂË6‹-¢nݺ¸¹¹áííM=ˆ‰‰±úž   jÖ¬Éo¿ýFÓ¦MÑëõ¼õÖ[¬[·Ž—_~ÜÜÜ dìØ±¤¦¦>v=Ê–-ksÚôâÅ‹ôíÛ???\\\ dîܹVI`ll,Z­–9sæ0oÞ<Ê—/‡‡Mš4áÀ2„B<19ò&òÕĉIIIaãÆ8pÀ’ø”,Y€°jÕ*Þÿ}fΜIBBaaa4mÚ”£GR¼xqàîiظ¸8^ýuFÅôéÓÑjïþmröìYÚ¶mËûᅦ‡§OŸæã?æÐ¡CüüóÏUûOóܼy“Æ“••Å´iÓ(S¦ [·nåÿûçÏŸgáÂ…VÛ/Z´ˆªU«òÉ'ŸðÑGÑ¡Cbbbððð „B’7aÊ•+‡ŸŸ 4°zïÏ?ÿdÙ²eÌ›7÷ßßRÞ¼ys*UªÄܹs™>}º¥<11‘M›6Ñ¢E «ïù裬þߤIªV­Ê‹/¾È‰'¨Q£FŽõÈΜ9sˆ‹‹ãàÁƒÔ¯_€Ö­[“••ÅâÅ‹>|8+V´lïááÁÖ­[-I`É’%iذ!Û·o§gÏž2„B<69m* ¬ˆˆ´Z-}ûöÅd2Y^¾¾¾Ô®]›={öXmïååe“¸ÄÄÄЧOJ–,‰ƒƒNNN¼øâ‹h4¢¢¢žªn»wï&00Ð’¸ÝŠÙlf×®]Vå:t°:zW«V-àîiU!„âIÈ‘7Q`]»v ³Ùl95z?FCùòå­Êîâ¼_JJ Íš5ÃÍÍððp*Uª„››.\à•W^!--í©êO¹rålÊýýý-ïßÏÇÇÇêÿ:੾BIÞ„(pŠ+†V«eß¾}–dç~ÎÎÎ6 ݃víÚÅÕ«WÙ»w/Íš5³”'&&þ§ºùøøgS~åÊKÝ…Bˆ¼ §ME¾»—„eddX•wìØEQ¸téõêÕ³yU¯^ý‘ß}/¡{0ù[¼x±M²÷°zd§eË–œ:uŠ#GŽX•ß[€888X:V!Dž#o"_Ü¿œFÍš5˜1cíÚµÃÁÁÚµkÓ¤IÞyçúõëÇ¡C‡hÑ¢z½ž¸¸8öíÛG­Zµ8p`Ž?§I“&xzzòî»ï2qâDœœœøúë¯9~ü¸Í¶«‡££ín2bÄV­ZE‡ ³ÜmúÙgŸ1xð`«›„BIÞ„Ý»ÿ¨WŸ>}øã?øì³Ï˜:u*Š¢C@@‹/¦qãÆ,Y²„Ï>û ³ÙŒ¿¿?M›6¥aÆýÎ{¼½½Ù¶m#GŽäõ×_G¯×Ó¥KÖ®]K½zõ¬¶Í©Æêû‹+Æþýû;v,ãÆ#))‰òåË3{ölFŒaS¯ìêö°r!„"Çß¡J^-o/„B!r\ó&„B!É›B!„äM!„B’7!„Ba/þ?†uxçÇh·IEND®B`‚pyclustering-0.10.1.2/docs/img/gmeans_example_clustering.png000077500000000000000000004051541375753423500241510ustar00rootroot00000000000000‰PNG  IHDR¡ìâŒtqsBIT|dˆsRGB®ÎégAMA± üa pHYsttÞfx8tEXtSoftwarematplotlib version3.1.1, http://matplotlib.org/fÿQIDATx^ì œå™ÿŸžƒáV@¹D•""x ‚ñŽÆ$»fãÆY%&s™ÝÄ›Mt³›MLvc.cÿƉYslã…¢F<AAåæžÿû}«žî·kªº«ç¢gx¿|Š·«ê­êžîzëýÕs¼o¦Í ­­­²yófËí:öoùá¶“ž ˜ñx<Çãñx ^„z<Çãñxz/B;K]ÈÒ¥AéñxJÆ7!ÏJ]C,]¿Ô–Oo§©®U^[ZgË´xÚè5gÎ9ñÄ dÝ÷¨OQ´™lÛÖ¾ y<}žÖ:©ßµDNúrâWN”™ÿ6Ó QO¯¦i×¹ó˜Uò«×É3צ¢^„v†U«D^x!xM¹l™ïQ=ž"Ð,´™Ìš•ß„hRO_¦­a¯4?~‰Ô¼|žüê¼e@•¹ö·¾ «6û‹ßÓû¨«k’¥¬—Mßû{Ù¹.”;_h”7WÕÛ×Åð"´3LŸ.rÄÁk-}êñÄ}vÛ¸QD‡U¤ ѤҠ–Ô¸ç¼Bû<žýI[S›ìúÑÙ}ïe×}‹åˆ!dúsí:B¦Iyñ{F±æF³p›Éˆ"'œ¾¹õòâ‹ÁkJÖ•h„ŒwFxʉÊQ•RqPÐíV o”ê™?—Ù“æyêé•LŸ>BŽ8b¸}}Ä”¡2óƒ·Ë!Ÿø•Td·¥áÀ¡ÝÕ3Å—ž´”Õãéc$57ĨZG»«™D­¬Þá)'2Õò¡!2xÁ`rå(ÉÔ ÷x<½ÚÚjY±âýòØcÿ +žºLj;Y¤ª´›ú!B»«grÏK`Û¤IÁkç&®¹³Ž–Q/“'¯)YWµÞá)g¢Uc«léñôv¢'œ0Ú–¡ï‰P×Ü¢tWÏÄyˆE€’aK¾3½«ÇÓˆknIÖÑŽÀùV® ÎOmά{g„Çãñ”?}K„2·tWÏ´n] @¡³½«ÇÓGˆ6·®vFèùÁ}æ¤ìêüCÇãñt}K„2·tWïÔÕ½«ÇÓ )Ö¼]íŒà½ÜgN?ð½Çãñô.ú–M„ÑÞª«{§[nY¼¸k]ýO/!móRë%%u’Dk¡}.ÑgÎ… “ŸA=ÇS~ô-šdna —îèè%éuçϹâŠô½§ÇÓ‡(Õ¡Í&N´Ú%úÌyá…ñÏ Çã)Oú^b’knz1ÆñTH§íªÞ)Úû2¡÷z0’¸Ç§Nmß$ ‰ÖBû¢DŸ9o4îÔãñx<åIß¡QèÅtdk`v#W –b¹ŒÖw{_͇b½§ÇÓG )p©3H„+þØ~ÜqñM"I´B¡}Qô½©£Mš²;ò=ÇÓõô}íÕtPAz°´~?ˆ«OO§¦æLÛ{z<}·I0:™+‰€Ù´)x cÇÃèò IK·IE÷¹”Ú|=ÇS~ô}šÔ«aBqý~îÜqDë«Y‡óazñ¾@ÏFR“ˆã¦›¡ª¢’,–Ú¤ 5¡RÞÛãñx<åIß¡׫a¶ÑiW€¸Q5§PFÝôQ‹jœ¥3Mïéñô 5‰è¬FÆu­hLÓ=ÇSÞô' P$>T!n”ž‘ã£~>öEß<žš@’ñŸ×î¬FˆRW4ªk>msÃŒæñx<½›¾!B]áH:.i¹iˆöŒ˜S¢~>Üôzn7ð÷LêE íóxú4×øï^úî>¬<˹®ù4ÍÄ=/ ÇéÈhÇãéô ê GÒq*I{6·÷ŠâöŒjN‰úù *J—,™1#¾Õ²”ÖãéD/}žݦ§¢”™nÝ&UÌ5=ow ûëñx<žž¥oˆP„#C$)Qz¦4‚P{FJ]w…©k-%¸ØQL0:ìS´t±)3«W¯=ž>NäÒO67úœÇz!¢ç…RŽ÷x<OyÒ7D(‘!’TˆjÏ”ÖdBg²¡tE)1¤î˜£í#=lÛ´iÁk§ã^ú…†Í>ç±^ˆH“²Ï…¥ïñx<žò¤ï$&1DB¡HФ™)©kiÔ*JVïEë XßCz@ÜKÿ¡‡Ú?ºh“‚¤h%®Iéñ”ÇãéôJ/F¶“+hÒLI.Q__’µÜÞPS~ã2,|é9@á’GpžuV` Eˆòœ×h.ZM™$DÙN³ä¼¾Iy<Oß¡ïˆÐ¨˜„¨Þ,jva¬˜B&›(®ÀŒ°qïáñ@¸Í!J"Rîs"%ëQhFÅÏþ¢¡¡AvíÚ•·@SSSY/½á3\vî”fótK»?²Ø¿·ÄczóbÿÞ˜íå´(™6CøÚB#:t¨ì4?Ô!Cì6¸ë®»äüóÏ—êêj»­ìÐÞŠÞ1‰ÅÔ„qûuBw>ný88¿žKÍ1Ñ÷ÄäƒeÔy&ó}•ýwW¦”ëu×FzŠbïÝÓßY´Y°Ž˜Ä!°Ô¦gÁd rü¢[æÍ WBxžC€*8!ÔßÓôŠû`/¥+¿ÛžlŸ×]w\ýõáZŽ;î¸Ã\ó1½§CT±?líZA®ì>ì0™÷™ÏÈ -[dÏèÑòà7Ú:ƒ7lÝ&HKM]çݧ_sMpÌ¡‡ÊŠ}Lv™>૯æî{í470wŸ§k¨3Å%—\bÛhß¡'•¸Þ ÒôpQ±éöªÚë*n¯jÎ×tÜq¾ãê ^„¶§œDh´Y¸Ï`„Lƒ"©/æxÜðˆUêá­Ë0OdÙcQÕ÷À²×Ä»/B»Þ*B±„²(¼÷x#n¶™ ·§ï iỾï¾ûäì³Ïî×±¹QT™~4³~½]m9R2¯¿n_Có¢ERyå•’A8N™"Ía\en>lk57—‡/¿\NûÂìv¥­ªJ2ÍÍÒfö7?ñDpC὎?^2¡‹¦mÒ$iÆ8e`¤›hÜÓ7žé ¿/ídĈ¶öw”¬?õTV€‚ F@ZL?[…˜4b(«ŸÞ.º­ÂÜŒ2™Œ”.P[šý¼‡}/Ž (d̯ÝgDpÕ)§Ø2û¹Êx¸íå´(icZâ¶õªÅüÑM?.Í?lK»·-îØ£Ž²OX@ɺîkÆ*êô¼Í?üa»óAö\~)i)×ïÎÓþî së<‹Õ׊…ž]‘‹]´(_ôFŸÞÓ‡e{<½-O˜ú¤‰+äÙgÃH\-ô¿î¨5”–Î Öjuúª€ƒãÔ¼Þ±CDE0%CxºŒÌ—¾ô¥6ÓR7¾$?’5 ãS| I߯géi—‰åâŽú Ä ÷nn¬sþÀD6m ú¤˜Ðè±Q´?Bprž˜ëvÇEIzïŽÐÓßíDW~·ÅÚHw²?ß;-ûå:¦ajØZ4FǽPº!r¸@x­¨im 7ÆŽ ·ÆæÇbít·™›QÛå—Kfóæ`]9ø`L…"¯¾*2qbp¬~¦èg½ýv‘«®’ºýdÕ´12ýÊÏJíWûËÞpŸrÛI¦¾¾¾­XL T¯Š!éiÌE›/â¿»ŽS®ßmDãYt…û÷Ô©A¿¡Ä…ZS/Xtû'öG×]ØwçùÃ'…yw„Þpsï­tåw»?…àþ|ï´ôøuLäÁª5ë¢ÆßDo Ð8~ñ ‘ù—üãžy&?#’mP^ˆ¨b´PÝä 2󯟓Ž8D&· ”[«O—Ù£¤6oU­kk–UmoÊôÌA‰uº‹ÞpŸrÛIEÚ˜–¸m~ óeV™†C·ßw_Êõ»óÄýܽçÓ¨QÂ…zô@É:Ð'¹®tú×]]W´/£ÒŸ‡~(î½=O‚Uщé´"Q|ôF@`9â‘§G‚hÄ€pE,*Ÿüdþq4ôètڜ˹µzh`AÂgã3&ÅðŒ!«^zÒ Px±r¯Ìoý£Ìhþ•,iÝb§Âë%-›eºÙwbËïäÈæ;e[k½Ý¾´uk^]O@ßJLòx<ûwØ]Jú‘8}†ö/*UHv$ñÈíËššrábqïíñxö#cÆäÆÝOàÀS#O@ãWK)Xãi®¾:(óqƒá¸––p£çzé¥liÿ]»¤êÜsíkûy49‰Ïóýïç[Põ½p©¯¨ºHî©x›Dë/È.ëzgáu”WeŸ¬ uÁ[G¼õx<]‚+"¢I3%)Ú¿¨Xt"ô1EŒ¶³_‡çÅÈá- ÏþöØîÁ‘ƨc±ÝqGÎ5ï >¼¡Äkn.ÔS¡ˆOžpyÚÔ›‚òðÃ׸îɪwÂìÐKœÇ=UÆ’ÓsPFß;!:,ÓO¢’ )±Ÿ,j-­”Œ-]¯6å$SG­¦Þ:êE¨Çãén§ãŠH,¡‘aùbq§¯Rë(}Lã„…í*|©_llRÇÓµh~ùå )1öÁ‘FÉgt8%nú‰åRqo àÞ\(9¸7 J\óÀÐW]•7C5ÙóÄË=G ¡¸£­QÆJ°² –Å•o·RªZK«|§¬«øûl½1¦l‘`x¨&S® ­¡j5u­£"^„zÑã£u*eÆÁ2aÂn©©‰‰û I[Ïs`PÎãø–]q_EPbÀTýeÔ(‘Õ«s1án}ŒYÉŽè˜n¼uk¸’wPî›ðw!DÍqLs׃vêï%v×y¤ZB+–M„%¥{Ü⊠d^åûÚ­ËÌ{H&ÓNØ–JoÐn;ñ"´›ñß]Çñ"´ô¹©ùÎzjlUîù³gWÉÚµùñO –ÉeËšû ÷øI“ÚäG?j‘ão‹­OÝÕ«32mZüþž '¿Û®üni#å:Žo9Ð÷U<å*]ð|3‘‘–®nŒÖÇióhØd­®ײַuV{…›=¨œ,nþpÐzf.ììß«–Ðc¢Â’O\ìX=oÊÌ•«Û±Ç% Öem¯Ëe-ÊzÙc·qÜÊH½R(×~ÓÅm'Þïñ”1™›ºØþ®Z†­–§žÊÈ=÷äÏ„Çè'$±:Z¿©©Zž|2(Ýã©ËÜÎgžY%sæäö»Ç±ý”Sâ÷k÷Üݵ@Üv¿t~éÊïÖÓ½V‰û]!ቓÐê’†a²n#–K²Ö ææFðÜs"‡¨WÖõM²Å‹PÅ[À½^*B„!îõ{2çÉDî1ú¹õ/VL²ÜÙúb6ÖáynÛÝÒ,-rsÅ)òHå;ó„%ã‡Nmþ…æI(pÜ#êE¨Çãé0Ü㇠Ëu<𓟈̛—ÿ×þk%ë@úŸBIHnòQÜþ¤s{<žîvKò ¢£$áE7.xM©É‰ÔGWæ…tº ;šUHÉMD³ê‹¹â{伊ÑrNÕx¹­2F„hÄš‰tAë’vC8m½rUëÃrRËo³ƒÛ³Ìjù?ÙhöEѸÑ/B=O§ˆZ94qÕ¥Œµ’8$íGlâæc<ÑB"ÕãñtÚîŽ>:#À#¢~$¨ŸtRþgžq²XÇv•Ämâ^[š?Z- Îóxîàöĺ”Lz,¬XZ;ãŠïxêñx:ýC;+G„BýM±ããö»ÖOÂÉJõÚy<žôÐÞHR¿÷^FÂÚ “D¸à!´SÁÀ™øPX¬á—1ˆDމ’yäU”FalPÄj½´æmg§Y#­¥õ@ àE¨Çãé4ô… Åú›4Ç»û£ž<\ƒœ›i§Ù§ÖÇÓ9hKŒ”ÄPž„oê$”[¶¯¦gw!V—<çp‡ýÌR¬á—1ˆE†c¢TQJ’îtÐqD7W¾/o;bµ¦ÒŽª0«îyÜô.¬ãÂg>úè¾¾‚¡§GèÊþ&jY%€mLêcC=ž®ƒ‡:ÙŽ2rdø"äþ' ÄŠ2»fâ ö}„(Yò¸Ó±®¬z·µlލèo-¥·Vœ–Üw¾ŠR÷< IVxÑyoË&9¦ùWÖ…Ï|ôG6ßi“™ú^„z<ž^B6jYu­£>6Ôãé<F\îq³ŸÄc3ªP2Æü“Oæ¶&C¸L¡Aìû®…•Ä"$ß×òg+$›T\ ßÊœl¾,¤Lé9áiê20þºpÎy`ü8kioÇ‹PÇ“šD·ZSì}ØNg†õS-«Që¨ õx:m Ë%nøLFäë_w„|ÿûÁhJX:M‘žy&ØÆ"a2nŒ(õ´v‰àÔ¤%¬“Zn°ŸlÊO´ýUj¥Úºë±2¥' LI¨µ´/áE¨ÇãI…vJ¸Õt6½$‘ØÜ÷‰sß%í³Ž–|ØžPñO'q= ¸ãióîxÀ×\#²m›ÈÂ…9K'õ­XD±žºSÅ#@§eÙ.»†[/Ã5’ÔžÉOýøRêKªŒ”~r»œ.ãÂyè±–öµá›¼õx<©ˆvJt6q"±³¸ïç¾+´Ÿ®ló’Ô³ÇS† "Õ­ŽdOw<àõ뱉»=:?¢”} †ŒC¯ÓxH .—Wþmžu!6´¾-;”ºÄ’þ.sŽTJF^—FY ‹å{rJ6žTÝü}/B=O*\w·';KÔ­Ngè{­Û½˜ºöxÊÚI~ˆI„èý÷±¡Ä*cÇæ, MM"7ßlSØÇ%^Ö†=ÉIÏU½ÇºÝ'…–NÊ{*Þf^µÙPâFUˆ¾‘©·Ã6A“)ß)÷É-Kìz_ËPÇ“ :¬q³éÑiu•—YßG‡\Šf¼»ûËÖíG¯UÏž ÷y 1Idx¦Í›¡ù»ßñžî}àÒKƒöèZOý%žqIöüÓUï¶Ùó”Ã2ý²1 Äj¼ç…™ ±ã‹öµxPð"Ôãñ¤ÁMºÚËÌû`=a,B×xH6.èþ^#@[®ê¹+Ÿ"<½¼êb'ÔM.âõÕW¢”Ëå[ß ¹œq·ãvïuˆ=bT³çɆW7½ï‰å”ñE¿.æ¦êph[ßûB½õx<%Cç¢"°;§ÍÄ’¢Ö þ¬Wë$÷‹+øB}¬ªÇÀOϳî¸Ø8P×Í*J¬þŸ(2=§'\ïs[~g3Þ¢÷W\`-:BôàŠûZY$ÎÓ@Á‹PÇÓaèx† ‚±+]ptd¸ý¢|(eãú^»ú)ÂÓkpŸEÜ©p)iƒX<“ðí²t¢C7Úú{;t“Ɔ‚ë–§d½¯áE¨Çãé0t׬YcËrAú®‰Ô´d¤m×>ÙÝÜ`çŒÇ]϶ÊÝòts‘6Ú‹ð"´L©k¨“¥ë—ÚÒãémÔVšNËtXÍ Êuõ¦³*"0£Â•õ>O)"1 bñ’KÂC\`^ÚxOÎE )”…„hg>³§,hh¨´–ÐG â>Yp©Ga€z4£qcï/—K—š¾2™Û̵ûcó0õüóÏË~ð9î¸ãäÚk¯5z¶Ý·dÉ»P¿¹¹YÞxã [–³+FÙi;›ÿóÔD‘§6ÊòÇ—ûì¶[žš 7?}˜´-ß --¹'y^ïÚµ+o[oÁ‹ÐýLœØäõÌ›)'~åD[z!êé DO”ifT¸BW$6•5iEb:\æEtpt³ÂU qñžœC]êL®còP²žDG?³§,àç¾æšÓå”Sª¬Ë°priàn¢Fï©SƒgêEÇ Ž^v=Br¦ù€'š8cÆ ùýï/‡z¨y–Z`>ïT¹êª«d=q†µk×Ê[Þò™?¾]¦M›&¿ûÝïdÑ¢Erï½÷–…Åúdæoä7çÉ¡õáôœ-rÛʉrÔž_ßÏnj0O{÷OòÏ'žxBž|òI[ö6!êEè~$Il®Ú¼J^ØX(Y÷xz3®À|ä8s‡1¢QT¸B1÷}·ãŠ´p}Øš5¹õ® HT¢Ÿ°>jpè@ŽqŸsFã%¨çºÔÏ<3trÖãÞÒ|fOÙ‚tË–Aö5.w’’HP"Cžd$µpR"JÕèÍå¦õ¸$â.«žB­=ôù|Á|Ñü1ï|ç; Š0ŽS^zé%k-…={öX±ºuëÖý*FùìÏ.Jš^Øn 8¨±R¾/s¥&|J0`€ <É#F÷í ÜL”îߨð"t?’$6§™.GŒ , ”¬{<½µˆÎ}2Y\²ŽõsÙnÓ&ög|hT¤™{ÕìÙ2ÿÚkmÙN˜u†B½yôsèûºÖHhMM &Ü:…ˆºÔ_}S‘ȨQÁèägœ(Žèû*ûSx:ÅĉmRYÙ®¨ezN\ô<_`éäR=:¬d`púR.³î‘5fÌkí<—±£:ÈÈ‘#e¼Î1jÀ’øàƒÊ=÷ܳ߄¨+(£]u°Ì1?áX©‹hEŒ"J!“!ÙìET:S„(uâ:}oħZ8)‰1Óúî{á‹-‡ÌO·ð‘<)‹5ÛŸøœs ÿÔ¬ÿêW"ŸùŒÈsÏí¯K‚kÞ<@ÉtÓ/µ—îСvG‡!ÉuÇGÁ’ˆPíi¢V`‚sÇŽ‰nz…új íMxêñxŠ¢.xÆûL²djbÖQDeœ¸,$P÷ ô²‘¸Çã¾÷=©"i'­ˆ¤ŽZ>ø1¡&ïÙ ±‰€u³CÜs"DÕ-Å­§Ä™³ô½ô³ù¸Ï>—ÌìÙUò…/œ&W^™k`1—º…ú\nï|§È×¾&rÁÁåѳ—„ùbÚ›`½2Ý;,a6φâüóÏ—n¸!k9LâóP§b°'qÝò”|°uÉqŸÐ¯_¿¬»^ill´¥wÇ{: ™ò~œPO9àºàI*"»=*Ý:”Û̽°#q£IµȬ^-ƒÈÌ€4"’NÀµ|2Ù¶v”LG“WDbÒìè”6QQÉg@»õð½ºnx—ègî%™'\Fk×"†²Ø%Ì~5œ¯‹Óõð†‘(ôg? WJdÔ¨QE( êöÇðMê–' ‰’uñ‰»þóÔp4¡8Þïé’†nòxöQ<ÏG…b´Î¬'r‚´T!Z®´M›&{4U8MPœ+)-Ê‹3Éjï¥"RáœLisË-ñ¢Ò”XQqÕ««´g>uT¨RF?sÏ+O7Âe4eJà²4©Íæ§zΠ¾Æ‹¯‹]ö]kñO¥§žJ¶¸’\ݧœrJ¸V,¡¯¿LŸÙ“ <‡ bK’\÷<ÛÉ‚w-¦³fÍ’cŽ9FvïÞ'\Ë/BËî'Ô[X=¥R(™HqëŒ7ヸùÅAÛÑÌüNcÞƒ7Þ(Í?oEŒâ GÊ /Ì_ëÍQ¸ÚÕÝ®ð^ˆÈqã z_f8Â*ú¾÷å×çõwæ JM{§øZYÔòY̲ÚøL¥$eyº.£Çþ²[þëÿ#ýd_Ñá–¨Ï3 Ï8,¼.vÙw=æAKâ<Ÿ…ç$’«˜è«Wq±|è²ØY”w¥ÀlDû“¨{×¼~&×bŠ•aÚ›ð"t?QH v×8¡¼—·°zJ‹g±XM·ÎòãÍu[D´v„¨ËÑ–ši›3']OLĪfrà?¤¤Çüçnßó³Ž D°ðšm,ˆ7¬ž›6…• ïyOÎWJ<(3(i}”UÝÿ® t­¯çP¡ê~æ®Rú™ú˜›«bÀ]€¬ær\êÍç[~ɻ䈅ÿ&×4½]Žî¿T6¬Ý'O>¶[^â »?zLuu“œ|r°ð:º¿»—ææ “? .Q’«¸|¹l7¼ÿòýÚ÷ÈïP&g‚ Ñ#*FÊ=u‚|ã¯ÇÉðþ¥‹4\ÛqŸ­§–ÖÖVs;˜a­œÌôD–¼ÑÄ~„)u´>èër]”L[$ŠF4tèP;ö”>-pÀ]wÝeƒy£°žÂÄ}w*±r"2ãÆ¥PhWeÎ#z  CC‘™_®”ëu×FzŠbï].ß (´«â;±€"@¯Î®ÔtÉwËl&˜l̹ÌIDþð‡À§HOŠÐD¤¹`~ºâŠ ‡ÅÊí¡È±œƒ±jÜx5zaÜvˆX…é\ËqÇwXáRvlØ ßúV¸ðZë89¢^*ÞÜ&mæA©íSŸ"ð0ØI¢ qЄ¡è¶æÐC6—Î×õ"4UˆLû‘íÁŒPum²ªy³L¯#µ™àó?pÍ0ÙvDi ×$.ðr@Ýð ®wwÌSö—û@õ$M]rÉ%¶zÚÍÄ}wûK ¦¿åD¹^w^„ö Q!«–P\ü dÏ8¢ ãÔU"·]òÝþøÇ…Ò!ˆP$ɀɼÕ2ÉLHlwg…a›;_<Œ 2ˆÄes«ñ¹Ì|À{!fÕ:ªÛ‰uÅ*VSêtVP¹Â7FìvåuÛ“íK¨ŽÙ¼7Ãþ0«OOßÒвoŸ<ô®wÉ>#F“8é¿a3fغ›ºu¦ní„ rÊo+•¡K¸'Éd®5ÏZ7†kxÍ\OgƈæƒÂ ñ<øÑ¡²õ-Å“’\N5ŠÌ°´?AX2½(IRkÖ¬±Ã1‘)¯nx’¨Vš¶NIÝ9sæd3êË ÚÉóÀCõîøý@w¹Û‹àLßã)'â\ïêò_l´ Ì7:f¹å; q¡Q‘…`Är©s&â®'ö±ùä2/Ó0*@™·ßžKLÂe¯nº){ˆ@×Õ $þS÷SªÛYWјÖ}ÎþBñž¼Ow¸ù÷3d##6ÝÒå¸ô7ŸïT#&[?òŽ‘Y{ØaVdÂÀÃ—áæ…ºûÖ¯·(÷<÷œì1×Wƈ èy»s©ªz«ý ±Ô,ò¯ïy÷‡Eæ|¹¨…ÖªŒlÉÔÊ­ÃI {qŸ­§¬°O=õ”¬^½ÚÎw¯¶CJ%ƒÖ»C4ñ`w®rY/B{,‘XA!N ê~Êî‚÷òƒã{Ê „¤›pͶ×ä&„hs×bF%èêħn‡¸ÐÍ›En¾¹}Z¯Æd–‹ý¤Ü³'¦=”› ñÉ6ÀRŠËxÙeÁ6åC ’œ°tºâ1K )á”Ä”Ÿë§7ªÛ’pëÔ©Á9ã@x& F™yüq©t,ŠžîÃZ3Íõsêï/§þßÿÉü»î’ùü£}=ïªÐÚ9øÈ#­(DêSŸùŒ<ô·+KÞþvi.2pz×r–YŒØtYy’ȟ̃Óÿ.ùÕéæ!ìh‘}Å-蛆×ÊÇ=[®qžü¹v’¼jÄhz:ÓK&âRÝênv|¬¢LãéZä¥i† *¼í!êó“‚Àƒê*÷ICž8«§›mMn*´¯¬H²"D¯¼2vX0C+”¥¸¾YÜ™\æÒKEN7-b‘}XL«*,Š 21x°®`ÉÂÂI@Tôr.ŽQ œ[?nsp“šâp+çÒ©4„¶ê”Säôk®Iœ§Ó F‡{¬,úZá5¢qzìW¿*u/¿l·ï}é%Ùm„OÏaúÈæÇDZC¹Â¼÷«Ýz˜ù#Œðü'Ó>Þ³ÃìÆ?Mâ#@ýÆßËêA‡Hc¦Ê.Ÿ6bô߇žf­¢QA>KíÀrÐAÅ-¬]Âó‰'žÈ&1[nõBBZåÌeŠå֥匡=ÄêÍ« »Ô•Ã2õ„EÕ㨳#ÄY=Õõ—‘_h_ÙŠ«‚îl,‚Äfb¬žÔcûr£ÈG ¶1Ÿ*0zÏé E\ýXHã@¬Þv[ÎÕzŒžÊûòþ,iÝçQÑÌç+d9uq,0!€§|Pq:ì˜c²VÑþ£GK­û{÷Ûû‰Üùq‘‡.ù…)ë‘£™æÆqpá寿h޼9$ÿ:Fˆ>]3Zîx¤¤_vº¥”ñùüð3eÄÜsó^wƒÕS§èÄú‰žyãÐvš€; >BÖVïÉcÚ˜iã@»*NÔ[T==Eœ3‰Bb5ɲ‰¸Lš=‰mÔC°vFw®u°;KdS8\ %뀵AvÈ!Áº Â/*9†$$„& L ±WCÒcÙ<ÿ|þ1z&g]áüqîó(ìG¼ª0ÑÏ—GH3xÊ\îÛ¢DŒžòË_ZZoþ»¿ëY—üpÓ*5SÇæ P!úϯ‹|x›Èá2<'Ê++ä×''< … HŸë7ÊŠRÊ=ýewÍÁ2cHÏ PpÇU¥a¥,”©?Ù<ˆúÁê=í¨íW8)ˆõBûÓÒ•U§qÌ8Š‰ÕŽX6‹s¿µRFEO\õÌC¯B‘ˤ‚ ¤Žv8Xc˜dÀ#jÕjê EJÜôšÀ„°%áéÖ‰“FlºèçW /Ÿ[jâõL}&`"€’>ƒ§Û@`û鯀ÖmÜh(ô¸K¾Ê¨Ìw|ÔˆÍ|q–Bt²¹Þ§†Ë§(5b´ùowÈÑ7]ÜÎ š†ÛyÖëa-‡xœ9s¦L™2%›ÝNù‚y˜%Ù1˜dÇ╬óÞ„¡=²PRP±ýiØ_™÷ž D_}«¹ç‡#€ŠÍL#V¹Ñ—2g|Z¼ßÅU¬(C¸©«þ¬³˜Ä;Џå£ˆéì¥Õ|Ñ î6²è“Üü¬“À nyÊ$½”Åp?¿ûøK³`ê3xz†`RKg&BTpº‰J”¬÷(ýÍ æo>)R“p£‰‚.3b´jî>9µ:+‚‰ærÇiioËÐn„xÌÙ_™-×>|­-{*>³˜E•Ïá—<ŵB®7÷Ê«Œ™û¤¹®\âÜÈ»:‘¨;ÎÙcsÕbQxÕU9w=Í·½-ß}è¡9áÉPMš-O‰KÞÍžg.y™”zœ[' Lóù=åÍ–-Ù1@±tnþãó¥›O Û–.•‡.ºÈÕôÀé§ï§á𠏿Ç)ò·Ÿ4×ü"o}Ÿyˆº0(c g~LÛî`%ÃkD¾o.åÍ'‹¼Ã< ÎÖó÷’‰tN…a–ˆe†$uÍ“ù…m ÕDV½ëÔ[ð"´!síÖÀ¤NYñ™OŸ¸äé ®R)æç†^Š»= ÝqÎN°KãÖÆ2šäªW\k£Æu’t„ÕT;)ÊE‹r"ÒqèfË#X¦I­ÑqC!­ Lóù=å îáÐ`™ª*+,]AI©.x`ß_ßûÞì0Mm:~eOdžº F(rØ[D¦žd”¦¹ÖGÆ5lª,«ªcü Ì)°z®>Á<ï„Vî˜=È ¸Õg1Ü™ŒùãŽ;Î.Ì„t¤ù]N8ᄬ«^¯ÇÊ”˜½ /B»â1§Œ Ü”åŸé—<чõ‘›wš˜ÐRÁ¢ÚÙaŸznü¼´nm„[¡øÉ¨µQç~g–#×Jb“óÉX :{’{níÜ¶Ш›ŸÁóK”Å>¿§¼é×ÏNÉk½-Œ5VA‰EtbéüóÙgË›æzÑøÐ(dË÷xlhš¼tv˜Ý´13XŽ=ôcÒÏŽú™›¡œ|÷{fˆ¿Ln8å[–C|¦O\òtÜ´¹y¯œÓµ.q7M›õ^6‚µ«ã$éH⬌êZB±Œb!Ex²ð¾óæõyµv"X±ˆâæwÁÍïåƒÕ¹à‚v±Ÿ;Œ¸QÑI6üŠÏ~6;.è#Œj1 @çýþ÷Öu_6Xëè$©ø›OHýyWɆóÿI~9³F~¸{‘¬Õ,ÿ4Väëæ9nË\‘sêš{VW€ }“Î’²yóf;F¨Î”„•óå—_ÎÆ~Rb!ÅbJBVÒ^™˜D,ÓC¹ `v—¸m~)¾TgªåÈáGÚ2nO/ÕÕòøç—‡¯}Ø–¬ÇÕ+—¥\¯;O7ñb.ñR„b)Yl†iê©8ɸ÷A<"ûì²ý£ÊÿÝuœýñÝÑÏ­^‘iÓÚûwÚH"´T1©tD(ò^Ëv‹,xNäÅúä÷ëègê(=vsç"$“·¹‚[žÌ®€ó#Lq«b%)I€jÝŽ k¬–ÄÉ* Gªï6å¹ö§ÜŸï–èw­1 ˆÊÚÃ#ÕÚfΓ°¤ñ¢J?sÿïä U¬¨LíY®ôX»í$Qf:b=aëÖ­6þÓ…¸ÐÙÌ~fPáŠUT]ñ½áïuÛIª›Æâ.À‡w—¸m~I·øï®ãKO~wMMÕ2gNµœrJ•-Y«ÇÒS¤ —q—bû;²¬ØÙlÅP²W/ºÕ¯I¦ô(Y«·³¾Iy³Ù–Õ­MRÕÚl(èû¹u8†zÛ$Ïh¶%ëÑóvõqÛ;µ˜qó#Ø’¥Ýжð:k›2EšŽ:*þØŽ,æ¼MÇ'M£GKÓßþ­4›Nξw´ž~#ü(cë[Ìçæó§ù; n{v)ñ\žt`ÕP²ßýêWó–²TTÈi¿ùGÞŠU%ñ¢IƒÞ{Òƒ}öÙgm(ÉH€µS“Ž˜éóÝ«E FãC{#™6Ííqª Ruox’(Güw×qzú»Kih‰m#ÝÅu×]'å.Ó •rÍ ÓeKå 9´e|tß“rDËNkU ŽÝP9X&´ìŽ­ïž{´9÷{´ÛÝm_Û³D>3h^^ÎUìÜåN¥yÈ8ýškdЖ-vîô'?ò9í _÷Š,ÿèGeói§uËlBî{×|°<øÍoJ“s=3âdþµ×†k"‹o¸Avt š÷¼aƒìž0¡ÓGšs•s¸L9½¯º–Pu¯ƒnS2••rö£Ú8ÐÅ\`­¥6a Ë©¯š¨TsÐAáåAo胠KMÄ ó .ùaÆÙ}®ËÝuÝ3>(®7[B½ífüw×qzú»Ãó˜"ä¬G;,¡ÅÂe\øÎº+„÷÷{2òÁ*e]CÆZ6—Ílî´ ü/;3ræ*M À²9gp›}¿Õu™VÛfËSVæ×aûìU²¶¾ë>K!:ýÝš ,³zµ´M›–½°2?.U§œb_Có¢ERyå•’Y»ÖZûš±ˆtÕÃFäý£ïÝ6nœ4ãz×÷3õ«fÏîØg‰ù[ Ñ•×-m¤\ÃeʸûªÆ„êÌHÐðæ›²ú+_‘W~ó»Gñ‹r¹I2|S*D™gÞ=×þ¤§û‘ŽÀuÃ0L.ŒÿÉðKÑd£h]í­1¡~ˆ&O¯áÈ̃,¼î ô•Ïè¨8û“´á2îRlG—¡ý«eP¿*+@ñ÷|c|Ý´KSEµ|hmN\’Œ4sh•ÝÇûÍ=¨Ê–l#î(Yç½ù П%ÍqÛ‹.¦c¨ž3ÇŠ>J»n¶WñÔØ²ê¤“$óÔSö"¤¬67êvçêÈóþö½Ã¡w ³i“T?ÿ|îóÞú, k±â¶wdñ”b‘¸NˆÒ‡ÿîïò(¬ýÁ¬õS‡ub¸¦~F() é´øÂ ­HÅZê]ôé Î3:Ò /¼;QuÑSº´7âE¨§×‚èÔ™YxÝBÔÁLWÏÙN¶½Æ~ÙðqÖL¶‘xäŽIÚÕŸ¥[Á¨锬CÜ“Ow\„qïÏù—/Ï QÄ0 H.ù,I«§×àÆ‰º4¾öšµr2‡uæßRóR_7T6ØyâUˆ">§›Î ë¨fËG…h_Á‹PO¯…¾Í±×qý]1+§÷Fã}Îx\äÞ7‚R×—ìèœøCx–:ëRtf¥YOŸ‡ÏYÖB´;,žÅ.p¥»Þ?Žž|/O—ƒ;žŒwhغUž¸òJyì°ãƒ>xÞyÙ}ÀNKJ9ÿ®»¬U”²“Ê›ÛÌ¿™æß‰æßŒð¯ÙÖܯYæÌ™cÝì Ä•S“Rq×ë¢} /B=½ú¸¸ úåbVNï=,Œ+øˆß<÷é\'%ÖHQ±Øp.Áú>®|ÈÆp>'Ÿ÷€!Íîñ”.wb>ó-qo¼a‡kÜóX;I@Ò±Bã’œäqDžSÍ?Äæ,óïó^ ÿÛ–™OT>!UCª¬e”×õNÀ|Å‹POŸ&•ñ꽇ɸ‚/ ij¹Ò®¢Q«'ïöGŽ ÜøËÏ}>ʲNPêj¼ßÓ j‰D£8ÚŒ tå•6A S”ŒxJWlòZ÷-:÷\Ù·3˜ƒþ@ (Âs£ù”ãÍ?˜þÓ× Ì?×BzÖà³äƒ³?h…(îyE©¯áE¨§¬ih¨”ÇÏtØÀ“ÖʉðôÞÃx4n“ †PÊ{fäÖõFtºRÄbWàŠ`Þé<ºsŸ öè|¾®J–êUx3¾§›`Ðù·Þ¿+þ˜/9ÜšcÝ~ ½ûÝòƲeÙLzJ\ùŠ›eßøÊ+òÏ>o@v…m/™zqûz3«Ì? Piþ=dþ=fþ­ ÿñúVóO­¢®…tã€Òï¸~Y÷|_Ä‹POÙ‚ð¼æšÓí4ši=ÔqÃ㼕³k@ØÍ&²rN ö(Ï9(·ŽøëßM÷HWj|N躮wê‹+í“ø ÜÓ`ažÎÇýÍßdÇua¦§>ûÙpÍ\~‡f]ù ¯«ÇŒ±¯÷škóåæfÙ`ŽqAx~å+_‘n¸Á–½Yˆâzÿ±ù÷²ùG è$óO-ŸÐbþ½jþ`þÕ†ÿx}´ùWmþåDóŽ0ÿNtbŸ àE¨§lY½:#[¶ ²¯ÓxžqáqôËÞÊÙ5DÅž»ÎðJ®¥´ÐpK,ø›ë :Óù€s½'á/pO7cÝóøƒµŠ2d“⎠Ì9O]µl¶ñ4ñ¦›äsS~hî\»eóæÍvt d½\Ñ#JE·!<ǘ¸Õ'˜¸Öçš÷™X@‰0žgù×dþåmæÒæBµ/ãE¨§l™6­MFÞc_§ñ4úð¸ý BÔµ”ªPí ܸЦ6‘[ ¬£]ù'µŠž~÷ÝVŒ²Ì[¸0k!%‘ið”)í,›c'N”~æŽ9r¤LÇê2Í$Û’uµ†ª˜Õõý F¬œšÍNÉvþi¶ûóO…¤BÂÑ#æP`ÿ3æŸCÉ95ÿªÌ?@¨bUki_Ç‹POÙ‚açÆ”‡nNåiôáqû×2Ú•¸q¡”òÔãÙ¨e!nTgObðz¦úÜ´n]žesÛ¶mò/ÿò/ríµ×Ú²_¿~vŸŠÕo~ó›vý£ý¨“õÿøÿ={öØ1{Ýu×É›o¾Ù#‚TEgTdRºq›d³ó©Ùî[Í?’ îô Í?7 ôÍŠ?Õük6ÿ¡Šeô@Á‹POYSSÓ"sæ´¥ò4RLJÇõMœlò‘ÇSÆ0c’ΞDÒ #™Ï(ÇŒc…çᇞ @l¨ŠÕ×_]Þxã +Xuýž{î±%ìØ±C¾øÅ/ZAzýõ×[êÒUSw8%D'Qã+æŸË³æ®u„&P"NI2Ú`þ©;êÍ?+§{ ¸ÉKÄN7ÿ¼õô 4! |x\ߤ»¬¬§ã|¤.yʃ¦M“ÏþóÖòI QÈëŸþô§á³ÇŽƒ>8\ X´hQø*€é+aûöíòŸÿùŸÙóQF›XJ¥X=g9Ã)©øT¡8Öü;Üü\æW™Ô¿ßüSÁy˜ùw±ùGò‘ IꨀE¤b央3ÛüÓ÷@€.7ÿ7¼âE¨§×“”äñx<žîE“–˜%‰’uµ|"±\"q­?óÌ3ò /ÈÚµk³VNhnn–Ã;,Z „¨&0E›°°FEi°zºÉCÌ?¬–Ät"’$}ßüÓØOêãJGp"£îûè9ÕÊ©Yñ”üSQúœù7Âü;ð"ÔÓëñ Idzÿ@xº³$â‹%‚ßýîwmÌçM7Ýd·)¸Û5vô“ŸüdVŒ:T† b_tÐA2hP0ZŠºùÒuÿƒ+J·„¡…@<’Õ® 6_3ÿ°bb™T!‰%3cþaUØGl(¸1¢”$!ih!+§+J4¼õôz|B’Çãñ”X(U€FQ×ºâÆŽanâŸþô§eøðá²sçN©©©±IKŒ•I,(Û?õ©OeãK)]÷?Ù÷®(~4Ä£&f³#0§*$Õ _cþ©E\ X9ÕµNÝ›°Øü;­œið"ÔÓëñ IÇS^¸J,š.ôÀâ‰åñè&-au-¨ˆQuß³]˜¢`}Eü"R9ï?üÃ?„{’Á Jâ›Á>ÎüSpÓlÄ?uÃ×É:¡Êx œK&1¢—›ZqÛßü;­œið"ÔÓ'@xjB’&)ùØPÇãÙ?¸Ê r®n¸úꫳC6aùt(¨„Ū”aÆÙuµš*OýÜç>g˯ýë6ñ ×?ë--e3ŠÆpÎ7ÿ‹%Si>iþ!0Ë&ÉC$©•“a©nz\ïXSÉ®Ÿbþ1k’BÝ)Û½T¼õô)|’’Çãñ”ˆK”¢.ò)S¦Øí@¢‹&Q~ãß°O„'®û›o¾ÙÆbQ}Ï{Þcë)nb’ŠM¬¦j9¥Ü½{·}킽ÓüÓN×b‰Û÷¹;kÿHRÂJéfµ«Ð\hþ©¾`þéñžx¼õô)¢IJwÞé…¨ÇãñìO¢q›¬#6ɘÇZéPÿÄOdE%“ñCÜò$7¹Yï®Û_ÝüZVÕÁƒsssÜs/='³gÙxOb7ÁµX"P±lj&»nÃíÎ1ê~¿ÅüÃzªB“éõ|”Ÿ0ÿ¼-LçDh«éÝ÷- J§ p“”ªÍ½/·ˆz<ñÔ5ÔÉÒõKméñt'jU×;LµV¯É¦¿ýöÛmàŠGDFÑ¡˜ ˆÅ}Õ” z7ñé­o}kø*çºÿö ß–Y_™%UUÖr‰u! KÌ?žW=b¢™ï³Ì?ÜøW˜ ÔÍæç£ô‰HÅé¸Ex®7½û†ƒ²³BÔ ZO IJ·Þ*ÒzEü°M]K[S›4¿ÒlËNÓ]í>Íy»ë½($øzB F߃ræ¿Í”¿b:[Svç{{O_¦ ²k×®¼šššÊz)—ϘÉd¬‹ž…ñ@ôŸþéŸlÉ>·.âQ3ä]ØŽU•c>ö±eÝ÷”QW>.ÿ¿ÿû¿·ïñ™OFædæÈšæ5Y˧2¦mŒ,j^$7=.ÕMÕÙÏÀë㚎“¡MCí¾‡›nW§ˆÛ^N‹’i3„¯-4"ž8Ö™ 8à®»î’óÏ?_ª ´S¸sóF€VÄôòzÃç&PhÔ@gêõB¿;OQÊõ»‹k#=E±÷®ßP/û~²/\ ¼`°T­ ×òA"$+GUJ¦:nÍY<šUÈ ±û“¶Ç‘X×mï6ˆßÜâÚ}ôþb3baY5ΈÈ|«E–ñ‹E^½"<¿ÃóDˆU—”÷œìõxÞéR½iNpþ”Ǫ0C"øV|q…ÔÖÇÚ7òØç“&ž®%ïn?|¼lܾ1ï=xo¤î{v†¸ÏÃù ý]ÙÖ{²}^wÝuvZÊ(wÜq‡yðíšïÓ“ƒ˜Î¿þõ¯R__/ iÓ¦Yaª1¤€+ŸlxMFâ:Xµj•µ†ò›Ì;7¯~Ceƒ|âôOÈ«ƒ^µëÕ$7>x£ iêÙ{ûD]]\rÉ%ö·éœ-–÷†O'0 wó̃  ˜íE¨Ç‹Ðнwc]£¼þí×¥¶)h?Ãø»2' ]ÁYHPb½Ä宸B6zž¤m‰çˆÞ½UdÈŹ6¯÷‚- keõä N[½È¦sƒ:P9Öô8¯Ajöó–ˆS…wg» ઉ¦ÇùŒyï‹ÌkÇbâŠ__7µTÛëñ‚3FJÕ+§ûÀ½¯E…³C!ÁWl_!—´?ºýþº_=·H.œq¡ŒÜ>^­ÐgH"ÏCBBº·ŠP,¡, ï=~üx;˜zOßÒÂw}ß}÷ÉÙgŸÝ+û$„(1 Ì„¤IN…àï½ûî»å裶¿MÜ1$=‘y¾>¾íø^ÑÞ~_Ú Vêî¡Ör‘ÒÂY¬n›{9Ó•7×rýîz²“‹Rì½í ÷wËY3Î’ªª*©S•(8…„fg,žÐ¼¹Yöþ~¯´íhËÃÛº»/J…­Ft*cï1âqX¾X¬ždŽ]—»OÄÝ7؆@}ÕT+\C‘ËÃ/dEj¾¸m÷¸Üu÷ƒÉ–PB^šeÊÙíuM»½aÂnÙó™ÍÝzöá³Û+I@êöI#&ÉIÿy’¼øú‹2yädYù¥•íê©pÄbºü_—Ç U—8±é Q÷ó;W¶õrnŸåÀÖ'ù¿·üpÛIç†h*7fnÐX ¢¢2 …v<”¬+Ú1iÌë'–ÖŠV©:¬Jª'Tg…#‚‘”jµD4%ë Ç!&¦…(DÏÝôr“ì¼i§ImÛ<ã¶¡ž”B÷÷>ŠõˆOÍY U€n˜›ŸàÜÔq߃×ýÍûq ”Ĉ[ºãöÜûcAÍÖyA2«ƒ×qŸßÞ£B ¦~ýžeVxa¤Dˆu†+þç ™ÿù±çBèaYt…%èög6?c(P.{)ô:… ˆ€ËžÒbŸ×=†’u%úy(±Ä2ä{þ¹_ÛéïÃãñô~ºW„B\'– ¬@©Ö ($P=OdÇ·ln±JÅ Îá¡à4¥ºÍÓ ÍBØóêÄ”ÖúŠO ´©´mÜõY’î y÷#4­µÓ”vÝlŸðH`µ<üÑ`[^–»iïîû(ˆÎ­W™¡õ ’©5–¶ZÚpß+ÑÏÏ{µ„ªÆËªm8ƒ¨H+•¨à»sÙ¥‰¸èOYÇRZY‘{A(û¼X9±€%ëIðYOýÚ©òÚ®×ìzg¿ÇÓ7è~šnæIÖ‘BÕãñdAxÎZ3Ë&'á"w…¨Z#]«$Â|T€ª‹w=VÍÖºÐÒiʆ ÙuhÝn^ë*en˜¾¬Ø‰ZZÉ»¬|ŽQH¦dºñ¬ÀþÒIFtñéf¹#ø³»Oð>œoÔÍFl:âÒÒ„j7çÛl^7›Ì¶Lóúðu î= kí!·ÈÑ£N-ÒŠH¬®Ì¹Öܶ $ëêì ³eÂÁìkJÖ]Öm['-­¹‡\æIŸ—÷$ùpÁßS­G‰àDØ*…ÎïñxÊG„Cœu$¯cŠTÇ“¥õõV©m Ú‡ºÝk$P6®n̨Q\;VÍ]?Ú%-;[dç7wJÝÂ:["D9G[só ”™áòÌ ÉÈuÀÒJûFÔa]t]êÄzª¥Óu•+ˆÀ×§»Op^\÷X>‹+–W@ȶcf©š,mý¦…+1è=ŠÌüL‘WΕÚÍseÅIi¥€HljÉ k¥XëëdóvDµØ’uת©1›qŸAé†Çò9\A­‡ˆNs~Çs`Q^"´ÚêX<žœŠ‘R×/®õÑuÇÓê’Œ!š4 ½uש D–7–N0eã³ÖZjc?Í¿— ”Ú keÈ‚@x½z¨T­Ì³´ò^yã†"£ãmÚøÊ˜p„iE`Ík®óC¾ÜÒÜ'òB|Œ˜%Á Ë+!«Uå›lLhe&— ÝÞ“XSµÌšó×ʺØXÍRAè©%S!Á(5Aø­Eß’¦Ö@ÄR.\¹Ð¾Vø|jÕ|îËÏ%&%!6ݰ’¥f\?ÊMJÅÇúÉv·"šó/þÔbùé?•Ú~þ>îñxÌ-3,÷qÇã鈽åG.—ïÐÎú˜uÇB7ºÐ>â¶ŽòAs|(D´5³jrw SV «ÈYK··IÝêìùvÿxw b#–OÞC]üö=öÆ‹Í{}S½ÝG‚ÓØaá°YX?ÏÔµ¬F­¨iB <Oߦc"Ô,®…Aoúiè&וÇs ‚ðŒËŽGD¾<Š»Mó½_6v³#Ã3q^ÎûÁ¹çöpLÐ"ýÏºbñ$vT- „ظQ󞈴æ~Ë¥mŒ¹—¨5Ò‹YªÌqjm †hšhê½raÿÚÕæ¹±šaF»ŠM{Ÿ2¢IJ½×ð¹&šÏYXgÛªxVÁ\äá;jý#3­5P,âoý¹Ìü?}üOrØÁ‡Y‡°TþÈßÓ}n2ûã,±qÛyÍpPêrįºÔËè¨Á£ìk\ðÄ}Æ%b±®q§qû=ÏGé"4*:‰×ŠZÒboî\b§$’²ãP×eÞòz{|Zò²çà´Ã4Á^sKøÓ¾\†¼)ë ¬f€•´ß´`Úl•,Þpƒ4 cTS<|G­Äbê:‚ ‹bT *®€U8öÔ#Nµ¯qK\óŠ;¾§+ú4Ùˆ÷гįm×mÄwVUèx©9øl¸çÏúï³dëî­Vè>ú¹GeÞQó&Û»"QËãñô J¡®¥BËÎX3é Òd³z<ž¢D³ã}›i“…Bq(ÃŒðXX—Kr\÷ipÝûœ338gImÛÝ&/h­¬”LÛ©`ÅêêŠØ¬XFÈqaüNLtØ¥Ž(5tâòà^«J,é$#PõÁ6*VÉ^ )%Çí¨?28>zLxøv… %Bk!JÒql’…‘ó­ºnUÖ"J}×Í}Qˬ Ö¸íî¶æÖfùþû¾/÷|âž¼„#ÆÕ:`,½q‹ÇãñÄQºuoþ”ÄKyk¦ÇS ð4;÷;™ê®Ð4r1¨×’ÉZ/£SŽÉR)„÷Á¥n‡bºrhàÒw2陳žXÒÊ‘¹¡žt;¸"–²rDCNÊ}†{ ‹Þ_&=g-’ÁAÎöÃ0„ºãk‚:ú`½_Å=$G¥›ŸDšó†D… % =êâvÅ  õTÀ2×{’…!Š¥“z¸Æ9W’ŒZfU°Æmn{ÿIï—s¦Ÿc?‹ŠjbBµY÷¥¢ïñxlJ¡îÍ_E'‹·fzSÿxðô¼Æï$ðŽqÉAi†xŠï A÷Þ+NغâR³ìãê²o̧ÇX«'%BôâÙÕ¼ï’ç—ØLÿèçöx<.¡§¬!A)Oô©ÓlÒìt¬—ˆ@ê©XÌdoÖ£¢Q‰çŒ¡Ëݬ» ^³®~]!Ë"eœÐsÅ+IK‡=ÈbBýîù +J!‚O?ü;h}Þgàý’¬¸ˆ <Ä̸ä Ý–4Ä%¢P!nS…`Üy㈊Kw¸'â>ÕêIÉ:Cœ¨ÞÏñôù6–×lc‰ÓçÀÁ‹P§B‚RVÏÍçÎ6²ÓÕZ ®XÌc€HfXPãã9#âRá=ò\îÎ{ÆZS Y£BOã6]ñ:ÁЗO-n‘d{ôüQÌz¦íÔoK°âŠM+ÉQ@'`Sà&©%3ºíŽÇîhW(Ýa”(^…`ôXL㈗QŒ<8\ 8sê™¶ŒŠj%úÙxÍgÈÆ‘¹ì=Ï¡O$O^9Ä&ʼnAкXH]öýß>ikæ„çx=.ïÜ1âÒMdbŸë¢öµ›=ɵ¦ÆY­Å3!nÁÈ~bC›C×¼+£Ä Zºœ'F€B[¿i²§qt°µ–ꟗÿÕ–D\œ¨» Wù?ÿâŸík˜8bbÖÚ=–âöiF;`錳>2|ÉE7µ'Ç ßù½w†[^Ýõjø*žèûÛ׿òp…ñêÍ«íkÇs`Ñ{E(F ‰φ+ãÄ  Û­…4LVʲLj?Ô¥—q±¢.¶ÎbfOr­©Vp‚*+ö†…â6ywŸ`»Z.aó%"ë̶bTó|éFiûp¾µÔŠÚÐÒGé~®â\Ñq.mwÛ§Ïû´4·åÆLýÌyŸÉZãŽUxeTÁ©T²ì™Ò“$#ÊÚ~µyŸÑµ¨*Jæµ ïOF=CL-þôbû‘ìŠæic¦Ù×M­m²yo“-=ž^Ok‹Hãî LIï¡tQwšÇã±ÄMÛ™%ÉJ@RÑ®%‹K2êV4‰LEbEInÊÆššbÀùÚ[gwq®ñhÜ&cƒªÀt…+±¡‡/^ÇÝ'8óÁ+dÖ7‡3² ZÚj¤­ÿœÜg‚8Ñ\µ(ÆÅh"Ø¢.mÝöîYïÎZ*++*åmÓßf_+qÇ*QчU5.!zù)—[ýŒ®µñyÏ5÷Ø×ÄzFÿŽ(|&†˜šwd0ÌKžh6ïw ÑÖÔ(u[6ʭϾ)?Y³Sn}n»¢ž^MsÝ^iÞdîÙ¯¯ÙjîÛ)…hï¡Öòà¸ÓvÝ™ë`<ž¢NÛ¹ó¦V –‚jé#C­ ž9æëhÞLKޏäüdÔcÙÜûó½R1,¸¥ŠM"/šÑÎk§ hÏx¢*0A÷MÇÞ'\q‰ ÅZ%…ˆŒåÐ[’gcŠÑŒ³JÆ@\ûkí I-æÏLE…„Ÿ‹+úK´ØPNqŸÑ=ÖÌaµÃŠŽuZΗ$šû2M;ä™®•þüKÙÞ´«í ­òú>gf0§·ÐÒ"Í[·É_?õq©ª ¤ZêQ¥Áë"ôNêZ¤ZäÕÞ"êé“444È®]»òhjjŠ]·4f§íD8îüáNi¬kŒ­›´4›™Ã22ðCí ÷.Ml¢lÞš­[ÿ¬¹Ù¨Î5÷Ÿª«‚c.`Ïãž—¥m¤©4,¬oî>ûî2bù%|Æ–jiª:Nš÷­É˜Í{Wd÷Ù’ºGó¼(YÏ;ÏØÇróÁWM’æ1‹¤iÜã¹ãcÈÛÖ°SÚÖk§m{õùû–£F%SFŸ‹’õ¸zq˦77Ù9âá·âeówÇÔ‹[ª+ªå¸qÇÉšW×ä ̸s$}F=egþޏâ¶wd)W¥N¾Ÿ™%¿<÷[²è¼oÈàú7íöá52r@û©Q=ž²ÆPyâÙñ§E²ùÑå²kSpojn1ýEUº‡ËL}}}B'7~üxÙ¶m› 2Än£Qßwß}röÙgKuuàÚïÁ™ÙóK©zýƒáó‡}8p••eùÝõÊõ»£Œ1BvîÜ™m#ÝÅu×]'×_}¸–ãŽ;îÚÚöWüìçgKÿ¦þá‘'§<)»kw‡kƒó¬({û﵃á+UÍUrÒ3'=Ya´h«üwÛ}tåw[Îí³8Юcÿ÷–nm'B7mÚdwz<žÂÐÑŒŒ3ÙSøöéñ¤Ã·O§¼¡¶¡­­­²yóf]üõÖ}øï¶ûèÊï¶œÛg9p ]Çþï-?Ü6ÚN„ÆÁµ¿†¼èíøï®ãøï®tüwÖ}øï¶ûðßmÏq }×þï-o|b’Çãñx<§Çñ"Ôãñx<ÇÓãT^ÇäÔ)¨¬¬”ÓO?]ªªªÂ-ž´øï®ãøï®tüwÖ}øï¶ûðßmÏq }×þï-_RÅ„z<Çãñx<]‰wÇ{<Çãñxz/B=Çãñx<=Ž¡Çãñx<žÇ‹PÇãñx<OãE¨Çãñx<§Çñ"Ôãñx<ÇÓãxêñx<Çãéq¼õx<Çãñô8^„z<Çãñxz/B=Çãñx<=Ž¡Çãñx<žÇ‹PÇãñx<O“i3„¯-­­­²yófÇùöéñf¶OÇSíDè¦M›düøñášÇãIbãÆ2nܸp­gðíÓãIÇþhŸ§4Ú‰Ð;wʰaÃl2dH¸5Ÿ¦¦&¹÷Þ{åœsΑêêêp«§+ñßqÏБïy×®]VîØ±C†níÒ´Ï$ü5Õ=øïµëéÌwº?Û§Çã)v"”LÃ¥³+$Bïºë.9ÿüóýM·›ðßqÏБï9Mé.:óÞþšêü÷Úõtæ;ÝŸíÓãñ”†˜ñx<Çãñô8^„z<ÇãñxzœF„Öµˆ,Ý”žž¡¥¥ÅºÆ(==Gss³¼ñƶ,FÚºqõ’Ž-¥­¥­›\¯Î,KÃR‰n‹«£l3Ëò…ΑD Ç4›:ÛL]ÊB¤­ÝQ·„s6ÕµÊkKëlYŒ´uK9§Çã)2õõõm áj.¨{Û¶mcBï»ï>9ûì³{E ×ìU²¶>#Sú·É²™ÍR[î,SzÛwáùÔSO‰¹¾¤ÿþrì±ÇJeeù}éùži##FŒè‘˜3Úf)íAøÀÈÞ½{eàÀrÆgHUU•Ýý[ Õu‰«qÇ–ÒÖ’ê²}u]F¦Õ¶e×ãÏYgÞs¶d2k¥­m²¹æ~hÊ·˜móœmß6×ÝÇÌú:³>Åü-ËÌqµlØfêN0ûšÌ¾*³ï9³í°`WîûDÏ‘t >&#èªî3u÷˜ºƒLݳMݪ˜ºiëAwÔ-áœÍF$þzöK²sm“ R--;ÜT·yÄÕm«ni÷¦=gO¶OÇÓ92_úÒ—Ú®¿þúp5ÇwÜ!µµ 7­^ÆªÊƒä ƒN ×DnسXŽlÙ®yº'cY*ŒÛ×W,¢uuurÉ%—ôH'wÝu×I)í“qDE xÒX‰iëÆÕƒ¸c×T“kÍ·nkqu'´ì–k.[*Éè–=rãžeCåàØs¶FæÏ¿6ÜPW7Â|/ÉVÍÅ‹o0×âsmn0¿Ý‹rÜq?÷ˆy`"÷ßÿ#sÖ„[¢ïÃ9vì82\‹§”c†µ˜ºõNÝþ¦neûºiëAwÔ-åœkjdëµ¹á‘FݰIú™{˜rI[7m½žlŸ§sôyK(V”ãWTÉ‹õÁÀÞ“jÚdùqÞÚÝxKh×ÐÓ–Pà=8·—ToÑ¢E¶ÃG Ÿyæ™¶~œÕ\˦W—z§¬ÌYcžÑ,M›=á©*ÙÔ˜‘qýÚdé±Í2¢Ç×I¿êÙ2 rmX; ­mœd2›ÂµEr‰ùœj)h¶n0¯s®Ýææ?šÿ‡™}ÓL©"¿® U3þ*|LÞê-¡ÏJŸ¢‰8²—‡+†Å3Eæ WʘÞô'UáRŽ:ò=§i#ÝEš÷F4²Ÿz®{]ÿVÆ^D<²´.06ãž={dРA¶ž+DÝzo¾ù¦,]ºÔž‡ß÷ÜsÏÍÖE\®Ú+2} ]•™F«¼°Odr‘[§á9ØÈ±ðrpëªëÝ­Ó‘"W¯óiôŽ©¤u·ooÞ&Wùµ\?ñkR‘Yoöa–GÌòŒY˜åE³L6Ë­f™msrÉYUE¾n–O/-c̲Ù,³Ò,*²ˆ\e–éfÉ^É×Pò1í0Ov˜ºÃLÝ$±iëAwÔ-áœÄmn]fêKFFÍ Õ "¨ûæªz9hz[/é;Ö‹c¶OO×€,ÁÃ}è?ð´0KœŸ)®o‘|WèСշ1 è==7 ®xŽö J=bðàƒÎ ÜÌŽÜرjbÅDp‚Ö¥ÓF€%늞8îÁ´xÐpë"&O0}?%A Éù+D¦.ÙÖØ^€å#ljÜl´d³i»çÈq éO¬³}scüuÖ\ùò¤«¤±•[Ùb³˜7fAp"<Ù†˜œg@˜*£Íò³ 8a¬Y €x}È,æÃZ1‰à:!,ÓRÂ1º¦n1±˜¶tGÝRÎiøó›å·ó×Ë3×L&BPrBmA¡ iëyz'*>yill´÷î3ô!<\P²Žwˆ:ô);š§—Ñg[²ZTèô è Ó/©µÅgÊw?Ü –-[fÝò,?þ¸¢û(ÂqñâÅöÆÍ¢BëP T«§‹+T•¤º0É<æ¤pÀÆ‘iñiô^ Ú©¶EʹOŠ\õ‚È#T 1}à*9²ÖT4ô¯D4ò´‰8B4šo-žW˜EYeê)[ÌBhÁ£fA¬~Æ,.Ö͹ÁݧÀª™6{¾`±ÜùBð#R²ŽM›ÝÞÚ‘­ïKU×ÓûQñ‰ÀT (¿X@1h`¥ÿ Ä‹{‚”™ã6oÞl×ÙŽpõ´wÑ'E(Ùí¯æ[`ú›¿T(ŸZd<]Ÿ§UšzcP¸¹`uëxºŸ¨p$F¢â‘>.xâ;]W¼‹+T±rŸ~úé‰uá£oÔ‚é²µId}êJ;]¶;xíZN“¦¦-O7 îw œ¼´b3§AÉ:°?:ï>¢×=bõãfQ×ï(³¼¼Ì;G™ÑQ!Iý?q}¯Ù”Ý Dq™=¢Ÿ}M9dR?kýÕ‰ëŠZF‰ÿÜzÍ8ùí)/­ëéÝ é+^{í5Û/ 65A’}ê‚g÷Â3XxÅÃøÄBÊyè_X¸çíÛ·ÏîCÔzaZžô9ŠÈœñx`IQ°Æh|šÛÉa‘™õDpŒ§spóxâ‰'äÉ'Ÿ´%눔~ý‚NHyþùçóêxºW8Â[ßúÖD¡ÉzÔ•ïÂvªÄŽ5*±nÃTAFXð\ð@è†ÏT'„~qÕÜz”ÈÒãk̓%®ŽÇÌB©.bĦºØ'™…!Dû Çí®h=½añÝj×r–¤£b±’ÄuîÿfJÖ»\毘"ï~l’-w­klgMâÍÕ Ò¼%¸w«ëé ‡'¶oß.O?ýtVp²C…)%÷ „©ÆŽrn¬ªˆPÄ(VSÆ£î|¬¯^œî_úœEdj ™Òà5;×þÆ9í6Ë¡>³ùä œÖÓ«ˆØî‹Ñ‰†¥»jÍCä æURŒâËfÁ-?Ã,KÌB½5fÁý®ñ¢ÄªEKiT€Â¢°ì‹@ý8Û!IbÑàðo¦d½pc8£–QÖ“8hZTk±ºžÞ¢„ AÖé#(ÓˆÏ(®ˆTaÊùT˜RjÄýLÝùˆS3eí|>›¦=GŸ¡ˆLµ¤(¯˜{™ M\òËÏu„thj%õt„Þ@(Y§1ótgñ0`€µ”zznÄtPª›<7jbH5y)Nˆ&WAã­YNZNQ°û:C+=g4ãc³Dž4íö´GAÃg¨K"aEø‘3u4¶ðxVC™ïÍ@Œiìg6É,ˆQs ‰J,ˆRµ¨b)UAªà¢¿0xÙ:# ØÎI‹ÞfþæsÌßL™2Ѩ3D-£…’‹ziÔ›ä]V´®§w â÷8‹ŠNµfvDø¥¹ŸQ‡Å¦j5e;ÖP>†)‹ºó5Δ{ ¦ÝCŸkو̕sD~gîÇj9Á­‡F¡ÎOß’ëÐX÷t«6RJ}ÚT먢c†üñÙ§SO× 3ΊÉ:7\w»Öå÷ÒcÜRJÖµž{,¸Û‚n¼õC;ó½Ä€ò0H{#{‘I&<®õ‡L[TAê>ºž ޝÅ&1ߺrùnÄ™ySëvǯ±ŸÑa·ƒ®Ôã‹*™õ*H7˜… {2æizþ´„çf>O1±˜ÖÚù†ù‚µ^1!™tN…úšé^¬®’¶ž!. ɵŒºÄÕ­¨i“Qsò‡vŠ«ç)ÜŒw„(âOÅ'¨ ]á5c!?óÌ3²~ýzyýõ×óú—¸miÐÏ âT¶sN>/®{×ÏkuçsÏóîüÎÓ'/éä5œGšÌ5².ì°´£ÄíwÅóÁ6OçÁª‰uÔÊénC|NŸ>]Ž:ê(;“’ Ý7Æ8+&%C3qc¥dÝ­»páÂì1ünCJÉzÜ9éþô§?e·¯ÜÕœoMœ§ºÒ…ëu -’ ¿À´Ã·>%ò±1"÷ÌÈ0¤¾ûyÁÓf›Ñ@nÌ÷€Š:™5 '™ì¸ÝO2ËF³bs€u»kì'bPE 3+M5 Çq¼ +Ä‚”)ZN<ñDÓNÿB2$ç|ùå—­…tÆ ¶OY³fÍ–G"»Š¨0ÕEÅ4Ÿ[=*LYXg;ßCW‹å¾DŸ¡ÚaQ*tvXTˆ=Ó²%;D^5÷°±Al|ž8…¸óxâ¡QÑТb’ Mn@4D,i4F,”l‡¤óx:†› O©C0Qò;%ën]íôn²š|äÖÓýQ7Ô‹÷!Ƕ‹·&¦“Ê(nÛr¼¿~=ðVè¢ç„Ô¥ZW±~ÿ‘…e3´Z‹§›ýÎ0KÄ‚ñ—7sJ( tÕB D#­õ“ñBã,©…p?SxL’ˆ+Û©Ö΃ͬ˜[_)vN—´uK8gIIH)ë–rNÏþ¡…@t“Žp…¨ J„#Ë©§žj=fX!]}Ì€5vìX™:uªÌ™3GFm—1cÆØó¿úꫲ|ùr;&23º=ûì³²iÓ&{¿êÊ>†÷báïâ©q¦¼f;7á?ü°}@WaÊkî›>Î4G¯Ÿ¶“NŽ ‹ Z\Œ'uH^pãÓÈÌ%1‚¸4Hsžž¤œ¾ã(4fD& ñ¡ñ\;¸J”šš{3¢Yò+V¬È;âÎÓ“tä{NÓFº‹4ïÍÍýÔ㦨ð=ã>?餓¬5}ZaʃAô%zNÖqÁsSåwÆjªB•¶„àÔ<ÆÅ5Oû‹¶-ê>dÏ:Ÿáÿ8#˜IÁŠJ–=ât¢9~–yƽìÙÀ*Š›åœ:sNDÂ(jåT°„âfÇ ›Y®5 ·?Þ•c±sÛ,X=±~"RÝé=9‡|i§àÌâ~&¢-)‘ˆ×i§Ã\z…È"#եϗ,TÊ9ÓÖ©‡0Œ‹ÕD$¦b3mÝRÎéé~T%\$±Žx*dùÜèÄxr îvúP––¸÷`b“mÄ)çÆºzÊ)§È”)Sì>/ö/ù‹µV®\¹²hT©èw¡ß}÷MD/%ëÀ}“÷Ô$(>™þð@pç÷ú–œû jÝ$ñ!:ðu4I¢Ðy<ù X™€Q7/Jc@‰ÝÑ% K(îzJ•+Z9'OÆ]é2ñäÃÍMáf‡¥È…›aR|\b’ûÁù^Û¾3/œÅ}°Sܶ¥í‘º!”ë ÄÊySVlAlþêõü‡Ä+И r€#Ž‚ “*ÐGÌ‚Kþ\³äÿ}Áàônlè·Ì¢q¥@†| !WŒ´ÖÆBp¼ëÒßúP FÓ$ uX&ÓÆj"PÓf·ûi;˵|ba¤ýãR/&>W$!úÆgÅᡇjë(iÅ}Öˆ#dâĉrÌ1ÇÈܹsmÜ)"xذaV&%@±¯THý¤¿KÅ©+LyÍÂv¾[îy_µærÿæ{F˜ò÷aÚ«E(ühì§ëBw;AbÍF…V÷‘U"4ýûµÃä8Ž;'>"’B£V«¦Âk\`®[†’é:£VOê"Z¬à“–º×5©±J’ÐÄ*7?pÅ+Ç« ~ )ÏY;4o.xb6ÝXÎhæ{œHU'Ô…séC"1§¯GtdP†EE-š¬#öLc—…f Å[XE7Këh‡tú÷°bE^vÄaWˆE,Yò Ùòqq¦]Ÿ1ÅpL¸ÆÓÄj&YLãðÓv–/$D}÷ DBŠíI œH:úë_ÿj]àóæÍ“Ã?<+ÒT¸–*ªô¸Ž‚ø>|¸vØa2mÚ´lÔŒ3däÈ‘öïC\?öØcÖÛSJK)Ÿº,j5峩Քíœ~Õµ˜ê½™mü&|^>S©ßãþ¤×ŠPµ¢ÐéážÃºŽ®u“Ž‹ùªlzx¬v˜Àñ¸½MƵ~qâæ‡kå¤ÄÕë®»ÖSÐópn·§ëáfÆŒIÜd£Sv& MpŦ+^9žó0üà·Ì–µá¥€°D`îÂÃP3oç¶-·}ê'!éˆ$&uÉSž:,÷Ș¢®gc‚Ñ?Ô7ïjš”¬# ¤¸×UXâ–ÿºY°xb)e(¦fÁâÞ$l9Ò,XH± â¢ÇÂÚAñµ`vT,bA%K^Ù÷ŠùRÃáŠ$ •D ¢×xšAèK±˜úi;ËA*v@-Ÿ”q‚ŒzÄ|âöƸ€å“¤"Ä•‹ŠµB¢.‰®\ôIÜã°Ôj÷L &$@Á–-[² PXvã ø[ôïê ®0åž«ÂT<¿ }1÷mµ˜R"LÙÎþr¦½V„ºVíô¢ÐáiÇEÖ®fŃR’ŽõÄ—*&£¨•×<%âÇ]WñIƒ%xÛ…uo í¸¡1s’+@!Ih‚ŠÍ¤ùæ—-[&¯>þ Üðæ½Ò¯­Ù D,—®ÈtÝðжO4£^gGbC:Ñvuh'_5úPÅ-üäè`Ÿy³¨E“’uW˜",p¸çh–O˜‰ÀÂbʬHnçøzXrü4³¸ÖA¦Ì,/J4Kþ<ó4ÝÕ3•(šÓÄj¦µ˜‚Ÿ¶³|@¼ &UаŽR QJDⓟٳg[¯ñ˜q¨ *U(u…ÈKŸû"™øä5ЇaÍÅrŠ•þlx ¦ 3µqãF+؉—å{ëJ¢ÂTÖÙGÿ‰a£‘ZMYÊ1δ׉P¬–Ĺî¹h§u(µã¢¬qþZíF£±¡ Ço3÷@?dS@]]“,]ºÅ܈ZcÅ$pQs¡«€d.`­C‰h¥!hm.¬oݺ5[ÇÓýš¬Ç%.¹ÔÑ-ÁX¡D¬ ´9}tÝð.lÕî&éC¡Ûv]¢nþ£k…ŠE‘I©®xu_S^l–ufQaJ‰Àâ¸ìã: þfO^ë—â0))©T¢çê?"}RZºR4‡¤µ˜‚Ÿ¶sÿƒ@áŒJŸ ÛT„"ƈ«d\è·¼å-V¨áò.„ž/*ŠÒˆÌý%¤ølˆêC9$6 aÊ÷§ P|'šÅw„¨ïÊÏÎçaá·à>­î|¦¼¿%ÞF¦< ŒÅ6µp÷ô÷Ù«Z6bÐuÁÇÅ‚ºu˜:! êTFæ{²¸ÇùkPº.ûèÌ™?17“ŸÙ!ªâ’FÆÅÌL¼ ÁÜIql‹Öq-«.ÄÝ$Ç“n(q‰FI$ ÍB¸ÔmUƒdcÕPkÕD(ºÐ~âèX'©H]ïqÓè±®›¿*S'+±N–b¥DP…Ë Ófa¦%\öîßÎMåŸÌâ~ÑñDK‘ØUb±+Ïçí*ÑìÆbªÄMÛéé~!Jîé,êVŽŸ û¸Wã!g·5I?$%ã¢u\kjÒœ»'áóh÷Râ_5 ×¾&@‘ðDV> P|_öŽ&@ƒÏÄïCͽ…×lÓ©QU˜âÆÇ°àºóé?ø]ºKœöªÖuÁÓE-%n¦œõDÐy¹®A:É-¡Áõ¼€{¼vtºË~Õªmò ÛíkJÖÁ•ÄÇh¬(%Î(l‹Ö¡1`QÕY–\’Îã) 7 ,É÷ÜsO»D#n$¸‡t2)#ÞÝžTšZP/:ï9¤U¶Ý½l~êBt”ŒßKv|‹ik <σ¥Ûž©}¨tÛò™ÃWÉ€ìlI”*H2 ×)VKÍt§dAeÞÔáD§GƼÖqÿ>>è›EŸX™ô!³¤dj¡M!ŒS&¥®¥Ö}mI°hý¡K‚Ðk)³Û»£n)çô”b«'âƒû» ˜Bbºˆ*ŽÅ¨€›š tŽK‹ž¿#B§»ÄQgáséß…E’0(M€bìPM€B°"öã ˆ=E–*΋¡¿+Ÿ‘{¸Æ™Ò÷y<’Q)Ÿ“ÏÕô*êv>I¬*nì'¢ È[L¿Düñ¡IçqßC]~qïu 1}ú™øàƒYÏMŒ§[öq³#f‰:Üdâ2âõº=©^\ê´7 œc„c¡:±×ñC_2õ?l4$©à>ª¸Ä*“‹¶O—õûÔª9Î,Ì›ÌBV;7UµˆI’’a…t½]ËÁþ¨%˜'V܉Lz–YRˆ:['b¡M…¬§IJ[J­{׌`ìQ^ÇÔGø¥Ín¥œÓSˆ‘RÅ'õŸîÁXûpC— ïÃRª ,ôùö7®ƒ~O [ШY³fe ÈÂGò'%@u~7žú°®Â”×,ÌD¥ýsWÓkD(RÒpLXH°”`Uég~wü‰kk û®s`TFÏÃkc[{‚È­¦^Ô:ã ˆŠJO\¬¨Â¶¤xRwO‰…ÎãIÆÑT4ш° …:Üà´® UpÏQ¨¸‚õ¿Þ+“ªs•Ñ(4áHèp»ó è M—¨×‡?=èC%^^ïk­•i¯Õ{ˆýA¥,$™Æl-š€˜$°’^¼Ìò³|ß,Q‘Ím2ðÖÖ41¡Ôq,´Íæ”$ £I@̈'VKI*µ®ÎI¼Ž©_Rv{7Ô-圞t ”x0Õ$P1’$ 8†™ŽFÄ’t„¥ :c±ãýJ¡Ð‘cz‚b"4„?.ühÔ 'œ`­¨ÃhÔêÕ«­µ# PÙB}¬~~îû|®î WˆP×%‡¥Q‰…¹àÙÇ‚…D­0Xd~ö–œX¥ÃRk %u]AÁIçwÖÊ` û¨uæ@÷û‹/b5[ª;žØÐ¶¶±æ)îÛXxv‘¢pÁcS릛ÄÇñÅÎãIÆÑä{fø$M4â;UxhÀú¬uU¨‚{JžÊãê+X÷šò¾);³¢‘@¼ú@wó¦“2ýmöÌTœ šäu -Fç£g? ¯a\M­L`Þ@N5ËD»-‡Ûp™SႸû•Y\±É­ðkf¹Ú,"‡Û±¦ uãNMIóI…nc€2ögœX-%Y¨ÔºîØ£¼Ž©_Rv{7Ô-圞 x€ÄòÉBH²˜õ“lv «'’ŽÔõÞÓ"´£Âµ'Ðï³³ð7j OšE¬©ÎÅ8ÜXI5Š1YÓ$@¡ ×ˆ{ßïJzÅÜñ$% @Üí¯m¶»ujб)tXÏ™>I­—*b î±@I\i”è{&Õë.zú;.„&&zÄÃeÅŠ÷ÛíÑmµµÉŸ“‹·î{fGܼˆ¡ýiñìÈ÷œ¦tiޛ΅ýÔC|*ü­øÃìwÍw dêM ¢u£çH:§ZB¢œÁÛ˜©²ÖJ„"mÐm.´)êP—Kõ˜(œÃ=gÒ6³Õ,Äm’d„kžÏŠØD€"H_5 B•ÎrƒY€ŽÂí<g–+Ì‚%÷<2–B(7… EI¾†ø,ˆM#èøˆJ(¢0šìƒØD˜¶˜/—¸Bbq™ŠÖC$F“…¢ût}ùö¬‹?F¡nŠ9éqcDKêLݤï4Í9÷gû,wèîG´[Œl»ï¾ûì«Þ›£Ð¾:oûöí6«œ{Ïæ\ÜÞúÖ·fòJåþûï·™ôjqãsqP& cf8B áÎ.7ôwÌÈÔSð}ÃÉÂo¦ F´!¾W]¸WÓ÷’¹Ïï5i’†)µk7¿9çRcDWÒy™Þݘ/pú³Ë䈚 Á 0]ILÙS»¹§M‰å4£– —ú·Ì¾«¸£Ã3QW¡SŒZ_À­ÓWÑá˜(q‰È|ì±ÈŠÍeË^MVrAxªµÓE±ÛŠ ÇäžÇSDb¡,wýî¹Iñ»ÄÕž#霬G‡v¢½¹ ƒx-¢TÛ”ÖaÝc¢í,zNˆÛfÖÌrŽYx*E4¢þˆåDP T(ü¯YB«¡Í–'#Êñ¸ùuêOæ Í …á³ M‰¨Cxž¹ØlºÅî̓ýˆÍè Q‹¤Ö‹ŠDDdÔÝOŽ¿onñØPê2/X¢çv@øuõ|ð¶n)çôäPñ‰HÁíÎk„–:Ä$¯U”º ðp÷b]C´hÒQÔh "1îiIú …àþ¶r¤xî.›$@M˜0!›Åoæ&@½ôÒKÙ(,¥’ã9¢,“eé¥óSÍÓ@û7+;24Ï8wÒöý–Ì4ÙíLÛÙ°ª¿lù‹Ï„ï, Ä'‚’6Ë= êvGd¸÷V^3lB…ãû‹^RÒ‘ž³3"”ããeO‰Ì–¦»¸èú¾†\¬eKøy‹ü­|î®pÇwîËÜç5ŠøRM€â÷ä·‹&@a!%îo–P¬§Ýõ·”¯E€Þy'f6»Z»úi9ᥕÖb *tdĘ5;×'R\zK7t¡é'5 WA°^½&èèŽ2¢óû¦ŸÒ:Ä”êk„(ç„èyYïk$ ÇäâÆˆBCC{uàZ>)±¾iâÑGÑîÆBž¸¢DÏú§ãpÃÁŸ4(}ZÔ _,cž6â¶½›Íƒ_t^ø(ÑvF wÑ¿fÓø_7¢‘Ò‚ѵnº±¢‡›E×ÙGòà‚ÿ°YÔýËñKdgpaù¬wÏBmë.ÏRÇÅâgA¥ÔxÏ„XÏž1™6 þW³ÖËë_+ ÏÜ(wÎð™ð{¬Z>•qâSQÊ1ˆb ·’{6b%Í(%¡|®RgGމãÞÜ+ß:ø[vá5Üýá»íú7§Ý"ßùùÞûÿ$÷¿Ú 7¿Ø(?|±A~´®IngXø.â¾ër€ß a‰å”$(M€"CŸP ú<”Œezî¹çÚûûûßÿ~{¯ïjÊS„†PY°ûr°Í™Ü@± Ì&ré¡ùVQu¯³hÒå…ç×cNIÖ»vŽXQ?©E‡yr]ñÑóêö¾Mb<á˜ê뛳ÖPà5ÛÆŽÍņ¼òÊž<±JgŸÝ-55Á—Ž”›7:b´¢®%nºNŽS ªžÇÓ9¸Ár×§'dÜ7@Ézn›¡M]ö\qA™×ΪåÐ]e@kcòƒÂó÷ß¹ëæ ´B‡uSÝéX±t²¬vÖo2‹ù0v bvzOŽ/A¨ó¼B´ešvœÏŽZP{b9ÓfÁïZ—{¨Ùi:ý¤ºžö Ê X0ݘJ]âàžŒ[ö¯ý«tDföÉ'Ÿl]»ié Ú™ãKE­œ”«nϵC^ß}åÝòÌÏž±ëmwÙ²á·ÏÊsÛƒctȹ]æ2½]§{‹ ß{9C«ýŸ•þU 0wÞyòío[Hbe[’±¡3”§]e.ˆÐjZ‘éL‡°ÂÜX#óÎ"F±ŠÞ3#°Š>:+ØîLXOÙ7&–Lß9kp.æ3 ‚U‡ir݆”qÛûÿ¹x1ÓŠÌŸgÖ-ÏÂk¶ÕÔTf…(¢UÝñZ礓~.W\±:›9ï OžÀ4ÞM:ÀZµtrœZP£çñì?pïhzœ[‰ gÑ„@$¢'AÛÙã3å™×¾+K_½YVlù®SÓÿà·m“Èî ,À–Ûϸ_ðàª̼pÑûÉK TO"Ðef -†ÖÊõßÅBaÈ<ï*Dãb>„g4ƳqTD®¿”0ôROA2QÚ,ø!“rHC'ûLø4 z®øD&Y?"±–">™áˆÙ}£TÕ›,¡jù¤\tÍ¢pkŽg~Ð<.8J2ÕíûŸ]æ^çšï-"´PŸÊoJ_=räHùÒ—¾d»šò¡X<±|åŦC@€b!]º4(>jôêUfa(%âǰ²D‡`zÆ¢ñ <¸°Nü¨Z<‘zÏ1°ÕD (– Ñ×@ˆöï_•u¹«[ÞuÕ¯[·Sî¸ã‚¼d%èw>—­³zõ›òÒK í.rÖ[îØcµÃ|¨ õ–ÎÞOÏÑ„$…¶âÆtÒÖÜdB Ýò$оf·¼&U¡¸<²ù Y:éµöí«ç#¿ W ƒ2âÎ,Ö5Ïõk\씞ˆ1ý\!X?±œš›Gy8ZnĬ¹¦»æyûsÅ-–®ë¾3±œˆÜB‰N=ÉDiæŽgû»—O”‘ÿþŠ\¸h¼\¼ÒÏ_ŸI?ÅÄ'u™²‘¤#ê/H–tGô;+B9¾#"´T\Ë'¥kMdüP©ù2UÄóÐë¡@pè "H îÎQ&Ê«e#.—,Yfz.Ó0ŒÂ1ýAhUý‰¦C1ÂE¶îßhüñŸîz’µ¥Þ\3ÄzbqÁ’J§ˆHýèÚ°‚AK¼()IK±îÃv±h½Ä£› ®[ž’ä#Üð:sÛfÏ>4/YiÆŒÿ± KÕÕÁeçÎç¢×Lw’Ï ¤jétëp£$Pº]bR)®ÊŒº†:Yº~©-‹‘¶.n˜è´In}7^K7/Ô¶§Bígø!F8¼4\úoÅ4ÜHƒÆê¹ûÍpÅpÒ;Dþxsàšð fC(äÚ 2S˧¡•!JÌÍ€$è[ÿWäÜ_%×/K‰¢´®­Y–¶nµeqËèõœ$K¹î©ƒx=ÛÜK‹‰Þ”ç%63MbÄÕELÆe·GëV™ý5ÓëeôiùuãÎy ƒèK÷©P¡HB!Ξñ&ñftV0uV„òþ¥ŠP(õ˜ÊêJ™~iО(õu,µU2íÉJÍïÞnˆçÙÝ­Ù„%…ï‚卵áZ(&BÉÕÀ{Ù]T`º§ÃwàÂ.´¤©SÒ²s§´s þ_»´t’4u”4UWÛý͈QuÑoÜ(mÇg9ª_“Léüø”ó6Iu&X§_œÿˆê&© h¢¼òù6+.O^Þ&U­ÍYK æŠÍ²³¾IŽ}¼ÍÆ‹ñ£noÎÿÌûöJÛï¾m;ôy‘ ?.rÚg̓ïv³Í|°çÌñëÂWÊ[Û‹Ò" !gÞx¦œö•Ó­1Ô5Ë É"mpEÐVްY2mùV*þ–Ž~¾ž€Ï—F„®Ñ"4ó¥/}©íúë¯WsÜqÇÂHü=Ű5kdþµ×†k‹o¸Avy¤}]i„ÈùˆÔ†PÐý R)*Ë„–ݶ¼vPn°çö,–#[vÈšÊayÛ]þ}Ï_ä{Ž“-•ƒdt˹qσíÎÔ›Þ’³ºÔ´KNÛ›æ/§Ê›ÕÝg¶îV­ª“/|AçÛ6ã¿•éÓó÷h/~q´üèGÛd‹Q£GWË7fžêóê RaÄ£È-·L“ñãûÙlÄ˾¼‹™7.‚fÆÓ ’.xêó4¬Å\+õ¹keqsT×IOÀà¿—\r‰Äå6X=VMD¥òØç“&2¼P ´ÝÀ ÕuÁŠUpÁcuQ¼Z>â²I"ê0µ®Îl6§a£÷ÌrþU"#Äå<#ŽË}îßM‰ÕÒ€pÝÆug:¯ã‚×÷8ãpVÁxéd†ŸiV"÷³GLÝw:ç…IC(¾È|–_”õož‘_ïž¿™Å°NÑïœPe¼ ”²×Há!²¢ê"©Í8Öc„!PAxb)’¶Dë2>)ÃCáÚDzêZESž $PÁ­ŽU3ŽÎÖ=è¸êvßiÚsk#½„Ü3¹"BYgLÈB0¥#‰Ÿ<Ð3:I4æsÅŠö;c ÐŽÂ’ŒOI¶uG )Š÷'.U¡mñ·&Y™n”„*6´îûð}òôÏO\¦Ê`w¨¬¤U_|«µtN”‘Ó©–Ÿ­ß-»[k¤JLŸfþ?²ÿfyëAMí:ÉTŽ•Êšc챫V­²}ßI9Â÷Êԟ̾Th¾ÿk.ÃÛõï|'ÜÒµdêëëÛÔÒ4àñãÇÛAL“03,œ}öÙÙD§1{Õ¬Y’YÜdÚ&O–æ'ž\ñŠùLU'œ ™M›¤L-Üö¡LG7{E•¬­ÏXËè²™Í6ŽìeÓ9NYΟ†×&‡™ýrS®¬®ËÈ´Ú6[ŸóÌz²JÖ5 ubM›Ñ0žzê)[GÇå5„m,ÍæZ¹o¶dö¬•¶Aæ:8Û\InÆ"tä{¦0ðo9ŠPµn¾°õ9bÔ²â‹+¤¶&øn¢b©P]µ„òDŒÕ$nh'â¦ñ,¸áMà#ÄE§Ø%ш„£ â>±bžeàZǺ‰TÁò‰´­Õ4:Ó½ç³"ýôwæÆˆå“XÐ ŒˆÝ±Uä¡_‰ì ¬òvû;?–>Àšù óùi2ä# 2§šã°ˆRî3u§ÿؼŸé¤˜xÕå"ç¾§è÷ j }AÌý4 Ê­óäâŠÉ9!ª–È8è’¶Dë2@~ÒLL)Ï«–H2ÛI,*×¹o[³Ü6æ9i5_]…ùJ.ÛW¬x¿MFÂUeüøÁæ)tw¶ž Ö‡Ú$—_~·l޼׈Ȋ¬%”ášæÌ ¬WÜuȦ,t„į ›.-™šlÈ«¯õÒLE˜‚Ž|Ïû³“KóÞˆËU›WÉô1ÓóDe¬XJ¨…Î÷ä½£h+j ÅÏTº±mÆ×>ÛL"®“ös×L[Bš×X;±lj{Bˆn|Ö\xo1ÛÌgç˜Fóf÷ÿO°˜7Üg,ÇŸøÌêùçP ¸ÕÕåޓ'2ÛYLg>ÛÜ\G›t !DWµ½)“dˆÌmù¤Õæ!¸É<·³ˆ:×Áë9m= ®NÅ9Ô< â–Oš)Ï‹,6m&ÄZ7Í1IÇFÏ›ô¦yÿ¾*By`w(àŠG„1–§ ƒ~,…ˆBÄe¡é4IPâþzÔQG…[J‡0*†÷é¨èб\ÅD(žr 1Í]‡þ­ùHô»=ÿ~€eþQ®¿t½œþõÓ¥_mû~¼µÕ<Ôß®‰<¸ý(y~ßëŠ?}¸Š‹ZÓ|qºråJ;ăė#„·!ü™®U¯§8Þ÷¾÷Ùáº>ûYóðß $ßEz„%Yï0Ïü€, Ón?Á<Á;ûéÔâ2ØYG|b}9s˜é“‚ÝRm¾ï‹Fu’(°W"K¶ÂS)èÜž¸»P€ö$ˆÇ•+ÿÑf¹ÿøÇçY šï&(¹ G·ÜrŽÆI¨rÅ÷Z ­v˜¦«®zÆ\äãìMŽ…Ž¡ÅƤU¶5dëäÕwëiœ['h_1‰[½¨TÒÖMJBRh:|ñŸym&Û³m6ƒ ž¹ì0Kæõ=ÿ/?NË'.x¨Æ‘º.z@€Ç÷3JøPó ×&ݘO—æ˜Wö®x„j'A`žP1JFTô·‚ (¤Ô,\ÇÑd¥8ÒÖSt†&ÚK¡¥”çEø¥™6‘èÇ4dR¿‚ñœiÏ›¶^_„{ bÌ ´GD*s–“tDØIGx ŠÍçι{AC«: WÄ&V”Bâ ƒ,56?ЈÅú‰Êsn<'V€BE÷¾\û@xbÍ P¨3CpmëC¹ÂoÅï^ì3âë·¹ýß’ šõNÉz ¨F3ØIŒ`ÂsÌ_ëçhsï}ëSæK7õ1}ØÓÇ›>¨>¨WÖòI¤ÐN´ PI–;Ùî*8±tbeB‘ºyóUÙñCÏ=÷׿ é.kýT­XG•ªªŒ¢--ýä˜cF…[cÀƒ…(YD§›H‘TÏSä‰ËRqŒ”¼1?Cl6|(VëÌ“gmxsd®[\ï€%´Å\—*`®U2Ü' b=¡*¼b݈Ž@E¨*3͵{xø>”¬—‚<P œž ?owm/xJ°‘èÇ´k]cÞ@õ[—¿Ï·6ddëãûÚ VO¡ˆ7æÿ&éˆä£™¦/Õ¤£4tV@ç(UDº †n.ümÅ>Wâ{:¢³ßÏúÉÀñgÍ7|)X+g&óª.øµæïÎÉçê "´äkô]Šàt¦æ´%®vµ’ª8u×Ͳjéêl2쌊ýõëæ ¯žuêÍ×Ì…yöÓhE¼ºB”×jQu_gq;À¸R¡ó+Óa›Ñá˜ç#¼W„1yÒIwØz*RGŒ¨Í?”:îüò®Õ»jÕerë­çÚsºÖÒ<˜-æÇq§dyµïšX=ÿ8ÝüpK<®D ÄªD«'Üî¿ô¸4´äâ¿{·MĵâÈ„?÷ GLQŠ8uqÅj­’o»2ðD¼óãAì'ÇÓT®QÍp?íç"·œ+ò­3E_Š ^…)%±  ×îâ÷õ(“®å" D±ˆ>VùÎöÉIÝí#©½ôjµ„æúV21÷½ýyÁæ‚â’¹ã·^3N~{Ê˱–SO"×;nUæûžEž¹ÜZ&çþ¦ŠºÂr§ñ̽¢HÓ¶Vζ-áZ9K¨¡éØ"75ç$#4‘™g%%3^× D6Ëô·Î‘#6…"61:ºÆœ6üý¹ÕëížR³s¯Ä|"6u{µ¨²´ªXX§[²…N/j--‹ˆFb<]ñèòÌ3oØi8±¹lÙ«öµ‚u §B]­ãZM—/¿T.¼ð·vÜйsû^V0â^ׄ‰Óï JÖÙ®3½ì]Ÿs)¾õ~óÃܸբ£ç Ýù^ˆæ£ H§ÜpŠ\³ä©kìáï'¯M|'H&ŠkÑa£D¦*rÖ?¢Ôõ0P—¿sÌ= hÝNó››kA™X*M ×!šxP\¿28ÎuÁ¿nþ¿ùÄ"‘‹~Nb@ÿü÷ФŒ MÖɈï UÔE'@‰!MÆ)n_¡úÚ®÷$|€xDDþvþKÒÒ˜(Ŧâ|suƒ4o ~{,§…ê(D îv“HÜdFf:"þ°#Â1Ò ¡jI}ýõ×íœåÌ]Ï0R't’M¨"6˜ùÌ—/_nà ˆAe¨)þ~òÚYDM—Sùb:·Lã{¥áûÅбr’_ˆÖF¦ÜñüMåJÊwÚwÝñqSs2@½yŠËŠN’”\+éÂ…¹uó”ÄRÛ°OV\q¬Üü+ƒí!ÃÌ=~óÉæ´G‰üÑèU½MSêt$P,ç²>î‰@”"Vç•g[vÀ{bͧ[²%­µt?àÎxDÉìFQqÈàò.î:u.|Qšc†²PÔjJ–¼û^¼w;\w!‚sß+A ¼ŽBÝû@ÿ»gÖRðnú<Kž_"KÖ,É&‘[ön‘Õ›ƒ›d‘×&L›qE¢Û>4 þ±ß›‡ŽÛMcu®Möýæ›xýÓÍiž!z×Rʃ"q£ˆÝ)ƒEF†Ò»¸®÷8¡Iû莙“" $ÝqE£b3º¯Pý<ž=ä‚ñ¨nø½¯´ÈÀqø&N”¸Ñ$šV#U£ƒãŠÕ=ÐÀò‰UÌf„B‡Ä£¤xí4”ƒ%”÷'‘ŠÑQ$Ã]ÎH*:w9¢tÞ¼y¦9!+¸IØbLi„)•éG°ûš÷YqY +@ÞC”©~Kø*ž¶–W¬5´Ü-¡„:¤µ„vë`õaÙ³`á4O/29tÁêÔœ ÏäŠNp§ï¼ðÂÜ:džÇ×¶6Ë¥÷ß.“_{É®O®iµ™¹L½yùh‘S‡šÃÂþ‡’é:I  ƒWŦJHÕ^¨?½Æ\ȸ±|jç*·Lª³Ÿˆ&a¥œ:õVÙ¶-gÃÝu¨ëΈ'µ±¤ Bw?S}/JÖÛ…DÝ…cÍï«ë¸å2‹!пܮ3¿P"D±zºçQwþj Etθ~†ÌÿÆ|™ÿõùöõ¤“ìL0zàh™6¦ð˜‚Q8gÒ¬J…öeÉk¦ %¹ÛÉ~wòX,™ ¿gÞ,žX@54z¬¡XPÉ®×s!TÌrïß™Þ6Ò)D]ï.\«%RßQHR"Y ¢IKqû Õ/'C&çD}euFÞµxbÁဓFݸIÞõðaEë( ÒȆÇ=呯´Ç¿vVÀÙŸ"”÷E82ŒŸ‘ÉPMIŽí ëÇx¢,$Ž!–uÎ÷òË/Û…W·å{ò”F\ïaYŠ… A)æ6B¹‹P¾§4–PD(£Mt=ß²ÕÅÎÌH°x1#åšNÅ<©GçŒg˜&öéôĹèúÊ•ÁÂëÍ›¥öÞ»eåõo—Ç>|‚¬üàL©u:E%4s—Rç…G¨ª8u¹Í<èákëÏl”Ú?†®D†a,Ãs?tr d^ƼémÆ|ĸŸQw9qšÌjÄuΚu{V"(ŒÊÕW/²”:štı7ß|–MR"îSã=9‡ºûqÁ Jï~÷ _Ú. ê.d^mÊ3Í5Ëý\³}³9(Ï[Q!ºáÎàµêÎ?…(VÏ_Ï͉ÎëuÛÖÙ1@¾öa¹qÞRÛ/½U q™4«Ò¶ÝÛdê¿NÍíÛ·MdßR‘ÖÈ÷®m‚xMÚ ãyƵ†_rÃ]X,Oza6Æúhg¼Cú›çMGsiìË.57€ð “d$¦‡8k§ëÂ&+u1$)%%-Åí+T¿œ@<žqknˆš]뛤ª&VTâºgh'ÿ¬¨i“Qsx‚›š!‰Žh¶é_jý쬀ì*ZÊ98¸×±èò·ÇzÈ!‡8=ŠŠ<Þ›$,ÆE˜Ï™3GælÄì}‡Ùý.{Fí‘Ç?ü¸¬\¶R6ÿûf; T©TÕš>ÆIPrÁ]Ûž¿ÏU®¤¡„|ð`Ñ·Üñ®—zÓ!èpK”*2qÍk’’;$¥®ëkÄ©9Oí³«å„ç—ÚÕOçŽ ‰ËÜUqʬ.®åSÇ7´õw™Î)ëJ4寘Ïö[±³²àæÃM˜w cÜèË4cÁxñÅSm₸Tw9ûªI!.¼ P5ªV.ºèHóô9ÞÖW¢îþå¦cgÈ&2é£C?e‰sºÃÊ`åDœR‡Ò¢XHqÍ#8¡ÒüˆêÎ?@ÝòŒ÷9qDnÖ“É#'gÇsø©©Ìª¥˜%ÓuåS.{i™}MýY_ž%·–éMo¾ ™ æ©mÉ"ëgˆì]’£”ûÌqü:Hâaë%íÃ}€c&¢G¨ê€ô@]²ß¡¤HFb_Rã\kŒè42wÖÌ—Íu¬YðÄ>¯|]ääŸÖι?3í;üÌRBQ4+~¢y0c=*T €‹¼`̦Á­sKÅi²¸òíí’–Ü„¦GÌ¢VÏbINÅÞŸ†„J÷u!¢B±Z÷ £kò†kR׺{.·¿cêšìN$&ÅQÊû÷5°òrÊ)yIG*"Üaš:BW‰Ð´–P,¹LÉÌ€î ¢U—a¤¢Ç§±$&Y+û›¿ibû¿iÐÖA2û’Ù²·1ÈËò#Fo0ÃTf`Jó}V 8V*úŸ®å¨èxšú‚%+(ô-µv²î‚°d›ZäÆh)vÞ›Œiˆå1zKt¬^Û:VbÌ\QŠËÐ]/£Ð(z¯–J›8¤Bw9®zŪ‰ò 'g×IJÚº•ñç~n-¤®‹s0†¨òÜ“¥JÞ{a©Œf´ÇÅwºõ¢o'÷VÓÊCA õös6pw@¼ƒo» ðô»47IEhM9x¤Üó‰{¤º¢:»ôõν;åØ;ÖZ2)Y×}º5ê(+d•Ëÿçr[oÅË+²Μ8JH¸Þd6Η¶õÌë¿Å–òü»Íï^ ¦4¿þŠÙ·WÚHT2p”¬7Uö“¦ÃÍq”f½yËziÚ½SÚ˜;Œøm»ûGAÝÈgµ‹žóéÅÁˆœ¯š•m¡@[·Óv.mJC›˜m_$Žk‹(m;ãNizu—´në;cÏÑ|ÇÛ¤­Õ¼bÝloÚiDPä}Á]ßÙ´OŽ c6)·4í–Gš6ÛíquÆ´üTæ·þQ>вÄþ†î¹Xª›Û䨖Ár²©«ç¤Þq-Ãí¾hýèû»ïk÷ï4¿ý±æ·7÷ØcŽ9ÆÎ8Ãk¶±OëÐ9ëú¾ rç±/BÑ”¬»çt·î¯O~QÞ¹x¼u­_ôøa6$wÿÿ³ÆÏdÏÆ ã·C8=ü&Iç,öþ}MTÔ üX:+B9GOˆPÞáGâ34‘LÅàöü]Ÿ$(“($ò´r}¼Èªy¹F¦OšnÅ/Ÿë)–Ô;vØû‰/ÅÏk¬Ï´¸ïgÀ}·Iõ³9Ï“ ßE_¡Ää–b.•ž›1 !‰uRÅaÜÌHZ‡xQu×–Q,žàžGStöÄ—ÆÕ !ãÝ tƬ¡vºAÍ¥Ñ|žûsÓs™¹F >8ÈÔµ‰;ƒu×=ˆE†ã‰ƒ#!C­?)èÐw“ä‹þõÜuö5‚8«&i1_Ó¹ µ‰DˆCµl"0.|Ñ P¶1Ò½÷¾$ÿõ_OØý5 n¿Áés³JhÄ)a³g‘ÚÆç°7¿‘Îà‚e '¡ÉÐLX4‰ï<çÑ\=„¥fù’”DL(.yw;LJ‚´Î¬F¸*ã,EБï9Mé*®»î:¹þúëõwÜq‡ù]Ú_Ûk¶¯‘kÎÍ«pÿƒå¦·ÞÔÎ Ѻ7œrƒ9¼ýü«¶­’/<ú…p-¨7aÈ›iO¢Óó»}kþÊ;Žü¢ ê—?|Éò-•Y£¿kîxæû_õó»,{*jäÁÁÓepË>™¿ç™°¦yt´ì¨ Æ5¬lk‘Ów¯’A­ Ro~»þkuwW°ç lÉ7ÓaÍ{òÎù|f´ŒûZ¥ ÜÚ"uÃ+åÁ/Ž’Ö~2ì¥F¸Åˆ¸Ÿ†âÖáÉ÷ ËÛ¾ü²á2ë¶ÜÃÔâÏ’“ÚŸ.k†6ɵ§äޱ¯B¶ h•Ñ{+åÆ¿$5­™vu”.Gîl-Fë'ÕƒbuÌ Ç 7˜ßw‚ù}¯1¿ï–-v.ðo¼Q2†ÈÖks®õQ7l’~GÆÇÓ5®©)X7ºß¥rD“ò½ÖïRìœ ÖÜK.¹¤GÚgOBWMRR”xÀÆCv&n{É=gžyf¸¥tˆWÅŠHòP>;ÉB #…Åóè£n÷yãfmB\³ Pãàœ$3ž‡yaz‹(‚´up«Tì6‚{²¹ÇZGûJ¡ˆ#Þ·mk’š’~?7ïÓ\-—6JÃá}CyûÛ\Aøî **LOú—2¨a—ì=ýi|Ëé÷ìZøàRÙý±ÊCK—YC¹^ƒ´qD5í?‰|P>ñ‰O)öbìoÖÄÿ²] ÖID!PºC-Q²ß­ƒødÈ& U×<óãF„§Ž-}/­ãÀK*@×õF#êÐM6#¾Þtâ:”ÌÞíæý/Ì%Bh<BT]ñXFYW°€ê>7K·Ýõyã:ÈQpã²¢qœ¬»ÛˆåŒ PøÞ÷Î4CpùP2”“ƒÅꉠe€{†l²V×Õ‚ ‹&ûY4®“ò±¯QŠuÏÃqÌã@ œ P(çìáb`5à&æ.@Ç· 8Tžü×'e%}þ1[²®ûÜ%©åÜ#ææŽ«*UCÎ̤§E&<&™‰OIõ€Ñ¶´ëS–KÕ˜©fÛÀ ¾)3á´·”Ùíf©iRxhSf.ú”iƒFœõ’y×'¤º~·š@Y½skþ9ϽB2sÿ&ضyŸ ¶®’Õ¼bK»n(ƒÖgnËÅAg6î‘Ì×çÛ1C3þ½T:Ä–Ùõ¡µÙÏ© ¸ëC«ÈSaÌæ“•›M"š,ƒ¥ÙÞ¦ªŒ­óW³¼©PJÖ««ªHý½œ"´%u£ç¤dÝ}OwISW;J÷5û˜qçâ ”¬Z#?u„¼k1¢µBž¹Q~=gƒið•íέuíŒI¦d=iÿß?}¤üýÊàõ?<” |VH:&îœîÒIÑ©;;HÜÇ›TIDÝñ|¦çŸÞ†t vŠcÊö޼Þ1ˆÏí‘Á›–Ê/-ò´y0ýòìÌI5§ðüta/F|6Ât¨(àæ2× P@xûÁÏm O®|ÚŠg,ÃÌÑޙﵻ@àÖ ¡Õ7é7ë zF„NŸ.u“‘¥æ–J™7Ô%ns¬œzó <Ú\@¸àÝa›6Á1>è\³Ç©åSãG9Oôܦ ©‰HÀLW¯1§7JÑGŽ3:˧K¥ùLÑDÜëÚQ7ŠÛþUóy±‚ºûÂ=»Îö¡é&¼gyn=Í8ÅB©ñž¯É¢± ÁäfË¢“¡œ4Þ’u÷<$?¹IK7f3 ÛqÑ3¼ÒÀ0±ÆZKs=ŠËÝ=%®w' Á©èÜË5{¸;1x„<÷åç¬h$+¾Ð¼ðiçŽO[ÏRaê 0m—2nÝ…ö—`Ä:|úà7È\SLÃìgaÛ—ó›>üA»SˆÝÖY“#4Œµå¹rëŒ8$ù¨&r3f1CÌy(q°z,ïîÜñ‹+.0[32¿åÙ±=×™$½V)YçúM~IÏIé^óq¸u£„u°€b¶±P+VÈc™kÈ”úÁ}£ª…lxÈMHžº…æyw÷««¤­w €ì  qqiA„r<‚K§%Æ’Áæq¿{8H¡…œ+ŽT|ö«»Ý®W¶†ÆŒwß*-?`§î;•g„ G…Y†¸ñQ‡÷¾bK€vD;Ëåz·öibB±øv·%·GZrÔÊLY!'JYW;"p“céTwù3Ï f‚(YD¤+*—/ÏÑi?¹™FÏÃMæTßšlú)£‰’I-£Q;Åç,1a'GÉzí(² W!q£t|ÌÚ‰’é›4œL7¡± =2)+<Œ¨jwG(b±d–#ʨp¬0bœ} ɤĉN’™ Ç‚€$vsöÍá†Ö™‰ØO²âëBáYaž°~bóàÐå¢ç ‡v"öÓ¸ûÐ6ó7šÎÞV5åCïˆíˆû2%‰ÆŠeÍw›)¿4—9_W jx‹ŽBî0ix-ÔËàz!Þ0åCÏ›;nh¡ÑMËM»m‘|f‰Èaa ¢ô(sm?òŠÈüŸ™ó'”믿Y^ŒˆË¸¡–â¶EAx¦¬>éæ¾ª–Nâ?]È„'ƒ‚Gc£·êUé,ܳ^Y²Ç,{­ëÝÓž8‹֬ΈGè*ŠõØRâ ‰íäúI+b8>*8ÓXm¶¦¬øl‡Ù]yÝ™ÒxiÐÉãš/6=g**«¤qÚiáJ>“ž¹×þV$ýÍ›7Ϻå Á¥¿víZúÀ²råJKûæ›oÚï®'I#B ¥ a«;éj=ä/oE¹êÎpÆ, "1[n!è0• O¡IJX>£Ó~"Z9'%oŒ¥ÔAãAÏ}ZäæAéj£[6Õu¼PëŠ'¬Ó ÌÀUhË$ñÈv¬¤{rI¶CÜf„!›BÃÉt j3S箳D!Ë‚1ë27àŽ×!•Ôé¥ÓŠŠÎèybA@Nº4'.)YÇ¥®.vÍzßk¶ªãˆr¬Âëph§¨åh‘¼btƒ›nÎW3],¤z1ÌÏò…Ä%û’ÆíÏõ¦ÍÆ ãT WXjXˈqæá$ç²ÏzÔ ±îF#¨þñá`h&xÉ\' Mç„0TpÏãô`>ù߼˴û_âTë’ÒÉqBãÄ%â4:Ô’»M‡dŠŠÌBÖÒBèPL –ÎÏ}îsv]Y´hQø*î%<ÔF½*{ÖÿÎxÁNïùÛùëåWÇ¿$­ í—§=]áŽG0±tT„òþ›7o¶±¥¸oq½3fgœhN‚ºiD§Köü™jiðÁë(ú¾|…¹uì–†ïu²á¼JËÐQáZŽ~«¸·µXaÐ#‡€P,ÂX†¦¼&i ¡‡hÇrü׿þÕz"ˆsÅŠÜÙßµiD(îø>a Í3fV¯—é æÒˆkB%ëêj'SþŠ+‚}ŠU¶¡há ‚Rµ|F]ôÎûÄŃbùt³ÏŽ%ŠhtÅ#ÖÆ4dlPÛ¢®A™pºc‡*zw[³uY]6´»,‰8=²C¢3äù+qIÉzž«Þ±Z.»:Øç ÐÑÎýÂÌ„v½Ç4ƒÆ:›ÑÎò…ÄetlPÖ»„sž&m³Fn4íQšFˆª°œ´K×e¯íT·OºØ4†˜Nð»OæÆÿTªÌ­ðSóÉ¿ýÿÑéÂÀörÙ¶!Npêö¨Ûœ×\·sÃ!™¢ÖÎ8A[ (± ÅD Xª.ºè¢¬«”òBÂ¥Š€ðì ·8â“aã¶.Ûg“^7oOO–8Q‡è ªîôR@4">P\_ çCbQ±XÃ8:"BAiþm[&ÑoßϤf÷‡Ãµ. Å|çf©Ü¹5ÜaÚjÔoÜï|?Ç·3Cᕘ;w®î$n?‹EŒ’tƃ¢…{¼Ø0XiášéÓ"ݧ¹BèBë!¿uµ¬hš&µ²/ ÓD¥mÛQù裙8Èš”¬ë‰ÝØOD«;Ì@tÎyç¸é™º¼xбæ>7ɬÛÁék¥öÍèÎ]ÍüÖ*0ÙŽU†ŽapÍŸüNóë…– 7‰óf]ŠßÉÅvêÎzàò\ÒωÕyî2½éS*zn0Ý~Ë-çØŒwœàŠN²êÛMÃip·'Õ±¨%ÔÅ~úƒu 9é ó{FÇu ÃÆbtkÅ<[j ^´³§/6xx_†Lv†T‚Bâ’ÁíušOJÖSSÈÝ^cÎSí´S@”"N A±mìÊxÁ™S:sŠ)Ã[œ;]ç†]"9Nä맇 $(©µ”AìÇà1à¢?¸&؆u4îZ.8Á™D!k'ÇÇ]ã… SczD dp"$n5ò”î`èÝÞƒ ^=6,ØdïU S}VMèº{c_¦+,¡€ )Eà P°ª“|Ä8›nV{G@°•*°\‘W³ãšðU2Ѭ§­ÔÜs‹ ¾qÔÞöùpK>Ó™/ý%Q„ÆÁ #Lœ8ѺïO=õT;B#V J,)ދŋ۾wÚ+–ÔŽÓ´–P,ÛÝI·ˆPô^¬!ÒŠÅp:=^ãJ§Ò˜1AI¼ºÓ!š¬D¬’ž˜ºdÎ㦬¥ìCÐr^…÷á<áqµÇÏ”•Óêäž"ãè[Ì}nî“æ36¸1ÆzéÎ]íf»³cª‰¸Q\„þ>ØXH±Ú@žKÑt(š8ÑB”;7tÜY»ÖåYKcîâÔ:v°gS²ÎâºÁ~2ý99vÆÿ˜¯óN;äRˆJžÓ†ÓÝ~Ì1·™§ºÿ×®NˆJ†Zº×üž:ëÂtÔ©9w=óÇ?zYP‡¡›b„(¢‹Ñ‚Ö%¶d=ÚÙ³­31t}†Rbîx($.‰#%¡©`bSœØäuÖÝnÊè>Äæˆÿ7„T˜6ƒ8M‚¶¡íÒi) Œ¨D\‚ºÝAúis߸ɱˆ’¨¤¯ _›g6/4ÆÿFè¾ë€Kžë¬ØƒORbÖN½Æ!ÍÕJɺºç‰û¼øâ‹mâÛº‹¼{Ь`ø8ÀòyÆmcmæ=sË¿û‰ÃÛꉧ+bBA’æ<Ä.2œ®cÜÉXðK–ã;bÉT°Äš³+¶Œé3b°ïY(&Ô¡±öR£\s;¢¥9p·*wÄÏM¶¿(™ÖÎý.ˆÏ‘#G3Ùô£3íw; *ß׫¯¾jgžÂbJÉø¿l£ û-ú´;>jÀÄ0i5àüþAbÒâÇ÷y˜iÝé VK…$#ÝGI¬’{bö3í§ž‡m ÿ¤ëÀûPÏ9®öÙU2Ìh“MaßÂõ‹Ö»ѱ^¯Ý¹«•ÓYévŽÙöJPW‡v’'´Ó¤ÅUï}¯âÇä²÷•–¬;Þ­£nz× öÜú7emªC6E‰Ö ÜíÄ‘¾‚õÈtž¼¡–(YÒd„ÄÞõÁk¬¢[ ^;¤‰KS§¯€›=.©ˆ±<™;žqCU\&Ö&6¹¢3Ilæ¹ÛMYg~+Ži6¿½Öý#Á~åЛ‚ãôQˆ­vÛ%mLA Æ…¶èv7+ÞÅýy°Á"ú§‹Dî~·ù<¦M3œÓ¥ùÄ"[Ìke䀒\òŒU;µùöÁgFó¯dIë–¬PTáI}8¢.ëJœµ3*X)“®T`bA‰ÆR‚ºç¤$’¨«>Iˆê9ÓU,ÏþøM[*î=È6˧Q2jv­Œ7PâÆÿDlÔ“s gYëJKh!ЍÁ%Œëë.d®u½wÄïrè¡ÿb®¿Ó¤ºzº_ƒÃåªp/´¥ÙÐþ¯chìÿ^Ù=æ iþ½pK' !iºyHM ñè¹¶ÜpЩ¨NùÀœþ^†Š:äC샤*jÞ<;W>1¸ÀoDåwzòÉ'm"ã©’¥ÂË)¯‹‰P~ç^i Ř™ ˬ$1©ÿì æSwªµ“uV¢'ŠÚ©XÞ'ZǬ“|¤ÉHÕæ:¾xó!²¾:&Éx­ñhzÑ38ýy4ëÎWøð¯˧֥Ä2ª4›F³Ñ÷ê nÆêà‰U2plpcp³WÝ:º%è¦NbÄèGŒ:Ø–9ô½ƒ±AûÕß®çÓ"‡KÃÁ?°Bµ˜u0- g]¾jOÙ—É›ù¬˜pjN$w#¼q¤X£‰)å·A˜2sãšò‘åš¡¢žzê)ëñ€b üî½R„fc@ JWo†0¿ÒæÍ¹Êꊇ艈Ur×Ù_jå˜_m•¹©×Ù$¤[2—°¹.÷Uô“i‡~TVÏÄœ¯5â=Ÿ â>O{y”ßžsÍò¸Ùµnô<Ì3ïÖ?f~û:ÄÍX}ïª#åÖÙ.{Õ­£ÛY(ZÝ`ï_5UžZùæ«Jj‰mì‹ÖÑíÄ’ê8£ÐåË/= u†ZÊ&1^¨étcaÜP¦ëT¾¢q#…ŽzIËf9ÉtÜtòQâFÝ:}‰R’ŠR×Edº¢ªÃM‰˜DD’h”g­;Ææ¦‡¼¦þDó[O0¿ù¡?6ûÔbÎËû€ É{n Ú”‹ÅÄâZHÕ›Ý>Á4nç–ä¢.YüÞ ^]õ@œ(–O—ÑF€RŸºj=Mé’G ªuA(þªu¥ðŠé„GI} “d¥œI`®ÀT¡—®{Þ…¹ØÅ=g’PU^Z¸KZÃK’uD#–Ðè°qiÇu­¨…êht§%”šHŠa¬Ëƒ:ÈÆ)2„Â窫®²…\ÊõC}J®¿¨ ­ªúPhéð»Þ"4~ ~f§"V—O„)±¦ü.  ü® õôÓOÇÅh™6 Ý"Bݧ#0¹0Nî]öšÔJ:ìëQܹ뀋‰%ÕÑuàõlsc}mnÖò‚½x”¹y‡ÑqûÉDÃ…l³ FL=òÛ ƒ\¹ð5þ3[7ržño1Weø•S}Jü{u¥f¬º¯]â¶ózì¼AÖ Æk# HÕ¦ù&¹¾´NT\²>oÞxY Ùçž[`~^çwpÁ’IÒÔ+l{e¡iÍÎMµÿ‘¡E™i:™% ¾k1RÔr4¿õÙñéä¶mȳ6õ%JI*J]×&…b…r€yzS!IÙDØL(N­¥3œ:ŸžËsõ«L{gðzÎãžWcC]!©h»©57DmgƒCƒn¶×˜í/›÷¦3VäÏÁlGòÈ?ˆl®E®ÙwMÉY9•7¡[îoŽ3”úÔU!K9µ¸Ý‡®Ãk²Ù6)ZbC~”™ŸÊJgÍçzw“òôúw¦ºK5TÁª‰:4”i;Ù‡pp]ïî9£çŠrø…C¤"üù)Ç9(kÅŒ硉#m½¾Lœ¨éŽ˜PDs²ãÒå÷'A+[•}Bå¶Ûn³¯)YGøÀ¥—^j-¦@‰RA ÐÊÊ@¤A&“þ^ÜÖVeÎ7>+J«« L¡ó*[^”ío¡¶À´æ°Ctžÿ”È…Ï‹œ¹Ø<\ñ&-í4Iê†Nµ¯ãp-G ƒØ“ÀŸë+àf/šT’º.3©èœ`ž"Õb©³ ¹"µÊü^ êNÙÜ^xº³&éyÇ›ßõÐÜ<ñyq‰çá7ïcÚ á,$(Ùò„Åè6Ú\£¹és¤È·ÍûQ²Î57ÛÑg˜÷ ?3'±dÁ=^§B–2zžƒX凮<¸µâ4™•‘Lrfæ`ùiÅ鲸òíí,ù ×*IwPm•z{ ûâ\ô "kPjXJ\vˆÍÿøÇ6v,Îõ®õ P!ú–˲e1+&‚2Îs%m½ ÄDWˆP`šI2xAŒrÈ!VHU=ú[© üÌP±çMùøÕW™n8“”ˆU†R7/DgâbÎõ!C>®aÕLkØØxIø*°„¶#…ΫÝÒÖôg„ 6±~é‚e»ë¶¤Ž%T÷nq”lŸóNÙõñÉÎÓßW¶T„ÆÑ¯_?û[~ò“Ÿ´1¡<ð€µŒvnÉ®>¤tu°Žnd¥˜§¶`;^¬7‡\xóóÃÏ2{"w?™ïœH“™p#Õ1©õã>›Æ¬q]Œ½'¸rÂŽ¯¹q·}ÊkȈÁ8AévûÏæ®ìXbÈÜU+©vŠqç‰nc¬Ñh" âdÏÆà3ÇÅHQÇ~éÎí…ª=OŒÅ“NB–j&f䜿4_éÏÌW?ÜÛâ†mÊK2„'bk§ óĽ074<÷õ DÈn¸Ó|§Á5Paη®²IöUÕX7û²¶ yÉí¸Y° ½f:l…&Ç4ž€Šé=gËïåÚS¶ÛR;|O ´!ŒZQc= $(Ñ®¥/Ÿš¿aZŒ¸sêqnH íˆ6¦Ðæx̳˜š’u\åÅ\ç®P%C¾¿¹)!.gŽ2ïÆæq ÕÓ`e Ϙë> ·Tœ–gåÄŽ[ÆÊÀlìhöÁÈ\‡Ñ$ŽQWµ]E“ ý©Ä3î8Wlâu¸0Læs5Á/ëÄQG,gf¬\ŒŽ€õ“1)Ýߺê±ß[¼ ­£¿|‹¤fP“¡ÍX•QËìe—]&ÕÕµFØYåAYmê…¡5­­!¢¥åýæzdµ¬—Úm”îëLf 9¯écðŒE«Êÿ\uÍceÉk÷ËšÝ9 l!¢ÂQÅ*ßbôñÇWÁˆëú³/—úÚáÒÔR!ÍýÚR©xùY#®:öPÐðû¡ÄˆBÙ'&¹ú2úÀìŽ7'Š\|±#@•åËEƆC·`ÝtOÄ~T+Ó‡ôöÍ8¹;FèwÛ¢ÈY£t¡i]Áyv6,{ö Õ_(HïâiiÓd”QØ6ȱ´<¶0ˆSs;E·ÕóD·‘°­S×½5ÐP†:‰ÞÜ]k& À)Q‹gœ›ÌŠÓ0cuÈ+ýeÒøàBL¶©Öü4¹,ß þ$u¿=>°zÒ°O¿'XÔÒÉLo{2ÈŒ'ÞŠØ\f¾;w0a†dr]ô'š'#XÇàê5L–Ár´é¸oo]“M>¢¬7³ºA5þŽºn‡ÏôžSÂuJ€'hÜ'‰FÑÄ"7ù¨ ^‰;gÜq*6™‘ì´w›uçú`_4 1YÈu^H¨Ž3×ÃêËE¾rjû»cÊÌx%ÉUN©ÙñëeÕ‘`AK8‡ëU¯Kf{®ê=6ÎÔíâ7˜s\Õú°µü/[½ÒÜ ƒö¢‚2ɯSJ`ºNâÀ€êüóÏu½Góì_¡~…hhh°Ñ̼Ã0>X?’X¿²´¶HåZÓ–Á l6Ü}0T’&´©`ÁÏy@ɾ›o¾Ù®77ßlÞ{·-ˆ% êîÙówòÀw›ëvuXç‡v;44|Ïœç [º¯9~Ï cDLÒº¦ÖÜésßAcÍE²Nî¶Â”Aß)–$óú}FùÚ׎”³Îš'³fM—«¯î'ûê+å¿Y ã>öe9ùºklùÉÿ Æ*m?U2•ñç)ÒXBÑC ÝEÆ|éyr”/ÁÉI#åss»ë®»ìMŠ›– Ñ{‘û•¹Yžq9/nœWN‚ßQÉ…­SwFÑ7ClžtRN„ráЧ™cï»ÉÜy˜šN¦Qx\X^ÔÒ²Þ¼WÓ‹Ò\9Uî}áæ ßkucZÎ<}žœ17rD¡Ûɹ0–!™ò IG͹Ýú¸×±nºç‰n‹¬G¿ã8’ˆE„c’u:Ì%¿ýÙFY|Õæp«X·V Ðó ™ÔOv­kÌ QÄ*ÖQÄé…Lç×½ih4#Þü(f™)K–4ËüùW› ýÛ·å„É¡¥‹¤¢Js^†_Úc:Äè|ðŒûɰKq„ñ­ƒ§Èòsï“£« *9qŸt¾Q«ç⊠lüÖ!O;s¶ñëÒΦ}òÇÿ(:å•#Mé.:óÞi®©‚¸mHÅbܶ4èqÄ™’]¯í2é\´BUðð ¦yÝÅrÓÏ$X0®è*Óa’1ïô½ª%”k“‡uÇ'mÂI°æ+÷dΓa5y×.×ó -¿56èø]7Ÿ+W{–¢|>®Õ¨5‰Å”zî~ܲÏ×^{­¤ãâ .±¤¸ò“ê$Ñ™ku¶Ïî†îša“¢ÜsÏ=VH’@T¬¥<”ðû÷Ç`óúÛð ‚`<öØcÍ×,ÕºC*l0×»éWß0×çlÓfÿÎ<ˆ…Ú¥±ÿ©ùûÏ+!çœsŽüô§?µß;¿aúß®I¶mÛigbbV …ÏËß«™÷QvïzSÆì><\ÙQoºÇ!ÈõˆP,œ|wjéÔሢðËŠexûöÜðpÍÍ+@Ó°eóinÙc¯}F(Ghç´’‘’`h®³Î:ËÖKúþ»‚.93×ptD$aŠA(“¬–*()YCߌ'{­P.¾ÿ2Ûvžk®¦"ýL£ÑY^èÔ4I‚Ž·¼¡ªå99ç´ƒåÌ3Ï”·¾õ­Vˆñ=hD{+K¦êT+&‰Jü¦}\'Ç;û Q÷ؤqo±á—&_”2CcýŽ›ØDB <:EcCáb'† á9A†šçθ§'~«Ìo»ÉüÆA|æS†Êô·„7D¬Ÿ¸Ó™÷Ím/@Á¸žú®Åô¼åRÎÃ2ó¬•9™ûl É„¸Œ P,žP:vê`AÒá›t›vúµæuäÎj[zŠà¶!%º¶–4w¼Â>%Ý`®‡ìƒa¸2z<í YyuC~ò!¥»Þp¹×›û‰j¯0®(S¦„k ¿6i; 6Õ‚Ïu|uÛ#aˆÉ¯²á&'ªŒ–F”– Ž›ÝŒ†¸Ñ™W:Éž4æ'Sþ!@ÁÝ®$EÅjší=ë]1K(¢ ×;±šM3w¯ „¢¯ú´;¥æÈ †¦µÒô/£Eî ¼býêwÉç™¶j¸ìßo,É,PÚÃCuV(–„éÌ6î:Ǿ¼õé|ºäUÓ‡˜ý*<]Wûá‡nÿ~D'P²®ÉTÌßN‚`E5ëyÛÛ¶Øõ8*XÕÑc†É?ýÓ0û~\öF‹gq_ïOÒXBy˜Ã ê~oÝA—ÊÛ¸~€kœ±A‰¥Œª–¨Ze½n},§,ÓÌkMÈCd&ujtzޱjà ûäÌü«XB¢gœqF¢Y>Ä#V, îœòtšI¨U§P²RŒE4F§ÁK N<¯öÎÝ`g2QѹuÙ¾v±¡*r:¹ä%Ìôæ‡ÎÎvÁou„ùm›L‡÷{Óñ]$+žºLjßõDànÇ…®ÉIÎØžy JuàúóW‹bß„¬d4 J7±#pÜ’¿Šœþó ”›/óÇ«M9F¨ Ó}èázÄÚ qÛ)5‘éÖÊùNˆÉî¼×jÝ"ûäÇóò-Âk&1~I™ìX'±d¥&‘Œ¤âR““”¤ã¢¤«žÒHôUy®t\ï ÁµlÙ2³‰Å”ØÏ(ˆ’¶½MR±>ÿ¡þñ›UÒïå»|àbÓÌ[µ™¾ï‡ Η}‹î›ðC{½ðù:› 9–c.¿»Eª¿)ò•å“å#Dáÿ™rþÏ^”&ò4àXD§ŠÏèw˵ÍÔ´iÓì÷{à oÈý÷/‘Çï¹[&ʟɯ%’µÿË_’¿ù›3äÐC;X>ò‘»èëý ×J1}ÃCƸî¦C"”{þý÷ÏI‰û·Û°AJÉØ  ¥Û?ð:+Z¹Qš'v£`ò³–´’žPOWÿQ‘ÇйùÛÁ>…$ S#“×µŠê¸‡aü&g@ˆ& ÎÊÓf»Lz„(.xí$‰%åâO²hF­:¬G¶eÞØ,ÚÍç ÏðŒ›Ï·º;Ô’»îÆ~**JñÙ–‹ ÜOšë[³ç±ñ¡yõ=æ•ù¡…1:¹ø­Ì÷(™Ÿå ÓñM4¥éÈ¸Æ Ý<øèœ•ÓžH^Ò)8¢#NJ÷µÙ7ã͵rLsÐxꞤӥóµ¶é¼‰ÅRD2Ó$b=R!êvôI¤©Sî0ýfÜ|ðqlÛ½M~üðmYÚM1 gTHÒæâÈ{4 •†[Þy0ÌZG•Fó{Œ9IäÌËDÆšɳÏÛ: ¥®›Î¶ÝÓ°‹{ãqï/ܸÎ|¯Ða'LBÒÐþbgXb§ožlOIôZ¢ÄŠïf½ëvµrŽiùi6‘éhžgÕx汦½åY?˜u­‚õ1)vaªSJ ..8ܨ@KzË-·Øî ¹âéÀ5^2I¬ŸK1‹iôç @@F-¡:ÜÎùË_ìkÄ'I®UÎÑTÝ&­Ç.C“¹¤Žx¨Z~rqÎjvë%¦žÙž1}Sû?+™Sþ6Ü“³¦vD k åPØsÑ¢Zs3ÊåÚkw¶[ö9þöÛuiz`Ô¨FKHÙºÇiGû¯¿®•wôÚ°e¿Ö̤jͬÄnù>C ‰O1YœŸ­Ùç¸}Ÿv;n)KöY²Ÿ4ö¸R˼µ«Ù6–{³øÆòÒ¸è k¡iüÌ|¾Ú|¾Þ|¶Ü|[s.Lïz±Ù²o¿ÃyBN‰½!q‰-û©÷K¤öˆs¥Î(I+Hß$\#µkפÃ>;v•F¿Æ([ök»ôJ%B5vé)¥¯"µúC){d’=Ç'ÿú*m<öÝs®ýºZîÞñSÏZi¶«­MÛ¯3mŽ6X:hêxšÿÓ}d;éµc;9á¡rôÓƒÍïo°eøçí¶e™mãµ­7„öYûšB1æÖr?¸Ž¼öï9ÖØhî!«e{JíÁÓ̵yÉlß0×Êo³Ö´yÄ´y´1[öÝÿä¶éøÄ^òÖ“¿•gëö“ëeŒÔÖ9mÌ볌ÒFyïX_*é`=z»î û¹£¯èÙ²¯Ÿl3µ >Û*b¯oñpé9óÖ3í6’ˆÆµpZré‹EfælË>d•¢÷©GçP* ·<Ç› &Ä=÷9ð"#·À ç½Çö裛ö!>Ìxu6$5z.Þ'j s.^SŽªn¡yz–JA«åó{Ïä”!F8±ÞkèÛ»fÙãd땳Ö^ï}BMÔmÿnù‰òªÙ’ÏRŸŒT‹Û›ÿ™Í®S m)Ϥä1héÔsî·ß~röÙgûG[ÎÉR‚œ“'¯£ˆ(Ä3Ý#³qÑ0RtÇCبˆ@ü'–>šER9©}ád©þä 9óß½¬åsæpOW•78ðžîR?ÌÈQ ÄŒsäKB!|JBá!Ìç÷ã¥Ä(ÄB LT˜8;:gÞù×[͉ ®ÆËïè}io¹à.w½ùÂèFÊ0®_¾#§ìñ¦} åF²KJ¼ÿ6aB Ǿ^WˆëŽo˜ê’_ýêW¿ùÍoüÝ&L™2%t–‹ª¸ð²Ï> eæÌrÍ5;ÉâÅ]L§©2¤²)8£OŸJYº´B6Ýtµ\yåsÒ¡C½|òI¹ì2£||\qÅ4£¼2@ŠŸ|"û]v™¿×„iW\!+P=:š6C›Ú¼0÷wÒÐØ^VU{~ù®æHiIì3äçvL›c>_å}^A‡uÉ®…àŒ1N¬—GÅ´.ÛÈŠòt“vT›²ÆzéZ¿VJMGßgoé1àýÅïö•¥ÿ¯©,QŸ_.”Ž;¯•†ê©›Ó^kJäËŸûÕ z^¸D–_»‰¿'ÒïŠùvûÅe~Y$ÎQÚ¥AʇÖHiO@j>éֆϵߢ:õ=†­’ƒüŽéM„eÚ4s=W4]ϲ²j0à£×¯õxmV-*=êg5k&e›K׆9²_UÓ½›ÖÑœ§,ý¾ô¨7÷×isĘŸÊc7“M×”É_ê)‹;×KMi£ü|Ïô¾£è¿¦T®z¡·ÌéZgë*®0Ÿ%ÔEë³µ(ɱcÇZëy[KL U°Åè}×MöÀ UÜ|úÍrÆ^f²P¨¢HhÖ<ï‘J…ÛVÉ,VR¬¬’ÕÖ–Jˆ¢ïä/[Æ)ˆ Ð\QGXA[ŸhYÏå‚2qFéI;s¾Æ¾"›™í;朙I›¤DV=Ù÷>‚×`…€* ’Xï‰íd’DÅ'–ÌkK÷²¥–\pz´”Ì„¸˜kžf@ª£n¿LPÝR)Ÿ3ÔÒÍ{CÍ{~ùžŒò+ŸoÎSkÎÓn¤Ô 2ŠÅ·´0{ä?3Ø2ËbÆE†¡Æ„êûz-X=Àmô}cQW#å^/%«¾²–ͺ#Îk6[ÌÚÆ¼´tõrièÒSê<ß*—{vš-«>7Du³29émÏÊ{ï.ŸÛZ ]‡Ó(+g×Y«å7$wmý™µš’4~Î)¯(•ûF._ϬµmŽ}~ˆ¬ü¬VzmÛÁ¾ê*²¶1½Àü×ÝÌ÷Í7ƒ¡¹žu¸]õæ™k]n®u‰¹Öü&s_I]ÕsRþÄaR²Æ‹ mì<\ê|QÊŸÝWJV›¶]Ìy1çÁýRJŸ-e¦Í']úÉN‡ü©¸%± “.æþ—ˆ¹:ö¸â:ÙCÆÉH›tÄŠH¤§(嘦Ë1ö8‚²\‡rˆÔ¶+ m÷›x»¶HBÕúéŸÚõàÝå8ƒdI-¡ÄM1@/üÓBéÓ5 ;ò8{s/̽£´ÙðwÓ-•.‚DÓµjÉ,–ÐÅg‡·uÁ`±“9'–J,žn¸ŽÂmia²ÈKé7Ú*aÚÎ…¶Åµ%Ua ï(ÏJ‰&âBeÂH¨ZB±h*¡¸ÝÕê©€L²ì&䔾|kÙþ2º¤os÷ºsNÜ󌈜‹ó¿\{„ŒÙi´ù[^Ö:V0–àÓý ëÜ%¬ ä,?ÑK(1„A#„Z-³µ´ÅúõýЍsrƒ×T-¡„:trDÑûl2²¾ƒþ´6RÃ’cX@!¢d½wìèdéĉK¬ ´ÿþûÛñ²Wé{ hí}MUOêÞ0cÝo¥îŠ1žrqÀþÀ¢¹âI8äˆ8L\Áü§LÙñ+V®!¿âï…ã[;}Kþ1þ±Éx&46ÔKÕ•†s ûö÷ü½&`­•&Ý^uò©Òñî©þžÈW‹ 9f,aü ‘by¤ŸdºO,×I8ÇäÉ“ý#ÅA^%špÁÿáïÉOº½dÚÙZñQ0“jÓ©š .¸î®1#4¢þgP1è¬:L±•áÃ5è*4”£Æ¨QßмÁ¤@=±àB*!˜ü% Á÷¹>@k¹ïSžB‰¨ñ$™èëÑ =îüËüWÆùMi×ÉË2gvK2±'+!)ö¾ª¿ôÙ©£ô]aÛ…Y ˆ%ýüÁ•2è .rÿÁ†l† èú=”l"c>|Ð7×ÓfÅ£ÄÜ›gî‡Up Ìÿ\j”üNar@âñ¡$*E•n2x±f–|ùM¶@}Å-Ù·ûxéÒQJ2!¥˜ƒ–$u‰ªå DX› Ö¥’‹óÝÑ÷‚1`»´å8ÃÈDôÁw”£w8:œ€K,½’fÖÝ>, ÈY fÂ(3ôð&˜ïgmyÞÇ=ï–j ;wÔ`¡ÇY5͈Ì+_|á¹ç$G ,ÀjʘÂq% Ll9_áÅOPÜóea×h_¢¤Ò‡fû?Yaëyºp j¶~ôœURocž7¼¹œ¹ýþžg¥T°îs€ "–4ÜáŠ(Ë%õ8í€Ktè‚v|?ÐßuMƒc`66JŽ$’Å}ÍT3¸nÔ ¥RLmmtíà‘PpÓë·È™sš–n|aÈ!²ÏÜ'¥~èD©ÝTϓϓü„53. ™¸Ú©ÊÀÿBjÈA6JßÃxk Ñg„ uqĈ#ä‚í/°çÔÒ/èlµvh.¨‡T¾ò¸4ÎB÷¥ã{w'S^-ãÆVË%ß›+»îjƵ„Þ,§Ë™Ò´bÄ«vÂ)3Æ23Õ.•:>o¾ù¦½G›lÒäÑ âg?û™ík“tQ "!¯©cõÁÏK#]˜þ—…é¿c&Px[×ß]0.1~¹ãm^7<&Õ–7©nB`bw¤QÛxV@ ” ÍÂlžî‘ÒY[yJÏV©N”%ƒ”&#±…€RªÁIƒàûÎçž{Î ¾Ï¾¤’’L *ã]Û„P sܺñ÷t!’MƒoºKæÅ‹˳g{µ@ÝD$¶ì3€C*Inºg·Yd#£Ä}è÷QÕÆÜóDù• ¤Ô>£ÝÍÓPÐÃÐ.ÎÀD &%œlŸØÃ+áÄ:ó$)9h(ë$oô–" “Jö’›KšjÉè¾eä]£ÐÃJßöIàQÉGÚ&h눽¼Ä|$D¿¤™Ý²µ‚"cÈZLK@Ù²á„xš)æ4j°``a€P*á„TB@$Ó·²Yb Ù´R+ŽZÄLhL fœEÀq% ö¸[òX;R¹[ýl¼27<À’éÆtÆíwÚK)°=zøÎ–P¬‰ÄvFÅnB ! €-û?ý<[7ÔEÜv2 AÍD@ïãÖç™­mó1pã9 L  ,\àùPÑSrÛ®]¹œñª¿:WCœµÛòq禌z((›s»”¿ñmû”4ÄOLÂþµ`Á›8…˾rI„¡íwwú®,¾|q3 n9ç^°ë®»ZrŒa ëÞK/½dŸô}­™ÉoÈ„Ç:œ/Wví-×:V®ÿöåòÑÖŸØãïo=Cn™x­ümÂdÑÃÿ’I×טûÑ`Hž7Ž}¿ë?Ü×Èsnš¼ 'à_¶¿ãK@AÙìÙÒáÜsíëb#NL(Ùñô«b£Å’L¿Ñ±Ÿ-ã:“pž,’àŽÿŒý™àê”4ÒÊÀ4ãe£@Œrù‹!3KŒÂRETlõ¾eõ¨Y—ZÛYEê»àØš}fCZ‚€-ûtRâixârw‹ÿ²¤'€¬âöû|ïv¿€ÀâÙuXºÒR²È }²Sç“}Ž+©\»¤^Jü>¨$5ˆ0"›(fsF‰Ë óô i¹Ùù–W´ž'%˜™ñ,Í©%œØ.ó-i>ÈþõÜžòžX¶…ì\Ú׺ãÁ0ÿ=He6e¾´¡J¶ªûWSÂHÚÚ3 BaŽüû–¹®‘±4¸ç)3„®ÌËö9 ³S·JŠO¦ì@sÑEÞR¾/šþä%;(éE¹¡±c›à[ýuv” cU$E­™8^o&Q$í[ºiVÒ>Õ WŸŠn–`™¼ùæ›ÍåðäII¦ ˆc‘Œ“õÎqým‡5ŠX>¶Š°c H÷÷EÓÏ!Ž,Èg\òMLRçè¤ÝNšW_´®ø½~§l¹&½,‘¢lîíæGÕÊóç-‘·÷ë&ïýÄ1¶D€~õ›%>éÄ>à:fõ5:™'¿-ì?ûYѾBºth^Nˆ0#ˆ*z×óV[me'FLx¶Ùf«·Y’“¬üú›¨— É×ßý }“[º¡¬AžÙÿ^ùûyç÷LÖv^)“¿=U:ïs„}ŸÏM™ò¦9Ï*C´×È’eUrÝuÕR}Ë-ÓQ:ÚOj å3Å×3 ۶^PƪW_õꀲŠ@¬:ä+¨‚ñ—iLÂH¡:¥i-3d³Ìw碨Ôåg›¯d°Š–6%çØu©WÞíÑ "5 °|õrè»X÷.@P>ÖNždÁë`,¦¸è™Ái iÜÚ†¬yMö;ÖÐ/Íïr­¢ êxìü£ôzo¬! ~q„|bå5ï+ÍÄïÀ›È /Oµá‰›Áóžâ„ÀzDv€!²\óLJ…÷|%n­¤X—”š-±º›˜Ž± dÖ´e™N¬Ÿ,Íé‚õæµl“ ¥­YÂ`C"‰õˆh£µ4i²‚×Á9;×ÿ[æùn|bëÞ”¥6!)!£€µ2PÒ,ÙÈ*ŸLüêÍ„löHs ©Ìö9 úU2ì>ƒŠÊ'.Û‹/ö’’ˆÕ¦(1ÖLfÅ:3&`}_¶MÎ ¹ÔMÍfÀî÷߈«ÎŸýb† dq‰f³È(‚.! 6›µ2H$A.Yï|žsBnÉà³$±…\ð KP8<Iâ>O‹[YÃÇZ%%)¢gˆe»y†`œ4çy¹cPxòMýàñRõU‰|r«ª¶è¾FóÑpªÅ¹)û…’~DÙ(u «Ç9à ÑÖ}þ#îyÜļ¾ä¾K䄇Osï ŠEˆ4ï•>Xzw÷Ö‹Å$•SÁké {€Y3O„€D%fOl› ¸ÒYK¾¢›ùÓ_‹<Œ[þšæîy¶Y ÕY$HÚy‹R±á–ɘ¿lbŽû¥™v˜)wíà¿6mk̳Ö<Àº¹ÙÑÝR+%Ñö®í?µq¦”hblbød» *"%,\Ëhñ^° R!eë´YaΧk¯/ÒÉŸBpü›l·aJ…c9´!F´+1£°?äeCÌMßÕaÈêJ.©<³aš=¦P·<±qUá„”%§¼§qtÔ[$®T3êɈW›À‡GìÅÊX€2$æó+2Ku’hˆ.G{/Ã>ܤDõ6`éÓY*3Vдá3[måÍnmÕjª‰HX¼æ™þ8П¹3`¾ŽºôÝïÏŠ‚̀ߡÆLø¦~Ö_j?˜gÉš*|&¼¸ÿ[w2ì‚öAkið$«ÎùçŸ/‡v˜U¤aÖH%“Ä*³œ©T’‰ÅH˼ðYŠ¡s>ñ©ÙΗ 7@Æ‚§–P=§Û·êF_/ÕÇ~%›®ö”syjé¡ju…Ô®mNT>¹muÊZ³¶ÖZo±¼cõ¤jƒK ƒÀÊKè¿G‰)¯!MôSþ?¯çÍ™'‡ 9ľ?~×ñ²ÛPoR¥¸ü˜Ëí5̆¹ñ³ïèÒ½B>ïùÿHfÔ–®–/—-¶VZµ„¦Áüöª‰ý‘Gþö7ù÷wÈ¿ Ù¹wÊ™Á„¸ÀoãzÐg2a½!¡îØîŽÏ”ëSã„Ó§›[8 ¥ècšá|MP%¶„ú:³1[¬œÃg5ɼ˜|«D |NÏpésމj&ÐïHš{àë½5)&-d¥RÐ’:XdÜXtí‚ÖÒ°cD ¼³FºdÅI,©Æyf¤Òu÷Ï0„^]û¸ZÝïæœÙΗ å@7qï[HÄ«ÙyÊ+RÑ Jºoæ¿jŽ.X"û\nïù¹|ðÓ:K>©]Z_ŸîªWRÑÄÎêH¸ÁqÙSÏ’‰“,%’_~ù¥µ¨"?S¿3UVüu…\{êµr÷Œt+ã÷ÿý}ûˆ(OÜølùz®l0´W¶«™`Æ?ÿHW³Ò¥Öã—%3?ùÌòVzâ7“x™ãû(õÀ7¾!¯Ÿwž¬<í4Yí—Gªóe}îf›IƒS.³XÐû›ÉÊ=Á°¶^¸ãݱ]ÇgÆnHhÂ,œ®.P#EZW‰ÑzQxÞï dëv?Å{maP¯ï›+ìeAK¹9á0sBׂâC†(BÜìšl„"Àò©¥—‚îz, ˜í5¦4tfKþ˜ ¥î°säñŽ[Ê´zGébÅêé·‘#Ïó¶NF|‚‰GýFwJ‘IÐyP¹=~Ê»›§%'…›€AàÄ×FÈ7§ 3ÏÍÌgW™Ï|`ßó®·¹^6Æûé®/`·î ¤íÓ†ëÎÒœ”fR×£ŸÕ}bG”þþwC¶}—"çâ3Áó;ä*ì] å¦}Òã·±è`Ù<¢ P$Kì²Ë.¡ "ÌZv ’ˆRAÑoµF2fiÂK&iï~& |òŠ»Ÿ$&’™ÔµÏ6xNÀg²¡Îüö¥ï¾k·™·ÝÆtý§¥%¡Ö"zܪ42úô”)rã)wK»cÙ§·¯’ù÷yzzÅ£åµKVÊyç=-]»þ]¾ým/»^ ¨~'‰CUôîÖ[omû¤yöÙgmŸCV¨qI_cÂår¿ç­{¤´¼ÔÊÿ ýÆ÷ñ]JJ5¶”ßEL7ùåÙbûmd“7·•M~±©l±Ó6Òñͦէήš!—¬Z&§TL±aÄ—Â#øNœ™¤QY‡0ðùÈcGi_»2w®”æQ6*Wèµæzdä¹5Jœµ˜„ÆrÛo0 œLÿ+cSš…ÓŸS"ëVKI!¨Äz]œ¾ßU^”@˜íד̕þ¼4Jk3C@ì-SEèa†PB,qeÑÙ•\2+p-ê–u …!•_¼rÍZYn¶«J|’éZ=!ž™J6…Àµhò„pB!‘ã>ÞºÞÝ6AW:óîÖm¬û~v Ü·³_kt¤i³­}ê'r²÷24ö Ü±$³Uð¾ÛÚP#´Âüw€õ³·é$ºn¼bZ6°!žnR†k)ýLVÉy/ÉȆ»lÆLä’bô¬ŠV”~}„«³l'Äså?Vʪ›WÙmM“9C&ˆÁÆ*:;¤ô™ ÈdЂÊ0,æ3¬mˆk„XB(ÝÀsˆ•'¶>Ñw wÁy8îcwÀÂ5M<OßÕlߣƒ[ RÅ@´PB:QR¸¬yÄz¨$eH±nUA`)U[öƒt9Fbç8†â&©Â­Õˆë?˜Dø~­)JbRT"ÇÈƵÏçq÷k(÷3|wÜs* ”žp‚Gv¼¾ÎtÐ0bÉ>Ä”YO^Û„N­µEëKJåÅ^£¬e4®Õ3. š÷íbIdét¡‰MÔ ÕÄ&uÙë{÷î¾Ðlï5ûæ:§¬›X•ül·¾•)YÚ“xô$ÄÂÜ+ˆ(®y‡|âZ× wÈdTù%,¡ZÆIQ+ò`ãoãEêY- °e? õ_˜ö+Oá°e?Wæð¤â®Í}úlçh´ ²8ŸóÉç‰évÛj% IJdä,cP¹ Þ#ÖSæzQ¸ƒŸÑ‹8"Ü1Tˆ/ÊJßËöý>‚J," þ(>-ʰUe¨ ø¸‚Ϩ5÷£*3¶ìóYH –•ï €´Å->¾sŽ{2–Di„¸º% ¬XK!­ºå;8‡¶cë~†sA4i‚çäý(¬0ï¯b<¶ì‡!n»è¡BPúý'#ŒÂ(íÐ^¶8Ý#(ÝF†["ÛuõȲeäq>|ÜyçÇÒ³ç?ÌüòfC,o”=nþýÿ)}ûÞh·ìó<ùäûìR¤XF™ü0Rk)IDeËä¾î÷‰Œ÷Oìàö×n·+Â) ^üG-¥Ÿ";QÖÒ:C^á•]xä‘ö ¾>~¹lÛ8N¯nJ$bþç¤÷Œ®ò«Õ­œcµEN³ï&A“ú/\y/$øo|_&0.1ž¬—$£ƒzÏ\0ºº c³2L’›Ü…õf¶ï*1UjLUd_Š,½Ô¼ð…KŽÆ‚¢Ü²¸ét(€lÂÌ ÄE@é<(í|A7þ.»íaÈò Yöõª‚  Èã’×+í6 ×òK_L_›–ØD©&uÙ»ï}ýi|õ>×P9¯õc%î½ ךÄ&µÈð¹€UjÅô&WËkˆªZYÙ×sºß†æý®C=9eË~â¶ÛÐf EAX"­˜1nËJB}ì{ý&r檑râ»Cd¿·K¤ó!žI´÷Q5öø„…ž—ÂŒ2²«ò4¬ZÕDõµ{ìᇿ]wÝÃf®×Õ5˜9¢÷û Ž}ûö•­Gn-ë&š‹`úÖÐò~ž<9øHyãµ7äƒ>°“2âS9?6âÉõ ³–~ðÇ?ÊÂG•vƒ‡È‚G±Ï‡.'}ÿm9¤òZ©®7¿ÇœæŸ|N^æ•î¯í#u%)|& K,MH ¯¹‡Ä”÷ªq±ìSÏ4î½ÉÆ‘l$+(X/I(F,žnXÀ+Ƙ¥¤Sf̲Û0"šÑ]¨H[1Ia:0Öuý©ÒËàöãÆ·AmP¶aäÁþQÓ!³µyðÁ­Ò`Ë>fy7ΔŽD=ÒLçÉMÖK¯SˆÚ÷w˜™*¿ôôéó¤ûO`°€Ž<¹‡% ´{æL?k߀6šÐä2jn°% †ŒÈó ¹yöØæy˜yr>:ŸS2 L›†x¨³«!«=šH­ëb§´5>Ã$Çv¨»W.–Wý#"ý¤£Ì.=ÕºíKhµdÓ†VIb½ø×~úZÚºña(iW"ݾÝMºLì"GUDË2DX ~ Š\Úº^ öƒp­¥ÈjZŒ·9®â¢Dƒ$˜ä¾Ï–}Þ£¤Âf¼MÍžDuÐâ»N<±éÜJTCÖÃÁ Ol'L•žK(;¼.¸éIÚ€db5düÀ¯íù,Êì¸ãŽiq£.áUrŠ…“¸M”š‚M7‰ˆ6@]èŒIXµ /\ò IÅÍOÂdH‹Û3éV¢Ê–}Ž¿+ åæ7qß}rèÔ©vË~â¶Û¡‘–ê’\H(X¹ækÛÏ–,],GÜ1\z¿ ýiµ”š±…§ZKwÚÞF¦OôÊË›“é(\rÉ‹rî¹O§¬£¼J$A—µFÇž.rÕQWÉ¿ÏF~&w–Ü);¼¿ƒ•³E‹É믾.Óž&‹'/–š+kdõW7»f%^‚V™éßó~Xþ1îÿÉ·~ü¨Ü0î·öý…=f‡« çt”¾ow·äóŸ|ºørixqÿ %Æd„U(Á¥%¢(cĸ@S,ÃTÀû«µ”û›„ò}´É$·…BÁI(`lwË-±r…ìñn)é4clÊÐÀ–ý BÝ…H×¢™¶b’bغܤ]¥ç*9X+3•[¢£>ùä“)[TI&f>©™–Ù²&. Î÷ {N-£QçÉnÉ&-Çä¾ïÇ~‚UŸÕÉ7°1¤Ü8Pê ù\òz¥|1½2UÖ Ð¦¹kŸk\׿×Ó;æZ|èÄÖ( `{·‰L¼¬p„Q~åM¤;¥”Ѱ2J›å—ZRüSö‘Å%•)²éZ-Ù´¡"—e;AåC•²úöÕ²òŸ+£Ýó„ÀŒ0}9¹Tð^X¹%EÐZŒñ®÷g«ÀK()8Ï*î Èk}Ÿ­¾ÇÖ퉚ñI¬û]¦ë>Ö ¶¡ë™S`eá©€8`5LÈ#[ÝW—½ Ž«KQÁkH)ñg.9…¢àdª÷1¿_“ˆ‚ P=n@…ˆ´’×[o½5ER±èBš9—kMUË'ÇÝï"†3*©BÙg‡RÄ’6õæÚÛÛ%ð ñ}­EBùâ—!D'Üã=zôòeiÖØ}&õ“‰Ë7“1×ö6$ðlÓÏ4ºï;rÊ)››s4ÊØ±é^€(L™ò‰uß+xýÜ/çX"Yýpµüæ/¿‘¹ž+Ÿýñ3™ðîÛ¦{—ÙÝnU;9d«CdÇe;Ê^ïì%{¾µ§ô\ìÅv¶›ÕNæß>_^yéû¾þÏ×öœ5×ÈÛÿ÷RWZ.ÓÆxKm>?æx¹~üo¥dè0)ëX!“—»Æ™æø›4ÿo®Üfm)e5tèPÙ~ûíe¯½Ìo7“U*õp¿‘Cd7>nÂnˆ•ÍÖâPx †3íWÅDQ¾!8¶O0}bê’N€ÁAAÌ¿k¤ÍÜ…}ª›[4]…f°Á‰mÊý/cbÅA¨›ƒ-û. ŠJ@ Ëu—à†ÃÂ@ÇàÆºnyYÚ)GK6¥[/ý÷}Ë' “¾×6íZóXGo𑵢>{æB§¬Sƒô³ÞLn ¤€„¶X+õš³m~=½cÎ ¶Öjܯ(]ÎÃÖwÇ¢ëÐíVçÑ9(µQic?g”Ÿ"¢Zj)ŽiÉ&Åwäå4«'m‚%›6V`á¬SkŸu ëRijqe£”tóú®ºçÓ\ÆŸw­¥nŒ÷&/‹ììÌVAd°¸Ç3½\·>[öŸqI,Ó=—ž;x<&u%•·; X7°Ì0&°\ VO\îLX9„º ë†wRÁbâ*— 1¤Öq°²¸„åÇ1µd*yZ ¢™Éò ™Œ›TÄ{Ož|²TMšd·™ÚnŒsÇsŒ~’‹3 ôŸlç`¢ñAŸA>±°+Ya«‰8lí¹Ê¼„#ÞëÑ££u§ßu—'Ëñã·´¯ô&hÆ5_~3ˆòÒÙ³»¿ì¯™*áÔmÿóaiü Üb¸éòMeçWw–~ïõ“޳=½Ùø~£Ì{ðaûÚÅ {/c/{H¶yr…Œìîm âÙNåί<QÇ@ÒóîÿôIDATET…z/ðVÄ!{\C&}œCå™8mbd d¼a ÁZŠR›£÷ɵ–Æ!¡XB[£F(( eüqÇvöƒÄ”ñœ…†t¹Pwa×3»ÚmIÃÍ-š(4’“J)Éä I®µ“lÞFßRÖ\~-¸®“}”„ƈIê`…Þmè$”hpÁ¹ ¢(=ç£SF–vÊX+OvJ6­—öýwG:å—6O+TO\(ÀZzàÍ}Ìy.3çÙÝ|"€[Ý¡®[¬•¸ÖÍ nVŽIÁ±wÍ“,ÙëÍS­«Ü?,¢þ}´Ç îVÂê‘ÕÊÆÑòzÃ\{äβl±o·Ô’ ŽQ²iÿ;ÒºÀYš«§mãdׇgc@iC©TÞäY>y®y`”ôôú$ijÛ9޼ù+[BiHFB>•à~˜­…(0ƒ 0>>q²`p ÌLçÊȸ*H$nj,3gÎLY9!©JTq½sœX7((ŽsŽ8e”І1 —~1táVÆ£åË—ËÑGm»ŸËD6yeeÍ%©ˆ÷VÏõdŸm’€ªZ‚L$”~Ê=',„Ð\ÆÁ ‘’PÎÁ]Ê1Õ{ ]»2™8q+ûšíO~2Bþýï-äö’¥KÏ6²qö½L¨kh”»ÞúÄßËŽ‘ËGú¯¢Ñu~W©nð’«ê—J×›Ný•ÝbqïA2³:3}ß»V¾qØ¡6ÞK&×Á%ÉŠ*þ*ë‚ÏãûÔÉ #jí„Gž‘-›†Ç”ûŵA^¹oÈwœº¥ÙÀ÷‘°Å„•¤BbKÙÂ7ƒ¨»ŠÛžÄ'BpëkA}ûʇŠÓqÒlÔtîç¨Ì(.Ô#<"Gyd³Y{60¦3®¡[ÂûYé„D*ÉÄ-¯ÖQE™QjÃÞ1í>4Wó~3µþ«ÿ†AiO‘áf¨ ¸ùüofwnü'À¢€"`Ü,˜´…€†ÎÅ¥¥C(œçˆ#ŽÈJ>[r]hÂO&VR Çp½xó éµMkÅmï‘Os]-ÙTË D”ßÌ Ç1Hcð†¡°õs(µ’rœ ÷;1j¼‡%"Ë}ÔóxŸ½¡ÖПz‡@0!‘q€  (4éÌç:Ç‘‘b¡%ßÍ}ì¡ÇdŸùû¤ˆ(VÐîçv/ éte3›Ë~Å-~v¼^׋|>ª‰tæ2(@"! fºÌ€](¹Äª©”‚à1¾7Û¹ÈÔ‡¸_AŒXFÈvE9‰Þ,MaPAü'÷_ 'cç…p2F¹ß©mã€Dˆ3Ëh6 j.À­ŽUR™-¦s­¹nÞ~»1q¢tʱŸ¯Kùl-@XªÛ’ŠÍ6Û̺~ó“t„`X!³œþ…År~ $†ß©áÚó¤rˆÕ'“3â!ªÄ7bµ sã¶¿è¢i¶¦(.ûnÀxaþ{U4^×4 +;·LJÛ—Jí5M¹ -E¿½zH]iîcâÀÆJ¹¯ÛGÒ·gÛ‘å ç:Á%ôµ^;wë‚¶œƒ§~®% –›û)å!/<ùn\ð|Ç”)S¬kŸ•!‹¢YBƒ@<ÿ¼È;¤ßÔbJ¬Zèê-(ÕT÷ÕÎ^É&^€‚ú…†ßl#2o¿t –‹ÌãY^%› †dª2ˆ»°ÏlÂ]I;Y´#A@µ [LóÙh!‘^nÉKXr“˜HBb=àNs—É&Ûµó­¨(”4îvÈ&OÖäW¼?\C¬ŸM½lÉ637=•%¯I¼GÑâ %ÕûÞáU·È µÞ5j×è p0Ž’™©ÜÄ“öѨ6#J¤â¬ ›ϳ 4KŠ4Tx %…cþ¯i`®% «j-c«DÖ„² زv,ιr€ë’GþÉl‡äáÒ$^œ§Ž®²Bèq&²VÝç|êuÇ*¶X0ÜïtÛÆZDã¸ðsE.IE´)<8I@Š@ØôŠZÃó…ºã!$„@l!‘X?è'>ÓI¤’‰ñŠ”ì‚CzèëšgžyFæÎk 3Á(b…E‹éŠç¦(hß±\J·ó>ö¼‹ùßíëåÓ^¾,|ݾ)Ù×}íF.— =)-(rf·ÅRµùtùjÔJë^#2Ä‚.(ñä‚My%’ ÁÑK\+÷ÿòškÎucBŠŒ#ïìsœ÷¹Æ\ÛBYKõ>Áu´´Ú>ûìcÃ+¸WL"ðìâÂg’€;¿˜hK¨k„pá´< I66-$&­Y›³Ë¥dþ(ˆ– 3- ±ª‡è¨Å.(7C½CÜúl_n07!HDÌÝõ˜¶iÇõˆŸáca~>r½ÆaÀ zן¦²Ýq½ RÖÑíääoH»9Fè†wyö£‰‚ß¡ÀõÑ”iëÅzâjç=ˆ7×½î$/qÿÔ•D¸5•ëD õ¬…æÞl;@†6v–Û_xDFw²hB*I8"Þrã§ Èç:¯KKKK¾»}*Lè   ’ŒˆñT­¤Áöß2O¯Q,ëc30È(‰ #Nî ¹Œ²„òY=5åȨŒ:§lוA²ˆü£X¸‡®¥’Ï µÄ€¬R†…1ŤIEîyçFI¨«?²­i'kÌxÖÙ:ÿ³±ïçZˆ¨kÇšº.å³µÀõ ú eô¥|• W-ƈ.q†\Ë0(9âw¨¥.ŒÚqnÈ'‰5.µÂ¡]K)÷,Š˜º øèY¼l™l·Õ–²I¿Mä¢ÏÛËíKËebŸ:™4Ü3ððŸùšàä¡Ð܃: ЙpÙ3„™VSf+à~¾5€Å3¬Ü’MRÒ$¦Ûº{Ì6¿í£°ÒE\—€ºà=½¹îugÑ€ mZFÐ{/ýº\¶˜÷Z#ÈÓ?—9o~ ß[œF ã”[ŠÓfCE‚BÛ6˜ K¦Ïd='äÒ×n,ÙNê–nÓÔ6ÌJê´—2Ó/ÊüEH¼ ³>"C™’… ‰j= kËqH&WÉ&OŠSCŽ¥Aç7¸5å–.Íüý!@ ¡d’!öQnÌ'cûX@€Z1•X²Å ™„T2ŽpnÀ1ê *hËû€1jÉ’%R³ÖœçÍ KùÈÛúŸMÇV®nzí óÛ§>l—Ƹë¼ÇiË{wœÍ°gç¼è Üó|A?$^D[,”” #J>ù.¤GIPȧÀ¢ #«>}–¸b|±ÄAÈxë;kÄSú‰I9XÿÂàPpCÕõrʲƒ-éܼr°Tµ¯²¯¯ßý˜”oþ’¼;õ™=ý yùÎ1²øÓìûÓ+§Ë/ýB~þÚÕR]é•j„€Ö×›qÑO(èTû•¼öê«ÒP[-ì¹» 꿉´3, â¹bteŠ€îYë=µ sM‰ 庑$„¥”'U2 èðÞsÁµå\LÆ a-¥ŸËÂ0˜ÐpŠI@A«[BÑ1dÅÃñë(¬0K(Ç!ŸºšË×3D‰kjn|÷ïu·‰ªè¬{žßdÈWé@‘þ7½¡‡é=>©„pBHqÉÓ6Ä ¸Z¼Y¡± TÕ¥sp-hï¶ã<$/qSÝãÙë5CXÅ=À@e‰¨ÁÕ¨ëܘ,¡X$ܘb¾›LH–R ûnd¤òæJi\Þhã=+άHyø¯LœlHA‹ê¥êCP˜ƒÐ-Œ\?23 ÈàšeÍ”­LÛ¦s•ÖO—òM ;× |I;îj^,•òù»IIý|i\P.%G’;`¸Ô ›ÎQnŒ’™3¥qäH©Ã=ä¾ï"×¶»ì"%~_k4}O¿»Ä(Áò½š~s#‰óÍï 9§{]µ1Ðë’}( ,JôoÝÇÍ…{RÁç8ãž” Yï}Ø9°–Ò.ì»UÞݤLFI“µ¥nûÍ¥±«sMŒ¢-çc)©ª1÷¥½Ôm·¹”¿ÿ©ÝwQ·í)›5ÏkסÔ"]ÌyÊLç1ç(©¬’Æ ó=f‚Hy%²ÛI.:äî»#-—amͼ¦_šëþÜÙgÛ×`ÿo”¾!Æd„’R­!Ÿë èî» ’L $Ï™ ˜¬ðyt}7zPžJlÔòE>ùIŠÄ3ŽÓç£Ú*8?F©ZÑ©Œÿj)åÉ~عÚ¶P—™q¥¤Ô5ÖJŸ1ËÊò5Òµ®BV¾„÷Î|¿Ý\'ÅÜ矕—îºU^0$Qѱ}¹ì¸ÕyíÝÙÖ4þ{H;C@ç.­–Êìœí¿Ä׈ÿÈSÿ/×–~«–Rž:AŸÑ{ãn]èDP B+Ü…,‚øÎw¾cÿãþðÿHñÐj‰IÉÈìÙr §P—˜v:¼“QpM¤Œ^2y-‚î=,¢ÁI@²ºC ë×èr.¹Är¡±ž´çú¹DSÏ<ž ù\ã0@D±ˆz Gª€ˆbÝʹÔ×ÑÔ{F¹T¼ã½/ üî5ƒˆBJ!›šl”¸º®w² )ÑDŒÏÁæù©é#üIÊ,!‚8é°¸´¹õ«åŸÿ“sJ¶–!eáY|Q, ™’“ò¹Î­IBýë_Ëo~ó¯ އ]—®•]eÔÌQþžÈ[#ß’Ué…ü)Ó´ó';KEMx¿~&Î9am+;/•ý7»Dº´_$«k6•ç>¿Rê;HŽŸÈ~C/ó[ø.ùiW\!+œ¥,{²¶ßeMí‚ï»hI[ íË ùÛÿó›­4„¦K¨LçT@Ý:{(RÆ–Mî_˜E‚¶ôËà9”d*8‡KD”?‡ÔïÜÐA:—–ËêúZynÕ—RïÄu÷(k'ûumJø›±æ+Ù¹sz]>÷vå Ù»kz\ Ç_\µTöíÖW*œó×Ì›kë|*Ú¼”r]bN¥wÛv<ÿ|DÝìÙRíT7è`i9!@bÆŽÛ*ò¹®€N ’P&5L<˜„Ä} ÷,.x%¯ÄI(4ïSº™ÉD˜$s^tã6Ûl:VÅÿ‰{©Ä”ñ—>ά¤”ûœ’%3!ª˜ñ‘÷Úàë²ÕÒ½>s¦÷C猕yýúÉ{$­„à¸ãŽ“rsþm͵-fÖ8×ùçÿêfŸë¨ÿ—-¿R™ Q}r^žLj™ RŸÄ$Ç=ß„ ¬1èÇ?þ±¤xhõìø\€û%S`\õwK{–J·s¸Ñ0Kh„•3W¸„“›à¦” [®W\r­r]ò©„S­¢ŒÂ¼÷X‘“Y°:ƒ•4 fR`kŠ*^3OGµš6Êbž˜˜qPœI¨] ò‰Õ‡58€±†<¥›j"m'%²°l|jyÎ\ÑÖIh1,¡mwÔN1÷ÚãOÀʹ¾l’%²ö޵Ù-¡‘ßo䳤æil¿m“<šcåóGKIíLi\`îäQæŽ ±^æjÝ,€%Ô¼_òùÍÆIù¾ûFžS¯k”%T­®U+¦f»@)0$-ŸA¸–Ð ønâëŒòîln¬¹ÖØ¡Î(#,•®Õ2“%4Íâi í\4–—II]!ÂÒZ[^’²n–˜±±ÑŒ¡QѸ–ЪåËåÉo}Kª¾üR:$‡ÞsO¨uÙ-¡¸w™˜Ð/²>FÙ%ˆ+dŠ”º’d®ã6Öv<•̨5- ȱ̸õ1(`mËÔ>ð;¸Çj9dË÷r¯•”nºªZ:|µJjzt–ö+Òˆ bîóÏÈ;·Þ`_?fú[c€ÜšpÌ1ÇX/]6âW ðßøŸú_Ùý¿è"žÜ¿LÀ{ËxB[Â!t¬q¡÷÷„NãÍÄñ‚ .ðß)Ö) Z>ƒ°–ÐVJÃr£»š ¶ªé§’ÙÛn¨÷Ý©óô©–’µÿJ/ý¢ 9X>ùÿ.© ºÞQ*(” {]?_rZ¨kÜ J<‡Fä}énø×Š| +¥JT48Ý㪃D¾9Ò(`~Z?!–aד÷ƒ–PÚ{ÄÔèwÙi§rùôÓ:3P•d?¯˜514.yµŒ2À*!½¥þc9³¬{7—î+G— •çØm.„4ŸëÜš$4ˆ8ß%Wú_8äY{ËZÏÃ`&sGWHYß2+gQ^ˆ®gtM{?²ÉuT.Yª“BõXqÂH#&“+Å}ð+YTb‘¶§ouo#ä"Ã÷Gõ!HãJBª€$ üßÿÊž#FHï­·¶mˆ]mˆ€„~üEBו|¶¸Ïèd`39¥LW&0ùŒ Ã°RºYïGH$ÙðP¾‡þ 1ÑgˆßÄúÉ5ßÚÜ3×j_Lð;‘!š>­‘ÈÈiwéó¯É Ñ„†¥cî‹ÏÉ»·ýCéÓ>”„"{LäµÓN;ÍÊk[ÿ—{HÿVRŠõÝH¿Wb ?Q¢É‚eÕ6·Æ+÷Vï3[žÜG,áçž{®\qŶ]1±ÎHhPÉEeÃ}Ã×Öª"¦”–”ZEŒ̘WK(P+iÀ:ZY])ï/|_¶î·µ<ÿÜó^ç5¿›ÅîZBõ¦*H>¢ÔAX› IÍ…¸ÆÍ´t.tfˆÿ:ZdìCæÏ¦u‡&^oÞ³„õ£ˆw5Q˜Ävú×8”¥ÝŒ„ÏúúëƒMGoZ&0 ÌÚµnaeÇÒ4Kè{%'Êö÷æeÍç:·u÷¿Ú˜Ð D1è…p'}mÄ`–;SòÖ>Š|Æ@¶>ä’MÜjîúîJsxÍí¬(  ÷š8.ñu”R ’P÷{‚q 2j+‘n]¼d#CNSØq 3¶:ýÈœ#E>ATf¼¶ëØÁ\¿DÖú„tçmDÚ7]È%Ët²JEê¸ï¾ÈØPÔ ýïQGIã²eös»ýæ7òôé§ûïzˆ"´+ %›9Ì•®€p0±ÇÒI|&µhƒº ·<}ÄZÚóÌfý¤¿B\ù,¶þýûglß@&•ÒVݲS÷~2¨×÷æ¾ð¬¼s +ù‰¬6d¹KU•|iäjº¹&;˜äaM‡LçkHjMhÈOýÏÜÂr¸?ôÂ'Œœ…²R§9ã>^ýõiIÅBëÛ–} !Ž€-ûApÌP°Â艣+š-)ØìÍ¢ÇZ:=ï‚ÿ©…pîbˆ'$ ¨C@„â aŒK@ÁJB ºÜgg¼ØØWR #yè©`ŸP Ÿ Œ³TÜïaä  £$7EÏ‘tDæ;À…Ïäh]PÀdÆ ôöþ‡&eÛŽ”ÿõ­WÛÕÊ;Soõ¹ÚâöÛe«‡–£'O¶±”¸ÂB i[(`ÒÊÿebÁÿ%« щc^EB€˜°ðžrÚ\}õÕ6öõG?ú‘õü¶댄bÁr ز¯@Ùa‰)éb:³þB³ÅeH;KN}…zˆ'.xu»»å`زo€ôÓ/Žñû½sbMú›kÚ+¨*ÝúJÝnw6OB"T!ÑÆ»æeÉ¿>Öê£Ä“Á‚}Šd8Í“×ã=m£A÷Ñ3ʶ´[\ðX@[ö4YÁ[°ööµ6!)™Ô¶¬+oxL LÃ&Šmô %$lÙ;¦Èô^‘ d3h½T¸Ò¤WºXF´ÕI³k*cÐhˆÀ›²V> °6ÖIýÞ®=ë%`˾Ë&M€»w;àïEA iăxÆ-R¯èf”iIoo E,¡½Í=:ò?ÿ‘ƒn½Õ>ü÷¿s:߯ÕE. ”Lf ¸aI6 ÓIˆ.t<{$†›^#n4X*‰8e&M¼‡µŠÙ2¸×% aü`î°ÓŽràë¯Ë.†hmýÀö¿Ï6á ”&⺹$m}¿™rO¬x„1«6O–BXYÃýÊâ§œrŠå2ýë_å?FÆ.¾øb{½Z m.&T• VÍ’n%Ò¸²éçá¬|ÈÌïÍ{ÖõRÆ)̲cºtÕRpé©­¯•Îí:Ëä#&Kµp‰­8üðÃCgAó(u·s­Ü˜Qn87šë˜ïLªP׸pÉÿw¦ÈÅÎr£ŸdÕ&"ËÌ5zp–ÈÕ3Dæ­f«+9ö?~C)—üÇfG8P(¤²ÉÍî­²yú‚P° ’a H€÷uÅf§nl¨ ’•’˜Ðp]ë&v’ŽCïQT2 +o­ ¼ç+ኑ^ó°F™>ë¤ñÕ‡°JA!‡Aò|}u¥Ctë+êkjeí²¯¤}îRU[Óü»±”Ó  Á÷°zB:‰ebídÈÖÎÀw\S7&4¹1¸ã!Œ\#¸a™´“8‹Z§ì1š¸d3e¨Ó–¾Å9±bª%]GOukk¥s!«œ7[BL[ÿ™•¡c ñˆÿG¿Q—¶’WäOc-£&’mô ô)š‰¿7 üwÆ“Ë.»ÌN2˜Àœxâ‰ò·¿ýÍoÑ:hsÙñÍ” u3f¢+Žªð,4> ¥%å%™ÉgºÝ€íìW¼bxïáRR["Ì ûÆ/ÞŠÍ…6˜¤DL(×+ŸZ ™PÌkœªIInÖ»&/iÉ&mëâþ㌢2ÿQ3ëS‰J”Lqkâ~ÏOÉC@ukuÏk²³ð¨A5äs×7êNì*ÛWJßïö•öáŠÃ¶õ“.ùÎÇ"H\j-À ¾9Ô°>”‰0ߣ£ðù,ÊÒ@\–',S¸×ÜÏB8ÎgPšÀ„ޤLã3Ècdn¹Y8Zd´düÛH(jÛµLôÖ<Œ X2ùÿ¸Ý£\äœ"“י\ï€óáÊ¥ßaõ¤ÿB@!gXÙ¢ÿÚ‚;>¸^È¿׻ʒ‚ëBµþ·q®9òé’ÒÖJÀÊ~ÿ‡ßÇ:ÿ™ä†û}ÇwÈøCùÁ~ ¿üå/íƒÜå*o-E›#¡®Â´®x³Á"ÚíÏ £ï‘ÕÛÈc¹ž,V%žÃû —=þo™õå,Ñw„¼ú“WeÌåc¬K~pÏÁ2oy“ﵟ¾&» k¾t ³…0ÂÉq®×®¥ó[¸D3[Ù%Ú¾ý…g=ý|¥Èf¦_0Ð|Ab³fÎÇÃ믿d+7ZŠ|®óúFBrU½°Zžœñ¤~ÔáÿkíœÚf“½0Dk€EŠÜ.À‚G¸íÑȃõ†õ!î“»4§Z3Að=9Ê eÈpìÓf–L—Τmïöe»§­&#)XéˆOëÀÊ-ÿÖ¥|¶è'AJÀ…N!9ˆ˜¾0+%Ÿå©”~§Ï0Ð÷.-Ftýk¬ÖR^s%hS®kºvã@ÿPâ–^âsÈ™RžðdPÿ3ÏÖ&âîÿÁÝžmQŒ;χ~Xî¼óN›„Ýš¿7ˆ6Õ;Ô­N9’ü¸zë’Ç ƒâë2¾‹tØ»ƒt<¤c*i åèÆ«q,ªlÝä£Q¿e (`{ïŒ{åå¿l çŒ_ÌÍûyqbl±”òÙ×?{ÝnÄ ([€uàž(m@qÁ³…dÎXâm3á·{‰üi?‘+Ì °Bf-¸NÔ0…&åMLJTsÖý(h[u“•8Æ{Ùγ±Âíÿ d§l@™4”úBå#¬mù€rK6ní¤Ðßf‹ ;g¸}ͰÛÈ13æ›ûîí>LE¥lÈtÎ šµÅê'-U~:_^¿û3û^.çG7FŽìa”6à=×z¢de (;xÅuF@;ž`yM•Ôkbä’˜Ow‰M,šw¡ñž´¡m2-Ë©íØº¯C@f|!—í¹œsc;Øà†Å²E@éCcÚ•6z¦ÜFškC§w½ Џþ ÿ á'Ö3èRwÛÒæù矷%Ep/ÜAÔ%ÈZÛ„'.ò¹ÎÈȺ*†ÍÊCÿOy VKþ«k]ÊÔ–÷4ΚבËåéœA@袌Žî{O†¨ ²'33ˆÐ¶L¤ÌAèNí>Ok‡¥Hð,3 ;gðº“$×ZEv¼Þ3¬(níPTׯà\(7Æk$B­¨Š ùèQnÈGTé$¢[çRºÓVMm¹Upá8îü 1£Ä¸¥™ÂÚR¬>xMãžsc°„-½ƒ…’:ÆJÖ(‡,¹ ¯ðt­Ÿ™Èm8'çƒ@4ƒý1ø>Æsµb1eò„¥PÝ÷<[ËM!~bd)Ε¸#®Ä]ÿ3Oä“ÿìZK ñŸéß$ðrnôcؤCÁ½xàäüóÏ·þò—¿dlßš(ùÕ¯~՘˲€ÅBp¹¿·‡¿-«+VKçªÎ²¦ãkÁÙä«MdËùMe>ð‰¬©X“zÏóâÐåÌ7Δ¥UK¥E{3–¬]â¿ëኽ®¡Ý†Êœ•sì¶CYùdù'rÙKMKúýi¯?Ɉî#¬ðê̇R0XÆUµô˜]-ûýá OdÚOûÉŠáF©”U7ÈÀWÖȨ;Y\</^ÚWê ¹X5°Ôw(•Þ?–½þ‘ÿ.«]aÐËæ%ƒ’àç („ëfü‚`Û /¼ÐÆ8¹V¥`›°ó ¬ëjYÀl  ¤Sí.m$K™ÚºˆÛäÒËb”«=øž‹L.ùLç "²­¹¿X@w?Ó›ø¹.wú/î@c:±©EÓ…ëºW@6°²¸­#ÊyPtiä ¥ëzwŠÈ[@(5Þ“mÐM‚5Dƒçtpýc­|âÔSý½èšž ¬m÷­·nvMãžsc!¡”G" …ë á¿2¡&ž¸@:O-ŸÀÕaaàúSŠ~ã¼\ËBK$÷E]øXp!ÌJÎ §ðŽL¿/W ŸdŠã±Ä‚¹É&›øï´øÏ.)å?#«úŸyæâÂç>bÉÕ\‰lÖOþÿ/~ñ ¹í¶Ûä†n“O>¹ ×·¥hS–Ð57™ºÏwHˆ¨8+}yÀ†Ê†4KhÅ…Í,2œG-¡¸ßgñ>òÁÈ žƒäõŸ¼n­™oÎySιó™ýålkå|þ‡Ï˾Þ7Íê Ôºõ&[Ë{\aɇkñÜ -¡?è^kí ¢q³nR÷à7¥dî*iܲ§=V~Ô)¹õ§"#¾”ÆúR×ð¦9êMbòµ„FµuÛ$–Ðtd²Dò_]Å×j™‹u3—¶æ6Ʋ„f³DºÈtÎ õýÁë Pú· ÅM 9ŒJH‚°r%«®Õ‰sáêcò傘hÜïHY7 ™o¼/i«cD´U § ¬©£ '®ú¦çL,¡ëD\Ý”]rIǰ¸Cl +Ï}‚œAL¹wô}×R ¡Î÷wàÇ{†~†P»ÆŒuÍQRÊk@ŸÕÿÌë0.ÁõÒ¤3B.¸N™ÀDeâĉ¶ý=÷ÜcIx[C›JL &D„YQ ¢µŸÔJ»-Úet âJ|«ò-ÙíŠ&“…›l”)K^Ûi›ÊKÏ¿ä¿Û´J(tB’¢X×8Ä‚“”ˆ=ìïµ VZzØÕîoÊ®ÿ›_Æ©S9ÇB‘?^`Þ0ÿ ŽE”®Zl¢ˆ#mï¾ûn9ó̦åWƒ‰H´ÉTÚ).ò¹ÎëRÉÅùníÿÁLö°ÿÕ6ˆ¸í@.m!{Q‰èúîø8+k*ÂÎõ=q¾Ÿ÷@T»¨>„R× *Š•{çZGÕ=óÕW_µ„’€%KɤKfƒÀêS×Ýoá’ÆÕŒÒÅ"Zk¶ïæ­Ü_dÐ&†`š±V‰ªž‹c²ç!îRœ™luMãœs]ÊgkÂ5)^xáK4ÐOJ>ý*… An {5×’Úšà÷rÿÜÒPÈ÷S Ow’΃‘‚ÒKä¸KU¶5ðÿ‚.|ô$÷@ )[d÷;ú½—ÍýN(«a`aõ#¬­mÅæäˆ`BJ,ˆg‡:Ø-Ê÷[(>Èë¶C¶m–l¤ üD“-ÇÃÚi›n]»Iy`r#é ˆçz•7IIÑÏ ð½Bf¬´ôü‚¦’Mº…Œ®5BñõŽ"[òŽpöÙgÛL<¶™€á2Ф$¶Z¤^AHiKè† íÿa“X9Ie&S[qÛ\Úrû˜[„ÝFŽqÛÇŒÙo?úÿFÏ ™Äª‰ë-ûа¶¸éÙºïÛÅŠ¤ 2ª±zlÙ¸ ÕÀV$Ö% JÈø|EE7£X›öõ|)@8!‹Fˆ(qŸÍ0ð±’ö0O7yiÞb‘Wß1,eu“¥”saÕϘ-ä0˜0IŒ[¤>nÛ\ι¡#Ì:H_ƒ¬0yá ñÊd¥ ®j&: 0}|·uF@¿Â…–IÉNü&â81<`ÕÄÚ‹Q‚äš`}€»›÷±‚R]Ïn[% €ßÆ5çwbÝÔâòX£–é_|Ñþ'î/|’ªŒ ¸§þóŸmÍÏ_ýêWrûí··Y Úd‰¦0+Jð8ûqÜ~®Å3¬î§"ªÇÉ®Ÿ³tŽŒ$sΪ&ï3@±Ú`ýd *¶L’ßXÑCÛ„‘Ìày"š;Ü ›"*Ü%8¹ #ª­ ,‘/¿,róÍÞV-“t,œqºŸÁª‰4“urªIH€äBv7H%¤s¿ýî–Y³¼ Lˆäûï/µä²{÷>æ÷-³íxî°Ãm–¨BXkjÊ-!å8À‚ºùæ^R[ö›xMÖ€WèЈ5“÷¢VOô]ßšê»ß]Ÿ‰°e?AëËÄ’'€LBÈ #3ÆMˆ 1‡$±AJ)h”±|[vUÇ䓨h,¿3jwbäÀŽqkw’x…U¯W[„™XV~7 Hg0¡ÊuáCÆ!¡„%qÄòÍo~Ófϯ/hÓ$4Ly*á\u˪fEí£”¦Z3[öJP÷ûó~©Bön,¤oÿÒ§Ÿ¾&7Ÿ~sh› ¸Ôç6•ر`_ ÒãnèÄ—#š*V¢õ,›$!QB°eVª–M¶´C¸TXhÃg‚ϰó$È M°­m¿V:ŽíéŠwÛFÕÖ]˜P![öy2¯ÁÅÎÖé.‘€xªa мÒ²« ¾Ý ² ét1xpW>¼»ù=M¤“íSO}ž"ªlGºÝ¾‰¥mEE;CX'b=ÎnÙo—L’ÍN¶;àïE’‰µsóÁþ¬£ºæ|¸ÞqÁS2©¥®ø°ØÒÍQ¹òÊ+m J¸ƒ±Ÿ¼†ˆAT œdRÓbÃkê‹BÎ0 @â¾üòKku[_Ào…Xãz†ˆ‘PEnq“R×jˆŠ&„j܇ä¡SÚÒÿÆšMÜ+÷†‰!™& L.p¿ÿáÉ“'Û¥8¯ºê*»çú‚6MB]…h Øi7—p~Yo-¢¼¢”¦kÍ &(¹Ul£.ýÑCGGžgƒ$“8OPîwö9PvOËË’Î{®Õ’Ìv„%A&ÝÙÚÀíg\‹'O7CžóÏ“ ; ›ÎN;É›[¼)åC¢“†´-•)¢ˆjkèÏAì–ý°cqñÌF^ɾ㺠ãë¯/²[×z9lXw4¨‹‘U†\OmF:Ï:ëqûZ1¾W5D-§â¹Ûn›†P dúèm½rK!îôfÀJ„¥TIk "aHcK©úäÉ'Kc á$ApÕ’ý|üñÇ[Ëç±Çkë%³v<¤TÝÏl)ÒÎq¬¦¸¯Cy’ü²×^{Y—<ä" )…ØBìpm“~Ú °~ò;ÕU©ö'Ä›þ'ÄŽ…Nø V`þ NüïW^yÅZ¹^Ä]·6 ”aønÂr´O¸GX}±šrAÕžõÑªÝæ“‚À½ŽuSÉ%.w(Ä“nzˆ(Q²ë×6¬µÄ‚L0š>gºuIÞltê=Žã†W çÀ­å³O×÷–íÃÎ_h´æ5n\~X7Y ÷{X²‘¶qÞC€ ‘ Ü>”cbÀÃúéB +3Qfê7Þx£ÍœW0;Áó1€ù\çõ11 ¬Ó>•'”8B6!…¸ÓAðX {… ¨Ó¬{>,lŠïÔxÐ8%¡¢®+ÄË%Äòùò˧ʌKä³Ï¾¶$ô°Ãîó[ŠôéÓQ–. W|ýûWȲeUæ{ w,‘>8ÝÜÿKj# h¾€€º«"¡ª á5D6H^•°F”iÊÁbôÏ?_Ž>÷ÜœûêÆ’˜p+ÛÉØ)%‹šDÐl$«I?”%Ž“ÌL'ÇI(`˾’ 1¸#ˆ‹á³ hšÌ” ;°@B[ö£·m1ÎÉ­W 2%qÜï6vÕdkK7ÂÏ6ª-Õm¦s†EçŸÿ”QfUrñÅÏùG<ôèÑÑü>/Þó×e<ÏQGý'4Û¾Yf<$Ò͈çu€\ï[õ, ÔtÂ*J±zÖŒgõ%÷œP áƒ@²S°lÓ‚gŸMÛwË8¹m±r®5$ j÷âu? Ás$H‰:Gu”%kXAÏ?ÿ|k=ƒÈ@Pqãb}ûÞ÷¾g]ÚŒ×?þñ塇²$+`›J’E‚c5ã²f¢3>KIœ&¡„¢<z€¬vòH.b™æÖ& €ï„hR&I‹èc4!Ä=Å5Õ$/H¶xZJHax¡ž+ÿ+åú=õÔS²÷Þ{[²J|ï†B@ÁzEBÕÊ¢5 [S2 ‰„€Î[>OÆ\>F¦>=•xT[_k3ÜiÃ{n©%>‹eôÃ…¦âC~½P»ò03ºQQµ~²Œç؇üƒC»5KJb0#³‰&3Xµ±e(y½öÚkåñǽ„Œ0› ;pclÙBܶÅ8'DÏÏ[³àµZ'ƒ’¨v m!¨X;‰e›O²’›„Ô¯_E3+(àq¡‹5½‡k~ôèþö5ÖT,œ \ø$3¹ NÔň=Œâ®“JVR²ë»ûÀŠéfÄó:X† Ð×=Šâ ”C°RR{ÇÒCÛ·ò àïd¶Ž+>X¶i !+î¾[Æ)¬-PÀÖý,–PvìXùãÿh]ðëSM×8X¯ÜñX@! Š°µå±nº.ùÇ/y\Žºæ(K@±„.üÓBëjsÛƒ`|¨¢µãDÛ”;>jùM0¼:ÞhívÍÜé ŽËY4¨ĕ¦ Ø×@ÝòņæŽLÖ°@B]WxØjDÜv n[æqbBm™Ï@3µÅh›©]Tb5£Ýv›,K–Tšã¥¦]ƒñ¬ªª•/¿lž„½ùæÃdï½™ï@¦y™ì¿KXÀÉ– NŸ¾8å~×óB>ÿú×ýä‚ ž¶™ôÖ-ÿæx©¨÷‰dHLheýjùl͇2¬ãVRaþŸ…¶sÝõÜB´¤²Y¹Vª¤Z>¬øLvz»£”®­)HL¨ûÞZÓÏ5$鈉“˜ÐVt€¤MtÂ}a² ÉÂǓڣq\î2¬¡êÂV+«ÆUªÛ%bÈq’Ô2å{ù®õüþ³þoú%ÀšL2.VÐLaXª™,°l'«B±!"š‚·A Ô¢¬,X*! ¸ÙÕ%?¬Ï0yüýÇ-l5ÖSÛ°e_A&>ç‚"õn›X;µlËx*°àøîø ;A,˜HDÞlÙÇRª@@!¢€óÑ&An€ø×n·Äpa½];ÞET[&|laí¢÷œt ŠðÌFy_ÝèÙPˆ¶NbCÙ‚\Î °bî½÷]–€µX.Z´:E@Ë˽ëÔØN,£Z Ôµ¦B^·Ù¦·ùþvæz –wß=ÍLÐÆÉÂ…çÙí«¯Ž• /|&½”ÓÿŒlö0$Œg€šÇNe;ËvÝv—Ú–Êf2ï¶c«åöر©´Sûv¶í=ö’óªÎð(€¬ºî~H¢[¶)¸ï"¬m™QÔî>ïw4Ä¥¥¥ DBA?~¼üãÿ°V;Æä_üâ¦K”Ù2PŒÝ¸¿ûÝïÊ]wÝeß²”B.!™¸±±êJ?¸ô!§Z³Ozk)ÖOe”ÖW ˜B4Ñc\S®-ÿ‡×LøÏX‰ 7Àr QÕ"ú_ ûTŒ7*ëmv¼ke€jb„ñïcÿ.UuUr¤¤®Á‹!¼÷î¯Þµ®w>YÊéóéöóÌþ;¶ïh‰©Û¦5°.¯q(pÉC8û™ÁŸU’p/“p7“ˆÜc@­ž¸âo¹å;Óepr­Ÿ¸ä™!»ç)ò¹ÎmÝ2£ÉB•í+¥ïwûJû ÇUëÀmËD/SR\ãœaÈd­ÌœÇtIÿɼ*˜ˆDX Z1£pýõË„ Ûšß½4­=Ä’˜Ð¥KYÔá[OT“Ž@0>˜‰iýè£3SïC:ß7íÌ£Â<^7ÝÍCq³yœl¼DÔg;Õw·ßœ,[¬* ÚKé.!%œ"É* Z2þ%–Ð⺀›+)†,¥IH&¤I“pKDZ”r>tu?‰û¤¼àþi¢º —„Ÿ¶H%õW -@ŸAJüwˆ¸k-…”þç?ÿ±ÖO\ð×\suûoÈX¯,¡ ÌÊâœ'žó°«“sn?'€âA•Lj h€BfY=éÂ)ÊÞ›ï-ûn±o«Ð6 ”Ëv2ƒú+ã›Ö‘‡˜BPib4µ›DÄàÁÄÏ–vjõdæGÜ'±GZ«õ“Y6ƒY’ŒT80iÓd¡Šš iø2:&ËmË–ý–¢çT@±X½h‰#Ñl9ž/ ²PÀ–ý\áZ1q³“å¢8šÛž-í!²$&A@ÖM\ñXJÝÕ“‚±£dâϘ1!€î`G¶ìC(G˜hggšÇNæÁ{.Øç8ŸÕ÷ùì`óX[V-;íbÈò¨ÓäÎ]fH¥ÙwÑ [ýˆ}-JÏ6ø~‚¶ ˆ%Dêsß®¾újkŃ”þõ¯µå…þùÏÚIV/"ùé¶Û¨1+2”óñ!XM±~2þkIbny,¥$<@f[- ú˜X&EÄ´ºðß™$AØ1Π#Ñ‹”¼:øàƒ­Ebº¡c½#¡apÝëŠ/V}!e¥M#þÐÞC­E3\2Ë–ý!@¹QÈþ y±¢$-ùDÔP7Þ]ýHÁñ§Ÿ~ÚºîqA0«NÈgaᆱ` -í-ö™B^‚ÀÂt±‡!—s戦O¼U.qÔXÓ|€%Õ,±[߈Ÿ €º¬æ'Ÿœ%ï½wºéü÷¿µ¤ÏyÞyOY2 (fÕUÈ·¿½½%™Ç¾5t†y(}»Û§rZÙ)’ 2M, Q™ò€¶_½÷^²bÒzúÖJVl‚ˆâ:&–“:¥XF×=ˆžqÆrÓM7Yb ñÄJ±Ô,q Xý aÔŒ†ÈBH±¬biå3$QauW7¢dQ[Ùñè3® áü§L y‰P=žÀ‡~Ø^'\÷:6 n<íFyüb3`÷õf÷Ò~ýôéâ­|ÄêJ¬˜„µ3 Ä“’Y‚±¢ @8¼[D lJ5f¸˜Ñ„Éu¹«åWä”™bk¸ß7Fà5Àβ3¶˜‘Ñ®m³-Û©.v­T‘‰ˆÆ=g®p-–óæÑ§¼×€ùN¾ÖPº .x£C²ºâ3"ªËjb­?þ[tžØOÜð' ™|ñÅù¶®èÅ?+—^ú¼ÌöË A.IVÒ5âILr-¦XP±šºÖ_}%£ÌC­—Uæá‚}ȤS–Q¬œ å óÀR Ø7ÐÇ<>2Üøa$6ÑÄïfó¯Pòúô„ ²öšk+ézH)®ôo|ã6~”ìp\í„^‘•O}K¼_Æ ³–¿_ÿúשuÞ£²ÄÉŽ§¥¦ø,4mO )¡núÚuØg ÊGbi!Ñ[n¹eäÿ¸ä§L™"x -<ÿä“OÚÿº1a½'¡)úŸö“ §^(¯þäU›ÉNÝÏ%«–ÈÒÕÞ:ËŸ/ûܶђLA,]µTvþíζ´D”2N‰>oáÅ„*XGÞ/Õ  ¸X†7 „W¼&.iÖüõ×_oc¿.-rŸ ð€ø• (“†ÒhW¼‚¶Ù’ru±Ç9g®Z,o¾Ù{ ˆúÈÇ®€xæ’ˆ” PëË­·îmI$ÀÒ‰ÅÓ-Õ¤  I ×Âj‹Ò›}«ŸÏàa»Å2¿â3ûbØÑ<†™‡â;æ™Ä’éB©1¡ê†?Ì<”d²m ÚGº¹y¶Jb3Mb@)4èÔ©Í Î»äµqÙ2Y9s¦}`ý¤ëæ!‡"¿ÿýï­“ú¡XA‰õ$&’÷°tžrÊ)¶L5F5A' Çg­xÆ ,ˆÔÍä8úBJ¬*ž8ö‰3 ¤¾ê~ÇøBZ¶¤*j ^|ñÅrÙe—Y"J)¦õ5öµ%XïIhÐ…Nö»ÆzVÕ4/ƒæf‡”*l9O‚˜¸ò@£‘š’Â2Þq›¨Ë-Ù‘ÌlqÝä nÛ`»L.ö¸çX+Ý,ô(„µ Z,÷Þ»‰”âÅòËÐfDÔ÷GµËÈ'qÄq*$ aÑT2‰¥Ó]¶9OÆ<.ú1c¦Z×<–Ò'žøÌžÏMJ⵺ìÁÐÕ[Ȉ†‘öõ@óÀòy½y(°€B&Ÿ4^æ4>TÝé®^É„¼ª›@D_6ìSæÁçxbÉ*I»ÿö·vL>bßÍrÇâIü(%˜”¼J·nRá{RÚ.±®Ÿ€”BÎÐo¾ù¦<óÌ3ÖRúïÿÛºã)Ê~衇Ú8É“N:I®ºê*ÛŽúšQÀ›¦YèœRJÂ+TŠÂOе”P/’Ÿ¨‡ZhRJ¬*ÿ +pœ|†Ï>ûÌÆ}¢ 1¾}ôÑ^ÍFˆõvÙN…ZB!—¸Ð3­ Ü yE°¶(–Ð~ûÑ:µ„¶¥kÜ ¸ã÷›*òùJ‘ÍL™vj UK¨Q’Âb=ÝvQmŠ|®s[ÎŽ‡øEe¢ÿk¦¶.¢Úq (T?÷œBGL'žZÈ#D2ìöÇmHP">÷|¶¶Qç ùe1D0úûÃú”XO\íJ±€B@IêÓ§éÔ:ôŸþžÈþ°—œsÎŽ¶MT–=ç¤,VPH(ßw⦅X×üÎ{÷’¯Éæ±Ð<–ÐRó€€B&!Œ#Íë&LJšÇgæÁ{o›À … B2·11æÁ±°v¸ë9ïM_ûªL;a¼µjB*Ö؄Hbù„xºKzpÓMòäøñ²ÖL\)V¤!(|–ö¸ê3$Ùñë7H<‚xj­RW¡)X‰åIÉ",Ÿq€U•>A’O,•º¼fàÇ]¶4Üïä5ñÅB› üÆŠoûÛròÉ'Ë•W^iÉòÆŒõÞ QÔ%7•€BL!–Ûlº ìáŠÜ|š—!¯mغ‰Mп˜±N h›„âI†|€€ˆ$„’A„g¹ÔvIBRá‹›ýý§¥¼Ô‹³`Ťml“Ö†-P"‹´OW/™)A@<)Ù   å¾ûîkŸAr‰”ŒH¶¼Ç}‘ rÉDÛ¶çq³Ðã¶nÛ#¼¥¨²MQç žƒ„'¶ Û÷+\òÈ÷»&)qôÑ#„LyÀ–}€u2‹KžÌúaÃü# ȰwcLyÚ×?’Y¥Íã(±RbÉÜÍ< ˜G›‡&•›‡&aÅÔ¸NÚq|gó ɉ2Nnl)û¼Ïg€žý6?4åVgKL¨ëJw e¥!œ~2mƒËvj9æ#ïÛÂúäà‰øÝï~g è–(RêÐ×uà!§„ˆa1ÅENY(È)^:ˆj0F•߀›K;¿-›þ" —ûƒfF‹ewâĉ­û=ˆõÞDеNmÐ3om* ÑQËv¶´iw| Àà@V$. MPZ—tCsǃ079û¯QmƒˆÛäÒbˆeb—©Äm´mU•È~N4±£$¹ˆ:/DZ¢Bb‰*„’ø¶¼hTRéÆo†¥ðÁY–€b ºó±¤n¶Y7ó=Ÿy.w3$V”÷!§óç¯2¿£AÊ»ÕÉe7ÊìòY6ty(°jBBq›/šÐ̉UÊkm³•yÌ3±¥ç™‡‚sò> !%ÖTÏ¡dSÉ¢ëJ'NÔuÁ³ï.Ç\¶Sáž3ÌÖ¥|&h}`µ¤\ÖL]j”2QK-žOk®Ç!~P"’™Ô}ϧOa=E‡a%û=[&;ç"QêôÓO·a¬ýžôÉtxÓï ¸ÖµLÛ£w8:åjײKÁ6I)¦ÂÀµp"¤”å`ëwŠ[;”™l‚Ââ7=nÛbœ@è †Ùˆe¦vF×å®m!Œj,cfÁŒ:/ûxÊ4¿Ž-ûaßH¦Z?!™×_ÿ¶l¿ý­Ö…®…æÏ3ÎØ>冺óY iäÈ›¬Ëå99§&6Ýzëá–€‚º•årËÛ[rˆ;]­”®…r©™ï1 hâÇ\:È< ¬ÁsB8!·”mRK+€$jòQЕát3äƒËq²u—íT¸çL`Ù„^pÁvu2â ï:í´Ól¬æ…^h-¥¸áö³ŸÉc=f'(Q–Rˆ*ý”$go¥¡H~"É+(Ä—UX ‰}Hj´Áí~ÜqÇÉ~ô#»ÄiB@›cƒ#¡a¸qâ2íÒiiIK µpC½OŠ û²é¦›Ú’ÚÆ-X¯ëÇ'(>¬u2díø0Ð6nv{¡$’qA{\ía.w#IDš=Ÿ tÍl$6  \o ¤Öÿ„`’åNâ‘KFa± n]QHª’Ü`íÐÑÛ ±ä«$™ëÓÌãFóP¸qœlwöÝí¬¦¤++AR±lºîwÜíLe«„3Â\é ¡LP @J)ßtî¹çÊäÉ“-Y¤v'û¸ÖqëC0±Bzè!kíÌDJÑ]Ô$%³2«K“ç Å K}¾7>uBO=õT[†ÚŸ”bÊT/tcÆwU(¿ÄÒ€-¥—X†óìÛζÇ@°M²2RËᮎDp·Î ÒÑ£G[7 VP·tÓÍ7ßli2)(6 “d¬¯½}­ìüÉÎÉ¥¶S„¾PÈD$³Cºßíì6hX§{ű´†¡¥$V›] ¤BkƒºVQž¬Ï`é$T³ë)Û؇¤*\«([VK‚D*™$K~?ó€P~l”l"ãP+T­dÎk{ÈéTó¨6®{¬Z>ãPÑt-Ÿqˆ'+&±r.ø ò$ƒÇYg•ZF”ç%—\b“‹~þóŸ[BI2•µÛ±nBJuéP,«[2àIt"¡ û¸ü±–’øXï<âJ5Þ4A46Hw¼›é®µ?Ýú nuÑ'h°hj1zVÃp‹î"Ьr”ÁÐrš ø >S3ÖóY;"ZLËh6"™ …²VF¡%$VqÐA^’â_ÿú†\zéhëfj%Ë·;Ï-¶¸É’Ò}÷lài–ŒîʣƙB@ï6µtªæ¿0bŸµã–7Ä®û™/ZJ$ißRke1áÆwRZIWGÂEÿç?ï+?øÁ.6ó]Ýî J0)ÙtÏÁ–}èÝw$ŸÎ_b.ÜßdÁ”?ÉìÒ¦p—LÀú©VÍÑæ¡ÉFwã@Õ2 ar¿»1¦n­PŽáÍ …ÓM^Z»d‰”t÷JR%嘴& ¥$:=ñÄÖ òÖ[oYoĒĢ뮻ήö·ýöÛ›Éäyò—¿üź㉠%ôð÷çH$ ‚xPâB£ÖOP@4N-HŸX?× —ù¬´Œ²_ ´u"Ù¸1›”Zrñã¿`­¢d¾?üðq²é¦ýwšÇ~Þxã¡Ö-oã> °€WZ¶Ó"[¤W¡Ðš.~d.ÁT@.5Ùè]ó€<⪧“ZF±œ†‘J™U—¾[+4ÌuÌ’w-œnòõA;^ptDZcH$($H²ÊÞ½{ËñÇŸZF”P¼ÆÛG ([ .¸ùä† ž„ê®-?ýóéöu‚â%›@býl=äÙ­­ZF»Lì"GÅ»¹|?IHq²âã¶Åh›Ë9X*5û]3Ù÷Þ{PÊâÙ·o'©«ó®VÑßÿþUY´hÝJXITÒxQH'ñ£<µ„SýÛý¤×RouÈ ’XÎÇ̓²JRx¤y\2‘JH龿1Á<‚å˜4ö3ÊÕÎ÷ñýZl–%°ˆBH©JòÒ!wß-¥]ºH¯í·O# ´KÖŽO°.)¥^(Åçÿüç?ÛõéIBŠ»Œh‚t”TUU5VW7e@Rè—òÔwŒªiEæ3e9ä6_H½²¦Rvùý.¢ÙðÃû—?›!íÛ6!ZŸ®q  ¸ÞgΜ)#GŽ´q5m‘„æs‘V×hbØÈf.ò ñ«¼¹R—7JIÏ©8³ÂIü¯™ÚºˆÛäÒB7zt¹é#%¦4š>Rj Û£m¶va}â9zôó™æ3=ÌgÆšÏ4½÷ÁËd“M*d«­nMQ@œ(„”Ï<ÿüI²ï¾÷ØsAÁz<~³f}í}¦¼J±F^¿ù{Ò§¢»%~£Ëü•Ì”Aƒäõº×-¹Ôc#LÖ™4·­{ðÞ%ȶÛÚý°vo”¼!{•ïeß/Õ½dÛG¹ÒŒ Ý̸ÁdÿÉ“O¶Ktb…€6–—7»¦aíÂ,¤­)Ÿ $hJ~õ«_5þæ7¿ñw›0eÊ3hFŒÞëÞ_ú¾üüÕŸû{"Wìu…lÑs /A1@|Ìe—]æï™k~…¹æ[lׂM{k(9Ûs‘Ï®•]eÔÌQþžÈ[#ß’UÞòŽAÄm[Œs‚O>éaúHÓ’FW\1Íô‘æ„+n;PŒ¶¹œSñÉ'Uæ3M…Þ¯¸b°ùLóu¢ßzk¹¿Mèà ûÉ>ût•9sjÒÎÄï~7P/®•k¯ýÂ?Òô=Ÿô0ò·Ÿ#ÓŒü­ØBªËªeN×92tÕPéPßÁ¾Õ6ˆLç¼dÿKdQ—E²éêMåÊç®´ß眠~Þ<©š4Éßéxþù¶P}qÛµ¦|&H eØà-¡kèè?˜YùfVÞÏÌÊjfå‰%´¨H,¡…Ab ߣm¶v¹ZB]Ðnç'§2ßGŒè.o¾9ζuÏåóškö—‹.zÎZ?õœ ì{2Y7ƒˆÛ6®Å”c¹|b M`#FcFpñ ÙmjjjÿûßÿÚíú‚5Uk_›ýšÝ®X¯qkÖ˜kþš¹æfÛV‘ÏuŽ##ÅBœïn¨ih¬_k·.ÂþkTÛ â¶¹´¥k˜.b·™·(FÛLí¢úК55æ3 í6xÚ´¹ölˆb´Íåœ MF ³€ºà}ŠÒó ¶ ž#¸ÂŽ,qW6ŠÛ¶çX4ã,á·]‚ Öl4$4A‚ $H AÛABB$H A‚ ´:JðÉû¯-¾þúk[kÞ¼y“XMàÐC]/“fÖ$׸uÏu&ñä +VHwU—ÖBùŒBÒ§Šƒäº-¹¦ëR>$Hš‘PÖDE€$HÁAƒ¼bà­…D>$ˆ‡u!Ÿ $È ÍHhCCƒ,\¸Pºví¹þ©Î4ó±Æ$ˆ‡ä·ò¹ÎˆÌªU«dÀ€RZÚº-qä3 IŸ*’ëZx´äš®KùL AnhFBã€7®ÁdÐ-’kÜ:ؘ®sÒ§ŠƒäºÉ5M`ã@2ML A‚ $HÐêHHh‚ $H A‚VGÙ¯Yœ:”••Éþûï/åååþ‘…Fr[ÓuNúTq\×Â#¹¦ løÈ+&4A‚ $H A‚– qÇ'H A‚ $hu$$4A‚ $H A«#!¡ $H A‚ Z M A‚ $HÐêHHh‚ $H A‚VGBB$H A‚ ´:š A‚ $H Õ‘Ð $H A‚­Ž„„&H A‚ $hu$$4A‚ $H A«#!¡ $H A‚ Z M A‚ $HÐêHHh‚ $H A‚VGBB$H A‚ ´:š A‚ $H Õ‘Ð $H A‚­Ž„„&H A‚ $hu$$4A‚ $H A«#!¡ $H A‚ Z M A‚ $HÐêHHh‚ $H A‚VGBB$H A‚ ´:J ü× .k]]TUUIyy¹”••Iiiiê™ A‚u•Ïêêj+›‰|&HÐv€|Ö××[ù,))I“Qöy&Ø0ÐC…×ÐÐ`I¨B…GJ…Šm"X aò‰Üq<‘Ï Ö-‚ò UÙlkkk¥}ûöÒ±cÇÔ¤QÉi‚õ -¸Œ â^Òšš+ zŒ6¼Ö}Unªì\å—V‚…Êç—_~):u²J åSÛå“§z4ùL °@Þ ŸL ‘/òéÊíÞ}÷]éÙ³§ 0ÀS9t=ŽºMä³í#!¡-—¥¥37@Ççɾ*¹(ðy÷©ÇT€&„‹}®D°$ˆdɕϗ^zI¶ÜrKéׯ_Þò©PyLä3A‚ü¡ò¹råJyõÕWåàƒNÓŸ¼ve Ú«W/4hP3ùä©mUõ™ÈgÛDüÔ $X>fqtn:z.\?ƒp ÌôÉqŠóWVVÊêÕ«eÕªUòõ×_Û'¯qU¨r¥m‚ š%Ÿ¹ L>U¡!s(Îgžy&M>Ù"³‰|&H %™*'ªóØfƒÊSP>Ûµk—&ŸÈÿÚµk#å“÷ù\·HHh:~ቃ0ÁbË1ðé§ŸÊÇ,kÖ¬±…"L+Aô{•O%Ÿ*Ÿ<[*®|òä;”œÆÜŠÈc”|ò™D>lŒ ß‡M•8*¾úê+«çæÍ›'Ë—/·ŸÙdØ•OWåý 9UùdŸã‰|¶.š\áQòIgg[l¸‚¥¯U°ØGhT°TññTÁRO+Á† ú6r©“C€l¸òÉëbÈ€~«øx­òɤЕO•Q”`"Ÿ 6¸ò‰e_冧’PdãÍ7ß”·ß~Û‡€~øá‡ò /ÈË/¿l傺téR{®8ÐïpåSe”ãjXÂj%ŸüöD> $&4¸D(’–-[&#FŒHuêLÐŽpŸ|ò‰ýîÍ7ßÜ?’~oð©¿U‰¬>]b› Áúú7ò‰’@æT6Ãú41gC† ±I ´u­+ùëæë¯¿.ûï¿¿$;‚²ÉS¿?L>õ™ Áúú·Ê¯A˜|BüˆÙ¦¯UÙà‰.…â dŸs"$véÒEºvíjŸ¼&ù0xþ¸P™tŸ@$Ö•S^ë{ rGBB3€Kã Ï¢E‹dþüù²ûî»û-2ƒÏ® ~ð Tx‚Šm"X Ú2èÃȘ’O­Ï¾öÚkVÁ 80%Ÿ-éç(AÎyÀøGòC˜l²]±b…}Ý·oßD>¬W ÿÆ‘O&Ÿþ¹Ìž=Û¾3fŒtëÖÍ~ùîg>øàéܹ³l¶ÙföÜ®w’Ê S>“¯.V¹Ô§ÓÿÃyÕ3™ÈgnHHh¸$a³dÉùì³ÏdÏ=÷´Ç²A•\¾? ùÐ0è­çwòZ÷UxT˜ôÉ>ÏD°¬Kh_E>QZ@ûl6¼ñƲ馛ZºpáB;±D9©²¢ö`.ý»P$4 üÇ™3gZùT«ÐÿÊS_"Ÿ ÚT"ŸôÛ°~Éñ XË&rGŸ1c†Íާ_ó~6¾[‰)„T·‡ŒÉ)²“TÙªUðùïüŠD>3 !¡dHè¬Y³ìL-8W[&¡Qàë“ßÿÖ[oÉ.»ìb¾r]‰`%h-d’Ï8˜>}ºU>Ä”ëÕ¿W†’BqÑŸU9©¢B‰D}G1I(“uW>yºP™TùÔýD>´âÊ'ñœ$Ñv‹-¶°rÈgžzê)9è ƒl¼&Ÿ#¡Ä‡ân6l˜$;8—Æ{*1剗ùvå'ߟ/T.!Ø„ïm»í¶©ß¯ò¨ÏD>šBá!&ÁÙ{ï½ý#™±¾’P(hât4æML» ¿ƒ§KJU¸ô½ Z úòÉh¿Ê¥)aD&±ºŠŒj?EöÃ,( ¨¤ÔµWlÊxƒ<9Ò?W.õ ô¿©\&ò™  ¿©þte*Ø¿)ú4a&ÈàСCSú‘Ï=ñÄràÚ8OÎFBÿ÷¿ÿI‡døðáþ‘ü çWBª2Ïä”ó#ç®Üs,yѬþvØ!%“îè5 Ê&[}oCÇFOBùûq„0{CöÙgÿHfp>fZ…îHP:j6ÅT0{|å•WìÀ„ “>õ˜^?~#ätc¬…ý ÙDF³ÉgA<sçεʘPd‡s3ÉÊt>¾¢é*)ž‡ˆbEùâ‹/¬§ %®½(|ôÑGÖ*ƒÂÎ*“üV^«l¶AùÔg.×6ÁƸò ±#´„˜ÁƒÛþ¬«–)8×ã?n ¸çÙ/& ã…+ë¼f @N”*9Íä%a¼¡.éöÛoïIÿ¸ò ôú©ÎÔç†*Ÿ- åoçªÜpá½÷Þ{²ß~ûùG2ƒó"DÙΛ+Z“„æjéÑîÄV…K¡¤ŠoC¬-ƒ+ŸÚ‡r•#úÖ”‰¬”eÉ?âÉ8o˜’Ë>§°±tàvƒ(ªk/¨¨ZâÚ+´ÂÕkÉ–'¤EɵQ9D.]ÏF"Ÿ ‚ ï _ôyíSaò‰ü’tD.EŸ>}¬ëÉ[8$ýŠ»ý0ùlÉÄ,_0…%@•sÝòÿ›9sæØ6¸ãsÿ;øª|nt$”¿‹ð(ùaÂÎ;ï¼» ç_ßI(‚G]\â&÷©×D…IŸº_Èk–`ýý"_ùTpBgPV|‚Ev9¯©=!…ÔÑ.ê2JÙ'ÆÎ¥JJ ¬:Ab ±Œƒ|âßrÖê!¢(U.õ©×$L>õ™`ãý"Ž|ÒÎM:Új«­ìä/ ¡x™ÌqŽ0ùÄ kMþ?FäÜ•y«m~7z™ç7ç •I÷ ôÚ+)Õ-O}¯­c£!¡üÍ–*7,Ñ sM‡ïYßI(BEÆâ¾ûîë)T˜Ü'ÀzµÉ&›¤f”®ò+ôµLÐv òÉ N_Ðû Q” ˜i\ïœGÁºÓô+ßQ(å)ÀR¤ J•Š W¤KJy†eægËn)°Rñ{¶ÙfÿH\¹ä©ÇTƒ²ÉVßK°á!®|¶ÆvLËãö bB÷Úk/ÛçùŽ0ùlMý—+øÍL<‘s&x¼ÖÿÁdÒ•w^ÇŒ†óºO=¦2È5‚”¶uù,ûµÿzƒƒÀ:BGà†D P& P¨×5FG¤=ŸÓÁº€Œ;ÎÓ«W/ÿHñ€Q€òBCBï‡ Š× Ä Ç!æÉµÔ‰„ žž'Áú î%±™(fí¹ÜSú)VC(Jo§v²ò<ñ›ô+•%È·ÿЙ4EY*ù/Œ9=zô~ýúYRLLû¼‰å7á®ä<È6ãýœß„÷EEûb€#®?òßÏSåÓ}®ÿŸßÊ3‘Ï ÜKú¤ÆOkÞSt,“<È“&r [¹Ü{j…"#/&ŸÈèÝ»·Ý¶%ð; €D#ÛÈîÎ;ïlKÂq-×’ÒpüW¬ÅÈ8Gä†Ï3>Źf´áéÊ¥>÷MåSõ'O®i[’Ï š„r‘u€¤ãFFl¾œó (²¹h‡B…Lñ]Ì Q2R·ÃÑYâv8œÏ¶ EIrÝZ\ ®߇+qWÁ➺‚¥[U|<ŸÉõº&h]è½äÉÀHØ“\b(ù,ròÃ…7jÔ([”~&¢¼§ ¬$¹ÎÅ]N_ÆêÙ½{w&€‚â#Ï(_”=2Ž•……2ÃZI?\ŸBõí\ºÊOþ×RepO•œò{ù/]öi£ÊOÏ‘ íBï%c,“;¼ ÖâAì2O&ZLéOùÜ_ú<ò Bwéd”‰hœÉ(2ÄÏ•˜òtåÓÕŸzOy"Ÿª?9Îû­-Ÿ$ u/4[.&››Ü·7Š`ã(7C¢®&߉0²< 3;HJ†Î„BA2Ò1¥3ÐY²u8ÚÓ®5H(ÂÁ÷!0­î’P®Pà™M°¸†út‹kM, ŸK°n”OÀ½äqßãPÎYã<;•ílŸEîø®uIBÃÀ÷£x±–`•dÜàZ ø±ª (5¬LÈÿƒXNÆ5®ÿ[å!jBëʧ>õØûï¿oå‚­²ÉïÖûϸɸªVðë®|Ò¿ÆŽC ¼§@¬ýÙ&€q åLÒ@ å·´uŠlñ»£~'26¥½NFѽÈOdk³ºøs‘y•E•Mî‘ÓûÍx a¼ Ê'Çù­qÆæ\‘û¨Õ†ÁÅD0¸€ tì»];t¾ÐÆ3:ÈË/¿l…ˆ’ £GNsEðý :ÚÖ[o-»îº«MöApµP/ÊŒu¨Ÿþy{JP7f{fDaßÙà{õ?´ôÅÈø]zoQÒ[Žñ»"–A‹¬L&! Ö¸'ôsàØWùÔ{GFÜ‘5 ²Ä2ºqÝÕ*Ãë´o£¤ˆoÅ­GÒÆ{ìa 7ŠŠk ˜6mšMÅûQ¥Ïs³ëÍ÷zO¹çüVW>c5òɤœ ;–´ë*ŸèΠ|Òy()yá…,IB—qÿ°ôµqäs}‘a~#¿5p­á LB‰§¥ôù\c5ÌÀ5Z"ó •OÕŸÈ#ŸWÝëÊ'\…RÅÀAB3 v^·”„rà ÂHÖ<O Ù3[ŒÓù8ŸÛá ®t8:ÇøJ¨à¦¤Ã±ÅͯVÓ–þŸ8ÐkÙZÐ.ßï O¬¹€I@‚Ö‡+Ÿ:9Ôûäʉ«è ²F†;ò!cGÖ´-¤ÜäòÝùÀk߇Չ1†° ”?cÉxh XOI $@Ö)+‡õÂÊÀE1I¨‚{ªŠßïÊ'Ä”cÜÛD>× ècô•O^ë}b T6ÕØBÊu|_°Ï¡¿©­Cǹ–‚s`$ÖÇp…̳r£Ê<ÅÿUæY\’ª2¯–Ólàþ"“|Ÿ+Ÿ¼F>5¦µÐX¯I¨ Ä3Jx*D-ž“ïåû˜¹#(È#Ö‰–è|·. ¬wRf!Ì„ ¹üf&$ a1e-l:¦tÜs\ƒB¢P‚úû[z]p]¸ÿ…˜©'È ®|"Qò 8Ö!NÌö‘5î!²†û;Ÿ>Â÷ÆÛ âÈïãÊÇÏuÁƒ‚‚¤SK*cõRQP/¾ø¢4cIæ8÷¥˜×„ó#QÀÅø Z*ŸÈX&ùD~±´AnÔØ’ë08_œ¾¸>ÈpÙÍœ÷¸ÊÃä”vÈh±äs½%¡®ðpñ¸)QÊ D)¸\ Jø fÜHn<åMp7 ü'fB=n9âGvÛm·”‰W3",¦¸ô!ȸ÷±Š´„|sÍŠ%HaP…UÈïD€˜ÅåCZäú ŠË•Ïl÷•ûãöU^'Êd‹ó`íc€m‰¬ñýîàÛš};´D‘aÅ Ö“1‚: ¸ñ!ðÛm·;ãþ0†éxF)6B€/^ª¤ò÷‘1* JB‹eiIÐÜÛ8ä+Ä“>‚üÊØ… |†!N›¶ÆÀÖÖ9a2 ’ o`,ÆuñJÃþH:Ããʽû½xù\BB}Äž hÃgó%¢|–ø¹ã¦â>Çj¹.ÀÿÅ*äšè£âÅèl¬zD by0ÝÓ©â€ÿíÚÅ\”ܺºOT>!8ÚÇâÈ'@Éqÿ9ƒ"ÄBD,$O&b-…Žë -A¬$Lb!ô(<.›Îõg|CIi*)ä(×ñ“ö<Ã,, \}ÜÛLmô'äý‰œú—>´!ô ä3ô<~œbùÌÖÇ )ÅD¡e7_ WÈ92g¯ªöÇ5gœÕ$(ŒX.WÀr 6zw|\ቂp¹¢€Á—Yžòɬ¢­ë/¶çž{ÚÚ¦˜ïq©ð? ¦nP3ÙaÄ”ë^hR˜ L, ­Œ¸Ä›µ…aCEP>µßðŒ{ÝiKèýâƒÕŸ¾[È,X~ ¿­Ð(Æ9ç-f¿e<„˜cÓÝ UR¸órõ´èx›I¦¹ç|"ŸÅC\ùä~¡Ðèú•'Ð+™îs¡W>‹%o…D±e·%à¾kØŸ&=²¢®}ŒX„÷ÀÛÁ°…ÁëôÓO—{ï½×?CáÐæI(7’Îßåhr!¡Xs˜ÆLÙC[éTqí Ÿfˆ(J0‘Ùÿ“‡ÿ IeF¤Ùv­ùŸ¹×z¯ Hhâê+ %ŸÄ/ñÄýN_EÖ¨$Qè¾Çùø9Áü¯u~k1åñ0LÞøN7(,3Ë IO™²t•¸d"¡‰|*Ÿè2•OîmP>9NH1ÃTxÁ•K¸—&Ñ>Ý™/Âä3¸Ö& Ú×øa²ÕVA?qXp&£wÞy§ Ø3Tµmö q¹(Ä)àR2”«rShgÐA16RF<qŸ¸®4“3®´e¸‰ „@J!§¸]˜!a á‰1¬(® Ї­XàÚڸ㠕OúOöó‘Oäš~Fà<ŸebijÐ}@‘«üv¸àéÚ»·Ý†!Ÿ±(èu-¢HhøA%œÐ3ó™Üò9Æ &*a×w<òYìk¹1ë̽E¾O^s}Ãä“{†ŽeŒ'–{\j“ÏÅÑ-ß™‹|fÂFfñ¢œþùÉh¾ïeC±e·Ðàþ†»±íŸþô§rÊ)§øG ‡6IBƒÂCL¨%7”Ï"Hœ/ tfƒ(D\M¸³‰›p L¶s¬ÏÀºÐbéÐ [” ÿw6Ê‚8!®O°  ¦à>ÇUŠq¡îø…+Ÿ*—aÊ-8‡Nô¸?¸Ý‰[*ô½‚ߨ šï‡,¹îe&_)ekþcû;î°/í¶ )_[‘qZzÍ3eæk¯fæó$’Ì|ÆZ  A‰|*ŸŒÉX®¢ä c8ùÈÞŠ¥‡õÈ ç-6T>3!Nþÿ¾ìNž<Ùê5HiJT³½—åzSv (Zìp™6EB¹i(6WxˆWâ¤C €pE Š |fƒ0RÖ â€‹õ©†k†’ap"«²À`EE· „[ú—*õäâÖ'sÁý)´,!¡…÷2(ŸÜ«\ú8ç`R©=Mðck EÇo¥_Ò_)k†‡òÄŒ> A‚[bjúõŠN°Ÿ«;–ÔSû: HX‹9†p½[JBàYº„V0~hf>$•q•~Ä$àÆo”ýèGvðýïßZQäd+ÎäÙÕ¤#À„XàLIG™tg!Áo ê KVÅ¢Øú³MÐlÂS(v*±LÄB¢(qID Ì­%Œ™PW×z›ÿ$:*AÌa¥_P<(yˆ(ײáZ>˜}ÜŸbÐÄŸ?¸_(.%Ÿ L¹e/Èò¦=HŠž§Ø²…ÕM“iè»L¨ Dü,þÁ (åw/ºHæt´Ÿ2EV|rª&/}*ê·fsáç‚b+2þCÔXW¸Š­féBþ‰9<÷ÜsmÂÆÆŽ¹Á•Oô¨ö}*¸×nÒ…æ™b‘ …ÒÁÙÀïuå â‡|^rlo¹è”Q– þò—¿”ßÿþ÷͉¡OT-JÛÉ ³ÒÇ|dœgäœÏ^rÉ%ö˜}oøðf$|„ þ+A¢š Å–ÝB#J÷[®SWx¼Tùµ ¶*Htt\ÉÌù~âšpeš ~¿s]á‚ :幋üú×Í×rÏA>b#® q°Œ²Æ]{íµv› è\_W†É'ÇÕû@Â)Æ&Lâ‚sºä°Xà{TùOj¼yšÈ­Ì²¯ÿýïËÃ?l_[bX])Þ6¿‡{KéôóíñsÎ9Gf-\m_+0„¸[>›:6{¶|çÄíku×/ú¯¬¸ÁÊ z?Öh_ “ÕbëÏur…ôgE¡”“ž„¡8˜åRƒ°µ„1 è³;îð ußï4ý9íÝ»«Ý-QR\ï åƒl; JrÀÌë³s»Æ—²Xv±Ý T>!žGHd&ùŒ÷—Ä6dsbe$ñM-cAZ¶øN¬–|? °pæœqoHkoa;ÒôcÆ ˆôîfKY#@ £ºÓO—îf¿¶Â[™«ÚÝÕ¦/·ä?ñ6d Ï$;>>T>+¹vÚGÂä3è}ÀØÂØ›kŸâÜ|O±u¿‹ï O§èYãÆœn€éúHi?ï9ë"]œ,£Œ~¹ûî»ýw£1nÜ8ÿ•‡;ŸøLÎýö9)â{ËS«¤Ç¹"›÷·»i–Q~Ÿ» ‚Ã\«bÊn!¡ü*LV‹­?[•„ªð ÜÔ²%<. EBù>baHÊ3ÆÎxrA¡e.ÀH;a‚—™~ì±Ëì>0%§l#ä"/è=*¸~thÈ€[8ŮŲ±Œj±lê³rÏ-Zdgdù\û„„Æ÷šëËÀŠ|òZ6È¥p 3± \[k0è…s€òÅê>óÿ³ýŒ } Äü~_("§úºëdÙÝf«èxá…²ÉàÁ2ìw¿³ûÖbúä“öu;?î¬Ãœ92Ãx®ñæn?Žü Zþ\èýæº ÜÏl$4ñTć+ŸT@¾Âô'aOXé! ™¼q¡÷0Ÿñ7ð?~ò“ŸØI ¡].þyÚj©¹Mdòódø¦ÞD‚ØÎÌik _ÅZ °j*†w#3>…aê]ÍÉë§‹½I&€/¨;_·dß»PƒÐŸÿ¼•;‹#»…F&JbÒABðTxøÃt¶0á &8+ÊXÖ¨}‰u Eˆ@â6Îgpç3qH1pÝuÕòòËÓå׿ž—êìýûÏŠÀ-¦’œŸA«–S èrHXQKVk©*ô\VqAÉ%––ÌPùDV”tr_r•=¬3¸½ u!,í5˜ |WK•¿ŸäB,¸;\}µzÔQ2ø7¿±ÿ§ü¼ód¸!¤#/¿ÜoÝ„¬qœn˜Ž¹Nêrï8eŠ%¶®Å´Þ3cë/$|`¿~ö}–þœ`EYþ9–Ï8ú}Å”oúN˜bs‘ÐxÊ'¡%ÁIm±þÓFËîEyâBïa¡&‰Qàü÷ÝwŸ¿×¬Ã&XÂùe÷ãdö"o¢A„€~ûnOæ€Æyžzê©2;à’W ÿɚϵ”òÝ\kµÝúœG‰¨¹ü)ƒÐc ”-·Vpïd1Àug Š­?[„": Ò¡sX |:?ŸÑµ§N”!õÏZ"ܤbÏãÀíì.°”ºú²¥(¦ ƒ+ CCHD)•1ZÅË)¶¸_ÓÊì$–Ðìpå“k«÷Y‰CB¹Æ+’и?(?,Û¹ô–ÈŸÓo~ïÞ»ï.½þóû^Ù­·ZwÝlúÈ#ž)Ìëœâ8ÂYeU£?žX‹©é“•¦Ob9ÝH|‚l·lÕU¶’âN°è³ô_Æ)ˆ©»~;ÿ«Xò§×šë^, ‡ÙH(}'™$f‡{¿è®lòñžô!¼¹$ÅöAý …B­¤Ÿ¯}y‰œ¹Ÿ¿c0qÂx[µâ:#[Õ;ùúÆ2ùjäÿÉ‘Gi߇ ~uȼT¼(ÀúK]Ún¸Á¾ØF%×tíè¿0PKûI“&ɲ/ÛÝ÷xSQ8ºW½•ŠB{'‹L“ÅbËg«‘Pà*·\ÀÅÉ…„¢LÄ ÄfËÀ霎ÔR!â÷«¡5á{øì¬j̘ÑòûßNëì#FÔÁ[e-¥…׫XJ0 |_”0ð;ÂVqaÀ%Ñ„2;dà»evþð‡?Ø~‡û¥ž *ŸîýÎ6Ä2£Õ%¸7Lˆ=ˇØð™\ä\’Ò’KÈ9ÏŠîÝ¥þôÓíûv[Q‘Ú_xÄé–MH¥¯`,¹tß‹€ºè×b©°ÖTÓ7ÕšªÄ¶Ì·˜(ÁÅrÚ¥C‡Ô Bºïž{ÚqŠcÈYüºH‡.Lâk)t,Ìç^ÅE\šL³ƒë¨2 Mú‡&_O ,&ê¹$Åß™¯|Fá¼’—¥kév›Bi;ùó·n÷•O—¿OºÞêíÌû€²^MÐÀà4òH{ý ’vlñB ‚dr•SA ,íIvêõ„‘g³Rý,[ôLÐZ ®¼²¹¾ä’&kh[$¤™ä´ØòÙª$4_pqâXc€bc£cR†EcK8OK…AŒKdiÇA§f°È£FUX—;[µ~’˜TãL¸fÍJï@…êèëšMi¹à·±šƒ®âÑ2;”}¸ˆõ«_Y×p‚h„Ýç(K(÷ wd"JÂÉgLò÷=®l&X‰}#Þ-ã]wýõRmP¶º?Ïüæ~øC»¯ètá…Ò~òdKDݸϬp•£¸4kªZK]t¸è"ëöw]ÿl»÷í+½bu×o‡ÐsM¨.Áudf€µ—$¾°ê¹@¯u1å;›<ó»w|~@.!V-M:Š‹\åÓEÐâÉþ­%3ík¶ú>¿}áàÿ'ß~f¢t;øN9óÌ3m9)w ¢öw×EŽÁ ò„Kb!ç.™œ0~\3"iÛ7yžçË3[¿ü“µŽ}ÎÖÝw¿—GYC5„®­¹è‘SÆú0[>× šÍÈàÕX0±!"¸]Ì…@FÁ€L c²l¡…±1` LHøÈöŸ€áÔ)‚ÉöÔS½Î=xp•Ü}w¸Â/dGç¿ÓRפ¥ßÇ= E}¹ÿøÇ–„rí¹ rC„ÒP|ôgÖ»\ªKdB\ùä÷hÉ%Jü@Ö¢VzI#Š%†$«üÒO°J¶¿óN»MÍÞâÎâ"ÚA6ÕZê’Qû>,Y52¼r>ÿœú S,\¸ò™hVÄup‰©–=‹Sp­ùwŒ,42)7Eb Í L:°ÂAº Lôÿ–$ÅE\ù âÛ%/5³x¶3ÔãôÆ‘ö5[öç'oäÖÛn·ûÿú׿l>“] ÑŸ$cÑ÷ù=GÀcD\Lºîj«£¥¤ÔºÒ‰M#°¥í¤f°wn»õ-°À%µ ¸‚—iøpO׫©­¹è‘Ó¨ÉâåŽÏw°ãâD6ŽCô„y)›Nuž¸È&ˆa,`,r<õw!(P‹XFˆ»d çÖÎ ‰<¸«éÞ÷ár¿á†j#oʼyN ‹Æ‚òÙBvt~O1•T|_&ËI®`Àæž\hÕÆî…’P“*ú²ëe(2É9p °–\b±„\¬¯ôå4rf„F‰ìÖì[·ºZ*3ï÷ÞtSÙéÚkm\¨ºôAŠÐšóU_y¥4¶½\’Z±ÛniVR~«+Œ?(·º„[ö ‹[—±ˆñbÊØäþwdóÜÏlòœÐxÐÐ \ï\Sb™üe#ù…B6ù ë&ôö/%eñô­Š×7Ž‘Uu'Û-8ï¼ó¬Lÿìg?“ƒ>Ø?~¼5(¡?©Û‹þÄÂbzúÄqv2ʺæô£(Ýìz"q¯SS´Ã;éM§NÚlyAe|œçäÉécÒìÙž  ÃÝm[c|˜œ2^p]‹©;[•„æ‹°ÎÏÅ!«T-2¸¯ˆ3͆8OT'‹(Ê1’ ø=( ÇÓuÙq0Žë÷!‰»dàñǯ°V̱c«RdrÕ*bWÉ[oy¡;6˜™¯È Ë…ˆºý– ¨‹ îs!#’ćì»Ï(8È V6\ßú6nãB÷‹(Ù„Ù0aÃê–\Š _¹ð›]"ÆqÙ´Û€eÒÂ@  ó9m7ô©§ì~õ¤Ié±¥ #„ºŸÊœ7íhoáüç`ühùãºq- ¦Zëã¡»P„»‚c– f×£ÀÈFBQúô¯„„fúŽñ ¢Fì'Þ ¶2ÉgjýT &6 “NÓ¿#þÓUʧŸgŸ]þÓÝn­õÓO|ôÑGm¿®þäú¯IF‡t»[üâp¾ôr;ÉbŒ‚˜jõ-‡¦ÅçíêJŽ›½ó¢É2nì©ö5]cÞ±€—¤¡Hâ?Õ?l˜wtßõj¶%·|&9¥Ïm0–Ð|ÁÅq… + ‰Y! *XdpÁgC.B…°Aw/ƒ;VÜ“ÔDÄM˜ œ‡6î’S§"Ï<3Ô¾ÿÐC}å°ÃÙ×éúR1¡ Ú…‘Í42Í]$ÉI÷Ý÷ ™ø-K‰"¢bEC¾®U%§ð%¬ÎÅ”ÏV%¡ù ¦aã"1p²üY£ªrY…‹Gˆ2Á%²Ä]1û² ‰ùº'é„® ܸ¹çž.†à®4‚ØÎZžø^²ûPS@ÑúåË=W³*˜Ôìðù _%˜/ø…$9„80‹kÍÿ°¾ƒ{€å «>ƒ1²ÆRÅ&òÜw•­àoÀÇ„3g×£ù¬–fbK ¨KBék¯½Ö#†~LX*–3̽ÎÓí–-Z$o_x¡ÄsÑ“!ïZSùŒ·¤Ôh#»I½ä’™åûR$Õœ[g¡ú.×·Jš®X”±¦AL·C ¢¸7•˜RöŠIv¾Ä4Êͧ@>S S¼¡ƒëäö®kk’PW>£½³¤©XüÄÆÖzG¿Mä¬]&úG=4töbBç–,[¯¾J;íIYtÿ1ò›ßüƺÞÛn~ÏsŸ¿} €Ñ²¢ï©©õwÜ9Ù^ <¡Z=ƒÐ(ðTÇ2ØZGŸZuŠ<Òí¿òšœcCUþßÿû–°ºñ¥í]–ïuÉl¤º“myy£¹^^(›??µ€ŒBJݶXNÕ*8m«^6¶bÄaÚèÝñ6ŽBâ‚ä«\™/èTœƒÎ«±9A×»‚¶qÕu£Ošä ú|^ëe’œpë­{ˉ'c”GGCÈ?’Ÿþt–UÏ?ÿJj&†ôý÷?³¿³¥&Î÷?Cð:¶Åv%lhÐr/Ä(CNp}µÖýWùÔ’Kü\ʶäR†0›Œ0‚å–j*…H;#}Šºš˜ý {ÂèZ7AÚµ1çUòé‚$¥4Rpù3š²Žÿ·š„ÁµVbJñnˆ)åΰ˜2逘SM²÷ƒ'FÆ\ùXʳ!Ê¢Pù,¤Ìo,PãLk!›þÄïPð§Æ]åöÒÏì뛇ï-Õ]6·¯Aéš™òâ€Ç¥bÿÛ¥÷Šûí±þ«0ýÊës€mÉç^âàù¿¸ÃNˆYQéOú“ôÚºæƒíÂP}õÕA4D1HšÏâ¢ïÕ¿¿ML²0Úŵj*\w»…ÛŽ-ZÉUj“„†)Iî9‰|Ü¿ˆA„˜BR91%4ˆÉ Ä”ª$X­ÃˆiUD·§î{Ýèë¥ú¸U²hÈoíÿ¹þúëmßøûßÿ.kw¼VªŽ]f-ओN’Ã?ܾÆÚãË©öµ[ÏÓET–{*KÞl•_ jdÕ/ÍT5pœl¹õvv’DØkõ“܇þäõD_Á}RbЉQÆkbM!–(0€«bª%îµÆÔ%ò™?TNrÕiù"¨?uÅ£mJîK³‚â’ÿ~Éëö5}˜¸i«N•y½¥6±z–w 1 ”¶³}]û=.ïTß7ïaÄtÅWÈ/þ¾}}Ýß'¥H£Z:C<®Yòõ¥ÍÈ«’ÖÚ'Ù&Ī?y¢?I*þjÅ ™×¾¯ÿ)ˆ.˜7Oª©2ÊWdóy›‡Ê®«ÛÉý`Ÿ§êÿ—_.K-NÓZ྆»­!Ÿ­JB3 ¦(:uñÐŽÁŒ› !áÉEÒΙ/r±„ò]XGø=l ` åFåò;2ýç0¸zÉ%¥@Ýó?ÜÏî»R:³‚'IéùÔÍ‘îÞ³»u¹Ú)Ey`m>vëcm›È€Ÿ°VÑË_ºÜfHk€r1¡\Kc‰’kTö ·ä±Î¸Ä4ø=ï §éìQKu6ø‰«O>Y¸÷^™è¡vb¹Å¶ÛÚ¬ÚÃî¾[Ž8öXÙöo“J#@óõ¬-ó;LÞ7¿óÓýÈ®¸Tyíµ)+gÝðáòöEYÙ€€ªuÔ%©J^Ó„;TÞrCâ‚óRÖÄÅÍxÂ}(nˆ©Z”¨jÂÄã^sþñX}öÙgí“ Á~ “õb{*®þĪ+Í.i¾2ï-[éU±A¯ßºgƒ 9ò›rÆ OY«gø™äŸþÕû·ïÈA>–.?÷ˆn>õe“¡Èiqõ':®Vc¨­nL Ë3óè”./&ãµ?¹@6‹ζÎ-¡Ü”˜Ù  ˆ³tK)ñË[9ù`Às: ®A¬„t6Hš†Ä=‡Âíxù E"MGTk§ ]“–D&%¢®å¸nö Ë½®¡N~ðßÈÖÚZºuí&ó~?O®YhßOÌyB¾Xú…¼úú«ÖbJ­Èb¬c :{!#Š-qÇçd¯JÎ-¹Ya²©5Gõ¾·„ô†-ÕÉþÚ·ß–wÞxCž7ΖïùïÛãµ~2²ƒïªç½®Ý^†<ñ¨œyò2©¿á»Ö»]dÂÑçŸ~:eå,Ÿ=[J«ª¤Áü¯f±Ÿ 3^DÖÍ•­b)ƱB“PÜGÎâv-J„21ù%žLf&$ÄN›æý%ˆ®-ÏÖ"¡|—Ê&+óé7¼®‚tìW}äÍW_·÷}÷½ÇÈ¿:{:åÖÒÙ)~j½côuW§ð:Mǘv]˜g_¶¿Ç`ÿs‘Ð(˜Ï•=ísìVÏ“#ø½u»+«¾y©t8àÙyôÎ"Ûxï-ê¹HJÊJ¬·‡Š>èO]nwþü%©j8jLª²^ÚßX/·Lð&c$(ÿà…[ý0èCQ$´Øús’PÜ2ÄXpS˜)»ÖzqZ¢œ€+Daà=âšp½C‚QÄǹJ€×-%ÃùRéZ;ÚDÔµœ, ®›Ý}}þÔó-!u þÙ`Ñdzò€Ã‡.7r³ÿÐñ2yîd›¥Ïÿ.H\YÍ”yÉ—˜rÞ0Ah °¼$$4ÂÈ$¹È÷ž*¸·Zr‰äHHpe3ä³ òåÌÀøÝ‹Íä–ïýÚLšXbØ~æÌð\Yuê8¹Ó(ˆÊYróݽeàAÉö»ì"»2ŠUIéÊ“N²m+”£O9EÖL˜ ‹Ž8«2Än)ë¨Ù¦QW…7-½æÙÀ}åš œ?JžñÈ[е”ÕqpÓy¤ç®M Œª|¶¸—È&$²Rêdf‰—9  ÿlØK~>oˆÜÿÔ¹tf?++Èx§òö¶Tp—èT”ÿpštv“Ýòÿ2öûv¥²úØÁöeÍI†ðšý¬#˜æsöó±Ï“ ¥Mý¼üÐr©=»V>ü©ýÿ»ŒÚÉÆO3ö0é‚ð-Z4×ôû9¶ý‘G.’ysfKãÞÿ>vóZY¼p¥ì±G}3¢Z,DÉêëŽÇ‚FmM¬jÄ{Bö2 Ö²¥Â¦B„UT‹§¬±á´åõî›-¿¥ØÊ! ®µS´zº¯A»²v2a7Ïxêè¦Õ!Àä7Â-7³–βÑeZf-¥÷¾{¯=~×[wIßMú¦­cM bwµÔ±_ù”rÅPЉ%47„)9Ðk Y÷ô áè/ ÆQ%—¸ÿ-&¡>ðh[NÊ`·Q£Rjš ¡qã=KËK¢m/gËÍöX¹oõ$6´ãw¾#} ñd’JRÅ‚ö½!O=%¾÷féÖ[{q¢‹ ±ZvÌ1ö5°„ÔŒ#šô,ùäBcÔ¸ØRp‹IB£¬+.\%W¬ÿ¹!£ÐžŠL ¯üzÀg6´Wé””%‚ù—ÛÛ˜jŒ;m»½ïÖگĎ3J»k÷°ÇRÀ"y×'ö%ÛR#úÙôëW¿%OÜ:Rªÿ¸—$~ô’tÝò» ‚ϯúxB¬óÄ‚_ª 4–z¡.š=ßé­Çl?ÇëƒÁ ýyÏ=ÝΜ/þó ©ª©’/û}i?{Ç›í匳*S ÷ƒº½@÷ºÅg eÐÓ J'ÈgœXœhÓRa£S‰,$E1¨d}Zk¬OHðRÙêW_JDR|,^mC›¤VMÚ­@v=¨;Vºÿç?öõ€Ç—Mû÷—f¶âÏ–™?ý©,ðcP‰EEÜï°¯CÆ~#¿o}%¡Ü‡lòÌø›ÄlÇG°/´& m(+‘{å„.®:Q.z¯»õŠuïÓËz80,éïtcG!¢ØsÅ!„팼Ÿ²…}i·f˜„ò~C5a®uÙ¤¹î¾n©ÔGªT“Ù6Ö{!æŸ4eϳuH*@6úôñØjKésÒ¦Òï×=äâû;Ë£ö—#\â·›—¸2Jæ ~k”¬n–P>È ±AnÜg6ÂíÀE¶Ò€›HRäHߘ*óòío7Ë®íaÍ'ä½ï—IʤÈ•ÕÚ·O_‰! ¸æÇ ãñ,¡KHê%÷\b÷OÝùTk ³—5ÆŠú—ÿâïEƒûdK]ø¥\ÜŒY·ÔE°TqadÌfSZ¹¢5fr2îI.²‡léäo“¸%—\ÍšLˆõ•q†Bˆ‰Ê1„¯Äü¾PE‡@9VÑ:?ùèÙÇœ£FV_=©ÉbÊÖ´­4¤•D§¥W\+7‰—ÚO™’š ñº™6Ë—,‘†¿ÿ]ºöê%K¾ñ ¿¥È‚× i&6ù ¾dSÆ-…U”똄&òÙ2p}[‹„v(-—£¾l*“xâªþòæ ¯Ø8ïÔQvÞò5¹ ü5ÿ]¸Þ5NTq[é,yã-¯¨ûó~RýÙYòƸn6´‹0½(àaƒðRE'+"\îMÖÑí~‹aÈ¥’ÍÚý¥þÓï§•Éök¼"ý fè†D„Ë‚ØÎo?*§Žó¸Ã„q±oò=ùä ùã·´qéèLô'×]ʸþÌ—1Þ2„Éêg E¡a1 ‹û̆\aÔÊB¶®wn(–O«¨”ÑA„´ÌËí·KýDo©1Í®æ¦-ca>§ä5’ ®hV¼&$iü§ÍÉÓ'KeMeêøÔMY½ŠwiÛ xôÑ”ÅV3kÝÀ|×rwÁµ+6 …$eBâŽÏ A}Ra\Ô4ÖËÃý¾ö÷DžØt°É‹iñ¡a‰G€c7È^òâkÛÊyoUXO™Û÷xÍ1±Ò÷ÜÿË1V üïØ}×u¹[ë¨G†gïÙQúÿå£È˜Ñ\P½Ë‘²ú¸HɶÞï­Ý¼Væwòjˆf²‚r¼zðŽ)òÚø¡È˜Þýܳ»™$J“®Óü†ôgjÜØi';î1ñærmÈq êOŽ…éOú×9ìzÒ¾Øú3æ]\÷hÉŒÏ1;  P"„ά<å~÷­—Á2/öÎ@HWwœ”ûÖÏÓ„¶DÖÿܺ€›µSã=«ªWÉâËÛ×U@\¨KFùÌÅ£.–Î:§Å’V´/|] È(ë…ãÆ%€—&+uA©(&AÁR@BKh|•È${$E•\Êô8³w@ÒqŸº„.Vµºžw^¹!7ì¼¶ÝùÒe“^òÆŽ¦»ã͈ÞáNomjÈ¡KÕ"Z{uÓ’ûͺUÊÅÈ–S£W³\)©Â{g‰7å3µ•~Rÿþö°5FÃÆsÌu÷6 †k¯™µýúõK%ò¿!Þx¨:à€‹Ö ¡‰%´¸h‰^Œ ú ±ü³?þT™Ÿ¾dö¬¯œñ¡¬’„Õ3 å?œ&{7C޾‡߃àã}¦þ@ùFôwh(_L‹fõ÷–—ïÝIÞ<µ« Å[U°YÌh>0„²ìóü®!–{Uˇ=¶´¥› ¨™P³ëRâ—u¢¼Ó+_{2óòŠ2¹crSi&ªÑZáÁ’MŒ·pˆÇE2^¨þTâŽÛ>¨?1öà}d³7HKh¾ÈÇŠ¢Q÷ –¬3 mà5wÊýî[/-”„y¯«Ÿ|,£ Á(™]Gp­›l':)d²¥UÝ^yÒ•v ˆ][»ÖfÈ¿õÓ·,ie[,0عJ ¡ ^—²¶ÔÅ.»¤²–ºÀ…Cl) ™˜ ¥(ÉŽo9PtAÙã^A~ТJ.åd3›œSŒ{Í@ŠÕ“¸cw ]DøÖ[½~ĶòëZÙwæ-v?³=æÄ¥£o¥,ÿîÅv n”3­Õ@Y®Ó®~d¶J§8]êÄÈ–S•â ß6Äð+yë­JY²¬Ê¶ÿêz†lÒ¿kŠÀ*lшkÞ]Y àš`-D™h •)4>®àƒqÖ™®åº&¡ŒÏÉ$±e(6 % †2ŠP8y©¿GÚ‚ÀZa¦`‘0O³àËï6[‡ðÑô—(ƒ‚‚>l“) > Ûï¼£zäá…-ÓäƒÚ ü'Kê¢, ”j®DKè˜i<¯LöýuIje%Ýj­ð8%›TRyˆ±™‰ºêOÈ*ý†1W>²Ê– .î}ÕŸ$ cÛq+ åâ±\îA’b\×{.çI;n´Îj£À€#ŠÕ³zÉ’&˨Q2ågŸmMÙ(KÜhdë2ëhIÍ\¡Yñl¤3x,HJ]òŠÕóäGO–Á¿l]ûŰ€ºà¾dSŠªÝR.}ÜûZŠ;ì0+„·Ýv›%© òCPÑåRr)W ç®Rr¡Ä²Å8‚Õ5,á rxú鞌³­èÞNžy†ÝW´ÇúYY)îôÖ³/»Zj'ù$ðÊ&ë§Ýú¿iÏ1õͪRœþ2|x¯Ô2{ûϺÅÐÔ9yÕÍ–°BnéD|vË85^r42ªà7ß|óÔ’¼XI™$`ý`dBaÕñ§Ø$”>“‰„Æé$\&>‚ýë[ Ê8JÿÁ• ‰¡o•öì,•åéº òI¼g& ¨…!xiYð>áC7>øàƒv ìÿsjXÿçXš5í£²à£Æ@ß/x™&™d7 dÔC@íë¥ÜŸà2θãKJÃìdÙ ú“ ­ò"˜–%÷ŠQ¸ °ÚA°P ü.n°ëF+Æ ¢€TÁ1X8•”^sLã@–RMr*¸/Ù”Vø  ÍDÆR1½à‚ là:ÿ÷¿ÿõ['È„°SIh>%—rò6IT‹ ÄÒˤ#Ô%çãúëëÌZm·`÷÷'Éê¯V¥âº«H2dmÚHOöŸqº\=Éj q Â-ÍD‚’+ë¢Eždά;t  ŸŠsä&™pòêTÒxs·d] %WEF(BïÞ½Ó–äÕ81d„°B’ÔÇ$Rš)œ¥%à>f’g¾“ïO,¡ù#ÌKѸ=^Ó‡ˆ;D.»”¦'ªû]c@CWBrP÷ûØ,x²áç×d$¶ì÷üÕ 9`Üÿ¬ë^”f2aã<Ó-šœ ûøãË{¦¯§¡2Of ”SʹÊ.ÖSÑÂfk÷}@IÔ â–fŒ ~+cc:ú“1ý9‘$Nó÷檫®ò[­NBs¹1.² ‹Ì9„‡ Ë |΃bð­¢îúl±Ÿ$/Uú–Ò…G!£÷ÜÓÎ6 ¡:ëàæªY„¥@Lf…»ÖŠb ¸ŠYﺌ§«çø]½ˆ@-¥ÅD6¥• ¸ïHþ]wÝ%þóŸýwä dVK1XEY à$W?ïj‘øB´â h)èôýïÚŠ ãþ3=«å³n±û©˜«KºH½Q¾€N7V“Ó–XÏÃ6‘É&ÚÕ•(pÿÑ^¥¬jµwÞÝYΕø{XK›bK 1ç|AäªÈ‚à³aqb„µ0&q~¬Ú΂;.×&2!›ºÅí±„®ðwÌÖîûàg1N”—6¦Üñ…räIìpÀvâzõÕWËý÷ßï¿Sx´: ÍaäQAm=H.o˜<±Q.ž ’KÁ·€†Å‡ª¥”XO…uÁûĨ²|æ´Óä##=ï»ÏÍ øêFsË1ÛDÁ“hãZ+4x¸Ù° ×害t^}ÒÕrï‘÷Ê’ÿ[’f)-¸¿…$6êê+±ÝØÀ@Š — %—pÝ Ü+ä“ïfΤk¶k‘É$©lƒŽ“'[‹æÈ‘ ÖjIRÐA~ÿ;Ε²Ù^\b8«ÿô§T¬&Du“ÞSîú±kïH­®DâRåÒJ;œHà"蚟$çÙïíß¿k¨U”kзLÎÂxC¬Ä”„Üqa Lp(g5þF! E>A’ÁþPŠ – z7m”‡Ù;ûƒ&½ªå˜Ü‚ôa%š “îªHJ.9ŸfÄ0HÊïùÔ¾õßjrÙÑL&”¬úP-ã4úºI2|šgQ%ü¦kï¾R¶xS»_¶`³Ï³·]J·Ã¹çÚ×£FIûCÆ‹Üôphù¸È&»nq{€åS3ëÙ²¯D”±äᬔ/~½Ânƒ“ë–‚þ&§gÜO“|p‘‚Âñ£X+3yP3üL7ŸŽ9˜š»ëºæË¿û]kPb=ë† “'zÈ#Ÿ¦=Nÿâ³Ï¦4†™=e©åX=*h­@cÀ…Ï¢«.´\•‚ Æ„ºà¿•—–KûòÂϾÂÀRH¨$4SH½V:±#–…„õ±5,VÈ D™¦ß3QC&\‹L®°™ò½º¤Å…®;Ö(Ëvf’çÉé¬Y^¿Ãz‰…òL?Ã`Õ%µJ¸„rÎÁË¢®ž;peI7Ùdx[Ê e¡ÖP%¹¯žÚ´àľ‚óúó^‹bPÈ×™ãÞ⎠[` f:qöqëøf#¡ŒcáLa 2£%$”{‡Œ1ÑÜsB9¢t×%fÈ·ý¢Y9&ž¼v¥ÁC¥,Ò[ï¿c_2â>úhÙi×]RmæïÓUêþê¹ìÀL  ˜TjúDzôí+dø‡'ˆtk{0}µÊ·ÔÖ-éó7óþ©6Ô¦ýT¯>¶Mä÷¿ðŽÔ ÜÆ¼ÌOqm#eׯ \¢«™õl러·EïÙBF)×غVÒB JNu’˜$&ù@Ø”tÑq <(,fnq3s¹Ø™ΔkþškÒ¬¢PPn„¶Ä(hÀ JÐ{3“:âØce·ü£EÊRÁ5Rk…»¦]yÅtˆ)઴8m®n|H§’Ñ0K§^§b*BÜß\È{6 D‰•%7`q‡pèÄÅDæyK&[6]åY‚º5zcQ¬¯¸æçÍ[%o½þµ¬7QnœÚ3µßáÆŽr^×ÊÑZ$4 îXIc q‚¤@Ý:¾XÐðBa1g<Ö1ˆ>“iLf¢ƒ|¶Öø²! x­ÐgùP-oÆd"NŒu¥é©Z>¬ÓÒ¥ËÒ¶AÔ\±Üsu_™>¾[*þS¡}XÑ%o ï{»¯Ó×¶Õ¦'$u8ß«÷»ë¤Èð×üp’Ž{¦ÑÕ†l.ýžQäþwtä?4É@cÓ 9½Jêwü…Tï~Œ4wd”]ClmíPƒ` Qµ€’œt«VÒÆm<+i!EB‘Oþ\¤˜huš/¸H\,ÊŽ  É€Æ5ˆÅ 踠Ãg"¡hóT«(ÐòKæw2v¬4n¹¥uWu5‚;è‰'ì{å·Ýæi½"€Á20tèP©îÜWÖô"»î9Æ* ÞC7‡Rȵ¨uT¬§*“ÖRÜ—0aÈJB%AuëÄŽg¾Ö–8 Ÿ¡ ™Tò=Ä0’å]ˆ¾€(»™òí*<Ù&Ñ %üÝï¾cäæ]ùá?²äùyûí7l2Q'Y#ß6TQË6A‰Õ˜OÜí¾ÿ}9ú”SRëËë–D'¾‹ŒùÇ_b•cÇÉžûž•˜Î>u¹%±€UQÂ’ 2*²  ‚ßIQ[Ç—É2¿•:„XϹ$¯áæeb5%“Ä–#WÙă¦[°|3±ÈcMœ§-Hßà‘‘‰õÃÓÊ1U7ÔÉC}—Û×lÙ‚~6x˜·¨.x3ÿ EIûôMüÖ'Ÿ|ÒÆy*T&ËKš’N.í'{ñÞv[õŠ}mM£:úßÕ’òÑöeÙ3ùÍ“š Ùd·zÔakˆ]óXG¿wL…¹W=ä‚Ï 5YTùŒ;Fä‹õ†„rSÕE¨V”U®ƒ44®UÇf½û üRý·¾%%þg;Ι#»³dÙ;¤¹ð­Ö+"º½ÙE¾Y¿‹œRµƒ ü°¯ü¦rpZÒÛ`QkžùÄv© åzó¿«>Qr¹ƒëÁpK.1@Åí3¹‚{„5Ÿ8D,ý¸Ò2õ|*4!ÿÕW^¦üš55–dó}Lèð2Œ94Ÿ+šý'†Œ“µÒYH6"N›ä%ˆ).󯿮•K.ñâBµÐý–ò©%­¿Ÿð¾œvêj›èt»]ãEÙ›¦ö°$ò9iRuè°á*ãb Æ…`Bê—’ÐÂMŸÁC£c¡DÔ›dqâÞ'á2-ƒÊf¶¾Â½Ö•Ÿçq“ ÝxÏ™¥«å®ÇúÈÕÕQS¸kÊõeO»†QÛíh]ï»N^é%)9ð ú‚þ~óüϽìy&©ì·¿¤’þ´O*yÐbõ”&"j]ð.¡4¯Õ-ŸzÏ\KV=Ô7Ìèòüe#“l¥âAßzÜ?ÒuÃu̓ZsIn[î‘Ï;–µ·û…²6áWù,6ò¿Êy"ׇ y"6 aƒ|¶ÄJÂç´3g…c e-è²ý˾Ĉv7ƒ/p³ëƒ(ä;×zÒÏçvH:=$Â-j 1åµÛ…µGk¨fZ “ëÔš ‚ï+†%4AËP K(ç#ŒÄ-¥F t&ù4IIÁÿS]Ôþ²䤋¾”Ñw® œ¦t–OIl‚9]z±Ùzñži°ny÷=ó;”˜‚ò–é!~[ê^¹ÉMñ  Ì ¯hgN5¡·bÀ–ýB¾EB‘ÙbŽA ÕIh.`€BIQ·ŒÌX§¥E±éÈ™6Öšžõ¿ÿÉSFÉ,9ê({lÎþûK!si(²TDÜ­Ê œšA*ÛE00×Kq­¸ÐLtÅ,©i‚D£¯éu Ü×y Jò… Q‚ø»ß…$¡ô)&>ô7Bk°<º¥Ô¢ä è­¯x1Úl£,¢îrúZcB?ÿÜK°{òÉ!²Å›Ù÷](y%aI‰#¨¸²X\\Ó¸‡ÿJä©ÁUiîvî1F"°hîüð ¤!š)âù¯O½Ìw·h½"EBϰ´æ[og_ƒHd¸Aý°a6Ùˆ¸N»M³€xoõÝþ /Æ´îø`|6Ýð M×mV-Ëv6c‡Ù™HhkqÚ$ %†× ä—;ƒq+¹Ç(p±C%Ä3a1œ9gŽ<{eóµ™U¾}É%ž Ä@!3ÙúY.éçëZÚ Ýsàm†ÖÄ¢¬Kaâ‚%ÞKWLк\+¬©% ÑDAv]Ø[*²[öõÛ|Áù ©Kha€Ì‚„bq'n™ìjˆ'usƒ÷'J>‰[>}OÏ+¡Û ‘îrúÚ¢Ä+Çä‚÷•x¦êƒš-óIâ5qÁc¹¬¿áºfYîìC&§L©k®-Ç”œ~úžf¬jZûÐCç[Ï×_Αæ¿ëø•u¾jd¬}¥?: âQ»_hè5. Õÿ¦Üã9c–Rj:xàþ; ²Á%aÜ¿ |ríuÕÌð2¨Ñ!¸ÖЃt’RG§qNb<ëJ½Xϰïp²ãÙ’ùî­wÁçmßt>³âdMMÓ‚ úÿƒ:˜º½eŸÍñ“ IGÙa¾×·†cÚw<¿ ÙÌê‘”å†ßÝ^zÏ0cÓçfljºõý%LNñZltîx:1Cš €ë x.PPÐòEª“g7…˜1(]âfé–únŒ8$´úÑj©¹²FŸÎÞ6.¾Úeµ]þÛù=™·Ó*Y0jÿNþàš@tÅ!,¥ \:¨è€_|’%šª Ë꽊ìë1» *͘J”û¥´òABBóCPF±d!q'^AðY,](Ebé[$³„™äóúq×˪«üÚ’!nyÈ&!zj¥~øBûzøi§‰œÕ^öþÉY¦OTËGxÇm¢’ù DTëƒj™$,•dÉc¹Ô}Hç˜1ÞùŸ­¬yê)/ábΜtg·n=d¿ýö”Ë.ë“SŒ”ú[áÅ·-ª<ÂnsB yÓkÌõ.¸ç “<3ÉO<-×X¯·.*Á–¤1Œ'©ëËò¶/¿$O \kK5¹¸açµ2î›+í6 Î4âAð úç'ß,ýcˆ¼9¡{Ê[G¢`0IÁ©W··‰H6Å{æßM_ý‡&ëo>°òA8IFr“’2¹ákŸ¨—¿=P)W}²&-ô®1¡ôõD¹h-ùlu ”.ËGcvŒeÎ-wÔRE¨`ÐU ƒ®‹M ȵòܤƒv”¢Tбêßó¿çC¿£È*Ú£¼N†w”œ, ¹‚4Žÿ¾ãÛÈÞ{í.C»?å¿ëau»h푲¬þ›öuUÇqV‰Ze˜‹…”ûRH¥˜(¹Â@û&¹‰‚*EäŠe&9ô­(d“OÉ-Í5kåÕWß”±cŸ‘¿þõkYôå2™ÝÎËšµŸ+­•K/ýXfΜ›ZÒó{ßkgÔâ‰E”"òd·»…ä]²zþù ™î.›nêã î½×³"<úh™<ù ëÅ"U_Ÿƒb% †1‡¤)PÝó:ùXÞc°ÌÉÃWÞþ{ç'Uuýñò,KY@J `Iì5ÑbÔØMì" [P±+‚ ¢Fc‰&ö‚c‹ÆX5&"Di ˲»,ÿû½oÎÌ»oÚîÌ,åý>Ÿ÷ySÞ¼yïÝ{îùrÏ- åÜéΧ%’ÏÜf$2ÖQ*‹"e´èka‹¥46æ=CðöÖW¤|¶°Òªo¤#³ð,ê½Á‘Ý~´‡Íc%Z§Þ ŸÈ FÝ«¯¾Ô­5ãLõI'Ùß64Ê÷Ì«·ØÂîkO6:,Í• à)Ü‹O8ã€ÆòA »‡…áëêÍ9>8ÃÉókehçë Å#ªžÑ|ç^˜±X¬t¶ÂŒ@9€…—M—åÃëHX؇>¤Lä/8OØ9H üŒB Ö*$™È°-«°C¬a`®ûµ†xñÙuÜãöÝî°J­|é…qïLmù©ê½HVon„¿ãL©,¿U¾¬ºT^™õœ¼üÉÑv©ž10Ékê!u Öo:ÏI®ˆrB›_Éi›ä‰Ð|4”"ùÜÈS6ÅîSɧÂËky±ÚúZë]„ðÖ×רž›ß½Yzý*±ò‹Ïý•–ò ç›<9± éT²©Eìy?rdbЧ¬Ò”)Á1ºv¼†êd–cÛºu¹\uÕfæYì*<°w’b¥tÑH)%蘼ƒaÞ«]K–I~,ª³–7}Æ…$¡™d92›ž3r‰§§F°|n¬ÌýÐŒýo¿eߟX½‰ уT…ê™_ðÌ3ÏØ}*ørÎ}FˆJ‰4ý”¾B´ŽJ ú[æ.`Ô.˜;_^4H^øÃcM"5 ;Jµá!š»Ý\( µˆy@]ø¹¢n¡z`‰æ'äÝÍ‚÷kÌc¸íÙ•Ö3ŠGäk–|*Y]ïsBéDL8Biðò™nY¾æxc\p~÷t«üyÍu¤b½>_€ÂÐöжÒö¶Òj¿VIîö|æ‰ «WɦA‰@©÷\Vóˆ´Ÿ¿g00tîfVZùé6SåˆmŽ“½6¿Oz¶}Ö«˜[}¨ü÷Ë™ Z+ôyæ“„¢ä¢p|óA;³eCBiGJÁMÐuæ©G¨òä{.ý÷üçH5ñhXž=8ý¡Ó¥Ódøäá6×”<ç6mÛÄ=¦Š†7ƒºœú‡ÇàÁYt‰¥B‰¥ÿÝØ±«â^S„uÞ¼ªøÄ#J/)åXH¬žR‹GT«®TÄøCÉ5féW-¯‘¯—`',?ý«¯ƒ%|k–ÛÏ\Xè·ÇÞåŒÁ¨‰pÿ<‡B!•wÅJ®9gë#?)†ÞBŸ¡;©›ÌVæö/¯¼Ó_nªÜ.I>)Z_Õ08^¼ž¾¥“•Ø«¬¹ðIªÎà§O€t\€±D¿cÖüv÷Í—Ÿœø/9ôêErè¹óeõ¦¿s&&¥Gí€R5{¶¬˜¤è4ò€6qrí“R¾RÌ{@jT¢ydŸ Ysv‰´Š­+gô”‚‰Iùš%ŸŠ„KnJr É·d aw¼™V¢ã±åâ […‚OÝQ–.#€ëÈ´„œ*Ó0ÁòAGä¸ÕkVËšïÇH×Ìç­Ö ºFJeÎòCìëÚvƒ¤låûØ|ІêØ;£ _±æ »WÌï] S%FfF==ª‘|ªЯp䀰ÉJô=—¤}DÐç1 Ê'ý'{Ž›6-H Ûo¿ýì¬y]5©õÿÛº&¶xMùÞÒP‘ˆ¾|{è¡2;6îÛ”Œš}íµ²*…Î÷—Í\·r…tX³¦± j9&ò@¿{»RJþjÎå„ëïì[›·Yò´›:ù\K> 7 ¥+k`Áè¬÷l@ƒ2¨eR„™€@OÂäÂÆpª€Tàt²Th¨¶æ…©S'%¯›Çlúþš³ŒÒûIC\¨¸î‡c×Fpÿ]v¡ ½¯Úhl<V·îg%ТmŸm½£ ¾ƒ´~Ó¾cw[’0 Éò„!)Eé(¼¢´!HÀkúùbÍy.\;BTŒõÎ×7„ ž R© @RjP$l(°R06¯,æ™d_][ô^=+DÈ$p?÷¡+§Íÿv¾œ´K æ†çޛŷ/–!õ+EÞü½ 9µFÎ{ì,Ùòþ2êÙQqÙã?ËÊ‚ wܱÜ(ÆEIaxí‡:9‰½"yÖY‰µ°92éæfþëå‘Ò³²›‘- ä3w0>Rª(† áèT²™O@:6ågòø?·ïÓÉ'Î% Ó³÷A¿#:Wè§Ô>IÿÑ~Äç¼&OЭþ,Y#µÇËà®Þ"ðÚ­Þ<æ]¯yGJª–J•1Š ³w|ôQéüÔS2ÏßewÞ)õfœ#KÔ† R)F¦VÕ'- šµG4æÕäúR’ÐØ„¥‹’ÊÙÉêWcŸ;×§Ææ¢§%û—$…ëó5Kžg Âdu½&¡xIžÎuäA5WØ =xlÈ·BY¾Ë4Xú s©bòÁŒøšÛkdÕó«dͧ1¢úo£”Ú´•’7K¤d‚Ùþ’HاÄIiM}Íg©Î_Lt¯»Löë}° ½£PK«ÿd?_]ÒWV·Ý;P²PÇC ð’òD” >xÞ("Âäþ°ÒÏO4í¡!ñ\×¥&ôDÞœU¬Y" Çça$”>Š'› m‡"Iµ ‹ë™dß¾¬}Ò{%ÈÉ}Bå“JÀ50o:†#†ìƒ§=˜žWœùð™Òõ¢®Rò“³eð„¡2©´]œø>ù¯'åÔN•Œž¿ê)üñëMjÕªLÚuX#$qРóYb¥%^ûòI~éÀ‰™º_T’”›ùÓƒÿ<áà‰2ïÛÅh›EçÈÄË:Ê}מ'±€¾ž¤ÈœYóì7ß¼¼öoû-’é­?—«ÿ&Í;×Nzªüâ+£µ³Ûhׯ¤”ëÏuüÍ<£Lã*ò…ãs:‹ ~êýÌ&JÑ\¸F¤"L>]¤ê_è`®—±™ˆ DU#Úß!‚È:çà>ÉwÅA¡ ÊŸqžªk÷”Eÿ:Q*_ü¹,ùl€TM;Jjzßt°G‚U”¨- ;pþ]bFݶÛÚ2q8EÜ]˜£‚î™»_ºôç›ÈÊz£Ï3è7ϳ‘ìz¨ÙùP©]ÌœKÑ ›¬¤áú|BûM˜¬K¶2+{­ž'(ÑÊt „pU®À[à -äTaE2p§ë$éÀŒ<»ÌN^"T?fLã²J¤ ì¾û^æùeÜÀëS‡Ê¾»<(½4T–Uµ’Ó{À¾>tX–‡'gC·\ÆÞ\Bíôyî5 IG¦ð¶Bv­Ñ×5È{m»ø,#“‰UŸæ,?È´kƒlÞeš|Wû ™U{¥%¦?úánRÒ:?³l]vC$‡g `å$•ùÙÙt BÈŸzœÃ =fûcä¡3²Ÿ¥#¡>0|èÓL>‚ÓJô6îHÊ`|gr„“P¼â°Ã³úsòý½n†Àúú3¿ãý„|N¾‰,­^nåkõuOœ¼5Rm¨âïÛþBÊÊÛÙƒT`’²ò·.¨ å…‚Önf¹]8鮽öZ9úè£cŸë %”º¡‹lÁíábÇ›†ç„N„Wr1MÅ믿n­·vï¶³e˜˜O'â¿ê_®· ”l„íõ½`XÅŒyÝö´`ð§£QOTÛ‚Š€Ùß;M„0A¦QÀÍ)@œ æ •ÎòÇ8¹l )‘*ó¾¯y?#vTŒh£Qm+/h¤3 Rƒq ôȪKL1.0*ÜÁ‚Ž×‡öFBž"dž³«ädžç‰ì1‹›¼Od1›õ§sÁr3àw¿$adâá<{òÙ6ïó Í’»Üe‰p:ÂJÎZ•ýEæï'—[ýUªJ¦KEÛ ©Z+¯d>—· á=ÍÉ­û}­üëÓÙ²Ãv E²x1†P ›ô1ÂyÌÊÇ£rñÅeÊ”rëE:µ­9ŽÈF dõ5áü˜ÞµP jÊO–ºn‰ÈçÆKK.<[Ûn€¬Úh\Fòµ9/J¿·ZRʤ§y­®·²ƒ壮$׎‚kD c`L£!ðDÆ"d_>™ȳNEøó‰>þH:vè(·½›%¤®¡˜x6ß¹vrÅÝtúŸ«žSÙ†ø¡Ðw:g ûÈ…¥¯òÚ Tgú{JJÙ]uFËm“ȯf]z[8?¦{¸ô{ä¿¢C{©èÜÅÊΦ³þ.íç|nCíµÛÂê¥LŽ"—d†NVCLµRb>À½@ú‰b¹à™Qcvâĉ_H¢€·—éH:`uв˜¼1¬/&1Øáö§c6\?F뀲_]·Ú~ÞæÀ„†iøÔ€P ˜× µÁuØŽxþí¾´¬ÔZ]( Eàíãþ5•@ã…Ì-E1½µà5Y]î­ow„-ϵ9¡ñY¸ê™1{BðêEÉf®?SøŽï±ŠÉb #Œi… ñœðrSùÀmɯ×^{-žG¡éоGè~Ç •nk&@ÃpÑ/н9åG§XÒxÔõ{]SŽzN¼3C~8ľ¶è2]äí;-©„hB@Aœ€óùàAæ¼QűÛÉ£M?ÿÉiöíG,0$rž5|/®²} E¹Ë.{Úqeܸcà.±œãC:ûö È‚’Ñ$©ÔuM&ÂÓÉÎSž¡0ò†¬)ÊV>bdndVÛTu»ôì–Ë~ß¼.[ÌýPæÌ™#Óª+ä…î{Éû¥›XÂJT'U»À€’NœW~ Ç]>m/Ta÷ù,Nï‚ëãÞÂÀ=¤‹6å -BB› %^™ J˜£!|:asÉç`2žN`ÝémZ‚c:•~n÷®îh:d³¤,8ÎvH%¨f¯ð_*8ÜÂFN‚Èóà;à ¯]án ømÿŠ[,™ìužÑª^ó’s>cÊÓ*Wý JV?Oþ+•0¤ ƒDï4ù=äá™Â‹4zôh¹é¦›bGGh °ú Ý" [H"WÖ ›ýŽÒrCè'÷=Y¾™õœ¸Ë‰ö}ÿïõ·9žþï€Î ƒ'Èà=Û×ýºò5¬ƒTj¾[ÓF*¾uˆf ƒO®— jñ’ˆHH—ØzæxP[ÕÉW̱“B¬6ärSÓ·¶“±cw”>}zÊyçµ³J¯cÇÀp¼ûî:;sþƒªdÀ€D¾è¹ç¶IÈgƒQxåíçjÌÅ'4->ÛʼO8’“+¢ x@ȳã‰PToüQÜ ÔTÕ0ò¦«1AJw«ØGößä9d§'¬çrÕ•žPø„}ñú"W™²’T€€¼YšôÏ»@ß´nÕÚz@ÆÞy8¯‘<«<{DZ¶á0`™h~_úË7¤í–¿—Ö¿a¯›¾¤zÐ7Y¼â aÕ æôêÞÓzA!£ûM‹£¦¨¦Ûýå/±S¼®Èêò%ˬ ñŒÔ¡ÃžÏ´ºú³êÚ=lniõ ?J©?[­ivß|f_w_òµì¾ë.6¤½ÃN;Û ·œ‹²SÈ÷ÁµA¨ñXû„³þ%Ãi>·/­Ó ýô«UÁµ±Ïgqz©ä”6AF‹!Ÿ-Ž×Ïä òP˜Ô” xÃÒå¡Lé •¦€ÇE /3¾™H¡äSQ÷Rõ‚RŽI;WÌçÔu¡¿Ð–’\n«N̽“@ ¹PAQÖ÷nÓr¹î³ÁìÙ3ä%;ÇÞ%Å…‚SÄóÒŒ2…˜úï3ð.Ö¤–èh.1~øáÖk Ò*óI ÿ@”ؽÓ.6<ÐÍDÓ •nwóÊ4—“ÉI·u›U8 ’ÕµÕ–€*Üßùç\:z©U”ôj‡NýG"7ÒzC ýÚ©ß<{™ý¯Á{ ‘qÆÚ¯»\¤V¢a|¼¨ÿ&C¶œ ×_?Ïô«›~u`ì€d¼øâkÆØílå¯ cýnUÍ*éÚ-~$\·´ýÒ‘R¾jŠÔ´5 ¯ó8)iµZºÌOä•.ªÿ…ÌXù›;é#L¾l™4c$&¥Á¢šÿBþ) .•=7½+©²pó¸y†(xMÁ A91†hø^Ó`4¿èœj¬† @vQúîï"d†Ê§‚±“ ‚äð¤µá™dË»F.iÓn£}nÙˤ¬4ÐikjWKy_cÔŰâËS¤UY‚AX™xèJ‚¸ç¶—¾%m›.õ'l%µ·„çóßœƒ~ú½>•^¯-‘Ù?î(__„ï‘K¿¯ί}^7E˜þdu> ¿û+"¡ £8HTnØW-­’ÿû$‘rVÛ·VÊf8úÞpƒÒƒ‚P%¢ J3åsýøTzC~ƒÑɾȎäM%(#ˆV()|K Å…',Ì•L¢£5tJþŸ¼8¬ÈèÜ©sm>gå“•vp¶å™  êè´8bËxºhsp›øD¦Úo E26BI7^(Ÿ€î‰Í A¸Öž ’Λ·tÍšR™¿êçöµ†òÖ«âz>caEõ|¢ƒÒN™ (àÒyNr¯¡¾ˆ€æú9¡wBJDL›*7. ŽêEñg×b Þ|°cñs‘7KJ ™¤r^OÞ[8áz•aÞ74´¶¤×' ê‘U ;IÆ<e~C?ž1Æ7Å©ÓЦôG?jHŸA/—èÃÈcœ€™4ÝNêNÂÝ íåÁ:ïè!¼†èTî…9J@Á§ýÓPPúØ—æ$ác:ÏèV[ô³ôyk¹lo°H ýo)åyÍ8‡w’gZº&1ßÕŸÚG]ýɶb§ƒ¤òÉÊ]‚ZÚ.¸WΩ‘:8 `~òÓŸHýÖA[UöªL" K7^*ó·›oeƒgüÑöÕ²eYa=ÜÜ÷èƒköB£EHhSAgð…Æ& žAïµvZ*âñàsÿ¡ÎA.ŠyŸï#=õEÛÍl'ïÿí}yãÍ7dÉÆAço¨0‚B˜ÝX7̆wÃô~2¤TóGÙW=Ueó™XCGÀóšêžÂÀ}ò< ¦*Tì]¡rïK‰)ïU鱟¹òòxX½URIÊ Eû01ÉÂQf™Àÿ¦SZ¹BóÍryf`µãñÀ… Y ßä*7©`W_S%wžt§}¿bå ë9 Ç’œ«ò²òFáþ0òª!?¼ãO/‹o],£mÛœ¾„òÓÜÐ~«!¦V&U%A˜}ú‚éÖêʔ=ÑÁæ3ys¢ lŒ´ºÕFö:É•Wö¶K’KI¨½²²Úì¡û÷Þ+3¤yK¹ãެL!íwÚN6.Î~ÿ³Ý&ÉJôÈ#Êâ%‹¥¦mНï`uÛ ä̪nw˪Xˆ~ymo&o»øœ@>ÍuYù\Ó:Y ””¶n& &‘SCJÉåvCóËÒª¤,qóy¶F#Ï–1IK¬ù+=†¤RÕ|=»Ò““Û§ùf‘|6Å&¡ôAWÁÀÝÚœÌmnÚ&^ç SÈ'º„ß±Õ^ŸðB(—|·È’B€¾ã‚ßÎúö™±WPÆÉ’ØLëЛïëc¹ Ë ód‡m·³ü#Šô-ž¤ãiñÇ¥}ÿ¥æ¬ç­1̪þDw¦Ì-5*;®?WÕòi~ËÖ·ù]ùaåvòq÷»[ÇXÕw•TîQŸ×ŸyçËÌÚ„‘6 k~VHrÁõ*pþä^¹ïB£EÂñ4NÈXÜüNg\ÒY ­Ó ø,›21<\:ü†‡Ô\ðhØÜN¥›BÃèKfÈs~• +e›×·‰%2óЙA8 s)ïPžt ­{¥.i"Ó´­§ÅË8rÈ!¶³¹àºüϲ¿uïOïWÁÄá@®7þ?F¹5"˜æ37ìç†ô²A¦Ù´¹âñÇ— &Ø|œ¹>à{²ðnš!+W¨·Ò} dRÃm!ÿ[ò?9¬ÿa2õ¬©vÐÃS×ß/x¯¿AùA`Ýü¼ßÍ“KžºÄ*=ˆçÝUøOj7èߣ¿|rÅ'röÔ³ýnÙ²zùê«/ ¹J„© žf\Ž£ÚpÕ=ÚÇÞ% ÇQÚé'[ ·å™îb˜üå‹ñò›+¾–Õ+ìØ+3Z…¥o 2>@Ì…ofýWßê„Ø’2„µíª©†¸’‚2O­Ö¬4Æl+›í—žgÈådëí$J¹\Õù–ä¥<Û 0Ç$<Ÿï/}K¾ÿƒÃå¹™ ì  䂱EάafÝâ-FábäDÈÈ'¤GA?‚He£Óš tFÆ)råÊ`:,ºe‘5 U–zÓÐOÞ;©½%…¤N1Î`Üøˆâ٬צ²ãná)ba(»ø¯RúDú>…é;nðê¾ü`[YT¹tÓk õF_· <Ãå¾ mgýKj6ÝN–íp€½^rYÕyÄ–JO£û]§í‹.<çëvòTM0fõZ]%ëׂ߱¨cESu¿COšŸ ¢Ê”f°pï¹hÞ4M½);ÌÒ©«q½ã•̶N!F§É:‚Zn¼æwlþµFÇËÉžïé xKvÜuǸç+§û§Ý¥ëºÊüÇçÛ°Ô.¹·¸Ò†ß é“;6¿Û|û1}bÓÍ‚ÒB Ò/¾ø¢<ÿüóIµÒxí– ¸^µö\o)Ÿa‘i. >ó¸·´!ä:ÞP»ÏQ©q¾0‹¬©pÃñr}ÃES½-ê­d¯¯É%ÓÙµPðüôçeäã#íkþÛï_(ÒÎO䳪㲨û·²´ÛûRÙó;0K@ Ï+  š_Td¢>hž ( ý ›~Qp-7…ó²2}ä‘䔀éáë R § d“ÿÃ' ·{°e×Dî/F"y yù´‹µ˜ßêµÏ½ôû–ìýûÌm„)Ôÿô ¨‹5¥¹q‡ÚÛö‘ê駦$  ¤­Û Iì¼ß>ÖcªÕ?4½æ¯}Õ’3òoÞú£t|êfigÈg›Ö%–€‚òo>“º¿0fÌ+ O=õT쓹ÀÐð~0;Ú¯'—é<%?ëó3yuö«VA}µ0±Àaú÷Þ}Ïö LΡ^Tõ„ž¼çÉòðû ’æC=šüò©äTáz^ âßÿž.{한¤¿`Aµüco ˜]º$>ÐïK°zØ$^¯ív·œ{N+yàÒÆžRP½é£ý‚ïè÷2ê=â=éÜÉÛÕY/Î|ZöÙìißz¶4HG)‘`f¹‚¨!z+Ÿ ÁrÝöŠ}‹õ$Cbÿ`è`YÕõ.ó‡uòåô€ü“çYm‚|úÞlÅÃ?,øÃìž1<['B„ŒÓ:ÓoY@倰„´ B_­è\!»ßµ{ìÓd01¾¸Ñʼn¶Gæ7®›ˆ&ã }/SÍ_À¹ ¡ë<Óaþ6mÎ6Û$Y²äùÏ¿/’}™¸ž·?ZúÍÿ—t^ø#[¡[~ô%RRÚ&®3ý½ åVš×”cb6¼bP·Z¹Û['žs㊳…¨Šið½¥éœ;LxÆùäÕî¹çäºë®³Õ1 ´daÀ ò7xØ((‚¹P  BgðAÃb°ñ:WJhÞz4¿ÊîÃ(èøAGÙb³-Ð¥½—ÊâÊÅòæ;oÚm<#þì4ò]Uuý]öùJ\ï(@že­8/ÏÌ÷–2Øé³Ôçf­=#AaÖ^&pl:aÉXrb„ü )žP”Ž›Ç9`×`ÂÂ!["S†O±„ó³«>‹çmr ¿¡Ð\/*€X.¹m‰Œ9aLü7ìÝ×êÑ$ÄNøÝ' 1å;ŽQh߯««¶“Œx@] ðtꄤø÷†ØA@Aé ³7ïï½&Q²¦¶ÝKNACëþÒþ›R¶èl«H]3¶í¾ÛN6,Ö{“ÍãÇU`&2øtY«ã¥Î\ òYQ5Rº.ØX:­¸8öm€/)ÞRë1Ç#Ÿ…çO'Ï*ŸxÀ"Ú<(ñlJ¤"W@tÐÁÌò& ·*ç”E«©­±Õ)\¹,-)µU^«³ú%ÝÜ è ¬ti%q$GB²BÊt滢Õ9­¤òO•ÒyNg©é[#¿¨0–S )×ȵ\ðzxréÈìH¼•\o˜`êïS m <<‘(B\þ„Ðr¹þÇ}~z­ Îånaד©¤K®¸ôÒKíÿŒ7.öI„\àzZƒé/x[rEuMµÌüj¦í_›m±™lÕ/¨èÂõxò?Ýzv“íoM”ƒZxëB)/-·Ä/(ÊnÜ€qö7~NgumµôLôAÞýnÁM ìµ1@cܪgo'€p¦ǸßC*! ÖÚu¬´Ÿ§U÷©4‚`n¨¶TñÜô§dã^}d‡cìd"õ¢Æj,ª ç†À–¬ž.K噾âYºt…m›Ýz—M+^±Ç‚†ÖýÌq_™óR°ÑÝIò ‘@ÞP`Zƒ‘öH'Ÿ¹‚Ê̤O•ïIí^òѦNuªDȾ|¢/ vMqÌdþ¯‘HH/úÓʉ‘[&×Bš.,A(~ï¾{[¹´û ±ÃKŒúmÕO6íOWæ³}7UßteOzAÌÍëz#Kµ‰Üðæ ¬Ìœß;çšÕõòíüï ÁûL;ì(ûøüóͽyßèrÂÚ;ì0Fºwÿ³ÑÛƒŒ¾`ï_¡:ÓßãÕ‰HM‘OÎOPO){d¬žR<ÒDœH!tqß}÷ÉK/½d·B£ÅH¨/Da Ó’;D£@¶  %r@› þ“KaYHï9?Іn âõAÑ=FçZz@`¥¢×ïkû×ʇ]>´áû[?zWðl^~91Äs:3æR…B ½v¼¨$rÈjª<:'.wëqñÝ>M€>KÈ­>_à¶· “‡/ Mň#¬¥}ã7Æ>‰ |ùÄc‡U}ðÁg-ürGzÊvûW*%Dëç¦?g‹ÓOÿnºUhÌd‡xª’ƒ÷,£D*õýîÇSºû»ÛïÈc»k¿»ìµõߺ¿rQŠ¡€Þö–Üó¯{¬lª‡Ô5sƒ‘ºjLÎ W~Ä)«[]Íê/æ…Û,`ça|Ô´5¼›lrec’jž z»²rôë—˜øóÒKÏ]×Í>OÚ ½ç˘r6Σ›¹TÙÌE>i+ŒV%¥D€8/c ×õðúÞ{ïµ:ù‰'žˆý²pÈmt)0,uVé  é$7·1ns  GcÐÀìÙÜA·©ÐIJ¬ ¯“• ŸñÄãýE¾<ðKù Ó6†DlŸ€BÞ.PtHsŸ3PëJÂ2¹³J@¯Ý Ðñ8NŸ1^‹|P ‚„ ²¯[ªŸù×Ú`ñ!Pš_4äGûdÂ>Ì|FŽñ®ûý˵+ ¦PsãK LC€`òû“-Õ R%©ú›ÿë÷–˜U~úÝÌÅ3­gö¾/î“^—÷j¢oeÄêP&¼úùy¯òMé´õc6å¥lqbÒT}û–€,„ ¡µçn¨¶T¿ç»öË. <@   ¢áqyûÍWlÉ7(ÞÏïõØ(.ŸŒ/™ä“×Ùȧö‘°qJÉg~Á³ÎV6³†'yõPˆN 5þý¡ú“½[ ôíÖ×V¼'ì|‚up¨lB>5M†=2Ï–0À#Ù¾½éóu1™F.´ÿ³‡Ú×f_¶ðÜ„ü4Î+M¤­iT€xBx]Ï+c(Ï«W¯Í̵cPmíÉÆßÙö}Âõèkäòý÷ß·9÷íWdY “O•+ž{®òÉo!¾ ,?J¤‚ñ™5îùO&#?^n»í6{M×^{­õ–k ¥cC¦È‡¤D–4¥tP¤ò!hœÒC£ñŸ¼oùt¡„3N³â‘”dRQZ=Õ†Üõˆ:„ÓÒozÄ¿W¿dd8Fsl)¿Øæ$Ù}“»­òé]r…ôZ¶¹,þìhk„BLQ¬Èʧ殩ÒCNiÛläSûˆ*Ë0Dò™_ÐN´K> 2üöÛoÛ~ÀLqÈ0mJ{³ÑήþÔœíÎý@ÆüxŒ\sÀ5²ðæ…2qèÄF2ä†çþáÜÆ`ŒüA$ÒÈJiLVºÄú}츄Á7Öồʷ I]2¡ŒÁuqxß'ÿwЯ!ääZî½÷FÿT:v<ß~ǵ)Iõ„ò'›öl¶{¤¢KW›v†¾Æ£ ÏÁÁÄ3%E…ˆ'ÿC*"K ú“qUå“÷éä“×éô'ßA”mÿØb矾yä‘–àíå¼…D‹‘PŸ€©ÕÅM«çÄÏ'âaë×h#Ñ€ü—62.õæœ7è(¶¸÷Óü:СÜDl žM,•0ðü ¢X4„Þ ›’·ƒõŠ¥Ñ£cã-ep„G[ªŒ÷)¦ä”2x»ÕÚã{&T|–N°@¤äò Úƒ-¢c°ÄC@‰!ú–6íé¢éNXÒ¸Êç ‡Þ <ü2°Ï@+7¿úñ¯ìúñxRPTMH¥NöíË/«%šæ;õ޲·ç7ÝEåÂö(ËñÇÛï\âÊk½Àÿ5×CÚ0w˜tž×C6+»Æ ¤ÎÄáxqä|2{¾¶û„„‡Ç!¤ú}Øw­¤Jª7™+5›|"5—kÞ1ªq¦ý®Wûd».7ËÆå/Ø÷›už&½{áÅ©µ9÷ºb «Î1Þà­dÌUƒ‘}:ùdã5rÊø®Ç„sG%Ôš_æ‹„2Ss¦(Lk, Ÿü/ÿCA¡w´éÇ~,‹æ/²zŽIvíÚ¶³²ãF,± ƒ'XÑqœˆP0AþH; Hg@"礪ᘶÿ;‘‡²¶#­—ÒDZ*‰#›åsv²F{Ÿp‡Ä/[ºÈ檺j7éÜ9SCŠËÊŒq¨ÿÛ â =wF+éòA{þU0.ò<ÑÛê¸?¼0„òÒÀhnŠîS=ÿ|‚wž ™6SX\ྴý€Ûe¹~«{¤öú믗£ŽJ$ŒGÈ:X¹ l„b¢Ÿ¸àXH Š  ÚØÂ€Âñ (mL[²gÀ_°(X}g¿‡}úçüCztëa¯ƒÅ\Ò8/ÄQñÙ¨Ïä믾¶òÍ@¢Qz(Dˆ«zjÜsùçÜúÿ•ÜÏôéÿ–]Úý0ö‰1u‚’£ Ë£ðP®ñ¾zgÌoP¡ß;ß¾_R~«% `¯-/íVM5Ÿ'È*à}m·DN¦*ÊÒeÕö™»ãƒ;F¸ã"ß«|êF„…¾@-ÔTòI™SO=UN;í´Ø'r/Ÿ¤¾Pe€jMAÐW§[§ Ž "® »ò‰Q½I¡]éèg 2¦:Ä—!ˆ'£ÊŸ ò·ÿyÅ?,T4ʶ0}$Gu–*ð„–-RyJôó¸ Ù´—ðIq*' %ý¤¤á+YÒp´¼õÕP;¶iØZ'*A†Ý¥¹­Öóˆê±µuC¤íÛÅ>ܽ^&ôÍ\ª’gÙçYë3‡ð3޹zžáÊ ½tse°ÇàÀ`À t;hÐ źä’KbŸ-FB"B@#óOUSNÁ ™k=4nOIÀ`Èæ‚ï ,6H„ŽÆÕ Áÿm¸N,ò¿ XéBïÙ‚NäÖJc%žKNú‚â¶âˆ#,=ë¬äœýB ÅH(ï'B£ÖE&ð™5±Pe“ Ü› /<™€ëZA£ÁR,6ßzÍõ~¦BØlwîË%¦ -æËÀ€uKØÄ-?“î}³ç¾é Ú©Ù³eãéòõÆ`És„$æãÙð ÷ªmNqˆ•XN<ñDû}„ÜFBIã€Ô`8è †!IúL¶5ÿ¬'ýÐß²J‰õÞuI¿Œ°¤ÏN2Š…é€Îzçó’V%ör:¯>àjÛOÙè_Jèÿ³æÎ’cŸ96v†@Á…¯çœ„øS²œ­”þHd‡ôÆ5¼'q˜J‘ºJV_{¥œÜâö©ÐvÎŽvÉNÖœ_ÜåÝ`ÒSŒXji'«Ø»Žm|-ž‚Nå±Eùéø `¼ÃÇøE¶Q† ƒÙOÒ‚Ž9æ[¦éâ‹“kšFÈÈ&2ª€òì‘ÅlÁXC€¨rUeØ×Ÿ|®àÿÑßè$×CÈoÔk§ÓeË—ÉqÏgæ^7W.{沸qÇù]’j=ä@ÒWíg¡{ oÒ'¤ # Ä .9¡*W±×m—6e•±²•SÌo’#qÙÚÔÈVÇéæ>̾ÄȘóŸ.ΞQ&“–J¿¶ òÕªÒ½^îΚ xî™ F6ä”T5ô0¯1:Ðå®|âU‡CœsÎ9rûí·Çþ¡ph1ŠõE§ugÌfÊ+‘(îwÜB&8úƒÑ2mö´Ø/ Üc Ü7ØQ,9‚{¢r³Ì1>ñ*ÙHQP. Ô\3%ye u<.a`’‘«<}Éãueûqÿe£VO&ÎS¬>Ræ¥$§íˆaIEH·¦Ö@:T驼ûî»í±DŠÈÕ>÷Üsí±šž=$CÁx>ÚqÇcŸ„ñ˜6Á€ÔYï@åS (Ÿ»ºƒñ€>N{÷ïßßê \ô«F8?ó?Ožúì)9p³í÷¯ÌzEŽþÁÑ2æØ[¥OurZ%]Ç…U>ˆ´¯7㇚®¾f^…°·F:š}bűê> L_7ÄГÓw¿!ßÿÁŽRF¥x# ÖPì“ÓúÙ.¥ Œ¼˜s01Ê÷¾ºPOh>= Ù‚¾‚·ydŒR…KÀ)&Nœhs¹q\±œ.)¹´ms°Î‘PfwC¾üüQnÁd<ÀB?DVs?Q<,xÙP€š<¬VcØuqÝ™ÖÇe–œ;;Þ?†Aë¢ ƒ´%÷íÞ;÷!gÐãø¹FùíN˜ø”SN±r,¹0%Bnpå“×xQtÈ““Üœãl@;qn³¦ž'–J(Óå`îpÍ2cьػÕ†úrßyöËgmî'^°sðß ºÒËž½LžùÏ3²qûe^õ<ùùÖ?—ÑG¶2Êï³;5”:†DÌ7²âÞE/×Ì*J'ÜŽ’)±ÇRf ¥‰w‡Yî¡J£ôVÖÔ[Ï+ %Wé)V2j»7p+xŽ„ôÄ'G“ðÞyçg UB¾<߇JLЈ;|Šã(ù}a ïs $âIØÞÍ “OW4ÍŒ1òÚ\¶?aiÆ•3¬¡È†þض˭²yçdcãÉæ4WÃ*F0„G Rx ­·4ÇÍLx6 a\¹rœ¬úzt/}Æ®DVÚg’'ÿF–Ϫ|»–élXnþûMu¹Í<¼ÔÏ&Íòô„Y¥ÍÐÃn»3v@<ùË_Ú4"Ʊ .¸ÀŠÅÂ:GBÉ'B.ŸM (¤,[ÒvGù ”~8CÁý¹ÄŒ×\›KJQš_™Îê“T:Ôþûï{g¬·wßµƒ$—Ym¹’„|‚k…°0èAW pàá"5+UÙ%öÀ•O>CÇadÑç·ÝvÛœR˲…oúF£ÊNmù@™Wr£•Ë=~e  çã¤J+»Œ³Ä‰û‹Ë›C4ñ^&!ÝwõýŒ\µ¡À¼‘«Ú»¥|ÎŽR²Ubù_~³¦W…´ê\û †Ø¹š"_ù0ÚŽ1 =LŠ  &–’—îüýï/G}t‹Éç:GBYJ k +œspù¾õV(¨W(÷3píX–n®Ço Ê÷zJDñ–²A>Î…ró¢ (m\ûi,!ÚN ¹Sˆ÷â*|>¿mñ<تS¦LÉ971Bfà=¡¯£|´ŸC@4Õ#è‹*›ìÓÉ'¤òV*”°’¿9õï‰ú~ßýî;éÐ.˜t§TŸ´¦›ýαç>r®F„¹í§lLÊ@ù£ì ax•´Ÿ†Â#• “§„âÙÉÓ`òRuÙygÆ0Ù®ëí¶ð|£?ФP~þysã²M{ÒþŒ©€±ròÉ'[9¦B "äôK—„â©$\NJP]ÅVvÉ•QdÓ•OdøŒü“ë›J~ót)8À¼gåÆ3¨À‹3Ÿ–Úº5Ò¥sÙ§çÁ‡±;áòš5¯Jû9N Uý®²£4,;ªqèÞ-»´Â‚³ÍÿÅ~ÓȳêüO<,ß‚žPÆ+Âï„Ý‘Uâ(5|‘Oø×ã?žSd«X§H(—ÊJG<3ªÜ ) «ï'Öf®ÞÏ\ÁÀ¢¤L ‰’26HÖ-d”¤åqTá´‹NŽàzrMXW0øé½³wËbÑæjÕcÁQÚ…:ƒQx¯0 M]%h_Ú†åæRß*:Qµ¢Ê*ÇÞ¸ÁÎxSZJD™«e_€ëaÑc\åÇÌütD˜{R/ a-H§öU;2éʨ›j¢ž«œÂÊ#¹ðH«Í%kŽ’·¦K.ûdÎãËx­Ã0%è{XsðÔˆ± é&í •ÌÑöO>ù¤t4tèP¹ù曓òÏ"ä¾|Ò™3@*F“‡4‚áÊŸÊ'{àÊ'Ÿ¾¥ŸcØ£ëŠÕ~*“àËCÌó¯)&€×+{ló”‘ÉÎÕIÍžIF`^×/ Âíþç¼®¯,%ý-(µdȤ•¥Ø$#Àk=Ns·õy3r Ý·¤”ñ‰12¬ íK‰ËÓO?Ý.ârçwZWK£ÅH(ë+¹tàx„Gkð{ÍÝÂê.â$ÜMcåÃû™+¸g”œ†ïÙóŠo0ƒ÷žÎëXHàÖGAá)a‚d1_à>!¢ ,L>âY`3Ɔø"aòIÊ!:–ÔõÁñOõ®¤ó~æ Î7ë›YrþcçÛ´„ØYÞWZ¾GECí.YÕcü²OérGéôqõ*ù·æ~kø9åþ]RÚ©¢]hÞfâ¤Õ[ÕenÅÿ¤ËFŽ(Ä˪H"™æ8Í+ÙzjhKÒ0vI;HZnÔ}åŠ+®°¡÷{ï½×¡ÏWûGc¯‚q‘T5ú(úÀ×U™ä‡žcwç\¬ Hȃãù÷¼’ÉF•‘ w"Q6 Œîx?™x_ÍÞ™/½¤d³…I§]‰ñA¾6c”ß~ŒQä|B<ÑÆ [käs­'¡ǦăcCè””±ç!C€ ¥ÆnÎäœbz?³Ï7:V*é„WTá1p0yÂLQˆü„€ùoÂÀU¨ÉPÜ3áUj ò(ÓÅF(\%ð®0ÙŒ%Q©ä3_²‚wœ™ïÏM.öIŸ4ú!xýÞõ°øÇhÒTa@îƒÃ¯‚F_2ßéø¤›ŸûÍ–ÎËT¶à )]9ÕžïX6WjÛ –úS t0ÄøžÐx~œƒl¼ gLº ]Ÿ~úi9ûì³­’»õÖ[£âóE„OB̰¶ ùlå³)àœ„–>ÿâs9êé£bŸHE3å–ÿ˜Ta@v;÷G^•›S—+¸d×%¥œbçÊ(ã ÏÏ_±eÅ&ßI«ÖI`"Ìï(a×3c^çš 0.¹w¢,Êtá÷×^{Í*8&CÞu×]iÉj„üùÄ(ÄYBÞ&F¢»¤µ+Ÿl¾÷=^ÁÐ@Ï¡'× ˜~¯Éicm]x¾wié™FçO1äë@él ã?iîÕJ‡œÎŸÿéÙ3±ÊÔ³Ï>jô~wÙñ{c¥{韥¦|4|ï^ó‘+< kˆLÁUp’Q»Õ7’Y~È!ÖióÀ¬•mÜb$øJN¡BÙaó…'@Ì\Rêú4›o1¸ÞO7ײ%ÁµpÎ áËÆJå>””²ñšûÀ;¬ ×MɧD™â!Qå ¹-0PÈù¤Ä + tÒI-ÞÔÓ¢`R÷OúÓfËg: » ¬(I¼ÝW¾reÖ¹›)sˤ;†û¸" üû3Šóž­Ê&ã“æ?Wt,—÷H”^K*ßäÂ#˜©¼› ¢jÈg†|TÚ’ÖxL Ÿ—©€ü•=z´ÝÎ8ãŒH>‹úé[o½ee…I D£XMpß}÷µ†º+Ÿ´‹n€ÏÔ﹃…èã…Gjbˆ<¡§ÊÊZ™ç³s,…&8Þ_ÒÓ}¿lÙè„Þ¬\(˪VZãPõ&››ïÝR  á*þB ¾Ç(¼úê«ívÑEeÅi ´( õ•p…¸ÂÓ蠯Ĕpª^Rþïlmð~¾Ãë„WEœ© L:ð,ݾ<ƒ\Ã@ëR‹…B \xÀÈÿäZ ïÑŠ_>Øÿþ÷¿ÇI(È—|Ω#Técšëœ ¹l.4â@TE{±€á1À³µkï»dÓŽ/ɬ¥?“ÿ­ºÒÊ&㔟b”D0Óy7]ïh à@iÓæ„ôÒ—ŒILn`¼$¼–#¡ðÀAÁ®ã0å°H•Aw¥’OŒ <@ÏgÿÚtÎaŸ®iß> '´êÐQÞÀkÎçêM· ŠA8hcdÕÏQgœ1b„õ‚R‚ñzmÆZCBÙ³)Í·wŇv.BïX\ ‰’+JL ÁòRO8L q¾ó;yή§˜ O1Ù.Þsÿx= <'®§9„8¸®7ÞxÃάeÒÑ=÷ÜS0Ok„ÌÀPQc¶œ±X2ZX4¡©``E9ÒécÅœÁ½¡Ð™UšKÄ!_à9í@I·a ZÓP++ªÃY7ž‘¦éVÞÖ(¿ 3oø_< éîy„÷vÞyg¥(&Q _>YMö£MÐe®îb ת\ò›×%0>Ñy.ÈF[¾ÁóË÷ö£Œ…ª*à:‚§ü6ä»AƒÙð<”ãÖv¬$” !¡Ý ‹4–#ÞF®‡N¥äŒk C¡lÙ°x )¸Ü?á°æ”:j $W°°¦ÈPz^S´P¤ö¿í¶Ûä–[n±¹Ÿ¢_ßÉu ªäOö´„Eåƒ>‚ì¨ÑÆž÷¹ôYÎ÷“Ð&ý¾˜•yÈ'cä×kjp"Wx¦Ò)/ G×+ƒ2ÄPåÇÆy²}þ<{ÂïxŽPhé&_ÒþÌzÿÍo~c·K.¹$’φ+ŸÈ&º cŠ>¤òȆ—#‡Ïéãë›aÏý=#rˆÌR,Ï$ÿ­ùÞÈ%ò™.ß»© µRmè“K®cêÔ©6ìN‰´k¯½¶¨†tsÐâ$¤ ƒZ1Hÿ©ž½T¹Ÿ\;Ÿ AW‹áæu¾šp9Ê`ŵô@A›¨‚BÑé€ç[|ù rÊ ¬àðÃþ0öM„–„Ê'²@ÛûòÉw*ì€Qtªüè#éò§Ôû‰ƒÕ]N°Ðêôcþ¿PÞ‹0ð<5/¯©§Fsxöúü9÷£ã[˜B†˜0Þ@l 饛xÅ8ˆb#QÃ{¹^k„üƒ1ÙÕŸ´ ¯ÕPa\¥_ô‰F0r1TÖv0FA°¹OŒ¸µ¡´”:³tÃXGO*o`OdkÄ!£„ßáÈ*cª ÆÑQ£FÉŸþô'y衇äç?ÿù:Õ¾-FB±\(:¾×^{ÙUH.†eíz?Q<~>E*ð˜ò9_Áy ‘@ŠyL„hi„%`3K–ëÄÂs…‹Î0qߺñ\sÁ|`g¾C¼'MšTt"!Egu–Í1C>³™¼À © ×üFI)›WXôôyÍ/.¦ÕÎujR!«;¤r£aÃæÎ¼wÉ&÷›cÈÿ¤=Ó={ŒV'#šn²R„â>|ê©§Ú|\ªUø9úT²€œ¡ß0p\ÝE_§¨LÒÿZZç4jDr/D2‹iDæÚ "ªrɆ>Å@T™äu˜yBVSUªÀQDz í÷ØcÙqz]C‹’P®䘱ÒÞHÖÿF Øìª y ˆ•z?)eP·ë†g¯nx[…<]ÎŽæÁAÂ8¾¥×«‹I[\Sºë‡„»‚Åoùzbx©¬n&kÖbˆ°]vÙeIN„âÁoO AW>Qz™ä“6fðURJüŽaƒ ¹/¦ä €Ú¿s5šš ­v‘iõ¡|€g–û QÂïȨæ~»à·L::ÿüóm‰´ë¯¿¾¨iÒƒvüÝï~gsèÉÓ¥=‘OV3cUA òvýš¡È$ã´ö ö´µ’!ÆmÎUL™Ì® 1óïqmÏÛ5ÙSuh醡žªRçxî¹çlÚÚ‰'ž(wÜqGÞòó‹ ÇþEõöÛo[R¥GnÖÞ{ï“ÒK¼Ÿ=ž½l½Ÿ¹BÝð*àÜÃ%¥:àSß eDøeÔÒ<í@§G¸™QˆE•«`Cô•th˜s0¨©`!hW”5ÉcÙÿýשAdCý…÷î»ïÚ‰È'J¶TùÄSf¥»à< ¨ä5Ñèïô>WÙ`_(ˆòÅkÀìsȯ¿œa¡lèŠ&x 5¹/› ß´%«S<0J>T^ûÛßÊO Ý놮"¥CI)2Yì>.ÑÒKk‹Þ,  Œº œ JJÙ «ä{kŠ d&lì§_ ‘E5Tx!§2ÉVÈHczÅx°¾ç É&ZV©‚ö"rˆT=¥¤ÉPˆ~]ÇZOBÃJéAJ÷ÜsOÛa±Q‚Åö~†Á â‘E!rM®§P•®†B””òºV'Í® ªÐáI<`ä}2±áþûï—c=¶ÅÛ$Báq¤P2 0y€¼OÊ0¡ôÔÃúÅ™ ú(²®²¦‘“°ópÞW~ââ¸b‚>Ïÿ£,ð ûÿ!ŒƒŒ/̨eI”;9Ÿ„öî¼óN;á%’Ïõ´÷Çlu':TW^Bwª|²Ì#œ°~àÊ$º‹>Nî¿+“ü¶¹@þ[ªôR1Áx‰¬B¶‘UŸdÃÆŒc67Þx£­TA»ð»|<ç–Æ:IB}Ð$c“_Èd”žF,Š\”^!€€â^ç1£ Ó…9F=AJLQfªtîTJ7h§çÚ2)¨æOa=îƒÕð†EØ0@¸èC±ýµ9JÏ…*@•Wª|à)@q‘w™ÉûZ03ªÅß‹ïͳaÌaÜ ”îÿÉM:t¨UöÈ'aÚp| 4ÒH )È$žR"È*Q0ùdlw)>D•”²åš‚‚Ž"’I¤Ž>¼6”^*xn©ReÏ“*%Ÿ|ò‰-_ˆ£m}ÃzABä‹<ýôÓÖMM£¹JNí*=J[d£ôš «–¡Á„´)¡@<:*àìQº¹ÌÀ÷áæœ„uú|ûg9–÷;âˆ#¬‡Å¯oaÃJ>¨ò™«Òs\«lзQ€€¼S¼'ôóbÍ€ç¾w]KÌÚEæ4ýÀ¸¤aY¼Õx¨xà‚£ÖàycÒ¬+ŸD4Ùkøž>“ªò ^x%¤È%igÈ «³ÒÉ6F”c׿ÒKÍA6²ŠáN•<À“'O¶”ÖG¬W$4ò©ô²†âPˆx?ó5Ñ t•”²q\· 7{ï‚fÖâóx‡Â ôç ±Ty¤¯â àÖåÒKÙY…0F…É*ºš¢ó¬JöË_þÒ®P¶>¦!(6ê#¥‡¥§%r%XPÅ Å©€«#à„•”²ñžp ŸNŸ.% ¹€ @:!»Ï% "B„\ JÏ•ÏTJôr› +“~ãQ£ PIDAT+.äíPÁkdReƒ­)r®`øÔeGÉ?o‰Å&¸'0÷Aè2çˆc DŽ6Ï2B„\@Ÿ'êèÊ'ã=©]iDN‘­0¹ÂIáË$2Ãyé»È1á÷õ‘€¢Ÿu"p˜¬2ž]xá…ò /Xï'“×Ççàbƒ$¡>Pz„Ñ\¡Âc·*=&9¥²ôÊE„2T+®%€€ÓÑ]Ë“ûÄ÷¯,÷QEIÕò?!óÔdŠ¡¹H¥ô |ôsÊ~ 0Àæ€f°Uª|°ÇË@_Uà #-›_½œƒˆG±Wûâ¹hmßlÊÖ@T)‰Æ$Dòç‹]«4Âú ú!«þi¤‘ } ÉB*)¥ö·ß?ÑMÈ6›ê ä“ã\G 2¹.{병Už5?!¨ä"§"I.–Ê ÷:¹™á¾–†k:>¥aP´ªxQÄäqý:[sÜýü×Ýwß-W]u•-rM! ïE(OHÔ°aÃlăÏ)DP•[6Þú.F›R6  }˜ÑFþ)ÑüSì¼5Œ^%ÀD7¸ÖTày=üðÃV. ½#§Åž¬aÃý ™tÃ÷Dñpª|âØ!úHä  ²‹œd’P52©rÉ9]RZ(GJ! ²Ê½ «~z÷öç?ÿYFŒa8¬$Yìñ¤%‘Ð,À#"‰Øµô(mÄļ Ed³) _ àÒÇëÁuÓ鱬|Æä&%¤ìýøì³M#@ŸsÎ9¶LÄ`ß}÷}!Bá€C‘üfú4ázäÒUzD$Û«Ò#W4)å\ªUF0ÚT.0ÞPžx~ [ \/É;Ey§SXLl¼øâ‹å™gž±yf”®+öõFذL‘¦¦òÉsüñÇ[|¦’%~OÎ5²¨›ëHQ¹\ó&‘UÂï8¨U· æxó9iÒ$»Ò 'œ°ÁÉgDB›y`äk°4³Û¨[ŠÒs=1Ù(½|Cצ& Ûºja3ð™âzƒÂfàãýeö³É/ã~#DhiøJRŠÒ# æzb²!œ y@6˜! å3Œ6<­ª‹áYÔq‡òSÙ¿ÇPF>Q|¬Ïñ"´4è¿p€dàÄ@>™ NNµ«? Y‡9u\™T½™ó£{-ííWY%¬ÎØãË*†3žOžåÑpbmˆˆHh3@é'ò!hùRzM–!žœTƒäß4nÙöXs¤ àx_°J±î.ºè"[8—¶Qx/ÂÚ †8Âç®|¢ô(‹‚l"£ÈgºœJ‹_|ñ…Í£DYjŸHáA×hË÷„DBz—ÜGXHÏ÷ûì³ÏÚ Häʲê‘%ŽQ>ýUɨÊ'çpj¸¤4U™C~#EåQeR£{…’ÉT@3Vj€¬ú¹â\/÷É¢tÜsÏ=Ö鳡""¡´¹J/hy¼žtú|礢!¤l¬NV@ÙÒØGˆ°®ùdòF¤«ôˆhø^•Ê‘Ù÷(6ÒoÂŒ;U€j´‘ã§·4'ÇK>Î|§#”¤)óÉ¢äi8°`†o„…òIŸ§Ž-ó2O"^.)%ò˜*ýÍî©Lꢺ"ï-²ŠSYõ#ˆTr>u>|ø:“ÛZ(D$´P¥§–ÊO•ž ûT–^*p^\úx@‹Q†°d™ ‚…Ô×ë"º€& \à[z©” ¡ ›q—O@vÉù$oeüøñV¢ð^„ ”e#eùdÍzd²©JÏ!s"#ª ù#Ãê•á5JMÃïé > 9Ÿ7Ýt“Ý(óRÈhH„k# ¥=d¥Z zJ Id”ˆ]ª|˜Lr¬KJÃV"Doc°ò9òï§ÂQ9çþûï—Ë/¿Ün—]vY$Ÿ"ºB•žkéñšÄjÊÂàöŸ0a‚U€…L¶Æ²:t¨Ý?ñÄV!Fˆ!³ÒcCée#ŸI¼2lL,$¯ E¥³ïÙ–,% BN“ )nÍ‚"Dœ'~øa\>ß~ûmëýdþ‚Êçî»ïn‰¦/W@eBÊ‚Љ,ª±¥þ'Õa¨Dã“K¢çwžu,Q=f¿ýö ý¯  ]G€Òc6Ëy‘K)mªÒ˺BËÿq^,9-$!B„Æ@é‘ç­JT¼+®Ò£’Fª¨J\1ªlPªå¨ YWBJˆžÿÃ@䨇~ØÖ"„ù¢¶®Ê'ó20öÐ¥ÉØc=R†àù½[ƒ =‰^d¿ŠJD‰T5$쎸É&›ØÏ#4FDB×!°* ŽÝ\¥— „ÆŽ+×_½ÝFŽ…"Dȹ(=<š„ßIµ!¤ç‡ßÝd  Gu”}OªÀ•W^i•]„²2EkM#§cï(ò‰þD—2yÉ%¥L¢ òÍDA·2TŠ4&ì>ýôÓvÅÍ7ß\´ÒPë*"ºž¡  ”«ô H*Té,=€ Þ㯻î:;™Y%ï*=Rm˜œˆ|ªÇãIø‘šÃ"D( Ï3fX§Î믿nÀ©³Ï>ûØ ÂÈ,rJ~(òI-aʸ¤<z”¥¾‰VDHˆ„n @¨Pd.)U¥Çrg¼5j” ïeSv&B„ÍžòÌPT®ÒcCYŸ~§v²«4!³§Ÿ~º ïáa‰!Bq€7“hïýk[·Ùd#ìNu Bäó¸ãŽ“qãÆå}±˜õ Ý@ÒCˆ ¥·ß~» ÃêK Œ!BñÀ°Œwù¤ÓG!×\sM$Ÿ"¬@>!¤ŒÌ¡ Âä3wD$4B„"Dˆ!BÑM{Ž!B„"DˆPtD$4B„"Dˆ!BÑ‘Ð"Dˆ!B„E†Èÿž•á]&8J±IEND®B`‚pyclustering-0.10.1.2/docs/img/hhn_architecture.drawio000077500000000000000000000044031375753423500227350ustar00rootroot000000000000007Vttb6M4EP41+dgIMBD42Kbt7kp7vUrV6Tb3zQUneI/giDjb5H79GTBvNkkowSHNVlErPBk79swzLx6bEZgut19iuAr+ID4KR4bmb0fgfmQYjgXY/4SwywimywmLGPsZSS8JL/g/xIkap26wj9Y1RkpISPGqTvRIFCGP1mgwjslbnW1OwvqvruACSYQXD4Yy9W/s0yBfllbSvyK8CPJf1jX+zRLmzJywDqBP3iok8DAC05gQmj0tt1MUJrLL5ZL1e9zzbTGxGEW0TYcvs5l+G+q7nyD4xzS+/nnru683Jp/cLxhu+Ir5bOkuF0FMNpGPklG0Ebh7CzBFLyvoJd++MZ0zWkCXIWvp7LFYZcK7pjH5t5Bb8vUch+GUhCROhwaP0+TD6DDEi4jRQjRni7mLyHf4ioox02Eq3YANXMAmdMcnj2KKtnvFohfCZiBFZIlovGMsvIOVI40DtEDeW6luI1dqUFc1hxmH2KIYu9QCe+CKeIdSJj3rRBS69eg+svnd+XAdpGMcUZyhWgcACDrQZB3oRoMObFUq0CUVPD+xti4pgo3FXBE6rgS4XmX+aY63idBFrfgQOXOvSdK256DXeaNWepB9IWsue92WZW82iN5UJXqjWfSyDVyd6Jtcz1lFD5pF//QbiN4ZWPSmJPrxeMwI6X9B+mzZVIi6NelFJEKCqDkpD7MeExNi9LtEiJhlO7f8iyX2/XCfXutBZ04i+sInpatQidVOJUCZI2pwOT5LDnmTxDQgCxLB8KGkCjIqeb4TsuLK+oko3fFMF24oqasSbTH9UXmeJUONLd663/KR08Yub0RsvT+qjUqvpFl2S1t5vzWFMb1NsuQSIintESei4j38nMML4XqNvYzIWRrzMy39HLDdRI6HYcLETjaxhw7ox8r42HwXiB7gs5thF6MQUvyrPo/eQWRJdj290kQCmBcWzexm0V9hImFeWiLhyKJPPA9MOv4VYXqhIa22Ieo7vgFzMrZqatIbkg7HktVkKNvlyAmfbByl/yeMTwhWeeApGrNaoGkOO3mIy59nlXC3L8DJ8WbgqAKalV1RpdVgcTmtdfDhv/BMMFtIiSWrbvBArEVky+S9qkUhYSDT2pMH5wNlcpAGSuFWLPsEBMrxcSgEHk+yLg6DxrAYtMaONXFsE0xsw3Zcs44kyxzrpqEDyzbAhAHU7oZQw2weJ/8Zt3kW58KvXCg6hN8yg1aS8etHYC8n6tp0atuq4QxawtkaEs6G6AnF5KgtYEXfLA2kGpItSvoqINmiZlzArUdwDeoDRdDoblfQiJsnsaqhGjQtzhzOFYc/WhTek/YPkwl2dlvH4qwxaJx1LynMHkO1jEqhTmBr0GUWdyYPmR+bX3T4FUsYQHSAH2ZHI9c+Bgq/6kA3FEgs8Zy4K0isycDh9n3+rLdw21PwHEz/otqsrvoH2ljTymCnCzHUHbtuJdYZZwWHISfwD1sPU0hJKmt+1QmTSMLM6WVUfgHnhCJq7SJJraLKl3XSbR1HQEAurOpNkaZSt7IaqiFXAL5FAX7Fn9qStWUOrS0g29b7HO97zjq7Hst2y1Srrr2tI2+RPfJtwGXvgsxj2+fWuyDxNlTL7JEBBu4qbKuEYX1gwqJlAO3gvER+XbzsKfDrkxP5nRo/e8hW2GugA8anMaoxxkGLYsqMsW2WfuXGeJRfmL8i45VvrH0aby/GO+jJsjLjBdqn8XYw3qP8uVzVGrt8TP+wpSiO0hs936LV5lKv9Ozf38SE7aiTbRm4v3FVXGgVi1XDb37ed8jTWJrso8zY7fC6vSe+7L1K8SJLcWYoHKV0rXS39bC9OYUeKt1XAadBs20RTiyCd4NT8eLPvuKqajj1cMZ3FXAaNP8T4QT0jnAy9JOuhykGm7nnBb8b9veMYrwKUHZb+Qlt4o9Quu0hX5FO1yYNCYt9zoTFlAtE01xL5YXy31lFrjoVsWb5cnpmd+Ub/uDhfw==pyclustering-0.10.1.2/docs/img/hhn_architecture.png000077500000000000000000000642111375753423500222370ustar00rootroot00000000000000‰PNG  IHDRxÓÓn> tEXtmxfile%3Cmxfile%20host%3D%22Electron%22%20modified%3D%222020-05-10T22%3A33%3A03.739Z%22%20agent%3D%225.0%20(Windows%20NT%2010.0%3B%20Win64%3B%20x64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20draw.io%2F12.9.13%20Chrome%2F80.0.3987.163%20Electron%2F8.2.1%20Safari%2F537.36%22%20etag%3D%22no9nVA4BqySDLTJ-iAZI%22%20version%3D%2212.9.13%22%20type%3D%22device%22%3E%3Cdiagram%20id%3D%22rI-DlgYSjOz-gs8c20Pj%22%20name%3D%22Page-1%22%3E7Vttb6M4EP41%2BdgIMBD42Kbt7kp7vUrV6Tb3zQUneI%2FgiDjb5H79GTBvNkkowSHNVlErPBk79swzLx6bEZgut19iuAr%2BID4KR4bmb0fgfmQYjgXY%2F4SwywimywmLGPsZSS8JL%2Fg%2FxIkap26wj9Y1RkpISPGqTvRIFCGP1mgwjslbnW1OwvqvruACSYQXD4Yy9W%2Fs0yBfllbSvyK8CPJf1jX%2BzRLmzJywDqBP3iok8DAC05gQmj0tt1MUJrLL5ZL1e9zzbTGxGEW0TYcvs5l%2BG%2Bq7nyD4xzS%2B%2Fnnru683Jp%2FcLxhu%2BIr5bOkuF0FMNpGPklG0Ebh7CzBFLyvoJd%2B%2BMZ0zWkCXIWvp7LFYZcK7pjH5t5Bb8vUch%2BGUhCROhwaP0%2BTD6DDEi4jRQjRni7mLyHf4ioox02Eq3YANXMAmdMcnj2KKtnvFohfCZiBFZIlovGMsvIOVI40DtEDeW6luI1dqUFc1hxmH2KIYu9QCe%2BCKeIdSJj3rRBS69eg%2Bsvnd%2BXAdpGMcUZyhWgcACDrQZB3oRoMObFUq0CUVPD%2Bxti4pgo3FXBE6rgS4XmX%2BaY63idBFrfgQOXOvSdK256DXeaNWepB9IWsue92WZW82iN5UJXqjWfSyDVyd6Jtcz1lFD5pF%2F%2FQbiN4ZWPSmJPrxeMwI6X9B%2BmzZVIi6NelFJEKCqDkpD7MeExNi9LtEiJhlO7f8iyX2%2FXCfXutBZ04i%2BsInpatQidVOJUCZI2pwOT5LDnmTxDQgCxLB8KGkCjIqeb4TsuLK%2Boko3fFMF24oqasSbTH9UXmeJUONLd663%2FKR08Yub0RsvT%2BqjUqvpFl2S1t5vzWFMb1NsuQSIintESei4j38nMML4XqNvYzIWRrzMy39HLDdRI6HYcLETjaxhw7ox8r42HwXiB7gs5thF6MQUvyrPo%2FeQWRJdj290kQCmBcWzexm0V9hImFeWiLhyKJPPA9MOv4VYXqhIa22Ieo7vgFzMrZqatIbkg7HktVkKNvlyAmfbByl%2FyeMTwhWeeApGrNaoGkOO3mIy59nlXC3L8DJ8WbgqAKalV1RpdVgcTmtdfDhv%2FBMMFtIiSWrbvBArEVky%2BS9qkUhYSDT2pMH5wNlcpAGSuFWLPsEBMrxcSgEHk%2ByLg6DxrAYtMaONXFsE0xsw3Zcs44kyxzrpqEDyzbAhAHU7oZQw2weJ%2F8Zt3kW58KvXCg6hN8yg1aS8etHYC8n6tp0atuq4QxawtkaEs6G6AnF5KgtYEXfLA2kGpItSvoqINmiZlzArUdwDeoDRdDoblfQiJsnsaqhGjQtzhzOFYc%2FWhTek%2FYPkwl2dlvH4qwxaJx1LynMHkO1jEqhTmBr0GUWdyYPmR%2BbX3T4FUsYQHSAH2ZHI9c%2BBgq%2F6kA3FEgs8Zy4K0isycDh9n3%2BrLdw21PwHEz%2FotqsrvoH2ljTymCnCzHUHbtuJdYZZwWHISfwD1sPU0hJKmt%2B1QmTSMLM6WVUfgHnhCJq7SJJraLKl3XSbR1HQEAurOpNkaZSt7IaqiFXAL5FAX7Fn9qStWUOrS0g29b7HO97zjq7Hst2y1Srrr2tI2%2BRPfJtwGXvgsxj2%2BfWuyDxNlTL7JEBBu4qbKuEYX1gwqJlAO3gvER%2BXbzsKfDrkxP5nRo%2Fe8hW2GugA8anMaoxxkGLYsqMsW2WfuXGeJRfmL8i45VvrH0aby%2FGO%2BjJsjLjBdqn8XYw3qP8uVzVGrt8TP%2BwpSiO0hs936LV5lKv9Ozf38SE7aiTbRm4v3FVXGgVi1XDb37ed8jTWJrso8zY7fC6vSe%2B7L1K8SJLcWYoHKV0rXS39bC9OYUeKt1XAadBs20RTiyCd4NT8eLPvuKqajj1cMZ3FXAaNP8T4QT0jnAy9JOuhykGm7nnBb8b9veMYrwKUHZb%2BQlt4o9Quu0hX5FO1yYNCYt9zoTFlAtE01xL5YXy31lFrjoVsWb5cnpmd%2BUb%2FuDhfw%3D%3D%3C%2Fdiagram%3E%3C%2Fmxfile%3Ešªôf IDATx^í xM×úÿß "ó$"‰¢5¡bˆV¹Tý/ZÕj --:©RÜ{;ÛÞ{;¸Z·Ú_©ª¡†Ž·ÚRZQ¡H$ÆbH‘y"ÿç]±¶}NΰÏÙûì³Ï9ïzžˆœ³ÆïZgç“÷]ïZnuuuu@‰ HR€ HRÀip#Às𹤤)@ ¤)À À£…@ ¤)@ ¤€“)@€çdJÃ!HR€ HR€Ö)@ ¤)@ N¦ž“M( ‡ HR€ Hžü(‘¤€ã+@€§À"Ð]½z•ÕôþûïôiÓ¨•ª HR@ÆëÖ­c 86oÞ¬NÃÔ )@ ØL<™ÒnذÆŒÃjyâ‰'`õêÕ2k¤â¤)@ ¨¯À|3gÎd c`XÏž=ÕïµH Š)@€'Sʰ°0(..(++“Y'HRÀ~ DGG³}xø\ËÏÏ·_G¨eR€­žL 5jÄ6*¯Y³üq™µQqR€ 짺f‡  vãÆ ûu„Z&HÙ àÉðÌ™3OCRQR€ЖüÖ'N@›6m´Õ9ê )@ HV€O²T 3b@Å?þñÀ¢8 MF•T” H»*€Ç:a$í‚ àµ×^³k_¨qR€°^<뵃áÇÃÏ?ÿ PXX(£&*J ¤€6†òòr4hlÚ´I¢^¤€Å àY,Ù­[·†sçÎAË–-!;;[FMT” Hm(@Ï5mÌõ‚«ž éA(C<*J šT€žkšœê)`±xKF<’QQR€иxŸ ê) Q<‰BÊFBâQQR€Фô\Óä´P§H‹ À³X2²àÉŒŠ’¤€Æ ÀÓøQ÷H‰ àIŠ,x2„¢¢¤)à0 à9ÌTQGI“ àÉX ô ”!%HM*@Ï5MN uаX<‹%#­ ɨ()@ h\ê) ðdL…V„%5°a[sÇbŠŽ†®wEAld¨Õ£ÍÉ+„´¹p!¿rO§ÃÖÕ󠢬D§¾÷Þ{fΜiuT 쯀VŸköW†z@ 8–x2æK‹ÂìÜX¹ùsÇ¢ë591în.c”ºEŸ½†'Aá• ëLMM%KžbjSE¤€ú hñ¹¦¾ Ô")àø àɘC­=åÂÒ2Ù^:´Ö Hj ~>^2Fذ螿Á„QƒÖ‰<´äQ"HÇT@kÏ5ÇT‘zM Ø_<s ¥!ZîþûM:ƒ»m"`@¶2Ff¼èÆo×ÂÌŸ4šaÔ¨Q°~ýz›´M•’¤€íÐÒsÍö£¥HçU€OÆÜjåAˆ{î®;Èܲ¶„;”*3ý<2¸§QÕ<==aÊ”)ðüóÏC||¼ u©()@ ØC­<×ì1vj“p&ðd̦V„K7aè–Ö¯ƒŒI+úÜ“Áö­?5Èìáé µ7o ¯?þøãðÜsÏÁ}÷Ý'­bÊE vW@+Ï5» A \<¨…!…‚³P1zH¢â{î ÉSVV³^|JòBãᾑ¯Àäv°÷·oàóÏ?Š"à¡EÝ·”HR@Û hṦm…¨w¤€c(@€'cžìý ÄCŒç|–ÊιØ«¢Ñ²RdAwíÙì,h¡1 ðëޓ으{Bþ¥<ø¿ÿû?øä“O °°U×®];fÑCØkܸ±”&()@ ¨¬€½Ÿk*—š#œV<S› ô{ñâE5YWtëþóðãž3윻‡ûw²®K}¿=““7´O êÃj¾yó&=ü:zô({-((ˆ~ÅÆÆ*ØªŠ ä*@€'WA*O hC<ó€77Ä®5›4¬#$´3ØÊž={˜EoÍš5Âûƒ b½‡~ØF=£jIR@ŠxRT¢<¤€ö À“1G €;w‚››œpôüq8zvˆ€1ƒî2ÙRvv¶à¾-//gyÑíÍÝ·¨+%R€PW|o>³ê¡¥ÏœËIɃA[r2áž®Maú=}d(|§hQQ‘qþüyöjË2š4©·BR"Hy àÉÓJ“ZQ€OÆLèVUPPo¿ý6lݺ•EÖª•Ð 7eÆlð íÁ[¿q$öèÍoî¿îí[àÀ¾xmÁBXþñB³Ö9)€·/óü·ôgØßò´i#BºÂˆà®ä×J9V¬XÁ`oÿþý¬>v–Â^‡¶¿‹W‘AP%¤€F ÀÓèÄP·H  À³P0qvC€'~ÏÆ;uêdee±/9I®Oܶð¼}|×íÞ”íŠZð>¨Ú—ZäÃe(š¾Ë;‚_7ß–rä`eùåæ¾[6yäzùË_d×O®¨ž+Î:Ù À“1«æOFÕ ŠÊ݃g ð0ÀâÐþ?`É¢· *:º'%ËŽ¢ïÁ«mUß§±¯‹5EB7:úD °×Ù§…,©~Ñ¢÷é§Ÿ õôéÓ‡ÞØ±ceÕM…IWS€ÏÕfœÆë¬ àɘY5»)'ŠÖàá{R#d¥¸hEÑn+;ߥÁ÷ÅipéF‰Ð¥.¾Ñõ°Ü:øX”‘ŸŸ/ìÓ»|ù2«Ÿæî[³MEI×P€Ï5æ™Féü àɘcµ»ªs^³Hx÷MÃçàé“bðð•/Œƒá#Çʶà-û6ª®›>oKéQö®Þ¬¿ÅSwß–Ì…ûppW@—®µ ­yè¾=|ø0«Â××WÈhÛ¶­µÕR9RÀé Àsú)¦ºˆx2&ڀǻëL7Yü\’É\¸ß¥AQm¥0#=ýâØkÓ¸©U3õÃ?0«î×ãiôèÑ öúöíkUTˆpfðœyvil®¤žŒÙ¶'à9Ã]´†¤ÿ¡øp=ì§AYmµ%Ù¿ sá>Òb½,?eß¾} ô¾øâ ¡Îû￟¹o}ôQ«ÀµŠ^»v ÆŒ[¶laïܹ3lذÚµ«?PÛÚTUUï¿ÿ>¼ð `é‘7o¾ù&ìÙ³¾üòËe ½g*¿¸ÿاéÓ§³—-Z>>>ì;´-w¼Öê¤F9<5T¦6HÛ+@€'Cc{^Fv,ÛxÂBü`ôƒÚ¹ÂkíæCPPT“†u„„ÖaV«[uÌ…Ëa¯êVý!ǘúÄ×Ã^pWhábQx†‚ºo‹‹ë#|ï¾ûnÁ}ëååeQ}®”ý5j`¤òìÙõGò Ta KJJ ``‹µI*tªßV€§ßŽõ½÷ÞSh­ÕIrxj¨Lm¶W€O†Æj^zåÀ C‰»i‡õ뱑Ö] &cø ŠæäÂÆßBH@cX0±—bUߨ«\¸|ø3O ¼[€½ˆF’Û¬©©2ð¶ L!!!èÅÄÄH®ËU2J0} ?´°%''³Hç?þ˜í\³f ³rHDÑ"¸råJà%%õ88?h%üꫯ`Μú«öxàÁb'ðNœ8a´_b Þc=øyçI.ÐjyÍàiyv¨o¤€tð¤kÕ §€7/ïGØYžs›e–+qÚºÿ<ü¸ç DGÃÃýmsÿ­%òðèÙ¡}â`PÛZò¸U-|héãip`aÏ^˜§ôˆY´êa”2Oxç/ºo{ôèa‰N›—ƒZé¸õN°ú.Íï¾ûN°xáàx ,`åõ¡Lü3Ä k455U°–! ®^½š¹HÑ +¶$*x†úÅûãÄvÅã!­Ó.u)à4 àɘJ5¯¸¶b3_ƒ’Ú*xbлY{ æ|– e•50°W;¸»U¸ŒÑÈ+züìøuïIðõ‚{‚§‡»¼ %”Æ=zöpïž8ý5¨sábDn°‡¯„ÚvïÞÍ@oíÚµw qð`fÕ>|¸¤:œ5“Àã.\¼‹-süç%K–0YðÄV;±»Óàq°Â½onÅ3‹â90·[ð õ ­¸â=xxκºi\¤€s*@€'c^Õ<ìZñæ_úIè©ôR2ò`ö,ðiÜFI?õ÷UTÕÀÚM‡ØÑ(£ÄCr‚õgÙY;}ËÏØÃ¨\qz(¸‹{þîÍ6· èáWee}To—.]è=ûì³fË;c)€ÇݰúãGxŠe€Ç]›úûÙÌwã"Ôa $·&*aÁ3Ô/¼–íŒË™ÆD ¸„x2¦Y-ÀC+^ËÌW¡TUŠÝæ —µ£2³ Ø><ܧvÂ}w¸ÿ®Së0˜<¬£ÚÍ7hÏÕÃ(\>×4FçUÀ®€‡®GJÊ)Т¤žŸgì<¬C¥‹?#˜óz-<Ü!ŽÖÖì(Ó²à)£#ÕB Ø[û^ÞOBd}¤8òÎOÕÕÕÞ’›—‘Q‘0|ذ;ïÏíþ茇×u»¤¸n¾0xÛ§®_…=F,xÞ0=ü/Чº=üüãE¨½UÇܵ’ÚÚdOî¹Û¶ïsË"ÜMÞ ÚÇÚÿ˜K>Lg¯°·§üÎ>#Ô’[õ†w6ZåÑ£G÷mmmý±-q‹ 7aÂKºByIM)@€§©é ÎV+`7À³ºÇ*¨Ö<2FÒž«¹¦3zvÓš "E³sK`åæcPTv^$'Æ)]‹Ñ²)‡Î°€ tË>õ`{Í[îÌ-™Sׯ°kÒв·¯â¬=ÔÓO€½!A†÷¢ÅŠd\¼x‘•Eׂ~áÙz”HGR€Ï‘f‹úJ W€OÆêP ð¾¸öLÈY)ôÔ؉‡QRQÃ"k1ðž“×õ®(Y‡!£µ.íD.\ȯ¿ý*0bVk{îdL'+z¢:Ÿh¬<'T×Ô3€h  wP`{ƒÍ,_¾œÁÞØû5bÁzx[%RÀ Às„Y¢>’æ À3¯‘Ñj·ÞyøÀ´ð ¶Ø™ê>¡²io;'^kÓb£B!,ØÏìÈ Š+ '·²Î_e×aÂsî†ôеËQ(f;¬p†#U¹ì®ª·ÎajÞ(ˆ_ÿ€»´ºiÓ&æ¾ýé§;GÛà}·zýû÷W¸—T) ¬xÊêIµ‘öR€O†òjZï¦]øÊ"° CÞ~ð"¤dä2·-Oè¾Eà ô÷f®\ÜK‡{÷ÐõZZ^ wUÕwîEwlrBôïÖB•CŒeL‹MŠâ•q̲WœG«ò„6¢½BØ»×_7zùСCÌ¢·lÙ2!ß¾}è=Z‘~:”‡ÒÒԕص $&6 ¡üõR9Š>Š, +!À³P0ÊN hT<£àáA½Roc05œŒìæ¶=y¾HöŒ•A¨kÂܱ ­Ãd(å\ETžc.\„½“ÕùÂàZ5«‡½à®ÐÛ¿µðz^^ž°OïêÕ«ìõ6mÚî[¼ËÚôé²ðùŠ Š?=a<ýtÃ`Ï?§ü(–#è“––iéépO¢aX·v͘+G€gN!zŸp ðdÌ“€'£{&‹–VC~a%à÷Êê›P{ëx¸»ƒ¯·'„zCD¨/ûNÉ´©g„4N_¯‡7Lm‡ßÞ³—=übÙky=tßffÖß¶áïï/dà/VKÓþipàPC žÍ×¥KC ^zz¤§S~GÐç‹/VÀÊ/VÀÄg&À¤gÔ‹Ì&À³ôSHùIm*@€'c^ðd ›ŠQ¢fwã¥AŽ(âùnïæB€F¢o +ýý÷ß3ØÛºu«PÞ‹î[¼‚KjºQ €_”œO<ç›S) ¦x2Ô&À“!ž“ý½,«öŠÓàbM‘0ÚN>Qž½Ÿ°wï^z«V­òàºÂèÛGyĬJxf%rØ x;uÔqR@ àɘ<â¹PÑßJ °—£TyWßhœÈ¬{¾ù×÷mii}ž:î[OOOƒŠà9ïB"ÀsÞ¹¥‘‘j(@€'Ce<â¹hÑ_J {ö n– *ÜãË,{ÿÏ·=lûü;{x=¦&Mš ×¢E åðœw!à9ïÜÒÈH5 À“¡2ž ñ¨(üT’)Ü Q\[)(ÒË/ŽYõ¥äÂ÷ÿ] ;wîÞ{úé§™û¶{÷î€Gžüy(:%4 ¨È¨¾ ÞѤ²+€1™‡ÓážnEëÀÓH]'즞 é ðdˆGEuø_qzýݸEiP~ëÎy…}ýÛBµ8ÿÅNøqÙ:¡Ì!C ®uÀ(Ú§ÆO€ñãu£,wWdÁš¢½ði‹§HiV ‘~©™(ŠVMµ©-RÀv àÉЖO†xTÔ · NpábFõ­;‡M'yDƒOêeØûöZ¸~±•÷õó‡‡~–-ÿB§>´àõ:õŒ éMçÀkÏ'ºN ØY<àÈ€Gçàɘx•ŠÖÔÝÔ½›u·„–Ûú@Þ—{¡âÇL€Â*ˆhÞ&Nz&N~š6mÊòùe>˾+yEeÕp¥°ŠËž›ìï ᡾à<ç&je¼x*}بRÀ  À“1©Žxt“…ŒÉ¶sÑÊ[5Â{hÙ'ŸôkPõÓQ€gÁ­´æ6è==>‡ÒÚ*«!ïèÙ8v¶N_(‚âò;nccRû7†6Ñ!СU´oåx7Ÿhq¼®xI½ïµó'š'´­À¾?vIî IÀ»víŒ3fÏž­søê—_~ »wï†E‹äÆœ-£#žÑ»h½AX°‰»h‹*ؽ´<¹ú]´ZZ»¥µÕl¿Þ¢Ã?Àá ;gì±>î>°=‡Á^“•càZËFB×¥Xòp½ìN¿©Gru ÎÇÂõ‚°×³côí¢í»‹µ>^W¼?vïÐÒÇúB hFÞ}ïÙ€ÇÁnË–-FöÀ‚áàªI뀗’‘›öæ@Ye ›¢°?ˆi ±Q¡ îÌ¥‚â ÈÉ-„¬óW¡ ¨‚eðõ‚!½b!>–/_ÇŽƒˆˆ9r$$%%™«’ÞWPŒ¢ý=ý\íäiA×`KÙÝÚóË"üu^3yûŽæÁ¯û•_/{ÄBR‡HG®LUZ/‹¢Íp­»hÑ‚G€§Ìú¦ZœOEeAx듌¥ 0Ëž+'­^IE lØ–™Ùlz¢#‚¡ë]QjõtåäBÚ‰\¸_ ¹§ÓaëêyPQV¢Sß{ï½3gδº *h¹âsð®Þ,ƒ¥iðCIl+?f´²QþÝáóV“„÷K+jàûYÌk‹õ‚u¢Ëöáûâ!ÐÏËòA*‘v= IDAT\ÂQÆëŠçàà)¼Ø©:§R@1ÀCUŒ¹hJ1ƒÑ"àeç–ÀÊÍÇ ¨ì:ø4nɉqpw«p£Ô-züì˜0< ¯\0Xgjj*YòSÛ|EÆ:w~)|WrÜ Î@5wö„u¦B#ÿXÿë1掵ÕzI9t†¹ûÑmûøÀöÐ*2ÈüÀl”ãl^‰ÃŒ—ÏF‹€ª%T›ž!W-¹h´xÇr aé™P{«ŽYë$µ?e-&{vþF 6úñ˜8q",]ºÜÜ-(ÙZC€7ùâðeÑ^óMÿ˜ñÝaиÙ6[/Ø‰Šªضï ØÃÝ žÒ Úµ´Þšl~`†sœ F yÌfëE<'ÛöŸ‚£§óÁÝÝ &%-wË~°ýçCÉñà¹â'šÆL W@QÀ3Ö îÏ;sæ íÁ0€]#uß}÷Á¶mÛì¶.qÏÝÂu™[Ö–p‡ÌL? îit¬ÁÁÁP\\lR Ìч>1ÚMHlX xî:y·€`_Hð‰† w¸×¿yøW—á´%ß„‹¹!©['UàŽKË!ݵ/Žì¦Êž<>^tCÛú󡿄䌗Ï?ÔeRÀ† ¨x{öì7ß|“¢h5xK7aè–Ö¯ƒ —W}ÕÏ=ùlßúSƒvü‚àÌé,@ÈÃ?Ξ=˾ó/þsYY™Ñ>zxxµü!bÝ”êßEÛªS;(®­‚–^æ£ÚWn:Â*ÔZ/úóµñ÷£Ì]‹O éhóétÔñºâ]´daó5àÀ ( x¦ŽK¡=xÚØƒ‡G¡`Ä,n=$Qñ=w†> ee%0ëŧt /4<îù ¼òìcœ`úHŒË—/7€>.Þàý 3êþE°+¥eËWÀgËW¼‹Ö˜x4Èw¿«»^ôû‚{òÖn:Ä/Fô‹·é*Ž>^:Ï•>Ñ4VRÀ´ª^JJŠÎáÇ®81öÞƒ‡‡´Îù,•s7°W;E£e¥Ì'ºkÏfgA“°pI€_÷ždçä-˜Ø<=Ü¥TÑ Ïõë×MZÿÊËËÖëéé©cýïÄÿ;›õÏRÀÃõòïUö[/â‰Ãhl¾^þñ¤õëÅÔ"s†ñàYõ¡B¤€S* (à9¥B êñLJo¾ùºtéP°fiUmÝ~Üs†s÷pÿNÒ Ù0×÷Û3Ù9yCûÄÁ 16i)??ߨõïâÅ‹&ÛÄ;Z~ÄÆÆÚ¤¿¶¬ÔRÀÛqð<ü’ª½õ2¸gÜßMùõâ ãµàáBø‡Ô Aƒ`Ó¦M¶\ ê&­ªrSc¦žŠöâ‹/§Ÿ~Ê áÔ©S*¶\ßÔœÏö²À Üw'çc¥:Žûªp^k¶`b/¥ª•\OuuuëŸx`EEým†Zÿ ~ðà  ûÝf¬Ï–Þ¿VîeçÝim½`ÀÅ«O)¿^œa¼ö}:žž}öY—¿‡µxã7àßÿþ7»® ÷•©™2² `ÙÆ#ìú±Ñ&ªÙ´É¶Ön>Ä®5›4¬#$´ÖÖ…ó—.]2hýC4gý 7êþmÙ²¥]ô·ð0¨ƒ ´º^žÒ:´Rn½8Ëxíx5‚ºº:8qâ´iÓFÕµM€§ªÜÔ˜ƒ) (à‚;‚¼;+ÿÂÅ/Œü<~ü8³©•¾ÜzRæCïαнC´ZÍšmçÀÑ ðÇáèÙ!Æ ºËl~­dÀµn,ê@*++v!š:÷/00Pña~qíhuÎN<:w.]ºšlãëí'àÀqí®—îwGÀ£ý¯—/W¯„¿AAÒ¢¨}¼8™ö¸‹vóæÍ0tèPvPù7_·æ*ttÀ[Y˜ Ã:C°‡¹¡Òû¤€Å ( x<Švܸq0fÌ¡3xÞêÕ«]þ˜x(ÌÈ‘#aýúõO˜µ¸{#gÂý¬­FñrÅ,BÒ^nZÅt»Â¼¼<£Ö¿ÜÜ\“Í¢õϘû7&ƺ½gxÓ/| /5χö‡ _“}àîJ­®snZ¼üm¼0e*û2zŽ>^œL{œƒ héÆhuÜïªvrÀ›‘û5LmÚŸ}詽‚œ»=E¥Âóîð—“ðð5L³gÏvn5ÍŒN x˜uãÆ0dÈ›j‚Q¦ËW¬†U?üMÂ#áÝ·^/¯Æ:mžÍ> /O~NÍÐyýý%«`Ø#£¿?ñ…™ìgž–üç-ˆn§ó¾W]]ÿœ3Ö¯Zʲ>þädxmÁBðö6üWê²ïR¡ªú̦'„zÛT-TŽÖ=SÖ?´K^^^ ¬â@€€£ec3_ƒs5×ÜM /61 zEeÕ,zÒ™ôˆáCª‹‹®ÁŒÆÁî[Ì1/ñžÞðâ+oýÁ[M.œ;£óš~g¥äáë£iCŒ¯—wµ† çÏ1¸3zö/~v>|w~ßûÁÂWCpˆá3 ¥ŽWmÀûàƒ`æÌ™l xJBÏžÆ4·ÕçÎÑui}ì 8WSÈàNiÐC£ \¶n­ÿœò”ëÖ­ƒvíÚY45'Ožd^¨Å‹CAAðÜvd,‰Ë˜ÊgQG ³5Z)=,EÏÔ9x¼ã®|¼¤¤$Ø·o“$-- :u²MDëŽ;`üøñ ¶5‹ˆ„w¯€¤>ý„µ„÷æëÓ`öÛ@«Öõxü%=ÿÕ©0uÖö3`Óð_DÆIcBä°×=)¹òðhÚçN€ö±êß9ªô‡Jn}8_Æ~FË ©Ô¬Y3£îßí~aBÎJ¡¸1ÐÃ;X?ÿ)Ãh´5¸á#Ç sŠs~`_ ùêªJW¯äÇK× kʼñkí^þÛ<“È×ËÓM0yG-Zñžö™;ã5zj÷Ðþ?`oÊvaŒø9Â$†añK¯š€‡Ð€€€iàÀ€®Z{$gs~• Ÿ’ Ç÷÷îÝ[Ñ)’ nRó)Ú9 T¦…q੸8àÍ™3‡ýåÃÓ¬Y³`Ê”)¥XoÐr¯w¼r„¼­{O–˜Y÷øa¿Æ®é24Ÿâõ×¶ûã yd4”—— Ö[S€‡kér~tèÔ ®^6 x|½H9ô˜[ñÄšè[ôì1^qø–,z˨OêxÕ<ÜV2iÒ$[™1‚Ö^ɵãV<±ŽJ€ž9À{ë­·Ø„£Gfs:cÆ ;v,ƒA±õÀÁmVÜj7þ|˜:u*³ ò÷hî½÷^a»víbBnA×ñÄO@FF†P-{üñóbb÷îÝY=h à`Š}íß¿P5ÔO¬ûc¬%K–°ú7lØÜš‰Û_pü‘‘‘0o^½u¿#c2VŸþ{“'O†×_}N¸>sçÎeVOüâcåZaþ… ‚àñÈ!,‡úˆß³æ3¦(àYÓW*#<„<ü ?&üåÛ¢E ö…ûZä`¤§§3°±ôÏEËàáÇždo<ñk˜ïåYsáÃ÷æ3«Zú¤ž9 Y|\¾ ÚÅ„@ëHi›â]iÝX2ÖÒÒ(*.‚¢¢b(*Âïw¾Ø¡ÏñMú>ÃÏ­âDí,‚؃îp½Ê^œ1‡刓‹,·þNžò7X·êSÀ?{ôsôf¡¡ƒ»Žy›XØ7Üâ…(vóêC)/óüóÏ›lá ´k×®Ô!Üá&ýþàSì7·„Šû[nvñw:ŽCs·nÝŒj…àùÑGé´ucY]Ó<ŸµÖWÅïMNNn°P]Ù5ËÅÐ<|?o¿ý6#vü A­„V¸)3ê÷DÛƒ·~ã.ö‹ßGÀ›û¯Å°kûÁ·üã…÷à‰Ç`Î:y÷ežƒÿ–þ û[QkøÔŽ).•Cç/½`æ3³!©“î‘.bK® CIìÞ/ºvM°NáÚQb®—}™çáÏ­«àÀ¯w\[ÖNꀑ/A|ÒpHê£úx ýq¥?ïKOô…²"uV2¤'FËâh5j”µ’+V΀g/È3'JK¯PØÖf:ÄJ¸?š×elžØ2„¿wòpn¹…ɘ{Qê¾2„”5kÖ4<ý}{XCì+ ·À­X±Ðú…ð·}ûvÁšÆÇ'¥Ÿ¼.cíp(䀇ü‚ð‰ýáàf¨o|/"ö­p†ú&·~~ÔŠû“O>aÅöôáÕÜú0ô¾¢€GwÑšžC€'.QVVÆ@ÎÊÊb_r’\ ž¸m1àyûø² ´Êà>"CA¼,ÂݼW§èìÃ24&²àÉ™iée¦¥AÊ•P”`غàÖ†WÅCÀoUp*«Æ>õŒ,‹–¾¥{ªà)eÁ ‚_z”²àY:^þ‡Õ¼}Äþ2–¤Zð¤¯ËrvìØúöí #FŒíY°¬eó¹mxæ[U>‡) ^‡¼le”­9 ‰ØU‹¯‰¡Cl13xXwmb"Å<,/†8}ˆƒ’غøõ×_tÏë§þë¦ÚÑ<±‹Z xb÷3Ž»v<(X+¥Þ–-[tò‹5EÀ3æ2·fÕÙðДڧOkúãÔeÌž’ƒ—»Ïàa¤·ÊEEÇ‚±à tµýðÍ“Ѽ Úƒ§ä̯ :~)f7\m¤“)Ðæ4À"k­Ýƒ‡¢+¾Wrà{ð8ðp+Õ]í;ƒŸ¿¿ì(Z©{Ò°O†öàq°ãǧX³Oîx¥þñƒíX2^{t¬Îê5ÜŠÒ€g¯±Úƒ'ìø8¤Âß΃®Zt3J±Œé[¥Äàf­O߆ðuåÊfðÐwÏâ¥ôÓOÜŽTÀ3d¥ã0¬¤O³€‡ƒÅ3ï0‰I±×‡Fkíª x8v9Q´¦ÿrÃcøQ*âüRܲâüE«ÎJðý»ðEL¶Ð˜>Øñ7¬*å@õðl•-5BVÊ<©Q¥úQ´ú`g¯ñJqËú|˜‹Æ2xê|–”lE?ŠV °“ xâ½mlÜ%ŠûÊÄ{Îøžºçž{ÞyçǤˆ-s¾¾¾:{Ù,Ùƒ§J<°­Ç<ØA¬½>Àò~ò c{ý,<ý=xØÖÁ÷ʉ÷"èb2µ_ÑÔ<͹hMìÕ<ìÎ9xÍ"áÝ7 Ÿƒ§LŠ9À3tT/#>ã‹¿fê,¼eߦBÕu×9OÉ_–Ô¶w*\óº>µ0½ùƒ‚ÅN¿á\8ïF0i„´sðÄg¹‰÷àqÀã{÷ÄQ؆ú.ðøz‘zž1°ãí«=^»âñ›: Oêx ð,ù4h'/·Þ) vú€§¾ÿ믿º>¹K_6Š[í0?\¶lÛK¾téRæºDW-F¨âž>q>qð€¡(Z}À“²ÍXt«©(ZK[5yT®þ9‚h±ÔŠåŒã·$Š–O;ŸM‹zbÀ㤛,,š*§ËŒ7Y¼½B·^fÇ¡¶h½{%÷k«÷Ø9Þˆ-ë±Î’³¬ÇÚÊ­èúÄëtlëþóðãž3Fï•6 årñhÈ¡}â`På*¦šŒ*` àí8x~IÕÞzÜ3îï¦üzqôñàÑŸ Ä ੸Ô¼âÚJˆÍ| Jj«à‰Aïfí-˜óY*”UÖÀÀ^íàîVá*Ž^·©ãg¯À¯{OB€¯,˜Ø<=ÜíÖWjØÀÃõòïUÚ[/=k‹õâèã%Às¥O2•0¯žyË¡àagÑŠ7ÿÒOB¿Å —’‘¶eOãF0zH"øùx)6>©UTÕÀÚM‡ØÑ(£ÄCrB¤Ô¢”O¦–6ÅÖÊzÑ/’:Øn½8òx ðd~8¨8)àd à©8¡jZñZf¾ ¥µÕ:£ã —µ£2³ Ø><Ü_¥vÂ}w¸ÿ®Së0˜<¬£ÚÍ»l{‡¥ÁŸ‡Ò¡SBèÒ¥«dVn:ÇÎÚ½`PWØ:9êxÓÓÓ óp:ÜÓ­ $&JŸ_[ëiËú)È–êRÝŽ®€ÃžØ"åÆTwƒúïø?ý]œ|çUÃùyyö®^þ;µßiIhïv^q«Rú²yÓfؼi 2„}-¯ÓëÆùYA ¤”Ÿ6¸>“}ÛBÜáÖx):´‰€=Úª¶ŽùµKX1ã‰nä§¾QµÁj¬!¼ªì³å+à©ñ`üø ’{WZQK¾9çÏå@¯¤®vY/XñâÈn¨Âzáã-.¿n·Ï‡µã¥›,$/kÊH 8½ŠžǤ à¡ë‘’r ´(iM†ÄØU~is¸ópwƒ—FvÖQAÊ †j2«€1À;Ws Î߸f°|íÍ›ðûŽmðË–­™~öxF ¥úz™4¼ ´ŠTo½œÍ+¥?¤Ã­[uªAžøóaíx ðÌ~ ()à2 8àåýuPÇ&†ÿ[ÿ½>é¾wûçÛ$寻S›Üüº½¼Ý¿º:øóÀŸðçŸàž{ºC÷îÝoÃÈxn÷‡÷ŠÏàX ôýÔõ«°Çˆ/Ðæ‡ÿúT·‡Ÿ¼µ·ê˜»v@R[›ìÉÃ=wÛöbnY„»ÉÃ;AûXûÓâ2ŸòÛÞÃãFÁ¨sŸÀîŠ,é2ºí>­‚c^Wm½¸»»Áø! ]Kõ× ÞÉ»rS¦ªŸ¹ã%À“¾œ)')àì (xÎ.’RãSkö#iÑ2#Nì¦5Á¾ì­ìÜX¹ù•]gɉqŠF×b´lÊ¡3, ݲO=Øž,wJ-( ë1dÁû¨`üýÒWfkÂûkÓ[ÎU>°þ×c€îK[¯tS>>°½ª–;}!Ð’çHã%À3»” fÀ;»×¯_ç΃–-[Âã?7¶®2 •BïÚÔ©SaΜ9€÷©K¦®Ã%ðîÖ·Þz Þxã »ky}âòâûj›4i¢!5lÛ-j 8àíÙ³’““(ùÀÀ—_~ ®4áú"¨xx-Õ„œ•Bó†ÀNÜ·’ŠY‹˜¢#‚¡ë]Q²CFk]Ú‰\¸_ÌêÄ€ Œ˜¥=w¶}ȘªÝàUWWÃ6~„òæÆ÷C®où< ìªÇ=jßïÌb¶Z/Pñð}ñªì¹37#Ž4^œªª*˜1c†AÀÙUïÕâ¸<\Ó§O‡O?ý”ÏÀ‡\-ÀãÖ» ˜>Ä;SϦ)ÄF…BX°ŸÙÇVAqääBÖù«ìú1LxÎÝ^±tŠYõlŸEÑL‡N»@áµkðõ†uðÕ†µ€ƒÛLë VoÙ§ÃÀ»Íkð:)òë~å×ËÀ±6= ÅZ¥µ>^E›‘÷$R­Ô9FË]||¼Üñ²yYYYmÉ^LL ´ÈÈH˜7o&~G«‡“{î¹fΜ °nÝ:fõÓ·àuíÚ>ùäÈÈÈ€U«VÁèÑ£…òóçÏgí[·Â Aƒ`õêÕ€½'žx‚å篡¡ë}óÍ7áòåËlË&m~ï,Z û÷ïßàZÓ¸qãtÚÀúp ÆÚY²d «Æ ÂØLéyÕ§ÿÞäÉ“áõ×_‡I“& }š;w.,^¼˜}ñ±Þ{ャ˜áÂ…àããì¢ååå¬ê#~Oê6•OQÀãÁ³gφœœؽ{7,Z´¾ûî;Ö‡1cÆ(Ñg‡­C ÀCëÝ´ _YvbAñ°×í/BJF.sÛò„î8¾@oæšÃ½t¸w]¯¥åÕ€pWU}CÈîØä„(èß­…M¥uØE`ÇŽŸ8q¾\»Ö¯[§OŸªïÉ=Q2ý~(Šovøv'ï°%nÝvéëw×Ëîô‹z$—¹m­]/èŽíÙ1 úvÑözÑòxé<Ë?\+W®„gžyÆhÁaÆA—.õ–k­$t·JM†Ë"`¤¥¥Á”)SÈaB8B¸C`CðÈËËò‰]´ø»ƒÛ´iÓàƒ>`åñ÷ØE‹¯#Œ;Ö`½¼}ɵk×™3gpb¿‘#Å^?}+"/óüóÏ›láj×®]€pÊ!¿ã—!=ÂÂÂX}ØN±•••:no|/..ºuëfP¸}ô‘NûX7–EЃ0æã+užå³à¡@Hò|Âq¢ÈE»€-ü€Zò!µd’ð î"ì±³¤¬~ÞŒìæ¶=y¾HöŒÕ‰P×.&„¹cZ+w¼œ1¸zÙŠŠ öǯíÛ· rD=þ/ö“‘õPæé¯4 ¯]úFG²½m߀oÃwëk‹.Û£g àô…"Ø36um¢CݱZ9ÞzÑÚx ð,ÿ´ó?º-/iŸ–þî0x¸… !NüŽ†ÃšØjÇAP x¼<–‘7ü¸•·ƒícy„þÞŠ+­_Ÿø¼B'cnPý×ñgcíp(ä€gHC}ããÀºQn…ãý3¶O??7ZB1á8¥ºÀ-YyŠwÑöíÛÌ,v[¶laý¡=xõáØð,™|Kò–VC~a%à÷Êê›P{ëx¸»ƒ¯·'„zCD¨/ûNI à玃]MM½Ë7~a4”hÛ}α׼ÝÁ+M`pçãÞzžz2«/²÷ÞiþL `Õ€ŠÊªáJa%—7\/ÁþÞê !γ^´0^<Ë—ª+ZðК†"}ÀƒwË<^^ à!܈!NÜ&þ_ JÈèâ0a|ýõ×ݳb8[öô_7ÕŽ>àÒËs—*_UÜm}ðàAHII‘ xø,çƒ Zÿ¸5x(výúhfD—¸ÀöéÓÇòO •pdÀs¢ipÚ¡=zT€:tuð4`ÀüÔH8쟦¯O Èனg€ðÚà3 ÙÑ)}ýâá—¸z÷%ÇP€ÏòyrÅ=xr[¼8àϦܓ¦,xú–0„¯+W®°½úîYÎâúøŒ›³à‰Û‘ x†¬tØž~q¡>ˆÝÔæ,xx–Ä\§žë̵Z#--- nçÎB³èfÁ=5ÿïñðÿix'ÿá½§Cû2‹]+¯†nQ¼ÃÕàD»Ýw§ÖبË À³L/žÛU¢hyP\ÀCÝвwþüyÁ НY³O¢x`È#¸g± `Á÷Æ!¬¡ñˆ9Ûëg)àéïÁÃv°ý½‡øœE %¦G}Ôª=xxtLŠñ‡ žu`*ÕPM›6 `W[[Ë2øúú2¨Ã¯ûúßÏ îË[ ìöă¡-t?á¶ímô.Z<ŒšåG¢öŽ£ÝEký\¹Â9xJž8ŠÐÝ+¶ á,`€&sQ´ú€'ÅMi,ºÕT­¥€‡à&®OUÌ­xúQ±|ÁÇmI­Ãž©+ËhžcïÁ³þÑI%•RÃèù¾:<•'Ý»@î]ìSb|8I½ï…?vïp™ñÒ@IKPð,iØóà¹â¬óÿþ÷?v_}õ•!88X€:<,\?¥W^`»õ…²·ð®a´Ø!ܹƒ›Yqù]´]»vaWæˆÓ矯€ÏW¬hPÇÓ&ÀÓOOhð:寗D‹ú<;©á|™]šÏA'Žº­ŠŠwÑbÏ]ýZ2C³G€§ÊšÖl#¬u—.]úù׿þUpÁêüéëW˜Åú „9„:„;„<%ÂßÁ´†¼n] _\OùëUw}”X#Z¬ƒO‹³B}ÒŠŠ¿ª ·hÑ"Ÿò¬•Û³xöTß>m_¾|Y€ºýû÷ À Ìù™uÑцïz½|£”Yì]þM(‡nX„;tËR"\]œ¹`{ì1³½z7 ¼{y \»YÁòâQ'h±Ã£O(‘¤€®x´"H•7ƒ—Ï™3ðöŠÅ‹Ãþóxûí·-®œðœoöóòò¨;xð 0@¼|›[ë"##Íü“«;™Åî\Í5–÷ÀÌb‡‡S"Hà àÑÊ T<wì—ÔmÀ›:u*àQ®¾/Ïy>ŠýŠ.XŒ†å)<<\€º¤¤$Iƒ]}-•í³;Z•Çò÷ñoÍ,vx½%R€0­­R@%Àã{ððÂÝÁƒÃ믿Î,w'Nœ?W¬%Àsì"^¥ÃϬõÎÓ#<ÂÀ¿KMÿ+Ng»ÔŠ3¬H‚O f±ÚCj”pyð\~ &°É<}Àûå—_`õêÕx Bº¯ñKKI?úСCœœ xÿiXXŒ5 fÍšÕà º={öÌ7bĘ>}:¢#[n/\¸ @]ºè à=zÖºfÍšIžÊßJ3‹~Ç×8ŒYì&‡5<÷Nr¥”‘pQð\tâiØ’Pð°E±‹VܛٳgKꔳfÒ²OwÕqKÞ ËSóæÍ¨ëÞ½»EËt_ÅYv_ì÷ÅõgÍ5õ `»ÍZTe&H; àÑj Œ+ 8àaSèŠ;v¬Ð*Á]½Z<úìÞ½[°Ö ’`ô+º`zè!‹e½uh±Ã½v˜|ÜÕRÜìðvodq}T€ ðh R° àIiØóàioÖsrr¨Ë̬¿ÛS¯^½kº¨-Mçk ™Åîã«;…¢h­C¸kêéoiu”Ÿ  (@}ú­¢E­#޼K‰ED€§„Šò먭­ nÓ¦MB…-Z´ Nÿ®V©­Þ¬`;<ÏŽ§g›ÞË,v­[ŠRÛ¥|¤€+*@€çгNc–ª€"€gê Þ<2…¢hµd!uÁ8r¾ßÿ]»²²2a(ü¼º¡C‡Z=¼uµÌb‡‘±å·®³z0"-v >QV×KIRÀ¸x´:H,xúûîô›¤}x´ÏÄììlêŽ;&t#„9Ø…„„ÈêÚW¶1¸Ë¿QÊêÜ™Yìzû·–U/&HÓ àÑ !TìizSI&³Øí*?Åê»Ë;‚YìÆ7é¥HýT )@ X¦€­áC\ÚµkÇ/??Ÿ=ðgLrË+‹æ´7à!È®Zµ FͺJ€gnƬ_QÀãÝÐ?ì˜ößÕ+C.Z몸$> øAÄ¿ýö›ðV\\œu:tP¦1th±ÛTr„ÕÙÂ+„Y즄߯XT)@ X®€š€‡½C >gÐ`w¬GGGCii),\¸|||<´t­Y³†Õ ­nK—.eÿßµkO„£iÓ¦±×ÜÜÜ`îܹÌz‡_ø–Ç?pßÿ}àA___VžðÉ'Ÿ@FFFàÂýÉøºØŠˆýÁßí—/_†ž={²~}ÿý÷ðä“O²öqÛ >—cbbŒZQ¿òòr8|ø0|ðÁ Œõ6Ö>×C_k¬÷XãáÅVQþo+((¨––¯>í—PðpRÐ’çêÉ‘¯°´ò +¿WVß„Ú[·ÀÃÝ|½=!4Ð"B}Ùw[&t—p°»~½>RÕËËK€:|è*™Ò*Ïÿó·ÀWEXµA>Ìb÷ˆÀ Ü”lŠê"H+Pð¸[­l&xûÛß=VÜÝ©¤¶'þ?‚Ö”)SسÂÐG}$wÑ"ÌÜ{ï½:ÀÃABZZZšPžù‰–In¹ÄvóòòäÃñc?ð}înå}ĺ¹€9 cÛÜ•-<|ÝTû¦÷“ÃæÅ¾¡Ûõš9s&³ ŠÇ‡åœ-) xâãRž}öY¶H&NœÈ\´ø3ƒçXǤdd@fvœ<_Eeõ@e*…4†v1!Щu$´VæÌ·ãÇ Pwúôi¡ùþýû `çççg®k½Ah±[^°‡•ópsg;„»@ÛB¬E¥Ì¤€‹+`kÀÓ߃Ç-Aø»ïÇÿsÐÁßuJíÁ›©&Þ×"àeç–ÀÊÍǘ;]¯É‰qpw«p£Ô-züì˜0< ¯ÔŸg*Ý}÷ÝÔµiÓÆ\vYï|õwväÉùšBVÏàÀÌb×/ ^V½T˜ ÔS@K€Ç-R‘‘‘ŠZðPM}w¨~T(?÷NßE»dÉ66l¾§Aè»›ÅQ¬Ü=˃*ÄÖ=±ë£mŸ{î9øå—_˜»]͆ÎÙÓ1Æ"9¤ò(Zqû˜—»º±=üÂí<<El±çÅÿÓ‹\´ºŸU<Ï.­Þ±œBXúC&ÛK‡ÖºImÁÏÇKÆݳó7˜0j°Ñ:5jãÇg`wÿý¶?vdÕµTf±;V}‰õ©f±ûkü›-Ž*#H³ Ø ðÌ6ìœ^` ìÞEE¢hÉE+mµxh¹ûï7é î:´‰€=ÚJ„…¹6~»f¾XN’¡„.}üëÍÖéûâ4f±ÛWQïîìÓ‚Yìž½ÇÖMSý¤)`#ðŒ K€g£Eç@Õà©8YZ<Üs·pÝAæ–µ%Ü¡´™éà‘Á=ªüÏþ^}õU›Í¯¥Ç™Ån[Ù ÖF\ã¦Ìb7)¬¯ÍÚ¤ŠIR@ðÔÑ™ZqL<ñÅîúrÐUeÚ¹ÉbéÆ#, ݲÃú)wヱÀsO>Û·þÔàm¿€ 8s: ÂÕÛóÇI­8Ã,vÿ+Ng/…{0‹Ý+Íl‰ë˜ê5)àØ à9öüQïm«žmõÕ©] << #f1 bôDÅ÷Ü’³¬¬f½ø”ä…†GÃ}#_Wž} ’"›…#UyÌb·¦p«ÓÇÝ‹Yìî»y*ÖUD öW€Ïþs@=ЮŠžv‡§­žÙððã9Ÿ¥²sîöj§h´¬¥Ñ]{6; š„…ChLüº÷$;'oÁÄž†¬ßÞ¹škÌb÷ÉÕÂ[3› ‚¿G<ažþRºGyHRÀÁ Às° £îªªžŠróÍ7ì&Œýì³ÏTl¹¾©­ûÏÃ{ΰsîîßIõöõü~{&;'ohŸ8Ô#ƪþ\»YÁ,vï]Þ*”®é½ÌbëÕĪ:©)@ 8†xŽ1OÔKû(@€§¢î‡fWË 0€ÝÏ«všóÙ^Xûîäb¬T¿ñ0俼ÖlÁÄ^U[Sw“Yìî*nÕß¼1&4‰Yì:ùDYTe&HÇT€Ï1çz­ŽxêèÌZÁCƒƒƒ¡mÛ¶püøq[ÈÈ.€e°ëÇF?˜¨jÛ¦[»ù»ÖlÒ°ŽÐ:LR¿]þ Þ¹¼.ß(eù‡wf»^~q’ÊS&R€pðœci¶Q€Ï6º­µS§NpæÌÈÌÌ /O~NÍÐéÇûKVÁ°GFÃÙÛïO|a&û™§%ÿy ¢[Æé¼†ïYšË,û.ªªoÀügzBh ·ÐÆÏ%™Ìb—R~š½v·wsf±{ª‰eûõl*0UN vSÀÖ€‡·AÜ{ï½Âøø¦ø¿³uæÌ™0zôg£¡ûV¥ dª=©uˆóéß3+µñ¶x?,OüþÙÞ½{ëÜ·»víZæ™Â{a)iG<;ÌÅ+¯¼x94¦´´4@·­-ÒŽ;XÄnnn®P}³ˆHxgñ HêÓ½†@öæëÓ`öÛ@«ÖíØkÅE×`þ«Saê¬9ìgÀ¦á°ðãÕRÿa7xRóc]<šöù‡ }l(ì,Ëb»Í%GX[Ñ^!Ìb÷bÓú>S"HR°%à!lM™2Ö­[íÚµƒªª*˜1c$''3 ã€«W¯BÖž¹ö¬™q[^~~¾  ö‹ÏšÙ±}<Ûkl°OÏ;‡îΚ5‹=H¢¢”‹þDË]||¼ÜñŽ ämÝ{‚Yò ^uuüsÎ xhäXiÒ¿·ƒË½øJý_h¦Ï’üX×¶ý§àèé|èÒ?¶„¯‹²6‚=|™Åîƒí4KÔ,)@ hY[ž>Ìq Ä–­‚‚À³Mƒ‚‚ 22R°^YxRÚC€[ø&Ož .d]CðÄ>Ì›7ýŒßñ5üZºt)$$$ÀŠ+àÓO?…ââbøê«¯`×®] \Ç[·Ö3…åÐ gÊ‚7uêTˆŽŽ†ÒÒRÖ¾OÀ3ÕϱcÇZÅð‰mO›6õÁÍÍ3êûÄO@FF 4H€h¬{É’%,ï† ØØ8„ky­Ú£oxöPýv›¸(ñÃ…©qãÆÐ¢E ö…¹éééÌl,ýsÑ2xø±' žú°<Û˳æÂ‡ïÍgV=´ô™<©ù±þ-™Çàãë›àxÄÖ]O7wf±û{³ ÀãŽËÖŽSEM“¤€°à!à p|ðÁ ‚ %AsçÎ…ùóçÜ9sX^kOj{¼O111ÔqÃ>"p¡Wˆ[àû&.ƒgÈ"ÉëǺ^ÑÓ¤ï¢Åúþö·¿1Xä°&¶à‰Çb¨ŸÆaî£>à7b^´–¢¦yyyÂøÐmŽ€ÚµkWAr7\¥xv~há_)o¿ý6û ?j%´ÄM™1[Ø3§¿oýÆ]Ø£7{oî¿îí[àÀ¾xmÁBXþñB£{ð,ÉãÝ—yþ[º ö·Ì„©áý™Å®y£ µ¤ vHRÀA°%à±Lb+žkš’’¿ðtñ¾r¬Y Öe*?¾¿ìÛT¨ºÞð<‡:N ª(`KÀã'>C ¾gðôÁÄRô]¦âöôûÃ#KÅîa}KrHMM¢hÅ.Z±Û÷“O>aø>ºE¥Xð°OÜ2'Ž$CË–ÁÈX„É?ÿü“€Jq^ý(ZK…²ÊØ«ÜÝ*Ün£?~ö üº÷$øzÁ‚‰=ÁÓÃÝn}¡†IRÀ1 žcÎõZðÔÑYÕVЊ7ÿÒOB›bÐKÉȃ Û²À§q#=$ü|¼Tí6VQUk7bG£ÐáÆªËO ’N£žÓL% Ä àÙ@T{W‰V¼–™¯BimµNW8èeí¨Ìì¶÷ã©pßî¿ëÔ: &ë¨vóÔ)@ 8‰xN2‘4 ›(à0€'¶H¹1)Ü þ;þOÿ_77ñ«†óóòì]½üwj¿Ó’ÐÞí¼âV•ê «G§/Öó³‚H)?mpÑ$û¶…¸Ã­!ðRthz´µÉâ2T)¿– +f<Ñ ‚üÔ· ª6Xjˆ lªžMå¥Ê\‡õ`{²Ü9È¢n’ZW€Oë3Dý³§xöTßFmq혳R¨Ý؉›.©¨a‘µx ÏÉëzW”¬ÃÑZ—v".ä³:1 #fiÏ&ª%\P<œt²dð$Kå8¹õ.Èæ…±ÅÎÔ(ð•M{sØ9y˜ðZ³ø˜¦ aÁ~f((®€œÜBÈ:•]?† ϹÒ+’"Í–§ ¤)@ X¢ž%jQ^WS€ÏÉf­wÓ.|e؉%À÷¼)¹Ìm˺oøý½™+÷ÒáÞ=t½––WÂ]Uõ !?ºc“¢ ·tˆ±“­1) ð´2Ô-*@€§ÅY‘Ñ'¼‡‚»{ìdTÙÌm{ò|‘ì«¡®]LsÇ&´“Ó4•%HRÀ¬x”HRÀ¸ûþØ%Y·º:QȦäb”ÑÑ(,­†üÂJÀï•Õ7¡öÖ-ðpw_oO ô†ˆP_ö)@ ¤)@ 8žxŽ7gÔcR€ HR€ L*ðÿá[Êf’{Þ—IEND®B`‚pyclustering-0.10.1.2/docs/img/hhn_three_ensembles.png000066400000000000000000001200311375753423500227070ustar00rootroot00000000000000‰PNG  IHDRø”µ·®bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEâ U( IDATxÚìw|Õúÿ?[ÓH/’"" A”]¤¨D¤)¨x½,Wi—ßÁòõ"**p•&¤…B ‘vAD !¡%›ìnÚfËóûã0[’-³» ‚œ÷ë5¯lfžyÎ3Ï™9Ï93§HˆˆÀáp8ç/…”»€Ãáp8à9‡ÃáðÏáp8çÏ@îì N§ƒN§3ÿo2™ R©‰D½Çáp"‚V«ELL ¤RÞáp<ÀÏŸ?³fÍâ^âp8 ………ˆåŽàp<@â¬}ݼZ­F||<òòòȽÇ1¡À_ðÌ3žÊ0€fÍ()Ñ{eKrôík¬Y&¯¯É[[ž^†š`åJãŸnË„V«EBBÊËËÌ0§¡[ð>>>ðññ©·?,, AAAÜ{3¾¾€Ñ„‡{®£¦†ýõF„„UUÞëi[""€Ó§o[î$ kðOŽÇð[œ!0Ðj½Óa46Œ-AAÞÛ" ×ß>¶4”8ðŽhš4**&€™¼{³Ž  @£i˜ë*/¿}lÑëù}Æápx€çÜbüýÙkñ†ð••¾-ÞVZÒà9ðœ[NC|*¼ÁàåM-jfoƒªDrûØÂápî.ܯ¹ù®Q¯×CÏKŽDr&èõž¿_g쨪ңIol‘Áhôz£:˜-ÕÕz¯«Á …D"…^ïe­å¦_î–Á+¼|áp9À;¿sçNøûûsïqÌhµ©ÈÏ/Azú)u¨T¾bçÎ= «ñXÏåË¢¬,éé¼x› 0 ™™YÈÏ÷ü#ú™3­a4&!=}»—Ž;ö "¢æ®¸Ÿªê»F##‘HÀ×ëºó“o…¼uk¼F£A\\JJJø09Ž ÉÉrôìi§ŸzÞ‚¿t hÕJÜ\=Z´ðÜ–É“eøýw +Ëó|M ¤À/¿œìùC>w®ß|#EAw-x¥R?þÐ#!á4 """ V«–5:‹-Â?ü€üü|øøø %%¯¾ú*úöíË<ç¶ ð:!!!8qâÚ¶m‹=z`„ ˜4i’Üž={0mÚ4:t¨AÒöh¼B¡0SåpØ=˜L2(2u3’J$ xs{Édì»Báy“ÚZË#âí­.“¡žî–ÇNŒ¿^xáÔÖÖbݺuHLL„F£Aff&æÌ™sË<‡#†Ã‡#$$mÛ¶EUUŽ=ŠeË–Õ“›={6æÏŸÔÔÔI×£°¦†g§~€÷ö³©T½Õc4² ê]»alÑ饲a|Ì?KÛ²nÝ:,Y²÷Þ{/|||‰§Ÿ~{÷îÅÙ³gѼys›7PQQ¨¨(¨T*H$¬\¹:u‚¯¯/š6mбcÇ¢´´ÔæœM›6¡sçÎðõõE‹-ðí·ßÚw¥C"‘à“O>A\\œÍ¼ú_}õZµj¥R‰V­Zá›o¾©×‚cŸ=ŽZ¨çÏŸÇO<¨¨(øøø 99kÖ¬qêÿM›6¡cÇŽðõõERRæÎ ƒUY1ö‹IWL:_~ù%áããƒ:à—_~Áþó´iÓþþþHIIA^^^=¿µnÝJ¥IIIv®;v8cß¾}èÕ« ;;QQQhÕªU=¹½{÷¢wïÞ ÷¨Õj@'N¨‰Ã±¦{w¢qã¼Óqò$@tê”wzž}–¨W/ït3[öìñNÏoÝ{¯w:ôzfˉwÏý$”5jµã²&!!<èðø!ChéÒ¥6û¾ûî;š8q"Ýü4IíÚµ£ŒŒ ÒjµTTTD£G¦Q£F™å·lÙBÑÑÑ´yófÒjµ”››KcÇŽ5£¥¦¦RAAyßúõë)66–222H£ÑPFFÅÆÆÒ¦M›ÜÒ-V=¬÷wêÔ‰.\H*•Št:>|˜ž|òI‡¾ÍÊÊ¢:PVVUVVRnn. 0€æÍ›ç–ý®Ò›NÏž=)''‡´Z-½ûî»B)))6û† bsN‹-hïÞ½¤Õj)33“âããiÇŽvý#ÆŽºœ8q‚¸Ü\å7xà·nåžcKïÞD£G{§ãÈÈŽ÷NOZÑ€ÞéÈËc¶X=ïñòËD<àŽŠ fËáÃ<À[³aʈˆ §žzŠ>ûì3ÊÎÎ&ƒÁ`>¾wï^jÛ¶-™L&ó¾^½zѯ¿þj.D×¹Ù®]»Fáááæÿ»víJ?ýô“ãT„tòäI™nݺц lö­_¿žºwïî–n±z\‘ÀÀ@*,,?ýúõ££GÚì+,,¤V­Z¹e¿«tŦ“““cþ_¥RÙÝbsŽu%H¸ŸzYµ ¬ý#ÆG”——“B¡0Wð:uêD?þø£óÀügø¯¿æžcKÿþDO=厈¼dÆYUÖ=âìYfË–-Þéyþy¢.]¼ÓQZÊüþý<À×¥¤¤„–/_Nÿûß©cÇŽ”@‡2ONN¦7Ñ… (%%Ŧ5N W???*--uZ»Ò€t:ÍñÐÐPR©T6ûT*…††º¥[¬WAdêÔ©A/½ô-_¾œŠ‹‹ú=""‚d2Éd2’J¥$‘HI¥R·ìw•®Øt¬+qÎöYÿ.++«ç·°°0»òbìpÄš5kèþûï'"¢+W®B¡¨—gà=_P`äãT9u:ÈÉP[ëÝØók×$hÖL†š#ôzÏ{²›ß¬=·åúu š6õÞ–ÒRBB¼õ —Ë¡ÕzgË„Øò%<<ãÆÃ¸qã«V­Âĉñûï¿Þ~ûm,X°Ã† ÃòåËñÊ+¯Ô¹owCòóóqï»îʤô°#†Ýž`ª3ôüùó1jÔ(ìØ±›7oÆo¼éÓ§cÊ”)vϯ¨¨@aa!¢££½²ßUºbÓ±×Ï !*k‡³ô­ÿ œ:u íÛ·o´çÈ£qð‡"==G5@­V¢¢¢T*)ÒÓx¬gõê{Õ\DYY©‡Ú¤¸ví!H¥ä•-›6%¢iÓp9rrù+äç?¥Òè•-ûöÅ"))YY¹Ðë¯Þ÷”§ãà dÄÓÒÒ0uêTdgg###Ó§OwK_‡™™‰#F4èõÝ{ï½Ø¿?†nÓ«]»v ®'<<ׯ_GTT”y߯¿þj÷Z;tèÈËËCÇŽøäädlܸ“'OöÚÎÒmÈtêràÀ :ÔÆoŽ‚­'vÐÍan-[¶ÄÒ¥Kѯ_?Œ;IIIøðÃo̓ä¬y_SSCjµÚ¼0 ŒjkkÍ[uu-étµ6ûøvwlûöé)5ÕH‡×Òc=Òqýz-M›f Q£Œ´`¶o×{¤gï^=õïo¤;ô4dˆg¶¨TµôÏhÈ#-]ª§ÿüÇ3[¬^­÷Ø/M-}ö™ 0Ò_è‡ôwÍ}URRâò}¯^½hÍš5tõêUª­­¥sçÎѨQ£hüøñ6r‹-¢¤¤$š={¶¨× Öû333©yóæ´uëV‡ì\é°'³~ýzЧÌÌL›N^îvŽ£gÔ¨Q4zôh***¢ŠŠ Ú³gµk×ÎFÏ AƒhçÎTQQAZ­–/^L;wvèûÝ»wSXX-[¶ŒJJJ¨¢¢‚vïÞMƒvË~WézšŽ«}Ž:ÙmÛ¶Í®¼;ì÷åÉ#…BA•••DDG{DôÜýS¿Á÷맦‚¢åËYǪæÍ‰V®äß¡ïL&¢Ý»‰žx‚èµ×ˆ®_gûÝýî]\L4}:Ñ£²Îl&Ñ—_º÷ÝÛhd¶ JôÖ[DW¯²ýC‡ºgKI ÑüùDýú­_Ïô®[Gôý÷îùåàAÖáo#:M»ëµšè³Ïˆúô!úÏX/zwm¹¾ÁgddÐOWzJJJhìØ±IJ¥’|ðAúñÇmôlݺ•zõêE¾¾¾AO>ù$]¼xÑiíÝ»—RSS) €üüü(55•vïÞí–ýbÒõ$1ÞÚo 6ùjO‡+;ìñý÷ßÓ#0j”³·@I »þ€ %ÅÙëZ  8|ض xúiçצ×g·›6ï¿tïîX¾¦øýwààA`óf`ÉÀÎ0Ëz׸?³ççŸûD­NžöìaitïÎòÛê­† c¶:¢¶¸x‘¿c«>iЧe±šdûŸyƱÏKKÓ§Ý»_~a~Ÿ<Ù=[ôz–¿üÂl©®ž{<Ø2áÎÎÀ¯¾êXOY“dd0_>ôðòË@\œEfèP–'Ž0€ÂBvonßήoÌ`ÄËxþôtfïË/ߟ}„²ÆÙLvbÙ²e Ö®]‹+Vðïiœ» |݇îÌV86mj[[÷1P*¶mY@.*²ü£®Àƒ™™l•º+r ¿%–æ}÷«V±ßŽd !U,‚ƒë§-üöóÚ·g•ÎrÂqësÂÃN€µk°0DzR)+ô~ˆþñ[Õë!Œ€àÃÈHÇ>óña~èÒ…­aþõ×–k´wŽ¿?pÿý@×®,Ч§³ëv$È*P={@r²ýIm^~™Ýguíþ—Ë-˜-}ûÍšÕב›Ëîë›ýaêÝÓ&;Ö¦ л7Ë[{°½û.«ØÓAÄ|Ïî£~ýl+ÇŽ± •p[_OÝ<³·‚]]Ô•mÀþH.> ŠKK¯×`ûvï|qq1ˆmÛ¶!66–—øà·âÔ Aaa!Ÿ‹žÃá4j >..ååå®[S[¸I$Àš5kðØcq§rî:äîkµZ@œ½&‡Ãá40Z­ÖãO|oÁ‹ L&Š‹‹Ø c 9§npÖjµˆ‰‰i´±àð‡s›òÏþÙÙÙØ²e àçŸÆ«¯¾ŠË—/ßQ-xgK“Þ‰KÒZÛìè7Ç}Œ””L:Õû_w&;“É•J…ððpÞ‚çp8j ¾²²-[¶Dvv6Z·n HJJÂþótëÖíŽ ˆ<Àß^×}«Örß¾};,X€ììlDFFbĈ˜;w.Ì2gÏžEJJ DͲètÝÌ™3E­†Ã7¾ño±9[ˆdÅŠ4lØ0›}R©´ÞäwΊb4Ф'·Ãµ¹s-·ËuïÛ·š5kFDD•••¤T*)77×îÄK™™™ÛÝ¿JOO'­VKÅÅÅôÌ3ÏÐóÏ?_OîÑG¥U«Vy?¾n ^­V#>>yyy äÍ Ž™ˆ/6àé§=¯q @³f ””x·ÎAÿþ2ôéCxï=“××ä­-/¿Ìæèÿö[ãŸnË„V«EBB‚Ó^ôO?ý4† †1cƘ[|ußlÝï àÒ¥KˆÇ»ï¾‹^xÁ¦¥¸hÑ",Z´EEE0™LH$X¼x1,X€¢¢"ÜsÏ=øê«¯pþüyÌ™3—/_Fçα|ùr$$$˜umÚ´ 3gÎDNNš7oŽçž{S§N…Üjâï¿ÿsçÎEaa!Z´h·ß~“'OvÚ‚_²d >þøc ..Ó§OÇ„ pöìYôíÛ/^„ùœŠŠ $&&âìÙ³æyÏ­qå“óçÏãwÞÁÁƒ¡V«Ñ¾}{üãÿÀÈ‘#m®uöìÙøý÷ßÑ´iS̘1'NÝ‚?wîÞÿ}dffÂ`0 oß¾øúë¯a÷ ±7ù)æz1gΜ>}«W¯ÆîÝ»ñÜsÏ¡°°°Ñß<¨T*´nÝ¥¥¶Óv/[¶ ;wîÄÊ•+½kÁ{ºÂçîÃLJèóϽÓQSÃVMó–Ga«¸yßòð^ÇóÏ3{n[þj3Ù%$$Ðùóç¶úÄ®—^w½vx°Æ¸˜5÷oßN-[¶¬7Eª«¼³µË]­{ooš\W>qµNû–-[(::š6oÞìr _G¿;tè@{ö졪ª**//§¿ÿýï4iÒ$—Süz’Ÿî®w;¬å~öìYJLL¬·ÿܹs”””ÔxSÕòÏ©Kx8Ñ?ÿéŽÊʆ dýû³5á"¨Z-/NÔ®]ÃØbgåÍ»:ÀûùùÕ›–¶ná*v½ôºëµÃƒ5ÆÅ¬ž’’bwrWÞÙÚå®Ö½¯‹Ÿ¸Z§½k×®ôÓO?¹ýZÞÙuªÕjŠu*ëi~º»Þ½ÀŸ¹–ûÈ‘#iîܹõöWTTŸŸðœ[GË–Dï¿ïm¡Þ0lÄ¢&¨–”x§cút¢¸¸†±¥¦†xk|}}]x±ë¥×]¯¬1.fÍð°°0»ë» ð®Ö.w¶î}]ÄøÄÕ:í~~~TZZêU€ÏÏϧ'Ÿ|’"##Í-b™Læ4PzšŸî®w/ðg­åþÉ'ŸÐ€H¯×{àùSNƒàïÏæ·÷ãÍÏÔ®jc‹·:4šÛǽžßgÖDGG£¸¸¸AtÙ[¯ÝÝ5Æ…5à ŒF#L&ˆF£±Þwä†FX÷€ÝuïÝeþüùÈÈÈ@RR6oÞŒû|ò‰ù¸¨Ü.˜0aÚ´iƒ'N@¯×£ººÚÆW ™Ÿ®®Ç^>K$Œ9§N‚D"Att4ôz= ‘Hðûï¿7J^.\¸ëׯdž lún‹^—žxNƒ •²¹Ù"À{ÈÂ뎷‹-<ÀÛÒ¹sgú(Þ|óMtëÖ D„íÛ·›ç€™3gb̘1ðóóCJJ ®^½ŠÙ³g»µb_›6mðÍ7ßॗ^BNN&Ožls<>>»wïFÿþýÍs!xšŸ®®Çùùù(..6Ï©°oß><ÿüó^Ý#ÎzØïÞ½ÿþ÷¿±cǧ£ÔÖ­[‡Ñ£G{àçÏŸo·–³sçN‡µ ÎÝIEEoäç—"=ý”Ç:T*_±cÇ„…Õx¬§¨èA¨THO?àÅÛ €aÈÌÌB~¾çïéÏœi £1 ééÛ½ôðpìØ±áá5wÅýT%â»Æˆ#ðæ›oâܹshÓ¦]™'žx×®]äI“PPP€-Zàƒ>ÀСCÜæ¾}ûbýúõ˜5k^yå˜L&<òÈ#˜6mšM ùàƒ0a¡E‹xÿý÷ë·ºL:'N4“›9s& d#3iÒ$̘1/¾ø¢S]b|òꫯbÞ¼y8|ø0š4i‚””¬]»Ö|¼wïÞøüóÏ1mÚ4œ9s111˜>}º[þúöÛo1iÒ$L:Íš53o àå—_Æ¥K—`4ADç§«ë±ÇÞ½{‘œœ äååáÚµkxä‘Gœﺿ­ƒùÁƒÑÝÉšßiiiP«Õ µÙ_VV†›ËkþñÇ8rä~úé'q "ñãà…žJJJøjr:u’#%Å„O?õ¼_X$%)pþ¼ññžÛ2y² §NzÞ‚×é€À@Ò£S'Ïm™7OН¾’âÒ%ïZðJ¥çÎéѲåÝq?i4DDD¸\.vþüùÈÊÊ2·ïføº÷·7}úôÁôéÓ‘ššê±ŽÇ{ ={ö=U­Ó¼Íä æ—… ö¾æÜµ(•€É$ƒB!óX‡eFR¼¹½„õá Ï»˜oˆ‰¼³E°§ažïm¹Së¯÷Þ{?|`¯Þ{ï=lÛ¶;ã6eÏž=^ëp·"+÷$‘ÚZžYœ:7’ÜûN`ÂË"o;¶™L– ÿgÛ¢ÓvêÈ^U:8k¬×½åáxà‹‹ˆî<Žu‹«a‚aC2޽Qø«ØÒP£ 8Mˆ¯ÎÆq€Gï0hè)ç/àªßz|}ÿz¶ð7g§Ñ|Qwǹ¼aZðÞë©­m˜|CØÒo¬ú»r8ŽërÙyÁb|a¡‘ƒçØ “É Óy7öüÆ "#e¨®6B¯÷üµ£^/ƒTz{ØRZ*Cp°w¶\¿H$rhµÞÙr'Á˧‘¼£qð"=={¨ª’C­î•J‚ôô#ëùé§6ˆŠ AVÖ”••z¤Ã`àÚµ.ÉÈ+[¶oo‰ÈÈ(9R¹üŠG:ˆ€üü®P(Œ^Ù’„„6ÈÊúµµWï’{ªŠ?XŽ—x4~À€2lÙÀ½ÇÁÙ³À»ïÊðöÛ&,Z$ņ î·Tu:à»ï¤ØµK‚ž= <@èÓ‡<²eútÆŒ1aùr)Ö¯w߃X¹R‚Õ«¥HK3! 9Ò}[òó?”¡W/6mòÌ/&°~½_-Űa„¦M O=uw´àÅŽƒçp8¶àƒ7™¤ÐëØ¿ض ظøäà‰'¸Cï~ûå¹^|ñ˜(Å'Ÿ¸7ö¼¢X¶ ذ˜0ýýæÖkÜñÞ§N °¡q}´i#ÅŠîÙRS¬\ üððôÓÀ–-ÀæÍRTVºgKn.³E«¦Nx@ŠÍ›Ý³E¯þû_`éR`ð``ëV =nÛr'ÃçÙàp9À;bÔ(àÙgž=É“‚çç±Þ÷§NXOjb¿å’“¨ÕÀÍi€R] ?4m ´jå\¶¤8v èÑNçô&.^d­°¾}]Æ¿ýÆ:™=ð€«V pô(°};ðè£@Ÿ>Îå¯\b¨W_’“Û\X<lÞ ÌŸ´háÜÇyy0WÒ¾ýp2ý1ŒF¼öìa§eKà½÷3„:D¥b6nÝÊì}öY`Çæ?€Ù Õºneçæ»w3ÛéÓSKÛÍ_~aÁó?X`ß¾ÝÒ).0¸v͹£‘ù1#ƒ]SÓ¦,¯:t°È8Y€Ì¦²sô(»ž'€áÃM›ØjtàçÇî_‡Ã‹ÓWôõ D ‚ƒƒë½6;y’µÀYà ²¬ %h'bbXÐ2™ØÐ!ƒÁrÜZî¹ÈÊââX!jÝ›ÙZN©d²[¶°¿ƒeÜp]ÙHòòØ8~ƒÁv¥/k[[¶~ÿÉÙÚj­S&Ú·g…ñ=÷8·5 xè! >˜7HJbò‚½‰mM›2ù&M€Ï?·øÂÑŠŠ±±@—.¬b´aή¯n^$$]»²J×ñã,˜LÞÚÁ¶Ö­Yåhà@Kà±æ±Ç˜?$¶ ÷‚ ‹ c×4hý€|àðÖ[@t´e%6kŸ±}ìÛ2jkñJ¥,}ƒÁh}Ì–€ûãÌ`Ìæw©Ôö¾*I2«Hõî ôëØ{›>yyyt6hšã”¦Måø÷¿HK÷u$"BÂB=üü Z¾¤Dü\ÞîÊs8V«EBBïEÏá4V ÞÑLvaaa|lª(l¸Sx¸øsˆÜ“ 7¤K¨Þ¹£›Ãiüg„ÍdÇ?r8žÃ?ný „„eeî£R¹'¯V‹“3y~p8ðœÁÇÇ2a‰X«B LrRSÃó…Ãápx€çÜr\ÍÏ0­®»ú9‡sx¾†{xòYQ¯oyAŽ¿ªçp8œ¿nƒ×h47ƒ‚z«©€V«‡þxn7MÐëM"娩1@¯§—¯®fòÕÕz·+Nc¡ç7#‡Ó¸ÞÑ8ø;wÂßf ¯áøé§= ãrÅPUÕ.\FzúY‘g DZc'pY´ü‡PVVêRR¥ò0»ve¢iÓjž9œÛä©âNàp¼Ä­qðqqq¸q£ÁÁ–arJ¥ÿûŸ÷ßÏ*†6mä9Ò„9sĵà•J–.5`Ü8×-r£ðóS`Û6úöu-_P´n­@NŽIIÕs!À‹ À Tò<‡Ãáðïe€¿t hÝšøÆ ðDî½¢×ë__÷ä•Jà9篆Gãà¯]3šÇ©îØ!E—.TU‘ãºïnd2t:@¯w=»LE*GM¸qó7nQQrÔÔEƒ/)‘ "B&ZžÃ¹Ü)ãà% œ DâÜÁùöWÈ[ÆÁggbóæ<¬]{T*_¤¤\Æo¿…!==—ß9.Ð館­}/‘ž~Ì¥üÅ‹Á¾99墯Í;…&M’püx1"# \ÊoßÞÁÁ±ÈÊÊAyy)Ï Îm˜qð:‹-Â?ü€üü|øøø %%¯¾ú*úöíËȹÊ}BBBpâÄ ´mÛ=zôÀ„ 0iÒ$«²x;,X€ììlDFFbĈ˜;w.<¯Èx2þ¡‡Êдi† 3aÂÂñãÀ–-R̘ẅùúëR|ô‘Éå¬wÀ;ïÈðå—®[¹™™\¸Lšäº¶õH1y² ‰‰ÎåŒF`üx~øÁuúçÏK—JñÿþŸëëÿþ{ ôz ¶m“`Ã׺ßxCŠ œ?/Á¼yÎõÏ>+C¯^“ xùeçò0dˆ ))„®] ©©¼%¹=3~ܸq¨­­ÅÌ™3‘˜˜FƒÌÌL,^¼{÷îå-xÎmÓ‚ß¿?Fމ+W® ªª ¡¡¡8}ú4Zµje–0`¦L™‚ž={B«ÕâÍ7ß„¿¿?¾ýö[Ï&7P«Õ€6nTÓéÓ–ý§NMêü\“‰höl"€¨¸ØU:DÆ…„¸¶é÷߉"#‰^xÁµìwß±ô÷ís.W[K4i“uEQQ·nD:¹–ݽ›]Wm-ÑС®ýõÙgDo¾Itþ<Ñë¯;—7‰ÞŸèã‰öî%Z°À¹|M ÑøñD+W}ñÑŽÄáÜ6eZ­v(ãççGeeevåääPLL ÕÔÔØì×jµI¥¥¥€~üñGêØ±#ùøøPTT3†JJJlÎÙ¸q#%''“ÅÇÇÓÒ¥KÍÇÄè@‹-¢ØØX’H$æýK–,¡¤¤$R(”””D_ýµMºbí£ÇÖûssséñǧÈÈHR*•Ô©S'Z½zµÓ<Ú¸q#=øàƒäããC‰‰‰4gÎÒëõnÙ/&]1é,^¼˜H©TÒý÷ßOÙÙÙ´bÅ jݺ5ùùùQÏž=éâÅ‹6ç,Y²„ZµjE …‚éûï¿wê7Wv8cöìÙ4räH""ÚµkÅÆÆº<§´´”¼zŽÐݹsDS¦8$[· BôÿGôÆD¹¹öeKJˆ¾ü’¨O¢_~qM&¢Ó§Y¥â‰'˜ìk¯9Öû÷=õÑŒ,hnßn_V£!úñG¢¾}‰þû_f³Éd_öÒ%¢ùó‰ :{–É:²õøq¢É“‰&N$ª¨`û]›NG´kÑðáL¿ÑÈ*DŽ*0Z-³uà@"á¹>r„hÖ,Ç׸r%óñÖ­BaùÍáÜ)>!!<èðø!Cl‚1«äG'N4àíÚµ£ŒŒ ÒjµTTTD£G¦Q£F™å·lÙBÑÑÑ´yófÒjµ”››KcÇŽµ ®t ÔÔT*((0ï[¿~=ÅÆÆRFFi4ÊÈÈ ØØXÚ´i“[ºÅêqà;uêD .$•JE:Ž>LO>ù¤CßfeeQ‡(++‹*++)77— @óæÍsË~WéŠM§gÏž”““CZ­–Þ}÷] ¡””›}C¬ iÔ¢E Ú»w/iµZÊÌ̤øøxÚaÕÒ±ö;êrâÄ àrsÄÙ³g)11Ñ«çÈé+z{¯Í‚ƒƒë½6»qè×xà63ZEëm2±ÚÝ»cÆM› @t4[褲Ҳ’YP0dðÔS¬§ù£Íš1••L^˜©-)‰Éuï”—ݺ±ßµµlmóšöÊZ"’“ €-€ €E‹€6m˜¾êjöªšðóci¦¥1[&Nd£||€ª*fƒÉÄd›5ž~š]·LtìÈ6"[[% }{`Ô(æ~ý€æÍYÚ:e‚L<ü0³7:ZøÉt?ü0û_«µôz÷ñúöe¾ˆˆ`û €Aƒ€.]˜ B~,íÑ£&M˜üªUÀ÷ß-[2y£Ñâg€ý®­e›0 O¡`6 vøú²M&c›Tʶêjf¿NÇö0=:³Çh‚ƒ™œÑÈþ&%±sF¶ w¨Á`¹vƒ e×%äum­ÅÖ×!üvôYC§˜®ÚZ¶¿¦ˆŒ´Øh0ØÚ"œëïÏò¸ºšý_]Ít™LL‡`wR;.Ø.è4XºÂhaÈ©`¯ŸÛW÷z„ `çùøXô ç*•¿ÖÖ²üñócù°cáá–{PØa±IÐbѥ׳ô¢£Ùµ ÏD]Ûû„ûÁú¾¨©a÷¥NÇlòõe×)—39“Iƒ¯¿vúŠþçŸÆ /¼€ÔÔTôèÑ=ôºté›*ûöíÃäÉ“qæÌHnNÙØ»wo|öÙgxà ‘HpüøqtìØÑ¬óúõëh×®JnêÖ­Þ|óM¤¥¥9|ëJ‡D"ÁÉ“'Ñ¡C³L÷îÝñÎ;ïàñÇ7ïÛ°a.\ˆ¬¬,ѺÅê±WÌ[ï ™3g+*ôïßóçÏGçÎÍû._¾ŒÔÔT俿жßUºbÓÉÉÉAÛ¶meee «·/11eeeæs6mÚ„¡C‡ÚÜOŸ~ú©ùó޵ÄØáµZÈÈHœ?ñññHNNÆ[o½…Ñ£G;=ï™gžÁý÷ßiÓ¦5Î7x{††„„ °°°ÞCW[Ë›D}c'ÊÊXAáëË H™Ìñ7b†þþ¬ p´Ôju5+0 –¶+Hì_‡e8™ŸŸãôM&Vy0-é;Ò©Ó±ô&ëëë|YXáÚärf«Ré\^ð/À³«™>L‡Lf)ü}|˜ýBzB`²F¾¾–ôM&v Ö׫׳ó„Þh®^e:…ÂÞ2.h«K©´è2Yð’H,×aTù×dbç º„}••ìÁA—µß„Ê…¯/;FÄtÉdì:%–Ïååì¸u³þ-T˜L&vžpO •JG×#‘0ôzö[Ð+Tx¬ïo¡B&ÜÇ‚­ …íu×õ…ÁÀÒ°ÖU]Ížc!_„´»¬ýmð­ï‹&MXBÐd²TzÔj ºvCyy9‚ƒƒÞ»¥¥¥Øºu+Ž=Šƒ¢¼¼«V­ÂÃ7kÃ;wÆŒ30lØ0\¼xÏ=÷öíÛg.ÀF#¤ujë‚Ýßß—/_FXX˜ÃïJ‡D"N§ƒRp(€°°0\¸p¡¡¡æ}eeeHJJ‚J¥­[¬Wþ½÷ÞÃÒ¥K1bÄtëÖ ýû÷G´Ð°Cdd¤9XÞ| "‚T*…ñf SŒý®Ò›ŽÉd2Wâœí³Î“²²2„„„Øø­U«V(½9“›µ¼;±víZÌ;¿ýö®^½Šøøx\»vÍ&Ïêòé§ŸbÛ¶mغu+ärù­ù_XX(ê•ßøÆ7¾5ÄVXXèÖ+É•+WÒ}÷ÝgþÕªUÔ£G""š1c­Y³Æ­W×aaaTZZêø§ödBCCI¥RÙìS©Tê–nOõÆzûOž}º[ú:tè€ÌÌLŒ1¢A¯ïÞ{ïÅþýû1|øpó¾}ûö¡]»v ®'<<ׯ_GTT”y߯¿þj÷Z…ÏyyyèØ±#¦L™b7Ýäädlܸ“'OöÚÎÒmÈtêràÀ›WôûöíCûöíìz…ÖË–-±téRôë×cÇŽERR>üðC»ç¬X±ëÖ­³³$û-hÁs8ÎíB¯^½hÍš5tõêUª­­¥sçÎѨQ£hüøñ6r‹-¢¤¤$š={¶Û-ÌÌÌLjÞ¼9mݺÕa';OZðëׯ§øøxÊÌÌ´éäånç81zFE£G¦¢¢"ª¨¨ ={öP»vílô 4ˆvîÜI¤ÕjiñâÅÔ¹sg‡¾ß½{7………Ѳe˨¤¤„***h÷îÝ4xð`·ìw•®§éˆiÁÛëd·mÛ6»òbì°G^^) sk<..ŽöìÙcWv×®]Ô¥K‡#C¼“]Ýqð&“ *• ááá¼ÏápnI ^ê ãËž={ðÅ_`ïÞ½¨©©All,ÒÒÒðÁØ´~=çÏŸGÓ¦Mí~“uôÖ¯_9sæàÌ™3ˆ‰‰ÁôéÓñüóÏ‹ÖáHfÉ’%øøãQPP€-ZàÝwßÅ /¼à¶}®ô”––bÊ”)ؾ};Ôj5Úµk‡wÞyÏ>û¬YOzz:>úè#>|Mš4AJJ >þøc$$$8Ì£}ûöaÖ¬Y8räL&yäL›6Í<ÉûŤëI:®öI$|ùå—f¿ÅÅÅáƒ>0ç«=®ì°Ç²eËðÕW_á—_~A^^Ú¶m‹òòrøùùÕ“ Úβ¬uû ¸ƒÓÿá‡ÚÉŽÃápn………¢{v;bË–-X»v-V¬XÁʹ«p«¯V«¼¼<rïyHl¬ŸnÄ“OŠÀ¡@q±Vp]Ê—”ˆŸËÛ]y§±ÑjµHHHpÙ‹ÞÅÅÅ8p ¶mÛæuEùÓpÚÉÎÇÇ>vÆ»………9›ÊQ«’XÆ ‹ÅdrO>4Ôñ>k„ê;º9œÆFqs\§7Ÿ% °fÍÜ9<Àsn ¡¡lܹ;”•±‰qĢѰÉI\a4òüàü5!>G<ç.GÊ]pëñdýuaR±ˆ­@vX}‰áp8ðÏ[îÉÛé\é²/aÙm­–ç ‡Ãáð_“‰;Ò„)`ÝA¯oy¡ïî‡ÃáÜÞ8ýoo=x<ôÐ[E¥RµZ;Cû8Ün4š ×‹­)P]m€^O ._]-ÈëÝ®Dp8…žßŒNãøùóçÛ_½áX¹r/¢£«¸GEPUÕ.!==GäÃqìØ¯(-àÀ!”••º”T©| ÄîÝ™ˆŠªæ™Ã¹Mž^–p8ÞâÖ8xFƒ¸¸8”””Ø “S*8tHN¸CÅж­#F˜0ož¸¼R©ÀÒ¥ŒçºEÎVêR`ûvúôq-éЪ•99z$%ñ¼áÜh4DDD8].–ÃáxÑ‚w4^¯W˜Ç© TT(\.aʹY«’‰ …Lô9DrQþêcbå-K±òüãÜ>(øÍÈáxGìJJêïsw×Ý]x¹×iNXƒ] Bg9±ò‚ïdÇáp8<ÀãÆúûø'³Æ ðîÈ»ày/z‡ÃáÞLi©m P&ã¥4v€€õzÏ*<Às8ð6¯è¯_bcy€w¹\|&rO^¯üüܯðÏáp8±Xãì £qð×®ÍãT33%xè!)ª«ÉqÝw{€—A§ôz×ÁWT¡¡rÔÔˆ7_RDDÈQSc5^¥’ ,LÎèÆ8{§qáãà9œFðŽÆÁgg_ÂÖ­ùع³NœˆÂÀùøí·¤§çrºÀ` ºúaäåž~Ì¥|~~ïCNŽ é鸔?v, I8~¼.å32âÜYYgD›çpn|<‡ã=ƒè¡2´i„{ï%¼ý¶ ¿þ lÙ"ÅŒ®[˜ÿþ·/¾hr9$«ºXµJ‚çŸwݪ<~ÈÏ—ˆZ_}éR &ÄÄ8—#¦O—bî\××T\ lÞ,ÅK/¹–ݰA‚‹%ÈÊ’`Ã×-øiÓ¤ˆ‰®\([ž^†Nr90y²Éå5>þ¸ >HèÝ›šÊ[ðœÛ>žÃiä¼£qð¯¼"E›6Rtí 2°o¸®Æuõ0e ðÌ324kæXN§&O.^^zÉù=ƶ‘#ËîÜ üíoÀ¾}@‹ŽåL&`êT`Áà_ÿr~MeeÀ¸q¬/Âßÿ.sYùæ`ãF ;P(œwøñGÖ¡ñ…€/¿tî_"à“O€–-Nœp.o2ï¼ jYK€=æÜ.ðqðŽ÷xÔÉî‰'p3¸ Ç숀cÇ€Q£€Ë—×^*+öŸfÁúÙg¨(Ç6”” “&+W²5Ö‘“ÃûºuÀG55öåŒF`ÏôZ·† q¼(ŒV ,[ŒÁìhÝÚy%dæLàŸÿV¯lfùµã¯_e•†“'%K€€Ç>3™€C‡€§žb×5{¶syƒض]Û}÷/¿ÌFAðNv‡ó×Âé+úºh4×{mvõ* Ê}úX‚ŸZÍþíÛ'mÚsçgÏqq, UT°¥M++Y IMž{úö:wf³­UU1•Šõü ÒÒ€Çg­èÞ½YÐ2,²¥¥,ý„`üx¦kõjà‡€ûïjkYúZ­eyÕ.]ØÛƒ¨(`ôh Y3V©ªb²j5³Û×<˜UD||€€Ge¶jµz=Óõì³ìz„™ãRS™=F#«Øh4@y9û¿m[öæâž{˜lE“*••±û /°Ö;\¸À*ýû3} Û„Ïš½zcÇÂüeùr`Ë–?;Ç``•¹ÜR1°^5P.gúÊʘ}-Z‘‘€TÊl2™Øf4Ún Û_^Îì "",ùPY tìÈôçXWNÔj¶@óæÌ¿j5;_.g÷•RÉ~ËdLDÂÎÕéXž×ý[[Ëì7Ù§¡òrv ññL‡Pñ²®„¹ó[©Ù>"–Ž=ß,½Š æ×švï*•ž§mïéÖéØsTS$&²´++Ù=b4²ûH§³äI“&,ª«™\YDG3?›L¶y.\›õÿAA–¼0™Ø½S]ÍÒñóc›LfÉ7ƒAƒyó‚ù+zçVxµZÖ{è®_·œÀ@¶Xšu!—Ç f__Vx4ib¿U«Õ²ïÛ&+Xà·.ð¬+*+ üýÙ •º-ä‹YÁ¢T²´Øßº¶ÖÔ¬°ò÷·Øêë[?}•Šù€È¢3(È ëR^Îäe2VAhÒ„][]nÜ`çH$L·¿?ÓïHþêUæ?©”ɲtìÉ @n.ó³PÈJ¥– +tÁ—Bò÷·äGa¡%0J$–à*“Y~ Á_*eç±71••ìš„ xîœ%M™Ìb³LÆd‚‚˜Í¥¥ì³BPóŸFÃòÁ`°lBðQ(˜ÂæãcÙg4²¼îÀ@–÷¥¥¶•kß¹ó[–lŠb[ŸXÿÞ"2ÿ¬ïEÝ·+žÚa]á a~¹v¥À¶ÚZ–'¾¾–}*»—„û. €=—*•¥Ò&äoݼ®Y£±Tp¤R¦Ç×—åCu5ó·ueG£Ñ`èÐ8”——#Xp‡Ãq ¹;ÂZ­Ç=Çáp­VË<‡s+Zð&“ ÅÅÅ „ÄQÓ‘Ãáp¼„ˆ Õj©TÊÂá4v€çp8‡sgàÖ+zÞ‚çp8¼Ïáü|݉nŠŠŠÐ®];î5‡sK(,,Dll,w‡ÓÐÞÑTµK—.…¿³ÁÜç/ÍtC×®WðØcy¢¿ªª “&MB`` w6‡ã!MU[RRâñØÔiÓ¤˜7Ïõ”«¹¹À'ŸH±x±kÙo¾‘¢sg:vtþÀ2lßn„«/ &ðÜs2,_näw ‡S‡ÎåèÚÕ„ÿû?×Ïçk¯Iñùç®åt:`ÂV­2ò©j9œÆðuq4Ñ[ JÏgÍž=lb1²!!À´ilêU1éWT°±¼Î¨®fcuŤ?r$Эðúëü†âÜôíË&6Z½ZÜ3W[ëz*äòr6#%QÔ5ÎÝÎ-í½"L"&h6i"^oh(+Ärã†k™ÚZñúNŸf“çp8w 2™í$@®P©\Ëðb9œ;8À ³¢‰Y ÒÂ#8˜MŸ)–R«¢ºàårÛ)U9œ»wØ6ô3Çápn³/L¹Y]ݰ»RéÞb)bt»“>_¬…s·!öS›€£žx žÃù‹µàÅ<ÈîXaŽs±4tú¼ÏáþÖ>sGDlrvÐ^/zö°ê¡÷ ºÍjñ TUé]>ðÕÕr‘éÈ`0z½˜(«@uµz½óÒ‰-·ª•¾L&Cm­Øô9œ¿2˜L÷ÌéysžÃiÜïhüÎ;=¯Õ* Æ®]{íüCüáÃÍ<Œôôt—zÕê¸t©éé'DX1EMÍu§Rú`ëÖt—CêÔêî¸t©ééÇùŹ+¸qã(•F¤§õÌ8pju‰S© ‚ôFzz:ªÄtÔáp8Nñhü•+%gCWJJ€ðp@Ì̵7nÍ›+ðÛoz´më\vÝ: F–£¶ÖuM>5U†„à»ï\·&”Jþû_†uÞš8qxøaö¶AîbBßþýeˆŽV¬à-xÎÝÁðá2(Àºuâž¹-[ 0€\Tê%èÙ“=ó|<‡ÓÈ-xøøøÔÛ_S£€âæ Ö˜àäI Cµ s%@árL¬Ð‹^áJ¬“[ó[\—"¹èôÅØ*—»—>‡s§#¬ÿÞÏœTªõÜs8Ï©''ÝüoæÊqç ŸÕÄ|^sçœDâÞ°:1º…bd ÞAˆs÷!¦“ ãN';þùÃù¼VkûðŠ ðÂP1Á°¦†µ1ˆ0”OŒl` Å'ÎÝ€Ø^ôîTê…òxç6ð%%@Rpõª¸óª«Ù˜u1pe¥øÙìÄꬭe•±^.'+—óqðœ»/À‹ykæÎsTY)^–ÃለMÎ:&wù²z½6HðÔSz½ë§]­– 8X†êj£Ë!3jµRèõ®#§\.ƒNçzÈNY"GMÉ¥½jµ!!2TU\8z½  &ǹ{0™d ÷ÌËQSãú™×h,ÏœŸßå% ȉ8wL¾ÝÉyëÑ0¹uë.¡  Û··ÄoÇ’%žþ?—‰íÛ‹ðð–ÈÎþÕÕÎ'„ÏÊꈠ &غõ€Ëú7n< ‰„ž~ĩ܅ ÁˆŒì€'.#=Ýù2—­ƒ]»Ž¢Y3çCvòóÅ¥ÏáüU¸~½ ˆ$HO?ìTîÌ™0DD܇ãÇ/!"¢À©ì®]m‰;ŽÂß_%ÚN‡E‹á‡~@~~>|||’’‚W_}}ûöå™Å¹mÐét Á‰'жm[ôèÑ&LÀ¤I“Ì2{÷îÅ_|ÌÌLÔÔÔ 66#FŒÀ»ï¾‹àà`÷*0ž “{ðÁ2tîˆO>1ÁÇxüq~þÙuëuâDš6%tëF2Äq¨¶– à ~üÑè´÷íÿþ'ÁêÕäæJ\Úð¯IQV4m L™â¸O *C«V„É“MN‡ô]½ L™"CM °aoÁsîžxÄ¥¿` IDATBÀõ=?c†Dl´ÍË/;æ† ‘¡eKÂ[o™!~˜Ü¸qãP[[‹™3g"11™™™X¼x1öîÝË[ðœÛ¦¿ÿ~Œ9W®\AUUBCCqúôi´jÕÊ,Ó½{w¼øâ‹èׯ¢¢¢PTT„ýë_8wî222ÜKÜ@­V*/WÛìOJ"ÊÍu~îêÕDÿ;ÑòåDk×:–3‰^|‘è¿ÿ%=šH£q,[RBÔ§ÑåËDC‡:O?+‹høp¢ƒ‰æÎu,g2Í›G´p!ÑôéD'N8–­¨`éž8á:}ç¯Ä!®ïùÌL¢§Ÿf,pþÌÍšEôïMJôûï–²F­V»´ÅÏÏÊÊÊìËÉÉ¡˜˜ª©©±Ù¯Õj)22’JKK ýøãÔ±cGòññ¡¨¨(3f •””Øœ³qãFJNN&Ч¥K—š‰Ñ€-ZD±±±$‘HÌû—,YBIII¤P(())‰¾þúk›tÅÚ'F=¬÷çææÒã?N‘‘‘¤T*©S§N´zõj§þ߸q#=øàƒäããC‰‰‰4gÎÒëõnÙ/&]1é,^¼˜H©TÒý÷ßOÙÙÙ´bÅ jݺ5ùùùQÏž=éâÅ‹6ç,Y²„ZµjE …‚éûï¿wê7Wv8cöìÙ4räH""ÚµkÅÆÆŠ:¯¬¬ŒüüüÜ~N= ðuºwÞaAÑyyDo¼Á‚¶^OôÓODË–Ù—ýßÿX¡!øwâD¢«WëËét¬’šJôë¯lŸ£ÂF¥"š3‡(-U~ý•hÚ4û²çÎ=û,«˜LDóç³ ½JÈ®]¬r‘‘á<}篆Éä<À_¿N4s&Ñ3ϰgîÈ¢Ù³íËž>mûÌÍšEtô¨{>!!Ú{PÍ•‘!6Á˜ˆè»ï¾£‰'š ðvíÚQFFiµZ***¢Ñ£GÓ¨Q£Ìò[¶l¡èèhÚ¼y3iµZÊÍÍ¥±cÇÚW:Pjj*˜÷­_¿žbcc)##ƒ4 eddPll,mÚ´É-Ýbõ¸ ð:u¢… ’J¥"NG‡¦'Ÿ|ÒIÃ)‹:tè@YYYTYYI¹¹¹4`ÀšgÄØï*]±éôìÙ“rrrH«ÕÒ»ï¾K!!!”’’b³oÈ!6ç´hÑ‚öîÝKZ­–233)>>žvìØa×?bì¨Ë‰'€ËÍ~ƒ×H—.]¢×^{ÒÒÒÜ~V¾¢¯‹F£Appp½×fyyÀøñÀ£²EWÊËÙ«ë²2 2xñE [7&»{7°p!Ыë5«Õ—.±qç÷ܼöв%“}ûmÖ;½iS&W^\¾ÌÒ0€éõóc²=zƒ3ùŠ –¾JÅŽ ÆzþO? <þ8K³¢‚í«¨ââ€×_î»é\²8xh׎×h€ÂB6œ§kWà•W€ˆ&Û«ðĬg±ÁÀlþìwi)píû‘’°ßÖÃ5v@«Vl–@¥Ò²±ŽMl3ps>p¦ãÆ ¦_.gþðña×X[ËöÕÖ²^ÍW®0?¶oÏl r¾ùû³óJJ€âb–ÑÑ,ÿ®]c[Û¶@TóqÝÍdb>«­eùQUÅ®óÊ6Ä01‘ít Æ®Õdbû+*l·ÊJfWûöLgy9;Ï`’“™Fv¾ðWø]Sc±³´”mj5Щó•F\¿nÉãˆËjBž ¶3Ûýü˜]EEìžè!–'Â}èïÏòÛ``i l4‡žZÍî«øx ,Œ]ßÕ«,?;wf¶VU±ãBžÖÔ°¿:ÓåïÏdÊË™®¨( ysÛ<ºç¶´re%³½¬ èÒ…ùFxfkjXšÕÕÌ®kרh–¤$v^i){^  4èÞù[­f~»v  ²” ›Ëþ6ŒÙ¨V³´4v¿ôËKøüsàøq !Aƒ? õŠþçŸÆ /¼€ÔÔTôèÑ=ôºté™Lv³ïÏ>Lž<gΜäf‡žÞ½{ã³Ï>Ã<‰D‚ãÇ£cÇŽV} ®£]»v()aÓëvëÖ o¾ù&ÒÒÒ¾Æu¥C"‘àäÉ“è`5+X÷îÝñÎ;ïàñÇ7ïÛ°a.\ˆ¬¬,ѺÅê±WÜ[ï ™3g+*&ôïßóçÏGçÎÍû._¾ŒÔÔT俿жßUºbÓÉÉÉAÛ›ßTËÊÊVo_bb"Ên®/.‘H°iÓ& :Ôæ~úôÓOÍŸw¬ý#ÆG¨ÕjDFFâüùóˆGrr2Þzë-Œ=Úá=%жm[+ ™¬£i«ÿøƒU"üü˜lD„ýa°Â3WZªÁˆq(//Õ±¨´´[·nÅÑ£GqðàA”——cÕªUxøá‡;wÆŒ30lØ0\¼xÏ=÷öíÛg.HF#¤u&Þ°.Øýýýqùòe‡¬‰:J¥Ò|<,, .\@¨UaYVV†¤¤$¨T*ѺÅêqàß{ï=,]º#FŒ@·nÝпDGG;ô{dd¤9XÞ|# "‚T*…ñfëFŒý®Ò›ŽÉd² ŒŽöYçIYYBBBlüÖªU+”––Ö“c‡#Ö®]‹¹sçâ·ß~ÃÕ«Wk×®ÙäYýçA?þøo¾ù&š5k†+V4Þ7øÂÂBQ¯øÆ7¾ñ­!¶ÂÂB>#¬\¹’î»ï>óÿ«V­¢=zÑŒ3hÍš5n½º £ÒÒRÇß:Eè°'J*•ªÎgE…††º¥ÛS=F£±Þþ“'OÒG}DiiiJ‹-rxݾ¾¾T\\ìü;°û]¥ëi:®ö¨×C¥RQXX˜]y1vØKÏÕvêÔ)§:Š‹‹)00Ðíç@îNe &&……… ´©q8NCBDÐjµˆ‰‰ñèüAƒá•W^1ÿŸ––†©S§";;˜>}º[ú:tè€ÌÌLŒ1¢A¯óÞ{ïÅþýû1|øpó¾}ûö¡]»v ®'<<ׯ_GTT”y߯¿þj÷Z…ÏyyyèØ±#¦L™b7Ýäädlܸ“'OöÚÎÒmÈtêràÀ›WôûöíC{á›Q\¯ÐúoÙ²%–.]Š~ýúaìØ±HJJ‡~(JGÝ7?Ò‚çp8œÛ^½zÑš5kèêÕ«T[[KçΣQ£FÑøñãmä-ZDIII4»N?1-ÌÌÌLjÞ¼9mݺÕa';OZðëׯ§øøxÊÌÌ´éäånç81zFE£G¦¢¢"ª¨¨ ={öP»vílô 4ˆvîÜI¤ÕjiñâÅÔ¹sg‡¾ß½{7………Ѳe˨¤¤„***h÷îÝ4xð`·ìw•®§éˆiÁÛëd·mÛ6»òbì°ßÙ< UVVQ\Üÿgïºã£*¶ÿw[6½Ih }H¥‰(EE}Ï÷ž *>å'ò XA}* €"VDÊÒ{#AzHÒ“ÝÍö2¿?NvïÞݻٻ)<}Î÷óÉ29÷Ü3çÌÌ™™{æLÛ¾}»$í=÷ÜÃvïÞÍL&3lÿþý¬ÿþìßÿþwãÙ¹Ýnò<ÇU[Á+C\J±}ûv|üñÇØ¹s§71Èý÷ßW_}Ñ>Á5~999HMM•ü&ì1¬Zµ o½õN:…–-[bÚ´i;v¬lÁh,X€9sæàâÅ‹hÓ¦ &OžŒ'žx"lùBñ)//Ç‹/¾ˆ7B¯×£k×®˜4iþùÏzùèt:Ìš5 ‡Bll,ˆ9sæ ]»vAõ¿k×.¼ñÆ8|ø0Ün7úöí‹©S§z“ É‘_Î{ëòžPe …óçÏ÷ê--- ¯¾úª×®Rœ4ºÏqppüμÇi; ÛÙ oEÑÐïW«ùàÄÁüÕìs2|Sm”Š¢§Îê€CN•œÅk`6;Bvx›M@-ë=n·ªæ–59#„‹ ñ~¢•ó~¥R»]îû98þ ‚Ë%¿Ï™ÍrúœÐçë2¾ppp„áàƒƒß´i3bbÂ?o0hd`Ë–hÞÜ\+mff+½¡ÓéBò--í‹ÅîRÜ}ûŽÀb)©•*;; À@Yï7nÆ¥Kèt¿òÅñ§@ii_DD¸ Ó‘Õçöî=ƒ¡öñ§N50:f³™+™ƒ£ž¨Ó9ø Êвe¼w¥+÷üwI кµÇ;pÍ5µÓ._®ÀرjØí¡gòǫФ °bEèÕDD„«V9q絯&P`Ð 5,GÈ€¿aÃThÑøê+¾‚çøs`Ô(´Zàûïåõ¹u뜸ýöÚûÜîÝ Üvõù†<ÏÁÁWðÐjµÐJxo³YMÍ%æÀ™3é°ßïäÉ;Õ¥h5¡k R¼ÆÔ²ß/GVÏýÞrßÏÁñG‡RI}¤!ûœÐ—5²û=G-ý´.ùŸ9/(÷œÝNÿÊù¼N}cÙ…¨ÑÈ£ãàø_AcÙñ¾ÄÁñ_tðUUâß‹Šä=ç9*#§[­ò·þÝnZQÈ™È}¿Å"Ÿ66–’Ýppp_w§NŸãààhä|y9в%P\,ßÁGD+ùÚ`611òøFDÈìvšÈlÔjy´ü˜wðÁûqcô9¾©¶?;&W^î„ÃáÀºu Üs……€Ã:ÓŒÁ @|¼ ‹+ä‘£Q‰èh%ŽÐ{õ*• Vkè#;UU@B‚Vkè÷ $$¨jŽ÷Ôþ~§SU“o›{yŽ?äM­ªåõ9£Qès‘‘ÜËsp4ªƒvLnóæ ÐëMøþûÎxæ™,¬Xq-tº£!_¶o_KÄÇw¾}§`6—† íØØèt{Cò--½  Óª•îâÅ8$$ôBVÖEètyµÒîÜÙññ­°eˤ¦Ö~d'/ï&(• :ÝaÞ¢8þ()éÆ!û\vvš4ù 23/¢Y³‹!ú\gÄÇ·À¦M‡UÁ•ÌÁQOÔé˜Üµ×Vá/‰Ãüù.ÄÆ÷Þ«ÂêÕ¡W¯O?­B\Ã! ¬–10r¤ ±±Àwß¹j=¦vú4ðé§Jäç+BÊ0ož—/ééÀ¿þUûŽÃ=÷¨Ðº5Ãóϻѹsí+”ÇWÁí~ú‰¯à9þ¸÷^ꔡÚü¬YJ””íÛÏ<¼Ï1Ü}772Å…&Mø19ŽF]Á;&·}»©©J(ô ÿ ¨H‰´´à¼6m¢Nܽ;9ð`§`^y7X»p¹”ˆŒ”¦5™€É“?^|±ö#;Ç;wï={&ø¬añb wo Þs¹TAeu: H†÷ÞãÇä8þD+Eècr¿þ ìÛLšdfÖÞç>þ0€â{\.%?&ÇÁѨ“GŠŽKë×X¾<ø wæLà‹/€O?¥À¹`IªÎ~hÞøÇ?è=R´ŒÛ·£F‘ÃîÐ!¸¬v;°`9á/¿¤ˆ÷`ï/+&NަOþ~€h÷^ºžƒãÏ‚PÁu6°p!0m 11B„¼?JJ€çžΟþýïÚûG®àåâå—çŸRRhU[^”–R§U*G!G¬PÐÕ®?ü@Ž×b¡k^Ï££v­Z/½D«|€œñ‚@‹D§×ÙÙÄ¿à›o€äd¢­¨-¢hv½žh²³i°¹÷^`Ý:’Åhöî–,¡¤º¸|ÈË£÷=ù$0t¨ðþ•+'ˆÎh$YKJhRñÉ'@›6Dk4+VPýNŠv:i@¥¢ß«ªh·Ãnî¸ˆŠ¢rßϳ= DFÒI•JˆH6H&¥’þn±ÿ¼<¢2„ŽÚlž¼ú¤£‘&2.ݺ Dïùq»I>»tév“Lv;Õûüy m[²‰ÑHv>{èÛHM¥Ï@:6™H>§HL$ù‹‹I†ÔTÒ¥Ù,”ýõ¯‚,‡Pß— hÒ„þ-+òó‰þ¦›è½n7ý0&üßsã`\=g4R»+.¦IšËE:ÌÍ%Y ¿ôÔ:$‡Ç&F#ñ¹|8ÞëáÕ¤ pë­Â3N'ñr¹ÈŽUUÔV;vš5#^%%dËAƒÈŽ´›$üøþMuª®&^çÏÓg¨-Hï……Äÿ¦›ÈÞÉZP@íÄí¦²œ²ó-·Ð¿ÔÞ›7:wx8AöJJ>ÿ\èEEÀÅ‹TÇûî~þ™¢âãâ€Ý»igÌÓç¯\!ÝÄÇÓ.˜g’ ,[têÄgŽzï´Õö Þz½‰‰‰ÈÏÏø.vàur¥hÚ”~ÒÓ·âNêìf39¦¸8ú>çqÔ¾(/§­=‡ƒèâãÉ¡&%ÒfgÓ`¤Ñmb"ñõÿÂÀ˜ «çýÍ›iigéM&Úbt8hà‰‰Úµ£ºImGææÒ€¦Ñпjµp•¬ZMƒkz:M@Ž£A”2ð ?žç5z®ºZpj‡¥R‘.bc©Ìj¥ºÄÇÿâbàäI’;"‚t Pm\é/9™tf±Ç©+•ôŒG¥R±Y3š„eg“ýbcÉyµh=J²Ò$dgÆÈùDE »>ñJN¦#–¹¹¤˜Ò«VK0Oò"†Ê<õðü_©$ªÕô\‹ôû¥Kôœ'ÓšR)þaŒ¨gò”œLü²³gÔ¶-ñÊË#zOñýW­&Y<õŒ%ýÄħNÑ»âã‰×©SBÛˆˆ }íOíïÜ9²G\Õ)!œ©g²ç™Lxþ¯Pп é>&†xµnMÎÚd"½§¤PÿõW²§ÞZ-ɦR õ6HÖˆêCmÛ’n*+ÉŽÍ›“ÝÊˉÿÙ³¤“¤$zOË–DçßçöïxÄÇ“®ÒÓ_c4<ùdªªªÀGjŽÆ^Ák²¹¤Õö±ƒƒƒ£`4¹ƒçà¸+x·ÛÂÂBÄÅÅANnXŽ0ÀƒÑhDË–-¡TòàUŽFwð „µEÏWð|ÏÁñ?èà ù÷wŽ«†üü|´nÝš+‚ƒ£±|\\œ·ÓùFÑÿöE¦?õThÇәô!CBÓ&$^M+…‚:š”›švÚ4âûÒK¡iSR(YN"-¹²Q˜5‹¢ßŸyæ÷1pTTÐq¶ý+4íK/‘ž{N^?*-¬VÊšés888ÙÁ{¶åãããE>3“ÃLššÇ¡CtVnöI9t%%tZmN’Cë9?Þ²t¬-+K>}q1éM.ýÙ³t„I.ý‘#áÙD ååtÌ«¾YE·oÆŽ•7 ‡ƒP}eÙ¹“Žœ=ôPýøTVÖ_–£G©Ýþûß¿£¬ŒÚ™œz=KGùäê@¡hù§@Žº£A>nEF w½‡BTTð¬VÁë•£᾿ººá•îN¸¡enlú`ƒrCAn[ªO›‘«—úÊÒmæ÷" @9äîX…Û¾äòý££¾“>ùá¸j^n,~¸½æ†ÚУ¢ÂK…)çýáÞ/‘Þ¿A÷Ʀ6à74šúO6JO†Àß~O²xt,§o4VŸ œZñÖ[oáºë®Cdd$0lØ0¬[·îwç˜ÿŒWg6› QQQ8sæ à–[nÁ¢E‹è¶oߎ~ýúq›4¶ƒo¬Õbc8øÆz¿ÜIN¸‚? þ÷´jþ=Éâi.×_–†„']ò«Ïù;ƒ¡C‡"//ßÿ= .^¼ˆ‰'âÓO?å£ü‡Bbb"ºté³ÙŒ#GŽ`ðàÁto¾ù&Þyç®°ÆtðáLžc».œ[c¾_.ßpW˜B<@c¬öbuØP«æ†ÜM¨o†‡†œøÔ$üÓ®às‹~îܹHIIÁ’%KеkWDDD 11#FŒ€N§Ñ®Y³=zô@dd$:tè€3fÀétŠVš+V¬@Ïž=‰ÔÔT<üðÃ(//­D …÷Çóû¼yó––æ=Ö—ûï¿M›6EBBF²²2Ùõ %k¸ô …óçÏGûöí¡ÕjÑ­[78pË–-CçÎ"Ï/:µ±tVvíÚ…Aƒöïß””tìØ1€nçÎ’ŽŸƒ 53ö¿ž->Ë$‹E@-* ÞÙÕ¨®vÃápËOƒòr'ŽÚGêpÞ¯Õ*a6+áp8e½¿¢"ôûiûQƒ²2Z´Í5yi0UB¥’+s¸u"#U0™˜L›4L¦}HÃd"{TW;ÂÚ]’Ò‹Ù 8u_~{ÚFy¹11u—%"B ‹E¾M‹z½J–<‘‘J˜LòûõyùíhåÊ•X¸paHº}ûöaÚ´iøôÓOÑ£GâÙgŸ…R©Ä+¯¼â¥›9s&þóŸÿ OŸ>0 ˜4i&L˜€+V€1…B©ü`k׮ž}ûžžxàðÁ`Ù²e°ÛíxõÕW1eÊ|§d —~åÊ•Ðéthݺ5f̘ŒŒ tëÖ kÖ¬ñ–=ÿüóX»víUÑ™/²²²Ð£GQÙ·ß~+šHÐÄçfkÿÎ;ïà7Þ(ß¼y3¢££½¿gf¦è0[–ž4Ü‚sçLÐéŽÊïnlßž‰êê¢Z©Nj`Ö¬Ùµºvãçå] “©tº­2¦‘8xð4RRÎ×JWY©0k×îFëÖ¡£òj ,}QÃo•êZÙôס¢":Ýv™ƒõ-ÈÉ‘k“Úm°v­.à‘pàtÞŠÓ§‹¡Ó¬3‚‚·aÕªmHL´Õ™Oeå°ÙTÐéÖ™Guµ@֯߃6m꾌¿xñZ òÚíÕÀ±cÉÐëûbýz]ȼ‚‚ëPY)¯=ªÕwâÀSÐjåÛÿܹsèÒ¥KHº×_‹/FïÞ½;vÄâÅ‹1dÈ‘³Z¾|¹×ÑÄÆÆbÞ¼yèÚµkHþ|ð×¹“ŽŽùL\£0sæL\wÝu²ê$WÖpé?ûì3¯®&OžŒ÷Þ{ .•µoßþªéÌÝ»wc z½ÉÉÉÈÉÉAzz:zõê…ÿû¿ÿÃ?þñî±ÃD­©j¥Vðiii(++“[´HgŸUÁf =C1B…ÄD`åÊЫ¢ˆ –,q⡇jwÚ;w*pûíj\¹â¼éÍÿþ·kÖ(qêThYÛµSã±ÇÜxíµÚW“ùù@‡ìÝëDŸ>¡g—ß|£À#¨a·Ë[¥¼ÿ¾ï½§DI‰¼ÕÛĉJìØ¡ÄÑ£òèGŒP!) X± {S IDAT¢î+U JJHL¬{ƒìß_…nÝ€ ê.ˉ@Ïžœ8á@çÎu—å‘GT(,¶n­»,%%@ëÖìÜéDÿþu_yLž¬ÄÚµòÚíÕÀÆ Œ¥†Áz—äÿþO‰mÛ”ÈÊ -{«VjL˜àÆ3ÏT¡Y³fÐëõ7WîúD¡°°IR×Lú 99•••ÞU çG©TÂU$¡P(àr¹²çù®@¥V£ …6› >“2ŠسgJKK*•Ê»½]ÛªV®¬žçåÒ»ÝnÑy°²pùÖEgÁðÝwßaÆŒøí·ßPTT„ôôt×jßpøó¼w«W ­dÈ·Ÿ{`].ϧ[°ôýN£ ýù_«ª«ÕÅÖs}§É¤AóæµÓºÝòeMLŒF4šÐKRµZž¬yéY¬-d—‹t!GfZÓ7[¹ôáØ¤6½Òn€Fòê_¹HL¤£‰õ‘ÅÓÏ- dª (èªÜúËb6«ë%‹Ó^hl¸Ý{c±h*ÓY—>'¿ž:u™3gЯ_¿»)ÕÈÏÏG‹ßÑêš××¹À˜1cзo_|ôÑGHMM…ÓéD”Ì3²re —^êûwmßĵÉáû{“&MÇÇõ×_Ï=·LÔÉ*5“Q/ìvrr"…å¶—‹î¯ª Mk·ÓýÖriýúa­ƒ\ž))òhÕ @-F~И‡^~Ǫ@šÃžj›l4D`[8ú­Ü¶ÒØziYõO¹§LºÏùâÁĬY³BÒõêÕ ?ÿüsýWEjµwõZŽ9‚©S§¢U«VP«Õ8|ø°ìw„+kCÕí¿©3Ïî@›6m°eË0ÆðÐCaúôéÞ¿qç~|IIÝcòœ‰Ã4k&/¢6\Z¹Î2>¾áß_— Í$%y‚ÇäÑ_í…žÍFuªÙÍû¯ÂfRSë/ íjü>d±Ù~_Þf“ßçÙp†“òÙƒ‰'âÊ•+7nN:‡Ãªª*lܸ^º7ÞxS§NÅÒ¥KQ^^“É„mÛ¶aäÈ‘a½/==[·n…Û]û§»Î;ãóÏ?‡ÙlFff&ž~úiÙïWÖ†ª[cñ•«³ . °°ýû÷ ަçø/9x‹hÕJÞ &÷HÕ 4o.o±Z-äÓ&%É;Š¥RÉÛ•GV¾äÊë¡oÙ2<úØXaÛüj Ü:ýQd©oþŒ†’œ굡Ž#6„Ž[¶”×ç­VjNáu9‰;v -- ÷Ýwbcc‘žžŽ¹sçâÙgŸõÒ :«V­ÂÒ¥KѦM$''cæÌ™˜8qbXï›={6ƈˆˆZ··/^ŒåË—#)) £GÆøñãe¿#\YªnÅW®Îvî܉^½z!::yyy(..Fß¾}k韊€cx>;' áàÍfù^î i6ËÍfùЗ6Ü”± ñþºÐû: 9kÙí@Ó¦´}ZŸ€·º ø¿ßP²(•4Qªë'ÆpmªNz=êãÐPðôy9õ²XhC¯GÈ Øº"** Ó§OÇôéÓk¥4h¶oÍ,PË·|ôèÑ=ztÈçzôèÌÌLQÙ„ B¾«®²Ö¥nrÊKgR3f ÆŒh×®(È;œws4ð ^îl €´PÇ\-úÆ''Á‹g2 7)MrrhZÆä¯ÞÂy]VuáLvžôXWY ’åìYE½æ¸\B»m×î¿¿jñô¹òòpúœiiµ÷ùÈHl6Ô;aGÝ;V n·÷÷ÜÜ^HI¹‚œœÄÆ^pÕÐjÝÐhÜ()é…ÂŒŸ>-Ì3ýª*-âãíÈÍMÄåËÉ()I‚Nw(€§Ó©@uuløí·kж­'O6…NwBÂY«ár±±N””ôAAA)¶l1¡¼¼$àýz}bbœ°XT¨¨¸ÕÕ¬_8`5ïrz½‰‰68ÐçÏ·†NwXb¢¤„ͦF|<}@={öDE• °0iiç$ô¥JÅE-/_îƒË—/#/O …Ⲅ‰€Vë‚VëªÙaéƒ+Wʱi“……euÔ"&ÆÆí¥W©LX½úZ¶4ÐWV’MjK"tüxí60›Õp»ÉµïõAÓ¦V¬Z•¦M­«Øª*-ìP©‚ËräH;4ibÅ©S-¡ÓeüÝjUÁnW">ÞR–˜Ö­+Dûöɶk‡F\–ZÂåRâÒ¥V’íØfSÂjU#!ÁB–›PPP‚Í›«½gª¥Ú­Ç¦“'»¢sçJäæ&B§;-1)UC¡¢£5í± ›6påJYPÙF Êʺ ²R‹Í›wòÑ™ƒ£1ü”)SDÁžD7Mš¤ #£J*b2©1rdsìÙ£@FFWoÇýé'-Rz·;ubhÖLîÝzôHGϞķ´øðC%~ùEôtº›Üá†g¨¬Tˆ"a³²€?T¡²’¶Ú/_JJxöY •ÈÈH÷¾Õ*–-S":š¶Û««©¼_¿dh4@F«Œ€O?UbÛ6Z·¦U(@òêõ ˜á=ë›—Ì«D^ž­Z—.Ñó“'»qú´R$ëŽ ,X ¬™\P=û÷g(+Sà®»Zcõj22:y' _­À÷ß+‘˜Hõ·Û‰Þ`PbÈddg+‘Ñ­Æ1‹+±v­Í›S®sµ5‰vè×/‰‰BFªãŽ ¤¥‘,ññ@÷î ññd“îÝÛ¢wo¢/+ ´I󿤓œŠ‹©Žž»»ÏœQ`âD' U’6ˆŠ¢ïØÕÕÀÍ73”–çÏ+¼AŒ/ж-ж-CÏž­áIúU\ Ì›§DVÉRX¤¥íÚ1œ=«@MÊkÄãÜ9àÃÝ8yR‰ŒŒT¯,›6Q{T*)˜«²’ô«×¹¹ ï' †ø$'½{§à/é€AƒH/••ÀG)qàÉRTDt×^Ë­}¾Š €I“ÜÈη={øôS%l6Š/.úõc°Zœ…÷Ó”JEŸª"#þý›A«lZ] ÌŸ/n·ññÀ 70äæ……¬46V¼t»©½Iý,0Ó‚{ꔓ'»°d‰Â;¸ÝÀwß)°r¥±±¤s³™êзo`{üä%vîÚ#\s CAÞÎGgŽú‚…½^ϰQ£ôlíZÆî»±'Ÿd,;›±S§›4‰èvíbìŽ;{çÆL&áù'ègÞ<ƶneÌnglÎƆ§gÜnöüyÆŠŠ»óN*/.flÜ8Æœ± :·›±_~aÌjeìž{¨ì—_ˆç¬YŒ­ÙÌXVck×2¶`=ûÕWŒÝz+c«W3æt ´EE$Ã3Ï0véñ™<™±ûïgì·ßÄï?q‚1ƒ±»î¢²œ¢{ùeÆJKZ‡ƒ±Ý»IW¤;ÆÛ¹“±Ûncì“O³Xzƒôtác‡1öæ›T¾z5ɼ|9éЃòr¢/,dìÇ[²„äûâ Æ†elÍÆ\.¾°±mÛ++cìÃÛ¼™dœ;—ì·sg Mvî¤ç<ån7c••ŒUTþ<68r$¸ ¶ogì̱ìV+ÙØfcì½÷Û³‡þÿÎ;Œed0¶oŸX–œÒeI‰´,ŒQÛaŒ±“'5б×^þÆñßµ‹þnµŠËKJÈK–0¶jÕíã6Œ±-[IJ\ºDz¹rE,KUÙßíd9ž±¿þ•±‰©¾¾mcï^ÆŽ#ù–—”P™o»ýòK¡ÝúÚôÊÒo~¾X£‘þVRBö®¨`L¯§r³™êïpP=]®ÚœNú1™ûÛßènæÎe¬ºZÇd¢:yÚ£ËEÿJõño.P??wŽÆ½^Ï888ê†ZSÕn€ýûõس'? ïå*EEÀ°a@ÇŽ@‡À”)Á#f¿øذ¾ß<ôPð€¶‘#ž=Ç™3š”È’èÚ¸ùfZ¼û.˖ž=À›oÒªqÈà_ÿ ~NwòdZmœ9Cÿ¿ãŽàï¿é&`Ð '˜=›ô f3Õ¥gOZ¡½õ­ä‚!;xôQÒ÷õד~k;°};0kéõŽ;€çž£~0,] ¬[G+Ô‡y¤nGÄ<6p:÷Þ nƒÚ°p!°c­êÆ|°n²ôè @«ã9sPë÷ß`øé'j¯ ðÀ$O]"êûöNŸ¦¶Q—º{÷Ó§S»½í6àùç¯~¾ÿíõ.]€þýI¦·ßÞç·m£zËi/¼(•Ì›— +U-G·p¼^¯Gbb"òóó:ˬ\ Ü~{èAýÒ%`ß>à®»hÛ0Ô fµ·Þz`]¹’õP÷NTU«WÓûCÛ9~81"t„ïºut¨wïЉ1àË/iBàs·CPØlÀòå@FdÝXWQ¬YŒEˆPÈϧ‰Ï]w!dêÑP6èÞ¸öÚºó¸p8tˆdñ¹Ó¨Nιm[juEq1°e ÉRÛ,6l Hò›nªûÙúª*ªÓÝw˳éÕÀ×_}ú:…nk×’CÉž•œ:eÀøñi¨ªªBB}ÏÁÁ¼<\¾|iuYqpppÔùùùh-'ùGý¼ÛíFaa!âââxÆ ŽFc F£-[¶l‹L88¸ƒçààààààøŸ@X©jù žƒƒƒ¯à98þ|aa!ÿÏÁÁqÕÀ¿Ásp\%W^——‡&µ„ÂS ßc\»w‹é¤ãCìÞ ¬X,X ”8p@(+*.^¤Èu^|‘ŽúFÖ/]JmÇw¡øÄÀ§Ÿ’Þo¿ýv\¼¨Áüùb{ïØAGï|mùá‡Àرb]œ>->UP\ üíoÀÎB™ÍF§E|Ûá¨Qt4ô/ÊΜŸq:‰÷9Ÿ„ˆüðm¯/¼@ídèPqÛ1B|\í¶Û€­[ż6m¢#‚|û-%÷¹õV¡ì©§€iÓÄ—!-]*îk6ðÑGÀ¤Iâ6ár‰/Ðyì1àÁ+ð׿¶óŽ9u@]Ý”••ÕJ—–ÆØ»ïŠËqR Æý”±+yåç‹Ën¹EüûáüƎe¬_¿@^›6‰Ën¾Yü{QQ ¯wße,)I\öŸÿ0¶n] ßÄŒQ’_¬^Èÿ«¯[¼˜þo·ÛÙêÕ«ÀØéÓbºÄ¿çäòZ·NÚ_]»ŒÆ@^û÷3öÒKâ²¶m›:5WQ‘¸ìŽ;Ä¿ïÛÈÿÇ)¡Œ?¯Ý»ko;Åżvì ä6¾Ðjûè#qÙðáâd<.ñòèÝn·³µkù÷èÁØÓO‹Ëþñq"&ü¾ÈÎ,Û¼™±Ù³ŸûáqÙm·‰md2ò:|XH:åAË–ŒMŸ..»ï>q²)Ysr{ôÑ@x ð¹íÛkçUQ!$üñ`Ò$Æ®¿^\¦T26gNOtÃÁQO(gÒ }§³IœæÜ›ÖƒÈÈÀgl6éÛ¼üo¦òKÏ-yf="Bú>mYõzñÝÕR÷Xkµ¼,JŠãÿ2Y¥êmµR*ÒP²––Šo^“ ™ ¦C«5°Ììs=€Ô}v{ \QQÒöö/ó¿…0˜½¥tè/ke%¼inƒÙHªÞÑÑâ:JÑIÕ[*¡LLL`¥ôã•Jº~rêm±„¶‘Í(CLLèzK!˜¥ì-Õ·|SßJéF£ ,“ê[á£Q¼F#ÝA}2cå÷8 ¹ÎɲP^.L¤¾ˆˆà¢ÿ@åË?/ÿ:¤ýËü'6¾ŸB9:ÿzWW‹€”Þ¥t¨VK_Åë;ØÊuðZ­ôdÁŸÎb#¹º`võ¯·”ÝìöÐ^jÂ(Uï`Þw"Å?XÛñ·‘?\^¼üõ#•‡Þ_7µ9`©2ßö*·í›ˆspp„‡:]ëp8¼×9Z,À+¯(1ožÛÇÁ«a³¹ý®‘Ô ¼Üáý¶Jƒ‡0òQd¾ZtU¤Ù¬„Ã^UUNÑÕ©‹UUNï·O‹%—J¥„ͦ½ÐÀló²ÛÕ¨¬tz¿ÓÊGãÇK‡CÌßdR¢ª*PÖÊJ‡h .+SÃnwz¿ËÛí²šLJèõÄË·¼¢B,«Í¦Fy¹Ó«W)YÍfªª”¢ëJ#"Ô0›Ý’²z²ûãe0ˆyiµ*˜Íþ×êjPY)–Õ`P£ºÚéИÍÒööÔÛ——Ñ(æeµ†¶‘ÉXo­V ‹E\o«U…Š ·—¿?/‡Ã§3PV©zÛl*TU¹ý®õ%½&&ú:=ß•Ë èõbYÕj5L&±¬ ÕÛs­¯/“)ÐFjX­µ×›ºº6›Ã`2ʥѨ`µÚÛbqÔ»¢ÂáÝ©1™û¼F£„Õ*î“$«ë~ðU(¨Ï)åú>Ïñ'wðÁ®‹Ý±c¢kFÖŠ ->ùd8† [ç3È Fvv™ßµ¡wcóæý¸p¡ª¦³«Q]=ëÖ鼃ÉáÃ-ôN§ó>uêÔµ°ZU¼víÊ„ÅRä3XÝ…Õ«·{¯=y²)€[D¼.]ºUU­ Ómñúå—ãHJºä³Óptº}hÕªºæ¹8·úÉ• §¨ìôéëí„NwVÄË–C¸r…¶+\.ìöQX½z“÷z×_MÐOÄëøñΨ¬ÔB§;.Òýž=GÁX¡Ï`žµkwy¯yÍÉI0HÄ+3³ ÎK]e«TŽÀo¿ƒN—#’uãÆ½Þ«Q‹‹£ Ãúõ:ïdäàÁ¸x±-tº>2ôG^ž:ݯ"^Û·FEE©ó¾?ý´Å{M«”~ýµ=.^Œ‡N—%âuèÐoˆÍ÷™,Üõë÷¡uk²Q~~ nóçÓD²:Cqúôèt§|vcëÖ“ÞkX«ª"ŒÀÆ[ R[¶lÁÑ£Éú‹øWVÞXÓ6zË ûc×®ó°Z‹|VÅwã矷#9ÙZc£ƒE¼~ù¥ Îk&ºÞV­‰¬¬ÓÐéÎû¼s(6nüçÎÑvXII€ÛE¼öïo ÚA§Ûï£ûÈÍ5ŠôZR2;vœƒÉTT3yP¸«WoBd¤«ÆFMpåJwètÛ½ÏwGqqtº="<˜­¶@T¶~ýno?ÊÏEYYètBTeNN{˜Í׊äw»oGvö…°2«ÕŠÙ³gã›o¾Ann.´Z-úôéƒýë_¸óÎ;WŽùψpuf³Ù˜˜ˆ£G¢K—.¸å–[0fÌŒ7ÎK³qãFÌž=û÷ïGrr2î»ï>̘1111\áÂVypX­V¦×ë½?ùùù »rå ³ÛíÌn·³³gíÞ€$ÏOnöÔSNQ³9¼¿ççSYE…@³l™#€×‹/:Ù£ºx-]*ð²Z©ìØ1fÆ@^¯¾êd­[»Ee11n6gŽXÖ¦MÝìàAá÷lj¿Õ*”}öY ÿ§Ÿv²‰ë½zµ kE•]¾,Ðüøc ¯)SœìᇩÞ&“Éd÷ÙgV+–u÷î@^óæ9Ù!b¦¦ºÙë¯ʺc‡ÀÿÄ *«ªh–/w°›nóºýv=:ÐFß}'ð²Ù¨,;[ Ù¸1PÖ3œì¾ûļ""ÜìÃŲ&&ºÙÿ#GÛáÂ…²víêf&ˆyuîìfß~+ð:žx]¹Bz7™L’6úûß]lÐ 1ÿ›ov±/¿xÄ++«v}ð“edˆy5iâf3gŠemÝÚͶmøŸ<Ø6—.u°oó8ÐÅþþwqY÷înöůâb{M«¸µh!î3O>éd=z¸ì=¾# ÌßF‰‰âçÞ{ÏÉââÄe:¸Ùsϕɲ³Z­¬ÿþì±Çc'Ožd6›UVV2NÇFŒÑàK/6¹Ñø4”Wáʺk×.Ö¼yóš@R‹ˆˆ`çÎÑ 6Œét:f4Yaa!{ðÁÙØ±cydÜ ;­V‹øøxÑ­B5ÐhèÇn×Ôlµ eZ­N§JTæÙVõüîv{ÊÆÔ¼ª«•¢2¥RÌ‹1y¼4\.…¨,&F‹E,«Ý®ñ45[éùÕP*á÷œ &SÃÔÛéTÁdRŠøDF2X,/µZ›M³Y,—?/—K£Q¬Ã¨(ìöÚeõÔÛWV·[-’K£Ñ 2R »]ÀËWV©zKÉê_oFƒØØ@Ùl OP*}y©ê­Õ*àp¨üÚ˜fs`½m6¡mKÉEŸ|t(§KÙÈj×ÛÃßéôµw ´Z%œNe@;÷­·G‡6›XVƒAágoqÞ ¼TªÀöĘÕÕ ¨Õ¾üUÐhļ""p:å‡Í;)))X²d ºv튈ˆ$&&bĈ¢X³f zôèÈÈHtèÐ3fÌ€Ó)þL¸bÅ ôìÙ‘‘‘HMMÅÃ?Œòš€!O‚/…Báýñü>oÞ<¤¥¥yódggãþûïGÓ¦M‘€Ñ£G£Ì?§„’5\z…Bùóç£}ûöÐjµèÖ­8€eË–¡sçÎˆŽŽÆÀ‘——wUtVvíÚ…AƒÕìHíGJJ :úžG°yófŒ1±±±hÑ¢>ùä¬^½š¯Ú}P§ ;ß ÿ ¯Ú‚d|<Ÿö}ƒnäˆÅÆïøËåù$é»+äpKùó’ òðò•ßnä,PÊ——' HN½ý’ââBËå)óåL‡RÁ`rêí_G©@)ÿèh¹õ– ²ó—•±À D¬¾¶”ª·T€˜^R²*iþúñð’ª·oÛ”j;R6ò—ÕÃË_×u ²“’Õf#=øžX`,ðF<Yƒµ§S,‡ÃxB!X0l0¬\¹/¿ürHº}ûöaÚ´iøøãQQQM›6aÏž=˜5k–ˆnæÌ™˜3gÊÊÊpôèQ¸ÝnL˜0Á³ãéý×óãÁÚµk±oß>¸kÅ<€gŸ}—/_Æ¥K—ЪU+LñM°Ñ²†K¿råJèt:”——###X´hÖ¬Yƒ’’ôïßÏ?ÿüUÓ™/²²²¼€×^{ ß~û- † †Ë—/‡œ”––"ÑèÂÑ0ÞÿèM°ªTJøþƒ¡ÿ"›-0‚:&&pR©¤+ßÁÄf“vðþÎ#Ø -ÇÁKOò—5˜S5Yâ¥Vˤk㎃÷ޱÀ«|ýõÌÞ´ú îÀ¤&6N'9V)Yýëíßv"#ËÜîÐ:”rðRÎIjr¨PH;eß¾#Õvüë-E¬ÞþÏIMºåÖÛ¿ï:w¹KM>ƒÕÛŸÎ_‡t”Q~*ìsçΡK¨;¢¼þúëX¼x1n¾ùfDGG£cÇŽX¼x1¾øâ ÝòåËqë­·"66-[¶Ä¼yó°Ù7S|ðÁHOO÷þ~ìØ1 2QQQHHHÀÌ™3±qãFYu’+k¸ôŸ}öºt邨ØXLž<UUUX¸p¡¨lïÞ½WMg¾èÞ½;c¨ªª‚F£ÁÅ‹ÁCÏž=ñõ×_×:9€éÓ§cìØ±Ü«û@]—‡ EÀªÜwV/µ¢óðm¶ÀAÁn§ÎîËËf rä¦NŠV­ZA­Vãðáòß®¬ U·ÿ¦Î<»mÚ´Á–-[ÀÃC=„éÓ§{ÿvýõ׋žùꫯðÃ?`ýúõÞ£Ûõtð¾¶¢‚.,ñ-óïœFcà d0Pg÷-3Ë<ÛŒžÏí¦ÁÄ×q @«VâAH¯§2ÿ5&&P>ßߥ̪*ºD#ÔÀê?ˆšLÎPJ.£1Îó©À2⻲1€–-Åõ–Ò«”~üe5¨>¾zÕëë-eK8äèüë–&­Cÿ²øxñwy§ì©w¨¶c4êGj7Ê_¾|u!UoÿØÆh÷ÁwÒWU%]ï`íÂ÷þíÔ`g)]øÛÜj¥‰“ï˜+¥W©¶cµNÂÔjñާíøËÕª•x$Õ.ÂÅĉqåÊŒ7§N‚Ãá@UU6n܈ŒŒ /Ýo¼©S§béÒ¥(//‡Éd¶mÛ0räȰޗžžŽ­[·zƒé‚¡sçÎøüóÏa6›‘™™‰§Ÿ~Zö;•µ¡êÖX|åêìÂ… (,,Dÿþýˆ£éý±uëV|òÉ'ذa¿”¨.Þf³Á`0ˆ~È©»½ÙìNžt£{wWMÖ2ìvÜn7ÜnæÂ:urÁ`Ê ]h×Î…ª*—·,?ßöí]5™ßèÇív#:Úí-ËÏw eKwMV.*ËËsâškļ ]hÓÆU“ñÎQ#ñ2™è÷êjT*±¬^z½˜Wzº?7Úµs¡¢BÕå ]ï‚g\âzwê$–ÕårC©tÃl¦ßF ââÄü 5:tûðòèUàe4º‘šêBy9ýnµ:j¶Ú|e¥z‹eu¡m[±¬—.‘¬¾õv»Ýp¹Ü°Û=:t CWM6*»|YªÞ®€z;nÄĸQU娨Ðjëݶ­ØFùù.´o/æUZêFZš«&ûµM—K\ï¼<ZµrÁåËJüÝ5.^t£sgqÛt¹ÜP©„ötù²ÉÉbY œHOËzé’«¦½ ²šÍn4i"èÕlv@© äÕ¦ØF—.¹Ð¡ƒ˜WQ‘mÚÔÞ6/_v iS—¨,?ŸÚ“Á ¶÷5×:ôðܰٔʸ\@QQ_4mZŽÍ›ËpéR% b¡P´EQQ tºC€-[Ò¡T2dg§x³©mØÐ½{á×_ã½6ºp¡/¢¢*°ys).\ Ýàr)ðóÏ¿""Â_~I…݃âbÁF«W_‹öí«pòd3ov¾#GnÂ7cçN Ìæb¯Ün ~þ™ì““…¢9JJâ}ìÝIIVdg7÷ÚhÛ¶^èÑ£11—àvùùýšZŒ­[(++EiiŽÎ¨¬ŒôÖ{×®Vp¹”(-ÚæºuA‡U8vL‹(“ÝéÓýЭ[)¶n­À•+5i^{"*ʉU«N >ÞãÇ›ÁéLDII/¯쌴4#ŽKõf‘Û¿¿n¼±»w;ávÂ劋o‚Z]õë/ U+SMöÄt””ÄxymÞÜ11äæ¶ö)ëë¯/ÃáÃj4kFç—óòú"*JèGz}L¦ëa2i¼õ>x°9‹DIIŠ^»"-͈¬¬ho6Ƭ¬¾HI¹ˆ}û4ˆŽ¾‡C‰²²ÞÐj]X½: ‘‘.œ9“ ¥¦mª±w4onFvvKo{Ú³§7n¾¹D¢iÓ<¸ÝÀ•+}S…¯ }{=ŠŠ¢ávwDy¹#¬,** Ó§OÇôéÓk¥4h¶oß^ë6q¨òÑ£GcôèÑ!ŸëÑ£233Eež£cµ½«®²Ö¥nrÊKgR3f ÆŒh×®(Uº?¸#—ºd²»ûîr–™igC‡ºXq±-Xà`?ü@«yÄÅp°;ït1›ÍÎÌf;»í6+*²³‘#)“Ö¥Kv6|¸‹eeÙ½™ß6nt°_t²yóœL§#^o¾édß~ë`/½ädYY” íî»],;[àU^ngƒ»˜ÅbgwÞéòfÌzä[¶ÌáÍx·p¡ƒýç?NöÜsNvö,eÌzì1;tÈîÍ f4ÚÙ!.VZjgwÝEeçÎÙÙ¨QD÷ê«$ëwß9Øk¯9Ù[o9Ù®]Äÿ¥—œlýz{૬¤ìzÇ»X~¾ ו+¤³ìl;?žxíÜé`Ï<ãd  :œ=ÛÉ–,q°§Ÿv²œÊdwË-ù,+Ëì­wUÕÛltqì˜=ø ‹ýø£ƒ-Xàðf5›5ËÉ>úÈÉÖ®ux3îíÞíðÖÛl&¹ÊÊ^.^Žl´v­ƒMšädï¿ïd6¯iÓœì‡ìÑG]¬ €ltç.–›+ð*-%½^¾Lv±ÛíìÀ{üqûê+ûê+âõñÇNöé§6q¢“ýöÙ衇\,3Sàe4R½++:eg£G»Ø† 6ož`£7Þp²E‹ì›oˆÿ /8ÙæÍB½­VÊÂwåŠÀÿòe;6ÌŶ³É“éºØ­[-ìÙgìãì矉×Ûo;Ù²ed»ìlª÷½÷ºØéӝР’µ¬ÌÎÊ23©Nßïðf%\´ÈÁÞßÉ^}ÕéÍJøøã.¶¿ «Édg·Þ*¶QNézçN‡7ãÝÚµöòËNöÁÔív;›<™ä¾ë.j/6ÙöâEWQñ?q‚ôd·ÛÙÁƒv6néÌ“íqÞ<'ûüs;ÖåÍx÷Ϻرc/½žê­× e¿ýfg<àbûö9ØôéÄëë¯lÆ '{ûm'Û¾d}öY'Û±ÃÁ† +ç×Årpü72Ù]¸ ÄäÉ|ó))$%©a±¨±i“Í›+Ñ·¯±±J8üç?<ô©©(J¨Õ¼ô’ï½§D“&X,*Øí¼÷žo¾©BB‚ V«ÙÙ;¦Â¨‘”¤‚Å¢Á·ßjз¯:i TRV®W_Õàµ×”ˆŒÔÔDrjðÊ+Ìš¥Db¢V«ÅŬZ¥Æøñ*$&¯;4HLT¢O×ûïkðÌ3J4k¦c‚¬sæ(‘”¤Ù¬‚Ù¬Á‚jL™âá¥Æ±c«‘¡F|¼6›K–hpçJ´nMõÖh4˜žø«Tüûßd£fÍÔ¨®V¡ªJƒ%KÔ˜4IèG¿ü¢Í¦ÂàÁj4ÒE—|‹>>þ؅뮣#5½ef;vëÖ eÒÏ? Ï®\ üå/@·nlc4S¦“'St|l,•¿ø"ðå—œ>MÏ®_ïdAhC†AIï¾ <ü01yŽ=ÿ<ðÁD\ºÌ›¬]+ýú+½ãµ×„²E‹€N€¢"’õÅ7Þ `ªØXº¦völà›o„zge‘<üikž˜n¼QH¤3m0a¤ÅÆ’\/¼|ú)½?6ÈÍ>ÿ\‰ñãÏèØ»—‚ž|†~ðpï½ØTP@õþ׿€9s(Ò;>8X°ðdsÔj£G#G€ï¿x}ý5Ùçºëè=F#ðòËÀ+¯Ncc)¸rþ|ÁFqqÀÉ“6Ú¼™‚¹ 2Ð͘ŒKQÖqq@v6Éúᇴ\¼HzX'Üa„#G€Ë—·ßÊ,† Úµ£µêj`âDj‘‘Tï³gåË…:ÆÆ’¶otÁµÓ6m€=€âbºámùòkñÿçFb¢ññ@~>ɺp¡Pïs稭xê­ÕR½m6à¶Ûþ³gý+À]ºDz}áàý÷)H-6–l·x±ØF™™Ào¿S§ õþâ  wo K²ku50iðæ›¤ï¸8º–xþ|ª»§Þ§NoOÛT©€5k¨ öíK2UWSî9²QE–™0úRI¼.^>úHlïƒÂBà®»„²ÿü‡Újz:éÕÓ¿ß{ŽÈÅÅQÿš3øázfÔ(7¶lá4G£mÑûC¯×3¬¬¬LT~ð cc™™BÙÓO3––ÆØ•+BY‡Œ ΘÝN¿;ôÜ‹/ 460¦Õ2öÍ7BÙÂ…DwæŒPÖ³'cC†0f4 eÑÑŒ=òcn7ýž™ÉXTc~(Ð|ò •:$”Ýy'c7ÞȘoµZµblÔ(ÆœNúÝh$¦Mh~ø1†±u넲—_f,9™± „²®]6Œ1‹E(S«IGÂå ŒED0öÅBÙœ9ŒÅÅ1–™I[Åv»õíËØÀŒUU tMš0ö·¿ õ>uбÈHÆÞ}W Ùº•äß½[({àÆ®¿ž±‚¡¬];ÆFŽ$Û0ƘËEϽô’@£Ó1¦T2öãBÙ[o1Ϙï}7ÜÀØÐ¡ŒUW eqqŒ#ü~äébþ|¡lÁjGŽeC‡2vÓMb¥¥16z4ÉÈé\«elúôÀ¶¹y³PöØcŒuê$¶Ñõ×S{²ÙXÍŒiµn–‘‘Ëì5 vçNÆ ÆV¬ž›7t}ò¤P6bÙÜ`Ê’“{ðAÁF'OR½çÎh–/§²½{…²{îa¬[7q?êØ‘läi›ÅÅÔv&Oh6n$Y׬Ê&L`,=]l£[na¬W/¡m:¤ÃÇh®\!.^,”½û.cM›2öË/BÙàÁŒõíËXe¥¸-ÔÛb!^3f4?ýD²nÛ&”•••ñ-zŽzBÁ¸ÃO¯×#11yyyhâI“:j““ø$D¯¿ÒêÀ7ÁÑ?ÒJ.%E([ºøûß…Ä••À† À?þ!ÐäæÒ*eØ0¡lÃZ½´k'æuÿýâì`+V=&:žVŒÃ‡ ÏíÝK»×]'”}ó pûíB68Æ€%K€1c„ãk%%À®]ÀÏ=JG¼n¼Q([½èÓ‡Vð,[F«9Ïq#£øé'à‘GšìlZÙôëçÀæÍ›qûí·cçN Ú´:w¯¸ïº‹V«õM+ëqã„z—–ÒË_ÿ*áµÅBº3F57—V‡·Þ*<·cµ_}ÿ=­=;In7ðùçÀOÇתªNÜž~ù…ìék£Ÿ¦q«VBÙÂ….¤¦nÂȑàÑh ×ÓjÕ—Wv6­Xʶl¡Õªoøúkàî»iå Ð.ÎÒ¥b]ºD»HwÜ!n›qqâ~´j½Ï·m~öñò´Í²2zöž{ÄmÓbÛhãF’Ó·-YBuô$r:©ì‰'YÏ#yv((Бv|ëýÍ7´z÷dÁhWá©§‡£F 4h×®ªªªàû0‡l„åàÏŸ?:p­qpp\äææ¢}ûö\u@Xßà=«öK—.ñYõU„Á`@ZZòóó½Ž\ïÿËÐëõHOOírpp4¢ƒ÷äNHHàÞ¾'8¸Þÿ hˆçÚþÃUÀÁÁÁÁÁÁ<Ǫ×_ýõ°P©0xð`~-ßÕ6×;×;×=G+Šžƒƒƒƒƒƒã¾EÏÁÁÁÁÁÁ<wðÜÁspppppp\Eït:1iÒ$ôéÓ7Þx#Fââb®½À#<‚nݺaÈ!èÝ»7žxâ ”––zÿþÅ_ OŸ>0`úõë‡#GŽˆž?tè €Aƒ¡GXºt)Wj`ŒaäÈ‘3fŒ·lýúõèÛ·/ˆÞ½{cÆ ¢g²³³1lØ0 87Üpf͚Ŏ=ŠáÇcàÀèÛ·/ºw¼<®{ŽFàBâ•W^a·Þz+sÖ\_õÜsϱ[n¹…_ÕÓ8p ÷¶2‹ÅÂn¾ùfvûí·3ÆÛ´iKIIa%%%5·×ýÀ’’’XiiiÍ-bÅ,))‰mß¾1ÆX^^‹‹‹c[¶lን‰9sæ0µZÍ}ôQÆc'Nœ`qqqìLÍÕ…‡bQQQìdÍuqV«•µk׎}Qsí_EEKOOg‹-âÊ”S§N±ääd¶ÿ~oÙôéÓÙÑ£G¹î98!¼Ífcqqqì»ï¾ó–åææ2ìàÁƒ\ƒõÄßû<c~ø!S©TÌb±°;=óÌ3¢¿§§§³wkî}çwX×®]Eøá‡ÙðáùbeàðáÃl̘1ìºë®ó:ø§žzŠeddˆè Àž®¹ÛwåÊ•,>>Þ;ÙeŒ±iÓ¦±.]ºp…ÊÀ¨Q£ØøñãEev»9N®{ŽFÈ-ú¬¬,FtéÒÅ[Ö¾}{ÄÇÇc÷îÝ| ¤ž¸ë®»D¿»Ýn”äcïÞ½"½À 7ÜàÕûîÝ»þÞ½{wìÙ³<½Aí0 ˜:u*>üðCQy0úê¼cÇŽPyîe­ùû™3gDŸV8a±X Óé0tèPQ¹FóÿíÝ_HSmð¯˜ùoÔæ¦ƒþ­ š[S4·¹Œ º(¨¤¤ƒ.ê"‚.Š¢ ì¢+ƒa QxS)ÔˆF´þÞ„ÕÊ'Fiä¦C·U›ýÞ‹ímºW×+½ïûýÀ¹8ÏsØÅ÷œ³ßvÎyΓƒììlfO4ß÷àjµ:©½¸¸Xé£_çõë×°Ûí‡ÃˆD"?å^RR¢ä>88˜²?‰  1Ì>08yò$,X¿ß³ÙŒ‚‚fO4ß¾   ©ÐO™˜˜Pú(s“““hllÄ™3gP]]`0˜6÷©/Å¿öÿ¸ßèç+$¸yóæ´Ç{ºÌÃá03Ÿƒüü|ÀòåË•B]ZZŠºº:´µµ1{¢ù.ðƒ!é×÷”ÑÑQ¥2“H$ÐØØˆ-[¶`ÿþý­V •J5cîƒ!e¿J¥â¿÷i\¹r?~„ÓéTÚFFFàp8 ×ëÓfîóù~êÿñ\¡ÔŒF#àÇIí:oß¾öxföDs“öüúõë±xñbøý~¥­··‘HV«• f(‹¡¾¾Û·oWŠû›Í–”;ðçâ©Üív{ÊþÚÚZ;¦¦&<{ö ^¯WYŒF#6oÞ ¯× —Ë•6óÞÞ^$‰¤þµk×B§Ó1àÁl6ãÑ£GIíÁ`+W®œöxföDsôwµ?qâ„ØívexÊdãÆƒ¡p8,‡CZZZäÍ›7IËØØ˜x<Ñjµ244$""ׯ_µZ-Ÿ>}‘ÏŸ?‹F£‘»wH__ŸÊ;wî,ü8LÎï÷‹J¥RÆ^û|>ÉÍÍ•—/_*ÃFW¯^----""222"K–,QÖifííí¢R©¤§§GDDúûû%??_:;;™=Ñ|ƒ‰ÇãräÈ1›Íb±XdÇŽ2<<Ìô2tÿþ}r™z™Gkk«˜L&±Z­RSS#OŸ>MúŒ'OžHMMX­V©¨¨Ë—/3Ø ¼ˆÈíÛ·Åb±ˆÕj• 6HWWWÒö===ât:¥¶¶VÊËË¥©©‰!ÎÂÕ«WÅl6‹Íf“ÊÊJimmeöDÿÎODDô¼ODDD,ðDDDÄODDD,ðDDDÄODDÄODDD,ðDDDÄODDD,ðDDD”‰Œ€fât:ñíÛ7eÞí/^àË—/¨®®|ýúñx‡±cÇÐÝÝââbGDÄO¿3Fƒ7n(ë‡ðz½JÛÎ;¡Óé°fÍäææ24"¢ß/ÑÓŒêëëÓn³{÷nlݺ<À¢E‹ <ýîvíÚ•v“É„††deea``píÚ5¨ÕjlÛ¶ {÷îEee%JJJpôèQ?~ 0Ø´i"‘ˆòY>Ÿv»6› p»ÝÜ DDsÁ õh6êêêÄ`0L;õm PÚ ƒœ:uJY?|ø°hµZe= I^^ž2]h ¼¼ûçÏŸ ¹wïƒ'"š%þƒ§yS^^Ž`0¨¬k4èõz¼ÿÐÖÖ†ÂÂB¸\.€ÅbAQQ<Ã#"š%>dGó&+++eû÷ïßýýýˆF£p8I?²³³ <ý[-\¸z½>é }""š^¢§ßÆŠ+044”ôбÀÓ¿Üž={ "8wîà "ÊPöéÓ§O3JçñãǸpá¼^/ÆÆÆ0<<Œœœ¬Zµ >„ÛíÆ«W¯DZlÙ2´··£££ãããXºt)FGGÑÜÜŒ¾¾>LNN¢ªª çÏŸ‡ÇãÁÄÄÊÊʰnÝ:˜L&¸Ýn477£«« >Ÿ¥¥¥Ðh4Ü DD³%"ˆˆˆþ[x‰žˆˆˆžˆˆˆXà‰ˆˆˆžˆˆˆ~?¯& Þ¯„Ï.IEND®B`‚pyclustering-0.10.1.2/docs/img/kd_tree_balanced_lsun.png000077500000000000000000000764141375753423500232170ustar00rootroot00000000000000‰PNG  IHDR‹³ÁèEsBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æð|LIDATx^í œŵÿÏ,QX1‚Q^V£<½Q1Q1êe1Ñrƒ O¯ÊFƒQ„U |±°‚‹Oþ7²ˆ& IJ(Ä+/5¢QãðêÎÿüª»vjjª{ºgzfgw뻟ڞ®®®®ªSuêT,ÎP–Ô××ÓÛo¿MíÛ·§X,æµX,KSUÃ'Ÿ|BGqQ$•Å›o¾I]ºtq÷,‹ÅÒ\ؽ{7uîÜ9šÊâ£>¢o|ã"Ѓ>Ø=ÚÖÖ=ÖŠ%¸G}”:v˜Ø—lÝJ4z,Ñ]+¥Þ'·u†G}䙢&hZ6òù¼™ÞK¿.ª8‡ Çä?ª¸X>þøc!üûßÿ¦¯ýëBÔÈ®,PáˆmsgÃT®ÎÖDºó’ÚµŸÅûÒ†øæjöÏìÞ©©‰—P?q}OêËç)> ¨(¾àêµâX,6@¤s«V­âUUUnHɽ:jjvs8«Ä6ª0ÃÒX÷m,òù¼™ÞK¿.Ópt†cò6 ‹?z¹^„Ä’âÅmi#õ£½%ýˆú9®ÓàÁ4´¼\œg6µjEãçÍ£Ö½Šc³g?A«W¯¦;vШQ£Ä±\°`Á:ï¼nükØ.[¶À9tI"ŽØZ,–惭,"fÏž=IÛ°\pÁb[Y9/¥RèСqÆ¢ÿ0W ;v,Pßš:S_êÉÛšicù× ŠíýÜõe•L·nÝhРAb‹}‹ÅÒ<°•E„ p2dˆøm6…å€rZ)x±mÛ6¡Ý¶ŸzÑ›TK[x{y¼ž•Ò7V/%ª­5ºíKWÒïGßC'påÒ—ÃéÍaÌåJgÏŠFÿA\q]-‡U›¶’²X,¹ÇV![äq.X¶ãÆkrÝ1tûË–sœŸtTù¢þýîà 'Qm û¸rá¢^¸õ\at*-5úâJFôçpúS›[Äý-Kãa+‹ˆ-r•¯¾úŠ^ýuw/™l»«rŧŸ~êþJ€¢ºUR]õ¢ f÷þœ;…ß‹„_ÇTTD{jjŒþƒ8ܯW@ûº÷BЋ¥±•EDôèÑCL\QiÕªsÌ1î^‚(»«¢Æôû‹ZÑF*MŒ×Ý¡AømÂobpƒö&ÿAî%(X,–ÆÅVñ…y\8qa °­¬¬Lw(ôî*ù±˜óØNž\‰3b?O<‘-‹Å’_le!(QXlM…eØîªÆñ†š.Àö‚ ‚ú:å^cËb±ä[YD Ku«¦»ª1š®ºµX,-ä™ ÝU‹ÅRHØÊ¢Ò]UHÑÜ*Tí.‹Å ¢²¸ñÆ…iqÕ~øáƒ%7¤ë®*žyfYZÍ­BÖî²X,ÑÐ YüñôÏþ³Á½òÊ+î‹JKkA/X0ÍWs«¹LF´X,þ4T_ûÚׄ4!ÝašékKÓhAG]™ÉJ@¢kn5í.‹Å’= •>z¬ˆtÔQGÑÏþszã7Ü3©ìß¿_Ø:W]s'_-èl û\Tf±Xò°–®¹ÕT´»,Kvˆ¯ü»ßý.-Z´ˆV®\IóçϧwÞy‡N=õTzÿý÷…'3fˆÅ0¤k «äeÓ‚F…Älw6…}®*³Q£¦øjnYí.‹¥e *‹ÁƒÓO~ò:á„è?ø-_¾\œüãÿ(¶:“&M«ãI‡òš;™¶ Qà1ÛmaŸ«î 3θ ­æVSÓî²X,áI.ý\Úµk'*@&Z·n-–OU]s'h æ´aVæµýÌvëæ·³-ìsÙDs«©hwY,–Ì0V“¨««£o}ë[î Ò‚†9m˜Õ†yí-®Ùî³Ýºùíl {Ûd±Xr‰(&NœHkÖ¬¡íÛ·ÓóÏ?OC‡ƒÖ#GŽž, Òµ aNfµ§.§!ÇJÙa‘Ò~ì¤ÙnÝüv…½í²X,¹BTè6lõìÙ“.¼ðB:ðÀé¹çž}ì–àÔÀY[»#ÝpßtŠ‹¥ƒv±{)k0Ûm2¿EauwÐì¡õë×»{‹¥¥"*‹‡zˆÞ~ûmúâ‹/è­·Þ¢Ç{ŒŽ;î8á¡¥£P/[毡„1ˆchyÊø8*§óŽ8ÂY6´®N{ìî¿Ð¶¥+–íôÁâ¸ØºÇÚlwüÆöïÛ|RV6„Æ'~/[¶Ll-KË#gÜ߃.+¨Ð~´f ¬-ËÙ”Á\‡Á¥CésêImh ׬{©(VDõñ'hÁÚÓ©ïÀÔEyê×RûýE·S½ÖÆHE?Â’@;ø—ìTºžÏUˆsüøü|>9ÃÞÍ@'d -©¨£ŸL)Ǽ@ý‚UI±ØÖÊ”»nÝEW\Ý•ŸÜ d+ß¿$6€V/¯ öN[v´¡^Ý÷QÛb'ûÔÖSÿ%´¡ºŽú•DS©¡>>‚+ìµ½ŒiÝ܈êÝ!Ó{é×Eç°á˜üG‹CC¹þÑGŽ*‹láÀPbÄ?BpÍÌm ¾â'¶êñÍÕܧO¦vígñ¾´!~í°2ö†’×Ç»ò5ŠŠâïÔÔÄw³‹ÅÚññaJøiÅçpü³µµñ Õ›Å6¾ïÁnIÅfáoñ‚ÏÝ»xƒKàÛl¸åWKœp8nz˜ÒÄt,*ç•ÖͨÞ]2½—~]¦áè„ Çä?lÊuÞ+YøÉâÌÒ)B£ -lŒF¤“,ÔÖÍ_þ2‹®½öZÑ%Í& XcãèÖâJW°C3h£8Ž…ƒt/&Á-ìêjniwzUëêÿ=ô:]3ìg,Q9]`û¨µ½F+–?Jo}Ð=EŠø|o,EÚÈ+YäŽLï¥_UœÃ†còU\,¹•,ܨ9Q^¾T´VDë¿U+Þ¯û^­½u³{÷î8Wb+Áï"–$©#¶êG¥ºÚ ÛtDÕºr©âx¶â-‰øUUU)粿G:òuŸB!ŸÏ›é½ôë2 G'l8&ÿaðø£—ëÆy–\pØVVÎëJ‡Yb@õU_f4šlí«Üí¬".vMm‹¥ec+‹€ 0ÀsÎC&…»—šlPó ¹&aÈ𻦶Åb±•E¶„U­U9üàö“Ý?xKt¸Â ȽcƳ Ò<ÈÝcÊèµ§^þ£Tõ«àðLQ[¯µX,M„Dµýd*ÜŸ¨(£ž´Žö}èØ|òC5 ‚‘9˜y1CÞÒUÅ¥©‹úÀ;µ~Ê·Ùã'½ ò°‹Y,[Y„D-à…;K[i ýóÙðîÛ‚—¦A`ú*02 †YÔàF(ëIì?¢»û˵2ê!Šû|ÝFzúÎut÷è Iœ4n?ÿ\¾Ü=ç†Cõv1#‹Åb+‹°¨¼±pw“»_ 8¦Aú ÓÐõƒKçϧM­0…Ävè”)Žg&ÞºØýå.­¨nËi£èœ ¹BëÙP¹ÁIã†ðsÒøñîqLÃëO½hŸ]ÌÈb±ØÊ",jo*ÜϼäjêÍ{;ž©õmÁÃéfʺ¡y$5¤6VPti%ÉU/~Fˆ9㉠N7”þ–•—s%X"Ây-ÖÖZ¯µX,¶²È½pòít¢É÷û·àát3åÌ™j éÒJ’+qL… åÊ@­à¤qCéï‚©S©bùjΣËWX•Y‹Åb+‹(P ÷èEQ°μ 'L„­’[,K>°•EDèóÀôéÓÅ6Ó<œ>},ÿŠf΃œ•˜m±X,Á°•EDlÛ¶MX—U©¯Ïn~‚)ÌLç<@"±³²-K¦ØÊ""zôèAEEÉÉ ÙÌO@˜±˜³Ž·÷¦.õØYÙ‹%,¶²HCº®¸“°$‹9–dÁäÉ“#@îÓ¯¼Ò0W3³k׉­\®UlÝóÛ–§.ó*$hf)á¨Î4Äb±´\leáCº®ì«3´ÁìÙŽ%YvBº¡â\9íîsÑN;x_«‡™ÙXŒ[ᮎ„­{¾Çøñ)/UÚ1,]¨á¨ÎkˆÅbi™Ø•òÖ? h¿0i®ÎP׿ÆJu¦뮿·†*ªnæ_=¨ˆã9oÊU4ʧ2ó[¥.]¼£"_÷)òù¼™ÞK¿.ª8‡ Çä?ª¸XìÜÝ*vx&u5;ìWÒ1bßkýiù[ì§Y±+ÈÊ^ÎÊ|ÎjuXµN®V§$œššwØÏîøÌ™¥¬È‡ýU«V%÷ 3Èý¢ _÷)òù¼™ÞK¿.Ópt†cò6 ‹?¹])% Q­7×£¦Æ°F7 š)[Äþ™ß)Zð‡<>£ÁˆàEì,Ä~xë –¶»G²ÇY™¦ÉW‹Uë2™«‘èNëL“&ÝD+W®tN0zWšÞÕf±X,Qed‰^5ЊÇÚÓx6´îÑÊWIœw¤ ¬×-[7péZ8AZBAÂó G®÷]L½ã}iC¼7oKbýão<þdüššxÿXŒSƒÀ~q|sõá¿vígnH üî%ùºO¡ÏçÍô^úu™†£6“ÿ°aXüÉ­dÑÌF++¡í”ºþvâü<±ŸÐ.œÉor®LcÀú>*¢ºø‹ôá…“ŒëqHc‡v€Ûb±¨ØÊ" P}0à ürh8ç¸{D‹ÝÊÿ gò›œÿ±…Ú£…‘³€Òûsî4®Ç!fbäPªÛùKóÃV²hÑ,š=ûjþÝä·„t’™”‚Ê ó?ö Œb} pèÀÆõ8¤±ÃàFìØ‡ÅÒ¼±•E`âZoZIKgÏw$ÈfIR¸rž¤Ǩ`xÐ]u[0{öl±•È®´0ÆÕ¥[ƒ,Õš©³-–ÂÁV€~ýûhí¢U) š‰yi$Ù0a=MŸž¹”"çetèp¨Øª@úcìP]ºu»Tëô4 =eâ츉ÅR8ØÊ"ЯÝÉ¿:ÓaÔÕ9èróÍ7.„UÂ&Lg’$jäÒ­ÓF—Ó˜“…¸Z Ìa×Ç>LjÉA]c-e±XR±•E _+9³¶ßu[0aBMœ8ÑÝ GPÄjWU¾Ô¥[;Ò ÷MW$bÉŠRÆ>ÄTÚ ]Øq‹Å’;lej‹Þ± å¨ÒŽ9Rl3AL£‚phE“'W&I)zWU~­É¦J>àöÛoÏx¡'‹ÅR¸ØÊ"K’¡¹U½éYþŸP¥Íu`šè‰”yQ®wTDë×cÞÉA)’O+–(†šQ·›Åb)lle‘©ƒÐ¨<°:^tc ƒ ÃSW lÙU…øE9ï#ÔbÇÄ{'SiéÅ ’¶••É’Åbi>¤T3fÌ îüú׿vX¼0µìãñ¯øÿng'Çè]Uj- öA°j·éÔcûR=­^~?-\¸Pø‡d»ž,–æKRe±~ýzQøœxâ‰î‹¦–½³øQg'"Š)QpcþºØÑ¨¾}é‰;îþ°Å>æ7Ü;fLÒ¼‡šicù÷ Šíß+ü¦CUÅ:P­ÒÔce‰jï^'<ÕdºÅbi~4”tŸ~ú) >œæÏŸO‡rˆ{ÔâGrËÞézúùÏ/çÿÑœ½(QpcþAÒbG¼ßiŸØbß`óéE.Øk©”Z¿ ¶é‘ê±P_¥êÅâØJ6 òZ¬ˆºt‰¶b´X,…ICeqÙe—‰Úüàî‹ÄkÆŽ>úhúå/1ËÀä~è!Ì·X&~GÁ²e˸ªp n®.hYyyCá-¶6P¯µ œ…x‹}“ͧ\°÷£Ú„c*Žz¬£¾J%%âØP¾·4 ²‘ZÑUSæY‰Âbi!ˆÊ⡇â2fƒ¯ÂþýûÅ*Jªk®˜æ1 ’¸úê«©k×®bL`Á‚©|6¡¾J„AîìÁ}¦M›F{É)¸k© ½é&ÚÓ¡ƒã…x¿~Ôv`_ê7¼Dl±o²ùTÊûFLñÖÅ~Vx-Kó¥h÷îÝTVVF‹/¦6mÚ¸‡ýA¥‚åö¤kèŠxé%ѧÞ\Ü›+V¤Ìc;f ?oºõÖ¿ð~JLÁSÁ wö8kp' C5ï,ºÍ§¨ vt½ùYáµX,Í”¥K—Š.°ˆtØÅbâ÷—_~)¾PÙ·oŸXC:,°ƒkšÓ²ªp^K«’»´*öY4.ÙÏñ;Ý",ékAºÆbýÝp°ñNœ%RÃ-ò"ïU]íO‰7õwºsQ’˰ ‘|>o¦÷Ò¯Ë4°á˜ü‡ ÃâOÊâGgu½òÊ+,¼Ôà°>»ñ› 'öŸLëÖ­ÅÞª4£eUáLK«:´v·NçÓ7ŸGj²³“%hÅO™2ÅÝc1ÐUµã‹%ïˆ*CãôÓO—••¹{éÑk æ„º´*¶¸’¥HaE¼](ŽÍ™ã´úáÒµp‚´„¤8H@Jr?2¿tתqS§;%¹ »Éçófz/ýºLÃÑ ŽÉØ0,þ¤H¼cñAïûÿÅ/~ážq8÷Üsiùòü˱Õ¡CîZý(LîÁY@eeù5:h±Xš1ÔîïŒ6º?Z³†>è ÷hÓâó½1Ú²£ õê¾Ú''‰Úº3¡‚|Ú¨^)a.X¶ŒÆNŸÎBkŠÅŽ£»®9Ÿþû§ ˵*jV¬nCåûhæã5ªdIâ¼óŽHº?Ýëë×ç¤5×ÒZŠù|ÞLï¥_UœÃ†còU\,¹•,xÛTñk•¨çôoì{Q»ö³x_Úß\ÍâbvïÔÔÄûÇb|œâ½©8Þ“[ø}cíÄqéGw¸á <ܯ¨ÈQÍÅÖïþ*ŠRA°kÿ‰hà÷ܹ/ðV—Nœßð5jZù|ÞLï¥_—i8:aÃ1ù†Å½\·Ü!Ѽý,­ªÆøD“‡j·é>–N¶ò¯ªø±¾ëU«kQã~r‹ð–^G¹‹3…»Vš9iÛ¶mŠáDiñÖb±4ole‘è¶9ãŒ3Òvý$ãƒlÌNµÛt‘ãFÄü׫Ö×¢–ó,2™o!µµ‚^ ÓæRû +ÿ]|qò“'G3§Äb±6¶²È!IÆøÐ‰ÊNµÛ´Õõ7tÊßõªo-ê7iúôds'ÕÕÕ´p¡³l,¤Ø‹²X,Í[Y4²+«²Ò)t ·À5/ÛºwïGâ·.D½2ŸÅb)leÑH  fU ó²­]º8˶ªÀ”ºº2Ÿðg±4/leÑP—8úuuÎ l±¯9u%½†ãòšíÛÅfïK[Rý¸Çêjà¯3MþÕï¨(ædl+¯»Ž:}ð‰Øaºá.©¨HZ™oîØ±bÅ>=ì0Ï‹çÆó[,–FFèDeIKR Cºë‚†+ToáÑuêD=õ¸t¦óò˜œ(è7aPú…Ãïw[õ<¶êoñ#N< h~ˆ‚Lï¥_—i8:aÃ1ù†Å«:«!ûÙ÷ì)Ü~v]«J_/Åi+éÁÉkÎýóoŶû‚ëSü48÷z˜.Áu§»×b«†…-&+ަ­BÃKº“Šü5¼‚8] Ìb±4"¢ÊÈ’¦*Y8Ü`1–Üm•±U’i‹%ÝuAà êOÄ¿ŸŸš¬O²Jlƒ‚´ :Y1(Až£9‘ÏçÍô^úu™†£6“ÿ°aXüÉ­dÑDVÊCŸüÓw®£»GOHêgïKcé½ÛœgiÂx­ LŸwÌ‚ Û ÕRÃ+ÈdE‹™lޛŒsD•‘% 5‚kίŸ½òŠ™ñU«V‰Uê$™¶XÒ]4Ü þZôª¡?¯¾jŠä³µµñ Õ›ão<þdƒ)¸bvÔ´È'až»©ô½EE¦i«_—i8:aÃ1ù†Å]²h‘†¥aÀ˜Ð†7Þ§íŽÅ8»Õ •Ñyóæ‰2XÞ@W:æÉ%ÝuAà êã/P[ bh°nq­c†„Î Š`„Óÿ$¸ö -`Æz¾É4Ý›aÞ[TD•§£zGaÃ1ù*.kH‘-˜×–ýìm)Ù¸¶ŠŠ„?Õ_Òµt‚¶„‚úƒD„g b†\•, UÀÿSsÖZÉ¢óÞ¢"Ó´Õ¯Ë4°á˜ü‡ Ãâ^®·hm(Ìœ–ýìw]~“hÓIã~Ø®¯¯þTC~…LæItÇãL¢SgX'™"))ç8P˜"y¹¨•(öók~çªukqH÷Þ,–B Å«Î¢ D˃~ÂEg¬Á¸¶Rý³©¨pâYÐu¦ú“…=ªÕÖ0hÝnO<±ƒ­[;P{üÞ›ÅR(´øÊBrX·ÜšžO¯Åœv°ãù†¿Æ3äî5K3ŸÿzÇM4¬W?£æWÍ´±ü{…qvt§N(¤Îp·–|àTÒ™šž·Xr­,’¾ÞƒÚ¥ShtýüCÑm6pÂ9´å´Qb}ð*ê)ºÙ¤{1^ÏÛÒ‚ïZkIdczÞbÉ5¶²Ð²ÞƒÞ¥ShFó’f|»³±G³††tbE¼­¡]mÁi‹¥É"n…l…¡9`+‹ «¦„VÒÿÜýý½êºw̘¤./£yeÏ4x=´¼\¬¡ë—‹ŠhC¼ ÿLƒòSa1ÖbiŠ`ìM6ܜɤ…ÕpkNØÊ"ËΤ-4‰~wßOè´1·Ò¥qgYTé¤Ö”PòV\!iQIͯGy„âÐ0¤â8æ”LŸ>]ü¶Xš Ž%æT3Íi¸õ¦bêQß›·eÍ C!b+‹4@Ľá¾éP‚`;šÝwØÉ./£y…¦Eíšo~ó›ne‘ ¾þ+÷—ÅÒ4pÖ·O]Ïþ>:–>ݰÚñd‰[Y¤aÛ¶ÔÕâ@WèÒA׎ԚÓFWˆZT&~©²i±4œq¹Ôõì/â"í þgº{–(±•E¼&L=÷ÜsbPÍÏh^!†3éôOž¯‰SÐ2dˆøm!iLé:ý…»¸ÅâÏ$¯gÏGÜ­%jledH.VÅï ¦0Î1vìX1x °7n\NædHµÁ°a[~Ks ¶Â_Ͼéc+‹À/\Mã_}õ½þúëî^4ú|KîÈ´‘˜ÓÍ܆Ǝ¿%<¶²ÈA ÃÓpÔyræu`¾Ç õ­©'ŸÅVÎ÷h¬ù–üÐøg,Ü?“¹ ¶‘Ó4±•E0 "ë†áðÓpÔyræu@m°)[ɵ$ƒÊ½7m¤í5ub5Gu‚§ÞH2)ÔÏeÚ ØRûw¾.1·á„úègt9í[µÌxÝ!ž°SæÌ‰(nˆÿÞu+"kàD©Pb% a¨jÞXµêVºúêXNYËqÃ@÷‡æ»IiòùÞmÙцzußGm‹ÓyQ¥sSæãO?¥¯Ÿ~º])O®¶Xå±(% y~MXÉÂ+`’^Tÿ^×úùÑ÷‹B‰G¾Ï›î™ÑÂE~Á7‡m&-Þ°i›¼š_•òá, õްB¥s“ïÿ°ñ‘þkjß’Ÿ”“o‰­9¸Ø©åº³h‚ŒiE¶rZJkÇâÌ“‘+<úM (mÄb1þõ »sÙÏû²ø7·AÎëÁ܈0ñ7ìÚ•Ð<ÜÂrE?!¯Àªr,Ùk}Ylå1‡kåìpé¼Ìú4[·f R,jŒ{î¹'~ 'ÄÛ·o/ÜÉ'ŸÌ5v¨M‚`% 3ò:¯k¼Æ4tüÂ1SyÝCõ£þÖÏ5&…|!Ÿ7Ï6mÑúçÊ‚¯Ak³ˆwS$„ôyXÅtïtñÁýÕñƒòrH7¸oª”?·Ür‹{¥CÐoM% ®)£—ë¢i€íÌ™3éÅ_ýéçŸ>ýãÿÀiKŽP¥‚\h]À|sP«æL.Ò¶©óÞÎíBûhﺧvÐÀª]œª‰%5°úpYŒQ¶¾TOmi·èË–d›¿Lêá2>Û—®LÑ“+=~p‡$)–.¼ðJ6l˜»NóP¥1$¸‚FT9äÀ5©•,ÌÈë¼®‘çÑBS[Mzºû…c:çóQ¯ÓÃÐ÷‹(â¡·Hõ´Ez ?Þk¼(ŸÈçÍuÚ# úQIâf® ӯυ6oú)‡üÇÝTLïUhA%.H|¤ö””  …¸Èwøø}oôr=E 3}ôQ9r$mܸ‘Ž;î8÷Œ7Í]ÊKKŤa¡öÿoÍ–Úºbq¾s"„V”ƒ®uá§¹âý,0Óì­q¥^Ô0La6H÷Q§m¡ÅüNÜ5œB‘N£eÁ²e4fÚm\„K±Øk4ÊU4ªídá=ÿxD±“Ïr”ö®­¦¨ÝÇG.â4Ù&Òä­ºó«)_‹Åè³xþ…¼’ó—¦üez×òûxjÎ:šTö½¤ûSŒºÑlº~A?êÕ§˜ž^·W, ¤–ÅÚѰËfÐoïšÀGµï ²’ΰ&B|ñÔ†Ú´iS¼]»v¢Öå‚?¾|ùr÷L*ûöíµt¨¥9솨Ð1µlä1“dá¥ÿžî˜é¼êÒ×IÝÔëM˜phJ«ç—§m¥òŠ64øÌ„![>jKL=&¥ /ÝnH!ëj?§k&œƒ=ç T²@ßë˜1÷ò›}‘[ÆhþüKE¿ª|¾òò4}zê< ÐÒ%‹Íœ×ÏG §Å™OÉ¢¾¾7ï9ÏݪÕ&Ñ'ÿî»}ß;®­©yÆ;†ýtËñVT8’˜ž¿ü0å/¿o²¦f ìŒëÁ¾Ìæ¼·³CRÞØ¾ó=|áTªçò­-½DE´—öÅúS壧Ñô39KE,AÎkd ²©xžÅYg;v¬»—Ls“,ÐjI´’.J:tÿÓq/¿~è­&쫘ÂDš{Iª/-Õú[?טD¯´õK¿ÆB>o®ÓiPT4@Ü[™&AÒ[õ£ŽèùËÓ}ôcˆ“ü&M3²MaÀú®¥¶üà½BzjÌ÷ÛÔ@y®–ëžó,øíß¿ßÝK¦uëÖ¢¦Q]S­Õœ8?¹øVi¾ÈDë"¨e[Uãª%â•¶QÎu‰–`Æ%³ié `$¿é¨švDCèÙgð2E>/¶ú7ÔÄ¿þ®ÕuZð^ýÖŸ±¤GT×]wýío üÊ+¯ˆ•Óžyæ>|¸ðÔœñZ6•[ î¯ü63µlkñN[½Ð<÷ÜsEA“®PÊ(€Qð‚0*ž™`jD¨¶?oÒôéj«ž÷3_¯EWm={v †‰°ß‘%8¢´Aæ¸øâ‹©gÏžtÖYgÑóÏ?OO>ù$}öÙÂSsÆTè‚.]º¸¿ | …Ù2nZÈÂòÙgŸmT³Ù(hQ£à¹\0Ë„^`û?j«¾>³õZð|ºqÛm·Ù†P"Þ2¤ t;½ûî»ôç?ÿ¹YWj J/t¥ ƒ¦ÐmEwB!cš¨¹Ã¨2³¤¢"iÒW&f¿³qÛ–/7¶¦_]š›8¨&ÊM6*ªGyÄ£²Jm`áûɤ07Iöؿꪫ¾ÉLBÁ%%K ÄÈE–è!…Œ×À™¬›3ç_b«œ™Ó€iðØËo6ø…i:§3~~ôýÆ"—ª³Ò5¨ªòV?¥ƒªæ*wëuž‹_þ™p‡Šj Ÿâ7J‡4öR§…ƒ€:¸,óÌmÈAr¢b?(êwã§h`ú¾$éò¨×wn Ž^®·(åh%¥Sô3Q®ƒ4æ§¶ê¥~˜ ~ašÎ©Ç€éZ??¹x†LÈVu6AÕ—³“ÿÆNŸÎù®^´ÈçMžlTÝ1e*-^ñ4ÿêÉfÀÿ‹6T_cœÐ™-[^ÚKSGí ët§ƒ¾õ1u;DïjÄÇóÿÙarÛͳWÒÀ~m“&šîùà*0ަu´dmß@¦ÅMß Hgj?H¾—ø}ç¶›68z¹ž,K6s¢ZÛKlÇq+ú6-0ÿåìÅt}ùoD°…’GòÁ½Ó¦%wqqÅ¡ç7yÿÁ•â_G±»ÝÑìî§wÛ~Í) #vñÖÅô ^£N£Î¥¥4ß`[ÅîUv(j«âÇŠÙÑ[NE{F8J/Øvšp…øý(]hUF¯ïŠ~Ý©ëׯת8k›×Ï×ø-!_d‰.®*~"¯kýlCÉc^bûĉs"úê÷W1S™Î??ú~c‘n¨Bqè¢2å©…×Uº©-¦Õ_{üÉø¬+þÀUCqü¾7KÂT‰›§ËGWp¾n'â†íÝ×N/©ØïMµ"¼t„=®®{¡v‡aë|ÇÞö¾¼¾sKpôr½Å­”1ØOä Ò å%æ¢5o°—èVWÓµ~~üî—OòÑ •k A@»(ÝŠk,œ® Ö¼×‹ZêûiÅã[è?Ü^ƒü‰Ö54ý¼òž×;vº‰Æp>vâ‹5,~w̓´tæÁTK~tO••ý?ZqǺqA7a£I]|·:ÇúöÜK|üNJwW«¢—i§Å»š]*¤›iE½y Ò€K.¡Öü­!•J7™´”€ÙåÓ¦-áøVÓk±Ñ4{þeMB$È»Ë)å:*‹lÑk BÇ4p&[6A$ à´n³`!U ÔÖ öÑjÊÓý%¦sê1Óy ×ÓÃëš|S(ñÈä´l‘°Õ[Â'O9þœ­³‚\PÐrv¤[gÝ S«[I$ƒÏÖÖŠD–ëºCšëºo¼zŽó"4WÃy<Èêtpð‹UìŠÜãØb_õ«*˜ŽI q“ÇLþT·vÎSîS6Îû÷–˜ò^®Û5¸µÖxÐn Ú®9á„ÿËÙ š_KßïYp ˜®•~`?jÚ´äǾ}GyÞ/Ÿø=wS-Fô™C½Ô/?¬Xñ&ç©×éîYGRÕÕŸ–ª„ÝŠßsIê Žw¥½t(ÿò¨ß^SG[ÊO¥œWk8¯†•V0Â2„bÂöxŸÝ.êÛ°îõØKΧñWüTœ“\ïóTQå `‹¼5¥T ìoÛù­Þð)Ùÿ êÑí0q^·à ÉbpéPúœŸ§ ?l=yIÒ”n-Wćԣߣ*æ»7cj±ÊcA%  wZ©6w²ÅëþÀtN=f:œãæ¾]¬>æu¿|â÷挔òæ_â<|gR»MgY-ú˜ë_Œ¯•—% gÿvâR׆–¯ã÷ƒ$¤Ž à·¿“~ÂŽàû1IdÎw–ÀTP*ú˜W: ĺdçiu6Zªda:®[ÊŒ¿¶ß³àðŽ»yÍ‹ÊÊÕ4nÜÆûå¿çnލj¥ÅÔ‡[Î?â¶ü*+;‡¥‹êÚµ«±•¹zýz£]L‘û†×øÈó¸›*?ôÐCtÍ5×°„\ÏÇZ‰­:WTô2M™2…¦NÊûÉ÷ƒ©¹–~ôþ…óK³ ¶Þ…Š—D&%°ššcøÙÌÖrõ1/“•èBÁJŠ©Å*e#Y/¿Ùà¦éœzÌt8ÇÍ’Å¢Eµb_Ói ¼âÞA‹[\\°;žÓ“ýØð«®îg¾Öñ?kÖ¬$¿ÀO›Ï ‡¥–(Æ'~ëþyä‘”ûé’î›8 £k`É~ô8ë¨yÃ+Ÿèǽü ^’Tc¡—ë-jž…E§3Mžœl_j‹U#GŽûémå–¼˜û(g2÷Aô;Çò3¤ÌѨ3†º±„16¬ºv£{'Ý@ß}WLô+rMÕ`;ñâ‹iæW)AøíæøÅšÖÿ½¿Á¯û+o½µa>ÖÛ~¶²’Ç.híöÙù.MþÑåJE4åÊ[Zþpßx®]4cÆŒ´ãwÈoˆ«Œsü‡V¹ºõ"¨¿ÆÚZî }a[pÚ[¢ÊÈ+Y¸/¿Ùà¦éœ<É`î܌ת×É~òE‹^Mi1m 悺kH6÷‹¾rlMç½Ì}@²ãï°ëÏc §°ÆîTv8Ž‹ q„ŸØª~{ó={ò±¾¼íK5ñZê/ç–>ÌtÀ?Æ.¤V’îLÚK²ï [Üï þp\TÉ¥˜0Ÿ£§ˆÇúÊJ'Ãy¸uóÇ»ò5%"žNÜ¡…±Ý/4œ0ŽòëÿžÑ06¢Ïm‚WÇǽüYÌèå:']öØÊÂ=ÀxùÍ¿0Mçä1çãp>l ª¨×ÉßNÅ’Úí…úo&4§Ê"ÈàªS0CM~±í*ö½ rÝyUHj%‚›+–uÙÇg=¿óêÇâK§?Éo W.šÚl,gΜøk³îŽWþê.±ÅR3ñÞãeÇÿçÒåñŸÒƒñ~Ï}kñø /¼Àyê»þªµªÃ36 ¸ó6È3£Õó«Ú¸‘ù ¹lé6kŠèåºàvÄä±l¸½üfƒ:P÷µ¶ïѪ?¥AµC}Ðê ÿ_Œ.›ÕGLf[©–JbhõòІÁ2u©Öxq[g ÊŸwÞT(6ušÃ¤¿¾{7µ+æ6ùÞ½ôúæÍTyçôU}½èÂ状 »îìvRŒ¯Yž2*L¹*®ò}v¥ïÓ²µ7%Ùq’yjÔ7Ý4N˜ÆàÂTXzÕ»BÔAx¨Ãþîš_ÑÒ™'7¼#g©Õ bÉ†Þæû:ªµÈ‡ÿK­Šê¶‰ ‰‰|‡Ápi› aåååb1#ù\X"õº’^'ÃÒ¸î º|®¹sWÓøñ©ŠaÛM =`Â]ˆ\! Öùì>Êå$>½\·•…Sž6+ÄÊ¢n1ö#úzoÇp†s†q†ŸÏ¾/ÿõçý ¼ß÷axûÇ€z^§®zí-é×çÍ3܃\¤ec‘ͳ¨A+W®ö”P µâB´’¦N5¿ŸY³fÑoû[þ¥’/ÓŒr?µ¡pÑç yÍA<ô¹Dƒ8OýEœMÆÑ³“÷MhC=2s&}óß ]»Rg·ÒðÒæ]Ù©óEj_ßM¥ÆñøývXw&qœްe]3{5wå’AŠ¿L1ͺ/Ší£oº‰NíÝ;«°ƒÔ@e¦Xm(Fí‚‘Èc…Ø …Ù¶ÇSM¼(¦‰Ò,ZÞφêÄ,\üÆùît‘è«n诎µKêû…:º¶g9†aµ¡¢#Ê4E7Ϙ1·pxŽo/Rµž0NátÝ [æ–[nq-œ ΧëË7iQt~4¸Íb|¢&~ÿvºÒ†¹§úÆYBNÜŸìj2×`ÿg'ÉÁd;‘úà™œßêŒp8µëÇM3dzqr6y1õßRWêÄûN7bŒ·QÜÃË©cRÒ `'ǯ¢pú< >š=¶²p0^~³Á ÓÛ›Š¼?Æ(Ð/ ?Øê…€Oõ·~®1)”xdK”ƒ«NXÎxÂãV²gxèCOôÕïæB-Q°p‹%ÆGºR¹(ôüúò“ÃýûÆ¿I±ø0š#¸1¾QÂñÁ¹N “¼GÛx7Þ—lå˜>ºªÑ£¹1ä),b¿ße¿À—n8ûýûÅx â* âšiÿ=1^9y‰h8‰Ìâ:4 Ô†Λüeêvsã é|S…—nbd¡;;)ñë>2uCyM´ó 'Ê®'Ì7YÔLoND½ÇŽÞ&&T@s.ž!šÃ˜…©?>hˆÉÆÙ¥¥ôŠ8ËE~€ðDWÅ´ªÏâ+‰+`Ô› nr”dÝ0h#õ¢£éô†o_¾ÓGŸè¦œ"?yµ¼‰b±ãiþü iÂääïò †«k3Vžš¿ó‰Œ´É¦Oϯrˆªüõ÷™R®‹*#Kô¨ÐA#OŽ­DS% Ó€öå8_8ê1ÔþN¿¯3Ȥ5 †™.ütç%ª?ý¹ïH2áâ%z¼š*™¶MÏk¥ r8´fƒ†÷ä㯉¾MÆ¿IGðõN¾Ž sUñš9k›±ÓûûU'•(°Õ[úð"ÎñÖüý8¿3èWÃ/Ô8©RWSG/׋xÇâZÓ\Hº{ü±‹ZÜ /Ÿ¯ÛHOß¹Žî=!y‰Í±ciÏŠI~u‡°&ÂÎÎ3¬ šicD{s+¶·ïS–6®Qº|?w®@ë23$Ô-Àµ»ví¢™3± éjZ¾|gàð>}q•X*õN:žþEoÑTú¶8>[,å:ÊY&MdvXBR ¶òXƒs—VÅ*ݵÔ߸¬ªéû‘¦eË8^¦ ÷‡­ò¹šÚóBTYÒœ$‹9s’[hµy˜Âñêg7õ?‡uÛtO•tç%ª?ýý¢ˆ{6Nħ…áHÞTú; $ G J¶ôO‰Nýâÿxð©)¢f6¤‚Ub+I§Jºd¡·¬õïg„…IçÂ(àzló…ó Þ¶§Æˆ_®ÐËu;fáö{:ÇP,–¼Zma´¡¼úÙeÿs ZaÜ“Ñ`0Ͷöê³5ÅÉ„ê¨×8ϰ†ä2š3L³ÀsúÜêŒãæŽiò›®ùô=«8f½1Í-ÙäøÎ;“ú»ÃÌJVã êìnýû)+»æÌYœr> ú÷……”T‹QDë(Ì÷Ù”°cŒ©öwü1k3xµLÇÓùM7ÿÁ„¦Wø’tç%ª?ý¹1 '®Nšèö¥r¯–Bº±2IÚÜü»Å"œ”pÐ<‚G0æ×™Ï·æ­ütplÆŒ‡9Œ‡ã‹½à¶¾a'?ÙÙg‚?¤ËÚ95΃³Ã¤·˜¶¹œÄ‘ü›z¹nÇ,\víÚÆÿ“MDä4 öìA?åjw›°o“IÿucpÁN_{eå'vo®XAcÇŒáös*¦Þ|¾µ0ú§ƒîšcöîuúiˆ+@m yÊXg[y8“Rȱh¸Ótúó®×S+Þ½¸Øéÿ‰Èu<˜.?Ÿ6qY€)„ØŽçwƒãÒl«mäôDT³FÈYÒ ®¬YÓ Î²“ªÕo4 ê9ǪXœuãbýã·••%­I s ªèŒàà[‰éð:õÚtá¤;/QýéפÛÏußBA,V “6©ÝZÎê{XñNGú… ×sŠS'bp[÷²¿$$°††é¼nB]:?ÅŠãéW…Øñ¶[+,Ý€¦ðÕwæ½:z7?Vö4ê¼µ‚w2ÂÉŒ˜8æ~ îqÕ¡ÂÀsʾcSÆðÊ,^ǃ ^›.œtç%ª?ýštûù¢±î› ²O=ÊÂÊïùä ât¼@ú•ÆñPiè3­…M$· V7Bà éö—Tí)ŸyÅâ‹~7K„SU;OŠÖïËëd£ö¦dƒÍqˆ_‰¨,¼4ó ¢‹8¸ÑnøÝÔÉmeÑD$ dZHâ¥r†ÔI‰CöÉLÚ$ ¿Ö¨Š_˜éöóEcÝ7,éT+3ÅïùæÇ`ëÈ‘#Ù_¢bÁ¾®—…<ü àòÜN<œ´Â5~ÒÌËP·•×8wq ÅgÎ|Š·éó{.QßEØ÷RÈè•E‹TèÕUÜLÇ5ÂqT_ÿ•è;ž7/± LÐ0€×ñ ¨×¯pW“ê¢ ¿0õ¸f÷lh æ>‚¨VA7üLÊD­ØK\%¡¶{!ï=Êî§ÔªÕÒ$µ] ÂûIi{êE éÎ9GÑÀþÏ«§Õ'ìœámnйª¼üÖiÅœy´ï½ÝTQ±„k†jÚJ£éäA‡KnðÌ`ì£3Çë-úÓŸÞϔIôûljXÕYS À«Uà¨Õ®[•0ax‚z­W8aº€_˜éöó…>9°9;Sÿ¼é˜îÂLX òãr l“Õv%G³ëLf½¹ªkV¸„ëOßàjNÝ‘ò±GcåM5…Ÿ¨ÐËu« €NТ:ÃÝ&0ö—©jb:Lf'òT¡’ÕDÑT+@Dµ2«^ŒGv¶î±^k©Û$¿ìr¥®Vm*¶Aß‘žV?b×…÷¡•…#1±­¤]÷;qþ"ê&Ì–o¤ó<'¤^ôÿ?šÝI'Äÿ›.AMˆ ¢ÊÈ’æ.Y„9ÆoPÔk½ÂÉ•d¡öM›ÌNä=^… ÒioÛLÒ(ì³f’6A¯qÞùpá[¯ç‘á…‰‡)­G!¹8¼3þ€¼ŒAöch®ð›,}P¼ ÅÄuAŸ)—¨q<·‡ÁÖ+“Í›¡``Ç,Œýð^}óaŽ{ù Ò_ì…&0…œñ•„‰ä™3ÿKÌ‘0™÷ Sž«©ySÌ-I·àR®ðJËB­CHq™šŠû¬aü#n<÷íëÁy°s kî¼ó}š0áPš3ç}ºâ ˜OEÆ„yG^i¥>Sb-ø¥|&±Îv1õaÙâeºhØš8q¤ï¸Ž ÓØP¶¨qéâÕ8W.Á¢Yc¦Mãj/ž²•ý‹_\)ZÝ`ô­ËY¾MŒ‘øë˜ÜçWOàTëO%´U„½h ǨŸØª¿%8 CîØ6ê/²û›ØK`ì†zï½÷¨cÇŽ¢ùþ÷¿ïõ¦)uC¡ö²èù=¾¿ ÇõcÀ4hŸIVÄq¯uŽuÔ0).’ºÅµb?Ôu‹««„¹5Lõ~‰î€ü­þ%ñJ÷æHØgM÷žWð;.åw\Ãïx0ç7•Ç&WÒO¦u÷Ì,^쬉•#‡»ËWèÈ8ƒ(Þ‘žê>ÀoÓùAA£pÂ軩'UQŒFPyùмØ;3u•-[¶Œ¦OŸ.L”  jòäÉc{Mv“ýW ›x?©JgÛ¶mBüxå•WÜ#ÉìÛ·Oˆ&Òa  þñ»ÐI5}èZÑÅ`I˜ãú±°Ï&Ô0åï¹s_0†u°Þ±:™N…+gÆö¤Í¿>Ð÷M]vù@Gs&ì³:ïÙY“Z\¤8uV4òTMy¡H¬k‘ŽBè†R÷åo'^»Ei˜o(Šï0Sôç’àÞ(wò‡°¨Ý—²\OQåctÕUWÑi§FßùÎwÜ£É̘1CHÒu邨¦A.,zú¼(¡EÆ'$$½ ÆÌ6r[²tŠñ3w†ÛVjO/¼ú|Z•XÙP(ƒo¢w>þ„ßm?ÚÑáHçºîÍŽi,·Xe·'ØÅùàeÎ{iÖ F3›&Ï<ƒüÞóÿ cþ÷"—ªå™‚2 P Š¢÷àÕW±®b‚”ÊâòË/§M›6у>èIeÒ¤IB4‘ŽkF÷LáãWxçj>^ö¹b¶GöO¸z%Ý_YµÄ¢´yYV¹éÏ&ºÖÐÝ…mê=¿±4 üÆÜL…"¸ýöÛ9ïíà_ùéBÌ oÒUc8;c0=ë[ÓÔÑ÷Ðß«hÈÿ^î¸}ûˆ¥m¾Îëá0ìø›?GÉ !_¸pEçB3þÆo¸G‚1AIq¥) w­øi,y‰‘¦ãaüEÎd–š"þݰcp~3{¡Ï^L‰nªžn¸O¹ öËn*iümÎÄľº >ž]-rÉÎæ Y¤9oýH×âw>è=@avC­ù³]ø¨¬$EC0WèÏÕTÐËu~Xëëã—]vYüˆ#Žˆ¿öZúþL¦XY¨/0Ýèõ²MÇÃø ŠìŸ^põZF7ïMÅâÃÑ-‚)`Ñß+?:8]ÝO݇Yi"·åý°eίâk.òs“8ýÍ©FÃäÁƨ,ô4PãëüÞoËœãù ž­ø;€ÛÏn휧Ä÷ñäãáÄÙôÝz¹.º¡ 6[]]M<ðµoßžÞyçáöbá’@!ögª8ãýè³.ŽÈ¼+ö½L{3^ˆ*±[(aváW¼‡õµy|†P3‘êˆíyÿ6ÚM½i3õdŸ'²¿¹,Êo¿õª­XNŸ/xÐQOÉ‘Û^QMQ5í?ëF7_üº•t‚Œ¹eÛíÙKƒÎtÑèùôÚmA>*x¶ø>ëv”{en ón ÔؘÜþðQ£¤ÃJî&Œß 8×&w“Mœ8±!~*Aî#Ããb†·‰ ´bU D:]ɵkÎ’Eº¼gÂKrP1åƒ yC’OÉÂ+ ¤ù„-ïåÄëþÂ¥™D†“M|ƒ’É»-$Œ’oî’K.Áéfß w!à¬ý<±–ÙÖ&Ö×ö^ ­Ø× FòÞŸs'Nsë?aô.®%¬mœ‰TÛ%?¼Ò`÷n¯48‰¦L)ÜïURè=aI•çZ(…üîÚ…·¹ÈtX_Û[uǯš2ŸÅödÜCt<@× êGåZÂÚÆ™ªr7'uf¯4èâv»š¸à‚¯0󭦟kle¡P¨ ÆôW•¯LwÊ)çñÿ4sæcžˆ%s ]ªÍ^inI€B¯0›Û»µ•EÀùhæQ,–ßL—œëL“&ÝD+W®tNX"¥¥Ú|Ñ\Ó 9=W‹¬,`jýúõî^*#Àd¶\ûËŒQ4{vþ2]¾ ¶t ½•œšk4—çjq•ZË0s@šÏH°@¬á0hРsÎójwÛxtèM¦KÌP÷ž©î78—«™î‹¥p‰¶²xé%ãTûBq0‹qï˜1ÂLÌe€*fѬ+þ@Û–®¤OV-¥¾äœïËç°­`ÿCJáû74dH¯¦­'Í$º–À®,ÍÏã58÷â‹/6½q‹Åœx4èã"¸&âä\¹0=f'ß®œ‡3-(Ïfƒž´ÔÙV-Àzéqg£ß-¯•ºï~aøÝǤ÷]Tä­÷­ëóc|ýz5=¢ÆïYšaŸ5Óùtר™g!g& 3züÔ}ù[ýÔóAÉäšliŒ{FqžEd¬YcÔ—/§.?‚°8 ~Á¸§»ÉìpDº3Ù%wÄ$«¬¦³[h˜º–êë½UpõÁ9,ÑÚœôÆ-™“,¡šºs-Í·729jQÈ9 Ã©–ªÌ&˜HEE·‹BÝ0Hž6ñ©ÝÇç.¢VEÛ Ð3K§Pm ît*}Iûè´•æÎYBWLèD Öö¢¾óÐfqy-¬`¤[øÅï>¦…ŸŠŠ6ÑÎÞkj«áuìè½pT.4³6®ûœF¶…ós»VÕ‘‹u–½ˆâ^céêoЈò£|×nVI·ö´é|˜õª×"âS]±†—~èuÀX*Šã'Ó6ú»8s1«—Wd5ž¶î¥¶tÚ¨^´vÁØçsãÚÖˆL'y,ÈóH‚¦A”y¨1îú)}ýôÓý? ‹.®:è6yä‘GŒ]20V3rQtÅèëþJgêÊ’†ötÙˆ¢òÚl»¡€ÚµD4 ^^ž0ç…‰µ[I/ˆ©‰¨ièD4”˧9’(î•ÈGÁÃIw_Óùtר®ÚÍÓØê礓~à‚„™Îé÷Tã+K?ê1lÅ.è5™„íåãžQ8 +¨åz‹“,T e¨K†Nž<ž**F¥´Êïýývš?ñCúíÕïÓÏ~¨8†ÖÕY¥?¡ˆuuÛ°C ‹[ê±—¹jy‚î_{zÁI’+öPi)Z€{Ø_'áÏI‹±œõB¢Âd"tC™Â“××Ôì¡Áƒs§˜©d¦-QÜK†VóÏüw VeºV¨é|˜–ë¿>,¢•Ï~Î=å#úæ!É]ºdÑ….¡oƖЊåF*Y¨ñøÝõðý´ëÖIÇ‚<$hD™‡ãžQ`% Õ|°W«Ük°Æüðܪtâì;K´ªx…ym’À¹brÌžoXP+Ö±èKm…Ñ@é¤és“Éó ÷ˆ‚Lø(î•ÏøFE.$ÌBJ‡ÆˆK!=?ÐËõ7ÏB'› 3eee¢®âLí/|Û/½h ÕRÚÃÒÃ9Òtê)F!¤[ÏF§ÒR*Ñ_øk³ ‹Csš™l F‹¯,²ÁdûeòäJœû…Ì®.ºQ9 q³@)»nìÐÓë²Ðk –_-™‘MCËÒô°•E–è-,XÃl ì¥hËqE9X.ì¯.ªÔ,¿Z,–ôØÊ"šf +Õì9À:Öº¬Åbѱ•E‹Ålö|èСMÖ„²Åbɶ²h± BÈ¿Ùs‹ÅÒ4±•E‹&¿fÏ-KÓÅV-œ¨Ìž[,–æ­,,‹Å’[YX,‹%-¶²°X,KZlea±X,–´ØÊÂb±X,i±•…Åb±XÒb+ ‹Åb±¤ÅV‹ÅbI‹­,,‹Å’[YX,‹%-¶²°X,KZlea±X,–´ØÊÂb±X,i±•…Åb±XÒb+ ‹Åb±¤ETýë_é‡?ü!qÄ‹ÅhÙ²eâ¤Åb±X,@TŸ}öõîÝ›îºë.q°%²gÏZ¿~½»g±X •7ß|“V¯^-¶–ü!*‹ÁƒÓ´iÓè /["C† ¡ñãlj߅*YmÞü÷Wác?èà ¡¢n["È'ëׯÆ/ç€ , nݺѠAƒÄû–ü‹3îoº¡–.]J\p{$•ýû÷ 'ùøã©K—.ôÑš5tðA¹G½ù|oŒ¶ìhC½ºï£¶ÅI·Ï;Zµ~tõ©ÔƒNåšsm¥Z*‰  ÕË+–]\s(?Šª+¶ÓðÒÅ1•Úºbê?¢„6T×ÑÞý1:mT/Z»` ìó¹ë#Ùž;Ìó_ïóTQu)ÿºˆÝT>ú^šzéwÅ9õ>ýJöÓZúx&<›W¼¤ß¹×=FCNkK9Mô{è,àÊvÌ´Û(?–óÓk4ÊUtî)§Ð¶]»¨G×®"Œ ÔÕ AtÓãí©õ7Þ¤=zPçÎݳÞÔÖõïO´aQ¿~îÁ‘í½PØs/§Õ‹œVhþüKC­…ŽBvÛ¶mÓ&J¢Jg¤Áرc©u}=õ¢=….½4µüAeŠF]½Rdµ**ëÇ·?øðHË™÷¬íE}¶ufN÷”Ï|”ë_ÿú×é£>¢ƒ>˜8“&Ã~â\Y¸{fn¸ááOw›Ùíf·ÊÝòA£Û@}ÅOlõsùvÕ4LüÄÖ+^ªõ¸têu^~U?µÔ;Þ—6pzõLò#ÝgT,üaûï—¸×vsÃÆ>Ž«×H§Þ?pÜ ÷ÔýÀÉøâ˜~-\yƒß¾qCãUìjÜcØJÒá½Ãü;‡úÆc Çœ-ÂpOš‡à·(Vćy[T¯ªªrs¡768Aa›k²¹×îÝ»Å3©iÕªU+q<H çúài£ƒ{­Zµ*ð=Už|ü ‘·ÖÎyÊI€€îµÇŸŒÏ½n‰Ø¾SSï‹q8æ$BFΔw£p›«9ÎYô=!yp[l ®$Dœ±‘J×#HNš7y22„“®ešOþ´z?ýhâ)B²hK/±lÑ‹ÚrkxÅòG$‹}XD+Ÿý:·Ž?¢oR/Ž©¨­÷[‹S$‹7¹EôÊëoó¯^tz¿¶´sõTR>Tœ3±‚úR)K85ÔÓFúœŠi _Û•vÒ.êÆ¿¶p\Íé&ýê~ê*–PIéQâ7â‹x‚žÝöÑ®wZ‹¸oÝçV-KR,m”µö|ð žp-‡Ù“ÚpxEÞ|ÍN:”ÿŸÃî)ªýcuÆJ°~ófwÓMì¿u§h;M¡ý´Ã=ëЊóȳgS§Ü# <ó ©z€k–žü$›ù9öS=ÿÂ{A(Ú/Z’òݘˆªU˜ëÖ ºéÐRL½ùéîã#·Ò¼ÊJ0`€ðã…_+Û/mTL é{5®ÚG+î§ÅÚ»M:ÆpþŽsþŽqþžÏù[—£ WÒÀï™ßú {¤eÊ–—öÒÔQ;èúÝ©Wç[Q Ú;æ=E-ÍdK$’…ެˆÚˆíñìÐRÀµ(Zj«µµhí®ýÌ ¡ñ@”8ª\ãqGË.“šD†‡-0µ*ðÜB²@«ÅMéªÊËã±X¶·••5´¼¤óJW“ šÖhY.¹n®yg’Z¹Ç¥Ÿlœ~_ê,ŽgÚj̦U˜Ö ”,úzH˜¹tQ¾ËaÔ-PžÜÍç4UîÉû'ðŽš¿Û±$é%éà=àÕ¿UÜ‚‰mˆ¼ƒ=\®$¤ÿø;ÌDÒ‹šH$ YÈna˜*ÑÖô¦®z• ÏMç\о\Ù2¬©ÙCÅÅutÌ1ÇdÕ÷»qÝç4ê´-´¸š¨C‡=4¸thRË­Š;îx‚®˜Ð)¥8cЮ¾¾7ïqĸåÕªÕ&š1cMš4‰¾úê+ÞoE•Üê Ú¯¤åëÕg¬·Š>a÷ºøÅŸ´?~bZÍñ9Ci¢Õ9«â–ʹÝy=Ëo TjÀ«eµzýz4~<ÿrÂ/¦ã8>uœ~}ÅXRO¾_û¢—Ó¶ž½Z……ØDÚ—¹›ŽWQQlM™24з—­d¡§µ×»4­ÁqâÚžìàœý+ÎÙ/ Ié EÊÔ‘’”~ω'Òí·ß.ò7?•—WÒÔ©ÞùßÉ믿žô­FÝ߯~Ç%Îð^A{G¼§i÷.£òªéü«Þé™™7/ÔøUÔ%‹O>ù$¾qãFáØOü¶Ûn¿wî܉ÓiIH'Šm”’jذ}ªA[…Qbobz‹Ä¯¢·|ñœN:&Z^ØçL<¿Ü†!]¿2ÞÏñTïÌ÷*á-Þ›Ú²S[rHKnL$ÅçLqª©yGøÁÖ«5¨ƒpô–'t0b1H}Žôç÷.%^­Â\µáôw5­Â4]M˜ÒÚë]êdz­ßup••«ùØn‘5Âkf&ךH^˜ûyOxþvnBoþ{rÚôµ ܃ ÷Ñš5"ÎR²àÇ‹Bu7räHá)‰Ê¢[˜øgÞ cN—L;¯¯ØbßäOuHÜ0Ý6a*.€—êWy©]L¸g õãøÇ—ïÆeíœã=f¦° ¤?*qrµ‡Ãr̽¶ØG<‘'$¸¿¬¨¦Óeç_x#yá[ †á‡¾SITÅçÌ W˜ªï@}×5sÖ:áðV=®»0y(lþ1 /lÃ4]M}—&2½ÖïºlÒ!›kM¤ /lŸî=¡LA>C ¹lÔ„q±CYžTYd‹¬,–,Ù–6Q9Ò`pQö©qAZ†NFGaî-±è™h„…î-œ‚×øeDç™}À鎌÷ /ˆ8»šWèG÷ê¢EñæÎŸèCÖ$<[1·æ½Þò¡¤ûØüáËJ"leaŠÒQ J—®8Ÿ®5äsÖÔd®U”MZe‹)­‚’éµ^×eÈæZ~ï$l^ ò”,аDØ%¶W#7Î(Yd‹¬,Ö¬qõ b*ÀL ²Š 4„©d«++Süª.L«®nÁÚø0ª[Óyéd¸RDÄVw)K>¨ñlmÙ$35SÍš5K¤¼ã¶&2ÍøÈ´²2“žž~ò8üMœ8QüÖý\|ñD7D3^ñ—¶éžÑymu5¶É&ÒЯP6}È2ß©ÏDbÃùt­vç]ážþ?²I«l‰â=…½Öté½%›k½ðz¶LóRÊË«8<4Pœ°ÑÐlLd¹Þ(•>rSá„R'›—‚̤U„DáÜ ó›c ºãéhÞh’‘¯né6To×`k:orz%Yâj¦©÷wöq¿‹…T‘*YÅW<þš›:fpKøÇV‚4vÞ—S`–—/MñþìÙ»E|RŸÁ¹Ç-·Ü’Tqx噇~ؽ.9S¾ ž¹˜ŽçôÞ8QçÈcQtee ¢€4™;÷…@ߖмÛ0è×á¾úXÞcøø½ó°Ï£âõlaʰ°8÷œÅ.ÚŠ/SôÊ"E*ä¨9WôýïìMÅKÛgÇŽF $GKg.û_OEE'Ѽyãk˜4&L¤Óz@«á»¥¥´SÑäè{‰ž_¾\h5è"ÿ ÿ¢/èùw¿Ð6Y½š:½u0•ŒèÏûfjùšþü_Ó¯É'ŒË(FwsÎvtÚã"¬äøLäÿ·ñ±z>ÖŽúP5½L½+ªé¨ÒDbèZDº&ˆIãc_¬?ÕÅ_ÌHï]†?õâJºþþTcøÿìv4z5Ì8úÈ#>3/¿®»û7¿> Ç[½L;žx"ðlrùÌGÆ;Òÿ£`f:ÒÍ1È¥v ×_¿Œ** }Õ¿±—CiàývtôüóØSOÑÐI“øLò{{læLºðì³ù·7^Z]€+Ϲ^éðÒr [†…aÅŠ7©´´ÿŠ>ìLе¡òZY€°ÀŠ{8; ÕÖÁƒ3û°ýªr‡LÒµkW®ï>®;wЉÊâä“OV2ÑwØÁ–S"ËÿÞξYPO½À–ê¦÷Mþú?þ+龟Îwqr&w ̽ûŠèñÕÿ¤Žo½D¿||¶¸^E¯¼ôIƒ&²©ð䵫èÛôzƒ+2% 9¬gù×Éì‚/âãõt οåBÚ9î5,Þbw>;uª¦iÒá›ï¿OÝ~ýëÔ ëöÛ铤áåGñ·Á¹§óòÌ™¥S¨ŽßÔ’¡ÞýEì8ZþØt:ªÛa®/o¶×ÔÑQå\¢†Dϰ…"RŸ˜î—®ˆ4]‹ÊâþÒ¢»'Üß™°eÁZêõ«îžC6X?fÎ|Œ&MÂdÝägAÓO%9WUg³EŠ+·ßl€oÑ¢WÙ¿³M‡—8Äů ßOüT»`äy NcÌÂ4XÍ3ùðe÷›¼¯z'ž©ñ‘ñçvºèR¹gtBë ƒàs¯û_³[t‹™4Ôô.0áøÜSsÖÆ?[[ÛVP‡kp¯Ú{ÖÅÿƒF7Ü]g]9l–,ø·á]TVŠø¹þ±ýõOËÄ3!NP †ŠðwxûΜ9ñÏ<ßP±\lÅI÷/¾þ"s.4È |8`k2gó%Æ8³kLíyï¹¼­¡ãÅoƒ"I:³=Ò½QÁibx^N¾_™7¸Àç Ð2‚Y™bcz¹YìäµD±ë™2ŒË4õ€:¾A¢Ø¥v©eÓ– 9í†Â¤¼¢¢W}EYÔÊa §e:ÙÆ©ýÇrí_/&Þ|óÍtõÕW»g@”¾ø´54ñº]ôƒÓ¼ÜÁdG·óÎãð’[æë.¤1#G6´è?âVÁ|~ñÔåtÑoÑŠu{©tÂ@ª™³Žt&ˆårZ¿ì~Û»·DHdzº­\º&]ø!Ý9ç}8ðPѺÔ'¾+¢-»vÒÊ•+“&ë]4ì zè¡;ųJÒ4ʳÏ>KÓ§O§¯Ø/&Mfñ?ÌÄNH§ŸŽØCÿî_ttI!•Éɉ‰˜*®# díÏþöýò.tq¤’ô£ócn÷¿øLºdØ0±¯MLäŸÖ¼×‹ÝN§ýB²ë±¼ àÝŸTúÚíÆ‡„y˜*ºrØë4ûá[Ä·ãוe>Æ÷zùè%œŠ?¦ÖTMÓÊÏœ]Qè Ä”à±sº+¿á1.éž-ÊI€É][—±»›]m¤RK&ä´ê®,ÚÓ&OÛ?~¢ø¡}“v¼Ýšºò-j{HádbGJvɼǶË=n++£+ñ wÏá†ën£i+‹n„"vóØy½ô9åýûD'Q9½KS“îZùH¹ì£öÊÌu‹kSÆKdk©W¯Ñ…\x\6u8ýEÅ€¢äÇkQ´^8éítñˆB‹!çž{®¨ _|ñEºæš‡ùKí P ΨF2rmö„ž]ýÝ9ñcº|ÖÁtê #}í-áÜ8¥B­Ì°?=*ð”–– ‘À©ÕžSë}ÚÊMƒ„Åd¯ÇQW£GßË¿^d7€ªª‚[ß5# ²y&“Â6]÷w¦•âª[–@7Ó ¤™í?e÷(Íœù4çqÿ1›\’Ón¨5t"jOç'Š»âoP7±•–W×Ò)âTXVYù]&u `§Zk…˜ÚŽ]’ŸXLtQ¨]jwÅk³îŽßø£¹ñz2^» U *µÐ~ÃÕvÑEn¸|h¿x‰Éº&â/'þ˜zúj{ e'Ÿ5׺àΈä²{¡XØÂqéÇ4ÉÎÔ%Ö•ÛDN¾KÖŽÃ%|Hl3EÕ¦C~J77¿‘ߣè"‰ÚÉ.©°ßšHƒ,@7K¦ÚP½‹já™vß ¬tª¸™ä'ŽNw5¶2\ÄÓ9.Ÿß±UW¦ä´ê;Ô†['ûHÑ·(¶ŸvÞq;ýkÃûÔgÑTáÈ–ëZ:Õíðð¶´š)XÃu¹^ºR2@«hܸqm7E)š@|¼ºúL÷–1Pú?ÂÀ&ûSWÞªoÝS7Þr3]{íµü¬°VKååËhêÔè[Ç©­-§µˆw&‡úÂH7ߡé®è]zî¹ç褓NÇ¢xªFÐ;Ÿfno©1¸ìBÝËñÞÂñþ6Çû`%=s!Y¨-ì¿ÿýïô³ŸýŒ&§Û#þôSúúé§çF²€S[n&pNÂrrÅËÊnÇ0‰ -^LjÃä¶ ¦¼Ü ’Z—pªþ;f1Æ•3¨›ph•ª-eg@Wieð¾” 0A Ãa°;HkA#(G;Í|ãŽa‡gN~Q´épf´†7}‰á$ÜðEÓÓá˜4Î Ä/‘NÉïþÞ{ïõýžÓM.59Tæ}©mƒTæhÄAËM½?Ê¿{›À-p=¶™"¿ùt‚°ìóëÃ9.Ð~S»¦ß¸õžøá"¾ÜxÇ䛣1#4òÔo–÷M}ò¦lü¼üàS)7Ãéæ>"í†jW|ðŒ"âv>½ÊÎ{~B&Sp?¯ÉyÎ@(ô¥—R,vÝ|óè$)¯®[§ÞO‹¯Ç@y"étQÝo®Lh—ª¥í±2O±øiЄÑÚÂ|.¤¾ÇŸÒuè²ÂºãXÀ*ñ¬±ØK|ñK~~˜”þýïWó¹Ì– ºx†ž¶‘Þ dm² f?ø ýþ~~ÚDEÏySJÅ€²—f[&“ôL & ¸0d2Ï&¶ï|†\x}Äéó6}ÉG’ßóíW]E¿>œ'ƒôƒ¶×A¯A'Ý:Á=¯n]yü:Ÿ®­úQè<U÷.¾‰{Çüž^ŒóÇâ:¿£˜Öò׉n¥ë&M¢™3g¿ë ƒÙ,H59톒5^-_§õŠ}lSÏ«ÝQâ×B–­ 5.hÞwù ìøºL UD!Àä £^ä^ƒ­Ig­ÁÔ烔•¸gæ”çǾ)M¶%¸Î«‹ qÌ6Mö™¦«É™âçç Ý~×Géä} )?5=^pv’œ“·œôkËîvv/LäV·¡ejrXÌK½$ ÙÂþó­f‰cs|ÙƒÛÝÜáb™a|SæÅt–±—̘!ÒÏîeå'òi<5Ó»¡ B²@Ë7ÿ»—¹6ÅñWø·¢^›Ã)ïéZ# é#¡¢Ù¹Ã÷iÒ…0ë‘H:]*ðk]>¿ò zøºçé¯t«P •èŠ~ªÆÅÒ¦ –=ó UTUsŒºQŒvÒ°!?¤G–¿NY9ØU (âð/ŸXEÿ=«͸õCúÇ[Ëé7gJvNøµ4aØ­4ã²³hæÂå4}Á21ð†ÖùU#Ž£[￟ý$·B+¯[H#JO¤>~'eŽbP[Z^úüÀ®µ›~v}/|N<£V¶©•n’Ø0¼{KY]­©V§Ã¾—dîy%ÙJ&AyxévºyÚQÔ™.b™~+moP4ÞB#¿7€Ž'üI°ÌîN#´šßçýs+Ä-àªÙi%¯^…[n¹EHôÙJ™\ï|ߎšµïfòäDŽ҇WXxiÑA•,bü?Æß™_Ù,H• tÉ"ï•0ÀGq^ƒ&ÃÛo?‘r>ÝÀ/ƒ!C@cãÍ7;Ò/~q|ƒ–…£uñÇmÇ1U*ѵ“ÚMƒs÷Œþ=m :1Ÿ£³>Q%;ý)Õ¹EœyæqæÑý„1— 5ˆ¶¢€š9“õBÃh}A¥t'M¥9t=-Ý'ð5ú½`R£„Ïþ~I7ÓÇ. -4Ÿ `¯·kJCØ%U–ìL¦L&²åÖ[oUº‹¨+F‹Þ3~ÔQt ¥Ó†‘`•ÁŠŠ%œ†Õ\ôŒ¦9U—å$ï«ùP²žt{ÒŽ¾˜™ßZ+k‡›4†tÒ†j—Ò:lš‡“åÕh@‡x½bÛÌ+.Wßq7œÐuŽgAнËnM¼øbº}ñâÐói¢ì‚œvCmÞ¼Ù=’Ùý3cÆJ!öAºÃ>¶êù\ ý¾g Ò¤’¡ðƒãrÓóu}nüöꦑçTí'ÆbñÇfÎLÒòѺ*'{xIsîj¸ü9Æ9{Ƈ)î‡T¿nð´øÑtJÃà¢3°ˆ/À1qíy¿‰¯½þÉøÝ—ü·k‘‹#µ‹—¾§Aëhäyç5\ƒmW:8§"´—É…lÝ¡ÇP—´qÌW·îð³éâÓA8²»Eχ|ÅZ'zÞR¤•æV¤ÆÒ/ˆæOº<¢¦s&iö¿îH–nÅõ(â¸åUâyàŽ|¶ .Hr¾\N»¡ ~ÍŸ2%P-zý½ÏSEÕ¥üë"¾îhʨYb_¶ ¶2mý™î£·¥Q>˜ð¸øÆ%ÕüE±—é™Ê?Ò÷ú'üúµž>e1þÊI“¸Ev4Hr;Æ{íb)Õ¤[CHñ¾w}¾ãV÷h2P¼,ž¢¥ˆµµawJH*‰n 9°~ï!möqÚìçßh“A–,¦ËiÝſ̭F Òv×®]Ô¶m[©˜IzK;ÊÂ:2ÍÒéÓƒ°yÑDÉ"Óµ­ƒ v· ›ÅévÑÞU€û¨ápeÃòظ-]!Ρ›s^šïß™Op§Ã±ìÿ5öŸÀU¿á5µŸ‡êŠC«ü•×ßæ_½èô~m•¦–<Ò’ÅÇÔ–¿ƒ^ü½Ôq<÷s|çñû?5åýßóèrº|æ“ì/Îþ6%=O¦lÛù­Þð)Ùÿ êÀ c®È©dq";u–´œ…-ö¥Ãù·öÄ€Z8²6•µ·¬ÙõÚÜË…õ/]뤴2ðœ‰Ö„Ü?¦¡€–„©õtKÃqg ÿ^-GUªÁ6ˆú%ü´‹9ƒmýcÎ\Ù|‚%—Ôu+¼×J÷\xÊÙ1:§•¥=·ölúsÁÐ"ü`[ý9„…m.pâ“^Í5*)áû=¯Iò”ïÆ4§$¨“Þu²;šÝq?ý]ù¨‹é;|}ª:(¬øÅR47"<¥i}1¯÷"qÞc°ïqW*àW~7Ho<ÒŠ« ñ;±ØY»ø“Ú:/2,HjPÀ š~MY®KÉ‚?ìi”øª\çW« ^º3ÐÕ"3˜i‘?‡Ì)îÅ[Óy/gúõKšðX7±›)]0Üž ©fBªF]:ðƒíŒŸ&5d×Ï)ìÐ-tuo(Ô½î §æÒéq‡æ2=49Td—‹Z;ûþ…–êŸ[Áñݳg‹g4<5ñ¨sÃ5E˜» <›×sÕ.ZäYpÈɺYýƒÏ†tÒFv;bëWqö+X>*{qCÅù™aÉÖá~™<×ÌÿºÅžßwÖažƒWþ‡ ó½8lS×ôßxõÝÆ{éϲdr¥ûäá*¨¦Š^YDÚ *¢µ—øžÉ¥/èvÚFWЗEÛÖ†ÐEæ ÆÀ¢Ò±– &jÜKÆA\µkç]÷satÏËÜ…n Pv¹$ œµÚD>ø rÊ)Æn.<§¤×ÖÕyh@‹h‡ðw9ÿšÃ÷ð[ë",êód’7üH§à`J·\iæItËÀŽî}xBaÂ/¯.°o¼ŸÊ¯ïE3?„ÎýñQî™àÜsë6ªº:U+ð¦;þJçL˜Q·ìŠëÅyêÚéÍž J ÛÝE¿ÔôBô.ZKÿIh⬛èÔA]=Óó‘%5ôáç]Cw…*9Õ†Ò?^?[-øèÿ{ôT®, „w,»­TUþ: ¯t}»&rÑ¿ÂÂ4¡ú»ßý.µŽ÷¢ªæ#þÚ O¯Û+>,0Ó–3(,cuçböòY‹Ì§¤o[¢«Xú¥SȆÓ0[öÐëtŰ—iÞ¬ƒhð ä¾Sô÷¾¾{7íÝ׃JËŽ¥É¿ª¥‘çHGvìh; ó\¨ÎNµƒ®_Ðzõ)6†A±vtóì•40`?µŽ_š¡É>Uc~¨XÇŽÑTXxÿzã§oßQY5°/&1bç§d­Àl 3–‚æ+¿±ÄNí¤äDzÈWTñü@i²(XSâcvXxBVÜZÉ)®¨ÚPËüÄwÑÕ!¬Š*]ü#¬ö€î„é<àˆ¡ÁÌ:È®'= ¶¢ßºJHÇ&º‡à×ÔMpLO_„‡}¯pÃö½›Â“]@r“cúÄûž*AžKE¼Kîã¢êž1å‘GEWƒ’G9Þ^]HQ¡¦»W"º²Â‚x«]`¦÷X¾ÀõX+=Êp‘/‚~[ H¾ò{—^ñÅ9Ø@+¦TKÍz×W7Þ¹Ö›Å÷¨u/7E§›ûàGËYYÈ@ý^ŒÄë#€iÐ>HÕå£['Hዌ«ê RÀ"¾ê¨‚c¦ôM.ާ»¯Šîßùˆq_g¼ÎÙ÷®øtüžKÇdN]ͪ=¡L?P¯|#qž9¿¶ž5Ü[¯w$ýÒ¡Þ'de­JØF‰‰°aÉW^ïÒ/ä9ý<®Å{߀nß.ªwÔ˜èå:?Zöèúµ†€8/u½M ¬¾lƒ| ¦ƒ…ÎK >%ãäE›î©‚0LϦ5nÂ+}++W‹}¯pÓÅWG-¬1í<‹:¸/5ªŠR4E¢À_5oèi óO‚¤‰_Á&¿Ež9Vg÷ÃTY njã(Ó¸f7/LïÒï^òœ~ À;G™öðÃóysy×”ÑËõ"Þ‰Ì à‚ÅÝsàYôõ£?ýÀ'Ÿ|2•–bžE+q¾¨ÈéïD?,úÒÑ'ˉ-¶jß:ú4q[ ~o\‡ÃT\W+:}oÿõ¯é·¿½_LeSçúzš;v,íY±Âé6¸e×_OtíJ¿áøa‹}“?ép¯¾TK±½‰UÅT0OB„KÐg¼{7†¾3Ç+}»tÁpzt´ÙÕ ú‹•õ¶•–ºÏ‚yüübKbfE-ÕÓ§V‹ý\#óÆm·ÝæI€´ÅSÔȾo½ÏýÚ2?c‹ý\€gF<À6ÝXScïÊñ¸“ç±E¿¿ú­66^ïÒ‹?þñî/glD}Ç(«0vuê©§¿GŒuÁT¦$¢ÊÈ’†hÍQ£;€è@·†åõÄôî%¨£:3¹Ö°n…Iõ -^¨£Š€ØyÍuÈv<ÄËm®XbŒo¢5®Äƒ÷W͆™æìVÊ3µ6q[ìckB=¤El–,’[O¹”,ôn(Õ½öøŠÔ1/ŽŸ—î¾—SU®½ÔµU?òX•ͰÎÔ5†S"¼õ#¨¤ƒósç¾àfº°tÉ"Ó¶é>AŸW']œMázÝ Ë$žeUWOéÕô=Á¹ù8xïG¾Ð% ~´ìi”]rAíT1þm*¨¥3\:ln’‰Þ‡Ãü…ŸQøf1©fCüÔ…/IʹDzS—U ãdØØêÇj9Nª_ÕùMß…`è"µW¦—ÈóååKeP=<õƒišn°>„ÅOçf)ÎÉ;U"oáP¦¦d,ç­ [5,é']Ú©ùC&‚< î³s~Ð –ZYà¼ìòU¿»t]ƒ^÷ ò¼:jXˆ º¡uLáš%¢q$ž'ñ,γQ|ÅœyIó›¤ »`›©Áó?°h¶Ñ“ —Ûõ,Ö¬¡ uušŠÚEì–Ñc3o ›&MJQ{üݬ§©Ã!‡Pßž{}U¥êWj²I tFké~ACéqš}Å<ºòîK)ŒUÑt*x¦9#AMŒèÓ÷u•P›^û=üô>úÙÙmèÄc¿éMF“ºß±ÃŽë¯ò| õ§6âÝ8x©°šÔJ¥:ô¢Eÿ .]Þ£½{áýΑÍo‘@ÜŸ0ún~ÛUã÷Z^>4Éö¿|–Çg­¡÷þý¯ŒM#à´IJsù3‡ 7Ò%Ù€›é=g¢ Sþ0å?• ñI6ž‡ô|€`Mxçò çY?ÜGŸ|…®¸õ*úœS¿ ;Eü혖J®y¦˜¦Tu§+/û_ºäÞŸ»aâÀ"r­W®!bÂ/Îo}ÐÝ÷yuÏ…níÿs2³ø›Ÿ¨|ó¦tÜ^SGG•sFW@§*”¦嘣j‹Î¦'èx*¥WSæ7…Yæ×„c4Ô1®‰ûÌc§w8¢£j»ìr7ÓÇAWÜê,~{é…¯\¹2ÔZÕ*èÏÓõ¯a[|ïCoð½Žäcoqæ—–k彸µA7ß|³X´Ç„nujü0LÕ¤¿ºÅµbÀ ?;N*zæ”ûå¼7÷õL—ifV'Åéé îcN@P{V~Èwí7· Ê÷þbŒ;èŽûͧðË/Ù`ÊÙD’ÔBôããÅÒç¹ú IAîWÇ•I 7ÜRÃĺÙÒL¾òš ãöye¤53 òÿrv²º\G§pÃòïbmÿô¬{Ôaûõ è¨ó1Æ©WªÉ Μø ~ÏD‹+¶SÉQûà]ðùþV´å탩×SÛÖ˜²êÏû|@&Lâ ª·ÿGèô‚gž¡1U°ÿž\.l¥ù£/¢Q9œïóñçŸÓ×ÇŽÍ]e@ñyMCAàµr]:Láþío£?þqŸMdÒ þH³gÌè^^×DY8©‹ü—”¸]d&Mš”Ä•¢ÞªzæÄþ:ÎÓ×ÌBZ'Ýe¦kßî0zŽÏWÎúµâŒ/¸ ×M£ÿü: *‰Qo¡=ÁÏv¢ÉåD¿ýó¹Ôç,GºÑÓAJee·ÓwNäw“ýÌê …w”ï#Håd×ýýï4½fÂg‚)¤“bÃKòYÑèúš9a4]{çœïêEѸ—Óê r"©I²¨{õKº{æGtþé?§WÂ<•Ãü‚¶<6ÝWÚSãüïÃ0e[¾ÏSË—Sûƒ$µKð\]9¬>bà…_e¡šÂÇ»ÍÏûûßÿž%ÎÄý«ªªèÔ6}}{¹ È ô¨É¹d!fú1~³·³A ÷„þOùÈ/cw7;'!gͺ(­$†( '¯°AyäúÍo~ÃY"µ»-W¤“d¼$‹eWÑt>S*ÎKô‚*h—H"èr¬¯~ÑêÕœIÀ¯cÂñÙµ²èÖ=xºa-ŒtËvÇòk §¯³ Õ­N£Åsæ$U4¯p~øRJ\qš¤&=/d² Òq̘1 2*Þùóçg”–³fÍ¢~ûÛ$ÉBχ¦n(½ÛÏ1¯â,m ù©#ík²CxsnYBwNüÜ·9 Èï›6m¢IZ7½÷ÆX)o‹Eý1KÔp?úH¶@aT¸Ž]¢eˆÕ÷ž{î9ú”8Ûnàõ<(àÃv½˜ÂR óÏa–‘maÂßîÝ»©Uq1 ¸ä·ÂuÒNö×òA§”1 wTÖçw„¯Yt•LºQdÿlCeU×& ¹hŒè6™L Ò[Wû9]3áì9SgŠÚ‡U÷“N:ÓüÆù­ÖÒÌ™OÓðá%Ƽ­K@™¬ð$¿†ihLºµšf>8›q…iè4}{j·_˜¼nƒ-[Pxukf*ýfCJ¹ŽÊ"[80¼Á†Qs€u„Žm”¨áBËÂÑ~0¯Ûí5!×Q/T1=—&G:tí ©QBÅñÎ÷oÑî3`bSøIXðÏ™MÄ [¿ë‘¦´ƒº£é™å1GíRj§A8¡Ñ§«‘†Õ*ÑB5ï19mñ;Љ_:â} P—Oͨ7*ªC§[P§Z,6iå´vŸæ.¼ÐÓ+Wi6\hN.¼®Òø}›&å©ß£—yþcØÉ|ýÄÔÅ¿nÝ9 g|{¦¸#Ÿg¢ž›)z¹Þ¤% „‹Úxôh´$þÁ.QëBDƒ¼ÑÈÖÊÏ>Û bÆb¯Ñü€‹•<»ú-º}âg4¸ìúÙOÛÓ'¿¨o¤}¡w]Áû°Þ:wâ:7+ü’¢h‰¯ñk±¼ûnç”w¨K‰ëÐÛ/)­"§«Á¼Ì¬ 'ÙþÚÒ/.¿‹N>ñ:cüÈäøF´ôd-µ°e™ µÐ~xíóTqó‚Àé– ÉËÌB£è\vË}%7]²#H‚Hé4ÁTÒÓ4åCµL1nDY¯GŒA‹½š—wb"WÝû&r*YüéOj¨Ñ€AèØF‰)\´º·DÝÖ€—Î}ò 7Y/ê5Ðră`M¤_rk¦8~4=_÷çÌ'îÅ«ÅbJkõ˜~ôÚõV~;Ò—’æit若ƒ–.»”s ¼¤ÈÕÎN$N´˜=Ϲ A¥·°8÷ÈM(/ó8ÇŠ{ÇbÃÅ}Õw¯£æ…l@Úù¥¥IðÂ+N~ùP¿FÏטœ‡|íg¢(_x=_.Ð% ¾m‚»ï¾;Þ½{÷xëÖ­ãýúõ‹ÿõ¯uÏø#…““arõP¦pñ–!KèÉø¿Z")2Í®Åd'žZASYébpRD?š:²_Ǫ$®ûݨQÆ{¨]/^…‘˜ÌçÎÐõê "rº‚òéƒ4C|pLÆËäGů›Ë ùasÛ^ÌO¾ë!cMW+Îhæ¶Ééïż"Ø"ž^]ÙàÜ#|ºE|ŸS§Ö‰­×{jZd‹WZ¢àÓåè§°Ý­¦|I^ޝçËž•ÅC=?à€âóçϦÆËÊÊâíÚµ‹ïܹÓõáM¢²hà X¿j¦ÊóC)&¢p¦§p/5M­Y©/;]Ë ‘A’3 ÂA¥¨ß#2¾2®¦x93£wû~¬Q¢ÇÉë#Õýéû:™¤9Àýœ4HM{ì;aFÛªO÷,ÀTˆDÌÒ-[œ{+ ƒ¤W6d’w¼âä–éÓ±Lâ5¦xå ÏÊâ?þã?âãÇw÷zõê¿öÚkÝ=o•ʼnâAˆ²K(WjWL@8ýåê­§ >H„kå@¹šI°/Ã6µˆü0½p5^·ڭáwT…¡jœð,A?,}ßDØ4—8Öyá4HK.Ö=N÷,ˆwB4[d<ÊË3K·lpÒùä:âˆ#X¢+rfp‡í†²äd}‹%:lúæ›Æ¹'i £ŒtàRÿþýéé§Ÿ%ØÇ*P‹ÅbiÙˆÊ\uÕU¢â}÷ÝGuuutå•WÒ®]»h¼0^e±X,––L«üøÎw¾#Ænºé&1õïÞ½b¼¢woL{·4&­Zµ¦¹¿öµ¯¹G,QbÓ7÷Ø4Î=¹NãHlCY,‹¥yÓÐ e±X,‹¶²°X,KZlea±X,–´ØÊÂb±X,i±•Eò׿:ö™0{³â±¾²%:f̘A'tµoßž:vì(ÖªÞ Ãc–ȸ÷Þ{éÄO“Äà`bÅŠîYK.@¾Fyñë_ÿÚ=¶²(P>ûì3¡¶|×]w¹G,Q«—]v™X§“O¿üòK:çœsDº[¢+4Μ9“^|ñEá DçŸ>ýãXÕÒ5ëׯ§yóæ‰ :XÕÙ&Z K—.­_Knxï½÷„„Jäû߇Õ_K.èСÍš5+¯K‘¶>ýôSêׯÝsÏ=4mÚ4êÓ§ÝqÇîÙh°’…ÅÂÀ¦@af‰ž¯¾úŠzè!!¹©ÆJ-Ñ)k™ÿà?pD­,,-×0wsÚi§ K–èxå•Wè ƒ¢Ö­[ ÓA;î8÷¬% P oذAŒWä[YXZ<—_~9mÚ´‰|ðA÷ˆ%*zöì),WclèÒK/¥‘#GÒæÍ›Ý³–lIrX_¼x1µiÓÆ=šì˜EÀŽYäŽ+®¸BhšAû쨣ŽrZrºI¾ýíoSee¥{Ä’ È»XVv¡$èòC™5(°îz.¬dai‘ ‰âñǧU«VÙŠ"O ÝÕ…Ó,ÙqÖYg‰®>HoÒ 0€†.~GUQ[Y(Ðn/lß¾]ü†ÙxKö`@°ººšxà1×âwÞÖ–-ÑpÝu×Ñßþö7Ú±c‡(Ð&OžLÏ<óŒ(È,Ñ€¼‹q6Õµk×NXzüÍvC(ø¨Î<óLw/ú|.\èîY2bº‰?üátÉ%—¸{–l€zì_þòúç?ÿ)Vqƒþÿ5×\CgŸ}¶ëÃ’ `¦<ª³¶²°X,KZl7”Åb±XÒ@ôÿ@àæE6IEND®B`‚pyclustering-0.10.1.2/docs/img/kd_tree_balanced_two_diamonds.png000077500000000000000000001673721375753423500247310ustar00rootroot00000000000000‰PNG  IHDRK©ä”²sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æðî:IDATx^ì} œÅñ½% žxàÅâÁâÁ¡FѨ$?$ jŒâ™ÈmtñŒ,ˆŠQY¢°ÀDðˆˆü,bQÃaDÀ+.‚‘S‘¨¨¨\*ó¯o÷ô¾~ýz®w,{Ìw?µýf¦§¦§§êêà1bĈ#F½FF«¯¾J¿üå/é°Ã£D"A³gÏv¯xã•W^¡N:Q£Fè裦‰'ºW’xøá‡é¨£Žq÷_ÿú—{%FŒ1bĈ‘Od$|ûí·tüñÇÓŸÿüg÷Œ?V¯^MÝ»w§ÓO?–/_N·ÝvÓ3Ï<ãÆ zê©§èú믧aƉ8ˆÛ­[7Z·n#FŒ1bĈ‘/d=e Á³Ï>K={ötϤã–[n¡çž{Ž*++Ý3D  ·Þz‹/^,ŽO>ùdêØ±#M˜0AíÚµ|ÇŒ㞉#FŒ1bäi¢þÙgŸíIœsÎ9ôÆoÐwß}G;wK—¦ÅÁñ¢E‹Ü£1bĈ#F¾P-‚Ö­[Óï~÷;1U €Ž¾K—.ôñÇ’pøá‡ÓÂ… éÔSOucÝu×]ôè£Òûï¿ïžIÅŽ;)ìÚµ‹6oÞLp€HWŒ1bĈÃô½_ýµXXPP NdðdÀ=²£U«Vwîî‘Ä‚ Ľ7nt>úè#ñ›…÷ªÄ¨Q£œ6mÚ¸Gé¸ãŽ;Ä}1ÅSL1ÅSf´~ýzѧV‹†àg?ûuèÐÆçž!qÏoû[Úºu«R7nLO?ý4þùn ¢AƒÑ›o¾)v(Ø`j¾úê+***"~9ÚgŸ}ܳ1€³™Î8»AˆN8!ýXG”¸6¨ø€º‡…Bjß¾=—…cù,v—œÎô.Íœù.tÐá"þ¤IDýúEn˜wÉ”wŒÌço0¼ò(LÞéq€°y­î¼â{ÕÕ{îyŸn¹åàŒÒk¼'Lºüž—IZê2¶lÙBÍ›7§/¿ü’öÝw_ ²ó ÔÜ|óÍN»víÜ#‰8?ýéOÝ#Ç9餓œºG¸çÖ[ou‚ÁHÂѰt)¾¥ mÇ:¢ÄµAÅ×ï„:xð`'‘8NœO$:s8E\Wñ§OÏì¹~ñÔµLyÇÈ qþÃ+Âä'L|7(þ”)Sœ‚ÔÑd]5ëB”ç+˜÷¨ã0|Ì{uø]«0ûÌŒ~óÍ7,i½)À¶BüV[‡JW^y¥ø `GÁÚµkéÆo; yä*//'îÜ$®q!×ç†nüpoŒº ”…-ZÐ}÷ÝÇGïâ ÷<‡½q9FŒ5 ½{÷¦çŸG¥¸®Ö!d$`w¦@:sü1b„8Þ¸qcŠýª¨¨ —_~™N8á*))¡ÒÒRºð ÝD_|1=øàƒ4räHÆp:Šu…´•:Ð2Ú¶p.MèÛ—Žßµ‹‰Npö£;¶Èˆ1bĨ‘hÖ¬™›6•aŒÚŒ‚3Ï<“ÇI£©S§ŠëÑùë8ãŒ3hÙ²ebÎÛÈÿšk®¡5kÖˆ8؆ˆµ1ê&ÚÒ :Q—âîô—e|.I»È©œh1bĈ£šP-vbÄ0±‚E‚Ž´”–VPçD‚“F”hw¢Åˆ#FŒjB,ÄØ-ØFi9wý…]ºÑÀÉ“éí ø˜è­„“hßC[Ɉ1bĈ£Z 1ª›6mR¿Ä,PÂTÑüùóéùç×àŒ8#FŒšÏ?ßÀÿçÓÿ ‘^¯ß1jb Fµ; Î;ï<÷è<š=»\ü:âˆ#ÄÚ”fÍŽÇ1bĨ (§ë¯ÇÂï®tǘð“õõwC.€ ¨eË–î‘?¾Ú¸ŠG I›2ìG+–Å1cÄÈÌõ=~(*ÂÂßZÁÿõB+hoá('µ^o %KæÇZƒŽX ˆ‘5Û¤‘¡ÂJ#,K¥G ¢Ç‡ ©êÄ%­cšK…ü{ذ2±~ œÊ—ø)é6 îëÛ+ž³Œ#Kx­ïñ‚\ï3‰v$ Ä!I“h5¢æŽCß-ù-›QI³ÇßÁWZЀ]ÅÀ ®«5±@#k¾¿œ;æNÔîòNDRéªÒR£WÔ~A×Òùçôâ£pH´ëÊ#t›+¨I€ØVzŒ¹&Äh> ¿ÅºëÖ­s%Ú@9MˆÍˆkèÌ3ã)‚Ú‚X ˆQ­À¨û‰~Ät¦ƒÔ’Iæ"ù¿«ÊŒ51bäPçß~ûíîw‹u‹ŠŠÜ_I(BN¢~ÇšÚ„X ˆQ­À¨ÂÜïdCÀk$²~ýz÷(FŒ¹@Ïž=Ý_Á‹uÕÚ¥UˆwûÔ~ÄAŒjFæ~ç ^#‘æÍ›»G1bÄÈ5Â.Ö7nœíÄzï=LÄVDkb FµŒ¾ß9̨Âk$ï.ˆ#_iÓDhÖGé ¡ÝuWWùFˆ±û 1ªEdbCÀ$#FŒÜ@väÙ8#‚ qÿ¨¾¤| ¼T¿PFŒÝ‡X ˆj1_6‹úÔhÂU(ž›7'y'Ÿó½øŸ™f v¿£~bÓ&”ùùnèÄ)¤dGîçŒhÛ¿sœe´å“Õòf ØÂØÚ0PÔÚÙÚßH.Ú˜Ñ 1"£å"5×ÛÿtÞƒ!,§iÓÆR÷î?ãߪÎE…R]ÆîWcÔ7 ì÷èÑ‚uaPÙ_·nµ5\Œ{9#êR|6_ïDS§×Kla\i1PÆ7B>Û˜þˆ‚¡Ñµî"5¹ý/ûQ·7ñHeܸ›9\ÉÔ‚ÏÁMR´ç™ªKsģܬÂ{Œu hôè~ÔË|Ðh_QëÛi…ábüDîØ7•–MŸ.èsþ}ŸïIÇòõ¥ôíÍüûѧkWñY ¬ ºñöÉÂ0‘2Ptãí“w 䳉ŒX ˆ6©rû_ön‡MÞ…´å EÎA¶F{žMu©x”›Õ}>ŽÝ¬Æ¨kuÊËoˆÎÔÆs½{›ã gDL¸þ4ƒQ°Ë/tÿžÁç/¢ŸpœŽt üwÑ7K±› ‰ž=±Îg Ýv›4P$ý‘Ï6&F0b FhØ\¤ÊíÙ»6y·¥¯«1EÒ¨qA¤çÙT—ºïåfuËaÞ>bĨð÷b#Ô‡rZ@ÇÓ,šz[­á¸½8¸þ îäN@Ø‘ëå^ÎÇ©8‚~üãðŠòÙÆÄF,Ä ¨ûl[០3$ú™¼WÐ~U˜"9†¿;ÒóLÕ¥é~U¹Yý¡aìf5F]Ã4l˜·ß¡>,¦.,€ŸOÇ^ØŽ°ÄÅýßs}€o‘ ~Çü'ÑA-Z‰§šˆâƒ$÷mLŒ(ÈJ xøá‡é¨£Ž¢FQ§Nè_ÿú—{%gžy&%Xª4I-~÷»ß¥]ÿéOê^Qé–A¶…~:ï{JÿÁÌш©9Èž½îç_CÄõ(PªËØýjŒú”ýçŸÇH~¾sQöQWo½õVr¹¶ç’K.åЛoT$¹jcbDGÆÁSO=E×_=K Ãhùòåtúé§S7–mffY³fÑÆ«èÝwߪ ‹.ºÈ!qî¹ç¦Ä«€z+F‚×–Á°ð[èwäæøÜ2:¨ÉÞ|¥7Mº˜n¸aÿ^Ã Ê ¸=CHÛêA‹šbĨk£ë3C² i«¨ƒXpk.:Dз¯¨³jmÏsOæ_é‹þ’T$¨ÿAȶ‰‘2î¿ÿ~!¹õéÓ‡ÚµkG>ø 0%;aït4mÚ”9ä*úûßÿN7N6l˜÷ÅØý@%ž??7ûøýú¥.ò+§ßýî§ôÀÒ}êË/Ïæ0‰x¯rŒvdS7ÚÒ QQÍE‡¨£oXì ¥/úóòAÖ¹Ë 6œod$ìܹ“–.]JgŸ}¶{FÇ‹-rüÕÑ%—\BMš4qÏH¼üòËtðÁSëÖ­©/K¢ÿûßÿÜ+1vð­ ÖïÚUª÷³5Aê·ÐO-ò[_ð#}È‘HÜÄøÇ”§éxšG‰m[Ešâ½Ê1b¤Ã¬Qëë  PQõÅ„ú‚B½î¾Qú¢??oˆQ€÷Q¶0E‘mûà Ÿ}ö™ôLuŽ?ùä÷ȯ¿þº˜2€vA¦f̘A/½ôýéO¢%K–ˆNhÇŽnŒTàü–-[R(Fn€NjÃm SU„+FõãßsEœLà·ÐO-òûþ¿‹ùér$ò¸¸‹G 4™¢Aô=7HSKgOq¡ßþjek ÓôƈQ[ ž¹ôèþ¸"ŽÃ`5uuѶ pàäɢΪµ=½zK ž Õ?dã š¼²¥€)ŠØrþñ”€E:ÇI;g$¾Ÿüä'tÒI'¹g$.¾øb!ÑâÚ/ùKšË üÊ•+iΜ9nŒTŒ3†öÝwß*нßåÖHµa—âtáÜÈ,£î"N¦Zè—hו›$9ùµØ_p©Pev¡÷éÄûŠEšî #E\„~û«Õ4D6é£6À¶×®øîöñ£®¢Î¢î¢Ÿy¦ÿ¢¿l|üýïK³¥ÅrŒhÈH 8ðÀ…êÇÔ@½´dëÖ­ôä“O¦il8ôÐC…Š…܆¡C‡ÒW_}UE±üÜaû‘Rm¸°4]EØ™%þŽT!âdï…~ûÚŠG“éM~Ö³@‘)U™m¸kO¤íƒöÛ_­¦!²OoŒ5¶}ür _n÷ñ£Î¢îÚ4&¼¼!úaöl¹^è!DyÕþ„5#:2öÜsOxu uàøÔSOuìøë_ÿ*Tý—ÃêU>ÿüsÑÉC0° ÷ÙgŸŠ‘8…RmXØ%UEˆ°ûí“øw7'¿èMwÝõ„û[©2ó(Á¡³nº‰þ[ð8Ðoµš†ÈzcÄØ½@Gmîã6¬ WÄñîÌ‚Ûv-l]¸œ–ͨ¡~S3KJĽmhOÂJ ÔÅ·Nsš7o.ÇÈ12ž2¸ñÆiÊ”)ôÈ#Pee%Ýpà bUé€Äõ+¯¼RŒàM`º gÏžtÀRjTøæ›ohðàÁ´xñb¡ŽÂâBL@qþùç»±bì(!v c‚4W8þøS­#žAƒÅ{•cİuA¯ÕY_mÀŽ!Û®…§õ¦N—·¡~SÓÝ­ŠX?´INDC+­`ÓÐÛcDCÆæû±ÕpäÈ‘t 'Ы¯¾*l@Å@8€X°`Ákã)ˆwÞy‡~ýë_‹W]u•! ì½7ö¤ÇÈ'‚¶)aäãRQ) âÂ"a¦[† |&˜äˆ'“tØ ÞWw· ¨mN±S•5 aʦRÏGQÓÉúoo2Ì‚ÿ„*hêmiƒ>­7µ)>Lýõ¡÷© u¤«iÁ ²ÐÈzEíè´/¹Ú]ïáÔ!|õÕW(7"ŒS¦Lq‰NœwŽq¼t©#Žš0¯ùÅ/á‹ïÂò§3|øqÞëu~út„É{ „S˜>qliö‚׳Là¯x«ç"ôã#3x}“IØò(lÙÔïµñ±A¯œÎs !ı^W1g¯æîs³½¯½oÔcÓ*i˜íÀˆ3”ÆP; †rÚÀç:y)5?ø– .¥Ki:}uÊ9¸#b žÒw¶îFÕEÓ²™²jö7Q· );ÊÛ¡ 'Ñ6n`6[š£,44ß{{bÁÿÐó®pÓ,Ÿ ×±QyLj‘¨2Ʊ¾ÕVÕÏ5M¦~£G§NµÝum8øàªºúnƒÜ/§·h'Ýxû¤”û#èÒ>þVIÃlFœ·èúÍðkDÁkóÂâó”üàwhÐë:z‚.£]û(î±@#m›R.·ðsÎ9Üð`Ý FÉ-CáÖ(H×­˜G”.\“éÊEšuãÆ!”<äùܺŒ#ȦlMµ—n0WÛ¥%ÃܸGšô-ÐS§Nëj 12ݦÌ{J uË×s ´˜G´i,r‘fuoÓ¦©<ä󻌣ºiÙ 3Õ@X „Ñ;÷ãà¡oŽëjî 1rŒúÍýÀQÖ(è^Ú B{5‹ÄԮE·‘3Û©¶u±@#k`ÛP ç%]$—AØÎÔtí§4ìê;©À]È„ð¶ßÿ‘öÙø8¦ÊJOm{Ò=bà§kM?ÒÈQ¾·jŠcw@wŒÇQ §ò3=£ö#bdõsŸ¢ƒ¨„Žw´ýÀ%%´©S'Z{Z/z~JwçH –:GQÉ”ÛiMï‘â˜.¿,eÛ“îÁÛ¿YŠùL4~-hÀ)täË/º®©@µÑ#ð²C°úÙyé> hšûýó5=£ö#êШ„1óv„ŒÎò®Ñ#è þ­ö‹ýÀLhnÚÑû|܉N~-^IË¥Ó’#ËGˆã¶ ¸³Õ¶=é ± p¯N0\*Õ¤…”jà¤bT?þ=×jØ$Sà9Ù=Š#ð²CðÅCÓ}@Ð8 ÚïŸ/˜ëbÔ|ÄA=:oŒ¬»*µ¾ÇÈwìØ±Ô½ûÏø×ß2*<:Ï·ioî¼ý÷'Î9›:^ÖŽ O{Žâ¸qîÞµ-ŠÊƒá‰ïÛjÑJc…t[ÃÀÉÜY/£î9mèraô(FŒ|ÀËÁ祮‰Í'm%p£—À¿¸c®.ÁmFÐz °ƒŽÕ‡º)¼ù&÷ÜeÄTE¦a¥nTfO•Zñ‰òÉtóÍ7sŒ•L-x„ü©ç¬Ðyn£FÜyc¯±tQ »™ì5Öç7õm€VH¯0„ŽÎ‰+B6 ‹\=Š#Àâ?›‚ºt‘ÚµÂ5‚¶¸Ÿx9ý‡zPÿâîyjS@[ajÙˆR·ëC<-Wƒ <ÔT9jÀkÅ”]@mª¨ y:þ|7—“B**>q‹(§#íÅñ믿îÆLw&ä\D]צ¬_¿Þ™8ñu>†“éð„;iá|Å—‚ß3m󃔂‚Îâ¡rÆ#wðû&1$¼ò¨¢b=ŸŸ/BÀ//Qwš$)uºS¢€Ã gÙ‚oÝX©ðã§CÅ3½ôÒK|Œv#ÕQY™lC¦Ôv£ƒ¨Ï8ï¿4™×¢Ä­ïˆÕ#,FH—ŠJ¹ÎLúûD&¥¬«tãÞN SÔò{cĬu_ê6¦Bq|â‰àœÌyGŒf0ª0 ?Ac4pÍpJøÝ QWbƒg˜u1bx!JвïëZs¨×é\Mµ™uUÁ¶Õ˜ùª­Æ¦ÓrÊ1¯:OSø£n ¯¼R5—V_ 6ÊOOì%ÔõŸçãLosE…ºá>næÆo±à º§tw¹«R„4wß}wÕ^e¹¾ »ø­T~Q:O¿ ©«o-îFh=_RL­vO­¨‘8'GíØƒŽøßÿhÛ›²A¡;5bóäV1aÇJîN£ž »¼Â¬Ëˆà ù,Co¼ñFÊšP.¦ÚF¯5jjC  „Isèvèâ‹/|ó•zšãi ;P¸¿k=¶lÙBûî»/}õÕW´Ï>û¸gë U£"íâŽTŽ :Rƒo‹Q5€rñÛ ’ ’`ÍÀž,±·eyñÒ^×ÓàÁrÅòÓ¦ÑãÆñ¯LËè`:‰Hì¢ñcGÓÁQù‚¶Ô¡KêZôÉXô ¹cùòrêÛw9ÎÜHt¦É“V fš;ðÓ—Ñû4—uç_pWf–)be êE—ó¹é|í2zB\ÃXS­â`|f¯%ÒvþÕˆ›Ç= váý²ÊB±B{êõ/Ó¼?¢kÇîC§v=¼ê¼ØÑn›àmB –]ZjÀ âmÃÖm Z±¦µ=r;5.¬3U/2V¼¹Fö^C#ʤ¶'ºgëüÊÐæÍÍè²Ë¹NõJ¯SX2`+¨:Õ€Gãr©®Ä ½n¥žãY¶meÿ³/ hÞâ}éœS¾¢í;7R‹=ªêj!À5ëmúóØY\wà˜XbîÂmÔ½¸ •^BÅ÷˜Â¯|ölê;ªB´RLùœéS~÷ôcNïøh—[g'VÒøqOÓuÅÍÛ¯üðkë³a¦´>SLÔ˜ó!õ^sxú:?`.ïÙ›ÇãÆ*ú„‰ë˜˜ƒlãòmÇ¡˜‹¤ãEœ÷¦§OÌ©9»ôõ©ó†fš ™'7-UÇD§83µ¡Sg½ /(¯×Š1-þž8‡Ç/Mœ(Ò\áòAè2´Ô=ÿµ±žG¨ŸÏ–òÅ7¦ºKf½Ru ¡íXAÕ)Ô£~#Pmet:õ?¾Ä?ôºÚÁ¨;Šu¯ù¼ké7îÏÜñ¹r¯ÛÒáׯøåG¶mb]…ÙgÆ‚:ˆ\HÃ+YHm{Ÿæ¥b+Kî+XroËÿÓ6úW–ÓÓNð•Þ'N\BœÄg¤vAŽ –‹yBØ%OOóO˜þÔÿÞ{ï¥!C†ðï$oŒ>xƒ˜›Ü¾½uï~DÕè|iÞœvj|Z$ޤϙ#Fñ«×~Jç]píÃc¨£éZCwÒwÿ¥¿Î¬ /¶ùŽä3Ñ„Ñ<Ôĉ|kŠŠŠ¨óNhL÷ )§.|²qÃÜsIlÝÑ€V|¼µ=lKÕõŠ…ûÐí§›‡7¢ÓNYK-ÎëÁinÈWÚrkPÉÿw¤i”6¬è´î“†iuiʳ›¨ï¨nü ÈLÜN¼U¥!ØÊuVLÚA›8®$Ö䱆 ž Û•òXÜ–J‰œEíO**œNÆjeIÎåߊç蹂’Öƒ4€žf¢ÖLþ½âÝ’7€§ˆçàŸàtë|×K3a{Žf¼îA”Ï*Ͷ¼ªOˆó! ¯2ä•Gæy¯xÀàÁƒE=r@sJäC䙿‚„S¬Ï÷Þ1‘èä²E“uç“ù!ëäðáÏú¾£yÍ+.øfÓ&ÖE˜}&gMÝA,ÈBtŠ(üªsŒ[¥JVT4ΠA÷‹8æ¶#:Ÿ0R¥ùÎ;—qè/@H¡Å&¨8…Ô^ðê©§ø^ïü‚• .ø…¹Ç–¯õq>¤ÂV†¼òÈ<ï¿Æ”Z?:sy‡€/nI0@€ðà4Ñz±•Pnƒ”çÂi2ë„‹iÓ–¹1dœ»ï~Q\G› Ÿg†yÍ/n6mb]„ÙgÆÛëÌÕ¹‹ËÕÿA+åà ¡bㆋ֮]KW^yƒ{%ÂlçSi=ænºèn¦o™6ˆ˦g6l›Âö)ø@€0I0ïú•0Ž‚•Ë&¸Ã¯ÚF ~Ùz€C\ÝkŒQ‘¯2~7 ‡Ñ0iÌèm.ûÊh˜Ð§‡¤/Ž’Æ~h¨«ë¥Kã¨n‡mÛ‰~ mÛ¾rÍ›7†*~cJ%WÆ”Tû’«6±®¡n õÐR¡Ía>lýgÛp…­/¿ŒàV&i1ñºë.M vRDQ)u6, Ú[4:èö“³šö?Œ #FuCmÍUa¦ö:’ö;2)ßÊÖ@.üÙ)À|¿iépôhØ!‰í|äBOPGP¥þÀkÅTE¶•¹AðS»)(õ[i© Ã¨è‚øÊëéjÎ&‰ä¼¿‚x/¾6…‰Ç÷üSæ7;ˆsë™Gí2€Ò† tå ÕõœšŽ8üé.5ÇŽPŸ^3ó.H žm^ÛÒ¢óÌ„?x¨éÃDar ‚׺Xg´=Ã|¾y¬ÃïZ}Dý˜2¨‡†‰”·@}¤œ[ÿ º‘/ç%™YEm¸þ/ã_ŠZó(Át0„÷‚uÅS§/¥5üþWt¿šÏB¥ù$Vt¿bB^¨ÉãŽ;Îý#FÍ„m„ìåO$ó:^iÉVk¡kåL¿%6 ‚œÒKZK‘'± ŽÀ”vê u«EÃÚú·ÁO’öZ¤l«¶8HSÐ$ù\h’Ú4¦†ÀL£º WϘ^JI£“W¾P]Ï©éˆóÁA;_TÞ¡,ÛêXP=‰¯´”•-Çà™)uŸmQ²®A@è×–™Ï7uø]«¨‚z HÝjÑÂ0¶þ1@|Ûèà ^‹‚Ö¯OŽà½ì•ëqüð=AIj@{ÓÑ´Ç;郎›PS×HÈ…NX# òãŠ+óùw™ºRáM¡f’71bd Û™;ú4›¹vÕm+ï^iiÞ¼¹{”è„Ñü–¤C½›îq1F:b Ž!Ê¢?tŒú®„°eТ À»! £ö[Eíùÿz¦Û¸Ç‚¨?ÑIÔ >`qÄ¥v—ÃHq§@'-³¦ÿ‰¹Ø²!7 ^êW™æMŒÙu7ÌΗ\ºêö*ï*-ÒôK€´äc•>:k] ÉÕŽýÝ0 à3òBŒ4de©ðá‡În6nÜHíÛ·§|N?ýt÷j*¦NJ¿ÿýïÝ£$¶mÛF)Ç5Ñxš¨²ºôÊ+´Ï^{¹gëV­ý”^zãêÚy/jÕâ ÷l:¾Ù˜NëÝ–”¯ .'¤î4²²dQoÂÓÿþpÏR~ š;Ýiö‚[S¬ˆ¡"öë7‘G1K¸á:‘–Ô¡Cï4+b:0øïÔi5¦"±Žà :…ÅEt4u¡E·§4••”bÉMÞ›Ê ÌMÜ`€ÓÐ:à<'…å ·RïÓVÐŒéDM›F·@fšë+lß*F*æÎÝDÝ»7£ŠŠMÔ­[²Üéyÿ fÃèZ‡^¶ÛµsOjðj tkÍÞJîëBãÇ®£k¥¤Èä[*Ó9]—_^Îéï'4r „èmàõ ³,ÕeŒƒÇÌZAçœßÊ=®¿È™¥Â'Ÿ|ÒÙc=œÉ“';ï½÷ž3hÐ §I“&ÎÚµkÝ©øË_þâðîèSHGTž&ªæCðZu”îe"jÉ´ÞIP±Â^¿®“nܼfVãÃF¹Z•o³#®“¼î®nvãØv3¨ÐcÆÌs›AsxêzŸ>˜3Ô- vóŠ:Âì`À3uð…L¶yVµc¡ºhA©}·C}AP9¨ @SFÂ2W™åÞ<6¥lëí€Þ¨ß3KÞ<õg†ù–¶¼P÷=4v%×ÍtãI J+ø÷Ra€Ìïæû‡yß™ÃÊD\?dûýjÌ5kN>ùd–Æ:Ò„ Ü3>ÛQÏž=i̘1î™$ !¸þúëéË/¿tϤ#*Ou]Cpß´i4Dx *<‚%ù ´†G®GXF®a5ð3¶Nž¦‚D‚&Ý~;õ:ç|_¯|Jƒ0½d5µ;ìKêÓÛ±ŽzGŒ˜M%%=ùWG–üߢaÃ&ñqoÏÑ„’öÇÛ@ƒA½g·=íƒé9ÑKû0bD9?û˜à44àÑG™ï(êõ×¥q¥¥î•$ÓUW]åEÇ4þ~ãÆ½ÈÝtzŸúPé”?¤¥£¾ÀÕÕ5HíXêˆ7ê·¶åQ”r¯VCð)·ªt¯ˆ´c;]Ú»=ò´pÙCtóÍ<¡rzRqñÅ\®;SEE+êÖ-}ªÒ+/Ôûýùê2úÃ#ÜØé¨œ¾”¶µëh}G[~t:ò×tï/æÑÍC6Ó˜±Å´Ê›DŸžÎéê­í“Þïg¾­™ïJš|ûÔ›û¡º†-ß|CûžqF•† #`çÎÔ¸qczúé§éüóÏwÏbûÙ zóÍ7élû3 OŸ>tøá‡‹…/'œp7Ò%\˜YddÂsÇŽ‚ `±K]lj=ÌœC™oª¿‚‚Ù\èGe¨Ó©ÇuÕ7€çL)O5L HóYÝo§JZJm¸CoLËYà(àç=Ï÷aU™«Fâ¶ÛæÓ]waýʇøÄ»bŽs‚¦£’¿ýí#¡b5 äÃoNû7}H ªçP·Óöu¯$¡œKÒÐA§ÓFΓÝk{p¾ü`¾Â¸4ËÂÀÍšëh‘f¼„¹ºŽºìÜHÕÕí\†Ð:ÁPaˆ:eœ¶Sޏö„`Kpý¿šv6x׳ܘŸ÷ì;ôP1q;ÐÌÚ>š.ëuÕ)l,êå A÷qç/‹ÉAÉ~TH›…ó$ &nçÁp ¶vËtÞÔô¨lØ |%5΃>_åÐH=_G¼›­xå¿Q—âî"€r8 S¼‹¦p‹ôÇÆäa:°‚C¹êÈåËqá<>xeVíÂ&´†YM|ôÑGørÎÂ… Ý3£GvZ·ní¥bñâÅÎc=æpçî¼úê«Î…^è:+W®×3áyÇwˆ{Lª/†‰ Zc‰ÛS¥Ujpþøc1Ò_´hr Üywú´b…ÿªoê#Lüìg?£R–L3ákˆîÔÜ›Ò~|T Á°’BúÍð䈼»uÿ m¥6ÔˆS[@ÛBkˆ~Êô:ÒU@‰Dsš=Vö/º¯o£”z®×k,Ù>’i-%hV…tûmÂÖèu;y°«G ³bZëE8aÌÁl’¾9û°¡p3· —Ñã<‚¿škÙ[4\%Ž+@L êS&@X Áßþ¶¦Ê:]bW´ÒØAS7^|Õte]BNr',¤¸Y³f¹g$Š‹‹îàÝ£`ôéÓÇ9÷ÜsÅï\ð„”ÃïX%íÔ5¤Úi ¼ úB ¾0B?è|š‹÷lÐy«ß^FtÞAÆ’ä¡õbñŸ‰€°0Pׄ€¯é9QO“¯ó^ÐÓ¬F ê6ñGº1R#*bR|É;v¬£þAi•bŠNR3í™,G«k~„z4ßÇ­·_]}aÖ‡|¿]C ×U›'Å)Ã1úGù—Mã3«E…XdÃ6A…ÿøÇôë_ÿ:Ô@<ö¤“N¢c=–yäq.[žiÒN¤×ŠŠXêmÉðis†:l‹’¼¾0h¢¤ó ؤw¹}(ýy:ïÿýïß4••-¡¾áCr« €¨÷k%ÌmY^ï%Tš×¯?ˆ®¼²}ÚÖ/aøË…UØö,%?§{îéã©Ù©£½ª­ÈTëæ…%K–P¡ajÃô8­¡KyÄÿ¾¸H @‚®;‹Ní*]yÙÒ°’Gü+Ö­õ­ß¶º:|¸\k„…{D0mq1Öo×î§ôþû¯q¹ö^° Ì»ëê\Z¦-< So¯:¶ˆ ¯mŸu 9Ñj‹ 7tb‹àõ×_/¶®Y³F\¿âŠ+œ[o½UüþøÇ?:/¼ð‚óßÿþ×Y¾|¹óûßÿÞùÑ~äüûßÿvcó ‚)íÔUxIË&ÂÆË:oõÛ¦!0¡ßgƒ·† }­„ÉË‹·×ù0soXþæö¨úŒ°yV[a޶Í&ÊrØ-mˆ#GØR[ÕŽ™g¹•NO4SñGúFphTHÇós± Pjš»kkÚÐ©ÎØ³œch’3w–\fƒß÷öº¦Ÿ÷Š˜×üâFA®øÔd˜}&]fø™‡Ñ ‘#GН¾ú*KRbîX·n0.¤€í†Øz‚m„gŸ}6}ôÑGâh ‚xƨû#¨#hLʇ;ÂoŸTëçïÔè0“QbŒÚŒ’1çŒ]1õQ3´EhÓº†´‚‰r¯[.\Aû Y*Ð^Îâ_I¨4Àí1¬}F5ÿ -‡Fmi;-£îBk#à³ioþ §4dâùôWš@-¶~èyJ‹ cäOÔDÔµ)¨ïàf€õÎ0¬J,Wª3tu:8<ÇkÊ@‡LÓš8qw^ê{*Í¥¥ŸSqñ6ºîº¥4~|'æ™>=b¾Ÿ×ûf“aî Ë?›tÔ5Ôå)?xM'À*àÇ_ÈO‡6Û¬ _ç.ÜFÝ‹»Péà%T|ßÛ, $÷öïÚ5‰–N?U,jÝÀÏXŲVEEÔtŸChîüFT2|;ýeA›ÐÖ1!¤¨ýý\Z©>e¡`ÿ–Ûùvñ™íbql!½O © UÒ Zxò÷+û^×Ôy}ÊBÙÐ,óþlê™ÞæMoÖälÊ &ÂTÔfÈE-ÚBMåV••/•Ò¢ûGW‹ÂL 4–ãØß Pi¾í¶×9\ïËÓ|?óXÁë|„¹Wzpôö¤¨M:êâE…©¤¶‚¼¶¯ª8ÊiµÛVâ×ÍíŽÃÅBVyÍk«¯ sŠB†à¹žë{‹ªvI.<|Öã_®ýʾ×5u^¶5É´à¹úT‹y¿¿ ˜mnÐ躳Ϭ›‚Z´íÐfÔÆk¡%msSȇÝ|HÐæ–œ‚‚·ùx MŸ~„¯†>*î¸ùf1®P0[M˜0Ÿ&O9Kl­ÚFïPŸ>ÏД)=­<ÃŽ ²1Ý‹‘TX‹tÙ¤£®!Ö¤Öí»|•~]Üëç ¬µÝ½š„Ú†XtÀ·´îó&b;bã†?Tß¿p-]4ä)¼a,h—3‡GôÍè/!ÛLs`:ƒ;_&.´bRBx¡ŠŠvtì±ß¥-<üʵ_Ùª·òù@2-H£Z`lÞŸIÙ²}— -ÒuõCC€×ª%¤¤~¯Q¢Þvd^Æ@¸±pÆó)C¢O¸FBÜ}©ÃA!ß#·þؤts$`+x¿{ÕH*hÛ•"|ÛöªúdI¦ß¤¶#QsÁ!òeCdJ¼ÃæµMC I_$:ÔwùñWñlq¼®©óQ5¹Ö>å²ý¬iˆ55 ¶Ñ~† Œ©\ z5wS"q × ûHY:”Ye¤ú%LýÝ­U+8Ö6:ËRFjžoûöV¤ àZÐHÃ<~÷ªwR㨰€möv—ELHC6ߤ.eX²9sVÑ ŽàRÿuÆZ¿Q.êÓ‚¥G…Îk©ùJzQ6l€Õ‰úހ߷ôûÞ^×Ôy¬!€:/Žæýóž]MC/ø‚Æ—~N]º`›d0b A¼† FÀK:¶"¢Â‹· ¸Ãnƒ’smI£ƒÝË¿ýGÊëù7F{ð5¼“¢û J‰“H4áórŽ£SC Ÿœç#’£+¡WÁë¼ [øÝ‹xHC¬!ˆdI˜oRס—gÔ!½ ÇC[Ô£Ça\uíå[ôÚk¯Ñ‰'žX߯Nẹ>Âï½tñ®‰ˆ55ÙH³A¯Æ<ÂÆˆ´#µsžuÍ…š„Ѭrâ5ÊÅÈ?Âì¨>ŠÞçaç¥qü;‘2ROÛHq[R™Õˆ Òœ:Zºß™SÂ÷áA>¤ ²à8…PÇÈ[â4ÉwDºÌ¼ð˃ Q=ÒLt,Ó|ú}C¯ôÙ çB?¾µ¹žç­+Ô‹éöîW¤”Ï R&€ª² G>²¥®õ¢ÃoÎ_ñnÊ#Ö^4©…yügØ0i,@£ÏJKKù®+ºŒ%jœÿ„É9K:Ú9ž–9 éb~N¡sË¥7Šç‘Ø‘2Bû»DâYÆ¥ºv…ä­æùäÊg92Áy›¶yäžõ&n«RÞ±3οGmøx©ó]$¢GÙ b’¹;$ên‘˜j&eúa3@ÖI…<Òî@‡ˆò·$‚«]høêÚ®"Á’&Ò×ÄÙƒŽÏ ÛÆ€½àËaP½ÅóÊʼùê¼LØx«<嫞ÿ҃Ă݌l4Asþ¹Ôø¡#µ¡·|@ùËbºòJ¸+~—¨‚{J?æ‘@ªKc¼æù¶mk)vTTl =ìy ´-*¢Ö_Ûh»|ölê?z4ýÀyŠëeÆQïž=«FñÛv$è´Þm­»AÂjL€—=‰ú !Xñæ6Ù{ (?’Úž€½'5æ7ÙÉôŸ|ôQþÑžëyÚ°A*“n¶÷dÂ\ü‡\§wFšë75ch”Ë_‰ƒ™¸ѯ"i!w§†àå¿Ïu¹]JMÏÑ„ÑS<5ßS!m¡¶´ßñPéÝôþ¦¯©×è™Ô„SÅ5W<#v¤×©ÚÅt5í,x'EC€6 ¸dÇp(Á7ÿn µ:æ¼*{^°i”ý‡òòfÔ ‹ŠXCPƒ€Ql“„œçï”ðžç×Éo¾[^§²t  ޸£íY8îH-ù÷R‘v¼¢c¤®vø¹ •qeh÷¨Ñ?WaÁ3Œ¥Â‰ýµ-ƒÝÏÇÉÕÃ^iƒ¶÷Ø´.^«œÁ+S7©aóÂ/͵~ï^S¡E˜/~¸×-¼L†„Ql&ñ­™JÀ/$&›fL•å{ï½7Ëò¹^Ô/i3ù½RóBÖUý[šL¿ïm^o3ÍXÃ6Gh‘ mÚ>Ñ6%š8÷õyX¬£À5¬ub!šypžbNŸ…f7¯*7Ì ´u,§TµsX…okk lÐóamÙ¡`ö™œäºƒÚ& J_”µ!$ž‘!Ì‚Žc³sD¡Çqii°7?׫¢ Bõˆ†ñÂh¬Pyui/¤W6˜à×Z4Q‘äa_üé%,!L^x (µ¶¾6лӦ¥ ɧR‚ïRgáØç¬÷ØÈ¶áA°5óiOÓœf}èæ’7P&žzê).ØZ˜^îudZ>e§–\(gëôõºª®¡~Èøò>ãšG‡í𙿠) ›z=¦ªsn<„êœðMþ¿þõ¯âùa ×W¿÷­Iˆ‚ÝsÞ?jÃhµ{í}OðÎvß»^аçÇŠP?ö³T¨`ÞkƒŠ # ”Pê¨éõÂ" =Qé}uA |m$ìæ1…E? .ÊR²Ã•6lB§YÖe‡+Iú+e4}@&å 廉ÑÎt`áàcwxR² ójŸ”Âu²½-²¥Ï<ÔNêë(l×é;2ôóóÆŒII34ÈË(ŽL…°êF,ì&è•¡ªð((8ÃBoHz5™ð“¯<Æ(:ýýL„I“Š +f%T‹+õÎÇfƒé‡0nå(" ”cð7j¤¶ø*€'ÒlÆó"ñ½ ØÒgž³ÅÑ‘mŒ<“Ú%dÉíŠz^âw˜ú¶ÏO£X“P?‚W^‘%§†—ÔŒó¨ ^’³P(õQ» xø¦~ç¢Í©NÔ@~‰ZE6É9,PØl’«_%Ê&ß™·MLy4^ c˜4©8 l@VäÌU)ñ0"ÕÚFxа *f4’0 •Iºj3 ÈO„µ¨kjdŸmãøèD2ÕtJ`a]…3cò’œ¶r šÒ@˜º†eVuĤ™FÆy%0!ı_l×Ìs¶8€Ê»\uÀX¿o Ö]áaL^BŽíûÀ€Þ[Oh m¤^SÕM<#}±† ɯ@eª!P@eó’\ñx>-Â\Âä[S5 ¹‰ûñ0¢¨„ ›F¬6Âë[Õ6Èú—À Dáƒkz‡«V´ËÎ9w퀼O.œ6m™à¡Ê¿­#†Ð Ê0B]ƒé—Û5óœ- ´+ipD-‚˜IF00ééÁÎ}a#(6rAõÃA ôvhÛçÞëœóéÉ÷£Þ#¢å+¨Ë [ÝØÞÐ÷²½åßýê ßl,ö·áÖƒ"`ò•ûéQA¢?§6ý h’»Ðy#´í½×¡öç·¡J±Oý²Þ…ÖýËæÞf¯½ÎúùƒÎÌÞ¸yÏ®¢¡`³ý;˜X²d õ0€%÷Do£·R|¼×uì_¶2îWî7lÚD«Ö­£VEE)ÖìLÌ]¸ºw¡ŠÒ…Ô­ ‹Ã.¢Ô)Ä-Ÿý=ßwbßf®û¬_O-›7§Êö¡³ùùm¨#5v-fÚèPõpxŸ T2…?”°÷Ù…¦ ÿ9}øáÔU”a¸¶?`Ы ûÙ!°]3ÏyÝŸ=lå2ª]´õýFÝÏñ[s›¸’&Ý~cU[¨àeƒ¤ºQ?ìàµj ™Û`””šN½RâzQÉ<ñ3 ïløª{Çѯ9œïTPû”ø:ï0ÏÑãÌ,yOþ6F@ØQ„:‘”—6%~<ä5œOU“zÁ6ºªo‚lGb™­ìÙΤÅ;9zBèeñäÅÃë¼T\W|/~^çEitR|"TH{‰ïëLæHeÚ« {ÕM@]ÓåšñýîG] £]_Û”Š¯ç€§®•ñ«ßž¡kHLø½Ou¢ªÏŒ5»JJÂJïºdyxÓ59ÓD‘XM¾jäRtÈZ÷Iô‘ÎׂFMà7w~#*¾n.o›µ†@Jý¯°´^Ê7ËzÃ{/£Õ Ãf9óxðÁçéºâft׬½©Ñþ…òN)­M&ýÍ›>Þë:v‡†ÀVÆ—¿IiV½lÓ??n5kÚÔ=“ÄÖ hÅÇû¤Y´«\݈.~kî.¬ÕÉ´íC·]½”~×£!µjq{% /MÄ굟ÒyÜF{R%(Ë|iíÀþT:äE:ÿ¬}µ:P«øÜuá1Ê´˜æ—•Ñyt®FÂD+iÄ­céÎ1ùw:¼ê& ¯•s=HZ_6l•”ô¬Û Až]ƒ¬»*ø=GYHÍÔû¬Ž ÷©.ÄÞ«a$Q@I‰Q$Es.ÛOr"…úÍ‘›ˆÂˆÂ[A=Ão â‹ùMä·iMM¡ºF£a†êe#“|¼Ê—×ùšˆ¨e(°=³¦“ë¼µW8ÖWÒÃk!¾³úæ0¸åÕñÖa–!„¸ÇK›…P'òû–~eݶ(W-”TFšüÊ Ò0Eìbk²D$¢, ÄýjMøæ«>eZ÷s ³Ïä$ÕÔ•MV àʧ Ñ'¢<ÁloX›z <7ˆ·_/„å Då­ žá%$ù¢±sU»"ßSWBrÏ{øF;T\„8®,_àü†Ò=‡ß–*H³^6àÖ•¦¥×&•Ÿ^çk*ðÎQß=[˜ÏDÙ\„Gé@¼(Ê.Ô[s‹Ÿþ¼dz¤£-ìFPe^íÇ7;vlZ;ÄÛL³Yî“çå»(så:p;ß"BßÖ mèp¹vŒd`!eìÉ븆wGšÍ{³!˜ÎW}òÊݳό§ rˆ(‹OfÏžM%%3¹VO§Ô‡ÿé­2ÎdñLµT¾øÙ,øyóŸŸÑ½¿˜G½îO¿šê‚T©t·9m©!ç—gq^¢€Æ šHçœØØ=æ'¯Þ_¸1½¤Ó-ôôòûÒéXòŸÿÐÉW]ÅUnR¡Ë^ÁqwÐß|U¨k‡÷Ew=rG mzN·`Z‹=¨!ß7·ÀvÎJZšæ^Ž”àN÷ ‡Ñº/÷«š^ñ*_“¦N¥Î¿ûç3Ò î2ͦkך„ÊJ¢Ë.'*_Ж:tI~«|B/·XêW6uA<"¦²²²ÐS:QË=âÝÔµ«ˆp*¶\8-ƒC¤Â½/~ÙÚšùK–ÐM„æ„…CÊ©Ë%©ó~ßÒ+/î¾ûnºå–[øü.ÂX^›Ž .ÉCigƒwiÎÓ•4ô‚¯=ûÁÁð‘Lk)A³*æTåâ¼õÖ[tÛm·…j—ý¦ÃN/ú!™fL³¸N–øý´‰ù@ý˜2ÀkÕ"‚ä¯oÙ±’4ÞMWÝá#/(©ÚÏ‚^6|½F ™ðVø°DªüLͤ#ÒÎÙÎë<þL]Òì›+Ò’I‚öA¦¹Lãáµ8Ô–FE/1>’ ºo#~úñ)Þiù,j4…™fÉôr¦l¢¾àد^ڵ܃ӎÜoƒAÒ=·®!Àô€ëfÜg#”Ñ&L^¼ýH¹þF¨~/ãgÛâ‚lßRå…nci050EüþjD.)ÕØ“°(Oøx©|VÚÜMŠúmN©èïàòªB~ MaÚÄ| Öäa5™l;ƒ¤]TTÄ¥è>â& „+S9"J]¬ãå*¹¦jnÞ€¶ï™º`+¹è ã¢âœBžý'jÙ._%žúÇ"ºkêFÎíßÒGôGÒçtêiä³m!¸­à»v¼O•3+èë­EÖÅúv0¯…’6 ñØèŒ¸ø„m1ÚÍÃQ¯’Wi‚5Z>¼k DÑdƒLÊýC'ÐÈ»¯å_v핾•  ¢ñL0ý‡p†;}ÏQìù×ÝN³Íuˆ®âr8õÎ;Ý# [ÙÚžèD•΋ý\Y«rÆû¤‹o ý;4£‹‡åvZˆdYžsÏó4tH³ÀÅŸ+ zúÁRÛæ;é¢ »¥\û¯ÝzçÝ´ß¾'ÒöïaÖ]¹Èt×|Î !›Hø-* ‹Ù/¿L%S¦¸\SÝ0WΜÃíK‹ŒÛ—L»?Î3 yz-îQÀˆ@J«ÉD†|’¶¶ øw O)W!¬½ 9Bj¤Æv?x…5¸¢C=¡ à£òY‘-¿U^C #RG©„Msd^È4#ôâ«Ö–(ï‘zèï­¿¯ä½œêBÐ÷ÍÌgæ3Ï¢ò–i“ ô¼êÎc1¡4¯›\;BÛ`{îÁxSlÉ„Ðo ®©vâá>÷‰6!hmLШš·&®† ×é|,5:8/P»ªønÛˆÇ^Ú4\S®£¡5éIÝÅ%/­šÉÇëx8×{Ý%5ž#.dHÐÔ@ûÈâ’SĤÚ~õ~~3¹¤œ&zøá‡iìØ±´qãFjß¾==øàƒtúé§»WS1yòdš6m½ûî»â¸‹êwÝutÒIâør}ôQ÷Hâä“O¦×^{Í=òGÚ|ÈnF‹-"® tÊ)§xŽÔ¶³†»^ácgêÛç74p`ê|¶‚Mz_™àÑ뺵¾£™g†•Ñ…wA K_¤.×ýŸ{dGÍƒŽ -A6„ÑB ¯± ¨I“&ôí·ßZ·AëÒµkW*¤ã9Ÿá3—2½O“ÊʨsçÎ"`ËchOþ]Ú[­rƒ¹s7p^|ÀyÑ’óB¦ï¡ Í›7úöÀµõ .C9ÈyÐ;%Ô{›ï›I>ï.„Õ2å¶gæ3Ï¢ðŽ’OYD÷õ=%˪—v k*§/¥v—y'*ÌÒUk?¥ùK¿¡³:í%¶TþîŽ;èQN¯BÓ/£§ÆÜT56ãû’¡…xvþ§T<¶+•ÿžz—I/–.¤¡ƒNO©ÏÈ£»|UqRZ7s+ªþÝøS¶š6|rbáG|‹UÜ"Íçé,ZA­Ü­¢@eÉLj×ý(÷H"Ê–ð¨È™†àÉ'ŸtöØc‡;zç½÷Þs äpÃì¬]»Ö‘ŠK/½Ôy衇œåË—;•••Îïÿ{‡;o‡77†ã\uÕUιçžë°€QEŸþ¹{5»[C GáW¦b$©oˆLªƒæ¢ØØ×·Û!ªíþ(¼p+³a6P]ƒ‘µm†ï¥Fßr$Ÿ¾c![˜ï¥—Œò¤(™VŒz ‰ ƒ\åYu`w¤ÕöÌ|¦# ow½3qbð6·(¦²­k|êªNaë-®#žÐXø˜„gc A­…Iˆóúĉiq±µixø¾Å«ã´^Ÿ•6 çÕuÀ<Îøf~ÚRœG݆†@}äz¿¼ÎUm0ûL~Lfà‘½3`À÷H¢m۶έ·Þêùãûï¿wöÞ{oçÑGuÏHà׿þµ{U/·|¨BîUñlÎ,pÜ”>un¢{G”Ë=vª92…/kÙ´iU¼LÂs`åïávnv•ºnã(" B¦¶ûEƒaÓT¼3¶?„^y€-/›ÙBo}ú8›6mr¯£êå{5Œló@øÎAû‘9W†9.ýºIúó^W‘R)lˆRèjІ LETPóñà Ìó3ÞxšeBÍ3ê¾9¾_ä+Íù@u§eö÷;ŸéËõ2¬­ÊPaŸ|° à¶ õ 6Èûdè‡åÿøÔéEÓåΠˀƤOJ-ö<øçUœ­å3œ÷JfŠÇŸñµK9^/.ã{0X’¼ôÎ\n£l0ß)ªvä  "h5p­=Í‚™ÓH.I-/¢ñ¡Mø]Ë9>úè#ÁdáÂ…î‰Ñ£G;­[·vüqÍ5×8ÇsŒ³mÛ6÷Œœ†xþùçwÞyÇyî¹çœã?Þiß¾½³}ûv7F*p/¢…]¼\ Ô@À§D¨îÁ(þÙáK‹i†0|£Î›¤xCµv íéMí‰&i…N§ŠÒâyGÓ‚P1néãÐ䭉˸茣4HÞ¼mðª¨ëùábÚ•ßa·áÎÓ/O”O„å[Ý'ø·EMsèïõ¢ûDÚù¨¿S¿„‡høõï§ùJs>PiE^IÁQ´¸Ì&Ër~Ò–7¾'¾½›¸ÐFÐ2}ǰ÷éBnXÒ8¶E{¦°ìE^[n§ÞVæ¦.æ;e’ö\U¿¼ö»–-r*,Z´È=#1jÔ(§M›6î‘7î¹çgÿý÷wÞzë-÷Œü±X§ðÌ3ϸgRqÇwˆt˜¤^®ºNi0;I›ºû±ýx›À55"ÍO¹üÒ~úH\ª7ñ.áöi‡}G¶ŠŠFCÙ @¨‘0‡ŠÁ 2Isè|Õo¹=ù]‘ŸÈWsÚÂüfÐy×tTgZÑá"ÏÌNyœÏt„åïUCEã†Û2yǰ÷y ïAá~~Y™ÍkæJ ŠÌ<ÂÀ@Ö ¬4ÄwEXó4 ¿Ý\ˆ¢§K‡ßµl‘ ›)˜×Ä´À’%KÜ3þhÙ²¥s÷Ýw»G©ðÔ¸/·; s½“ć·©+(ÛÆÛ®É ÒÁ)$ö6\½EªN/ù0eƒ­À+;ãQ$CAóý ¦Ò¦fý†é|W]ØßÙë=—–/ã‘ø{ÎÂä¦Å;„}:_õùbû®zc¦á‰ÚQìNèùoèuÏDˆö çó™Ž(¼¥[Ôø aïË”¿l<‘'È3ôó n›ˆ aÚ“¯í9Qá•.2æ"^@_©÷™ü˜Ì€E…t$Úµk绨8öÙggñâÅî|öÙgNÆ SúÁ|¹š¿ÆÈõÇÖGCè܇’Aƒ‚ÔtŠ„Tê¥PdÝš¼µg…!ì›öBÔ|ö‹´Ëoî]tè|ýžd’ °ßew"èÝs ´=‰Dk~&êcrai>Ó…·Œnž?jš£ÆW{_¦üýàÅycžq,m4ø×K“¯×s¢Â+]&¼žç—¿kÙÂì3 ø #ÜxãÄN<òUVVÒ 7Ü@ëÖ­£ÂÑ•W^IC‡¿®tûí·‹øGy$}òÉ'‚¾ùæq!PbaAXôzùå—é—¿ü%xàtþùç‹8µØ_޽ú:`ûÈóìeçÊ ~¯ ¶»ç´©¢Bnrö ¶ ÊizÉjqMŸQu÷uN$˜l†IêB º”J)±c›Ü@@Ÿ/\®ÔÚÙ%öáÏù1±_?Ú4wnZÜ­ —Ó²•´}Ëv~ÆtZQ¾À3'ò{þgÚ4zfØc|¼”~ú;»ëU ±m+?{V¦>Ï“`J@¨Gš'ôí+ÞÁö.«žGeÞ¡~Ÿ"<é@z‚°ýH|¿¥b¸×ûëßñ÷ÙûÜh‰°>6?x ÂMêJ>jA×]wih¿¹B¸¼?‚:w>Ó×¶H}òÖ\mytÿý÷S£€6&Jý‹¿tÕ*± CÀ®@‹-œ=÷ÜÓ騱£ó ó¹8ãŒ3Ä®ÄÃãLÂ:`ëÖ­ÎÙgŸ-v`Ý@QQ‘¸Ÿ… q= ò©!€ä—‰ŠñåhÒ®!ðR!e9‚ż4¦PZ;ƒÝë^ñ‡WZÀOW‰íu£YCVÎOtß=Œæ¡Â‹?ôÑ®™5“‡QÝÜ*I˜4㱸é^¦„{Bs¡”Nx¯ Éß|/¯÷WðㇸºV#æLÊs®íÜ­aEíU·Mµ`¾þõ×_éÀ-^yfC”v@}¿ââ©)yo~7@®‘.¼ƒ5Íaê‡ A÷©¼0׺äQÓ¬4£ø¾âÆR.©£æ¥” ¯çù¥#j^DÙgòcêò%˜©­BûAÞŸnÆ¡mmA”FÇ ƒÝÏ|çÙ+- H TbèHl.cm4…¯É|“ ~Žp÷Ûƒl o¿* Ô)m…= Ò¡ò&(ÝÎ…M³"›ÝлÚî4CªSÒ)K~GsÁ:ÀöTᔕVø6¤^i޲K‘Ù)Ê4Ëo‚ Èw=~ur^µ;y€=àÈã(‚I²<»uÊ'ßpèT÷‘§ˆëy‘K#^™¤íÒ¡þ1óuu ß[¹¤Ž’—~0óÃ+Í^Ïó:ŸI^DÙgÆÎàåPÆÏ&îÁô œ©8 ~N×@cfíO眔PÚ ènA¹`ùšö‚â­;ÒñKsòý]r&ù[e¸AÁ*+_»)` ¤eذaÔSsÞbKÃ6z—**ÖT™ø5ᕇzº£¤9pY=jÔ(ë;¥Bºmµ9¬1¢œJJúñ/ù}wíšD6ÓÄHs‡0:  íÄÿ1qБ–»gS…u &©XuóŒã®á_»CÙùÑÀ:¼Kª©ÖL‘êô Îp×PëüJŸ´ƒk £™ 9ÿ§ßKÇ?8Xœ÷Ã&¦ó˜t> ˜`|×,E*î7t>½YÔ.¡ïé)k«ï¡WAíËÂ7Ói½ÛÒ‚òÔåoÕ·r,äôÊ4 œtÄ¥Õ™ÄJáÜgŸ&вʯiПõ Aw?ñ&}ÉqîqfS§½ ÍÁ÷ç{àºÕ€ÛΤËj/¾6·Ê:Â8ŠÒGx™!¶9ûÊ&/Â"v¼›I©À•Š+È-¨×?Â>}ðÆýú³ÃÒ‚û1בTËeæ(( B­Dú…ÛSË;‚Ô{êÓ1"Ý<‚V#üŠÒ2q®:Ò¬žÇ‚³rÖÜ*MFõ¦›[áÔÅØ"åU6–ð{ÙòA‘—VC×xYCDžé÷ä›ò¡!ðÚ“ÎÝ}$£^¹¢o©PL9/ŒåȼÇ7Ðët&uu:õ?š×t ëÛœS÷E­3Ï]=Ì-Á™C•ý´4m‘ =Ë4_„úh m|ƒÜ*G™: CAüTÿd“aQ?4<ªÞ§±”²²…ÍŦé sÛŽ­ù¸!íÓh#Ý<ä:úåý7~B¿£ÿp^$p~Ïá_驈Û¨Q¢‚VÒPGoq*’£ö¯8m7ñU¤TÇÔëÆÒïJ“£Ô|Œ äèI:£’Ðò,Ç£Ž0ã'*üFÄŸ~öýöʾü­ZÒÞô!—m¢<–Þ;“ÆÞjuÝ«#Jy¶Õ'h‹€ PYYúÈ5¬6ˆ®!P-Á æ½#MC`ŽZ“‚=ù.Ô°5Üæí¤k/¹„JŸx“{¨?ñ¹îâÞ$v¯†À¯mþ¯{wn€d¹O$Þ¢éC&Ñó÷6òüþa E)^‡XCäKCÕª–M ´Ÿ · ™ÐÑ"\dª{ƒ¨„šq~^×mëL„àšß"8:o9>%V^~¤²«¾ çëýƒ M€xGG_s½S6l¦³rÖ â>ŒØ‘„RCú}¡!(¤öiy£çEP>‡ä'Ó‰ùs¸ÏÎïL€lÅóæ~ù†ßfyŒ’Ûý^À5=°¿¢¯}Ñ!ãJ¾ýø¹N³ŸyÒ/ËlÇäZÙ&Ê´çv ×7ô‚®½T‹| &.¡½Un•å{L©Zü«Ìu„Íë0ùì¯çd’Q`jø1uU/—ÓÅasÁ-: ˜¢Å1B¥ôRç¢ãÐ;tfzƒc½SÑïõ#<§lðKÎ14ÉÓj—‰°«Y£¬z5AñV¾ð:AПJm¸ä®¬*Çoì¼ÃÓ¯Jï÷Žx–zÄ7œ QRi4ïaÖ‡ÜÀIOn‚A†„òבŸ¥ "<>â°B¬*âx=„Aˆ7*ò•Ž(qà ?”w› ó¹N•'ÚYÔ!}—H Ȱÿ“×tgH$ x'´#ùz7lÏQéȇÀ¥ y€ù1s-ÑÙ KD½/lü¨|£@ñ¶ zEõ®UgÃUÆŒ™É¡lŒ¼¼š*ÎeîtR”©"ÍcJ6„:U8OÐEÖ{t²Mw劼TµÙ ÊwÎg™ÈW:¢Ä ƒ°ü¼;¹Ne;¨Ò¨E›"1! ‚QÑéò¥†¡òÛ‚Gåà¯?ÇLG.§dt˜}fÆ– cxC-$ñZ#:°( lºví*BÛ€Å6ت‰mGB,âªÎsX 4þ|;v¬Xl z'% ±åíWL258êH‰•T6|8áZTÔfÁ_hÊôBj±à‰”óQéÇô&?“´'SGj^>ÒzO Ár% Y°Ì–‚¬*ƨyÀBHµHa>­=6Z³‚–Q'jwy'¢NþÔ¬{wzƒûÓù|lQúYóÍæºÖ9ÑN”¿uÔˆ:ÐmtäæÿY­VŒêÇ¿çæÜ²¡ Ý’ª-¨}ºÖ‘uN Ä‚:‚š¢!0³E¦ü¢Þ6~T¾Q x?QͱI˜wÇýú9.å+Ý ºd/)i¨sœúâ1yÊtÎ1*®Dâ8~ö|Fùä#ßòù-¢ð®éˆ7 ²}v”ûÃ" ÚÝP˜¾ÎÇ„ÒÜ=1$œÓ|h²t„±¤*¶H汆 F$¨Ñ.ÂêÄ>'Gj€7Š–°ÔŒó¶¨KñÙâþ¢­_€@dÉ”ì%­cšK…´‹kµCwÝÅ£}Ë<ÿü2dHµÙ?ÇhnΜù×™"ìÙ³zmùÇÝUçvÌ÷Eøú»ÿ¬míxœ«]>Ô¬[78y2½Ý ×6 €®¸b°Øžç¥Å¨ÒÞ¶í"4^þBà¦#UäU“mçÙÅ·ˆtt¤–4ú‚ ÒÒÑ‘ßi¯Ng!z~!Ä‚:‚š¬!3ÿí¿0ˆzŸßœÇRÒvT¾Q xg«!À}¸__´&¤|0ß „¹JŒXò¹@(x¦z¶þ;Qâ†E>x*Dá]ÓÒÍ­ÎéÈuš3I§×ëþ0mžÙÆÀ<–ëV†Ö™ oü»“H¥Ù\«„ô ž"=ó½†iN¾¯\ ’ÚD•/r['´™ö!^ˆ5»a翽Ãz˜ üFAóXÊ{X¾<†éø¡a㪂>Àü7“&‰ó¶÷á~§0i J÷¨Ï)æŠl# I´2ÑX¬ehÖ,¼6Àï[Ũ[uo.UŒ²×9]Uõ/ ¾øŒzÑ Ú¿bÑ I³¹íèYTD7q›‡ÇꚢMãǧµ1o?ú(]Àáù$Û¢çKF¦½ÿ„¡wP‹¢d{ŠcxHmºöSêÜ#®c†—Ò4r½™îxë5ñœO×JO¯Ð(@³€z‡0ßš4å ·¶s:úŠ|ÀrÊO˜ž¹ûnzþ¿ó™ÞÔ½ûüÎ7QQQ[*1Âþ^QéÍ7‘Œ$„XPGPS4úüW&£[l9Â,ôt™Ò¸É+êZÄÏ1Tš½vpE %!›ïØÎåæC:™Jî8 ›† o• ôg‡M%nXdÃßßo¤…w6éBÞ™h¯rUÿ¢¤Ó÷Ãå)éÊ%™;l°Ç4îÕI„bWNØ1f<´±¶:¦Ö¨ú›k  £~w #ÒÒ¨Hy€%×d5´ ¶]I™Œøé}fÝ4]¬Ì0#/Hh­ZµÊj‚¦®1PÄuáø¿‹9ì\£#µáÑñôøãÓ©§ž˜fÝ®™4Ãlƒn¢só–OhÕºuÔŠG ºÉT”©Ð~¿ú'ýë¹ïiƂӫLyšðû~æ7ñ:ç…lÊîýàƒ¨eË–ô¿ÿ‘òÌyÏ®¦¡|AãK?§.]pïHES¨:pŸéTK‡nš“°y1wî&4£ŠŠMÔ­›ÿ÷ ‹(ßPßc)ßäü+ oýÝŽ=ö»œ´ QòMÖÕW¨ üÝMGiÙBϯƒö/÷¶¼}Â?©Í5¿àeúû¦®ù÷Oh==[1³êýç/YB7 Àcút,RN~Ý!аzí§tÞ·ÑžôÐ#Vsí÷ÝwÝ|ó“Üs¾A‰Dgšç|³}[7P¹º‘ø~Ðì4jHtîå³iCÁh._öÑ6F1˜£Í‡s•÷'ò¨r`ôQeTGí¼´0®Ó²oœ“¸´¿ÆãÑSh‡fÝÚ{Ï}iíâtäa;¨°aê·õB’÷ Ì{ü:ÒÞÜ.¥}® žgž)ÊSw®ßpQ%zídšSZZÕ„qÂgÖ­[iß~ýbçFù iõ áÑi×0ß·£Qç}Rrt®6×­~$öÌ ¬v"_Têj1š×rMæ|dØk&éqMíLf% éü7ðNLú(Ëm{i¨Ô(*¬}Þù¦´43á¼óÎBCÀéÕÏÛHåI:ŸCYGõëÙX‰Ôó[?ïÇõÆk¤4ªÍ™ÔUq ¸ïî`ŒÚQ––M›æÜà Ý’f×/Œ|Oå_ Pøo±ù‹Ñ ÏnOÎ×Ý-x…ÍŒ¨umòµS®±C; &ʾíz]¡ú±† š4K–,¡þ ·aJº9-¤£Yª|šÏy»Ž‚Uk?¥‡žú‚Æ=u:?é—<‚ÇZûà4ÛFÄxw®Ô¼ysq_ؼ05!¥Sþà;ŸeÔ¡LKkj$Æ¿ÏHCPÎiíSòO>»© Mþs¡‘QùÑolcröþŸuž-“²áç"Uiöo¼Ž.º°íé´d)ÿ–òï¤ï þ›Â׿†öþV-ù[ù͆M³®ÉøÇ#3éWÜå^ µ†%‚7ÿùÝû‹y4º„è(Ÿipsäó9“Ük.ß±ìê«©7¢tlÝÑ€V|¼µ=l 5n˜GêP|¿wŽ£íô/Ïá¿Ó4olÆåœÄºšvGm÷!É»‘и5â–aÄv±þæºûN´®½QeóÚ±M¨øæ ¬ßò;þíåÞY/~+ðìá½—Ñê„1´”!›†@®+(§‚‚þœ¶x”žtñ¤ÕÀŽ«þýûÓ?¤Þ絎¡¢bõèNc‚ç(÷ߺ6̶¦GÕ§O9/>寧\@ßÔ뺌Ï{Aäa‡tÓ ªÖßA]S¶5Ú¾‹žÏq¬ñ£|OÝ ¨t.×T |Åi”iµåx*^h;$šˆóÈw¡M2Ö›èßí„YWmñM»¯ŸZ5l'¹%eeÖk&y5*6Èmˆvìø´3A”|–ÏBÙ n@Ô÷ÈGyû®QÞ- ôwÓŸ!ëµüNø^^‚©Ì4û½³Zd¹ 4x›²é2ݤ¨îÒõò땪¬âð†Á ýÊ®y!Wei0æ&·åɺî·xÙKXú°dzZ¾DiÇün𼈼±}³l2¿³œÂÄÑaö™õrÊ ø©áŸ³‘.qMi_WÏ™µ‚Î9¿•{œ¢l¥RÈäPµõíÛ—‹(Þ™‹¹¡šlÛ”²y¶ºˆz¿ŸŠòßæ¤-~Ê%`ð¨ÝeÞ‰EÚÚQk­ÊéjY›:6_ÐÕ®……r‹¤×4@.Ê‘ }Kl‹#£©¸s Ûtm fe¢€V¬[›ÕT‰_>ê×–/®F×õ{Ù¦o¼ª^=øqúùØK¨u¢F¢~I]Û¸½›Ëíݹí].ʪÛûíjOçÐ-|f§iÝ4l4]6j&íI•œ ù uu¹þ.Û© ­¡ÇùWš[1š¶.ÝLG çJ—à5>x°pr„Ƀ|lñõCÚV}uUÒ^+Ç䧆óº–Kg™HØjÔ!Ô‘š4–t©W: ‘ï ÕÜð>%Î÷ŽH%@}§î2j6x¿ýIXWi^’v A û®H'žYõr$¾Wž¤ãqƒ%nXˆwtßׯnå›Â>ß #¯là—æµ¨#=~ϱaù‡ªÞ3ˆlù…¼A0õ6ïö.jšlPÚ¿\,ô{¸Ï}‚g6m¤¾–ûwAø­¨I"©pŸ¡ÂÄÉ%b A†ð[8–4r‘”Ps©!£ô \L¢Ȩœ±LºÍæRêΣ‚ñt!=ÂvéFE0aÓŽ.×®(_@m¯îâ…ƒ’¤?iÚk¡`“´%_ûâ§lvôS5aFlQↅ®!ØFÞu+ß°iþò¥!ðýå2£ðBº¥Ïx:›†P‚n§>}~Agy¦§†`ÌØ‡hŦýé–±¨3îv^¦êÔ˜[§NJW]uUà‚H|× ?§Ñ£\UÇôr°›0¶2ò9÷ßó9´Š hxŸ?ÒÈÝåEF˜úºæ‡ú¡!p¥\"HrÃ(T-èPÎ(r!åA”£p)™#ÄsÂŒr©!aAN»D'gþõSefø¶í¼Ä4ì,75áÇ’Úmsvúh÷™£vÜÊѯÅO™BñEÌEscÁ”>oŸ«yÖ0ˆ’æ(qÃBç™þÙB¯Ïø^Xû¡€rcj¥‚~~…¢äAÐóÃòÂý~m‹žfYÅoÝ•·­½ÓÓåýü Ÿ›®ýóK«3h'T[uK¸IR{²Þ¹ºŠÐKë$Ú4ä*ŸÂÂì3ùÑu»S PðÑѨU·¹ø¨JM¦WZ‡Q_æ¢pÙ*š4¼;d¹òW›Jð¨œ^@zÑ™‹ÄgIzåËW‡%Ÿe\é•M5¼òȯÃÈ5¢§9\ܰÐyæƒ. ­Õµf®ùM@² _¶ñƒ„ú°yæùay…i[T›¦§UA¶sóqãÒÛ;3RNSxÕc¿´*˜y3âÖ‡ùXËOmÚÓl –À{Ay¥XÐùí‚e)÷Ø)&<Vb CDùP¹ü¨(ܲby7&^ÈU:ÌŠ¦øúmŸÁ [SP72a[ÐK'Z  M/ùPhΧ™Neù‚´8 ¨¤-_.’¾ƒ`‹›Í7Î2r[]Ðsô4#nÔѱ :OýwMú&0Æ„r„yk”7¯2‡ÿo³¯üGYGÑ¿/ŽaœGÅA9ïEÓ=Ë;(¨Ì+ Óñê3-wxîÓ]•{¥³„¢€4…z.¨ÐïÅ{6 ‘Ÿ^„5ˆ¯îú¿|ÇmêÙ^'—ˆ‚ á÷¡P°ôF2×UJÛÞÛQ¼ët(è|ñκ° F¨$"’Arµ˜š´nR‹–@ø­ðM LDÁLc>;\ýYA°ÅÍF ”)äˆMù”)•fs«YØrhƒâ‰Qæ˜13ù÷úœkn²A²/`C†ß "4Ë´²z—RþÜó*N>ȯî(àfÒ¶êÎ)q„ 0i ‚­……~/¾±W;• y½£|¶¿žÍ»e‚œ =ôsä‘G: 6t:vìè¼úê«î;fΜé´k×ÎÙsÏ=E8kVêüò®]»œ;î¸Ã9ôÐCF9gœq†óî»ïºWƒ‘@€„õCÉ •ÚHæã£f¢îÎG:?¾¯¿þºÈ‹¦LºÃ“FŽÎLÒF8|ŒóÂß1Ó{%3ãi™s_Ÿ÷Df”cSêiÌw‡ë—&lq‘vY†´#ðMßA§¥%sDºÎåtéßô2¾ç3ãž­å3Ä7üö åKzÍ"î$¶àý[d%däê›iàˆ§@¼ƒöíø>Sû%§ÑšˆëMÕt.50؃4ÀOdÒ¶x“ðþ~?$ `¥ÒWÈ™@ðä“O:{챇3yòdç½÷Þã—ä4iÒÄY»v­#‹-Ü]wÝåTVVŠðG?ú‘óÚk¯¹1çî»ïvöÞ{oç™gžqÞyççâ‹/ÂÁ–-[ÜþP/‡ôD­S7¡[ÇRÀ«‚¸ˆ_ÁÐBé'ˆ(dRP¼*zØgzÁ¯Q/òBDÊžò¢ø™iÅÐó ï);ž–L˜ïÌm‡ë—&¼¾£,ƒ©#µl¿“À3Ê÷QZ¯ER6Z0²¶ùR0 ¹dаùÏöM°®@µ(CIëtÁÂ&žc^°eiÀsÕóq¬ÇæÔXÐ{z•É ¨4—–ÊP¿ßLgÔ5~iÎ4½€™Ï~‹|£Âï¢ÜèÓ¨ ›ða3*å7Åš--›þŒx÷¬‚“N:É0`€{$Ѷm[çÖ[ouRñÛßþÖ9÷ÜsÝ#‰sÎ9ǹä’KÄoh9ä!(lß¾ÝÙwß}‰œa ‚˜L·™^äÕ©ë ¼.¥#e)Œ@Aê1¾ ADI[„a^¶9ó(Ï´Á‹¯*0øÌÝ–1]•ŸAy|†2SpešÍN =¿dš“#ÑD"w#Ñ ü0¡§Ë„Þ €O6ßÉÖÆ‰óÇKCðmùÎ?‡<áü– }5pk«?¯ZøÎ¿¦Cªê‰"¤ï›æ&l¾…ç÷MÆŽ[UÞu‹WçkøF)Càm,liA¹×ÓlãÏ‚øÃÂL³×.•Î(Ï0óÙLs&éÌ4ãXòJ_ä6Þ à‹ï€ò-"ø)|M±fCàEtSR ÈÈÁÎ;©qãÆôôÓOÓùçŸïž%4h½ùæ›ôÊ+¯¸g’(**¢n¸AÂ<@>ø ­]»–>üðC:æ˜chÙ²eÔ¡g‹_ÿú×´ß~ûÑ£>êžIbÇŽ‚°§N{¾âßûÈS9Ç¥Ô‚V%Ö +X€Í¡„re9bQÛÖîQQè®káÅÏr¢r›œ²_7±’¦Þy']åº:VãC!™f¼”tæ´£àZ>£‚¾ÿ¡¨*-p.ÔoTÇ{ƒ éÏ·œG'ÿäqý‰yÏRÿÑ£Ó\A¯Zû?j{!öõ&- ½MãþNÝNÛ—‡ƒÊ—[¶Ó®qhüà%iîFWÇ©˜#ÂDu£ÃæžÚælF‡Ÿ=‹åÂe4YÓìõ”ËdÓ=¯×yõ ?u¦uô)Ÿ‘–$Æò¹ÁW^)~›PyôïwŸ¤ëîeuã6/Ôþí†NsÚæº)‚#`/·®^°½_X7ÐQêÞŠ÷4²Ä¡k1ïRû=¯.{‡îžº€Ÿ;ËV7¼‡È—0e+(ßl<¼øÎ_²„º ¹ì½ˆéCqMÁöžfÛbƒþÌÍ[>IK³_]ŽÏÍkH÷–lteû6ø†OŒ.å6æPñ½ñ݃ÒkÂ+ŸÿöÀ?¨û ³D}Ä»}/x·W–~I=nø…ç7Tß9~nr‘`*2„Àþ[wþˆV|v µ=ð3úzÛçtÞ}÷¥ÚzÁ÷»é&Ú·ñ~´ñÓ=éЃvR£=Â¥UǦ¯¾¼¿£–üå>ÈÎÁG}„8 .tÏHŒ=Úiݺµ{” L/̘1Ã=’À1Öàžà­£oß¾ÎÙgŸí¥ë pIÐ@ƒJòY&>éI6—ªò¸B¸)IG¸ç °L¸R–é¦6—©A¤xû©q±§éÉ…E/?ÒÝฌϻ'B‘zÖ:Çz„奄Ÿ™¶(¤òÙL³éBW'¿çå³ÜØùß’šóÏði¶};P&y¡F?ø¶ëµ‘ô©¿o­((ßl<¼øâ›Èü̬ù•?ý™^iöª«¸m§íZ6¥¾ø¥ÇH£Þf¹‘Iæ‹}Ò_™ðÜ×™äwI׊ínʉûã?þ˜?üpZ´hrÊ)îY"è±Ç£+`»*Üñ‹Q~¯^½Ü3D,+qÛ·o¼ºté"xzè¡n vôׯ_O/¼ð‚{& / ÁqüVó/É_GùË/SÿG©ùüñWýiÖì>Bý䛯X‚üÇjÈÔ–iÇa)Uù@úÔÝÔnýb;­]¼1mt¦#ª†@ˆZœr(5Þ¿‘ïHSIà wíY庳Abg5p{$çÄZå}Gã¿Jƒî;5%-úˆa%º¹ Òó¹€óyÅÌ9ÔªÅÁˆ *_=¼œöûüCjÒh#]psqÊ;¯âw®œ#5~ù‘Ïçñ¨ÃIMóZ ×èP寖f¯ï¤FwæÈËë¼íî,Ø™±VC!9ó®'€Ò(7ÐïÓí´•>¦kùúåÏŽ¦¢C÷wcúcá[;躱'Ðø!oR—ãñ̈‚bÎ-¦WþnÛ²“>yç3jм€.6ÄúM6u˜ÈëQ?¢3/<@ÔO ùfãáÇÚ¹A%¢ÖÔœG Ð¹ìHÉÛ{šm‹ ú3nº&-Í~u÷žvy š9ðŸtVç¯=ÛDÀÖ.òW¤!WL¡±/ʳÒø¥×„-Ÿ ;hêï¦÷?•Vü]{Ïÿã^Òµ{{÷*í—d¾ìͼZ¤¶‰í²§å÷(à>åŠîÝiæó/ñw9„¿Ë*îu!]ÅõÀ~}„*sQÜrëP¼¿sö ·igvî„Å<™¹K€+£ó³ŸýÌ=JwÔÎý÷'­}8.**¿ÿûßÿŠü[¶l™8VøÕ¯~å\yå•î‘?Ô‚L|ØF>X@(ç˜0§•›…':Àü2á4æÅ¡na,Ê3¯²Pf[T¤#(­€Œ“}>Ûž¥§Ùä&m~Ð%!Äq.à—f^é÷{¯°¼üxéËçÍÅzQ€ø^óµø& rÅwø<¼x{åO.òÍÆ#ˆ¯>wïÇ; Ìg‚OØv$(½&ô4«6ËT¢ð°Aç+×ÉuEX§ 'Gøˆ§¯)ÀoÛ"G,‡öC¸Žv×= äa˜Ð|)ÂZ©eÓ¦ ÛQbŽÎW­Ë ÚÑòJÞJCÀ¯Ÿ°¨pàÀî‘¶ú-*ìÖ­›{$E†æ¢Â{î¹G<2YTxœûԇЂpž§<@6jÅ9‰ß* ‹ÙØÈxIÓ¥5QùþöÑUXØó©gÃ&­™¾‰¨|üâã=ƒ0u®¬¨ðJ¿×ùLK^ ™òÄ÷u2¹…Ǫñ‚­ìšETx 7¹È7ï\ð¯6C¦ÃßÐNò^hÒd›kvª~PïšËú5µÿ(É̃°£qŒäÕΨvTèÁe¡>È´ÙP÷è†m`š åBCTiÕ³&jÑ¢…XÃD¯¼òŠ{ÅF…®ºê*÷Hâé§ŸvÚ´i# lQ„½Ê040v„éa¡^î½{îqæßv›³~ܸª-Q l‘ú­ö‘íÅOíõ”…Vïè°ðªLHÙ6¹ÊÒˆ0,rÕ&åÔ|ÂÖ¤5“÷±Á«qö‚×sÑ`ɼòoÀÔýa,äuØQRx¥ßë|&È%/…Lyb«Ÿ,{ |Ÿ¢HeØ«ì†(L$;¼t;Û|óâ-ß(ðk3‚¬]ª{åäÌ:HÕñÍ(ß*žÓÙiìLG[’wt5M¸­×·÷áwÂ}„ú5EæHÏA>!ošy“-xt¶ù‘S ¦¡êåSB©däžO­ð»çÕŠúLŽ\#“‘«ÆÐÖHäZC€gDí8Qé¼g/¨9@Q¡ñp¦(¾² ÷ð}¾#Ò#ó-Ú(É^Ò”ž°È%/[¾‘í»ÀžÂ°aÃB—[ÙÍD(‚x!Ù80*üxgÃ7*¼ÚŒ¿þõ¯Vþ^çÎÿŠšÉgA/?à ú6¨<ÅàV2å{%çæá‡¢lXª? ÌûÛÞçqÝo¤Žç¡mUå!—@ò„Ù ~“&¥hyiš°ôªz `(£D…\pš‰î¥!ÀqÔŽ+Ȥ@ ¹j eç £h0¦®!Ðó%LZõ8™tœ™¾›èä YÑ©,0vàFÆ«ƒ‹"d„%s½‹žOˆ‚¤!̹䥫|G>ê‹Ã”Y¾¢/jÔË4àÕY*;›|óãïá¯zõÔSO‰¼wOú’Í*e 4qMз!=OÛ‹c7^Èç7ιznýÜ—³…I_C`[ŽJ€.Í”z7²a‰Öqå ™™æÌWx+྄ëâX†IÀ̵0ÓOºW#F˜}ΤãT£hr”‡ç«Šë…(}j2Ž|Þ)ÔJ~ÝDbÞS€ð*¸„0[ä’—Âò|*æ^?,IÜ½Èæ }˜­¬Àƒ¦éŽ6ª½³LãØ«³ÌÅ7ðã ßL ß=µÍ@:Âø€ÐÚ)Ñ.uDÎïa zçqøå©‚î©îo¡à¥ŒŠz/ø˜ ï¾vœýW†Û|€¼: ³Bä‹Ð!]6UUä;U8\{oFé5ß½©¥[¾HªHÅêÈÕˆQ‘ÙAz¯„[ê@:q¿êÌQ¨9r€‚÷œ9,éÒV§\—— ÑøP„Ù"—¼2ýÞ˜¿U†À Ì_AE«ºu£:æ5!àÅ|Èöípüî´iU¾A“Dnµ4àeÞ³å› lPX?êÞLvjaÁ¢üÖÍã·Õ ú^ðÊS?øÝ³;¾žŸ  Â|Ì\wT¹&!¨DÄÃ}†[yeJ°ko;o’_'­†ä×8{Á¦!P„i¤gî¾Û9VK‹JÏÜäWJ 2$gÚ$oŸH2üÐ0@V×È%—¼üò=ˆð]õú=§é'Lº@½ËŠÍaŒp2‡dÖE< —f [Gœ ¾Qa{¦<ì (½¸¶‡Ôè]9Eä÷¼ Øò4^÷½[®÷ŽªåðƒÙgfd©°¦– ÷Ýwߤե,[FÔ©ÑÒ¥DaŽÛ‚å ·RïÓVÐŒéDíÚÍž=›FeXÒ’hPP@Ï?ÿ<5ó°ø–+ %%3¹vL§÷©•Nùƒ°ø6l Í›Óÿ¹Ç€Íš›Ömü‚.R\eém-S JПÇ΢cÚ7–èÒó§‚VÐPÚFoK÷tæ™gºç%ôo±|y9õïߟ~øáâÂNeee¡ßoîÜMÔ½{3ª¨ØDݺ‡…ãÿN]ŠÏvÂc>SWñ‹»¡*{îËiêmetÕè~¸`òÿƒ> –-[ÒGážÍ åååÔ¯ßDÚµk œH“& ¨Ê§0e;,rÉKÁ¬WQ ¬še åøöÛo§ž†…¹ÊJ¢Ë.çüZЖ:ti,νùÏÏèÞ_Ì£Ñ%DG%NyÂn=覆üÌkO¡kÆžf[Ù› º´w#zä-èÔŸËçF…-ïóñ=‚M:üâÉ2ÜËð.aÑoÒ¤I)u}Þ³«hèI‡0°»ƒãÁÿM¦õ'lºQWW­ZE­Zµ¢ÿýïë=QÛ›l¶³kW´<©íŽ­M ƒ´>Sˆu¦´„0Ò>’1U‡•ày ÝŠT>i嬹N˜³×$D~¶ZDØZ‰´»7gDR;Å)p%wå…KŒöúHXRnõ–f‘<ÄA NTõ"`ò±<1"ÁLcàûbq4 âFlêbŒB±ÊXJêPÝ-qÃgîSªÕ1rÉ%/…Ý¡yÓGðQŸ¯OU(Ÿ%êš×”„:?³$š;v¶¼ÏÇ÷‚í™aµéŽ ‡Ãùü_i3ÿ¾Ž¥²ºˆÇf-ýÙ©h’åi´@H–J†SãNMC½FŒ3ƽHÿïÚtó¯è„ã¥ôÀ?ý5ÅÅœk…´Ç4øŽRþÛfzZò(x''pÆêÛZ[%Qç/­£ø¾Í œ{ÿ¤ÿG7óß½ü7ž¿á ß°’¿Çeœk©ˆsõ4º†Ž¢—i.U”.¤n]0N—;š‰Š­_l§å/¼Cƒþ40…w}Иi/ç‘w¿Ñ£y4ª¾^Fz×1µ¥‚ÄJštûÂÏý+×Ñ%½.àï¬ñ54•«…ò9oÆS‚ŸpW2•¾wc¥#ÌhQ•¯œþg¸|uÓ´^Ðj­*Xøm£{AùlÓ2äBCUNlš·°eÃ|ÿW_XI×ã¡€ýÛ£Ý*ævë[>ÿ5ÓÞL¨1õRN?mKÔ¸!Z‰Ö~Joýû:ñ(.mîE«?nHÃ&FP0´åj£ÊƨÑí§ñƒ—¤ÕU³ÜÙ0ûå—ity9ýÀ÷!þ°Þ½©§¶« ¹fO>:’ËËZnWwÒÎ ›öLaË7ßоgœQÇ5¦‹ušÒ§O•‰b„8¶ÅÃH#Îï{Ø2ÿ\àô?ïæ”9½«zôsúHÂ0ó8~¤ÏÉ] ¨ nš3à­M ªÈ`Þ-̼( çì’‹±þ‹¶Ä‰ vÀ3ꂱƒñíRº•´‡ïZ }mâ@„Eb¨±Ó†ó³"®·ãox?óû ± ìHw~´•p(G#( f>FÉç¨0yÛ֨똷ÄÜuà>ý{ç*ÍQ¾7bnuaØÝ ’*œF\>ñÞ¦‰Z3ÏÌwk¾$B?ØâW±M.HSi6Ó´SÉœÿ·/Qmm€îG臠ü0…o¦eH=öl‹å¤ÙLçÌÛ&Êy$¥5QÏFw‚ÇaÒlƒŸ&È„oUŸéj8‰uU/‡œAPš;¢R:‚ƒÔ•꯿þºï‡‹ ýC£1aâò›*=3Ἂ£é`ÚA.ÌIŽ`p¬k\TÜ jŸ¢QçõE: ¥jË5”¤®$tA×ý­BX Auùè·pÊ+ÿm%nTÊå÷6GÞaœjù!l™°ÅCZô©DsT(;6 Ô<§K!ì{DE¾™¦!—ê}UÖTZ¹¥›šõ,µ-9Ó²˜/˜}&ÖÆÅð$yHê!A¾öÚk”H$øJ{&]¢lɧ”4³]p•Àü&FûA€Ìý ¶U´„I—ÅÛÒ ±(ñú?:á3XÒ±wÇkA{TTHQ˜iSéxÜBTZFgòñîù¶ Êň!Ž+§ƒãRÚ~$¶"Ö.Èm§øæ“¸l`Y‹»¹,¬oð#zˆ„¥\_"|ˆé"¦K™FÑV>¿Œ¾¸olÕ·ò"ó[å‚òñ½Q?±X õá•WÞ Î‡Iæ h+`Ž×qärA„ØZ‡óQ€²S¾(K€*SÍšy—)½½ªnäãÙ{uîÊå$!ZE'r;¶Ikc‚È«¬!¡½ËUÅJh©„8–KÅÅ?ãpƒq¾Bˆu¹Öè„JÊ—ç“‹d²‰TTº ºÚI'Ga5òšó7çÑÔ\ÙÈ[Ÿtó×WÍÁx^ØQØ"Â| ˆ6ÏW÷‚jÊHž,«åCùÒÈ!›ü‹lŸö~sTf« ©ÚÖí˜ü½Ò%ëwz{ö=¢Bçëõl…LÓ ïïh‹åt˜ÏÎ4-~ðÒæ\rÉõü[j餱HœÏ¥V"˜}&'½î êåì„!¿Ž{ùK¿ÎÏâJZº ªsT Ij2TãBô‰xUPáPhý* ÞH¡p—•Áž¿Ì>À«‚xUܧߟkñÏæùê^¹xhwß«Ús™L/¿pÙ‹…R°ë¿;Ël6ùÙ>#ÌýÈkSèZöÜçÕ¡šé°íÐðk¯òÕ>©t„ñPšiT;“‰ëd$<ÚŽs/!¦–õ|Á1Î ‡Õ…ú!0ñ¼ìq«CÌ«b^ÆP`½¦CU‘vŸ ŠçUm YɢޒÌûs þÙ<_Ý ÚÝAjg„5.²2»lÞ7¨ŽçgûŒ ûSóq“?òÛÑ b› m«¤"¿Î×ÍÎTò‘HÜ—Cd’Ž(i°µ3™@¼Èv#ÌleõßÒ=!LjgkWwê‡@G ö¨«BŠýÁ—u»Ðõ>hW•Õ4àõdÚåï¨ðjÍ…N~¥ *]™¤) ‚øgó|u/hw 邬õ¥ïÁÏæ}sêx~¶Ïº?HèÞå…œêL냆 jûá›P$áa.Þj*Y>Ó®!À6Óš‚ú!¸/—-ðQÁ¡Ú÷žÜwtÚÇΤÐV'TeeR!¼Á²2ì²€žœÕ+B{!_•T!ˆ6ÏW÷‚j–†i±7¤Ù¼o.PÏÏöA÷åµ­ã¶‘_gŽëfgŠÛlé2Û+Uß¼âg ¯×³¢¦!ª†Ñ¯ïu—F$§8ÞuŸ 52_öî}§³fÀì3ã]>ÐW-/^¼XìWÅÞü¶´– C¸V­Äa +œt`qXäsUp>xÛv+ _š7oɿʩGbï4lØ/¬Â0û|7mÊO~`ŸºæIž¹åÉ÷óZ™n®¤Îg~ìn¨|ËöÝly¤“ ¼v ÓrêHÛÚu”›Ï=¨Y·ntɽ÷Ò[\¯`˜øm®O˜/Îã:îðóƒ¹ËBÕ·|}kÔU GèõìL±×^{¹»¹vÊ ´3°Û«V­íµ´ÏÿøÇÓü+?ííºuëÄïöíÛ»eã`>‚ù_ˆðšklN“ü¡—¹¼Cˆu¹Ö(@Ú•Ò¤ëŠ+ÏWe£´ô3†yz^ ŒšA0ûÌØRa UûY@ûÍ•ÇÑœG§ÑÿqKð_Ÿ>½é¬3ÏÎ&Ö}òIškMå@CçZÀñ=÷–Җ퇦¹\‚¤£‹äýÊÆæ¯£Þá"–VÿÑJÜ굟ÒyÜF{R%}Mm…~¤%u¢£èß3Я¹Ë™ìnwˆ< ‹d6$¿Ÿ¿ƒž¨–Ô ­/Z´ˆ.¹ä®æ'TYÜN{q•U?•æOùû­nŠ {ZAc®éOgŸÚ/ÅÁ‹t낈¯ÓlÞò‰pÛšâl¦à­@'(¹F®-f]…¥¸Ý~±t!ýŸæhÊÝyÏלGࣻ/Þ™Z¿”:å–ÏÍ››Y­l†qàdm_Mèžqó¨KÇÆâ;›–"Íc/÷ÆÊEo¦ß:ˆoC}ÃÆ¥ËökÒí·§X5UX.ÜtSŠ£(›{i[ÛÅœéò© ·£];ïE­Zä™6°º:¨äyjM£ù¨»8ÇëG2­åözVÅœ¬íTèßp#—¹OD^ÃâÇßhèE½iÍÓ§Ò…#ÚÓoFžøÍtØÊF.ÚDõù^«H,b,Rj½^×H·XgZ¯ÛÀ”fá%Ú°‚êp8òrá›Ý¦H¼#˜ù’)aç ¬ êóŸòx}(Þz:Ô®„Ø #Óœä+òCÔ)Šò-¢Äõ"±V@ƒ8¶Ä "3-Qeû­ƒø¢¾Y5U”­›ît¢ø™à´Àâ¦WÚl´ Ëg‡%ÔY¤OB+#ó'ÌôFI>©~¸?γ†  QÀÇÏóˆà 1"xkÎ:zªÇ4úÃ@–>÷ÚBÅcÇŠ\VÀŒû¸!CèH`.¾ä´ŽµÄëváMôÐ3èÚ뿦S;Ãñftøiöir½¶˜hê”4´¼µAâ_µnµ**ò9ü}á6:»¸ µá‘\Ã¥qãÄJš;çi1J:÷òÙ´¡à.‘$íƒwèÐ;ÔÈ{wk²qÇ 4¢YüÿΓéžÒäè.à?ëÞVŠ#nRÜÑìØcÎvéôfÚ5yíÝ™tí=ÿkÿ”Ht¦{ŠO£[ÇçoÔcIÍCƒ‚uRC©¿†Ã›®|²Ñ@ƒ4ïÙwè¡bó÷Š¢!ØžèD•ü½¼F“æ±—¯‰¤† ³oÄ·ó®]ôo÷\¶r YK-8?×ðWÙáž•X=ð^:ªËaâ·]C€”Ÿ@ÛDù—ZŽ¿=ø*uç¶ÈL› ¦‹ð|i¸K¥øír^Ú+\½«gõýãÓ´oËö´wãu´ákhûŽÖÔ}ÐY¾é·•XCUWÚÉ0"ÄÚðFhº–Ít$àGp)œÍ|‘™f—>ÖG»AsTê>¹s •¯\¹û’3mZª§GýY~ñï•Ê™B¾cr·ƒm¾3ßÖs5/‰ydäƒ>ºKˆí­O‰¼ƒô9T¹Ê®½ÊFu!l¹ˆ ¼K&ïf¦Ç,38öâm¿Wi‚çªM¾Ò7Fø¼1Ÿ¯Ã+ÍaÄ·±±f­ Œ_½>qbʶC)ãXÊã©‚žæd>&Ë0ŽMCha óå®5Ok’Zf+K‰#C¹Òzš£~¿00ûLNmtlÞ¼Ù¹üòË–(á÷_|á^MÇçŸî\{íµNëÖ­ÂÂB§yóæÎu×]ç|ùå—n ù¡Ri„ îÕ`äK иªŽ‘Sõ1õíEA[ˆLÂyXŽC%’÷µ¼°µÀ츢@O³•Þ0û‡uÂû© ¬ó5 º^hq+Ÿ¡T<÷ß¿p!K¨Å=<°¦Sÿ†ê}mdû¾ðw¿û…ô¡ˆ–+ ãN.k!oéiGþ«-ž ú9¿­[¸n+ÕäÒ”ËüRÈäÝléA9—õäEyi=ÿù\_ªsK§¿'ïåP/ÇS¡Ó†ó¼15i™ßKAO³×"E/ ~y©óŽ‚ ¾r0˜Ëc²Ãºêª«<Û8ï·ØQ¥í€ä—*Ôª<òJ›ÀWn‘–íx.Þýû÷‹ËUÛp S/œæ ›œÖnt`a‹±ƒé÷ ƒœçž{®ó“ŸüÄY´h‘ üîÑ£‡{5ï¼óŽsÁ8Ï=÷œóÁ8ÿüç?V­Z9^x¡C ûË_þâlܸ±Š¶nÝê^ F>fE1Q¸£Ju¹ØwÙŽ†Åý.T…Õ+.T¨ÆrAy¥ø ³Ï"£ ª,_àœD}œ7žx÷D¢‰3ÅǺ[Tz±tHh[:•°´Ö0¿¯Òð¸\B6|ë9?RóKGí7,áT£ƒpjq±{œ;!3W@>q2sž_™Â–ž°õÄk>XG™ƒV*›ŽßÌK˜ÈW^ñUB4,´BHZV5¨I–Ó\Q÷ôza*­“çc]ÈÒI–ëvâY°þˆ<‰*4é[Ü‹0¾mdû€Á‚x˜As°;‘µ@ðÞ{hàÉyíµ×Ü3޳xñbqnÅŠî™`ÀrÚž{îé|÷Ýwîä9Ï>›tŽ5E ¢Juˆg“„ÃÞÙjT§)/9jŽnÂSH5ŠÓ©—½ÑØÑ5pÏ«8ÙW£m’.ìxAo„JÅ BVåà‡©¿<K0 •C!+Š"€U,dBUOD™ÐÒn:;%ì¦j¤³“©e¨z–¼7U€SÑPl„š® ;•H?R„6„˜lõ.›ÅŽÐÖÈú—ùVÊ ÷Ê’¿ÔDÈíØö¶6¬† ŸÈZ (//wöÝw_÷( œ{ä‘GÜ£`Lž<Ù9ðÀÝ# $ìðÃw8à§sçÎbºà‡~p¯¦cûöíâE¡óÔ_._0 T®  ¶9o™èéÅ3ôÑ®ß3õR5^íù>Üë¥!P%4|Iü6hêRÁ'­‘à‘‡-~TúpÖ N;ê(Ô¸¶tBCÑ‹¦‹P¿Ooìqœl´“ïÛÎmœÚÐ{¡:8”S¯Ñž $ :‚”““ £Gê~8w×]w¹Gþøì³Ïœ¢¢"gذa’1±|ùrç¾ûîs7n,ÎyáŽ;î/cRm€lTaaa¦•%Œ6ÃË6;¶a4¯òóˆ&‚òÞ̈0ê–n”m=[ø ?úhG9«BF³ Ç êàðL}´Ö  ¦%Ô\-|g´àPoxÛ2%˜¤ïÜ“TÚBMM ÕÀ×d í\Xà›N¼’Ë3€àf{^2ž¦!àc/-™U«–Ã:ôþ¶ëfóZ éWmPÏš8ÑjU¯_ÐÞ™ën[ºs ¿ù,|¤Ujuò—†°ð¼:W–,Y",4ѲeKg̘1î‘7ðà“O>Y¬Cعs§{ÖX´è…º¦!rÉË ™<•©1W>4TØ‘œŸ– 4G2íA‡‰Êg6J~Ïo¢L²òbe6Ñ5™@UH3}jÙ­½n¨jPêu+ÿf­Tjl£ Ì“N½þÎÅ4#Mà“õ^&¬À<)®cu¶¾J[ï8e#"äjPõ†O’Ô4å#ÿrd 'U„56A<Û4>Q.GÐsJäH¾B¯©œ/àò„Ž!œ©™eFi^â2"¿·½sÌHø"´Áëº^ÇüxxÕE”6ëdýÔ„ >†à«×/¥¹´i!ò-Œêïìõþ^ç«è+‘OªÏä$I|úé§Nee¥/mÛ¶-«)ƒ-[¶8§œrŠóóŸÿ\ð ‚XÆ’ó'áFËæËå æÇÌåÇÍ%//D}*lZ%äΫàUç))Ù)aä«Ãë™àÎLW‡ƒšð¹0 E.v`D)5’*ÄuÕÁê±ÝA€óEï•ÌtÝ÷œ˜ÖX8ö9‘‘h_¼ûn‹Qà̘¼P¤µ¦"jÌ'ðýlsÒ~iDÙ šöQŽ®ˆ¦4ãÙÊ€ë¶zÄ?,‚´•a¾a°Ð5xÐH¸ïŒÇꚢ0ë‚´y™Bϯ<ò:_ÝðÂB-*ü÷¿ÿížqÄCœó[Tˆþô§?uÎ8ã çÛoÃIfãÇw5j$4a áõhø¯i•‹-ì2Ào³C7Myí9V¼qË\ŽU£ÔðfÕ¨BM«?ß$\×[„z£F ðR¿Ë„ó§Ð‘Üác›R’.pÕÇË"ÎÿïîÕËAˆZóõýõ²­¾³WÑ!+A¡ê M˜A60Ë›žMtêÑqži‰ ð Z¸ô Ãð s½ÂÊY/8eÃfŠP$€É®!о+«XCЬêþãŽ;Nì.{ì±)Û7lØà´iÓ¦Jh€fÓˆ‡m‡ú¶Âï¿ÿ^ÄÁ–ÄI“&‰-ŠˆƒE‡˜.(..×à& ¨ÀQ:4?^¹BÔg í~#hP Ý‹¾„éhTž€ì‚‚ „_Û ”@"]Z{kpñÐ(Û`6X^$TÂî;Š˜Zº¿;Ðiùõ-е Õ¹«¨y•À¥7‚IÚý«—ƒ€ìÀë ÜPß_/Ûê;Û¾©-¿MáW¦ p?¦òÙéÊò„0u$¨¾+à5q¡â O½ì˜<ÂÂö,ðþxŽÌL¥IDŸB Ë+Sèü½žåu¾º‘††.»ì2gï½÷„ߺa¢Õ«W‹‡¨Æ!Žm„¸ÀܹsN8ÁÙk¯½ÄbBØ6xðÁS¶%¡¦ªRm²ÁäeBñδb¶gñEÚ½v@àÓjYz‡•\(¥¾½Êi•¯SW0`a Wê§H8~‡±ˆæGfúöàNY¥O<¤!¿dƒ††Î–O`‡xý éóý2¤P„½Öéï#,ß¹ · ûáÏŽ]DE‡îŸÂwÄ„ *™òGþõƒxϲaÃëï{Æ=ñŸç&F³É¯æðÔÿ »¨!5âœÚAëèÌÖ=èO+Ÿá³»©ý—*éK÷X¥» Ñ™®8ïPš6g¾5ŸlÞÜÝ£Û_ÿñ<çÅî xˆ{ôÎ;…/‰’) è3ºˆs¡¤ê¼ÇsÊ)^ëÆN›F7+ã_ç0ͦá}&ÐÈ'‹k5••dõX(//§~ýúUÕU¤¨ `"Mš4@øó·ù·k_~6ש’’™Ü#N§÷©•Nùƒà™-ô4³ ÃeÑ©ªYùBGjCo7ø Åÿ‡é«¡iÓô|‘8šéiáCd½%ÒÓõeP7þt#”{,ã*؉ÿ/åªÒ‘;7uü" åcÕ¼ ˜žg ëŠÂä­°‰é<¦]\9«œôp[ÃGI=©ð⥟?˜Ï·às»ø® ú7às6¾ê¾ét)]ÎiÐùÊkÏQEÝéqï&D²€óžäñ^º•†Ðô'zÅš—òbO&8„)&%|™XÍoy'¿ï ‘t­¿r¾^Çït çëXÎWõܯ8Ýpó<Ó=…Óí•ÿ•|¾7ý¹À¥Üˆnâ§îÍox+§ôx~Êã,.õã´ìâ´pZ&qZT¢—­ô,§¢ˆ³–ãx•š‚Õ#Êé¨_ŸàUl;JÑàÉÿ¢Kûœ*Žü:¡þýûÓ?$xé ::Ë-ZPÃ]ÇR[z„Ï\ÊBê:ê’iÞÉô¦B&¸.Pæ”–Z]®›˜ýòË4ŠßüpR¶¯¸‚rO´Ñ-ë+Y 7¼G•ð«';GÑbzWœ „ŠY$8„>¥= v¤åE'›Àms„!úÝF??ñ1h©\݈.~3n¸˜ïsóÒ½%ÛÓ„w?çpaòU¦Ó0uð•­Kê\#vœ2çumó¼™RX^Pçá]ý ÷`ï9¢›Æ€ô}éž[—,|Õ}6#C¶½îŠ7œ~É»PÌ›³x ÑÑÎ)´@riE§Þx†×V-Å÷ŠÈ9 ¯|÷:oæÿ·ÿX(vl-Ÿ!W‘1=Û§sZuOÐ~ô­ÔP¸‰ý–UÝ£ÓJNC§¡í:élCçóÏÂ:éÒ8ߤ/ÆD1Æi„&tµ´ ¨™eùÌ¿Û]ÝBÛŠ{•Eî6;ý¾6ίè—Š2ëÅïy®Ûˆó0õ,P—/p?Õuó8[÷Éê~ðCzÌëù <Ó|l]Rçšb÷Çy„}Ô!µâ°aè§ŠßIÞþn|u„Qa4STTÄ¥ã>âbI¿âQÏÛó¿U«VQ«V­Ä±)íŠC8=Å$È'œ?ð9ä òÊqà$TºgM$Úóñ’*Þà÷ÁPË–-SÔ•Š¯ÙÔ¶: ¢î}¹œ‚)Ÿ^è뎶{÷(µþ£ÒUW]:ÿU÷Û՞Ρ[è;¦ÿÒGô9_['£Üß«ÝÀßõs•§û¢€æ-Þ—Î9å+:pÿ]U‡v\Û¹õ †ª>¥ã¹\>B ºœ†÷éB§wœÅàN—Ü6\â*i~YµlÞ\ø¿Ø¾£5ut–ˆñ‡ß§ŸŸü­ø­#Œ¦#ª6dÂÓÿþp÷î%QÖO¤É“¥ÿ/xi.½î:<~<ç õ  \Îi8—ïØ\e¸jîÛOÓã`˜\æÐv뜹V`Ä„SÉ”üëRN×si•°±^|ñEºuèP÷Hj+,ÐE]$ΙÀ”‰2ÊV[´fŸ µ Q:‰yÏ®æJø/ýœºtI]¬[=ÛÊÁûÜ@I—ÑK³®¤£Z䯲#Š|î\¨ÞPi7qš›YÓ\]zF¶,Ó–=Öb`^4EõÙàmúÛßÖðûê™fƒ 56ëú’Ž… ?§ëŠ “¯|…&M, wôËBøÁèHGÐÛ 6Ò˜1cèÖ[o­@víÂúŸžžå$L9ʤ¬¿‰Š‹›Qié&ºî:ÿE|ò{ßM œiÉðÚk¯e, ‚¬EmýšÚ]îVXV'|ÀägqŠ87WØBŽyùM Ì .J ®É´Á1Ó:Âl½>ý*„ÂÎv'b †!ªT¥âλ;£UTQÑŠºu³bÙ±ÇGËx?›GðÁ¦•ƒøêÓëqи ‘©¨ØÄ¼ý™hy,˜D¾›2© `äpÓM7ñ¯Lhð€å,,Ìç<>30¶å°Ãzˆ4‡É‹Ú†ÊËRüú8úYÎ:4¿MéX:“ú±`þ5¦¥týuýè†?ÿ9­£„ÓªQƒ~A3JKS®m¥N|Í{ýO˜úš‰@PZº ZEãÆµâ:ëßDùÞÏ +£&΢ë.x‰&+¢·’‹xƒ„.¹¶áþ…6ìq&Y¡Q9³sgþM´xþG4~ðºvì>tj×ÃÅ9/'N%³YÀ(¥Óäá=S´ J(Üê4¢¯©-íM+¨‰ÅSM„iº8v#2‘*ÃVܰ¼Ñ±UT|ÂVçPAÔ4Gʹ‘ ïÔ–6 iVîFáàxøðÖ©‹L ç‡šð¤(5sž®¤¡|í;¶2a;}—ð/ñ7ö¹sŸ[Sðæ??£{1F—u”{²†#Å; Ÿ[®êC‡؉ýi`jgÅ×tÏxIÛøI?pÜžà}bÚ^'tNã™®£)‡!Q¦˜°lŸ­ ‡¨›e:OMùÙêWØúªæ°Â§¬Sr'S"QÀuÕ¿°i„låo{Æ5%T:qxJšS+g>uߦ¥SþFæ‡ûü TDü0˜ËyÛyU0/[Þ+`ÿA_W;k,“9nm¨­[˜àá²n »É¹QDQ5êX®¹…£åk_wÒa:çÀü×N®D^Žx ªÂ…q*¤æ_áèã´ÞmyLTIO,habχÂ[|ì•Ù3ݶÆOWåÒN÷±\aWÓ´iRûöh’3‡½A*heb›ü:µQ‡¬GÂ6ôµ+YHm{ŸæÕ|$]L'!;ê :ƒG÷ãiƒè¼á¢»ŒIï à2 ûmLíÎC¿”t.!TÓsæˆß¬_O‡TD_om!Ö2|½å“´2ç¥![_góH¸¤d&§az(á3Ùñ&st”ºª€:«:ú‚‚Ìs ‡·ZÓ ¬çühÞ¼¹g‰w5j&çÏt®ƒ}DÄ»$ó"šÃ©0ëH–ÿç?ÔñÊ+ùWê÷]6muȲÉ7b÷ǵœ¢ºÅŠ`ntø§·Ib,ÐEt„~HºuMŽIjÕ²Zic¯•öòùvg@^itŸ ^¾fÜyOß4<%ù¤¥/¦¥Q­„6É–vIÒu,v‹åEmCeùk¾ÕFêHíœ{ ®°×k;yá ¨= ʵèYî*œ£˜ ™Ô7Ço\3W³cÅ<êB˜äŪ~Ä“N™ìN°¢ÔWEØ‘dîП $w¥’_ùDÚ8JZðŽҟDô4{‘ªƒ@2ÍáÛ—°È'ï|£ªÏäˆ5» ™jt7 Ð\6ü¨4÷¸JCð)óÖ]íŽ;–ì%‘ Zµ¼ |}ò±C%÷Ó_´É©† ̼ä\jOÝ…Š°5¥ÿÐ9ò´Ô¾ãÆ£,.M• S]ûbžór“ºË™Ã#ŸfÔá„d>ø­Þ^µöS*™òÿhÆ ebÔ…<OÇa*/ ÞªÑbw»?Ž ?mÐ èŠ\ +`TÑë’I“ÄWäØ2u5»—æ kX¶mkIÝ»ïÁ±ÒÕýaêë’%K¨¿°)€Éé îÌ„M­[öª((ׯxÁ¶è9©Õß¾„E>yçiÓìB,¨#0¥š]ÒGÕùéD\ëê#—kTµw×Ï®€‚t ’x¥¬9JÕcÔoÔuìµV.cÃ8 £!€]¹‡»‘8ç>(lû²mç°_{ÃÅ7dÂjªâØîÑ ÷'÷`·wX\Z¹]žGˆcuO]¢K¦ËP hÊðáwNœl5*6\í–•YïSMâ¼>mZ•6Ä]VU™Ee¡ÒY9k®³tú{·³^H×%šˆrýí‚eNIŸáüìN"‰D§´:“Z_ Ä;˜i’Ú Ua/¤@<ß«Ná<ø$d^øµ xø#ô‚ŠWÃaÚ/x=KæEæÎÆüOÞùDýÐÔ’E…¤KµZ=Š4 É]-”³-Àƒ„S×®U#0€¤.×ýŸ{ä ¹jù‘´ µjð¨¸@6» l£™z‹8Ó¦-¡WžÌã dq÷yØFö^£}X”Ã\/ö†oÛ^@/½ñ uí¼µjqï$îkÑ£§WYhšhæ/ý†Îê$yÕ%¬®¨¤£†ó0®–z¬ÅL39Úœ±×ö¶0AETBñ/¹ a8N=é¹Py›vAÔ" ú õ ÿ4êë¦Ã22_:—ƒº{nÙ¸~ÌcóÀ‚8‡þÀÏ}(í¹&¤öíÏT6Ø¡~c¥-/„×È8ðÔÆxÁïYQOFA>yç fŸ µaTTˆÓ¶¨ˆZkŸ×ÖF]PD­Ü€_|ÈÆŸ@€8Ó¦=@ãÆ á;½W*+ØÞ1è½mÏ÷ËKm]Cšw®k¨ív„1¢Q÷v$VÒ$ÃN@hœ·ø+ZüÎF;ít8¿ç!|¾Xº†:=eªb{¢Uò@`âmSiÀ]¿ç3þå'L^+áó ý¤ †œ!„ÞÛ®ñÖ|¦¢~3¼Í(ßF—^í?íTw=ß ~Ï “ŽL‘OÞùB¶é 0æ–€ë*ÆB.LcR€m§‘*W7"ìúâæJì0ª ¨– kÁ¶Ã\`îÂmÔ½¸ UpÁïÖ¥0­SR> P1þ¯Û œ”Ü3GXœøÐ-çÑÀ‹~í^•s¥}GÝÏ×[óué~5ŒÃž°€¸Êñа9/©îáºuÿ ¿KjÄ×áPHu´›77KIÓš™ZC€wƒU5~“]ðÑakÀ‚5ÛóƒÖcA|ë"êã;AÏÀ+lñ=®)DïÚ5‰¯÷Ìë(ß%ŸAaeú–â*‹Œ\õæy¯x@%·#í¸UÌ'ªã¹Bý°TÈ¿ë¶~@¯àA×g.ÿÂÈbÇíVWYHYÅÌ×Ôjj?!a7qûtZFÏqJæð³i2ª§£"}׆Jü4ŒéR5*^°5`¶s&Ìç‡A¾u õñƒ ç à•?z<Œ¤{¶–»ŸT!Z vQ!mgQ»­¤{f-§sÎoår±#Êw©n ×.ó¼Òìßx]ta· A#jLÃûßIÃ'ÝœªÍ³hԈߴóâ¥QhqÊ¡ÔxÿFîÙšœX*ܼy³sùå—;Ì@~ñÅîU;Î8ã ä~ ]|ñÅîU‰LøêÀ<ø~õÊ+r"§Žö!c¯2B› ÛŽ§B§]¢“ØËlÞ«÷sT§dàâX]{iâD÷[¥®1˜z[™Xçg·,?÷Qê· 8¿=Ìq0§W(ÿ=tëHqáþAƒø\òùEüC-ÖÜ~”tøÙm0¡ß§`;— ä‹oMF}|ç èyâ—?ú5Xãó³u¡_›9¬Ìåà ¿çš¨î5¶s€×yk°^íBµVÀë¼?¾uU}&‡¿ntœ{î¹ÎO~ògÑ¢E‚ð»GîU; ôíÛ×Ù¸qc}ùå—îU‰Løê0_®>"LAס:ÉÒRê…‹ˆä›d‡ žÒĨEÑ+“þÛð+¤ôúïN›–¶ ï¥vñô8aâ+ØâF¹? òÅ·&£>¾sô<1óuÑ\)r¹NOËœ¶tó¤+Dëƒ6nÝmCœf­”Ì|`>×~ž^ _=Ž-¾íàu^i°-Šô:¯Ä·.Àì3±Ê**++é…^ îhè”SN4yòd1§ûþûþó&7¦C9¤Š ÞWȆo}TÒX ‡Ð¨Á17Ž8ýÔâ˜g„j(.†A¢! ˆTÞXÀWP—-<~çóâÍš…S…+HžóSxëX·nµ%éÅ\Ñ’]»¨ý•WÒ\'á+~uâ8Rmwâ‰'ŠªQ=Ì%òÅ;èûŨ;ÈÕ·F=Åâß®]»Šö4€’’ÚÊá[ÔVÐjºlì´áàƒ©Y·n4Ûη4¨šÉ~Ÿn§ƒZøO¹(÷fzqœ¯úµ/hǰxØœÂó:¯Ï4×X± øã:Ü‘»GIàÜ#<⥂<Ð9à€œÿøÇÎM7ÝälٲŽš9_u]C€Ñ~®¶Ê@*NŽþ±uINã$é|MU{ÉYÅ ³½'І ¤|¤]»ÉV=­aÒ xñ{¿ÀÇ–Ùò­¨ëïìõ­ý ç‰²y;ú4`’*\™a>YÛ2ŒzRV¶Ä½œ×Hc˜:¥0£|«ˆ;³$9Íh¶¤Žþ„— †_ýýõß ¶s™äsDÍ‹Ú ³ÏŒ¼¨ð®»î¢©S§ÒÊ•+Ý3­[·¦ßÿþ÷4tèP÷L*0Ú?ꨣ„fàÝwßñ°ðêïÿ»¸ž ß;vRÀ¢B¸Æ¬‹» ¥fº­ÍåÔd'Mÿ¡5THÞÎDLg!á…sT‚mw—ÿ‹ÖÑ]|”ºB£ s{¥îÒXê¼w èi‚ÒÑœïO×6µn;ô3O¬à÷ý>Ú|¤u±T]Fmsn™ÖU½ž5Z³"ÐqÜb/:€õL¿²ÖUþ¿röàä“OæîïÇ|ô.SðNœgFUÊA×Ñrr‘°Ÿ+ï ºj¶;ª®fãɆä÷kÍGÒáSóªÚŠ´­úB,`ÜqÇ(½¾Ä…Æ=z´Ã´{Wܹ;cÆŒq‚ñÆožK]q/¾^i®ËîsM/1!Ï Í›×L†y6IÝ„ŒÍ•i{jé\qÅà´9=SCÅ ’žÖ0éöãíe˜ÈoQWÊöþ˜ê¡œ…× ¬Îçѱ¿Q"W¹×GÙ’ 1ô®S ÿñ­Ó†Þs––ËEÍ SC\ÃðK>öwå­Ò겪ú­`žSuÏòDÐPåEm…§†à³Ï>ä‡#<’üqºñÆéË/¿tÏJì·ß~ôÀˆÑ|à± 6¤Ç{Œ.¾øbzä‘G"ó5b+ÝñÇŸ‘D ?#Jž wèÃÝ¢!°Iâ; Þ¥µkí£sdFC ;Á3ƒÒVC°wÓM´jÝ:jUTDÿ 1Â÷5î½Ï!†º†XC½ž}²åkQn z€JKoíeELk™:rýz›Ëê.ß{Xê î(a jpì6<*^é;*öj ÕSö8XPáô-á³—2=Δ¹6Ï«ðk_Öq-â:ê—ï&líR½Ó„Å{g’ãüûßÿvÏ8Îk¯½&έX±Â=ŒwÞyGÜó ¶2rÁ×”vê É«è,‰«ß™ÎqÉÑ7æËßô ¦dnÛ âø¹2 ;Ò·=OŽjüM¶âœ>(ͼú§ðâúNÉyË(|Õ÷ChKs}í›Ö%dò­“åKî€@´Û3µd:œ©@•iêä ºèz¾î½õõ×Å ¨#¦ÙïBˇz¬´{‰Äe"ôª«€ÎÏÆÛv¼lí‹<ŸùÚyísgž‚(èÖ­}üñÇbž€E,HjûÛßÄñG}D?ÿùÏiÚ´itÒI'Ñÿû_š1cK¼ÝéÀ$îü馛n¢ÂÂB1wÅFÜÄ7UÒN¶T—¹¯¿ý6ýñÖ[éGî9 ÌD‡š÷†1Óz·¥²Áóiì}«hü¬³è\Ãx‰)™{ tèq°ú׿ÊÔ6Lj'HC àçnÔ‹7FSK—á™noiºø*H¤Ž¨ |ü<ìÎð´Ü¨€teâ!Lªíˆú­UžÀªæ Î7\jí»«Q*ez%¨M¦åtªÅHFêp‘ÞÈy•GЩoŸßÐÀ©½4ƒ'ÿ‹.ísª{lG”v ´ôs*.>ÀZWt~€ÉÛëy/<»Š®»`>MלÎ:M×<&ß)mœi ¶."'†‰>ÿüsç²Ë.söÞ{oAø­Z½z5rºj¤·nÝ:çg?û™Ó´iSgÏ=÷tŽ9槸¸XðÑÄ7UÒ^+&_RóÖÓ©—ÕüµZ' Ã”Ìm’º =Ž_|]‡“Œ¶MxÝïÇ×Kû€ùV[|6Þ^kÙò.†~ß®¾Bå Ê*æÚu ¢ã 'A9ެ·²\8s ©»ˆd<Œ Íõ9ê ÒfÈÑö”Pß%Ì7Tq”Í‚0qê¿l瀠z©S”õ:QâÖVB_)úÌl45õACøIÀa5ÊÜç‚òÒqÇŽíÔ§·SµN@‡)™GxIû:Ôh#ž¥K›¥Åñzž_:²ÕØxçBCC"LªoPy’êwÆÃ×á²Ð¤Þpà tß}÷ñ‹n¹†£®²²ùÔ¯_ÒQÆ„3ÎÛz)mƶm-¹.æÎ’ªÛ¥¥›¨¸¸™o\`òözžét̯}Œ²£'Ìî¡ÚŽœhj*ª4®´S—¡Kõaç(u˜Ò¶—ôÅĉ¯‡Š«C_]÷Šãu¿×y]û€0ì\?`ã­Îž÷QøÆ°åo}G²|=›Rna™ÚVÔEÛÈŸ»;¶FŒ\'vaC‡ÞÊB'l ”‹c” Ð´iºÀ€r‰‘1¤@‘@­Zµ¢‚³{i@Í›·tǨ‰ˆ‚zs´‹ãíG¶¥Ž´”*§/«v6UTPçDB,EºšVP aX„èóÒñ"ââžúÛhFW°+Ff05Rõ™6ÌKýúöå\Át®„ÃÂøÑ4ŽÖ¯ŒVÆÔ4_W×±ÐìÙÞBE>Qy˜©5 b%AA}ZT˜)l‹°èÆæÒX_˜£9áz˜…9zœ øêºW¯û½ÎëÐㄉ¯ ÇõÊ3µ@+ ßQ¶ŠÕuRæÃõò%ç;Ã.þ‹›c©Peî‰riâùiš uJp3Ç߆*ŸQÊr˜¸Ê0‘ͽº Ÿ·íàuÞ†(qëâE…õºêPÁk´k›ÛÓæ$ç"1Íàïn4€§™æ\|—,™Ï¿¢ó5G;a†«¶†L{ÒÑüÿiáXg½%´fºA!U§sþ]ÎõL•Ih”c!$8D9\#o Q>måÞ„*÷QÚ›ËÛR¯Þ}ùJ#FßqÔ‚9é¼7on–âdM!JšãºšŠ¬ÕdTI;x­˜BÑó#ÿêJãöùq)…Gw7Š‘KóhbÚ½ e>dšUf—êç­gºŽH;ôsë>Ý[šÍsQÜ0ÇHE¼† Áõ®Ÿ†À6òF\”Á§žzН%ëO˜òi–q2q;<§d©øéÅ79zæ-ÊŽ† 4#?þô§?qœ¸®šˆ5õA@Iî(ý–úÿŒÏpt%g›‰S)…W¿†à®_¥³‹»Ðô’ÕtþY_¦˜õӔϞMýFæ´îÁ|“.²XC°ûk$luë v9Çð¯§è}êC¥SþࡱK×è@ù,*êÉÝßî™h‚ƒÞ Öa ¡?ׂÔzôSs‚+¡\h 1Á–á亩¤ë踮Ö +íÔg@âÆÈùМ/SR5æÃÃhÔüù A÷s|µóÀÛd².µIð꺜ëOM³ß½pùªæOE—̹TnOIÒÔplϵCu3³^ù#¶¼¬¯@™1ëªZ•ЕAsó0ƒŒë 0åSñ Z+„ã(í€_:Ó5mX?!ë«ÎÛ¶†Û$©Âi’è˜õfŸÉÙ[w ©PªC³sTEE(+·w§†c}1ΠA÷òoø:Oç« ó×Û ®ƒÀSO³ß½QÔΘ>hIóÏ{=Ó¡Ãö\¯´x5T1¼á•—õf]U(BTþ *(Lù”kzGÚ™…t°‚¡K/«à:U–æiQ‡z¾_:ñÎæ $‘Àñ_«Ú³ ÒÛ¨L¦Ÿ”¾èÞ]¿aö™ñ¶Ã: ¨Â˜îÔMœ"ÔÕ“Pç™VúÆÊ¿ZR>ŒŒ€gXs£^[×t£JŠ~EôÀ¿†R®·2)5©©.#,ÂÖÕl¦|J‹¥éÛ—ìÚ%¶5 ݼKg êN«¨?µØú5nÍxgs[ïí·Oâ_‰öÀÖé–B£´VPãŽ]pk ±@CÀ«S³Ù-صëþïoAMíóUa>€µ ˹zokÇU“‡.5ëÖNžLoðu¬ˆM¢mÔˆU¯=õ1jdçšÞ‘žÈu ¬Þá¢ΕÅRsP¢û]ð²²xñbñ;¨x»AÑ ì΂Ærê&ŽX ˆá ›Mr)É{Û$ÇB,”fc>5SÁ Ìk¯½F að¥=ΈóÛSòsíÆgjG:€Gðè`õ0:â\u®^ƒ»_¢‹/¾Ø×h€v ±Haì™Ô±@Ã6uܨòql¦Þ=î“£«éMÁ"¨ò›8ñÄi2 °f9¶§£~u R©gtœzGªO#Vt_M×~J Éî {NpšÈmͶ…s}½¯VÇtL]A,Ä„Ÿ:ÏD¦S &‚æ ÃBO»Ÿ«Ø1ê 4c _×*çF³Ý+Ñ‘ŽtÉ’%¡ê°î}uÅi½©dÊíô s”¸VÁ„ƒjmC—âî"n}ñ¾šOÄAŒPðRç™ÈdŠÁ¯yÃL< ª4›öÔs1’Šcw¢ÁŽäHzÓܹ4¡o_:vWCjÃgÎ5ÊÉ€QlÚ÷¡moÊNU„|¼êÙyT6ìšqñL¿‘¹Ž—_†¢ú A%HÛ—²Ppú qîÈûn¤vÜñ¥b]k–Vˆ¸¹XËPß 1rЍS I SN:3±  4 –-s3ÿoޤ¢NGĈQ`snôµ¥÷ù,Â鮆MàòËRv ØhMï‘"*Âr>nsÁPp×…"ıÏij÷›ÿlš°PEBÏOyE„Íé8!¨@ÕÆ¡í‹NÞµ\uøY§ÐMS®¡wìLYÛPØ¥[N×2ÔgÄAŒœ#Ê ¶`êJ=zÈÎÙ&Xè3MaÎ#©ãwíâc¡Ù@EýĈ±»°å°äHZm³»Ô½†°Ob%=7v‘°æÙv×3m—€Ž,!îm<¶?õc›Ô„ýùxƒ¶Ó`uÉtqí¨á—§ )!„ñ ýQ„ëiªTlÛU\„JØ0§ÌE‚Õ½¶¡®#bäÚݨ>Åà·SêúûGõåÎWvÎ0‡ªÖ ˜‚…Yù£¦Y¦0ç´ÏZ5H[—-Ä­1bÔ n(WÞ?4”[îÖ4=˜ÞkÔˆ.¾çZå Ñÿ0yýrð©Ôåê¶Ô¸ ×0m—€¶ “ïóéýï7¥OÙññ……Uq¿<ëü*aD*t‚òÐ7ùî™–0}$Û6FÄ…3„~[͵ ™îDŠa0OTG[* eA ¡´Tèm¦Ðã뿽 âÀtª—…1fKa MD`Âo¤ƒGâº×³Â¤YAñP®b”Ú-±½;mšóúĉÎÔâb§#µqSÒÄ©WZ¼ÎÇðFœgþð²T¨—{Ï9}úLá0µ.À¼8îj9Sç KÒ%³·Ió°ßf‘V•æD¢…o}tÞê7¬¢½ÐÓ>~틉°i®/0ûLΚºƒX ½’¡`¹?¥s4Í”Â<(:H˜6U÷"ô‚Š#+«w£‚ß…Ïvùl¤Cc{®…I3èÛËœé% Ï_êô¢éNeùçª=øœ>@§w\Uc:ÄMso=tàQˆ‹0F8Äyæ%¼ÂK È$&›mþ¦"L=׉;s˜~aÖ‡.·`ØêžÕ‘Zòï¥VÛÿa¾¡oNŸªß^P¼Ñ>Mœ_c«ê'B¤Eñök_L„Is}B,ÄPCV6YQʼnB§¦R©8²²&+,ž¥Fÿ*6Q &é(#½á±=+ŠûUÝ}ò{ÔFü€_ƒ¦FÔNØboOEU•¢vî}¦Ëe aò#F*â<ó‡´2çE¿²œS-WЈY!¨NÙlÿ‡ù†6¾ø­·6HÞRc¡ Š ¤Ï3Æ=nô”ã/žåÇ;.w©0ûÌx A=GQ‘\Í¥;] 2Sª IY%¬“»b˜;x*À•iËmÛhëÂåô÷ñ i|Ÿ[¨9ÁÍò:œ~L¸¾žsÎ92²Ô„ 4 r·,Á}òö‡¡Ki:ýsH)av´ÿ‡-öwi]ÊzÐÌoÜV<%FŒê…Z,XQ’,ËjÑ *ó "L='©‚*iÏж;¼ê”ÚÒ—©í_¸Ú-ôéÚUÜÆÈ…¿ÿÇÇfýÄšŸ³‡u±§¢×Õí9݉T/!Ä‚:‚XCº¤ŒQDA€+S=¾î] £í—ÜP©‘ùp Üß§¸×+Üs¥ô‚¦S/!ñë¾þ\aÒ è÷«ßÉi’ãÅÈ¢-žk#ŒDž>\ÜOäqžùÃo Ôâ(÷Ъ%רs ¸Æý¨cÁ£q[òûNa¿¡\CLs÷ã3o›(™3±8ãtb2ë%¦PP7;%äzŸ0.æ¹¾Àì39k¢cóæÍÎå—_îì³Ï>‚ðû‹/þ{g^Euöñ7A$,*`ª€HÊN,«kXk©-Õ"Q `Y—((胀ì<*±U¤…°%A .ý(ˆ¬šùÎÿÌ™dîÜmæ’î\Þßó¼™™3çNæÜ¹gæsÞåŒÚëͱcÇä?õ%+V¬Pµp¡¼÷Ï;Wí +ö±v <$¥46×7òOì?N>Xñc™­œÌÝç¾{@.¯ÉÑÞ³J.±õÄ;<ž~Óz_®7 6^ó‹æÿk%Ø9óçÍëúͯ$åsß¾}‹o´XN›6MÞH휋¿rÆ?üÆŸBð›|óÍÏÅþÅõÐp/ f kŸ tì^C½Ž»Z.í;æ¬9,î1%¶ BŒg‚¼×˜üNÒÛ=çë33¤)ƒ^½zÑîÝ»)''G Ö322Ô^oêÔ©C§Nò &PåÊ•© f˜X´h‘G=q£V{˜p¢Ç÷ï –vøšÖ-˜äéËŸ•UìúS©¢F-R/ÊeƒÄš4ðázr‰ýs&N¤fôƒ>í ï'ÈÏäÓUzzì|Û±œŸs V—Æ·ß~ÛÿyôèÑÿœ‰Hð›LKÃ4[Éo} gÏž*wGè±;®¥Oæ!“…Ô¶•—¤fbÚE¯ÈDBB›î”ÓHZfvA¶E• Žc… //O*BC£6mÚHÁ7ÕC‡©Zž`^'>>ÞCÖ®]+³UU©¿×ªW¯îQ¯"ü^™ˆ¢â¡]âQn/gºU°?WÖ/™÷#©€¡eœìªøscéíßÌ0n#XìŽp€8 P¤ýÙ*èqB Ñû¹ý¼$£iøðW(&&I¬ÊÀ2X’–1áÁ±B€ÔÕªU£V­Z©¢Ö­[˲-[¶¨’ÀäææÊQ_?Ö!C†P5äEŸ7oYƒc˜¹|ù2;wÎC˜²ãiB C!i„$ä!F9–s)^¬çR%‹-óç’eùAŠ3ýg«›GøÁ ¢"š£#2L4P¶oÌz?ê xaa¾øëy7ò’@)¤Lôéó ­_¿I¬Õ.3çFƱBpúôiªU«–Ú*eØgühRSS©mÛ¶ªDgâĉ´råJúÛßþF>ú(5Š&OÆ0“o¦L™"C05Á„ŸK‰É4’Þ¥ß÷èO{ccå–½þøGšSÜõ±\àkº´`©n-ýÑGô(ÙE…BúÓE:Lµ(Õ?щΓÙÅðŽ°†.6GGdÆfO€âiC9 ’.cÐóQƒQcd>´“O„§ÊŽâ«4~üxŠ7ó@²cÇYëV4MóYnåâÅ‹´téRŸšÞرcåD³fͤ2ð—¿ü…¦M›¦öz“™™IgÏž-–'N¨=L8©pº–Roz~]67 ºc9rÙ2¯i}»+ÅU-ZÐ]ºÐ¸ìlн,  J\¤Ó4N,A9¡Ô…ÏeÈH©j ]Œà¨¡fRd˜•ó;>ý'ø´á/‡w¥lùz ?nbcbiÚ!´ü¹ç¼”‰ck?¡Kòˆvï’Ê;ç)[Š ÕÃ> 4jÔHÎëûŠýí·ßÚÒàV­ZE.\ >}ú¨ÿ`*ÓþbTW¨PªV­ê!Lø1§&­-Þú;ÁÒ—Ÿtšèüð‰6Ç$‡2XPP ÷bbšˆ’6ú"~C᛿7Î¾Õæó„4ÞXØ™‰f‚ Ï;¥JZGÑ<û»5Ⱥqã„ žJ§wÅ]@;üP/3gú´A:øp&µìJ_‹{”wkr#&¼+˜·OII (qqqò oãÿüç?Õ'‰¶mÛ&ˬS¾À°ÐC=D5kÖT%þÙµk—üŸ04d"¤EB•‹©â oÿƒßzK¦%5Ò“v;_¬wñJM Ã=Œþ ö¸Øê¦Òl•ù0<çt©8Ï=±úy^Á›aÜ€gžy†J5Ý·î PÒŒtĸà~ðU­Zô»¬,ñ`£uô[Ê A*¥QÊš)>_êŠínjú°›x4%Ò8ŸÉ˜ðá9±cÌýwîÜ™  Ý? XïÞ½;%'ë†c'Ož” „Yi’Ý´iõïß_•”ðÁHo…}ûöÑ‘#G¤Ø1chàÀr$€qxû7»ïòÀjÖ¬Qbí,¶„QVVÙÌåãz7ßâÏEØHûmªG_·N7èAèS¢ùèïFØb3ˆ`LÍ™_–-[¦îf~¢½{=_*™0ƒèDÑÂYKÔ%Æ?Öˆ]Á"xûƒ¥3¶â︈ž†ˆcæÄ%å…àúAŒhdÎ+Ð>=ŠR¤–¤_5B§Úù¼õ‡áï,"ãû3²"Êpâ(bD ýhB—ô)CÄãØovPkxn‹êªÏ—ôKÖÍe¾ÐëéA‰Òü†-6îæ(‹$Ã7–÷”á\|aœ£¿ýfœÔ½°>3C!`n\&Mš$º“> h?Àˆ7Æp"fw ù@H#!°86[ÃE0TkcÌ“þ®ëâó¨™8WýØE4}ÒÀ2™–`˜ë%4¡úÍê7¯‹âíHLŒÇ\¿YŒ9{9B°s'ýgóf¹¤úO㢠4µÿL8`€t×Eúê†ËdeHZfž‚x²ysúðµ×ä1î¦×è·þ(×­`tA‡Œ(‹:o ¹‰²²²ôM&ì°BÀ8ÂP Bu×3"Tb`EO b` kÂE0kc<ða’BgÅç=­™qscC&ð9e äç}úxüî ó¼åË—ûµ™1\sãÝ>l¨,_*ÇX(Žò¿4“ŠÄ‹¶¡ÌC²µ$JÖŽ¶ǵœÇê+ihÀ~Œs*yø×¢Ÿ#¦™²Æ^éŒCt×;þ¼\^£¢O}¤p5§_ujmlŒ@¤[Äç=m'ý*ø#M2\€ W?C¬–üx£¿ÂNˆk®q¼[×L¡T¡ cô’µÈX†2émÜnÜr)ÿ³€VMÌÇX´7mÚT­•WKÝî€)X!`àQ×’<ÅÀ08ŠëõéfºŠÁ4Ú-n,f&¸ÂUÐê¶ ãøÅ€kŽ©K9G ”&’ù©‚o`ˆaÉïĽÖêR\ï·hTöS´¯ÜyŒ|Ù÷kÓчp<”áø¿÷Ijª×yTjלêuM¥=ÔN·ÝÛn»].¯õÃ8ƒ溢ßLjP²2üƒÑ#ÃHIúI+Ÿj¹´+Áðé}jI{>Zì×k ´”†a˜h‡&¬ b¤³£Ø@I7ZÒ”`ƒ¤ÜwóäÒj¬4©ÿ8ª#~Âý&*µp¬ Ã07*¬0aènÝô<Xúz`ëÑΞ§‹”@0ø;¤Sú°aÒ( I-K•K³¡â¤O]0IN3¾Ð¾Â±:ÅÊ0L¸@·F!b(FòìŒè!iSö°BÀ„_‰M|1Ò çSLŒ|DÿL0#@X=?=ñ|§^5þÔ¡Ä1`¦ô8¿ã3ñ˜·?¢‡ŒLÙà <㈚XúŠò$¥»>óŒîl=žÀqq\ïÔ« ÃDUÒ: µÜþˆ"02e+LØ(‰ðee=O:uÒwø Z5}D jUÝÿغçBmªS'Õ¢Á0ŒyÁþgÆÕXó¹?EqU C¨‰ÁFô‘){X!`ÂÊ—_B!H¤ÌÌß—ª!‘†aì¨Oa=!!Aöcôç®][Ѻuöú\ÉqŸ¤¢¢†4zôhÑ‹PX!`ÂÞ(¦O@\aDôsú˜ŽÎÁ'äç‚a׃a{}*NûQõ5ÓÎ÷UÈÜH!®É~Œþ\‘ hâÄbk…t%ô‡µ¯"ñŒ3Ô:i°BÀ„ ;®[z·¤<êJ w{)7wXÆ®Ã0ö0úT ]’F};éPq_…ì°ôãšøiB‘®„þF ¸¯º V˜°Ì5ð+±N1„„§Æ›GκIb-0v=†±‡Ñ§Rœ4êkAÉÅ}bN£ÜHH¡ŠBŒ‘¿& ë{ã¾ê.X!`ÂF0×Àü¸8J²¸"%Ê EqæÁÀ0L0Œ>u9¶¼4êÛ{Kq_…èi”õÔäûÕc~F¿Ý¡‰eWº°s3vÃ}Õ]°BÀ„•@®¾F lþ$Í™ ±d%†¹6õ)¬ÐÔ©ð2ØJ11M(é·º|DéÞó2ðå¾êX!`Ê€Ú”–ÖÁë­Ûæ,;÷«ï´g2d˜Ò%PŸB}ðÁ‡ÅÚ½4v,FŒ~ A.’.„ _¾ÜWÝ+ÌuÅAxâ‰Ïå²e˲œa˜ÈýöÑ{dº^ s‘è°Ñ {a…€‰jS½zä’aw ‡ïÉFƒQ+Lñ=Š‘Ž'À0î 6ÃFƒÑ+LD› C¤DZ´¨£\Ú‚Æ0ÌõEŸ>`£Áh€&øŠ6¬+‰hˆåôI9ò ø6ŒBR²²²¨mÛ¶T©R%ª^½º* Œ¦i4~üxºóÎ;©bÅŠÔ¡CÚ¿¿Ú«sæÌÊÈÈ jÕªIÁúÿû_µ—‰^ò)Ù I+bÃ$†a˜2$$…àÊ•+Ô³gO¡É“'Ëã>|XíÕIJJ¢~ýúQff¦*)áòåËR Ξ=+svŸ8q‚ªV­ªJ_ìÞMB!#úâ ¢fͼ·­˜÷ƒ@uÍØ=îС'iö쟋Œ:ýCÈ}»öíÛGwÝuªzìØ ÐyÛù¼õ‡áï,Ë—ãþH4>Ñ#¨BÆ÷‡ý¨è{tò]«kì… ïˆÞWcbÊ‘¦m ú¹`çà«]ÀÎ9;6pR÷FàܹsT§Nù ÇË7†ó%/½ôƒ€²}ûvU[gÑ¢Eš8ˆÚòÏæÍ›åçÿýï«þýûk:u’ëYYYšxøËu3÷Üs6eʵå‰sfaaaaaañ/â%Z>S‹G¾ûî;)¨[·.ÅÅÅ©-û#G¥úõëÓÎ;©ys8–éüæ7¿‘^ °'X¸p!=ýôÓ^ÇÂþ3fÈQ+Ö|611‘ um' 14ºháö¹›hoàkèn¸}%àñÃ~ŒÜˈ“PBÅîAQQ‘¯½üò˪DÓă\~vÞ¼yrûÀRSÙ¶m›Ü[·n•eT%9{ö¬¬e´ímäö¹›hoàkèn¸}þ ɨoàp ĉ,°9þ¼ªA”’’Bk×®•ë111r$v(üðã?.ãÀÕ¤¦¦RçÎiÀ€$)XïÞ½;%''Ë: Ã0 ć‚_|Qý¿ôÒKR À:dÇŽªIWA¡¡¨-¢gŸ}V*O=õ¥¥¥Ià 6Ð-·Ü¢j-Y²Dº2ÂÒ¤IZ¼x±ÚË0 Ã0LØP#QÁ¥K—¤¡!–ÑJ´·‘Ûçn¢½}€¯¡»áöùçšÜ†a†‰Ê$0Ã0 Ã0‘ + Ã0 ðBÀ0 Ã0 + Ã0 Ã\§Ì™3‡êÕ«'#&¶lÙ’þñÄÒöÏêÕ«©aÆ2™–Fl„HÅIû)1¬réÒ%U#²Ø´iýú׿–Q±pžv¢|ñÅò{À÷q÷ÝwÓ¼yóÔžÈÄi7nÜèqí 9xð ª9L™2…î½÷^é*\«V-êÑ£‡­L¤nꃡ´ÑMýpîܹÒì È*ûñÇ«½¾qÓõsÚ>·ÝC­à÷Šó…K ì^CW)Ë—/— Gå]»vÑ}÷ÝG]ºt‘’| Š<òeddО={äòømÛ¶MÕˆ,œ¶àGêÔ)1‡—Ž$~øájÚ´)½þúëª$0È’ÙµkWù=àûxá…hذaòÇ©8m£:ækØ Aµ'r€röç?ÿY ûôÓOéÇ”ñBÐf¸­†ÒFà–~ˆ”âS§N•1c ;v”!ä÷ï߯jxâ¶ëç´}ÀM÷P3Û·o§ùóçK(Ž®¡t>t ¿øÅ/´Aƒ©-””íùçŸW[žˆFk;wV[:H¦ô裪­ÈÂiû솎ŽDðÓZªÚòͳÏ>+ÛoæOú“ÖºukµÙØiãçŸ.ë9sF•¸‡o¾ùFž»xˆªoÜÖ­Øi£›û!¸õÖ[µììlµå‰Û¯Ô>·^»ï¿ÿ^/ šPZµûï¿_>|¸Úã“kèš‚+W®Pnn®ÔÖÍ`é•}ÍÈZ_|~ë_OBi@¤H$t‚fŒ0Ïx“Žü]?hþW¯^U%Ñ"}þìg?£x€„’ J##ém·Ý&—¾pSô…67öC„ï½÷äè†Ö}áæëg§}À×£Xݺu£_ýêWªÄ?N®¡kdbľãŽ;T‰¶OŸ>­¶·];¤4>|¸ÌûãÄÎÁî5tBP£F *W®œ—VóÍ7ßxi?ñññŽê_OBiŸ䳆…t´Œø»~7ÝtÝ~ûíª$úÀM*’¯áСCå¦60Ì7õA3NÚh%ÒûáÍ7ßL÷ÜsL2‡·L< gΜ©özâÆëç¤}V"ýÚadß?<¯p„ÀvÖ¬Yr£ÌVœ\C×(¸Èø`ùkÛmÛ¶U[žàËZýÕ¿ž„Ò>+Ðú c:ðwýÐÑË—/¯J¢ÌaFâ5Äï oÍ˜Úøì³Ï¤{l0ÜÔA(m´â¶~ˆó½|ù²ÚòÄm×ÏÚg%Ò¯¦1%‚s4÷ÃÇ{L®ã¥ÒŠ£k(¾×ðÞ{ïiâA -X°@;pà€6bÄ­råÊÚñãÇåþŒŒ ‹üÍ›7kâ Ò¦NªåååɥТ´­[·ª‘…Óö?^ËÉÉÑŽ9¢‰‡ˆÖ¯_?Ù¾mÛ¶©‘,cqžüô¦OŸ.× ä~´ m48zô¨V©R%mäÈ‘òûÀ÷‚ïgÕªUªFäá´3fÌž‡ÖöíÛ'÷ãs«W¯V5"‡ÁƒK‹ì7j§N*– .¨î´ÑMý033SÛ´i“vìØ1mïÞ½Ú /¼ ‰·bM< ä~·_?§ísÛ=ÔV/ƒk¹†®RÀo¼¡%&&jâZkÑ¢…‡;¾˜¾}ûª-•+WjÉÉÉòA¶H¼ÑšqÒ>( ²nÍš5µôôtmË–-joäa¸ØYÅh–h£ܘ›7o.ÛX·n]mîܹjOdâ´/¿ü²V¿~}-..NºGµoß^[¿~½ÚYøj®[nÚ ÔF7õÃ'žx¢øþ‚soœÅKàöëç´}n»‡úm2+×r 9ý1Ã0 Ã0îó2`†a¦ôa…€a†anxˆþ3uÑõßt‰DIEND®B`‚pyclustering-0.10.1.2/docs/img/kd_tree_unbalanced_two_diamonds.png000077500000000000000000001660431375753423500252660ustar00rootroot00000000000000‰PNG  IHDR J“³šsBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æðëcIDATx^ì] |Åõ¿ rÉ)B€–+åôDE±J ¶UëQÔÊiÕÐ*VÑ ˆ‚R‰En«ˆH«¥­H ZA.¡rƒÈ)GH8²ÿ÷ÝÉoû›½~GÂ~óy™ßÎξ};;3;óæÍ¼Æ  @¤a€ €Ag!@€àˆ ³ @€pDÜ…ÿüç?ôË_þ’š4iB¡PˆæÍ›gœ±Ç¢E‹¨sçÎT½zuúÉO~B“&M2΄ñâ‹/RË–-E¤ýïÿkœ  @€”%âî,9r„Ú·oOýë_glܸ‘²³³éòË/§•+WÒ£>J999ôöÛo)ˆÞ|óMúÃþ@Çi¶gÏž´eË#E€ ¬ÐÕÐ,¼óÎ;týõ×1Ñxä‘Gèÿø1Dƒ ¢Õ«WÓ§Ÿ~*Ž/ºè"êÔ©Mœ8QYYY‚ïèÑ£˜ @Y Ì; W\quìØ‘Æoĸæ–[n¡ÂÂB‚8ôÖ[oÑ 7Ü`¤ †ÊMÌz>jNù¤HƒŸpMóæÍNU´£µÜUèLY½;uîLk/ëK{g‰°Qv6}®i|žûµÑJè›o¾Á¥ œwgáÊ+¯$x+½üòËâ?ÿüÃü+0N®,: Ê»vm£¦•ˆc„ V>p õ™(²>¿úê³ü+“æÍÓNm…å‚-[6ˆÝ:Í8yò¤¯•Ö)Œ”¶~ó%ÿ¬Ï@+ÒhÜÈÁ   è,(3èuýÞ‘Q'ÊYIjjªç•Ö)ŒgŸ}–.\4J$¨K^ëTk-úc’ÊË#,¶nÖä‡w€Š ³ L€{vöEüKÿÀßyg?êÓ§wФpAäpòäÉžV> ±Na<üðÃÔ½{w±‡´} @l@B]òZ§êtîFMi…;¯bÑóZ‚'—_‰_DãÆ+íøå b ¡Ž¤*àÎ0-ú‘®¸ÂÙ‘ÔŠb ±ì«ùœ¨´ªse)‡WÙ§ûx‘œzéE ›wñEÜ ¤¦~AûÛjî8œKùù»¨gO}8`å’Bê{ÙZš53¼ºRbá²eÔ}Ð J§öÔŽ^â˜Û™ÖQ3þ_ƒ)%#™zgžÉGÑ8Z¢M;Ò¨E“bJO«”Å?@€˜±kß>ê5x0•˜> ©\§Þã:ÕȦNýïë úýèæ”{Ëû4qùzÿÛ/Œ3  Û°…>¼ójßðLêõ쳂÷CQ#•ó¢e†ƒEET{Ô(ᄱV-Å7…ʈÀ‘Tª´N×›Ï9¥ÜÎ}ô§‘.P;ŠôzHÚäÉËÄñ¤IK#\£®™i0VÐV¦¦ŽÔVy> €*[Zcª‹¨Ÿ!&¢VL[™:jÜeñ2M@~dB›lçH*Ð,0â¥ÛÁëè]ž+K9¼Ê8ÝÇ‹Nš…ûî›Nyyw‰ã””Õ4eʱׂ“f˜>o Î}ŽÚ}Â&:‹ŠIŽKÜ4 «Ó#ZҬܔղȈ   Ò, N½ï YXùUÊ}º Ýývš6¯ýìÊy4üã|*¡¶|v-]HwP+úÝÔ£-úðÃ@³PhÍ‚2­ÓõæsNé·ópc[29mg‘>D´qƒkméRqÜš.Ѹ¡uIIѾÏÏš…Ž´\[±øˆÁ!ÐD,\¸P¸´†[s¼o„v.­%¼Ê Àé Ô!Y§øs® <Î8£†¬S3g†ëÖÒ¥KµP(ÄÇçŠ8¡a`žcÇŽõU_” ä7ÓN³8(@[ðQÞ4ÂXxŸÛ ?òHeéÎÁž Bß°¬¤D8”‚£)8œª¾ æQjÀ¾I`܈]a]0pi @|@=z4ÿjô‰òòfy2D4ïàÄüá£j"Àòè.]ºõõDÐYPfÈèÔ•†Ñtš“[@ÝOŽ£ri³8÷gn0‹qAJŠˆ‡£)8œ*jÑNœwƒì8~$ˆ˜::t(ÿ‚ÉpSþè{Ù4-rGx$¶[Ô×SAg!@™AKÏ ÕÔ‘ZfgQF׎ÂqTœâÜ*¤M™"âáh §p h´‚uÚ$6øÛ4Mµƒã°aÃè™gž‰iyt€Š‡ ³ Üµæ /¼ ~‡B)ôôÓO{RIë´H.Z·nm«P;²Zwp”Sï½÷ž8FL9œº: ÊÐX7V‚ÚSj BG ©#­ ô‚ú’ ƒ6¾ó!=×ïE:¿$M¬«hÏ£ŸIÌg×üùéœ<Á÷ @40úÇÊ$¯ZÌÌÖü_ݹhÔHß?E†NM…å75' aàCG±6Ó ý7£ZN/Q;a ’F‘ætNäÅx2@€ÓÐxÕ 4j„NÄ …‚)‡ÊŠ ³ \à¦æ„a# aè(6q0hož>m=ai6Š4§s"¿Æ“œ®ð§èKãÇÛw.°B"°3:ut” ÜÔœ0l„# ÅnOÕëÚUœßÀéWrh6Š4§s"7ãÉDbÙ²ež>ògžiß¹À ‰ÀÎèÔE°ƒ#SÙÐPcà‰ï‰•Vu®,åð*àtŸxå˜?eg7Šò aÇWÆ#}zzAé2,?ð#s€§3|åæ^Ï¿"wXµBÖ©×§Ò˜¾‘;¯þsÉQº6§+µe©))BûØ1T<|˜jwëf»ƒcÐY`øùx$*­ê\YÊáU6Àé>v{üÈaÇ×Ïýìðá;iØûé…¼½Ôµk=#6@€ÊLlÙ²El¿îö¡FÚ«²6BòCo÷‘_²d/=SüÝ:¾§«æÄ°Âätz*&2aÃí ³à§§‰JëçéB¼i½ÊØ¥ƒ*±ÿ‰¤iŸS(Ô…¦N½×ÑÊ«v|ýÞOðx±ßs°†0b`¿úŽô+ Ñš…›wS¯¥j\çR計óªY˜7o9Rø©€ŠÇ{Œ®¿šŽ‰F Y: ¾ïe>¨Òaþs%%íùˆ/঎¡°}«Ý´€Ê9ÔŠ‚têÜ;‹–Ï, NYGÅhs›‡µ´ŽùbDSêÏ—_¦.wÝÅF\ÅÄ÷ãøMÜà4å§ðhˆÖnªNíZQFººHocÞͯ»Žê”œK=èŽÎ×fÿðÃT+GÑñíÜ]ÎjpŒªW­”Õ"ÀiнÜæŒ+Ü JÀ`M–}¶ì9H×ÿ+R;ªNkŇÞêôiXàrºµ¦ÜIøŠÞ¢/i-èó<]Óæ°HLçdàßÿN'ùs#»ý†þpEÇz&y›×LÉû×Ψ£¬«AŽ#©À‘”2­ÓõæsvéÂn§#]Nñ“Tn§—×#tФ¼Ÿ~`ËÇL1ášÀµu@y£iLp/zƒÇæóÖ:åTá¢õ5pU]1)pQh|ßË|P¥‹E³°êß{hÌÏ?¤Q¹D-[êq…Å©´vG-j×ä e¤¤½ûöQNN§t:È#šZ<¢ ñˆ“_Š+Ò™°äq-2ŠhÓóÏSÓzõhźt{n[zéÅ"ºô"u‘–š…´’j̬61côžáz7p] ²BåvZŒÒÜNËúðÜÏ)Tm3µjÔHÔ53¶íÝKÍÿðJÓÒD*¡]tŒ~BïîA-ë«WmÜ‘FÃ'6¡Q÷î –MŠØh8i 4TòðÊ;@4ÍB YP¦uºÞ|Î)\˦¤t纹šUi$a´QŠÓ¨c„pqm¸¶e2räˆfNîãnj˜]ï"4Ëìô¬œêp*û*x­~ùæç/ø"tƒo;Ù¼Ê ò›i§YHÈ> /¾ø"[RõêÕyÚ™þûßÿg¢Oc!îZ óÔwß}wÔù‹/¾Ø8 ¢Æ…0RT›°Xa·ÑÒô#¨yJ uç4qŒM–>ŸœV®\I—_~9õìÙS,ÏQaîܹ´sçÎRúꫯÄÎ}7ß|³‘BÇ/~ñ‹ˆtùø0¨pÖ̱®—†AãÄ‘#…‡R_£F‰spB¾ XAc¢-¢=Ô€r¦N؈©¨¥n1©¥!•30M¸Ç p:ÂOÙ·óÏb&ød™Ø¿?uà=ê/B;_-á´‡ßêÚ n¯ƒúZQwgaܸq¢·×¯_?ÊÊʢ矞š5kF'N4RDâÌ3ϤÆ—Ò?ÿùOÊÈȈê,¤¥¥E¤ÃuNm¨ü=À§ÃçÜÀpsRJ*_×çæÆ ë(‹šÓYü+ûö튠ãX¶Y¶óÏb&¯õ72-Ö9u¦vTäèöÚ d˜ÃÉG\…cÇŽÑòåËéÚk¯5btàø“O>1Žœ5Ôoû[ªQ£†£ãã?¦† R›6m¨?÷FøáãL€òF¬jBN1ÀvR’Õ׃Ls;éS ©jĈehð`]µ‰ÐMµ ÀéÔ…XݹÛMšÉKýN‹ÑËi-Uðãx?Sƒ¸VCìØ±ƒÎ>ûlZ²d ]zé¥F,ÑSO=E¯¼ò ­[·ÎˆQcéÒ¥tÑEÑgŸ}F^x¡«OmœqÆ¢poܸ‘FŒA'Nœàò¶\hT(..$ÕÐp«!üßË|0§CÅ„kiÌMÂÔðáS(7·oÌrà‰?Fh<à#Â<7‰ŽIwnìˆncÃtÓG" ßUvPí À© ¹gIÄ ®³^·Y.( º£7×ÏÅí¨cW{?*nõ× ½ý˜Äõu·Д)ƒ|Ù!`€àTßý´‹"!W&e5ÄöíÛ…õä'Ÿ|bÄè9r¤Ö¶m[ãÈüÑÑÎ;ï<ãÈÜ)ѪV­ª½ýöÛFL4žxâ !‹•‚Õê´NכϭX|DëHËÅJ†ïóóµÎ¡c]µNC)æ‹tnpºçÖ­[Å ­@wLøÚ ™êïvìØ±1í÷`§Õtº’¨.pª¿VøY a…[}wjc8Ãm5D\šLCÀÞà­·Þ¢n¸Áˆ…*x0­ZµŠGõ‹Œ˜hÒYgEO>ù¤Hï¸4†]Ä#`ç½hš{ø½—ùŒ›Äœ¥  ªÌºÃY?2[ÁzâO;,H`”$vv¼ûî@³ €e¥Yð‹XÚh6lØ 4ÎXh¤j€ /¼P»÷Þ{#YYYÚСC#5þö·¿iiiiÚž={Œ{ Ò¾òÊ+FŒ;d/)Ð,¨Ó:]o>WVš7`Dû Â~ )ÆH#êìºÎÛñÈ @E„ß=ÌHV}ðË2ëšE®çÞu×]¢žƒ4 !n“Üö_à7ÍBÜ«!|ðAâE/½ô÷D èü£X69hÐ qþÎ;ï¤aƉßf`î AêYv;|ø0 2„>ýôSÑ[„¡ã/ùKª_¿~„ö"@Ù@K‡¯¹Nt4«“XªxïÔ©ôEjªp)ƒ0û±)ü»§H—L@³´ŽÔ†T}yñÞØÑÔ”Þ¦¹¯½¬ÅÀêÚQØ÷ ôS7¼,Œ…B«àžŠùæ¿M4k–#ízá±ÜÒ¼´úë3è2MßÏ¡Ó-Z5Êï÷mö¯T7ÝF³(eÿq>@atâ„ ´æÍ›kÕªUÓ:uêÄ£ùEÆMëÖ­›è š±nÝ:уY°`Faa¡víµ×j 4v ™™™âzî€)¼!Ð,„¡Jët½yNQ•Î//jê³ ßHéZ–¯‡pb9;2Ïlª¯ÝF3µzÔ>¨¯>áÖYI1 ój“¨´ªse)‡*Nµ,)%%•—ÙÞÇ‹Q 4´’n§›Óítfè4ÿý·l ­Ì.§÷ü^8€Š0j2ÜSºs¨ó©½ÄG·Sjh½£ƒ+ÂÎp~æÁ’þ„¥Š:0gçäÒ\ä(+89Z’.¤­°–OUyÝÆ|›?÷\T}x¯OjtÆ"M¬Øuø0õzõÕH™™œxOúª€î_¼¨Ô½õän˜| ðñÇLPèí·HL[™~ÅiWѦ޽©iœ2Ÿ.8xìÕž>=p$åtx‘ݨ´ªsNé­ˆ7­*N½,ÉP÷ÙÜÇÏrC©:Ù©%™ÕŒÒ n¤\º»ÛD¸\WP˜*b}P¹·~“IÕ.-,ý-]ØäN‹ê@³àù^ÉÖ,œÐªÓºž¶ÓkÔŠ:Óâü‘¶š…éÔ¹w-ŸY@ ÏÜdh°!—áž:¥Ø¢YP»ö«›]ÁƒŠcÒ,.r”bÑ,˜Ë禟дy«ø 1’Bôõ»¾]ÅBX³YÊK³°}wUš0§ÝwÓn:»Áq#–ë-ój>s&•p»"Û¢£Lç2}ÇyQh| Ð,šeZ»ëõ9аÛéÄÚ,„8­trœS´òEZ»%`Nç¼BÅ#¾^ó#@€DÀo•å3?_nt•ãzi$KÙ÷ŠXeVÕ)3/<ÞÆ$^æÓò›i§YàWP9tÂP¥uºÞ¼*À)àv^Sãd…Š/ÒÚíçtÎ+T<üòõš$ ~ʨ,Ÿ“&¹ï|ê·ìûA,2ÛÕ)3/?|D­³÷> *äÔ€—]Þ¼»¯Y}Ý;yœÛµ N¢¡ìÐfçªÖéœW¨x$‚o€ÉD,e43³µðíbwÞ#œ:%³ì'’·™W"ùˆDÐYÀþ{ø"°©’[ã$ »®»s¥ÝEˆã¨a­k^ШQSš2eаIÂTð‘ `‡ ³ áÀdž’ÝMnqÑyiœÐàÁ«ešiǶI|¼kþ|Ý*ÓDÛ8n!ó@h=—HÚð·4yøÛ"T7v»ÃîtØý.@€dCU×¼»9ÂO€0Øù4€‚Õ ´óeµ ABu®,åð*àtëjˆOV¬¥Ûú?K5„·zX&S„óšùKŽRvNWÊÏ[B=»¦‹óf,\¶ŒºTºrÚh0ab=Þ)LÉhêpŸþ,†u¢©´ÒÓ}6æÎ¤–Ù7ªÉC,Ž¢¬Î¡ü´#å…SAÆÊ7GRAgá§0&*­ê\YÊ1þ.ÊÎnDùù»¨gÏȆŜ ’]: `VØ+¥—+ÆÝùÿr>ßIl  (R1Q‡©")¡?žêy&§Ò’µDŒçðè],ó±\Ò víÛG½æÆ¸ ½ÆÝŸ{èXÊ—bÉfS›Æxc~µÁ­q€ÒK¬Ÿv$^@kÛ%LIú™î(KOg… ³•ªÊþý'’¦}N¡Pš:õÞ¤L?xð³”—÷†m:@jž¿‹~þÇÈ]±›V<§›F;æ3ÒÕEoú¼y4qäHú\Q4Ý:ÉD'jËw\'æ‡aD¥Bàæ:@Y!ÍÂSskRZmTTtŽ xiGâÚL/ÂȶK˜’4·%N ?m]€Øt‚ÎBDÚ† £7^2ûƒ§Ë¿þÄÞJÕš¼'MZHƒuç˜È­WU ƒ|øÎvãBz!¯uínøäfMYÜe¨.î£ÃŸ~¯7Æ&ÍBêWQy`†Ÿ÷ @¼ÀGxàÀbe †aäT×Й½þ²§i+#P®1¸Dl~Ö)KŸ6L4Ü:5 5*Ü‘>œú^½‘2zê$@ràÖYàQcåÖŠâñ‚}"Óª·tŽ\_ýÁÜõZ+‘F‘nòd‘AØîN\æó5\Ñ#ÒãxéÒ¥W0Ël†Ü"'çe_»Ä ð5oRÏ2$~öøh|>ÖËkéÔ^ÔÛ¶tƒ(¯ ¸¾ŠeLß3qßše S&Ä[ÓL_l­at*Í‚Œ„Õ®—íGËÐ,t¤–É ˆ`XmAº6nð`ý†LpYÛ‰ÏK÷°éÔAð1ïþ茄T~øU2#Us‚—Ñ”ú³ûséO^à±”O¯/¢ó™RJ5 ¨¿]ø>ßçç—Öm¿„¶@º‘F¨rg8ÜGh8”ip_« jÚ¤ÁE6d…ËìDçG²òúT„›f!°Y`Ä:ÿOZÕ¹DËÞ²}—_Vµ]å°êß{hàχÑòÐKtR+«žþíoéacT/V ääˆJ!un§Û2ïö´’>ü:]=ö·´<7Ÿ:µÜ/ÒKì=X…>þ²>uëUƒþþY>õ9Ž?«m(ZOS{PÌSnã¹ÊåôÐûþúW>æ¦ÄxØD,|ôQºòœsø·;«ÂE^µŠé¶|ÿ=e6nLµjÔ£üÏÑM¯¦9÷þ›²»ì¢ô´è*£ts WÙN}0#ÇP€·èf·Ó èW´… -[A)Ô™¦\Y‹úÆhëÇ1?}Ãr´âgiP½&íÙ_…ê×=A37¬¡‹tÔ!Nדjq[RH‡éMàçr•M2â³]ØUXH½òó£åvà}ìdˆL¥:µNR51Z¹pðøqªý÷¿6 N@ç9Ð ‰J«:ç”Þ /i윮ÿ.w¦8©r k%³+iÕ±™ä¹Éô 1o¡%à¸{\œ³»F¦I9=“¤ÀÍu@™¬å3ß(Óešò$U[Ô©²¥ÀEu YPj~ø¡©íõÐ,Œùù‡4*—¨eK#Ò³f¡„Ò©ˆûýÕi-µ¥£ôì³/Òî£Í©]“ƒ”‘vR¿ÀÀ¼ëГÓ΢[z½KÃÞÿ?މÖ´jÔÈÖ]ôFªB˨*ÿÒÝÑ>ßã |Ùeü;¡ma3Ï<3bD†øl¹™ <ì2Þ2D¤ ìà »Ó&>ŒšÑê~CšþΙôzîw”Õ²—F@éæ®²ÍBˆU³àÅ-ºÕít íâZÕ’®åzôç;o¦:5j)ý!—Ó€ÕíôеhÎÂ×ùLc¦û˜&ÐaúÞÐ,X\e—“fá‡ýUhö¿ëÒ-W阮uO±•f!°YÐTö N×{ámžïÁ5¬Ûœßû¹:c7-Á4&ƒ/B#~µ×Î¥|íejf«Q@Úagpœé,¬¹ÉáŸa±´¼^ʤϙJ;Œö" Fýˆø£Ó0mÄ-%TƒïÓQ„874hk~¾X¦‰PAÝࢎtë„H±Ûô tˆÐA™5½PD{É4¾^ò#@ü–!”I¯ez¢VL[™b3V!V™óó­†Ë7‰pÆŒ¯Œ”aÞX†­2ˆŽ~äöšÏ§*Ü: ШdÀC³s™O?Õ—þ%rÃ"Kµn¾ùfA^–mLË •Ô‰ö·ìD}Ÿ|’6oYK Ž!ŽÅ|ˆAM{ö¤+ a#¦[Ÿy†þCÇévÊ£;¨-ì×hæÌÚðè£jE!71uaÂdèWLá¡íÊË+å1ùv¡,N·œÖSýùžáTM¹K ?ËØPAU†±Äü¦NJ))ØL½©XÞœ(O“*™½`Ë«ëzL3=Þ <¿ýö[ºøâ‹cr˜å„Xå>-at**»faÅb}”¾|ú mùÌ5Ú‘Å+Ä…ª¥HCX²”/®‘pº—9ü`¦n7)B?€z£Kp±ÙiÎg’y¡/Õ i凙TÆ_^¦!Hdùe–C«ºÜZ_1JvûYÞ¬‚/2KÍBÔ&Qy‹õDLª6-Þåžh/Íí¦’ЙÛÑÊ7ÍB`àÈH´a¡„SZÕ9?¼¥'?¾¤óÀ¯lnÀˆÇÍIÌÄç6ÒÔ!ûéOï¥ßþ¶žë lntuöoèGjG—Ó×ô3Ψ¡{£L§NŸBki rf…±Ù7LÚÉtÕmÐ9DÂì¿bó&Ml5ûÈ‹Íé™ßo|>(S ü»ù0o‡¼bíëŽ>€Xê·„›¯0˰råtšØÿ9ú\+ð՞ŃxîcnG+ܶ{: ?•'QiUçü𖋆ç¦ÓM#²J÷vW5.)¡>~“n¥{«û•Í ^¤y±ßs\9¹eó³'Ë ê@³h5Íæ¸'O¦.]¢?ôÀ´3hl^Uå<¨ ñ8Eª U~ØAæÅû¹+({ÿ ‚â“!ãéòqäzˆÕ<úŠ¡Ô”â(/©Ò¿Š_^:.^aõ÷ðá;iØûiì³û©nã&Žæy_‰Xò ²û¨: •|é$¦Ú{s6_ƒ³Ù¹Ì£N¦ÜܾŽ÷2kvo>Ó³çD/Y¦©¦µ¢ôm¢?Óñ”o]+»Ø IðîÀG,0°Ä2B´~ëÇyF<Ï7ß|#¶±þðÃ#òãþûÇÒøñ´u»m†Ì§ŸÕµ"/äí¥®]½iEˆ^ê—t‹Ž-ÚáʬK’ù¿ÙGjyznµÂ««lk›ææ0Ë ~ÚZ‰X®9•àÖYÀ¨«RBοTV›™VÚX¯Á|¢´òUñ5ÇYçD_ì7B?™$Â*Ü ò9ÁnS©>}†)¼CæÇ˜1c|mɬçS°s€òÊV- ì#´–?i¿$œD‰zl²Ùác¬(Ù ¯óõ¸î£I“J¯O¤í€uþÑ! ²‹0·iñ"» «Œ• ò›‰P~ôø1a­E‹ZZZšÖ©S'í?ÿùq&ûÛß„@V:zô¨‘B‡ž*œî3dc‚ *2¡±Àu0$²6—RH»òt/oFz;òÒ€„Ó„÷/@£çVéqÞÚøñ¸JEÅ?79p/ì¥ïçš ”7»%ªÊ&B½ãïÝKªt>á„äƒÐ©ãâf™­Çv÷NÀ/–οUæÊ†¤wÞxã ­jÕªÚÔ©Sµ5kÖhƒÖjÔ¨¡mÞ¼ÙH tjÕª¥íܹ3‚ÌðËS…Ó¥³—çÞC$2‘—-ŒÅu€ÊæÖ€èToÄz­ H'?ýzÝYU,°ÓT8i8&MòM€e k»ñÁÜïD§|qÞ=Ò'¹ .›<9b@à—0¹f–Hœ/ñ®|0Ó¦¼Êíöš×g•öEE§ûjήøpá…jƒ 2Žt´k×N:t¨q tj×®m©á—§ •½³ «Ñ°ã™{Y¥YªÈïæ~U9åRK4:^á4ò‘xòÉ!+B?*C¢[lŸ÷u[Î…s~5 3f¬àt‰×,àú7ß|SP¼¼T|àÇ»Üв~ÈN´jpPÑÉËà%^Â2i}C*Eç_?ðD¢V ‘ÔÎBqq±h8çÎkÄèÈÉÉÑ®¸â ã(è,àšÌÌLíì³ÏÖzõꥭX±Â8O*sgJéjÖËGÌ/øáZä—þ1m.Ò'r~^—ùvÁ¡¾áÎÂmFù¬àåUm©§õ¦¦Å9]]Þ†¡—­­ óÅèFŸ‚‹—_€Š ¼[¯åÓ/ô²9`P üFñ˜aä"¤Ý¿Ìí²L‹4p)tK'M²Õ Í¥ÔVhâØiðâU³>òZ)‹<ÍþÎeBv½ïE³^Ér•]QàÖYˆk5ÄŽ;ˆ?ø´dɺôÒKX¢§žzŠ^yåZ·nÆÿþ÷?a¥~þùç ëËñãÇS~~>­^½ZXâÇÂàN† ðnÖ¬Y¥[ +Ý9\+a·®fËç… ÅŽdfÈe–N«°ò`é_Ðÿ Jǘ§t;]3eµãªóžr©“a·Ó¿¡v4”c¥ÔÐz{L):‹Z4)Vº}–=w;=:÷Oüëv¦×˜Œg}ôQÊjÜØ“Ûi3æ}ZB7LèCónO¿Î:dÄFÂìÒîq‹é1J£‘Ôeh̹ƒ­O‡dgS‹Ó™â“)´ç`Õ¯ULi©Öý$‰=JSߟ>7Ž%Ào<ó«çâ·vf-J«žjĨèðâh©øD¨Ô]sZŠ‹NÒ[ººBÞVXH͹íL£ö¢ŒJÎOµÿ]»ú%Z~Á êT m„Žý…Çhû>¢³¹ZÔͨfÄFcWQ]Äíïf〧Ϻv¥FÕ«Ó±’:p¸*mÝû-}úøcGÈT“NR!ÿ*a)4ŽãKWvî@çš¼ÑÙÉüžÁ˜Î߀b÷UäÕdn´ú6i"ÎÙ2÷b™£òÙà»pß>ê¾+?Ð^ÂQU?&½Þý¥Å9toË&TUôç"q¼„Û·}ǨÃêÿ0ïp[›ÊíÏ&æÝÔ¹2àà‰T{Ѣ䬆ؾ};rWûä“OŒ#GŽÔÚ¶mk9ãäÉ“Zûöíµx@ÇÊó‰'ž×Y©²iÂóì®Yð«–ô£ô’6ìj¶‡ò¼É#4 üÃÍ·ƒù“Y÷G±Æ ¨¢ g/åÛ yõ¡â‡¼ºNô½Á'rw×sÅ1œÇÉ4v$e6·µ8ö3uq*PR]T;vŒ2x$ôÖ[oÑ 7Ü`Ä æ‘ÞªU«xT¿ÈˆqFÿþýňyþüù1ó<ý4 p;­»rå+)%åš2erí±Í ×tŸÐª—º®šRì¨Yð²¹IX³P›¹^È1ŸòèÿÏO¦­kݽüsÆŽ¥ã”NkøÊ¯ÅX§9ÖÑ”~·Sß+¯ÔÝeûÔ,¬ü:•†®Eãú­£sš1b#aué[¾§&Ô˜ZÒ&Ûj¶ïO§ ÿnC÷]½žÎ®±j~Ø¢…ktÕUD ƒmN¨\!‡˜neº—ëZÍôôR×ÇhîÎnÌeè{¢wÞ!GWÈË6n¤ÜP öWç?éÂ9…Ëæ[w§ý'[S»[)#µ˜ñ¨{º5BÁ¹…i6˰—îä‘qMÅÈØm”þÃÁ4š½ ÷Ãöh€Î“k¬8"Ó}wýWPÓ† q¤YË,ÜN›4 ±ÀMf‹›8±»kV ºáŒfôÏeµèš Ò™µ"]êû¦Ò˪Єw˜Î1ÆfWt4Ð,øŒï½÷^ãHGVV–gcÄ’’­K—.Úï~÷;#&~ž€œ©¬6 rÞ]ýIã&¼òÀ[Ú/ t››ó#³•¯_ǹL¸~âĉWe!3æ;¥Ó=¼ðƵf›/󨧢ÑZ@:Ù¹\·’xÇ 7›Ìß˹y³¯h«QfTYŠe¹ì[Ë{؆¨“Á Ë‹uÃA½\‡ïƒk­ÚN'ÞñÀ _Èb6ÄF–BV„*Èó#F$GæŠùÍLŠfxóÍ7©OŸ>4iÒ$ºä’KÄV¿ðlöõ×_‹ðwÞ)lF-ÒÿùÏÞÃ`Ÿ€Ñ^^½úê«ÂF; "O/»QU6Í‚Äüù»(;»çß^ÊÉ©çx¾€y÷C7ol~x[ùºi<,X@C‡ 3ŽÐŸ'îÏóxeöláéÒŒ²p»‡WÞàûé§ŸŠß(ãn2{Õ¨x€ÆîšìlQv±3¬Ì»0.Y²—à:tÊר©þ9}ëG{‚è÷‚q5îÕJtŒA8žÆ ²óñðÃSþœÙÔ‘VОŠúväñ=&Û™æ=þ8]Ïuë!n;ÊÎÖ/„¯eã¼Ú5>MìߟÚsdž94€2(DW_w­»`ç“Tzð±)Ô¸VM!Kzš_ìÅLýû-¢³r”Üwu*Y¬~j¼h!ì4 V­OeFÐY8…: N0ó† òz/…ßÙHÃnÜO/äí¥®]í÷ v«\*uÞ§ ·Ó3C6ÒϦëÕ‘ªrÜEÙÙ‘Nh¸Ñûìý÷£¥ ›wÓÜ…›éìèÊ.ç—Vz@ÞëxjMújS]Õù jݼ8'·Žŧ¬¦M,§™‡¬›à˜á·³dÅ«¯~MwÞy.͘ñ5õés®?¼¾ÃeU}ˆòC¿ o |¹è(À]šÀL¯3ÿ_Îu¡wœ%ЩîG(‡eºŸ¦Ñ×¾;Õ^ðá©ÇŒ{Åo;Y’ù|ßl¾o>ßµ§Ïû.É[@]¸Æ8 ÃO{oF¬ŽòDÐY8E: øHÉÑB¡.4u꽎)y½[g|_ì÷W\}n1Y¸ƒZÐÍ#úˆÝ³¹³`.T!½¯è,Øa†FŽ):-ªÑÕ²eËhà Aü«-Ók´–îáÑÌêRû§ŠŠüÈé7¯œF!êM#FÜTÊÛËHÄ ;7w?ûLZÇMtÞ´û¢Y(«w |`÷q…U,Mœ2y2uéÒEÄÙAåýUÕ©† ºØEÒo½TAŽÌ7Ó(jNÃEúÓÐÛ¨õy79z¢õ ·¶@”þ#óÃíçcÙt·Eªiøæ1b„øíV_ý´÷ñ8Ê Agáè,`Q¿óÝrŽrxnº0p|ôžÓÝ×(}òãwBû¥ÐKü9¿2Bë#ḭ̀sÊôòŸÿLw=ñÇ£‰iÁ¤;¬Σfô2m¿Ë °ÅmÊúçƒiÏžÏé™W¦…®¤×†vî£vLi­è1I’<ÜÈ2må¼~¨—CŠŽ‡hçîjtVƒcâXþ®^5œÿÒ¡Uí<êApÌpÎûÍŽN§${ )'Ÿ?LÆ1àæÌ …'ªÑÚCgÓ·[Ðè « ®‰ôZÆe„éÕ«®¢s ;/8V\B‡¿?LËï¡kW¡=‰4º•0»ö隺ÎÇ©ZŠ>­1O&e¯~‰ÒéÒÝÏ.§Û·§FÕìÝ`{Á®cǨ×êÕ†•Â9”…÷6N×\¤ ?§p!Íé>äú3ÛQL“â fúÓn¦;™¢\e[xòãO©ëú×iI›ÛèÒÚß±öð*sEÄÁ“'©6˜ì: Ü«œàF]>%–NƲLG.OQz¦…ø·ÊIŸ%S¸ž+ÿÔCÛ¹h]B­#®ÿž‰û@‘K"™oN/½ÃÔ™ÚŠ%5¨½­s3Éç°Ê,)²Ã•µX–É2©Îû%¯.}:õ)ü®ÕçýR´[fݵûlãœLM2xÇê~>äæBÏŠßægöZ¯½Ü´"SR]TWdœš…>—-¢5t3¿á_q f9#çîÚï.§ù‹¤ìÁ!ʯQÏËj+Õ™)¡U"­tá,\Í†Ž‰Õ ï}ñ |é¥RËéÉ÷Ü#ÜI{—ÓvþH 4º*+DU¾;B-'þÉ8£Œ.!i„{\ÈlýOç2ðï§“|Üwò¯M}ñ¢\°‹{㽞}–Nð«4¯CEŽš…;ÒhøÄ&ÂEwµÝÛèì9yÆ™0”2Ã¥/ÿŠ]y ¨–Bµþ ªM iÝGèlân¦„ß5ê4„?ð»æòÉ¿by×»Ût¡¤)uËŒIL:6pdòãZº¦¾å‚ÍÔ°–®YÜpD£¶ÿÛÏ¥sß»Hå³\4 Òœ®)§;zü8ýw•Þ^Iìcºƒ)ª^µnMªV¥¢'héúõt€ynå͘gæya›6T½J:Îݰ¢Tʨ~’ëyXÂ]|¯^Ø™Ó8„Ìߊ ¡YX·.˜†pBywpNŸçònI¯_/w#ైIÍh^Û¾^—I¨äVÉØñ¶dúA,2ëÓ2‹¸£¶9ÀÜC7ÑÊÕÏÙðv“ÝÎ&Â¯Üæ|NÙ¿‡ÆüüCÅ¢µŒ´¹¤ésç+@r Þ ¿ot*¹Ê …» %ô>~¶õ¸Êûr^Ù±ßÍü¶qÀ8î8ÿñN(Ìý†-[èÛ‚š8~ ÂóðØ2å¶>Æ óU¯Ì°3Àv+÷ñûy­Sné¬ç'öy˜R^~šò9ëJ.@Õ!}&ÍÀ=à|z-÷fÙTõÅ ¼Êì–Î|^îxo½Z“;G¯ÀÂN³ 'ONÈŽ³eE?.ZÄLC±j¨FÒvHTZU/=Þ#FL§Q£»¶ßN/ò¡_–ÀæMijž¹{!¨º‹Õ >®t±27ÃÏj •uºæ5Þ@²v½ ¨Êƒnœ˜G›è:žò­ç•4àùúë¯Ó«¯¾*¾üN+• :òi- ‹X%+ À4iZÉùTj ˜²ÁõÙüÔ—²ÆÚUGéɾ›èñé-¨]L_D²;­êrÛŸÁŠx´+e…`5Dì,àƒªZ&+o½`'nãÕnp€ÝÆ/åÙ8lÌ/ –#¸ö* ç‚£¬¥ùW²ª­Ÿ5ߨjKFÝ`…Sæ ŽÔ˜ßº?[…dA®òºÿˆdg»#ó[AëŒØÊµÓS»{ºG‘pšÚð³YSy  ü"è,T°Î‚쥫Œø¡iL¼ùÆ’ñö`í|T”×f+~°1w&µÌŽš‹ìFŽãŽL!¬§)=H}=ìŒg†×ÎjÍ·ê^rtòË¡ŸÑ{O¿ì£pŠQøC½•©ºu)ÿŠå3-çÄg1Ÿ,‡´ÚoÏW £?ÓjbÄÄŠ°á¥ý³ÍcÊe™±TˆÏàó—pœÓ¼² ’Å®¦;u´×Vû%|üíöj±¢"kW¬8xø0ÕîÖ-è,8¡,; P v·q8T«Ö•1ñð{Ĉy4jÔoâîÁÚiÜTëåY1¼¨Uß/œF€SgÐzOýnãwå_Å â!‘ÒÃZþÄ­àR'ª™²Ú±<˜µ¨o¿¼âš÷1v(à²ULS†÷-‡Ög{°÷4ø¶Û„ÆÂiGÕ?ý4B¶É Å ^wwõ; !ëwû’Ö̽riYÜ ƒÎ£,; ‰Ò,˜?èr/ö,÷WjG!î4LåÑÏÎ>ÛuGÕxóÄ+¼Ö¿XÛ É?ݤe!î4Øí²Y™4 „ÎBe?0ÞN…\ ¡[Gú°üð6[Ï'kã«w¯p³JNüäÙâY±agå ~z¼ó @—Ù{úå‹xËŒ,Î[ è DX1 Úäɺ’•WÆ=½Ô'?+ÏÌðÊß ´ Hƒ¶¡l+*ä7¡ f¯¶ÀNiã] aÖ,4o¢%+ 鑜kùL¡ž€Qš…ò‚ÌiÓCDiΫ„JÕðÄÇß·šÖm´ ïg?‡ÏϤõ¡~4~ªÚG„|ßÉXÑ ±(k#5»©@7xÉ"_'XN«ŠlÛæ©Ìû4±Ø_éïʾ>á¼?2¶FN)V.¯TitCÇ|¾Ïç|Ÿ.4Å´ÒÇmiµVÞæcÀÚ9Ã3½òÊ+tî¹Înß%ŸcÇ~":[Ví¨W›Ìí—û2/HfÛèAg¡œ: nª.ÉGWA‡{Ð%%S˜w߸xǃdñŽw¤à„°Ì÷R:½ ì–4ù%Θ1ƒòòòJ`óæ8˜je²ò>|xĽܦr¬ùüçG¦wžníKí¬rß xqé N®ý”¼ºYä½:iMh m7bÈW3¶Œ [G#ò‘WsZ»=D*âÒê‚Ü9”•ÖÌ|ýõ×t—0mÃGúóKýÊU³`m¿†›rs¯OHg!™m£…rè,xQués’‘¾ ôÝßBtÿعtiw½‡m“žÙ7Ñ>ú5mæÂîei•yÉãö~ >?LÝ»œáÎ£Žˆe|p³¬pâä~œCI-ѦiÔ¢I1¥§ÙÑm{÷Ró?üªií¨HL;˜ò<´Š6=ô5år`†gQï,^L¹~hé2›CÁ}ô7ül­øä=¤ÛéïOœI—NíKËïFšDnÒ#ÝN§i?3YTãí¿D³®~‰²êâ“@tìdˆL¥:µNR5aÆ®ÂBê•Ï#<ãÀGã'F(·¼n®“îS™!ŸûpÕCÔúƒ÷I޵ñ69Yš¾c ä`é~ÿÜ£»³ñÙtèp Õ<£„ª [×hì**¢^K–DÜm8-äòÔ}åJº«Œ\¿‹›¸ÞøÙ ¬»äk9§Úñÿ îjHØÅûE"¦ |7˜Ñ…ÓÝ[/õ­YÓˆ‰Æ¶'¨ùÖ­壈¹ cT¿uªö•Æñ’:\”J5ÎQµªp3¦Æöã'é×Û¶D?k³fÔ¨J=¢Œp;+µ7oVC8Á%½—´^\N»ùp"¹úäe„L?‚2…küFhuë|*ºC–2·¢f"ŒÊsý ŠâÝÞœV¨¨ò®­åï€Ê–ÂïC}^R²Ë ¼±âàL:_»f25×îàã=Æy•u³h·0Ýf"ó5VÒÝ»§‰òWƒª{rïž(ZÊ™!£ê¼$ÈÄMþ©‡~eÍsu;­Ï%Öä{±LšI&Ëf%aÍB5îAn[ ·ÓNšh¶|ÿ=e6n¬L‹f¡`cuºcDKš•»‘²Z±ÑkªqonsMnjCEš……üҦ͛'júúý®¿ž®²h€¯7n¤ÿ{é%úÖ8–À(ýý!Cl]NÒíôcý~ ¢ª5©]ý=”Qí„qVGX³vï]%×õj߀›·*zúöW¡Ùÿ®K·\½ŸÖä‘HÍ‚Ó}*3äs_Öu;u^òGÍ‚ û¦Ò?—Õ¢k.8HgÖ‚Î!~5 ´Ò­t —ã)Y-¨o“&ÆÙH-ÇÇg1Io•xçSZð5 "5‡pÕüɪU<ê‡ók.‡Lhzð(n—%vñHº¤­2¿Ù¨·? èœET;Cý¼nØÆ24ß°!"¯!ï¦:ÆoPÛÌLÚÊi?ܹ“0ap “‡¸®EçñßWTHG}i#ühAÂ;X†eF;ó uu¹þ`¦T«®Ú5õžC‡è«=i‹–;Ð,”ÊS³èëð£÷R|Ì^SRNsä >ü¡×bô …\×íê÷r×vàågM0ΧˆuÇÎ^åüò]±øˆèù À¦¡¥2HÂ1âešïóóµÎœWæYNƒx3/sÚLjļÂ|ÇŽkHg°à¤"t‚—üp[ ®âá…¯^e®l0?w2ó-ÞX·ï´W‰kA—Ò˜iÍž=›n¾ùf[Öp3päÞxã ­jÕªw´5kÖhƒÖøEi›7o6RDâöÛo×&L˜ ­\¹R+((Ð~÷»ßi, Æ/ÂH¡‰žå/~ñ ;¥´wï^ã¬7”§f=C9ÚÆÈÚ+T|ÜFÓsF6xFjÞ~úiezIkŸ%n†ÑAŠq-B»yÀŠ4÷]į̂牅bY`=1¯9÷;ã ¹—Bt„~Yn@™‚Þ3FN»ÄŃxd>•ïs'+ßÌåÀI['áÅFJmŽÅy¿£Øxì¬AV†æÍ)ÿÜ46‰Â‹Ï~'ÚŽ×^ ©Ú"îz Y“-—’®Y@¶wë&NœhÄ`éW–X4zôh#ÆèåÕ­[—þú׿ÒwÞ)â Y8pà€Xr+’¥YpÛYM5Ú^J¡µ[6GôFU÷´óö(!çÎüºZ–½w#e^s-\~˜®ê½BÂëzi¿š?ˆeI·Ñ˜ß‘…Ÿr!‘È÷täÓZFæ½öXž³2 ÞýDü¾k7Gl@,uJÚEØHÙh Q¯nç…¨ç 繎͈µl;ÁËóªÚÔe•çG+¿J§c¡sèý·GQK›ö.ÑÀwë­ÜWi–h™½Õîê!C„†¾¼TÍBqq±èÎ;׈ё““£]qÅÆ‘3X@­zõêÚ»ï¾kÄèšh4h qïõë×OãB`œU£¨¨Hôˆ$¡‡†ÇK´f!–Þ5zŽÖ^¾êžnšôH¹³Àס¥Áè!]kÎ=T·y·IC‹{½0V­í±—Ye“@¾š÷ÇG¯eyíw¤â'$̲8&Ì@Z¯# /2X‘ŒÑ—Ý^ûæç±<ç©”P¨³xn„±”[¿ï:™;¯ZCIÖQº$«œ ïÚë}QÞQǽ¬Ú*o-)V³X5˜*Íì2â­ÇñßM¼„*Ä¥Yرc}öÙ´dɺôÒKX6°9X·ÎÝ…ç}÷ÝG~ø¡°aàNƒˆ{óÍ7éŒ3Î+ 6nÜȽÆtâÄ ù,§´4ؤFãÿþïÿèÏþ³qFEÓ,ÈÑoQÑ9bTc¾§9ünàô~7Y²“ÃîÞ~æò¼Â-Ÿ±“\ÿ‘ãø¹ÚðÈbeR!™×U$BÃáUÃb1nYWÓ¼®ªÜèÈçò3[ýM’ªYؾ};ÞˆöÉ'Ÿ1:FŽ©µm˽><óÌ3ZݺuµÕ«W1jp§DØE¼ýöÛFL4ÊJ³à%­¹§Ì¡Ôfñè#^ŽjÌ|¼Êgó2:–=pó\¦j„j…Jáê û±&Y¼BX.#ÜÊ×}4i’Ui…­‚.tɵèÏeÄË4‰ ¯£UºXFnÖÖß?-Þƒð@hÊ›D¼ 3AVÜïýt€Ÿ9~' ûp=B/ðšÞm¤üÊlF<ׯë}ÝÚ5sþÉvÖ¯wÉXá§ÍEÜäÉ 9ÍÖ2ÏSðÝDž!T'vÄ3 eh˜jàž˜ã îqjOÃÏ#䃗Gg@A˜öÂ|n„óEclmàÛ…iAÞbS¢íXEñ¡Ó/H(É*6‡Ò?öúGßIeª2pD'Cõ\­˜ññ”dîܨÎKÊçw9ÆûQndG0YïÁŽÄýN,]ºÔX¶v®ñè±âõãz„^à'½¹$~e6#žkãê¾úÀË~i:òmÈ!qO5ÅÜ'ÒeCètßòÊS’ÚY.¼ðBíÞ{ï5ŽtdeeiC‡5Ž¢µÁµjÕÒ>ýôS#Æ{öìÑÒÒÒ´W^yňqGyw§ÆÞiÔš¨F¦"iVLLJ”ù…óý>/OÓfrÇÀ t°ƒÝÊí6¤ Cõ\8Öã?s‚Þ0„$ÝÚ\dÈMê=€ñ.v)wº‚ÿé¢YÀû’åD'ý£KyAV2 zßôÉ@<2”—üv÷uÚ‡$Ö¶/QÈËÓeCè„òÊS’ÞYK'§OŸ.–NþáK'7mÚ$Î÷éÓ'¢ã€©‡jÕªisæÌ‰XyèÐ!qáC=$¦66nÜ(z×—\r‰vöÙg cH¯¨scomàÛSº–Å—ïæ~ 3cJF£­̼õr%œ–$¡ÂÅúAêt0öAâC©îmY !˜={¶öæ›o–I£ jôµ¶ŠNƒü(!ô›W€SY‹ç]èy–íÉ¡JË©,‹•‘T¬Ž”¢ýuÌ{FÎøØ2 z¬W3f¬Hˆaj,ð+³NçdÂNf§gIÔTS¬À˜÷Eè§g(k$½³`ß„æÍ›‹N@§Nø½È8£iݺu‹Ø‘ éô—IO<ñ„8_XX¨]{íµb%:!™™™âú-[¶ˆó^‘¬Î‚Ÿ cåëÖÀ«x£A‰·ayòÉÁ¡ ““êr˜Õ£^åŸ ®°Ð,D6ÖêQ±—=¬ù…{xù@{•Ù è”èå7Ü a½tGzZëdÕž(žÇrtoŽ—dÞ¡N•ö 'O¶µûPÒêy^QM¸ÑiJ)Ó¶¬8AU_íþz½‚æIoóìÊh¢Ê§ ~d6#,¿}»PÖ2£H#¡C/çẉ6×*_²äÎËÛ#î‹Ð NÏ`‡dÉìÖY|C0¼Zùú]Y óÝF“&m ^½ôµÿvV¿*Þ@¼ïàÛ¯ßGükÓ4mZw[~­ÄÁÛ‹|Ñ|±[„¾“=Wà¨ý¼æ³ÙýÌ3½Y‘ûqìðy<7—¾GÜ0ò«#­¿d¸ü…+bxó7Ë|&óþ/ÿšEgÑÏûõ¢«’°—Cy`áÇsyŸ&¾ÌðrÓm·Ñ¨7Þ°¬8I¡bjK)ë|­žÁûÏÍügÒ:êGyÓ"W«˜!ËZI[á‹€ÛcýÃZFU>Uð#³ní‚×v 8µní6vHüÓŸÞצ¤\Àr Š çyä‘„Ëí§Íõ»Â$™yí¶"è,0¼¼0¿Rà‰aiìÓC¸hÆÕfѯ7]¯hˆ÷îÛG999´—ð™wæ]›p82Šp0br¾$]87¿ä,ʨ«vHv õ–a(Ç<Ê<Ø:pZ¸f uê)þþð'™>ú(]y¶’ Ãs(;¾¹ãºé ©i½z|¬C:†2»on²M®¡% VSÖœ‘ÆQù`:Ó~®~®~®—ù¹®å¸žâlÂ9Lv65ÊÈ CGÒŒ÷ßçF±pŸs€ËÇIº“;;5ÓÃË» OT£ÿí®G“—Lã”á¥vØÖÉ9”“Ëém……Ô\8  ¿‹KXæOÄÙʼ¯LX°†|,¡iÜ›À¹{gìvîünàúíævº#5åÇÖjåR™Û·§FÕª±j,ä¶´»XoiÚ¶¥–ÜÙÿ ×ï(GH.|k!*,L¡ŒŒª [S¶;FÍW¯¦4ÓÉTîæ¼×º55ªZ•VÍ¢ÎçÐò–7Q§ôý"ßïßOwî¤OYæ‡Xæ™uNwœµÓ8KôÕž=t÷?DËmðV2¥Põê2—:ʺ9Üær«nçjEñ¹ÔyÇ»´¼É/©SÚ×F¬~¯cÇR¨Zµð½ì|99Rñ±CàH*AÓPû€W‘VíçÀ "JP¼»v2z´#'ׯaת=”ç­”¬%‰~ø†evÏ·ÔžÓ-y rÝÛ… ñªkIë)]ÆÏ”Å!6aAVxàñ,Ý6É)K2oàƒwq 5ŠJS™‰?wZ¦,ª.V%Á~ÈOY »YÖßµÉòŸNY|ezŠ©,ʨ_™Í”¬vÁÜÚ/íe,mj<ä·Í-kùœ(pQ]NšîD¨7>œºXvp‘š…ãœú §®Eky¤yÔQ³ ]8Oç¡RGø•R ¬Y¨Í\á¨ëSæqÈÑ5ôô?¦Ó_§nNSxD?¥ïmÔW¡ ñëv|ûO{K#6QZOSû©ù†5 a÷ÍÂM¶B³Px¬ ­ÝS¿Ô ôt~ÿþw:É2A–É¿þµpÙIÅôÄ5×Ð…SÓ3ÎÀ¥Ž¡±3fðõpsӦš§ Låc×áÃÔëÕW£G}úP#O3¶ï®Jæ4 ûnÚMg78nƱ¬ €¦}ü ¿…lú˜^åR§…óše–Sv.¼å³M߸‘rÅ/-+\ñY§5yqÕ-µ3iT=2ß<¹ÆfIÆÓd~×Òý´;ë™í¯ U«ÚºÂÞÇ­üçŸ]tΪ]Cí::—jêò=6—[u»ÑaIuZ{ü§Ô®ê·”‘vŤ8•¾ÝQ~Ú„ó)M¿W,š;š…8¨Çim¯B³àÁÀF¼¬Æª8 ?2Ûñ°d41ÚÁ/ïü|l”µP„NˆEf ³ì ë;Àúz?¼íò×ÕÁ`s¹Ö9”%\çúqc{ßu× y¤\™üCŒ4ù:«Á£_÷¸N«j'ú¢ÏA~óº¢Ã­™Ë €ìã¤"tƒoäý°Ïƒ]ýRñu“K¬bAŠWÛMÂB#4Ç{ák7‚vsç·ìƒP¢W½Æã@QOåùŸPC-DáºàTA^W«ÅR6¬À-ùršá—·ä73Ð,8À‹fAÂó™ÇŸN¹¹“ø×2¥Ð^XUq€™íx$~x—µÌÜ íŒ™tmæZá¶Aƒžx;mé»äUÔuläû”®²½¸ÈžÏre³\ù,WO—9s?|%6rùkùëHµÓ‚ hè°aÆñx‹Äxë‰'ž ~ýú%¼|”7’U>dÕ++_7¹ül;mu;+¬ÛRc: ѯ¼BÏ=WÄ™aÝêÚ»k7™UºîæòüÊ{ÐA耮º îpƒÒ÷>ý”&æÎ¡yTà»^­¾˜ÚÝÓÕ8R#Þ²¡zçà Wp…päÈ‘„—i7GîsTN$C³øOÛR%7ø‘£¢ ¬eÆÈÍvG§Q›ÙfBuÞJ‹9Ò#Äñw”®e±L˜3—£Ÿ²šÃ–„{¢ž`ŠÓµN¹ÉU^rûåZeôª ñBÖz(í—¸Ë"vuE¨ªWˆëò…ÆAÖ?k|‡©¥q|[âxí‹ÿÒ"‰°æòVoËH„n +'š…kbI xIï~ä¨(H”̲‡mçŠÚ }©Ñ$*)ñ¦Ý±ÂiÔæÅå°„îø*Ÿ«íç¢Î”I+Ähg/“>ƒ­z&N}ã\*ç4jÈ0;;[ôhŠù¾›7GºP?QQë”›\å)·×´UF¿N¸œP¿‘²FÜdy‡´gøŒ¾¢è¸X!€ÉLh!¤Í„yåP*­¤KW¹“‡X–…«àÇqX Y(wÍ‚÷ô~àGŽŠ‚DÈK;Öh€xe†›7éva d7?ö±÷£ñp‚›Ìzê#B„^G)•ñ¾ëdÁM®Š*·V)³y§\0´³Y@lÄM-¤ÚàÌÎÍ”¼ùÆ“‡Xv»u"‘7.pÓ,À4@W`„±"tcWPz÷Ò1Ôp¡Â%+iŬâx×üù4±j_¢÷õN0@Ä[¯5S£}ûÄýE¨8ïD2Cv¿€V+hn½õV®±¨‡Ð#èÀ¦*o¼ñ†ÈSŒêÇŽ[f#{hVÞ{oÿZ(ÂDmê @"`nk¼´;Zz÷;ÑѬNBmѨgOºwêTú"záÕC†Ð¼-[èú'ŸÔUjÊ×\Ém BךGóÜ‘×oRŠTjÚê<ãwr€vãÚœGø‰–SgÊ¢Q7ÞH]B!aq%é–kW~¾®ªq ‚™ØÒm9µhÖñAï3T>TTÍF‰ØªÓñ"–Ѽ ~ç)µ9|ܬ¶­d7ºÁi:µ÷m;áo%B;xIsº¡¢æ‰›fìTx—Ög°“ÙÜÖ@'Wî8µ;vùƒúŸê™.OØ·¶ëNf>CVýù#µ2Jû¤uû–ø)nš…ÀfA¤×9¿XÒH¿reü[u¢‡ùúcšÒ°Å<ç·aónúèóÃÔ½ËÔº9Ö~«aµz¼Î—YáǰZPÇ*‹Û+6æP˽£Ä K(‹G>ùz÷ò½{±ÓðRFý”ãÓ1O0ÊtÛú¼¢¿KÕ3tjw[”Í‚¹~cu…¾Ÿ!Ú ŒŠ×r]/¦M\×Í+"bÝÂÚªz&WÀ½øìFš<äÈ­N=¯òß–xÁÂe˨û Aü ºS~±B°R¬ÖÈ…è‰Ñ£éŸýŒ>üôSê?rçiÎÓõ4õ±•¶NÍ‚TÍæÒÚ’î hAÞ⨑¦_·ÂXc Õ`~µNT]$Â:èÑsEèw½u¼äeþ Àcã„èQ{µÀN¬ó¡^I¥Yè,vôÌwtŽ¥‚>ºñ®ÙœT„vð’æT€—Ñ•WT´FDaÅ‚*¼Â®žÉü}?wy´väe·L/i¬”›…@³ÀðÓ3÷“¶`Ö :Ú»_BœY-sÓ©K«éÅ!ytÁmÎk~Í»:FìD™²:ªÇ.‘HÍ‚Ÿ^.`·§zÿÉXß®B<£6Œ¨H'Ož³žx8Þyúb_Ú XòßK>WôѨ éTÇš'~´9Éæê»+ö Aü•¦ÝO+Ú»´¾„Ög˜öÂ|šð@Ã(ÍÂEÙÙ´Y?4É„˜èvjÂò(¼:µ¦ôm¢?Sm )“'S—.]D¯pªgûö5õiØ‹™4ô÷ëè;êJùyK¨gWwíh,ÀÊ©#DZ,møh-çÀQ‚÷)Ïš-[”Ú‡…üÜWZž;‘š… ³Àð³Ñ’ŸŠùá;é‘PÎÃÅtÕ%?ÒÍ¿éóG×N=õÌ“¯ÑŸFÜÆ¿½ÁKdm$­=«—H¯ð“Ï*Õ¥Ó=“Õ°û‘YsÇæÐ¢(«7ž2Â’¼ÔõkŒ£Hĺt ên¬233}wȰzõjzôÑGÒ‰•X²d/=SFÏ­KÛö}”ÐŽH,å×xÙbḭ́÷Ó y{©k×°S¶xË»V}tu`ãõ·øÓwKýŠfLú=Û¿z„̸ּ¬7Œ|ZNã§FN1Èüi_ÒšsŽ®’‹=¢)~Ì¿¼µI~`-8?~<Ç.ƒævçðN4 ®éå"…;RªåÏ~Ú¯`Âeª¦ƒŸv+œT~Rõ†PÅ5äBèv/3ÀSW‘™Õràu~Ü| ‹TÝ—~>R‡óñ ×|v“Ñ ;™ã…™½À<¥%\ršÂiI—j:Ãiú |: ‡E˵ Î7;™ý›žNt35Þ¨Ç!ÏÝÈë»V¦SŒ2ˆÐºÝ1xÝN-”ÏQ [£ßu×]¢ŒªÎÛ‘XJ¨Ê·Üv<å{ó›ÏNõ uå\Êg1à Lß S^ÊÎ/4É1]ù@(Ÿ¡Œ¯æ|ln›óuÖ{è×»·Á4„ƒfÁkÏÝ »™P%zðCߌ³µ:Þ×1ß¶Ì·&÷ü0ê[»­KÝ ñtõT>÷Ú?ÓíèW;›„ gçPVè΢V >)ÜCžÒ·£pêäÇ9Ô–ûiYÁQúY« :q²1µhRLéiê¢äÇí4°ð»ï¨ûßþÆ¿¸šïEh?®lÙ’‡±‹{Á½ž}6Ò¹ d6ñ†ã§ïY†ÆõêQ=î1ÑÎÝÕè¬0£¢ÒßÕ«†å߯|›?÷\¤ÌpëàÀÉ +v7£Îs†Ñ‚ì4,d´CÞÓ hà¢Ea§GݺQ_…:`ÛáÃÔ|æÌh™Ž¡VíjDcþ{ :çujYãÚº{7p¹—ÈjÑ‚š5¾8vŒÆòhÞü†±¨lHûöTÇÆ±7Äf¸¥ßË2ä2 ÁÑš"-®‘½È°‹ùöb¾çQ3z™¶±^·”ÓúžÆsÛRÏÆ±ì=q‚r¸²¾ëqM3©FI5¥»cé ù@Ê1úõ¶-Qeûÿê_L#öL !‡SŸï? :t>õ GøÌpæ½™Æs[×]½v트÷-á'ŸÞø꘎-Ä¢1¿°eïʧVhgMù#ʃƒ“¥â“'©˜ß=ii”žžJ3¤{ö„7gª_ŸúÖ¬ið˜cºó›hËo"ùZ /ð³]|'–û –{çsÓT<]4„#©ï¿4 *@ €4æŽ1‚¶CÁôÅHAr{Qô±u/ÜÞväpÁ׫1 ¶+E/Û—ªÎƒF<;ÒÕÊó^)ßàƒÐz.ÑäÇí4(žD“_™½P<ÆQxv•3ù‘ÙëÕ™¼80òB2ß.¡ÖâØ\Ÿ%•õ6Üf:Âm Ê Bs|^Ê£Š¶<ºXGS®¼P9švráœÆ²ë® ÃÀH¥Oö=ôJ~KêߟèÇâã4fFúÓë©Cë°K]'™cÕ,¯Jk4¦ºU¿¥›_Ÿ®”ÙŽ÷ë÷Sÿa©!`í\úšQÈi6sšœ&Óì£ÚôOº†ÿþIg7`;©&k^Žgr›%ÿñœ‹©öY5Œ#{ì;˜Jÿ\VËֳʅ3R=qÞyt!×õ¦ ÷ÐnÎä'®À»yG¨7gdPôt.Ûî.%¤Ö"ê][4 fÚSD57~iÙÃÏûö•ûf!3ølÜ‚j©©ÚðmÝVL-8A­ŒÚvâ}sü8µâ¼jÊ#{銹fhµÛΙyÄÛÈñnãÿ7|}+¾îÌP Z{¢µ«òM„ g3öO£·¤QG?å£p; no×k@™i‘ïë 7óHc‚ ¥6p iËÒVáv踨úRÎq|¯?бÃ-¯%¶ðÝ‹é5oܘNž¨Bá2ò8™´ \þûÖ×1äas¡¥1-=eyÍ‚^4 æq¼ºTKé0W$眉ž°>‚ÛSÌmÉù&'O¡Yà{82Æjûà'Þ°xî¹çŒgÓ{óæ‚Sßnèt—Ñ4ÈŽ·åöÃRT{›„dç³´³aó'þ^—pÆêÒ7‹:‰|еbáùZs:¿¼½–g \ÚÁï;ñÂPñ•v:cÆŒ‰Ë&ƯÌò]cy¡Ý<ºx ¦XÞ·²ò…Ku»ùoü†œœØÅZ_U„kå2pþìIIÓÄ9/ü‡1}=|¸¦Íœ©¤iýú•æG ?ë˜Ûn‹JS8}–¶&wŽ ž|2â½IB¼5­™·x‡|Œ4ïpØÙÈóxãÝÊz5îzG;2¿åN~3Í‚±B.JãÞ™ycMØ/¼òÊ+t®Âm«~–¹@+’¬åƒ*ÞæåP:ô%MºíÄ—ôBÞ{tjQvŽý²"•«YëÆK±BÅ[e™Í•‘òÆÌ¡g†l¥wCäsÎKHåÒ× ÈvMv¶atƒ1&d“ÖüVû•d—ÇÇæ6ØÔE×®Ù­xñÃÛï’>¯éýÈàuÕò{Ñò }Cçµjª,C¥qiÏ­§ùï¿åkÕ…µ9Ù'™7/[²éC8jäz‡ò¡r4¶aó´ðó]tU—FÔº9´±Ã,×¾ƒß ™¡M¹øî»#5°F]Á˜ùSó§ÿ†ÕËq«RQ¯Àú <%´Ê¨ïho¿qÖzm~§h«_±î€&Çɵ®U/“ŸÎq™JGÿL²FYÓÚñv²KÀVÎYw8W,?uÅm5DÐY`øiÔœÒΞ=›ž¾õV~µñacîLj™mß²¡°—åò5ÕGWG>­£áTH÷шD#Gz_ê(á÷ƒbT ÕÒ4Õ²ÏK«w¤ï{w&, %®Œ¨ºhT„%ÿ¯`/?X / D,ïaòäϹãÜØs'à ~ßm¢Ê‚ØëÄËrU»ü6ÃK¯ðÃËïG*¨>N¨^ëŠ~F_¢mÞ "À=º+–ë°Èj‘G¶ Õ¸]hG)Ô¿ßpº÷Þø¼½Î_r´t°Ô©ÕAÑfq›YÌç0 H7u¢¼’TJ??: eØYÀ«ÀÛ˜²ÔôE_sz‰†Óœ¢WÇ;‰B2øûåYž28¥ ¿'½|çä¼lœq.Ûv?'[¯2KØ9RòȯÛe„ë0žY>—SYÅo7—ç±ä“è÷Ž´9SÅÙA•×~eE:»¼©ì ü¾c3â¹Ö ò›‰P¾eåDyuôó[µÉ“ýo`$>˜`^Fäd\h%«Q’yI SBêÊ¢W\Ã0Æ;–Š[ÖÏ ‚¼X.÷Ñø|ÛÊ\VPÝydý˜ø)£± üýò,OÜÒ;6긕mðží>,^eTe%xYF®*«ùùXZ¸P„VÄ’O~ ê,yí@Yó:Y½ä~Þ±ñ\ë·ÎB0 Áð£ÖqKŠÈMeꦺö ¿êK³QÒ™µ‹¹4*.¢~}5úåÐÏè¹g¦RîV¤„zÓcÝD—\r‰«¼Ÿ.ÜN/ 9H÷­E—v?[Äùß<Ñ7¶Åé³o¢a§Z}÷ÝM”Ý4áªG‰X¶µ†¬N[û­ ÉP¯zåéT÷T†t0š;§¤„ÌÛýÈrØÙIDm™^#l|”VGÌ©{•Ù®¬Ä2//»üKt›¥‚ªó:mg–ûÌ3c“Õ®|8MiÆ3­˜ŒzÓe¬YðÚ£UÁ‹èéÚ©ýÂËýÜ`æ!¶dÅA „eY±>‹×<‘£ºtNçuÊ¢¬ [Ãê²En¦M"Y¢üò;:E·dõ#³¬;£G¨½Æ¯28i¸ä¦MQ#Gý .Â{ŽU³ËˆÖ ú;õ¾ŒÜŒòÐJrÒ ¹(¹¡yM1ä@èu9(´›~§g¼–¿(Í‹/¾HcÇŽ¥;wŠ%‚Ï?ÿ<]~ùåÆÙh¼ýöÛ4bÄúöÛoé§?ý)5Šn¸áã,²A£?ÿùÏbÔ·ÿ~ºè¢‹h„ ž–JÄ£Yp19õêTF.~F­~F~—Æ©ˆª¹g^TLü¼D³r7RVË"ZûÝwtûã)ÃxíÉ'©A:”““Ã-6fEÒ3ôcꚘ £¼ä Fo°žæ±èÿŸ Û´¦~“4Í‚Q¦•œO¥[D§lpMy-ú=¡îôë÷"ÿâä§…Vqý™·ÖÇk_õï=4æçÒ¨\"ËŽâ¥Û•—hØôÉ0ð Ñ9üüš…Pˆ~ÂqX&'¥ÓpTÏ´aÚ¼?¦‘Ó°¹ÔLZOýhüˆë"–CzÍ7/Ú§¶L…X§•§f!ž‰Ð,H`ü…ËÓUÏ ÖÍÃ[¥«§e·çü—¶†Fñ÷Ÿ–3í¶ I×,¼ñÆZÕªU5®ØÚš5k´Áƒk5jÔÐ6oÞl¤ˆÄ'Ÿ|"zÒO=õ”VPP Â*UªhÿûßÿŒšöôÓOk5kÖÔ¸S¡}ùå—Ú­·ÞªuÖY?Œ‘²—4gÎ#ÆæžšÛˆÉNs G­æ^¾uÄà†x´N€ ªÞk"îgÖ&¨zøV[»7FXH#GEv2ÇðÂ;J¦f¼ÜǸ6ð‚Ãhà$e0YeCŽNÍ›k%šV>~0÷;ã‰ÕpÓŠ©Ê±×²­"/Û­Û9O2ÃI jËÜê² ¼úSùÄ}½hþìK[àõ9¬rÇ+«„“Ìà™Nçr¹ôg˜-Ék™ö |¿ñÜvšΦøpá…jƒ 2Žt´k×N:t¨q‰[n¹EûÅ/~aéèÑ£‡öÛßþVü.))Ñ7n,: EEE÷x´IÜ{…ì,up}á^wLsòâ%]kƒçU%^‰0T²|¬ †Œ÷~¸ù€ü@¾¼1ôImùÌ5Ú‘Å+D~!ߟçòMZ1!”ù)Ï™Õí²se's"wú{Ò Ç‰B"å67bà“Œ²`wBÈëÇ›^øÝÙ7t¨+^½!&SÍ/Éiš ñærl·Û*:5 'O¡Þ¡ÓËv¦©øxÅR§ð8¡ìäŽUV '™Áq©iTõKñLÝZ¡ç…ð–œiˆcÇŽQFF½õÖ[Óƒ¦U«VÑ¢E‹Œ˜0`ôóÇ?þQÄ_þò1uÜß}÷˜šX±buìÈÅÚÀ¯ýkªS§ŽØ Q…ââbAP©4kÖŒý„RR6 Þvj87*ÜHmi«I]kgäòî_þEÝ:×Qz‘”×F¨‚}z’TÁÎ×Ôÿû?êÂTb^‹ ƒ~MëÕ££Å!Ú´#Í·'ÉZOs¡ÌúaÖôåËiàßÿö˜Èï±/thƹóà¡n9_Û™¦\ŸI×µjåêER³'I³÷H3¤¿‡jZ;jJ,;=Céô«¿‡â!Ú³¿ Õ¯{‚Òª¨y;ù¨°ã}¸(D¶T§Ö™EtFõH¾ÒCe~öºnþ(Ož$ýbWa!õÊϧÝü{‹i›q矠?¶…^4Ž Ñƒ©ôξoè¾UËÃïµS'êkèï·1ßæÌ7ʳ`ûöTÏâž$û­^MóÄöÐÕüØãÿgüƒ •gIé“¡µ¦ôm¢?Óqâújá·Ó5¾ÂÏŸJ+i§kjs_'ïq¸iSx×¾-¨¯É{§¤,±ÌŸ°¬^‘ÈM™$ št§¬:ºÿ'l;~œšo€¯‡ö‘å“Û^•·Gé²jÕ:~ûlúä“OÄ29 ,¾Ê£¬µk£ýs§@hn»í6#†ˆ; °£¨¨HðêÚµ«à}ÖYg)ˆ¸³@[¹'øÁ1‘°Ó,`t‚›¡ Œc|¨Ñ¹kéÿ¦7Ú‹ýÑ{þL¹Ó£yKhØàËé„V]ì_{…USŠ£xš\fzZšÖ,TcΆ'¶Þúw]ºùêýÔ±Mdù*kVý–Ú½ñR´Ì Ô,@æR¿\æg_eËû‡ýUh6Ë| Ëܰî #6R³åYëu#‹gH³'ÉcLG˜¸£@owéBÞ·;ö–ÐWÕ£Ë;ì¥&õô–Ê“¤ÁV³Öjï|1jÜ´ N²DÉܺ55rðtyèh*}Åuö<®«5ÓÞ5§ïßOwî,Õr@¯jnM„ÌÞÂ;dqKj—¶ÑÖË£aÍ‚Ef›Ñÿ‘âTúvG5jZÿmÛS~ÚäÕ0¼ÞZfAz¹lÇõGõaÍB¤Üsë×§3øÜžô„ŒúuêP]®G¥°ÌUYv½ ¿Ó«…%´Ó,¼À$½³ÎOO§?ru‡¡ÐC5Ri0·vÞ %¤'ɨ¼vÐ,H¡T¡†uNDxõ5£L4 üqóÌsçÎ5btääähW\q…q þ€kãÆ3Žtà833SüþöÛoEïfÅŠâXâW¿ú•vçwGî6 è-ñ[2÷@å2óœ•uîØñ‹—y3 ¿¼½ÂŽ/B»]×¼Êmæ­óÒ ñâ…ÌNˆEæòæ 2Á¡b‘Ù+üòNF^ø•Á ¤µ›/÷Ê×œŽ›v± «¼òö‹Xø:½s[Vd–²¾üâ­-­Ñ–O´Ù°R²¼j‚̼%ÁЖ?ÃBSª‘á4°1Ûs|0w=ÿž$ìÜœø"Tñ[1cF©ý‹õz'Rå‡ý È« Þ™´³°Ó,ðk‹0p¼÷Þ{#YYYŽŽ={ö4ŽtÀàÑjàøÌ3ψc’X fzA*C£žËé>Ò2inT†"Í ¦2–.]êÙø·Àµ½À\± _<ÑùLX¿~D÷#7x"_t^Ñ v¬ð›~e®¼½v¿2ûÞÉÊ ?i%VoàÂSøX™yxá«×sݸ îr¼t/¼c_¾Éz'vÀµVK¯|åàë‘ßä‹ÐË´W¬Ó:^h)Su&ª–~Ì™œ¦krï* DUç$%Sf+o·);Ám5DÜû,¼ùæ›Ô§O⹘ŠÀZQ¬þúë¯Åà;ï¼SLUŒ=Z¤Ç4ÃW\!¦*`´ø÷¿ÿ{ì1Z¼x±ØOàŽ‚Hÿ·¿ýM¬~ê©§èã?¦uëÖQÍš5E7È5£7 J—»wß}w„Áäu×ÝEï¾û²ø­ZÃL´’¸Qñ¼þ;Yëaã…Ûúl?r{Yë]Hf^ǺöÜ ³fõîM4s&Ñw‘vëéË —-£îb7DnâMu”Gltenò°®ÉWí°>”Bk·ØD;Áï¾~¡â_–팓Ó6·gïC'K˜VPˆºÐԺêòÊÐC\†Pz¼`S/–º÷+½¸ä.¯,%üìu’ô}€ &hüÁFŠ:uÒ-ZdœÑ´nݺE-O{ë­·´¶mÛ cG,³Ä~ f@»ƒEhÒÒÒÄ”ö[ð©Y˜1äy¥Fá«3J{’—„߈Çù&©#a  ÔR8©@±,C* ¸-ó„øˆGè†x—Œ& *™U# ¿°j—¡5‘ÈËÓGYOˆŠþ¢ËÆ0YË^*ÿpÍy…¡ˆ¥ü¢lHU.ÂD–ÀŽ?Ú´3âÝ $‰TË1e[ux(Tƒeë(B›¯{iÙÏerÖ•%°tؼï Ï(ŸÏ'—˜ g&¤qkïðž¼NÓÄd1ÄAh…Ó9+ä73iš…ŠŠÒ^ÿVô‘\ò0!‰ZRÅ¿dŸÙë’¥‚™Ë)뎊£Z8Õ4 ^FkV™F@^á÷Ù¼È)ïnŸ*ø¹¬pÚé°,!wwsóµÅdœ8´×/èÚöYÔšGm0ÖµBïröSÇ‘#?˜^b´¸™GŽsóßwù™µ‡~ŸÔdxiv´›èãË÷•«k{/måB¦îâ·è¦pZ¡ 2ùÆpC¢Êy¸~ƒÇv&Ýлÿö·¿ÚVת½Í¿îÇ€¾È—héÒ¥tÁˆ8p¯D캫‚S{í§-/ÍBE„ì%-²HïVYÈM³Bï8Åè-¥k™FÙ›†VEˆôè=C#!V*ªfÐG)êßðøâ¹8t®Óç{õ‘‚jôÏ_—Ó}´f]9€ÄCy$;íÒü¼)Q%QVÌrZFVf ˽!U¬ðšOñ¢"i$A“0™ZñÏ1¥Ë/:-EÏay…üG9Q¥µ£òXök-‹˜»6"ô‘¯¢¼%Šìê՜ѣ…,Q²Mž\zmX³ 61Òèiý”ýD–óH­(¼f¢ Ùk ð(°oÓ¯‰¤²Ö¤š¡Ë¥‡V8³â´×,8ù†p²Y@{»7Ž{ %<² Û?˜{m+WFd;vìë¹WW°›‹÷:z4/Íü‘G ßñH¡çý®tÉ'öÁÏ6“kTsZG[éÿ÷§.Y<òËÌ´õÈ&ág¾oc~AÂGWv#¦—)‹ÆÑLzn§®üTú<&Ò…!–x1ySÞMÍè Λ)\®ºØÌµ;¡,æE%Ö®:JOöÝDOoAí:`D_>°>s1¿“41Î3å–ÜZ–oÜH4|ÑŸþÕƒ:\]߈Õëù‡ó¾¢ h4kf#W{ x/í?2Ÿ›a]3ô\Îe4+/¯ 4 &-—áÙðоF1{0ô hÄH'Ož,m {ôèáIg¾–?ÐL+t­ÚcÞlä;w[¾îá2Ô†t ÇR¿²Õêíý6nßñ¬( eºŸŸumB5©~ádSh<@ö’ܼNΘ±‚ÓaEÀ ÇÞz¾è=š{Àr4k·M4âËB³™b¹Ë^'|Л¯WÍ͹‘—¹àLjÄÞwùÅJ=QšY»„ð®ë®Û¬Zï{º‘yd^^”§Ž”©”ÓŽTòã•ã4B' žè£ÛðèÇ>úh©<­ÝÑGÕÑÚ@¯r' x~k[h'›òÚ±ßicÑÊ$K£,NïLæ3VËxyÖ²îídSå§l𝓲çøÕ,yáŸÔ5çZãÈÉ´Yˆgn^öé|]äõ[üÚ·f!¼©Ï:šŸ÷´Í-[³†>õZÓÙô}K9Æ•:T#?3ö2Ý3e*/~À¦uÅ4%wÝ5ñj{a]1ò3o®5yøpåèEå±Î Œê¾Ùº•j¤§ÓÅwßµ-÷ø¤ûŸ{NOl¼k¶ûÉOŒ£H@ã2vÚ©9 Í”K¸…®Ñ"¼,5 ñøáO¤æo³óù¬áçùw!ÝóóÍôÚô"êÔ!²Þ¡¾mز%Jûˆr~Qv6×—p¾7­¢ÏÞw·/q<@>SFÏ­K=n°oðÌù YTÏŠò˜l»! ÜËM£ã§lšÍ‚ìyüôÌу“Îg:R«R-æ‘ì'ÏÎaÄvÒ`ž`ŠwýÁXh>,×3¿¥Cò„Ü+ÿµÛxZ{ ìFSrV^[ÁZ×#«È¬A:Ì Û¥wš7†––ø"Œc#‘-ÉÒ¤!\>â„Ó{H$Pt 3Š€ÈQ¾iû\›4 ^zÄ€ªGÿû\@"æòÚfzÒ<”Þ¦¦ô13¯Æª‡'P‡1¿7Žìü°³ô…æcpÿ ÔFÅGÙz¤9ò¶ðHNÆT#ôâ¹AÛwÛ >]¸^rî[‹.í~¶ëŽùKŽRvNW|Û0záÍ1üN ‹¡‰À½¥lØUe‘¾ìå—©ÿ]wQW%l4³éFöÿ^¸ŸîÒ„žy=~ý[ØáÇùjÔ¨A‡NÊè&Y{Nøyô†0r”Ó×4{ölºùæ›ùw$œä÷ª)¦3 à{–ð=S¸þO¡•ßZ0k+“õNÌùì¥ùÅ~øÎFvã~z!o/uíª¯ZqÓ-[¶ŒŠ}5àäL·18J«#VRø•ð"7Ú±~ýó¯6¢õôX¿±”;íÞÒ½ Üdwƒ¹ñ’Xöõ×t1·;QùžR#ãUkš͈ïp:½÷¥šóQÁ®GÇ Té\øxq{ —U£ ÉÏÈfÃëïh-š®3ÚÍÔThêQ{×üÀ³ºÙKÈ]ÛH8ÖÒG~²ç Š·7Žkœæíì€tú;‚†%:_ÎÉ)Íg„ÈwØ0p# äE(W=஑׺½oœG¹@ù€ ±<· àã%?½¼7+À+–|N$¬Ï‡uòúq¸.B« z.'ùñÛo}]2u––É×dQºxïòÝ[ëxYË‘ù¼•pýÒI“”õتYpz¦x>^Ê‘r tx%ÂîKó»ŽEfÀMnðÒh¿l´’IÐ\Ê•?R.Èd§ÑD~»åÇi¯YX:e]ÐYíȽ¹«²£â.%£-÷ÌjrÏÌ©7ˆ9îEËÐuü90£-“Ñ£ ;†òçrÚ‹k诿ûŽîzüñRËû½L[ôŸ¢';ùž{¨¯e½²ßéL_zIŸÛ…DϸºÙm+ä¶qâ´»âÓæÍ%Îúñ}¯ÊÊÎKvîO§³êÎKþ¹¹]›Ÿ+ò· À0ú†ý뿾™^ûû[âz ¸Crçü,µ¨`kMj×!jÕ±w°veqáìàÀ .§¿Ø~”.žÿ2w‡Úð\gœñèb°R+Æ1n¿šÓÚìè ®¡÷Ðó¡~“TMÌ8èn£‹«¢>|?zU†…ï×7ÒÇüîä{»¼cj|f+ªS+’¯açP—¾ çPÉ‚Ù锞ïöV­hÈ75ãü¬"êÛ¤‰žÀÀÆÂbjõébNßlYg¹,nbùÝé”åÙ\CÁeñ¤í{è;¿³uIíÕéÔÑãÇéÈÑ£tèÈÚÀ£c‰,æ×ÌÄoÅ‘¶ÔyÍ«´üœ>Ô°ê—†ã)‹Ü<ª¶s<™‹ŠR¨zu×Ð,K/GÉìÀXq4‹:oœCË[ÞDÒ ŒØHHÇSQî˹݄[2•¦y Ó™%U„;è÷¡‘qš×x|¯¿úÖ¬™TwÖ³¦[wïæ6+œÏ%Üêþ¾zGê ‡[¡£´—ÛÏþæXÛ²q5kSÃTÔ²H@KYÂíБP =wèÇè6Göu¸=WA8«:t¨ôY‹X²#,Ùë[éÒjºs·°¤gèGú’6q>Û9¬:È×ÔþþûÓW³àÕ‘ÈK/Q¦‡ûéñ¡¹GWÖîO½ÌÍ;‘¼þM¦dÈ-ó,½ðXóZ^‡=”š&7w¾±ö£Ç=n£æÊó‘ʺLû%7 y'{“xŸ-Þúç‡Ìu©¢½/õÜMf/¶?‰^ á&w²ÚŲ$ÈŽg@9µž“”TÕ^5 =³o¢ÃÜc2h•ëº]ó>Ü+ 6PÿQMhêðÔïÆð3¬Yðçrzíz¢'Ÿä~à½;¨qƒ´iw jÑà¥W=I{ùyrÆŽn|¿Õ“—ÂÍ…³tßüøãDí°¤Ø*·ÓBnoŒNG½ô5át;¸ç:ŠG-y„Md©1SÑÕ}èì6gÐÆ<ºz}U£µÜk–{—‡xd~6§ÛFæ·#5 ¶4 w>®C·\µ›:´;¥­øú‡èü·ß¦êü'eQ1ÍîÞ~j“×?ì ÑœÐ÷Ìr÷¿¯˜t׳ÜÀ„èÌ•CŒT£é¶ù\” wÖitýßR•Ô4š³ðº«×j›Ýlã‘Jó™3}¹–÷¬î¡÷m>Hg.[ ÜïÏ2ƒÇqçRØå®ÄTfÓ-ü7›ò›ÛwÁµtfsµ}·ÓÉ‚f2Ô¬Z›ÖiFíjl¥ŒTÝEù‘âb1RßÏ£°…ßü@÷FZáÝ…+êÍ‚åÙ\4 ‡öQÍ_GaüH5h Cçq™*ä{8íÁçɪ½_¹3ÉÒD£å_ËR¶ãÿû˜7¤’›¹Íz9ë'T£®ú½ÅªYðâÞÚ‹Kk¸þ†Óµâ{5å8éÖZº³V¹ŸŽ×õ§?žEgø”sWoŸšÔ¯Oõ ?D'“y›Û˜³XæܾԳŒþáîy+ü–ð=¥Ùº†–®£«Ö:FCî‰hgÀq¼‚·„t)õ¬|tUN ª\Z6ó·£(Ð,¨ 5 n6 ˜ÇÁ¼ÒÚYP›!ç·°ÖÖ:WhžöËVØ`ÈäÔÛõÒûV‘jm¹^åÆ3b^0ͳ-‡ÍC!áâ×r‘×ú¢‘:’¯N°\×­™å<£ù~ïç†ó”Œü€vˆ«“~| ˜Gˆ~ù"Q.ðìú3êÏ©šKöšÏ²Ü¬s«f+~³M…ž¯ÓJwa\Οã_uæã|×ý@üÊœ x•ñ²\é„gµ_-ᕯv«'ÖäΉ((7Ü„ Þ½–O;BùÄ¡ß2*I¬Ðr@,ùá~y«òyýÜ´IΡŒ³³'2“ÊŸ¹NH²Úž€—lÛªx› ²šmK¬@2f%ÂXòÚË5~ù–jãOWÍ‚ÛjÀÉšß ÝrVîâ¹@vr#%ö+ÀÎf~ö7{ô;Ê}\³'1«µ-4 ÇC!zã•W¨ã¹çŠ8;Ø­-·³¶æ‡]:Xçô›@mi÷`ïâ¾vUÉðø¼Hôg7Y¼÷ÁBýÖ[oå_#y˜¯ñ 4ˆÈ§7^*¤1}×ÒÈ\"pÛzV“ùâg%‚Ü…ð7ŸK7=YŸ&?úoº ]ŠXÑ`µfžòòËôãÑ£ÔŠG(v;NÊü}jnMºé7m©MD•â<à:–º>j—7ÿåNÿmµÚ¶ZsK¾G¶â¼k•>¼“ÞÏøhÝuóúâ­.žòç´ü[¤e‚/ óš_©0çžñVÌœ©ËŒP=ƒdò“/’—¼‡äé—„ä7iÒGâÝ‹u¤¦Dæ…_È{€¬y ÏyÆŽ[ªK„ezE%Œ¾õ2i*sF¼L/‰¯ ª|·ÓB€°:¼’æ•Áƒµe“'Gµ^FÀfR¢ÝF¼æ¼Síq-‚ôÇãFÈ\g§mó’¯^È-Ÿ‘LÈÁaEA Yð Yðôrkr/3WfËjŒ1N[ÀdîÛ›ç3Œù07¬¾˜ ;tU®ý¥jé¨F3Å`4^³VãÒ ÷üÞÖÓÁð@‡žäѯ^_ÓûïóÈœÂû¶¯çç]dñƦï89‰y.ã‘Ñ4eÊ åŽ“³fõæÐL–ùŽ;¢{âVøÉÉ ¼q3ÏXòWòËÏßF7÷Ê$¯š?÷¬y`—7Öx<4Dgœq]|ñÅütÍX:uà7ö%½÷uíê>¢®è°–o}Ån«ZOS{Г/7ØÒUïÃω‚Ó(º¢yÂu‚9?üQ½{¦y¯'ØÕ•°¶-¼ON<^`å}Ð&T¯­•µ“£<h’ Y@ñwÙ}˜?öÆšÛtÛ¹B§¹v;Â|b"{žb4c¹‡™åu² 7"JÓç^12êzôÐU£i¹ïB;øÑ,ø…äeÕ,Ä ³lºÍ‚®Ð š™ø÷—÷PÉk¾¿æxÜ߬!R½×É“ËÏs^¢aÕa?¹J¢à%ßÈ’ˆ=WüŽ€óó 9ʸSQ³Ñe~úÑNª`æex$ªŒè÷±×ÊziËnš·r"Ñ /ê[~â%oÕx¬¢µbÂ6¯Ö ,•ÚËŽÌQâ:ã…Y†NŽY^/*¿9¹zúGïû‚ù„JæÖEnÅjÍC§g;U; úï­âë;)KLƒ ï¡’×|3ä{W9:Óé'Lº‹ltpð^*Ùø«`—ïæxÜ;ž›ÖNùdâ­؀̉†¬ë‰È{«Ìx–X9•Õó0w=×-uû×ßÑšQ¶–E$tC¶xtÐYÐ g¸‡(,̹°™G‘¨¸˜¶6N~ §9­ŸëÜ â…gR5:Ö´ú³ÛW̼<½‡üðÃ{8D¥§%ê"òGÂ.ípjw¢Ç ÉKÅÏî>^5Jíº½Ñ°Ëwó¨L”ysgÇ*›N[Ä9u‚o×A±“9‘°Öuk›á*™c™—Åós¤ßÈBXqEÔŠi«ØŸžxå»)o¸uRød¥FúºUúQŒ´kþ|šØ¿?µ/Ñ-ôpíÞ¼.¹ä:ŽÙDO?ý¶˜2dˆ˜7‹u^º,ù8ÈÌŽíæç[¡9æùÆ*r¢±cáQ²/ÿ¥S!çÑSt[[Î1—< <µhGhuæß˜5Ó))ôþ“³ø÷rê÷ìûûül€0P'`/ üüóÏŪ3øã lbìð=ƒ¹y„86í‹S;»¬–0sñ°Å EÝ\Aéêö.^RÕõIˆxUz/Y!3d‡Ý Ú, ¯~ÊgtéÎu k5Âu®ÓŸ˜ô5͹װ—¶Ð®ÒwSáat*J{IxÄ$н½úD©ùÐ;´ŽüôdÍiý\ç?¼TiUqÑ£—ÛD˜—·G¨¶HGš3|²Á-f!’—ŠŸÝ}̪P¬LA}¥„R´‡>^:å„©$9ýÀ;¬ù]'ô=4Ž5BºÍBç³Í‚_»…y´÷Ä4“½ú±_ªh”ÛoD©ÆB¶½xd?ˆU#áú |‚è«\ð>¸Ã ~KÂ4¶¨üLæoFyÁM³pZïà誕ǸǸ&â"¹ÏüÙ—®ž2EŒÂÑ9öjõjN $ÊZ6VdZUz÷ùpƒÈÄ èv¦×høð54nT ±úÃiõV Œž»–zÜÐÚ8Ž„ßÕ~ y©VCijl€êw¢d¬üìòæíá“é7OÁKŸ¬ϧV4Òrú•ˆ3[ËŸJòÖ|®ÈKÝR¿ê—ÇËÍm—PÝ;õ!Ñ©ö€H$œVZŪÀ¾(#ú® ¡Á¥|¡YÇy¼ o ]Ó+]Ü1oÞ<ÊÍÃ_è™|m?Ê›vŸ­F5^X÷†PA/DcÆŒ¡‡~XÄ•'‚Õ ²Y@ÏüRR¿u¿0J„¡Xd¯QŽüX›{½è1ã·ßž³ ~zÓªûªâœ4 ú1îÖ´Dç¡ó¹äƒPÉ+d~È{ÄËÓ,[²ß¡ŠŸÝ}TFVYrD6S_ð_ÏþK”Ñæ~g\Yy€²—C;ó»pN¥Y@¼ÕÈØŽ¡Y´8oAÔ{µÊœ(˜óÇ\ׯk³€ç02´”Ì«®¬ç¼´.méÒ¥ )V Ï‘÷Bv~ª÷ ÍÂ=÷¬ùõÇ?<‘h$€ ežÖ®³Qï㕯[ÅÅý¬÷UÅwÝuÇGv¤j©2Dˆû"y”Å •ój¤%ºÝàs»8¶“Á/Ìù!ï/O)ÞY²ß¡¼vy£Çã=„n«LfÞq\Y€g±–ÁX âR回6Ú ØîY¡ó•[¦Ç'·õž:ïÄ¿kð±æ¬ëñ~ÐÀKåF¾=¥‹Žïw¦íž.¿õkÃS3Wæu<ùløØ• Ù‰Ò ãÇ ñü<¬y(¸u‚M™<†506 oñܜҩ.Áeiˆ°…ñ7¢vKHÕÛ¾}\·WæÝ‰¸çãeq©°U|SS¿pÜH¥ÒVÅ…yßÈGo1Átg ååí¥GröQê@EÔVlÎçQfU¤ÝÖÍ@X •íS|õÓt,u.½ûîvÊÎn”àüЧNòówQÏž±JÉü …ºpóÃ2=¯ÿç35÷Ù²e^é;´›†ñØ&=]ßhꇚ–¦mØPçáJ=eC\*㊂XÔáp?/7$ËÀ* éμ1YJHw^áÝä‚~þªÊ~ö6Êò:õì ®ØX—:Ȧå¹ùÔ©å~¥Ûø]ûöQ¯ÁºªÛ¹cûr´ òòbrmo¾gÃZßNâ,2;8 ó‚]?þH½ž}6©Ì9ÿvÏ :¿åÙz„EÇC´sw5:«Á1ª^ÕÜr†au?¿—²…A çy½¬ :Ïy.îè÷ì¯BEUP›7^å¼íÀ±zýÄ$6ž—®ÂR™Ü\ÛƒWýº'(­ŠÌ¥NâÂùœBëèOg]Dÿ´&¥ÔªFùßפ+žåsMiùÕ¢Nu7Škݰ«°zåÃù]Bft~pðøqªý÷¿Óñjð3«åo¨ô̽F³êÍ‹Úω·ßž§j¾Î˶p?ë}UqaÞºFh˜‡ÿš{î“Õ„~Tˆ©Ø0h™ˆJl~貃w<ïØüÞÌ¿#3œ^IíBG¡å’P½@o.’· Ye&U¹´Û˜Ì)ßT|TqÉ&ó=+š;k/¤’ÛtÇê\wè¥ç Âxz©ÈK>Ë÷*ËòàF§½‹êäi¢GŽHcÞ*Kžú÷ŸÈoâs1œ:õ^¥AÞ±@Å×M³0þ.1‚7¶5 Ъ¼Æô(ÓS¥š…Lú-÷§—S[¾g÷àÍ£:ÕNâTÓ,˜ß1òWß\x³ø¨w˜™™Éü‘O™¢ß£›fAÆ[Ëã˜1¿¥Gy$Ð,Pi¼ÂšSÝ4œÆE¹r74 …Å©´vG-j×ä e¤i­q«Ó#ZҬܔÕÒp³lÒ,H÷ó.®íU¼ó=÷þÁ³ûy?Piàý§Ô„Òh;øaª§¥J·ùpÇß²‰îRÜŠ°f!,s S7jȼ໼H×_Ù–.p°Ôܾ.ãÐ}7í¦³§ ŽÑÂí5é¼:ßSÎ?Þˆ¥;h¬¼TP¹Ÿ‡Ëü›©Aù|¼—²»õ¤!Ôe®Ñu6QFè‘Üh’„Dk}¾(<é4'¹:}nIö"wn³òÎÉyYüvÒHx•¯Ôx¨€sª¹6»‘«žþqŽh¸Ã6 zÞÈçvº¯f¾ql'ƒ_€—ÌyXyªÞ1ÊlZpDÙ,è¶2àyŸqãÆ ìòÆoW± ²×òqªÏ¢ÒöÙÁ.ÍeFæ‘ÞÈ{hqÌußé^~dìxY o/9®lŽô2j§ÅTɬÊ'«ÌºAd6§·Â)oüæ‡/3Ì|u‚VP—ÇùË_D:ÕóºÁ¯Ì~ ¿™vš~„رoß>­wïÞ÷Bá÷þýû³ÑØ»w¯vÿý÷kmÚ´ÑÒÓÓµfÍši<ð€vàÀ#…Žp&‡iâĉÆYoHFg0«q OX}.Ø8vš¼Ç•"q†Hf™í€k×¹qzN¹¢àá‡÷‹°_?<·žÔ§Ï_|U‰²X ñä“"tÊ'ؽc"q&n5ò/RuJt#'”Ä[ŸÃ|§ò(ó#Ö|¨È@Þy5´sz_ª<òÂuW~Hʺì”ç~dœä¶Â/o¯ÀªýC~®å í‡Ýj«ÌvùH™ß|óMq^U†íà–7~ò×à‡o–J^ä‰ÓóºÁÌ~ÔÎÂ/~ñ í¼óÎÓ>ùäAø}Ýu×g£ñå—_j7Þx£öüCûæ›o´ÿûßZëÖ­µßüæ7F øoû›¶sçÎR*,,4ÎzC²: æãTxð"õÂ.(òãkŸÿëÜà$§„ÓÇÄéz©I2Doü¨tƒN‰Å"ûøñX1ñ‘/Ïà:¯ø-ÃUï8E¬<Ð;X‰”ùñ¡/2¯°Í6Y’–á:åGí3oþ 9•ÇDÊy*Ã)¼.}4“Ý2È—srÄÛàçæïGõ±5·«ïOÿ†50X-¥—¹è¢9?½.uòU£rÇ ò³tÝ `‰û"ôŠÈcµûøûèõyËš~\´ˆeLBgaÍš5‚ñÿþ÷?#FÓ>ýôS·víZ#ƳgÏÖªU«¦?~܈A¦’öÎ;‘ËÃü¢¼; €µò85 €ÎÏ¿F nr±~LôÎÔŽòC& %uô-;òIIci“ÞÈxy¯Ð—nªŸÕ/¬ïX÷¢Ë™H™Ñèåò"?,£*ùzFv†¬²âH¤œ§2œòAtp2Ád~gVèï+úc‹´æ„Ynë¹²†Ü_à½'g9~¿Ë-¯ôEvFŠnuC¼¿8áT>œ0v`¾¸ÎN¶ŠBnŽ1û†àŽ0 ¼è¢‹Œ>ò÷É'Ÿ1î`Á„1E•*UŒ÷ß?Õ¯_Ÿ.¸àš4iY÷:?cFT½íÖš¸a0~ëàÆÄq/ùD†rØuFyBøt·3„”Ø»û`²¾úé|üȃ¾péÕù!„Ÿy¬% [¶À'E¤¼ñìÏ.Ëf,eÏË):~†ÑtšþðNëvŒ‘”Ok©ºxÔMUöèÑ#†ò(nœI·ÓLÚ˜;SßúÓíÊË£.¡Hÿác˜þ./}gßäçë©ÙùXxeð`º>3“êÞ]„ó¼ÔwÂßßš( x±‹$B«O‰²@fá~–¤3õzüúœ?A0 •´ŒŸ¡Qv¶°ºm9¢7’‹üÜÅÏnÍ'ø.A¼°Î5Q_¦µsGÓäáo‹ÇÓGŒ ^!½ÍDˆc™»’"ŸQÊ —ÞÜßv5Âû`™üjÕ„Üd„Ð2Eo ä†ðtH$%bé¤Äü¹ë™—Z)n`"¨5O/dUqJu¢Ù-·¾|¾P{"™“Ìv#G̼£Ñpþ„ ¨ï4·«’Iw:ÂiªaMî=“|F¾ÜýæŸz8–‰?k|l*{ü#–¥€fúž©³Kdë³$“ ¦/Ön£™Ú’±ï8j¬Óæ2Ðk›‡v^¯C¦ü4ij¬Sqñh]ðˆà…ÐT×Åú¼É¾›¡ ü‘xâ‰'ÄN´lÙ2ÑY€¡¢<ŠÔFmÙ]tÑEÂîáØ±cF¬è0À€Ò vrŸŠ„ªv¬ˆU kœ¹Òé¶²²J+h¤mwDXç[ß!*“Ì¿üT@Cå´æ 7ÖK#”êM¢ïm×D›×³Ë8ÜÃéã#;æÆÇ_͘•dm\‘÷øø[W3Ài: v (Ø!¡„*ît„xOz†EÑ ck÷5Šõóˆ³;²î  —=¬î(BsÙ“¤üÃeÔ… ñÖ´‘Dsø ªÊœ,Ó½"<¸—uƒî'§âxüοãÛ­1Özbw],Ï›L¸u¢öYàѾ '´hÑ‚^{í5zðÁéÀF¬Ž:uêÐ_þòúÝï~gÄDãСCB%š‘‘!Ô¡Õ«W7Ψ±dɺì²Ëèûï¿·]#]\\,Hû,4kÖ,aû,H˜×®ªõífX׺;Á/o¯ˆU™Ö·råt¡â–³î¹çmš6 SyL_1éëÑÓéjG#(÷Éo©W¯Ÿrœ;äÚøÝ\$·qÀM7ÝDƽ•°üÎtFÝM[¦«:ŸA­›7ç¦Ï›GFÏÇ Wqn¦‰oJ]hðmWѯ»µ¢Ö™™Ô”Ë¡”÷„VŠøi±[e•P1•hïÑôÅݨú¦µ®ÎdüBåìIî‘“ó ýõ¯÷”ÊÎ9ÅòÃEò4eÊ 1íàö~ãÍÛS²\<7~QÚ–Ò÷ 8í â´#©°Ã7[·R+n£ä=¬@YÈeñ$¿Oì1öhV^^ÔÞycæÐ¸!Û"-nûJ$±c-¦×Ì{Ïà.´hJÃn<·C+Õ>©)«éÓ—_¦‹ï¾;"Þ¼cc,yc}6¯8UêWÒIIÇÏ>û̈ф±#✠Ñk¹øâ‹µnݺiGŽx³P}á…4îPˆ©¯½¤SU³àç:7øá¥ KWÆ òG†³ ÃÆ[o|CÙ߯çâÛ)NŽÆ¸r‹‘@"5 v#~óh÷ ?D‚ª_3L¬£§'‡N(å½bº® *lX‚šèû¼¼¨¼ÝÄ”ÍÔ‰ªó1F¬i"þR¦èzmíÄiëç~ MztŽÍï'‹GOf^­øñùüÞä3Ê´ed…œRkqºÙ²«ke¼@©´Â:ú´–7ërëÓ—Ös‰îïE…/eAhä‘y‹²/&€TZB»7Ѧ1“h7|À)O*|kü gÏž´cÇa`Ä Ãšwß}Woß¾®¾újš1c]xá…B£pÍ5×Paa!½óÎ;T£F ‘hР0äõР\rÉ%”žž.Œ¿zè!º›{‰ãÇ7R»#Ñ;8J˜{‰€[ÑO¯Ò/o¯ð#ƒÊµ*̧̮ŒÍçíó =õêåƒaB¥“ý®€‘oÙ²EìLhîÙ«vÝ[Ë„±ÚÓO/ ¡C¯‰ÛàÅ},7*gÃÜÈð³¼ÉÏÒFI˜G&›Q¡É*\¾¯ÔxË)ߘŸIÓP˜gMaêÁ„}ßt³6~qƈˆ;®éÏç`:©©|®£Í}T÷w’étwQýá;x´Û–…ËŸÛ´,ÝKXGëf·Ó‡K¾¦Å+WÒe;Òçb?ÌÚ6þØÓ”áéïõ×g#aÕ²lؼ›>úü0ß²˜rô.­ÛÐ%·à|ÿعti÷LpŸ…ËÃZB•O´$fÁIÓ,ØdéŽ;îÐjÖ¬)¿Í›2mܸQôTÐ3âXEH ÌŸ?_ëСƒvÆgÃFìÝðüóÏG,­ô‚Š Y@/|Ò¤¥¥iÜzç~y{5Öqãe†uÏytF©1’\à ovš…‘å6 m˜ðN-=zct„ÝÍ#7̹Ëç 8PœÓ £¤L1×h]h…Ÿüð§YHçã¦zú , ³[ûm¾ß3?1Ÿm7"ZÄ„4),Ÿù7zBíOGʲ—R¨†ˆ7ß_%S YÐñÒýcJß_,ä´ ÒOùô‹Ožý‡¸?FÔ!áÊÂ/ùµ0Ûï¼Ã?:öÔ^)ÏßkaVù%µa“Y^Bí)…Fsl¶~Ò€ÊAÌê¯CôÌh† щu"\ÚJØ9›yþ¡‰,C͵ÿû:ƒ~?º9=uÃRºòü½¶.aáæªgÿM´"ì rZœÍÀÁË7,G+–}ÉgÍè·ÿÍ¡™t;õ¦×ŒðjN5‰i?{'šÂ|¬ŠYì*u{çO;Eþ@É÷w¦ég]Mìü7ÿâæ…å’jù…W\AW6lèè\¥nZ :p0•êÔ:IÕÄ÷_DzMhà'wÑßÚŽ¦f©;©fÆ ª sØvì-=|˜†û­P^aŸˆL‹#L fú…8Òqy‡”^µ*}~° X7„f´Emkn£ÂÂÊÈ(aþáûïbþ׬^M_Š£ðs¥ðsý/+‹>þáºwoÄ3a®ßµ€ÆGLQ¤ò5›Z·¦¦|ï]ÇÓ56ˆi(_…º•é=>߈ÏÛaÅÑ,ê¼q-oyuJ/0bOlã|kÎù†²Ø€~E[(WÄ#ï&ׯO}kÖÇVl;q‚šoÝý>`´h쳋ÓôiÂï„Ó42Ò×BtìX U«¦—ë±æs»N²ÜÌ»Oè—ô=Å),õ¤V-º²štÂ쌃EEt€Ëý–ð:)zœp—ô­8†Ÿë~£}oƒãÜçç$­ U­–BUùÊeœ§¹ nIà¬m-ÝÃårµ¨;È î€s½Áÿg3¿uü€ã¢“'B”ZEüT0§ÙWr’zq›dÍç·Î8ƒÎNKã|„Áo4¼ÜgÛÉ“Ô|ÿ~£­2¦V!3—‹F©¸‹È»潚ßÏE‡Ñò3ºQ§*_è' ìbÞ½Š..¼“ƒükó;ãÎBàH*ªkd“jÉœ•ì–S¹‘Þ^É ~ﻂÎiwÓ™¥ábºD{.Õ^  µõ¦†Y¥ÉŸ_ŽÒGò¼Š’1bòšÑSØ÷ž´Ùú’bç0l€…çÃï¥F¸˜~"âUÆ\â òûÎ+Éw!Ë¢Ì{/e,ïÃ+™åNF=‘„g/Ü ¡—g´“çE™õò|*µ|ø¥S¥~.ª“¨YhÞB½œÊ¬Y¨FÕ©!5á‘ôwÆYnš…V­S¢ÜÜ*ÍB ó*ÑÞ§Y¹….j%V~U…rŸ®Â²Óè{·Ûº„…f¡ç³¨ûÏX˜Âc•fÁŒ‚o«Ò„—ÓéÁë7ÓOÎR/ÛÅ£•^¯¾*zÏXdi^™ÎwjÇùC–üÁÈ£Fn¹ô-*. Ë øú¶,Ó:šÒ9‹ú¶l)Ò9iBŵhö¿ëÒ-W阮uyäc`óÎúhIuº¬Å6Z±éLºæœtfH7±‘£}#©TΓWø—¾Ð2 ©YØùcýg}Cº²í.Ê8vjnÔ9pãI×·ñÈíSɹ¬â½‰©öÌ,ä|ÚLÍ©aãTÚW#•iFWÕØJ­ÍeƒGs½x„•.š…Â~ÛÅ-©]ÚFÊH‰.?•aÍʢᾙëŠyôï„ ÇªÐ¢tUõMÔºZ¸œ^4 GŠSéÛÕè§MŽQ ~ŸÖc3Ìçö§ Í‚”{/}Ëu ï¹דµ4šËÓëÕ³U›q˜ó`§ÐTe>é~.±f™!Å<Ú½enjŒx¡QعWß©Uµ(³qcª–’BÓ¡?c>ºŠ˜UóR±ò6û#PAòõÂ[÷`è,§N2cnÐÎØ†ŽØ@HÆa~]ÎÛ©žÉi¾ÑšRf;Ùd¼î×B-;>ÒnAÊ8»ûæ{JCÊÆG;ÀßÞ°/1"ÂÈRæÍçå ^^l!ìd `dæ›os™Q›a=gæ jBõ=kEÌ­ /æO–g Ê«ÙfCUo½äµSH˜µ¼ X4 ’/x‘Ù /ÏÄÂ;ßL;Í?JåDywkEQU3båív<ïÆ…T7âÁ®ŒmÄJ7ØÝ¼äÇ_~dUÏoŽ3ÿ¶ãkóµv×J8Ì®¶’ ;;¡­[£ëŲeËĈšAÀICXÖÀs´±ÔØ(¡~¨ê͎ןSŒHÝN¸áþ†ã[$ÔÝk©º˜†ìÄ-Ò|,õ(»0u2jòGäÓ!Ú-´_hÇTímäø~ý8ÏÑ6b_”Žü»: ä÷±ÍÐx¨È©m<%¡÷*ÍB°PîHYz"Šu·11:·Ýª²k¬ŽgpŽúE<×([ \{q dW/f̀󹄆ˆÕ†ÓâØ:¢.r‚çˆM³`znC³€óãæç /áÄ’Nóõ8¯ç(E«JM•í òM¿Oxù¶¢îëB8’ÛŽ«N´8oq·Š@³@X(¯¥÷EO}IÞ‚CB«1â=œ2+Ô…êΑΎ¼"BÃàw5@YàdZ´½…RÙfd?O=é_÷5 rÀn.ÞV;¡Þ½{Ó½w]Ä#Òî4¢W&½2x°ÐüƒÏŽp³ÜêèQ1ò]Æõ ayŒfQzd—{x7ázÀr >ÜÖ6§)ÇÃÍuJHÿü œÌLj‡;ì‡ò¦ñW¶Ÿ) §súE¹Ãî7øŒ¯7Óqj k*¹-“£z«Æ¡ÙöAR¨ø(ÝN3iíôÅÊö „6¾`¬ù{*®™7bt–¢m¼6ç‘JQÿƒíž}e Ú4” |3‰ùówQvv#ÊÏßE={z7‚s“IòTiP¡ÒD…ãºø{µÖ÷#s²ÒÚÁ._$ï¼¼½”“S/îw '¦T°räË/«2ïã 5ç¯=Ÿe!¸ÉHMý‚Þ}w»¸¯ÛýÀª]L!ÉÕ‡ïl¤a7î§Xæ®]뉸å nÙ²…233ŇÇèF8yã V¿X?œø(ö9N|Óù¯M¦ÜÑSþ$Tú¯éÌÀçfú0Ñeç Mø¬;¢ ™ªl%K^ø'5Ϲ–0‚O¸ÎóùY²ùYòùYzò³`¢›)G9æâ_f~^ÓùQ]¸Æ8ŠÚÈþÜùд|Ä PMz¯²D££XRYÿ±„³¼HNß̃ížhÂk ]Õ˜x¨f¾ ¸ V*<¨4ÝT§fø•ÙkÞÅ“f¨î™·{’Ç+¼ÕF¥“'/ÇN÷«êÔÉã4R@ŸÂ[+cKeL[©ù†1ÝÄÄýÝRõ~¥k™\ž– ¥íÉËÓnç¸ÛLt#—±™Ùt.d(h&‚+u9m†ÐìZ=¸É¾fŠÐ+_lÎfÞ¤M7ZëM&«ÌÖÝ&­SvÙ§FÀ õ ù•Á|PÏœ€¶ñé§Ùœ À±•½ê9b5Â,+¸MCšŸH†f!Þž¨LÑ|¡ê¼€6o~'în,2{É»DöÊ­Ú‰hÞ73½E3f|M}úœ‹Kb†äVr>ý„FÓ×Âå67QòRVÓ»Ïÿ‡²sºF¹4—ÀÈ´göMTHm©Ô‘La V‹~J—ÐÝ´ƒÇ“'BÛhüøñTÏä„,@Ùaï¾}”““ƒ¯A)àhé–»ï¦Ñ/¿Ì#Þ0¤Ã¸Z5êѦiÔ¢I1ýïÛ¯©ûSO•ºƒ³¹&þ˜r§-áó3)D½éÞÛ:ÐÀ7Þàz?‹á¾9t,&͂Ć=…´pcWå¼ôWW™Íظ#†OlB£îÝaëŠiþ81Þ ý!Rn¸vÑ,¯Jk4¦vu¾§Œªxû‘0»ã/¢t:ÄÜëÐZúWŸ›ùVš…SÈf!V'0Ö%zf„ù¾#Ò`4m·ŒÈ/üÊì5ïüòµÂI;^¡PÛóñ ^¹‘ž;.¥2É_@CÍBe£±Lf-Ž¡qÐ˦N86Šñ[¿&\vq<Û8‡È|ãB#‘ Œnqy?¯£]hP70g¯ÛÓ„ï%‹fWóý–{'€—Þ^Ú™KÊ“!·_™+ ä73Ð,$ÉÐ,HIJ@·ÒÈEÿs[ Ýצ}BOö€ÖÑrjË#V,TYioؼ›>úü0uïr† [¡/Y²—È©G£çÖ¥7´qvð“wñ¬†k AxéJM][ª9xõÕ•tçØÚ%qš ³ÜçŸܳ幛F%X QñMÐ_|AÆ s]±vÕQz²ï&z|z j×Ö :¶1o¶n¥VÍš•.ìŸû,ÑÏæ‘ûvš:bHÄÒÁ…Ë–Q÷AƒøÂr‚yý…“'Ó•]º«,òÃíÁcÙ×[ïg…jEÇúP ­Ý²Y”åîÝáÁrï… ÅJ ¹"(Þ:dê†WÞ^Úsš† ½óö?2W«!*ñ¦Lv=}늆9NrkÃ(#d¤A¨u8ñpÚ”IÂÏóùÍ +îºë.¾>ýþìø9µ¨ç^mh»{Tä²è&ò'§ßjKÓÄjŽ#n¢K.¹ÄóΛ•¦Úݺ6 ‰‚—žk¬ˆ•·]OßÜ[&J){TAOkoÉcìG€óæ} üÈì'-1Y<}7÷-‹:ií)½T+`ç°Fìðf);¼ÁYM Jžf·g–1[ZËëšaàÔ@¢ßŸ¿Dœíîátïò†“lRóâwo…Ó…‚}N!Í‚ÝhÚ + Ò©s﬈¬šíFv+œ4?üÐÔs~xÍ;ÜﳉïÓož‚ÕwÖ½äÝ0ŸÎåôåô÷sú¯ØÈñx Á£‹Éô䓉±Y0?c,–Övy”Ìr ùHôûsâgmGTm—‘sAѽ¹¾,nG»f±»,:É{¬æH§ö¥{¡­£gž~ÚÓŠ–ÊŽ¤jöíÛ§õîÝ[cÆ‚ð{ÿþýÆY5ºuë&z/fºõÖ[³:bákÅ©¨Yˆu¾Ûm¥ƒ$Œ¢­vfØ=›“MƒŸüð’VŽ€Ò9aG i/ö ï2íA)Î;»Âµî=/ ù|.åkÃþ€ymщx¹=£ì®—o€òE¢ßŸŠFΨ«‹ó¸>àd‚H´K&$úY 'Ùœl:ÐîÄ¢ ¬LßL;ÍB\«!n¿ývZµj}ðÁ‚ð»OŸ>ÆY{À{×Î;K µfÄÊ÷TV`eVˆ®±Gj·xºÐ* ”qV×Ó hœ¬ë11‡˜ãäJféà åÛRßm…ƒÙ­¬¾¶B£‡§¢e'OÒ€Q£øeYǦÕ,Ó )S„«h1Œ°PF׎ÔéŽ,šãá’úkêIYí{0o#þ*20íFÎ=÷âú>¢´QµæÕPv”È•NÐbd°¼ížÝjŽD¯h©”0: ¾±fÍÑ ùßÿþgÄhÚ§Ÿ~*âÖ®]kÄDš…ÁƒGш•¯§¢fÁo9Š@hso™?ï®6 f›xN3óÖGüÑ6 ~d^œ·@O샠=7nÿŒÖlÌž=Ûàì-?$¤Ì3gê¡“ì~ø~òCÅÛîz?|T<ØÙÅŠæ~Çuc¹¨S_͘åa±#¥pšõFêȶÀëÈÙNf¿eQo;"í%üÖ+¯ð’Ï^Ò¨,™+ Ü4 œe±{²ZíÚµ£0÷ÒK/GÑ@g¡~ýúZ½zõ´sÎ9G{衇´ƒgcçkEeî,¨*ŸP°§½0ŸücA3Iw®m1B48<‰p7‹† * œò*3ÜÀâz¸…U¹±U¹•…ñáÒ¥KçVJÞ^óÀíÀÇ­³à—/ yÛñ”°ãmw½W¾*ðnUÆÁ±×{qY>gødã ¨/˜:ôò±Ã=ìê+¦öp „2ÎŽTuÇh[äoU[ yu9ä|kzxùm N5¸ub6p|ê©§èå—_¦õë±±MmÚ´¡ßýîwÂ`D…©S§RË–-©qãÆôÕW_‰tPgÿóŸÿçcå[\\,HŽÍš5«tޱ+}ñÖZúÙÓwGöðêÞvuÿN­¾XEQkú„6±a”·l/®²9Ÿßão@£*UDžýرúZË¢‹vþƒ–7ù%uJ >Ûa׉ÔkëÖèújâ]p°¤„joÞìÝÀñ‰'ž½ 'Z¶l™6jÔ(?àÆUað‡_=z´qäŽÏ?ÿ\ð\ntóbåk'÷é`àèFóéçÊxIÒÕ-–$B«€°‹oN·†ÚŠ^û jgNãD^ 1ág5Š·sã—¤Ì^åñC~òCEv2%CÖ€’OÒr¢\8K²–•“¨XË¢”ùj­<÷׸¯7Ø*7Úª¶%^òã*;¨Kjò½trÏž=‚œÐ¢E zíµ×èÁ¤±:êÔ©CùË_„À pû´´4z•G‡·Þz+½ôÒK1ñ=5 'C!zü©§è¢öí•Îa>ý,D÷ý^£—ßHÚ±‘˜þñÇ4pút:iðÍd‚»"ávüxážvźt{n[zmÄ:êÔöˆH·ò«*”ûtÕoe5×—mZ!5 '(ЍU§µ<ª)ŠÒ,,äL6o—Ø‘Üs’jSwzðú úÉY:_•{X?š…u[NÐ+ïgÒµl§—Õ§Û/ßA‡«Õ£v5·SF•cF*~4 ‡Ž¥‡Qš5ißÁÚ4ï¿uéæÎ›¨Iu^;ijV­Mk4£v5¶RFj¸<žLSƨØkÒ¨5昔BÇ}iŠxd{”Û¶B.g«8Hs-2×¥:J?åt¨¨•OµhKg„~BÍkàzr,Jñã‘TúlM ºèœ#T»†¾xØŒ­»wÓ6ý@wR!K\ï`rßÌ27ŠA2}ÿ~¸s§XªŒr“b³suQöx:šJ_m¬Nçµ,¢šéÑ2ÛŽ§æ6DËlý<ªÑ¦ï3¨a£Ú‘ÚŠÚUý–2RÔuÔŒ@³`…X ?ûì3#FF‰ˆócˆøå—_Šk-Z$ŽÅWοTV›i¬7Æ ü¶›KóÊs™0l”ssVC(¯¼Í2« ¬poý¾z¯_Sµü|oó«N¼Ä™ç±ýu¼2ˆ3Ïeˆ÷Hï•ñ¼ksùÒ õeL?6×/¼QŸˆ>RÖ«È:¾G"ʧÙ^Âo~$¢ÁïxìFœxWÈo¦gÍ‚ôìÙ“vìØQºôqÀ€bùλï¾+Ž·oßNW_}5͘1ƒ.¼ðBúöÛoiÖ¬Y”Í£³úõëw è!]¦§§Ó²eËÄr<À¯TöM™ aðê×ns;`y“j3!Õ³ûÉ;¾–,aÙ7TLÌ”Àl%—…üþÝ·avâsæM¥Ò©>¾¤òÞ£®]õ|R¹ßœ\úª´<éâqÍxz|z§WÄ*¸¹ Pyà÷]£<.YQHä\Ë#ZöÑÙ´•`«"ëÇyL_ÓÀo¤Ésçóï³™¶Ó4‹Kk3à¾zÀÈQ\^KÄRh,#4/Œ®ƒú=fÏžM7ß|3ÿNœê«ñ¶1Öú¶%—ô~d>!¿™ ×,{÷îÕî¸ã­fÍš‚ðÛ¼yÒÆEO=J`Ë–-ÚW\¡yæ™ZµjÕ´Ÿþô§ZNNŽàc†_/85 ɲYdÝ\Å/TÏž¨üˆG³à,wBY¼UÛ½ó˜U$2—Gý7׎0×Zi!¦tjÏez¹(×vöVÛlz†2ꄪZÓ”âmc¬õ_7¨;‘TÍBEFe×,^WFøÕ,Ø!^Í‚ÌNpB¡ ¸Zb¾}ãæëE³ Ú2Û ñj°ƒ,YÔYh°Š¨—¬]„Õ í(%´žì}#=ûê«Ä>»N¿Ð#P¥°ŽÚ³5sT9¦‹¨‡~YIÄÛÆ$J³PÙ‘TÍBEÆ©¨Yˆ…·—¹´Dɬâ“(ÞrÔ¼<=L_ä‹ÜT*Bi³ësXóß«ÍB€NåqĈwJË-Â1cÆ”ÎýKM@„fUÛŸ[÷;Pi$bÝ´È zý Ûö¨Ú);ȼ@+Ìõß¼©\€0ÍÂ)¤Yˆ•·Û\Z¢dŽ×EµH~3gõîØ|–òçåí¢œœF¼ý<‡u„dÎ?޵°ƒ¹8AŽîgÌøJ›4 sîöÏüh¼8™ª¨ö;ɰ¹ †›f!.GRN}`TŒyK„vÀ9¬HÑxD 8p ã5§Üœ\ÌŽ®`/Žpç âe\>à @,€#qàÎ;ûРAX¡ÐœæÍƒsõhÈѹj”n­ßº‘›³:•cºx(VGV’éÐ*@ì¦!|ß„d©™“ÅÛŽ¯®Â@%üÑãQrÔR* 46ÝË_«Ö• •YÊšŒi'Þ³VPVo>™ lÌI-³=X©`–X6¿î:®“ac<Ôµsùÿ¦P ­Ý²9jªÑOýîØ±oBë«W@ 0Nž<)–ÈcY¼WÃÉDµ‹‰âSYá6 t|"™.Y¼U«,üÌ#†Ó¶á£×h-ÝCÇR¿Öĉž£—yPÖ…DùåØ˜_@-G0óbÀB&tËÍótî,ü‡cz?²]ºtá_a¨l ìÊêóÏ¿Gä4Š{þ?@»Ë>‰j“ÙvW… ³@K^ø'u͹Ö8Š]BYtïÔ‡ÄÈ ÑFC2òòöRNN½„#9ñöš÷n#¤ßÙHÃnÜO/ð=ºvņÙx‡Ð,ˆ|u>‚Ú}-wŽŠnƒbqì´$ou}àã(~ #˲H/HT£ªãÉ”ûTƒ[gÐY¨ŒÆ§»# ðT®fU®c±ì ¾ñ—Nš¤\~euQmgôp+ð#º=¡|'ÞòB7`¹™\¾fF2ò#Àé½ éÛ7KÂ2ÇŽ”ÂÔX¹4òÈâÂ]4B§ªßúq+¦åŽ.œý|œŒ~㞉©SÈðA$SîSò›‰P…@³àÉý‰æ^³Óf$ÖQrïÞ½…C/;³| &g£9Š€“YLy$Š/àÄ;Þé™×i%çóxð%޹RS6x^ €yênÍö3ígZ1a‚âWL+iáäÉt¥i*Ân«rlï5:|xigiÃfþð~˜ºw9ƒZ7o âœ`mö2m¿ô¶n²‰÷鈃‡SínÝ‚iˆD!^uµ’ÅÛëo0ðáÊ.ò ¡Êàqfƒ£ÁƒÇyâí2^øßú$PGjÊAŠ]"Qyïg7½T°3 µƒŸ²ë—7ÒéF€¦©…O ¿|ßÏ5„VPôô˹âx©~ hSÈ8Çòœ’Ó4Ö©Ó‘‚iˆ`é¤/¾P§ÛbT“))_ðñ&æÝ4!2KYg¿¸‡Þùý‡4ŠG-[ÚX9A¥"…f¡˜ÚRÐzÓ&7‰Êûd–THf™ã€í†lfo•~á¤Y`œ9`ä8®»ÑÓ/ª«RSVÓ¦÷Þ£¦S~^´§§3ÍB YH_;¿ðܤ8òÆh×zuHY­#X“0â€QäÔG+ÓJyÀˆ£!ó}ãÍ£Dñ À+’YæPg½hüBúgAhÜC¥­ˆn‡ÎdzgÏ6RØÃ‹öôt…üfÚiß<—`ÞÐŒ”þ‹¥]j`>ÚŒNâØ 6iÇã…ðö»ò^ñ"ÄÊ#õeÚ”ŸOo?ý4eQuúÿöÎ>Š"ûão$È_9E¹I¢È Š‹ëÁÙÕõ¯Àr,+‡„?x±¨D9þ"¢Dä2€xpÿWA”B¢$Á AˆB€$±ô¿~ÕÝÌLOÏLÏd¦ãûòytwu¥¦{zªºêÕ«÷âéMêOùr|Í4( Ø­–P«õ\­ï°IÆØ8PðÐ^?˽B{²KîõìÙÓoû[ 4C3‚-ÛY‡§!$œ*¿p•ÊrQ]øÆŽzŒVLigê&9µßÆqÔa@-z1Ÿ^_*ÝÒæäàÓÀÊ*®†XâJ(-m.¯–ªï(œ¿†1ÃßoÓ‡åõRjO­‹«.×áz½wo-1P—‡|]tþÑQ°Þ¾0Þáiž†y¹®F|2l,B$‹4ØbçË™!UƒâïæÎ]'Êqùªï(Ôß5ÃøÃ×ojvµþ”ÏKa¨×ééj‚m°,6U½(–8²f!ä庖‡PÌÞ0•G³°8-Ÿ¦M(¥Ôôb<P¡3°2û>Âéža‰· h¡4èÓ}9¬x%‹Š´¼\Ñ /š)ÞLåÓ~¶¢€ž{8^ì•ÿþÖ,°fAêr]ËóWv EºÖBydf†ÞÀÊx͸¦pùŸg˜pjíž™èƺ÷Ó`—+z.‹ ¾>«u š6X ú;Ó›f ™°ˆAæ!1#F`;_ŒÂk`…ù\xxTÕK<¶°k@:ÃØ²†îÆÀºgfR²Ã!uqº´#o¤»æ³"Õ>ž,µð¢ðV,Ê* °¬‚9sÜâ1Øa¹vp  U«Ø`ñrÀƼ(QùBõÂÔ­š·rÍ^Ú¢9¢ââ"Ù@µ°5k‚½f~Á´+h¼6mÚ$ËÛºukH¿ † 5‡N–ÐvÑØWãFuîKHQíÚ”C=§N¥ÑÑÒ);¶©¢ã]§k×Kù| ÊX÷Ûor[tmeQ'Å ŸÊäg¨Úkú·Þä1p®dP‰×UžUIPè«&‚mÿpgq£û`–:úÃ_¹f/mÑÑêˆCŸƒ4›‹,Ï5›/¢=zÈòÚ¶mòï‚aB~“º6[»Ö‡þóŸ4zôhš>}ºì[y»–í¶mÛBò’Ç ½oß¾Ú‘ ¢Ý£)„M†ëÖxÍ8fB8H8 ØÂU¶7(#V ¢\ל=YFCÿG¡/R|ƒ³A‡±-8xŒF!OKq”C±Ô’è{zµ×XúS¢Ã-¼lRÝCòo@±ùjvËÞ4da;zû¯+©ùõGiÌ—_ÒÄÝqâŒj@™"Æa·‰~ô¢T×ʉU))T'yÍÉ9ÞˆZ1•²ïEIÕ µT† =E¥¥Ô 3“ªP gð2ÚMƒÅ^5™Ã“dÑ4®[W;2§¸¬ŒظѽN é%:Ïì©&ÒsDíH¢y‰e4ÀOYFŠDÙ DÙWÑÃtŽ–ÓÍôªAÿG«Z´ :•+k¹¼sæüy:}æ •œ>M™E×Ñ0q-3ŵÜqÓTTäqÍVËeÄ;ó?ÿ¡kÄKˆ CD8 ØÂUv¨  \½)®¦Î¦y‚LEie'ÂÒº~¦kz0’kò6S+[ã¹@$”×ÉÂâKBÂÙŠ”·žè×O•Iå©'\×B+¼t’5 !×,èÑ'–Ñw;é’f¡J%¢Þihñ„BJläœÛ´¢Yظã=1m•Q"•ÐxªIĨãþÛ#ÔöÖÊ2¼lþÑZ”Pë(ÅU¾ ÿ£YøiË:·ê3j(Ãßž¥ÃâÓ®¦RÊã³ëÅÿoÒ:Oµè :ê©YâkQV©(å$ˆÿãD9 .0+ÀÍUHÔE=„³ø=›iº ©*ä]CŸÓýâßçbD/^&@©‰ Qºj~~ß¿‰št ÒŽ<ѯ¹2Uۻŕ¯£JtÂo½Bk¢ÃÇýBÿç^×Jĵx»f_å2N(-¦7ÍwÄŽ…@ÊÅ<_ áf]ËFgÛ¯oå ö [Ä ü¹çzˆœîþæÎ]G?îÛŸB ×ìÚyªQC\kÊó"u¾è<ô×nÚ+޶Цð¢è0èAlÑišÛ¿? (Gð† 5óׯ§Á HcCý7 ô4P_HM¹‡—nåQ6eOȤ¤FǵTOÌÊõõÛÏ+Œ‘˜ ´ÂL¢þwB]9›àG¯ô4ºQ ô`ÑþùEȃBŒ„^={Ò³}dùšwN––Ò5?žiˆcÇŽ)}úôQDÁR°üøqí¬'………蘘Šk³ó³gÏÖÎZƒ§!œZ.Ö<¯³nV/;-Í¿¯c¹È£úPÀ3vh¢ªÕm´ô³`…`®Yÿ>ÒÒV\úLÑÙ×¥—÷í·ßZ.—a®f¿}=mêÔ©ò7:†­þ[·Ò˜•ë còEÎ7§•Û(Sy²{ºø›Jfú7êúC™™Jk‡Cƒˆ¼'Ú½½ äšwôw¦·iñxƒ§K—.J³fÍ”¬¬,)ØïÖ­›vÖ“ .(t“qãÆ)U«VUJJJ´\øÑ‘²páB·|¥¥¥ÚYkpgÁIø¯YuœK-DEΖs¨Éâ\f0œK¥W~½pv8’Å6Cf5(Ÿ¡—­Ï»•¦Âáú5þöCE åªyw„öÊ+¯ˆüz' º²ÝA‡ž)?aë,äææÊ‚7oÞ¬¥(ʦM›dZ~~¾–⟖-[*ýû÷׎TPÆŠ+´£àà΂“p^3F MhŽü®CahՔºÇËñ=»Æº`˜ŠL¸Ú½\hý…£G¢à¼²BSâp4ƒJ²¥Nc … ý,`Í.lþð‡?h)DíÚµ“iYYYZŠo²³³iÇŽ¦óËÆ £ZµjQ›6mh¼~y¬ÁwçìÙ³ÒNÁU˜ð³/ŸÖQªtØ‘O1OrIOðõ–D7ËãÖâx¥ÌíFTj§´MñÿåöÆuê ÃÃ|êÖÍ¿Ÿƒýû Äÿîí¹îÅÑŸS¥gŸ}–V¯Þ önòê  Aw:Dµk×ÖŽœ 笀Sbb"ÝqÇZŠÊ„ héÒ¥ô¯ýKÆ(úé§iÒ¤IÚYs&Ož,;*ºÔ«WO;ĸšý‹èŒ˜Fg{h; ¤ïE”ãpˆýk„$QÅÑ#Q×°bÿ¨ø{X8ërXtö’jXS\|@nà ¼C²«g†)?G~. V4ˆZˆA]+qŒíQ·Š×¬Q­ ]¤vñA‘ÃÓÁ¼¥ZqªäËA>,= ’ŸH‘h ð²vj2„|!ä}JO/¦áÃë„õšçÌYG©©÷ˆß×É0ý·Ÿ™YD11²½Eœ•å/Ì¥ÿž”ªùÝ€Z½‹r$Ó´áhqzºÛòjrT¥—g|Fw&ÅQ\¬3ÝÕ)\R"/OGÌeÂfဲhQø¯9-&’QûÎUH؆bÞÿÓTZ‰±' •u19ë+þF dôçàÉÛyvÆ ›S&Ñi [o½•¶lÙ"ýçìÃn!??ŸâãgÜ;¹Á&aÙ²eZŠwfΜ)çªNœ8AUªÀ%‡ YÀtk®Ì5«ZØšl¥¨¨64o^ªÏùÅ‘#_£3ž{Ð2DÑÀó(#c@دyûöÀ®“aìÌûY4mP±çlöͯŠxP—>+©(j’¨KæþN ±ÃC¬æžú"õ§2Q×3ÞJ·4®ëæîßBökšD»|kL xè!yÎÕ)œ«Æ)kK'›7o.WA@n¿ýv·¥“EEEŠè4(¢¡¥¨ˆ‘¤CY³f–âä“O>QæÍ›§|ÿý÷Êž={”·ÞzKúp>|¸–ìYpr¥®Ùê*Œä«ŠßC"Å*7‰Ñ¶Uù¨K½Bñšy5ó{„VT_ýñ‡I¾œ‘éÕÏÒ|iòp}8F»­ kü.'ú;Ó›f!hG°xñbêÔ©“Ñq ÷Þ{O;KtþüyiÓPZZª¥¨,X°€n¼ñFù7F*UªD³fÍ¢öíÛËòf̘!í`·ÀDÆÈo®X5D‚Çš¢M€ëÖ"1’À¶¦4:ÜcZny1^3L1íÂ>(ŸªR9¤uŽ.m¢¢¨ØÕøØ‚ ÿÖ9s.ýÝÆôµ¢¬l:W/AjÍì &‚G̈îªjô¼ÐBìÛ·OFÈ4¢‡g® Z§¡ÂÁš'á*#_ŽU¬~.œªàY¹Ž$ÔãoMË ŒL`At»ü½ìp}? )À÷³ŽehûÁÙ, ¿«ÍC¿~ý|¶FüiòÌ4ø,h£CÕ0žøÓ,plˆa›ŒT°¼éâÅâH|€WDGï”#}¤`õsa2mÚ4±§ÎQ¢,u1å:!Oy” æ+/Þ”e¯^Z@Ï=|Üo -†±+Ûwí¢¤¿ÿ]ìéu¬™]´æõשË]w‰}OÌlŠŠ‹©A·n¢Áv,AHž²Kv2L¶ãG· qFr «Së´Ÿ"±î Ó°öˆMñxF]$Ñxˆö ¾hßÂ€Ž a ɰfÁI8Êu©8{ÿ˜¯Ô±ò¹E`Ä`,+Vì« J•*¡ªë…¨³>WA˜ù3pjôz¯j(b]Ãd;Îùý—ž¦ü_ÿ‹ꞤŸ­dÖ:I<“A•)¢´pجY¬Y`ÍBØÊUç.ðIŒTLü´[ù\}~šu5D[¥.uÇJWzIiO7++ÒÒÔB|´ ò³ÄÖxΛf!ŽšÉkF6ù·bË0üÖõÕØú›ÿ÷V/Œõ6 ”늿ºè53Á£¿3½iÄcª˜pgÁI8¯Ù—±’ÕÏUµAÀ¶[·¡b_5 r8¬`ùû,×FGý¬ŒK×lõ:Æî sîmi£_õÂXï)×+u/ز™Àð×Y(×ÒI† ŲC,™ZµjŸØ[Go¿½‰Ö­ž%'$Z‰”‹ñŒË!è˲0í¡~Ö^*ÉüîÀ¡·¥`¬÷¡*׌p–ÍX‡; LDP§‚»©´ô5ƒ ̆B`o­G¤óV:X‰©7:êg1 Ã0VáÎsY€f£z‚¼¼m”/¶°‡„`?::šš4i"övŒ†.‰:Q͘1ƒjÖ¨AÅâü#F¸i®¦ê”HchhŸsÔ<þ‚–ꉮY¸@±TF CùTÉQæS³Pzî*Ê?Z‹j¥¸Ê<Žæ÷Œ®Y¨¢Tq†¦³´ªo_ª"êí+ï¾+ëòwBÖÁ¾CHWú/jAÏÒ/4KÔǃ4>5•ßx£8ãD¯¯ú:ˆ‹¢Þž5}õˆÎÔ¨Vœ–Ê\ X³Àš…°^s¨4 FÑGûË&äjŸäcË0¡ÅWrà¥tïÞ]³Ú¾zά.ú*›¹rèïLÖ,„Ö,¸cÅfA¶  zõê¹Ù*˜Ù4”QkÊ£m´xþêÕ?VKõ–na6–^±E5Ô_uÊõ€Ñr•‹ñ” £¹8ë±™m€}ÒÑ4mÁM¼Ü9"8yê]Ó±#kBE8Géá*Û×lm ¸B–»h‘–a˜ˆõ7‰ê«‹-…mX³`›kv­|õÕMÔ§Ñ¢ED½U¯Ñ ÃD0ïgdÑ´AÄžó•âM³ÀDþ4 ÜYî,¸®²/&î,0ŒPÛ‚ù5˜.^üôÈGKì?ÁèïLovÊÄD$ÇŽ©âô-Ã0vqZöIÐðÚÊ…Šw˜ˆÞãFŒP=2bËÆ>Ô©sÝ}÷Ýlh\ÁàÎQÀnC×2 ÃDåê,Lœ8‘î¸ãŠ‹‹£k¯½VKõ L$ÆŽKuëÖ¥ØØXÙݵk—vVåøñãÔ·o_9Áþ‰'´³LE†C×2 ÃDåê,œ;wŽ}ôQ2ÄZa0uêTš>}:Íœ9“¶nÝJ×_=ÝÿýTRR¢å êÕ«íØ±ƒ>ýôS)ØG‡©øpèZ†±Ðü¡=g*.åê,Œ7Žž|òIºýöÛµß@«ðúë¯Ó /¼@?ü05kÖŒÞyç*--•¡‹A^^žì dddPûöí¥¼õÖ[rùÍîÝ»e¦â‚yNcǰOŸ><ÿÉ0 lŠà”)5u°<^¹r¥Ü2‹,|ûí·iäÈ‘~§ öîÝK7¦œœjÕ MU|ðA9ŽÃ‚ dœscY8ÿÚk¯Ñc=¦¥¸söìY):XþQ¿~}ÊÌ<@wÞº¥“;vuìHôÕWD-[j‰!"\eÛéšùåºí¶Û¨Š’BMi”Hy‘¢hÉÒ¥TûºëÔL ÃD‡¡GyDÆz(¥æ´‡¾õ¶#­^6†ë«Í8yú4ÕKI‘ï^Lÿ{€ÎByY¸p¡" ׎¼³qãFé!J¼´•Aƒ):u’û'NTn¹å¹ï Ò&Mš¤yòÒK/ɲYXXXXXX‚“hoUw<4 0>Äô‚/07•œœ¬Y×,dee‰Qþôë¯¿Ò 7Ü ¥‰Î‚Œ€éÑ!ã”æ²±fwôèÑZŠ;FÍ®ª±ýû÷›÷’lh ƾ7S?Þ6§¢ßàghøÚ~†*è Àv‹ŒvcÀ£³pôèQ)¾hذ!ÅÄÄhG‘1 a_: Þ¼QÙ¾?ûÃÏÐþð3´?ü ­áÑ}¨U«%$$ø׎B 4jÔH®~øüóϵuEÅW_}%—`4⦾ýö[y ¶lÙ"Óô< Ã0 Ã\>ʵ*~,kÄká±9uê”–ƒdçbÅŠrßápH ¦öÃ?Ð?þñé§Ë%Abb"uéÒENMlÞ¼Y ö»uëFñññ2Ã0 Ã0—è±0R’#FH ëׯ— têÔINU€'žxB¾ü[j¦ò°Y€mÁøñã)==]ªE>üðC9§¢“’’"§*ÆŒCï½÷ýñ”K)Õh`}>œ>]uÕUZJÅ‚ïÏþð3´?ü í?CÿTب“ Ã0 ĆrMC0 Ã0 SñáÎÃ0 Ã0>áÎÃ0 Ã0>áÎÃ0 Ã0>±mgaÖ¬YÒoVH´nÝš¾þúkíŒ9Ë—/§[o½•ªT©"·úrÎH&{„c,,M5JYY™–#²Ø°aýùÏ–ÞÂpV‚ÏÀ¾|7ß|3Í™3G;yzXQäúÜtÉÏÏ×rD“'O¦6mÚPµjÕ¨víÚôÐCY ôf§zÌ=Ú©Ξ=›š7o.W¤AàãfÍš5ÚYsìÖŽzvkGà7‹ë…‹_ómÙYøè£ä—è•Û·o§»îº‹ºví*ý=˜±iÓ&êÑ£‡ŒføÝwßÉm÷îÝ¥³§H%Ð{¨ t“`h…›Ó§OS‹-d¨r+Ê%µøð}<ÿüó4|øpù£D½?¼Œ\ŸÜœG"è¸ :TúA“µ .È%Ó¸ooØ­sÀ.õ‘\§L™BÛ¶m“rÏ=÷Hoº»víÒr¸cÇv4Ð{vjG]A†yóæÉΑ/‚~ŽX:i7Ú¶m«¤¦¦jG* ÊèÑ£µ#wÄ¡téÒE;Réܹ³Ò³gOí(òô­óŠDð3=[íÈœQ£FÉûweðàÁJ»ví´£ÈÅÊý­[·Næ;~ü¸–b/>,¯_¼`µOìX]±rv®‡ zõêJFF†väŽÝŸŸŽ¯{´ëó+))‘ÁE§V騱£2bÄíŒ'Á>GÛiàü);;[öð]Á1U™ž”1¿ør¼æ¿Òsž3< ½ix¼Ä¼¢àíb´pþüy-Åþ f ‚¬Ý{ï½$:Zjäwì Frk†Ýê¡+÷ìXáÎñ 5ªÞ »??+÷ìøü {àè¾ûîÓR¼ìs´]gA®ðÐëÔ©£¥¨àøÐ¡CÚ‘;H$ÿ•&˜{„[mÌ·}òÉ'ôÁHµ¼eh9ì·gÕ°¿Àgv¨1­òñÇK׿è0Àö!Òƒü­C‡Ô¬Y3-Õ»ÕCW¬Þ£Ýêá÷ßOW_}µœ»NMM•sטÃ6îÏ/{´c;Š—°W°B°ÏѶŽ0âp•Ù˜æJ ù#@®¹]»vÔ§O9OŽyý%K–PÓ¦Mé7ÞÐrسïDús´:ˆ’””$G=0nÅHaÚ´iZŽÈeذa´sçNÙ¸ú#ßt$aõíVñ»C<ØeÀu¿~ý(77W;뉟_ ÷h·ç‡°Ó»°xñâ€ì*‚y޶ë, *&ü\{A‡öè-é Òe ù¯4ÁÜ£Ä#‡%wEÑ,x{†ðu^³fM-¥b†+ÒŸb¿`†)¨m}a·z¨È=‰ôzX¹rejÒ¤ %''Ë‘)^’3fÌÐκc×çÈ=‰ôçžV‰¡-„À0q—° µ‘`Ÿ£í: xðøb\Ã\{ a‘š1ÿÚµk#6äu0÷h=Eô¦¡Þ®x{†h*Uª¤¥T,0W©Ï¿/Œ¶1eòå—_Ê%¾þ°[= æØ­âzèÏ »=?oøºG#‘þü0U‰i\£.h{÷î-÷1è4ôs_†íøðÃñ‚PæÏŸ¯äææ*#GŽTªV­ªìÛ·OžïÛ·¯Ûª7*âKS¦L™¢äååÉ­èu)›7oÖrDÞãØ±c•O?ýTùé§Ÿñ’Q{ì1y[¶lÑrD°ÞÅuBð3œ>}ºÜÿùçŸåyÜîQgïÞ½J\\œòä“OÊïß ¾ŸeË–i9"‹@ïïµ×^“+&~üñGå‡~çñwË—/×rDC† ‘VãëׯWsBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+‹ŠIDATx^í|EûÇŸK!ô"]ªb£©Ø@EìÁ Š {ù«/ –×^° b/Ø+Ê‹‚½¢`C”*Ho!eÿó¹Iö6w—KH»d~|†ÍîÎîíÎîÎïióLÈSrsseùòåR§N …Bá­É>é 6HóæÍ%%%%¼µhpý€ƒCrÃöH~éÒ¥ÒªU«ðšƒƒC²bÉ’%Ò²eËðZÑàú‡Ê$¿nÝ:©_¿¾î êÖ­Þj••%|ðôë×OÒÓÓÃ[J®ÝËÉÚîëׯ×½víZ©W¯^xkѯ°¨Œïee»'w?¥y?¶(@òì cà#Fò“'O–#<²Ò|ÔÉ×îåƒdm÷xßp¢Hä•ñ½¬l÷äî§b£4ïÇ~ÃÅsØ9888888Tx8’wppppp¨¤p$ïàààààPIáHÞÁÁÁÁÁ¡’"%33S;èý­ÄÛçJË–¥’»¨¿xsé%ëQë©âÚ½|J²¶»Cð÷ß"G!Ò¨‘¤$u-ÒKÖõvö;8$)B£Gön¼ñÆðj>&Nœ(5kÖ ¯9”zµ+Mk}/äÉõRäßÍ»ªeº4¨1OÖlé(³þ)™9õõÃæÍ›eðàÁ.º>Q@ä|@ ñRSe[­ZRÍ$QërØa"ÿû_¸rr¡Ò<£0Üý$û ‡¶nÝê¡Í[°ƒ±u«V­Š:„nêÔ©ê?¬R4py#íϪ#Ù^ñ„6Í‘¨ÎFRÅ«q¨ä4ŸäÚ½œ¬íÎ7ܸqcGò‰}õêð ß¡Ò~ÌŸìWýa2¢Ò<£0Üý$û §dddèØ_?­ÄÛçJŠü-¡”êª5mXDª&w )²OÙ63¯>ˆ8Þ•2)ÉÚîEÀÞ{«ÎкÖäU˜—<M~¯½Â+ Âgþjî/l¿ƒC ÂÞ•éKõ"v.ùH”LŸ~Zd÷ÝEj×ïÐCåË›niÒ橞ýEÁ©§ŠL™b¬,Y÷ãÌ3{€ýS§šu‡R‚#ù ²UG°DusÕÎ’õ’Æš‡Dj©ÎcÝx‘\Ì„JoðÖ‹d즶÷Sü®~›ý;±sqppÈä ‰F¦;ì 2j”ȃJΤI²¡MñÐî1Ñã‹gQðùçá?Âøâ‹ðaLŸ®ýÿ99"ß~kþvp(8’b…ê6„£:†Mªc`½$‘ù«ÈæEê_ –_© álûE¤•êT:ªÎ…eZ;‡||ó!QP™V«¦¾ÍüØ$‰Ìö]4vl-¬vá®·8î‡"À‘|[TÇG¼ªcØZ‚R¶—%ò÷%J3Pš|ÖâðF gžwp(Q G#ÓhfüŒ %do3û!éí™^·Nð œç€Â+ hõýú™R\w€ƒCàH>ˆªc€p-ÒÛ…ÿ(¬ºIiðç¨_u(ËOVKgõ{tJ©Gá)M¢4ÜU'dŠ–Þ»w>™Fó‰û4ùÔ­[µ¾Xøé'¦èÝgCâ‡.òâ‹f_v¶Õï¾Û¸Šëpp(É8~ñš‡ªRûVõán/¶LWÚûBÕy Yv¬ÙÖò=s~,¢´üÍŸ•¼{ÀÁ¡ªò„DÇ1"ŸL1ã}â>M>}ËñüÚxQpÿýF“ÿúë‚$þðÃ"§œ"Ò Ywp(TM’\‡ÜúÅ[+)¿ùË"ÿ\¢8xI¸B1»Idåu"MïYz¼Yoù–$+bÿ” ¦^I»D>XäãÃ+ ÑÌø>M>móf‘ðPâ"aÝ:#@œwž1Óû݇"ò–úæÏ:+\ÙÁ¡lP5I>"¸N-—ŸÞ¡ àf›crÖ˜:Ѱu¶©Ï2ˆ®i¨Hþï‹Õù—)‚GuÕÉ>½­ª`ƒóË;8 ñ†Ëí´“ÈÂ…áÌöøÂÉ'`}â|X“OSš|„_=QXwÀÉê»~·À'Ÿ¨¾a«öWƾN‡R@Õ$ùˆà:µÜü‘ÈF¥½p-º¾Z;¥…ß©HyˆÚ®>ÔhØðºª?E-ßocãdEèªÙ¨¤x€–“”° >ìeJ£o¨È¿µÒ0ܰ9‡íCaÃåš5Sßïró7æsƯã/·ætŸ¹^kòE%yúŽgž9æs.0c†ê/Âý ûçÎ9ýt‘÷ßwcäÊ U“ä#‚ëÔ²foc&_Ú_>cZ£˜Ï«wW¤|‰È_g«zyû— {•ú˜ïV­\OmÏü&Õ©üû_‘¯)M¢µ":Ðà!x7lΡPÔ‰ªlI¤NY/0\ÎûöÛˆýÙ½{Kö´iÛrg)bÏZºTr‡ïÁ%eÀ©±j•d׬QW×éß_<¥³dÝ¿?[·§4õ¬sÏÍÛ–Û°¡x6“^JŠäöì)cèí»(×YDÛž¬ÅÝOâ„<ýW6ßm´œÕT)òc’‡\!p?¹æ¨Žm¡ZÏR·EzG‘~TDM Z…uÏ™ãšÞoün€óÍWš‚EµžÚDiƒÕñíU£ªó7SdíƒJÊßE W«c•|µpu.¬ @­ëìwJÀ@ñ~¥i÷$C²¶{¼o8ÆŒ#ÉjvòÝUWéõŒ5k¤û}÷Iu%0 4¬ÞuWùcà@éöÀ’±vmÌó88”ìDUU“ä£Áÿ–ˆÝjÃfEÄ5Dê+²m¾H#õñÖ`êþ{»Y6ºÆ,×=«ŽõùõwTëd±Ãì¿išÈŠÜ׎i¬>æ½Õ©?Tþ}jŸZJ4óª1ݨàH¾|P•HM>щª,hŸ 3ÏßKê°a"R^‘g¶"伨v¦Ž )m±œüô¤¯õöÝW¼¾}%õè£%„ù<Œ¬Œ ÉyùeIUÏÝ"­Y³ˆ:hôÙ+V˜•Å‹%MÕÍ~N)J¸)^(¹Ç+©ŠèsÞyG}æ[%U­çÜ¿¤*A 4s¦xJ³Ïyüñˆë,iT¨gTp÷“8ø†™¨ªjšë£!Ï¿F}Áêc®®´ìËÔÒ|´²æõ1«~‘"éUŠä×<¬ˆZ‘7ÀŸgþOS­ûŠÙ¿qŠHýs•ðŒ"þçÕ¹7‰,Uç ¢¾¹ÚVë U?Ú#pQöe‹¢NTeK"uʤ´l))S¦Hèß%tÆ’¾lYþ¾ß—”>ÐB99’¢H6µCI[ºTBDÛ‡°UxZÆç÷×!"?´×^ùûÇ—õU½>w®¤*)ýµ×$å–[$]µmúþ#)×\#é»ïn®S O,¹î¼ó”RѶ'kq÷“xŽä-"‚ñ”¾õk‘eÇ(¾]§4öÿS½àªÎç¦xJÈ^¬È~ŒÉCOÀë²ÕºÒÀ31¦ùÌyªÌù£•È_#Dê7ÚüÚÇÔy²T‡ÑTõ:µTÁTï‹pQö‰!YOtûƒa0„.Ò`i†Íµmk¢î‰Šçï´4­ácê÷‚Épž|2ú¤5X?&M¹ür³™Ë?мð‚ˆ"wyE ýàèçàPÆp$oQ Ou -ßUÛ÷SäÉsLÐ\É+M?÷­]+rá…f}âDó»5j˜u€–¿ß~ᇲ‡#ùDA¤}n~ôqâ ‰•”RF­þ"ÍÓU888” ð3 Úr—.frEÃÆ/¾Ûn&Óæù=÷4¦ü=L€`Ю]Éks=š¹hçÁ(ø›o6Ñ4l¨£çµßþÏ?EéÐh*7ËœC¹£ê|0]-ë~ä*é=ó7Ñ™ïV?$²â<Iÿ§ê4æ·QËU¥ðT”E‚ê0Rêš„;Õ•Æ¡'ªYR0ÈÁÁ¡x€|ñ“£Uó÷úõ&ï²ËD®½V䯿L½³ÏVßuxØÚ7„™÷êeÌêJ3g¨] B€|Ó¦á•0ðÿ÷ ¬ãƉôí+²aƒÈK/™€>€gŸ-Õ!r…¡ê|Þ9õq ?¿¹"üÕǸŸ"põ±ÏSñ‚]E–(²îqUo"f%…×Që˜Ø3vWKõ£‘ãW!A¿™µTi‡+9a®Ôoþža~󯑪SzUmÿÃaˆƒƒCt@Øÿ÷F«ÇϾf!㣎2ûÉa¹à8S:ësæèehÚ4©·`©oÍOô>©rÑâ!÷ë¯7SÈâ 8?<3ѹ´µ匪CòCä€ú;WIøÙHöê#÷6›mžÒ艖§lS~ªúñÏó÷¶ŸE+ɽ“’ôÓZê³$ŒmóÂCîV¿ImuŽœE¶*m w£êŒîY:P J˜Øô¾Ú†0¢:*„‡Äá’£>lzׂ3‘îvˆùéÑÚ!cLêøßVßuزÆú´M›ôßyøòËH’çxòÔCìøGRG¨ Xp Ä88”#ªÉG ‘óÁÛ&z+¨%äÛäõ§"úUêCÞú½HË·U§°HuW+òUûSßj„ý{1±Ud³’쳕Fïÿ­¬ßE꟥´‚DZ½§6©Î‚qúª“pIqŠÌïøÝñ¹ÛIaðÍÏŸoÌöL$ƒöß¼¹©§@2œì`$ü¯¿Šì²KxEá=’_) `´|?,°èàPލ:$o‡È Y€,!«$7Í öyJÚg²šê=±«Î õ4õw8ó³Ìý{«ù;êx&¡i4Jm¨Cå nÆÙCâê÷ƒIojî£þ³ÂH”ýñÁØuéˆoÐÀÀÙ–hóøÝ!of›ƒˆ;uÒDOšÛµíÛ›º€€:¦¡µÑû€€»áÃÍ6?©„Þ½ &Íqp('T’·Cä:,1¾q;ä®2K E¬Í_Võ”ÆÝäFÕBái#ÁšñЧßUUv oƒ¨ùvJ#§>Cí°Ó@˜ ø‰= ²ÜÕ8Pu:™‘þ÷hãõn?ü`ÈûÞ{EZú\k3äÑ3#\çÎ&0qó JÎ=÷HÝE‹t®zmâÇ·ßS ûøëI²Cà=“÷@è<~ùO?-˜4ÇÁ¡œPuH>$ðõ!ê©e}HUšxAá•0þWŽVÒÿ"õÑ>*:mmÔ¹ÒÂÑ·,Û|¥>úÝ‘“P ÂZ€ú;Uu:hè™?š<ö~ÿ{¼ñú‰"?î8‘[n1æyÖ1ÏCø_lüå“'‹ì¼³‰ˆ‡¨³³%õ‚ ¤úêÕf2þÊ+#ǹ“MMó‘ÉnG%ðcà<üÞyç…+:8T T=’·QöäŸ'èMGËÇ1{J ÿ[}Ì© EšÞ¦Ö£Ìô›‡Ôy^ª4û1ª38Vþ.Jâ?TmWRZk‘¶ßˆ4¾A‘û:UÙšûJÁÿNlÁ†wÍÒÁ¡ªá]õîÏ«É[6n4š6d¿A]›aÏÁ¡¡ê‘|p"n‚æq;ŒíwõáÏo¥4€nª¸$|Qø~¿{ ¿yÝ!ª#™$ÒâU‘f‹´VZAgÕ™4-²òZEúJ ?~^—¢EIûß·-P÷û¹Y:8T5#Û!i†ÑMŸnÌìë”]O}ËXõ°Ö©¥×®]^Ø«» Ä{äc  `! %.yíIƒK]‡ †ªGòÁ‰hXšÇýÚ~Ž’Ö7¾®¯ ‡´ù†É¤4ˆî7Ç—Ïls {šñðÖçN$}cD–"Òì1Õ®êÖQ¥¾Ú~rÉŽ‘g|F0ßÁ¡2"8ëvfx?Z´Y´HäÅÉ’þ#œŸ‚D:ÒöaÀ‚±ñhð—^Z°Ú¼ƒCDÕ#ùDÛ"´}µô›Ñõ>Ÿ¬RÇò›3 ]¦ÒâƒcÞë+Òà"Õ©BšÛNëEÚ+m{Õ(U¯„ÆÈ“Á/K‘, XRJ1aN…|FÛw?‰Ã~á­[·zhóìhÕª•¬ZµªÀÇÍM:U½Ã‡UŠ®Èþ[Rÿ&¡Ì™âeô”œ¦ˆˆÚîYJhóû긟ÅKm :—Æf{ÒT§æ#õ\Æ÷ûÝ 9«$”³FýînâÕ<\$½]x‡HÖ÷o¸qãÆU“ä¾wÞ|ò‰ñ½ûÁ½àGgXòד½Ž¡o¤¯]»V<µÏÛ´IBmÚHè±ÇL†»ñãM=ÆÓCð˜÷9‚is± ` ˜9ÓàÅ#îÃÕw†I? PaŸQ1áî'q䑼§Þ¦ïã®l œ,ˆÙîDÌoþLd‹*üM]ˆ<ù…€ÜüÛþTB@ ÑÃü³ÏßHÖ÷=‚. IMò€n 3Ù˜ÙO?ÝDÕFðdÕC8ààš¼zçPÊp$_€_ï,EØá:^ŒÀ+¶³ŸzÔç8‡Ê› ’FSF£'Ø®G“厴´C‡šas¬Cðhé>ÀãoH_;&z€0ÀÜñ'$rê©æÑ€á‹/Œ@ÀœóœŸñö~£)çÇTïf©s(e8’¯,@O O’ƒ?>*ÂÛ©ç´w‡Ê Ûð{3Ôrà"“&beÌük¯™9çñÝ@‡OÞ&½Q€Ò½=ö0ûƒYó˜a!‚q÷Á1ñÔgÈ]ÿþ"<`üü†Ý+D <à›w³Ô9”ÉW&Æ6¤ˆÜ§‘Dhõlg¿KsëP™AäºH¹êñ¡?ñ„Y‡X/»LäŠ+Œ€¦n£ãè½Ýv3dCäücâ±0Å,ÑüÏ?o‡nÝD}ÔüÏ€óã2p¼C‘|eA®ê¤HcK¤= ¸.ó7Cü,Yìwin*3üÉp0•3\ŽŒu¤´}ë-³NÀ r*ÄßnMòa¤LœhÀ0<"ò±øë"0|ü±Hß¾f(^Û¶Fp˜<Ù$àaØÝ´i‘çæ÷œïP†p$_Y@ÚZÒ×Bâþ຺§Eå±_§¹]>ÐÁî*ZR,[©SêeéRÉíß_g©c™uë­’«ÙSZ³§È>w—]$[uî1ÇHö¤I’õöÛ’Û¬™6ËçÖ¨!žºwtxŸÇ\kݬçœp‚®›5eŠäÖ¬)¹ŠÈµ¿ž*”êÕ%ç”S$ëÞ{%§W/É}àÉUÇä(m?kÈÉ=ä} º>×¢È?ê=”bѶ'kq÷“xn] ¡vߨ4†J›ÕP¢›*þ¡qÁ¡vž*µWåÐðÁѬï{¼o8ÆŒ#Éš«×رÒdÖ,I ³vK…»5è8W­¯îÜY~9ûlÙqÆ iüã²äàƒ¥å§ŸJ½ ôþtEô>'—BÀšNdS‹RýßemûöÒü«¯¤¦z¥oRäÿ¯jýólnÒDþéÑCVdûÚ+cíZé6nœÔŸ7OÖvì(³FŽÔõJ6)–#ù$@¡íî©îhÍCJûE¤ú"µúGœglü¦)"[T½Ï®f&¼°VâPU‰äÑäMŠeAûT„dAiŠlCo }«Î.¼Vìñ Áõ ´ÕàÊ+%—:Ìùô;ª(Ϩ¤àî'qð “Ë™ë+rDg¼c ÛxCãìP;êé yÙf»C•GFF†&st<ñJ"uJ»„‚“ÔDAaÜ·¾ BãÇKêµ×Jz·n’^­ZÔëª(DÛž¬ÅÝOâ8’¯ ©‡Y÷I(± û©G}ŽspHv©NÄ:ÁqAÐÑ1¤´Ú|·=8V Èd­;ñÄüñøŒÅwSÌ:TP8’¯,(ª¹Ð™é* ˆT'bèw?˜Œ†ÈwˆþºëÌô²Ý»‹0¾8ïÿŽ;‚ÇDOîûw6çÄUðÁ±§˜u€C9‘¼ƒƒCåÀ?„ÿƒ1íï¾+òÎ;‘…YåŠJò Å#‡ýyç‰\}µÈÙgÈÞ©À0¹?4ùém9î8‘sÎ1‰wÞßÍ7ïP.p$ïààP9à÷ͳŒå«ÿê+CÊEÚ?ãâÉdG"’ß·`…~«_˜xùe‘Ûn3ãímÐçpóÍ;”!É;88TXßÚX Ðòq  ©ßt“ÈgŸ‰üù§Ñæ1éã.ð nR‡2„#y‡Êë›g†9›Uÿ7Ä‹/ü×_ á2qLÐïCv¤¤ÅäŽù¢G{ß“¶výz“º–üôìÇd?|¸Èî»çûë)dØ‹&|88”2É;88T>Ìœi|ß^hƱ“‹-üÞ{EÆ3d9Ký¿9~uRâ­9ÞšàÑÎÉUÍ5"Ÿ|"òÛo‘çÇ5ÀD7D÷c¾çº\žCÁ‘¼ƒƒCåDü⋆<É=O¾úƒ6Ú7CßØ×®È•WšIküÀäŽY¾nݼ´µ`âÈœ€;~öl‘AƒŒ0Ç3×¼5Ñsn¢ñ·l0 _ÃwAxeGòÉ ´á±c¿)c_}ÕhÛhñ5jRŧFyåC¸À:Ú>Ú·ÒÔÉ1ß½MAËD3óæ™¿™ŸžóL˜ òøãfÚÙE‹Ì> |@¿~æ7!tû»Àá9”É;88$ücΙ>ö¤“D.ºÈhÎhƇbH—ÙáÞ|ÓhÞV£3Æò)§B?àCò”õ6O‘ºgg®cˆÜ3Ïs0„¿>> Ñõ áWRsü7 ¿‘œ\ÕN ,¿]äâ ’Žä’ÖÜmæšs´(w2Î]q…1ëýµËþöÛ"{îi4iÎAÉmÐÀ™¼F‘|6ä©ÿñ‡HëÖÆz0gމÌG(°Ø¼¹àP¸$6dž½Ûî-©)ùÖ®;îþË¡"ѼƒƒCòÀš»™$&žÆÌ0· .ùâ ãs'ç<9~vÆÊ¯\iŽcܲeFP¨WOûHŽ—#«6¨ût¨Ðp$ïàà|ˆ¦1ÛÈ{Hý„L`\çÎ"d4z²Ð‘Gž¬thîhìÇcRކˑ¦Viø!†Ð„\¤ÄmÓ&ŸÀ9֢Р…Û¡îò¿Kÿ'«î]%Ÿ\ý‰<|ÚÃrÚã§É¦ÌMáŽä’Ñ4f´i"ÛG`Ýwšˆ{ˆûúëÍqDÖ3¦òæí(h窄” Cç rüîäŸgüýçŸëShà7Ý“ÞÖo¶¯Ø£årý€ëeèC%+;,(U@TõQŽä’VƒÇo#ÛY\G¦:ÙÈÿ£Œ6N‡¯MÒW}háBIß¼YB˜â!yµ®ú0ß_z©9`9Àtp°TÁ v½;õ–¡½†Ê¹Ï+¹vÔC£>˜óA•àHÞÁÁ!¹aÇÎûAPDÍ:’Ö€Ç37¤Ž9žIf,0û ë߯CÙÒ¨‘xÃñ —kÜXûëÙ/óç›úÖ’`Ï ªh»c»+½Úõ’k߸6¼¥baÆ‚’ë¤*Ž p$ïààÜð<þu²áá¯GÓ'PÌtäœGkoÒÄøóÙGðZûÀâ)! ³=óÇ︣±`¦ÇdÏߣG‡$ —ÁNã¼>çI­jµäžî o)ü»ñ_ùö¯oõ2QK Æ`tÀ^mªÖ3r$ïààÜm§N†À#Ðô1¥£iCÔÌ3+¾{´uÆÏ#Ô¨!!UÇ#`o—]̺¡0|ß>ç±æ~P‰‡Ì£’ù+çË Ó_o)y,üw¡ÌY=G/Á²5ˤyýæÒo—~zT£%P•’©^ðõë×G••µÄÛçJé×îåS’µÝ«üD Y“´ß» ŒCÓ‡Ü-Ðú:‡Ù¾}{£ù“®6ŒœjÕăÜ1Ñ£Í# 0æžvůÿðÃáš Ñ« f;òþ#å¥o^’+_½R/‹ƒÂ‚äþXù‡ü½ùo9ïùó ¤»êµ«äþSî—)—MÑ£€f_•=z´w#ùž˜8q¢Ô´ÃH’›7o–Áƒ˺u뤮ßg\ ì×S$ï“'O–#û ‡¶nÝê¡Í[°£U«VJ0]Uàãæ‚¦Nª„æÃ*ÆG]EàÚ½|¬íÎ7ܸqãªGòŒg*×÷Þ o’Æ„™í­0ÜÎjøä¯ÿî;}Ožvš´S$ŸÎT²¼Ú–Üøì™£^ ReõŒÐª‰^·hP«toÝ]ü°tj¦Ú>@ª­®n%Y9ùí‰ Ìýk®<üñÃ2þ“ñ²-w›Þüu,6gn– ”w/~WjfÔ”Ÿ—ý,ßu°öåSÿã+?–ÝZì®~Á%ž0±=(Íçc¿á”ŒŒ ýû ࣕxû\)½âÚ½|J²¶{•ÉjH_ûÆá >„ùCô$´!NЄO Û0¶©>0D^{ÕIæÍ' x|óX8Ƀï?¾ŠM „Ô¿½Ûì-Ïžý¬Œx~„¬X»Bo/ hÍ~‚þ ¹Å«Kvn¶4«Ù,¼%v ÝMïÝ$Wô»B<€àWm4Ú?KÖãဟÍû¬RDå»À»*€Âü\I ¦Œ½øb“ÊÖŸ‰Î‚D86 m3EøãƒÝØ™è yícÔejYüóX&˜È†T¸¤ÌuÐÀ”ݯ‹ në´C'iÑ …4«ÛLòˆ }r¨¬Û¼.\3:è“¦Í ç3¡áî“îÖ©s)¿®øUjgÔ–CZ¢ÝÕÒªéôºþ:”Ïç~.¿ÿõ»Ôù ð™ÔãTÄîG¼èü?Wþ)G=x”´mÔ6OpIæ¨|Gò•…‘xUOáP‰AS¼’§ÞGÔ`|<vd­#å-³ÎÙ`=¬hæ$Í c›ª"¢¾aC3™Í!J5¼ÉÖ1‰ Z?sËã°þú*ÊÛßnþMìx œùÔ™²SãäÖcoÕéoý»(f?EŸ”íe‡× Ø7õ}nÝGn~ïf™ÿÏ|Mî5Òjh>½×éÒ«}/yaÆ rï´{u¹gê=Z¨ønáwÒìŠfúw^ÿþum]ð£AÍ®íwÀÈGʸSÇÉGW~”'¸$sT¾#ùJ€ÂHœÀ‘ªœ ¡ƒ,tô˜1á §Ÿ:¦õV­D8Àl' ¢g®xb’Î9'°ó4ùŽ40ûÉžŽÇä6€(þO4W…}üЃ$Cߪ—Aá¿4qæþgÊqÝ“S&œ"»5ßM.:ä"éuk¯˜ý}T˜æ·fo•?Wý)S~ž"í›¶—ÚÕkë}[²¶Èî-wפï/³—ÌÖVƒÅkËÆÌòþ/ïË©*Oœñ„4¬©„6Ÿþk°×rÒ#'É1£ûÇw.zGÚ5i!¸°LÖ¨|Gò•…‘¸ß_–Ìf'‡ÒCQ‡ÒÚ’HÒ*Ù| ÞË/KÖ¤I’•µN۩“ä®^-9mÚHÖ‘Gæï;ã ñ¸Ïœñ¦NÕëlÏTš|®"ùìv’ìmÛ$wÞ<É]³F²Ôß^À—Ϻ=_y—3ž8CÞŸó¾&.Èô ;Ò¶!kƒLûmšÞí¸Ò*v #!Ç?^z´ê!27DöS ¿Í«KŸDß K×,•ô”tõ¨rdSÖ&©[½®^¯‘^C—ÔPª6çS¶eçåჯ–ZM†ì3Dz¶é© žmk·¬Õ×X~ýç×rû±·ËˆÞ#ôoøï£´ ˆ¶½$ y ú¯0lD^´¨ZªPÑ´U…µ;R;³}iïr¸jÜÃÇɬų¤O§>¥2¤2"Yß÷xßp,ŒQšp2 ¥MÛ´Iú^t‘̺àù'F–¹ô äð³Î’ÕŠäë-^,kÛµ“¯¹Çpö³#†•jD܇¹Oyî9IݲEº>ü°üqôÑÒâóÏ¥ÕÇKÚæÍ²¦sgñRR¤Ñ/¿HJ®™Ä&»zu™úøã’Ű¼r;„ ÕRªÉÝÞ--k·ÌËW˜¿v¾<÷Ûsšàþ÷gM²m·&ÝdÔ>£tµ™keÜìqòûšß5)oËÙ&›²óg·k]»µ Øi€þûuèý»4ÜE¯¯ß¶^Öd®‘?Öþ!Ƕ?VžýíYY¾i¹Þº7é.×ö¼VO\À%¸–®»Êè^l†I;”Ö‘| °v‡Ä1}¡ÁïPg9¡Ç rãÑ‘6ÓAžõÔYòʈWÂ[ CU"y4ùD‡ÒZÐ>e>Äðï¿%õœs$„~‡${ÆŒ˜ hR† ‘З_šˆxuoÞÞ{K.Qña¤$¡÷ßW]¼ÒøRSÅ;ôPÙúÆ2õƒdÀ„ â=ý´¤á“ÿë/“O£×§î Íœ)^›6Z¶Lr/¹Dr¯¼Òœ´Ia­¸A²zóê<í¹^õzÒ¥y¡Ë߷ݾrÔžGéœóñ4è’Âoý¦#íù-4øêéÕåÞ“î•Óö9-\# ë£½#´¨ßBkØøÆÑ²›ö˜³Ï1²cýu4þÜ¿çJózÍå׿~Õw³–ÌÒ÷ÈoÜù`¹ý¸Ûåš7®ÑÁwß/ù^ïé©é:ï>;í#Ÿþx¹(>¥ù ñ 3”Ö™ë+ü¾£ŸoüY ß.ˆ4Ù×ʨ%›·m–Ù‹gË÷¡—EJkK"uJ´ .)ªS ©Î>¤È—õ¨õi§¾û®¤ôì))ŠˆSvÝUR=6¢NÊm·Iˆä6IHu²)Ï<£·£é§¨’Þ¤‰„”Á–)?ý$)S¦èí)ŠèCJ³O}ûm¡%üç.òÌ9Ïè1(öñUëeô:Úº÷ã?ʘ£Æè5_/øZßþwì/Þ&“™,Y¹YQÏë/«·¬–£:Jš]ÕL/YV/Xvoµ»¼xî‹’ž–.3®›!‡u9L.yùi|EãçY±n…,Y³D<€¬›Ôm"©*xž¥k—†ÿ2øgÃ?yî…­Y[5éÛõg¾zF X/ð³û sÑ‹ÉþG®óz­íCô?ŽùQ §}U€#ùJˆ†µÊGÝ(¿xqži `özã{Cî“~˜¤—I"ß™¿Ò¶€|ƒþxê‘Æ–hyÆÌCô˜ÜÖlò0k–1åÇÃA‰`¢'/>Cïîº+¼#Œë®3¿ùÄyÞ&³VÎÊ#e"Í$Ù¹Yg¹¼ßå2íŠiòÉ•Ÿh2¤ï¸oÚ}rÐÉ~ÿÝOî˜r‡Ìû{ž>0m«Õ°q|ôÛGòÕü¯"ú™xhR§‰¼6â5mR·à<> Šôì^‰„׸±+Ïd4s4"¿óNcúðÁð†Š†¦ù‡Ïâ§þß%ÿÓ3³‘¨æíÙoËñ/Æ «_»Z[ú ÷qÓÆéé\ñm31Lvv¶ü¸äÇ$NàÛû¯ÎyŸòØ)rá ê1úñðܰçt¢? >üíCé2ª‹ÖøÉ6þÝ¢ï䇥?è´¶oø[¾ûç;wD„½`@—f]äàÖÁÇøõ§Î™*ß-þNf.š©gÆãš>™ûIž ‚‰?8ܸ2‘|%5i%zà(m#HÅ"-%MÞû)0‘‡ƒCEEpÎøÃæ¤Gð>de‰|ò‰ÑòýÀO¿Ï>á•0Ï£½ûI~çöî†Ð­^-2?ºù¸¼€Ožáa$Šñgm#8oÀä¦cnÒÉ_(C{ Õé^¯ëzM¶– !Ò%k—Hµôjš@Ѱ-HJÓðÒ†ZH¨S½Ž>ψ>#äîî–¦—5•ÚÕ–Ãï9¼€Yœøb¸.?вù}üïÑák·ih‰˜¿n~¹ ¹¬ÎРǭ۲N¬Z k6¯Ñ Mß»ûÊ-öÐý"`Yš9C¸g”«òv 8’¯D €æûEßG‚Vˆª‚à?ÿOKÉÁclá|EAEy©*!üsÆG3Ó[ôíkR×ýï99ƒô”vª-Ñ€&É3u­%nüû˜ñ7åßÎða&(p·ÝLL@ÐjPN€L‹¾âÎq³¶AxdÞ{¸ Låp4 `Ðo¡­Cìhî€`=›Ä¢C“²|ír-,_—?>Þ„¬ï\üNÄ„ÒLUKò¡Šàpãä“ñÚ"åå±i!y¡mP"öƒ œhÀƇµdõ=ž•ׇ>~H›ÔK²¢*“"‘sTÈöéÒEäÔSÍ2O=eÈ‚öp€‰Ðí1YM€Œí= P÷Æ=q®EÞ}×TÀ4aÂÕ&Éüóa€ Aû[åˆâ>#Û¯`ÎFÛ… ›Ôn"_þñ¥œûì¹òû߿Ü:Pß7ý¤œ¢îýë?¾. X0ËÁ§¿*›¶m’ýÛï¯û¬X$ïÂF0ÀbÇz;JÓ:MeÙÚešüÛ6l+³–æõY”V”™•©&µùcåz‰õáwA¬is-Jó²ß°Óä“|ˆH‰ûÚÍkµ>QÄ#xLodÇ{qÆ‹:à…IHO9èAºà{Ã$‡¿ŸóTó˜EUñw9T -›Üò,!çXÚÿ¢E&ç},XŸ¼…Õ…bùågÎ ÿ¡oh_’ 8uüÖ÷nÕ‘íè†üûwÓ¿òá¯êázhûZ0@ìÄáS×9åç¼Ñ_ÄC,‚ß§í>:jžëéÚª«œÔã$³ ×Büe{´vî“™í¾Yðî oyï9çésdฺ ~|°<öÙc:¿>θ*&øÞÈ÷´’TV®xpš| ^»c÷kïdqBºµuqÀñGìv„ž2²UÃVÒ²AKiÕ •Wš‘e*Ï00ÑÛôºN“/?TYM^]‡žÇwŽf=˜2ö¡‡D>ÿ<¼Á ïžvÜQÒÕRO|sÆ&xayæ™}ŽimýÀDÏïAð M ÛÌŽ‡`##_Y ¤ŸQ°¿±ÈHÍÐß|6=tìYíüJDaVÃâë@vN¶û9ŸßGÀØ«í^òÒy/å¹&üÖNæñ€ìÙg·3,p÷»Ë_ k6­Ñ„FŽù 40a "g‰õÀŽÕ…hÖ »¤4¿!§ÉWðÒú¥ÅC:"ßÝðNÉÜË|\‰“Xýšõåås_–åw-—'Î|B®9â¼Ï`mŽÛ©ÉNq ðCìeáïrpˆþóŸ6Ñòûígüí±0F{,ØÀ;à¾[³Fdút3îÞï{‡Ì1ÑcªüþÔ©ƒý’ô7Ñú”ÌœLÙœµY>ŸÿyÄŒrÖ¯_Ò°ð»ü¾zLÿl#‚r…dQùìšÏô¾ šÕi¦ÇÔ—6üänÁu2å,ÙýH¸c¯›%yíðÒ7/ÉóÓŸ—§¿|Zÿüqä‡ÄAd´Sù2$¯ÕU­ŠMö¶g€±3Æ–ªÀà|òI»3™&'+!·nØZî:ñ.Ù¿Ãþy¹˜!êÅDFÊÛŽ;t”=[݃àp|÷ãuRŠªˆd}ß«œOþí·E˜î‚ D˜p† uK–„wÆ)jÑÎÁwÜÓjEÔMøAO‚£‰šÔ¶M›2ï®!}„ˆhûóýñÇ›@¼ƒNZŸ<¤Í Ÿüþ‰ÎxGпo\ð†tkÕMGØ÷¸¥‡lÜš¯1GV‚úrõô½%oÖ÷ƒë×Ïïú9üúÄ2á®DHanzÌñ?Åþ še‚Ä=]ŸácüK}Ÿá¿?þíc°‡ûeVXÿôà%û ;’OøÛÉÏø–1ÿŸù:c”膼h¼Xvé³2Mþi²Ž‚=¾ÇñR7£®¼óã;:²ߧÝ>:›U"~e@²¾ïUŽäI”C$üâŪÇmbˆ˜\òññFËÎ=yEÌ3¯ýóhè £ãLôhðhé±HœÈ~„‚b¶I¡¸Ï-Ó*ôLëʰ·­Ù&Í÷~_óƒ¨wŽ£~"&{M°Š\‰Ö/* I†ôÚß‚¬q07ýÌÅ3µÐÁÄ< j6Ð}#Z¾^*‚·ž÷wv–ü÷ÿ•Ÿ—ÿ¬ûC?ü}0û¸ÿ’V€±ÛÛ\ÛF†² )Ъûòûñ’€ý†¹>É ´³Ã26gn–Þ¼AþïÿÓsEÛ:~°Õ£ŽÒË`ưžÐù2åÒ)’‘–!O}õ”òÀà´ÄÛ뿽òf ª*yŸ*80£p‡ž`·+Ìß±I÷ïo†Ùùç|XÓ±£ž_^Ãor§s·¾wüò,ciéC‡Š<÷\x%ù€ o r"³êÞ¾ðí¼ y¶@„Alxpƒlzx“âŬoh/DÌ9øvÛéT¶EAÍôšzDQï é³­aí†r|Ïãuß·/z[ûÚV˜ ºLгk‹]¥kë®Ò³mOTÇœ‡ìrˆôÛµŸ×OÞ|rúŸºÏ©2õò©:³Z¿…¿hélKKMÓ ƒVfîüš5užÿÚÕkkW“ðØþ—ëÅ…PZp$Ÿ ¥ã·}«—Á@»§ÎzJ^ÿîuøÀ@m2zuÄ«òʈWô>>€D 0¿\wãÑ7ê¥öã+°ŸmòÏ“õ:/ç°‡Éû—¾¯PN›pšI1©¤\>DàÆÁ;TœFi«š€-~ü1üG …3Ôú1¢ßg)ÃßüãëùÛ?n¾0á?ztÁ(ü$AP™`L:d‰A_ä~xŽ!ç=YîŽÜýȨ¾yРF9y¯“õ„5»4ÛEçç¨W½^xob`®y†î1&þ€Žȹ½Ï•+¿R["ýôQúÄPéysO]Hñ}Ó»7É;³ßÑqHA­<l`ñ’;–äÅ#ÐÏÒ'yý¸ÒàI;LúáÒ‚3×'¦ÏŸ.w¼z‡\}âÕÒ«Cþ4Œ¿­øM®}ãZ-òRóZ@Èç1´SØ£C9ÿÊ·¯ÈyÏŸ§MGH˜«ï[÷q[p®Wf¾¢§®e¸ ¯ uxIyé++œ¹¾›ë!M´e¢éÉOòüäÙçbe›ƒ¬É1oÁº¢WˆyO7ßlƽc¶O» /šï¾ŒPÜgd}òÑÆxýõ µ=aü ÚÔΰÝÃw=\ûãQvn¶³V6n|k„IÅbdß‘òýâ﵋‘Ùå8?VBêY+B"è¼Cg½D¸Ç@Mö_ÿùµN`Ó¶q[°ûí7g&»/æ¡3Óa9@™Ag¡ßcü;ãíÉmOb4î¢Ä%¥ù 9s}—rMæI˜ Š£ÆL£g“ºaà 0¯a’:¶Û±q‡Æ±ýÔk߸}t”Óãåó“þ0WñQ<8¸âͺåPE€Ž&Nòüç ‚·Án±€ÿÞj£~S|að•O…EáWpX­5ÚpXˆÏædÇ}wÒ#'éÀß뎼Nž9û9{ÿ³õ:‰iHRCà.æj? X²Ò13hä•'ï<>üVõ[…kE¢m£¶á¿"Ápaú­ž­{êì{£Þ¥ûÊ[»UÎ9à¹æµk¤Ï}äÆI7Ê~í÷“É#'ˇ—(7}“ ÚsÄÃ×NdýmSn“9A޼ÿHÙóÆ=ó¢é“Ù=éH¾‚ƒ¼Èù+¾QqŽ“c:FÝåP>±M£6áš‘Àì5ó†™:Òµiݦá­ÑÁ~ê}{÷ú¸X ¸eöèÙ²õá­rÛq·Éù/œ¯Ó<®ÛœØ0=‡$j™’‰®];£ÙÇ‹fG`Ü;Ö‰`ªÛxà˜¢|¢³æ%!‚þz4o\älŸðùßþ€Èëç¿® æø`„=î>ÌÝ´ù‘J— Û¢ÏIÏüôA¶=4õ)s¦HŒÚ§Î ›½ní%Ü~€Ìýg®ÖÜ54þ“ñrÞsçÉÐ'‡Êœåsä´}N“×/x]>¹òyâŒ'ôL|{´ÜC»/qZCw2»'ÉWpœþøéZ“'ÂóUȽSïÕ$†† Ù½0$ZŸá'Çv?VûìrwÒ£'élQ¤„tp(@¢hæ6¾0ß7CâH†/p.4ù¢L#‹ð€á÷ëWtoÕ]“ EŒ:Z9xàÔtßt˱·HŸÎ}Œ9\ ˜þË>ûh=ëü¥„"FùÑb¡ bÝÖu:Ðî„î'È/Ë~‘Ç>}Lç±òV a¹bý ³ôÒp£ ¡Ý~ïá2vÒXý»Çu?Nî8áéîÉ»OÜ ü;ñ‘å¶ÿÝ&ýú‘¬ß²^ï«èp$_Á1kɬ¼`7€ßË~<å íÛs ŽÆ'¢ŸÉ.}éRé{W_LY¡’ ä”oÑÂL)‹¶EùóϨtÀ<ò‰’»šÿú"têœ?‘(ü$€Öb|«­vLN•Q-CûÁ‰õ!Ú|æfj·_0ÏÍß"í³r³tŽ{†–ù/ %¤q­è|øàü»@gÚà ôW=Z÷Ðã>8ªëQ:}÷äK&Kß]úÊsÓŸÓãýéÃÇΔ»ýºôÓ÷EœÁÏ7þ,Où”6ù·ø;þìpmÖ?ûé³u€ß¬Å³tüREƒ#ùró-3ËQ¬B.e?HZ­ž-œ¯¬ÁÇsøn‡k_×Wó¿’~ÿ(éýXd£{í53w¼DŸˆï›z6Ç|Q6ßV& ˆÛ,šV0'k&ÙÞN}ìTMìïüðŽÎd‡ùý݋ߕ97Í‘5÷¯Ñ \ FóGêÓWQNÛKÌKJcA.öû¡ G²péÒ¡^Á9ðé£]¯Ú´JšÕkÞš„‡.ͺhßý3_=AÆ\Qù$ûà²døÃõt¹Ãž¦]™-3j‰û$ ¹<®:ü*yù¼—µ€pË1·èß$¿Èqã“ãȯ\¡ƒš‹Á_pÑõ匷g¿mflŠñ"`ÒúlÞg²hÕ"iÓ¸þÐbùØù˜éè®G‡·”=è(üæ6>N²ždB²¾ï•>º>3SdÐ ½®~»HQìÁwœÉ’1ï 7óÈoÞl"ì1¿'vžÈ3 &¾aŽxÌÖ¸1Y³¾=@h8áádÆÂÒ±IGiÕ¨•6ï9ÿK=¾{ "ãIZsð]kŸ8‘ïøÍ:í!½Ÿûé5º—|¿2ÿ?ˆä&æÜÿ÷ý«ƒŸüâIyõ»WõD4ÇsS.[³L&ý0I"0;'Ázñ¬ÝÏ wLFwoÝ]öÞio]°‚€Òü†\t}S6¯×\¿Ð|dH±þ²{ËÝåÒ¾—ÊÙ]ÎÖKÖƒu8Žã9ç+OÄJÖãàPbxýu“:V µšlñ{3=ß7ÉrHi[TààØµkcޝOVéø÷Øéé$0ÛKð˜úŸûú9=–ý ßÑ IaPl>ºâ#XìÇË~ÔCØVÞ»Rr'äÊøÓÆkó¸óÖÆ€ŒFðMÂÆÕ9â ÚêÈðbÌógLÔ× -´Ðõß¼ðMmªG8AKÇLÇ”;ô\öA xçÌýÏ”ñCÆkmÿ…a/hé—å¿È/\ ?ý‰Óeü§ãõýD›ƒ¿¤Úºu«—‰dìߪU+YµjUTM~ªzÁSS2i6$`ªÃ/þøBÿ½Sã"üî9Jû˜3gŽtéÒE)+ùR'/ù”™õé€öè™ä¢ÍžT–@jÇÌ5sÑL=~Ÿ$…™ó**’õ}çnܸqåÕä 0óÁcª'âýî»Ey$¼³0üW_‰\sMxC$bÞS!ãëƒ@ñG`1‚奸'òŒÐäq­Atæ%•ÿ‚ñï#_©SbsÞ7¾C“0Ä>í²iÒ²aËB›Ä5øÅ1ãîM~öªÙy‚ CzÉÌùÑoE%y¬Ÿ]ý™Œ}w¬N”ƒðbA’¯Ç>{L[TÙwb ¸¢¾—Ù>9¢'Ï1]ÑÁ|øè[•öëù_ËÄiesͺ ˜?„ã¸_†)c-.ì7=z´wã7†7çcâĉR30yƒCéâ¯Mi3ÔÒK¥AF©[-v½~Ûz=v¾eí–Ò½IwiV« Ê¡jbóæÍ2xðàÊIò¤°}øaSIj8ÀD̘mŸ½ŒÊ¼1ï)<1Íß9äLyF¾IßOöî[7&ySÄzÄ•%âE(-$òŒ̉‰–ø¦8À\ýð'kÀÿñrÊ£§ÈßþÖÃßZ5l%_ùq^^a¿Í>|å똀;îgâ›åÅe/ʧó>Õ‘þo\ø†>©eƒÀÀÌy3£€øÍ{O¾7b&<”«G?{TÞýñ]9¯÷yZ0I„ì®V\oÍzKÑÃ]‰5$Éÿ|ÒÒÒdÞßó´€0ãÏzTÊ^×V]µ‰Ÿ<X @É;M¾b— ‘$ v褥Ԡ&ϰ¹ÏÕ‘­}:õ)wí½²"Yßw¾áJ§É[Õøãͱ˜ìa×~ý {ú,\1‘@º˜÷þý#>¼B>È:Xr%5.yQñ/5”é3RÀÿLfL¢ÑÚã(é~sw3Þ\ý‡î|¨L½bªþ; 7P&]<)O£õßÏüUóuÞLâòúøPmé)éÚDþÌ9ÏDáçs?×¹GH†³_‡HWs€`BŸòó=Úy¢dŠ“TØóÉÌÊ”–þ IŸ¡{$ ‰öNÉÈÈб¿~0Z‰·Ï•í/ukÕ•ì¨_,&7€Ô­‰ÞþÍvöSúÑÎãJÉm{Y–Õ«Ó娣ҥY3³d=Z=©t€àQQH¦O7ëhõ»ì’ÁƒíÉB‡@¡Øü›:‡j‚ñNáÏ…?U²iå m–hüóŸ?_î9é= ¨ëM]eÕÆUyf-þ+1@î±Lֻ츋,Y½$oÈDþÁåèÙ4Ñ€ÑÔwÞqçÚ.“мqþ:qÏå¯\®ÇÉÛ‘27Èý®·.|K»¿ïpm’DIÇ$Ñ×£Å_Ü÷âˆ1í'šœÇÞU@ðr(â¹ý!lg?æ‡ÊËoh†SK)æ k’¿¿4x%‘:%Q<ÚŽ©Vìê)vÍ™8Q²O8!jýh%W1­]ŽenÏžQë¥K³¤ÿ\¥{zÉ:ûöÚ+W ئÃgÙ³gnã)&dÉ¡‡æJÆž.=V°NYm{I•E+Éq'ÿnøW^?ïu™4{’&{ÿTªÒ#õl´sD+k7®Õ³Ê·û÷I=O’ç¾z.bóºÍå¡SÒõýÞ/oè,Kÿ]Q‡ä9 yL>œóa^Š^,gGõ]†W 3ýÆû†ca̘1R‘csz+MfÏ–Eô¹))’U«–¤oÞ,+÷ØCf]r‰dÖ7C’â!cíZé6nœÔŸ7OÖvì¨g›‹uÜØ±½dÖ¬&JƒKQdž+]»®”Q£¦ËÚµ2n\7ùõ×R»v¶Üyçgº>ÛæÍk ;®‘‘#gIýúù.ЧŸî"ûí·B:uª\!¡ŽO—}*Ó–LÓJÈ’ Kô¶ÃZ&ï-xO6fG¦²%vhdבR?£ðg®_(Ÿ/ÿ\†î<4¼¥ p]Þ2ó½÷è¥h쌱Ãìè+»5éVà÷‡¾?T6då'Ï©“^Gž;¼àÁ›³6Ë{ ß“_Vÿ"Û”M{Ä´0”Öf®•q³ÇéhüŽõ;Ú–66Ç‘|ÃÜ¿æÊ#Ÿ>¢'—!5ã_ëþ’ŽM;JÖ²,Io‘.óþ™§/0¹“0Œè3B:5ë>Ú¡$QÞ÷^¹ì23Ëi¢A\Å!y4ùDcs,hŸ2‹YøûoI6LB3gû·jÕyiœias&M WÜ>Ø{:ûì£dõêüN~ÅŠÈlf\"§žêÉw¤È„é…Ôóñ”ïɤI9Ú?lXªLŸ%“ÈŒÙea_Zψ<ð—½r™ìÚ|W=ÞýÃß>ÔÑî¤ÅW ¦ýfÈ­­vÒEE{FoÍ~K§Ê>kÿ³Â[¢ßÏÅ/],³—ÌÖ}#Ú.#zö¼iÏß8°×濎A*ÒuÒ'?ðñ2ýÏé:»çÛ²/Íoˆo˜Øg®¯`X¼z±ÎÏ “‰©ÏÜ÷LéP¿ƒ^²ÎvöSú•Ì·¢Mùé'Q¥‰/Cƒ‡à  ^56Ç–Dê”HiÙRR¦L‘:BJÚàA('GRñG=¦˜m=kÕ³g¨@½»ïN•›oN“o¾IÑrrB2sfŠÞ?|xº"ÿ%l…dùòœ~zäñeU@´íE-«·¬–£:J^ÖPö»§œ×ç<}ÔhâÕgc9sñLìÚLu¬G;g¼²põBé¼cçÛ‰fH<©CØÃŸá·àÚ¦/˜qlQ¯³qÝÆrãÑ7êlwD¹3þysö›ZXhvU3Ý>´S´ccm{IàH¾¡'¿®øU›Á:4í §I$]¬5dzdíì§ž­ïP¾ ¬Iü´fɺÅìÙ&°›e"X¾\ä˜c̨°Ûn3)ÚÑÜ1ѳ,km°Â¡”gxÃôîŒG ' ?ä k¯5K+°´—ãó3f„ÿHR0œQ?37ÊšÍkä®÷ïÒÛ£›áj$ò;ÚTµ‰âþÐcÅ Ã/+~É î³i /ƒ´„©Þ¢g€Eq¯“ŒuýóÞ—ëÞ¸.¯_ÑRy;’¯@àm\»±žÛ&ûh`;û©GýŠ8)BUÓ˜CÂtê,Y·`´—RBuºõÂ@®–¡CEî¹Çd_uˆL˜4JÉ´o=77Ÿ22Œ»$ÚóÃÂÒ»·ÈÍÓºuþå ‹XòÇ¢[½ºHvªh®V¡€,mt·%T« ³^X¶v™žÞº0Ä2–ܱDç#sÿ¤Ñ=ùÑ“õ°¾’ç]³eM!£"Á‘|BzZºœ²÷)Ú{,X­žúçP¾€üð¯[wq<·1}ç}÷™Äm¤Ußyg34 \Æ’u…ðp¶Ò2m<‡o@ÎhæãÆòþî;½9>h´}²Þî·ŸÈÊ•æY‡¢ïÚÕ¸_Þ}7|P"Öð°’ÐÚ£"‘1êñ„ {mä­ÿãÖ?ô„_ÌmÏôØ9—JzØ\IÑ|CQƒ8Ê:ÂÓ!: b?H¥èìøÁü¹þŸÌß~lÜ(rúézd˜<ÿ¼HíÚfûg”þÐ9‡‚ :žà9ž)ÃðÛµIKyæ‘«®Ræ²pÅ00ד%÷úëEî¸ÃüͳûôS«L\0üSO™õdDiiìÑÀ¨"jïxHTÈ`ÌùÄáõ4³ô ybH‰XA˲]ŠGò%±5Ou !`ª$Xó#¸>w®ÈÑG‹œsŽÈWÍqýz‘ûïùðCâ4L½¢æn©lZ5ˆy°ë‡bJIY<þFt<†‚_~1&ø[oiÐ@äÑG°µiSä5a…ÁzóÇæZ¾ø"ÿÙ±¤îÀƤÿ{Á9M’¥¥±GS´’Ƶ¤Á5?:ôQMø Cf²˜íi*Ëv)É;8”vÛ͘ié/Ðô !´ò÷Þ3&[ù㟷ÄÀÌ¥#F ‘ ;moð`‘–- Y”b|YRb%®«KÚ‰u,JiY<®Û°Á˜å;v¹á‘³Ï.hiÁ\?fŒØð¿-Í_-²`A~Ú}‡è€|O¬sÉ“…Žõ’D·ÖÝäòÃ.—Œ´ „G>ûÊ GòÛýûï#ËÒ¥"7Ý$rñņäÑÂAW¬[²bhá[o‰ôí+rõÕf‚5ü¶Ì¤úì³¥_–T RÝÌàÑ0Úš(v+H•„fþû_£ÕóLúôéßߘãý–Ü1˜ê!ú'ž0‚š\ïœ9fâ<\4ÑAtú÷K¾×C…K+ZýÄž'êY;3f>òI‚³&!É;8lð¥÷èQ° M2õ8$îG0ºòBøè#pwçá ¥_–T°îh†¥@¼VÃF Âʲ½DÏo É£±#”u–ÈŽ;æÿ6K"ì?œLc&&Ámß}#¯x‹!CŒ•Ç!:üQü¥­>zÐh=ŽéfI¼óæ÷o†÷T.8’wpØ`nO £jBà<ç^qˆV ó0…C˜(K„ˆ• 9b¬† ’J„ËäÉ'Ež{ÎÄK|ù¥¼¼ëÔI¤[7c9xõU“çàüóÙÍŸ¼$hö\_¯^Æm³®àJ‹²ŠV'rÿ‰3žÐŦ­›ä¡’/æ}Þ[yàHÞÁ!È~6hPjLÓï‰'š@ªc5ë~­-ØúÏy8ŸCA@¦Ä9`&çY0>}þ|c¶Çgޝ­Ë¤–|æÛ È-üÞ{E-2×Àð8 Ý~»±`Á¡ð,O8Aä”SD®»Ž|ø"Õª‹À>û˜œQ–Ñ굫ז'Ï|RB)!Aô†·n_–ýÞ[9àHÞÁ!È~6ujH›~1cŽ0Aä®»Dþó(‡/`¦·r‰€ºL>óòË&ÑJÓ¦áQÍ}AB ‹‹´j%Ò¹³Y"ø9C¸ãÇGjùÅALÜ#2z´ÈŸ«Ñô~Íœßøë/‘.]̳%HyvÚÉŒµ?é$©ïPe­Þ¶q[¹ù˜›¥nõº:;÷La[YàHÞÁ!üÙÏè¸"Õ¬™1CLCvºW^aîñÐøÚ(Ú;¾Ãö³8N{¢E"áö†)‰ô–¨~-œvÿñGS§¸ÀDi_z©  Œ†0Ú;Ñø·Üb‚);t0ÖˆŸ`=ÆÏ;”?zwê-Çv?V'Ëaò¯3žñnY¾n¹6ÛwÞ¡³œõôY:Â?™áHÞÁ!üÙÏƆÖ¦±- Œ«.‰1ܱåí‚%ŽÑ D¶³NœÅÂ…&í©§šgW @|ò‰±àxóMcÍA˜`¨&û»ï6æz\LŒ‚B^ê;T 0ÈSg>¥“ä,üw¡ìÔh'ùâȼ!}ÉGò%|ó~`ÊÅ_ŒiŸ¡^¬ûLsëP:8ùdC°ÄQ@ühñDâ­OðÜgŸ™¿{,¥Xy»ïn ˆI¾Ìô—_.²u« Ð$8Íqöhúö=À̓Éߡ
þN}@6en’ï}'5«Õ”[Þ»%¼7ùàHÞÁ¡Af4?0Í¢=2m,3™u”ÙŽ¹ß-¦^‡²í ù‰qíL#‹NlZý=÷„)﯇ëhôÌ?pÛm&pøpCîd೉‘²Ä’°e‹3Ϙ{F Ý;TìÚbW¹è‹¤iݦòíÂoe隥òøç‡÷&É;8ÄŽ|ûí¦‘²ÙM¾øÞÑæ0Ï’ÿœ ,Ì´ CcÄ@‡²ƒ«Nî’C5>9å7n )²¯+§œ’ª 2. ðñ“mžL†ÿ÷f"Ü\`´v"ó±0-þxñ\>ûЇA{’ÝZì&ûuØOþ\õ§|ôëG2é‡ä ¤q$ïà †dΜ†z™ f³À$‹Ÿ!)Kí¥hsø‰‰¾¦ƒßžo‡âƒ@9RÔb¶gN+¯d¶¹éÝ{©ÖBzZX²Óab/ uò)ð¼ÑîqÉ0“fz‚ÿpï¢Ác=hÓÆdÈÕ°n]ø×ô¿F–­Y&‡îr¨dçfË„Ï&È×|Þ›p$ïàhzkÖT×>ÛDÁãwµYÙl4>š<¦Y&®± ƒG«gúX¿`àPö`äW_™çqÇ)2kVSyôÑlýÌxöÌ8Göºþ ÈOOÎ|Lñ:ñÄlÛ&ràæÁºƒŸ˜ f#t¨X…BòÈGäÃ_?”îmºëÄ9£Þ%¿­Pz’À‘¼ƒCÐ!“²´fÍl=Ü*Q³móæ³²L´äT"ˆçP~@kÿùç:tŽ\qEšv§†av¤Í%K]¢y^h†Ö‡_þàƒÿŸÀ?f°cÆ{˜‰nØÎøþâý9”.jT«¡SßN3Uª¥V“ú¦³â-_›™ŒÉ;8DæÓ5kBФ7é¥_ /üÉR*6öß…,X­‡Ü1¼Ž=æˆG“'Oþ~û™)c>y´uLõ¤ÂÅŒO>~{òÝ“ŽråJ ÈÄ7-´[½UûæXúƒ é5DgÅ[·¹âûXÉ;8D/\õê9:8ŠÉHŠ ‚ºHq‹O–%VI<ܶJ¡ŒHy&µ!=.>tf–ÃÏXx´rö㊉ÎÃÄ5Dî_t‘È‹/šüúþíOò;Á qÌ‹àP1±O»}äØnÇÊuv×¾{MÎÚÿ,/3K}ØŽäª$ðƒbRU~ý?ªaä:u<½­ž-ÁyãÓ›’a !à­_~1 X’Œc¿ÿ~ã›'@ žlv¸Y&GªÚÂó z¢çqû0Q sà—gTÂ$Bc-â=b›CÅÄÐ}‡JZjš Øc€RwÊ^§ÈÙOŸ-¹ØÏâHÞ¡JbÚ4‘ûî3S†F+øã Œ,YVÂy8_DmÛoŸNœáusE›²Ö¡bƒ!Œoÿþ{#b‘!U-Ï‘QüÉ= ˜‹‹Cö ó?6xøí‰²ç7y$|C…Äû¯|ôÛG2¢Ïyæëg¤O§>rÙ+—UجxŽäª$ÈPFÃÛ bˆÜ_ÚFD4`Éz°Çq<çá|A0S?°Žúß¡ù¡å;$ ã/¿4Ar$°a”ÄÎ;›gÊò¡‡b»dŸÙŸÄ8伇Ü}AFD„–Ä‚}¯07€Cù!5%Už<ãIyô³GeøÃeÚ¯Óôt¸wL¹#\£b!%33Su<ë# ÈÊÊŠZ¢î[ºTrû÷Oõ|,Y/PÇ•í*QÛÝ•b—V­²dÈ,4([µl¶,^œ£9[jÔ0%==[iß&K KÖí>ê-Zľl}<çá|Áߘ0!Kim¹J ðÔñù=?§ýö[¯@ý’,¥ ò ÑcÉÁBƒˆiŸ©‡1á³/ðÁ€¡£Í#,’]à;ŽgÖ<ÜŒwØ>ؘÚ¸¤­gõjÖÓCë&|>Aúué'+7¬ÔÛ<óUÅ=z´w#Ó40Q½‰5y#@¯±c¥É¬Y’¢DØÜ”YÙµ«L5*¼·øÈP"o·qã¤Á¼y²¦cG™5r¤d’ÁÂÁ¡ñ×_5åûï›ÊÒ¥µ•v•)uën ï)ˆõë«Éš5Ò²åFéÞýiÖ,±L6cÇö’Ù³›(m>ERRr¥kו2jÔôðÞ’ÅfŃ–uëÖ©{©Þû „ýV­ZɪU«bžabªRa;ì0%Ĥ‡·–.訇 KUBRH­'?žSè¤AEÁÒ¥Yr dᦠŸÍýÁSäÖ[S¤IO,i?ü!¹rÏ=¹šÐƒÀ·ðÁiê]2„ÏoèÉ#X²$¤Oµ­2·%õŒJ»ÝEð~â]× A©2mZH Õ!%˜{z6I&›*I Å¿0ãiÓ¨4©ÝDf,œ!ƒ÷,ýwí®¥ù ñ 7nÜXB[·nõý¸c]PZ³fòEy Jvq§tò!uÐ ©ß åæŠ—š*Þ¡‡JNœŸ³<:Óª4©O? ÉûS'4o£ÁÏ™ó«êpwQDªz"sç†äðÃ=éÓÇÓZW¢°ÑÌ™!éÙ³t;Iûq…äÇŒ#Åö×®ÍqãºÉ¼y ôüûLÏËì}¥¿°¤ziÑb£œþÒ®Ý:Ó`{ÁùgÍj¢ˆ»èÂ$ýôÓ»ÊÇ·–ŒŒlY½Ú¼ mÛ®“:u²”àP/¯}h¯ï¿o¢öšûµjm“zõ¶ÉÖ­©êÝÊ‘áÃ’wÞi/¿ÿÞ@“dÕ¹sé¶o4 Ä\{íê:ªµPÌvIä=(©:€ë5j?ùùçFúy…B¹êÛ]#ýû/ÒûÛowPÏ$ß#]§N¦<÷ÜvÌ+¯Ì{E>^ò±¬Ü²RZ×i-uªÕ‘Ó:Ÿ&t ×(Xa?ä¢è êÕ«µƒ€l&Ož,Gyd$Ù` Q$¤íˆ°ªƒÑ©¼p`m°³øÃ‘Y'”¹Š!f»;”(ˆz&·ø®»š×8''[~úégÙ}÷ÝT'›¦;"äãܳgø  ˆxßp,W“õÕÏäŠ+ç÷/=É¢Y³4Õ%¨‡Fݺž" \Eü!=KíÖÍ“îÝ=½$˜ ÄÓøüû8GVVþùkÖôä›o²y„7$€IcœªÎËy(¶‹Ío~Ëž6ç·níÉŠ!ý7×–›kÏQôöõ+«W§IGO{á…­ ùeH ù׋ jÅŠ|¡Š¡†¦* ©ï$öu¢]OÒ÷”h¾}͵Ι’Ì•·ÞúGýN ÝÎ&°5ÿºjÔðd„ÙygÞ‹T%p•®&>0P¦þ:U=!óœ÷j³—Ô©^GÏd×±iG½-JS³Â¾z ‘PWª—AlÛ¶Í{ë­·ô2ýåyýû{žzòz9}ºç)uÇ{ñÅp…0l½† Í’õxè×~Õõ”ô1U1ÛÝ¡DÁëzÙež÷裦<üp–wî¹³õÒncÿK/…¨ ˆ÷ 'ŠDÎÁûؽû_ª^nÞgJIKó¼Áƒ=ïÆ=ï7<ï—_üÐóî¼ÓóN=ÕóŽ<ÒóN9Åó:uRÔ£TŽKI‰<Ž¿Ùf®Ÿ{1÷öž==ï =ï°Ã<磌<ïóÏ=/;;| Ák®_ßž¯`±uì}ø ר¾½©c¯7Xèf…¿ïðßg¬î43Óó^{ÍóŽ;δßäÉž—•y½,iÿýÏó.¿ÜtÓgœáyµj¼Nº¬ï¿÷¼Gñ¼³Ïö¼ôôÈ:Üç¼yž÷úëž7z´ç T°]h‡vò¼6m<¯mÛ/#c›ÚùÎQ‚÷dŸ‰¥¥Â覸hxICO†)†—´óÒ¼™ gzûß¶¿wðëýýïíïýµ®à”fßn¿á’Ñä£AÕÌË—›¦$èFãgà0âaÇJzѹ?ý˜=Û¤‰bÎN¢W8Ú;‘.„¢–‡#¨œá4ùÒÁN÷Ücº ^1Æ1Ï›—# ,”víÚJ‡©::Í -ŸD(E1×—%УɑÈ9x/Ñè6lP ã cÈßϸp;ñ î }LíJ;b C#o<Ÿ8¹qÎëíï&HÓ·¯Y´?#0&Ú%ðûäGK·à2|ÂÀþ}ê-Ð~ò.]BJ“5Q󼤡%hމkTóè;†Õ1,’ÙçgѰ¡ù]î9î‰n =2ÜÑUZp]LfÃû‡&Ù;qÿD`ûŽw>RöØ#]Ÿ×Âo5Ë´% yxê©f¿šúñÇ›6¨UËX²è¾)ÖòÅ3Ç Ësc%’TÀ¼Œ4!8‘y°˜Ùûâ\¤õµy8–wÃgTÒÖÕõéÀ:dËgäªï5ÿãá-/Š8â¾#´&Ÿ“›£#ï÷k·Ÿd¤gèùè¿þÓLfÃöÃv9Lþwi$ß•fßn¿á|‡EIƒ f~E¾H¦e"yspà0_j|5$Šf¶Æ’¼û®±‘¾ª’“tpP  ÚïLg§4*éÓg©êÄ=½ÎvöSòr ÜEZùLDÇN΀;ï4yÞbFpôwßr‚iC:vÚ•.bÿýEZ¶ÄŸOð€åG™ýýú™èõîÝ€ 9[B [ {FSCo‡3²$c¿Ë$D‘Dì©kÞ$&dkB"-ç¢.‰l fˆ‘k‡ð˜]¡ÅOð€{&³ï ¿EÁüÁsO¤·ÅÅAþÈ’Bb?„j²-šsuo¯ø‡kï™H}ÿ:÷÷Üs»(½)5bH'K&ÅAÿ:è 3Ö‚„œ™Œ‡ãIÊóÄ&ùmA=ºcÞ}ÅK:í/çÿÏL~~®a â&‹ßuיᥴ é€!j2ÿq?Š .ÇÑNS§Æ$Af¶Ñ6¼#Wœãè£=Uoº~óÎqÌÁC/<§hôëÝHñŽúì§57ªÝH/_=ÿU5p”Ì\¤¤™0¾]…ïÊ¥§ÉûÁONGH·Â~Á¼u¿¼|=¼ô|ñ´j, ­Í“å s¾J¨í;M¾ô1!_¢Sz÷F ÉRÔdÕA)_®eN4R Z IM*"ÊR“Ÿ8ñCyñÅ~J;K) Iù?[È¢ÇZ¡  [@~çgŒ~öôéF°`?ƒjÔÏiBà\…µ Ð%Pa ºš#´M ƒtEtÔ&°]]Q‹¹ŠxþRõš©’¢M$6E™¿€k$¾ƒwŠ< Äq`‘@PD»]° \Q¢9Òü>‚¤f‡Ó1^²´4ò£­¹n×H;Ñvôê\Cƒžêz§Ë 7ôTÛÓõu|­”KÈ•çÅ{Œ°db*Œ°ábQ «åº¹4pºp„5†ÿ!ÑÆ\'Vö1½.׊ijtYœ—vày ü` @gão~‡ý‰ øÎõèaî—kÜ3‚¡~+CBí…5sѶØuÒ #ôP/ÚñÑÐeTùuEþXʃ;,]yae¡É— É~†·ùÖ[Í×ÊSfIz'Þ(Àׯ›cÁäˈμ¹Ø¾,øJ­‰žÄý%ÚúIGò¥ >|’˜`0‚ˆèèØƒíNjSŒL¤!…4[éT*Ê’äã½—|¦~²¦“;Vä !Ûž‡¼íhnœ¹ÒàFcÄœñAædÙ"$PØ™ x!$$ ,+„ÙÙanÁ{¢Û!ñͰa†¸$Ê9!5,ª)5‰sß¼G‘½®ÑâBèÖ0|"TÐÔ³d„mrºÑX¨_ß“ /œ¡ºÅ2iRº~wé2јigô"¦Göƒkå=‡(ù.¬K5‰þMÈ] + ]/ßÝ/‚Ý5ľFÛbíèÐÁb 0½Œï‘v ÏÛÖ—/ÏUBÛ?êiªÚ%E×å:ýíɵàràýà™Ñ>¸#üê@\¯×Ç;Ë3ci ëô ±((¹ëùøwcâ ©u>¨’“¼b5½#Ó:áãmcÖž2¢/_´Å˜1"—\bÄEÞ¨ fí<8÷,iý$Ci¾¦xí5ó1£ÁÓù™íÛ2A£‡¼N8!¿£­H¨($Kþ¶|Яa@(¶0ë›ÿo4*KxtÒ?d ¡¾ùf¤v\ Mfdxê|›¥[·rÀ)ÚZƒ>ñÚ{±u)±âæéŽÐ|ù›ãýdɹOö<€@€.Ô§¹gÚÍ_¿0Ð.¶GçúZ·ÎUïìÕÕÖk®IÑd‰ þ‹/Ì»ÌuA—Š•íÖ‚ss½\÷GÛã: ž­z~pý¶$þ¦o¾í˜äñ+ö¡¹scÛa*É—>ø ‚S¼vV¿¢ ¬I¾G#eøðôšþa|Ñ3²·ßD^¬ Ï ‡PB†bФŒð¥+‚è8„’™IRºDnô YCjøù?ÿÜt? H"‰’¶ÁtͽZwÖâ£X4ð.Föäæ:Ì‘¯¾Ú¤È³Ž"K†’ÿ?AŽt­.$š vr÷c]Á|O»a•à´V ¬,;lcô·m[/ÍšÕUÛÉe`®Éo1Bh FÀþ¿]p]~EŒ&˜"ÐX!„bÿf‰ûMÎõê¥ýR¤ù§ŠhSåðÝÊ'ð®lIB¦µ,p¤àì@\FlÄçÿRy²LèŒíð6‘ïQ]£ž÷çu¢©•ŽäËÉÚîeMòãÇRZŽ1ÒéiþÞ{¦£µ~P:\4½Ë/7ÄF¡ó¶ Á^DžÛÞ ­ìä“I•sbš‡lÎ?ßwˆGgo¯âײù},5(d¨Ë×uŒ†h×!ùlE(ŠQÉ[MÐÖ´üçÝ^ðZqmÜ3ç¦M H>‚ä÷j‰4 –«î'Eu•¡'?ì6ÿ’ß ð<(´9m+v‚ç‚—çf…*{m¶äää*=p“z^µÕõ†ôHž‹<‘ÿþçûØcFG´÷È+ÍdAX4ìó·uÕ+¯AÑýV¤xÖ¥`` ï ÷Âz,sY¼ºéH¨šfˆšc»î¿òJü,E)œ‡óU”f‡ØHÖv÷ 'ŠDÎaÛçðÃs"¥Ø„$Á*ç'‚ &&!Á̦Mž·zµç­Xáy}úD~î”ü„5ù…D)Íšå'Y!OíÚžW³f~}ê°Âu°=Ú¹L±Épò“­ÄJJCa_üó•w)x?E)ÜmfÛv¦ddä—êÕ#K¦øÿö—XmÅïÔ©cJݺžW¯^ÁR·n®z¶ÛTܼw+X8? …Ú¶õ¼Ö­=¯eKÏÛaÏ«VÍÜË&M̶h…ýþóQ—$=,ýÛI²Ã6Ú#øŽ4hX"žÒìcì7¬ä¬20‚™D ãÁÖçxÎÃùʤESÁÇÉ °$  ÿ'¾S"·1—£Єç Fbp¹³¼1Ïæƒî3ü¢œ ¢bšEƒÂDVEœ¿ aúAׂ6g~3ÿ‡¬J‰®Éj™Eìcàþ¬fí×®1gÛ‚&í/AÓw°Äj+Úž}–*m=kàð.¥¥åêsû-5~àŽá]d ¦ó¶m«ˆ¡‹Œ¦ –‚Q4ć8HaÂÈíàõáâឃ1hü¸Vì»gÁuŒˆæ^R¼(ù#òÓ)Us½¯¼"2|¸ñÁG^BtÐr|dØ8é¤ðƪg®/8s}bæúxíCÇöþû±?qƒ„£Î–Ž”N”zœ#h®'Â;^ðäyûõ þŽІ©–À;ÓÉ›¨‹ðÛÁûð» éÆÊ\œ¯Ê ´U¬v•À>œgÀ³Ã¼ïvÐUvvŽz'º Þ4Qð˜ðQàßÇßÖåã‡}‡‚>ý ¨Çû€[ˆÑXÊŸÞ 7äÜ\[Ðl_æzuYeî”`;ÈôE|=‰vBŒ-A{¯bïàÌÀ¯“åóG»‰V¬ÿÛv¾DnãûDKcI°uø›4³Ÿ—Η¸\¬Äî»4>âè¨ýäÁoí>ú}p]h³ñî±*R¥í(<‹h…}~ò -"µ$Ë’m´1‚ÅX Ò$Ln £&ÊìØÑŒÑGSGC'S"Ã!ñ§“—+™!d ð<×Êèík®1ƒÁøXàÞH7Lüø[o™äGƒ™‘öÝÀò€Ÿ¿¬Q°µ¶|™ˆî|…Ö6Á—HŽKZû1Cúl¢?øÈßX "› ;¦¢ÂºЙŒ qص‘ñ (™-þmöïhÀ=c“åÁ{2t¨È…Š\pA®Zç$ù÷Ã;…ËÇæÉ‡äqÓÐ&<7ž!,>ê‘d‰qúÌééOu,~ð»4£<0ùcrå›w”\ÔA¨`Ü?BÄoé-Þû^š(Ys=_¹?ñ4o¶8îš$7øÒ±‰ùaÓØžžÍQÅàÌõåg®/Ü\ß«×jõù6U8óŒÅ"%JÙÿy“ÛœNÙŸÓ¢qÑÑ[Ÿ¯ÑÖÌvêÚhx–̱˜BÑÒIÑZ”t³±À0¿; ©tatΉŽW/.ò¿èàGŒyùe#ÌÐ.6.!—x;MˆvYò }xööùp/–Ø)hâñ`5| õ£µ´y׬™«„¾,uo˜WÌý@²øÓÑúçÎ5ï´Ó­›yWx—xÑ)1¥c &&ÄÆg \ {ÆzÆÜŸ5†¬{ˆë†Ü KŠo„wY˜ë‹OòDÐpõ¤"--_7¢5_©_¢Íî |é´¶ömöÖó[XªÉ—ÉNòÁYèОHfIçÉad±öû2!ÆÏÓ1Sœ£C¦«ˆVè¤-èZlö; (Bûö‰$#Ó臘2§¹þ³Ø\V`h"„&I&p Óõä*M6¤…¤æÍCºýüϳ]-÷ZÔû„ !-„ Î ¡úµõhݸ¸IÐxѰ!a®›g üVNާJ®*)ê¼F°äá>ÐÄù} ê“N—$=¿×KjÞEž9ãìÖï:± @=¤rá8î18Œ®8( ’WMTL@ðhí<]îœA‚=­ Xb?‰ìh~p _ö¨QfiÏeÁù±Û988T0 ]ªoF0á<ü°I]J+üžþ.ÿ8d@bKò‰ã e‘Ðhÿø4_zÉL?{Üq¦#ež4~Æ?cþ'Bšh|<}< åB$tÌÑ€PDj›FC„@T£ 4´hëÃOÃ,jÁsGû-ꢉFD™‘!œÈn²åAZX#Úµ[«4Õ}]Á$/Ô¡X²¤-¬vä~ŸâÏÓ·@§y–¸SÈHNÚ.p“0³š62Áw¼<7?ÐÊ|䨹ҷïb0ÀÓôÂvüæ-‚šäÈuÑLDRsö:¸®ÕŸ†s@¸vØ!€ ýyÂè^±TØ{Áâ°Ây‚q\+±ÖtL»‘<33[|jŸ†êœ!ý;~$Ý0]7“Ñ0†{枬`Ä’öàùðœØÏuÙ¥×Á}Ùí~Þ‚ß#PrÀCÎ hÒèn¤È…R¸>û.Xð>ð¬jÔÈUË-Ò¥KuéÙ3U¿s¸€ f†^â_çw©Uƒa™ ÈbÂ["!Ìà‹÷ >$M4D‰Y”cé :Yî t¦Ðö9?ÄÃeAþhù/‘P¥.MƒsÑ=AZt9¶C§Ë4!º,‚³Ø¯¨@ï‡$0û{G^üÂüÂD áÚÙ¨‹cã ´S®ÛH†Ùøôc.v,tg0!ItæÝçšÔ#ÐÙÚn»Ít—tAm@8¸IÐÐLñ °¸Ûn9꾪{m+óç§jB7÷iÀ˜q4gÚ™g…@Æ=Þ|³éz9÷ÂùiC~›öäºÈJÉæ™ðL© xV0€¼yv´‹ÿ8ž%ÂÏ«T‚ ŸíÜÏÕW›Uæ¼d¼ËQçIS%ÿùpÖ)ü>dÎs&^çÄy_x!ßrD<(×ÄñVXBÇä´çÇS̳ô_7ðS_qP±IÞúäƒZ;o o/‰jˆˆZ˜·™'kµ÷X°Z=b(=¶ž™3ø:*9É—Éä!!¿qNràsUU €N2¢€Ä1¡R×’ä )й_u•©K€æÇ”©¬Õél!H®.­ŸŽž:ü6ÝTPаġS—î«cÇEüË•vßB¦MK‰ DÎ?dˆ: nH€c!<†kñ7B¿Gœm1ïóàÊ`h³DÐ!ÿ>&nºFȆ‚!Á!_DxXáùA×IzV¦!¡kB­Z¹ê—ËQG5“Å‹Ót[2Ù'mÁßW^iŒöAÈ"Fš6ÆÜŽ¡•kà÷@ˆ2çži++à ˆXÐX]Ô+£›¶£M(FÜ¿IAø?Ï× Ö-#ùIÛ¢gÏ\9rŠœrÊaª]Óõs`ê[¯¾2Ϻ ýíùýà=áSæzx7*±a}!—=Âm€e€6„â°2 0p.b¿­ iÁ;gƒñŠŠŠMò±.‡šª£í1¼%ñ@KÑê‰Â_ŸÞ¢æûJ GòåGòE#yüñhŠ…Î ½ñ Cît’˜Wif:jÈøŸ>…ÎB€L,ÐÌû!M’¡ã‡° &:ü Ðâ NÎE=ȨN¥ñý£î}u|ŠÖd- 7®%–Ýè=:èŽ , ç„@0ACj~ 9s Ýã©M̬sè,âÇ“ `LÇœ›qÝ #ô· $áÒöÄ: ƒŸ~ÊU÷:E†õ¥}û6•sŸ´/×ÇïZ¢f;ÑâøÈ¹>ºrÌÜlÃÈŠFÌý2'1ÖL™²WA‡öâ¾ØNøqÇЬóÌhÚ‘çÄ;€ÀA›Ñ~Ü Çs<3½HxêØUR•ÀÒu0ý39)t`_WÎA» p¸$hKJœëáXêYäÝD8åú¬ bÁ»Â„©ãÇ›x޳mæ×äùM+fÎ/ ’W—X‚ Õ°áðdiIÖã¡(üõ kyr„Júßz‡ :C:_>U"©ù\!F¶¡AñôÑáGûœU¨;u‚`×QÐõÔS† Ðº8/dFñâA«¤ç:ø=4à®]=¥Ñ­ÑäC¡„H–@At:|S/„Áy¸nHÿ6®¬V¨†NºFÜo¿m4kKðàºëŒV fà¦mø-\{ÿ,1¤òvüÐöwp,¨¯®/¤»Kîƒ}h«~^¡ È%ÀóÀ#Š•)ZÑðíd ]ñÄâ6@8€q% Á#œ¡ÓžÈkB×jI“gÉ>È—ö£.Ç …ópßðÎÁ3«_?S??ês œ ×BmÏ;Ž!ä`@èÁ Ä~Þ„(€Ÿëå=A/%`ô‚ ÌHž“Ÿà÷qÅæÓn´!׃`ƒË…™Îø›˜tîØržW´e…’%yÞî [Ë’À¼5<5Z•±ÌÁÁ¡\©EŸ)ÚZ>{¿Vƒ¶cµ¨x ÓE ó¤¡úÁ9 È„Ô#Gó5Qþt˜´é* 9̯qm˜j™÷úëSåå—;+² iò€l `:oL×\ÿãÒ…@)~ÐùC$ga÷ÊïB\hÑ(d€5‚@;ÎE€œ&q®­ c bVæ~° Ø =–hŠì‡øˆ]F(@HÀ·>{6ÅÜ/ׄ`éQMÓ/0­Nœ‚]+ FYŒ¥øè‰'ÀªÀï° a…¶di”k ëdî$ŽÖìÄŠ°‹ hçún¿=Göß¹ÒÜJÞ×J»ÓvgDý#P]v™Lxo8'íÀ=ϲF¨!ôkÜ8¡¯u, ¼³Ì`‡Ðdz„úxvOIŽAˆ%—Óïq>ä 4\´nüÁt˜æÑ¦ðÅC6hÉt¢ ±ÃgJ—€É-s3æ[Ì̘—ï»Ï˜R1½BÜ‘FÀÞF7ÂïBLtüAC!žI4:H’ë¤ã¦.çÅ?ŒÎa HvKð€úhËXȼf  iûÉ)‚Þ?G ?ë•äév¦½¾pi ,О\ ¦kH 0Ýs™`…nœzDù[,í‚fÊ4ÌÜ‹ƒô³X* hž„GîÚÍšgA[q­~‚ eĺ€Àøz‚i?È•6†Ðx W i«k2þxÛ°Îs#®« ¿ÉúEÑÖK 0ò¡¸_¸o?gCè>üàï™3£<´F‘4ùl%bþ¡ÄÙöíÛKš¿u-‰x;h=þF´¤O™7ÖÎ PRà-Æq‚SŽ·4‘è‡ §É—œ&_4M>б¡U´EçÏ߀nRŽì о!kH’Fx@kÃÜŠL Ávˆ”u|×<碛±Ú/XŒ3‡ä0‘cÒÇ´íÏÄm«ºŠôîÒû!8:i®S< ûc»Õƒ7ë\—]ŸÐçÄwŽ•‚ó²ŽÅ-Ô‚{¥$ I!@0Ì Râþ ëÖì3Z·n€Ò.ÓäÉ'#ɇ¶ð›Ñƒ×m€ƒ%ƒxÑÜéfƒÝ+þi,\'z-hçÜ›Áöþ߯zÂ3%a¿Û«W–&Ë€æ ^?tÃPBëwǃAÂGø >A~éÑüUáw”}A]ŽO”JxƒÐX÷[»ÊB“/š¹þ÷ßeŽ"ÎÝÔ!©´:-âv¾>‹`x" B†7§âþû’_-ö%+6Ñš¨ÅÌXÎp$_>p$_8ÉÛd8ß~›R@–æÓG#²„Žæ 9bF¥Ž:\wà/Zõи¢Mš.“/]Z| æw4NK¢|òþn¢Gƒdú ›r×€î(žì¸ã&yûí Õ1§ësá…ÄW‹ _1ZADÐUáïn0#,ø-\Údm#탂à¼~!„ãlH·æ‡ßy']0DmµÚx× ¶=вéÊãu¯ –ûÇÕBüÏa Wññ`ïçÀ”™3Óõsç^ÐÎyÏHçKj_ˆ=š—÷‚ô™íœ÷øŸ‰m„R¬)ÖM »×¢ 4ûû G±¹ÇGnF†xˆ›ˆÄ6S"]<°ŸzÔç8D¶Ò$x€}ÎïR€ðé x‚%‚yóh‚t D‚‘Îç‡ìÏ:š/š:'¾sbsñ‹“›Þ< 3&è }#/°K«Ž°„4 p€É8ŒŠtÆt5h®±44XuÉ%Iß¾©Úò€æKP_<‚\;AçùÂÂB€;‚‡X!®‰%ä "ÿ}B´~ø÷­~a`Ù°a&0na О\" »î 0…ßt“±J`êW¼¦)ÁBÉ’yñ‰k ×G­¿:q¼WX&@XòÎùa-Iò›_ÖdŸ%çàÝBh-ʽV4™äó€ ÊgPô¶`;û©GýÒ0ÏG_o Åå:¢=uÉÌÌÔ’¿¿4x¥cÇ5ŠlóLmJpÔþûg+8K‘z–ZÏ’¡C³¤S§,µ?úy‚3&þJ4k–ûïÏ<âæwX’ùÌÖÝk/%]„ÓÑ®§oß\E®YJ ÈRZbÁóÛ²Ï>ùç5çÉâÅut Ú¥—f)]$úqñÊ7ßxZàÑgT§œ9ÓÓ×Àµ¯)xŸ¬ûÏe÷§§smù×Éz´úÑ ð¯÷훥„‘\Õza2ôäŒ3òÛ3‘RØuÇ*ÙÙY²çžYŠŒy¼<Áͬõ˜`Ám))YJðà¾l~NÞ›X÷^- Úö’( Èæú¦B•Õ¬h퇻 ÅŒ—æ¶´PT»RDÔvw(u$k»Çû†ca̘1JcU*k'N”šŒ]еk3äœsú©5__¨S'Sž{.†ý¼˜àwÆë&óæÕW‚ÅZ9r–NŠb÷Ý}w™3§¡Z )íô_¹âŠïòöǃ=ï÷ß7Ukùý×öÜÃØ±½döì&ŠÄRùäJ×®+eÔ¨pÄ^1ïþ‹ƒ¡CPÚo¾›µ4žYa(v*Ê9KºM+6oÞ,ƒ–ÐÖ­[=¤x :ˆV­Z)\•ä§*mø°ÃËëôB¯¼"¡o¿ç›„¯S ýþ»x{ï-ùìË©ƒIhÚ4 )±ÎKMïÐC%'Ú Ó ŒhíîPúHÖvçnܸq‘Hž> Ñ~À¶ÏC ”>JÑf{4¢CõdÒ$¥F% J•iÓBú ‡¾}=yï½°:^D`¸6,UêÙÓ“ÇÏIØ ^Òˆõûï·¼žYqÚ©°o²"µ}"(Í>Æö¡Ñ£G{Å‘àAªêÚ“>Iië™õëK(;[j©V©uOiõ›Tëzii’AT„ZŸôÑÚ§_–à·»'õçÍ“µ;ʬ‘#õµ:8TVX ¾,ï°tôèq¤ ž^äà­ŠÈÁ yÒ¦Í?òöÛ ¥eËä¨í3 Z£òï7¹žY¬ûIV”æýØoxû4ù¹s%eÂñ˜öIu!õæhž¨Œo¾1|8™phÁÉ%Y ù#Š„íîP&HÖv·|Y‘|er#U¶{r÷S±Qš÷c¿á” ¥Yóû ࣕˆ}+Vhm>mÑ"ISËÔ£Ž’4Eäi½zé¥^ߺUï§õýçr%ñÑî®”YIÖvwpppÅ®'|ÔN{mhKÖíP;êÙú¥Žâ“<ãé 6HóæÍ%ÅŸÚ¹ˆ×XTÆ÷²²Ý“»ŸŠÒ¼Û ùxà‚ VãPòpí^>p핱}*Û=¹û©Ø(‹û)~àƒƒƒƒƒƒC…†#y‡JŠÔ1ÌLQ¤¦¦ÊA$ivv7‡2k÷òk÷ø¨ŒíSÙîÉÝOÅFéÞÈÿ[×™t;‹‹™IEND®B`‚pyclustering-0.10.1.2/docs/img/kmeans_plusplus_initializer_results.png000066400000000000000000000506271375753423500263340ustar00rootroot00000000000000‰PNG  IHDR–7‰¸gÝbKGDÿÿÿ ½§“ pHYsaa¨?§itIME⤒þ" IDATxÚí½{p×ïùí (RÄHǬÌF+'‘)+¶EJ£')…"å½ÞÔ­Ä3U‘h[·f½“›kÖ5×ukïFÙ?Tw”ñnMb»veÇ”ïTùæµå‰«ô ¤È¶š“òCÚUÆçN1ò˜EQ”% Ðgÿ88ìÓ§O7 H6Àß§  Ñèǯ»Ïïüçw ƃÄþð466‚ Îèè(îºë.Ïßé™!'QuÁªU«f¦ªªªÐh:Foo/vïÞX,V¶§ó(Ÿó˜ššBccãì3áEXŸ™J»V$¯ÒñøãÀ/ |ë[ÀK/•N^ÓÓÓhllt+Ã0UUU¡S,+V¬@UUUÙ7dtåuâ™ð"¬ÏL¥]+’Wiþñùç×^^x¨¯/­¼Lº‚ –G–Å?[ðÊ+¥ßG”ÄLQ™\¾ Œ9—=ÿ< "ëŒÏ=´¶:×ih¾ðR,D¥36twƒƒ@K ÐÓÃïþ"éëþöo ’-Q±tugÏ:—cƬbùè#†p>Û·o¾Yü~ÉF”ÝÝ@2 LLð÷îî9mîG?€çŸ§G€(ÓŽÖž=@]WÍ’û÷Ë—r˜P(IÕHJ‡¯ÿÄs;“b!–R%‰`rÍ$ øû¡C‡pðàA×òÞÞ^¬q¾r2™¤k_òÚÓׇeRÇh¦¯'ŽÓ¯üWÅ_‚yL}L&“¸uë)b‰"ÕYb6à|Wvð÷gžypX,ؽ{whç¼O&“hoo§9ï+@^‘Í›Á„ʼn ¶y3|ðÁPÈkzzš ±D‘ ZfÓi¤¼z{ÄãqÄãq×òX,ê†;ìÇGò ÈÑ£³#£¹FOÌg,C&Wá’B•D¸ 8SA,¹ŽQ(R,D¸)ñ”ÄAb!–:%œ’˜ R,QÒ)‰ ‚ ÅB<ƒ«½ÇXÚÛOILÄâAYaD¸)rJb‚ Èb!‚ H±A)‚ ‚ AAŠ… ‚ ÅBA¤X‚ R,1/P±J‚ ÅB%…ŠU)‚()eR¬²¯Ø´‰¿)‚3eR¬òG?€ÿ˜.AŠ… ÂM«~ñ þùç?çß ‚ A„•2˜UïèQÀ²øgË^y%Ï(!(S¨º1AÌ—/»õÀóÏŒñÏŒÏ=´¶ºõã¾û"²Y;!¡§‡¿r÷_OO(•(AŠ… ˆÓÕœ=ë\f Œ³Šå£xÀp¬³};ðæ›¹/º„²¡iˆA®0‚˜öï–/ Io¥"©IéðõŸxBúY—@S5¤Xbi²w/0< ¬Y˜yž2Óî¾›¯¿w¯ôƒ.!¦j&H±ÄÒeíZ`dxøaÿõy„¯·v­òƒ.!¦j&ÊŠ±Ä<²r%°cð³ŸÙ{Ã࿯Xpƒ4U3A AÃö÷J%á¿Ï ¹tåèç>‡M?ø¥+¤X¢Rèï2 åú§žâï‘_þöÛó´ã\™11;Þ}‘ýûéb¤X¢Ü¹}¸t‰^½š['Ï>ËßW¯æË/]âë•)ƒÌ´,ï¼C„X¢©T ©TjvÁÔÔ N#N‡æ@ű„é˜è<*û˜ˆ¥ˆÀþw¿ ¼;”ÆíÓ…åçÏ”vÐcKËì˜Ë4 `P›G,„b9tè<èú¡··+GŽd2Y‚§óÿyܺukÎÛ­­FŽÁ|¼htŽ–_¹xùeÀêüÌS½¥ô˜¥Ï††på‹_DâÅÉEA,Œbyæ™gpàÀ‡ÅÒØØˆÝ»w£ªª*T=Ëd2‰öövÄb±²î!Óy”Çyë}®˜wûŽ–7‡ægÐc.ƒ,“N£ÿØ1QVeLóM¾Ñòù=Òì˜)‚ RËÞyøÊWœeò©>AŠ… ùæŠɵk|ÉI§eRH}0šÃ… ÅB„Ã"È–I!õÁÈmF„ªF‹¼È–I!õÁÈmFb!ˆò£äƒŠAdÿ~ƒƒ\¡d³`--È9¸½Hs3ŒS§`d³`‘؆ 3˜u¡ y//ñ™ Aȼ *~òIþ’)¢:e¼« ÷]¹‚š?Ääš58ßÕ…Tnðg¥ f](H^…ËK *&ÅBúAÅßþ6 `*g0ëBöÀI^ÅÉkzzš AC¹ *.—ã#y•¿¼2™ Ê #‚ J )‚ ‚ AAŠ… ‚ ÅBA¤X‚ R,A)‚ ‚ ÅBAb!‚ H±A¤X‚ ‚ AAŠ… ‚ ÅBA¤X‚ R,A)‚ ‚ ÅBAb!‚ H±A¤X‚ ‚ AAŠ… ‚ ÅBA¤X‚ R,A)‚ ‚ ÅBAb!‚ H±A¤X‚ ‚ AAŠ… ‚ ÅBA¤X‚ ˆE J" ˆÂH¥RH¥R³ß§¦¦étét:tÇ+Ž)ŒÇFH^ÅËK|&ÅBrèÐ!s9@»‹‚ÚÝÐDÄ×®FF€‡ö_ï[ßbáëA,xìd|œ¿74ø/÷Br­µ.`dùæ¼íî#  v7T©V+W;v8]b£Ì`ؾaÅ ºÇ‚ ŠBq­l¹'O»ËÛåBÚÝÐåðÛçì6ÇFF º1‚ ŠEã:ókw#Þ.BèK?Éð”âå˧žâï‘C6k¢¿Ÿ ADÑh\gÞí._þöÛe¬Xnß.]âŸW¯æZòÙgùû—¾Ä—ÿö·|=‚ b~ÛÝÕ«ùòK— kwC¥X¦§¦&à±Çœ¢µkÁÁ vîü451R,A Ðð$²u_Iãö¿ùVàÑýÑ0`m-?]êÛÊ•À÷¾÷.:;ïD>ˆÅ€]»(èO”‡ÂÁƒ]Ë{{{±"Äs:$“Iºx$¯Mú§¸cr¦eÁ2M\ùâÑìX°??ù¤ý¹ÐÒÅ>òºuëÖ"*–žn¶ q+…‚öDñÌ3ÏàÀ‹¥±±»wïFUUU({àÉdíííˆÅbt+E^<ìßöÎ;À† H¼ø"\„vT–×ôôô"*–R¸Ób‘ˆÇãˆÇã®å±X,Ô QØäU wÝœ8€ÏLo†@^™L@çc!‚ ÊR,ADIq¹ÂX.ýWdº„…t:[·najjª¬Íy:ò9ñ ˆg‹°>3•v­H^á——gŒåÆ€ÆÆF’A䞉êêjßßé™!ƒ)Ý1˲ðñÇcÕªU0ŒðÌ//2oFGGC™yCçQyçÁÃ7pçwÂô™°"¬ÏL¥]+’WøåµjÕ*ܸqÃm±˜¦‰»îº+´'QUUU›Î£<ÎÃÏR)—g¦Ò®É+Üòª®®¦à=AQZH±A%%òýïÿûes°‘Z[[FË[ètttŽ$¯ –WÙï b¡©”à=A,ô3ãRÇü1¥M„Äèè¨opžž‚pâR,«V­š}˜äŒˆt:ÞÞ^ìÞ½› xüqà—¿¾õ-ॗܿ“¼ #Œòi”â™ðÂ뙡ûaiÞ7KY¶â™q)aÊ«©vét+V¬@UUÕ’¿€ããÀ?þ#ÿüÚkÀ /õõî‹Bò*ì&«¼ò¹·¼žº–ö}³”eKYaEpô(`Yü³e¯¼B2!‚PÊC._vO%ýüóöŒÊŒÏ=´¶:×I$HvA,MÈbÉCWŸOG~ýþ÷Ì¡X>úˆ¹ÖÙ»7BÂ#ʱ1`Ï ®Ž¿«½*‚dMËÜÙ¿ŸOt™JÉVŠês·¿C?½Ž=}}XV².D¶‹;ç}™±v-02<ñðÓŸz¯÷~Š—âƒkGQ†(" ÅÌy_ó¨Gz†Ôsbb›7ãÁ µÅRóÓëä½y3˜°X"‘ÐɺÙ ë½òËØÐÝ --@OÐÐPðfV®vì~ö3Û%&cÀÂãV´4QË[áÌeÎûPÏ£>4丹X ÆÑ£0Ë Áýüô:ŽåmÓÐŒæf==¡”u!²ëU~ð¾»H&‰ þÞÝ]ô¦†‡ÈlLÞr¼GÅð⊋ Ê­óµg›°ŒßÐ`×®¢:aD¤RÀÔpú4Ϫ~å+–ÁA çÇD6Ë{eEÒßd2@i,G OáY,G dA oWï¡‘(ßÎW: ‹ííÀáÔ!6ßr?s†Ë=査ºH±”--¶™‰ÍÍEmæömàÒ%þyõÊO0l¶àYü5†ñVGþþûíÛô¼eÄ… ÀÉ“vç‹1 ª 8~xúiÛÚ?qhj"å2W«PVÒƒƒîõÞx£"¹YÑனöv¾¼½½hWÕô4®{ ù`Ö&>¬Åÿ‡ë>t¡ëÖ‘b!ÊŒ¶6wÐÐ0ì†O(€×2šƒ+™¬BÅ%ßÒâ^±’¸í›hÅ]¸lÖ¾(Çs×ÔñãsÞ|m-Ï ãÕÓyÇ+Ù§xùö·a ä!§D9qõª{ÙÄ„Ýð8áüm®ä%ê’?}èíåïºÒ9ºíÉb™¯ '.J G·Î*±184HÎÅFJ…(;êêÜË, àÖ½\]Õ4‹v%/yTë$“~Ø{`ÜÜö¤XJ}át±”f…9¬£‰ §9CÙ`D9r挻4·x†`Ý:ÌÅx¾=ÝçÅÑÓÃe(`Œ[‹²«p&O”±¬ÍŠºpr,Ed´ÈÉR™—ƒƒÎžÆõë|%eÎåFSpå ï©VKw7ðÖ[ÜUcY@’µ-kµ–áÓO»e$\h"ùé§½Û®L&Ô².‹¥§زÅ6ÝkkÏ~V9K3/cϾL¶b^}•?h:·à ¦)ÖÛ°6"<.Ëâ –ê¾R3ôJDðþûÞ.]‡k©ËZ(• @òe’åëÜ’b)! ÀªU¶ò¸~çà«À¯—áå2ûâ†ý’ƒiJÌ&ûâ‹Ô°‹oÍçËÞŠ*N ±¾ìï—“·¡kô–j–X¾Z…º A¶!ÚÝÔÀ!–ue¤«šÞ0œèk_sÖÇÆx,Hž¸¬4::xZ :ÚžšD­y¯ì-a­«eó3;æR]ͨa¥fEŠí×ÔØ Ÿˆ ,5tñU'W r½D»2: tvr[}=ßGˆ3ò*C±¨š~ëVçÜ–‰3 ·ößÚµüûÅ‹ü"«Ù†AÙ`DxïÛTŠÜù=/:UMM<6©ö¤£QþŒLNòç%›åë0æ.B)½M›ì¬IXj¨åZ„ ü*€¨×LŒÎ–ŠNÖW¯ò¢¡¡îÀVÆD_jÐ]½(uunËDõ!G£níï5y˜¼?ÃàÙ²–nà’ò}{挽üäIžŠsËZFô¤å˜ ¬Ä×Ë`lÌgšvÕâ|׬·—+~˲SŽËÌRK>7”Îw©Ë#WÿçõÀ44ð‹ÝÜÌ{¢·Få-ˆ0X*^eY³SæUDOú¾ûôÉ*~E(ׯw>K÷Þ[Ùcº‚Tè¸÷^®Ä;Ý´òvd·¼eñ¶lb‚_«ÏÞ{àwHÇÏES©R©Ôì‚©©)@:FZr‰ÏiÝ4šaçÈDöï‡ñÎ;`6 {ä¿þê2åÜ"ÍÍ0N‚‘Í‚å2½²¹u"ûöñß`ŽuÊZ^‹@åUv×._Y/ Þ³³Iêþ_Sc÷¶»ºlKèÄ þ›Ü+ô–~%Z„ròŽì5¹qÃiê:jº¶*áÕ!ÐÉÑË«²ØŠåСC8xð ë‡ÞÞ^¬X±Âµ<™L–çÍðä“öçáaïeñ®.Üwå j>ü“kÖà|WRÇŽöôõaYî†00\¿Þ±NYËk‘“¼nݺU¾îÑPÕֺǣÈtvúײ{œ¼~õª»ñ›œ´{êñx廯tç'¼&‚eËÜÿSc¸êõŠFª*._Ý5 š¢‹å™gžÁKcc#vïÞªª*Gï-™L¢½½1]ê[¥òíoóN€]²5³y3˜lÍ|ýëH¼þúì:KV^s°Â&/a½—…k¦»›÷’goЈsþ¡¡!®d+¬¾Þ ™¯NX&ãŽË¨Èc/äA—•–~\Ìù†;¾¢ng×.~=vîtÆÆämŒ¹Kñ„PÖÑx<Žx<îú!‹ip¯åKŽ£GgX£¹FOL’ל “¼ÊæºÉk—3].\àóÖOLðõ¾üe¾L­Ä+JºŠ<öBM¦©$Äù ðs°Ë´ˆÑò«VÙV‡a­­¶BnQf³<ÓTÈé½÷ôû½vÍíê ©¬£Ô”‰júD\3ŒqwŠhpíÌ¢¦&g·¿hksWâ®-¹§ìåR‹FmÛxchš|›"æP©c¹Ä³¿g3¾!d)¬‡úz»¬ËáÃ|ýÁA.'‘I*—ÑÑY!:‹PµTåk™›ôTD¸fòM!ªJ¨>ù«WÝéÅjVX4 ¼ù&o(Ujj€_ÿÚžyrrréÌ*é'K1þGdª>ý´}=ä²ù^“nßn—ËW-BAWÏœ˜°SÉC)‚(GäyˆNâ£äåÑØ^Óo«JHŒ–ɽ÷Ú™]2Û¶6ðý¨½è±1~ ^…_‹™3)l²Ö¥ôª²”Ëã¨J``À;Ž51ÁôÎüµv-ðÁvÍ1€+™övÛò©«ãS„ˆßEU÷¤“+Œ $hоL©Ó©#ûöÁ8s¢?Ë®]Û½Ù_ýŠÿÞÜ £·F®áaé4ؾ}Ⱦø¢#Í7nÀèë㙌1†ìüˆæ-#÷_cr,™äŠ(±“VZZ€}û`d2ö±€i"#§æ¿ñ†},gÎðcyýõ9Ëa!ÒÔ#>Ê;qìÑG‘ííµ‡1 òú„éôl†(ª«Án߆QWÖÜ #§¼gÏ!än\¿&Ë<÷Û¬!YU…̯~…ÈCÙC Ôu01 "›K&ç$çbd+Ö%ÅBRhоL©Ò©÷ôõANh5ÃL_NäRÝã]]Øk`D6ÓׇÃÃŽ4û=ßùÎìv 3ÃÃÀ7¿9ÛÀAj¼Œl©éiL®_ïHÁßùïÿ½óX¤¦§geO_–I)ʳÇ"¥åÏ•ùLSèìY‡,¬³gqLû“ObÓ•+ø“‘Ç:ÙÉIo½òx/¹‡TÅaHךu,ÓÄ•/~ýÇŽi‡9ˆ÷ñ¯|ÕòïÙlIä\ˆlgSô™Âõë×výúuÇò™™öÚk¯±™™Fä‡äUþòòzž¸ª IDATn߾ͮ_¿>ûeØøø8›™™Ñ¾nÞ¼É^{í5vóæMÏu ye;:˜eWñb–a°lG‡{H„ÿ‰¸~÷ZÇ2ŒÙí2`v?¾Ûð9u› ÝN1¯RËU÷²b1§< ƒY‰?‡ÑQf%.y¹d‹Ùr–dê¯aØŸM“Yõõ̪«cÙÖV–mmeV"Á—™¦{ܱ¹æó)Ûññq€‘ÅBRhŠ~¡ëòùÏÌpŸ~.ÉØ¶ ÆÑ£Î”w]JüÄ„3“è‡?¾÷=àìYÙ,ŒS§\»3 ¨©±q£>­þèQ8>wޝßÒcfæç>ç܇ø}ëV÷±Î‘yMSߺÕÏ0rS§`þ»çšlÐU'±u+¸ªÊï",¹gì7Æ+{LþÚÉ=b9EY4¦^G--îÞ}&ã¬5¶ÈñŒl–[.Å^#u0ªN.…¤T¿ú*Ï쪫ãﯾê J§õéå~ÙZÑMCMŠ… *µa?|Øn¤ÄÑž<ÉÓrGFl×Qg§>˜|ø°ÝÈËåCÄöÄï|»j±Iù?j£*Fþ«ÅåŽ(˜HØJ¦§‡÷ÀÕšâüäTi9ÍyçÎҤŠY«eW>ýÔÞ¾z=är-Ë–ñÆøÆ nAÆbÀöíÎÁ¨r-0UÁÊÛ–‹yÊë…tñ"ÿ¾v­³À¤ŠHiöJVãAÂ%'”Ö|©¤tcJ7&y-rº±.U¤âÆbîÔT]Zng§{½|é«ù~×¥Åc‰„>™1ÆjjôÛ1M¾¿DÂN›õK3Ö&-vÎiܺí«×£¾Þ[>^éº^©Þ^û7M}ª·XWȯ¶Ö?½»­Í},jвºŽÇ±Î%ݘ,‚SLEôÚe7”WŠ©ZþC$_Ñ E åvº˜˜ð.jõÛZïÍ KæÌç¾ Ãv!]¸À-(õ¼K‘ëå’·¯+þè…Wº®WáG¯ý[–>Õ[-<:1á?zÿ7܇R‹‚ÎC‘JR,¦˜Š®À$àÌ Èé¤ ÎI¨t£­ëë½û‹MŠ ´\¾DEMi-flG$bÏ ØÐÀkšé”i)Òb½Òuå’-ºâ~Ç®;.Ý5õÛ¿îü¼¶ábŒ»ý*-¨ûY¿Þù]7)– ñ³‡iâ#b~Ñ¥³z‡kkyãŸH¸ÓVuE ƒ~ïìFGíb“uu~‹1öÉ'c)+Ô‘Ï¢WQió„s£¡§[–³”K>ëV÷›×=Whì'›õL)Ž[dGéJè KeË»ôŒzgÎð¼að÷3gÂé (V®²œDæ×W¿ê,ÂùÍoòóN§ùKXMɤÛj”lmÈ®=/ÎÓ»3™¹§}“ŲÀ=ðD"x¡;’WeZ,~=]ñ[m­»7©»W䂎^V†×vt½nÑ+N$œÅ ÕýµÂÕ}‹¢ˆrVX$¿ë¶!o»­¿¤uòÞ7Ÿ|â´€ÔgKl¿¦ÆÎºòº&걩Ïr,æm½ñTZ¸RdxyóŒFõ–®Xßo_55,ÛÑÁR«V±lGG`kL< ¤Xº¡ Rq¶P³šKy)¿N„WC#ªë4Ù­¤ûM—f질äïrj«a8S†ó¹qewŽÜ(ªÛU«òz¥çªÛèìÌßèPY±©®ìu~^•†½ªDë¶äzÉ×MU.B!{¥¤†[iëR½5î0+·ŽU@G—ËbÇX–¨!Å2ãmµú549¿wÞÆ2HدaÓ[É7.EU:ß¾:¾%õV`ò6üÞººü÷Ÿ*o¯ëå£ÐÉ@'ga}Q*55ŒmÙâ^.Ëѯ”¾8NÃàÿ)´Ì]ûÍoÛ¸‘±ßü†b,áôSæ¨ìôbù7»v9‹"ªSÔŠQ9Èkžz1‚Ïžjê—¢ì5Ϻ<.EWEYEßRUåŒ×xUåU§_η¬åãW³¯¼Òå8ƒ×õzï=}ŒB=6]µjÆø˜¹nš:/½¨´ÜÙ ÜwÏÎÓ]Ë Ybr­7QÏÌ+,—šÎrë°ÜùüèG<ÓùÇ?¦ õÀI^á±è¬ÖO>Ñ»‰TËVî-‹Þ¯WìÃk¤¶iÚ‡šy$Žíƒògw‰cô³Âkkõ®=5–¢nC^.b,Ò:b,ù²¯DLË+sMȤ¶Ö‡‘]J¦i[õõü?ùÜ›:zeúYVò¶£Q¾n4jÇ|tÿQe*ÎMеe;:Øí\ŒåÊűYC'eìÊr…•GC9—ÔER,å¥Xò$‘ÃÏĤ{E£ú{Ï«qò+GâwNAgŠÔ=ʲ™ÑÑÒÝ7:*fÌôK8©Õ^×ÌKþ^nÇ|1Y~âdwW¾Ž®’çžýáí<ÓdìïþŽ\aå†LT&^)°cc< W.p¨Këõs§©Û–Ý]~à2ý½§î«¾Þ™JœHä¼(\tòþó¥Õëž eYdÿ~ç.\ài»¦Éß/\~Mt.%1oL2ÉÓsåôë÷ßw¦V˿Ʌ!eùË“‰µ¶Ú-Õb£ª\„üÔykDñËU«ôÿW]}55Ü…ç#ŸË—yÓóçßý®çÏÏ?ïô¦=÷_G~]¾L®°ÐôÀgb«: Ü”2±„*ÚbùàfÕ×3 `–p“è²±DН_Ö š,»xt…+ÕT^ÙMâç’ÑY b_ÕÕÎõ‰à÷œšå%¬ î3qüÒ2+³Sb?øÀ}^êàÊ|éÕ~.+Ùí¤»Wöš8nÅ…ç:Ýuòìz]s]f^,æÜ‹ Ai?Û6¦4Æ•¥,³\ëlßN®°Åi(57Ê£ò‹Òõù_ÏÏ8–2SNŠåöíÛìúõ볯ÑÑQ€³™™×K(Ì*Km •÷Ùå¹Ì§lG‡#ý3ÛÑáÚ¼NmX‰„k¿–aØŸ=ö£;¯ãpmct”ÿ‹µǶ•c•×gÒùÌî3‘àëä|:³ÿÛ3Mþ=uË%aÙÖVïcû¨«c–¢Ü, ïõšÝw]s{A®¹8ñŠFY¶µ•ÍŒŽj×Qå£îç妿eñ¸¥Q&^=‹Åã{é¥4gÍ ¹î®lH&1þíïáoýðó+­øûßDý{§½gá+Ñ_r:„ƒº–÷ööbÅŠ®åÿãø8„Èà0 0ñ=÷å»eš¸òÅ/¢ÿØ1ìéëòÜu4²YÌôõáıcŽýÈëÌz$Œßy'ú4ÛÈNNbbÝ:Tÿþ÷`¦ d³ˆÝ¾ 3ß~¦§±L:ÞÔô´c¼Çúä“|ÜbbÿóÙ·ñ“Ÿ4áñÇ/à+_¹¦ÝÏ™®.Üwå j>ü±[·ÇÊ$9‹sŸYµ “ßøîx÷]–唵òò0sû6ð™Ï`Yn¦Mq=þ¸~=Îww#US£=öÃÃÀ“O6ýàø“‘Ç5•eŸœÄ}ÿ÷Îu, Ù‰ †œ:…ÉDõG»æ9·ä콓ɀ½ù&¬{îÁpë uI>†r½ºþåǧ?|‡5ã_ÿõ³`ÌÛ}j wÞù)þÃB]Ý ôöÞ"WØ‚÷À•^êWü¯bd±T˜Å¢ôf]ß•žk1‹¼¿lk«ý»¦·ÈÚðéõÏöä –íè`ÙÍ›Ýû—þŸíè`ÙÖV×~y$ËÆþüϳÎÙeÕ×3+ç²rn²™‘f)chVŽl}謢Üv<¯…°4rç53:ÊfFG×Ü4Çîu´÷A¾kÞÚê²BtV°¥ùͪ¯g3##žrþão²­[G}­•GɲÉIûx„ÅBŠeÊ?ü±á?ûK6ln`ø ›Ø—>ó±#côK_blxØùúÃJc ù€Ì%cñP§fíx•6ñ»Žb¯.Ÿ|âö±‹ôT9ž¢+~©‹ ‰cñÉ-üöʨjkcW¶|ƒE1“;$‹§³H–Sbµq'¯l/QãEµµúk¯*ùbbºcš¥'®‹šæ,oËkôвjʵ´Ÿ™ÑQöñ®§KÌ0{áJ7^œ†rt”Ä¢}î ƒ`1Jv¨œtãlG‡÷hí i§A‚äÞ5¾üƤÈ\µ±,¦Z€OÐ]-«òCãa&2ÜzG6°õè¾ÑÍj)tçê5¢^—PSHÚ·_ê°×õÐÉNNÖè×Õ™©ä~EÙŽöõ¯ÿ7ZžÙéû÷Sºñ¢Ù¿H&±?ó–c,ɬú. Ç`ØåË'žXÄê­DÉɾø¢=ç{,Æãiê(z¿´Ó )êêÈük×ìßüFióõtq95åøÞ{íyà¯]ó?iÓtüÿ²Ùˆ‘»µSUûnãyö?Í> ÒY aÓ&÷²7øó’Jñ”n¹b³®êo¡zI½ŽÅìôkÓä×L܉¿®â%sîœ÷þ[[ÝsâÈ\¼¨¯ø16ÆS¤¥ën¼óþéŸj‘ɈFy{ôÔSü=áÙéo¿M#ï¥.gÿ\ÄWÙÝæ‡ŽÎ¤×€è/™±‹++ŽB‹Ouc]¯ß+W¸«üzԺʻAFÑ‹‘ãòý$R”ÅñˆÑÚA]/²{É0<¬÷l~ë}SÊ%·@#ïýŽUNõrÖ¥b××s˧­×ì®Â-[l×¥X'hucÕ]&§>û¥ƒ†wÚù–-NkES¸S{,ê­º/°Ò `ìËÿ}z¶=ºx‘±»ï¶79=M®°o(³އôÓ¯ƒýùŸû?‡>ÊØÍ›ì¬sœËâ)/÷KPŸ¸.Ž"W?öZG-ƒï׳1U‰ýø¹¿tÇ–HÌîû¨±-7S,H¸I(åfŠ]wØ%·@Õƒ–¥÷º‰„ÿ6:;ówî‚tþÔcÍ' ¢È÷¡€ò¹: ƒ]5l=γÇðv³ýŽCýôSƺ»ûÚ×»v\a‹ãúŠí­ü‡ÿ ;vx€6 `Ç@“µê_h¯PsœX< MW×t»j¢Q申©”{¿É·d¬\‘n}Ælט55|t¸üŸ‰‰ÙmíeG1¼ªkÖèë[:¼hÈânü†?»{/*:Mdµg"W?îîæ3NTª « •g¥Æ†Ä7nôW`‘ÖþY5FF€‡ö?”GðSŒà~¬]öÏÅu ¼ªû·úÌÞwŸÿÿ2gƒ®;¶ Ç®®³k?†U«€ë×½ã>~ÊsófCŠÅ¸ÏÏqÄ¿ÄõTªM³H&Øluc¯ðÅXŠ\¤×ìk÷ÜcgU,_ÎØSOñwaÞs¥g/‰‹\]Ö˧îc)´®Z<2H!J¿}©%IätX/Wœ’•ôüó>sT!Ë^À_Øî(M oAÕu%[ÔÔiÝÌ‘jŠvMsòÊæRSƒóUo–gÈT×ÑÅËäuüRÁ½f— 0+¨#•›f ž³¯MOÛ×XÐûÄæªä¨V˜›B&-š×êÆ~½¸qÿi}õ¢ÑñšèÉ«ü~±÷ŸòËñĺÃáü(fØ~üßîɹнoÔñùž ¯k£Æ)T%UH"M¾Ø‹ßÔÊãOU§-æ™$Å2ŸøÓ'&[¿ž±Çsè½bsUr4òÞÍl¶®EV,~½_J¿’bþvµœo¶HyP^ý:¿»f{"ÿ/W"‹[ïñçØrÜb‘Ü`É{ð¾­ð4Û)éôjCíuMt¦HjÈ7ïŒz,~³oªJÅoZi?ëÃo¦KŸb—¤XÊÈbaŒ±lÖÿïù~/•’[ªŠåÊVФEón±øeò覒U¤['Ÿ,h»Pmmlq;uÅ¿pë½³“]4îawãÿ;ÒlqÏí|ßø[¾ 2y^¯Œ¼BæÑeªÇSÈ”É^–Wơؖ‡Læ¢X¢©T ©Tj6æ255H§ÓHç ­‰ïò;áÑ#0™þ~D7m‚uäŸÓAI@É— R’šÍÍ0Nâ÷"°  á5\Èûë'?1aY&–ÅðòËþê¯,ÏcšWzz€ÆF×ý1(Ÿšâƒ^ûûÝó}Œ9º©Ù>ü¿ƒƒ<0¬›FWÞW{»{?ù²—Ôu4í´Û8wÓX‰&\ÀýÁgžÂŠµ×ž¬íêÂÈÙønæÿÀ»ønc9–g¯—¦€ªß±ûÁëëíßΟ÷ÎÈëéáÉ'Oæèzîœûȉ7ƒƒº…oÿøq~MOœpþ®ÛWbˆH̘‡BµÑB+µ&“IRAøË¿ä/ ˆ4¯Ò—ªÁN®Yƒó]]H)RÃD©ï¯«W—cr2îXöì³Í°¬³™µ÷w·‰ )³)|æ3 “5¸kÐÛkgRÅbv#"&™ª­ug"‰Fn(DõìH„¿¤jÚ¨®vâÙEíí|[;wgÎØ¿Ý{¯{ýõë½×éîæÇ&ã‘QT‹IŒà~˜`@üø–-&'±2›ÅËx þ{©ÒèU©Ùvâ7Y6µµ¼º@6Ër1b^(Žêjwèž=Þûg&—ßáÃÀÓO»3¸TåÑÓ45ñÌ19ÃKwΪx'¢»Û_&Å´RëÍ›7Ùk¯½ÆnÞ¼©­àJ¯’WåµeK¶¨I‹¶mËÎVj÷©‰uCª›C7[ukªÛÑM”¥‹ȾyÙïÌ÷[Gݧp·¨~ü-[‚Ü÷‰ScñËS³ÜÔsÒe×É ü2¼òÅ>Tw¤aØ/]5† ÅI½Ü uužÛ  £I^=ÊS¹ò6øúG.âœ÷^±€B1äõÅhz ¢Q»‘RS´ÔÙ!½Ò_½ÒoÅ ŽjìA”‰)´ï|Ü7ù’ t±Ïi#øõñJËV¿ §Kðɸs¯bs‰³Âh€$QÑìÝË=‘Fy›ÀÝwóõ÷î]ä× z-t ¬¼~"ÁÝ9º8K&ÃãÃàî:u ,Tãî}©Äb 3àWWÌS.ìšJ9ƒš&_®x)ÇUœ¿©Åbî6ëèpn+u”ܸў×^ÝW:ÍÝ’¢È¨MMÀ•+À'ŸØUæQ¶¤XˆŠgíZåý_oíÚx*Ń÷§O]]vC4>n‰ƒT´fŒÜöËI§m_½º¼©É¹YaE£þšzãFþù«_-ìÜc1`tT_‰·”x%ÈÊFT1•‡wì๨Pì…¬,ÆÆ¸OœpW£>|ØÙëI§íjÇrãïWE@Ä]òU:ohàÛ#ö…%ÅB,IÆÆì2íË–ñÏ<+W¢ô5Úæ»}æŒÀã g¯Ô«d¾WO<ö>ù|Œ;÷#—<ÙµËû‰o4÷ìúú Ûguõü*YFrFž(Y£fJ Zs%qü8W~z#,2¡TdÅ-2ûêꀶ6wV`:͉¬X{zÜIj‚D¡÷…×:¤Xˆ%Aw7o\ECÄüW(y¶ùDM5Ååßó¥ˆÊ©Ãâ$EC¦«7–Ý~ü\)Œñì¦dÒ?ÕÙk_‹!g‘:ìe¨2JVuS‰m‰{×Ëœ˜Ðÿ&[!ò¾t5Ø û:Zì²DéŤXˆòDWÑ·À¢ÿ\™ EËÍ<õ7ƒMZ´x”ÏWÔPuSÕÔðFì׿æ‘_ÐÉ0x/¼¾Þ^O·Ÿ†g%cY‰å+(»½ÔýÚBÈY-ü(ÜEÂÝ—Oºë%+GÝx”|JÝ/uX·-aÕSìrª¡“b!Ê]»€âömàÒoùí¾¿Ã0À³ÿò- «Wóu.]âë…‚žnY¿~k«Ó:ÐòUÿºê^‘{»^ ~M W:ÜÍsá°{·°÷ÌÞøWfÑ(oS)>æEíù'¼¼(Kt?ó%g]B„ìî“mûv~^j £§Ç©`eå¨Z?õõüzÊËb1[öB~ƒƒÜõµs'é TÅÐÓã¬fœJ¹]Æ Q Ò)ݸ,ä°¨¡Œ­¼ÏÃKì&>ã’oÒ¢EI7žk]8Ót¦§)_RŠZrjJt[[þqåôœ©2ã‹äÙ$½*ËËÕ:`¦éN)÷zÕÔØ“zÕ×» •ª%\Š,,JãXH±¼ŒGÈvìñ¢ÖË&L IDATh+;ÅâWÐR-Pè5†b®µätc\æ±²ö¼ÊU½Ÿ>ø ½5Ý4…Ôñó»†AÇùèoQáœÆ±„’úd»˜G_öu˜a~ò¥‘Üíäå»ñ)±în~þòŠH„—gÉ·¿cQÝ>"@­ŽI$€;îஞ|éÒ‹%ëÆF^óKÿŽúšnj@>™äé᲌.\pËL¾^†Áe_ÈÄd"Ž#²Ë¼ä˜ÉØçqò¤º>ŸÅBKÅȫĕœCe±uïU&Åoä¾ê¦ikÓïGr–]-ºRïAæ1)Ò7/ÏYg'wMb9è,uò-ù¼…%§ÊÑË’ô+¡ÊQ-¹£;6²Xˆ%ÁØ6ýàˆ~îsÁz°º^ód»,jVœ.ET–ƒ:VÄ0œÖ™nê4¼ï½§ßl ª…,å*½^)±âz¨)Ðê~Â"kÝ9’žÉ8åxõªó¼…%'óþûöõèèÐgωtñ¶6÷U!ÇW_åÿ¯«ãï~ƒXç R,D(ˆìß;Þ}FÐA[:·×Bd»,fVœNiÊrБ—Í%U§tûйÃîò:|XßÈ…­ KéÅøüñ:å¢[&ËDŒòsqé²»ä,3Óä©Ð"]ü׿¶¨ª×Kí,lÛæÜ×Ö­¤Xˆ¥14Sôƒô`ƒô¾bäöBá¥4ýƉ0f+Þ®.žzjš¼‘ܾ]¯xÅ~jkùKÌé‪ªÒoC”—x²§Ÿv«˜&L]êð®]À/É-€š{¤}}=W8:¥aüU[ üüçn™D"üÿºŽPCˈº^»w»e46Ư©ØaèÓ‹_}ÕÞNg'ÿ>ÏD©I#ÂknK&¹r Òƒ9$ÂŒPš~rP5¹ â¹sܽ#äû+Þ7ì’$'NæNÇZWg»{„ò߸ÑyÝÄ<0a“õ… Üâ÷VO÷5ãëž>íî3Æ•êþÏü¿b]u»…\sÙjë-ûÚg2ü»:OO¾íÅBT*Ù_Ä•¯} ¬˜Ê½•æö*Æ’QÝ1‘ˆ3㈱`e<„kM­<,êþ‰Dô®#/·Z¹\·b¬ß+l‹DUìBÞ^Û ’õçgµË×)ñ*R,DhäþÿôŸù×õÅ(J_¼Xyn¯ ¨rGrG"Ü=%6ñ®‹¨ ÚÀ€ÞµÆwé$ølÃm–Ép>c`6 {äNóíœ:#›ëím¨ L}¿v lÛ6`Ù2CC`ÍÍÈ9‚Èþýö6’I°}û}ýu®„~õ+~¼=¤_gŽ”Z®ž²ö:ö±1DOŸ†¡QÆ,ªªÀÖ­ƒñÞ{ÀÄ—co¯ëü£ƒƒŽm°ñq­ŒÇ"Jë kR¼OLðûbŽr.F¶b]R,Dy±•YóqèÐ!œ8v¬dפTrõ”µæØã““hûÞ÷´ƒ&€™Ï|ÆÌ ØÈ–MMÙr´,×ùoúÓ?ÅŸä¸^:¹®×ø8þxÿý¶œ¿óû¾(‘œ ‘í­[·„…[üÉßü†±ù;A$D^…NÏ;$o߾ͮ_¿>ûe¼“9Îfff´¯›7o²×^{ݼyÓsB^ÙŽf)߬º:{ÑQfÕ×Ï®c™&Ëvtè·““§n{Žß#f)åB\ëÌÊ Ê³"‘Ù}ªÛÑK1¯RËÕSÖšc×]YžrÜç?2¬X̾^†øzÍ—œ‹‘íøøøÜk…=ú(—UW5Œ¤XH^º‚~ ¬XBQ+Lá®S²BVµµ|]1wº®fX]stx!#óåýxÕ›§ë¶ Ï™WI¿ºa~#çÕºmj‡Ék 5ÞJ(çE)Byå cÑ(?§h”'H±,¨¼ò¬hÅâ׈¨rñ*ÓRŒÒö[G×àÍ£E¹¨Ï™ZAX-Q£V–®¯÷—k¡åˆÀr_”’.GÚU, xårÿ‹ÈŸÇ)VÞIçH]ôÅÏsÆ¥Nž,~>t¿ut“±éìUBFÞo¸—‹9fjkéÚ¦Éç¬ñK1–3¼DÖž_6šÈ¸K$øþúûCUÌ3b¹|8øÝïªqþ<02<ÿ¼3›ñ¹çørùuù2µ}Äò½Ì¥¦hEÊ«‹:ß=cs›Ýk])1`¯Òä¬+Ÿ³jW–åü=æUüä81Á„<¾ÇïZˆNEK €99ªÎU ¬°®.àìÙ€ÖÙe†ÁÀ˜1{Ÿ~ôÃ8imß¼ù&µÄ<¡Ž:—̰æ^hEëJSRÂbæC£ÆOžÔþ¡×ï•$gâ<[ZøXõ7!¿ÁA¾Ž\M(£ñq[Ö§Oûg@Y'ÌËþý@<Îc2ö}ª^3$¥,_<ñD@³²Ð§!»äÞx%6d…(Z¿B‡²œüæT÷*T)zв’’·#Wæ­Ô*ÓBFjí4Yº’ÍÍn $õ—µZý@ø¨[',²ˆ|÷ÝvçSÌ4-ßéL“±/™±‹K8Ïï)x¿÷PÙÍ é—Á¥ËLúàwòƒ_p^7»¡.{i3÷å9S³ítÉ#:¨òÿ "k5)¢­M?[g e½`Yaÿõ¿¾Î~8ë«X}”±›7 ÈÚ)ñäL¤X– ¼æ©!+;Åâ'55VtËkR/YžúÉ»è9 –­˜¯$ÿOMýV‹˜nx;å –¶|yÛ·3Ïùn ƒÏÞ9;ø8H °’'g"†J.—_*¹èæíPã)¢D~c#¨Ï­êâÅÉíÄ«ÝëéáçXŒ»ÇÔŒ9¿`¾ÎÅ₞§ŒžnÜHd¶RDþ@ ,?aQrü2•âϙܩ1™O?µ³Ê䘕˜S½»›§Íй=DY|Q8ñóŸvî\šÏ¯um-O^PÛ=9wŽÇEÒiwÆœ\Ô²øKž¬KÍì“Û…°CU°b0Éð¸ÓòåÀSOñ÷H„Ëëí· ´FøÜ–¥6÷ bî=ç·ÞâÏ™Üõôð†PNëçuÓè&“ÓœÛïZüæd—çˆ&¢¸çJíg2¼$ˆ×³çõlvw;ÿW_Ïç‰_ªy²œD ~`€w†ì@»,Ÿ={œ“ÖÉÓ‹k31Á•ˆì+Y/ÞÔÄAƒò”JJóë²ñrµ\¹â½UA1FϦÜfõôp9s¬‹«n~Ýu°,®`êë¹5ÔÙY |ñ å bá;s©w+È.—HÄí߀ûïwwøÆÆxJ±l­‹ÚMW—]÷K(êܔָõðr÷0\½Êc.eÒ¹^<ÅBAy‚XøÎÜ[oÙÕŽëëíØ‰.0šN»;|Ýݼd¼ì²©­%µÊ¹sîeBùŠNµœüÀP]íÀ˜~›«XŠgBAy‚X¼Îœ\M÷øqà½÷ôÿpoC§An°ü†­|½2½sø£Ñ²=Ý‹ªHººŠsi…¸AT$~¹–hk5E"î ©¼zâ„ÍÖ­Îï­­¶òÕŹ"ž…'Ç“·móßf%)–ÈþýNE¢ÎNÔ¥EAy‚XXÔÎÜáÃÎ’/›7»ÿcYÎxèµk|ÖÂXŒ¿–jzq>^}Õ.}ÓÙÉ¿«×!‘°ƒòºÎµß6BNÁ¶–14äT$bJÍl–\ZfÔÔa9Ýõ­·ÜãY ƒ÷®Õx¨að1DpYýM LMQ®T‹…57;Íé­[É¥E刪0®^UºQw±Jê<Î/’-[°bɾø¢S‘¼ú*¹´¢Q}ýꌆ»vñÏ"E9ã’©óX8rœjçNÞ!_¶Œ¿DEèO5\(…§ø™qA”==@S“=Þ"æÊò¸[ìða;EY¸ºãqê<ÎÅÉfyh™3gøuX·Î9ÂÞ0ÊÖ:ŒÒ'ˆ%Š®º±hØ®]ã%òi¼YiÈWýx|œr´ÎѲµMºâ±„ñªÊ+”ÅWæWÎ2òø áŠ,Së°ü MüE¥CNA®¯wŽS1 î£äœÒʹ­ زE?n(«Y—Ÿ+LöUЬ ŠùDq¨Uy嘋p‡ÑóUZ9ËdYÞÂJ©y—ŸÅ¢ú|Ož$Ë… JÕøÉq€l–?oÄü±n=Ø´‚2îÊÏbii±-€û%Ér!T*…T*5û}*W¥6N#­N›C,÷ú=4 B.```šÈ„ø˜ËE®:"ûöÁxë-Ù,X$¶l²‰„{ â2’­X·ü‹˜øëäI;ØEÙ*ÄrèÐ!RÓÓ8qìXè¯IØåª•u_–å:ÈF6‹™¾¾PʺÙÞºu‹+– ½¯Ðô  àW¿B䡇`œ:ekû  Q¯¥œ{R$/øË3Ï<ƒ8ž™ÆÆFìÞ½UUUžÛJ&“hooGLžº6l½è­[Á¤ç*¶u+|ðÁPß7å W­¬7ovÊzóæPɺÙ ý-´÷–žA¼« ÷]¹‚š?Ääš58ßÕ…T™k{"\ò½/×½#»–Çb±¼`u•£Gg§7š›aôôÀ,ƒ;ôr-cY"[±^4hï+”=ƒo›1vQOªì-–°ÉkJžáo©@•5HÖ% Zhï«,{Ô“"yy,A¼'‚ Jk±¨ X.ÓJu¤Óiܺu SSSÔ“ É«üå%ž¦NÅð™¡ûž³¥&ÛÙà½úÃ7$Y‚È=ÕÕÕ¾¿Ó3C6Sºc–eáã?ƪU«`HµlDPttÔ3¥’É«‚äÅÃ7pçwÂ4½½Æ^Ï Ýôœ-5ÙŠgÆe±˜¦‰»îºËóUUUt €äUÞòò³T‚>3t?Ðs¶”d[]]MÁ{‚ ¢´b!‚ JJäûßÿþ÷¯‰ µµÑ(M]ýuíÕõÕÒÕ³Z)I$‰D"‘H$™ÖqÇH$‰D"‘H$2!D%?‰D"‘H$™0¢’‰D"‘H$‰LQÉD"‘H$‰D&Œ)ùW$‡Ïš•Ìšf^–œºÆ‰Œ2WÞ`˜¯HNÅDñ¥A£éÒ õ¥åšS_¦â:+yÙ(æQdrèª[b¦ê؇ž–îì‡÷ú`ÑgSdfà­asxVAÆ€X‡‹ñ¥Q£éÖ £©Ô®ä_q8Ú'93ý=ÿ”Õ ›÷dfõ)Éüäúäèyéõ—šŒt±Û{irÊ|÷{À\qø>ÉEî÷HáKƒÓ¥êL˹G}7i]¾ÄE"bÍ©ÉËxï“=1“SV»çefŽKnæy™^Ï.C|6EfK’Ë»tAÕ•.û1 Öáb¢þQ›þQ«’OïC#üï5·}sJ¾+¾þèdÞ¨+ú  Ó+Ò1-#c þ¼£“ë³”™ï&ú‘™¶jÉ©3Œ¾f¬O‘Q`Éåg¤µ ­[D:Ä:Ü£œÖõ)ùiƒuðÑíæŠ^öûvµVmtO,UôÇi¤º¸âðd^'½"}Ó22v\‘ÞQð󕙽ϸ<í4H¬O‘Q`ï3’3 5|GÙ™@¬ÃÍ1âi]›’ҧ¬dþ‰OÇO»ÜÉŽ;»Ÿ)×_ôÕöh¾LYwÖ]‘œú2}è ¤‰+2˜Jkò̽…k¼Œ|&Ÿ]õ^B6k‘ž»ÒëkOÏ·¹þèym9¼øu¥™Y³V˜kºÒ735̬dñÒnæ…£Tú‡³–´lšÞêì#‘šYsêIÙ’Æ6K’׿*({'¯ÍÓò}Ï!Ÿ]‡Qx6…Éô†*Sºl™²ŠÉêƒ.§¾vEÉ·©†i~N¢~ÑkŽú‡7hƒÒ?Zµpy+mƒørnÛ,¹ÜÙOgõ)ó§ä’ù­SV‡í/_2]Nè\s~Éý9^wèøå„§û³ºuÊ|kׯùÎÒg7uÿ’4e8=¥5¸Ë—xLü¦üNÃxJêÞüùmÄ_Ó¢ònþ)iÈ_øÓlx§â7=,ÅéŸR:œ)5¤eÇ¿Ž½Ž«ßÝH¤7ºËÖT/ƒ¿úžC>»©û‡ùl*†HÄ¢žÑ¶ý™Bë"žöc˺iOª´e>:eßÝ?½}›Áuxš\Ô?2TùlÛë¸úÝ-Ë€v×)ËõÉÍ«ÝOÅüSÎÎÖ¦ÎÛ)v†‘K{EíÎÓü䔥í!°¹û½|sæI=´·$ËŠ–¸á³½;Ãd;';zg ª²:¹9óâ¦äVÚÁ*/õ¿‹’×&­ï~79ލ,ympê¿3ãræI®ç:/™Jæ›Ó÷€'¼SK³ÎLöÑÝÖ’é_[8K¦åÔL”ŒªÎMŽÊ3©y> ƒQx6õ†H$ÈÞÉ©VÕæú䢯zJd§MI‹óŠ3“%Ç•>íUÚ23F¿è- Qÿð§õ õ!+ùå¹)+Im¨˜m<•æú‹_½¦s~²Ó¼ìGšËg¸Ý,J¼äS‰önBÙ4• ä¢Áêñ»>ÙyGW`ÏHã‘ãOþÇUØŠL…7À™+©feÓ¿®p–KË+’ŽØüÒê‰L:£ðlê- ‘H.{¿¶ó‹, ^óÕ›“NéØ:åŸç~÷R¹*m™™§_T CÔ? é5)ùª—S •Ð¥Y“Üz“ûI/MÖ0u^bóÏ´Ñ÷’½“¥índF¶N«ôš³~âW] ³5`ó’þÞÑáõUJQ!ýk gÉ´\skÂHdHÜtkÉgCŒÂ³©Ÿ0D"E¨wXœ"µ:Ù)Ù÷(£ü_±"9³kÖ»J[æ£BûÖc\‡£þѸþQ“’ßýBm^£µZÏS_Ð-Ë|³¯tی€д}N{Ú6´lüªv–Ü 3ónNŽk­á½gë çè–•ÈLüHÛë4uŒÂ³©ž0D"~¦Fbµ?5¹5Ù7ÕRº•ÿƒO:³³dcÜï:õpZ×OmËuö^ªÖcy§| »'Õµ®4ºCQuT»û^ïz½:Ézƒjû»´|¸`I_ñ+Á¼åÝþXÙ’2{¢Ãåv…ô¯%œ%ÓrîŽi#‘æèz^¦¥|Eás¡fFáÙÔS"‘è%;G_”Èh¢Vþ¯¿ÞîjU¥-óQ¡}«ƒq¬ÃQÿ˜Î€õúÖäÏ=*9»ÓÕ $àžšòXryϽ˜©Šš6¶u¼âÔÎK5>ô½-ʵoý2®u8ê]4¤Ôúâ-Ó7«]ÃÅ­®v‰uMí׌Ót»<÷åÐBôGµÎܧýÒàÇŠÍW# iϳ3Ôö:çuÙÞ5¯-•·¢§¸"ùph¡V—ÛŽù§$òòw2o§Ž[×ÓÅKÃ~¸Ä£rüz5h®9uErSw¤ªÓISÖ;f?–$—ë¼®œþ%ÂÙwZê7ÙÏLNÊdtE'¨¦é(X;oš>á…)åß»T§J[æc&é}Õá¨4¦´B÷ŸS&°Ï¬Ú#TÌ’%S{vìÌÍifuËØýKs˜ÚVŒÚ#Uí{šån÷}KZ§wÚa¼< ú£ËœýZ1ž°çÆÏ—fÞÄ5˜¸eû¯vÙ¹tð¥ANºÀ´4õÄIÈM(NG_i)X÷Ù8ýÝϵ‘H¦•Og¦Õéœ:8>ϦraˆDÚ„ô‰ÔøžãÚ{›ûëP~y«Ò–ùÈmßfr6qú‡Âº_“þ1‹©C‘H$‰Ô;JÄf&‰Dš§Öå:‘Hd0üñLÞûÞ÷&ÏxÆ3’7Þ8Ùu×]“o|ãîj˜{î¹'yßûÞ—¼êU¯J6Ûl³duÖI¾ýío»«Óyì±Ç’ý×Mþ×ÿú_ÉFm”<ýéOOþîïþ.ùÕ¯~å$"Ã…yÜ@ÁÇpG"‘ȸ•üHd 8äC’}ìcÉ[Þò–ä´ÓNKÖ]wÝdŸ}öI¾ûÝï: ?·ÜrKròÉ''wß}wòñ™]HázüñÇ“}÷Ý7SòqûSŸúTrì±Ç&›nºiòÀ8©È°ˆ#â‘H$©B\®‰Œ8?øÁ²‘û|ä#É»ßýîÌŽ‘ýwÞ9Ùzë­sý?üáÉŸþô§dóÍ7O.¾øâä€H¾õ­o%/ùËÄtþùŸÿ9sï¯þꯜmdTw%?vR"‘H¤YâH~$2⠜Ϟ=;Y²DÞÀO’ 6Ø yë[ßš|ï{ßË]JÃ(< ~O<ñDrê©§&ûí·_¦àÓ1xøá‡ÝÕȰ‰ r$‰Dª•üHdĹñÆ“wÜ1SØ5/yÉK²ãüãìØ7ß|s¶¤ç/xAÖ™Ød“M2ÿ^øÂf#ÿ‘á1) >q .‘H$i†¨äG"#Ê÷6ÛlãΦ»_ÿú×Ù±V¯^Y÷ÿï|'ùÌg>“|ö³ŸM}ôÑä5¯yMò“Ÿü$»i–IÁŠ~$‰4Ǭûuå•W&Ûm·]¶›F$iŽGy$¹ýöÛ“¿ýÛ¿M¶ÜrKgÛÍ;ì<ïyÏK¾ò•¯8›6?ÿùÏ“¹sç&§œrJòOÿôOÎ6LÞšüÏþóÉÁœ-Z³fMòÌg>3³¿óÎ;3?¸™H³Lâ2IŒS$‰Œ"³Î=÷ÜÖ›ßüfw‰D†AZ“7½éMî¬^°eÔþë_ÿº³iîqÆÉÛßþvg&OÉ—k{î¹ç´­9_ýêWg‘Ûn»ÍÙt³víÚ$ÔÏ‹_üâä†npg“Å$Ç­iÊ D"‘™É¬ë®»®µûî»gJ£…ƒb¯½öš¦¤ÔÆßÿ=k’½žx"ù:/î±G’œp‚»Xƒc"ý /®½6I~÷»$©1&!­V­Z•ÐÉNëaò²—½ÌÙvCX’óÓŸþÔÙ´¹úꫳkÿñÿ‘m}YDž’ýõ×'</^œ|á _p¶mÞð†7dið?ÿó?Φäã@A$2\ò "‘ÈÌdÖ 7ÜÐ’Q•]vÙÅY×ÏÀ”¥ÃK–1Üw_²Wzúõ¹sY`ܾV3“ TÂPü ŸØêEößÿÝYöÇ$¤ÕÊ•+;£š¡úÇ^õ¬•ÿío›}ÐJ`?ûãŽ;.[R#ËkòÈSò|ðÁlp·Ýv›ö¢-²÷Þ{o¶ç¾¶Ülb @ó®w½+K“¦hÒ?Êi>©ñüãݦFó'¹¼”(&q¦/i=»ÇC–Å‘-ŽƒdáÂ…îWÍì¸#«;3³#çb`qPD?Ê3 ~”©ßÿþ÷[³fÍj}ä#q6­Ö£>Úš;wn+UÊM«u÷Ýw·Ò¿õøã;›n¾øÅ/fî|ûÛßv6ݼöµ¯mÍž=»•*óΦպùæ›[ë®»nëÈ#t6Óiê¢i"ï5MúGZNrü@ü#®M0Éé9ŒúW–¾h¢‰¦YCÝkl$Ñ¢EÉe—]æÎjDä/Zýä2¦+k)¶ ,ŠèGy&Á2#ùpà&—\rI6BÈ‹¸gŸ}vò£ý([²Ã(:ðUÜsÎ9'ëÁÏ™3'³ƒ“N:);²Üç /L«ÌaÙ¨0 0"øÒ—¾4›-àEÞ´}ξ®ËúlãéÛáÊÆ¡NšÈ{MSþÉK©“?Aükê%ÜINÏaÔ¿*LìLŸ[&ü®ôùø±.¶Lò¬Ô0ã6 UÅ]4?=»7Þ#ù‡Ú¹Ÿ;7;.Üv[wa041:3±~WOzRÛð»&!­ÊÖ?Fî—.]ÚJíÖ†nØJ•ñÖUW]å®¶I•üÖ:ë¬ÓºãŽ;œMFï±×GùmI†Ö^{íÕÚtÓMÓ¬zRëÿïÿÝZ³f»ê§©gˆ¦‰¼×4ái(Lbü4Ú?ïA1Éé9ŒúW…‰|>Іmµ…·½‚¤!&¹,;n¢RÖ¤¢L£©øé:ר>ù|\§VdÿÖ[“ä÷¿ÏÖzo2àõˆµÇÁÃDúA^~’<ð@Ûœw^Û®O&%­ÊÀÖ–'Ÿ|rö.ëíþó?ÿ3{_@þöþóŸ»Fñ‘xìõQ~[^ô¢%iç![£ÿû´^}ùË_Îf"ƒ¥©íH$R¼_vß}î$eøÉ¡I€E ?ûÙÀƒ …ÆJ&_ì¬yóÐh¦*Ç´Òuùùä'·M %Ô‡áGšÞ;¦Šb'Ýy >úhû7üñIò¥/%ÉsŸÛWÞLJ~DªÃ.@Mý«í:9ƒdÒÓ3Ò ßú( (nµUösͺë¶Ïbàq34éß$Ç šö/cSi}Á´Ø¬YÙ4YÇ0m¦çWø½á†S×7Ø`pó/‘nHg7ÙÉ KC$?0rnón†1võÏÃ$Äa˜v‘˜½2êõoáÛq€pdí•Z&¼#KPd qóФ£7²·æ•ÅšŠŸ®sã7ÇtÇ4îÄÁh½ž_ñcýiwÑLŸ³Ôy ,nšôoØq#˰²¸CÓñƒñSòŸýlZFwâ ²éœ`êlà ÝIÊ4:6£QÓ˜ÙQÒýu¯›²×O1o"3¨àwCZ zÙNdf0åReÂ]~¡‡H'àœsÚ÷ÔÌ$/=kÊ/²‰~Ø×¿ÞíãXYܡ鼃Ɣ|>ˆQ |èʾè*[ÇFŽIÌ'=©mÞøÆZÞ¤¨-9Œ½¤ó“Ÿœ¬={ú 5Æ6âë¯ßsÞLJ~DêbUrñ 'd£%'|ò;IqέM¾óI'ñ*gçgíw>™|ò;±,D"3”õÛns'=ˆ% %J'€ ~þóz‡‚#}£ûauööê?üÁ/;.4¦ä³7wm èzèÔh½ îòÅ‘~L >Ô‡cïn§i~ØŸþ45¡†0ÿŬ xH2Âß#“’‘:@Á¿0Il+ínýÍä¢B¥|ËäåGœ¹çÖÉÎÏïß‚ÿño&ÉÎ;mélú'Žâû‰£ù‘:¨}p&g™p—_h‰¼ˆ+°,µæå¨M<5é_~é~Ø}÷­íÊTÅA®,n:ï 1% k‘¤Ò¹cdz¬‰H cA™R+t­b. %Ÿ]kþîïúê€MJ~DúgÕÅ&7í|`òz§«?ïù;'÷Þts©Ñü›oJ’­=+É2V]œ|üÞ´llU“Žü|¢¢é—Úgr– wùE{öœçL ûFûû¤é§&ýkÂ/²cjåða%^`ÜQ¯öêÈʦóSòkÿŠ#Ë?À½X›ùA"†æbú¤‰¯ ޽®e>H­ÐµŠ#µ¨†Íh'%?"}²ö;É5©¢®Gã×Þw¯ûUÀÚ›“›RÞ;HŸ*ø'üôùÉ ÏOÒÄó“:¾ÕüHdðÔ>8“³Lxš_È|p-Y>šxjÒ¿&ü";˜„i÷ÃNè,8Јj)¬·^=YÙtÞAcJ~íXÅQºXzÔXF’#Í!5ˆZ!kò1ÔyèÁwˆŒ"j½|j|ëÛW]Ø.2rìG%µH_‡Šy3)ù13Ø:Ùó•N ßòåÉ'¼¾–å/i!J´ßZká,ÁÉôþ"¸×®µ_•\üñ{“We ~JÞrž D¿:q4?2rÐ^™eÂ\Û—aÛ¶ÈHZXfŒ˜W1ÈÆ’*ÉHÒ˜’¿råJ÷«¤l™ž±“[ù›ßðÝà©]\,eÝ ÐS*2V~øÒÓÕ’Ìé"k¹ÇëÞ]GºÐ=äͤäÇäÃ.6$ÉEŒÈ2 mzÓërØZiê¾å;^VýtúZ{ìÒ¿ ÅÏ3í|3ùx©-9ýD¿w¢¢é… ÎX-0=ïøå¹6šxjÒ¿¦ãöûßwû§•V³¡GuÑKÓñËÆ'§KÃ'€Û³&mú$°• É—u/RŽPzÊg¿å›ÐVŽïEëërkÂéúW’¢8ÜüÅã[Çÿ‰Ö·ïsµrsë‹]ns~|ë%<#\_¼Ù(#Sié˜~ùŒú3dá;âˆ#ܯ°í—E_OÍO~rçwÖ¶aømÁ.ÏÝ’ô·hÒ¿AøåKv~oµÏ–#²£\Ó²yôˆá\£eËÒTZê:7ÚkòËôŒé^Ýs;Q°W­•o¨§=c¥'ÝaýÒo¸è-ÅØ]Y=ófba}üÖ{¼œÁvÖ»çŒæWçyÉów¾7¹×Í’g[in½gr@æYfáÿ0V¶#OÑhÿëñã(~ÿ~q4?R…O|âîWEÊÌ(Kû©Ì'î=ûìö×p´Š@ÓsÜz¤Iÿêö+”ìS+«>ÑYYeeQ[B*I¯ÙÙtÞÁh+ùzî$´¾ž¦bÙÏ”m¼ñtù"÷"å!í©Ìiå¥'r<©1t¼[ClÞ@ïNDF‹—¿jçäÞo~¼³ü%…¿&ž÷ú“äÂöòš ïÝ39RÖÓÈ–± '[–“Óáès=~Tð#‘1cJû+^W¯eõfë¾ûª¸©P²ûÆ­,*eH]«ìÆTZ)ÊÌ…Øù”õÖkµÖY§ý›9˜¹s«Ï§DŠ!=Ûs]íc•<âÜg§©âþ˜3²õ¯“‡º!=Ƈz(Ë7 ¿G™qIÓ¦õú7êáë¢lÛƒ=Ër6Ø -«ÍºëN¿¯¬»‘ZÉKv~kõ£d'Gm¯å€ß£œºÎ56’¿hÑ"÷«2B_4bºc‹HséQÓ½úÅ/ªÏ§äP)=2~”èÆvüðu™}vš’ÝäIÉIá>É³ÈØpË-·$/~ñ‹3ÃïÈxq÷Ýw'gœq†;‹ôM™Ù~ÑOXAÀ22öYÔKtâ*‚‘!/Ùùm?e «åREóÜ5f¡éó€Oݨÿª«®J,XàÎ `™©*’²ÎBª£¦ŠâUW^™,HziçÊ]Tä¹Q’Jq葱ðCJ>JJº§”wù¡ò¨#ç³ìÙfóhwØxx¾ñÞZ4 ùÁî=ýÖ?–©DF‡O<19þøãÝY¤NbÚ–c”ž u<ãªÂàÌe—]æÎ*j—4F?Y´É&ÉeÛl“$?ÿùÔBn–¥²Þ#Ïé9n=Ò¤uûU”Ú?ŸÚ Eªh™"#4•–ºÎær^çBì2¦Íªº)éiç°úE绘 7œè¼ÉúW‰Ã¹çžëlf.¤Ã8!y7NepÜÒxŒCþI› ß•W^é~U@·?y:ƒ‘»rÁ‚FužâÖMúW§_e²Sûç“/r£èº¥©´Ôun´^¼¥KDw òæBDŽ£F^îzÓL›1•F¯:Ï{‘nt:‘žv®K(“ž>ºÃvÉÇ£&Éç>—ïV$2Äm#‘Ñ §ÙWÝþä,ÍÚ<¥Ÿ,¸òʶî!k<àÏnóÜé‘AÏ^[šô¯N¿Êd§öÏdkvî³ÓØo{ržGÓy££ä£ÄéÅOàS"­œ(ÙÅ…ÊÅ4Êá†&Éã·íµ’¨Ý8ÿü$9ï¼éîEºÑi–—NeäB2ÌwÉZ} Šùò3‰ÌèHÅ-5#µ£ÛŽœ‡@/Ñú :‡îàëÁÆ#×1|¹VÖÞ“S,ÑÑ£Àº»ÅË/ZÖ7g¢±„"ù™J(ÈŸ¢Y‹ÜÃÑw‰Œ8QÁŒñÅé>¡½Êk·¤mbk0@¯Åë Ý)rW_/’ô‘/³Ø@(›=\Å…)ù‡z¨û¥°Šãm·M­OãHÅBFöœ|ßœIÚÍ:”.oµWÙ¾Êæ~޼753²~øÒ‰\`t?臽‡Ž]À"&%?"ãETðG‹™<š?nïQŒº­boD»¬Æ×þaªXõrO¤ ’.Op*⌜0iLÉŸöráž{º+ÎìÙíßÂ#´Gñ”÷í·æÐÞf§2Ê[îEÁ_î[G2?ʤSht?ś߸§ßzáxÇÝççž;-ݧáÜZ ËÆ€h"?"‘HÄe;MîàŒmÛì¹ Û*FïÑU<í_ærÈçiš>©xOÓOMú׫_9ªH²ÌŽÈùg‹†=¯JÓy)ù‹Y¤$Bh^”åÁÌ<‡·ä”t”uwá9Ïi¯wÚνÅt d&€%;jç ñW*£È¸’ûV†sGWÄHøJ[KHciX9Ê2©o~ã^÷[/íߺq&¿Mºw¡ÜZ|óÍa¹šh"?"ãÃ$â?üðÃéãÔ=O#‘ "88£Û"޾%Â"Ç€¡€‚o×x¸ÙíÌ'Ú2(Ò4-e´SCÓOMú׫_¾…²Ó§œçùç+*úܺU†¦ó.ã†n ÅjqlŒw¤™œ2œ ‡Ú>Ò“ºe´2[mÕ¶ãè“5«Õš;·-/X×]·}Ä ÜôÉè°ÍʦA¯räv’×úš˜²n…䯄¡Ô¿š‘8œ{î¹Îf2!Ž“À7ÞØzÅ+^Ñ:ï¼ó²8‰™„ü›”<*ïýëÖ~ûí×É¿Q}†ŒÔ3ζè úœ¶É''öiÃ8¢oøtŠ<ѺL™{"^tVhzMb[Ö[¯ûœë£Š®säw‘×í’ÑbzÍ2â ô¤EÎö~AÜÈFòén±ls÷ÝݣƲÖ_÷ ‹º„3²i3’ß…uOˆpM–l y~– [$R#“4‚ÿÓŸþ4ùö·¿ÜÆ;P‘±åî´=ûò—¿ìÎ"¹ÈP.m”n?ìa`È–.Y €mˆ;v—m»yã²ÊRa@Æ.ƒ…?‘ŒPRê‰Á®Λ,ÑîZUCïŒÊÊqÔɲYä oS4¦ä_wÝuíÄ’T¶Û`Z°c©„ìIÄþD"gSŸ ˜ºs¼p ØS¡™‚cYæÁÛÊ¿à{A?|•.¥‡2~ä¤A<Ì$=¥Såèò£È=é(p?_•%W>”[×½ä%á°ÕDùQ–?¦éòÞ÷¾7yÆ3ž‘l¼ñÆÉ®»îš|ãßpWÃÜsÏ=ÉûÞ÷¾äU¯zU²Ùf›¥É¼N¦äYyä‘äŸøD6¥ˆOJëÝ.»ì’|úÓŸN«R ‰ŒtÄ|kóãzý :‡¬³°[pë%ÂiÇèürä™G{$m–vÇ®ßàÑ$¹Oµ…ܡåÈ9Í´vjýá<Ò¡Jòpíp')dqh\к Zm¡ßGÑ!kéËánÙ0” ï@hj*máÂ…½Ï›X¸é3Œ¸‘®¿~ÛíuÖiOÙùmð_dJ†#‹Ã€9?HFúÈÏN~¥¯Í#òÎãžIÈ*õï oxCk½õÖk{ì±­Ï|æ3­ùóçgçiGÄIø¹æškZ©’ÓzîsŸ›ÝÃïTÉwW§øÉO~’&ÿ:­TÉo}ä#iyæ™Ùrä>ø`'5‰Ã¤.÷ðÙ3§Ÿ~z'ÊG1“´ÜÊæ™=Ÿ¤Þ‰tÞ+Užquqíµ×º_)¶á\£Û)»&ƒsÁºãd¯Õv˜ 7l»…=Åçn í, oWÜ IÿÊøU<]ôZVg'hÿʸkÝË“ºÝ½6W¶.tkLÉ衇ʥ¢EW@9÷UŽTæ!ë6×6Ø`ÊN 9-÷U ‹Ã€)?lZÓ)²iÑùãxè-o™.ëCû!ëÅ”IȲõïûßÿ~¦lÿÛ¿ý›³iµ}ôÑ4KæfŠ{>ø`ëþûïÏ~ñ‹_ *ùk×®mÝ|óÍîlŠÃ;,»gÍš5Φ‰Êã¸C<4ö|Üa÷«^õª,^ÿøÿ˜ÅD%¼z'fÐmx¯”}ÆÕI×à íVÙÁ#dÓg]&Ë‘sA·U]{¸smdðѧ{ˆ?Äè¶ÎúcÂÛÄà–¦IÿÊøU<]X¥œsö¯È]Îé¿i÷0¨-º˜X´»ë¯¿07¼u¡ëœ™S,/˜¶ÌFÏ›0‡a-ùæ9ìz|Y`õÄÉÆ2%Ë‘)3¦¿XæÃ”›^Ââ*½ÌÃç·‡,f¤ü°im·»ä:éh§Ó´ÜøÒK§Ëúà>™c÷¤PùЈGé,GùQ†‹/¾8™={v²dÉgë $o}ë[“ï}ï{ɯ~õ+g;M7Ý4Ù|óÍÝY˜§>õ©Éóž÷¥Û*Y¿‘/Øl³©å9¬aù0í]hÙ)²¸jë¬?&¼¸5D“þ•ñK'ÙIR‡T7²B^ù“ ’4Ú¿‚dÏü‘ï¡YºC …A»{àLswÐ4¦äg„R‘Ôñ-Z"U­¢ê(ÚÒ s”J‡l…E¥¢’SÙuŽ„üŽLOkýæ‰N{A§¥ïã!!È#®“gEïj°òœsf\~Ýxãi²ì˜)ìš—ð^BÊüãì8XÓ[n¹evœT&Q©·è/¤²…¦fœ;i3Q©_» ÓœÑ:„¼[Ê;kõ‘Õí ¿E‘¶)=nüú×·ƒl»‰ŒÝPBàî:Á¶Žsß[¤)M<5é_Y¿H’UΪeÌ9ÆyIfýZ§€V>ì™Zý¡o‡: ¢ž†wÏ9§ùAÃ%¾PÌÖ_¿}ô¥¢UæylªJåB¤§­{åZV”y{TXßn:!¿-Ú­I#7ÒV?ˆöØ£=:!ß5Ðy:-éò’Üëënk?1Ò9 ÖJ>ûä~þs>j¹ „Øm¶ÙÆM!v¿þõ¯³cÝ<–6Z§œrJ²ýöÛw:3«ðO‚‰RÿÃþÐM¢èK^»âO?ᄲ£øµÛøtÈk/°“öH´GŸ€Î ÚGÎi¿Ð*i+ÑUäå^ô­·nÿF&¤QF ±ª›¨6›ò’9/[-ܯÕ!f|EkÔ¼’bÛmÉR>rÄèœ[H©€")¹£S•sìQqOȧ×2?D™¿óΩ·ÙÉ=*Ÿ/G¤r ¼2msšóÔ­¥¸%oƈ¥K—º_ƒ£Ë·,|q#Í©!@:²KQh„BåcæyAÅ—iqŸŽPø)ºf…ö¸",VNå×Rpü´r5æOùQv¾ayŽeC—Þ\Gyd²jÕªäãÿxšƒ\ŒZÁ¥Q+üãÊ¥—^šüó?ÿ³;›LÈ'­ÜËom7. ÜŸxâ‰A%?R‚‘×^ø´GŸ]ø…ŽÂèþ³žå_I p>ÁƒTƒ€¦ßªte³I’;¤z„Ðê²E `ØYÛiµ÷ÙgŸdÑ¢E]f·ÝvKV¬Xá$Ú\uÕUÙ5Ë;ÞñŽdùòåî¬ÍÊ•+“E©b¿6}ÀÎÁ"=²®ûøãO–-[–Éd¤©óËÙ³\ÍVý¢ä»Ô>ýE/J–⟤`jÿpšÈ^grå¾´ò*J n¸T¦r+˜šV•ýª7¼¡£¸¼#½ùå—»³6+/º(Y”ºõNp“’‘2-)¿üå/3wíúåÓO?}šÂÈȲz›Æ9s椺öùÞÏxàýçG*û”§d1i“Æåø4NY,TܦÅÃÕ†ÓÓŸK%Ý]é}ø ƒÚñàœ›òûü4eÛRy'OÒNÂkÖ$+pÜñª´¶d±Ð°Ôw¤×³Xˆ|z}ez@ö)[lÑ.„%½~|j· 9U&F)?XOÏ51¯xÅ+’½öÚËIä³ÑF¥É—¦ŸáQWƹ^7þð‡“³Î:+9餓’×¼æ5Îv²Ñ ½ü–óqÇ.éTÇpG¥>Ri;´”6N´*ÑÌ”ÑiOL{‘áÓ}vŽ¥iÑÑ#8څ߀½og…Aª¦žšô¯Š_d§í¿ådSÜ=´´ôªbAßO{¤hYÏÔ«‹_ð‚fó.cào¾ç½­®)zµYÉá.vÚÈ«ÐEîé·àeû+MÑ+ÚãL™¸‘úµrÙ¢Ô—ÅÞî  ý2 Æîңݪ*7&”­ó7ÓÚi§ÜÙßøÆ7ÒdžÕúÊW¾âlòÉÛ]GóÙÏ~6ÛNóˆ#Žp6a$lÑÉnÚðUÕq€ðûŽ“„ÝMçÕ¯~u×9כرªItü0ãÄ×¾öµ,ÌêõjŸ}öií°Ã]qXÞ'eŸqµÀ³?mÏOKýËÚu_[ Û Ú5Ú<+ǹmghóØ™Ïè0§½ô¥S:„øiïçj£l¬wÚÑpO*{šOG §všû5x¬_DÓfC‘%{òîáÚTrŸ–%?v›mÖÎ^Žú~†îûÛç‚–ÅȦNb¶Úª÷øUA×¹f¶Ð TŽi”±O÷uj¢`VqœöUvÀÎVâIÁÆÍWC8×i‹É{0q/×m ÃC®¨& \¯SnÄ([ÿ–.]Úš={vëp6mþå_þ%SÚïºë.g“O%ÅŠilÝÖþûïïlò‘8|ðƒt6ãá×f)Rò1Z¡œ$$~ã[ò ÂìÛÚTêœ6mÃû ì3®l»Ä¹Ú ®IÛW48ĵ²J:ç>Y޶â·m'}zrVLÊþ0 z’ŒEÛTrM’±(É‘E=D–#çÚN î`o³R‡Ëú¥ím± :!wê@×¹ÆöÉ8¾œ«r` •ÈRHÜ|%Z®ËÈ»˜ÐƒL°%\L™oHxŠä„ªò#DÙú'ûäó‘*AöÉßm·ÝœM«u÷Ýw·V­ZÕzüñÇM7EJ>ö¦  àc=æló‘8L‚’?©0Bÿú׿¾OŒOÉŸ¤½ò-Äo\:Ê}]LÑ3dXHXŸö´§M›éÛu×][—\r‰“lså•Wf×,Ì*žuÖYî¬ n#{ß}÷µ-\»óþÔ|(5Ù¹ãŽ;îÈdy>fÐf¤2Œúƒ,çê ²%9ÙóRsˆ–¥ÍIµËR»K°Ç¸Ç+S“í¡¯Ü…®x8wop²÷ù÷¿ÿý­}èC9ÌNvÕvÛ9©6Œ‚sÌ1î¬Í´x8˜:äCÜÙp@½ùáèÄC1-?åÔ<”f°¦ÇcîÜC¦©'³gÐÚsÏKºT” Úñèv·Õzò“Hï?«Ë.I(³ Swîë²ÊSÚñÐ*‡Äc»íVuÉn¸ái­6:&ûMõJçGw8ÎK‹joù!³{Û¥åá…/|aöûå/yêfJ¾J ›‘¥Ñ©©áœ Œá7~Ìž]Ÿ‚ïñ·ç8T`¨~t—ºö¹@šê®2ç:ý5ä…|}X_gÀÂu]3sä³xTï…AçG•úG…—/ÞžqÆÙG°ÖOÓY?Àù2-J< 8†¯ærý­o}kÇN¸ýöÛÓÞ“[o¼q듟üdëóŸÿ|—ùïÿþo'ÙÄaœ•üIG–~h3Ó”üQ„FŸúƒá· u*”'úºìF k#áãù/KK‹F»«´!YÛfbh«¸[f„¾¬ÜAô¬ò®UÁ—$Ù íä^ÜÕÙƒ*c‚èkU²ÒÊbð×wŸO¾.tœ’ob°pÛmÝ… h7(ÔJ¡ïTd Êgš«Y¯¹ŽÔ2a÷tïiP Õ@¼;pN‰-*ù©L×W©A¡’nANßËy€,ä{aÐùQ¥þ1rϲm¶Ù&-þ¶^úÒ—¶®ºê*wµ £3¬¥·J>Š=öú(¿…k®¹fÚu-wâ‰':Én$QÉMPé’GÚD%øèΗ,•b©Î’%KróDêœ6µ·á5QåW i;“r—io¤MëU6ýÝ5 …vÉuŸldBf'·j“Mʹ[M < Ö/ߨ¢' :êˆ6$gHMá7îl¼ñªŽûö^‘Y}¿F_/’µñ+’ï]ç§är•jw<ç9îBŒ™!·ÈkŸ¦±²ß\ï'嬿œ§XÅi ÝÒŒôÓ¥ÜbÓYMzßOyJûš­]E ë«™MžfñÉ×Ä óc`õ¯A$QÉM$¬‰Jþp¡óE±ioó+*ù%0íC߃3ƽœ›öqáÆ·W”YŠZM jšôÏç—dEÞØ¢d‹Lvpy“U]`Ç’ä­Á¿2àFõC⇜¯xÕ…®sÝûGÖ‰ÙËhÎ+_Ùþ{é Eµ‚l}¥÷Õg{ª 6hoÓ‰=[ ÞZb;*ëŸ`Â.û*±â  ?ØSŠýðCéGzè­GÙXËýû¿'sþþï‹7õa÷Å6£•½üU˜²xXù*~• ‰üˆD"3k¯½vâ¿[д²§¡kø®GÏxÜëØÓÑ6bøî˼yÉÇÑ9Ðó6ß¼-WøØ\½¯¸õ@“þùü¢IgTTŽÐΧȰ¥|Ý•ó¼Ïú´ïŸîŸRù )ÚÕBüBÅkPÔ¯äKá„<åËbs6%ÅÜ>àØû˜/Æ-^Üþšæàƒ“dÛmÛ_–c/ZÙOœTgwëçöƒLr]ÀЗ]qËÞ;Ê…Ù–Z·oþ4ôGÄÔþú¤fJÚ•I+‘û.)„éÜs»Ý²~ eüŒD&œû¤>GF¾ÉñÍo~Óµ¹ÿþû³c̯Šx4­¾g¬{´7´!VAG¸ãŽdÎoÛ>w~÷Ýîp_ŽnÒôÀS“þåù{íBTÛ!,Ô´ÝkûÇwÊ6Û¬úXa^˜|Å€øyŠë@©WÉ·…DùÒ1¶rœÛ˜ÿüçíë|VC™ÄMºjàÈoÉ-éºÙQ}­Øã¾/¥%ly]@ðÅaÔ)f­¼ƒï À¾RI:‡Ò Œ¿>]&4ä³–ÃØÚäs/22 äðq6 ¿#ƒÁ§LF† yò| 9ùä“M›ßýîwÙqíÚµÙ1R’2Ú__Û¡ÝÚFíiõ ôƒg?»Ûodʶ;>¿ÁêB¾öv‚ʇÎØ«Œã†ðe¡ÍqÅþ ƒÚ*Ÿo¬0í†îàO¨ôS\{¡^%?T8Ó.»è¢©»¯§fˆœŽ¹|þPê5¾Tqþv¾ÚJå#Õùúª”ü¹í¶)q@»ŠCJ××msäúÁ~A·Vt:fß(½^†¤“Ž¥õž{ºv@:ë´ú«¿šz€•I+ŸŒ.²¯ÛÀ”-ŽR›ÊøY‚æÇ †/¿øÅ/Î Ë"ƒáÒK/¦LŽwß}wr 'dÇ™e?>Wj€g=m ø4-ÈJûüÖšƒ€Èð<²Z$ç÷ÞÛ½‚€µ!{ìѾ&³þykJt¬ß:\´{Ò¾r´úŽE»;Æ”ê 9_’%Ë|PX²£ñ©ÈižJRŠ,رl«âêÅÈå×*a(C½J¾VÊŒâüðCµKÌ­œŽùsž3u]>MNa-ŸqþfãÜÇg¥IuŽâ%Cæ÷ðGRHY”Z¹‡£ª`]#Ž¡¸öÉ@G5 cïŽÔ[KÑ3<´$nÈR³¸ÎË£äa¤Ó -¯Z5õ³iʹ-ÅÜkÓS—‰¹s§®»||xãù6ÿÔ™£t\|îõ@eYÚQÈ}«8g™ë fÙvÉ…!²îÒ>щÿºíD–vKüæÈ=ÒÎ!+aÑî:ºž\2<²uÐÄ@Án7ãm¿|‹ À*éd•޲,6Ut“Mü«²…;ï<±£ÎÙ¤$äšÅÊrní‹”ó©"ubpñøÜí“d=‚¢RÜ4²˜ªª²UÖý¡²•ÊpLêUÙ*á>V”\UZÜdÍ?J(x”ѾâP’Â8ô‚‰÷a»ìÒŽoÙ÷S ÆE§A`Në°Ë.›ª%Èè93J¹öÛ„¯Ë-ÒØúçdc¶EËâž-'>» $?f02×—ƒå2Z?‰/l._¾|d_®fa~øÃº³HÏäifеì(¥µ­^(ëWÞ@ím3}zƒmç8´‹ÙàV¨½M t‘Tsæ¬Í]d¾±<ÐI¾¾”ù§>µ7Ô&J%Y«.8YÖ´$ž²ø€WM}Ê|É¢WŠþ”|B¤{“¤„¯R¥ç'0¯R4¥Ý³ /Ša@Ž)í.X …¢.‹»B)'î¡@êÒ£•ÑT&7â~…âP‚iqè “Yz”ÅC#rfŽRRy3D¾6Ëoö‚b?gf=BsZé1‹…®%z'#‡¤nê|±_® ÆÉÎJÔ\'{.›‡`;/ü.(;!jÍHg$2®;žB:>¾oèuÜ>ø û59\sÍ5É\àÎ&ò”oüèG?r6‘žÑš\Žö• dåi[e(ëW‘Û´;´]´¡5"£ß[ è+]hÊ~P z  ç¥IÞyçÃr€NN-£“E¾½ñ5È?òÈa™JÁ6€”dõŒñ–—e:~’–¸‡J¢Ô™®¬,YôJÑ»’O`u%BYóU*'·Ë/9}zkS±÷ßoɑۅŠ-FˆÈiŽœûR{ý¦†O‰w~zã:LøU‡ºâÐ:L¦[ºË«_Ýþ ZN¬K*÷Ê:w~“žlßœ–soj S”¢œëù*í§ä‘t<8Jí”2¥·(S³»HúâàûÐkíjËH™¸>[#»®`V¬XálÛT}qVw~ó›ß8ÛáC¸B3¿úկܯÉäsŸûÜÌ]^S7´´'ÚW6åÓžªPÖ¯2AÜK[åÓè÷í #÷§œ°çž^ûA1È.Ût§¾eIeÇéŠÀãÓ 2´ZâÛÛr˲d¥ZdÉjhBî‘:kpÓÆOcå%+ñ³DÑ+EïJ¾V9Þq‡¿Rù^`RGÇ>$g±þ†ä¬ƒãÈ9û¢x‚}Sƒ®•ÍÙ"?õuñ3/lM ÃDœCÝR_ÜtÉã¡# Š?¯‰kåœmý¥ÆÙªeté#×m™¢Œð$¿È':d¸í‹ƒî—ÚÏ‘óH£üŒºe˜t%¯ˆÕt€?çyÔ2S‚ù¯ÿú/g;|ô²£™ÆM7Ýä~õόܕÊjT<ói£xÎ[- R»]˜m.³ÞºmÁ/=8å‘õ!Cû„ùP;%îZˆ6Îjz©ì.„Ç7 âGý»êèÒÁ²Iò³Ÿuûå‹¿µê¨Ç—?ûÙöx¢Îz«hs¿¸»þú»t)ÙvÁˆ,þÈQÜ;ûìö¹F«˜v¤ÞÆ´¼ÎJ~kUTÂÁ± ½+ù¶ b?ïÌuBó‡?´í€”—Êfsìý`cfý9 áÑ (~“3zT˜0H7äM ‹õ“{tÖ×Åϼ°5 s¨[jå8G†Gigý Èô ·@éå5q­œcçsÏ¢e4ܯk§-S e…<@Êø tJ"Cƒ}Û=öXw6óí’sçwº_Ý0úÝRg—þ “™ú{¿yh™qéHûêÓЬ ×hçi“|ړ玥ª,3Å„ÃrWì|í¢¬$@Û³­éé0­(ÐËl‹ÂÛ :ˆiÆCM·••(XÕQÙÎBÉz»à€¾”¸koè Ã ‹4ô>"„Ÿ×ËY­br]Ïøâ§åCèppä¼,½+ù » ¤Ž(†R©HMb™²œŒÀJê[»(¡ö~_̰·r^âê@xØ·å”#{)霦¤è0 0ÒSîup~.ÚÓÚ%‚FYW`0é½’|nЇ~(›N9r°#m4lWé{ƹ—¥Už{â§î‚Kþû¿ÿÛ]‰ô„¯ÝöÙÏ|·r šÑ+Ê´i" \/¹‚`Ú@×´^D8Ð ñWëLè ZcdŠö/¤?¸0d¾It8uñÃÎ ôH]:ˆ,Ýtk¿|²€œV;P¹¶ß¾}MCҒĺÙ'YHbqwÓM—ç&ƒ,Ò@œ={ú½ /ˆúJX¸¯Lü,d­^CB²>zSòI9­|£@é !š®@BRW@w­-Ð\£Bè2óRÁñ‰O|bê^*³~  i°R2÷ ƒ‹S†T`_ü{ ó£tü9zÂTè‡Í_ÎmÍ*H¿Òñð¹«ý§†J§ ;ÕíÎõÃÆtÒe1‡¾ó#20ø¢ë·¿ýíì8l±}Ík^“œyæ™ÉW\ál§ÐëîGв¢^À f/êìà¡HÓùÆð{”¸ôÒK“Ýwß={ÿ೟ýlíº;äݲ™í;ÌøÊP¨¯Íô§4gC3zå@•6Í׆†dS¼ƒf,seÄÃrWÚ-ë?º„´I\­$\V’⫗䀄Q–ÙzÂ[•:º\‚ÁÒ~Éjx¼’Ô’T'±4ûÚÝg=ke®»Z–qA{ŠØ[t¯ß²”l ,<ÈÂR&~7­NªbÁï¼0[zSòuÊ¡ä#ŸRIH(lÄ‚£Ž…­D]!™#¡‚ëT›‚½t¥.RèCî '©À¡N‡%Â>LªbkçP&ýzÁºkË—tª¤†•ÁÆÚí«Q‘Ú8÷Üs“E‹u™óe9ÛÑáaŒ[ES¿PìShëžÅ¨ßKÐ ŠyJ~¿øziy¹˜ÎÕ(1è=ÿÙrtFA{JûÊ€Gi_ Ú¢lhF¯¨Ò¦iB·¡?ƒA¬­Òç?öÒ&­$Ò{>±ß~í´`VÀ.ÉÑaÔ¿û ®.Q­ ,ë—/ ¸ãSIê¼$Ö;¸»jUqÜD–ß²²Šä–ñFðä,<ÈÜ)Š_(nš¼/æúèMÉ'D’r¬!Ó#­V©´±€P%’R€"§s‹%úþ¼”Е©êK°Ö]yÚ¦4a!1¾ºFâdÝø!y(Èeã-£üÖù«kFShÿØvÛv:SÃôƒ>_0¶,Fjƒm/»ì².³˜üKAAûõ¯ý®Ð/ùËÙïa(Ðz~B¹ôN*£ò~‰ u(ôö¢¢ÐÂò,ÄÁ7‹S'óìV“ŽÕB«-O„ìÊ md`.Ô¦á¦Oÿ(Ó† Ò–ÊVÍ¢ŸøÚ#è¥MÒi"H8%¾ô"'¤²U%¤>Ö™Ä>´j©‹…O΃RøâF1–•Wm±.¢¼’o ¤œí>QA )È@êèÊ(…SJîq$¦âGßZ}ìñ$§™_ÑÓ| râžÆ¦ðš5ù¥»{î™ÊóÀu‰“o¯¥:Á/ÒE+ùzºR@NÇŸ£o'€²X÷k’Óh)_©)2‚O¾ä=è{¡LØ"}‚ö©O}Êõ UÓ£šøY×2–2Ì”TøHT(M}i0ªcý½ýÀC|/¤$=öXü´EkV´³´o¡6™¶"oå€^o«hmòÚ íÖôÐ+@·iyäù:Mˆt\@âàKŸ!RÇAGߪ\e“¸pÓ׉°ETŠX•…‚/nø#+¯8V[9%_ ¯-<É-­SAÓëáS9¦î»Qv9ZÅŽŠ{¸ƒ’ÌÑ®Õ'%SûE"ÜKŠëi¾P<„PޏR¹hΜ©Ê'nQ¡C[ué8á¶ìµ”ôt*ƒ„…¸jHCퟓë¤ç„Qw èŠR#¹J'AüµréqѾ0=ßòÜ ¹’—@œx %•[DÇÉçä¹§)ë)?"] À}ô£ugã‰(ø¾e,ýns9©{Ÿ7QzûÛßfÇI…¸òU[‹,1*šø%hƒÖ¬ŠV òV˳º…ï>+ã‚-jS´‚ÕB‹°~øKušÐ™A¿Á®(ž¸1„Á,¼Ó*My•$t}«r ü²ÅB‡§×…B(n>Ë’¥¾ÂCÈ¥0r˜‰œYä‘G¶Ïûe-Gιßva¬¿zCT½Vßù›ùàü›v/Škh·w|¸ŽÄ‘(ôÄ—}mµ[”`ßGŸlI&×­Ÿ†®t*‹Ž«†piÿœ\W:F=º!Ê´¸'r>´¿Z.=)ûVaÏŒH‘{!·)Ot–\gìHŽäƒ"÷„¹žò#ÒJñèôÕ„V›‚TñR-*ƒ:‘ž¡SX÷¬³S˜‘€ç¸(¢V›ã7í@‰U0mpƶC ýÃ-ܤ D†=qOä+ŽdI×At6äØ|ó)wÊÌfƒh‡¥-É-r¿„MÇÁƒÖ×ð£Äª¡×. ZÑÙ‡:²+y8êO …² @ÜõÉòûŽì\+›Eç.*„¨‘InÙéž{ŽìÙ]KYÙrJ~œs-—÷Q(Ÿ{b¯ç$¬oŸ‡î³öÚ¥W= ÷ œ£äŠÂËïTì}•wmX4”FM¨ Û/¸)q%ü².цKËék‰§Ä5$g ɉ=é,#ðyé!· ôàÜ%mw6Ï= ò»H.R“U«V¹³Á#Ëjx9³ŽõóÜÏR#=s`_ôýcZ~zy©xœÖÜ÷òM‚Aï43Ó s;ˆYŸ¿ù›¿ E_+¢¢Ô‚Öfh£Ð5ÐEVÚuO×à vvåXÿp“y‘÷´œnÇ\2ŸD–öF‡c™ÙlâIü|¨NÅ‚_ýª=´Vꋃ֡3xUfUÐë@—š†æÖz=%» +y8êæ_ö¦×Q¶ni¦Ü.Ëïßÿ¾7®•É"!Ï]Ðj P¤H=þø‚àâ(rWSV6-%‘Â+…‡£O‰9r_aD.t]°r¡û´=•¥°³#Óv· öZáÅ-zǶÁ¢2án™8U÷>ªa°èß–¼kš~å8'˦;„Üâ»ÔFS¤¶Ë,¯;rOƃÑ™ýˆÔ Û69ZRκyöÎïwȲF¬ë|©x‘o|à(•¦tšøZôÛßþöžwÛé¥ã2©ˆ¢?Teß7p>mFËêÑu«ÌBÈ]Ÿ};iÇ|²‚¾&á+ §Ž§ÀP° @éŽJ:CÜhÀ¡0äQbUA¿è$È[`ZV_×öDŸ½éË.4€» ¯•Í"!Ï]²Qp´3¡Å箥¬ly%ßG‘¥X±b…û582?DqÓJáóuHŠà^æYÜ˵ `ò‰µ"w(R²9r^@cé4`2?zM÷"6Û,I:(YñŒg´ÓÕŽ¼”¼ýÜç¦7†&Òj’ib4—QtFÅÙK½ÎYƒ²”QÚí%´÷}]ðA‘’ÒÌÖ©·ß~»³iÏvôBÑÇŸÈó¯¤Ïy:d¿Ï;ï¼lÛÍï}ï{Îv:£ô1µQE¨Ê~¨½ði3Z6oÕ„ÜõÙ—µ Ý/ȵ*³Ù:ž¢Ü33/ŽvF›s4ßP4M­*PH´¼ eõum/ŸÉúÈ“•kU²HÈs—l$[ýð÷øòÜõÁcµhBJ¾@H Vÿ?Šã»·„{>2?toX+n¤@ÉIî2%‹% U0³ÒVNü’’ͱ„߃üxPÚó:~øÒÝç.¿™1Áˆ½Èñé8ÛYJÝ;÷Ý«uëÜeÛP©Ù@M´/[¥4‘‘þ`ý‚ .È”º~g PåãK,¨Ülê‹·£°D¥Ù¦]/J>éVæýv¤áý¿ßô¦7eyxõÕW;ÛúÑeåÎ;ït¶ãVöÇ×^ðÛ§ùˆ¬gÕÀ´Á‘U2>û²vž¯X¶lÊ^Ú,ŽØñ<Òí“ÌøÀ^â©•{À=×áíÄŒ6K:<¾°åQaUA?]:hEÁÄ~Ù²Ó®ûîóÙ…È“]´hE¥,Ò乫ûcüFml/>X‘©0¡Åç®À=e!ô¯ä‹o¡sžú 7ÙÄY(|÷¹—Ã…^ØÝæXFé Á½ô¨’šRʆ³LŽ)²8”ÿzTÀKùQ6~‚~øÜÅðÆ?%ƒ®ß‚áaǾT¦³”•):b¡—BpU:PøñÛĵt~D¦Tç°7};ëØuò²›O•qûcûXçãKu½äˆÒykh Šm?Ë“ê€4¬k¯÷*kЫ¾ß ÃÙë,ᓲÒÄnOMoµ:Kx„Šíh“ƒ3¿|máõuPBøâI[Hûè^üÍ|+»š@èaU0”´lü«šEEȸ²@V¡626¼é¦çgÉßËâbUbB¿’+eH®û¶•¸.…Þ·m²ú^æ0òÜ|á;Cùã~-çÃçÛô¨™¡+¦»L6ìÎ[–²r>HÇ2{JaoGÇ}øÂ⋟OÎGHŽs›¿ä9Fw}itõv©Y—¯~¸%e‹N÷ãN™¸2bï›CƒªqxA‰biGÝkÕQ¬Êì¬#_­¢üáöqÇçÎÂÐq±Ûh6¯³Cø‡­ä3¢>{½³KÂYGG´‰%[ÃxQ{¨£ú>J>—sg|n”t×GǯN@›U¡ƒÒá¡3*ícÚN]¨W@™°ãwÅUB“]Uüê#Ë:ˆ¡,òù!v¨aúšØ“U2ÎŒšÁ{¸‹yðÁ {Z| àGÉE¦+ùHÚÞ¨;”)z]v[)b]艹ݶIº3bŽr—çøÂgí€ûPþÊ(ÂÖ= 9C®èí°Ña—pæ¹Åo)yrE k÷”’‡‰9òGŽûü ……øÈ,Gò¯L˜C} …<÷)Ll—ª;UÌoi?í•Wã%®Ä[ûkÓ™”=%_"¥Aá,»t†J”Ö~hR¹¥ã¢×›÷JÑzóòóŒ3Îpgõwþ©ÆHŒêËó;ô\æ\k]>|nøìzÁ§ô 휴õ€F§×“T ;÷ôÚÙ( ÞeAT‰v/à*.j“-*b§?a`p/ý)y@à~²T®W9àÞ’‹:LWò­òĹWp WeÎ_|o+PÈõˆ©Ý¶ Yu×_³÷H äuÈ}á+czÓÁw¯Å'£Ã.ñ¹%i&%‚°øäÊ€¬ôê¹ ßÃ9õ>A–¶>° …Eº‹I/æ{Ú^C¸X( ”ì¹sÛ5C+ùÄEÜ"=éºÊu;*/²È¡ð“îuºë4ÔWî÷Å!2X’a•<¾Ñká^»ÓˆC\êÚo_ÓëÒtäXvtž8ý÷ÿ·;ëæ®»îr¿üð±1 J¾||¬ tºþâ/þ"yÆ3ž‘üçþ§³aünZŸÿë¿þËÙT7X‡ßÄã?>{Ÿåš#ç!sÙe—uñ²¦ zT¿ê½ÓàÙ\VÙ¼vicÑÂÐ|nsv7ˬ€P˜ÅD'ðé.!Bî‚î8ÐÖËU‘µñÑaÏs×REÖ·einC 'ˆWv$܇ÈZ_´C²>òd±W§øAQÁØG,׊€¸+²–W‰P}í"Ü_fèê9]É×…Ê×Õ©+ ç{[sÖ¥…óPÎ}î!CjØ9 Fr}#ñ¾ð9».?´Ê ~ÓA—.Ÿ{í>), ¢„]ârË–Høyè¡™/a´„Eæ‚,È©÷ 2Y7§ÓåG^˜¥4Ë1æ.œ{™<”H+)¢”.ù[ä=Ë¢x8rÈT×—n¥DKºã–«‡²K©(cºC€û„ƒ)ŽÌH—ôÑ¿¹®>ºv(×Bq4JhôzAq.Zo~ÿý÷»_Í"£ñŒ¤3âýÃþ0;/‚ü }õµêLK™NŸæW¿úUò“Ÿü$ó禛nr¶ÓÁÝÝwß½¯ýæqƒuøM•EQ®eª"÷õ¬èË3¼Œ6¨5GÚ!ýœÖÏeÝÆ"ÚtíSn![´zBa¶öÀýeV@È]¶]:´õ„YËêøè°¹Ë¹è@E²ÈízÜW+œí“iy^æKG5ƒÇKHÖ’ç.øT\ ¨øŽ¢…`Õ@ú–¤Å£Vô¹WwB$̤qа¨Hj’¯ •ŒPkH]©hѧh ÛA% øÈ„Ï=ÁúkGŽIBï Ÿ³ëòCË‘úºô1õ,9 Ö= viH*R%õ5ÚOí–­ˆ(µ? ?<¡ý°sAäôû÷à[ §ÞksØKZ1sÃ#+øl &ëÅ-Œî0‘¾¤³t¨$ÝÕhÎÜ'ÏIÜÃmqß>f $ÈKÇBÿæ:î9¹»îêwk0JûÞ÷¾7­Üxã“]Ó°}ãßpWóáÅÔ%K–¤Y¹U²é¦›&{î¹§w$¹Õj%Ÿþô§“¿üË¿L6Ûl³4yŸžì³Ï>¹[Ž2ÃR”‹(³¬Å¾L¬iâ%LÞ©`T|kìíÈ~¯<–¶¶²#ðMsƒŠ(ú••}«íäiƒZsDËbØS·‚n¯R²A&ŸÛÜ#m@ÙÕ sz<ÔÚ[YڬаqÈ] a¦md +•銛ŽN“;•E‰ÿVÚy¡“ÀZ^áOúSöRéþûïŸÉâÇÒ¥K³Ù®ñ¡a’§Ø6­˜ö3ºý£ý(Øùö‡µ˜-ºùæ›ÝÙp`Ľî­WáË_þr-£Av°Æ•J£ú<‡õ3Ü÷\Öm–@ž÷ çm}ª…-Îs[°á°«´®aeÅÝô¸øõ¯ï¶×²´}¢Ëˆ›º­Ÿ»>¸–¦ÁbYK\Cm¨ƒu×ê2¶M5a(xÔ^ÑÌjÅ×¢eQrišt‹ ’¯}Ê/-ë Ö´h0–’Õˆ»ø½Î:‹;~Û—gq_MêwÜÅXUŽlàÝéìÑ}ªÇ_ÜçÄmÒ…#çÈû𠳤±t4ì" ß{¸SzSòµâ²Ûcä¼ :÷l·åhç GÞ›Öo”[r†Ø3²œ×Ýô¡ãÌÆ´JqÈø”Ñ"e·.ddÒG©Ö/'•É'䤸â¬Ýà¡F^‘V”@J¢”ÈsGÐéM Ðe C^‚Ï-òZjÕƒ¢>{öìlɰAšÆo}ë[3ž5É!¸—e7ûí·Ÿ³I’-·Ü29à€²­w;q|4Í»­’P°Äg´þlTá*Uéw„u=jQò{Ut%/{?‹¶=å«Âƒ\úš÷º¶^}ˆyüH#TÕ—gx蹌}•‚´gèežùЫðËŽÀ‡Â²½Š@޶­Í»ßB¸ìJ„!w9—¶Õ¶©V¶$UnY”ZšfµÈ`ZtD¬ªÄ5 Ü+)" ý¶/ÏŠŒ„!Ï]då^AܰÎÂL1Ÿ¢&ª FÑŽÐoAWÁÞ”ü²IÅî:ætìòÀMÉ=ÝUAA•®¹cÞÜèšõ¥¬¤"J.©W‘븟Ԥ¢ùJCñW?0|v)Þé]:3e_ÁöAø¤4§d>p.]XÒ4T ]Š}q6é}_£õ•Â"w4r_ ö^ÇztŸ[¾¼Hç «Q™ngýüŽi`=½æ%/yIvüñœ}pï.»ìâΦà^”5–ãJüK_úÒäsŸû\6jÿË_þ2Û-…eBOyÊSº:>P{UþÊŒŽŽê2’:I–òðòh¯Š.kÐ [£V}1¶It‡Ñ–ÇA•¡8º?E¥Qý<Ê®mj)h;ôê4-=/ï–A‡ƒÁ@YE€NS5Nݶ¡ÃØYù²è6yˆ¼E “Óf«ŽöEM»vK/8 IÕ~¬)ã&èlÑ °'lº3>7µjŒð£þö›ESJ¾­6vr®ç4lŠƒ¾OÅîdÖ­éÐj÷|1F–ÜbOjÙ‘Déò2_úRròk^3åŽMYÎu*r¥Ð¢ã èì¡s”’)LÑY}aIýëŠ0ãÀºiß+Øf}®Ã›Òµÿ~›VÖ=íGâÌuÉ?Pnœ, äq/¯Caý áäNþŸÿñ»%yOÚ©ÎMVßGÄrüíÚ-$GnРøm³Í6îl ±Ëõ­rï¹icöÜ4Ž(rÛm·]ö.ÖýsžJ)»Æ@Õ‘yÖ¸½9¨õõ!ÊÆ¡ÎQm–ò\sÍ5¹~ã_]_•EúÕÉÛ9§¨ ‘¶”C:¹{ì±GnçYSu÷ IGê³µgOøÚð7mômXÙ SJ>>ŠiS {9g׃PŠûRÚÅî=ò£åòöQ²î1õ¥»}zOÚ-»€5펤¬¤¥H¿éàSέŸ*L\pAûîQQˬÃ^+š„™Ü´9Š;©]qÀèZÔßtÓaÖùÅ(qíEh‰‹Eü&,:­¬{œc/¥X/WÒùÎNZvÏŽlக?}(¹ 6Þ8ÿI¹Ð î|+ð·²á|a•å9– ]Èû+KpÊÞËLÁóŸÿüäÈ#ÌvWùä'?™­Çÿû¿ÿûäèT #šUG6YãÎË‘ŸýìgÍðég›Å"H×ì,“—~Œ¢jÇ›~”Õ~•sa£âEK d{Ì7½éM™róÓŸþÔ]ɧŽïLêÒ¢E‹¹_Fµ©'3óÍyYtûÆQ4>Ñ€»=v†‘-CpMGÞëh´iªé±8T#›œyîˆZ*2zVÀfÍ-·t yv¹ësS£e‹Ù§=í‚\7 v$?÷`˜@ ¥·¸«í¦qà 7 õ¶nh«¿­ÖŽ;¶Z‡ÚjmµUû|ƒ Z­õÖkµ6ܰ}ŽýܹSr}G{]Ðr³f…å9Ç G÷Êú’«Ó-èGNÛa6ÛÌ §pMòÀÞKþH~qäºÜcýðQ$§¯çåŸP䔑-·Î:í£¾Cº"'a”#÷qݺWÖß<¹Štê_zÌ#U¾[;í´“;›"mHÓhÍj}å+_q6Ó™7o^kŸ}Òn¼á¬³ÎÊî½é¦›²ó«¯¾:;ÇMË _øÂÖ{ìáκ‘8ˆyùË_ÞzîsŸÛeWÖüã?þ£su:üà½÷äî qÞyçuä^ð‚´öÛo¿®{˚׿þõ]çÖO›>e̱Ç;ÍNÒ&Ï=ʈϾ¬±q9÷Üs»ÎÅøÊkH¶ŒÑivúé§{e°O•ù,ì5n1¯~õ«½öڈ߸mãÀ¹&T_ò’—xí«_Ž?þøÖµ×^;V†0k¤¼Þ0gN÷sÓ>Sõ3›ã“žÔþ-†çºPåy¬eiE§ðÝç “nKuqG®ùÜÒpŸn‡¤ýñaÃr{Ò¨l¸&qÇpŸÈs´~zìl–`t¶hìí6{¹.r¸+Í9Ǽ(Ywµ;>•H’Ýç–Fß#²qSã“ aeIŸ›`eóÒ;/ :—;#ùt-í¤·ÇÚEFz™®b=£~nä78a»Iöº åx‘w™‹ðÉëå5!zñWËéîP¿nYú‘ÓvŒˆÓ•ÂI÷îÖ[ÛGÐ÷²ƒyríé-ÝEK‘œ¾î[€&Hºîè|æ¿1üÖnúÜDŽ¥Gjd>ëòSn%]î¼sÊOœëˆUõ·Hn@¼èE/J£uë´-¿ÿýïgGÖ·à£ÕiÝw6m¸w“M6I£”Æ)å7¿ùMvü³ £(x¡“‘þ2°¿>kúGf'¾–Ê‹£Â°·Òš^ûÏø®YE_˜e$Ý·,(4kQfù‘¼0ž*¨cQnG•¢Ñû}˜åþÂÚ«˜Í¼è¢d·4/³¹PòÔ­¸*=íÌêªaÏw¬³ÎÔ¬®y^™þDvíw¾Ó¶wguS=æ™%ÃôZÚy̶ Îp²Ùideãôxþ>J»Â¹[A¦²+®¼2û-tÍêªUïHËMý–ÕÙl˜ Ÿ—ýÇd¿…Îj¶NVËv²Uff™rl6;».îç§æPžóÒŽ¹öíÀT[ñ‚´Ï]8:ùÁyÌh-ïÖñPÑHÇ'?ÿù2už$ßúV;Ç{K iΟxâôÔ,íjju<ºÝ=?möÛ˜BNÔÒ/~ñÀôZ;-¤Ù»ï¾«’‹.òϲS®ºÝ]™Éž|òÚ.UWÊU·ì/3Y»”«nÙ‡“Ûo_”<òH÷{²ê¡[•ïÀTõÊSVØn·]»\MÉžŸ%Ÿÿüs²¶žkïz×»2ùŒ®^6] ÝÓ³fÝuýÝsÌ1î—"¯+tY´ÿÒ… àõp·l׉sŸ|úû˜-¶è¶Á8hl÷Ž®ªWAº³óÎùé.`_FÎC—tËõè‰-gzD¡,i#÷cèþ3ã¤íH§>â¥ò£t;T!ÏFÙ?ò‘8›VëÑGM“rnk·Ývs6­VªÔ´V­ZÕzüñÇM«uá…f÷^|ñÅΦÕJ¥Öæ›oÞZ¼x±³i‡¹C9ÄÙ´Á~Ý´îqÄΦ‰ƒÎC#žE¦‰‘|FlÓÆ"8ú[Õ„Fòñ‡´èe„Û7Z=Œ‘ü!NÄOSÇH~‘½–«"óµ¯}Í;ƒ@xÒN@6:Í1äÿLÉ·£÷)¯]«@?›i슮c|m·¾·è¹®eq_†Œ}펖Õ3¾>z Ã8È‚G+ÝtÛäáºd—½YÉ^›ôVV_³”‘Õ2ýŒä‹=ª„¨bç“õ¡e ‹?¹ãK3 ·T í?hY†NKS#ù—\Òîmæ­¥çG÷AFhõènsÒÞû4l·…s ]Dya#ç9~Ïag{ßyëúl ¶òÎ9Œùܰ¯˜.o:A>ëp‘N¡…_©Ì>v“—îBQþä0‡Qa¹—‘=zˆ.g\×n¥#ö=–t¥9ó­K§ ÞÇ|Où1þú¯ÿ:ûHÕÿù?ÿ'yï{ß›œyæ™Éž{î™êè£Þ÷¾÷%©¢×õ‚aª<$»îºk6R*)ÙKŸ|í6}$'žx¢“J²m6yG€a½îu¯K>ýéOg#¬ÓçÝ„£>ÚIŽ7Œ¸ì¾ûî}±ä%Îq¾‡µ½%õm4«ÂÈchçf¨'effE£÷Óöˆ…Ò¼Äʳ_vб+xVczX5Й-û¬gµÝÚM ²ŒÔWøàÔÒ-¶ð†¡ +kÛ»<Ù”`Ü<²]T‘'¯ã‡•|ö†Å2!¿— AÛb‹¥Yò£${Ç]°ê‚–É[l@ZJòƒLþsDVâd×ÄÛ0Xw5\Ã=hµ–vf,P…ôâfzªú¢(jʆ¡{¹ŽVª¹^<‘í© „Ð*Á%`ªuyʨ —ë Ä‹ß¼ýÁƒBHÃñNvO±á*RTuˆ';XyçFŸ€=¤‹Å›NöÚu;£tÐá å¾ ã;õ2—PºC™ü ðNü•{ «”+ìØÖ–3q›0R“HÇÐ[=Ä3m :)E#ÁÓF§ GÎøû ~™§E©ühˆsÎ9'S´?ÿùÏ'GuT¶¬æ+i~¢° ³Òz‚Ñð!«Ë/¿<{Q˜jùB.¼â‹¹ótJáãXøÀÒäúYòž÷¼'›rd+A¦I­l¤Ydýºv±ññÛßþÖýªÎ¨~Ç _$½™îã†VîK+ø ˜Ð.ÐŽ³T¥ž[Òæ¢Ü º}Ê#ç¹>mpFdõ@&G_[ŽŒ~óÓ'#¤îÎa $Ô¶è6Å^ì«è éõ9è>ZÎçnˆ*²ÊÙø…œ@aÕIKNË’ŒyIÌŽ;ÎélÜ——â.„’Odòv»¹öÚ9ûQ7XåK±”¾3èñHqßç®ej?ƒ©r‰*DÑ×iBâãBeT¯2aèVò‘¤›†Ò„a-Ý—ƒj+ŒtGÔN;…@CŠ…º[ø¥SRÀm©üµß<X/*î!ë W‘¢Jˆ—Tl©Ü€²„?En@ÈÿA@˜‘ÐÊœÌtÈØÜ×a¤Ëê{_g¡ ú^Ê‘þê-µÎ–3 |Èèp¤Ô[l~he^ÖO’>ÄW—·< =-F¶ÁdÔžQz¶½üÏÿüÏi»ó°%Ê¿mäØ1ç3ŸùLšý÷¥íê2ß÷,¶Õ<î¸ã’›nº)Û±¥Åÿ/þâ/œD¤ˆA­§g}”ü¼]lšü–ePïNÔôw šBÒ;/݉(Ôƒ2UážJʽÀjžÑ´ãzH—w}hÚ`yv[¡$ÁÁ™2m9v2Å '™_¾°ò»¨Mñé ¡ûœý;‘ ¹'p­Ç´³ô:ÐE¶jï‹’Ù•+ß9-9òð%_î¿Ê?Ô QCÅ-]@G Õ’º–¨n¨B¡MñúQ½¦¡×îäâ[,d…È[Ÿ;z]G½ÈŠkÚMm´ûÚ ö!ÿ ³ŽK^Cé7LtÚYC¼|ظêsí^Ù¼ÀíoCéRºþ01œ÷ºv:oM¾oÇ™"#k½56¼ý»–ºÌÚù"ã[“ÁÍ~Ö¾™ç<ç9^{ŸÑáè'Ï1ÜËš÷¢Žúñ#ÏŸÛØKÃË¢Û ØËâqÚKùÍâhig5œûŠ؉ñµ)ú^üÁýP[TÆ=…gÀàž/ˆÈ`gƒ¤ƒ,¦LÐõ}½DUßOòËûÚ-Ž’-Ö}Î¥xp´×…\Ùû‹à>®ºÎuä ¾®‰î2&Y¸„}QæK_jï·¶»¥ÝåÈH®¸G÷?Ä/F€Y{-Ðû—ýaSÙ[X¶ »>,/`/t¦eTY»Èе–²$‰n›,ù0ÝÍ[ò>Ûøkg%ðÏ×Í Ø—ZçÊ=Ä[º˜„“…ÙÞ¿õƒ0¦éw‹ŒšHü´†´ÆÈ}‚–Ë#½~ ‹Èòä´[º hˆñòùI~_ziwžwŽŒþ‡Ê›öWà·Î3òßÞܲß~Î22lFeÇ™If˜_Òe–b”v8jùn……µaÓóè½ÚqJÓ®säSÇŠÁ÷œh3h÷pÓw{É ÚùMÎ`GÑuû¥ÃŠyC× õô*Üg “ «  Œ{ Ï€!*ú³:è2¾å%:ÈÅÀÊY$ùzñÖ÷ÛâG–ïÈšx]´P5¤xpô-<î“EµÛÚBÅ6²VõÓLWòCwØƺê2‹§P´ÓÆùXwš)nºpjw),ˆ÷0ø¡Iñö†(©” UéŽe~HJþʺ?޲ž˜Ò¤:r†JÅ!în»íTªKNãoêDZ·ßžW ~&üähÓȹçK;ÖKç"÷âéÅÃpv]±)m>?Ò‡é±Ï|æTü@äPC_ºÈ sN.7­¬[ä£.[sç¶ÃG^ä”±c,h×:†’§Yè¦Ý“òfý÷l™ ,8ýêWýqˆŒ,m’å$ïŒ:qýw³ðñ1ý²º22ƒàf6J²¤§å^C;Î@G¶–gµ´ù´o@›ZöcO¶»·|îsá¶J·´qv@Kë$ø-ƒ~‚Qœoyþó§·7¸‡ nk]¸†½öW/ÎÖš1Š¿è;ÜŸÞsËìÙí{Å=‹¿¼@\áh—eåvÉ2 [§}^äv4§üòÝëƒdGz‘¬ îî·ß-û9êß‚F«d›†óPpóÒKÛþ ¨ˆ¨/’EÚm놇Æ7¦ÙU]§M¥åM 1…Æ^>|”ÉnWhçe€¹·<Ä­ÂkÏyXó¹gÃâ›Ê“ÊÞqÇÎÁëç€_z(k$ȉÎÏN|qÞPY9å^W|øîµéÇhÈï”.?¬{ÖÈ}>}8¹Ü´ò¹Eä(øä„T<¥m/S¿bȯ*î!£çüTËâ¡ý­™iõo ‘8ˆá¼×e,}a;Ãÿûÿo¶|CZÂRÆàæ»ßýîÌô²ì'Ï b¹NÈà¦^&3L£ÃÁ–¤ýäÏ?ÿó?—ŠÛ¸úìû5¡òº|ùòε÷¿ÿýÓ®‹©c¹N™wå™^ž!yËuzYšãCêA'|öy›÷ŒæÙ.묬®¯»nk¡vÃ>¿­í6Gi÷ùñéN~áÂ…í߸+ò¢cptrúF/’vŒë¾8sLϳ¸¥ºš,ÍYŒ„QãÜæŸ#‹_úv‚-ÑÃήºÊ[…ŵ$Y˜+‹ÑY#è0Xw-Zvýõ––å¨TƒÌp.ñÕY ƒNKâ'Y^ ²M ‡¸ÍQ'üÇÝÍ7Ÿªs®‹¨Ð½@é•Ýéa3m®{ÚZNC—ÂuQ²×éUÊK’î"ÇÌ€í}â&=iAÞÄ·8ÿ»^6Ä= GÎns2ºË)H<“^Òƒ¿io>s=WÀ^âÀÑ'°rʽÂ-í½¸I·üÈoÞè(ã‡v´–Q·LHFR˘ºpî妕öSdlZü”ü·n¥efŽìB|ÂH³îÏ_@†‘qá~'7Çú(lkùš×¼&ù×ý×Z·,ä¥É~ô£™‰Ë~êçÆoL>õ©O¹³ê?e¶½wj›ŠFøÎw¾“¤ì÷L™]Øè½@{o‡ûŒfý‡¬‡°²>ÖüóŸ“»Ó¬=³Ïoí‡ nÓîОÒîKÛCûÀ¬ƒ†öÖ ·~üã©oº½! 2*ÏQ¯áÀ¹´ß?Ú1–0¡ŸØÕàÒ-‹[QZoÑ7 Íìƒs7Ããn¿ôíD…d“  ítÞ*,Vlí¿ÿǃ÷»ÒZ¢Q….´ìc}¼´¬uñDU%>|×µ¨¨n¸áÇ;£ñ¾÷ϵۺØÚpˆÛuqbu:é¦÷@HO Vá1¬ )”ZN£+>SQ´œT( R9Y.RPA~‹²‰¬,W±þûÖý ÈrÈTØ(•Ú›røKêÙ4±`Ïu‘c*RR[âDœ­\È=ö^])}eüÀž©?Ò‰å1| –´ÀÈ"1yè‘ß¡ôlø|rE2R.ð“ΘÏOÛȬåpKjUž¿üÖsvyá‹4ªU«º–Ùôänï8*LêÎ:wÝu—û5ùhå~` >Øg·ÖfxÖJ{Ä‘w²ä}9+káïÚíl‰¶ƒwøìó[žï´+vÉjSòŽ ×DVpÚVáÀœÆçŽ@èè> ²h¶¤ƒ„!•É@œl†u¼ˆ§`e»Eñ³·£zД‚~Ňì@uËñ*¹è¢9fØ­–¡. ’¦ì$t»;§‚¬_­Âf56˜­»„ó[ßšÓég^k戚R;l8Äm_ø°Û|ó¶]Æ´©´Ì Èô˜2_ÀåºoŠì´™o¾Â7?’çfBîpnç@ªú…¼Ì¯hƒu¢ý!Ìv«}¿žlIø‘«šeï ùi)r{6”¯ªé3`J׿Fâ †ó^—ëX£Ó¥Ÿå :<tP×µ~M\®Óÿ®7eóĦu]&~½„&/Œã¾\§®¥9>¤t…/ôìÖÏlŒèY‡‡m7xÖûÐ~ËoÜ–£öCÛœÕEBúv²nç;pn—˜ªå?üöé _ºùв‰á¶iYÅ]öví6"Ókl’è쪢þhw‹(’Õ×ód±—°c8'üd½Í!·}ö NÕ¹é#ù>è‚ÐeÚd“©^µodÞ‡ëæ,c4Õb»!zy G®Ó“d)F€eË–¹_%‘.˜çv÷Ô®’ûôÀ¥ç,Hœrè)Òý#ÌÌØø2?ÈSòD‡S÷ðå:³6O¸&3097L‹G‰{:ØrH³¬LùòO .7†˜bµó|TÎÈÈS×ì@“¾¼CÏŽôûBjSy¢Ì®a‡qP tiNžÙ¾g·~fƒÌÞsDçÈö>]Á¶CÀ}´›Øqdä\†X¶ƒvRÕæé?ØÉr;³ œë•e_ |ÃÖÈäµy+ë[U Tq׃½Ýf#M’ºW¯·j™^È@r=ýéåÜ­† #йàG S•ð9j}6üƸÔ+í>aÒ”4£T'zŠn–-±)_pÁTRÂ씥Îsyèé9$]ƒ9rn˜÷tAú¤YaZéZ¥‘f j-S‘Ű>žÔz‰N?ëñGŸóµt0(0Á |iNhwXwáCڦ샘êʠϵßô>yéŠ5rT úQ¥Ý'LZɧC¤: y :p"Š«ÎSjažÏCOçQ^ÍrL‹G‰{2¤„S¾|k¹îj_aZ^â¤Ge€óÿ†&òcÒ˜éÛ?ÿØ9¬Æ°ß™à…o?üáݯÈ@ÑÏ}Ú¡Š†ȤmÕÃûîë, ¾vÈÚÉì„[¾Cãi—z®ë.¬ÞxaçYM•ýëqUÐKü*Y†ZQrA†øEqÈQõ:jˆ?ºˆHq*RŽ}q+{/è ¦2Iºï¾³\Ðêl”¥XÉ×@ÈóUR?/e Œ~K…"%u¦“!J›NÕ:ýí×-fCtª“¢0Ëu6fµ»Ö0 i•x¹ÎQÒXÐ5˜Q~Ê@™¸ÎãFQÍ–ÚwÎ9Sß><÷óF‹~0s®ý—´)‡H!ƒÁæa<.ÆRµ‹t¸úê«Ý¯ñd>X5Öðœ–úfCÏŠžÛ´OyZ‘‡ààŒn»¤Òv´gh¤(ól¶! 6úG ]Ø@áÒÃÖŽJþѦõ¸ª@è5~8_¤ÐZðKšù¡&ô>tʃM}‰™¥¬H.Ó±`ÔY~ó‚Z§¿½¸eNÂdeâÚ+EaÖ×ù00Ò5¯²KºËÑÂ=ä}™¸aÏ:xü }5X¨§mC×>fv˜bÏóSâŒ:ÊÌ¡‡v/€Óryqˆ ”æÐhë¨r{¤EfÃü`ÕD 5ÚÚøV ”‚¶Ëj…b§•yÑ7hwÐä$|Vïe{« †…næ­ªúzH ×Å©jv•½W‡uDFô…^U âI|­êÅ7Ðzɶb%lèIuß(nNêwîùäpÃŽ¦b¯{ )¯_Tqîe>»ðùk ½ˆšŒƒOá$l”ŽŠŸçîi´(^úzšŽ™¤kè-ä%Ý9†ÂœãoW”MG¯]e¢¬eXdpë­kƒý)d‘}pÍyÞb7®É‚Ô¶¼êˆ,ëûLˆV-'n^vÙZo:6 ¸Ï˜:ï5Øt@¶(}3¼{Øú°›qú6ý6üdVìØÀÔÉOs_»r ¸®÷ÏWnvàüIOjݰÉ&Ó¯i¸&­ÊÞ·³Ïî´8W-Ï^¾Ü#›ŸêkvÜ…ù·%=}Èõ4l7Ì™Ó>ÇÈ&³l:«7™åȹ¶óÁ5¿]ñàšÞà#ùˆÑa 8rÚø–óÔÏ >·ÉÙ|ÀØ2äÜ›æOJÏùQÜ/UÿF‰ƒ6uíEÿµ¯}-èG£÷W¯{¯õ~÷7¯bH‡~¾P§F8šLkkµG¿˜~÷ÚÕgˆÔÝÂðñ Nå:†g·k³:m„<»}²êù½P· V–sð=÷­¬ìÓoÛ p² EVÜõaÝ Éâ‡èOÙܸ^NÎ%ý´É ¯¢Ë¿ ”‰²•I’…]²ß:JeÜŠduܬ¬O^ðÉúŠçÝ*È ›àsW>kÀµ²é ë\y%ß‚o¶âAžÏ!Bn¿ó }Þ½–¢°‘’ò‘ ŽœªÝ”{õ±(\懫NW­lc¸¯j|· 7îøòYüe¿ßô#µâÏÐsý!$ÚÔ¥ŒñÁ¥½šº•µ¿þë¿öÚÂQÉ÷_´´’¿å–[zíËšQ}†HÝ- Ïxisô3?ÔFˆ¬§íòËç®ÏÎÊÊ Sh ËÉÞ`Ýð¡Ýõ}ŒJ°qõ(íÓâfõ#éÉ}ÖMLQx½–+åwZ¦7tdõ5=©íCî E²:n\•#c¶ú~“œdŸ¸« ×,: ›o~ô0hlÄHë8hwm܈—Ô¹Þ•|ÀU]˜ Ïç~ç­ªúeÜ”¶Î§?pîKÚpí¶‰Gž:¢TI^m$úrM«úw™, áË*ŸàI«ýµ–^à^ÜÀ-‰kÙ8é:7%ßÃYgå~•Ħ¨6(×’‚ªËs–\/“ ÈØŠŒ!§|•!õ¯ã¾5(÷Ü£»_ì*R9Bþ@É8ëe/›^ùí³Ó¥—¤;EZV“ÚŸµé¦^¿;nâ–ïº{„<²Æœõ´§9ÁÁQ[~hªþ ‰Ã ÌI'ÔzÅ+^Ñzï{ßë½> ¦I%ÿºë®™噦äÓï2fTŸ!ÆI;jGBøîã·mÇ1hZÛ.áV¸­ÛdÑ9â–˜›ú~t&}M¬) ßB´H«.=Ÿé5Ê6«8÷Ù 6)¢_Û× ëÚ¸ŽOÒ6†À½¯£lûÂŽo´‰Ü”†ìno®MÏüCwá>ÚdÜŽlÅ®²óŸj/»Üª@©´¬H¨Þ}÷å]ö$ÉÄî2z·­’\¢èße¢lý$«Ø”HT}v×T@Q-¹—lU«×´Ä/ûi‡ÒôÜ˦K!#¼Òeñu3° u4>9 Ýz¬Ú¯2†îSž¿Ú?kl\ø-]É"#½è¼‘î& Í$,¥×o»œEé$`o—#Ùn22¸§åH7üF–kú~Œ›÷$l¸‰,˱l—VËÅ¡Œ\ƒô\ÿF‰Ã ̨¯ƒÆ49’ÿÁ~Ðk? GòGËŒê3¤¶gÏkûìpÄG¸_°m£6ÒžchǤmMÍ"à @Ù6%Ï/Ü÷Å“óÔߎÚÐ>ŠŽdÛé*áòÐSZæ@P|Í0Ç 7dD½"m·aB*Gk_”Œdp[ú:¡b"rªŸÖñO®û²†{Šà^Ü!Ɉ¥JüÊÊê:×ûræ'd^˜'ñÍèyŒ¼ù¦ºd©‹OŽy ì6ÚhJNCXøP’Ì¥°T¦È_Üœ;wúr -Ï‹ý*þë9¡vhû»ýöÅ~6~ûÂBœõœS™tìmºës7•Øî‘_bÏR(Ê s`¡)IŽƒà[Þ£åʺ—'‰Œ(ÃøUˆßþö·îWsüð‡?t¿šg”Ò~Æ@û[e‰§ÈßZô… + ºm䣟Ò^Ð^ù–ñXÅ, ƒ´Ã,¯ÑÈÒ_{¿?÷9w@ëOoÜ^²ƒ{¬wÉK‡!¡ïÚæ™ %£À5dH:ýý2[L“M¡~ âKwÈ>QY4¿2a ¼wÞÙ¶{Ö³üË{@Ë—_ÙiôÕ˦KAw“×½(ê‚`/]'ûB‰ eèá§t—Bþù+à½tßRÎÛå¡mèþq=ävÈ~” KY9ÒIÏ–hy~ÛüÁNÛë{8– nÕÕ%.+×}Õ¿Aâ0Gò»Í¨ì¬ƒõ‘íºM“ùÜ‹ÕgH_Ï8žÕé½]&Ô€•ç<íJ‘¬èE£øUWyîÊ}ÄUÚÐ<ƒ¿Ü#mœ¾–†±Á"ÈÝ·ë*ªUdA×¹Æv×™öÕ´ª¹ieléHéõËl]èpɹËý…ë¯?e? j‰C}ùaÓG£®uù=ù…ñÝêÞRç)#ŸV%hªþ ‰Ã ÌÜôéë³%3S•üa.†‰J~oôõŒãy¯µ¯¼6´|ž†…½ aÐꬬvKk~´?=ð„–(퓾// À}Z“”%¿ú>Ü•ëb‹ÖL­?UÂÐ U‚Õ«¬6$9_¶Û$¦˜a——Ä–²a´|·‹dA׹Ɣü+¯¼ÒýJ±!&%¥ù*`§+9eäºüè.qŸcšSW.XÐ> }Ç¡¹~¸¸v¥­Ï®€ÜüwÄ][“JÖ¬iñà>é–×Ä ó£©ú7H$3ÕÌT%¦™¨ä÷FßÏ8i'íÀ4R¹…›l’/{i˜:Æ3hè•ÑápáZ¸í¶ís»–A·[¾ûø-íaª-œ={êºO^È»Vººò‚eýªdÈ"Ý÷òÝ'r˜m·mû‡]Håà·ƒ=×`—†~ãWVV׹Ɣü.)) F§ŠGy¾wêĆ«n÷GÒÝ–t<¾Ñ…*øÒUû%Sbì¦ÈËÑá”ß<݈2”úW3‡™j¢’?3LTò{cϸiƒ3¶ýÐíO¨]³2´)ž6¨ö Ü·þ(»Ar­—ŒGU©z_ºÎy¶©é^û-úدˇ8æíð¢Ý³;Ãè×•Ëø yrâ>»¿üîwIr×]þ×™ÅyóÊù9Jè°Û×µï¾Û 9ØMÀ~0 ;â^^Øüæ\¿JÏNE²3¯Þóz<õ8r.¯»ËîÖÏg?{j—$ŽœÇsÎéñ•ôHdôx衇ܯH$R ½ó›´´l±"»¼… ­â+D´OÚÐî>ýâ ë¸é5àS+|ICÏ7Qëhâ­û’ÅÚ^«CRtä»óüâí0øÂo!ì·ÝÖV©8r>jíe‡ºB)—\r‰û•â“ÃØî˜O·“»$$ÇyÙÞ¸s+“Ñ&½?‹ƒ¾.£Í!·z +êÆ…=K'߽ħŒ‘¼’´4ÀV{îéplZ¨Ò}(j2EUÜò̓!'%]üSneñ°n Ø‹[Ü·*0ÐüH©µþ ‰C4ƒ7û×>šÁ›¨ä÷ÆÀžqÒ&xžëÓgìèÒ–iBîúìÓß—<ãÓe}øî÷ÁuÚ9Û&soÊ´ÁFÚZäË„¡=Ð%üg<㯺À5Q?òŒ¯OÄ1”ì6nº˜hÄ 6dYM,ê þ†ÂÏqÏ=§üÃÉbŽR4%}a.ƒ®säwዲîåÉ‘²Ø[òW»å«<üÆ^»•¶Q‚0êšB§Gâ§óŇxSªåŒNw[ºu—WÒ,”Vø/òyéiý,#‡»¡26dj­CBâÍàͨ+š“lž‘*s>ûQ1£ú È3® èœñÉb|šŸO6„“Í›B²Øáí¸[Ôé0H›¬Ü6†ÂÐ'ƒè‚©(EÙªVµ°%ÕDÛIöJRêäáÈõí¶›Š[HV£etÖâŸuGgýÐå.×t§ÂÆ“ó^Ðu®þo‰ÄV£í9ê˜hû¼ûòÈ»_+¶Ö_â–Î9A»GI…w\°¥H§ñÕ5ÌWst—•xKZÉo)Í"'mZZ´[yÔ-7DÊÖ¿G}´uì±Ç¶¶Ùf›ÖFmÔzéK_Úúú×¿î®æsÿý÷·Þþö·gËJ6Ùd“Ö«^õªÖÊ•+ÝU?ܳUš—³ÒòpñÅ;[?‡h¢‰fx¦¶6¼fÊ>ã*Ás=u³c8aeó4§~ܵ²´;ÒJ›*†ö1Ô.Ywiƒ­,mµu“ÞÆF£U+«¶XCr #ª™¨'¾,ÒÙÂQÔ<ëG()¹ßסЈߡ0„°aà¼tkfw_ªæ#_¸%£ÈT ©”†<l˜E¶JŽ"¡xi°“ªåíCÅw¹wy*èpŽ)eëßÞð†ôÁ²^¦èæ3ŸiÍŸ??;¿îºëœ„Ÿ?ÿùϙ즛nÚúÀ>ÐúÄ'>ÑzþóŸŸ><žÔZ½zµ“šÎ;ßùÎìžuÒ<ÿÒ—¾älýH¢‰&šá™¶á}PöW Ý.ùÚÝ6`ô@ú€•°/ÛnÉâ¿øé3¾ö´»„MO»­¯û†½Ç‚mÇuòp]Ô8mˆ¾Þ|pI2T’<6[´J(~%¥ÏÝUe% ódóÐu®%ߦ*9 †XØëœ‹}ÕXÚû¬ÛbŠRÐ&àž²96ªØ4*Bä«*îUý)C¯aQÊÔ¿ïÿûÙˆú¿ýÛ¿9›öÈ>_ƒEÏã /ÌîÕŠú}÷Ý×Úb‹-Zo|ãM7?ùÉO²Ä?øÁi÷ú8DM4Ã3mÃû Ì3®'Bí ç¶m@×à\ŒÜº¿l»•'‹t.8ê­¡Ë 2f¹_·qø'ñÀ W6¼# Mz^…s‰&²(ómrä-6w¤xô²à@°îæ1(ÙºÎ56’ˆtO|Ý%Œ¤:ǸC|÷i·ËŒD 6Léù!‡2u­ß\Ðñc€ô凎{N: $ø£òò²yÙƒÎ2õoéÒ¥™Òýàƒ:›6ÿïÿý¿L ¿ë®»œÍtößÿl‰åðÃÏ–î<öØcÎfŠ=÷ܳuà¶¾õ­oE%?šhÆÄ ´ ïƒ2ϸZ¡-Hýëi£t{Þ£Ž‘‹m9êaYüÔçE~úâÜWwØG¢¢“° :9ʪxâÏ ŠEÇIÿ$ºÎÕ¿O¾ÿ÷dÁ®»¶÷·_ý$ùãÛö²©ìO/ûßWÝ“ÖmJºàW¿š~Ÿv{ûíÃûñ[l˜ˆÃ‚Sר;—cÍtü µøqíµíioõoP;xè kŸx"Y ûâåe4‘EÜxãi1Ü1ÙtÓMM›—¼ä%ÙñÇ?þqvôÁ½»ì²‹;›‚{~øá4ûÒüS|ñ‹_L¾÷½ï%'Ÿ|rúØã9‰D"cDÚ*›˜Ó6°9mßhÉÓ1ÊlnîáÐCmßcÛCÜ]‡ãwtŸs=ý-ÕÆ¥úá4ÝddñkˆTý­¬Z!+ÉaU<²Þ—¥¢Âí¾û¡MJ],Î;ÏöZËžþUhFÉOc³˜-QHó>|uÏ=í/3! u$çT*.– (€ø‰£«Wû+‡vO#%czmñ 'L—©™Å‹»_ƒc𡸠r„É—'~þóéI¡(­°ç‹ Éâ7GóÐ[¼ÃSy yqè‘&ò£ˆ»Ór¼Í6Û¸³)Äî׿þuvôQåÞGy$9æ˜c’w¿ûÝÉœ9sœm$‰Œi{ÝT¤ùýïÛmGÚÚsÓ–d:‡UÒËÊ-øÚ×Úz‹m­| QŸ[½ÆB8=úJ6ðÄï 4ZšèêÕ/I­âé¬e)þ 2))R,POÿüçvü¬Ê4P>•Ƽ„±se Ã’æQ|óœk÷ìZ;mìâ,Ö=Ÿ\™q¥(núº5¾ô-ãžÍk+#øÜÂØrá“ÊÔ¿í·ß>ÛÝrÛm·eËiN=õTg3uÓ337EF·WöÚžNK»W§¿èEÉÒ¥K±m“Ê>œºƒìu¸÷È#mÙ”ógÏN]wÝìwfç¾A|`*·âÊ+³ßB'º«•ßñå/OÇÕW'‹Òkk9AÖuÁŽ?þødÙ²eÙoá—¿üeæî-·d1épúé§wÇ#…åÈ^wÝuΦÍùçŸï";ðÀûÏTvíÚ,&mÈ4NY,TÜ:ñ¸æš©ôI9=5Y,Hßç<'ë2?üš×$‹R7³x¨óÓ㡜kR÷Lóº ò:µóÆ#µGêF [ZfV¦éƒx`Ÿ^?>ý¹L䣔K–,É®‰yÅ+^‘ìµ×^N"ÌFm”üQÏR9%íR¸¢ì½·ß~{ò‘|$ù—ù—dã7Îì"‘Hdì@·ÌþvFϹÆ0ïã·g¥™õ/e×î‚kw2˜ Ðãî½·- z˜Ø7llÝÍ£ŠìP6º\g%øg?;5rŸ· ¤Œ»\“É0Ì›ç.ä`Ý%›efáode@÷ÄL™pôÍÀ{Ù®+s-EŸÞ®ôp5Èô2º«_â]wÝÖµÏ|fû:]/ü9é6É5í¶v£ôê=2YÄ­qíµ×º_ƒ£ËofJìÛ,˜‚|ÌÒÊ—J&3UFòMÞtâaåBîõÀ ó£Lýû›¿ù›ì#H–o|ãÙHûW¾òg3yóæµÒ¼;›â¬³ÎÊî½é¦›²ó·¼å-™ì/~ñ‹ŽI;7™Ì§>õ©ìü‰'žÈd-‡h¢‰fxf`mxŸ”yÆÕ†¯-ÀØ6sdÄ0+íkû…»b§‡iõo‘ ás7DÙ  lt±—äÖF²ÒfiYw}E$$ eݪÊWA×¹fv×I+ÏBb’ìP(1eR‡0Kun²‰pˆGL(EEŽJž#“¹¯íÀÂ… ݯÁ1͉¿‰o'-¬ÅÜÞÇo'“å7ùãùªyíÉ›®xˆ\‘{t~”©ì®3{öìÖ<àlÚüË¿üK¦„í®óô§?}š‚ÎDZØ_v×yå+_™¹•g~ÿûßg²‰C4ÑD3<3Ð6¼äùð´§=-{žj³ë®»¶.¹dêSÿpå•WzŸ»GqD68¡ÁmdÙ8õAì¼ö¡Ôè6èŽ;îÈdW­ZÕn'ÜàÕi©9Yîu°dÙÎ s÷¼Ôd»ºI[“ºíÆ·Øn»Ö%{îÙ¶ÇÏTæÊÔdí ÈºcW<œ»78ÙûvØ¡mï` å‡>ô¡ö‰“½ØÉ®JýÔœvÚi­cŽ9Ƶ™ÇyççÝ9ޝÛÚü`ëæžóÃÑGW~8§ÄÃE×™‡Z›lâÇzë¢äÄÐÚsO¹rÙã̵­'?Ùm·]˜¶{÷)ÙVë)O Çc»íVuÉnµÕôüà–Èîø—†«\~ØúA´ýß®õ¾0ûýò—¿¸¦Û;5è´pýõ»ï͎͑y²œc|í£“ÍâfÝ Z¡4Ú/]o² $-×­á“÷IrbôB‚uÖYèuW览ˆ:+«Æ¯WtklŸüJ±áº¯û(+Ëõ¢0”‘™)è´H½®#öÝÝávÈ}yùÑk÷z߈S¶þÑ£—/ÞžqÆÙG°ÖO=²qðÁgJ9# _¼¥#°YúÔÓ_¼}ò“ŸÜºõÖ[”Ÿøâm4ÑŒhÞeŸqµ‘¶M¥iGzÑ58:÷3¿¬Yox´,&¯KÏBó´ö¤‰Á4ÁúE4%i,؉n$F'§U[6Û¬8nya°hYë7çUâ׺Î5£äCÙØpݦL]…{J¦NÇâÏÎ(öt‹I7.y%¸ ÜÏ=b8/ ~äåßR¶þ1rϲ>lµá†¶^úÒ—¶®ºê*wµ ӯ묳N—’÷ßëmo{[kË-·Ì>€õªW½ªT}GÉǽ¨äGÍè›·á=RöW½¶MU¨âGÙ~ÚdžM*k¸nePíÊfp7Šä|X¿9o ]çšSòóÐ)9¬”Áï*¹?Éwý& ó[6=8ï¥C„lLç#QÿúDâM4Ñ ÏŒê3d(Ï8ÚÑ)ÊRõž*òed¹F{*ëIbûÄ&#úŒEZÕã³+“m¾{«Ðïýý ë\g ÍAc·+ì ÷)*Ú÷¨€ eÐÛa™m…¾Ü/ÉHøAÜÝ‹lÁ¨ÓCòì’D¾,hú¡÷”Røè…IÉH$‰ÔíJè G¾} ­¢¯…ÈóÃR$«ÛT>äɇ'ûl'T=–$ë­—$Ô>ת ¶è“œEY!”P sÁ}žaeecJþ´/h’ST4û¥8ö_·9Uf#Ñôú63-!çuOï§‹âÊ×wL_ ?|+½°-ýçž[œV:ÝCµLËäáäæ\{­³MäG$‰Dê#88CÛáSæûÐèjÒþ3Àöô§µÂ¦žšô¯Œ_:©'çS¢ ˆj’ÍúCÇ–<ÿ´JXq¼¹ƒUušÎ»Œ¡M¥É<ËBdÎÅî£_v¾£ŒvESa"#KUòüœdˆ³¼d+†ù-ë’ÞúeÜPZiùù.ûñ÷ëÖ1”úW3‡h¢‰fxfTŸ!ÃxƱ c´´a´ïiX:FÚ5Ý® # W¦mIeN+ÛI|²ØévM¿ÿf˜·Ó¤eü"Itbìö$¾Îë…¾d·þ!£“Ýžkò®YDö¥/m&-uŽ’ïËß>EVŽsEr¸'(OÊú9ÉØ4@ù¶%™sòMËé´’R-Ç c_“·2Bè!=¦ ¥þÕŒÄ!šh¢žÕgÈПq´/ÒþëAE«Ìs¬2ȧݭC;Ú3ü²îÎ@HÔF«:¹ËŒC‚¾gX²u¡ë\cËuº°ó |ZÿÏnŸËTÓh,™‘5ßyó%Eó*z~G¹WäÖL@§Áºë&ÉöÛOŸëâüÍoö§•-zÏ‚ü‘ü–lq]ºÃoá ”™˜?‘H$)‡] C»ÁšwÖ¾³[–íЦ±LFÞG]$„v7O·YÒZ$+k;hÿʸ;C!9ôêa°jIÉjoÖë£^CQRr­l²ÛUæuɂƔü[n¹ÅýJ‘u÷¯{]·HRñʾ„âÜ»e»íürä¾~A7yÃçž ›’éŠÃ€ ?tðFËêÕî‚!”Vi)¾E—jûž…JÓ òGòŸNÅ&›´ÒI'A}j‡z!ø–Ù³§»U3MäG$‰D„n_8¢o„”ytÚ+@6oÉºë“¥í¢ cá¸P48UÆÝŒNž 7 «‡œ‡Æ!²GÆË&;²v¬Ñ7& >ÙÆ³³©©´Â¯¦1‡Á|‹Û°¶±ó0"gX¸í¶Áku,óhâËoáGšþÙWIç²óS:_9ê¼"ïDFÍ{eù=`VMÕ¿A"qˆ&šh†gFõ2Œg_þîB·/rn×Ph;–ê÷C¤÷¬Ún»)w-¶-ð($/p]‡W1-n¦IÿÊú•“<ÓÉr¾Å«²,ÑE È]›¥¬Z¶EI°²›lÒLZê:ט’o?Г ©äKµ=¤¿ïxÊSü× ïÞ’TŠCŒ¤_Nm¸cÿý‹kKÈ Îe]$†µ“"£î™„ühªþ ‰C4ÑD3<3ªÏa<ãJ Ψ¶$ƒßi8;†sÁÊ*rýB^ôŽÛib PÓ¤MúÕÎî…•³Dg)G;~,c’`e·Ý¶™øé:7Ãòá«Tí\™2:Wò® ÚMŸû‘rfºä†Ò0/‹Ü¨aæeÙúW‰C4ÑD3<3ªÏa<ãzœ µImUævymíYM»ö51¸¥iÒ¿:ýÊËÀþ)O¹£§,ÑncBc’ e›JK]çFWÉ÷A*ù*Ç*•(äN¤”XÒN ç–¢4.rc†äÑXÕ¿‡h¢‰fxfTŸ!cõŒ£L¨«­ò¹ugI‘ܨIê:ר‹·¥ÐoAøàM Þ°àM ¾Â ÈÊKº¤¯~ #ä/ÙèC?÷¹ö‹¸!#m$=ï¾;ÿå$äŠvàM^²…Ð[.ä1¯ÇK^G"‘H$2(Ðì‡CodJ{Xvûí¶ÜuŽ`U¼¼,!;¹Ê ìQ1oÍù²Ý;ƧΠ‹Æ”üeË–¹_ʤ¤À+ʲõ•R&—¡ Ê—âòÜCÁd‡Îî~®¿…q¨‘õC§çþÐNC`‡ý@trËØM@ÒØ–zdØ=‡m3é,ØŽæÍK¾^LžüéOSymòfRò#‰D"C€6¥HÙ¦m .ÒbÇ6/ m]ž»ú^Ž´wQáïäE›$‰,I¯³Â—eúp¾"2*4¦ä?üðÃîW€²]/+§¶¦z˜‘aÉÍ<÷È}{ kÈß”Â8ÔÀÈú¡ÓS§ÝCu× '—ù€#ñv+í–®€[·Ý6Õ‰¿l¦LJ~D"‘H¤>J ÎÐÖix=¸¨4¿lpqýõ§¶ˆ†òHg¦:óië­§–â¹K›©WEap4=ðÔ¤½ú¥“¥^+æqÈŒVëáÜUÃÈj·èˉ:ƒ›ÒY Ÿ†r/²¡¬Æ acJ~!¤½`ûÁ$’AæE4Œ³0J¹úÚܹm·0‹wËE¦Ði¶ÙfS£ï¶f䥻 2eæ¶x湉D"‘ˆ¢ÔàLÞ`“ÅÊò•~7•ù¤g£‹Ü ­$Ð+rhzà©IÿzõK'¹¬œã[mubòœç„U ›•ZÅÔ‹/Ûaƒ†££ä)l_zÑ)É‘5ø>dnFãsè8à.¹À×\Yޱr‘n$=é²|p¸føÒ4·ëeú“ù5yñ™Z„½\?äF"‘H$Ò+´)´_¡vL·YZ–¡bÚ-ÁjtEîjÍQFôQüÑ6­l¤:É«eì¶ì8$*`HÅYßx$nÊ,€Y_¶¦¶·ºï¾ûܝаg‘ì…4kVûÈ9Ÿk÷‡;æ¾vp7å ÝËÛ[ÉCÏq¨ÀDúáKs»ç”¾†)±¯Õ$¤USõoH¢‰&šá™Q}†Œå3N·YlÍM{…_ÁÅN›2_ÆÕàîa¸7n«9HÒ^’ÖÞÇѪ/Ù·Î:íke?’ܺÎ56’˜Á­‚t¥x“´Fô™.ÓSdéïÃ{Ìä`gôõb=¢_–¦óSò{‚Ôs' »Löe[ÛÅÒ`‡‚‰)Se‘þ`ÙEZ:ïdãZò‡ºÃ&s\’ŸtÂ|nG"‘H$R@_ƒ3´]28E{õÆ7v.Ò^¡ü;vùÝïʵW¸Ë zˆv¯"M<5é_Ý~‘äqÈ ñO²üÚk»Ç€G–‘}°#ú|³“NDYšÎ;m%ß7w¢¹÷^÷Cá“…å^^‘öÉEúƒ‘zyhé¼Ó×Jº#Wq-b$‰D"Ct=ìkÛ*ìøê»†YhìC  ¢â.ÃbÛ7pòÆ!å¼r¡Ç€íÈ>+Äõ롌KþâùY?lSò—/_î~UÀ¦°ÍCæƒON+œB ÷,=Å¡"cåËndSZŽLe:–“¾’w\ÓSž¾t·nq^À¤äG$‰DF­+„Ñí*²|²€ˆ&(÷„Ü =)è,×Ëq°GÖ.:@Í‘}`–`”³³1%åÊ•îWl ÛÜAT©ùÀT˜•ÓÈÖãCOq¨ÈXùAú±)-ùc>$¶ò…/œÊ;®Ù)OKŽ[!&%?"‘H$R=Îh]!4 eÈ|b+$‹(ëE¥„»!šxjÒ¿ºýʇÌÀ?岋ÎzT=‘Ñý¼/å†h:ï2Ær[Ýo N½á©þ‰Œc_ÿR$ÑDÍð̨>C†ñŒ;âˆ#ܯ(Ò°gïü4N˜#8rž'/­×°™z_që&ý„_yÙ)þ‰L•Ïä¹¢©´Ôunü”|›²äŠ|$‹£T ®‡¾` l^Î@Æ®þy8DM4Ã3£ú ™„gÜ4h³DïC[&ض-¶u‘Ñu®±å:µ ß—b˜ú¢ŠGY¾£ZÅ5p£‡//#‘H$5hŸìFëz‡>½\Ç×¶Ù5‘HCŒ—’ïSÜõ‚*½8*d b',‰D"£ŽOi§½ÒtDÉ>¶mYnûxãBcJþ¢E‹Ü¯>Њ;#ö¼­NÅr/x.âÍ ©hõ˜jèAׇ&´&,ÚtÓv`ë0>b7“%ïdÖ¥ÇNؤäG$‰DFŸÒnõnpq€q¢@±}¼q¢1%ÿÈ#t¿ú@w^kFId¿YRûŸý,9ò¬³œ` ö\—0Õ3µÄ¡€±÷ÃÕˆ#z¨½/0_¢ Ø€V}Éò¼ì±6)ù‰D"‘ú¨up¦Êà"ˆžR㣦é§&ýkÊ/TFæçÌiûÇ9Y…±ª";¦Ö513ŒAÃÆ”ü ¸_}B%ÓŸ/#Ü),Yb­79¶2i¹Ð˜"õ£Óýàƒ“dî\wÁÁHÈ÷GFbÞ”æi9ï{ß›<ãÏH6Þxãd×]wM¾ño¸«ùüîw¿K–,Y’ö§¶J6ÝtÓdÏ=÷Ln¼ñFwµ›ë¯¿>Ù}÷Ý“M6Ù$Ùf›m’£Ž:*yˆ¥W‘H$2S±ƒ†´c¡…Úq€q¤±ÙóìgO}0K`DŸ~+[âCü#GcJþŠ+ܯ@)d;*R\åÀŠg=«ý[¹š”ÈZã`"üHÓ{Ųeítç;ЇÚ=ª/KtúÌ›IÉ2rÈ!ÉÇ>ö±ä-oyKrÚi§%ë®»n²Ï>û¤ýÚüQ¢'ÒÆhß}÷MÎ?ÿüäŸþ韒“O>9¹÷Þ{“W¾ò•É–O)~üã'¯~õ«“G}4óëmo{[ræ™g&ûï¿¿“ˆD"‘í”4¤ý Ö[Ù>Ú¸HýØìAEá#ûòµ[á¿hÇ>+›úPÅ®»îê~ÕŒúÈÄÀüp Ú}˜X?øH_ûcu~M'›„´*Sÿ¾ÿýï·fÍšÕú·û7gÓj¥Šxš¤s[óçÏw6~.¼ðÂìÞ/}éKΦպï¾ûZ[l±Eëo|£³i³÷Þ{·žùÌg¶|ðAgÓjuÖYÙýW]u•³™ŽÄ!šh¢žtÞ+ežqusÉ%—¸_‚öË}ló¾ºßàG®7C“þ 3ndá:ë´U1úûfuÐTütkl$Ÿ¥®s*iOz«_ýÊY†ÅA1±~Ð]>è Z»Ä“’VE\|ñÅÉìÙ³³%7Âl¼õ­oM¾÷½ï%¿Ê)÷Üûô§?=Ùo¿ýœM’l¹å–É\zé¥Éã¼–òÀdËÞüæ7gKz„ƒÒ<ãü¢‹.r6‘H$2Ú,c&y¨áàe,npˆwàq34éß0ãFn¿}ûýj é¯{¥UÓñƒÆ”üÁZ8Y÷›ßt¯‹ŒÔ¢—OÍX?¿cÚ˜hå^ò’—dG–Ù„àÞ]vÙÅMÁ½?üpZmÒz“ò“Ÿü$ùÓŸþ”üÕ_ýUv.¬·ÞzÉ_þå_×ðG"‘ȨÑÈà íXªnõÈ#êM<5éß°ã6€±È.šŽŒ¿’ÏZ8YÇ^Gk”#‘qãî»ïÎ^‚µˆÝ¯ýëìè£ì½ÈO–™€ógÓ†8ýÝßý]rå•W&{íµW¶vŸuúצùdÃ=»ø„Öþ¯\¹2yñ‹_ìÎ"‘È0¸á†¼Kó†<š _½ì²ËÜÙ€`Àê¼ó’Eücrƒ#o|c#ÿÄMѤÃŽYJ_&pYÙTüt›•*÷-”ŒH$2<èd¿éMorgÝ „³\æ§?ý©³isõÕWg×þã?þ#Û&ÓkùçÍ›—|õ«_u6m–/_žu X‹ÿüç??Sâ÷H;_¼`ûú׿ÞIµÁžþð‡Î¦îe  ‰ ¼‚a"χA$jšÊª®¼2Ùç±Ç’Ëyùöoÿv ƒ‹–Fâ¦hÒ¿aÆm@c‘]4?=x8‹íôÍÛn»í’6ÚȉD"‘&`Ìí·ßž¶›ízããØcÍö­ÿío›Ì ÿú¯ÿšwÜqÉwÞ™<ó™Ït¶ÝÈè<„Yj#`vêaï|ÜäåÚßÿþ÷ÙKAïz×»ºvx,mÀžúÔ§zg„/|á Ù%‰ ¼‚aŸ‘Èpà™0‹=5Ýy$A~ðƒd_¸ýð‡?œ¼ç=ïÉìø.KuPÌùJ-ÜsÏ=Ù×mçΛm¹ ŒÌ£ ñ‹_L^ç>×·víÚltï½÷NÎ;ï¼Ìeø¯ÿú¯äg?ûYg'ñÿÚ×¾ü$7îÅ‚Hd8”(&ñù‰4‹~&D%?<ðÀä’K.ÉFÚwØa‡äì³ÏN~ô£eKvd© _Å=çœs²Ê=gΜ̎/Þrý¦›nJ–.]šÊò“ŸLîºë®lù ʾÀ6™óçÏOvÚi§L±Gæ£ýhòŠW¼"¹âŠ+œT$‰D"‘q`üw׉Df(ïG}tòùÏ>9ꨣ’?ÿùÏÉW¾ò•®µð,ÇÑKr`uÖÉÖÒI8í´Ó²¥?[o½uòÍo~³KÁ‡½èEÙ±m{÷»ßœuÖYÉÛÞö¶ì¥ÜH$‰D"ãEÉD"‘H$‰D&Œ8’‰D"‘H$‰LQÉD"‘H$‰D&Œ¨äG"‘H$‰D"FTò#‘H$‰D"‘ #*ù‘H$‰D"‘È„•üH$‰D"‘HdˆJ~¬9õe=É/õ 5É©/Kå_vjúËÚS“—9÷2SÊÑ+’Ãsï1×C~÷JOaŽD"‘H$Òµë+‡WÐ+¢¾2,¢’_•´`Ï;zçäòV+iµ.O’}Š*…w^rôõîÔÚ¯^”èËK^»·û•ÇÞÉYV'§ÌOOÏÜÇ„£}}uzqÉå©ÜwJæº+uÐ[˜#‘H$‰4Âô•6©Ü>gºßeˆúʰˆJ~%ÒîIg¦…ðŒ´HBZ0/_’œyR^¯sªðú¹"ùðÍÇ¥…Ÿ Ð6gT-;/I–¤ÎŸ¹ÏË’Skíþ†¨!Ì‘H$‰DÄ ô•6W¾"Ù©@&HÔW%*ùUXóÕä¢ëç';Ísç0o§dþõ%_íµ°^±"93íÕ2…Ôû ÒNÉÒï^ž,IûªGÏ;<-Ò¦–0G"‘H$ƒÐWàŠÃ“¯=#Ù×V'ê+M2yJ>ëÄdÝ&°¶ëŠÃ•ŒÏøJÃê›Ób¹s²£žGš»cjs}rójw^‰vO[8sŸ€¿¥H{à«OIæ'g&û”t£§4¨5Ì‘H$‰ÌPÆJ_+’ÃW¼¶†‘ð¨¯4Åd)ù¼\±Ï™ÉüSV·§e(D^ëÞgLMÝxM#ó9s“£¾+~†ÖªU`îQÉÙ8’ºñ²ó`½¥AÍaŽD"‘Hd¦1vú ŠöŠäµuùõ•F˜,%?ë¥&ÉÎÒuM Ñw[ßMŽªó Ëš[“›ÜÏþhÆË—¤epEï%pîQßÍܸþèy äz‰D"‘ÈŒbÜô•´Srëke}=D}eðLØröK#¯]!S8á;zšúa=[ZEnæ¦Y÷Ö{¿6-}²÷íë™ûž|ÕÙùèmúk:u„9‰D"‘™Ãxé+W|øèäh–»8?ç±ÏõG'óÒßý(èQ_,“·\'Í쯕é™p¯¸§©Ÿ¹û&Ìï^Ï–mÍ4ÿ€dß{ßýoï”öXÏn¯w;:g/¬:§ãš‘H$‰”dÌô†lžù§$«Óßý­à‰úÊ ™,%?{ѤzeÖ{•#-ŒÇé-¨®H>œÊ%Çïéºúæpáí@¥?i§di¥ò·:¹Ù7ÿÆÔóRƒ¦§0G"‘H$2ƒw}¥'¢¾Ò8ih¢H{—-¢Õ1óOi¥=ÍZÑ~,¹ÜYf¬n¥[ãçå­´èª0Ío"WŸÒJûÂS×lX;×—¤®LÇÆµ;,mñÙ÷LQ˜#‘H$‰2VúŠ!sWßõ•‘dÿÒÈGF™+NMNwÔ`_ȉD"‘H$釨¯Œöâí¤Á'¦g%³Vì+L$‰D"‘%ê+£HÉD"‘H$‰D&Œ8’‰D"‘H$‰LIòÿ nRGW%J×IEND®B`‚pyclustering-0.10.1.2/docs/img/optics_noise_tetra.png000077500000000000000000002053061375753423500226170ustar00rootroot00000000000000‰PNG  IHDR“H•åsBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+ÿ•IDATx^ì½¼]Uµö=N?é½H $¡÷^”*HE¹zÕ[ü|¿«^ñ*lx_½ßµ Øè¥ˆ HI„RI€ôžœ~¾ùŸ{}æ^{õµö>€çÉoeŸ]ÖZ³Œ9žQ末®×@0€ `È€2@UÑÓÓ#]]]ö©¯¯—ºº:û~ÀÛd2€ª@I¤»»[ÚÚÚ1ƒD8-©@..Á ÌðÖÅ™ W Nˆz# £££øWá{¯ÈA" $£ä¢ÇÁ `o Érb„‰à•¸žF{{{Ù{…Нœ§Ø¾}»}?zôè’'ÃÙ ÌðæÃ™ ?Q…Ï÷ê™Ä%ÎYºt©ìرCöÜsOûèu5<¦^ŒLÜë`ÈõÅ× ”DV­Z%[·nµïó M)1pà•455•B`â"ƒ÷½7oÞ,[¶l‘mÛ¶ÙÏ;;;mÙ”„0€Td2€DPÁÛàxá…dÓ¦M¹ˆ ®å’’ „¢£Þ ŸãQ¼%þæ3¾Sïi@þ “ÄŠ«Å ¡¨‚¯¸n”g¡÷×P$£ Ÿq>åU‚Á{Q/¯†\ßS¯/fȆ2@$ÔêGùbÝ£ÀÕ#ˆ£ôӀ릅—`‚Âd„Å\/K½˜0Ù d2€@¨e‰¨'â gU‹L@ž×¥œ.Áh¨LëðøãËÚµk-É„…ÉHf¨Ä™  (K§†€*cK5òÞûT ÜG½à&Ë “ x1À™ ÀK"Xâ¼G©z½|^-EÚ_ Ú%ÈEõb  “A,J2Ÿ«3@0øG™ À*=$JK;‰(ªE&Õ$©0Ý“òpÐ&n˜Œ¿µ¬´NW†`ÈÁ¸^Ì@˜log É?0PjÈÆm^E§ “×8PE†¸×r‘æœþ€¶—z1J0| ¼E=^ÖÄ àí†2ùÄ"Ãyâ‰'¬rKB"Š8d’oUëG0ü­a2Úžvǃ™5k–lذa L6€·<Èä ªÈ4좊/­âª™T“¤‚À=«®­m­$ÃßÌÓö “ñý@˜loV É?TYA$„UT±ékZŹ(¸¼A¹ÞîJSëGzÃd¼&󮉓 à͆2y›%ƒBRË–÷j%s€,ŠûAé×Ú7.Áh¨LÛ£@½%þØ:fý…2y›ÂD°€Õq‘Å»¨™TëºoFxû#üÎëÅð7ŸÑVô3ÞŠ†É”dÜ0Ù€3€ja€LÞf@Q 0°N]OÄDYw–sÃTÖ·òh7í[%=Ô‹A4LÁp¬X±ÂÎàÓdÿÁ  ÉÛ(%< U4QŠ™ßTÛ3I£¬úCÁõÇ=£ú')¸žö½&ão>_°`%<Hï…d?z1&ëöÀ[dò6ƒ/D­LU$q•¿K«487-…!K™Þ*¨uýT.¸¯›‡á3 a2EÃd:›l Ù?€( É[(qä7Þ'Ÿ|Ò* o$ABPåÂ/¿ü²¼òÊ+²fÍ«”â(£¤u@|¸í¯£a2%•#äÂ%%¼ “áÅ ÌÈä-®ë‰ðžVGB¸§ß¹”ïÅ_´;ñ6A-Y²Dþö·¿ÙÏæÎ+‹-²DH¨ÅïiË”µ&0­_Ü7ìž|Ç¡$ã “q>ýKŸj²`MÌÈä-¦ß4_|–PJ#íùª\\/ä/ù‹U.Gy¤ì·ß~²Ï>ûØ¿O8á9ðÀeüøñ¶.$ƒgÏž->ú¨<õÔSòÒK/ÉÊ•+KÛ» ¨Ü$…K0êÅðÊ{@bÔ¸kb51ÿ “·üH„AÍ¡<‹âõB蹯¿þº<öØc– 8à9üðÃeøðáÅ_€âá³wÞYöÚk/9ì°Ãäïx‡ýí.»ìb¿_½zµ,]ºÔZ¹„ïH¿úꫲ~ýz[ÿ·Ò(õ¬ ¯òº/×áp FCe|Ž\âAc ÌŸ?ߌ†ÉÖļ½0@&ob0èu†–ë‰(‰(ò “´çs.VçßÿþwÖš6mš{ì±2nܸâ/¢Aù‡ "'N”éÓ§ËÁ,û´¶¶Êî»ï.ƒ¶³¸>dE¨ Åá$ÉüÙÐ_eΓL‚ rª$ƒübð÷ç=d¢a27Ù?&{kb€LÞ„`)‰p0¨tpú)>Ë2èt€'Šo°Þ…[Fþö+s´®ÒÔ©S­§sÌ1ÇÈñÇo=š‘#GZÅ“4ófCš¶É Ú¥Ö÷E†éS׋Ñ0åñ “qh˜Œ±0&{ób€LÞd`Ða•éÀa‘ˆ‚ïÓz€k'9Ë‘ÐJe0vìXë‘ òBP}Q@£G–)S¦XïÅ›‡¡Í¼y<Â,(&¾C-U(E½g˜£F² ’!Ãd‚ƒ:Èæah<3ÚƒŸ›‡A1EåaÂàmÏZ¡Ö÷¥/kyOîŘâ¾x.J0JhŒA¼bÑ0™&ûÂdÉ1@&5B‰pâj+‰¨ÀëkZ2Ð’å|4Lׄ@˜êK¥ºÛn»•îáeO{ß0pÝþÈ( 8yÚ*m¦?ê§÷¤}k î$CÕ²©÷Õq¦a2ÍÃh˜Œß2>uʲ›ìX2©2DJ"¢ µ; è´BÊut0¤çRFVŸÚ¡Ìx"(Q\¨G5”¢Û6oP¦ < ³ÙÈÃ੸yȆ°áBR5Ú* ôþµn_•ûZƒû2¶‚@™8\’áào•m ƒ51Ñ “*CÐ ”µ ­ß âó´dÒžÏ9 r(BBÈð.&¯eD1cA"¸X–„5˜­•Ô+mÙU0½`޽®eao/¶¬WO ‚Áê%†ï.ÖC˜U9…µõÛ µ®§—Lü€Â6lXE¢ñËÃàÉ<÷Üs¡yGµ÷D®k}_€÷×}A‘Ñ÷”KI†ƒ¿ùŒöBça B*š‹áõ¿ø…ïXW I4RQÐ!Ú‘iÀ}â(t~Ãf‚X‰,>$ÑJL¡HK*Hi@Û¸÷Ū!þI«!ŒÂ"=bøì:j¦æ[žLèd4a·“˜´a*÷ ;ŸÐ³‰á5¡”Hëö'QçGóÓ*^z-m‡ÂŒšA´«¡ô¹v5®›q¦*céB.LÐTåþ¨÷Ôþ®T®“ŽÉ¬à¾auuó0î„ ÂžnbÑ<Œ®‡ ËÃpßjxq@™ªå™¼m×™ÐaXX„Xg@#¦ظžEZ¿ó)§nBœ–Ä/¹¶qÁùü6­‚Ñó“‚û‘¯A‹£P-¥_kåÒÖÃ;U™vD1Ñ–AS•±züaS•óF­îãBïÙ$–ôžü>,ƒ!Á8Ö<Œ†;Ý< z ¿È¤÷¦ÿÞ–ž óNóÅÂH£H]d%ÎwË@9±D±N4¬V…ãú´ƒ= ™ŠÑòòi¦¹w\¤m7‰¨©Êȱ;U™Ùd:U¹mJ{ö‡‡úã¾y(VÊ­yòix`)£áN7C˜•g&.ªEdÈãÛ&gBg@~3´ “ —3.¸N2á|Ê„3¥”íOØKÁCy„ &ÎiçÇ=×]tÈ&Œ„h²€zUc°x¯tjÜ»Z ŸÔòåÀCÅòÅc¥/øÞ»«²»ÕH´U­•:÷Tù®%Õ¼oPFg’©7ªy]×”&Õ ʉÎxË“ ‚D":(h¼¬ƒŒkdé\í@¬„D+Ž@ëoÒ–¶ˆ:áö.:äÙ'Ú–Yî] …î*½Þ5½Ò}k·ôn)¿ïíçæû·T±ÓþX·îTe7´’×Te½g-\Õúž€ûÆ{yaÒ‡7ƒñÜ< F'Æ}™Çzô eÈ ró– sQx¨$¢Ï+˜y‘IÚkP>r6€²aéãþG ú´eà|ÚÈ ª E‡Š°ó£@Óž®ËÑý'Ó.«LûÌì#K$æ½ýÜ|Ÿµ ý¡ð‚@YÜÐJ’©Êak(h£Zד{ÖZ©ƒþ ÀVãP¼QÖ5yó0x5ŒCò¾Ay é¸ðÞ;àE·œg‚à! µjè A@ãñ»,Ê$ ™¸Jö¬²N’¼VP7®™´÷\Ú#jÑ¡Âïü¸ ÜYÚ>z]^Î4ÃhS‘P^+‰yÏç|ÏïÞjHRf~5U™¯±{¿©Êôq­Û©?î ¸o ÷Rè´‡_ÆíKÍÃè¬À8ëaðlªA&„c£®û¦":+¡G±Óàa$¢P·.­U’ HÜS•4‚ÀCª²(d@Òžï½wÜE‡ Ú8-!d97 n¿× 3„r¾C(·;Db>çû·òj3wª²Æîƒ¦*3³ÆoªrµÀõûK©÷Ç}Ñ#iïë×—x1üÍçØxŸÞ<ŒNÚ¨™àYEéá7™Ðé4$BcPh:#ªð m¼,dâUÆAÀez' ÕTI3õ$!$?Ä-ƒh+ÎMºèP¡ç§A–rGÁUt–PÞS>PxÿV$’j#hª2–0Þ ã0JÒ]•ÓÙˆ;–ó÷M«Ô³€ûæ©Ð1–1 tV †«7£“6Ð?<÷(Ï< dâÍð¢_É…@j„(‰$>='‹""\N: K€‰µàUÒY•j–óiK¼º¤‹Ü;­á~Açò93‘ˆ»á–8ðʀ͑Ü_ÞG¼÷&å³ m¤÷òÖ±š@Ʊ|Q AS•Ý]•y`\S•©'òUkPÞþ¸/z$O2ñõró0 cèóaòÊü©=„ ¶¤BShµãÓ®¬^AÐù”¦g$‚Gâ',”?K8?逥-±@˜æË¹X IÚ=­²à\?%ŒÐÒn Œp‹>ÄJcÀììºfͻ͌ß5ô³R²]C[šöws(9ÊÛ´§;ÆT)aẻ*cýb,ñ½Z½i§*#WiÇu¨N©5úó¾@ŸãÍÃÐÏÅx :ÝÝ‚ò0ì0•|5­1UÑZXÎZ% ò&ʉâƒÕ!<ÅÜò p´ $%]tˆBFxhÇ4‹÷ö¤8ð’ BÉ–( ,'’ÄÄ€õ!VÖgSP~HÇK0€öàÚÝ÷8DBŽd’'‡b¾O[þ4D)vd„kœ©Ê ñ{ .ÍÇxÃ*ôË?’RGø›Õ†¶»·Îš‡¡ïw:ÝÉùåaðf—ô)D…†« ŠW  ¨ÂF ©4¯¸^XFaŠ: Xç4 3$Ò€Ž AQÊX]06Œ•ÏZ :$ œGl3N|ÑœOœ;ê|¬ ¼9Ú ¡Œ´åç ui@û¡Ü½Û¼Ä–Ï FÉ@j(!fú]•ýÎoù ßcãšs ¾ƒŒV­Zeó?ŠûŽé’A[I÷éÝÒ8²`€ˆé’úé†_땆“ Á )\y‹R˜~`[Ú ¶ õâïÝ`þ0r›â~X|Ô¥]+à-ÒÆÔ3 hOò0ÈçRfúL^ÒæÔ‡6ÄÀ›Ás¡~ô#‹2k Ê@ÙâXÕyÙE¾ÑµF:uÆp‹‚ŽAÚ†1Hß Kø]‚®¾ãŽ;äsŸûœ<ôÐC¶Nä‰Ñ1èEêÆù.ªJÛ.‰PþF(•D°¸×šIЬž e¢¼jéS†ÁQpq‘‡gVÚ0lÑ!åçH®‘¥ìXªäk°b°`±z’´ä¢?âÔ‘)° Ûm“ù{Ì—¿?÷wëÁ¼ðØ ²ý—ÛeÝÚuÒyv§HaD!–rcªïxZ†¼±§ {}7ûÊû4HrÏ<€|äuO®ƒBA!‡~S•1|tÅ7c+é®ÊYÀXB®k ÆQx&Ô7Ë}i+úLŸóóµ¯}Í—_~y)ìùàƒÊ%—\"Ÿüä'‹gõ¡j-­$‚À@ž*=/uåA&i¯…,-f@ay%tYrÐù|¦ëY°ð‚‚´ƒ“º¦);äÁì,"Mêú…Ú¸~Ò²q^‚Îb9âÈ#,xÀ²ë’]¥ec‹ ºoÌylŽ%²çžxNÚni³‹;èÌÔ¡0É uK]O!Ç+ïMíû73ò$“ hXE§·b`ÉúMUŽ·Oú_ÇE-Ñ_$Æ}ãN¸‰ ê'ÿòÕ¯~Uî¹çK07ÜpCñ}ȽÆt tQ@ay¤¹Š!V¨ P÷GJÎËRêà*@JZ׳D-:i(ç'Ä´J€?(,Ñ0N£ ¸–÷<Úhøˆá2èÜA6_ÒÒÞ"G®mGÌœ{WCIE]7l#õa žæ^{íU¶ÐË«¨t mÏÜü8³cÔO¥·¾0¹€×cn¥Àö}\T£Í¢À=£d)opOú#´ßÜ©Êô›wª2³£¦*ÓÇqï›'(CÝ·Zdg6Wê# ³mðFT`8’ kžI™P6k¡C "œ^¶CHaÈBF´%ÉJÈŽöK³è¤½?÷ :/‰•ÒX… p&&¸3U¢”~ZDÉQÒEŒ´‘WQ‘ƒ!tHÒ0ÛÉ%»eøk+eÛæåÒÓÝUJ¼Yw6‚%ÛÆÜ-Û&.”žæCíùovÐOIÇgV WYîɹީÊYÈaØTeŒ[ ƒ¬†jRPßj(õ(T“Lª²Îa¤Ðk˜‹Lg¥! P-Ï„1Šë…'„‹˜}âWÖ kÄmô|Ú“ Ê‹6EÑ©·”Ü?­R÷;—þe€¢\‰k3€)Ÿ·íxFbiåÕ'õ"F¦óö¬/¼PorPÔ‹ÙgL­V‚á³Áõ d×®ceâ–}¥eÅîÒôÆÙR×]L¼÷®•AþÉþYÚ& hÏ·Ã=¹cÄ»«2³ÉxOè™ÔH„w8c­Z¨–RB5îKßåæâ¢tŽæE”}éÔ, TÃ3Á"Á&Î y ™vŠòBV2áü0¥êÖ”NEf¦ ñý$ÛÖ{AÝ’ÜßEù§Š›6`v !­žîžH/ ÐsƒF™]—ÏÒ,bŒ;W f§‰dÏ!Ÿ‘æ†Bb½¥q“ù{³)W¡5ñ>oΟSm;ÕfÕ÷LÓY@{„»¼@½00|0yOþÅ;Uo“(…NUÖE²A»0$ã§õõ‚ûÆd$A®a.„ñÎÐâ ðyxy]¢c-‚‚û‹•‰µ§‘©OZe 8?!ЄP˜ EL¢Ã…OJF^¤-Ïê™üäd#5RÚ ™EJ‡íu˜ìõÜ^Ò²¥o½ˆß`ã¾½=ù+Æ 2ás)Ê„"‘7z,%åùœEŒæw%ĘÎ[ö{P1k«ð[7ñÞ]7^&NÚ˶¡TwÛy12Œ`*îYeô™pOÚ§–àž´9÷õNUÖxuª²w†,S•¹'¿g,×è¿jÜ}•Ù3¡aPÎJ!¤s\ãòðL(+pȺƒ)ˆIÎe)G(Ñù-:¼†Ú éù~ÇýÒº©UFþy¤,yf‰%ß#÷=RZÿØ*=¯0ßÛÁiH§ýÆvéÙ\~¦¶&ýðhû}"xBNIP7ÎÇÅ}D¢°„Âçæû2¤™Î[ç3k«ntYâ½mìm2±¸ÈËÝv/¹†”Ýd± ²š¥¯Ó‚~ì2é{‚ åJßèTe]$›ÇTeíÓZ“'@wåM&-m‘:gBCi8K‰aÐÃE^žIZ%NYIªcI@zĺƒÖbD!+™‘ŸE-:YÉ„óƒ„<ôñ’=—ÈŽæÒÚÞ*/;XvªÛI:n3²Ñ(‘uÒ|v¡œ äÒ~k¡ðºó¬¥yCs‰tâ NÈ Y »^‚òýÜ¢¦óÖÕÛYZe³¶ÆÞ)Û&¾$[vZæ›xçÞÄëñ4!eM£¬P\Œ,^¬_¬afél$&«QÚ3¨Ýªdº?î ’(uÆÖ©Êzß¼•zTƒL¨HL&Ä€RŽ;Í7¯"-!‘sÀʇHé¾Ai‘™¸çÓ~X2X6Q‹÷ü¤à|æ(ð;”×ÞÔ.«Ž^%ƒ;m¾¡ý¦ö‘´\Ü"õà ý©ðßA(Ý+»íkÓŽ&éÒUø>ŽÒˆr\+ŒLÁbLç…,*ÈÃ\KêGEž«  919Ð2‹QAÌ‚¡?ô¹à~Ó]³¢¿ÈÙ¬%td½/ç'™ªÌ+`¼çÝwQà^Õ ò¸Þ}¸üPÖÒH\Qô‡gB±|t2×4®" õÍÒùÔCËtÑ!pÏOÊu>}Kè‚#?¹¡ÜêGÔËÚƒÖU@óÍ–Hü ¹”¥H:ÐêcW—ý69­ O _bðÀ—¼â‡_È.$ŒÇ¸ÒAŠ|(Á0ݕؾ;Ý‚A–‘2ó/‹’ê2é/Õ¸/× šªÌs¾÷›ª¬»*£c«j Þ2dŠn‰BÙ/hŽ8$¢È‹Lâ\ƒø»å2Í º9‡¤„ä‡<”9‚’fÑ!ˆCaˆ:_IÁf¿$N=9òcçwK,¢ãÞŽŠü„ɸ€„ºZÈ@Ìmæ«Ü³ ¡W~!»8a<àÊûMw%aLA<„Å\%¥÷‰zý¥Ø‘ÍZBïY«ºjß‘ÐÇHð›ªLÑ_rè0Ýù;¯©Êè?ôqž@gÄ™ÉÊz8MãçA&\#Œ¸þÂ… m'ð;:‰UÍnÎ!/2I{ ʈ»ËÌÚ0j:­²’ ÷õ;AeŽ=LìSC,Ú×Ƹ¿Ž³ûZÙÐÖûïÃÉþ†d\@BõÛ(‹˜!§¤²Ø/Ù Z{‘óÙjûÞhrû^‡(iÝ™BÑa¸£OÔcMUÔ³EjÝ®ÿ(Ðz_êìNU&¹¯»*2c,æ9U™¾F‡å õLâô_æÖ¦ðYÉ$è3*$ v¤…ñay/ò „ é5èl]tˆ` <MÚE‡YÈ„ó]áãZšø‡PdHØ]ËÂï;îê°ûZuê´a¬†ÊÂY|Ïï È…Ï\Ò„&ümB…†8!'d0UA!«€]}ïjç3ã{™÷õíÚ÷YD0ô/9µ‚!/Á0βÈXЇµVìýI&Q #˜ˆ€>¬ÊªÌ ³´S•ãÜ;)ðLâ$ßAæÖŽò*â@¯¡Ä+q}’@ƒmm®P2É¢|’’wÑ!S‘³ 2á|ÚÁ£ý˜† ×%Î늩ù=ÍÒ1ªC–¾¼”÷ÐüHýNõö{`IE‰Ä!®Á]–P”tüPfÙ¨b!!'ÎÉÒŸId}Õ·?%CޘᲠÙ_ÏüÝþ¶«åúP7{Ï ¢J¯ìG0(*B-º"c ϦZq|€LµmµÐ_dÂ}Ó(tt Dâ>Ï'hª2‚NU&Þ⨙¤ s¥ép!ÏК¸Æ’"É` †U6½FeÌ5âœOç½™*8Ÿ©ÇLY$KûAÃP?¾^6ž¼Q:[ÊŠ%”B1ßÓþ äbIÆ!µÇ¯•¶mö{¿~B Y_A|xËš‡cå@­êÛgËàµ'o#`æY@ÈnǘëŒGÒþ®œdÐ#ÃëgÉ×÷ˆÕiHÇK0 ÊJW„Æ`’!d,áj 2]kÅÞ÷è°¼î‹>ñ›ªŒaˆ¾ÁaÖãþD"’îĆš{&YÉ„k7qÛǼü¸ãRZp°ó±¢f¹?ç§ÊFÇ#L(‰¤íWWïŸoq:¤bÉ¥H$Šž!=²â¨ö{(#aÛ¶-2fÇå¦“ŠŠÙ¼6¯¾@Ö¯[¨¸jé™TÀ(m›)†«€†±\Rð Ùõ´œ:ÉÒØ§ùÙkè¿J]ïjûYÐiÀïã’phOÂ,º"œ'bºq|%È_ &k¢˜{ƕüÐ_dÂ}UUÔ OY¬ÌÆ„`ˆ>t©;U9ë4óÔd’ÆÌJ&'  …•Ÿ4q Tp²”%ˆL8‹9Ÿß¦U€ÔÁO¡‡ßcI2ðùÁŠIºÇ÷ŽSn?á³^'¨ÃuÜ<1aÊ´ïÞ;KKé׽­ÌkSÝZYôrÁ²ÒЋ&¹NÚ¶ÌäCz Äç¢/¤H %xg‰ùy,£o6l0貤Ñ(ßð ²Éß 2¬#%ÆWÚµqÁ=ûƒL»þºoZÃó3gΔýèG6?ƒ!pÕUWY]ƒ§sûí·Ï,GæZ«G&‹•¤³P8$\¡ÎJ Ë5¨ÂM¹P\i¦UÊ@…ÁÛ–\0›ƒðËÙd¹7eO:¨uú±ÆUYï¦,%‘ߘ*CV**æšêŠ9'G –UÐ> ÓVš|ôÛ¥7QB»~”¿gà GÁϳ0ÞN]]_{GTY’‹Ҳùê² 3ÎâÔ¥ŠÛ.ÁàÍ@, Ê Åå]K‘7Áô'™¤UêY÷}é£SO=Õ°ŸúÔ§lT=~Ï=÷Xý㇊ÖNjµ 4t¼ŸC((Þk&½_¥•”² ™PvMÓX\÷/Í¢C€gQèÀ=‹ŸG,“ð!Á yßiAA¿Ç=—a6~Œ§™«11Ø õ8Qµä=¡²–·Çú¦Üî> »ÉGÝ¥óÅŸ—–5T”%PôCÂs±p~gÏSýU ™IÏ2§ÓÓ÷wX»ÐÇIÇxV ÏÜ“1Ž§â·–Â%ôã.ÖcâKÙî/2é¯û¢÷’¾q@{£UßgÑÇ+ø!s­µ.ð7 jÈ‹ð7ƒ›¤×’v¯5™x"Ôi‰@ %%4…K&ÄžY˜„7ÇZÚ0j½ ç§-?×:—þaFmÙâaêôãÈûV„zB,qµä]E[7Úz3q¬oêâ&ÝM)oKãi”µeéé\oš_]Ê<ƒð\*Îo9\w|WºzGÙïãTÉ›Zumõt\„¶«A ÷ R°ŒYÖR¸ƒÑÉXÄe¦†3Ð'Œr2QCݳšÈÛCˆ Æf5î‹GçÁX ¢µ“ Æ9T†Ôp 5VtÐö'^$%?p8„¤ lï¢Cõ²‚4(C¤b € ?DŒeùR6w-KøM–{Õ»·§[^_±À æGm"¥ì†ÙÂÎ-A ¢(r– ‚,ñ¢%ߩжn,Z2žW%&LvpEYð¶·7—¦€–]¸pai…±­žwÅ>^RÜ$¸çüí=ûʳm÷Å#¨bèOÛ€R+(?Yý;Ìáµ&d2É=Cîb=v¿€`Ð%x „^ü†]3t»‘þ"î[ ¥…j‘²_³Ù\€Jè4U:™ø(1Ó¸@‘çA&a×ÀÊ [t¨‘¥\+Íù bûk…M|™A\pï,dâwî¶u–º%“e·ÎCåäÝ>,GX_!\(Šh2©—í£n‰*B±Îßþ™¿ãÏ6^ov…WƒOƒ"Y¹eé˜0S†fîé³*¨—®0&D†Á0 ‘P_Ýf%ýBÂB›ù”*<;è£G¶L˜/ÛÇþÉÔa¼ý<ª]ûƒL¸gVÅÎØDî\‚ÑÅzx ‘²LÄ€` &bÐWI½›Œý¬uMî›7™pMä¼fdB‡¡„° !Ž©˜4D¯" AdBùâ.:iÈ@Á5’*tf%'&>Œ B"q;Ðmž–L¼„À4Îçž›oóÍõ…Iƒ¬³+ÖÍí{…÷Ü t7’(TTWgd¢w˜U¶åžD6‰ŸP+*ÂNŲP÷YºÂ/›I#æLycåó2{öÒøÆyv¿=Ïx ­k/2DHûûx1±ÇIg×°«ô´»]kM&ܯZ÷d¬0Nˆ.0µÕ}2¢æ<ɇ2ƒ±÷Ñ»YÀøË[©ÇA5È£T=ÌÛ&¢£ð*ðF˜Z––•«á™ ,–JœE‡Z÷,å þqº¶!¯®ÍHCF îv€PwîËwI›‘ChmÜ`¾+”K¸®û 3bÊãñœû¾~¡¢”dQ= Â]Ò„»Ê³,”™ÙyŒ‘¡agÉñÏ‘3öøXEÛ4ô®–'þv_YØEãú¥|‡ãÅ$ê+oªÌ‰Q½_©]k½gZ½܇„±NÊ€`ˆ@è~VÈ·>z‚Qo“pfS ¥Õ¸/Éw•ý8HÜÃ„ŠØ·‡˜>…'¦%—µ¸VVÏÄ%¤4‹i¸,Êp~QOØmC]›‘„Œ¼Èz.å&ˆ5Gøà€ƒÞ!½ ˬaÞK}y<žv ëÿ,ÊK¯k=‰¬ë=²À“³(- #>W«%Ð9yß—0$W^*ZÛ{"Â@j¨ˆ…b 7¦ŸU®‘…8—dL¤„ŒÒl™µ.œï'hìY…•JÌE‘øÅ"Ó ÞIÎ¥ž”‡‰ÚNîŠzÐÛr˜tL^"íS^7¯Kí{/²”9 e$ê)Â/¤¡ƒ& g±mÂÂrOÁCb´ÍˆÖÕ¥ów×—Ææ±¶ ‹÷÷ÍÁ˜°ïó@‰ÊE-ï ¸¯+ÇqÀï]‚Ñ|™NÈà{¼</Á``sOú3é}ó÷Í›L¨z>nß…ÖZÃ4˜†Š¬ÅêAz& ]tH|ÍuMÀ%EV2A\ÅJ™ð”õà K^@"”/ªÃ³ÜŸs£”:B)Ò •0ç¢ïüκ&!ŸÆºÍæ‡ÁåNÓ/œã{ï°PO)U8× ¼ŠWùk|1´®¡DV"1O^¤gCYyDÑÓ4­ì^õ£}=Ÿ½ö>ªlEä ™OóŒ½_Ö1’È2÷«å=÷µ2]P—`Hîkˆ  ™|ÁDŒ¾]^ôÝÖ'/TƒL4Ì­‚v×ahb8 yy&q¯¡dç·è°?HÍL'`õ Ç‚‰Ú³ÊEV2 :…àiBô-mWäkEZtto*¯»}îûíÒ³Ú\²èöLmm7׿ƒå“/æå»Û÷~ˆ"¤DàþÞÄp«ˆõn¼´'¤è£ü÷ùyóyD9ƒˆ¬"§Rȋؿ|H¢"ÏàùŒôÙ@É>d,,Nä`Ì*Á=%±?È„{VK©‡¡šdâÚTׄa4ê3Eð:é?t“»­ûÐ*ôE8Ÿ{ä ä+É…ŠÖf°lÜs(àZ(qUˆa‹³vJ–k°æa0«ÕU™y“ ƒ™YEÖí1G%{N' }]Ïozê‘á;†Kçí–@€%’[ ‘¼Þ#Ü M¯î.-¯Nê# £›V/õ½†‰@÷jû>R!ÇÔKBÑùÍV‘«ºäµ à7Ù÷%"*y …ºòJ’ܘö}RÔw.)°éyHÃox¬X7W±G†ð Pº¢îðŠÒr·×§$b8ècx݇ Õ’LÇZÞOQk2:öô¾Ô›Ý?ˆî@0î¶>ºo'C˜>ËSÑ¿è®<¡9“¸¨hm „ —yx\ƒÆó*@'Å]tØdÂLâÚLEVá)³úAL[îç’ ¤ñb­ÚM"÷ë•Ñ('Îk:«Iv4ï°:é^Ùm_{7…7¢N†q†Í?X(ito°ëN\…lסà½x<˜4 \eòàãMØP’ûcñyeD´êHóùè²ßµw65H¾XÔ–ký%Å7Š:û@,S‰X$QBX/A±Ò‡aùb„!ŸÀ}Ê^Öqú¯ÖJô™0nÑaãžï0„ýöS‚!:¤;_ë£È  mL}«A&qט€\Z;2цp‹FJ²è02A]…îŪuÊÇ9…ß…$àþ~„z.äFÒŸP É~»I丱…Õë†,<^DÃÈ™¿û|û¼%¤ý¦"‘Œ4îû…;¤¡u^%iT¬C©#Í+)#,„’ò0@Èo1XR=()(”äæC‚å¦teD„7eªîþnÁƯ3ÚíûDð” ð7y‘H"Lñdã}ؘÆô1™’Œ’Ba1ËPŸgC.Õªcú‹LÒÜÓK0ºó5^§>ZÃ0&!2—`è/Í™UƒL2y&i ^EhC()¥Yt¨d’Vƒ8„¤$G¬šD‡ Y aÌr>çBnrC­€÷lô÷"Š«Ùèöf£àO±oKh>£YêGŽô_¼Ø0Ú®;Q…\ZRTØVÝÊsä‰' aIÝfœD2Id7‘ìç§Le}âu¸ðõüˆ¨w}áA]ÅßmíÞÛ~—1ËåE9MÆ)²à>eƒŒ*,Âb®ÂJrqAk­ÔA ÷ÌK¡#ûô‰>Z¼«ö—K0ôã0ë6O33™¤±"òðLèx¶4H»èr:5-¢È€±M$‡õ€’TP‡,÷Os>–\ žCnIÿúBpV³·vµJïƒå ®ãÞéÙ"‹Yw²iìù㢛¤cÒÓÆò_W¦°›êÖÊ1GîcC.ô#áI7‘Üç^þþ×?âùk) ñ”“I¼u&^O Há×›¾‹ +iž…WŽnãÕt¯+ü ’”«A[zÇ‘÷ac^…å†\¼Iã8rÊoÒ蔬ྵ&ôF5ïI;Ò_.ÁàÁìç;?3KH3Ï$iççA&z> ‘û§Yt¨VAËað;¿°ñás¶ƒHª£ ýH.èü¸ IÈDg¶aá“”¾I£ðÂV³“lßÑþR·¹Îè]#´ïo±¯6äE¥ýÀÅ‹uõ ÒÑ=Ä(Ñ‘v1žûkèðÊv¢_I$ç?`v9eêårúŒËäS>(c†,±ƒï¥k%ol›![Æ¿/ÿàB~q/^ý~y”'üw—!¯M‘aæÕ>-Ò¼êãríãˆãæEŠðSîÕ„·n~ <®ÂrC.Þ¤±wÚ+ÊÇ+»Ü³ÖJ2ô×}óòL’€{2ž\“>Ãã$‡ëŒ;)Ã/à¢_Â\T2ˆ#¬^pŽ.:ÌJI»èP…'«2wÏG@tžNbŸ ’KJ^P‡8çÓÞ b쌒:?h5;}ÐqW‡ ê$½Ã{¥åâiعÁ¾*¡ð½Q}¦‚Áqÿ^|Iþºì³Ò%EOÍCX¾ yíä2Ø™xZ˧å€ý÷·ƒcÔÈQV©¡àJJì/Éì§ÉK –¶·ˆ-{Z–°2)§—`ÜI:ëâ aMÐo9T‰ëš]t”…f¡÷’AR(0ðȇÑä?GÔƒ¾à,÷"Ê……ù"XŒ´ W<¡Š•ð‡h·æ÷4ËÖ![¥ë¬.©^¸¯JýNõö{?EĽð J}ßC?$=S_ Ý~¥ !IõæÍÍ2}ÞtÛ:¶L‰¹ï‘²ßKûIëÖÖÒö(1^u‹q¦A—µC1ÄØq¸¢l…CQx_ü.èz„Â4Dæƒ4Ê=-h¼îÇu4iìN{ÕuÈ"ý€!†\èÖ#i6OL í÷þ “ZßÄ%1Æ”AZc—`ðF‰ fæ™ï÷ß¿ÕÕQð­yRKJ&šÁÊdS5„E‡(Ä,ŠäA&„´~Øš†“üW(¥E™à®f# ° Ò]¡ª‚œæþõãëåù}ž—žÁåçZBù€!ó½!(@¡Ø™v„UU²2Ü7—Ñ+#døÓÃeÐæAÒ=³[z·•ôV3(îm–¦uM²óÂËV#KÔO—raua-3ãníêE¤ˆŠ³0§Ÿc´>)Ñ} ýºø•uÒÖ5Jz4Ÿc^»dœttºž¦!È@½ˆŠÄ:ëRúÜ~·¥ø»§n¼9§˜¯ò󄨏ÑMÜxÛ¶š¨6™#Ñoo+ïöïŒû« ï2&*µ÷U]VKd!?0fÎ:ë,Û/?üá­ñŠNüÅ/~a %¹Õï$H‰£Üâ,:äY1 Q“^ƒò1=•òQ¹ARpÿ´Ê¸d¢í†…M¹ˆ{2 ƒGPÚûGËÀÖò`yªg6ðùÎ~ï£d[6_-Û&¼X‘¼îÒ+K\RØ B¹]‰ÄX€çm’º¡Åû©—ã(iÚ‘x/‹GyÌë‘Gmó7ºe<Ï—êÿ’ÇÿúWkÜ,}þv9r̹2CŽ*ó"ʧ/•m“^•-ãçÚï\UÅß;F_G#>¨‘AT«‹‰ûÂõÓ(Ê,à~µV°È“÷ž¼gæ‘wûwˆÒáäŒÙcJ0(4ÂÎq†óßJ=.¸¯ŽÁ¼€§H;êÎæLê9餓BÃü¾-žFàüÈ„NÇÂ@ÖjÑaÒkÔež6‹%Kü7Ë€óó,’@Ï'FI¹°h7ލ| àü´J*ì\’rbc•5ý¨;%h{ź¯Ÿ’%Gª·ëaê‹Û¿óÊ>]ã?+Ó{O· ­+§Ë seåyåk¯ËºA7T„æôšžßè·J  u…Ç¢zá[îÐd‚<¥½'òH¸‚!Rà¾$¢€‘ÃDÆ ÃŒ$îKsã¾?HŒûVƒLHE$‰ÎøÖùLÜûÒOä±7î’¹[î‘•ë&U$‘K!²‰K} ´ oÇ^H÷ÚøåNÊ–flg÷ÌSÁr-7|ɳx+,àÃØa|á‚A1[”Dª-|ùÏ[©ÇAµÈ"O"/¹õ2L'Ò€)g(Ÿ$±¼<<“ 2 £™™€rdÐåmò ÷ 6f³P.,*\|¦G{ËYÉ„sñ*YÜÄ d†G)¤e•è…s]E†ò<„Ï¿"°æÔµ¬‘¡G¿ßÈéi7J¹§¨”{¡CÞ%m½œ pDãE‘à:{ Þ‘%¸Ñ?«8¿QÖÈ!GØG%wf –:+ûnYcü;ÚÚÍõFû¨9OkÉa!dÜr'D òTí{2f!ŒV†< òzÀ”¶ðA– £ŸˆF‹$” éä…j(õ8¨™¥#‚™LP,X²ý(i,:1͢ìŠø]C׳@&ªƒ*‹2Ú©q®ÁÔZ’ŒÌí†D˜£O¹²Ü_ !-èK”"a ^6²q£»£ Ú-.™XxÂMeP"ЧO¤¾w•ôüe£l}ì&éí(*eã=ìhý¾ô¶ß›×íÅz“„Ó„öäúßÈBù{àZN(;¿»ÛK«'Êž{ï,O?]oÛÏ–x>Ê ™ò‹ñkfÎó òìŽ?Ê+Msdý¨gË ÔãEÑŠÚ’QåNŠZ“ 2¡V­€ü3I*ÆhdlÑ?äûØyD>„Oß@2 !³$ó‚ûÖº®}—ÄhƒÜ<“¸pÒA "Íþ§‡g¢×€Üt= V‹*ǰúq>B‘H1:Pa Sè+y ³$µ¦\YÉ,±R7à÷(>r5´!-&"(1¢ì [Îûï8 ({Ø}“eÔ¿g´t÷"›~¿@6>´D¶ÊKÒ~÷Ųénóþaó~ìK}‹$c†ÓÊaîÃÔ1~ã9õúñrοüNº:6Ê%—´¸U/¶÷ÆøQ`W„`ÚÚ:dÑÒuòW3fPb(¯ ë–z¼‘Ââ•;èŸDýåþ¸§ŸRGá2Þ ïÃÆøœ<êÂó¢¿<ÆlÞ÷E6“$ßA*õ[tÈ ÊêUÐÙyx&t<Ö>!#&nþA;%m9”üÎGÈ5Ô¦y<תàܬd’ä|ä>ž¼‚MÊû~óW¯tßïl·RÜð³×e§qoHcC¡~ æ5¯¤¸Ê[ýà#eǤ¾50ûq…%xw+xäˆ1HN k™¤?ÆS©Ý™²6%Œì«ʆ\ÕÕ¸§Œn;Bß0vÈ—áÉ3i…hƒî,Áäó¬z1 \?o2É=̅𹋙ߔ¼î/Ï„D ˜PÖ¬¨%ÖOY¼„œG9²(F™zh‚÷X6îÖ1Aàû¬÷:×K 2¡/™•äN”#„ ‡œ¥¬ÒôIéšÞÙY$å™&l,­Îá¼¼=“ÜÈE¥[‡5gÑa¯Â õÂ)ÂIãã-áB’Ð$®‰’RÒ’ !rä–˜ÙFΆØxè kƒ0p¾žË+‰u—¿!„Úh®ò-SÞ¥ì}¯ÐÏÝsý@<M[/B^Û‡Ü"½å³³lRþ|3Œ£Ðð®:©ë5 Õ±ö¹^FœÛò›O~rK …÷xj…¿gÍ?Bv:~¥,´Ìî#ÖÓ8µì>±aÎqÃu¬¥á½i<û>)h÷!ƒ;íJÍ þÖÆ 2q|«mwd”Õá(-f_æ½Æ"ôw”îÈܳÖd‚ì£3¼÷¥î~OGD7@8x7nS— °}5^øž#o2A—å’€G!³mA’E‡yy& H‘ëÌ#¬-]ýꊜ–\$½VWÕ¤˜j˜fåE&¸Ø”‡¸-á,Â$Þµ?=«{¤ýÆvû”E çòÞ~n¾Ý«ºË~§èÞTüÜü.ˆLøŒ2@h„#ÿò—?˼§–… _ôß]Œû{¯Ù;á0Ùº[å†$ß›Î'C»÷*Û‚„õ êeðÊû0lÝÚhv“iƒÊ~«¯ï–ÜŒ²D†¬*¿O"xÃuæ5sþ¥Î*õN“ö.[%ŽWŠò"ç®±H:6 è¿Z+vd¸Ö÷T9£Ô‘k¼†¨Â$'ƒÄ›„`¼ódª§ò&“Ü<´p4@Jx¯£IlyDÃcùû)ë¤DàUªQ@€ÔK‚É 2x µÅ9ß:ÒžÏy!-þ¸Ø~{{QöŽû;¤çuC·ˆ‚ö¬ÛVWxo>çû®7º¤ýæÂ{ýè~ÍÉu}¿3g–)~€eE2‹˜Yu'5DNßã£rüÄsdÿA§É¦U*mÜGÿ¾¶änôÚŒ’¢né™_qM<”ŠÙY†x¯¿¤/9_Ü‚äâ‹[K^¯_<È\ϾõÅС]2vl§%PW‡",ü=n\¯Üzë6sŸ”[(IÚç·°•}¼ò>Sþ¥8•Z×Äø…á(0bùî ä¥òÐ)°:C)2òè7N« îYk2ɪÔi#Œ=ÖÁÂÄDÏéÃÆ¸.Æ#<t¡ŒžŸ'r%“¤…SÏÄ;ø“€{Òhêáðʳ Ü$¶Î< ßåAjQ×P/I%¹˜—ŒüÀ¹´CÒóù=3î°hm–ðçÍg7fH øœ÷Ö­2áoÆÂ5ïù¼é½MÒõ é ŒUsý]×ÂÁMdº‚ßñ,-³zj‰îÏ6~ÜX²áR©ï-<±­©~ƒÝëê£Ð°ÌÆŽ-S›þ]z [¨°sï¨í62ÐiÛ:Ôë °öÛw&(È1¯«VÕåhßú¢¡¡N~ðƒ–8Àøñ½òàƒÛeÙ²-Æ“Ú&‡¼>™WQ$úöÙ…­R,Iîe>÷Ô%ý)/-jM cÓ׌Yë>yˆ„›@vãûqÃ/ ï=kÊÖ_d’ç}i7úÁ›#ÃÓ$õÀ½t¼c`@.Ìáacœ™$]€ž[Í£BTq¡dãÒ@Ä™æ7‰­D…ÔÂÈD“ÙXºåˆwݬ„†$!’zº]=®3Gœ¶ÒÇò*¡Lxl‚4m7Ä`ÞÛçÀh(ŽÕŸEBéø]Gé}Ë%…ßQÊL¿Aþ#ʉ©“´ ýñ³ÏlµÐ.“†Jsý:sÂ÷ºsoƒl±³`==ëAó÷s¥„e©ŒUïæi4Ü´eAx0¡GFF8ûïßf,¾m%9üð!íe»7à>ösS77£Iv;»jí)Æ‹) úºÞÕ†P7›úÀk}/a½ìÓŒí‰55q;a0o™ø>á¾sÃ/jë£xýÆ\(öþ¼gµ‰S †È ¤Ï¢g"!îÃÆƒºO£KB0ôgnžIRX…ajAÆE !¥¡pÇÉ?Äå Áò&„ETÅßÖ‚ÖÛER2ð"îùþ#¡ÛÕ#hIî ¡4ŸQ¾¨“÷ÞçÀ—ÅAó{›¥a'óy÷zÓÞÝ6±K¿éV"eSÈë Š˜=®@—y}}ÍD9ÿ¢Ì¹æEÝ]7^zëGÈñ‡·Ê™{ý³œ¸óyrÈð÷JÛÆBXLÚ—ÉòÞïKO]a†š†yn½µ­äeÂT;Œ|Ù·¡@•ÄE@8éé9 žÜŒ”¯‰1 gèºøw*.!UqÈÄ ~a‚áDTÀ ¿¨uŒò¢P^„aP^ú +d±¿{-¾ðÓÕúCÞ}ؘîÇ+C{`€ùmDô°±~ sÑy4fZ2Q‹Ÿ•Ù$°Xݯ* ´C³šW™³}5Ö6–?®¦_2ÛçWÓ3á;·þÓíb¢Îõ‚Hǽå³zxï&Û!”¦+ŸkÐ3çIiZ6Õnþxô¸ dÌ%–djo¿ÕuÌ1åê4ýS¸îÆÍ£ä½Ÿ¸ÛtC!ô䣨yfêÅ¬á±Æºõrà˜/Êñæ>ªÐÀ’ׯÈþTî_z«<þÆmòòò‘2eÊ*#SëûÂT‡Æo— Ì~öpÙù„v‹•IïX)³æns1š›Y½ºN>ve{™æÂ;lÙ2ƛߨÒ‰¸†k»Ê‹Ï?}.FáàZl{ŒƒZ‚:×úž ˆÄ( Æc£Üû°1Îó>l #àÆo´ù2ôqR2©3VIK(㤠ñᇶ•$ÖÆ=6¬\1£ºlIAuî¿ÿ~;-Lá‡81Óù(II’x!Xÿq†Ø2 = °¸‰aÏö‚°aˆ]¼Só£aÑɺƒ×Éп•æ…Ð Db“íäH\ÝXß##Nß×®Dg!k1ºëÆH÷n¯V*ÆÞi~uª9ßüÖ\¤«»Î®ÙØåÄ×ŒÇ VÑ—N!ÏлÉ\c¤l6ÖÑóÏ>.§ìvqñË>°!=Ý]²}Ûk²iKlÞ¼Õ†Â'ú…Á¡‡†e]`ÌО;ï<Ù±ÛÝp4žÄA†ÐÙ˜1½æ}¹LªÛ>’´4ê«Þ–¹¼Òø´Œ™0£ø®º@¡“ÏJ+—I‚%¯HØ•q®ýA¸Œ>pû„PM^ÐÉ'(ÍZüù ")µá+Œ\ônÐG>žáÊ~ô£V£_0 ©DÄõÑaÆH®TªIø8@éës<ˆÃR`b´ZRsAeiˆ¬×@iëF‘Xþî´¢Àï²Üßï|BZX„w(KÐÎ °ÊÀo:îê( ÄÑ5®K–¶Ü¾·¹ó}÷FC$·‰ÄT¿ùœf&$I]æòUÊZwóÇØ(Ò±Ôze§q«dúÔ •¡''îO?tt. þ®ï\\|W9Ša«÷–¶ì'{Ô¿Sö¶½´©¢»+,Æ®>“Ü=¯Ô›{öÙVÙcBÈŠWw:1CßMêC$cÇrn_›óœ•s>yW™—µ}̦ãJõൽ{´ôÔ%Krf}¦ ò²Èý fi°.Œþ Ä‚F0]7QŒœpþ𯵾'à¾~žI\PfÈòE#â.ßûÞguôÕW_mû,J§Ö>ÐÅ%]]ÏÀÆMv# “E@Z2a°ÿå@yÃÊI7ŠÜ_•S¸„@=°(µƒ£ˆÏãÜ›þm~O³ÔïTȉàXåÝÜQxo>ozw“tþ¾Óœ`äµùâfYÖ°LfOž-MFÉï0J¾ô ªÂN·îæ%°Q¤'Ò%döÓMÆâ‰*k½ìà%eè•Aë/á¦Å·ÁOU¤Í-ÝVg,áib(è‚1¼Áõë7Ëlª¼žw^ßtb<’øÞ¤þu×í0ïÊQîÿË‘²¢Å™]Õz„Ì]=SV¯+¬¢çõî§ÿÛüe®åÙO‹îs“ùy¡Öd¸§+«ôDB0¶ûÈ´»‰baÂEá3E9É$ýA&Ü3‹RO Ú„6Íè_tÞ'?ùI¹á†ìÓ*'Q÷ɵŹYèNµÄéàŒè 8×HC.Ò ÂJ¹H 3›…)­0v ÈYê çcÆ;"Q†Õ@èJWú!.™€úñ†H>P ûÞœk?IwóyĆáì8w‡ümÉ߬[}À1ȰŽí/ÝR²¾Ùév¥ü–²ïË`¼yëÊé3ko7‡+6ä‚òô4í^""™]6%7`jpé{(ô±»çVsgç0£Ì0´\uF©×k­0庣£Mn¹e{ERÿÄ{|I†‡ñ²zzëdÝ:‘ÓÏ;®,ßò“ŸÌ)ÇdZh™ýA&Q÷$ÄåÝD‘C Ÿ’»‰®'4ã'ëýA&Œ×Zß oó&1¤‹8u`íÓ•ò#š„1ÂÀ÷X†Ì:ðcº k$A2aK ÜkˆD·Árb¤E…îîM{a0À‚BZ~ ß’ÜÛíg÷\ý¼cx‡¼¸ß‹2wñ\kMÚ²Œ!õC6JãÙFï¶TÚ'¯”ù[o’²=Ç .yÚûŽ-S¤gœœ©gñ(•­NgzÞóZ6ªô}Aœyœ!U\Â+÷!¡ìN§&l7jÄzûª[’Šik{Lî¸ã ã)òp³årÀí¦¿Å’ŠßÌ1%‡©S‡BÂHh°“¨û¯¿y~i]zSIZ&AÅž7Ò*vŒ&%|Ý‚„Hã½å.à#\¦Ó_ûy+Ø(ôÇ=A5î IC&Ie%W*õz&/Lˆ†ØI¦2pƒP+Ï!'>‹0B(.Á%!#?p~2ážLÙÃ2àÄ—QàI:5 ‘q®’(×@ÏÆƒ }È sJïe—ÚzC"ͯ*‡ ?U¦õžà»[m!×PgêWP¤==õ6÷`gqEÀ–Çx6íï6ï´ê ïµ]¦ì–¾÷À]¢>¼Ë]rØ~³då£;Ëú¿‘×þ²³uлPŒI„ÊFiÚj³ñb +Æ Ç´¶>+úÓ‹Æó^)/¼°ÙÈy¬]+e3½LÉŠ‡Èè‘ì¶öº®F½©¤ -“ ?È$¯{r w…xi“ËÃ·Ñ  Ó_Ï‹nrIÈZåºZ`¼ä­Ôã Zd’&*S52A!Ò±Ä<±.ˆUûÍNò‚†ÉÃ3 »†>û„©qX=¦KpœŸ•L’žÐCº¼â…è>JIáBR0`ººŸX5mCY«ÝXñÞÇ÷6®ý˜y]eß6ÊúŠÇù‚B®ØyáóRÈÇq€5_@yl]Ì}[6}É|Ûwݖ͆LœûÄYna®”_Á€þñ_‘{~Ü÷ ¬±£VËö…—£0±CãýÞü ò³qãz#SÏÈ 7Ì72ßlŽa– ” ŒÂ!ÒÔ2B¶µ©ð¦Ò,´Œ‹þ ä©Z÷äºîú þÊ LÀ ‚ì[xúºÉeÞS”ïi<°¬xKI€L4lDR ÂFQSÊ\dUä èúìÝ·Š™&^d-Cï·œ©Œä’ ]ÂH¸øqÏ÷"ɽ½à<Úˆ°Ó*+öõò{|¯= Ê+Ûû8_À»ãŽvß0 o¾`Þ¼ÂtÑúöG¥¾wuß}‚r"ÎL°@DäWܵLÓ÷ ,^yÏÚGZhþEWŒóÔÄoûXC,jp’žXx3¦K~ñ‹-òì†/•?šxÔOM»Tæd¸¯,GÚä|­É„ûqÔRÉr/î‰ü’Ô×M.ÙAc–ióx,ä"9òÚä’±“·Rƒj‰_Î$rëeFc&„‚"¢3“ίF˜‹¿Yðp}.lߪ, p~TÜ2éôc%Ý,÷Os.ƒ//’sé;V;W´ßã{íQPPÌèò>ÎPœÝwï• ¶. ä7nHˆ×~p„ù¼[møhQ Àß=uã $3Ù¹Çú áù•îÞav¦+ô¯¯­ž( ŽnÚ´©Îx—„9UióZ®À7lhK.$olœ"½~‹,îü©­çugË;&ÍEÏþ¥ÔN@ v÷݇Ø#mrž~®%ô~rTEpOWÁò7kß_L'÷Áð7¯N'd©›\µH²É%¿ë/2A§å‰~ sÑq¢Ñè4B#~Ï77T–J&”œ B‚kK|5ÎŒ(/%ç)tÊDòPËÄ,"ïôã,d%9—>ËÄý‡`!¶Àœ–±ü½ïíûój”±A—Œ®xœïSOÕØ,»ì2ÈÔs˜,^Ìú‘â— yê]ø’W”rûöŽ¢'ÑþÞ1úº²ûD¡äõL!§ÿÓ]ÒÑ”_©—6ó~ÝÆ¾™gïû×»l˜Î†›œÄ½ !=’ΪH{‹ëP@_Ý6lh5F×`;vrÃöçÝk¤yÍù¦_^•¥K7—ìúõÌ.+ü&9ìÕÚ3µ¼§Ê~¡g'»Ïy×¼i!d¹ÑFX˜2Îä÷!V~ã }QKÒT +ó&±~ sqSB"¸Š$gY3’µA³*rÀ5HºiΆ˜6Öñî8ÈZÚÀï| i!¤Z&¿Ý² çê ƒwg_ƒ+ê\ïã{{†]fß?Ûö¨<ßñ ý^AÎ?¿ÉBá= ð’Kû*@?%¾×¼g%·—$Pto¼§Tø]˜dì»JxìØ‚½iS«ÝÃkuÀ#sƒff¹à~^¯ç7í̲RpwLÚSfÝ:C:ŸßY=÷óil[x‰õ@yÕĽ„ð¼;{ †÷ædsUžoRvãyóË–k.sô}CHcÆtJ{ûªØ³•âü&OèýÞÊFƒ¼ªw“KôõBÏ` B4¬}!tM4$hżQ 2A/T=gBGétQ E¤ƒy„¨¸FEJÇ÷×µ,$EÓäl@”BŽ‚žO™tj4 ><â´QeÊrÿ°sµ¨hf¿¸;û2Ý !ªI“Zì+ïƒà=àmLœˆ5¬J%|v’«„Ÿ|r›i3êR/O=ÇæŠ+í•W›O"df– ?¯Ç¯T~ÍzYcˆõÏÿÔV–˜g²ï$€"L7ÏŠßÞ{ æÐCº¤©~‹ýÎÖÜ-ãä̾ÛÖ».P¸ÈèѽöcÆtËÿ÷ËFæ_-›­Ä¾JÌVÄàó‚þÉKÉÆÊa­ïÉýÕׯ ä±î&—(_"ÜŸp˜»¢nrIòß;F²¢dRõœ‰®ÆFaãzÈ+ß‘ô:••¸?9‘¸2A=‹´ϽédB€xpÖLÜÒû§™¨gÄth„ëÊog_÷\^ܯ¼j®åm/º`æÌN_L±`‘³‚ØÊÏF‘‡ÍÌrQáxf“)ºe˜½†÷¹+›¶Œ’sþå.»Û1 Aß6Öa$Í_ zó9oª¾w]Á›Âû¨%õ uÄGÎ…%ZÜJ ɽ-òª³•Üý®PlÈ &“‘êêQiå,úC±÷Ç=ºÂ½/£ûŒ¹òE¯•¤OÞ9é&—Œ7ÕWy€ë!¹‡¹Ôšeå)ÖIö°ŽR%î§TâB&¬A¼ÜHÀÀqçËk­É„:ë.ÈtÀ#©u˜s) ÂÊvšìã¹Dä¢â}Pˆ*¨Ì…¢K{û²Ç3¬õ¦‰¶Ò©˜x¼Þ™2(üÿùŸ‡‹ïúH­”wIºò݈®W—`”|cÝfû窦[K9fs‘³!ì´ôõÃl¸mÏ3×Ê /KoK1Üæà©§êM¿¦ï^ôÞç¥y¹'ŸÛŠK|a@îÜd2F „Ãg|çnG‚±H¬ŸÏò\-Îu’Qyù ÓQÕ÷Rê|O(ÌKú„œQÞÈ?‘ ú„Ð¥Ž‹ M.UGFÝ7)Ð_~ƒ¢ÚêT ç³;ö"ì§NCÖíYJ«³p,eÐ÷4>¹æªc z~Ê5²  p§I"¬q' (þ.QñÊû Ëx=V³9 ‹d%^-eqÉŒ¬æ²§'²¡¯‡ k—=¦­5}Zè ^÷œ¾VFŽ(´»ò}Ëø…²v롦íìW±¡IüÃGžj·¯6Tä —Ë˜£×òxMæ<˜ ¹¡Ø_ye›ÌžÓld¯RáΞ]/'Ÿ<ØxOìÀÜ#?ÿÚ9…mù 4ŸÓÓ3Â&ØÝpï MÛ÷ŠPâKú‡%áÝŽDŸÆG8Ló/ô…®OŠášqä.OpÏþ tE¥±ã©`¨ë&—º«‚Ž w“K׫TÏ>ïúríÜÃ\YwGÃ'YB]⽆†ÛtrØö,~ç'–!J¡sëšÆG9ÒfÚ¹i --™0ðQÄeKÇP(™()¢Z²¤Ãw»,]Úaß6Ós±¦PHÔŸ6 òhÕzÖÍüø-”>=qóê‡ä´‘—î'+þ¼‹|ðì_ÊÊGw‘?N†®rfnåé¹cdϽ†Z Ñ‚>O؉-ao¸Xn¹¥MšZPð<£cAW¸ ž.Òpá7 ޾Ñî½¥O–Tdó¦Í6Á®á2<ÞoÜT}¥K߸ʿu;5‚4ÿB¿èjq Åhþ%n(†ûå­è¢Ð_d’ç}³ÞM.1¾GŒŒ,Œ4ÈàUb\³ô@ÇnZPtmîd’ª„³(ràæ<¸³ffQ p¢6?¤ i¹"ìtÓk ÓàšÒѸªJ¦ÚiÔ3ÕÖçÜ AaÐcIr¨"N# Ú¦î}A2ETeʹX°Ìbaö VS)½^c¸}ÌV{̘.‡NøŠ47l²ßM³Z~ñËeÜèUö=StÙŒÙL6l*[G¶ Ï-³…7ìTœ¥uèÁëCCMÞ­_}´Þz$Š›Gú®>r¤M°O>©°ƒòä“VÚ÷AáÃçm™6p§ OÚd„x‡uÉYø¨!2¡¨äu1ŸÝ÷«Î¨ds]Ü·iëÆ3|ÁæQÜɼ߰¡|y Àz/už$~oAéóy‘Ò^òúèGÙѶPFÀuHØÛ†ñ¾˜ÏÑûر…Ùi¬§ šY–7â‰ÜP ^ ýë.æSKE¦!J¦Äc䤹_0æúâmky_Ú•~!”M¨X§(óŠ1†þô [2+7l“K%“Üði™ÐP$¢pßPØÌ„HR¹ "H/èŠqBZ$ѰÖü¦×*(C…Þq‡4¬méó§[ú¬öž×{ì÷ü.hg_-¿‰  ¢ªÛV~.÷]ÿ“v9íð†²µ&T«|e»Èg?»·i—Q6\¢Z&•|QÊ ¿pËX´ô÷ÛŸÙ…G›þê«/ }Ô¨6yöÙÇŒ’›'sç.3Êm­\t‘÷b®ã&ñÙ&,‰Hþû‘O\?¾PŽqãzä›ßÛW:&Wîd¬ ö[o}À”ÏxA)ìi@¿æ¥Ü½‹ù4ÿânOËØÍ¿ä½[¯Œ¹þ  ^B­€žuïI½ñ µ«¡K¿ ›AîôùTr1£îÌJÈ„k¤©Kî­N!Ò’ ‚F\–ØÂ SØA  œ¤ÊÜ×P‹C=$b‰äjâ(L:6éý©góÙÍÒ3¬GZÚ[,t¯ì¶¯ú¬öºÓëlaÒ6XˆÄ·\ƒ#èÞ|ìzÔ‚‚¨ºnï’–ŽÂŽÅ–Àni—Aæõ Çnç—–< ÃcžiÃx-²}{ò™k(ÎÔêè*¸ÛÌ®ºâªÌka0µôyŠá¥—–ï%†¸ÌœÙe^7å=JN8a?cL2å¯$€õëM]‹Iüٛº®Ø^Å‹%Kê+È‹ý 'ôÍÂZ´h›v˜idS¿ŒÑwC‡OhÈ 5¼0ÒQü+_ sÞíà‰$¶TEæÝ­7ç½{ìÖšLÔèìûF)}¾'äMø›þ '©!2ŒbtQ–_ÿú×V¯}æ3Ÿ±ÑÕwIZû¤J¤ñL ×À¸Ô`Z W8‹wÂ5hLâÂxH4¾ßBÍ XiîÏ#s;Ïì”¶–6K í7‰dD¬Çzy|Þã¶4Ìà'ÀADæ·¢] ¢êÝÔ+,9@z^+xB¼_º¾^>|+u.$‚ûŒåïN7®K ꪇeJýÎù¿.>ñ5ùÕ]*­„_ÑR°ô½^àïiÓzå#kÊS¡M›šm9Ý2S‡gž)î³´ðeÙjȰ½½àùº±ã¯ †É-·BUtGPŽÉiÆXz×ôJ÷­ÝÒ»¥¼m6„Ê÷µcXùë.ˆ4¸Sagü¶™bô™ÐoF2ñ}a¸Ïå9÷Üså›ßü¦í+ŒùK/½ÔæMøþsŸû\ñÌpä^{ šD‰âúb©®aÅ(.3qجDÒ^e{Ž%±á!‡L2ð)CÚÑ0¢A^Þíåâ»î¶P­ZdÛ„µ°ø‚àG&¼ ZÑnŸù~q‹%”Aƒ¤÷ŽÞ}äž¡òúÖB½QÀ£G·›ÁþŠ]P¨i^ÿã?ÖËyçQFTy`ÈninåQ…÷ôAË 2rTáú$®ý¶J¡^.ɰ‚ž¿ÇŒ)üŽZwÞÙ%G}TiŸ%ú\½Ð ©±Áä•®¯óDØý'#÷«ŒüÏì#^÷X°‡4®3ãÓ|F˜y{x,úÁ;V #Bgº™¢7ÿÂÚ¤8eî2áži”zV¤%?ॼï}ï“w¿ûÝvmã|Í5ר0YT…Lâx&ûÖ 8º²oÐ@Y\_µ’^aÅ2B—:%÷OKfõÛêeúÒéÅwL]4UŽ=àX£¸£ÛÔß;ðP‚a+Ú!”æ3Ê'74ŸÙ,ßÿE·U¼`ĈvùÁVÈñÇ'ïz×p£l Ó†/îk¯åy…ó]¢ráGÆ\˜7ÓÐP'¿üå†Rtš®^ ½á]1Î{¼?’af–ÎÐbª3sùuŸ%Ur5šY¸p‘üñOÊã¦Æ²5üøñ$y˯›f6V5:mÜp¦Q0D7 å5C0æµµ½Uz†Åg¾÷닼ÁŠs¿ÍÉ“êÌDÆ$“^ yw¯+¿üK ã¼Ö÷y’‰¯Pg‚’{9ûì³'~‰}…ÐH#pQdB6b†³°ÛI½?ÐÈI®Á*Sf>àè–iHDÁýì¤ WQwWÁC Ôµä%Ò;¼W·5J祤¼ÂO!Ñ–Þ{£ìÂV´sÝŽ{˧uÜÓ!»Œ|]n¸áùÞ0ý¶ÝX/»”úŠ”¶i:3¸Í= òâ%ª øÎ®ò<è ¦‡OÓÕ„¶û=eó#Æ^X ¦«k¸H»Oe?ùЇÞ%—]vº}]ºt¬ñÿû¿?e\A‘Õ)ßÿþrc¥›ã_ ¥^7ÌÊù¡ÜnÆyEž¶ŸºÝ~_ Ði”,mRš"^Ì¿ƒä!-ÝSkÅÎXË[©Çú-‹Žò¡ý43¹@î­äU XºÝ¡A(m¬/‚®‘qÉÁdÞ<1[¬QÈ K5+¡!ÐIϧvüÆXÝ›ëdGói?½]ö}×¾ÒúžVS!óýÆ^鸫/¦o“äžéÂÀL_A+ÚíuŠIþ¶æ6é:Ç´½1NÈ™4ßÛ,ûLÙKN:é`:ÔÿgÒ¸qåÖzØÖ+€âÅ]RPJá$à÷½’ÌÒ¥[Œ¡°ÍX½åmâÅóÏ‘“OÞ«Dnç×W¾µkä_þeš\pÁ1rÕUGZCè—¿\!÷ßÿœ‘›¥6ïâZÎÞ𘴫K(ï)Wp‹§.®‘d0/²D¦5‘LÎÅM$ó9³˜m‰ÃúŠ<ò/qÁ8ï2AGæ}_ÚñMC&~ž‰®Í`ª áqa‹bjá™0‰ ¢gf£lÚ9qÉ(~ = ´ñáy£æIÛÈ6™¿û|¿{Aów>Þi$ÖüaŠÖxl£ JîtaEнýV´sž%(r$#ëdÁž dyçr™=y¶tî”æ¶f‘Ç Š!(ònXkÈ£ <]¢ ‚7÷À+ï½Þ uÍ¢tçέ7ò6D¦N _Oõ>ó™=K {H¤°~¡|x,6ÔËêÕ…÷ëÖÕ›ßO²2£sü<ð`C2ŒGÓn=\ïÊqÖKe•ë¸ GÒ}ù½¦-fC¨µý†,V è }Z¢æ_0ùŒiò:at÷aVy­wAŸV³žAà¾Õ “4 žAh ¤±*\"À2ÃBp×fÄÙA—ª¦g ¦L¸ÊšÐö>fáÈ2ð¹2A¨ug_B(ûŸ´¿ »|˜´7¢0çÓV:Û BéüSgÅtaû½Ó¦aD†Ì»¼½þ{š¥~§zÙqêÙ^¿ÝÎ;?à˜ä¥w¾$û¾±¯L}zªLû¯iòÔ²ÂV-~8è N¹å–Çʈ* x-~9 ¯7“F4A\ï[·®¹Dújz¨øªèûÞ%¿¹sM'Ê1Çì)ï{ßá†Tޱã®'C>N½Ò÷yn¬¨°D2Ó ››­áB£pÌ+9“–?¶”ÍòÊûÞ.T~k îG{“Ð',†ÎÁ‹!/ËwîJñ¨üK\Pϼ•zT‹Lªæ™$È„ÙPXbXý$Ú±’,f«–g¹a%"L$²u¥¶_ÃÈ(✴³¯ ˆ‚;Û )M6ïùœï]PŸ$J¢kd—¼|àËòôKOÛ{FÀs¼ðÆ eMWaϪÕ[VËù?9?ðºXa± ÷/~èªDÂøå4üÎåžz^±IbEÇûؘ1eä6r$7󯌮-á<ÊäGZ }3—tå8^9–4íE½èû<×ì¾Ç!r',ÿ1G[S›Ôo1F’ùžßYÒa q•¦ sZ[ì^ÅÎXpó/êEb@2öÝü .ä#ÿ¢ ù¢P ¥Õ¸oÕ<“4 dD2›Áê'yæµú£@eõL\BB¨•ÜÈ åÖ|dÝÇA˜wÀç(˜œÖ±`%5}uÉÈw¶•yï%vo´ qeÚ¥³«Ó*;ÊÃý7îØ(ol~CzŠÏáà•÷|î‡8Fˆi/g3F–X\wÞ¼&û{7QOõ¢È%Êûq¯Î»öÚ…Fùär»óNÈÎÿî6(A¤¥¤© .îì1Þ³JY$â&–ӄǸfÃÉF®'‰d¨‘#¦ ¯-|ß3Ú([¾ßj>Ç{a q•¦ #ƒ”§„8–Ü3ŠÀøë[Ÿ5¢ùv³Ö…|„äq¶‚sÏj€²Ä5Ðã2I³/È­ T…’D«ÕŸœwðA¯¡ÛŽ@nX‡Qk4YË€pùO ˆÐŠÄog_ —|g[™÷|î…÷\?0`·èì5ÚEǽQ,#”‰Ã'ÚM'¯¼çs?èyA 8~Ö;º&Ì›á¼+®Sv‰q/¹øñäýpŽ÷ûì³M|ð…¹ñìvL¥dðH؃ëå—ûÈÏKZ†¦íÿäj‚Êh/W±¹+”QrSïEóŽ„jè¿ ö®gåâ›l·äRœ*ÜÚÙ*u¦ò¤àÜ0X•¦ ký@ýÓOË=÷”aÆKã•÷Õ@ZÅŽRö.äC‡ùmïÍ¿`ø¢/j ôKÞ÷í×0‚@`q~Kœ’ÎLÓ¡Š<Â\€AÇÂ',A¼‘ 'Dú!+™p¾«Ð![’„9w`Á=ßmeC[ïwB^$á=„BÛ‘ u"ÑOb „CûÎÙÚ¹Uºº Öù ¼AÆ +´ÙøaãeæÇfÊŸ‡‘IÜÅv×íÛÙH¶è;ĸ—”ôÖÞóý¦ ó±é5xÕ¿ÙåÁ·—<öÞ*Œ}kÁßÞŠ ïuýà-/@þÝð²«[óJ ¹ ¹ý¤S…™!X·µ®4UXÃ`Õšá…<Ùr˜×A_,u¦Œ€WÞ‡6LJpÏ,ºÇ…ßVðŒ[]äªù¶…!ψaƦ—Œõ°±ªAbý梱ôAUXÙ„³|¬þøÉu’ì`cÛFY·mý{ÍÖ5rÙuWÈîÓÊ÷ôò‚ò†µËæÍåË_žgä¤0¨ÆŽí‘›oÞfÊmßš2‡Á®¿~ Q^G®$%ªæm¸ð#6BWW_=Ý(ù¾©Áîù^Bòß'!ÌÏ}î²vm¡?ÃÊëÚÛ/îÏß|N|ŸX?Ób ½<çeÙsùžÅ³ `ê°;³+o¨üÒ=F÷•<¯¼/k˜œÀ=«E&~à^ŒuÆmï>ëÈa0Bb“肨üK\0Öò&PÕ0— Ø•˜-ÌKRáÕ)w µt³4× ±TF¥ ;éâÐ ^ïF·Z÷†…lɳø¯qc£ÌxfF¬ßz¥ˆ L¼Ûogß8P2±7ÄñÊY[–PøÜ|¯ÀÃ8ëæ³äèm=ßÿý÷Ö¡ðŠü,æM¶»à³u;ÞÕE+2l«?2Af@ôÍÑG7ÊŸþô¢üá—Ÿÿüc”ûŒQlÁù"ïy.ìS·™2Üüšy×WWÖ“Q ,0ÊÌFq€¶ ÔȪdd†ä2«Æu°ó=+”9xZâmH…^Øâ}̘nùõ¯6ýºG3– Œ[º€÷Xü(j3ç£Ì Ké,÷¦82mZ‹)e$qÝks œŸÔøó–MŽÅ#ñCœò¦íÌô_fmA$Í5KgK§lyÝ(‡GHóŽfÙû¶%A¡ÑoXÍö±¼æï7ž^¶šÏƒêmaú¤,Én\Øé_ÿº4 ¼'é~é¥U% ÆJ-žIzO¯üÇ;ÊŸ”HþEŸ”HˆÚÍ¿ð=×ȳ®Œ-¦ßÃé™à~‘‹ Ö7>÷È#Xå®y”4øÓŸþdãÀÞŠÁæ„EHþ“Œ JfSnˆ†k¸p½ …ë}(`éÙÌ–#_;2ô·t,Wâ‘ÐFäh'’ݸ¯ƒ¦ ²ù”Ï qÒoA¿Ûç¥N9pB·<òÅ-rÃõ÷›¶ì.Õ7Ü~Ø 0/z‹^’W‚d£¥©I&}üãÒh IûÞ0ô1ßú–L4ú€vg,Àj¶³ÇÌ÷ÝãÆõ%ÙÍuí¡ïÍkµ’î.hû P- ·:îó×Å`°dQ%ÊÝÇ{êéݦÇÍ¿ÄÕ ˆ RŠ«/¼ˆlõ4†L\"H—píPämtVTÉ"  ç»À3‰³øóy„­ßo·¾¾µ”8&ä·ÊŸŽÞÒ¾%Ñ*rœïW~‹*S]IÚá§ÉCW>$_þ°õHâxA.èo?!d|ŽÑ#¶÷…ëx=ïÇç•ÈrSû&ùÚ“_³ñc/ßS­}J9é;^É¡ÐÎÔÕ%È…µn]·!#\AUì]]…ç\{g1aºƒKûˆ0„‡Ä‡ ë.†¢ ¿åUgdÑ6ºäµ%Šâ³BÜ€ÔÇý]çm¦ V–ÿ®ñ,s=Ó¦IÆÍ~ÉE-Òµzƒ˜^²ù¡¸3À´î±ïgÚÑ;·aõj™4xpY»£à°Œ7åõäUWI{1yÛidà¹OZºÌ+¨fÒ]¡2Gû×µ¾'ã}Ã8b¢É}wòŽ·Äà•Hù˨}àseñèªÒy JÀ”V¬n˜˜dvÜYQ~d↸l¸*dñ»«ò[¿þ%`{[»Œl,l\IÂÊo€rÿÖúÖD«È] œª´ý@èË+2sWÒ764ÊЦ¡‰U æÈÎ{oõ@&}v’}åý¢‹dÕ–U}diþñžiÉJ"/uápËÃ{ä„2C,¼rð™ÌÞÞ Æj/<0Š}øðò²qŽßX:Ó$aC7ö¬Ï¾ð‚[{s/?ý)ƒÐ¾µ!+¿g…X"qòúüžMòê&S÷­¦.w”ÿŽmN’bû£O˜ՓemïXY);Ë!=OÅž–˜L {FMç¥ÝÝ]{÷¿â Ùj,ãWÌx]ðÀ²ìÄå¾ë®“ûn¾Y3D²ÐMà¢>äüJˆÌGAeVå§V@Î﵄{OúbÑuHšA/ Ÿh&*¹ùŒPïcÞ–ž •Ç2ÅeC0PÚ(Š$Bâ%„7îâ?ûÛßwØ©”<׃0k×Ê¼ÝæÙ)•|>eÁ”P¢¬½=½e‰í$a'®íG&t>á¦ÚbC°ÞÜ÷ö;7 ³^™%§þúT9öÇÇ–ƒ¶àZÞpÝÙß?[–¾¸TÆ gø§¯>æÂ7Ús¨'eÑúòYÐD~GÕ[!ùøüóÏÙ';ºŠý׿ÞlúµÏ{éèè2L¯‘·¾kr?’›Þ‡+A4aId ËF®¯—ëQ_]5÷ÝlU.röÙCÊBJ–P<Ï qR=3Nå¼ –Í,ŸxPÿîòJìñe.:á£Ëx)ôÁ8óz·¼W&ŒïŽ9¢^‰`úO"étÞÓîcŒB›>c†t±·ñ\4¤2Ñ(5t‚wQï·>òH.[­¨\%Ñy=Së{Ò–aú¹ÂË@G»dâ”;ðRÈ‘@.?ùÉOì#{ï¹çkÐ1>Ò 2Ï×.{ÅB‚ Á’I[²m= @}NÐ 4Ô{Þóžâ'FØVžýÁL,7GbC_†HìâÀâš ~»æö5Òxf£¼²î>¡Sv¶“tÞÝYö[?`}=üÈÃräñGÚ<Ä–Ž-Ö#‰«< ,vò0€~À !lC •vñÎR0@ñ\tZtÌZ:KNü¿'–¼ büÐñòâ>/ʶwo“]¾V9íqé¿/•åMËåÄÿvÎ3õƒ`}eQ™°Ï~åi¹ðgÈê­«dÂð rÇ•wÈ¡»ZüÖêJkawv®‘… _´d@qçùޤzÁ#)íÁâÉ|`˜µÎYtxã›-(E päšYxXd¼rÚwذrê©û¢*låâ&âe«²R=Ž9 lè‰2ílÊ{÷[dêèBÛ€ã‘4]d AÝ–Ìà_‘Hp?~÷r£¬q“Âò€8O:é¤â'1¡_ˆó?ŒbøLHaÚ¾ ”ïfÓÙÛ o0rÎ9ÒlîQO¿š>ë6Ênõ¼y2Ä(Ã$JIå9]6þüç?ÛÅŠAã±`rcrÈ (ÂÂwÞy§%yfò1._R'HæŒ3Î(þ:Uiq‡ëÄN'Õ½«@”iZ ÈP8®œdñ_ï˜^™¿Ç|yzáÓ¶xG[ÃãÍx~뇹+æÚ„ôΟÛY¦qº,^³86‘ƒ–dñÖ¯0=76LpÝsã€ßžÿÓóK„HØ®2ŠÃkdÐ]ƒdüñ}á:óoBýùÄHÙ}Ìîåç™6_½uµÜûà½6^‹õóÀƒä߸PVo.L]³e\pÝö·‹úôV™êç2º¥LW?NnÞýfëá o.†M(Ë ñþÄcN”±ãŒ0nX%þ˜i“Ö7Ì—…2Ñ®«6¯²!¯îî^9ï¼F£€ÍcgËÆÓ¦Éå(3¾4Ãz3Aat¼”»WÙ³1$ä,!´íN[ºÃ{oñ[äŽ-JŽ8bŠDü˜1í2ä1#×›ÜÚ.ËY&«êWIç™6Êçßy×vsÝ^ùÅÅ[KDòކɬåòþ™†‹Ä#÷™Ã\:ª/K0}š&ì¤RìyÁoW`Ú·ÂC0Ÿ•­GY·Î#3¿€ŽS>ýi9Úô!äN_ám?aÆä¬ûî“ù†ŒxïÍ{éýªYO/T¿TÔ³Êྱ<ÚÐÕïÍçž{®|ó›ß”+¯¼²øm4ªÒqÉD7Ô"Iâ©7‚"ˆKH~"“0`ù¸;ûjáH ”³ML›åw—‚²Ö¢˜9CÈ'®ð$%ïvó€¿~éÏeþôÂÖG×-/Ž{Q–ì²D^Øç9âCGHWkUö·~äöÒî¼ÞñOwÈË^–“~v’œzã»eÓ»3c¢x}ó:²y”Ìýû\¹÷Þ¿=óù»ß+ÒZ 5¼¼™É“Y¯Å;–¨‹ß¬«Ñ£ É~Hyâ•C  J.üÂUÂG7xñ3gvɈsFHϸÙvÊ6ª"Üðëß¾(Çýw‹<½¢AþŸ»[eö©»Û÷ÉÊÍ”½N¼Ú([O1÷Ÿ`”æ‰0‰½t4hÓÐ=Æ[ÛöÒKv­Æ6㥲æ#.’2‰á%ó:袋¤Á0~÷¾æ3ï,1Ž^ÏÄ®1úòËe’! º£L¿ùÏÿ,'›ëa]ï¬Y6×¥y/BãÌb¢í“È~Vè½T®jä7ï{îef^Z”Ð$eú(2ÑuÌ* ±în©àIˆÀ µPâ\Ð5,œ§ÞeH#˜%å\l^sÔ,.N¸vÁ­'ÌCÛ`-$AÒE™ÀºŰæa6I=aÚö¾ÂÂQê1²~¤4œÖ O¿T/{ì1Ø®w¸ø]ÇÉmg/‘ßX!/_ý²ì:zW¹àgXB°(„´§¾c¼üè}?´OœØj,þ©kÝ 2Øñ^ø‡7Ӽц.¸€5+ö+ ”ýwt”){Þû‰*õcà)ÁøMM&ÇF^Œ¶SïåÀ;ŒÂÚb¬àM6Wbó1ã Q]Ú$ã§/>¹ïp¹öÚãäÅ•ƒä”Ÿ“« |ÁªFó~h‘H(CìFì\gŸ5"Å4BÔØª°øçÎvrPUÏć êü¾Ë(þIGQžP×m3ä´„öæšÖ5»dŪúý®ºJŽ=滾‹0%ý‰§Âx·á±Ù³eÉSOɪ×_œ›Üv­ZÛýš7™à™TL’"ˆLhxbè„Ô$ý6Q„qI§Ø2}”Ø! -×;ŠCF^¨rÑR ¨Y\Þi· V/°$‹W”FH¹ÒÁsÈäC¤±¾Ñ&Þ¾=÷Û2eôéücùöÙè–‹.lµJðÊûÅk–ÈŒ«gÈ®_صlʰ%ˆÖu"3Ÿ•º×Éÿy—Ñ¥c­7Ê6*¿ýmŒƒ0·O4Š£(’¼ò¾Ã(ŸbkáÂÕeŠå¾hQ›é»í²xq›}´òÁÁL.òuĈ‘G¤rOO—° ~ggßÂJ·mÑu}á6Bj…c̘⎹EpÊg>óWãõεÓ2Y; µ¿yo/–U%/AP¿vmy™Ío|Ãu£Gû’ŒuAýȪH4ŒUÍ{1á‡÷G#á8sÏßùN™lŒ±ýë²ÙcÆB@F¥ªµmüɄܬwÇ‘$ˆE&IÊO ë³Ox z ‹´ŠÜEØ5°>™Å SlývöÍR þúô_ËK_x)tñ ÂxîÎí[ø×±I>ÿÈç­ÕœÖšB¸“x&€íP ])móæýê›VÛiÓn²yÓ*£ÜW«¥({‘ ~êx#.´ç ½CËÁ){8$°xQ‡Üóï·Ë„}ÞKÝŸî2™“[Ö!ì6¤¿F{ü1¹÷O÷Ê\«”_1Êa£QöX‡ö´DÀ­gÆáˆp ^K÷B Šz/7ÜÆƒ´Ö­ã÷}…âïSOn×0ë¥Ñ0sO·%/ë·%šU%Ó6.Ap½“_™ ÏU„ë<×psBõ†|•dù•Ñ8 íÍïFøÃÒP$ëfsß㮽Vö x$/á1 Id!é˜ÈòQkTã¾5 s%…ëUÒbFŠ[Ÿ}gGOJ¯‘~dÀ ÒçÁs}¸Q.”…~çÇBIÈŠk. ÄÜöüÙvö“Zñš_Ùܱ¹ì™$I„Lø!¾gŸ~VÆ SÊ›ð:¡i‚ ßb„ËHãÒ°Kƒ4_Ø,#&ôÊ„¡FITeè.ëí´ß’7â‡ÖÕRê{åÀ+× ñö¤ýµSŠ —=ô‘%…/.ÝYä2Cò—ì"Ÿ¿á9ùçGÿY.ºç"9ó¦÷Éqçl”ý÷Ÿ$S§6É/~±ÀÆÐ™}µÚ>eb3ä°j!6¿P"eD–!ˆ…W>ÓÌî¬}Ñ * ·ñœ¿|ΤIC·¹³!­ÂŒ<Àts™XË„7yþ3÷VÒé6äãk­{A›kØWT•L JadÉõ0×/^\|Wß{Âu$ÃÔv<›K.)þ¢s[Ú»çd¹Ùô½ÓbÞ-áÕ“!/‰gê΋³b K~º£Ú¨™h>-ªÒ 6¬6:o+<„®HŽ®‘F‘»ð’îì‹ò$ÙÏôÓ°{¥¬pCV¸÷òô«þ °VÚ¦§­Ç†Á\%ÎŽ½gÞp¦œ~Ëé¥ÅƒI åæÛ­XÛËìð×»>y—%@"ýÖ÷ß*uë¤éBc(ÌŒª^'­7ËÍÿ¶MÆ9 ôŽ›Ûõ#n=ÆÑÄ@á…pyMmÁ–5eg]ΨIk¤÷ä³ûò-æuóAW–<¸mëdӑ癿zM=Zäê«6å«·>aK”2 BCJ*äEX ÏgÌ£'<Wð;dÊͽðzÔQ ÆÚÝbîµQ,à±óÅ/î°;ëžZsæ ÈØcŽ-‚#L¶`65zL¿üõ3Ÿ)mQÂÖ$«~úSéòŒ ¿™T^T›L,hGãÝ[EïÂÜÛB„b¶à†dêçÌ)Ô CÏ!Àß=¦Í¼°2o,ëÀp™ú°&ý äNÄ„(×ñ®Gg莽.ømÞJ=Ðèȼ€|d sE.Z ĸŠÝÓX‰°ë"Ò°.^¤“Ó¥ÁÀ$´±ywö ÂÌ«KVÈ ÖA¥…ƒQà<”?  ]‰áÕo°ù`a cíÐ6äj°J™† áèÎÂL«íêé*x%Åk@6qwþ(Ì[ºU¾ùô7í5Iþ“³ÑPýI{ xiU¨ôݲW—É ‹_C—€ËK;)9Ñ&Ã[FwØ(üÌ|ª3}-²ë®·ÈÓËž¶ëG˜öËÂÅÏö9ùú¬¯Ë†¶¾º@R‹¿¼æÆ½F,üÊXã…‰äN0v)+.».D䨾½M::%²]&NoëínaN±‘tNQ¥÷Œ¦=›[ËPãÅí·ßH»† ž OšüÉOî‘“N _`Çu¶˜‹leŸéŸÍÆz$L†7ø>t¨Lg‘ž/(Y”'!",{S¹âUpZÖÛ¯Dªs/¿–±w 6õ€HÈÙ:?¦6üÍ+AÌцWJÈòPsyH¨ìwô L(ÇÈGTgÓö(Xäyâ`–%k¼üFC÷µ3<³ìÌτ’ßþö·©e$W2aF Š’Æ‡ÁO9å”Ô¬BIJL¼b×a ÜXˆ űéB¸ à¨b;x¬|ïŒïÉù'œ_ü6xx$^¼þí×­µÍb & x·g(!»u¼ye¡£\ÃmÚnï¯îmó/^BÂ¥‡¤ñÈX媻!:x(#}H¿3`V´­Oß÷iY³mÔ·M”žûî–Ñ=S¯Ñõ6„ÃL*rÈÀSÏ>%½m½VØ—·-— ¯»Ð’ƒßÊwÔ}ú—¦Û¼‹ —¹Z„„¼y%¬dó:¼o+<´ }€õOÞ£~x‹|ðƒ# fŽ]sÍsÆ]i•8 yùò‰òïÿ>Õ´MCY]òÂÚµ=†p+7ãºå–ûÍ)ƒ^yã9ýºÓKÞEŸ_i®Hyú¶yä‘…F¡/²m•C8p]}6JX ãÉŸŸ\|ç3»f}SÆŸùY››=ȼ¿ÿwFiH4/¾¸Ð>Ÿ„P˜z”õå—·›úm5³IŽ?~ªye8kTØ¿K|©yi0Ï!LõíZf½iFŒèyóVe0¬ÔŠFcH ûÀ*­k/ÌÅˬxSÖNc ô˜×VCDcÆÈŠü@v˜1Àº¥ÌdBe|Î Ö4_p]ÝžXiûԩ׌¼//\oOCŠv ”×Ócm»žRh·È?>>Éù€hž ŠXIÝCÊ%y€-\ð†¢Œã¸`¬0 ƒ—ÜRÄ%A áÇ­$®ˆ býÃÊ’I Í™¸,¸'îlØdó›Â£‚ ßcÅ7ãh½õl´ôV=×Ä2 EQyÙ×"Lõå¶ÛÚÌý e¨«k2wœ•ÑŠä¾i'ˆåxe`—ðô•Ûf\E]š5v¬½F‹Qj É(ó]>ñ YjŒ=&&h]ÈÙEmOâEœÜŒ¢ó ƒäþ믗MÆÀ,%Ó=íoÌëŽÛn³¤±ØÏÌ+ï-©¡Æ¢T^OÞE¥•|nÉ1%¸'²™`¤y7TÄ CáI ì}•eö Ï87Ï\ Æ;H“’PÄòL`/1À¾„´(HâÊUAOJŒ íÃ?;TF5 LûƒÌð°T8—òÅTá™BXñíxž‰‚öZøÊByuÑ«6œÄ´Ó$›ÀQŽÝ>¿›¬ÙºÆ’ åH’7!/sÝ]×ɵÏ\këB~õ_É)¼<ÚJ’W®éUôeá&¾ž Ïûè”[ný‹¬Úø†UŠ»ŒÛEFe>ieÀíC7/â }Ùï~f¾Ûb9ÞÈw‹¬=ÜÜϧݴeøDnÂ:ôû„ ;ÉŒƒÊ¼7$fªZá5è÷¦¥J1s=Pô)ƒNê‡Cya«7ÑqÇÖçÏ>»@.¸à£·X|YYŽ2¥;ؾ/–g°k¿ÙÃôc= ÁTh˜Orz©)Ûbs]Œ+ ÑP!¤J= äðìwsÝ o!$t¥›.¦n˜3Ç?‡:Ç”Ó/Tåw’ä$áÕŠòCIóôLˆÆ@ÒPapÃcz 'hoõ\8â¬-C'Ú$4¨a3<”´$‹LP.:‹Š°—î.ÓëüÜ7,: —6AÄ=xà+ŒXna 3 #1@P $µé,:,ª£]¸9’Èß8éòS?Pü6 PÊ‚@p“îž–{ñË›ÐVxOXö(5ÚacÄŒž0ZÞ÷àRÑÝ´‰v»*#aá&Í™Œê>Ä^góæf?¾[¾úã'ä?=Ûž X°ùS¾#“š&Y™Q…5lø09öÇÊÚ­kK„íMʯ]×#»N7òÖÕÙW6M°Så²h õÁK¦Ï‘9ÖŒ¨Ü° +èñHüBbAß{ï(Â)J0´?‰ðc.¼Ð®Îv•í Æ¨Zb”܈Så„ö+\Ä[§Ìù­Ff¼Š{»ñ(L#•úûwC*#÷Û¯ü\ã­,»÷^yÅ”õ°#Ž(þ²˜Ü7D¨¯(=òhªÜè3ä¸Îx8I’ê;Ì8xú¡‡ä¸ÓO—!F¹Ç%¡HPgSN%è%dͦó.¦ ”%± ìž @ŸaôiÛsÄ )Qç¹;2K7N;í4+×Qd„Ød‚1X±ú.t˜×Aè‹fZÜÿý6,dÕ3°F8ðŒ˜u…U¬ ‘L‡•ÅPc€úãß¶~›33…4 œCÞˆƒ|eA±¡ÐâÎSp­Ý®ÚMÖn1 ×ü óL\òcÖÖõ_/M›,¡Pn «©òáào„0Hhøë™pÿ±CÇÊÓÿù´ n*óæ-5¤¹R¦NÝÝ(›)v\Ï0¿·Þ„Ê I`-2hTò9ïûÍûŠ¿èò¯-“±Ã S‰Íí½ŠìUþ7Þ¸ÅXtÏÙ ‰0{Ï[7® ƒìõÎ?¿YV¯6í<¾GfÎ,„²ÂHA[ÒÖ(ÕÝ}fôxÈ`™´Û$ÙiôN¶~až ù ×›¢ lÉOÏ-óÏOù¹ígÚkxñâÑvKy?o¡2™Ý.üã|#›{”qàw=Ö‡ÐñÛOX/DIæàÉ[‚ðóL–|uIEÙ½Duû•·Ë>ãö)y/¼\þfCУ 52PȽlÚÔ`Ÿ{â…o¸(Œ¡í{=?DÝ£í±ÇdÈ¥—J‹¹(+×;gΔ®ƒ5íÖ+­­XüÍß›Œ·Ë7%Ôd‰S”B^1p S¿ÜËFã=w›{•`ú¹|‹QâuÆ •óÛ.3ö6™>…$UÁ!+ôÏ(#kì‰å…z(AJÝWñ“´÷’‹¹OPîæy£PªÌ&-Áü&)!'F$3ª0œkÆ2"¢.Ìš¤íñ1d•XôHbXÝa<_ž¸È Ø´ˆE&ü†L<H K#»¡2„U×iЈ|•KaÞ93'˜à‚úø)g÷sî·då»pñÄN¬'ýàœHë–VF"á§3Ø\@DBÒ0 ½™€ð®w½«ô”Fï Gáîñå=,Á[¸[òµ%6ßD½tÔw­‡ Úƒ6¤¬†0÷¹fŸ²ð—æ;˜ýuÎOÎ)åLF-¿ûØïB×”„M†„!= ¬û!C†É…’Èn2×ÀºŽá5„]“Õ3QÙ$Ä9ÅO»# æxzNC`¨Œú¡ÜÜ Æ ¾zg6_‘¢bV~ÍXÙÃ(ösmWñ¶‘È7}ËoêžzÊ Uâ†7ßx£trˆ½'‡Ê\Á '„úPl›ŒÁqÀé§K“©—®1aåþë³fÉ®GØÍ[ó» ‚@ùC¨Â«0”»yÎÈ*„ÆŽßµ¹ú‹üq­ÀZr5ª×èGdI‰Ã/<†l%ׯ¿þzûØ^&N¥EÕÈ„F¦2iÝ« T†•Ãâ~Q¬|A€ÁàìÅ£ˆóèÞ9;攈ƒ™PwýË]ráO/,'µŒyÿ1Ï[¸7lQ%ŠóG3$ßyæ;ÖâwC]VQ,]"ó_œ/ƒ:ä³~¶ô›;>z‡°𓳞”•kVÊèa£åƒø`¢Uè@'@†%dÎÒPåbå>× ò¦Ò‚¾Ç%¬ðÜsƒäk_;ÂXù-Æ`i“k¯](GÝh5Ê$él¿<ˆ“3бN!‡½÷Þ×”s„5‚AXÞÇ´µKžš¯Pb¡~(¿ /.8Í#ÁA2êÃ.)å²Ü‹é/¿DÿfcáC6ÀUJ..Éø/£…ÉæºFn^øæ7eå¤IvòÆzaäa½b”¾ëå©™ßy&óÎÁ€­¥bçÙGäèÈÙÖ DB0’Ã".:QDd õN®ÐðØ÷¾÷=ëüæ7¿)^!9b‘ ÀjJBQ2M¾@Á¢EÀà Ć—&Ä^¬Z½Jžšÿ”œöÎÓìyTµýÆvéyÝXd#ë¤åâÂ#|!’ö[Ûíî¸ìEµ÷‹{÷‡ùGb˜÷^D­J'ßÂúÝÔ/ “ÉŸ\±Š}î˜ì7ò_ù/Yß¶ÞÈíÿt»L?Ý>õÌ~e¶}Ò#Ãv.ë¶UnwþØ?=&S&N±å*'r“o"Dé†6ùŽíåÕûx ¯^Ó·]L5ÐÕÕcŒ“åÆ"[d¬ÎɶLuu ¦mÙ-˜Ù0åÞ „âZ÷~«‘MUÌïû"(¼7—°ïõ§~Ÿ)h‹’72eŠ!¶é¥g¿C>×]×!gUé­®xu«Œª‹Î îì+Áp`qªBæ ž¼§~n™°ÎK˜U$ ƪzây\1ƒâµ×¼Òh½æ¾”{º‡;6×ëy‰QN‡|²½§{F‡P”‹÷ýüçí¢Æã­Ô›kj³Áõ|Ô’&íƒr!(v¢äjáÜudµ“‚Á'ÉÓþÈŽK0Èyiô,úùæ›o¶†cÄ&<“˜?µ 4‚ð°ú<)¸³ $˜e ƒ&a)»µûÖÕåV½K†PšÏh–Ž{MÝŠïw¼w‡LúZ¥•1’=©:6—)öÅ_]\ Õø‘uÀŠ`IR¬ÛºÎw[•›N½Iþý/ÿ.ëw¬/+ËË_~¹0àͱÇÕ{”ÜfXÚô÷¬Êÿý%¿¯PN„ )/¿g"Ÿ¹¨™ ûTÑ?þøvyÿû‡½×b,Àn™9³Ó×CÔú¨â…\ð K%^.Q¦øƒ¼Ž pM,Úƒv6lD…2~l· ïÙ(‹×’î^ò½rÊÈYò‡¦³ý½„˜P…ì´=ㄺó7Þ»UnCú—ùÞÏ3! f.TüQ(pwvÙ6£tX˜\½Àý Qš7Älaîåõ.ºŒÐcÎm1åm‡0ÌçJ.År•%íÍç¦òeÉ÷ÈÓf™ô“ä†1r³ÌZM rÁô{šð¹ ä—g¼0köÁ´yQÆ Fýö±}Ìæ]ã"Ü4ÊB X‰IA#Á”XÆ |?)‘ÐH„©Ön+l¿€WÁ{„Oâ€@Úoê#>9¾ü¶x&¬¿îÂë¬Ò¼~õ½_•iÿ5­ô@+ÈË lŸx”]ãþ¼Ú$ä„—Àú ÚžzÖ LB‚P’.” Ãe—]fõÄ’±)5©²ÀR‰ã™ dÌbï’¾LÃ…%Èi½f™wa^yÏçÀ&Ûï-ŸPÀ{>Ç¢êz½Kn<ýFyö3ÏÊ 'ß ‡ïVXŒ†²†Œ ¼*à•÷^ ]•» ÞCvÞÏ]Ð&ľ§ Ÿ&¿»ðw²ìkËäÕo¾jËA?Üvåm–@¯wüÓö^€Wfk¡ä¯¼§-ݤ8ƒžI @B‰íæX´q‘¼óºwÊ©7ž*—?x¹ Ùmˆì6u7ÙѽC®>îj».09á{§ÏNNë¹X»¶«ÌÂ×Wv  a©,ãvÔ¨:{ ®ôšG½wÉ{Áõä‘Gäù_þ²dÝ7D»Ëë¯[oFA$½o˜×;:äw¿n³ ö½‡o”ÁW\/=»*ÛÏþžUˆ « š?’&dxå½¹iÁú‘/¸7FTQR&wú<ˆj0Ê_-BFä&v1F^';$0æ¨+²ÖtÅå^ÓÇ?.uÆ °ïÁaCMÞ²{:B÷CCÖPLLNAéûy/~(ó^€ùm!™!¦Ü$¸!'žú2µø–+n‘ ­F™î|ÐÈÞ‹››ðK|÷ú¹çž—|àDs=ÂNÏ}ÕØØkä)]~ÃAÛ§(h#¶a,ΣèQÆjÝϽçQ¬ã°ºaÒ=Óè&s’á׆S›¤óR¿ÅèÁõKeØ ï•º­¯—ò<ðÉÍ;”Yÿæ}œ ^2…u^ÊxaÊ• ÑPǶåËåÈÓO·Ÿ‡©ÃvU½§¬\ y"߆Ù`^‘KÊ>ºy´ì±`iÚÞ§¤êZ;dèOÞ#‹Ÿ©$ ½±Ql­¦¾a ßm¬ÛÆ!Ħ½ óP¢2÷÷’¹¡ ?ÕójÞ³Vdµ¹&óYC£eTÏ€ñE¸§l½u5ßÛFvÉÀç~š`gJ2uUYwÕò†<뫬Kc·^Hƒó‘sú‰Ð¯È(J˜ï•d 0¢ eÃeéß:³j¡k[ðø¾õ­oÉ{}žU#:KÆSp+”áSW5ä]ðpÒ̆RàYhVËÁ]gÒÖX°ò¶½'ï-#ÿ>RZÞÓ"õãû„‹…ƒä}>/ذ…wn„åqÈKgF90 rÀàØ}ÚîÒ0ÈXX­#,ᆑðÛ…ê´% u’Óîæœ”+ð"!ðn“â½ï­WÜ*3FΰʆvàÒÌ`à=Þ'2¹éD ôˆ9%Wòˆ ,Zú¢Ç”í¤Ë.«x‚¡*{dYg޵-m“IOôõí²Ã–IóäFi~7Ì øC)È:ÊC`ІjØFòSÔ.4¤—|\¯É»VÊ~ÄÀ£Dž0€¬lËÅ3ß›/º(Ìâã‹væUÿvÕ÷sÆ ž¼×ðSÐŽJ,šázÔEå’×R.)èCžÛÄþy{› )°Œˆ!³>ƒÁ/q~÷Åw[¤ º5 åàøå~)Wýù*»ž„üm¹MŸz¸¯×¸GÅCÆÊÍgÞl¿C`ÜØ:ðžxTî6)~÷õó^P¾(D¼V&g S´;m« Ä’ÖRÌê ëkt¨ŠRx½›{¥ãö£´‹t é’¥-•uí…g†S'ê¦$jæ=âLËÅø‚Hè7ˆ„ÜC"¯# L9ÊÈÇóž>ĺ§L´ãˆÏ0r¨ÛD3Vwû·³ùõn¨g©n/¿Üw=¾÷Þ/ôÐûº²Ä,;%ä.JŽ8=å ï!%^¹ž_Ž‚¾%ï„®eÞ¯$lÁtÐ\/‹öK‹ØdBÒaqÕBá°Êu!S e0 â NÞ% ”0™*Q–'‚æ§\½@X ¿43D “û¹OÎ=ã\{?749|þðÏË‘»iË¡n2ÝA[sÌøÒ ;£LôÆ!ÒÔÐT"—?t£»Ç±và€ /ƒŠî}` À»^EÜû‰{åÄ=ûv, º¯×{¡n„jt›x,Z”“z.¼¢0ÄJ.¼Æ•—´Po„òÑÜ·„…WF$攦Ӛ¤ó}ï/l’ö¦öRÝxE& Pê5Áx‹»¢|}ò(*Ú Ò-ËC˜òÄ]’hSv+¾j<'¼I Òf´Û¨L3JµÑ¼’còCéózó} ïcÛ:‚È cC•èýçc¶‹C0è8õZ”dø BQ‚áÀ‹FÇñ>¦Ÿë¬ MÚ>íâB/hCÆ#º–ë¦EÕȄߓo Ñ<:2 p¡äšÀNfy `ƒe¦ny”`„…Nj”M>Á®í §ÂÀ›5o–Ôuêué:–ïcÊU•SI!%fUýú´_[ÅÄÁÔÝ#¾{DÙŽ¼x&ìե®×öz6|ÎV(‡óð²ó-›ùÇ{¼)kºƒ‡sñLVo^mg†­Œ^Ø~^i`a3@QŽ~íÉ}° ]rá=2ä’‹ZžYA¹½ÞH™”µóæN;› âh¾°Yê†ëÝ!vShº´©¬¬Œ Ú@ë‡6H«! MìS.62‹7R3×Hª˜ýàzA¬TŸsõÕ2å¼ól?”! \j¡´P8½¦ÿ]LãmÑNä‰^`¤ê£¨ù\W ~á}Ö眧 co òâs}»_Þ·@'¡Ó*ú %¨m‡á’… ªB&„3ȋࣸ Û_$ütsÇÙJ=-HbúÌ`âÕÍÇV.`’ø$B\Ò6Nºâ!«¸ðÐk©ðѶ¬x'/‚`ÓVt‹:BA£¨½xþ?Ÿ· ï«WH×ö.yaÍ òõÙ_·[×ã½Ü|ùÍrÌŒÂÞd~ùïFŒÞß|å̯Èïùbè9àÆ'o”ßòñR}tÉäG~ÀÖC7‹Ä»£ÞI< ,tä ¤|ÍPºz0¨’Ƭ]oÄÍS%®3i:ˆ!„ÒùûNi<¥±,ÿæî²¢~LØÀ§ÎÈòª$Jù¬gid+Ê3 TÌæ÷‰&ƽJðù-°ójß•ã‘;ï”!F‰4uë ÊOù#ƒD4íÇlÏ < PRñ¾ºÐqç’L¯x˜ôS´ ‹Ñ‡ ýÄAŸñ>Þ‹Ñ¢-aùæ$`|¢ñ´²Db“ €‡ßÒªÂò¤±½ùŠ$psiÀù¬¦§CÙÖ%MŒ‘ø$ç%™9”lÿí¹¿•£9ºdQÐôì£uÁOò.NafÍHÙ#l‹Š<Ï‚w§ìBPlßÎsO8Ÿ–ßxç7äø½—ÕWK÷öîR ¯åìÛΖõÛû¶aѼåp½úÑXà}ïßûåLžýܳ֨  «*䜠ÜO(+ýªäÂ+Æ ×%— Ì}!t5—Äñåñ»OÐçAÐð+†ž›—Dy?ÌÔi´)ëóÛIŸø„ï4]SA_è¸ývã=]˜Èòï2×înç^DÐBË ã¹í†ûÌŠë3F–›±ÅbD¦&}æ™Åoú°ÉôS“ Ю(?fbMc¬¦é?ä€kA ¼ê¡ ïÜÃïô á5fs¡ˆÕs¡¿0V€æË”dâ&÷Ã@èž<²»\! £Ì8¥ÌYÆBnd¢qK€ FR5Kò $˜-A?ÉÀD@tš-LË|ì¤s²UÙ-}i©Œ=&Ñùœ[æ™°ÊѲìëËJy šö$/↕¼‰k®¥ŠœmÞ]¯„üE×]T~¾' ¥1àeo,“ã~R9¨ozÿMòé»?] ÇyaÊ™ÜrÚ-2c×6¡^õùóË–+}e¦{º`–Ž«x9.¹ðŠŒkù³Fj±üßõ¡I“ñ˜|Ï3Ÿ™F/÷tøÌ”Á~ÆoŒü ‚xÌçz'N»Ñ =údJó—ÙJ徟ýL†™÷Ôq„¹Ê“Jþ‹»{x —@ÉEß»êQIE_ Ããq³hÔ ÎÓ­’ ï YÒOÚ_I'œØñcÚŽ$ ¸»Zž|òɱã‘Äý 5HƒT$!7Q>fÐùáû~(gsvñÛhФÌ}@>|ó‡íÖï㇎·[¡3á;Ú’ƒÐÖnÿUY.oâÚçA.„Ä,Z Gý RýÎç<¯÷À敄θž)‘ýŒM ŸýÏgå%‚®=ï3óÊ<žÖù?;ß’¬Â@³‚òx½Â€Á‹Â†`PNyÝ3 (k44§ˆ7å S?oãõ¢e¿ÑrÛ_{Ín;BýŽ»è"›/ýÖôAÜíPP¦(HfR2vYõÏvò^&IŽ£áÆ +ê‹åéøá¥û²ËŠßཞwjò3æ=S“J˜1­ÆBµÖx GîxåoW]B¸º¼LÔ°s †Ïè3ê¤$cgûÈ%:‘0yä¼r4èØÿøÿ°Þ^–ñ›Lø ‚÷X …kîÍEb‚\ÒîâIò'\°(AYà®ÑÁÄåÕÂc»iÜY ÜÓ›ï`ƒÅåߊ÷ld¬_ÍÄ¿÷ÜkOyê™§ä¤cO²‚B›©`r-ÞϸÚx&!Sjý€¢„0ÛÚÛäƒ÷}Ðn1ç|o>äú÷_/gþ¨2¼pó©7ËðÖòU”?Lx ×AÀlB9vðX»ŸÙSûžOÝ$½ašX±ºÃ/¹*dra S­Ÿ*¦ZLñ¤,Ìn$$L˜ C'T¶’ÛA½¹NI ïãµÿØÊÇÔO}Ê>ñ±Í(Ý…ßú–ìýùÏW<¿Ýë™Xr3ã…gŒìIEóæóeŸ·aÞæRP'^oo5úÂ(„òÏ]è}Œ¬yt²Ùã«Oigb±å<)‰ßÿþ÷ÅOÒ!6™Ûc59 ÈÌœÀø®&…ÁÓ‚eÁ ÌEjü!H²Y¤›3!dówG.>ùââ·} ºÇ OAËA³"L‰-þV…¤Ê)h:+¿Õ™Nü­1l®Ïb±$J(¸Ç£/?*ùõGb'Åu õ$÷@r« ¡v•¯+à^âúùe?·Ä•”ÝöqÛ‚Ïü‘¤ > b%^ésÀZOd¼ ¦~ åÇn½UöÝo?{N*˜k™‚Ä 7E´)ýF¼ã#l¤9ßo/²¥Fqßu× Ë¾‚Ü®¿^Z}fd[PœÈUÜ9rÄ5×T.èôÔÙÞ{ÒŠö#÷q½ް3S)[ÙýˆcP(KÕî« äÔK2~€LÐ)è3%^Ùa„>¢*ŸxÙqäŸ=¹ð¶xÊb$òLÈG$IÌSOZ¸I|ŠªÛK@fXè”' 4t³H:kÃ|Ï×D?!57\¡Â¢£‰²E˜õÀš§J.äœÜ[¬¹êˆ«„gºÓ†yMô‚²ú…»üBO(S}ä’uE µ~9u¦Ì¶[ǰݎ£¤ì€iàAVcPGúMëÇ+V¢bêÇë0ã¡%7àmȰ(̾KDhI6ýƒìZCÍÈ€—˜ºŒB~üöÛe‹©£kÙSOVýgÚÁ|@ã¤&6 ›1¥9Ø&¶^_¯Iîéç…"ÇÞ:ò„ËbgÆ`^çUýÑñª‡B‰EÕ#è &–\¸ *ÂЃ:qm%LêÂá5 ÀUW]e½­ÿøÇÅOÒ!™pÃ?·5‚›æÑ½ Ö™`eÒ  ÅÙÛ à5@‚qÒå…÷!_ÔË€ÏÜD¿¶ ˆ ¨•‘ë¨0s ò¡û>dg€Y¥nþñ wV°«0Uq·CÁa°#y˜wJ¬Ý²VzÛ{eËæ>«P¬*^ޏá_Ò:Nøð%ï0«7’+õÒ¾ä•M"ß}ÅÒdÞû…ir‡¹‡¹q¹Ò €cx#i®wDL꡹õDy¹ù%Ž!WîÌ/Ö™œ¦\!}ÂõUa3¶C'옺–‘õeœ™¿ã’©-EëÈáÀøE>™H„A‹Ìé,àþ@ÉEß»ú–û¢wˆtDé3ΣüÔC ÇþVbA~ÿâ¿håáÚk¯-ž‰ÈÒJÆ Je’z.˜M@YÒÔ¸ò„ˆ¼LšDFÏç™+W¬”—¾d-9¬”*à÷*(³¤Çù¬Ùÿەḿ\ù™<¡05m\4 ¾Jº˜ˆÇ;cO0¼‘»mE‚¼îƒ@«Òå Q­'êÇág= ÒÓÅ ÕðF’‚:"÷x@Žüú×K3ªæ}ùËRä‘¥z¢”jFz¦L]fü¼h”õZSd%â Æ·éK}ŒŒÓoÚ¥¼„éƒQ¦^,¬{å•‘JŽp8rÑgwŠ Òƒ´ Á„•¹ÔӔߞãéêǸgÉb½é"™"—JžzTcLd‰²ðÊþÅEn4Ú£º†#JžÐ1ô“Öò¸ûî»­aŽÇÅc{Y ¡§‘ͪ’ 9 PÚ-ä™^Ëv*Tìàƒ¶sË“k‡Á÷ѹîõeÏA¿3rüÍo~“x«ª’ =a"¿¢a Cq{Qä4V "Ó· ƒgšD¦pžÅæ}Ï-{NÖ/[/‡¼zˆ}RýNõÒòÂÔc‰ðYÔV!úž'éê®Ê›š7É%?¿¤Âª´‹>€ª{G·lÝR˜Õ¡ÊHoZÅJ™ðD(SÅÊ|Ÿ ýðÈ‹ø®]‰»ŽD•’X^5éMý^Zÿ’|â·Ÿ°;'³tæGgæ:, dU-YoøÈ ~áhýT)á­¸ä’5¤ÒmÆk+“BŒr¯I¸M×øãM7ÙÄ8$õ¥¯½“k|aÊn*2\ æZA¹õ¦˜ˆ¬Æãq0&•DéKþf©¼j¦]­Ž¬ C‰ ø­Iâ^ü†WýÌ:Hõ“Ÿ>:õÔSåJãE^~ùåVÇÓÜ'©ñžˆLÔ@\Pƒâ(r@Q %€+s³d€¦³X¸ÈÂÇ8pëÛÞÒ.K¦/‘©‹¦Ú§0Z‚¹¨Ù>Q;O;JâqáþftëhùÊq_‘÷ÿ>+|€ëúMõõ^›íTöµ‡b=YGA¦^\ú¢ö?•Þd!Pîi_œf§U»€ŒùÔ#rØnÉ=TÊ£‰}ÝJ‚ëiì‘]ÆíRªc’‰!ye¢¹<ä2ñ+õ+×qÉ…ÙReDy›_¢x*ä‰çWü¤IgX%†‘?…Í“—ÅȘFQ#/È«7÷‚¥¯m•f‚A(ˆnÁcÉC&„ѣ¸a Ÿñ^´9ÜIÚ—j¡© m˜(A_Bºœª›8( êÆ¡÷çá^_úÒ—ä<YI‚ª’ Š×,ÎÓ»hpÜK:BcºTbážq׉xAgêÓã€\4o‘ŒÿëxÔÑÒQ"éÒ×1Ú) :/jV”ý7 ä±úù׳‰smÊ¥³T)Ñ®®Îkâ%Lcã¦rù—˺íÑ+ëݲòê—Ó0­T±%}`í1¨8—𓺹Šhý8 Ôj„\h2 ™mÜØ˜yaíJßiy¥è;­'¯Þ0'2ÀÔh<ÝݦL‘}Ù×ÎÇ 7'Ϩ¼[¨ìøþ÷eÁa‡Y“±Ìø¦¬n˜“×-æ`þàI“lýö:ùäD» GÂ\ÇKt:m{ÿµ#YàNÒÐC½mꨇ›+¤=Д™Ï"ËÈmí¾þFß!»×]wÝ››LP³gÏUä\ÁÇZaf”») À½Ã2e‘P0 Ù~àÝï~wñÐ äWPÖÍeÈëÎâ—M7˨ðÌ6mô %Å™µhù"9ð;Ú¿]èo‚<›¸3®¼@X^Wñ"°¯*^ÅÈì;,k¬³g_6‘‡¥žÒE×_dßû!n¨KÐ#ÄÖ‰©ãzûYsüNcÙZOHÕµxyu-Þ, MI„2)D ûyŠç›$³o´~¼2¾M{°•ÈPcM·bÁ{£|Äû©w¤eb1×2 ”=„¤0×´ Û‡Q0vÆ {Öï~g×ÙèÄ/ܲ²×Â/|AöýÔ§Šßöa‘ÓÖvJÝŽî}˜±ä»ß•Éçž[³¼º¦ã‘=aÐgÈ3†¸îu˜‡ÌzÁ=Ÿ}øÃ¶º—ðq£7AHD&(~%.h06%C‘û5ƒoò€}iH/ì6$ô>¸øI2 T¢væ7”ƒNe&Ä!Ìé°¡.ÅìúÙrÙšËdõ¶ÕÊ•Úõ »Zů€x^½æU;À ù­Z½J®øÓ[ÁûM}Åkñý.$±ʨ/mKˆ…k0¿Ÿs(^<¿ ZYÏw~åùò_¶Ï51*¤øËB˜+iY½ÞHR‹ÑOñê`uI4©Q™å\,l7„õäE%˜Ä0mí«ð¡ÆT\’ël‘ò÷ÿüOÙhŒ1Êæ’hk³¹¯©¿=ßiÿÜCHŠ€P[Í×åGL+Bc†PêÐ7æz”‰ê4†Þ}¿ú•4™:Q?÷ˆÛ—è±—ŒÑ¸Î(Ñ=?\&ä´v$ (“îBŒ·F]еa!À´@—Üwß}òÑ~TÎ>ûlùßÿýßÐiþqQU2AI=üðÃöy$nG»k5ðDôÙç~ÀÒÂc`jnhüvF!bõâýè´ãƶÆRÎÐðžÙqÏ9pᲦÇ(Îâîºlþ8ûÿ™mCê‚ú’ÉàÑòä¿>i‰¡€¬¬ZÈûÐÇäÆÉÇÄÝŽeÂl¼’ ÄfQ¼¼jŒ—2s Ô®WTVHƒÝ!E’-ShÃ8ÞHR »Z?%>n~ ¹·Æ€Q¼ÈIÐ:§2BQd ’@…ïQ¾=¦xFÈ&Œ"úÐŒ›õæó-ÆcC>©›ÖÓ’¨)»_^#—e›6-Ñ–÷†¥e°ÏBOõ[g ÎBQõ9ÝfH€…”®±@_ÆQ¼Èá#Ú$îTäZ@S¥©ÑUÔÃz¢æs­Ÿ^½ÚéË_þ²üìg?³$ò¡}(P÷&E"2a S˜¸à÷lÔÈ— Rn90(Y$ƒb ryÌ’A±$¦ð–AAç`ù¢d°|Q¦”¯íÆ6é}½H$ç7HÈY¿j½LùFå#tgž=S» ïDˆÅ\þðÿ¯’ôn;ó69ü€Ã…­´ã(—×êç3ò)liâ‚­G–|µðè]¿ó’Ïë¢ÅºöΦAqê UA¦mTxU!íýµ½Ë<“±CÇV$ßÁò¯/·Z¸å¢^i¼‘$ >š_ÒºÒ.È#õÓƒ¾å;d…üí¥€zVšqrkß8!DZ¿³!DÓwæbñCJ¦ìFŽ~JÙ(X?ë¿íÞ{¥ùŠ+Jä³ãÖ[­·âÖ“þ¥7Ž3V©Y“ó´+cößÿÞn‡Òl¬í(¯Ç%L”Rmëjä’|‰Þ2Úqë(^êi¨'ªÊã©?·²c<‰Jþ«A¤õäpóhzÍdra-ˆë¶ÛnK´ÅTT•LÀý÷ßog À HU`XÃq@Â׃ӀêA&”e@9¸¤†@±%ˆ ¿íz£Ë&QÎl°ëLTOÿ¯bÒ¼è™h؆úЩ„‹˜¶{þçÖ‰ð;óM"^½0’4¿ô°œõóŠïú ùÊ5í8œ‹Ðj~ÊÝK, ´‹†Æt°¢ˆW´¯/ýõK6Q÷qëGn•‹o¸Ø7Ç5‚ÊM¹ªá$²Â¡~ZWÊFÙ ÒfŒz¢~òLZ÷xVZ>ÿI‡VÁžwžïsH6›>\h®³ß©§J‹)£K4¦°¡u±$jÊ”cŽ)=ø φíS–<ö˜}=Dž´h?rŽ(+Œq¦ÍL#V„×Ê`î]æ!™ø¥õHøÛ”¯Œ`¢<œ"\O”±I™èKtÆýˆâÍ+–DhðFx Û82 ~Þ ýFݨ/cgŸpŸ|ä#v0;VÃP«:™°9$9¡*”D\¦P÷/ÎŒ° PVvjnBØat@pP?„Ë;lˆégDn„øç–Ë~u™]Á´ß/ù™>bzIxÕâ rM¹¿;½Ö å}Òb’0BFݹ>u§,Y 9‰õÖËÊ5+¥·­×N÷|­ó5ùÜß“µÛÖ–Â[ ¨Ü Œ Ú»ÚÞHP7æÛ#«È¯z1¼ª'ª}ª3ªs&zdÄÿÝWêŒ1¤äË`~S–À6©2í1ýC¿ú•´>ÀôÁðË.ë#¨ë®“Ö³* ‘ oÃõºM_ùŸÿ‘7 aROä„ Ö‘#lŠ9 ›ö¢mèǰߖÁŒo?«Ç´OñjÊ& {¡úƒò£{tÚ.u„l‡n9’è§´ ?B¹4B“$Tú Ã:²¯![¥à)269äùà?hpÓGyÝS‘ˆLø)–x\àUÌ;×*í´ÌK£° >éjLäL( •õ*®+I°b”Dôð¿a6ÀKp ‡k`]“‡˜{þÂß^(ëw”O8`«m¯þôF¼ =…P.”w6 $ªÊˆWêŒò9b¤L›;Mš74—åH ˜ÎŸ¯’‘Ÿ¯|8[`H)@ÁvKÿ‰Ï^ÆvZ_žÑ”פ`ý›>p‘k¶iÓ|Ô¶îùÅz2&tmÖFFUñò qõ*Éê^u±aîï—xçùö^l_¾\Œ[Q|íG"„Xì-—ë½POô›†´®yz/n¹ÐEq÷L øË/¿Ü*‹ÉQóÀÂ'Ÿ|R.¼ðB¹þúë‹¿ÌU!”%î.Ö Í>™°lœ©½~ ¼ì±ƒå‹k{à–,&¾£c9øEæ×©|¯Êvîò¹þ‰sÓYXý„?áE‘¦º¦1mD±Þá#†ËI?=ÉZö®òýÙÙ2åªÊ¼MØt[®ÿ›Ç~#_züKÖSòzy&ô½ MQ@¯¼þŠùý#‹Ÿö<yâ¶ooÅ‚uœUÏ5 ȇ’hÛŠ6÷Ü8Y0e´Œi±ýi’ “‘í'‰=U°æ7F©±ƒïþF†Ë@B¤e®m +‡CDB®*_ú˜¶bì@¼Œqä8)*&Üv›4_tQå䀗_î#¾ò¢°ú! ä+N?ê–ôVráHã½pmÊE[b\Ç-WRPf°^qÅvºïO~ò[f…’(õɹ’ KgGéÓñL°V`à4 xd’ÄrEA£8‡ÐWP%¾ÓË2e;l‚tötÊÆíû”üÐqòûK~ogø0˜Âf¥…<B ±,_½\θõŒâ7}Xòå%rôË3ázôÁòËåʇ®¬ð 4‡‘ÇTã(ÐÆÞû k&7Ÿy³twu¬z#Ôz@,µ3¸ ŒšKÊšœåZT¥ËÀÿÊ29ô«_± iBJí†$d†¢«`Y ñêÿþ¯L:ûìðr™{{Ãc½æ^mÆs0ZøM >¬¼„t˜)ÊìL<¥¬²”—÷‚W€Q‹B/VKÆ)ï·¿ýmù¿ÿ÷ÿÚ×üã©e9)‘ ` øÆ¦±LÄãt†«Ïi@m Éy°ð1,ñ© 1q»Q Ü“…?”¿0¾×*ÓùAà§yõâÿAŽ8舲0UP_î»vëZ£ ŒÇdî;¢e„üüäŸËÊŽ•òÅÇ¿XJxûM·u·‰ßi·dϯUnCƒ7C¤Y™òù?=_Vo5JÎü£^xB,rœ1²0ÓH꯱z=ÒX»qÑÜ"x#Ü;oP'«ˆŒ±À”Ý-Æph7Jw„! UF¼ºò´+víZû<öQ1Ã;V ŸsŽ}J!`FTûï~W®x•t¼–ˆ§d:Ç*úSä‹úÐ^ö©¢Åï;L6y/ŠŒú¹Š7v¬žëšk˜N ~"„ ÁÅ9™q?ï…zñŠ\Ñ^ožcK,ÿõ¯µù–P ¡mkÔd¡.%¡ ”7ç¡&:—Lí=æ˜ccŒ” «„¨‹ UÁSNBm V'‹‚à(Åáç™°›® :6&Zˆ~÷cÝÊÖ%+~GghÓÐ’C Z!r§>Î[1/0/â’kYn¿òv9|·t‹CýÀ ‚ÜiëIS'É^×ìUü¦QžÆŠ«Œx¥=Ti=“²@¹ð²Q>Õx®²E±,„ ¨l㑃GJS}Säzš põFðV]oÒK†yÌsë©õDɺý‰rFvék¹+KUC€²ªäÙ–ýe3ž‡Muë© ‰zê,@«”Ìõ{n™ÒíðæLF¦ÌÅʦ+¸ßòeËd·ãŽ«XY"&óYRÏ$ ZOW预yü»>øÁÂ"Kó]d‰wÂ>]o [„Ûè?fk©a·?9ür/AÞ S|Ù …= ñ‹_”rÔý‰Äd¢38¨l§ÁÒnÔˆB\„©PªÌ¼a®6‹\ ª`ðÊUí70½ÀBPáEñj§r/”"÷Æûª¶û¦lãx.Qð†ŒV¬Y!ï¿ïýÅoû©$õ‚¼¯‡C›fÝ& šð¦Žzp_—~„Ha¿Aš+Ì=½Êð7ÞÀúŸÿ\æš2@Aaâ0POdµÔ§†@ÞeL òæssBèôZBQ(ǃÍ=Æ~ä#LýìÙÒÌsßW¯e•Öª7Ä6ÉÇ ÿç?Ë0ãПµÎ•¸ B‚±‚‘љ֣÷z/ôÞ(ÑëìäñÐCÉ5×\c÷Øúô§?]u½‰É…ÄÀŒ b‡YÝ `aò 6„œ"3øôI`J”‹%•¶ :¡€ës-:•ë+‰ªÕP e¤l´iÿ5MÖm[W±¥KZ¥L]y¢¢®iÑÉ^DíãõFªá…$‘ÎÀÔ‰!J.X…JÑe”7ÁU„“n»Mº Ù.5FË+F9ø==/-zÂbƉÜy§ 5Òxs¿]>ùI»Ëpâ×)¬Xºx¼ÖPc¼›>6Tæq”ÕÍVÇÌ™ÒãŽs΋ ®¸Øn¼°a¦<ÍæzJ”< ø™?üÁ>%Lÿéå%\mE˸ÔMk‘ý¸ÛDÅ…z/üãå?øô ‹iqÆv5;›àêÒþDb2AÑ€qcèYây³fͲ¯(-ïŒ1ŠOy´ Ê´@ù@Z $í ®MHA‡Z ®2ò†šò!=Ê5gù¹fö56,•—‚v•>Áíêé²Þ„J»õ½·ZbÕzÒ>´1í®«yÕ¡_ Ä<ò#Y ®B)’×óæÄ¼!#”‘7d”›2r”ñ6Ó—LJ¡írŸŠlîãvZnŒ±†¼xÐT“©«>·˴ͪ9sd¸©+ý¢±þ¨<¨EÀ½Ô Š•“‰ µúg˜²Ïøÿ_ßkVxiæ9¤}]‚ÉsŒ¢xŠ+„K¿šž3RÙ …í¿ýÛ¿Ùöxâ‰'ìÁç$ßûU'4 ¢¸îõ¥ðÌ3ÏØŽ" ï*x†W?­¢‚(£&²ƒâÖ.¼SX5á§tÓ‚v~îåçdÍÊ5²ó¤m¸ å–w˜Èõ†¼û‘äŸ6|Z©ž T<2ú’ão,²ž¦žR8+\Zà9c)Ò—ª〶V%¤õ¤]\EÄkTŽ0Ȩ&ÿÙÚ£Zù·@%¿yÈ|¿ÕÔ‰~£/ñ’'Gzi׳ÉwÓVyäRÐ5/²¦Å£{q„Œ3õÄ”˜Ã®E{#ŸÚ—¼ê4s·OñN“ \›È:ƒˆ †T.F‡ÁýèGrõÕWËUW]%Ÿýìg+ä™O+—y"1™0èèä¸ $}Š–#ìËV%(.âÜ(S@‘)‡¡O£XU(°È¸> д– ªB«y:Ý%—$–îc/>&—þüR» ÃÌÎÌì… ˜qfi¹äâmWòK(k¦#C–Ï­zN¾òÄWdCû;x¬\ñõrü^ÇWlO_ ÏÃŕŠE6P>J.È¢ö'Ê)ªNnâ­z²ÔOášÏüü‹=$‹Œ’‡@PHÈ­ziªt}e7àz–0ŒügåÅXZ6s¦b”h³ÑY½ cTÇ)¯y¡ŽÔ—Ãëź@÷©^òN Ê”ñŸø„õJnºé&»Ùm5ÇOVTLL6ãáTq@qHâbÁé¢-f¡˜ñPtüáNÛ¸:b€ÒÊ;ÖIÕíÖƒ¶Ó Éð·æ]Tѳ–å•e¯È‰?9Q6uë8'eœGƒ: ÕL¼Ï³Ù2R®×õ²²}ea{úëìÖä¶kuVä"X‰«Œ«1è UDô/ ØUº(&Wéj¸Ýa)[Z^¯å™¯|EÖOÄ»ÖF½4Wéò™«tym}öY/ÈÈrZÏ„qMX|±ÿ§^y¥4¥Å» ÷"¢àÖ½€\»õÄ€@žÐe„µðÚh³j…µkã.»ì2»˜öÆoL½·a-Qu2¡sÂÝë‚Î"žŒõ‹²bVÄ‚Òå:z$çCVÄú5Ü  ½š ™ý,],>¶Iù?÷ýY³m]ÏòÙ£>+Ÿýóg‹gö!m˜ˆ:gÉaÐçšÑ=ÈP˜Aá¬%W/‘ºÎºÂöô«WJO[OY>‚#¯|"‡À‰šŽ™'hE•‡*]ꇢB¦1Vâ†Ûr…éwS¨ò¸ùl1Ξ3^Âx£  ¸(ùGvƒBF#M]GCo¸‘‰!C‡–ä)Mβ~Î(ëNCBû¢ô™½•Ä»Iwf'¯È)ÄA ÔÑCÕ2 «×]w i}æ3Ÿ‘/üÿíÝ[̬U™'ðšô\8W“Œx57ÞÌM‡ÅD˜ƒ`<…([Á€bDˆ ‚œâaD1‰(J&¢CìØˆwÞõÍôôM§ÇÌÅ\8™©ßëþïYûíªúê=U½ûÛ러Է¿ýUÕzÖáù?§µÞÛoŸ$::“ a)ömarV=º·D”•’_IÜ2ž¬{Qd6dÂF}&ÓÆ!Åãsö ¡< ÷œ¯œÓ\mßTi{ –M¹ê‚Æ>:$‡aSQÖÆÛ˜•çF¶%©(]Ÿ•æ½¥Eïç.sê3y¯Â”Ÿ›žP·+DéºÖF~ô3–n䌥;%V)ó?ÿíß÷àÌåk÷/ÿÿ\eÿc)óŸŽ*¥K¾Ìë\ê¿_’Îòzàý·gŸ]œuÏ=ǟθT4‹·\+Sy&ÛÁ9;bý’Ëü¦ð¸œËWs‚Eo2Ë|ĦJŠBz+ìØø‡ÿþ‹¿ùüßû×ÿÇÃÿõáŽwo“‹xíxíâ‘w?Òä"Úa”m°­Ò/QŽo¤ý\ OøÌ¼®òÒÚ¥ºë¼ _®ÊyȘ!’\™KÓ( †R‘fNG³>—s-9þš³Ï>ቋåCµ„h†T­"ª=ãŒã‘7J7r’¹c²6ÿ¸\gÂZµÔéóòM‹ÿ»ôš¦<ò ä@$ˆÂ˜%—‚`J9yŸåœz5§]"¾çòË/o¢%N³Oy!äT˜œL™xìn¹é“ÈS– :É" ‰hà÷åÌd"–Lfãr[´H&–²³¶Ú–õ>!TxÐ5ñ”Ó?þó_.u´pÉëwjdÕ¶±è»(}cÚEY›§¡f™Ó4sÚéGFn"¸} !ZDOñ¬3cåoKYí'a±RÖ>ñøRɯÂÿþïÿù´Ó†Ù²ÿÛæCI®WDjM‘ÂEh5ëÏiKâýëÿòoo¸þ_˹^êVÞÍX ¬1ûs›ufNÉVÊJ¿…HC2«*ä¼÷‰%É iÝpà MÕÖ.ÂîS 3™øsÕåÝZÞ/4H(} >V’ÿÓ °fcn³ð)ærsšL–‚÷ë+¢²(F³þÁ ·‘›üüç?n¥èMb×iþ½­EoL7)}De±¬÷­¬Í© 9©þ›CV›â ëißÏœÏ"¹>^¯÷§Ì<Ê(eæ¥"2Ççb96'(ùc¿öWxz¡ —ò—ÿè‹¥×Ó·RËúÊœ2"‘*42. $Ï´/=“}„µ;£À ¹ó ‘–sJÖ©ÏWðãa}r#Ï?ÿ|C(žÏ¾¯ý6vB&¹[‹òdñ q´c¶>×b£0 hZWøœÔ€³î|§ì÷Ù˜©¤Ú5¹X¨Êm¤vœÿ E¿«,zr“3í@E´„÷Î1td\X¯šó?ú…Dö6‘Æ0Ù@ F¬okj ”¡1¯šùËúõª@¤k”<Œ"ZÎGßJ-`$¤´–Aˆ¬ÿçŧÝqÇâ5KÃáϯ}íâŸ{lñšsÏÝjýŽ}nâ%ÚÛxüÛ"DJÖ»ï¾{ñÜsÏ5„EþË.»¬)Pr3º0×ÉŠ‰Û ÍP¢KX+Áçh¯Ú¶ÞÈ*ØÜ*…ªâ‚õê³|.KXÌ+,š2ﲩ¾|($=õÍwªîYç= …±´`#k©ˆ"k£÷÷sñFÚ°Ùœ>RÖú]"Ö_šyG&™Om Ed=Å`á%YÏS&5ùˆÌé¿!R¡ÏåEÉçºø?¿òÊ_<†Ç O¥èwr”õªP^“Ø_®Å?-ÇøOË¿÷‘jÖÁ˜ŠÞ|Æ»däu~Ž}ø.ÉuwjÉ‘¸Ä9&WvìÂ}ßþÛÉ,ämA©,ŠúôÓOoøZ¢L`ŸIô9Å”"oÇæÞ´Øü}Q”.²aõfÁR¼ÓÐE…´r"{Ê3ëÐVDäeùÚ…hSséç☟æ¬ÁÒÚÍ ãm”5«—ò‰¬%‘f^ýàÑÀƒ°\WËAØ*—a>£¬»,ÖoY¬aÜS¬QΫµÜg_™OÞ¥p±=à3§‚ï¸é¦›?ýéO››~/¹ä’úlŸÚ‹cå.Ñ‹LLÀAoKH‡G)S xo¼0 }ØD6·ïã6÷=]L¦rsrI“ŽEßÅÊ%›{ŽX¯ÞÏSZe‰íúesê"!#ÙK"²9‡Â†ã0Xx#úÒm"ÕÈÚ7ÙöÞûœÒ“ír2¤$ÿÓ²oµœß±¿–ÿG9Fézݵ¢Bz挥¬Úá`¯Štd>}Gé}¯ƒõÏS²?Íç”cc¿¹C‹Q­%¿vØ0:™ø}Ný8Ö›Ò?XrÒÿ[üÚ2GgÁv±^·…Ï·XÛá¢,X Ђ]•lµÈo‘#‘9^%…hã$7²ŠHýHT3—]Ë]a]ä\å;Ú=²I²;͘”ë’Ç“\—ù<ðÄ‚aÀ²¶Ÿ(kód ‘F鯢'cfJ£ù"Þ›q›ªXÂ^eTfNÉï;rj1Œ /‰·$Z ô>Õø®,=ÄO|âÍóÙ=q.FÈØèE&&Êâm#9 Ó'¤c±@.nÞç÷}'0 ‘²¡ÕÔÐïrÁêƒElÁFéZ¸…¨Zcß×g”Ð×äF -K±Ûð·%rÚœ–I6&yý<–²õÊ+á]îäÁUÇ`-GÙF‘+²R€”¥k­yÌGò6¹Éá ùˆE9c4DÙjöÒP£ÁúÉÒè]ÂØÐE‘Ó+b!!ŸŸýj*ûw*胋Ÿyæ™æ¹ìï~÷»'#­9`2ñ< ˆÕF‰†}ýŸœ¥$±Eõݾ×w!&Ÿ7¥µ¼ ä¢üÈe±z¥-–˜ dsÎ!´¥o”µ9‰7Òd-ÃE>oH¸(ð¹®§K”ëÚb4ÑIvslN)RÖ}Z—ÆžÑf.„û’oi4ho ¤È‰T»ÈÊS’H¶/yJ’ísïRP4ƒ@N _ ¯c­?†›»µŒÝSO=Õè«ÃŽÁdb1RT~GQeaûXÍßQD6¦k£&¬‹> 7Å”(°)«¡º‚Œ¹ë‹B”³1&”¹õ³ m#ëX°a,jco1oòFº"–_YÉ9’••L!R`¼‘±/Ú²ð¦Í-eÍâ/e¥0»È:&rc…oÜÆ$5ò’-Ö¼†LQ¸ëdõÞxJŒ<ëm_†^tPnsnFÕ_ó\ÊjM—¹C2wWŸûì³Ï.®¿þú†Lzè¡Y”»@/2Áò” â‘H&Y˜2Î_"ù´ÈËP²ÏÉ‚a0É)YsC<¥)@H²Ó;eNiè´Èé5²–Dj^×…½ÿÖ[omì_ÿú×—^zéltÕ.ЋL„&LEUæ,B¾V’È:”®v”®÷˜@ïWq‘Þ\”ÙÄѹ̱ÂÖ-°¥¬iÆ+ U#÷6Ÿµ¾#ñê±½‘.Є‹"«q£tmlýRáßs@™·¡‘à¶ W{^Éßõ ¡0Zì7óH!NmlB)+…kšOó(ÄH¬á9Xã)1zﺯ"kFc4%¼Kfs¢ø‡.P­å=î HN5ô"g•‡{|Œ ”óû>JÌdX,VBñ»X6¹Ÿ÷¥„,.Þ9YüúÒ>ƒ¢°H£tÉ%«~[%´ko¤ ÚÔ7IP¡ãHgcf^ýÿ.aäà„P£t†®-Ÿ‰”¢€´„‹ÈšÆ¢ß´G|N*Üæ:Ò7z@U”’s¥+T–PvÙûèƒ> /Œ™ðî˜d¶f3§¿üå/O&̯Zëo|ãh¹—“ ½Èi ðvÍzíK"à3bñ»j$¿eë•;Y*!¯S{-d¶q„A¦ºyØø•¹²F EN­/Ò·x#ªzJ’ß7¬aÊU®*7¦VæÓÒ¦TB€pëù"“©pQ2-CžZ€`3Z”ÔäOgìó&§¤<%ÆO‰„w#«ŸÉƒPóó|ì^œ½4µgN‘É /¼Ð¬$ê™ìä¿úê«_þò—ýå©Adâ­cx#`ÑÙØpÅ…‚1‰¥Âõ:¦…ë;XÕ,V}KXoˆЬ.Ï#›Ò†”»"ïܼ‘\hÉj¥š“UJˆ|‘U+‘D¶¹4n»ËØ7 ¥ÅgéŸulÜædå2 ÌiJß·ñâÈeÝ–sk]Ç É Ý³rqúÆ`™âœR Få•W^Ù—°ÈJ1Þô¦75¿;UЋL,ß[5›»/‰ ¥T‰=r™»*‹¶ÂµI-Ì’\ºVe@Ù·äÆPdC O6%kZîŠu¨O,×È;–Âí‹ÒSj_hÙQB™WÍg“/²RD]”mÙ·]&²‚}dÝê9)i{,‡ ÓÚ^é®`Ü„ž…)Î!OŽ$ké•ZÏæÙž-e- q6¡ìÃ`ÊCÂúî’Æ|ä#͹‘¯|å+³2àö‰^dâÁöÞæ%åFĪm t¬I‰Â¥„4›Ôæ´@£„XE›ú«zŽ?"Ñ7Ö´q³™Ú 7Öyý<4°-|¿ˆ¾±ª­‹±`ͱ#'™y©¥Â%ï: ךÐ7ä#É>f߆‚2ž1OéC!²jþ†×YµƒÖñHK_èh BËž¬~†¬cmÕ:•ȹ–ÓN;mR²EîwÝu×âñÇ_=z´ñLæ`ˆÌ½ÈĆt­¼ÇKj\ß7¼á ÍÊoyË[o~󛛉_7Ð< qtOOd¹Nm²p³P) r¡–®iÁäêŒ!Võˆ§´)7b:m°lJòRJndÕÆë °ä”xq»º}x•Â-ÀÅ,§ñ~弿2§æ+—Z”‹3Æ¥ÂÕà …ÛúÆ+·xåÆnW¯ïNqJo¦4èûÁ>°¦ì›q¸êª«šý$¬…ð+ND/2)AQS"!×ÍK ³Jã¹h’›¾ÊÃò)n²rß]ǪA?( 4=EͪÉÁ%ýßenä ”ÞHW‹ß&ŒœšMêý6d†ì},Ïa3Ûd6ü¾Ð¶p5k”U-–nÝ “MOßæEÞÆš3næ¡ V)ÜQ¸ZŸ\£Êz󙼑9/sk/0öô‘—©o!T{vLR1ƪ¶$Ô=¼êÑG•^˜“I>N9ã¯ýëãž‹„1ñÂG<òÈâï|çl¬CЦ¦p-ÿ.­ù(Ü}œsÙÆé ›0ʇÌÈÀÜ”žË6áJšáÀâgQ³¬we¹„¬CV5C†¸¸îºëfe(Í““I°&^yå•ãä‹a=¹¦ cguV礱²RŽW gÌG®²øÚ¡"C›ÍHá¶CE%‚cñÏ­Š, Gÿòà*ýœñÔlø)<µƒö}xlR#?k¾œ[ëÑ|FVm•±ƒ„…ýýªÓâûʼn€ åù Ä\’i ¥¶5?eä kÉÉÇiS¬%ßÃñ]Óõ}æÚOþCúP%•-0K2iâg„\„Ælì3Ï<ó¸çâ!üëBDdQ+¿Ì騱žëà;KäÕ&µ!K…«sôFÊPÞ ¬«êYç©EN2›Ÿ17¥uaN)]°¹M¢;ò²nÍ[dõê÷”5%Ýç¢Á)ü…Üxå,þx%«ÀPj[óÖò6dÚ>Ûš³†ômÊJ2sIŸ9r¤9Òà!VÖ•èÈo~󛯀’3©8'™´aq³ Jrñ¬‡–B., ±UŽ«ZR†6ú>`˜sà. ˆ¢¶™)b$'?2Ô ú+g“j¨® ÆS+åõ»Rù Ö¾¤N¹•åȼ’}‚$£Æ8 ;™wl2íó‹¿ïs>ÃÚ¼ZI¦iþݕܒó^ó:e%ÒP¥¥8èsŸûÜâãÿxõ@à¤$“6ˆààWYŽÌ"d©ªšyÇ;Þ±xàf:¢p(CÊ”’áÅh6Q,[¯B6»î³0#ËBä)ñà*sDá„X4ßCöÈêõ åásT9ÛÔWN ò™Wó¨p‚Ì‘WßËPÑ2í¡¶ÌëØ¿ÏF‘Õw”ž©Æ“Y7WÆFô@áÉ.½:0}Í5×4¤êù#"Ãp(Ȥ ¥Çž-Àz=ï¼óš’0™ÏEÛ‡"Ú”‰u…kCòTlÄ(Û©óJ!]qÓ¥ª/bÝF^Š—|Q>m2-ó”!e<ðº£Æ¼¶+ðl³Udš³L‘y*Ï4Æ …Î@˜Òâ‡Ò3Mã ´CcÖ—ùL)·¼’ßO 7û*û•p—+™ÃÌÀCG&¤p‘JŒÏ|æ3ͦ!¢Å,Æ{ñŠpXÜe92å9%¹ä¾/ñi!·Mqj°ù²)¡24VèĆF"”Žâ„)/Ë[}ˆ¼edþÈI1ó2…ç–¾š¡@‘œ9ÙåCókíZäÍ÷ •ɱúw™WjÃL˜7Í¿ æ=ÅÆnªþ wj©ÜrÇÖ7Þ8+¯ödÇ¡ôLx$›64‘Y‰’l¹æw¿û]³q%áR1&3†eÎáN³ú‡lèÒÚ‹…KzÈÅÏ]­j$罈d.yd*!ôÁ+1f6”mäÝ—B0ö9Hç~9FÌ’ã™–¡¢ÒxHÛ*jØ!9ëÏZæÍÆÎ¼òäÈ•µm¿•òŽe,1’®½öÚ&BñÝï~·ÙßãâP’I°žLÎ…+l»9a1Õcm"èêt©c͆\4 ‰‚-7ä:Bô·HŽÅÏÚgõïÃj]‡œüyC¤E™Ð B%û”¡¹ÀØé›>˜×1Ë̃ÒxHC°åü®“—ᢠÞyWíÏɓ㉹ñL„µÈdkËk ¶‘wìkaoóôÄOL2W•LÖ‚’zõÕWO¨£ÈÎ>ûìã¡1D³.‡1–7Ò¦’5eëÕ¿YwQ¶^bHŽ7f“}6c2vÎ?l"9ò®ª+ó^Çö´v"oI¦my͵‚yòé‘}`ìxKúË@ØD ä- JyÉš¶®H}õ«_]|ö³Ÿ]ÜvÛm‹[n¹eV¤zØPÉdKX˜,½òvdDád~ÂbBd6É~ô£Æ…ë[ßÚ(›1½‘®X—gá³Y­Ndëß\<ý¤¨)ˆ>ž\)¯&äé3B,^ûæ!¬óª´v.֒Ĭ ÊWŸXߊ(Èùds4`ßcpØQɤ' ›ë1JrQ¥å:áÕ"7ÝtS£°ç²ˆm>Vaâðˆ%Iî(Ú})Š:ÕPrÆqŒ>”ydJ^dJÖ´mâòÆ ÉÐŒ1š ¬E笲þÌa™{iç™xT»´Ð¼±Cr7›ò™]Á(ЬˆþøÀñУÁ‘€‹.ºhÔï¬XJ&#á¿øEsí‚ÍêÚ‘rGŠ‘Ç’Š±©ëçWÁ†sRœÂi+êlÆ2tR&})¦m”íDQ[Šõ”‰bŠ¡”òúÞÄåÉëç([ÿÇÚ¥¨•ûÎíb˲¬V%™þ— /ë=²j]òjC¡€ÂÜŽ}Õþ*ÕÅŒ¥ë–_„ï*&ë^¾ÓÏ»<×sª¡’ɰX-Þûï¿¿y64EmXŇy-)GvßÝVɹhÂ%S*'ŠÓf¦…RÔQ>”m®ßEé´•í£TCpûPÔú@“3òRЬw$ŠhYÔHnn焵̭yN݆È+ïPÊ+$Dñf~½®ËCl k& ±î§„uî»ý&¬%Äœþ3xä<”ŠéPÉd$PH›µa¦¤U‰åê}åÈ”VyÖ…ÂÃz²™Çxp•~ç°][ÙFñh]-[¡5E¶Ê¢ÞÈ«o” F!ñÞÚÊvŸy°RQ‘»1Ÿ%¹”yˆÈlmoûÈŠò6nS{šà».¿üò¦ÈEÙ¯‚ŠÝ£’Éž¥åêýx/ν°ø]íÏųõ»V •a£.‡è¶Ï\eÙRQ´^×UPyNÙ÷¹ókjP€BZΰ¨)&a¡¶²%_©lw•g2Ö”'B™JQ'ôIÖ4²•¡±uÞ©*2FÂ..·4O<ñÄâæ›o^|ò“Ÿ\Üyç5ŒµGT2™XˆBaÈ%I}!Õ)ñ\ü¼®úÊTJ`³Zw6J…M¼d¦”lÆ¿•üæ!GÂ2s+[E5…„„%pW²-­fœC,^ync½+x0‚Sn>¥¢.Ai'¨™cKÆ‹Ÿ­=Ï Rò;µw ?7ÜpCó|v„òö·¿}'d^±•Lf J‹•WVŒIhJ&&4&¹o#óD~ò“Ÿ¿ÙßbÉGñ¤‚ŠÆuìm”c^…É6…‰ÚÐ?ž’+[æ6J>Ìær˶·– ªÈ¬í*g€ìxŠxŒñôÍ6ȇìõ«_5ÓE$æMyü¥—^º8÷Üs›ZUB™'*™œâ ¤y+ñ\\9Á«p%LÈ嬳ÎÚx"ÚgðFX– §FO”mÂD%¹ðdô™Ì:ã°ð礑sAÂF«îýòëÎ÷„XÈÕÖ&[ØÙTÌ•L*N Tž¹¤™¢F(¼a1WïGQ‹a ›¹.C{W–r EÑjúÇ[¡¬õ‘ì«ë ¬ÅâçÍ9;Ò%lo-Ã[£èKÏeÈaJª!ÿ’wãÑM™kó}Ï>ûìâcûXC&=ôÐ 9ÿ¯ yÆJEwT2©Øáʤ<ëâ` U%Eøµ¯}mñ®w½«·Òš¼Ö>%‹øXõ‡WR*Û}å xÆN¢}¬°‘Ïl{k䋬ä–ÄÞ†|V˜"᩸٭·Þºxê©§šË…µæ´ž*F%“ŠN°\¾ÿýï/®¿þúã÷U9¡<´Ì»ˆùïKP¤ˆ„WBQ³Öõ›‡+Þkª‰B.^wá¹PòÆLÿ(êULc€!Ð.Ïmêªò\ïÑ?ã6eÿy¬+¯¼²éï~ðƒÆC«8ùPɤ¢ž~úéÅ‘#GŸÿü盃c Â§,G¦ˆ„DÊŠ±ƒÊƒÇ@Y’¼Í3QÚ9dƒ Kr3?`«åºåÙ»~Á&B%¯&C¹;«MÙ?ýqkÃu×]·¸ì²Ëš¤;‚­89Qɤ¢R¾*?² –EU’‹ûÆœå@.!ï“\(AÞˆðŒÙBcQ²^S1bñÚ÷)”¶þ!0ý›K@U8K©9ÏÊ1Efc06©ë;9€èѺïÿûwJ¬㣒IŤ°¼T¹9yWïËc” K¦+|~.@T0戈‰¢ ¹¤b,䢥a”Óªv“wp¦gÊ“ö}@.ÕZ¼2eɈ9¤Êxrý*8Ù/¬å{„µŒIÅÉJ&;…å&ÙêI”ñ^<ã…rZuõþ&¥¥«Õuû)Gvî¥ 1½úê«bÎB$û8Ȇ,x]!¯IpS’ž„HÉ:17¥)Ì”³A¼B¤° "säõŠÔÉïEk2ø›»îºkñøã/Ž=Úx&› …Š“•L*f ËŒ ‹iBEN?;ãâ ƒ?ÿùÏ›çîûÝ\”’­$Á­Àˆ<²$ÁK~ß'¸‘€" "RÁFfįÅgËÃ…=÷Üs͵+ÈôöÛooþOXK…XÅáC%“ŠÙƒBVaä ‚Šÿ–$víyÂb<˜}_½¿*ì¶®b,ä¢Y1¶ ¶z®”‘[ò)Æ+‡)ï¹çžÆ PaGæK.¹¤y6»kQäfªgr¸Pɤ⤀g{‹µ+G¾ûî»›Ã~ò-©ãɸE¹LêO¥,WòdíSšˆdÝ٠ᥒ\TŒùÛx-^ûVŒmŸç¶ðú\ÀÙB—÷Ýwßâ‘GYÜÿý y™'Í}pÏ<óÌ⢋.:öׇ•L*N HÒ³òY¶mXÂÂ`UÈENEˆ%¥ÈÚÐ[nWÁwÇÚßælK”®7rÑäT{•a1a²!ä¢ìÑù<‡K§®&â»êª«šRca-‡–@læanWÛT C%“ŠCKšRvi¥0‹ UQÌ%¹ð †”«Jsv$ÏÃÚÂÓ÷ ¢!OI.]ª§²Vrÿ×”žšï3Þµ"}×ìLíUÌ•L*=,q^ó- 9÷Â2NXL;ýôÓ·NŽçìÈÔOiÔw¡°24Æ›¡¤C.ZûûCtÂj}qv*6·"xlô¾ð…ŵ×^;ºX1oT2©8%AɾüòË ±¨ãÅø]yõ¾ÒdÉñÒš§ÈËpP‰¸ƒl—°]ËC…^…TO!bw9ç.G žîùḹ*F‘„¦+N=T2©¨X‚v <¥ÈE«÷‘‹äº .o¼ñÆÅûÞ÷¾ãÏ´ß7x!úªQìªÊxXn"Ž÷2ÅWT‡ü”°–1úÆ7¾Ñ|WÅ©‰J&+ wáôºïÅ™ ù 'óŒòV Ô)Sæ!¶…0ž$;Rä ”x.©£èC.ˆqH¿}2m¡-ÕZH¶†µNmT2©¨ØÊXI2 üÁlH†×âßBIî•*“ú®LÙ5¹ðFäo^÷º×5‰övr¾¬C0~ö7!¯ÂdÛ’²ìk®¹¦yN»°–ƒ¤•L**6€gâ‰ßüæ7Ox€•m£ô±¤Y˜ÌýV!Í5îSYìñžÜâŒÔÜ̼ ÊŠ1䢑±„\ÖUŒ)ÑVöËCûÖ·¾ÕÜ.\Q•L**F€mD)#•‹?Šçâ ¥Ôä" /¬å{•%ÉßøŒöc¹oKi±þžþù‹'Ÿ|²9ˆèŽ-y£Öª(Qɤ¢bØV®NQ‚œŠ1'¿)ý²t=¼çP k[T’9õ?¶R×÷Ü·õØc5·¥© óxf²’3r}MEEPɤ¢bGPuõÒK/'!#!'9‡Ë™gžÙ$ËWå]$½å)‰—»Pæ{~ðƒlNο÷½ïmnÐ9š›o¾yñÀûËŠS•L**ö‰ñ(ç$õ…›ÚW﫼’ñˆÛ /¼°9„8õãm‘Ü£>Ú„´Üø‹8ÊŠ+Zx/®¬©¨€J&3’þÈEã…¸óË•(_|qSŽ+é=eŘð–ç²ó¢„¸Î;ï¼Y”?WÌ•L**f ^Šθ\pÁ Ñ8}ïy e9²’à±”½‡” kyòâw¾óæ³+*¶A%“ŠŠ™Âe‰BaßûÞ÷šKmUeÀÂbš ,Ý¿Ås)+ƺÞ\ ¼"'Øo»í¶Å-·ÜÒ¼ns™dEEPɤ¢b¦lýë_¿ön-[WîB8 ¹È¹ð,OY1vPÅ—3'N°{¿ò_$VÃZ]Qɤ¢âÀVvuŠ*1yäà¦dKÏE˜,^‡ÄþW\Ñ$ÒåGv}qeÅáA%“ŠŠC [[9²ó-ˆ…÷âÜ /åœsÎinD~þù盈wÞyçä· WnT2©¨8…àšýßÿþ÷‹^xaqôèÑ&7âÙ#5¬U1•L*****£^®SQQQQ1•L*****£’IEEEEÅ`T2©¨¨¨¨ˆÅâÿÓ<_b†>eùIEND®B`‚pyclustering-0.10.1.2/docs/img/pam_clustering_two_diamonds.png000077500000000000000000000705721375753423500245120ustar00rootroot00000000000000‰PNG  IHDR¤E£T™sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æðpºIDATx^í½ÅyçßïîJr+­„À Fçü®ØàŠ1H²0Xò°…þ`Ë''—8(¥3:a§.‚ª•Ja K1uÉñsJ_ü³~rÅ>Uä8ql•UdCÀpÂÈ’0*^ê*U X+ ­´ûÎõwfzßçí·gº{¦gÞ™wûS5;;ïÌ<óLÏÓýt?ÝÓÓ8ŒÐl6Ù«¯¾ÊY£Ñˆõx<Ç-p?§OŸf—^z)ëëëcé•W^a ,ˆ·<Çã)–cÇŽ±Ë.»¬Ó!­ËÅë­çÔ©Sahtt”Íž=;l2µÁT¸Îùsç‚Ý»w‡ë:áõ.¯wyø´.¯·Ùßô…nÊãñx<ž.ã’Çãñx*wHÇã©Þ!y<§x‡äñx<žJà’Çãñx*wHÇã©Þ!y<§x‡äñx<žJà’Çãñx*wH½À믳þ5kØêõëÃ5¶=ž©L}õjÆ.º(Z{Ó¯7³gÏcccñfk²»7ß|3÷äª>ú(»é¦›j7±`Ýô†jìßÏ,èïgÁòålbÏžxoµñvR½˜ÖkÖô³ýûlb¢Áúû¶|yÀö왈÷voÛzàoæÍ›Nê Ó¸÷Þ{ƒ-[¶Ä»[ìÚµ‹Íœ93ÞòT´Œ¦Ÿ>o1668ÈöíÜoy<½Ëúõ«ÙéÓÓã-ÆÇØÎûâ-OÕ9sæ [·n]Ë!ùR;uÔ۷ʧŽz÷bZû’{ÊÔ[n!ùÏOHÔJï×^ ‚U«‚`Μ 9o^pö‚ ‚‰•+£ßk‚·“òèÅ´Yࢋ¢u•L¿ÓÛ5²¿ñƒêÌ­·2^•aìĉp½âЍeôîwÇx<½ Lý¡‡{óÍhíM¿Þx‡Tº£Á ÅòøSŒMDá „ë†FFÂÿµ9n6D×á÷)®‡{~ •5–I÷/~õ¹CÖûeöPÛ17³8%ü˜;–±ß&¡FÈ¡÷e’>6×¢:cÑER=žºâRùÿnOx5ýö'ŸÜÁ&ƒmOogw}Ƥÿ¢žæúÜ\ˆ>ü>ïŠï÷|×ö8 žfÿðƒèjpÓ¿G<½ý.6LœÅCw ³›¥cÚy™=°Œ³ýiö¿ã_äÜô¡V¶ÀAÁQyj7ö6üL Óûµ×‚½ïbá3éX|0~5}$øò‡ñÛÁ—_zï xÅÿö®`/_ó‚m⼎eiÀ ê{7v³qo¼s$ضTÚ7¹9âÚªe#ß±w£j?–Ö1:F¶-åÇÇ×õŽTuˆõN¼ÖÒmüŽÂ# tN¹÷I9%¤Ïäµì¨[ž³0ÌÛ /~-8v,Yoql£šúä2o^ûþ¹s˛ѡné-(So?SCÝ@‹ælü¿Ìê?7x5ýâΪ£ŽÕ_c{y©š½E³šÝÍKÓÖù\Ö¶m ünð×ÞmT'™ÕìkèWš<`)Û¸m/ã§x‹å›øJù0[Š>+«¡Ý&×RÁÓqã6¶÷›Scy«_¨Á޹˜mØlÇbÀéìÙñ1"ŒGû˜|(¯Â„n‰à[HÓU:QÝ ªx‰z'U1ùW¨\zRG½ë¦³lú]ÔŒ÷$Sïïo3mZôÛÐ,+>¡@êh# L½} ©n 8ÞGÓܹŒavvÓA ¢ê¸r¥eß“ÇÓ]h¿P__“-Y‚²+o|#zW“T7­Á Þüë€wHU9lÅŠÈ­ZÅØÕW3öÄö±‘S!kl{<¦e²[¸ð ¶cGKAÔ¿£¶@Ø®Ùôæ_¼Cª:“³1ÄÓ?÷\+0ŽuÛ°ïd9Øöx* LŽ-£‘‘9aRR@@ DÔÛh‹­-oþÕÇ;¤ºAã>öàéqÀøðUX¬“ò à[DõÃ;¤ºqÿýŒÍ™ȱÆöå‹_übüŸ§W‰^xå¶ÎÁ:) @_ŒÅúg?ó-¢:âRݸûîèƒ|cí$ä8†nD À‰ˆ%â|ï”z›( uaðƒÞÀ;¤º!WÓúä8†éˆ‚(Êyx§Ô» Ô¶|yÀÇÂuRè ¿û]ýñ©nØTmœWÁ¸vÞ M jÛ³g‚íܹ/\'…Þð»ÑÕïê†MU°"q •óðÊSŒZ{Rð©nØT+Ç(Òy'45€Ùºõ:6þ€µS©XÔÚ£Á;¤^¦ËqŒ"‘ ï z¼„¹ì0§­S©PÔÚc€wHÝÄU<Ÿ×¿f [½~}¸fGf“ëJNYÎÈ;¡zbcjÏ>Û`ÍfTTÉNE'Ç&jm£“§¼Cê&®â ü¼ÆþýlúéÓ¬9‹3¶oŸ½\Gú”åŒTxUlLíšk‚p.; ;›¨µNžb𩛸Š'p9XN“vaFI\útÃy'T?lL sØa.;Ìi';›¨µ«ìèÉŽwHÝÄÕ(8.'ˆå(çC6•›SŸn8#½ŽwPÕÇÆÔàD6o>ÀŽïp*®²p)Ë“ ﺉ«Qpü¼`ùr6†)ŽçÍãO•5¡Ât°‚k<öx‡TGÒz_KÎUUqF*¼ƒê}L"˜ã©Þ!Õ]ïkIãW«èŒ¼ª6®MÓd ‚¬PúÆÆÆØ©S§ÚpþüùÜ‹+9e/…êýÊ+¬¹j xŽÄÛÊãR–æ5×´1ðusÉ’ðwîÿÌgXW ±Æ¶‹ëÒEUðßsÏ=Êcu Pýžu¡@OÕ1. ú½ÊK·uþÌgš¼•Ä­• ÜV'/Iz_sM“ÑÙÀ—,é”grŒjyå•ólÕª&wžA¸Æ¶ê¸´¨~¯úR¦Þ”ƽ÷ÞlÙ²%Þl±k×.6sæÌxËãŠë¶ne9ÂúšMÖìëco,\ÈlÞï5cÆè([ôàƒlhd„³Ã›6±±¡¡x/¯y®_¾“$À`—÷º‚Ãè§’X´hQü_5 :VM·©Ìúõ«Ãí 0‹7&NÍÊèè öàƒ‹ØÈÈe›6fCCcñÞ“cT`º"Ì—rñ†žc´ŸÇgΜaëÖ­c'Ožd³fÍb³gÏh% ÐBZ°`{óÍ7òÏ÷(¯ßtÓMlÚ´iñ¯Õ§h½æÏg TcÐb?~<ÞÊÕû]¿ó;á ²x')¬b¤Ýø8kpG&ÈzÝûî»/þ¯ZFY)*½e=ó訢Žö]׬é¿üŠí¡µ‚OJ`ï4º¥7æÎÃtE´”0ôÜ”:Ú(Soø›y¼|©oÆŒá?tP$ïâJNÙK‘z7¤—×\£<.˰îûæ7YcîÜpÙ©qâk ä¾®Ê!$¦:Öfªßó,rHQuLÞ¥(¹E.ÝÖù›ßìã]#ìCÂÛªãä¥,½õ«i쓟œÆÏG}pšá¥Ãõ5×4”ç¤-@õ{Õ—2õ¦øA eSÆËY‡èÉŒ㺪>#ÕoU¥Nºö2UZMGäa™=3/(yI‰@RAãƒ<1Þ!•MY9R~íüÚk3_·®ÎÈ;!-tDêtèŠÅúüyÆžxÂ/ïz 1®ö™g›3'Zr´ÄêêŒTxåÑ!×ã€2^Þ!Ë—-,eõoØÅNœˆÑ2–:)ÑúOÖrº‰wBåci²‰9\€oyLÍT'9¢þ‘Dá:f„øèGkcþµÃ;¤"pùj¸¥¬ªpª*¥¥3úÒ—»ñF+9UÃ;¨â±4µDZráðk|¨/+¦:Éõo}‹±x|PÎì±Úšåñ©\¾n)+ÀÅ4æ ¦,¶£tFxW ç½õ–•>UÀ;¡rÉbþªL{N;x°5Û–¬YŠŽ¢ØÈñ˜áR¸žŸÆ ÷¹öó¯ÐÈñLm L­U ¦%'gIÀ‡ú²’E'=÷†¢¨µ7ÿbð©’œBä˜AÖ8F'¥3ÂoòyW^™*§ÊøVR9hLM‰ª#ä`vLÙ“ÇÔ²è$ çþèGÑRCó¯Þ!Õ]¼áõ×Yÿš5ávXÛýItF=ŽwJÕ!O ÆÓ;x‡T5T½»ºÜzë­¬±8¡*Öy‡þôrAíPñ¨LXGžŒ§wð©j¨zwu¹õ'?a¯\z)Ûqûíáº-¤gY:ØYJœŠâ”{T&ìñ˜àRU…üÃwöîêøÐ‡Ø3×^Ë~±`A¸n é”(”ÅbDÍK%ëkÇ;¤¼èZ ¦­ QÈãUpá¸Ò3_ý*{é·~+üklORDéÐc%ŽwPnÉ3ÄÚ%¦YÏS¼CÊ‹®µpË-Q«û±Æ¶ Zȼð`Ø»{äÕWÃ£ß9*¢t¨J‰“Ãf€B‘N#)kzGU]¼CÊ‹®µðã·Z=Xc[…\ȯ\ÙÑ_„YçÎF^<ñ,×arÿý÷³ãÿñ?²ãï{;uóÍFN‹M‰S¼ƒr‡Í]}.IY³ÈkzòáR^\µ ùüÇdÛ·oïXNàeY¶'÷ÿÓ?±íW]ŶÿÁ°ï¬]›^:˜bSâTO‘Ñߤ¬ÙcçžÂ;$[äö>o¤:LLÛƒiƒ§O„òpnJ!¿hÑ"ÖG§2…·ÌpÞÂ… ãpËp)«$¼ƒÒãê± 9øÞ˜Ž'K}.MŸ¤:uT¸ö©SѹG&˲Aèäb–ò©†wH¶Èíý»ïNo-`ºàU«"+ÇÛr<úòLÉ“;àV½øž{Ømÿ÷l&?¾A'ÕJ¡Á«€üÛ¿±Ûn»-^¼8þ5—± —² Ä;!;\=V!¦H6¾ÊšH%MŸ¤†¼pT¸&® p®«‰ì[:埥|ªá’-¶íý¤\9¢oI&+¶òË^|‘}ö+_a—òjÖ)qùïyõUöÙ#GØe—]ÿ˜BÚ½‰jŸiõ±¦qï ÒqõX©…\ŸÓ‘E‘%ã88×ÕDöT§¼³”O5¼C²ÅUŸäÈ%M±òÁ“'Ùmÿë±÷¿ÿýávW>ÿ<»•çò Q4áê«ãb®º*þ‡“VUá*JÀ;!s\š?e|<[‹$>ò¹¨ke•E¡róÎR>ÕðÉÑÞ—Ó¶àfgR*²è#û££Ñ×\`Ú8×ÕDöB'³”O5¼C2ŶÅ5RÎ;ÆØ;ï¼îB_ZJqÝúøÿØ©¼sá…ìØ'>ÑYÕCkG8Á˜>äIrˆ™«†:%ï Š§[&•ÖØïv6Ÿêx‡dЍVUdÔZGΡ»õë׳ °ÏðVͯ9Ãh9q§óÂüùU=T 傸iCž$‡è«}§ï–I¥5ö+–ͧÞ!™bÛ‡bŠ.G+öp4±CzÏ{ÞÃ>ûÙφk°à±ÇØg¿úUv髯†Nç…Ù³ÃãÛ€£¡ýWí-¦Y³¦¬Óñ­$;t¸Î¼mq!/­eVT6÷˜á’)¶}(¦èr´bÿyÞ’™;w.[²d ß¼•]xá…á¡3ïëcƒo¿ÍnûÛ¿e=|Ñõãÿ8Ï4qîá,zðÁ¨—–ƒÑuŸ8p€Ýv÷Ýáñ©ˆ{Ãp# ;Âð#ÕÙšâ9ºÜu‹£èLQÙÜc†wH¦¤U«Yâ º°_õR윑‘pf†I‚€5Ї¤CÜ®‡†––®úé"vR¼ƒJFW€çiq£Sðä‘g‚I6Oƒf‹5kúyVšïñ˜à’K²Ät9Z·Ÿpbx8æ ²äV›ê§‹ØI…ñNÈ ]na¾´L¬5OyI¸¬[Ñl±ƒ=øà¢xÇï\’%ž ËѺý„Û6±ýAYs«Mõ³èØIÅð*æÛ511OyI¸¨[ §ÖþÁçŠ6³ÆÙ¾;ã-3d9Yd²ÈRƒ¬âB'U[y×mÝÊ.9t(ÔK'ŠäðáÃñÑ7©z•?üÃÕìwZ#2/¸`ŒýÝßí‹·ÌY¿~5;}º%gppŒíÜÙ’ƒŽ~ô­ŒŒÌá-ˆlÓ¦Ãlh¨U)¤ÉÁ ‡C‡.áÿQ ŠªH˜ÐsÈaÚAš¬–>Ca‹&I$ú Ÿ ¡EÕõeti4U8sæ [·n]Ë!ùR‹Ü-¤ÓV 6-¤;v°yAΣÏÁ}”ÒBÊ o`þ|Ö@Ð>&le­\™9ŠDÕJêÅÒ¥—¶Zx"¼âÊ^}u?V üèG ~-ü¢®ý›¶èq(ä?ö±€ýàQ In‘DÔÚÆÄ¦˜KNàªE’$GÜ;ú¹0»7Zhsç&§·o!EÈ-$¼Åßß– XçáܹsÁîÝ»Ãumxíµ`ↂqn!ÍiÓ‚àÆÃ߬Á9«VÏá:‹ ¡,¤óÙY³‚h xi4Zç¸ÒIÈ™3'æÍ ‚¹s³ÉÃ9<¡'tnBVVJ‘±€:Ú·Ngx´6G.0?U6‚\z˜¤ aj]Ô /~-8v¬¥·|-\Glcý”–¬hÕÔl䤥·+}Š@g'.‘ý |íLi‡Ä©³ÞmÎ J„ªçÈ&Ï‘¯-^œ;v,ÞQM¨CÂRG;Ñ錂1­P×!;±È²l¯Cõ9œ'®709£eË"ÇW¥^—ÞU¥L½eãGÙõçx“OwôòV•xüîøñãìÀæÍnÆïÈTq—÷:È”21Ñ>r-ÏuÄh6¼¿ˆ/d#<ˆÉEfÌp;ÜS>Þ!õOýùŸ³0ð±²Xã;GžBû•z¸ŽÐQ¨£Ädˆ2u40?ñíH8)úJ[ÒuL C´ÚY@vzžzâRqú½ïeã˜åc_ßx#úâ˜ÇSõåXÓG©£9zö³·¶d0äžâ=%ÙéåÅÔ ÛR”Ü^aj;¤n[‡íõ±?éÓã|¡Ô½V KÇõ»™¶AÞ˸š€$I`X6F¥!<'„Á_øê?¾¢y.œÅÔ ÛR”Ü^aj;¤n[‡íõ±a8äJ,ø y|^ȽøÈ‘h(u,ÝöÞjJ/†îd\MhšÇ$ðΆH„é0BïŸc)¢ß¨¨™±Š’Û+Lm‡ÔmëP]?­‰ã)È™±Î ¾îC¨TÁÒ{8çMµÐ]žA”<&hûû£#×á9EÍ*^”Ü^aj;¤n[‡êúiÕHOAì"Ö9à릪9Oœ$S(çõºƒR…ß² ›Ì×Ô,1{^-"<§ÂÔ Ûf/WνW™Ú©Hë0±TÕõÓª‘ØÀ9èX@užØ±ƒ½±p! ä{É'¡øœ×†˜Ón*ak2Ô$ðH˜¤©Yb*ÌdPDxN…©¶Í^®œ{¯2µR‘Öab©òõhåüO[8ž~zÿ ùïóཞ¶{q:ó9/•©Ƴ5˜œL³[U)Âl‚Ê!÷pdº+L‡”·z'0•£²Tù\Œ¥Û·Ü2ù ò|RܤeÁåbŽ9L|Šu›N6¡³´{³Íyi²lp%§ê2ѪHBúåÕ,È&ðÃÚ?áÔÄûC¡»,_/.ÍC'K命h÷"²uÞôvyoµ!œ¯Ð³SÎW¢ÕÛPŽò8ù7ÌßF·1 þ æA1ËmÆrÂ5ÕI5i–øMž‡ÿS}°-HÛ§Âðxgé]2BoyJ¡*B“°¯o"X¹r"ÞcLæ t±}IÓ aÚŸ$ÒlÄ¥yèd©æà“ÓçÑl5½Ë{³A›'2u§²¨áÏZªª‰©UŠ|.ât˜¶f(\.fßášê¤ %Å^ÒîMu?iX¤w*®äDú’hŠ/¯Ú¡wíã  vÊÏ~ÿc‰KóÐÉRDèà<š­åô¶iõTÜô aê8$‹ÐÕ¢ ?±  –›ÊQ9ù\X%ÝþÈGì }—Ë«Pá¿áZçÈ’,=íÞT÷“†Ez§âJNIT±/‰&a£Ñ´Ý& &#Èò8D½†~Õ *æ¡“•T'“Ï£ÙŸÍÀç(ˆÊïÛ-Xc;‰š™¾Âv¡gCv"L¥™úŽ ¶ÚàXhèÌPŽùÜçŸÏ.‹ÂÏ›X¹28ËõÆZ+×’c8q„ Uß HÇà|9ü'~7HïT;1”S6²ÞUÛµ’°Ìšu–?òfÛ£7Ç “Ÿ•0yâÚÍ#iüo<†¾LåˆßåãÓH’¥C>¯•­;?›!Gå±DV}ò¢Í“‘ý O’vzÖ!}ñ9Ñ'c•k»ˆUz«,ë,÷œõ¼˜:ÛI’Cª¢SÐupp,|Tb¡ŸÌJC˜ xô‘ ¥Ÿ'ާpÖ¬½Q°Û8RìÏa–NmØ8¤n¡Ò»(dÓ»!;›`­ÄáM›¢¯¬Ú†Îò’Cg+Tá·¬ë©èVP—aßtÆ€bQŽJ«&ƒ0ú’FGÓÏÃïØ®ỹNd"§ªf‰¨½®Ã ‹L¼CÒ‘×ÚëFÖªlÇݵQÒíÐ]‘ û¤<­`We£,NS%'oîÒySYøä:>½î1§7RZN°Ÿ×1kvkw¥p%KÈÁ‡h.¾8šI\%OçX’ôQ•:ø¹ém‚¬ƒtÖì¬Î'íÞd= {Òý§Éí²ldd(ÚÐɱÁ¥¬®¾K¨åL º×²ékæX'½^Î÷%ΚmÎKÓÇCYÚô¦rÄ¢’'Ò*i¾*'E#ø¹™Ò[ÖAž5=N†˜Úwѳ7ÈI!n]õu:'É’A6Â1bÁ5T¿ÓE%Ow=º?Ϭ٠]Vd2¢8À,YbŸXTú*‡#Ò»}fŠhê Uz'ÉÉ‚KYÀÔ¶] û~ íÔÒ!%åéÓÉ1Å•`(K›Þ²<%ÈuòÜ'%Ü[òy˜ÿ†nçÑÉSû¦©§d“„:Me%e'ú»j‘åaÎ78<>¬±MéÔ§ï±G–%è ‡ÝMÌ()轋¹þà@1Ÿ*½mž›—²€©m»@ö7½²ÓÅ'Lê\·ªðßpçHk'çèOéÀ•,*G ËÓµýw7brÞ›qzSä4¾t;NŽ)º/©¦–¿Ó™¼*y ŽiˆPŒbm ÕGž5Û*‹‚⟾@øÏäeá¤4¢E îgÖ,¾7…÷§T¸xn"»ž>ÿÀÉ*«2„n‰PË’*>A¡ÕZ¥£à^UjòªÍ8?fâ†:åPÒdêô¡ˆcQÍQk(K›ÞBΜ9íñ *Ûié$WÅP LÐÇ~®Õ,åq/"M\Íšn}ÙJ’“"íÖu:ÛÈJCÈ™=;2óP¼#¦¥Oç¬Ù¶Ð{“¯‹’|LÒý'ƒÿ嬓–Þ&×ÒA¯)ZeYeQtvâÙßð[i§–I‡ÉÓ'Ow¢¯/* ÓÐå&S¨U K΀“ôÖÝ“#])‰z‹g°Î›Ëc›ÞE9$lu΋Î\tû®õ†á9¬…Cʃªˆ):½1ã:îA,¨kº h½)²¿©ÈNf&Csžyf²ÍÝ×l²Úài¸hsÓpbèî))Vã ú,¯¼’±Gq3·bt{Hx^L²ЙvÑæ”ÄsÏEE8ÀÚökµªûÏ:ú/ñ?1"ëÖ™ú;$:Ö4OÁEžfh«º§ë*7¹rl.ÐÝSѹŽ>K\C|ºÛŽÚuwBÓ,§3ínâÀ&Ë©œ«"G‡êÚáìôSêu¥qöìÙ`l¬ÕñvêÔ)¶`Án$o²Yè™ËÈùóçùÃz”—k7±iª^NG ̟ϰŒÞffãÇÇ[æ \r kà#/1¼ýËÆe (~þ XãàA,YÂ&vìÈ”3Ò[\‹îÏ…Y¯åª÷¯q»k{–|ÁW^j`&‡ðåيžï»ï¾ø¿ˆ{î¹'þÏ˜ä† ýÜ?7xA°;&Œ¡«<‰÷‚~õ«Ö÷+.º(`ÇKƒ]8B׃á€])®Ë½0Û^pÅ;EýýA8ã8ÒÞäþóê­º6Jtû³â:½Ó€¿™7o;yòdèoˆioÙ²%ÞÝb×®]læÌ™ñVu¹nëVvñ‘#a˜­Ù×ÇÞX¸ؼ9ÞkŽ©|*³ScBPÌÁ†io0Ó€)yÏ·…^/h4Ø´Ó§Y_äJ«¢ŸÁù /äÞ(`£$ÊN?×>|8þ±E‹ìßâÇ ¢GŽ\ÌkÃ}áȳ… ß`›7ˆ÷–Ct(‹õëW³Ó§§Ç[Œ ޱááÑRî_uí;÷Å[øHâŒp&¼| ð‰Ž¤Q}UåÌ™3lݺu-‡T÷’²…Á±n 9¿|ï{Ùàw¾Ã¦áUs Ì(€O%`vê,5÷¼ç'‘”Þm×ãÛä»l™[“.iÓ›·Žt­Å¢ÒÏ–¬ö·•dÚ:Qá*Oºjù˜RZY¢@Õ ÁýšÜ^½‹jé(3½å¯€¶#zÈJ™#5:0¾£@«wÞÑuYÏ׌:KÔ[¾žX,Ó¥(´é-“7ýa­7!ψ»¦KçnÒM½U£çš,™[ï´kI™é-û›Þœ\µÈ‘ky!d=?kOª|=^ {Iyí§aM¨>§õÄæ%oúW ›ÁHJ3úx®EÅõúë‹y„žhù$ ¼(zpCÚµ{•ÞtHEZº‘h:²žŸÕÉÊ×ÃD¤EZ¸œKo¹Å­ƒ²M¿¢d²Ž¸CÒ>ñB*шª3Šy„L²JR¥76z…ê;¤,¹CUh¹Îeˆš¤‘t=Zí^(e’t¢2P-Nr²ü8ô­(gÍ–«Y@¥ ×Séc‚œK{,š>9k5RÖ ÐûÑ•ÈÔAB ²ß›C¨SJrPò­“WåÂuÚ¬Ô!‡Îš­B‡$Jzd²Nºk'a+øèS‘w¥°••Tïrté­ÃVŸ4\Ê*”0pG¨\‚§YƒæYŽ˜QQ kõ6ÕÇä8Ý1t¿˜¢XPæÛƳfS™ò±iûtˆ€7æ/ÁùI íóáç`FŒ±´©ƒòèT}hYäH¸°oÚ—¤êO’o_lÛÜ •“6k6=Ž.ô‘É:鮄¤1¦ÂìÙòñ®ô¶²„ÉËY’ÊÉ3K¹­>iØÈraÛ¦Èþ†«×Nå’I'¶°Œ¤ÞE ËAÁ©xBZ½Mô&ÇéŽqy-AÚ±6rd¨Å‹yYäEÎ ü­#Í£ zå‘#áʾÓ’|똷#'¯îV:“P=k¶|ù±ä}9HãÁÁ1åñ®ô6²ÒŠœÎ)}²ÍRÞ­{seÛ&Èþ¦ú!;“þ –I Ér˜€Mû§LŽÓcq-^r„ÿ†ë¤ã@šLÓë© ¡:ØÁ¤L[\¥5p)«PB·D¨\ ITEàÒ媈ÀÄýËr²5gR Ôêm¢09NwŒ‰ À7ž5[–)fÊF"M°è®§ÇÓô!Ñ4Yü˜f\Ýoâ¼Îce}mtô£;hc ê,r$œÙ7'©•”të¶IÒ:>}Öl¹¶×NÂFÒßBèKO³¯x´yô6:¥9hÉÒ}F3“n6úè°‘åÒ¶uÈþ†'W;•sH& …Î%•„'TªÞɬw–´Sacñ8$\—/bKpFB6l;À¥P‡$;%—¸Ô¹LTz» gefaVÂäÛ÷uö{U2íDö7½1ì[„e0„DŽ1$!>+bülp5v5Kz>÷ÜäÌ“säÑAÅ[oÅÿÄÈÛ ë0ð©L·CP÷ß |À¬DØNG¼åÆ·"Ëf]öh·ÚŒ®‹é ‡äKvº™³ùµyÕ1üY7ĵȉy»‚x¥'KÔ%øº-Þ -$êQ¢8Z±"ûì€0k“în—”}½¼ô†CòtbZ5*;gS½ÆÆXðþ»à‚h‰¹sÝë€÷  »ÁkªXc»‚x'dG·ë ,ÈÈõ(Ìq‡‰W/º(˜4kW Sʾ^^¼CêUL«Feälê„è‡÷0íÀŒlßßýõÕ(îáZ\ï7¢© °Æv ðªÚÐÀ@]G®GÁŒ1 8&¿f]t@B®‡^}u±×swH½J•ªFÔ9ÂñÁ9®fööDx'Th`aÕªhF.“z=¯ˆ€Íj˜mãÉ'›3§˜àCô¦C2 W•IÙ:u»×—B#…ë…ÏLxÔTÙAU1‹ÙBïá£Õý¨îÎ'K`!ëy¦Ð¬†~­ñqÆNœˆŠ\È÷R%zÓ!™†«\ ²VeꊮŠÙ ;G2ã¸ø~U"¦éÛ#Ô¥•T¶9gAg:ôеøøãêûÉ{¯eš°J4@’÷^Ц7’m¸ŠX &'ÅWI1}Âe‡ÐŠ®ŠÙ ;G›Ç«žƒr¢+¬ªê ªNBg:´î EäûÉ{¯ø˜_Y&,²ZÒÄ$Un½élÃUÄrñ5R|"ÛÓ'\¥ZÙäqŽu(ùr *4ëÐJª¢9ËÎ:•é´OñÓB¾Ÿ¼÷úì³øêkô?ÕCWÉ‚ÈjÇŽE}[¢($U/†ºç\> YÞZ£5r]¸Šz˜Sí’C‡:?ã„ê «îMn%èt¨d©à¿_·u+˜?_}œ©®ä~nâg3&9È•N®ä .…ŽgUaEIsPTå´~ln?Íœmä¤!ä˜~ÆAvîp8Ôt0òŸê$Ò]€V…ê~è½â£ˆøH¢Í½]sMk>;aÂ8>÷íËßré¤ÒI´ú~OûÀ£“÷³¹çk ”6u_Ãv^ 1M æÁšNl•eŽ¢ËäT6¦rTSæy™ô¡ÊÂvøDEÒq®tr%ðsµ³}«ÒW¿›ê$Û•g!'ïô*ôRb‘/i2,GÌ®R_§3•¥:_&))må$Aå˜|ÆAžNHèÓÁÔ>röÈ¢§Í9"½1w Ž“‹¡§X°_EšÉü&ëdú…îÏóÙ dÃ/ÝNiI¶ž¤§¡BNYù<6²€xâ"7g•#ÐÝ›ÎÂ(†éÔÔ—´ßF`¨®dÙÈÁ=&åJ 9ZûÖ _ ¦§J~S’åÐEV_§³íãHJJ[9ItÊIÿŒƒí£¦ÿ±Ö™>0¹·V–JžÌV–ƒ…êKÁïI÷T:™þFéÜŸí³6Èþ¦{!»<ÁL¹_d•DàuåJóÏ8¤¡»7UÇA†éðß›br-ÕqIrltyž› —UJzSÒú¤\Þ›ùRø¤„®{Mº£rÂR ‹ú¶·Ÿ””®’‘ÊIûl† -Œ¨Ò)Kצɽµ²Tƒ9rq8¨Arè\xªkÂf?üa²É•N¦¿Qè~“ô.„Ð-Jk!e©žh• >[€6¹ø‚™, ?Ïø3ièîMWU¡èdÅœ;v,xmñâ ™t\’•.âXì“e%ÉÉ?wↂqþ,›hå"ôšEžNØŸTÝ´£µo 6*§µ’¨$ú?}„:mt8F•”¶r’hÉiøÀ/ƒn˜è0IqŒÊT)-YéÇ© ×@š.[e’Lǵg©Î–†©>ØGe‰–4E%Ëô7JkúgJ\"û~‹í”æò R‘4Ï@iz ë¶Þ¸¶\ª¨~+mß—kt¹ÒBíD‚:$•SR¡z„®uv””Z oŸ0OB¾ê¾iפÇçí‹‘ŠŽ¢ÒYP¦mËþ¦{!»<ˆ¶öà`ôœ€ª-[5D[Ó#¶">ɉQIÃd 9räÛºuk¸¶Bç(q¨uƒËî#S þ ³ÄiºL–aàe<Â2“rdd¿öO9€2îS¾¦\L»f+Ká䪘dÕ1Ú Ya=‰ÿØÇja²™©§Cè‚¢6ÄV€aÓ>]ȘGjÙp¤³fE9sÙÛôã(øÞ÷¾Ç:ÄxÍ&þEµtáøT¥ŠËtÕ íûòt`â J|„ÎQ™©ü sq?eܧ| è•vM‘¥0©*&Wµu ´[Óþ`:Z_ìeêíTµû¬ÄVÐàVp1oeôoØïpHRîqPÍûÁ~жVB-=Íñ¹LW ˜:è… Y0Ur\Fl[Iy¡Ê)”…l¦°iÓa¶|yÐq?i÷éêäk`š¡¤kº@.Pw­Qƒ>aàŽP‹>¤"‚µáà×$Ýå µØ‡µ®·–ó߇g&–×_=Þ#ÑÙÛïèvbqßݤömÓ—$'ãóÏa_ÆààX¸Ö%+ΑMÒ”¼°ÓL›™Ò:Ï=¸@؈xÉ4=ª¢w¶Ý}HE@Z/!2 µ*<TÕ¼[n‰^ãG5kl'ð0öäíItñnV‹¦­¸"©B:(°i%ÉÉxãŒíßß`§OO׺dÍÓhÏûe3Í:üØAàÁ ¶sÙ©Šƒ©‚wH‚Ø :BI; µKTŽêÇ?Ž*ˆklEa‰0]œƒ’Ãv:KÏ[’¸ ÈRÄÔÑT! HsPr2FñbP@#LÖ´äÐÕ]ÒÈûe3µ Ès.IšË.‰¤z«Œ©9׉ú:$×O#¶‚ñãÇÙÍ›“­ Kü‚;% Z8ô©O±C<ÂñÂëŸòí}ûöqC,~|_§|ˆýô§?ާË/~Á~G›déU¨RYŠ˜:ésļrÓ§G þwQ`˜¶’ädD6韄ɚ–ººKy¡iLÁèÒÕ¼ £Ló܃KTsÙ¹ÀÔœkE¸#t¥)Kй @k¦øiÞ ¹ ¼qµÂeé¬YásQ-F#u›.ËðV_¥ié-Ò²ˆ—[:;'âé ³œ"^‘‹BL&Lú’ädlõ!ìC2M[’¡øÝ6›èÒ|þóŸç÷À‚/|á ñ/ÝGè­šË./A_gtùüLÒÛ²¿á·ÑއÄS /<Ž™Îx€§”Tà\lËVl››’äHh†JÖšLIšNb_lÅÿÿ—¿  ~ á\l8)œ¿cÇŽø Pjá­?”¤Xc;+i÷FÈ”ÞYÀy¸'žá’öœÄ5“J¾fߨ” ,¶†PCuëÔ!é’¦%§ý |üfk¶i:鯇Ça"'ÍF„>ýýWs¹,xÿûÆ{ìÉso”–œ|3¤éƒmaWXeñ[6÷f’ÞyÓHÐáΞ=nˆåرcáo¾ùf¨P–™´¿}Ù³›Üò0µêX,òÄ á&ö…²b+ÆÛi¿'-¦Ç¿óÎ;áÃÀZµ_%'Mÿ´ÅT'±<ùä“ÁÅ\ö@J HµôsÙ—\rIx¾J®XlõI[LeeIoÕqº%”ca“i‹N'´@‹fh-ÍðwzœnÁñ­Ù Úϧ ‹¼Ÿ.Tf¸é¦ñðw”؇QlXc[>W^¨¬´kªЭôˆÒÄDNšà¼¾¾ã\NËÞ_y啎ãL–<÷F*‡¦·í’¦œ–Ó¦5SŸŸÍ½éÒÛTŽÉ?ƒg&RƼeËþ[;»víb3gÎŒ·ìÀ÷m¦Ÿ>oñ«ñå—‹G}3 ð"*ÞýÁûá†AâXY¯•²};w†_uŇô†FFØèð0;¼iŠê$IŽ-*9¸~’þidÑéW¿úû‹¿ø 6Âï ¼eù~ögÆæÌ™ÿªÆU"Ó»›r€NÖúõ«ÃÑl-ö¼ÉþäO~ʆ†ÆâßôÈrÇØÎûâ-Æ>ÿÇØ–-_ìØ/Ðɱ!,|c“6›èº†íÆ3Ár²êéó÷ü¿ÏD?pî¼óNv#†Zâ*’䌎Î`>¸(œu/úâݪ4{å\pÁ»âŠÑð|ÔIß~{Z˜–˜3Bà%Ü$о·¬œ9s†­[·Žq‡Äfa¢€ÂZH\4¹¤¶ø5Ãsø1am“Ô\uµQÓÅTNZí‹RNŠþi‹R–â8yyûí·þùi­ZaÒ‚ãp¼J޼dÕGµ˜Êʔފãt‹+9Xt²\Õ"uräVRÒu¨œ<5v,:ÒÚ"›7¯Éu1““f#8±ßçK8b#h4‚ßû½ßë8ÎdÉsot¡rhzÛÊ—GšµäFÛ¦­[›këÒÛTŽÉ"·¸Øv°ƒ‰×^ C"“N ™7-À™†ZòÂ>WÐÒP k%®ô8ƒÐá€E5upèÄE(N8Õ‚ýV¼®ïÍ@ViéíJàç %Í o{)q¼—×ÉAuHI]~-9ùgqÖédŠØÆ×¿þõà™gž ~úÓŸ¶-?|Ûyû€^Ó<Øq,„ó’p}osæ4¹.gƒ¡¡f¸=4‡bÁuÒõÁÇ lΧØÜ[Zž´‘c‚ìoømµãÄ!qÐJ0úBR.Dê£×OÑÅ¢- U$Ý‹ 8>®mÛ8Ž:quËÂ…Ù;yË SzW—zg4Éó¨SJ£Îiý¾÷½¯Ã¶Åb3Ê´¿Y˜ne'h= …Ä/>'gªçlZ|ˆç-Ÿïš2íDö7އôîw‡ý(x¯Gù2AÒLbp=fÄ‹££ÕdŸç…€ ï¼¼þúëì¹çž‹·"ÐWD×¼—ñË_þ2Þr„ëwÀ¦8Ï<Ón0 ¨éLßSrùË0‡}ìcáKß´ßIÀ˱ø¿y;ç ðôº­”âið£5XÔ_='Lj¯z/ÊtR–ª¼WU$Ý{16i&U.Ãv7^Ò4%Ï‹”Þ"”§Â, ³gÏfŸþô§Ãµ˜µA œJ(O)’Ç{:WÛ—DÓ¦ƒ ¶¸|„e˜ÃM¼~ì±Çx…kß‚c² |1_žäËí¥'H|eF€z"ž—ê…ߤ¢P&Ë Ãu£{) Z@ °íò}×äy5=CµgïÞ½¼Ðê›l }ò“ŸdGå5«[Â5¶öã8ßAžRDç€Mœ]|L¡Ÿû¨ ããñ?1˜æÇ¤Ž@M‡bÒJÊS‡’q)+k¯½–ýöo#2ðA¾˜]È#È8ï:üPJq‚4¡­94îz±Eãšî9¤|$þ'Fl‹\†€àCóª,Ô&^™Ð’ÁЩt ‡îQL Ôäí´†¾ýío³ï~÷»ì’K. ‡Âÿúí·³ïþó?³o_}5›=kVx’˜Zh’"[u&Î.>&×ç>ªf¹Ž—“"9LÁ¤Ž@kÌiNH$ÓüùáÐklç©Cɸ”¥ãïÿþ×ÙŠO°éÓ×Å¿¤ó»¿û‡üøæÅÉüÄâDE^ÓŠÒ$ÊÓX§}X/©(œ’„=Igƒtc¢'/Ëp{÷ÊìÐ Iºú;ŒÂã¿zùåp Â§>õ©¶ÏL@ßp ‘õú7†Ç-Z´(8uêT|dLÒuM Ï#±ÐYy8öÉà7rL8øÅ–<÷—v"’oÛ“$±Eèà:À&:ÙÑÙž'ûɸ”¥B•Ö…Œ2%Ð4ËbZH¤3ª)‰¢ÓOF\/i…KÛÖ!ûžÜí”æò fÖ97…ÌzëžrI÷"ÿŽ%μ•C€¾cƒƒíÇDzTÇOê›7à\9çb8ÕÛ2伉¾¾hø´-Ú×öä§É–¥*‡$'S£ CÎúÈËF•ÖE2•‡h£Že‹kq…*ËRÊÔ[ö7ÕëCJ‚¶¡Ñë[`Œ¡¯þ5kìÚë&a*Iñú» ­Éƒ'†‡Q-Œ6ˆ,åñ®zHU¡?¹SDì§ÄaNîD²î£ÌXQÁÀ\`:„–²D~)"Œ×nJ¨„6¬L´j¸eš– ôTY¨®”Õç—…ú8$ZàcAŽ…%eí³IS5öï·s.YŸr\0wÜ‹ø}Ú4ä²è7M¡‹é“‚åËݦKZ®*§@;E°¾öÚèJìs}î#)íj̨¿fIU_’H¦èõœÈ–ªVÙ4Êt3·#ãQ¦Z¤ÈÙ\de}6.HËVº,——J×ãÂv¡´™†¸ÒÂ3¶²’àç…ÓÂÐëÈ×J×¥í`Ä_òê gàvžÞâxô]‰Î Üú‹¨èƒ5 ý‰suá@þ;Ò¡FÕŒƈë9xþ¦r´é­A¾’5-Œ’¤šêw¶£¡;ùEMÓkØâ^Nû Ÿþô§ù}ôM¾KûS±Æ6~Ç~÷ðJð?ÒB,4›ãÕó°¹·4ÁóÙ kl ’®„©Nâ81çÖôø–œü3z˜"û~Ëí”æpç6©žv¼­¬$øy“s”A–<ñ4aÕxÚñÌÒ©ç·, Z Ë àwzo²CˆÏ)4½ée#' ~..³,ª«,Ç$ir$´é­A¾”x¬I>$Û@fZ'|Þ ¨&óç€ÔÜ[¹2[‡¿©>&ýNE_ÝÇ€Ý9* ‡9i}cô(°UA–´¦ðk„éÌ ×Ye¥¥·Mß^šÇØ\ }Ôð¿8>IŽéB”$Y"{ЙÒ’ÒU2R9øÄÂ’%dœ|÷. ìÇqÏrE¯½v°C§´"% Û{Ã''Ö¬éïèJ{÷ȶkÔT'Ýqªô.Ð-Jk!ÙVOÄñpãòñ¶²d¤ªÂuNú4tú`Ÿ¨ !ħêw¿ý&R}2Jo¹Z–T•ôTÕ9“´Æ>Ä¢p<üOçÿ#“fÍ6ç ]e°mZÝL“#¡Mo ºK‰ý0<~q X°-ŽO“#·’t:'É’kÎXÒ’2M'Zrê;K9ôn}®!:¸Ò˜ÊÒ×Ú?ûlAJÑ‚%¡/%D6ú2ð‚©3½Ó BK¬ñ»@.A•Þõ rŸ×H#ÏyrˆO:×¹ÈÐ4Æ:ŠÖªŠ$—ÜŠ)6) ª 'ÌONJ‘Ì.²#6Œ¥PI ï=AßÁÁ±Éç†ÅæÙu‹¬v’ÙßÔgØ·zyüqÆyÄnhv¤ŒaÓ>m…nœfÒ~3Cq˜Z ·µ1‰&Π|/Ã6 ÈzžYX¦LCŒ®@ú@_Ä' ìD~>„š;EjIƒ†îî»ï¾ø?;èãGûرNÓa=ÙQ@mwíÚµñåáâžðeXîÌÃÿmŸÝT¤> …2-\QЉ—sótÄ1LìÙ“ú)t%:Ë5±ì´7ñ²:„˜ÉŒM`Š3ë ëyò3ÝÈ‘&é_1ÚãùÑ´Ž¿1&õ¦¤ÇoÓU§öÚV‘ê.î Ÿ)_¾<(üÙõ õqHx’r¡-èvÕCg¹&–-ö è›xoýÆÿEt%ƒã™ÝpCôr/–o,/GÒÒõ‡?Ô§Å@2‰:ÈŠŒ=j_ÐVÒáÇãÿ:Éã·åF|Ö쨲ÓsçαݻwÇ[åá➆†ÆØž=™ŸPU’*u§> O¡*j!eTMÐY®‰ec6z Îɉì”JÏìG?B‰-ø?KŽÌ-]éTFIé_1L–uc’BwyZÔª²£®MjÙØ°ëBZwOe!Wð¿+¯dlß¾è7ô\Ô ÑoDu’ʺd ÉSmt‰ÎrM,;釹¬ aÂé…ébDéŠB -´´ôïqL†›Ô›’ÌQç@“Z_iŽÈ¶B•t¬Y)°A®(à~ÐI€`J ýFT×!©¬«*"£Ó+i?Íݸ?”ò19sY%Bwe"Ò‹Þ7JWƒ S 8(Ù±$Õ‰(YÍQÕúråˆyZx”$§Û-hEý‰òÜÅ ~#ªëdë¶°’~4Zªb1Y1ÉÝrYÖ ^KhzzS´U$sÏ=÷ÄÿEȦ—To¢d5GZ¨ò‡ÂÞzKíŒò`ÒÂ3!«Ó- ZQÀwKådBÏE¯˜wu’l]¨+yì±hØwU,&+&¹ÛU.#ôt+IN¯¬³mL>ÿù(Œ—ձؘ£(TáŒdò´Š(´àÎSÉât‹lUÑŠ‚<ë8"Ñè¹èó®®C’­‹¾§„Û䦪¡Êݲeß¿“\&gøžuJ®J¥eÑ¢Eñ-²8Ûä?¿Áöísß*¢˜´ðLÈâtËjUɺ¥}½ŽT×! ëzá…hûw¢ð‹@üoj1®ª0.«Bp6ø®îklË–}÷Ýú\ÆuÀW¯_}X0A'mæwyo®dÙÊI*•\éS"yT¦çŠ÷üùlëÖëâ#"î½÷‹™ü¶QU~^{-`«VEïçäyyÒHFÈ:p ÊŽ™¦ÜªÂ›"½]Þ[Ö JV%á…T•›:svÐ9TÄœhXl¦ƒ¡r°Æ¶­Þ†rŒPÉ’§ 2™k„Ÿgú<[º´¡Ò'+†²´éç bÁv\ÞG«·ò¨LÏ¥³7‰Ï Ð)…l°ÑI¶5±9iiMå`QMkdŠN2ô\UzgÊLšêÒ›{+öõ›:H5+zŸ‹¨ûÏÚ+ãJPÉÊ/àr±œp¢æñmµ×¢ï- ãJ‘·Mqyo%‘Gez.}äÍf;x°½Åb33¸‰N°)U«¶'ìÏÕã rf$Ï2“uB+Ç´EA[.ôý}Uz›BõAߊ;NðþÞE²ÁUzMõ’ImÀÍRЫp%¨dei“s9¼Úþ®5:ÉNi÷&b§OÇ?p²Êʃ£¸úêü÷V2y=—úñY'DÑé¤sD¦¨AÖW–…nkÓ>!)¦ïïçùŒƒêÞ¶õ2Wé]8ÜPÚ¨\ÈmS´/ÓÂs&a.*G„üí_­Þ&úˆctíkY&ðól?ã€gL—úà<»ÐÄP´éç$b X›†ì¨Xã¼¼÷FÐêí€<ƒž+Ì]þ¬ ÛaÁñYMV¶'±$‘$GEZZ 903a&ºTT'ȃ,±à7SZrò}ÆêCÀX ŸØoÆ£²tÇ–aÛÙßð[k§rɤ0-|°FÊñNô¶ÕØX—‚,zÓ‚Ë$ytÁ9%MNÖê-tQ²šèe©‡-YÒ»Û¨t¦ÉÖd²µÙ’LÒÚÖLÄñIÇà·¬é!0ÑÛÜ\/s¡£ —zëýMõCv&؆¹Š¨ÚÊGx)ÏäTü|“Qv2üùÇÿI˜„@“p ±3{≖^H3’ÃË5Ñuú^L˜&§lRØNë+*›43Q™¯ÎijD΋ä[ߊ^©ƒ>Xc».ýB6ô†CJê›DÑU[ùÈ Ð]`;9?¿±?›~út¸Væ@& —¬–ŽRjl óè½ë¯w›“e½f¢DÁLâ´„U*Q*Šª/ &KßC— lØ Þ+’á5tÆ[m ë4ÇV&æ«;F.R@Ù÷AQqµé² qöìÙ` …HÌ©S§Ø‚ ø¿ÉfaD[FΟ?Ï ùQ^ÜÄË&^8U nMý6°ÆÁƒ,X²„MìØ1éÄœè"_ÅÀüù¬œ¶ay5ßf2¡ã|žkÆ·ôLŸ>=þ/b‚_Ž #önéøh¡‰.hÙžg“Þmòù6-ÔÖIÍÜ6 l©´}'¦3üÀÍì™glt´•Â]°ãÇÇ;l%"àò‚°51Ñà…c~Ÿ]X³¦ŸíßßèøÝÛ´6¹¦­^Yî£hSܰ¡?Ň;vL¤3Æ”iÛð7óæÍc'Ož ýM±ã-[¶Ä»[ìÚµ‹Íœ93ÞòÉu[·²‹f}¼@E‘Úä…ù?ÿÕ_±Óï}ot@ 3FGÙ›6±éüÁ¢øhò‚ùE‹ØÍ›£ ¡_ä|ˆ·&=ø a£ÃÃátM>Zˆ!Zi‚±ÁA¶oçÎxK ôǵæðkÐ\K ½x5Mã×Bš5yuþü…²io¿Íúx©ˆí7.´Nƒ© ýNfsÀ GŽ\ÌL_8R¬ÙŒ«âá~4®'&Z—ÁÁ1¶sç>¶~ýjvútˉ‰ß‹dtt{ðÁElddˆ †ÉÃw‰(&ÇPT÷ñ×ýX,cûß8þþ¯ÿ:;üJ¬Nž'âÌ™3lݺu-‡4%[H)”¢·hA=û, x;{â¿ÿw6€¯°ñ4‡S±j•ðó?‡æÌaã?ûYj‹L…\ó=‡ïQ„Îø´:^´gÁµ×¶µþ²´ú>þqÖøáCGêÏkKã(uú }{á× ¿·„{Àµ?ô!m«4/u´oδ•´aÃ=“µï·ÞêŒì;v®­vŽ"äÉ';[Ýh!ê>€ø­ÑÀ1üÒÚÿÝïžõe ¹…„È6äQY)s¤†KJÑ[5ì#ÉF’}“P’¦w¦é¢CutPͺø­tx%Šo!• 7ªXr­U.©µV³@Z5/$ÄÇ7ù2±tiò±àÙÓeÈRµÄ"tµäܱcÁÙY³BÝ•rÅ"ª¦rº©~+ªÙ·\[W=èŠ5ûû›‰É%?±d%ÍtM1Ñ›B¯™”¥\ ®™âÝ'a¦ØW51¥L½eÓaiµtHÂ2Þáa6ðã1ÓÁ˜ÅŒJ„>I¹Pì§Ö ð¿\¸bîIä(1Ë¢¸×Ù³Ãu“ßók‹7ÜÐ)èt"ЂKˆ8וs9®]lK~ôà÷ÔÄÛ~ B*_èNGúáZ( p.üozý”jß)ˆÇ‚[/NÒÇN®ƒƒcIäg.–,ð¸`âq&é•DKN“Ÿ;Ê‹Ð[Î×i"þG:aV¡÷¦““f#6rt¸”Ê´íÞtHx ÂÅbký€o:kv*T9²¨£ÂšÞ—já×€EzwôɈœk©Sb¡¤Ò¹ŽÿÛÜ/?®­e„CT5E ;0Ðr2I÷ô{”jß)Ð[Ç’VàBWUKƒ>k±Ð¾$[dè’æH€xÌ™ ³b¬ÉÍÁ¬…$g¤ ±ÇDè½éä¤Ùˆ.e2m[ö7½Ñ‡¤êßÈÒŸÀ儳esÂuÖþˆ¬ýª@5déà×À;O}2“mÌÎÑ×Òö6¾JÌB‰—P€l¤wüoòFâU{È‹òX´´Hz}>ǽÕzë•Òúj0#À„¦úhOôx Y'Ì誫âhŸ²0+~v8¸“>zU—"_Åd§ƒƒÑ6Èc"²©=ü°]Ÿ–À¥Éö’ù÷†C¢( …±)\¯b„ÿ†ë¬=“rŽÈÓà Yxm^€a˜B¶€oã\wVÚ–:ñÊJüŸäPPÊàZ¦²i)Âï«í*…s“r˜Êa—é]3loïÆ`Øõ[ou:"^³æ2:Ÿ»íÌàT'J’IQ’œÞuúèGƒ¶GŸ4`AUoqe"ò½áž² –pi².eu°D¨eÈN´óÅPá¬ÁT~'—B’#Ú½{w¼e†‹VRÑdu* -˜‘G®'Þ!eA’ËãThó »9Â(tçsp×Ije ½Ê°ŠJ—*óL f˜ÊÍ‚Ï*j¼CÊBšò`¹8-#8•¬­€"sD´¡»Šé;ÕHrDYÀ#üÒ—ÒP· WÓ¹Ê<Ó‚y"ï:pm|ºàCÑøø±wJÞ!e#ÍŠUVŸ•"s„: ÀŠëÛ«¸nQÄ#ݲ¥å”h+ …(ýú~7ê!¦r•y¦3ð|‘¬Xë^굺´^ú"e§[ñ) iVì²P®ø‡Túv»úÜä9"gdòhè#¥À)áx¢(LyM> iÙ‘"›' ôG–…©â<9˜!’Q•œyLºÈøú›wHÙHë˜wéDLsZÉЮ­@Té‹ïªÅè™$#˜<úHÿçÿl݉Â\¦ìzHZv¤Èæ Òîÿ¹çâb0«Å$ý’€.óæÅœ¤¢¢Ìt¬SÇ!¹z²:9ªB9 ,ÓœÆÏÃ×Zñ q¬;䘢Ó'É‘ê‹ûFÅd_6-FY‡£G3éÔ«¤µŠ’I:þ@øir‘„iyqÎûÞǦIDxédô•îI®½ö‹aX‹Îl…BV<ú´ÂZ~ÌY«9;ÁáÐûGzPY¸·´ºeRú äô¦@˜öªUÑõTEÎëv8´t¸!·Ñ³35¾Ö­ÕÛPŽ®dñóº1K9ìD,PYbQÈìHoY‡<ß/(­MïÄtW@“´¯o"X¹r¢ãw9ié>±ˆérèì ˜í ÇÊ“jè¦õI»¶LZZÛÈ‘‘Ï•M-éÞIצ¿Óô¶r ƒ.r:A™¶=ugjH«ÚàJp¨“õ,媪e}:jíTÀ~]‹È:¼õVfz…,­" MÒf³·x"YxIyùñÕ宿þ‹ÊF¼.r­35jžøR,¾«B'' ùþ1i=•…êÞIé—”Þ¶@ŽLž€:0u’«¾—}DuâU²ðßpm"GS¡ú€S§ZÎJ\ ¶šò½­\©ÎÕ2òyÈít»×s$!Í™:#@“´Ñhò%JV_¤½7ÌR¾d‰ù³¢@Ž*ÚÓpÃn£gCvªYhõÆyòl× ²´꤅Ÿg=K¹*¦"ôÁ}‰ø E${Ë$†÷Ö–Þ8FN[›™ÄKDk'9¡iÚ‘¶–´E3˜5ë,¤ú݉sè¤òx$8 Ûa¡ç˜Ì)ÜÒI}¬lžƒƒgôƱ4L¦ «Ù ÓÉ”–õ,妸ÒÇ–¢m›"ûþXÛéY‡dˆ‘Þ°š+°Ýe¬Ó;ít´ÐÄbC›ÞL×$¬ÓÛ9-Åâèšô säÇ#;$Õã…ª‰“¢´ËŠ vèoiš]¥()š2õ–ýÍÔ ÙÙ¢êcä \W…ûïglΜ(ƒ5¶ºxŠ·£ø¿ˆ¶0SZ:ÊôBºæÀExNÇðð þH#y&a)І£à½$ÕãSE†M ×Ânñ¥[`išžšáRý6$礴\aSw“»ïfìĉ¨¢‰5¶ô‹‚×ø:íõ×® M›iŠ–6i}E®¡Ÿ0Wõí¤!÷™ÈóÚ©_Ö:½¾p‹/ÝÙ)Úèï©>Þ!%Ð@ÎIÊIi¹"k•°l’J èûÄŒ?½|2cF«·Ö‚ÉÖ¦Dš‚¥M­"Šø„¹j C^ð^’üø\×1d§èRÿ"Àè@ŒDšT¹~Z¼CJ @ÎIÊIi¹¢*a']K-©¤È¡¿\ˆ†…­M‰T·Ò&e¶ŠŠDn%Éo*Õ1TY£1J°êõÓªàRá‡ã䜤+äAZlr¾+t-µ¤’"g•¶£@J%’iލnÎH…ì TuŒ2³A™ÈYnÆ~622‡×ë¢çÝÍúi]ð) UNÒò ­69ߺ–Žêþ€cÒ˜?_})H¯:"Ù é(3”‰œåðBlžA$Sïl0 g%ô ˆp^\Ýàÿu[·FÛXèuøß4'¤éoˆ\Àª â©DZ«¨Ñ9¨"²Aƒ x!6Ï ’©ˆwH6ä gå>_E\ÝlðêæÅGŽD£ñFÎ æÎ-='ôjakK/‡ç(*'”š+"T9¸°cG4:°¨A$½ˆwH6˜„³’r!09ßRÝìk6YS3Ó*(@á×åœ0ÕZIS­U>÷¹–S‚ƒºåuh®ˆl “– ‹ÂApaÊã…[mêgL,ŽÈåog±X]Î"ÕÍf_ –,QWAurL±#¾4?×Ég3*Dš#ªº3²x´Jä¾ L¼ª Í™f¡OÚg’ Ùk8Ç<÷&È›FWrzÆÙ³gƒ1¼sêÔ)¶`Án,o²Y³fÅ¿ÚsþüynòÐMl^°¬(û÷‡3f¼ –/g{öÄ{Í@_ÂgAÁÊ•ÖrZ¸%#L‡–Ñ/ßû^6øï„é-~ƒƒÂˆÁp;ç½,i4}úôø?ÆÎ;ÿç&½»…ʾé} èýv]žÄû2¢ŒQaèˆGßÂM¦ÀqüêW vï½­–Ò–-÷ò¿ÙäQ}0IéÇ>°ü€|÷;¡‹`Ú´ |­.ë½ lÒ(-½ó¦u‘”YvÃßÌ›7o1668ÈöíÜo™—:ij`‹,ri:Íe‹|Ía'†‡ÙáM›ØØÐP¸OÆÅ½,rÖ®]ÿ±{÷îpíJ§n#ߟ@Üg]X¿~5;}ºåTÇØÎ¼•oZ1GŽ\̾ð…­ñ/pJ‹ÿ2ìà3.¤—IñþΡC—ð­VN²ÑGè‚Ï?À™¡Ñ:1Ñ ÙÞ› o \É©;gΜaëÖ­k9$ßBjÑVcÇÈ4 àÕ*¼$¾—dbX´(ŒG +ANÀÓ ˆ’¼ï—W_ÍŸ|R™Þ®Z#YåÈ­´\éÔ „}«œQ•ZE”¢ZH7á›gži°8Æî¹§UÉ=p`sæ–Qc°o! 0ô£ÝPÄ=ùdþ‰o!¹En!!®Ý†<ûjV0Slífº}­õ‡fž/•ºœ7>M–4õ1ôNLï49bŸÉ”Ì9äÀ®ÄÂ÷[6£"Ð{¡K•ÑåIñøLÍV/­Ÿ„ 3‹ÙÀM‘gôn4ò}ÆØÞ[*9â7ÙìÓÒ[%§*èìÄ%²¿éÈASÚ!q„ÞM9WÀrª,9všøtùk‹gKo"ÇÚùR4rhÁÔÑNäû÷Ru\§5}ÜtAVAK’\àŠYUw‘ÍŸ¯²ÈúbÔѶA™zËþƲK u.»ª@ÆÏ"Ü…>¤L¸zSQ#‡Û[ü_„j4Z•IA7‘ß."«È#î¾úÕö÷”äQpôxyX8Þç©2®²ÇûND9—]Õ ãgÑ÷’4 A‹«7 äÔ±ðNrD¼YÙþ¢2  »AdÒiŸ:O+ÄM‡…WWÙÇãR2uËy«¤Yo9ª¡ÒU"©E4•‘€>îU«;v¬•UdgèleâØPÆ»>®²Ç;¤ò(+wdÁ•ó5”#·’’†MwžÓ“ö¸E!ý•¯¨[IeâiaA—š½ÇïÊ¢¬ÜÑ 28Û*ìIŽÈ;£Ö£Æ_}ý^õÈi!M­¤2 qß·S?¼Cr…®PîåÜáÀÙV!tç[EzÄ£ÆÜ½p&xçH÷Èå‰WË ø¾úá’+t…r/玌ÎV.èUΠ Ò‘wFíÐG-°­_ýñ1k½Å ß·S?¼Cr…®PîåÜ‘ÃÙv{p€wDv¨+$cZ‹Gn%Ù:±,ø¾úá’-I¡9]¡¬ÊI²láçaÌ ‡u9™ôQ9ÛŒ²Êj%¥µŠ<ÉÜÔo„¤£É‡À€M‹°â|¦ŸÉdU¸’%äd™¥|ÊÃ3`~¦ÞI¯e‹WÏmæI’e ?35@N¸Î!lj>ÀP–HoØ]ŠD¾V–ëÕѾ]èL«¼è&3A– ³7ôõEçéL-MoC33•,*§¯o"œi¢N¸°SüL yI ÍÑZ¨.êªZ®:p9˜ „ërœè,eqãÿ+ß*Ê}¬“H-² Ý}á ÑÿyL­‹&›•ƒÙÆ1Á«Ç ïl1é/Ñ p¸èÀåð*Yøo¸¶‘Cã˜á È£Èyo®CwIŽÈ;#;èc…©Ì›™NÖnQ„îò˜š‹,$²ùJ&Y*9˜¥³{ÌðÉU‰ŒiUËD– ü<Ìe‡ï am%‡:OŒåÅ &yõîMv.œ’o¹…>Ö+;zÔ~Ѐ<ÀÁÄ<ð$|²×¥A‡ fÖÈçÏÃ^Ú§@²¡SNÀ.|£òsñU ïlQ N1­¶™È2Ÿ‡¹ìðq»ð{B6rdçùÖ[‘¾ÈYõïÍ¥£ð­"÷d|¬©\{íµrðÁ>|?H:¸Ð‡f˜>Ë#dÑu„*Tr6o>à$¦ Þ!AZµÍÆÂË€:O€œ”f¬ ²3òލZÈ­$##sxa=Ó´ CÒê4€ Ë²ª³Ç;¤"H«¶ÙXxçI p×9Þá<ò8z®wDÕGç †‡OðB>z޲ÓÈKZýÑ4úd9>TgwHecjáeµ¤„ó\¹2¹šXSò:5O±Ø´’6m:~æ[å4ò’VD«GŒó¨·%eÅ493¼C*Óþ¥¬-©¬Ž,­šèñ”@šƒc{öL”^Ø#`œã~ºÔèe¼C*Ó‚ß&V@èß°!›#óÕ;O Èõ¥Ï}ή/©l šÍxƒc‘=ð©lL ~Ó–”D¹%ƒ#óxÊ@×ð·ì`JÖÀȘ=ð©ªd ¡È-®rOž\ìñ(P5üMPsÔ9Â42fEO¼Cª*&-)’C1©êŒÑQ6±c‡»Ü“'{< LZIjÆþÌæ˜1bÔðäÇ;¤:CFcÿ~¶èÁÝæž<¹ØãQÔÚ0i%=ûl#³9ú°[=ð©\†ºÒd‡IUßzñ¹ðË«bº±,{àåN9ßúÏlö/{€ñ½j®¾ºõ~Öï{cý(>ï-ø?åÞ^~`Y›©×ê ±;BÝîàÿeàÐß°ßFzÝWÎkÕÙÔ0½ØF NHW_‚ƒrÄg®º*ÈìTèg3°Æ¶ù>°­úÍãïŠÀe¨+Mq_¿=gFø¿IÎË_~<Þ¡A¼ÇƒõK/1ö8?“uayì±|÷VsŽÇkO;²ÉÞxckûá‡[°@]˜Ë­¤–œ;räâð·¬Ñè»ïކlÃŒ±Æ¶ù>°­úÍãïŠÀe¨K'‹:Œ˜¥ÛFøfk¶ƒ§î¼¼CÎåÿz†=…ýOÝÉø^5Ï=ÿ#r4%åÞ.¿ó©H‡‘mliü[/ñë‹ÿˆýó¹séi8‘MÓ#Šm˜ê2&…9æ¸çá3Ï?ßȶɒ¢ç)Ÿã2k{:ñ©\¬Ód‡vÒ…'Æ¢ ±„–plƒ—ê0ÚËìeQhéÿç¶ŒÿÏ—†xÕ4n‘uÈá˲ew°‡Ç䢰×E„ÿø5xàŽ(ÜØXƼ<ù{¬Ï÷öPÛ17³íñžü˜;–uÈ¡÷]»vm"U†ì²] Ë5éÉ&‹Ø$ær+Iœ—÷36YR´‚hÝKœã2k{ðlþ‹±ôÎòõØ$Òd‘OSâK±.» |vò²q/?6–3rÁ@ûþ¥Û‚‘HZÌH°m)ÙO—…ŒÜxcL›Œô+öcéÇÙð’rŸ.½G¶-U_'^xk0ý8rͽûÃec€$J½÷Éc×RÜ—þZÉDŽϫœØ¶²É>ÿ|´æfÃï/Zt_d¥_–½è¢f°xñkÁ±cÙõNËF2sç¶ô˼yÑ96rÊJo×”©·ÿblØŽtKë)•eqìo]}ø?¾ƒôÂõ¿íW˹üíó<{†Ñ–nc{G¢c7bûÈ 6ò£áó®ìòñ(8¹ˆcž~‘`í˜0 ÉKð{ÙH¬ÿÓ/âj±ûïzš¯—2îŸb}öÆúüûš//?À¾6QÈ1A|Œà¡ûY(†ÿÞ7•ÃÛ7»ãäG(’gV¶û«·³G?µcr-ÊÒlÛÞÆZxì×øã­3²É^ye´>vŒ±U«ìû€þÛÛâì3RˆläE¾—³ñó ]j©l\Ý7¸|5[{’£?ï Ì)1¼Ö꯰m¹[}z;»ëæa6 ½’4¼Lݰ)ÌM†Û`“Åà(ñ%\&Wõ¡¹rð© È=¥Ï<“ÜbúñãbÃÒrWÞŠ[nó>ÿðoñú!v/ðïÚ~%ûý¸ Z,]aÒ9щXžjw G»FÏ—ÔNtûîVŸw¼»ãƒ®üM'“Ð^ërvç×ÄÀ¶W8§áÞnËáÇãÿ²a3ŽCÕEk_ƵÑçÉNߨØ;uêTÛΟ?Ÿ{q%§ì¥l½›¼úÄ=¥X‡K\úù™ÏL«Š8±¤…$–¥Å^¹Ë?Á¢Cîb7‡û†ÙÍQ|Žë¼ü.öå0·Ý,·´>üev×r\7JÃpPÃç¾Îþ7öÉihr-¾L¦Ox~Ìöø˜_Á~#>ÆõT¿Wq¹çž{B}ªcÄòÊ+ç¹ir„klÓý×\Ód­ï)lɒ蘤sæÎ=Ͼÿýóìøñhm*Ïtªß«¾”©7¥NÃ-[¶Ä›-víÚÅfΜoyŠSþ`–…!^KåÓœù6ýw⽌ †Ÿ'K¿ð6ïùçÃnYì—‹³›7³ã{þ”}îëÿ®¸ý«ì/רú“޳=ú9ÆQp»ý«ÉÖüº8æ öÿ^ð*û“w"gt_¶³¶y÷wØbþÿñCöm}„E¢®à×ü{ï¿Îù—ü˜? 9ô7k?DAëÑ=±H·ãÃÖr+6ïf´øû›µ[Ù#+6³ÝjÄíùûö×…N1WÜξú—kX˜Çù9Ûø9áW°·š-8¶•}ý¢?fÏ÷¾ÍRø½­ø4»‹_#JQ“4äÿ\«3}p­°Oj [œÒ8•[F‹-Šÿk/Îâ]% Lj¼… ßû££3ÂÏ Œ ñÊÓhø}%l§ã)ž3gΰuëÖ±“'O²Y³f±ÆÙ³g´’h!-X°€½ùæ›áYç{”×®oºé&6mÚ´ø×êS½1/¦Âì akiùò°(äõ×Yÿúõ¬ñÔSáf°l›àÎêüܹÎõNÕÃÞNÊ£®i}ß}÷Åÿ±ŽV“³9àZZ=LJÿ#âyð0õÐ5×á—\–K;ÇÞ¶õÀßÌ›7oÒ!!~݆< /+~ÈcLÆ–Šc0F•¯Ï;æ^o›1®ñvRUÔY2c¥‰Ñ!àXTàÜø ˆpmAÒ>ú; KÇo®Ì¼Ž6ÊÔ[ö7~PC1Ž$  ?Ìç=<ž ˆ70fDHý–Ô*¢`ЯЇƒ°¦ƒ’4ˆsÐhð†o$êà)ïêÊm¹¬\çñÔQŸ‚@ûPg!“Ôw$H«;%Í® Î4ÓÁS<Þ!uQMT ïÖ10ÿóöÛlõúõa¿•J}< ðfƒ¨O ¨³P–fŠ ç±¤™lZë P‡…–{óïÞ!u)ìf+@Ւ·§Ÿ>B°Ž9ˆŽø‰xéÖÇ.<"€Ž@å,TÐlƒÉçñ~xšÉê"Ï4t‡–’ÝuïºIž©ƒ¥Ñ/b¬FÄYÇD§NÎÇ.<2. fR; 4ÛˆPÈj²4t'ðæß¼Cê&y¦–r´È—­@s¸ ‹Çë®k7ýk¯þ7A± òšlžìèqƒwHÝDÜNCÎÑóæ…/Ðâ]!+9@Îáh}ÙêãñXÇôé¹7Ü}0‹™<:yÜàR7Ñ·Ó ¹çúëYpå•“a;k¨¬•+£i™mõñx,Ècúô\L>%‹™<:yÜàR]¡¹gÆ ÖxòÉìƒ|Nôx<À;¤^à'?‰3pR5Ðñ²~\«Çã©Þ!UûyË(ˆ{wS5Ðñ²~\«Çã©Þ!Uûã×ݛܥjÈ3ÌÜãñx Æ;¤*£s d?ÚGçgÎŒfãNêòãZ==ʱcÇØŽ;Âu>b]}¼Cª2:Bö#T‡o)¥âǵzz”gžy†ýâ¿àu4^IKÀG¬«wHUFç@È~„êoÚïHÀ¦óô øÈÛK/½þÿâ‹/†Û*|ĺúx‡Tet„ìG¨n ó¯x#âĉáqtÁ9ïyÏw©Ífø.¹XWïªNRàÛ¶ÅãèžšAM¶Ùìã&»·púxK'úM@'XMbb¢>¼0þß›Uñ©ê$¾¥öæ>€î©ÔdûúšlæÌEì¶Ûncãã3¹S1›¹±Á½Õ\À^zé6ö³Ÿ-óæ_]¼Cª:I#í¤OãàÁèÿ$’äx<¥e²[¸ð ¶cÇ»ì²ËØù/Ÿeï¼s)o5éÒ{ÞóöÙÏ~–}å+—yó¯Þ!U¤‘vR‹'X²$ú?‰$9OE&{üø8Û¼ùÀ¤Éþû?ÈþÇÿ¸]uÕû£¸üò+Ù­·ÞÊ.¼ðBoþ5Á;¤º"µx&vìˆwx<½O?¯„Íœ93ìSR>£'Ÿœç©Þ!Õ_åóLa0¼û…^`M ™#ˆýýM6{ö áqžúà’Ç㩘³îwÞ ÿÇÀ´”^ýƒáh<Ñ·4sæ;©sÛyª‡wH§v uàŒºÃè»{ïýD8šîìÙ_ã-£È)‰ã<õÀ;¤^àõ×Yÿš5lõúõáZûN’ÇScD¸ˆQt}‡¨õ?þãeìóŸÇö¥á~çÃvõÁ;¤^àÖ[ÃO—gþ„¹ÇS#Ο?ÏæÎË–,Y29ŠŽ288¶˜>øÁ†ÇáxO=ð©ø‰á'Ì=ž`úôé¡ÃùøÇ?ž8Š¿âŸÃñžzàR/ð¡EŸ.ç¤~ÂÜãéÐwd‚éqžjàR/ðo„ßCLÿ„¹ÇãñTïz_ôL5lçöT›ÆÙ³gƒ±±±x“±S§N± °7ß|“Íš5+þÕt$>úè£ì¦›nbÓð’šPG½1²ƒÐ„ZIø`_ðvR½˜ÖkÖô³ýûád«ýý[¾<`{öÄs}š]z饬¯¯¯Ó!¹7…&B€u{^ïòðz—‡OërñzÛã5x<§x‡äñx<žJÐÿENü¿súûûÙ 7ÜÀâ_ê×»\¼ÞåáÓº\¼ÞvÖ‡äñx< >dçñx<ž ÀØÿtT$QìÇÇIEND®B`‚pyclustering-0.10.1.2/docs/img/pyclustering_build_msvc.png000077500000000000000000000650001375753423500236540ustar00rootroot00000000000000‰PNG  IHDRU=­+OsRGB®ÎégAMA± üa pHYsttÞfxi•IDATx^í½y”UUžïÉê·ºß뿲ßêîW«_UgUÖ«UÕÙf–™•Yi儿RÓie%X™©%Y†©’™éã°žýo‘Éd2™<ÔLü#“ÉdòP4ñL&“ÉCÑÄ?2™L&EÿÈd2™<Mü#“ÉdòP4ñL&“ÉCÑÄ?2™L&EÿÈd2™<9ÿº÷ò7/‚kn3‘Éd2™\*gË?€ßÔÑ/ŒùÚÂ÷þÓä—'­mkë7²‘Éd2™\dgÈ?~Ê7ÿÝX™Éd2™L.¦3äßÌ[^1ȇmd&“Éd2¹˜Î„­Ûúfü~¡<ÃF2™L&“‹éxüÛÑ}lácµ¼xÚ†Æ"ìgî\bÐÎk£™L&“ÉÅt<þÝ1üA¯ßþ‡^y|±ܽ÷xø‚d2™L&Óñøg0ì©›^îÚyD-õ»áåÁS°*UÖž}Õ°aÃνw½™Þ³ÁHXrÕ1˳]3[ËP$×Ü.´Ü:ëžÓUobº‡Ú¾q³‘(ÌräéO,³µÎÁÆ'“ÉyvþÁàOalìOžØºe?,²Âr.|¬¶ni»‘ÆÕ–¯EÈötˆ¿ßø¦‚Kæõãyî5þùpZª é&!¿GÎÅ)騇Í÷~ScÞìû~úõ9Иd2™luþ͹gÙ„+f(’Ý~î„5/oõÂïŽáˆË„•Í?Æ9,šç†¨o¾,ñÐÎBÄtlçŸÁilâ™LÎÆIø÷¸׺vÁôúO?{ºu[Ÿ(•ÿœSyL*X‡&¢8Ȱ4r.?3éw”Ó'þšGó¼Z”ÎCöl‚ ïéspÇô“ŒLBn‡­™Dèƒ+ØR”ˆgµÎ›­CŸÑvøeÓŽÀŒMáØ>ÜôôÙ¿9œ9òÆ÷n2™û6Õê»ÒÞbж"“ÉCÌÉùîì¸í›+¤K•ÓàŸu|à—ˆB$Ø’,Þ¡käÔ‚~D;±Uå4ÇB­%[ûÜ1´ (â;X_OþþÙVA,r;Úº%7jÓÈ4+ΤeˆÄ?s#@+>ß[‘Éä!æäüó»ÛÓûhD ücÿÑ{âTÔDõt±œ¦¬ˆud ”*¶ª …=;ÿ¬}¶t,h@Ñ2{â;döåŸeŒtKëQôæø`ËQþ ‹ý¢: õÙ§9Æ"o|½B2™<”œ~ðS~ò7/ªG#rÌ?Oñ˜vc« ÁЄŒ§Ùð›µây‚3`€Ìþüs–êñ ·î$–®ŸŒÎ?0«Ç©Vë³Osž@ü#“É¡N¿çZ‰áwóß…Ÿ÷Zàƒ#¦67ì…R)ðĸ‰*J‘ÝZ<¦Q4ç•_åk{¶7Ö1w”YVgpf£ Æ¯9 æšmÙˆå´nðCFo—mŠXüãø”$€ZsÚF€V"m|cûÉä¡ä$ü»åëT»cø#›VuÁ"ëí0sõ¼¦TîaM…*çV—ðD7RËicd£å¼*€ v»±̱;k矽ÏaS«0÷'›[Ä73ØË?<ë1¯Ê¼%Äí¼¥u6áägÐ’õcÒ°é°óŸ5Ê6ê§ÖgŸæDÏ&ùŽßøÆ¶"“ÉCÌIø§üÇ‹§©‡À~w„>òóÙF X•Šn¼„Üÿâ­‰<€J¡§¢¶kT[:f_Á.\¡Ïúzø'øB°ÑÌÉáÝD²N{ë‚C kf£æÜ.– ÚñŸªD( ÏöæÜl «l|ßmE&“‡˜ãñïæ¿«6ó–WðC¡Ï*Éd2™L.¦ãñF{Ïܹäös'¬œ³ÙX¤F)2™L&“‹éxü‹è(4ŠÉd2™\LgÂ?p(üd2™L&ÓYñ€@H72“Éd2™\LgÈ?°ÀÛ¾ùð¬?,Þ¼¾ÇÈF&“óêÖýóŸ8vÁßœú î žØof nØÈ·¼¥6ò_\úÖ·ôÕ·z²‘Sv¶ü ‚_}bLKÉdr>½¿~ù± .u"²câ_ê®Gÿ^è~k"!0[gÎ?2™\~®â-O8f&þ¥k¿íìøØ|Orz&þ‘Éd¯[œAÉ[¿YÞ÷g HüKÛ}¿ö–y³µo"vÿf9ÎLN×Ä?2™lñþ‰—ùí`Z†câ_ú^~ì7ÆVuÿù  ž©‰d29ÄÄ¿"[ iƒglâ™L1ñ¯¸Fã?:ÿ™¥‰d29ÄÄ¿¢zþ-rkÿÅ¥õž¥äôLü#“É!&þÏøŽPüelâ™L1ñ¯X^~LÁ6uö&þ‘ÉäÿŠâåè=;·ô™KÉ雸G&“CLüËÜìm;¿b›øG&“CLüËÖ?±yi ×Ä?2™bâ_†F7¼¨‹ã¨ü{þ÷?ü󯻮Z zÞÉðãGÛUþ¬]÷èhÜŸ?ÿúèñ¶…Y¶ßW‹iÜÛ,ÌêwÚò&fÝz,óÎ(Û7]°sµ:`ãxˆr(âU€i¿"øJÑž8êÏ' «©=‚ægtw¢~D9Î`»¥ètûœp¿„½ÿŒß‚ûíÜ>þ²þùe³ëÌôx.ÖA‡Á*Z…#F%ßl *|'™†:M$TW9ÿ+äÊxgñ@œ Å–7vtýìÇÜìGoÄ#-®=Õ²C%Ê¿Åú¡ÅãŸ2t/‹Í•©SésÂýâ>êçkëW ’÷9› 4üô.ýã‚ãI±râ_šöÐÎBÄ\XßYì_¶âí»"ð/~t8z‹Å?0ÿß9¬­býЈñœp¿TÿÄF(|{&ܘñ]ÿp¢‘ý¼åð<“±E@Tb[_4}ÙìçQ6ÕC7¸àã›ÕŒ*ijªuaïöÑËj(M=ëQücU ´ê§¹jQv7.«ÃÖÑ™MwŒM„º«ƒºÄ††–sžÆê¸ýÔ¡mß§ú?LÖ­*ºê.rc™ïšŠR*Fk$ÌÒ+·®…£«.©pÌ×®šýÀ±Ÿ€›3«%ûu‘Ø/r–íG‘Gû9¤è¨ÛYï +%gÍâiØ9õcÏ ,üß;§'rQÐaÀ6¦±šl!›»RŽ<öàïLø'{)²é?é´Ìš°í?¶½´¦ÝM£­,B›;5k++öº\¾}p—<=׆•[Ûn?ÙÄ/{H7ü`ÒVǺ1ýv·V¼~öx± x5Ó³v< >$àLû툭uX™uOöÖo«²î¹ ñN ZÓ"¬‘0k Uîl¨ÃÌ<®TäâÇê¹–-][úì?Z»‹ ¹SÐNìY0ÛÝ#©:Òv¶ö–ªœéÚ­™m²ø†rzÂzît à0Së­Q-3^qûFt²û_d½n/µiýwhëtáæ"ê’\m£iÞmï6gu  ß>è`…ÌUÎþ±ÏJn¼)Ø&’ýd=q7‘·]=¤†ínH·í÷l¶¼q< võîÙW!`uøöA&-³[ªU­ûmUOÜÃÆoM‹´FÂzå¾k¡žâ(V¿Ùà>mIûᄳs¤ílíI–›Qý ôÃ[,~ÛG? ,¿GoA–¢VÜg#ÈY»3ÿÁj H$Ú¸¶‡ÏÂÙ´UÈþ 0zaû¨;ÖÂÙt:ã¶îV®1¬ŸÆaêaá«c)ÎÁꀽ¿7gVÿU #îtà!”¢ý`g§[·ªÞmnµ‚>kZ¬5f‡–ªÜ-À¬*ÝøÀúesä€=}6Ž[§‹´žóÃ/ƒ ‡m;Ûz’ÑfT‡®eV,zÎÐÃ@M{Ž[V­{´øn„ gÄ?ã(Ißöß°§iœM[…Œ°¬YßåѶì-¼oPj€Dï–/ÐÚ¦p­÷ÙÒOÛ¯ÝouÒ3ØòæñàþÆ|¨ o„€Õ±iÛ^­Ú8~[ϲïÔ ú¬i±ÖHºçVî»ÐUô—Zksíô5BÙÒuXŸn,òî¶ý![W?GÛÎÜFO²ÙŒì r¨£ìl?þE; dºQY‹xE‚7‚3àŸ»zÚþö4Û6us¦gþ“X=ÑvF¤í‹øí 2'tò÷³½žŠµMáÚï0Å)r¥ÂWÇ/=›-onW=1Ô» «‹,GZÁ¶À,Èíï·õ¼ýq×ÈgM‹µFÂZå~káîfÈÜÁìY£l~³!}V½ Xdö\˜ý <‰é8Òvvz’Éf´¬)Ú­>m==¿í00"*;¼½û"x#XœÉý/l߸}mÿûôZ[ø`fM«½Ë¶‘{”h« ¢Cæ«o†˜hÛ‡E@w¿ÂeÓ¤ßOmS¸ÖSo?Ñ!eu´t|ÿKk¤¬«Î,ž›W¶n¬‚¶:>‡PŠ6`öëÕ ܪj7±5rzî·¦<=û5fÝ ] ªÄŠ>Ñ çj-RuHŸõÃ>`‘œ^ð³wXüƒJÑ!}ÛÙÚ“,~€Vöð=ËÕ·ƒÊõ0à³—áß >ì]Û7B 3៘e?3noÁÂ͇S¿0ÞÓ2ñ÷Õ8Êè=t²¡c(5óãîoîˆÛ‡¥»?rÞÉ zhtƱ~˜rãílô3êêÈtõóÈd˛ǃV¹€ø¡çÙÏLþBð*è«ã{¥hÏl IÖ­Ê»ê>!eM‹³F¬ÏzåÖµpWŽv6}G”†`¼wP‚¹=¡ÜV6EGÚÎöž¤ÿdM[v oˆµÂ&,ü‹zè¤Ô×TÚYËFtTþ‘ÉØæJ.Ó¾#—™3ûׇøGŽoýß1r9™œHûô™œ¡Ùð1£ÿ؈ä8fÑ“[0N“’óiãMZdrØ8È 1ñL®XƒL®y!&þ‘Ék#pÉ`ã /ÄÄ?2¹bm2¹lä…˜øG&W¬ÀA&W€ƒ¼ÿÈ䊵8Èä °qâpþ8t’L&—£ÀA&W€ƒ¼Gâ_GÏQ2™\v6™\6òBLü#“+ÖFàPÞØ¸gèØXw¯üäœØØMÊÆA^ˆ‰á~dÚ‹°ŒDr©L»#ŠÅV2‡2—χŒŒu÷Zæ#åLÆnR6õBLü 7Ü\™vGÿ”Œu÷Zæ#åLÆnR6õBƒ¿¹ç‰e5-bºö÷þû bºâ)àviï>¢fwì9¦¦Éé:"ÿ:{ú;»u;º:{”wô¸;+cæd»ÝýNëG¡c¬{=ýzæÔLüS2ÖÝk™”3»IÙ8Ô q þ­ÞÔÑÔÑ'¦·uZ·y§˜ŽhÀƒ"„˜pbSÞpù¶=öݾ¦ErMQºrÖº½xÁ=‰º‡ÿ‡ðsþWš[w`:º{:v|£yÇú×·¯Û´íõÆN±Hp(cwmkß ÖÕ·@ ÐAAèëI6$þ)ëîµÌGÊ™ŒÝ¤ŒóÎÝl¤q£+Ñ#ÞùOhfÝ»^­nÚÖyH%F÷†¶ý“—µNZܲºy¯HiïÖ2dfˆª…a:B.Ù{k'w/¹ &–ÜòßÔÏéÛ¶¼}îU»Önh™ŒTßÔÓÿøgƒÀÑOnüÎ-Ï_þ§šöîCÅA`²Ý}[¸©º ÞØ¼¯­ý ü…i˜X°aW(Cù'à·ôµ r݇¶lÛµ¼zÓâuØk×7µíèehôOË]¿]¸FÓЙÍ[wоA'3B ñOÉXw¯e>RÎdì&e|œ þÕíx#Ê¿Î^Çã_Û®Ã+Ömú¥šÆ¶^•`ô;öƒžóþì—Ó‡]2Yùÿ¸jÚíÏmÙ’¡;Šv\ Ð@°klé†PØÚuf»Ø?àQ·WpÀÛàä{–?°òîÿ§é±èëÙúÚÚÍã¸n½õÖï}ï{#GŽL°õ à­; ÿý\ضÞ÷j!œ½¶óߦmÞ´}oûÎ~a‘²`ÓNH„ øo2'hŠ@â0hضg{[/ü…i˜øçGkor(ï@ÚÖ¶=À ìhr)ð@"!L·ïìËlȆw¯­mÀÍ-[µQÍ!L@¯ Ã©“˜ø§d¬»×2)g2v“2>Îÿ¾7î;³êçÇ «³½ÿà×ØÕ áX;¯á¿~F³‰SLÞÿaöõÆNXį ™¥¼p ø—Þö ø±ôÎÖöƒ,Ä7öÿ\êe[ŒÀZ»{_ܸ  2uEücV"°ûØQ`›ÚA‚OÂ"efu»ÀÕ_ÿz–D`ÌQ —Í­û€|0!þ1 èg(ÿ6¾Ñ&v4 òÔWC.`^íÆ­"½fC3KôTR°tv÷+ôB7Ä]à¦í=+×¼.ÒW¯Û"& ÃÄ¿ìd¬»×2)g2v“2>Î!¦Áßoßÿ÷àÛ^¹¹u„Žèªlï®ÀOøÜ1ÏB¤6 nöý®ƒàDˆñ¢OÄ3`¡üÛöØwùÀÞYp[Ç¡ú-Ý‚ É“'‹ôB͇}w¿ÐøŸ.{ÜØªà_j6ósC‘`bEäX!0–½üSüƒÿŠŒ"ØÑù' ƒ0¶£9~8íà¯:0¶wîïèNyÈÎ:tZ²r=Ô_]»Y5* ‡¥"ŸpøW]5LSUµ\à/(2üñÝr&Ç2ÖÝk™/\».7eÍÙ,‹íQ62v“2>Î1ÿÀÿ<åŠXçB³½ÿeÒâæ„'¾ÒüzËîÕ[zþw>FQþÝìÈœâYP€à',bShø å__Ó¢õsz–?#?€ßò;¿Ö:ó§Vy¶´îßøÆNÞzë­iñv3 ø`Þ4³ÆÙ4&AÊÈÇê`¶wÃã;_º{ׂk6ÎU5X`Èl5æŸÕéòoUÍÀÆÆ!¾¯»Z:ö‰¥[¶íJý(T¸­}¯¨¿±¥š‰Ðèt<±T8/üs™)–1þ1øù¯¯@#ñ/M»IçÿÀ±Î…fuÿ‹h_ó{ôÕmÛ:úZºzxû|•(üŸ¯x¼µ»7Å{a:{ú!®á³¼zü§ã€Í[wâôú-ü®t³ìà€+.pöm[.®ùÁ˜oûô‹à¯¸fá¢åüƗɯ.]ÝÑ9°½íà¸qãRäß%ÖœÛ<1kÀ¯íàî¶ýÛ ÷ny~oõ½"¿ŸýøÓà–¶åÅ?0ð†ßu©8Çþ=‹²`OWÏá7šwˆúù9Ù.›ØuЀ8ü öBCŠlƒø‰ùÒª2Ùe#c7)ããÜË?áˆçB³ºÿ†p¬"š€xÜËÍÿüh-¶ÈðBÝNÌ4Ì¢›qͼ¦®¢£qÉÊõ|XÔtpÀnŸ{•¸æäƒaÀpx°»±®¡€7zôèïÿûsçÎΘ1#-þG?¹ñ7ÈQæ„WZ€Fw¿ÐÓ;lWÜÂ>°ýµÄüSŽÎ?@×¾ºyï¹cžU•.Àc)×lhÖá> ÿ ‰€]Ì`ü×ܺ[Ôß´½×/]Â=„ç‘Ƭ”â þYóàT-7kOÈMµ×P°Œu÷Zæãâ}Pk®æØ„/þäÂrù ldì&e|œûñå\h†÷¿L^Ö*™‚ŸÕ"Ï­sÞ0Šcß=þ©?ÿú±/5æÅ%ëlŽÃ?Ý"ú¬};6;/ùÝwA0œ°‰v‰^ÿ`àÿ.´¶õ0^]¶V\ù›:u*,Z»A^Fµ:ÖÊ.ÜÔýŸ.{üò?Ǫ̃n‡YØÙÐèÁíÕWØqù÷Òºb؇ ‰*Cèøz£½E =Ð10LÔlÛ×¶ë º[ÕëùÇþ¡1Œ÷o7»%¸®¾Eì}a”;_YR=^׌™Ï¬oh5²9>ǘ¸þ·v}t? Ñú&±úPÿX@×±¤æP>ïýòì~¼ g‘É8wõãb¯†P=>ý9ã÷2rô­[šÛäâØã?·#æT5üõâ™-ã}ÅÛƒ¢Ð½2v“2>Îø=šáý/0á쥺.ƒyØ"¸`L…@ø±øÒØÒ-¢› Õ ì^ÐÀèÎ?Ž´¥¯¡.u°;?9üÀŠ -›#®,ì{ص“·üåµ3aBJ¿×4ÀqùêPþÌ  ôE`B\A„ÿxüXÿ‚Í. ÷ô«sàkê9{ÌlVcüÂZ÷«'ÿ6mn‡Vسðžœq½Iø§¤…q#¬«pøæÑ¤rY–G«ÁG8˜F£Ê2Ÿ’lu‰¥¸›…ÏÉÞA&4‰W¢à½2v“2>΃ùwރߚPý0dèÚsÌúÈYV÷¿@\^ݼWE4…À[ŸiPg>…E"„¾3ìww? [êœï]Y]·ÝX„ üSÎ`6 ûDv °`þMž<ùÞ{ïüÀ4Ħ•krÀÛ¶hhì@,^^ƒ ú9âÊ2ìRÓeÄ?Hôž͈â®(ØÝb¿/¯ÞÔ¶£WÜœÑ/-\;÷ß¼yk·±È0qî:¨žÿ[ÿúö´±Iøç é 6gJ,uã½`‡”, Ó¢´Qã&±¿õƒŸíÙ×'“ëîµÌ‡$»£­f›3ïn6CŠ¢€½2v“2>Îø÷“?ýxñ¶å<[ã?0P-Öû_þ·QOª &¸µkßß^7[% ÿ§Ë‡8h”µúîñÓBya®µë€Š;Ø0Ô3àæ/à(ìü'ç߸qã ¾ÃtUU øD¸7à(+ î}}úþMÿä …¸äükn݇ï yqã.ø? þûÁ^¸)<²‰áîfçEá;}Ùªl¿ÇŸð+KV…ÂOº{`{ç~uºF>k˜Ê(0¼ðOŸÑhrã½o¶À…‚[€ Cп•è‚ñD¬0ª,ó!‰®¹µóÏ=ª©ÐõZòÛk c7)ããÜÿ:ûWM{;ñu«³ºÿE 6on‹s³×t¼Þ²ûÕM;ÿóSqú¿L©c§hS»ÿ“ý›ßµ! ÿŒ{á·dåzH)üþ—øü Ù1Q íPË«À³=+ï°ùºµFufK¿ÿïwsaا|ïFêÆ—WoÚÖ¾þëÊÀ…òO|'žs8I©oÄ{k^‹“¤ ¸©á5.cݽ–ù¸Xܶµ9ÔkmK9R«GJGÆnRÆÇ9æ_ÄsžØYÝÿ"Ìž=Ü ÁC¿›Ý`¼£ fÿeJŒüxδx€ÌO=yŸ5V†˜Èï}…á—¿‡Œ]éáç6‹È?v ´ïõ' ÚY} yt`HñíÜ]Õ8ñÊéT®Àŵø‡L]}\úÚ†ˆÇ^bÇå_ËXw¯e>RÎdì&e|œ þÅ:ç‰íý/Ø€ºêvÞ:ç `!D½­;@méžöÄ'¾ èÔoéOb)Ã,;íí¡+p¤€Ë¡þþö·¿7n ÐkÉ¿8ÿ¡ªêßÕ` Îêž×nïÝ3ÄÆìiñ:ö޶Ç3øO+š{úÅiùºúèL&ÿö9&þ)ëîµÌGÊ™ŒÝ¤ŒsÁ¿Xç<±³ºÿÅ0`P§â¾|Ô!3ø¹î>Ì^oÖ}hkÛ=ÀÂæÖÝü†—þèo=Žp™.ZC@«îºë®dŸNô7#îÞÕ´³z_Ý£QøLªE4d6Š.íùO†@ç3³%„Ÿt7tF~˜7ëa(ñOÉXw¯e>RÎdì&e|œ þÅ:ç‰áý/91¿Þì;àÜâ¸f¶Ç ¸ì¢;åkoÒCsŒíÝGû[—Õ¢¸oóœƒÍ/™5dé‘Õý¼pSwÆüƒ=ÂþJü IÛp(á$ñOÉXw¯e>RÎdì&e|œÿâžóÄÎüþ— pÜ€[tç$²'tÖüš&þ)ëîµÌGÊ™ŒÝ¤lê…8Ûû_*ÃpseÚQLüS2ÖÝk™”3»IÙ8Ô qåŸÿ$“‡¬À¡LüÖùH9“±›”ƒ¼ÿÈ䊵8”CÇÆº{mä'çÄÆnR6òBLü#“+ÖFà “+ÀÆA^ˆ#ñL&—£ÀA&W€ƒ¼‡óL&—©ÀA&W€ƒ¼ÿÈ䊵8Èä °qâa_ÿÞUd2¹"m2¹lä…˜øG&W¬ÀA&W€ƒ¼ÿÈ䊵8Èä °qbâ™\±6™\6òBLü#“ÉdòP4ñL&“ÉCÑÄ?2™L&EÿÈd2™<=좫ÇZmäC¾îâª[þ1RbÿãÙ d2¹¼lüŠ•¯ø· drü+oKÑqù7«aðtOÓâ*7å¾±‹ÚûAŸ8¼ñ67=Äð[|ï92™\.&þ‘Kn`:ÿÚrgaØ·¸uðà’IS¯¯š5¯©½¡i1Êdâ™\^&þ‘Kn`º@þÁìñ†E³®BKE!&þ‘Éåeâ¹ä6V  áßÍU“6ô˜8$þ‘É•iâ¹ä6V ðO øÄ™O<øK‰drešøG.¹ €è¸ü䄼7Âl¬¡ëdr…šøG.¹ €èüß\Ånx‰÷Àƒa♜̳þýª»¯ÿö«Ï\gäÉÂÄ?rÉm¬@'ãßuWMüäYMšx±¹(ª‰dr2Ïþ÷«æNùåöGÀn¿ˆøW¸ŸêÜÿ”'=ß±î?a–Uý%ñ-cŸißÕk$FôÔ9+ ì• 7Ü3§Ã,$Â"È€Ó± €èü›0³éà ¾?¹ŒK€QmåßšÑÃ\¾ÍXê5ä?oÒ$#1ؼ‰¬ñ¤'ð¾I%zê详v˜y¢8ÁZ‡²aü÷Ú‹7‰éq7_uKnÌóž¼æèî)8f!Aœn˜óï_¬6‚Teúùýƒom½ÃH õÃ[ žZù°'½Ì}ëØÙªå5ÍØFž{~``:.ÿüvÏ`'?g5°‰ù5‡w×ÄG ‡“¦~[cÞšI¿Øç.µ;9–þ`طëJ`Æ¿5ñˉùö"0"üÀÄ¿¤ü«¨‘Ÿ°àßÔ9+…Ÿu=Ìy‚ýôü5Pd庭#o˜† ˜…D#›a`:.ÿØžÎj'FµÉ¿Ž_œüDü#—¬%p!ü¯zñ&(òô#£>9ù &`l^3þÿ/VAJ˜ŸTäzkëSëN vU«ôcëªW¾%¶>/ !¤¡Â9sBC(73«ÙÒ\¨°õyö— ånIùŽÃx—æòi{=œ±uO¯ne‰ûWºœRöεñmb&Ú;ï-%ÖÅMG­,ŠhÀžð#Ócà ªÙˆVŒ?°0ðŸZ¿6õß^sNJ«ÿ7´ÔMlœ)Sƒ ö”þ½wÛõÆ]¿§¸ÖÎ4â1¢K(ŽðÉhÊNrBW¼ ŸšÙ`ôú¥|HÊd³•¼Bu~ÕÔŠvÝæ’ãt‰m%U?Ê©zhÉFΛ­Œ?pü+F‡8ÿ0TxBüSÑ\Æb™“SÓE«A¢ñŽuû1lœü‚XW¢,>ýøüV+BÀ |Ú§°>þóé+~ì-ÕCsüçÓy±œlo]ÉIæ·”­¥øæÕWGÛòöE ”ÂVé‰/Î~¹FTÆ"«Ø” @ Ÿå`k}E,âðëþ“ÈygýB‡ƒƒ'ÞÉ çŸ÷)øHöðOFsïHÈ(àPþ±i}ü‡aã_3Ÿv*„"Ö$+îáŸ(+š`œ‚¬wíüÖ"¤Kç}ûjqåle)39Ÿ6~àÂù^ù ¢i˜0ù9ÿ`¤WXäÅQØ »l¨¤†;ˆ1F ,X»Ù”Ýü<2²#êèøñ3t SÁRXãŸ_÷ôâà€h+ë]»Ð-`-el^Ñ„sŸEq-€gØÈjuÍì½Æj6lÆ?xÌwÖ–x{¥QŽù°ÿXÆæŸ|È?öüûøÄáÓÊË8[¸½ücfÜœë`“y$! ã_@Í.ÃôtÍœUHª™_«ŸñÃ’åqù»KfN¶”žläüZ ÂÀ‡_ÂÛ7Ü?åËaÜàñ·þj³FΫk~`ïí0~ŽÁ?OÐg#Ä?D=Ê+$À„G*Öóq#Ä?ndgé /'° þÙêÑùçÛ=¥¬›BÉ]Y#·€“ÁBV}ó‚Ý-°(® ç¾æ‡¯Ù #’I‹óŸ(°Çù7½Ûü¹ç?ål\þaÃÈ/ù#vþ ³ÑŒC wd£ì†þ‚øT³Â 7b¶Ïø™ÑN­‚“¢cɶÑ»$6‘.Å?¿ÓÈä¼È ~`-¯a häô3¾æ' ³hdó~³ÿïùÿbµ¤¼¡9ÿ,Á] z4…ðOÍ‚¬2'⟵¶`þùtÞZ›oŽ}2‡Æý/ÂFž{ïöô{(Â0"™t©øWƒøVÈ)Oþ‰¡!^ü3r ÿ†ŠaÐèúè­YFz°½w{Š3±QF1øgà‡GÞxüóÔ ­á„c5 ÿœ zôw›~Ý æŸ_ç­µù6áØ'ÞÔÌ“‹âúÆ{¦ÇzàÛïQ‡(D$“6Ï*ì¹'B± âßÔ¥‡÷[ãËÂ!ücqŸÇq/{Û|ù‡ñàÇ¿ š 㟨G/íj™QSìñoè8ÿ¼ðŽˆÀüãpiÁâlLþ‰`íFç¹+»<¨`Óaç?Ÿßï$zÈ„•ˆöîy[a58Ù|;¯×¦ÝÉ´üK©>°§ÚÚ‹Šé?N]ðü«ë'?½ÌHC",‚ Fº2"™´¸ÿÅA»æ§†ƒ|‘åþ—Äüç<•çÏ\ÔÔz¸}^ü³ &ÿ  #<ðñ“‹4Öañ] ¤ÿXºÆNnq\$ æH°ñáŸ[Ëà —·¥êd=´­Eä.ysŽ ™ÙÈ•êüÛVwï«Ï\·iùŒt0$Â"È`¤cÇá˜#P¨«:öùOn¯…T÷úätóûpK`†+ Ö£.ùóO­Z%{q0«A1̯ǫ́6wƒXšÐºd)Å×Å}¼ø•‹·°ùùÏW€jRx,èБKŒS>ÿ)>‘ÎóH.±Àât¢B“Õ Æ^E˜8«ô"~5ë àŸ.(°ä7]Îñvo“=!p&é7kË‘““ø7Tœ€:&ÿ4óÈë‹rŠØÔ°Ø”9ÿðõ¿NåúŸxÂH ±‡nrdr.'þégKjvÒÏ6\+ÿ¢»pþÝ\5iñíCH‘Lü#“Ë˱ø¡)'ð&þEwbþ ì<Á<ØJü 3ñ\îN>þ#“S²°àþ…½Ý5‹æÿ!éW‡ÿÈär7ñ\r+Ðqù'Þù’ä†OÃÄ?2¹¼Lü#—ÜÀ t\þ]wqÕÔǵ÷ÓøLbæüû…ÕF"“Ë©\ÿKåûd29×&þ‘+̉ù§ \ýFúï!“Éùrÿ`ÑÆÆ=dry9ÿ®»¸jâ xù5~0=GÉdr¹8”Ÿ“He¥ü›0“öT:Þÿä'˜øG&——‰¤ S\þ ø‰þÍj`ók’^ÿ3~]dòòÑÍ7¤k£þÔMü#U˜âò¿êLM'|ÿ™ñë"“‡”X_|PŸ–‰$R\ÿòâG¦½Ø³ÿ-#‘\*awT6ÿö¿¾¯mÁöX†"²0‰Tο›«&mè!þlâ_®LüóšñïŸ~aµ—uk–ŒYTûðáé×<9á²ñðW¥†ÌPD&‘Š¢¸ü»oì¢5òmŸÀ¿O>ý¡¼ˆ³…›øg˜ø—+ÿ¼ŽË¿m/6øÑ‡Â÷Ýwß\UŠaÈLü#Yqù‡ #¿ä@T(ÿލ‰vwúhçîcjÚÏQîÚ -7ÜpCÒK//lïv¢î>ºce lk~lâŸ×åÈ¿êªaÃß-g2´5lXUµœËB»žmBEj&*„9>ÿ –éƒ~]úÚz°HYUÛˆ‚‰tøÇ£9ïûßÿþ÷¸Æ_|øµw›)©¸ÀM}ã7Šÿ „|ðAHä‘Gä¼#ÈÿFˆR]þLÆ?X µ"0¼ß‡ÿ::;€y ŸÿüçÀ?ø+f!=×ü+&6cˆø—²âòoêÒÃÇû-Nòþã×åg€SgOg÷¡¶½-Ý[¶íjí:³]=œ[fþP§^!7+äÁ%¸xy P &Òÿ)BµcÇŽ-üzŽ´îxòÉ''Ožüʒ׌¥…j®kè„j­‚-iä7|óÍ77îÕek•—®¬(†‰`H¹ä’KÔÿ(~N<þ[]·õÅ_Z´dUS[/ì hvùìý¡À¿ú×ë{^A:ñ/¾ˆ)+.ÿÄ9Oåù35µ&úDDþ±ÁY÷!@ÔòêM‹WÔ)Ãìë°¨£ e– pêr»ðû!—@`úüc£ öª…ÊCOâ¥k¿[o½Zÿõ¯ ñx «fØ(jUJ —½ºð ¸ˆ× ض½­W¹}g¿Øþ8 ) ØA -7*ÁNÀ?èÿ/ùËó]~ùåõM=b‘u 9”Ç‹/âQ —‚A, 9@‚tYg‘›ÙÉ‚@¦3 ÇxV£ËàΜ,¨fU‰¨BdgùPb‘*„ÚÕ[«F½°HïXPµ* ä&‹üne’TÒ^U ?ÿyÝÅU‹[³¹ÿXÕ±ë`͆f *ìÕë¶À®³gÀ(èçÔ+äÖàW÷zX pÊ”)jai*D ¸¢*¨‚»¸Ä¨*gÃÁÌF„øyòGYÙX¶¥Î?1*ÁŽË¿W—­ùÁ~ Ñwþù?ýéOÕYV?þ)¼ó€ð×: ¶òGc¤yÜA˜!Þ™Ra{÷ã›yµbn96¡²<î›WͲn¹ ^¥ò¡B¼/Î+¡Z@Ó|Æí²)KÇ|«Ýý¸êÏ#ë4{ˆ«äåe¾½ª,¥rý/“çÿØYÊîC¬®®ÝÌm‡â^§^!· ?dEœ… QNTÆâDö-­ûE `éÕ¥«Ÿ|òÉ{ Úm‡Ø¢ô.ÔÁ SÁ/X9ÿE²¼Gbitþµ¶õù:»Ìÿ``´¶{ ™Säü7på•Wrð1ð{cÛ^6á9ˆáüÃQØ Þ°Ä üþÌìB(+š©‚n HZ^½ ^/@ùôEnFUlÞÒi!KÇüªÕå6¢ç÷]‘8½ª,å÷þ—Ξþ-Ûva2mÞºgÛ;÷§.ë·ttv÷‡ž´ôVõ@mP'ÔŒÓ#Vè?a…@È 28*ÿøPLŒüÀg¯½öZhåꫯ7nü…é‘#Gª©"©ÖBÝw È‘ø‚Uµ@tÃÓ§OÆâT;ÿÅaÖÐË â6éòoÞ¼y}øÕ7õŒ5ª®¡Óû?P0ÿN¼Ùº¿÷@¨Uþœó¯£³£þõúÅ‹ó@ÞÛa¬üÓ¢2JPS.|b6ªD¯Ï-ɦÌÎËj6Å3»U¡Bú"6Ç—˜%pnF$±…j†Ë§Z5§$“õü~+¢çy*V¹å«aκ:v¯©kT‰ÂKV®‡Ìa·®˜ Cm¢ZŒÆˆÂ_?ø B†(Œ{ q*¿ñ¦›·îmÚ¶oÛöÐhsË{î¹X1ò'7ÝêÖÓo¼€dd‹Ê¿°^Àqùƒ?˜¾ð çÌ™³Ê£G†žÏž=–¶u‚­‰)òoüøñ’~矿dE­JðƒÄçž{®c·›_8˜GvlÐܹs¡7¾ù'p;L,þ9“(P³àn‰ÙÞ2RFŒg³L8¯OÍ^L Bú"6Ç—xª2«ðJë˜Oµ¼^­ÃrZÏï·" zU)Ê-ÿðLIÁïæë_ߎ-2lmÛî확`»5ÀàÏ‹À° Ãá'±.0¦uçŒü~¢!q÷£jf¯¸â q ¢QVøîñOýù׈}ɨ1/.ñ¿+!­Nrÿá «†.¿ürˆï øÃ;˜†R =jSˆ­‰ Q`2]þÝsÏ=~ ž¸íEÁôÿñ8¿p(ÿÄð“è¿›¿Hüû¥Õùçw;ŒßøO‹ÂÚ<ñø> šx>‘Š&Afí TÎëS³¨¾HÕà©ÊÒ ‹´ò>ÕZ’hò¤GëU%(§üö4¶t )øY-ò°[7oZÁ5`+†V~ÂÚwü÷êÒÕaä'ZùcÁ /üɳÏ>ëv(c†ÀO8}oXñOõYÖ%#þ dK‹|óN›6MpN°·ª¶QÁ´ðÕ¸”p9òïœú¥Õù§ ÌþÁ_•b矇ÙÒ 6Ã5þðüμåþæå¨îê*·Œª-w’š!›¼¡D§‹§-w‘ Þµ¨Y:æS­[¿lÁ™Óóû®OØ«ÊR~ù§®ÉÁPÌ ¶Èî؅ñOUhÔ€ mE¬P`+޳~†lŠ•`Çåß“O>yõÕWã&0ÿÀwÞygè3‚¿»ûQ€ß9ß»²ºn»±Èn[m"FB`ÖüƒYF .Cø Ó!-þ1øíÖÆyVýä'?ÙÒº?àúŸ‘®LüC<)#"ã ïH„n.¹ˆW¢2©åâ!^£Êé¤:¢šU6 ]ì‹Øœªµ‡zaÊZ­›Ü~Xª·­5Ü«ÊR\þÝ7vÑêyAžå)bwÿŽ´v(+–Œ³—"CsëîÀÓ•Z…F 0Ô3à^!e'NÄü[[׳J0«Á,dV­ŽË¿»îºk„‰¸ „uEÁ9sæ‡xá»ÇO‹ ?n+P óïÑW·ýó£µÂb]0ÿ`,U×ЉËzíåŒ€á¯°Ø éò/"ü@ìâ_ÏQïSð˜ãLJþúÅ/~öd€‚yæ~ÿµaïë°½ï¿F8±)dqy¨"V¢Œ—³O÷4µ7HÝ“Ðs$á×}$à›†‰$RiU ÿ¦.Õ¾ü2ÿàÿz@ŒÆê·tçÿrž}öÙ±cÇVUUÝwß}3gÎô{ádF†a(¬Ý”)S¢Ã 9Aÿy‘#Fï†DØ/Z~íŽÝG_zù‰¾¤ðWÿÈäòr\þM˜Ù´¸ÊL¼oì¢YW™‰!ŽÁ?6hédªà_¬5³Ew*Î;Qân½'æãºúÅR`ÕÒ;íÝEþ“×b­Är£{‹ ƒßù°ƒvÿÈ-üÏqà 7<úè£õM= à®0þ=ûJ ™\^ŽË?ñýۦǪnùG6 ¾ù5‡O¨äXü NÌ?26;·™ÆÀ7ÊîPÿs$€¸Âøwìø›ÉüùçŸVº>øàƒ ÈRn—`íµ÷oX´±†=ð±`âŸaâ_®\„ÝAü&þ‘J¥ü‹oÞ‚bû”‰ä!î²äß÷i5ñ/XÄ¿|ŠÆdriLü΀Ÿl[³öœi«~×xRÌÐÓ|é´çÏÜ´ì¸H.žˆùT\þÍjüø„yýïx¿öD$ÿÈCÜ@¬tmÔŸºË…Œv3kGÍuù‡ÄÐøÝE;úål‘Dü˧âòÏz«§õ¦ÐÿÈäò2ç߯¬ÎÿÞ[ò o€ÿõòoðÄ–çÌiÞ.çŠ$â_>•ìú_ &þ‘Éåå²àŸƒ7AA/ÿ }Å…kʹb‰ø—OEäŒðÔG¬¦ñ™\á.þ}Ô7eîê©»aÊäã"¿þWü“Ÿ â_>‘ø³íýì›GKÙtò[`à³qK™L.çžøÚžßøƒ°è·Àÿò©¸ç?§.=Ü>O{š@cBþÁ¡O"‘ò¯2àßé®1.Ø|ùÇLj>‹2ñ/ŸŠË?ãý׉!&þ‘He¤üóOáÔìê¹çH‹'â_>Eü#‘Há*ƒñŸ&¿ñ4îÿ$qÅåß„™ì‚ßÁ%òhAÏÿÿH¤rQ9óO</G„tÿ I).ÿÀâý/J§{âßü &þ‘HÙé³Ï>Û°aÜ9s&NœøÔSO­X±âí·ß–Ë©Üø—/ÿò©ü†‘ß}W1‹ÁÄ6ñDÊHGŽ™2eÊíºî»ï¾ÆÆF™#¾ˆ…ˆø—O%æ_¡&þ‘HYF~ ~=öØÂ… Ÿ~úé;ï¼fáo__ŸÌSÄ¿BDü˧\ÿ3ž|7¼ØSÄn≔…6lØ à·bÅ `¡HìÁø"%®ˆ…ˆø—OÅå~ÞêYž"vð¯}¾øýrÍo—©éëHÍc‘ªÛÈÿXÍ9M¼‰tV•­•¦¸}‘J°…ˆm´ôµˆ´eâv8êî/7Í™36Œüü„jkkÅÖ|ÿý÷eRÿ ñ/ŸÊÛùO÷PTj¯É.G €Iú)g†—´ÂzQù¹}æÛ\ÛèóåL`ŸtZ*Þ:K?ü0l¾E‹ÉyG»wïæø»}ÿþý2)Žˆ…ˆø—O%ãßuWMüäYi/‚‰g;ÿXè+ZDŠ@ŠDý‰ˆ3ÃK„µŠ¤Ì:蕆¡ Mž6ÿx¡46Vž4cÆ €Œå¼£––Á¿7ßdȉ+â_!"þåS ø'TJþý[Ûøâ‘o@b‘Q :”Š’Xmª>œ‘'‰<*Ù<#öÇ®¨ºÐ$H4(*Uâõ|~5Gé°jD/£RÝ9Ñ®ªW§Kb…d*Ê©*°dsÉnËãÉÁ$ K±f0åÝ"ÉLdåÜ4K†2WMM lãV—Ï>ûì‰'ž€ôx@&饰€£{÷î•‹þ}ãû¿²šø,â_>•àú_{ÿàîî÷o·ðþkñÓÂbÑÉÚµ¨…‚䑚ùN*/ª’!ûcj‘¶ fjؔ֫ҵLHZ…ú ÄzLf¹,™@xοf>íd ê°*íŠ%‹ìĭ·£KævVÅXí"Ÿ™ –©¨ˆM¸Ož:µ…Ž´Ê…´.òbþ –€sÏ=÷Û©u6l†ÁÈOÀ)2«Gü@Ä¿BDü˧âò¯(ï?cŠIR8ޱ–¨åæò9o~=O•LáýÑŠ£ez6Ü„¾Ä·È-ŦÜe¸6$–Œ¥ ÈüZý0£ÕZHÒ%3§ÊgdÓeÜ.˜Ò¥UoÖéé%dòkW*Ì:µ…¶ž f° «‹å#~wÞyçÔ©SÅc 1 †ŸŒ½ðIþýàj«sÆ?ñÂ3ïû?ýÒ3WùN·œð‹WüÓêr.Uå˜ âxÔò ‹<ΩÀæ†@o\ö×ó¨¶Ô·mw O‚pƒú­°oÍ‘:¬gÒÄéÐ{Ò:âNEì’%§P@§X!w‘ÏJI¹}™uj A&ÿê¸Âs”¼ðkog›æÃ?Ü¿²^ •ÿ>èi¾tfí(ÏGŽüÒ‹ â_J‡æŽöé{a*Áõ¿¦ÖÃM¹×ÿæ×>ØšèûïáüSÕ/,ê1åò]€%!ÿþ ÊP Öc²SZNëKä\Pͨ 7'—ž I,ÐKá1¡ù»dfÓ¥o –3ZV³N½)Èdí+(æ×\™èĉ[%ún¿}„ [·n•ËÒSùðO¼ùzÀóý¿ôb¨„üûpû„s†94c\3årN_Šù'ªòѓΈ5|AGŸœüxïÖ+§UÿûN>óÁÎÛœw‘T;Ó\¯^S΋³zTŠô¬ÆF‘Õã&²"¯]ÿƱöÚ¾¦ß–K„Þ©¿ãkÃþû˜Z‘—à,ß á # !L¡¸èÜõÂr8ñçvæØŒÝâèþ7®J Q-¼9oöFØSBasnÕ¨H@ÍlÚ-£µéJÏ¤äæÆå¼}ÂÝÀÓ‘ºäÍ)oOñ锔іñ:TÛ üüŸÞ \âBBÉ“¨e´e(3ÍŸÏ6˜ù¥®ráû û¼‘ùý#¿ôâ(˜Ÿ¶4œóTݼ9ëª}ó·¦ÕÎîûRÎ*íl<ZÍ´½ŸÉY¥=[/š¶vr÷Çr0„³.b‰_µø°šIÄ?¼^9*æ>I2h9Lú´Ús.üÜ"X¶ñ®‡×ï P"S4§wC°OŽü„ðOX¼ÿ:á˯Ávþ‰ØçÊ¥TÌbQP%¹‘ÍpQq‘IÏÃæ¼‘0¨?nÓf¸Æ³ª1öR58¥y‚^įf­¼O‡µ²BP„uÂÍëÎñvÛÝhý’t‰‹ÕîÈÉiɆd4ÒWÂ]褳ºÌ:½µØ¥•ƒBþý*ÁhÆ|°U2ù •ÿÜoÛêœóK/–ùwvíRÙ+¯®S&8Ú¸r%„ò‘ë~!¤¶T¯‚ô+kû?‘ Rm5k ý§kzß“ r0g ¦ègÏQŒm˜srðÃãBÆ<Á-œß”…nA!†CÑËì6á¦ó“žû˜ó¯PûðTTEeFÖ*&†P[€Â\¬~Á‚1ßÝwßÑÈO¨øÇnoq>ï‡9ç—^<•òúG BÈB76K‡ul&YÅjꤥ°X„@å‘—h@)äâÓ6X‰¡_Áü›º”}íÖkúþmY*/üã=)y¢süXæ:}ú´œÊFeÀ¿Ó]cfnZv\Ì Îù¥Qy¸ÿ…Ÿ¥D8˘ iìÜ#°ªV ìŒñŸ«TÇþq~þóæ*öÚ3åù35µnŸÿEhÄ¿<(?ü#å\ùç»ÂgŒ-À37=»Îž~]&ËZyàŸ‰3“‡L€,7gà%,DôIçä«ïž6]Õc ²rŽ í×ÿø"L;V>çÄ?¦‚ï1,^“Íó$)*ƒñŸ&¿qÞÐÿ 29ÒÏêKz¹i9ñ ˜.€â¶OºÜDÐRÎ9'ÝszÓ)â€PTîÉÆ?¦äÏ?XÙó$)"þ¢\ŒÿH%ã_fß ‘H¹T¹ñ/_"þåS ø—æ÷Èdr¹˜ø—XÄ¿|*.ÿüÄ÷f5°‰ù5‡w×$úþCGÏQ2™\.&þ%ñ/ŸŠË?|©OM'¼þgüºÈdržMüK,â_>UJþÉ.H¤rñ/±ˆùTáü»¹jÒ†â‰Té"þ%ñ/ŸŠË¿ûÆ.ÚX#_x üûøÄáÓºŸƒaâ‰T^âü»Æjâ_°ˆùT\þa‹wÁ$|‚øG"•—ˆ‰Eü˧ á_A&þ‘Hå%â_bÿò©¸üKóýײ $©T>üc|8gšûžöåwç]YÌìC€Eñ/ŸŠË¿4ß-»YO?ýô1Eda‰T˜Ê…Œv3kGÍÕùWtæaÿò©ÂÏ&ÿµìBdÏ.Œ)(" “H¤ÂT&üoøÀïù$þ‘¬Jåú_‘žÿ#þ‘H%TYð}‰¡N{Ï5ñdÕ0KE3ñD*/1þýð«ó¿ú¦Ì]=u7Lyøç^ÿŠ*â_>Uüûâ‹/à/À¬½­í“È‚ÌÁü[s½øÐ×õkdª¿ ÿyS÷É™hâMD¨:\û¦ž—NEqÔ([5X¦mD©Œú™ÞÆÔT’-[ŽÊ=ÿØm/ß]´£ŸMû~çˆ&·Ø$þåS¹æ`ïôäñ'FýôÓ“ìk½©ò=õÖL '[$þEÊ”@9㬦uAV«_˜Âzë™Ã^çMyçßé®137-;.fü¿óÇÆˆ>‹2ñ/ŸÊ5ÿ>:°÷ÿû+'®ùÅÙÏ`ÖÊ?øñ|úé§rFWÿX`ñˆŽüxQ’NFPøNyìx®¿Ùoþð«óÀ?>°S'9»Dt˜DFGÄ¿|*_üûòË/Õ þNÝ>æÔÿù¿|ØÑ óxÏ=÷ìîé‘pã‚_ÎG‹¬ ÿA¼ó x,Š+¡L(ŠêÕ û¬R%^PÏçW³(¯†„j®GUšèiQôW¦¢œa€rnUHÆÚ"‰%nn¶àžà>lL­U\J‹ª¥Dmn’Ö­’G9çŸ.¿ñ¤Óó$©|ñO\çú¨wß;ÿ㿸æŸ?ÿˆtèÐ!ø ¿7˜8yúÝ ?yjÒ¥37¯ß‹Îž=+ òOFIoÈãé*èjs(þꡘå²dá9ÿšù´“‘gTƒWZ=û¦NåSá‰Ú›>ï¼ëU3|Þ™c=P¥,‚ÌÖê«®‰Ué®VXOì}ölL[‡µÎvð-‰ÏzCÕ,ɦòå^¸ö H,¦ˆùTîÆïo¨}çyúÁÛOÞtí©?û_?hi*Š¥@»'Ǽá£à÷»¯nÙ¶%ú¸‚ùÇă%ŠË )¹XÑ2=Êc,ñ-rKá¬×fÔã]ì—­E3gx,K ™ýsÛî‰V-Zæ×a³)œÝ¯Ÿ®·L2TVüË—ˆùTî®ÿÁðäµ??õWÿõÔýŸNüêÊÏß;#ÀÏï†ùÀ9`OÁoöØÉù'Äb¦5-ñÓ(Šâ€ª‡T}‰VØ·f=$³9T…!K=Ñ}Zd9MyªS²ƒB¯Ñ”jØQ@Oüú¬OyÄŠYŠs¹%A¬E™_d²•%9"þ%ñ/ŸÊãý/ï×­=õwÿýÔW†}°¥þKôÛxòWÏÿéâ~ëk»N½{¦PþXHäÒ@ÝØ‰¢¨Pµ®/Ñ ûÖ¬3@uÆ*K=Ñ}Z´÷d÷äÖ+ôH5ì(zOÜ¢Ú”µµ€t½yÞ¬AH1òtÿ‹ø—Oå‘0|çþÛß{çÙwOË$.à_KÓ¾õ+Úð` —ÿTàdaQ‚(>£(ªTv=Kä\Pͨ 7'–uiÄD·wŠÉZÜ_ú*réõy…·“;Ö´›­øu¥«d§Jh ÕŽJA!£$SÄ¿Ä"þåSåÄ¿…OÖ ø‰YÀûþáQÅ¿ãÇwèÚ¿¿ÈLJY1ya +™R©Ä*`bF5W’ˆ‰Eü˧ʉ_|ñÅæõ»Ô3‚0!È)øXß!öš‡/mùIéŠ ³"#0t±q[&bÓØ/‚ˆ‰Eü˧ʉ@2`žâ™˜…Aák/lþôÓOI9TAüc¤e"H•VÄ¿Ä*{þ}tðñ¹ò”âvñ^}gQãy¥òý?å 3›{íNÀ?¯A4È#‘²Vùð}âÏK>Ý·Àx_ š±*eü÷ÞÒE…ó/•J¸rÆ?ö!\O¢Ý©ðä’ó$)• ÿØ×þfÖŽÒ>òPš×~*ÿÒã_Á*{þ‘H¤â¨Lø'Þü9€ßÿ9d¿ÿ~²q# :ï3Í-ʇM˜@M.bú¤e-Œž­g;MtÁ†½læÆ¥r0Í º£±Ó]¿u*9GæaÅUÍÒª]tŠ é Èk¿m<æt ¦Å>u«ÒƬ’ÕS»TU«§öÈ%¸~aX‘¸ü›0³©½Á×OÿH¤ UYðäd¨Ãï¿f§CKòÚk¥`þ}ÚÒpÎSuó䬫öÍßšV;»ÏsrkgãùÓj¦íe_…Ó´gëEÓÖNîþXÎ °)B ìiÀcéŠ+~. EæŸV§!³&Ô7‘Á¡šäœ˜Õ›éÄIÈ ìáu1ëmÿH$R$•ÿØ·mÅ·Ý1ÿøô뻦8ÿþŸ…ü;»v)ôjåÕõoÊGW®„ÞŽ\Ô¸µoKõ*H¿²¶ÿ™ ÕV³Òº¦÷=™` ìäp1€ ÎäØHƒ J·ÉDW ÿô‘™+³«õU‹¹åíž•.wÝzXº[Pm:ÿI"‘")÷ücã¼ï.ÚÁ£¡Á?tÏËPúþ­—Î,#‡š`ÒyæUdþäPŒY§…¬cèÌ$3⟑)2ÿ0GyÇDÄ¿Á³Ÿ~tæøž“6[}úÈŽO>jAšìŒœÃJ“ ®ªH2þ]wqÕÄ?LšõФ‰ké™<ÿpìØ18zäLÚúâ‹/Þ;¾k`ËÓ‡·>ÿÖî:ÃÇ:—i™ÿÞÑ.™›DÂbüûÑ¿ZþáܺfD4®ÿ•àr`.øgáÐk£æ¹ƒ?.Î ;Š@!^Š1œ…:“´Ì&ИLWJüƒ~ºœv•€¹ƒ'dqÐñ†E³®2ó„;:ÿš››GŽ™‘ÜgŸ|ðv÷Ú#-/y»O¾6éƒ3'Oìo þ‘H œóO—6æƒ8x©vþS\#,žJÉ?÷¿s`Ç—zG{ÚPI°‡Ä­‡Ù¡‡™“Ò©]_t3›ã´“Kq¢[¿ÿôú™E=~üCýÄùãòï¾±‹ÚûwϨºåÙ, ·&B`,þ}õ«_M Ÿ¼òÍ®å}uûÖMˆâþ7ž à_vo¤$‘ò¦òå‹ ?P.Æ/­$!r9Ã͸ücWøŠ”â¸ü1bD*üèþ£-/ pÊü#`’ÊVeÅ¿|)üC§.+^l;`þ±ugÃIJáßÛo¿ ‰$R2ÿ+WüsNfâkr/ãü'_÷Ó]eÃ?˜HYðÏý¢œÃ6HÇokŸ.˜Š¾WGïr&•8ÿ®µšø¬Rñ¬×ÿšZ7=æ^ÿ›_sø`kÓâ*-[¸ðT8Sçȡ砛6ÎCØ¡ñ©lEüK,â_>—`q ŒÒéžøð'ã߆>f̘³gÏŠ”¸JŸx$'zŒot•¿¾Og?ûþ¥?;õãøggîxöÓÞ>¹œT‰"þ%ñ/ŸJÀ?aùÝw•&qþ?PÆ×ÿÜ5…ñWüûô…=ÓgîØ(3‘*NÄ¿Ä"þåSÉøç÷ü{ Çå_*ðΤ†¿Šçøýõ2©ÂDüK,â_>•€%xþø— ü@ÙžÿÔæ9ëÖhø«þýìýÙÚÙÎÏ×ßsF!†€*â_bå§úˉ­rÉ/}((Áý/¥yþ=ø²¸ÿÅá›Ãtc°aÞ±,˜•#wPHü«PÁoöït­ÕÄ¿`•œ¹a_µø°œUòK/XÇž'6¸`åÞÜV©²T.üãoû¬5W{ÿ™+†CŸE™©¤üûpû„slc<¿ô•7þ™*þ¥®/cJ#iÚø¾ò¥÷ü*XeÂ?ñæÏãýŸJÎ⋪RòaÎ6ȳ¥¿ÕúÆ^lk¿b üÌæ§!™ ›0X6¹ˆiφZ5°ÖAåA×¡í£¦Õ½pDα‚j4vj÷ý³e%çÈ<¬¸ªYÚm×=ÅŠ†t¬È¯6½¥ºÓ*Ý“9Éõ¿b?ÿNÊ¥|ø·žN~V¬Ê‚ÞÌ÷_Kñs¡9ûþûà§- çû>¿Ï­Ï{7~ì>Aç?+S9çŸ.ÏøF‡¥øò»P)ù€úyEs`Ç—zG{N)É6ÎSõp;ÔarRئ"³VeöÌ=5j¿ÿ,ë÷áŸ^?3¯‡Î’bª÷Y÷UgV_úlñŒTrqþ¶:÷ü+åàTRþAô_ñí/ÆùOCÁKËQÄ¿Á³Ÿ~tæøž“6[}úÈŽO>¯Œ•àú_{?{æ¯q)»Ú·±†} âxC–×ÿš›› ùà»!c$÷Ù'¼Ý½öHËKgÞîûÄ£Μ<±¿øG"ˆ‰•þ‘¼ŠË¿©K·ÏÓ>û'îˆÉüûi!ð“÷O¾Ùµ¼¯n¢ñžk?¿ÿšD:"þ%ñ/ŸŠË¿¼ÿSðoĈ© 0ÝïùŠ¢Ü¿óG"aÿ‹ø—O• ÿÞ~ûíTHü#‘’‰ø—XÄ¿|*Áý/O \"OŠ÷_ï?¼ñ6-[¸ãò&RA`ªüÓ)Ç>íÇ>ëǾúçH."‘Ê_Ä¿Ä"þåSqù.öû¯ÿ@…#°üc¢ñ©âDüK¬<ð/ÊýŸCM ø',ÞüØÉøwàÀáÇò9x≔LÄ¿Ä*9ÿŒçü”üÒ –ûr–€·‘]¼W¼ÿLà7ñ“f=¤ÝÏ øW8ü@Ä?)™Ê‡ìCçLÃï)2"çíû™‹QÎ6ÆóKOM!o㌦T*Jâ Òñ†ø?€ãò/øˆ$R2• ÿøwjGÍUüÃßE/5? ‘µJÊ¿8/ÀNYy㟩¸üÿvÏp¿ÿ¾¸5ê!d2¹"3þ‰7 ÷²—ºc>öÜ¡Ä?†9Û Ï–ÎÞÿ"^K-ÆÊò]0lØ„ d¼&Æ}¥uè§û¾¤½¢Úý˜ŸªYÚm½ÿÚÒ±"¿Úô–ê’óÎTUã¿ØÏ??2™\aÎÿØWæ4o×ßÍF„ò´'?Ê2UÁüû´¥áœ§êæ ÈYW훿5­vvŸçåÃ;ÏŸV3mïgrViÏÖ‹¦­Üý±œåŠ5úc`s ábOKWïBc¤ñ¾2M*:ÿ´:uy*aÂHæl“õ8œ³zs ¸Ä?2™\ sÄ?6¶92¾ÿ ±ÿKòˆ@þ]»:¶òêú7e‚£+WB‡G®?ú…LÚR½ Ò¯¬íÿD&HµÕ¬ôŸ®éÅ﨎uíÏØ‰á £~ù5†JÈK±ãñ“ ÉÆ?¨C×­³ÐÒ=â™LNÓ¹á¾Î§ó]óãã?AÁ¢¾„ç? åŸ3 äRLž–®èüqòS”:í,üc'3]»ü32cÈ¿ûÆ.jj=Üô˜{ýo~Íჭþ?2™\aÎ ÿrÚ×Þµëî°#°È·€–±Ï"þi´C. ^jã?$~! µ!MvFÎ!eË?p¼çߟ ™L®0ç„ìÊŸ9&àC½Cð‡ÿbP㟕CójGita‰1®ÿ!^Ê1œ—žk ZføúVæüÏ¿‡?ünüTÈdr…ùïüëüÜÿâÿ´{^ø½0ú¥ÁìUJþÅ ~^ÑØñ¥ÞÑG SJ²‡óT=Üuœv£©Hç¬U™=sOÚïÿËú}ø§×ÏÌë‰Ë¿ 3-£=Òódòõ¹yçˆùœØWløJÊ?ˆþ‹#¾ýÅ8ÿi(xi9*.ÿ¦.eo»6®ÿþ0þý/ðƒþÌ ™L.?aå\ò/_*1ÿ"0ˆpèÔeÅ(ñõ¿ã îÇ߃ÞÿbüT”‰dryÙø +ÿBUrþu¶û@µt;ÿœ“™>Ï畱’]ÿ¯}ùû”ŸŠ2ñL./?aeâ_¨òÀ?’WChü÷ÀÆÁ†C eÚÈä¡fã'¬Lü ñ/ŸŠË¿Y ƒŸ0¯ÿ}ÿÖø©(ŸÏ´ž8¹«vGÛ’íѽ£vç‰SPÖ¨Lj6~ÂÊçŽ þ…ˆø—OÅåŸõVOëM¡ÒÆOE9:ÿ~úòàž7v`óþU¬xíþ嵓րçܱ`üUSþtÕ”çn_ R CNÈ¥ˆd²ñV&þ…Šø—O 3p•ºŸŠrtþÝX=Øq< þ½1ëõþŽCŸp­[·îנѣ×ÕÖŠCòÿÈd°ñV&þ…Šø—O•ÿ@Éøëƒ-GYñãïY0§ü›008°ÃLÌÈÐh‚'=E/83¸¥ÁLLÝ×î0É™Úø +ÿB•þE¹ÿs¨©løwðtlž?wpò–/ßßÚtêæªÓfÖï?+ø×±±í•… |à17Ýt9Óe7Ýt#ÌBâÑ£G%ú¸rÍ¿†ÁÁ3ƒ×‰90ñ¯Rmü„•‰¡*9ÿŒçü”üÒ –ûr–€·‘]¼Wøýg®R·ñSQŽË¿‹^ŠÀ]6¸e×é÷{røßö¾°@ÿšÖ4Nœ8ñ'Mœ8¡·÷€Dñ/‰•jã'¬œ?þñžiïy)<"ýã óQÎ6ÆóKOM!o㌦T**[þÁD¢k—} EÆT>×öå{õOþhø™1£Û»ßZ³Oò¯}CÛ ¸ÿþ›n¼ o¼fgLŸ^[[³½¥ECù'ÐÅb±$všEg–ÁYäf”œÀüÛ28¸`¹œ¾êpÎUíAV¿’Ó®YU"hÕ‚ *Ü–X…ÜvEÿ…Î N&Þ1Hñ­–¯Ž"·ÑCH±®8F¯ÈØø +çì Ÿ3kG¹y×Þÿé| ·¨*)ÿâ¼;eå¦Ê‰àPþjé—ûNÊÏ%Ÿ=óî{“'žüöß¼·`Þ¢_¾ÐrýÏ{90 ÿ@˜(2(ëƒ3âaBDv‰´åƒ "òOÈt@‹3›ÀˆL­@ÓgÜ: þÄ"¶"Nq<-ñæG[Çüª…ªn¸ÊÓC¿‰Ñ+r66~ÂÊ9ãŸxóç€ûþOöÁ#44f‹¢RòaÎ6ȳ¥³÷¿ˆ×R‹±²| 6a¯‰q_iúé¾€ïi¯¨v?æ§j–vÛEï¿v‡t¬È¯6½¥ºä¼³UU¦ã?ðÈWO~8¸¡wð;Ϻ°G½:ØØvìôƒw¾ó½o¼óÇ»OŽø‡w«~¹gÏ›÷¬¿ÿ3!ÿpF¯Œ5„øG&“ ±ñV&þ…*ü#yEü#“É‘lü„•‰¡"þåSÄ?2™ÉÆOX™ø*â_>U2þ‘ÉäÊ0ñ/TÄ¿|ŠøG&“ ò¹ÿBDü˧ˆd2¹ ÿBEü˧ˆd2¹ ÿBEü˧ˆd2¹ ç‡âÛFòU/`ôwôvPü-À"‰ø—OÿÈdrAþV®ø‡˜§„ßyÍ@8¤ÞMòñL&äÜó}ÿÖýàÿàÐùþ;)@Ä?2™\¿uÁu¹æßé®1蜧8úÝE;>’ Åñ/ŸÊœ~†ŒìB˜š››¿úÕ¯¾ýöÛ#FŒ9r$IrA}÷ô{Œ=9üo?XÂ>ñý£¦5~|ïí= ¾|$¤¾$jËHk®vÞÔ}r&ºË^;–Ûþ“|¿Y@Õ9⟺ø§˜ç~— |€À9ÍÅüŒñ/Ÿ*þÁDD~ùå—j⣆'4ü̘џ½ÍÞÜ*ø×¾¡ÍúÁ÷Ó§×ÖÖloi9zôhDþ‰¾oêyÄœ€éî_Ã'™Xg‘›ÙÉ‚@ 3euja5 ± îÈÉ‚jV•ˆ*Dv–5 ©B¨]½µ5¨…v uK5â͆:Æ„ 4N*¦òÏ?,>ÎãüÛ£@ùE$XDã?¨œø E 0Oñïì™wß›<ñä·ÿæý…óD¢àŸúþ­ñÁÛ€ïߊ ½qEFk-œ Ò8S*žï›:ÕÌ«S@•c*ËTß¼j–uËmð¼ó®WùP!ÞgŽ•P- i>ã HS­óUUz6<§ås¶©ä*/þñë|xìü'þòß'ÛÖ¬%þ‘@eÆ¿ >|̘1gÏž)^}vüØéï|ç{ßxçwŸñïVýòÓ·Þ‹2áfƒËÏY¢ÈdfBY1PA·$-¯^P/‰ |ú"· £*6oé´PxÇtáEz64Ô ©„*3þ1쉟~ÿ‹Ï§á3ñ/Ÿ*'þE†z7l|ûï¿öΟý—“çþõ{/ÎU#BƒGmiÙV[S3cúôx`ÌM7]ÎtÙM7ݳ¯,\ؾ¡-”z¨wÔ”F[`G•èõ¹%Ù”9 ÃyYͦxfP¨¾ˆÍñ%f œ€›Il¡š‘ÒW$3 á>£lîkD«”•ÿóÔóî¹Pzþ„T6ü‹?¡ÏŽ9}ïm§¾2ìÝkþé›Çdª‡B½½½~·Ã4­nLÌ?gÒÀ‡%²{ËH(2XƒóúÔì©Ò±9¾ÄS•Y…WãÕiý´Nã9V"¸=Ri”þ‰{;…'ÜEE‡ˆø—O• ÿ¢ÃĆ€ÛšNÞ\õÁkKÔàd匭·Ã@b”ñŸ«µyÒñÝ#Š1ºÜÐ'Afí TÎëS³^¨¾HÕà©ÊÒ ‹P1³c–F˜p6<çé)'Ê?ÿr+â_>U6ü‹¿Yù§”øþ'À³9¹YL?OãÏïÌ[îa±ßYŽê^s½[FÕÇ–;ÉFÍMÞt¢óÇÓ–»È¥ïƒZ Ô ‹B;æV++ÖkvëEmº5Ðý/9ñ/±ˆùTyð/ø²àŸâI¹ñœ GG<¸ ÉE8ô£åâÙ^£ Êé¤:¢šU6U…jK_ÄæTݨ=Ô ‹PF¿Ž¹Y ‡¶ªZ6}#àuÁɤRŠø—XÄ¿|ª øwêÔ©Tà’­z`Ūû—¯›´Æë9w,Õ”‰WMyþö"rBþ0þù‡çÅ塊X R "þ%ñ/Ÿ*þ¥¨S'wÕîh[²=ºwÔî<1pJ–÷( l|Söä`1¿Ñih‰ø—XÄ¿|jhñ/uùñQTžà—"ø‘¤ˆ‰Eü˧ˆ$)’ˆ‰Eü˧ˆ$)’ˆ‰Eü˧ˆ$)’ˆ‰Eü˧ˆ$)’òÏ?ýûGîûϸØk¯Ïq>QdÿŠ¥Þ¹#þçóžì‰tH þÿD­_f•VIEND®B`‚pyclustering-0.10.1.2/docs/img/silhouette_ksearch_hepta.png000077500000000000000000001650511375753423500237720ustar00rootroot00000000000000‰PNG  IHDR‘H‘ðsBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+é®IDATx^íÝÜ%W]?þÙÝôÞCï]”ŠXè~‚‚HDÄÂOEŠ‚Šˆ "þþ E@©AŠ!‘„Л ¡÷ôFÚ&»ûŸ÷<Ïw÷ììô™;ϳÉýä5¹Ï½{ï™S¾çûù–sÎlØ–#[b‰%–Xb‰ظúºÄ“ƒ}²eË–âu‰%–¸jbé‰,19ˆÔÖ­[³+¯¼2»ôÒK‹Ï6mÚ´ýÚ¸qcñºaÆâZb‰%v_,Id‰É@”\È#<Í›7ïôoäáÚc=v"×’X–Xb÷Á’D–˜áyy ¸üòË·F %®ᥔ‰%Ê[b‰%Ö–$²Ä(Ÿ+®¸"ûÞ÷¾—]vÙeÙnt£âs¤áßÂió.|7® .¸ ûÊW¾’ÝñŽwÜN@ebñÿ¶ÄK¬–æÝƒäÁÓà ‹.ºh°b÷› !.žM„º îqñÅg?þñ³ /¼°¸¼÷¹º,“øK,1?–$²D/PÒ:ò ¸½_D¸I¹AHA,{î¹gq…â;ùÉO¿gÕãßÈþû¿ÿ;û¯ÿú¯âßN?ýôìG?úQ¡¨«Â`s+è”XªÂaú# ‡¹Äê°e8l‰«+–ûD–(%ˆ@‚4âêŠüàÙ·¿ýíìàƒ.öŒ\ûÚ×În|ão/#q(á°ò½ÂþûïŸpÀÙX„œ¾ô¥/e÷¼ç=‹[$Ýõ®w½ì¨£ŽZý¤ú«|E;ƒˆâ5þîÛŸK,±»`I"WczŠ]Èêk_ûZá1üäOþdoeç÷_üâ Ï‚2¾ÙÍnV‚òSªdËðoËïöÛo¿¢œ ¯{ï½÷ê/§¹îu¯›}ôÑ«Ÿ ƒv¤W|äáB&éJ² —%–ر$‘«! ¹R$AÞ‚—ðS?õSÅû.ðÛïÿûEØççþçWÿuå>m$R¤"ôu›ÛÜf;¹¸ä$öÚk¯HÅë¾ûî;XOE"Uˆ©åUÈëcûXö³?û³;ˆ~6ó>õZ–XbwÁ’D®F0Ôeò °\HÄq#·½ím‹Ï› ‰òÿýßÿ-þæy€¼ÇÏüÌσB"îG?úÑì÷¸ÇN¿Sï4'X¼÷á°”X¼§”Û°HI!!ÿ‘|$»ûÝï^ÔWŸ¤øÜ•’JJ,®%–XoX’ÈÕA‘ü-[¼ßúÖ·²óÎ;/»Ýín·úI5¬¸B”·œ¬¬3Ï<³H–³´î3„DBá–I¤ Ú;ÖƒX¼jg„ÃRrNJñ©O}*»Îu®3‰ÔµI•¯øžW}‰~ÇÕ§_—XbX’ÈUmä?ûì³³cŽ9fõ“4¾úկ߹Á nÝð†7,”Z <“Ÿû¹Ÿ[ýd<‰°ÚÕ·/ÜOi(Ìß<9•”T'"¼Æ5®±úëÅ 1bjzu…÷1ŽH%<—÷KbYbN,Iä* ÃäAùP,qUÁ†»3Î8#»Ãî°úÉ (¿¯ýëÅŠ«k]ëZÙMnr“lŸ}öYý×@.ÿó?ÿ“Ýõ®w]ýd8‰X)öá8»ÛÝîV(Å© .)©Äß”ïA´“×"6„Àê!º)VœéÏò1¾ú,½‚púŒÁKtÅrŸÈU  ò üC‡•Ú¤Dü[(#PòøÏÿüÏ"Ñ-×që[ߺ’@ üû1X”²Ê:ôÐC ÏãV·ºUv§;Ý© ë_ÿúÛ=K•?ýéOgúЇ²ÓN;-ûò—¿\¬PŸ>YÐ?ÆAðBb~‚<ùä“‹0Ÿ¿c³$o™‘‹ðL—Xb,–$r…@1ô%€ïñX\”¦MòÂ[.Öyü~j¥4‡’Ó7Vwñ²,ÐVÞÔï|ç"l'üuî¹ç^BåM|á _("ð¾(å.õ\t[RbqyŸþm\ÉFK OLxHrŽ>_⪅%‰ìæ0鑇œ…à}(¯}@‘P’ä-oyËì§ú§³Ã;lõ_ÛQ§€ú*¦¨÷Z)4÷—”·çÅC¶,5¶`@¾ç·¸Eá½PÆ–6ë/¡7»ð½·W†ÅŸæ/}Çc(¢ßÜÏäÂc ¯Åç¾ÇàH&X¡çÕgahËZÅëKÙMaR›Ü&9åo‡·•SCÈÃï„®(¡ÊRx§O9Sz"}ë?}îe Rþú‰Ÿø‰‚dåm ÂAærGuäµX>ìì0ŸQÌs)b÷ij— bIÃaÞ„wä² ‡-Ñ„%‰ì†ò`)šð¡úNjJⳟýl¡ô$”%“)Heõ…:L­Tv%EñòLóró›ß¼X˜€X<Ú!SÎÂ^Èl8´»ßj¸sÎ9§0>ä¾ïJ‰Åß.Ÿ“9u• bY†Ã–€%‰ìF0AƒVŒkV¾°£ñC0VŠ}ç;ß)–‡Q‘bî~s¿É –Hâ{ïó¦p˜ÏüÛ2¶{bI"ë&KÍÄ¢$b’V‘GÀ¿•= ¿³jK¸beë—Õ[FLô¡ðû²ðY]}›¿¹º*c)äuÍk^3»éMošÝþö·/BŽùV‹ñ-†@&–bßÏþóÅÙeñð¯9aœêÆÙçÚäR bY†ÃvO,IdÁD òp™<1 Û”q™DLF sÊ…•K QJuåĤ åúýT“½­½Sa®ûÀ˜{ù­ý,GydA$N[¶ìظÚ8É›AˆÄJ=òcÓ¤óÌ~øÃJzŒ‘ЄӮðÝ”XêV‡¥á0×2¶>±$‘uÑä0ùM˜h]'§ï)#V\ {P,bîbðÊjBü~(¢žSNì«’’XT[(`»ð=X ™Ø$iɱM’–i»¯œŠüŠ]ø ‹*„7y3ö(ßÕ&_m ?®”XÒp˜{˜êÍ0ª ‡-Š(—¨Ç’DÖ„Þd†0 b"…Rî “LVúø=ò°ÛDì‚)<‘2„#X¬c«ŽLö®÷èÛþ%v d¨j¾%Üö»X^l©±<‹g·Ø…ï0JË‘[×qŠï-j¼”›z-þ yõžwá0si›KY#Ä`AIv[îibôŒ¼JZòUYrVþÔqU÷ÂQ†:¥çn©e„~×0Ë\®û,JÑ–¡=å{y»ðáÏ[±©Ô…hìu1vÝ˱0Fx´é.üª~ŠÏæl›y’K\a|µ…ÃÈã266=7ÇêßKÌ‚K€ˆW Ü„\î¢+”ã©‚&:E-tåùæC÷{¨ Eoè2C^ö<°‘™0‹D¾¶±‚ýÍöï¬aKZãz}às@0,iß]$(È8½w‘ ¸´I,¬p+·ºÈÅ‹\È‚ñc&DF1SºÆ†lÄ8±ôÃ[¡ÌµÖ%d:„àÌuM<â ‚ RtÞ¹Ôߘ œ Äo–è†åQð3!„˜Ð¦Âê¢ÈœWÅ‹hƒßšÈö(Ïê sžŒ²Ç1”Å©§žšÝ÷¾÷4‰„ÒÄÝ‘Ë6’øA–u F{(=Š)B.m‘HFŒq<»WŠmJ8óʦ@„µHh“{ +-Æ‚<9¥x*ð+é8y5¾@©Ÿ«E‘¿v©‡üÏP¹ôŠÏb>¹‚âß–ØKY0t¯ H)Fئ,UO¬‚WÈ‚Å.$Áb åì÷¬+׆€UöÁ~0»Ï}îSLš® HZ•NI²lm$R}&æÁWÊ ¥¥}ˆ%%®1 kNá5¦Ï _ÏÁž“EÂ8i—3Âx"G»Ü#á _zî ùä)8¬’œ ´t¾q³b áô•YߟBÆÊЖ;d«Ã„ÏÔSŸj‹¹ág9Œ¼_Š]e廒%‰, y°œ VgÝÄöo¬õ2¦ƒû(I¿¥¨òWµâJSH[êIYS,NJƒÂ`yÂT¨ª¯(,9yWzl…¥>U ü¦Äð\˜óÞîU'kSƒ¼¸Wz?J8þe¾°š]ø6M†ÇgLxñð/I<ü+BdUp¿EHÜ/< —ðBô³º’»ð–‹×tu˜9³–²·h,ë"„ʹ<Áª@Ø$]Ys@è$1…?«•4BWMËu…º®\ÄPðpL–2´GM|–Å-¤–†’ü¾\O“0ú¢ë!ÎÞ¶ÊLÿøŽÜ‰x ¤¢nú¶.1 8å°DÞÍ"á~¼$ý³h„B[tˆ:¼ rÓãÏ·gS}a/‹þ''°Å"Œ²†PÈ4CŒâv /‘/$5ð,ù Äœ&{å ´Eéý¯á©¸ ÊÙݱ$‘ @I†Ð €Ž®BBÀl¢B"&d(jIr«¥ÂÊo‚ ÈÚ£8êH„¢.¢%òyiÞ#`ò³>SbÑ7&MßÉÂ*E }—*ƒ{…ÂËÖ'ˆ%HÉ8QPˆŠ’¢t],JõÕþPS‰XÊ=‰ ícPtÙ¥h‡¬:3N‰ ¹)ýÃ@êÆ€Lë7 u2aŒÌµcÕW¶úÀ|ŒÜ[Ô!.u Ò‹z’+ºì¹ÈƒK[‚\R,²MSc™X]gQøg*H}`Â[›/ùHÀÒÕM]„Xoc’©'žxb2 ‚0%Í-Å•›@0&FN:é¤"Ĥ˜$}•²þ@¢ò"‹‚ñCØÚkü(_—1•牄p(‘”û‚§hCŸ¼Î¢AñÅA›‹†þšcÁòH–ŒyH('﫼é!ÃAjñ þ) îé•‚QcÞ“û ¡¸úꕹ0­¹u5'Ô¢°:eè@ó ìV&‹ÙdôÚ·÷.[3}ážêA‰:ƒ"gÑË;]5ÄïS üª²¦†{hÅÁM7àQLU$ðõG$ð…Uú$ðah_ô…:Íu¯!^æ'Þ yäQÆÃ¿ä[x/^¨QÇ.|óJ“d®ö™[SB)S›Ëß.ä/¤ÇãBšaØDßçæ'ÃlÑó£+–$Ò yD—÷~ÈD¢€œ$ L‰€ò†` !“E$iÎèN}0E@Yk5I($q{žWšÀG&2"‰>o¦mg÷ܘC±ƒ¶N­d›*umäE ƒ1r<ü‹`%_jX\‘î¶¥¬»Œ•û “} -1Š0Ÿ+Âuê)JáWÄ»õ·Ï"4æ÷sËß’D:ÂàDäy°&¼ï eXqEùÏCžÜc(BІÀï„ÂÜŸgOâKÃR] ?¦`íYO0™cÅ2qbÑW,c2 ¤è€C+Žx§ñ@)¾ŒŒ…1˜«ÿÈÌœcå~m¤ÅèIGè+KåÈÌaù°ôYøÆŠÀâOÇÊßs’¤û¥¤•ê™ ¯Q'ú„QƒHÂcñÄâß•¹HbY’H -¡ ¦7¨4&Ž¿»()9Hh 2Á¶ÿAì=„¦K9u TC~/ÁÌ¢Flê¡N&Ú蓲°z?T€)ø)†ÞG ±ˆ™ÇóÕ)+¯Ž1&±”UŒ òö¦8A·sõ¸×z#‘*P¼VX—xø—±b,ÅX1 x*æ¨}-ŽÔ§„y,^ç@™DªPE,þvù7}4g8lI"5ÐÁ§ìy”'ŒÏü{”Ãåyxw'Àé’Ò˜s’K…rc…YÅ#"ŒcKßL%˜S–5'ŒN"6} Åe •Yí'è"p[~ìsò6ú­,§‹‚{…üÎ)ïW+ Œ•ð¥™P™¹-¯bþ¦91„Ó7'Ö]H¤ ÆÛ¥M~ß5†\͘pØ’DJÐ:3\Aïc€\e0ß©êx‰> >‰YB*ÇPeåGÙsHXÃâÄ̤±Œ8¶¡ûûU}½»B[„XÈJz‚®Ø=¹ ÈLæØXJY•ŸTا_}w®þ›ó^@ÆIZÚb8ÃÊ’{ïÃHsb±©•!`S«9.$L9™ÇCI¤êÄ^‹×èCrwÊ)§ìC,ÚIªS“ü-Id:©L:ÚÕ4Ib0RÁ1,|®±¥ºPÈ£­œ1§ì¦VvXT,Ö–xqºC‹¬C_LYVšÆdÑHc÷qdH(+K]6t`›~Xz"9:†×é‘à"±/üXqeb „1cHÄïP¬œµzκßëcá=dqÃfi¥¼ÆößzÇœ„è^¡ø¼Jà[(¤™&ð-;–Àç¹ÚÅîꎾkª{z¯EýÈÉÜ$2bð0í§_ʆ@¬ä£Œ•˲cãgÙqÛx•ÑÅq¿&¹JŸâ«3‘ ² .‚Ï*æ*vy56–¾b-°ö”Ã2à’Ú88”©òšÜÆ2´à°ôÕO;)ˆ!á4 ä i“À4ë­Ÿå`Ô…«Î¢Ò/”2áΛ >ó8M—5l9+e{S—®ÐÈvŒÙ¼2mí"kc!\B™u 8Œv“]õ2V’úŒ"õ5ÆÅø0žÌ†™÷¯òn>SÆ¢AÞÍ¿1ÇõÄ7O@¿Ì ]_#û”¼¢¿Ík¤oþÐA.ïëÆ‹N06úÍwªÑ÷ iƒñ»Þõ®B.Ž=öØÕOvÆUÒ òh[®KÛ,`‚„øÀãM½ÉØt·è>„liÛhO•â]¢}] 1˜cuã¥î’õé.|s ÉD^LÛîÇx¸ÚäD‚<°o00+“G Iùë`JLç\.¥ªZq¥œ¡Ê7е –ûJ XH¥‚0†DôSßßsŸyBöÅ› †¾ÇØû.«˜5éQfþFرT2Ýåò¼4mWÂÉ[ó> M޾øh§6ªWJ‹…e’(—ç#„fű†‘šû±ÒÚ,,˜+œ¥^úGuÑ È…Õ@‹€±$cÆÒÑ”U:6‘æEŒ¶ÇØW_™ só` ÚîÅØ)ïKe'ßÂ`B•6Lòp ‚TžýmžÌ…¹ï†ÎœpÏÔ°rsš÷õ⿸˜3 ŸW¾ò•ÙýÑÿ÷/Æ(°Û‘¡e¹p»07â¸ú€û¨,VµÎ!ÜØ¸o9Í`ŒAJ", IK®$Ë@>ó·ÕKc”UZ‡¬1“[?. Z•ëãýTÊrlY”‹Xÿ¥Ê ÉPjÆ‘°†Ék+–IVÅ…w7ô•á¡ /}ïEi1†"!\>‡Jß—ø <^ Œk]1·R_ ¡ÿÚî‰ÌÓCòìùÏ~á•Üç>÷Yý×݈D–ócµMÕC1'‰hëœ÷2ï‘‘Øô[>๋٧9°!¡JszN¥í› ú¡-œEž¡I¬KÑ™yHBäÐpÐÄb$H”5¥˜&§£Ì±“^]ú–!©KY‹Ç ­°„ûzehO× R†‰g¥†Õ!êbbZµÑGAøîÐûWaʲšÐå>ú–Ñ‘î—à±·è/ÿ.ì'éF?=Ö¥O_ŽöÌy/mŸM÷*/®(çÀÊ¡ÊHà³:Ògsµ ºä'¦D´¹É!»ú€GX‡uE"e°¹¡:ÔDЩUÂçMÖ¿ø)1‘Y,Ž©RŠmåtNîZf§`ä>(”dâ"*C=ú–¡¿…š‰¨.öÍ ™<~3•â7NS•µ(¨£É¥ÏÊ'éFŸõ+i¯)+9&á±Eïð®š3‹Àœ„ÕW©§9°r¨Ò˜)ÏX”=Ê ~ã3d …úÌI"a„7Ý“¾â…4õú ‚žG4L¥›„³Nù›¨âÖ.¤aR‡¥X…)H¤ WÙqm)±A‘¤N•µ×¾PFŸ2|efòpñãY#c‚ß^H¤ ê]u¬ ’ÏGÔâõU;¼…ZÛ¼ë.˜[±ïN÷2GÊ¡ÊÔ£4—ƒøy)B” ‘Œ©Æ§ôP“BŸî§?ët# Ó¦P¬)‰vƒÂóH“æ®6aae¤Ê?”4‹Ú†7‚aÏGÛ ¸×Xi*Cû¬ðáBkcÄn)“ÊK"ú¬­ }l’ñ±Âä`„f„jºü¾ ~¿»)þ69›îa¼]åg¬{t"AŒÔqä7šÜôÁœcà^sô!Módj¨x”)ñ["nãŒq(O$ð¿S€YDûêà~M¡,ˆ•YMc¼&$Bð†’G <åˆmRÒþ61åÊJºQÎT€6QÒê%ÿÁâ!œuIsõK"êѤ@"”f /ˆ÷‘žÞÙöû6»1¿O1eYëå¶hÏDÿ[6&ˆå\:+P8¶jåQ“âr¯®óh,Ü‹ÜÌE‘H¢ÿäO…Ãy|D=ÊG²Ç&Ö!{è¡9=ú²í~Îj¬$¢Su” äa°F_¡÷“‰eÀJàŽ²ª›@U˜By—‰HrÚ¤·"„×!É×t”hÏ$RU²ŽP«BˆO̾û#]yŠËê#a1‹3ÈœqÖWßù4ämÎ{•ev‘¨º_:>q:BšÀ1é^£Hà·í5š›DܯÍY7á,g@¡§ô žê+€Ê2 B2’“OÂ,=¯©Ê0ADX[rNÊ™K±Ïy/0‡*u¿ã9¦¾¥ÊKœˆÅÁ†<É{ù±¾óeÈHלH6"\Ø a¨,¥ ãtn߆Öu[qe Ÿe6Vé‚:©ßø Ðêuaé×=s¤ ê1¶=Ê  $¢•´izÂ] c4¦©â÷j’°ŒÅŠyCZוHÊZ¢Ì-Æùã —-bý­ïˇv µÔ¼Ì5VîEÆç‚ù=åý”U^N— w qzNøXL™Àh_I®IN„ ¦ž²¸0_W¥®¸²B„°zB?Tù§PN_ũ֒³ðXvqDIß|Lб$¢¯X0Üf*ádñô™àê0D‘ÜK×ÝjD¦.ÈÌØÅJ$dÒF,cêÒ}úg,溗~ åG¾Ã"Êd óXâ°Cã¡ãÑ÷X÷š«]ê2çx¹ß”$R퉲+ä"y_^`Q΃Eß¼:O̵.$2›'¢!*…<"in\éÀ«tª(ªàßcÅUÄòÅÓ³›”3‰ô)‡EÀBP?ƒ,>-:¶.úiH~Kˆ²P¯67µ Æ©Mi4A]ä©ô‹éÇó3Ê+‘b‰k±]š<‹^›ßú%¯Sñ:C'ú´Ý‹¬±.ÛŽuA(Æ#Ý„G©¤2ó|Ì¡ÔSç6%;%Òû•X¤y0F"ò@$æZ®ìãUºßºg©¬Ê´‘G É!$,R‚KYDzØ* na•™T‹Ǻ6á´Qc”/è¯>eègÅb¡¾1B¯]„¯ õ·*E_"Ê©M@›ˆ…gG¦ºx,cÑÖæù¸ïŸ·çÀ|B{õ~=C{ªæ^Œ}ùXJ«¼ üG _ÈÔœBb.¶an™û~ú°é~æIO¡6Fi¸²ìU6éæûmúb¡$BP5ZœÎ‚«šX¥Ë Ào#,þ‰Â¦e±Ê™BpÕ·©m–‰MŒ­|l|”ѦŒš Œ®$Âj§T ˆ Kˆ•1¦Æ­ïï--åbÛÑKÙð@Æ„õ‚X”ÃkóXE,ۑɾx¶!'jðê}ÞQÅûVÓU¦¯bƒ)ˆáëÿØ„1|Ö2¹—4q<;Y0NSÇœJÝ Ÿ¼s@¿u™‹C ÜˆáËw™Ï,áôxv¡ÈH—ǃÞ íjSzS!tÂÜ÷ëK"UPçð*«øt˜HÐ3gŒ"oìÒ1B"“&Ö)ÄIs¥Ñ}6”¿ðvo¥ °gÕ¸:Ô)ÿ¾PNª8 j„‰08ë+Ž©C üí®*CÉÁðÔô5 @Ëá"eŒ­C ¨ ˆ÷A¹7‚é·U¿ªÌÚ~7±rH¶57j¶­ŽWï}Þˆ|RfS>iâÏ `ÅûEb‘$Ry3îéñìé±.éx0Í«tÕ¥E§tAÜkÄ<šë~S’HÈCJþƈƒdŒQ$ðã„aÌ_ø…_(~ç¤ÞenèÔC~<Ôó(CYPx#RBU ± ef(R2Š}(”¤Îe]uY?¦>!¬) è+n§Ae9X²Iaš°UPÆ1žu¿ºPÊ«FØ1õÌü¾JÐ†È T•Õ„!Ä£âáÕKÞ§—¾ùÍÙ¶\A‚WïóFïk‘ßk'&oË^9müЇŠ÷‹Dß~÷ªßòx c«ŽX¹”VÝîû2ÈæPYꋵ ‘¡:u(ܱ£Hà‹¸£ç=ïyÅG,¯yÍkŠg${ì±…~LÑØCÄä2 §žzj1á42®>PŽÕ,j•WÙ.OË«CªüÇ@9È‘W$…©›c×6Æ÷Æ(ð2‰ 4›>ë”#j‹MªÇ¢U¿g½G]bGnU²mìýSLUV±{ š<–­¹'zq>q.Ê-ç‹¿úÕâ}+x0¹,¥-ð÷¾O|¢‰µòÁ‚ ßºÊîX¸WEËèH ¡xÖä*vß“3¤‚\Òó¨ŒÇ\íš[©›÷‹òBê ?«îiŒx!Ï~ö³‹¥Þ'žxbAøž­þà?xúrô FÄ{¯:¶o§ê“Ò$ea°ðYÒMá¡.Ðxõ£¸)8z ¼"®^ßÁÔ'n ©E¿"ê 4¹!l®£SÜ#ý½e„&±cÔE’µ®.>7&ë)±Ø´9rèe'bɽ°óòß^Y7Æú-'þâÕ•—qé+_™¥=åï®ù”10]äe,ÜgŠ{Y‰gaHì¾g›‹éyTˆÄcxô …mR !´±$â÷!&©0 .u™’Dæ&¤ªÐK+±¬z,ÛN;mÇàݨ¸ü½ï¯ÿz¶5W‚½ó)#óvшñYĽè›ô<*ºƒáɃ1Næí"u1æTêkE"M÷ä}@ç%¾:ÍÀ¸üäÒ'abÅÃv'„+®Tzˆâ/#ß§,‚Å=#t<«J„Ц€¾Ò.u¢ŒÔIÿˆK²À†šß!ð{u1-”€«ËÁ”áþc'o`ʲ†¢±|ñ‹Ù^}¨ç¿Ù{#®âïÜó†È§\‘[Ûò)@ÿ-1>d¸"±”<}Raì“0ÿÌ%ËX‘=ožçÒu÷} eÍÕ.˜û~úÂÕF"ä¼É[íµf káKÉ#ÐʼnP kZÜŒ5]^qÕ×£©CÔ³kYˆÕ"‘Ǫ‹¥ ¦$µ¾ <öX„§¦o ÚP衊W¨ÀŠm $-*hÚ§S…)ÿJpv!–|ÜöÉekãêØ«uÔ¼XœÊÿ¾ýíÙg?øÁìãïxG·|ÊHƒ9ú/ä}®±r¿ò½È|ì“°ÁÕª"z'öIè #„X¼6mÀ ø<Õ[‹ԤЧFè¼&‚ ,ïmßí½ä‹Q÷ƒ&å/wÂÕ§å„?ä>ª*è¶nðú  pmÅP Oì­HÏ”êRF¸®åÄîwõ"üá©­‹:ôíWž'Á†ÛÚgQA ¿™ŠD`ʲêЫú6ò ô|춇¬V/ðÙ9áðK¾ŸËṫ†LUò~JÌÑo÷"+C@¶Í‘6˜<–t÷}ú\ÿnù¾}N6àÙwŸLŸ­Þõ^SÁ=ç¼_È]Q"Ù¶="°½„¦Â ŠD¼‡Äð’_±âª)üÄ2ÅäQVҕӉ僾‡þñ;ˆæœs²}åW^¼‡ª~`H,‚X†ôy_è·9îp?2¶HhÕšŒ*óTÒ>öñÔ£ú>“º#Cú ‹RŸd§í~½ÃYmpS+vt÷OÇ6íh‚ÊOÁâQމfE†5…ÕR娄©HD9) ›£¿Ba7õW¹Œ¾¨#!}G•DMx¥ˆ{éËXPáX—tL„ÆD`Xíqdˆpµ£BDDº>LJÛBÍícÌ7ëå‰Ôõ*NȺwS ȲÝ1ƒ9•'&ĘMIêÆÂîS7â[÷TF$ªíðfÍp»ö—ïLI"&^U"®[F „âJ~?ô·U˜²¬:8ŽäF¿ó;;<ˆÜÓÞÿ¸ãšóBU–êªßÙg¯„ºb9oñÿ ›_ÿúÊß#ÛÒ‡XÜKLH(¬ÈZÈÌ¢ý×gnAÂ2&±û>Ž 1ßm |…®Ë“ª;Ö%%­9@&ÚHkt8+]qEé[åÀŠmc¯.Pù1‚ÍedYsÁÀÕ­ëõ™‚DX&q,2èû¨Ü2 ô…1ŒßSéQ%]B{!CëP&[ñ"–»Œ…÷ôO›R-—µ(lÊ­­=óI½Ýƒ(þŸ¿æõ¬Ê{ÄÑ'Px/¹eZ„ºV¿·Ó,Ê?KCZå96UÄâ!™©r,u0>S·©!“sÝ>âØ(Ì e8ÊÅ2Ü·mǺÄÉ9d´¯M_g)<žG ë B9•E3Ô!H‘ fYÛ`$DT—4ïŠ1$bÐ…ùäŠ0·jÛ©¿uK"ñû>G•¤ð×PANk|(.†whœxi& wß$Š Te™©GlÉ'‰e¸ÛJýSŽb)ÊÿåõJíjYUSÄe4¶Å˜×åcz‚!Ô!¡°>Ц¹¬ç˜sÞoª{ÑwUǺð^âXá/Ä2õîû*tñDxR½<¡ ‘"L•¡Ž˜ŠDúz":Q‡ê`¯óYÖˆm¨òO¡>C”7ÒJ3u¶ué,áC"ú!=®yô=6(ï¡uˆßÊ›ñ>ô%fÓ—½'<3K*­ÙO'PXf®pù ðÐzôBÞçßxÉKv„ªŠÿç¯Æ"É{ì„\ÞÇjýÐOPß!5–±ŠÚ¥Ãão,}Ba}ˆÅø¤÷Y$BvG©}êLª8Ö…ž³Z’q¬ßy$ÏbO‹¥ÅCg,±Ð #‘Xqe‚§ê=T¡OY,ZIs‚-öhèd«¦"‘>å°š)JŽ PØ\Õ±;„DÜ“`4á4  ‡zgê0¤êm°WG$uú;@a™…Ëo’0t$)Ç®~Ù ú8±ü/Éï+De‰î6J?Çö¼G•’Ìë¸K¢=—É‹rKò’“OζåŸ7•ùý›–A›rŸ‚XÈÉœ$â^sݯ‹’îÇ‹¤´\…¡Ìà²ôX4!ttúø[9—¡ÇºTÍͽÃY ~WúpÃ9=¡4V)&æ R2ÜÁÔ:˜ŠD”Ù¥߉PefÒ9jAßu-£ }Ë dcUšÉoù0ô¦2Œ}_A^”=a{†(¢> _áò Ÿj IJmÕ/ñP£!a˜²å¿_®Wþ!'‚»ß½Û‘ïùwwI´¿å-Ynye[ó1¨*£Rá–=šüu—ZOÄØ Q¶}‰Eø…¼N•ci‚v¥sÑ0‡æ¼Ÿ~¬"-u ÈyótMùñ·ÀxC(Æ¥ë±.Æ«$'[‚©B”Uî”°ò%õ«Xs*i+G›ãàF²d¤ŠRc”7˜.eÄ 0™åN¨çB1fŒºÖ½„9W›õ$Vuÿ¾u %IÊXýB©‘+ßÊJÍßBzÛwkGškÈ_Ë–ÿMžþt•+Þ 8ä=Z”ðÖ|ü/ÎïyÑ7¿¹+át,£ðhòöÅݽzïó¡˜b~¦h"Ë^õs›Ç2æVêsßO?¶)õ€z ¥ÇºÐåc]äVâX—x®:c̽\U:5@ŽHÛ3Œ ‰À‚¡³Êå4ÂG  Ø9¡•÷¨CU9CÐDoˆlâðÖÊ¡>0p…âe4)pÿ»ñ…ÔLhÖIŒM}Smèâ‰h'LŽÊ==%3‰êêA©YV™*5—±Ù'ÿ· óþù|NlŸõ«³½Vdß'ÿ·Kó>Û–ËUÙòß+÷¢¬ÐêƒíÞL^‡ýú§³9‰®DŸ ñDº"ˆÅb †T›Ç2±éE¶©Œ>J} hߘûé›ò±.æ%=Ê3f°XÌb\„†ÄŒ.ãU5.ƒ<‘¦AŠN¡´SO„ÐÇ.x ÒêGÿùÙ^«a¡=ò sУ•š[f—³ü£žùëæœ¬Ðꌼo†ä1ôÉ.mÊëç”ßøÔ«÷>Š9H$à^1æ}Ca}‰…LƽæÀÜ÷[i‘}/‡l‘Mì¾g/2NÇå…/|aö¾÷½¯ÙOÎR!Ê*Ë_9±ºIâT,\ã¹#]’Ѥ$âÕj!¡+“¤)œ–‚À­‹2Ê <=ªD™œ&kô›k ‰¨C D=Œ•BKåãnbܪ~?Ë©Pì›rå”zŽk¿Kn œùªWeW®ÖûòÜPùïg<#ûQn‘‰#wJPRü%ofp£*Aß²š«+ºÎ¡1ÐOM÷™’XæVêî7µR¯ƒ{‘õ9îg¼}úRÚj0cÞ¼ÏÇÓžö´" ã1¹Ç|A,'tÒ.Kñ¡×¨LE": ‡xÞ]ð©òƒ 5É(‡Jêà¦pZ uoT>–Á Bcõô®}äßÇ(qB–þ^¿Ä‘)ú©"³*培 \FT(v(/µÝ'wõ¹Ï}²Ë¾þõ"ñ½ù›ßÌöÎ'ø²~K”±òe—%•c¿ºñ6¼æ¿­Ü _Ñ·]õ¬Ÿ©á^}ï3”Xè‹9Ú WÚæÚT6×ýÀ¼NI+Žu±:׳Ôõ½þ~ÉK^Rx0ö+ZÆNµn¤±$â·Ö:SJ”%á‰ÕMC0‰HTS ”†úô=TÔe,‰D{$ÀxB&NÛQ%eÄ1õˆßSúD=Ll}ÒVŸÎÊ¿½F•b¶ªSξ—ï†ü•ì Š#G‚’+_Ò%•|íßȾÿ²—e[W½Á®Š_Ÿðå/ï²'¤¼¾vEXG QìCá^S(¾.Ä"Œ‹ÌÛ<–©`ÌM"©R_4ܳ)º"¢ýxÀ²?ú£?ÊÞö¶·yP yÊèÕK9dÐ!0-¥¨ ƒ±$«‹$˜Xû¬lÊcÈ$Ôác M}L ƒÕõ¨’2‚†BÛMVK‡‘½±’£ê­"Ÿ Uji9ÈÛ¼‹E …RÕ5]ùR,©ÌÚ1¹‚»ÆQ+›ÀNÏ'Ò{_ñŠìÄüž~Ë[Š÷rEǹäcb%Xe.…²ê²š«:÷Ùp¯¡cÛ†2± 28UŽ¥ æÐ\JÞ0oÕ—e7÷lj¡{ºéNßhkÄO$Âv!SŒV `³):H­ïÄñ›XF¬“ÄøY£c„Æo‡*oä!çaC˘6ô„d¿ªHxdêÂ[4F}I5¾7…"ëÛöJ‹¾ƒrn»oáÀÜÅ¿æ­oÝô÷Èn•l± ,ÿûÖù8•{@úÍ¢ûWÒóÈ~Ä­³¬s.Å÷"ìÕ‹Tìe÷9ïeŽM•ciC(ö9ЦЧF»Mžˆ(HW¶W/¹iT  ˜LÀ '«šRŨú–Ó„èø®ÊÛ‹PÁŠeıÞ} \ß2|_ŸâÑ/6Ö©ËR¾d¦_L¶XL ´“.îŠP(Sô.'HÃï(à]ÿ¾n%–~fÇq.¼5¡0òǹ ”ñýaNÎå•au¹”ò†Hï»BŸÍ¥Øç¼™®Rê]Ba}‰E»\Wuiºgx"]Æ·7‰´1ºÉcÉ«LX€5[~vEQo%QB(¹.Ê;vU ŤeÄSš2úYUI|@H­/”Ñ—DL&cÅS´¡à ÍQ¡;®0´œ1 xä ¨ÏJ,2çÂHA,vàï½ï¾ÙgžûÜló*iXöÅç??ûVî9ítœK~:âꊵVì‹@Ÿ{Õ 㨠±tQ²SBÛæºh£¾l’“®{D`§Qi¾&ñy,#A(kZFtØXÅBÕTŽS0íÜ”çN=¢@¨C(ï6ÅÇM”o°ƒ”P§Iü(c º–û`â´_ýb=¹¾Cúµ|ÿ!JÍoz×#¿og¬ŽmÞJ®ðG­ÄÊaÎ š{þÌÏd›sïä¼Ü9#—Ç9ÉXRœçò•\©õ!®2ôÙþ‚9ïE¦b¾=TÞ¤ZG,"(à1CBa}AÍI"îx“HªH„ Eˆ(¬êò‘ eD‡¬¬*‰%²B ,k¡§’U V]}åÖ)pqó8´1ò B!é$4IÆÖ£Mùª¯ÃxùÛDJOûõûº6tAÕý›êS‡´_:££çz+?y¿ûeûæãR‰|<¦^‚«Ì=òrËZ†ôu`kþÓsó)éµ ÜkŒbïƒEÜ«ŽXDN€ÁÄ‚àµ*̘ÎÕ îUz0ÅBs"içÙF!"ñü®Kcu˜kŠ(h  ¼ŽP§"œ°÷Þ«ßØSHA¹õ‰£J A­Ë7(cŒeÔ‘’Gª,,;Þ­ÿ.ïƒ[‡è‡)л]<‡¼oRoe\!Üø÷~ÏÍŠ÷eLµ·­- â)y¹¡sÅÛßže«Äµ5ÿìÛ/}ivn^OFˆ³œ¢@¹1Þ¶Ÿ¶ ÷BÀŸºxcvóÏïŸÝàs¯Þ·a轆€LO)[u@,,p÷J‰Á—=–©ˆÅøµ)õ)á~mžH×càa§Qiˆ ®ŽÍX–ÇZ½£“…Šú”²Æ*nÐù1xAj”v¤œò¶·zÞŠUSeoe'Û±Kpóûlʾ×6¤Äué×¾–]ã±ØøJ¡¹xÔŒ"ò.$I¡Eˆ”Ì¿>cÀóxø×öÍκr¥}^½o÷4Nà^s”ïUç±LE,s“ˆ:µÝ/ë]ÐkT'ë^GéLãÕ¶ë}, ø}JBr/”›Ð"2%?]ËBf­žC…·"\´“·Òuï¹òKøLØì¶÷º×J²_̽­ õ+—¾E>LÏBâm Áðf"I§·Æ±àMǹœŸ‹þWær³zŠ—Wï}ÞãÓuŽ…ºÏy¯¦9}‰¥éÑs“H—ûMžqS!+ŠÀß:¬.iÞSx"ÂC.JJX†’,¯ë:Fqy<¥/êÓç8— €!Ê3 ú5V±V­Òë2^ê0öþ~¯‘{Q÷f%#úTÁÅyUå{F9ƒ ¿ë<‡üßRoåÊÃ˾þâW·„A+¿ò~>6ƒ gž™íwŸûL³z,‡~"kŒ&ËZ%Š­ò3æV‰O²P>ÎE¿Çq.‡äúäè=rŹz(½Wï}Þ„.Êv*Ìy/ò:D©7‹D±ã8X[8«'²!¢fjzÀ–bŰfuD0Åp÷»ß}õÃ!ÁÌJã%ú€@é|ĵ 46ØQl÷½ï} ¦~’g Ø;–Êö…¾?å”S²c=vð„¡œµ‡ Þrò¾ \q&o3úÑxð:€±¡OLÌ (õã‘ÔxUG}æò}“X]<Ùm!Èe(»à‚ìk9ÉnÍ뤯‘ŸÒ—KãÁ "ÞN^ùÕ/U ÷ F:—Ñ<$Á;I¡ß…5Ó~GÞÑïßÙïèìé—Þ$;kë¼ù&—fÇìßlXQˆŒÒ\4ÈEIïE‚áE· âE€á›Ê>ïÄüЗ!ÿ1Ú”ýhoU»|à‹ƒ—Õ†]4U(û*°%1Áâ9;†x"&BEîl/‘?f_„Õœú‚è'£”¯Á‚ Ž!õ <2ã†ð­öi:º¾¡è‡@èÊ¡ÄWä^Ò:ø›»Ï=ˆóª¼ú, §“žKy÷÷$Ð׫ÞJ§öVäR:-½-…ÏRt.£êÚ¢ß)áŽsIúý–~œýË•ÿ™ýó…ïÏþñ‚÷g¿ú©Â«6ß¾rË«·|ÖW¾†Â½æòDÈàO¤+Ê‹P7ëÍc“¼Oa^uñDº<ŽvÖ —W"–p¥G_èXè4éZeu…FÙÓÇÆsņ•3–ØB8û”cbQpé> Â1¦o†ˆûÅkc§.t(±ç¾mPß]Й ÒuÒûž©ä [AÉ©‹ †œ4ãÁ%™lñÄN›ô㹋º•_þ­i¼òï Ÿ]°rÞG¹Œ®ù˜0v]{¹ßïœ÷ûýïö3Ùíow»"vÞ–bÜ»ŽñXÌy/z`®{¶ … !ßo#Iú¶«1¼SO@Éàˆç—÷U`/ßé£äêÐÕaÙreu/ç¦ ‘hc—r|'Ž*Q$û,¼Ó7Ѧ®e,aAõ±Cšâ%Œcê@õù}œˆÉN™Àº*µúÓïxSÚ& ¬ õpµ)qýÁ#“ÿ`©#²Ø…¯ê:]Ï;`pÄóÕÓÐÕ˜û§(—Cþ„/±I/]cò˜Hò2±ä¹™m}ºòïî²óýøã³­9¡\úÆ7ÇÀoÌïµ—ÿ^·3>@¾òI¹5'ú¾ûNºìáˆïóýdßøsû<ÚÉçå%¿çmÝ´cõV>ÆçmÜ'Ûpà¡E¿Ëµ„aÅS$›Üo iõ%FR©óXôµñ¼Ä·mòRþSˆN+—c÷-e­ÁBiaÝ6¡Iù÷AU9ÜsÂßtTI ‚7¶.ueDØ(ž±^w´Œß!¿¯S®åÐ¥zbPE"Þ×*ì ùû«SsÉÆ‚$x=ᦗf_½ÍÅÙ·osQöÕŸº¸Xþ›¶)%¡ÂÏVuò -}e–|H™kqœ %VuœËœ$2µRoÂ"H¤ A,úÑ–ˆ²Ç"Âð[¿õ[é›§<å)ÙßüÍßÛŒGÖŒDtšx©U7žéª¬S¤d4AUG•TYüUH‰h(B +'âÌêVÕÁ¿Q¼”B€×¦ÐUü~*ÅS”Umóu1\ÊÏ97÷bNyò÷½þõÙe¹u®¨Úþwîí\üîw:S« ón(+tïu…Í“ØÕ7ÚýãV¾ºí—,H¨LHOøÆ®ÞÉí÷ÛšýoN)i¨Ë¡ùÔŒrC±w ‘¥([Éæ=…&úÀ‹ò*ç˜cÌ„l.æ^Û<›s‘H ½_:÷¸Ç= }üž÷¼§øœ7I>úÑ.ŒÇ:ݶKOµYKSá—c…x4-˰íäß:茺Æõ…=1„·ÏQ%)‚ˆÆ@ÿ›DÈCˆ%ž5Òt€d Â?¦~o|º„®ª05‰Ì ãÇ…çqþ\îò€dç½îuÅÎvðÿ|Á ²SN8!;í_ÿ5ûvN6\xád2X ¼¬ÐA¸ê¬-»*»C³ÍÙÝ\5V‰&H"„ôÊ^Z„ªÂeeÒ(ƒœmÙ¶!{X’ICd}ǹ ²†XìM‹Üè*çÒ{ÑD(o.1WÜo.q?²Úd¨ sýÙÏ~vöÎw¾³92ªëêØ»§Æ’âà¶®nlb SÞ„9aTÖvº„¸üfŒ2‘̲òJÒdÒ7]NEÆ /¿0»rËðþЗ\×.¡«*LE")˪B£é€ÜB»,W`VT]ñ­oe·~üã³äFϾ¹ÑS¶šÉRÝŠ°1ÄX¥Ð#Ô•÷øê'&ô¶ì¾´ý{圊¼‰¿?ÿ+„„lšÂeMøÊ¶³ŸùÁõ "ÛžÉ_«ò1}¡¯ÒÜ–q°‹œ‘gÞËg‘S}Ÿ.š0ÆÈ9<§RwÍu?2Ùv?²[^™Uµ(Ð[SUÚbûâê¬J‰µA鎵8ÕgˆâÖ‘b¯B5~ˆÌF=VÏP¨KYqtþ¤|XþÊÒëš |òÛŸÌnôìewúû;eǽå¸ì´o–{ñ¹ëã{BW¬=è>+CÇLà@´}в&~X]QEFx©©Õlu«™²ã]—•›e°B2S¶'B]GE¨kÓÖìM‡};û‰Mï¡.§rýܱÕÅmá²rž#>»2«?Þt›béï V¾„к’POsC´Â<Óç! AZnŸ.šÐçúÞ¦iÑd£ÿ»ö½{Í剄îÒ¶9÷kòD‚DºêŸ]zªí‡}=ß“dÁ„“Tã2 !£2Ô§/‰°­Hpœ†°!¤†Q ‚ׇD5«‘±þyV±ô`÷|È+’yÑ™Åûó.=/»û‹îž]ë¯U ‚iBº¢%Ùº„®ªPE"]…q­0V±k_zbªÜxs@‰QpÆÚ" d-\)Î?æþåP×u7]¾“Ò!«*’T…˪òåÏÎݰ÷v}À›v- Ô)v}O^Ë‹&¼Ú‰ïwB1¼DĂܣ﷯Æ+a-Hd®ûѹú¬é~UžHz×¼«ÒN¤Ý¬&«Ídƒð ÆNà(§ £JX(qT‰WÚ§œ:˜®e a=k ¤Ä®SFù¬Î³8ÿÒó³]ø£\y¬ü[î oÿ± ˜ª~¦ÀôGº²6¼ê]¡/ÇŽ)(¦(k-Ê-Ϊâ}#h¹?d#ŒjEc¦X–{é<Á!;¿y߸|cv‹/ìŸýÌY7ϼåN;)ýãNß?ïÇ,{÷M/Þ)§R†žv•ó(‘ç°%>;{˧·îäá•{ §7”?dÀÕUÑúcLßóêãœ0än¾S¤BÆVãÑO怄²E5感Ó3Pß÷EÃýÚÚ6šDÚÓű‰Åä  bÕæ<åŒ1 º‘•NL¨&}$,ø{Šº´•AAXÒˆ@„ÐYú@¯*‰PUgqȾ‡d×8è¹2Ùu’!ƒ€‚„\Ö‡þóCEÅʘ]©ÇÅ]õû!dÈoÖ3ô‰6™œÛé ±"ÌÒW²À[ ¯gôÒMau!¦T韗íY©ôŸøÍŸb({–üV-Nðr ŽW±x8oÉ=\„&GÈù ¿¾g´1jõ½<‹Ð¤y)2¡ß)QÉdï‘ú¤–ÐE©O rD÷6Aû»n4„Þ£ÒD"&Az(!e‡7–§Ç Ê©RÞ„¯í¨’€rÆÖ… Ö•¡~‚ºÄ1.,Ôò€–IÄßi¨ªÊ³ð›·?éíÙQU¼ÏmÄí„âõðýÏnÿüÛ$tƒgÞ {Í¿½&ûÏÿGöÄ>1;ö Çf·úó[m'&cUÕ—)ü{Wä÷eƒ)ËZ w ¬X&¤iÞ¤ôbSØ?}ü²¯‚x³Ïí—}⢕2ÊÉó*¥Ÿ•ÞU^Ç¿±ï.y”•¿Ó±Ø–ºõ²ìÓ7ç•0>Óƒ?_¿}½Å:ÌM"]î·&$â½%w,(¬²ôË N!uEÜ£¬¼M¾.G•š +Ô¥J±F‰ 1ñZ¡Ž*”I¤ª ÏÂç)îpý;dßøóod_üÃ/f/½÷K·J¼žõã•s ÎþñÙÙŸ|äO²?ûøŸeg_¼r|GJLîߤ¸Ë^Q9_G"U†Dâû‹&‘¾õšUôîò3?›ýé^Ç^œ+û‡|eÏì´O|"ûÑé_ÉßpeN+}Eá#S"¨JxWòyñõ.-òpxîe¬ü{ÚW²§_ö™lMŠUcŸ¾dgoÆ.ú©È$•­E#ô #¸|ð'ýḠ%Â[´IÚ¼6LJœ¶$ÒÅ™-œe‚[áÄJ²t“ú®û tÞXÅÖIÔ‰•G•X‹Ð¸°m횪.i,±n9!+¡+ká›P&‘r¨Ê«÷>/ÃoÛÿ°ìf‡Þ¬ ”þÕ³O<ãÙ9Ÿ³ƒ„òÿιäœìŒ ÏØ…˜rª["¬^©W¤Œr¿\ãbÒ±â"<ÐÅŠ[Ê} Ì•®m¢|Ëý¥{ì]<0j»²ÏåÀ!ˆ‡\çÙéÊ®ÈËe¶ûoÝœýõÞ_Í^vØ÷r"X‹ª„:”Wo!"?òûß-ò(?yñ.ßAP?¹åì•ñÎ?N½™3òWy˜›}®}ãa„<¹×p¿ô^t^zœKê-²Ø¬ŒUQ†8B¤Ëiºà^s’ˆú´Ýo6O$VôP XZ|·ëY+*¯¦/‚ŒX±»š’¢°«ÂEuPFªü† ÊpÅN| p–ƒv™¾“‘÷i¨Ê«÷u Éç1 ¶^º5ûò羜¶Ïa;‘ÐÑ]MŠƒ÷9¸yÝú…·ÎñžGì’w. | 0]–V²Ø,ëø,N{-ÇüËX´'sÜ£+Êù‰PÂuKuo|ô‘Ùÿ½ü¦Ù³9÷ùžùOn‘rè_Ë^qÞ{³7_|bö–-ÎùÑé»<Ü«¼Ä7•ª"´õÍ}wùÎQò7½4Û–Ëy+{3QÊY[†m<,ƒ<»OÌO ÷kS´á-ÚSÆp¶(%tŽ(™0$ƒ¶î8·ÝkJ¸_›ND"}tù.ÇJ¸nbQ ¬k §uâÐN d±y›uÞ†“O>¹è—òúî4ËåOäM†‚•M1ê—8+Aë‚[(éïüˆv.ˆ9…¿à² ¤i2Ò8"žÂ°äô¬ü¿‡½êaðbÞúëoÍ~éå¿Tx(y@ óÿŽ:è¨ì›ÏÿævRR·ƒö>(»Éߤ Œ 2N}Ü©Ù{P Í Ë/‘|(Âðo.ë•b3ùX@qi«/Vô- «öÊý=5X§ÚÄš­‹qPÞ2B ¸å 9B¡”)lB±ßpï­á”!O!Ìdìl¾ÓÇ\xQöƒ‹.É6\|A¶Ï^{õ¶ðzÀe?غgv›/5”•×ï‚\ÿ­„Ķg*Qž{í½ÏNõ.#~?êÏ›_Ø£’KÐ.Q•!'h”A®CÆãÕ\Y§Ô}Ǫ½.FæX0úÝnªÃýîw¿ì‰O|bö˜Çî=*'é¤×ñ=n™Â­µîÜXhÌpVšpee‹3ðCIDý‹Iø‘¹ ýÂÚìZ¿ð?<¸È/À¹—ž›ýÞû¯“ÒIáE ØøØ47õéï~:;æ/ŽÉ®ýŒk¯Vl¥à oīϣ¼2ì9ï~Nöõ?ûz‘oùÐÓ?´PŽØÿˆìÙwzváHJZiÔg÷œÇ·Kf‚²€§hY4ïÕ À>ù•Ýu!«T §Š<Þ§ ü° Wf/ÚçkÛÿÊ9 ¯O8ãÈìº×Ý9ÆËÜküûƒ¿“š­$ˆåV.½âÊ솟?0»Ég÷ÉþóÌK·+¶x ]'‡rTéÈø´.Cà^s‘H´kŒqÜýe^†¬“o—>½ÁÀ*Ÿx`ÑRçõ :Î=ê@ïÐó}ÂY##B1ÙÅb´i'V8 QþeôõD40=ª„ð CŒõh€ö­K,¶2ƒû+tÔg +ÿ97*”óv/`ÛÖìœKÏ)¼€. ´Ó ƒH¾L@ê”’A¬ÔJó,¯xä+¶çIÔåÊ­Wf:ýC;å@¼FÞu»ëÜ.ûŸgÿOöG} {õ½^{»c‹%Ý}È£&›1aˆ3“=áŒXןæWÈhŸdfŠÔ`Z4ÚîU&„®J8õPN<ð‹Ù­÷ð¬hóp€ñcCänrtöõÛ_ž}ë§.ÊöÙsìÇVŒÅs·î‘=êÛe§®Z̼nH½Cõ¿ûA[w92~,Èï\ã:`.Ò ¥ÎF&é‰ñ uqÚ¨ bñÞyãÃÕ*`ntñDx¯]QÙSÊ}hL¸È@F¦ ‘>žHÕQ%ár õ"R(£+èäX>,æ@0wŸ2B±[r›‚pø¾‡W®¾Já÷±À¸Dè*¬ŒT°Ê ñ‚¨.>§mñ(ä>y§Gf{lÚ£ðHà¼KÎËûúÇIê±HÀ_ï™×Ë~ây?‘ø»fÏ{ÓóŠÏ}\ÙG¨›PVÊ&Üd’ñË/cO…d¦™h¼–ÁÇ]ºöIUȪ ÂCa”û­‹‡“BYøæ¬-¹<'Äc5Ø-î°b1Ç=â©‘baE_vé%yÙêQ|e4ŒÝ\J=ädN šBÿÊÉÈ'Ú¢ǹ0¦jÀ;Gèú?ŽsÑÿMaß ­&LB"< Piqë´C5n ˺”“U¢CÆN'J2ªC":±Ê™ñÈ(ît3e(Ð. «¬Ø‡íwXö—÷úËÚWFzÖ«% ]ÅX¥u¨[&Ìó@ƒgQ^öëýkóÚíË‘™]xÙ……§Úú÷Ÿýû‚Ô/¾òââžê=‰@[Yd(ò+ågS¤ù•TÑ­÷üJBƒÔ¢ªMC<œ:â¹æ+3ƒÌ ÎvãÏ,‡Ë+ÂúB¹s*u÷jšSÂýªH¤ êǹ„wNGÓt#˜ö?‚·J4=£­Í1NôÜèÕYrMŠðÔSO-WŸcÊ«À’wŸª•1:—"4B«ÓêöŸð˜t®ãPp å5Ž=öØÕOv@a}.¤Î Ë· ýöÿñÙ½ï}ïV¶×n ëXéD±qÀÙGžò‘"LÆ•-ƒ è³XuUud=!±Zí^÷º×Ny+¡3žâB – C|&)nB‰ú ^Šö[ö£s”Ýî/oWü.…zó¨”û·¿ð·ÙM¾Iþ h+Áì«(~ù‘>I¾*¨?Ò‹·m2é#õ";¬¯)BqU° ÙÅi³‹‚ø¹v‘2ÒÕU]tdÕj°ðŒwŒ©{ÞóžÅûÆ[ÿF_³lÍ/y¯X æòw—Ü*%H9Rš‹†ºR¾”ó°p„AêÄ‚©ý¯-iÿÓIþMØ’N5Æ$…¾&;~_·!ºŒÊYÝÆÂ*3Öò‡*OÄ„\ƒÄiÓQ%.^D”¡ƒËœç€!4IHVW@(Iå´ÁwËû?ÞñäwlèÞW…®ª”r]bG{„¯nÝÛïœ'¹h%O"AGxäöý(®‹Ï½8ûΗ¿S„Ûʈœ²~ëݿթý]Ð&‡]¡"ä#S‘_áq“ªüŠðØX¹ ”åjQpŸº~ëëá4…Ö¶äŒtñƽ‹#áË#É aGá^JÙß&Å"ÏæVú¬õªþ&OU²¾Ìy/hó † ú¿|F=J6Ü“>c4“yŽÐï 'œP|ŽØ›ôm•½Õ6y§"—–cCŸ£JUdÔ!8Q·NçÆ9`Ua´2Êe´¡¬Ø½WFª„›BWUˆúU)-eÇ2áº<‰îo<öÙéÏ=½¨K†{LÉÞî6·Ë^ù«¯,¼ˆ×€2ξäìÂk™ ‹R¾1Ñx–.²†œÓü 2±ô’L®§üJÊ$B¹9ϪŠxx(·=ýˆì‘Þ/;â3ì²1² æhºë;Ýœ‡ÈÓþNóYäÏ|jÓISÁ½¦VêM˜‹´´‰œëG¡Þ vcAÇÚôûœç<§ˆÄøîÃö°ì/xAvÒI'†tÕ~* åOa ÂÓ稒€FwUÜuÁÑ.V¿PŠ&èmç€Ô—@ô©KªØã½û–W]™t]ž0¨9‹s~|ÎveçUÎCÛ¼z_—'9ü€Ã‹Í‚¾k"Çñ1úÁâŠGýô£² ÿöÂìËÏýrñZ.ãÈýÌسÚSë‹®ã?é=X`i~EnE¿óúêò+™uÏ¥(cŽö@܇R¯Úý>ȨX.¼e¥¬ SˆûîN×§dZÿ¦ýæ³ÌadäK]û®Hêsc¥ +èÁ¹ÞÏ+Aì6Ê÷¾éMo*Æ„÷"¬÷¤'=©5ŒXÙ[mÂ>‰¸×–[+Ÿ–IßN¥àÇÖ'‡ÕV¿pGßÝÒAc€T»„®ª ÷ñ¸“—Ýø¹7.r.oøØ¶o<èwÚ~Ε}#MÇ© פJÇÄß7CA(Cè%™ú’B2sñX¬ ™2Zù…âHëÜ ò8û?è}Éu¡ª¾@N¼š3sRZ!rµë-SÂâÞGŒyò^?GŸGâX_§Éû¾ %x:.Fä`|X„Òg5ÔPеŒS†P¡þæ7¿9{ík_[„лb¦cù›lò ò &U¸´c >}BH¿’0B:VÆX~Û·.ièJÈH{ôIzäˆWï›°=ϱd£p¥Þûžï«¯é,:J;Vdľ .PF„ä\SX„0eYM{ãE Ä3Aªò+䞬EÎEí3 qJh‹~«Z¢ëRwúÒ¸ðV,ŽÓ£„®#‡@¥sÒ߈‚7¨Óıp¤ù %È4KÙkÖ¦·Ê÷Z4èŠ6Ï`*Dۛû®†¬ì­6åAÙö%,(ÆŽá$ÒL² Œ…úôQÜ&š½X™CYÊ[Ôµ ß+¯º²¢Eýü[ºzÊ«÷M o{žcuXy"®òŠ*ï}Ï÷y &šWÉ6+hú´¡Œ¹ÿzG9¿‚d„h¼'gäO^eh~¥~k BÙ§{CÀaLxË*­_÷{Ù Wœ’s»Oº;½ ÚÔ¦ØS"O7¢ú›GB9"oý-üÈc«:U—ÜÏ¥ÔµkN‰{5éwý¤¿ú`åö!G•°¼â¨ˆ õhR(§+‰„'$lc=tº¬O9u ì]ʨ[u¥¹jõTxupo9ŠCöYi…ãL„® Â[Þÿócþ¹ð~Äñ)6ã.õ"˜’Dæ ¤¦ 5%ܱððÒ£-šò+ rRί´!Ú”.ÑýØ­.ÎÎíð¤ÃÎÈåñ  ¹RÊEjèÆÈ®Ð7C¼zÊ¢òqíúŸ!Ë3A,±ÏJ$ów¨Õqs~h—>iº#ƒDQJÎpóÅùSWI9:rì€uQþ©'$ÄVªD¦ ‘ :´­º2Y(N;É«VOñš`Yî›{sö…?øBqPâýòþÙ×þôkÅ2â‹^rQq’ïŸðÁì’o_RÔU?¤ÇX€¿‡Ž‰ßV)þºÏ›Öéªí+ï_IÃ2ò*V&!r+_Ö¶E§ýKt]U;ÐëŽ>iCù>‹Yœê^ŒWg¯É}2Ü Š!…䙈±06‡žQÕ1Çæ":»í^òK“HÛ€µ‘HzT‰ BQUí±VœBq7M*»ÍyBX–ÀØ€C`Êh*§+@•öY— ƒéû¦ÕS ÌX²›bÓÆMÙ·ÎùÖö|ÊŸsãìëg}½/öËE<^⛲*ïX… ²!P¿ªßVõIL=q× ÚÑ6¯€ ¦ùòJV ‰ýa=§ù÷¨ë¯ªðÖ˜†û”ewQ ;‹º—1Ñ+Ï¡3ò =£Ê²×XÆ #Ÿ¡kæêG÷k#r4INšžò¯R¶>‹DµŽ!üÖ|×uR4h¬â®SþâÂ]`4uzŽ­KUBòBW”wÓ†Áè+§j3b 1éžÝ£þùQÙ­/ïõþ/½1LÞK·uDÐåßZ®,±™nÚK•^ÆÔãªo5ÝOÖ³¹˜æWȼüVղצè}A>›tÄ”X$‰”aîÒ'á!–ϨB2¢õvÛ§¡Ç¾&ˆ{ÍÕ ÿ0Üë0Yb½ eO„ ö=ªtžNìkBHL˜tó"×™YuÕ6XudÔÊ«; ] µ)oHI¼/?ŒÊ¿5%Ý|ųó/Û9wrÁåd·¾ý­I=àßãþ}á·êá’ 3Éô)ò¤)ÄTéÅZŠÏ¸¥˜krE¿í.Ð/©õù},\£=–.WåW¶\yÅ$9 ÷˜k|æ$‘º{ùŒr­:J$B±"Lè‘áÔöègób®vAVÖ$'Âò¡¬¹ÕX»ëQ%©7„…€ÌXâö|´u\ %€¡ ú¦Kèª 11›êÑ–t¯»Ï>ûv;GÒûû»*lVã@&œ *¡iÓ¦ hY(=}Bé sú~œåK2M@r1ÖÀX/X´ÒU¶\aA×åWÈdœWUµ:©+æ$÷šKÙvQ´ß«[ÚMÞ…-àa,!t§}Þç^SÀýºx"±À¦+jG¦I@‚DLvÊ‚ê<¡’¾‚Uöj† :F] ¥EQYÑtÈ„JA!J~v ]UAÿ™0Mõؾ”·"éîþ›®Ü”¸çÎ.©'òhº‚:˜¸Ðg¯Š:k·0JzTJ•Lh#¥–]zHKÈäÉ™xƵO¬úÊëî€hSYÉE~%Ϋ*¯N*çWš@~æRì»Ó½xÚô¡P#JèÑÅx¢Ò>×ßt_ôyÓœœîÕDZÆ|–p–†RÖþ£Jc7…Å] Ë€ a A›ònB„®„ó(Ç.¡«:¨GÓ$öïå¤ûÛ~ýmÙ÷ðýìý|цWÕ‰âþƺë^1x®¼É`²”J颬}?]’I˜•ÓsßrìêŒ6åŸæWbu º*¿’öq9‰ì﹘Îy¯1$R‹Wè$¡ä´Ïƒ{¥}îU^Ùg¼Ç¶ñìz¡Íóâ‰T{,Ú”}MÜ{j8eq÷»ß½—•]V&K‰Ó:DèJDHÄF-Ó—ES8àM¹¬á®ÐGB/& ÅÉòŠ~ðƒ…Ó6˜îí¸‘=¶ì‘½ã¿Þ‘=ãƒÏÈλì¼âɈ/ð˳ÜùÛ#1~7|Ö "°c÷‚|$ìËT¸ƒRÙû ½ Â)C¢ŸW” /A¼ÂgáÊG9j=àÞ‘pì£ ,±$Æ7 ,Ë-y*Â^½7Qy0q‘ƒ.† ÏÕŠ'¤ÕêaŽPÊ]ÚTÕ–E`Šû¤}—÷Ú}kܵ_¸lј«ï€çË¡.<zË1IúiDSæ.J_§rMÖ‡j‰cnWA´]H¹Ï¸ÖRnZI„¡s…¯T€•­qSÄ«û–£¡aõ+'4˜ÂêEúzEU«® ðØz é.e苳¾wVö‘~${Ö©Ï*’ç€HžòΧcIù~åƒÅ*­8¥ióbx"Ma3ÿù'ý&Lb¢Ço§€z—ËòOÑQ‹8ôÔa0c"¡Ýüåd.$´^ éÜ‚´ÓcE-O‘²cPòº§È¯´aÞAæ¾—¹ú<Ý3D¯Å3o§Œ0³¤=#$‹%y›¸_ÔÇ<ékˆ7ö–ÊÅ=&EacšN¦´§ ‘>ÊŸ5dÆã%ÔЗŒªÐ•D"tÅݧ8ÓЕ2 Æèß¶2‚H Ñ-osËâ9i¢Ýû ˆÓ¾uZöÀ—?°ø;…ç§#„2tL¦ª½*5å!÷ÊBâ±ßÄo§"‘® Ci,âÐ]Ã`]ê+)ý|`;1…¬™#ò ]ʫܻ` ©¹Nó+^)·ªüŠ¥ä¼ú©È;dqÌy¯6¥® £4oˆXâ éb‰t3jÝŠ0÷kòÎy>0YbÝÄ#„€²Ž£J]n”Ó¦üý;¡ÄÀ)™¥“eŠú´•AÀÊ«®xf©Ðù»ÚÐT†EˆHÅX…ð®{ÔuwñŽØïˆ‚ ”#“ÂóÓ«ŽûÇÄO÷ªœþ¼Ó³ý/Ù¿P¤VZU埔7ViÆ”…Ô(¹òXa Šß8’'¯H±i9&™°Ò¬þ½-/3UŸtAÕ˜N í1_ªò+ahZö/U&ïr~¥ ëI±O ÷êÛ.uC ú8],‘ö™zâþ¶Y’Œ“û¦¶‰Læ‰Èu`¼òQ%9<‚Æš¡´u-“Y ºÀ€Ö•QºªÊ5•ÑÚR&ï¹³¼Öu„( ÷L=†Ãö=,{Éý_Rüo$ã)|÷7»Çê»QVÞÞ_~áåŽ Ï«nétù·c0uYUa0qv2Ø“èlƒðÎz€þÒÖE£J±»¯ç~èSòaž¤äM_Ä&½ÉxÏ‹i ÉhS_e;»#aѱ"LT ]ÈŠ,UåW"$C‘Y¬Ó´eNÅî^S(ö.˜ŠDª€<âá^ò*ŒN2ºà%Fˆ÷ýïö¿ñÙ;ßùÎÎñëŠÚ‘i©H¤¬ü%’Í9ˆLã `[}ª /RðÚºª‚[e¸¿ k‚ßI¤§íð/%–ûò@>ôôew¼Á‹÷UÐ^¿ €R¨Bl¶müûTŠlʲº¢Cš] ¿Ú¬é¶¾›sÞ§m.Ô|FH¦êyëåü =Ú–]´<˜»CÛÕ‹$‘2ÈE,e/q0–O8á„"§â;÷½ï}³g=ëYÙ‰'ž¸ZB=÷ÖÔžáÐJ[ƒX„å½MPÎ$¢Œ®¡«*(#øPp“F_¨cwnßK'[ê¥|û/¾ÝH @ 3„çc¢W…«0¥âŸ²¬¡ ÔºBüÊÕ`Càžs‘È”÷!_uù•m[·eçýð¼ì§íúXܾù•&(ÇuU$ír¿TŸ?^"ïÐÓ Ÿýìg^Ë¿ÿû¿gÇw\!Çïz×»V¿]5'å« (.aŠ[˜¡‚ŒÆ@'«K×ÐUàáÆËÿ 2“Éê§¾{qªêà³ò\eð­ð` ʃµy>U¨SüCΔJj(ô™lƒPÐA„ÁÊ«ÁÈf“§2ôýýF¾ye˯¹õÈìÎ_¾söS§ýTös§ÿ\vÌuwί¤K^»äWšsf.Å>'‰¸4ÝO ‡Èû~ÊSžRËË^ö²Õ­G-‰´ È$Ba[9 ¡C0XB C s¢£ú‚ð]É}˜„]CWUð›!õ øâêò@HÃrUnå»>D¦Í¼.‰s!4¹0Â4´ýÊ«"’!˜ªœ&´ÝC(‘{Ыú„ÍcÓou«Á´Ø?…gƒ5Î7sˆ>ë{ŸB..ÛU6š>ßúo[³½®\õ‚/Ͳ}NÞ§ØKù•tÉkš_ï»%¾3Dî‡Àý։迦|g÷Ö¡àÄÛ#ßÀâ`ż¡$’†®b—y_Ë?…z QàúBÌWÏ:íò„êƒPä]àžâÎÖ›[ùFRŠ}Ú"˘úæP†]¡O±Ç›Ýóž÷,HÂß÷¾÷½‹÷”X u„²Õ`dœ|-zS¤ßÎÑoîÓg¾nûѶlË«¶d[þ!¿òWï›>/`Õô%y_Æ¢ÿ”¿/>_…ùV•_Aæú¼jÿФrU~%d~.q¿¹H„®Ö®¦¶1æ›/Õav±’Åk°Ô$y†*¬êÓ‡DxAåUWb²kÌ$6H]ëAaب œ5+Œ§Œ1}Òå÷êhé*¥ìx_”$äÚ¡ÀÆôaŠ©Ê©C_…ëû’ïÆ‰¾êZ†ïÙÙ‹î¯ùjk·ºð0|wË»ó9‘{òWïë>ßÞ†½ó2öËËX=e¡à)ª]Ÿ£¶AUgUÅþº¡èg™²ì•^¢ü{_™ sÐýæ€{µÖä$ÒÖ‘}IÄRQÄa‰&Qäú*ÿ:è .åܺUWÑÉcê£ ÷hšÌúE$žËëH8t!&´ý>¼/Ç~ fê1ôþцh¿brc°xí eÍ¥ç@ôMŠòj°rŒ¬«®a0ýUuŸ©ÑvŸÔÃØúùàó b(½záêkùóUÎTþ–ûmÉ6ï±ú §}óùõÀþqòýªý+ú[ß 5êgÄMîÓüÊC¹+è™tÞ-]î…Dún4„Fl¬®Êß °´y&ŒÁC"ÁÀ”®ïŒU]H¤mÕÕ$íªRÂÚè¼/}AØm*¶[ܱ$bܪ~Ÿ.f•±ÎªŽ8pÿ¡ã2ã÷Ÿüä†ÜÜ+»öµ÷É•ä>ÙÉ'_PX{]¡¬±r±^еÚœ†Áúž æjš·SÁ}BÖËðoec'¨‚Ñë5ªŸ'žÆÖ#¶f§Ýê´lÓ“7e›ž˜È5úµ­è“Š|‹ºS˜q¤ˆüŠ•Iæbš_ÑÏñ,Øù=fn¦ gêúpjб¡ßê0{8+” šØ#…‰ÑM†ª¥¢¡@ÇL‰T…®ªV]ÅäC"1PåöĦ=«ŸXú£ŽõÇ’H™ü-Áh,´­máÀå½£·eyÈžÙ™«›åÏ=wì‰O<*'ñ•Õ4¬jKº­DÓßW˜#]Ã`úÒX÷ ƒõù¬%«Õ\ÆNäžD¼ò(ÈŸ×òçi¹î³qÓÆlÃ>+aÖ>hÌ·Ô@VåW›±óÛ£žÛò+mð}cզا‚{•Õ2Hßs³`0‰¨P‰¨ŒNf%q)̺ÊEÚ© ªH„öÙ0è;Ê«À!ê¢,1WŠ“'¦Vû4MeŒ­CüÞX°Xã)ƒ]– ¹´ëŒ3.Ï•hå½×sÏÝ;÷þî¶Ýª>÷Üó³ÿþïÿÍN=uç¤'Â5É”5”Ìú`Ž{@Ó˜÷E]Ì=È^ß0X_ã“ÿWeåžD…‡±ñ‰9i”< ¯Þ×yÊ®›¯)|/­‹×Æ|KÈ|ù^i~%v~ÓgŒQ߭˯´x̯¹H¤«'2{8«,±LÕñ”ÁnÛål BðÇ@¥õºa°ŠŒú ÚCH¢,Ek¯»nÚ›‚È´R6¬Ø>˧տi²uÁW¾ò±ìðÃ7çuY)ÇëÑGoÍ?[I.Ÿ}ö ³‡>ô.ÙñÇß;{Ò“îŸ{$7-êmRZl€ø)=—~ºö½`l¶Á˜ÅòL ¯KÌܺlŸ ÷É÷á•V¾ºTyÅܨð(¼¯ó4ª{•G•7”ä[ªÐå^êhªœU]~%Nz¯Ê¯„Ž™‹Dܯí^daÖpÑé.BÈ…& \;n`U¬¿M^MW„òﺪÃX‚f’Fä>ÊK@›@LjuñNû¼KŸÿ þCîÏ’Apë[ß*³Ù5xëÈ#·eozÓ%yÙ&k–=üáûæÛŠÒ8ûìÙSžríܪÞ1)Y}¬mäÇ]Glšòs¯1}¨R\»3ÌÅh“1o ƒÉÏ Y æ7üÒ ³ —¯ö]…•ßæat…1n#÷ÜÉãȉbË»òºì•×¥%ßRFE[ó5ͯ¤.S•_!Ãs‚~mÒúÑœšœDš/*ÄJdíb_–¶eª}7¬L¥¸uT×ÐUÆÔ…À³:¼º†Öa(‰ P.µ±Ðަ¼KÜ?UmÐ_– “ƒ KÊëwØ–×esî]\–Áʵ¶Ò¯çŸ/Ü¥+òåÕ{Ÿƒûfr$”€ÓØ4EGé¥Ê¯Ka-¡?›æÓˆ1kºOÛj0òË‚–?« ƒåݼç{f¶­Þ§ÆÊWl½4ŸùÕG®À<Åî·»„ÏÜ3õ8¡|/ŸË-ù–2Ü«ï\­Cx]~…gdØq9 ¥¡ù•.èB g5! ”¡ÔAM§þ6A‡ñDYì671º†®ª@ˆ†ˆ1+C²˜•Â2}ID»M~JPbgõP¥åw]9Bv”¸Õ^ãî»éj°8e×ÆÈº0ØÎþA¶yÏÍÙ¶ «2âv%+_]Š="?ÜšmyÅ–lë+rÉ/!§. î9’{Ùúü·UIr÷ ¢H°õßsù;:'ŽÞPJX‹@*ÃBaôCOŽx'ò+æqŸüJ˜]<‘Yë:ZÒŽ¥B…(Ì1ï·C&{ºâJÂNH‘*À.ˆó¦ >E¦„cŒòêC"BW<JÆSû´¡Œ.÷×n–ª¾gmñÂn#!Äòæ7_Z„¸À«÷Uº¯®œTù!®4„às¢~”Ÿ±aéÉMEÒ>ES]w'D;úHŠ.‡Á(¿" væÙ¯ÿÅìŠM+†ä•{]™]ðó2iŽbë[r9JWuçú°7uìó gmÈ~ò?™m}G^’ð™¶n¼_…[õŒü{ו]æ,ÙŸîE×D~Å ÆŒ"2ÌHªË¯ ] áûM:š.åLN"厷ÄMc¬—F,í&v늾žHYºç…1 t%4¬Ô¥`’ÅÑ-}‰¨Œ.J\;Yˆ¬ÃxÊ`< @ŸŒ¹Óïµ[ò[» 9Ò²KeÅßmJâ˜c¶fÿû¿ç“â¢"Ôå}]ÊIÊO}©ºÅNe0^ú‹dÓ+ZTø  ÷Hûh‘XÄ}&ä,Â`WzEvþ/Ÿõ ³²oÝý[Ù×/ZYøáÿúpvÙ;.˶]ÒЧÂMŒk}và˜íqeIÇ(: Ÿm¸^ÞÞžù*ù¹I¤ ÷¯Ë¯Ty†þî²¥î~^Lž °Þ¸W¬~‰b ‹[¦Rc•6ô)'Â'åUW:ßäéBMP—¶2t¸²X¼x§I•Þ…šà÷uu0±XÔ”¸„X+×8¿£ë”79¿µêK¸C»í.ce¶eéNuí1Æ.¯LØ]C])Æ*C¿Êaé9°ÁXl¡=ú’×2ÅŠ¥µÆÜuÞÿ€ý³kÞàšÙ-n¹ãaS?qÓŸÈöܼg‚ªÂ6 @dZ¼¶l»`[¶é²MÕe%$aœûæ?ª@&›í”0ºÞ«Î3d´Ò}±%ͯ”½nó®Éà§Ó„Û†„àIDC)JJ[ʉâ¾D”S§4]V]u!€64•¡­VYD¹.ÔD]PGB„BûYMO ªTÊ$¤.áV#Kíæ‚×MÒ¯~õàœÜÏ®u­½sq¯œpWëåê}É“áBûÛ=ªÚ<´ uP.;B„&¢÷B5&‘¤}ºbiʸô¢}ÕWy±*ßÇ<>äèCvò FA«¸rÓ•Ùç®û¹Â(Õ`ævЇm}ÝÖ]~Øø³;çü¦X F.ÉÇp¯1„Å3,ï_Aä‘_áÄRy}mµ&ã¨NŽy2< !²ÓØc΢¬0 Š§˜ŠDtf]9„µë†Á.dÔå–•™ÉÖ¿DÛ²Ù±dV®ƒ¿C‰J¼iÿMôM¹]¡Üø-+i a±ä)^qñ:øÙóžwL±lrñÉö°½ó>Ù£¨;EíÒw1‰ÜËø§Äý75‰”¡­úK¨¡DÒ>V,¥qigÉõ9^<Å Úsˆ{+¤¶V‡ç|–zöËß¿)Ûø¤Åµ÷oîÝü®7ß¾ ‚ýº}5Ø·¾]ñ®+v,Ù­B~Û­Ùu¥—{ÙÙ ‡UzeK"ehsU~Ámm³¤›»"¿B¯É± ˜*ƒ´ {Œ•-¦\·Ça ¥ uåÔ…®ê0VyC¹ 1s–iXÿؾmœ2†*pHo€M²Pâ]6,Ž%‘ 1mfÍLž—º ç·-¿$öW&r,ß½à‚•÷ÊÖ>Dîs‹Ï£î”7ÁVðVŒË˜~í 2]±qi |Ÿ§Ç‹§áÖ^é-š aÑ$’&Ìïð…;d›Î©V‚¼€OÈ=…Gç ýWóËû}sqåã«=äæ7¸ya a°ÕÕ`?>÷ÇÙÆKsXí.¡,ÿíÿV±¤x,ÈVÈߢA–Éû"¡-ú4NÈàèë4¿òö·¿½0Ê=cÝ<û‡ø‡Bß™]ÑØc*Ñ$”Ñ:3-§Kèª Ê™ŠD\ÊWçµí¾è·1ÊÎ=ÜŸÕKIQf]•8D‡*.Þ‡Ð%ž.¨ƒ¦žsζ| ·æ»%w³¯È¿¿rïíRßœË7wÙµ ~{þùälSA$E|– ®Œ?h‹÷~Ÿz+SJ—~"ëdЄcÌDÒ> XâÍ¢žëØ:t‘Ѿ(ú?ÙÔ·ç•{f{ž¸çN}çïXÖ»õ•¹§ðOùûWæ¿+-ëMÉÈ릳w‘«Ûݪ‡Åòa¡,§øºüŸmÝgkvùÖËwÝ72äiÑŠ=@nçºW1v«m#Çi~å©O}j!¯~ðƒ Ãîï|gv¯{Ý« ™ßüÍß\-¡£hw* ODÇv ]Ua*á} ñZžG[§ õZ.Œè™Rââž]ûâ»}¬ûQÞ 1a%¶=¦8=©÷Æ7Þ;'þ Ù '\Y,Û…#ŽØ–½ìe’ÕOš;å”SŠð/çßÿýœâ7×½î~™S~?þñ­qrµ»¾—¯à­ —zEûôqJ*þ9Z4È'ã¢>´/Ÿ+i¯nÆÕçS)½2UnV²©¯ð.ÍÉjÕ躬׵Óód¹.è×")¾ï nÙ{KvæÏÌöùå}¶‡È¶ìµ%ûε¿“myÍÊý.{ùeÙ>ûƒÂk£ÈMŸy6ätNÂÒ¿æN c§ý|`»§ýøÇ?~õÍÕcS‘ˆÎ 躪‚rÆÔ‡¡Ží{\I@=†(2äeOƒ<ˆÏ§«¾ºÂDtu­EÞê®ï½*£ V`ýò/ï8©×1&Ç¿O>~Ûr/Σ/ÉÛryö€](WFk…WNõ=ûì•{øí/ÿò¹’½¸ BÞßäV'dá/¯dÛQŸ2±ÌE* ~H/Ý¥F˜œ‘´GÖ’öˆ¥Oè  ©"žÒ¡å„ù~ùýòÏw!†*ø7„S"£âµšJ“äß½×w³+Ë=ÛknÌöøõ=ŠÏözò^Ù ~xƒlï-+9Ú=6çÖõGÍþçKãΛS±»×œ„MmãýÇò^õbY}Ù­hÆ)H„âŽuÎ}BWUÐIÑa}@ÉÄŽoèþHdèdTFŸzøn+"è·ç·OöïlÊûá¿‹<Ï…lT)ís}þó{g·ºÕA¹GsH®¸ɽ˜•½K1aômŠËß>›‹Xô¥Ä¦úXŒDMÎØL&d*í¤ýú飅Hå¦ ó"¼ôVïW&†*ø_"£âÕû>ØåJ’oݶÃ;ˆÏ6lÎTòŠ,+þ™;ì mÆFÝÙ`tNôyÜkÑ ƒs–¾kj[J"}1ªÇƈ‹Ð•Ʊ¸û„®ª0„DxÂ+&¯ÉÍŠ£¼A=º*ôØ \‰\V6ŒQt„¦©ú)NùEšbü– ºeXõUP¦zù½üÇa‡ù^|w[ñ¾ì¼}êS‹p•°Õõ¯¿o~í““Õ~y)¡h£#¿·e}ì]³ßø_̽²[ýÀ3”Ü£(}E«ëCºWáÅ€W;î±ÇÎI{ Ř-õW÷ m‰6éï.ˆ‰œn&“WA,B æ@„<³B>ŒqA6%íþÝ=…ð²'dÙÇoùñËhËÄPFþ[ñl]ih’){Fñn“]ÚÔ@DAÚUgƒó]Vƒ%;ÀÝkŒþé28‰h›{5É#~a$Òtã¡$R^ue³\ÛéõéJ"!2Q  ÆŽï!DTAlSHÖkS,¤86$ŽA£Ôšê „bQX±\Y»#¿qó›‘ýگݳxŸ"UÀþ^©gyÜv~¯ ©¢çœ{îŽrSù ÆwŸô¤käŠà¦E®áîw¿{‘Ÿa½³"­†¢dO<ñã…çSå Ô‘\DøË«Ëg&¥"·¡M®Ey+Mòä¹S"ig*©ƒ#mx‹æL$í«âÿ‹&Pþ¶½ó¶ä· 9õYê¥Pè_YÒë‚ÚN8pt~¥ÕÜœ+Õ$/’Bûã>]î—¿ïs”í¾+íµPiºŒ ÈÏñV,&¡“ú†Á†`Nér/í]ODÅÊ‚Ü  jÕUßrê œ6 ¼˜yyõQ—2Ú ¬º2ÒûûN,H'¿¿]S“I ‰Ç»'+8–+ûjú$ .Ø«xo©³ñqŤvY¶{î¹ú-ê¾ò>UâþNýÊwWþÞ¶m%vØaê¹£ýe2p/õ$3r ÆÌÎóc޹q±ŒG¼šÃ»<'¡Ó‹°EÕÆªè¾ðÅmÉc“·I{¿3&]aìcÍ?‚e°Ú.G'ôŠ—&o 8oeDì$³IëF,ëM¿WÀ°¤U5|¥¼H ä­Œòý ]ñ•®+ƒQµÜøû·¾a°! _î7È®v5‰,dŸì" TLÛ@$‹)Nå…â áPÎXÅ mÀêt‹§üqwˉku[õ¨R6&Ü_îA¢nñ@(»¡ÐÏñ{J‘u¥ÿ—þ/ç|(ìŸD¸±x/ï¡?¢,õŠß [µÆ[þÎŠÆØñý£ŽÚºJD;Ãçå°X ÞÄQG‘=ÿùÂ+Ÿ©×ü ýŠbâSÚÌãdÍË5PBx/ 1…ò¨òVb¢§DÄ’öK¤ýÝê@x­©â3ÔSØ)ª#Á|›2iŸB_@´Ç{Ômö‹ï¿mG•¡«HÜÇý iÅWw0/ú†Á†@»B¶ 2Ñv¯…†³šÐ…D"tÅRª[u¥ÚgBVAGU€:Z­!$ñ¡‘*(cl=ÊDäþ}Ÿ28–Ì‚„bÅ—PœóUE\ö5®±’—û;(y“Qy®TAäo³·½móöå¼^½OuÈÖ­Wfó7§g¼bfÊ™¬äQV¾ÿÖ·n.îÞ¨C¹œ*¦?þã—^ÿíß•Ýò–·*¼\a0^†eÊò(ú'¦>3qª¬KÿNx'ÈD±øÜ¿ƒñ1¶©·â³*ùé£Ðº‚â#Gÿg”˜Kö‹¤=¹‹E Úêý]‹rbßkgÓ„ô^êÒ5 6d5YiSìSL’‹&¨w„Óûb4‰¨`U§Õ…®ª9Fi‚r N@½<è…5Ê PKך:TSÔ#&*7ØDfµDþ¡m@0™ì&âFà&ïà u0wÞþö+r´òþàƒ7g/xÁÿäe|¿ ¢:8}7–ó~ýë—ï,a ìº×e%_”[p–üÚ‹rYî¬|ÿŽwÜZÆQG­ÈБGnÍN9åòìwho{9TVƒE®·iüå¼2VïèÛXØA8Õ—µi£eÕø± ’ðV¼Ë_òæ·)±x?fûB=%í‘g$íɼ>0qPŸpM$íÍÕ.Š/ =A ÅžðrÅ]öŠ>©ðº>ëÃï[I¤‡gS÷Ñ®¦{ëª0ØÕ`îr³h´–¶#Ŷ“8ê°!/ Qzºª‚IòÿñÙ½ï}ïíŠQ瘌B6,"J³.dP…O<±ˆsW Û,Ö–¤$ÅÇR @X¬nŠÎÙ9]÷º»ÎÏ;WxnvÁç! °TâR¦‰t$Åí6æ ªý¬‹&~ô£ëf}èÞù„âÉil(¼ä¤£ ·QF×nò«¾$â†wƒœ”!'ÂBD d ê°LòmE;]äÚ„JÛJ†ÛÆìëC¯ñ·‹¡\x dB9®VåØÚÉã Øê >r'Úí6WŒ¥¶²²ãªS<¬ÖO}òSÙÏ~5¿‹¿„ÍÇù •6 añ@Ê(’í«¡¨&Xø"„׿¹ÞrRŸœ@ Ϧ†˜ª@Ç™sH7äzô¯þÔ·qé/sQÿ†\1ZºlæŒ%2h5`Ô™Ž:á„e§£HÄO)a“LèŠâ&<,¡:Ï£ 'tÒN‰Þ!òÒqwÑ’ç\a$ñÖ>à½ø­åŠ]AùQÞ<mÖvViÔ9U€Ú*LŸ›”T(Zd˺ýÁ®ýþïß,Wä{Äðò—ÿ oïç ÅKqÛbIïÊŠ,q£`äCv(ü¡°|Øê/H“Çðò@…-[Ö&qh+HÛÊ %›^m–¤yða‘GãîH e,©0&»ÔSµ5ˆ…,QpÈD[½ouõÝ/~ò‹Ù?wÇÕ*°ªÈ ™â­¤ðo¼–÷ÛOôÓÙõnz½ìÈ£ÚçAѯBXùtk+» †9ÇÚC CõYJ, ³y¤­¿§6,€Ç©oEü]%jÀÃê‹Q$”¿x,¥–'Ë¡ogØÀRëj5WÁdE"‰þ¾¨ò®ºÂäc ÊØ4C!‰gÕXS*`y?KWÜÖñ!#Îvªƒß_õ …ÖeštçwAv§;]+'9-ŠpkÞ盳÷¼ç39y]«Ë .Ø3'±…jƒÙ”˜ß~'o¦ü6ïúâ·—]viÑ&-˫͂í‚P²)±h¿¾NI%”,°ö¬R²ˆÌ %ëô5E¸«Ï<J"U@¤A(^µ_]Ì-FÑYgž•Ýåï²rôI•Ñ ‚ þM4'ùN±ü÷šÍíJ=‹­ûnÍöC´9àg¢­ {ìñãÜ‚¹<ÿýÊå$À]îrËbÚÊ^ŽåÂÏ ¥¸òzøáWf¯zÕ™ù„ºb§Íˆ^½_­Z'PHSþfY’°r‡ÁÀRsƒ ©©’oZ¹£ÿ}ß8FÒÞå³P21f.JÈ+MǸªì© Ž,cž-…£ý·»ïí²K¿4ûîý¾›}ù§¿\yÒî¶}ó÷!Z^Ùm¶YiµÕ†mù½ï¹Úªô¥6ÎÐ-éýÌ?Š>] fþÄj0ž 9*¯óy“ž²Ò¢ /Èý‡ µ×Ê ™–®ºÂŒc’áÔØ®`uq?u¤7ö]ÄÎã±P—6¡,ô¥HÒ$áèBBMPFp°RÄ/í}JǤtR·òï)õŠºùŽû¤cœQâÕû2”+lø‰O|<{éK¿•EÚ¦¼ÄWŽ>úÈìßþíÊüuE#ØÿñÚ×~'{ï{?SäNÞûÞHÝ «&hâ൑C«ß,DÐì.$8ÔCJÑêKA)¯BÍ¿›üòmäFÿ±è…OË0&dÐïô!…\¼÷¹±$ïHE9þ®÷©¡|÷QŸÃ8<»á-n˜Ýöö·Ýå¤Ý¯Þô«Ùg®ý™‚\â³KîyI{ý ²Y•£âXøüý¶½rjšðè÷ê¤_ç€q3Žé¼«‚ïÔ­#BØd‰Û´Ìý$u@"æÏÐö·†³t.õZµêÊ* !”¶Ø{¬^‘|”Oi‚|ƒ„©´>^GãuÞ˜¤x )?“öƒv ›”xÔà ¯6A©¡ S”’p_l2£ Z¬þ λÔ=&KU½òj\íÂ7ˆS,oV’ß]P±²ÊçÈ º±ê;—]¶9·¼È­wË¢wäUÞõ®OæßÝ‘o({¬znº>Q“ ªí}Cc}P—û¨‚¾WïÈ«èK¿—K!kÑVa›Ü(+ÆÔ«y!”EaDrT1ÖcæCÈZYF¡N’ä¶ñ¹è‹²‹Î¹(;ÿ’ó³ /º°Ð'Úqmf¦mNs"¼™M?—ËÇGòq¸úª B9Bâ ‘Eƒh¿o},ôw],ú—CØ8YécûØ"Ü&wUèD"B6&Š˜(éª+±˜RÞklTSòÞD¡\¹|e(’âr"e¥ÓuËk ÅÜÌP\e° ?øÁJÎô‡É%Ç-©{#ˆ&ØU«1t1¬”º‡ä÷^YX:Âvuè¥ÌWá7ôgÙSýO)K¨q¦(CÉz5).ºhÏJ|ï{/Ëe"¿Á*6^þ©l¯³šmÜš—µñèló‘o˶î}Ìê¿¶#¼!Mò8d/OŒUê­¸Xšú>E{YòäŒWN6UÈ,ã0|O¹ñ>ò¾²Ñ$Ó)ŒƒÎá˜S@½¢Í¡øÂCÓÇ7¾Î³k¿o×¥ê]÷štÙâá!ƾ ÔK#ï1è3òaÜõ­~FÜtÄ›ßüæB¯«ÏûßÿþBßtÑ/)ZIÄ?â:+Ëd"|*9XÒ 1< «mbÕSjuÖ‰ˆ¶)º&pïÜOâ”+h¢š¼êF°Û ÏÒý3CÀ“åÉósï.eÅp"–2o‰Òqñ^Úú¯ìص~ÔQß.Ƚëã›<šç­” !—Bà<Ê%<¥³ï¾ûgxÄ]³sÎ!«QÏmyý·;勪çÈ>ß¿I¶aëYù7¶æÿº1Û¶ñÈì²k}Wö*AßNá}ô…yíŒKŸÃ‹¬2xüÝ [;¼Æß!3 •:b™ˆ\䢲OÑrð!Ù-þûÅ#yóZåc–ÿ·O~=f[¶÷>ÝVP¶è’c\4¦&á6­—76s‹’ÞûÞ÷f'Ÿ|r‘N@ätoìøãÏþð‡¯~»HÄ€ÖÁ„òïÂ?c€,¸¹ÊqOJR|hוÂY:Œe:–ú‰m³¨ûëÜ> DÄ<‡™Á”kO¶Ú¨ë^ýV§WÖF(Ryú%¬Y¯UÄäY"_ýê¹²øJN`‡B`ðöõDê ÞBˆB¬þº0^„HN0†á“IJ^»ÉŒ± oÅe¬Û¼‹ðNBnÒ+P&Jp…«­V#Y °ñ¬EŽÄ¾”+÷º2;ýæ§ggm8«Ëh««‹¡T¤È£sÂâÁ0Õ‡ò®‹†ñE" ëº9üÒ—¾´Ð7ÿüÏÿ\‰ ÆG<â«ßhF+‰€ Z"eEÙr¸ZÂb&+å]墷A‡©K]¾¢ &“ð¥ÁÍ‹%»}Ý1z[î"…×.äcrt!ç˜ôa]ƤOûÍ¿S€A(©â Bñjò¼Œ)òºY¯-'BwåÕÈïÉò]ý0qƒá… !vÝÀªÜßx…À¯‚À=ôŠìo<%—ãËrcd¿ìç¯ù+ٞϫõDÊá®ïnûÙNß§ÒûëƒÈÉ3y±4'Háš?©w– qùmÛ|"C!O©lˆÕ‘VD*«Ë¸ ãT(†Gïê±KÒ~ÕPŠ0Ï"i¯½^õS[›yúW›9ïÅ‹µz ×鱿ø‹¿(æÙÞð†ÕOú¡‰̺¯ 1`ð±®­D²¬l÷ª¼uò©Ë›4Áú~“T{ÅÇ„èúîÀ7)ÝÛdAb´á™5Á¸„ &KÛ„ °TñlÊB‡ÂF3‡æuè¼Ø‚(Ò*µŒqÞd9±úë¼9åWQ]ùá­\~ÁG²ìñ´lïMçf—]yhö•¿0Ûã€;g‡´!;ð kgœy«á®m³Í[ÎÎ<è³Ùáå•W#Bc}jä&ÛÆ˜<0„´75` ¡d»XîäB=„²D ÌÑtEfÈ]ÊÄBôÙE®Í~„âÉÐ#Ú™KY·Ð? Wä¼hÌy¯.}øGôGÅø¾ìe/[ý¤F“× ³ŽYÕ@aÊhˆr òPè0¹J°+(¡3õ@^5à +¼,µl;?Œ"gù³îÒ%ËVŠ´:kÅx¸ô™ËoºL´*˜h¼?u_Wn(ÞKºÕ+¥Þç^yõ¶+{¨ uyEQé‹tAZýÔÅÓÉ›P|¿²ª9lÝr^vÑ7e—_ø‘ìZ[#Ûkã99©äÖú++¤Rìî‚-çv €qˆp¥3$<@¡`c|9YO‰¥Êr§Ì†U¸7ä/}M2éB*dOh… õ"ßÚm§XÉtŠËÜ×Fm[4Ìmý>6Ütˆ ¯ö-Õá©O}j±]á/ÿò/W?é‡Ñ$¢óM|1·¾ $!˜”>¡RN BÇBêzð ëŽã&@Ü}“–ÅVw`Y´yDîMY²¸ 1‹;MÚKzøª­ßy@LÔ¾ TÜǪÖmÕÂcŸ*¯B(œP>U^£ê}èC³Ç=n¯\NV”ý«_½9{ÀvÍÃ|îsßÍ ’/JR_¤¡š2a¼å-›³ã_Ùå>6粫7‘‹º×ò>^õD>uÁ»óvîP´E{è‰[aMcc\Ú–T9¢Pc|]­¶¥cKá™§þ66užiIxÆqBNãjkÏIŒ¾IAÈt‹KÝÃbé“ìú¬‹†v2Лö¤<úÑ.’üÏ|æ3W?é‡N$BˆBa•! £’}ZY±aÏ YNËZ ¼ÅîÆ ë¦Å¸ŸIdb¤±ÿª•b}Á#âÉH~–ÉeΫ—yæŠövY,‡lRÙvºblt¢ "ŠÝë+´í7˜—•†Ïº€”½‚*Ï¢ÎSð ‘û2ûð‡¿‘×å¬ì‡?¼8'É›æ„ptÞ?re´’ïHQuO„ᱺ{X}N¤ ô§>>ãÛïÉî|í¿(r"C¼ sƒõžŠ+¼•°Ü]MÖ;y k˜|øþZ@["ŒÆÈ@få:G{£­.I|rmÕnïÛd5ôJ9æ"¯Û˜!÷‹"Õ6Å®>a<±ÐY … ” —6ãÁFbƳœß¢!×Ú¶›—òüç??{Ѓ´úI?t"‚m«ÀbwÄå_åê)ž °~¹ÃÂ7U'!”ŒsÞ ‚–&­ >KƒkÇúoÛ•)Ô&Ü3fw„Õx"Úγà™˜]&O!,mÌBàò>¼@í/‡Œº¢Î+¨Bê)äR_òñ¿2Ö/äJÿ;ÅwX¹jõŒgÜ2ÿîžµdP—D§ò¹\O§æä^‡ð\ºyßì¾ü•ÂÎ<ü°Ü#Þ–VáyTBY {CBá±P<å\…cÎ 2B.?S„L†‘1ÂÌÙ¾a´ÔS‰‹Œ©ÄUçy§ oäêè óEÈ»¬¦‚TÆÌ‹C;ˆHb|]Æ¥ÄR&Saî4J±(´-'ޱþ§ú§ÁQ Ñ$BÁÙ%^ućΠëŠåÛ´ì–·3ôaP)(˰æ4"6A šÜK—dYJ ‚¢7ÏH}X¦] Þ¬0¡¹tÇ9¡ìÓ7ÊAFÂstm(í.žH•§ðò—_”÷ ù¤[Ù¢>juÌ1Gçä´ã¡V‡rEvòÉ_ÎÛ½ÒÞ¨ooÂ(¡ØÏqÆqÙÆì¼âýæ-f_»üï³kßøAõa˜¢²7Ä< Ö…\(Þ Œ}V­ŒZ4È ™f "«˜µ)¥ÞÂŽUQq™é½|GͶº1ˆLyq©o\2¡ô­¿¹F?uYÓc„¢Í<6/E›#\Y•/mˉõ!ïËæè¦W:‘1¨uPɯ ŠK¨@Œ‘Þf]Ž)ν2¢AJÃ}Î7»l™5"'ÂK£0Û<Ÿ@L }¡Ï >a4]ÊI\u1Y}ÀûR¯lŠ'üA•WužÂùç; ê{ù¸ìú°¨:Ïæ?þã3ùoÏ)êN©šxA¢e¥Ó òß½^î Ù`¸ú‘+'€º•TµDQäPÆ­È2ÆæƒG»ÌÊÆX—½×"=2ežéÐMº]®ôsi/Y×F Ößú…"ònjw‰WW|–‚œ”É¥NÍFâ}¶t:Å<bÑ× n}ä‚,{ËuÍÓ È*¨Ÿºu‰£Ftlrè ”+×Sœ{…D"‹ +•aé-k¡ïcFue,¦(Y6B%]Pž!ü)Ò‰‹âqŸ ”P²ê þr2¬Ê. Ï>Pżù=wèͪÏLáE¡Ê"dT"r¿©Û3¢ ÆH(œ°hlE{½¶µoÛgeûÿ°:Ö]¹§£‰(¶ž×¼7¤C˜KŸƒè8`ìWÍyÙ/ø^vÎù[rÅ»²;Úêu*oE¬\Ž,í0&0dž‚å­ ]™³>cE[]]lÌ—râ ” %-S“á9•±Õ'b0,wŒ÷ÊYhÚI¶µÙkØtýW•#ýOOÐyC=£IHD.Cì’ò¦8‡ õíd$„¤ûB3„ ¸Âî+Y4”ŒìÀ×ù}Îû§Ü›’àù8wK=ÒÜLÔ;|‚ݵߌ ! Rq'e˜ ÆÀd쇞ÚA)°‚Xw¸NAµmL¡ÜˆA©7ã G{Ó4ûê—?šÝåˆïSlÝxTN ߨÁzše¿Ql8x—}%Û6Q¬æÚ¸ùÃÙ^g?.ÛX±ÜWÝMTJ›qAiW‘߯Ë>‘—ñ°ÜZ)㢃ߘsñжºŒ·¾L•¬«¡„œ#GX^Þ>7+˜ÒTãŠ5ÆØÜ `Ó6w‰VÄœ*¿¦ˆù†DÈiJê‹‚£\ä(´Ô‰œF»½’sòá;A,ú /Ñ3Xu«UÉ$™ô]hèD":ŸàUÒrHšÇäM £ ]wy—A‘˜€âd¡yÎtŸ½/9«_"P\;Ú„ôMS,Ò¥o]9®¾ˆ:ÈÿPÚ„M˜„!„Ð$,+Ù©Aø .y º„Gòæçc7,ß!DÊÆ« H1h¯6KOW¼ÃÁ÷Ï…ýÜ$œµ!»ü¨S³­ûTä½ZBVi¨Ë¿ÅwV^ó¯("ùÍæU¥­~ ¬:¥@ö>óžE9P¾/ë[mvéƒs†’­óVBi“ã3&G6ÚQJ¬î„hsÄü޶º´_½C¦½jO" "qÿ˜ƒæˆý(úCyêWê­LzޱÜdäÆ8§ÄÂS ƒ)ˆÅÜ®ê·@Û‚ùb}<´­ƒIÄÏ$Mÿ&tÄ M ºZFê›cß…•Þ÷ E¥0hVWY,Є˜HYÔ€ ºˆ§Ì¥Ðw©‡54”¤1P“ÀdJalR%ë5”l Jü dJ`ÉBß0âP^ ÉÁ+Ô.Jöš‡~/»í²²Œ7;<»<÷¶í[Ÿójʉáªì€lŸÞ<'šÜãLÈ£Œoïõ™ìK_ùA1‘H­Wˆ¸¾w£Ü‹9kõƒh:F…üD˜3ƘòaÅãgʇ¡!Üܤ´çCƒ‘Fåaš”ig¡\£Í>#ûi›ÛÂAú.è fŸÅ¿‚Lâu ”ë\=¤Bô}€D´WÛãR§ ”ðZRk[ FÏ=ô¡-tùPyD"aùóTnªïOãCi“[ó|ªÍ”Êe°ik\e"+ÆØVŽ~˜#é<õ·+ ÏÒ«OŒ OÄB¤¶\^Ô¥½A*t3r b1ôuÝ‚§žÿöoÿvax•…N$â+:]¥Yš‘´5I±^ú<ï1—ÔØ¦µÚêAIH Rž¬‡tMËõÆì|7U(õC$# …YgM°Êy ±ÉÇo >LpÂÔç¬Û¾M”lJ*& qMIŽʓE{È‚ü‡qwB) %‚ÈŒqÙe5^EˆêÊm‡eŸ<ÿ]y»/(”¬6^ëÐïg7Þç÷²=²•#OêWe»•ñÛ9ŒŸ"‘ƒ³K{¶ç¼âíåçaQв6f—uJuÈ­b¾F¨Uûª”lŒóND:1*Œ>JoÑ«À€lRªÑ^ÝÁXBžô„þ@ m!=ýÊ4Ó+`.“ýx­ƒ:ˆ¸•/¢¯ÉqŠ6ÓAê^J‹6ûüßþíß²¾ð……ŠÎ$ 6I5œåOð„ƒ@"•1hz^{Ô (ϪDÉáFûM†‚Às9‘H夬ø. b¯‰#òÕ ºBІ@½˜  ¯ùвš`²ÄÄ rQwhÜ]î‹Ìµ‡<˜k}[å}삆dù¶ÜÓ(ˆô¼s³ën¾K¶ç†óòöåãµ Ñš}cãe‡¸-»ÆE»æ·x ’à~A&ÛVÆÃîüªœFÊžÎæ#ß>˜@(k =Œeºß"PV²Æ8ˆÔü r™Â[aôЈÝB“±ø“b‘E.'Î0¼"Üí«Kh×|ˆy¾¦ˆ¹î =¢Næh:š}J ,Ñõ‹ñ&úáÝï~wæÎãõ +:‘ˆ†s{xU¡ŠP²Ç îyí‘¬Õø6^„ïC!¾ê¡RÎCš‘wÑá”T—I@±Yj$!P}á÷ʰzDqÎWî¯ïƒPLB}¤Ôñ›|„pމhõ>RTx"»(ø¢ùعïËÎ9ïÊìÞ7xd¶×Æ‹Š¯ÑmËÿ­ü¯ s‹ïÊìë§0»ÛµWü&ESNc¥õÙ9_‚±"wdÅ2Ò®¹)¿ 4ˆ%¼•ðT\}¼:n`L!.aêE¬ÈÃ[+£x$«6‰zÕ±¤:®®r­¼¸ôg\eU‘ᬲ]¤Mã"’q '‹¢ô ‰±aAÒCò^Fx'¯ –’sÖ„§c4V¸$’µµÍJ¨ò"ú‚س"e2ê¢4ïÒß—«à¹ “Ðo‡(~ýjÀM±i×ÿ¢Á56F\acÁr baå;“.U:]NèßNÞG µÉò@Ñlóoß»~þÉʆE³Æ®÷ýàm¹rXy|îõ®wì§öû…f¢Z (À0¶ÈkßUŽe¤ÞJ(ÙÔ[‰q®òV|7p¾rƒA#±¶MŒô‡ºG›µŸ yŽ«‹!d’’ }fÅiÊÖw®©IŽےøó7SôÍ‹^ô¢"ì¢ÇûÆØ™D0UÝWYêB,cŸœ.‹mZùÔ„Ô‹ê6G•%×5Ö¯\„Ådc±‡0𨼬˜x^›,eX²K謳tz,´%’øêÐËõV_V]Š+NÚf g zyUh±ôk‰¦ÆK9ù;oÍ®Üz`Ñ.óÁ{5»óµžŸíµéÜìÊì¨ì²ÃßœmÜÿÎ+÷mØ„8Ɔ±Ñ´e,Èvê­xÕæ²·bî’]‘ ¡é:_4Ìc Òb²2d? ¹ÖÆ”XÈ`:—],ý¦v¦ž}F©‡¾p”á }3†XmIü?ù“?)æí«^õªÕOúcá>cû¡g¯x4Áüâ¨,Ì®«Žê薡ǧDü–E‚» žû4¯.mHëZí®²åîŠPSLøýÛZRNO]ºZ”ú ¬p«1IÛlòu%è!ÞÇ ”‰ÆûœDöùÑvxÛ6f—o9¸È—\ÿú+ŠR)¹•_øýbÇù¥—^–]óïe·=reyñ– GÄ´m`®£ rEQRÜêá­_6cR?J¶Ê[Y$È¥M^)í±ÆK º0H%.ˆœa´9"t ƒØØ øÔ2ÇõWù5EèWR¡ÃìŽgÔWáw÷w‹ºòD†ba 9q›†BÙVˆŸRÜ&ÄÐвO$¶Â£,MMY gµ)põv|W™<êà»U–;‹A_8ŠrJáïuˆ$¤zËU¬°˜tÚëU?â —­¦ÑÞÇìœìÊ „mçårXvñ¡ÿ’ísHó“6_~YvÀ¹âØvNÞ¹œ”ž”¨Í”ÏB\/É?€ÌÈ-Ã/Í5 V 5”«6«ó¢B¼ é\ž{¦ÞŠKä¹7Ý¢.–Úv! ’Ô(u”™^ueš/§vZA"uxžPÈd(:“§qUà.RÀܦ! p&ƒŽ§4Ç>„¦Ïñ)šo%…) ï`2J8±`š–߯@C ê„B &˜¾A ëš#yÈ)Êm ™·A¿icJ¤CµÕø™€Â¥±¤|Öž¬‚µÑ”`ÝJ&í@^,\äEy—•’öH¨S¤)tWX0”@ü^PÚÚÎâoË7–ªXX7&Ÿ«oXC]¾¾çy™„CV’Mu‰%ªúÞØpËCÙLÕæVäžÄ¶-çd{}ÿ˜lSv^¶1}tnÓj«’÷R…ËŽxO¶u¿zƒ‹|!‹h¯Wm6&ˆ>ú¥k~jjCóÇ&SžP×G4A›µ3msê­±”½¿#+äw­—«¯ù̪óÊRø~´9®´Íq5y¥c¡›ÈK,Tâ•2I¼‚MÏxÆ3²‡=ìaÅû!˜„DXR¬ÿ.O%ôÝpËÈæ~5Å𺠎 ÂF,=mÀª –È’pnJY?côa3YÆXüêVl\½OÌï‘9rBdCV°L….¹mN­Ø´Í¡l\m«ešÀ“Øó̇d›¶™mÞ²âõ ’ÊeÁeÔx/).¹öw³lS÷å·ÚkùµMÿ¤V¬Ï¼2FºX±cÀšVã@9õÉ;öAŒ³ñ KF Ñ^¤*k|Ôe-½2u³ÏMÔ¥Lv]PÕfãœz¥.:«Ég€¨‹9añÊ”º+Åmns›ìþá²<૟ôÇ$$âßÚ–ÕºP«!V)”­Gwô‰rÆH#¨€ Hq ‘ ¯¶U_ñx[ᥗßÄÕʉMƒÊV©-þ¶X¢ÏbµS$ñëÆnÑÐ/©÷¡.}Âä¯ÜfÐÎh·‰×¥}Û¶nÉö.Bµ3ë©ä+­‹y¥.‹&¬2´™ŽÐ^‰|„!ÓÑæ! |(¢_Ì#I| ô¡ÆKèÜhsŒ·9޼£½®ðJ£.u‹ B)ã/xAö·û·Ùë^÷º"¤5IDc baY-רÊÅÖpÖ¿ß³þë’Õ,¬±»Íˆ U©›$Wï6»J N % ð¬l–¿:¤ù—E‚À°’BÙ¸j(dª“‡ƒ:¢‹÷ÑÆ‹Ï«û¤Ï+9HÇÓØ|õËË~úðû¯~²}vï”ÙxXÎ+¨(÷d,ï=êíÍžÌ*„­Ìíhš3mŽ˜{´Û{Öy´×뼨 9’‡»‰q Ô…¼P¬úahk´;õТ݋òÐ(buqï¹úÅ8“Ó´ÍÆ…Ñe\éi{Ûu†~ÌcSÔo{ÛÛFoŸ„DओN*8,àûX;bF!¦&7ÌĻۋŒ…m å}è.;¬Î&âÐú(Cî…ÛÇP¬UÒO»bù£Ée²™Œú‡BMì˜pP¨KX¶C¼¾ [&\(XíNÃdUŒß³GŽ9ø¸ñ»Î­Îн&|G™˜ÜB¾ ûP‘’‹öÆeLSo¥ÍC“§4‡Â[+o„À-*Pgó¹ÊË2ŽeËb¬]c½åÓæ 2›:¢ÐÚ( @G ]#ò®nÚªýôzZ0„@,‚zå+_YôåXLF"”¿cÏ ›"c"ÄÊ ¯mpdä9cE<0Ø:VHt~uWIoÊ߀¨KL:íëª`ÝßBo@× ˆB]XrÆC;iÌ«KûÔ7Úíï& á}ì„ÕåµM»Ã1e#G&¬§_BÁ^ÓI¾{ÿîÎ'ùîu»Ö2ÇÂ8H†JÌRØ]ž® HÈA:Öá¡ÅX{e4ù.‚çÅGÂz‘FEÔ%N‹6—û$òÍgr–¶9õV¢Í]½åÑ ê#¤×w3ô”P²KfÊ¡´Ô[yç;ßY„®DȘs±žúÔ§«`µ},:“ˆT:C6dAA˜ }…OU„Å< dh’LrÞC÷ÁfÁTY6Á½]ÚéU]”M`\ʵJÁú“1YÚ<¼wº ´'j-©@:Â,~FÒŽ±>7Û|éYÙ{‘]û°f7?àv=~B¤ËeëXK¹+X¬Ñf¯æ-Y5VÆ&–¹Oe@ôHO#Fxcãœ^Êg@k/‡xÍuQ'u™B…6Ä%ui ¥ñ&m*d01Эd³øˆ^p üïÿþï¯~s&#‘~ô£Å`Á#Ž¡n¸ýï|çÂb] n”f& ê"NÙº€EWTÁwBÁ"¬²‚5ÙXoÂC¬É)„~((„nìxC…^›Y6+Êuå k.HÅÕä¡-Üû€]’ÚÕ¡(²"GfR1tªVñï]pþyÙ5/¹cN žË°uåxø­‡dÿ»õ”¼Í+{WÆa䶯•=5Œ3cƒ•ÍøÒ. –| ÖØ/ºž”q¢OôÍ¢ˆL»Û¼Ð/”õZ‡õDGD[iÊgÒËÂWޤzÍk^³“Q͈¢Æ.‹îL"¾F˜ª@™~ò“Ÿ,„.BZC‘†Åº@½Â¢$èT¬ÜhKù­Ntù›6dbPBÜm‘cpi Ïj.å =^þƒÄšÚÚÙj_™xÚ“Îåo÷-÷Ñas`Äø#®Þº àʳ³ý~pýÕ7;ðÉ >sþÖ‚\i»»*X$ϲ¥<]B¾‹‚v¨‹WuÑ0/"4ãL‰Q¢é8ëÏ©dŒl!®û-T¾‘™9òcíµU~&„±¨ _•Aüýßÿ}öçþçÙŸþéŸgdM­£HÄ{‰sLiÊ?PXc ,Öuõ’EHŒEç;qÓ|Vwª°¶¸‚@ü&®¾P#ô„JÝ)…²‚õYL:×”“.…ûQ’Ê6ûztC¡Ë!0¡’°ÅŽYÙ Ó4x"Wæ¿ÉÇSæ%w ³¡±3’mÜæ¡Sùdɯ²w“*XWYÁºŒA:Öú Á#úµw£Ë<¶Ò7m$Ï{B€Ñfí§tÉ´ö†’¢`•%aMŸß…ÊK Œ­ºðHYüÆ(ÚëJ½ñ —òXO}nŒxÏH¾É“§ûžô¤'ÞÊ¿üË¿ŒÞ¼Ý†A$âïX6«)N+~ ¼dÓp¿0l]ˆÜŸÕ{Hšˆw–‰Quª°ßv ]µX¥êRU¥A¹DøË¥1éâã"GX$VÂu=ìmзêa|L,^¥£bÒÅÕ‚ªœÈÙß°È7¨¶¢b¿GÔÒAŒ›ú×ʼH•‚]ë²ÃÙ”í¹÷‘Ù÷ðÃâ3Ê@ÿ¬R‹ßšÈ7Þuá gí4Öu2©ŒHXËÛ‘ß)å¢/d±šÛU¡4äc­Í.s=%S×XoE_ÆFF2ÓD¬¶7Øóa<_ÿú×ÏâÅu&`YjKW¸(Ï`S¦^uø”wŠ—aÐ ®d©T12‚C2–4Óe]„y¨*'B4Ú/^Ûg5™ß›t¡h\Þ g>á/¯„¥K%׌‰:蓵 ‹4å>šB`®˜x£Ã]«Ëk·l=0;='VòÐ;ßаó¼Ï²_c½ùÂd^ð«Ebþ²+Í>þýgf›7Þf{{½³¡ò8ú_øjQ‚MÇÙEfcæ4ÙY넵:Ft….ë“/0Ö±W'äÜ{}íÕö&2-#Œuž<ã°îwêmÉîsžóœì™Ï|fq”Iñ-½ë”C¬ò1)ÓÉN¡"L9éFÁaiGœ¿i•+B}â4`MôûhªÉ:t‰òÊèT bå…ru™€&¡‹«,|”2çuñËœŠ(…¾í›ûðý™¶;Ö·§í¢à”EI²)ÉÞ«ýJžH:m@Œr¶äå$;à¿»×Dz %k\µ5×E(ó8òes.Q5Öj´×+CÃø}Ö»Pš×µ’aõ¾ùÔ¡+DStñV¼–Pú yÈáÑ©Má}å[²kˆð•c£æìÃ^á,Kg)* /¹è Iñ1°iF\ë" ¡-Îçc9Y½ šW;´s•¡\î®KeÇ€Åd Ô†:í¶£p‘Ù?MÞG_°J£Í.$cܵ9.m®G㇎ ‹ì´ó”$d®PG´…òSJ2rTÈ4<Óký`Óñöý¡s¹ŒÔâg ®ÅJ0²¢½.¤ŠT´/Ú¯©·bL_ÿú×{<~çw~'{îsŸ; ÙV¡‰h¬®BUb ¨{p÷}¬Ëîj…i«N‚ž HÁººN¸‹`=$«!Vé}©¢Ñn,&›kQ±ö)½>0¾¡hâ¢hL0FŽD(Kr!žÙ*¡´_Õ¡¥møRç uH=Óx5OÊŠ¦¼8CŸ°°}_]º¬z\Œ],¸0—šbüc V ”eÚfóa)š/ÈLŸµYü‹F™ÌÌãkbÑwïyÏ{ŠMÔŒ%á«7¼á Ùýîw¿…Ìñ®˜ŒDx!„cìr2“²$\”S×£É5Ã¥~.bâ2H!tHÅßMÌmÅŠÉG°Ôc-“Õá‘YÝ%nÌꯚ°h¢ÍþÖÚ×Ð E°H•+_ûZÙjw±fm±0:vÉQu$ ®0KŒ³Wm'§!ç è=N-Ù¹ÌH€—8ô°Bs;Í1x%÷ŒÄh·«‰B†é«Eí£êãH†ÍK¹˜ªºk#“<ÿØÇ>V„Ö‘ßît§âø—ZôRÞ:LF"¬/1ôY Ê•ð‹¥Âž‘ÞU9i‚ M1qS%ëó˜p.ʘ…Cð\„ƒ"ÉÇB",ZîÿZ±¼zKš‡GV^Ê܆*25†édów×2×Êû¨‚¾‰Ã$%‡å?B ”P4.ÊÆ÷Ëíž’üôsJ[ £ƒìj/ùfˆ1>(¦4Ü9ÖˆºAßèsr3f){Æ5BA*©c‘òO†}÷1”̦Bäbä4ud¦oyË[ŠÐÕ¯ÿú¯›Ž/q‰LŒ=¾d(z‘ˆÉIYWÁ¤ú,B»mBvÉ­¨º‹²tù}W…‚“.Q,~“o­Dý—~% ]=²&è+Dm6é«ö†’q•cÎ~·ž¼$Æc¥4¹þêÜõ¯ U%®ûŽ·²cÃz°jµ“Ū¶y‘¶›|‡ñä¢dÆqo$/‡Gfæ2Èè(²¤âÕg‹äßëd9³PÆ!²W—¦\Œ:ÿÁüAq¢£KŽ;î¸5ÓKU˜ŒDLl»ÍãÞµZGbc,,NÊò&tÎÏj‚j«KTß=‡v¬A¢”Ë„r¢¼ËVܼJ_h£ (lÄaòMi¹•Ök\Úí~Ñf„"×¥Öƒ÷dætžâP«‰„’qû°^ãj ¥dFPÈk}cÞ蛺|ƒï¤Æ“ök7ÑÞ°Ú§ýéd†HXük©°ÕÕNŽÍazƒñùÃh7cjÑóÒðUº°  êmó Ù䉤«V× &#éƒü`ñœõ¶‰í–˜¥mP)§H„–÷x”á·.‚á2èCÉC9&ž²i0UØÊ¦PYì1é|?.„oJ‹ÜÄãjSؼµH‚ßh7B'ðúW[ì"ÚÝú$Bi¼©ÃÚ’Š¿c¼c̽’ŸÇj'›ÑÈÍÜ!¢ÂVÈÌX!3†OW˜ÓÑn¯MíîŠØ 7–è§½$Ê¡oä´°ÑÞh;Œiw˜Sä¸m)±1x×»Þ•=å)O)–ð¾èE/šuåeô"ÐUÒýÀ>P<줩±¡ ZìMI öx8¾ UU÷ Ïc(pûÕƒ!±6¥äÞ1%“7 ¸† ´²YI\ýA¸Ö2\”*ìXá/¯¬Ùr»Ñ7”’$(ϬËÙNS Æ;ÆÚ¥_X«dR—8¯m­Àè2V õ«ô´ÛÜåš¶;Æšreô•ÛM70 ÍaD¿ËeSÈÅð†*9nê›r»½’íNIÅû!ãMfbc°¾i OÓ+vž[yõŠW¼";þøã×TÆÚ0‰áAèè2(~Š’—Ö[UB×àÙµîÜû€*ú½Ëßc¼eĦÁ8J`¨¥drÅDsB“+&á-çÊèKf‹„¾í’ûHC"®‰h¯‰æuèdKa2éž‘¾Yk¥'¨2ÈŒ±KC`Ú>GÈÌCJ‰GOA¯EÁ8¤¤b<ÈE´Ûe^+òÎZK«Y]bW>bš‹1'µ7Ú®ÝÆ6HÅe¡B›QƒŒ„¯Ô7Ô¾RçG?úÑEŸ¿õ­o-ê¿ÞÑ‹D  ¬ÂYÇsLÑÉ) ï‚àcᦸº‰iµ°˜ª¹Ü×eâ‚@Ð ¥D¦„¾‰‰ÂÇú!l«×ˆ7k!ìsì€oCê}è›>¹ãš*—6ÆD‹ÉÖ§},6!õà±NVèíC¬~u‰%ÖŒ*íNÛn\S%ãï©ëî~,lÄm>5)¥E@)Ôh3‹__¨ ;Ú¾DÂÀÑ7æ¢|RŸ ÚÍ`Šñö^yŒ¹×ÔpDòæU„öê zîýï±òêÁ~pöÒ—¾t{ˆ½cRùÏÿüÏHÂä‹„–U+]¬~ƒrê©§ z÷‹ê!¨K’²æÔ æ”0±ÒÉæÒDBi«ƒþÚ¼>H'[„ÿÈ " ãªòDYȃbba=Yv*¨?ˆb0VMa;}Y3Þi»•1D–•Ï‹v™KVƒ SÀ\•oðJA©j7cPŸio(Xý°ÈúÚ¨g¬x¬È~£LÛSR1ß ÚL–õ9n:ÈÑÜðÌ{@<„'²–ãÚ“’ˆ]â”´‰“¯ëê Ï£‘¡Ì(Ú1ªâ´X…½–ìn’±hÅøÕ¹i/K&<W•r]Æx}@ÄÊ¡?Ê6âÍÑvÎXùÌÄ[눈‚ìzäNÂÑæTÉÄX»º„Àô…M^XØS{Ñ}¹ »*OEO¤”¶CŠËßc 0VŒ Fb›Â^4Ìq{ÌÌs“óÜxEÛéÂù[™êɃòHV_ÛÝ ½HÄW q>þñBht$áêsü¶òu¼íü^ǧʵOX@=Y´‡u½Ö P“©†÷Aqh¯v꯰ØC¹F›]©{<Üw­÷}Ÿ°àxèu2î]”ë"À‹¢°õùÔû ÈwÙ;¥CÁÄkȺ±¢h(¥«µ {ª$ˆûäb´ƒ‘m6öe/MÛûÊz䀮ÊÇÎ äjžGÞW[bŽG»%ÌßûÞ÷ÿî»v;}wQFÜ¢1‰ø7Êß Š‹ö±$ýÖe2¹ÒŽåª\—’JUhA9&A÷]níZZ´&P¥-ÑvþV(×h7…“&o]”ëPR™Ëûè $¯><3‡zÅ„K•k\‹$;²»à»ží4îY· Œåßô ãiEÏ@®ò Æ mCÔ…‚ŒsŒ»>¨ó<]J¼G ¼!Qóª) ËÀþ³?û³Âè6þ<(cnƒµé¿üË¿¼úÍÝ“ £×ölóʤhƒ<â*#¡\ tÄ\ƒXüN8$âk=éXØ$ †XIú&&Z\ ½q™pmÖ©~^kï#_](u)¯ QߺüB›!1Êæ}3Þ‡²× ê`¬š>!CB`SÁX´mdœÚ^ZȼÏÒP‹¬#¡j {­ç9Ùá é§¶çðTÿøÇaÒ7¿ùÍÅB$ºÑ+`.¬ÕXCÑ‹D€€ °ÕE}’Õâ ¬~Ñ·Õy.Ê*ò¨ƒ{¥»¿•C©°hYØc,ö1Hä.ñ„6"Éh·W}a¢¥J&Í«òõä}¨3£ƒ¬ ×®yª4¿  ý Œ´ÝH¦O_ëÏ4\´Ö{ṫ8*D]ȲÏÒYåš¶½O¸·+ÆŠÑÆû@àsÁØÙÔˆbX_c„Ðädgk1Ï!ÂWm¡Fm©yìc[œtþêW¿º³«z“¡òV¶ÎÓiK!’IUüÖbðãÂMAR¤”µ2CÁ*S½Âr5éOŽÓ)FÞPW9úIÄ$‹‰yýa™!!¯J€Î ² ¹Ž}ª²NŒ¿cÌC±6yid™ìø™]ë}(H‘7M¹c^Z´Ÿ²1kl.M¨Q}”¥AR]¡Í±OÇ8i›¶» 1æ^]‹–só*ÂÔmÉ|rÿw÷wÙ ^ð‚ìùÏ~ö´§=mMCoS£7‰tÉzc)¥Ëe)Â]Îr+·$àC…\9< .Õ¦A÷@0&XJ¬’ lˆ…°M51˜~ábë—µ<ý—rd!éÖ»¾‹=µ¯Å>&{jtÔ)È10±É§±ŽK_TyiÆ xO ̵"® Æ'B±g¨¯’ÑδÝ}ó )ôc}U¨qn˜[ 3󹦞tyÌÉ™\‹(DÚö¡Ëª«Àh“¢ƒèº¦05"~Ò“žTȾð•cÛ¯jè±ü–À2)'Ö(tæ¡))üÎeÀ]yÌ€& iƒûGÒ6H…0„°…r’„gé‹Ñš¤ÒTqú!ÐÎrîC_›\ÑnûL{ãZ”—f¼‘™ì²·a.+L_¤ 4´›Âa¥R¬G!‘µ ‡ y²Ìà¡ §Ú3¤}aDÅå³2¡–(s„‚4nÂW‹ û>0fêã×?]È>ÆÜo½ê¿ Bq Í)ÅÖyž}Óœ9í´ÓŠ=êýú׿~·]}Õ†Þž Ç€TM:î¦Ë’µ€âƒ<Àï†NX ’ÄZcµQH!l.J†‚!¬„,H¥)$@ð>„ö¥½VÊ"÷Ú”û0a½±èÛt’¹Æzi&¯ú© Ù/Ú«‹´OgŠ mwW‹},Â"kŒE†‹ŒAQq¥!0cÏ›‘ãŒg[,¨è õ•ræ:²:·'B Rq™)¡jAù~xgmá+ß}ùË_^<²ÖXŽqŸËpZ ô&Ê&¡ ¹Žö@)ź|×¥Ç(XáÖ>¡7ˆ‹È5h[å„IÈÒ0X'@XŽdˆ3ôó˜•W~x‚P\Œ¶Æ$Óþ®–òâs-•mB(+bʹÿ–&­]”NJ¨þžRÁ+?öZ i-Œ1‚Ô…ü“›u×\„šB½Hž7¤S‚|¦„Š\„áÀŒ1•±Éøo _)ËÉ»¼{?lš^‹±“’ˆP–ÁÿùŸÿùb¢øžŒkÂÚWöÜ.,‚áh‹¶ ÍÌž©BWï£/Ò•P.^EºŠ¢© ™ŒêCNx&ãZ‚"ê’¬„‚‰ñöªoSBu ±#,õAJêS Ï c«>(ã¬<îæ@XìA¬]BJCÐÔǽæLæ#®˜ë^]æµ~!CäÝx5µýsŸû\ql»°í?ÿó?¯ù‘=s¡7‰`c‚Uà^KØ þïCµâpŠq=YûK]š¾ˆÉEÐü½è•!Ögˆ÷Ñå•P.ãJÕåßy±ë!Âóþäy IVª5<Ôw$Ó$ëêᙹsCUP¹*W]¸ÈwÚ,v—÷CçyÀ½È–,÷9éb ï±€H– Ç|W?DÁ |Ýë^—=ãÏÈžþô§!¬9tÀzÁ$$¢·‰4VªÉåÒá}’Í×j åØq¾Ö›‰¢>^Ykñ°(mVǘd¬VÂVNÖOm¹-Êûè'·¼D¤þ L-ÁÔn“m.K2Eôyd=ªË”H=Ô¸À}âÒö Qõ`]{žñok‰¨YUžFW¤»kŠœ’ú)[¸h­sgQÞ´úéÐoiÛùÈG²€Hñ _øÂì‰O|âB=µõˆÞ$¢ÓIÀÏ}Å`çÈ-Pª.ʆÛJÕkUšbb=²Öâ(ƒµdtm’HcÍ £u©AÓæhjL°hû¨ÏœÞGÔÇB Þ¢‰d¡C‹¶G(ÆÝµÈ•kêÕg®þq_!wWX­HÔçˆ᯵…›ãbuÑØú˜³åœý&­]uŠ5V;韹NÞmƒ0ŒMõ‘÷à}s†Üg>ó™bÜ-,zãßXxäW &?s"WSè ©`ð˜dþŽpãR†•*Ê7Ù|¶– ü 7¡PŸ¡K/ý>&—öwÍ-”±¼È’w¦=êSõ(ߟû.II¥KÛ»@?«û¨ÏzØ8¨>±8C1ÒqŸ" Ôær]ôC¬è{j±›Kå9`œ1BÔ§iµÓPïX|\›Àw%Íï÷~¯H¢ÿùŸÿya,ÐaÆÜÎtK{×2ü>'‘H$×]`"ô™ ÊR £Ba³âÖ"f¬Mb׋Zê¨í1¹âJÔKÚvýÞGWoh‘PŸx`EmÂu Y1>ÊÆÄØPÄRYa"²ÖámcÍ’gû˜(Ì0¤b̧j{ oõ!7ÂWs'ó#2b%GÚJYóŠ´}ÊyÖŒ4œÆ{®‚üýßÿýâùçò ¿ø‹¿8›!°^Ñ›DœùBÉÝùÎw.¬á1B/ŽnònÉOƒ˜’JL.Šu!3ÙXûˆ„2rïEý"m÷™{f}dRFkí}„µ¯žúgl®J;õy´Û…d#qWi"%¡4ÖõÜ+÷ª =ŒFHÛ±.鸧m/‡Æä”Ì!áXˆD¾„þ"Hª æ´=‹¶SŠŒFEdyê”Ê¥/Èf,.˜zi3"ˆ¶»"¿bÌãâ­– ž°®ý;šÛà(Ø9*]=º~„À"á¿ÔKeX ékºCÿ­¶Õ`¾ûÌg>3{Ó›Þ”½êU¯Êò‡¬™¬­W "‘2Apÿë¿þk;©X© §ÀSA(&»S,½”±Ê(,—P®,Šp…rmR¬,#‰4î>σ²–®¾>ìšûHÃ~^Ë k¯S$mHÌûЯ”Ñ¢ˆª+(#±k‚\‘)ÅJ‘DÛ]”ÂciôG9.:ÜHfC©†b%7¡X½3û«¬Lk²®ç€ºÁÆ!©CÇ…‡GΣí®¥ÄÒæ!“!òB¦›¢¼á+ýîѵút‰]1 ‰”¡Hn•©§žšp ŀ°d¹Žá©ðD¦´ÚÊŠ•ÅCXBÁxoRE.†UGšis ì}ôUFu 롊5r ÂëEEl¿¼q0Í-Dû}ívQ2S…>aí+Û˜­E2_¿ VmFêä3žŠö¯Eè… ™cÆd«aH†Ìë s<ûðR}?6W’é¦ÍŒ¾ëñµNß}ØÃ–½ä%/éä=]]± °Ç=îq…Åo (µ}èC…·âÑ,[žJx+\Ë©\ïp‡]9B”7–2z˜Ãb­ƒ®_ÄÊ«P¬¡T]î•N.ʯŠÀý¡á½µž<ÆJ}x]bûÚÉ+MÛ¡Ï´ýC+«4–¦®‚"¶ZN]„SRmR¬‹…ž®N›‹ÄÌy÷Žq÷·ùÍ[A8ÆŽŽi’!ƨƒ_óš×dÿßÿ÷ÿǘ¬åøîX8‰¼ô¥/ÍþôOÿt—¸£‰ýÉO~² a0†¤ü¬ú OÅ£#)þ)1Ã'¡æ©¤Öº×ªøò¢0ÖûèCL™„bõ¡€h¿ñ±°€r¬Zì07Ô9–Ý—æ”\ú"’¶qu ÿ‘ÞAh”ñZÂÆj9ʺj¯NbMÛ>4·P†1‹£f„®¬[K¢Oâè$²£~ú#5(ümììKœë£·¾õ­EŸ.ÑŽ…’Hp?ûÙÏn'y“ÝîÏðTüÝ7ÖOh"1ÌÒ˱ÉZÅÊZŸšTÜc­÷}¨òж ƒ um¥°íÿÐkPŽÂŽvìRâ2”cî¢4xÀ¡XÊ…þ å¸N%õfí#²>Ö>¹¯Ê-¤y÷ ϱàEæì"NÞí c'IGø Ò…®W¼â…®a¤Èã:<Öቈu‰nX7$Ra§H"ü…X^©xJ˜Á®#Þ‡2|Gþ¥)1¬ÂZ‹û“+ˆeŒÅ6§÷Ñú8–6 ïQœaµ¦9¥P.} |Äöõ‘~Ÿ+×`œ#yP}B(IÊQ¬%Ô+bû<Ʀ½(] <ò¨ÍÚiü…‘SŒ»‹,ÔÝÙ§ù¡µ^ f¬ÔGTøª‰,9)ùÄ'>Q²rodŽnùßøb3áÍX·$RF(<¤žŠ‰db#!0äÂ¥çŠi²*X!C6¡é–ªeÅÒ¤ åÚeÂ(k=í:‡Íè–l9ÜÈ:¥P¢ý©µ®í. v*R¡È…Ä÷Y…N.˜ªì¾0^ Þ‡ú¨‡Ï" c?Á¥`EÇÎê¾'öòƒL]6õÔ\úB¿Ä^‹¶dõ\P_ˉ»šp©œ-}aõÕínw»BîénQyqï{ß{õÛKÔa·!‘2T›Õ^Š‹×!–Oñ‰Y¿ò•¯,BS vòŠd(ÒPª&W9¬°½8Ö¥Oh&¬õh¿K¿š¬Ñv ó („F)›¸£^+°H…@y²,f9=¡½¹*¬òÔÈQŒ5ˆq´–†}@®-âa¤5åô|—¾xìc[šöÝ%†a·%‘2Xú¬ 'kÞínw+¬H‰ä^x)<–)ŸãÀ3 Åâ*'l)VÚz8‘(>ÊšR ¬ÇLJD{£ý^)_ÖqªX›Ú¬ Þ¤>Z‰X@h¬}¡O†H]”µî»Ñþ°ÖÓ¶‡µ>Æ*vz3BÚZCX™‘uÄ©Èzxjq5…§„±ˆ|ŒðU“\ëÏ¿øÅÙ_ýÕ_eù—™ýæoþæšç·vw\%HDns›ÛîèßþíßÑ|f‚ {…·âY'69"Äâ:™Jˆ"ak’q• ,ÅÂûå²èå•UБf¡Ùg1µ%ëiøÏÅû¢XRÅžZ"¡¬}o-¡È ©éŸª‡45!¬õh?ŪO¢Ý.Ê­O¿ 9"42¤(쵄>"C 6Þã(PNX«;‰¶“EȾ{é#òÃ0j _É·yÞ‡°©³¯¬]b<®2žˆäò¨ƒfR\ÿýßÿ½=¯ÂkŽ RáÚÄ¡ƒ{¤¹Öuj­S,”ˆ Šu kµ N3ɵÍ}çB9žš‰Náê£1Kw§‚>¢ˆxR”õ¹² ½Ñv¯ŒŒÈ©ÅU•WñÛõvp"A!Ö~Ûòf}žZ\Ú¶]_ 5fôQF]|ìc+–ï24¾Û¤+–臫 ‰ô…fSrˆ¡ðV¡öxßðT]—j—܇ Öj(‚ÏB b1±¦PÚGN¬·d¾>b¥RLú–B R2Yß}$q.\ùšÚC „¼Å¸»Ê« ô±—û@@mNÒ¯¯Z¾1ähH‘}ãX¢º’j~g®)¯m9±ûþ¿ÿ÷ÿŠX6þßÿûל¯j¸Ú’HÄV­O÷ªøÌþ” •;ÞñŽ… E'Œ!IÍr쫬u½‰`B±(/H%&VßIKY…"â}¬u2B¥µ5U*þÖ¯Ú퟊TË ˆÔǽ‘þZ<μ JûAÈemÜæ$Õ2ŒOäcÈÑ”ûuÈ>c"mjÈ¿WžkÚ~}$ש_lSøJ™O~ò“³OúÓÅC¤îz×»®þËSbI" 0‰XÎþrQ:w¸ÃŠÂxùË_^„þîïþn´²6&áR¡h(Ò”Tê&ŽßÇ.フZBYwÙ8Öj´ßkj‹¿ÇzT±¯A(QÖjSe@»…e"rVŒÊRû)ÐÔ¨êˆð•{±öçÈÇõh·ËßäW»õ…,úHøª-g…8õ¨GsÔ£j§Þ°ºÄ,I¤Lvá¡SN9%{ík_[$ê)jÊH’Îê/äbÂOa=š„R­[VlRÖ¾cYêz˜4v ; UÖeRõJ‘(/HÅk—„²–·¢\Öþí£¬²Ns êK™§íP´Ý5¥¡ Ïí›àÄ"Œµ ÿ0 äȘ‘qu £"®Ô¨Ðgœç¤ð?üÃ?Ìžõ¬gÍBºWg,I¤'XúxÄ#ŠÖ?þã?“Lø+B`”7;]Öõa]]Pµ¬8H„rE ”ÌZÂä—^Ä‘ä ¥šæB±VYÍú‰÷Ư%ReÌX×mÊÚoÊí£"UªC½ÉððõÑzƒòF¬°–Õî¸ô‡qµAP¨Ù”çttÉ=ïyÏ57®X’HOPZž‹ÂÊ¡´SèJ‰Ú 9NA¡ðVš6Bõ %÷ÁR£@½—¸G*¡P½–ãÊ‹„I¯Í¬cŠÈ½ ä™*U–«öGÛY­þ ¹¯µeˆŸzQŒU'v…öGÛËí«K^…ÜÈ5 ãÖ×kœæR¬PkÚCĨ2×þéŸþ©ˆ ø¥ÇòæÚ½îu¯"Z°Äâ°$‘B×R𬣠•ôa]A,]¬Ð2âQåPQ,­ Åâoî~(UW¥ÒÂéÆÁµzÈWº´Tßû‰Ÿöë³µ"õbYóžÈÔʺmi­ö§‹Èh,•]/>ƒdÕ]ˆOë þoxÊÇv{|-㙘kŽ.¹ímo[l,\bqX’ÈŒÐÕ,EÂ-YOÐüfÍz ë©éa]”„¼Œ3BEmgLQîUËŠC¡xM•ÊðÎxÂX¬Øµ§ Ÿò1Ú(œ&œí7W÷ïþ^tÜ<%Ù.û¦‚ûÆb—>0NÆ™"Ö¼½úc­–,5å»ÈÝÓŸþôì}ï{_á‰üÂ/üšàÕKYCèz1]èŠ`öªXBŒT\HÅò´5á2{WxCbß”JªPC©P }•ªúÇæJŠšr\ë$¦¶ Y¹+a Ë®SÅ¢Îådµ¥í÷:e²:âöîc,ËaÐ9¡ýò(ò1<}£Ïb±FÈÁ\G–B–ŒÕŽ®&BK²úJ_Ú}Îó]bm°$‘uVaùa]&9ËU2ÿ·~ë·²g<ãEd «Ëð³èRR ¥š*•²R½(~+,³v³b…ŠX¯¬Ø.$«ýé&@¯ådµ~ªTãàD‹+ÚZ“¬öòˆ\V¨ÉE^)ÚÏsÑÞtü…ßeåó®õ‘{ _µ<ñ¶·½-{ÚÓž–=þñÏ^øÂv^·Äb°$‘uDèß cI}XWR¥KšÅJŤç}H¯‡½(ê,L„dY°cÙŒpuJÕk[#þبÇk\'W‘öQÖuaÇÈ«h»>ð7ò Bqùíy%}+|¥ÛúêÏ€B"VF>øÁ^±-ÑKYÇ „<„ëOþäOŠØ¯‰,%é(üÞJ߇uõ…ÉK™HT;’1Ù‘…êš;ü@pq6Å(75´7%O,VRṄRâ-b cæðÄ>6#¯¤âB’‘WŠ«O™ÔNË$h’W¯ýÚ¯ßñì¡Ó%Ö–$²Îa¢É7ÔÁ7Á"§"Y/TA¡F¢¹PcHPÖ”¥„¾O(U ©ô±Ô§€üÝù¬|uê£ÄÆ@Ÿ§‹XꦥªÍöYð†,'^t´A]cƒeùäÝ¡ÐV㟒Jx«A(d Î«@ʱ¥Køêßþíߊ§ >üá/Né^+ƒe‰j,Iä*Ãi­|x).Š–A&A,m«º,NJ™ÕíòNî°ÔSR™rY±% Ú„Ø„ŠÖzw¾>§Õ‰GÄcÔ'eK}î°ÅÎ#2†]NÞƒðVãbXðÀ¢íaXÅ _!Ò¾’«yÎsžS¬¼r¼M¾kMÊKìŠ%‰\Åax… I,+6‰YÊ%B`UyÄÀû@’ç]•¥–z(“?”‰‹Õ:$¦®LauA ëÁ*çÂk—åÙú‹ö{õ>]åµIŽE$ô}:q=ù‰ñ÷7 <^ZS^…!äèv¤#¢_—XŸX’ÈÕ †Û¤F&±Òæ,Ö|š¨wl„‘ÿðÿ0:Q1õP¨^)“ÔJm[Va;@UEkm•ª“¼4ž^y9q Éì”T(G–zJ*Þm“~%Îë%¡¯NMîN}b5˜þ3îÚ.<ÆËÕ'žxbñð¨>ðÅ1î‹ô –%‰\Íaø-Ó‡u}àÈ>ûÙÏ;•û°®2âž”i(VŠ%Â?¡Xã~¾Ëû t$ª×rŸE@„Š@X¦¯¢c©kw\,uá®”Tú†“:!cuZ ý_i›:…ç2 ídàyÏ{^A–²Ëß ‘?þã?.<©%Ö7–$²DbðÊW¾²xhU0zЃŠM¼•1ëê÷î …âŠD-åãsVþzÙgÑ÷àÄ.`­§á KÝUþIë´^Îu’'B V_5Õ‰çô„'<¡{á7¿Cˆú×¥$Õ—XŸX’È$‚åW~%{Ò“ž”ÝûÞ÷^ýt¼„¾ë á/yÖ*²’¸e퇕îš;’œÈ#Zä)·¼.V¼{¹"D¢íúÁêd‘:9Ìq*¨'¾j«õÃ~ìc›Ýã÷( mmæ!#!å,±>±$‘%zƒ’^ŠeÅ.>Ö%ü%6tEV$ª)I U$qôPª÷±ú'”ê"—»¯6k“ÐÞÜ»¤MÓtY­WνêÂҗך»^eÔ…¯ª@Žþú¯ÿ:{Ñ‹^Tì<ÊSž².<¨%úaI"KŒ«Y27Ý«"®m‡}$ë½RöMJžR‰ç]5-C.oLs A*S,+Ö¶88q½$ôMY«—ô¹'X"ý@#Òh¿×)½Ã6Ø·Ã+êRã¥_Y,áì+žì»'–$²Ää R”®ðW„ÀÚÖå¡BBX¢ïQ†}€€Ê•ÊÔÕwY±¼ ïC‹U½ú<2+ô•~Ò®@$ëÃ[Ñú3õÖ¦ Ö2ô½|Œ¥ä¼´¶çÕ;î1yLá¹zBhÚ†%v?,Id‰…ƒˆÕ=¬Ë-¼ŠN8!{Õ«^•ýÒ/ýÒ$! E Õ«z”Õu‰úõvp"hƒd³zSÖ<¯&PîÈ4úÀ¥oSR©KÖw…œ•ð•þ±¡±)|eLþþïÿ>ûó?ÿó"Yþ»¿û»“Œõk‹%‰,1;ˆœÞï|ç;³?û³?+’¬WŸ§žÊT+Ÿ@ÙÂ=A(.–{ …êb¥K ³ª×Ë> u/Ÿ¼;Ä›(« Ñ”û +aZQ…h»¬R3ÞO~ò“ Âù—ù—"ĹÄUKYbM âÖ<àÙK_úÒB) sD^¥ïúú‚ØÇ®òPªÞS„,üõ’¨¶I‘צn,ýX¹4ôO"%÷¶C&A,å>@<±¡QH­-|e3«gØù†7¼¡õûKì^X’Èk‰aûOúЇ®~²¡à»>¬k,ÜÏš$õ)8eR¨¬eÅ”i(Ô9—Ç*5dÇ©,ú]ÛƒX¢‚T´_þÙ¶mhäùX²ëü«g>ó™Å1îë!,¸Ä´X’È»XÈå‡uQR–GøK¢–ÕÜ'Ô£ÜØB)R–tY±K(hG•”¡]_ÿú× ¢m[¥¶h¤}`E’AÈ6úÉ”ë'©ÿ›¿ù›Å8 _Ýýîw_³6,±X,Id‰Ý’ñVt¥ËŠå<ú<¬+µô…ZÚ¼šXVVº¤uºúÉU¥Pû€’Ž“w‘šÕTk ¤&|eq„~Òæ´Šv{Ö9²PçÇ=îqE®8m`‰«.–$²ÄU]ÕúÏ9ǶH"Û¤÷’—¼¤ a¢¦ƒ›«ŸRb¡PƒT¼öYV¼Ö'ïVÁGÉpý#|X_éw^‡P bçÝIþ;>çnw»[á-ö]²½Äîƒ%‰,q•åVõ°.«›(FÖ4+ÙRÙ©Â,‚TL/dÄRµ¬8MT¯—a¤†d‘Zò-Ùu€§Ãµ[Ÿ#t«ïx}ëÁ«Zbz,Id‰«(xGlxÔ°0"á¹ }XW˜Z”kŠW!1Dá/!4!5ÄÒ–¨ž ú*ÂW]HM?Z}¥=ozӛг®úÀé<“%®šX’ÈW Øâéx¯ýë‹&‰}<¬+Â_Â6]Ö5‚PXçöªðŠ„°RbY+ÈÉèu¾j CùŽ#Kx ¿þ뿞½à/XÓº/±6X’ÈW 8‹‚«Û£`Pî‚ñZ~Xr±Zj,©ðFlhD"ÂD<ŸðV¬öIó*s-+Fª¼¢.á+dóðņÑ×¼æ5ÙqÇ7™·Äî…%‰,±DL =ÖÅS9í´Ó Ÿ†¿l¶ë³CÚê+ÆõÛ2AXR›†¿ÒeÅA*S/+¾Šƒ/-4h{”sЄ¯xPoyË[Š™K\}±$‘%–èÓĪ.;éy*®>ëò{û>(ëÞð†ÅÕ…„»âü+Wª„âu̲âXRŒHäd”Umø×ý×bÿÇ#ùÈìÅ/~ñBŸ¿Äî%‰,±Ä@ðÊë²¼ÕÒá9âœâ÷ÄÈG<âáPüCËŠÃ[q¥ËŠ]¼¥.!7K ©ÒeI±v=ûÙÏÎÞøÆ7f¯xÅ+²ã?~¾Z¢À’D–Xb"Pð”r„¿\–·²îyˆDRŸ’ŸJó T„¿¼šÒiNÅÞ˜”TüFHʪ©Ø'Ó„oûÛÙ£ýè‚HÞúÖ·y¡%–,Id‰%ŠÚj¥ç?ÿùÙøÀÂÊÿÈG>2èa]}`:Dzâ ‰|D‚PšsÂÔÏê«¶ðÕûßÿþbå•Ã2”¹Ü4¸DKYb‰À³Qþê¯þªX{Ì1ÇŸ™jñ°.^Š×¶‡u…{Æcumfô é^äR^š+ã™Pô žÈ2|µD–$²Ä %,iÝtt»©W÷°®ðT\cÉË눅¯FþŠeżŽë_ÿúÙmns›âϱúJÂ}‰%ê°$‘%–X'0)î”T$îd˜z*}ÖeE™ÕWHMø Y”!×LWâ¾¼%a.O™¼×½î•Ýõ®w-6].=‘%ª°$‘%–X§05íú°.›y66X:Þ¥iõ•¼É _øÂìïþîïŠ0–3Æbã¥#øßö¶·ezЃV¿½Ä;°$‘%–ØM`ª ‘•Öe¯FJ*ãYÏzV±)ñ·~ë·ŠóÀšà ÅÇ?þñEÂ]ø*r8á.4ç¹–Ø}°$‘%–Ø!•>¬‹÷ÂVörüÂ/üBíúL}+Æó˜Çdw¹Ë]²W¿úÕE¾d‰%ú`I"K,qÁI'Tì$ÍŽ<¤Rõ°.^…ÐU,C~ÚÓž6úL°%®žX’ÈK\ wâÙ(Ï}îs³Ç>ö±Û½+³âa]<—ðO‘¼ãï(¼%–Š%‰,±ÄUVbµå-Їuy¶ÊoÿöoÏ Yb‰1X’ÈK,±Äƒ± ‚.±ÄK,1KYb‰%–Xb ²ìÿmá^·Ìse8IEND®B`‚pyclustering-0.10.1.2/docs/img/silhouette_score_for_various_K.png000077500000000000000000000467601375753423500252010ustar00rootroot00000000000000‰PNG  IHDR%dÿK¿sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æðM0IDATx^íÝ |UÕð@ Œ@#›P,*d•ÅZP‹P•J± epfX>|¬ˆÐTpX-¸ B)HUê(«UYDQ@*$ ˇ H)a{“ßɹáääm÷½—ä¾—ß÷ó9¾ó¿÷¼“ç ïæÏ=÷Þ$_!"""*eåô+QùóçKRR’lݺU/ÉwâÄ iÕª•\{íµ²zõj½´x}óÍ72zôhIOO—êÕ«K5¤C‡òç?ÿY· *»¼ô]µ}ýõ×’’’â÷óóÇ?þQþå_þE~øá½$öŽ9"²cǽä*,Çg. kÖ¬Q?¯ŽqãÆIË–-åÊ•+zIbcRBaùî»ï¤cÇŽ²ÿ~ù裤k×®zMñZµj•|øá‡ò‹_üB–,Y"o½õ–4nÜX|ðAÉÌÌÔ­ˆÈQZßUÓåË—å׿þµÔªUK/ Ϲsçä™gž‘ßþö·RµjU½4ö”L˜0ÁoR2dÈÙ´i“ŽJÊ8 ,ÐK“ iß¾}jtâôéÓ²víZiÛ¶­^Sü~ùË_ª#.쨰síÞ½»::ìÙ³§¼ð ’››«[Qi~WMÓ¦MSÉ’ 7ð‡÷äÉ“*1(-7ÜpC©m7ªU«&<òˆ<ÿüóRf[0)¡ p$qçwJùòååÓO?•[o½U¯)8Òò7”ÚºukuTõý÷ßë%De[iWHŒÆ/³gÏ–ÔÔT½4üðÃ’““£[7`Àu*û“O>ÑK“ ;¶.]ºÈõ×_¯êør‡ëÒ¥Ka•H3|9qÞŸ¨¬óÊwm0Ê?à?ÿùÏõÒð`dåË/¿”»îºK/ɇ>ï¿ÿ~yñÅÕgœÎ5j”UùéOZd´ÉÙˆ#däÈ‘*9iß¾½ >\½0?ã7ÞPõgŸ}VªA 5:³sçN•aôçÝwßU#}ûö•ßýîw2wî\™4i’:½ŒQ*üÿÿóŸÿÔïÉÎΖ›nºI¦OŸ.+W®T£¼GUÉæÿ„‚9u˜„ÿ÷„—÷ '*$ï ‹½*y_<ßñãÇõšð8p àý¡J^r¡ß¾×^{M½wÆŒz QÙäµïê¬Y³|×]wïØ±c*v>ß矮â`/^¬ÚnÞ¼Y/É·bÅ µ|òäÉzI>§ý«¯¾ª—ø| 4ð%%%ùò½$_×®]}©©©¾üã*ÆçÁ{ñùlyI†ZgB¿•+Wöå%Nz‰Oý ´«[·nA¿°téRµüý÷ß×KŠÊKò|gÏžõ]sÍ5…öcØÆx¯¿mÝ¡C_›6mt”¸8RBáHY?Ž:0q-\?úÑ$ïKVÁ€Ë—/Wö<ð€üÇü‡^JT¶yỊSI˜2eŠÔ®][/ &Ÿ‚=úùñÇ«×Aƒ©W&»ãtÉ_ÿúW½$ßO~ò¹ýöÛu”¯ÿþræÌùâ‹/ô÷š7o®N9pº0BU¥JUg¹yj&/Q#,ÿú¯ÿªN¯¡`ä#/™‘Ý»wëVÁa»>|XG‰‹I „KÑpnxáÂ…j¢U¸;;œóÅ8œ‚/f¸0ì‰áRLxÅ0©¿¹&De‘¾«8XhÖ¬™ºRs=P0ï ðGIS0ÎéÌ1aâ+þˆãt­ ßÿ:uê¨õ&,³9Ëì¶nàv&l;´ó`HŠ^zé%uŠû±-[¶¨DÿOæiž`°]ÂmϘ”PP¸lçL-Z¤¾X8· ΟV¨P!¬‚+Â/2Î+wîÜYÞyç‚/>å+íïê®]»dóæÍrÝu×$*€y" 4Põ@œË‡íÉë5kÖTÿ/ÿ÷ÿ§—äóù|rìØ±"—c™ÍY†¾J’1Lˆ}ê©§äé§Ÿ–»ï¾[Í%ÁDd7õÑÖí%ÖñˆI …„ÙèØá½ýöÛaíìb}ú÷*AB‚+ –.]ªnÈDDE•æwÉ& ›Å¹$øå—_.¸R%›o¾Y½~ûí·êÕ?âðßÿýßêÕƒœþpÖ;¾úê+5)Õ„$Ü÷“\ÁÙ‡”ÄÈFt@Ùû-LŽusª ÷¹å–[t”ÀÔÌ"C Éi'NTËxàßÅ‹õÒâµ~ýz5Á¬aƾ?þØ·iÓ¦B%ï(D·$*{¼ô]õÇÍD×ÜÜ\õ]3fŒ^’ïÊ•+¾{î¹ÇW¡B_^Òå[½zµï¿þë¿|×^{­¯E‹¾óçÏë–ùRÓÒÒ|õë×÷Í›7Ï·|ùr߯~õ+õ^xáÝʧ&¦âgaò(&•âó>|X­ 4ѵgÏž:º íž|òIås&O™2E/ñù:uêä«Q£†š¤Ïÿì³Ïª ²Õ«W÷=ú裺Uà‰®'NœPËgΜ©—$.Ž”PØpù\VV–ºÅ{¿~ý$og§×Ü‘G3fÆåíÚµ+T¢™¸F”¨Jã»-œ’Åö¿üå/zI>Œ4`„—ç%9Ò£G‚˃1 ÖÀü—©S§J^â"½{÷– 6¨§O˜˜š—´¨9&ݺuS§S^}õU½6ö0RƒSXø ˜‡û–àöÿ¸¬8Ø&8…öÐCé%‰‹ä#""OÀk$˜›Ò¦M½4|¸)&Û†:UoðØ€úõë« þ‰Ž#%DDä xˆ F&Nœ¨—кuëÔœž²²M˜”‘gà´ FKŠó)Áñ§˜ðäd7wég<}CDDDžÀ‘"""ò&%DDDä ž>}såÊõ<Üô†·'òì2p¾7Þ*W.~Žk¸?!òž"û$%^uèÐ!uÃï|?ýY»v­¯W¯^êæPh÷Þ{ïé5­Y³Æ×²eK_JJНQ£F¾9sæè5WýáP7ÑC´]·n^îOXX¼[œý‰§GJðÌ€êÕ«ËŠ<ôˆŠÂ ’pKvÜ 7ڡиÍÜÃ38òõÀ57“œqÃ*ÜÒgËKJÔcÁ÷÷–xüñÇå7¿ùzï°aÃäOú“z?,^¼XÝ,köìÙÒ¡Cyå•WÔmº¿þúkuÿ†ppâ¿îq›¹gïOÂJJp4G½mÛ69zôhÈ àáM¸žC€aÜÉnèСzmxð¨i|È'N”ʃ”⠾˖-Sw<ä"<ÜfîáE< äSSSõRÿpš$ÔþÏGyÿý÷ =Âû <¿dÓ¦M*Æ´äÌ™3GÅ€GÄ£ßçž{N/),77Wö'õêÕSû0îOBÃwwÅS¹ùÝ·™{ØŸÔ­[·`VRRG>á`RâÿÀºÇmæ^¬“’N:I‹-dÆŒz‰¨÷à&Zxô=vQ¸-ø’%K¤OŸ>º…ÈðáÃeÇŽŸ^ë<œÎ†[~£?"*}øŽãá‘®’S¬Ž|ÂÁ¤ÄþuÛ̽X'%Mš4‘AƒÉ3Ï<£—ˆlܸQ¦ÁÄTì¢ÒÒÒÔÁMûöíu ‘I“&É‚ dïÞ½zIa)‰úÝã6s/¢‘S,Ž|ý²¸‰¿îq›¹gïD‚ 7)yì±Çd̘1z‰¨äÎ;ïTß}\5ƒ¤‰ ÂèÀçÞ|óMÙ³g^rÜaÂî·™{öAN±$%¡Ž|°Có‡Ã­DÞg·‹ƒì¢"9}ccRâÿÀºÇmæ^‰%%ÁŽ|êÔ©£—Æ‘’è𨿨f+uMdWÆ=ºvU¼l3çÿÃßÿƒ[¡¶‰ù³üµõH N÷þÏÿüº’Æñoÿöo*á0'º¦§§««o·Ür‹z4} ‰®6&%îð¬{n¶Yç?Ô5‘ìç{‰Ë ;))–;!é8v옎ò?~\Ê—/tg’’¢>”Y¿\–ðJM¸v¥µC£ÄcïÄíØl-T_¥)Øç²?·»a¿×ŽKÚÖ­[Õé@BúøñãUŒ‘O'AÜ£G—kÖ¬‘æÍ›«G´Ïœ9³Ð•zýúõ“éÓ§Kff¦jƒÛà= 4Ð-¼«´xõs¹ËÿP}…Z_œJëç–´°’’â8ò!*¥¹Ó(I^þìÒ¥‹šb—ùóç«õxEbêܹ³|ñÅêô-ö/þF@p[ììlÕ÷LÂ\/*Ƀ±üY±ì«¬(ÎmVœ}§h?wXIIqùyU´;Ö`гoŠ-·¿+s–Ím_¡Ä²¯hÄúÿ+¬¤¤¸Ž|ˆˆâWþ„Ë?ÎXç5TßÑüÜP}›Ü´-«¢ÝF¥¹}‹eN Q<‰v'^Û^Üž‰«¸·LJˆ¨Ì)îk¬ØŸÓŽCqÓ¶$¹ýÿ(NÅù9JêÿÑù9%ñ³Š“""H¤?.D‘`RBDDÅ*Úd+ïôýT²˜”•"þÁ,ª8· ···1)!"Š‚óGŽèÈ«BýõÒ¿_&%DDDä LJˆˆˆ¨D„•aRBDDDžÀ¤„ˆˆˆŠ…Ûù*LJˆˆˆÈ˜”•nZ‰J“""JNâÅä+6Jz{2)!"""O`RBDDDžÀ¤„ˆˆˆjœÈûìGÇ ì‡ªU«¦ždœ>e³^*’ý|ÏB#‚Áb7mÁM˾ÀŒQ3õÞ›Æ~ “[_–§¶$ËÞ¬^1í;Üu0ãHû3FÌ8Ò¾±³Ízôè¡4˾;ÀŒ#í Ìu0ãHû3FìŒÀÝ™ýIyµ4L8c öä϶mÛªâèСƒ´lÙRfÍš%3gÎÔK ö¨qûÖÓ¡˜G6¯F 'v#š÷ÆZ G;ŸËŒCmƒpcÔm±îÛŒ#í Ìu05Þ"ëcµ bÑ·GÚ˜1ê`Æ‘öfŒ:˜±ÝìGÅJX§o¢yò§£\¹rrÇw}ªg°G»-æã‘z¸±›Í{c]=j¼`½;õhcÔQ[¥Š›÷†ŠQ·c§mŒºŠGjë6FÝŽz´1êvìÔ£Q·c§n®G!"*a%%Ñ<ùÓQ•;vð©žDDDäWØW߸}ò'æ†àyû÷ïWÉ®ÜÁ«ÓžˆˆˆÈvRâöÉŸ§N’'žxB]>Œ«t>¬ÞÓºukÝ":˜,ã”X+ξ‰ˆˆÈ¿°“póäÏiÓ¦©§y¢-æž`Ô¤]»vz-Qa®’’²Š£&DDDÅ/a’&DDDñ#%DDDä LJˆˆˆÈ˜”‘'0)!"""O`RBDDDžÀ¤$¼Ò‡ˆˆ(öâ&)q&DDD‰‰#%DDDä LJˆˆˆÈ˜”ÄO3‰Ìž=[5j$•*U’ôôtY¿~½^Sž™•””T¤œ?^·Èç¦O"ŠOLJˆ(¦/^,#FŒ±cÇÊöíÛ¥cÇŽÒ½{wõ$ñ@RSSÕSÆÍ‚äÃIŸD˜”QLM:U,C† ‘¦M›ÊôéÓ¥^½z2gÎÝ¢(ŒŒÔ©S§P1EÒ'Å&%D3.\mÛ¶I·nÝô’|ˆ7nܨ£¢Îž=+ 4n¸Azõê¥FC‘ö™››+gΜ)TàâÅ‹’’ì+(nâhÞ*Že_vŒº;õ€q9ŸÚ^x Öu;vêÑÆ¨Û±S6FÝŽzıÞf¨›ëÃzo˜1êvìÔ£Q·c§mŒº¿Å”äˣ랃HµjÕäĉ’>e³^*’ý|ÏBs6Ìu0ã@mÁMŒ:˜q¨÷–¤›Æ~ “[_–§¶$ËÞ¬^Q}îpcÔÁŒ#í Ìu0ãHû3FœmÖ£GiGÚgJJŠ:ò2 àEî夂â&Žæ½¡âXöeǨ۱S_ÉOøð¬=êvìÔ£Q·c§mŒº;õˆc½ÍP7ׇõÞ0cÔíØ©G£nÇN=Úu1ЉI ÅLÅŠÕ庫W¯ÖKò!6O½ƒ;vHݺuU‹>‰(>0)!¢˜Â)“¹sçʼyód÷îÝ2räHuéîСCÕúªS+ÌûX¹r¥ìß¿_%#¸Ê¯N{Õ'%&%DSýúõS—ìfffJóæÍeݺujâ*®®$¸‰ãÔ©SòÄO¨K}qEÍáÇÕ{Z·n­[„“"йaÆIvv¶º,—óvêÔI¯Y³fº‹«cÚ´i’““£ÚbžFMÚµk§×^¬O"J LJˆˆˆÈ˜””0Ü÷Á)¡¸iKDD‘'0)!"""O`RBDDDžÀ¤„ˆˆˆûì3Ý‚ˆˆˆèª°“’©S§ÊàÁƒeÈ!Ò´iS™>}ºÔ«WOæÌ™£[†õ]»v•1cÆÈÍ7߬^ï¾ûnµ<ÜÜ\9sæL¡/^””d_A £nÇN=Úu;vêâ›Æ~PP‚µGÝ.vÛP%¥œOm/¼ªØz¯;õhcÔíØ©G£nÇN=Úuëmææ½¡bÔíØ©G£nÇN=Úu;vêæz"¢âäË£ë]¸pAªT©"K–,‘>}úè¥"Ç—;vÈÚµkõ’«êׯ/#GŽTÅ1mÚ4•”äääè%…eddÈ„ ttÕÂ… ÕÏ'¢ÒwîÜ9éß¿¿œ>}ZRSSõRïÃANµjÕäĉ’>e³^*’ý|ÏBÅ »i nâXöfŒ:˜q¨÷â@jrëËòÔ–dÙ›Õ+¦}‡£fi_`ƨƒGÚ v¶Y=¤B… 1íÛì Ì8Ò¾ÀŒQ3Ž´/0cÔÁŽOž<)µjÕ*ØŸ„•”9rDÒÒÒdÆ Ò¾}{½TdÒ¤I²`ÁÙ»w¯^rUÅŠeþüùjçå@rñØc©°Ü\‡FcŽ=*5kÖÔK[³Œ•êuWÆ=êÕ䬬·cÁ®^½ZPá A¡q›¹‡Hݺu™”ä‰e˾ÀŒQ3õ^&%îc&%îú;)q5Ñ5))I×ò!Ÿ±—™Ü¶Ç„X|(³~¹e¥ä^NR%Ø:g½£”µí‹Âm澇°’d1ÉÉÉrìØ1½$ßñãÇ¥víÚ:*¬N:®ÚQÙVR‚S1¸ÃÜ&ÄæéS»v튴_µjUÀöDDDT¶…}úfÔ¨Q2wî\™7ožìÞ½[M`ÅåÀC‡U먮°q`,’^xAöìÙ£^?úè#uY1‘-ì¤÷Á•3™™™Ò¼ysY·n,[¶L4h Ö#AÁ„TFD-Z$o¼ñ†ÜvÛmjÒ+îuÒ¦MÝ‚üÁägQ¼rs£Å×^{MÝ÷èºë®Såg?û™lÙ²E¯Í7hÐ 5Í,mÛ¶Õk‰(Q¸šè:lØ0ÉÎÎVWÈlÛ¶M:uê¤×ˆ¬Y³F%¦x@’à’bŒ®ôíÛW¯!¢DåöF‹Øw<üðÃòÉ'Ÿ¨›.âvݺu“Çëùî½÷^uàãQbq•”…âöF‹o½õ–:àÁ,n´ˆ‘“+W®È_ÿúWÝ"®ÎÃz§Ô¨QC¯ñ/7c´ãhÞ*Že_vŒº;õ€q€›1¬7êvìÔ£Q·c§mŒº;õˆcãfŒæú°ÞfŒº;õhcÔíØ©G£î/F1…uŸ’ÒbÞW ¬Ü§$˜P׃㗋£Gçy ÛÌ=û¾¦Hn´hûá‡äúë¯W}ôêÕK-Ã雥K—ªI÷Õ«W—Î;KVV–joÆHä}öÍ™”Ä&%±Çmæ^°¤$’-Úž|òIY¹r¥ìÚµKÍIœºöÚkÕ¶ȸqãäÒ¥Kê42FPü v3ÆÎ³¶ê¥þoD(vÓÜıì Ìu0ãPïMÏ\![]‘q[Ëɶñ÷Æ´ïpcÔÁŒ#í Ìu0ãHûÄÎ6snÆ˾;ÀŒ#í Ìu0ãHû3FìØ¾#OßQÌÙ7I uãDÇäÉ“åOú“¼ûî» `¢}Ïž=¥Y³frß}÷ÉòåËå›o¾‘?¼š˜Û‚݌Ѿñ`¸q4ï Dz/;FÝŽzÀøJþï ¯ÁÚ£nÇN=Úu;vêÑÆ¨Û±S8ÖÛ us}Xï 3FÝŽz´1êvìÔ£Q÷£˜˜”QÌDr£EÇ‹/¾¨FTp+\± ެ0j²oß>½„ˆ“"Š™Hn´S¦L‘‰'ÊŠ+¤U«Vzi`ò=tèJNˆ(q0)!¢˜r{£Eœ²yöÙgUû† ªQ”³gϪõx=z´º\·$À%Ä8…ƒQs2-Å?&%DSno´ˆ­áªÜ×#NÁéÀé /¿üRz÷î-Mš4‘G}T½"I©ZµªjCD‰I Åœ›-¢&ÂÚ—ôBåÊ•ÕÕ8˜—‚ä%''G½WÒQbaRBDDDžÀ¤„ˆˆˆÓ-D&Ož,S§N•—^zI>ÿüs©S§ŽtíÚU~øáÝ‚ˆ“"Š)$ƒ–!C†HÓ¦MeúôéR¯^=™3gŽnQÖ#Á3fŒÜ|óÍêõî»ïVË£$¨#ÉéÛ·¯4kÖL,X çΓ… ª6D”<”`g8:sæ K;jËYn3wÅp¾Ÿ¦ .ȶmÛ¤[·nzI>Ä7nÔQa)±ÛßsÏ=í8 ÇŽ+Ô§y:wî°OÈÍÍ-ô¹OŸ>­–ÿý÷RþÒ? ÊÉ“'ÃŽÝ´uDz/;FÝŽzÀøâ?Ôw¯ÁÚ£nÇN=Úu;vêÑÆ¨Û±S8ÖÛ us}Xï 3FÝŽz´1êvìÔ£Q÷ãûû“¼Šg}ûí·ø”,,,,ø~Ú>¬ÖmذA/É—••åkÒ¤‰Ž «P¡‚ï­·ÞÒQ>Ä+VTuô…>Ñ·éñÇ÷å%*:*êw¿û]¡ÏËÂÂâÝâìO’🼞têÔ)¹îºëÔ¹èjժ饎1L~èÐ!IMMÕK)n3÷0âP¿~}ùûßÿ.Õ«W×Kó9rDÒÒÒÔF»víôR‘¼¤DÞ|óMÙ³g^rU^ò¡NÇ<üðÃz‰H^R¢N?^õÕ¡CÕwݺuu ‘¼¤DýÞV¬X¡—†‘ö' 4àþ$Lün¸Çmæž½?ñtR‚_0vøÐü‡Æíå·™{Á¶NßT©RE–,Y"}úôÑKE†.;vìµk×ê%Wa‡4räHUÓ¦MSóHrrrdÿþýòãÿX¾øâ iÑ¢…n!Ò»woµCBþ®ÝáörÛÌ={›q¢+Å F=p ðêÕ«õ’|ˆÛ·o¯£Â0¢b·_µjUA{\ZŒ«mÌ6H~à꓈â“"Š©Q£FÉܹseÞ¼y²{÷n5‚S&C‡U먮°q`IÈ /¼ Nïàõ£>R—CRR’ªOš4IÝ¿d×®]2hÐ 5"Ó¿Õ†ˆCrîHäaÉÉÉêFIåË—×K(n/÷¸ÍÜ ¶ÍpÉnÍš5Uñâ‹/Ê?ÿùO5ŸäöÛoWëg̘¡Þwÿý÷«çàqÃ4\JŒ÷ ÁåøLØ9%˜’™™)3gÎTü‹-Rïuƒ¿kw¸½Üã6sÏÜfžžSBDDDeOß‘'0)!"""O`RBDDDžÀ¤„Š˜?¾ºâaëÖ­zI¾'NH«V­äÚk¯-r gqÃý*~ýë_«§Äâã¸A—y "ò&¯íOðÈ‚ÿ÷—o¼Q=q7ÔÃú=0’J“ Ëwß}§žöŠYárMóʈâ†K@qï ¼âjìÀp¥îöKDñ§´ö'¸‚«S§NêIÖ£G–åË—Ë3Ï<#~ø¡ºç Ÿ:]ú˜”PHûöíS—dâŽ{¸aUÛ¶mõšâ‡‹Ãð({\ú¹~ýzu_ ìTð¨{܃ˆâKiîO°ÁÏþùçeذaê2Ôßüæ7ê‡V •.&%n ~çwªëÇ?ýôS¹õÖ[õš’±nÝ:õpó,œ¶!¢øUÚû“ *¨WÜÖÜä<éR¥Jê•J“ ; I\ýõªŽs°áºtéRX%Ômr”@ÕªU¥Gj§sнzõòûp7"ò&/ìO0BƒSÁ¸gèçŸ.gÏžUÏTÂ)œ–-[ÊÏ~ö3Ý’J “ Èy@ÚÇ\è鬡dgg«#’pŠ¿´™0¤ =ö˜šäŠs¿/¿ü²š_‚sÒGUë‰ÈÛ¼°?ÁÍ'Ÿ|¢¢Ö­[«ƒ$))Á\5ôA¥‹wt¥"0[IÀÏþsyÿý÷Õ<Ž?þñêVÀáÀÃÒþ÷ÿWGÁÝtÓMjÇÈO]:vì¨×†Æý‰;ün¸Çmæ^‘ý ’’¼‚¯W¯^êQðym|y;,jÍš5¾–-[ªÛôæu¨ž#`ûÃþPp+_´ÍÛYé5áÉÛ‰¨ÏsâÄ ½„‚Ámš—.]Z¢·wÜfîáûˆï%¾Ÿþ,[¶Ì7vìXß;ï¼Öþdÿþý¾*Uªø†îûúë¯Õ#òvè¾?ÿùϺ…Ï·hÑ"µ ëÐmñ¬’œœÝ"4îOÜáwÃ=n3÷ìý‰:!üüCn¿ývy饗†„#=z¨£”íÛ·Ë3Ï<#ÿùŸÿ)y;!ÝBdñâÅ2bÄÉÛ9©6h‹'¾\vìØ¡NýøÃýItøÝpÛÌ={QRR\;‘ŒŒ ™0a‚Ž®Z¸p¡êˆJ¾ãýû÷YRÒ¤I4hqulܸQ:tè ®–Áþ$--M6lØ íÛ·×-D&Mš$ ,½{÷ê%…qBä}öþ$¢¤¤¸v"<²‰N¢déÍ2Vª×]÷¨×âÄ#÷b=R‚ýÉc=&cÆŒÑKDí;î¼óNõÝÇ¥¼ØŸ`Ó®];ÝB$++KÞ|óMÙ³g^RX°ýIçY[õÒ’ùwøÝpÛÌ={ñM°³19¹¹Ü_{™)%%E}(³~¹,á•xÜ^Ç­*(ˆs/'©b·+®Û¬´K,Õ©SGŽ;¦£|Ç—òåË«ƒ‘ZµjIrr²ß6µk×ÖQQÁö'ο±’üwÅÙ^,án3÷ÅQRR\;òކOXPüÅD±‚Ñ]špYe«V­Ô«bÅŠ’žž^¤ bs$–ˆâ_DI w"dcÂB޳gϪ¹c(€«õPw®¼Ãišª:`’|NNŽºO &ÏÏ›7O^ýu=z´n!jÝܹsÕ:´9r¤êϾ— Å7•”p'Bn1 ¡@¶nݪ&£ö¨?^ŘÓaÞ7NZ¶l™¬Y³Fš7o.'N”™3gÊ/~ñ ÝB¤_¿~ê2àÌÌLÕ7hÃ{4h [Pqs¾óÎ÷žû**)áN¤l¶qÖÅb'Ë¾Š›3©âés{Y—.]Ôü1»ÌŸ?_­Ç+ö¦Î;Ë_|¡&¦â ÈßÁ˰aÃ$;;[µÁÝbq %•”p'B%©8ÿøgßD~)RÍ)!ŠWÜQy“’2ª$dJògQéàwœbI áÌ·2ç]7&%DDePIŽ`†úY¡ÖSÙÁ¤„<;+"¢²I Å5a%&%DDT¢x0A0)! w¤DDÅ‹I QLB¨,á¿wò&%D Žlˆ(^0)¡„Vš™j¿È¤„ˆˆˆÜ¸àýå|Û,PÛpc»[ËbŽHcÔýÅþJ0<È¡DíQqòêçŠVR^"àCB±dÉéÓ§^,2|øpÙ±c‡¬]»V/ ìÖ[o•víÚÉ«¯¾ª—äÙ,]ºT*V¬(Õ«W—Î;KVV–\ýõºEQ2aÂ]µpáB•ôQé;wîœôïß_NŸ>-©©©zéUmÚ´‘–-[:¨ÁÁÎý÷ß/Ï=÷œ^ŠÆ¯k®¹F-ÃþäÔ©SjŸ.ä 8pƒƒ-ôÛyÖV½TdWÆ=ºV¶4ËX©kùÛÀŽÓ3WÈÄVWdÜÖr²mü½Û;ÛÏŒCõ*¶ë;ZÁúvû³°ã ½k×®R¡B½4ŸÛ¾Ã]Îç*¾ œŸuòäI©[·nÁþ$éðáþ´´4Ù°aƒ´oß^5‚I“&É‚ dïÞ½z‰[¶lQ;¡Ï>ûLZ·n­—æ-]{íµÒ A9pà€Œ7N.]º$Û¶mS#(þÛ‰Ô¬YS/¥@‚}!ÀüÇ`ÿÉ4FÌ8Ò¾ÀŒQ3Ž´/0cÔÁÙñb›µÈúX-ƒXômÇÅ%ÒÏ fì|N;¶Ù;Ó… Ôrˆ(öANAR²qãFµ#pà ÿæ›oÊž={ôÿ~ó›ß¨÷~ùå—z‰H, ,Z´Húöí«—‡¤¤ZµjrâÄ &%a@R‚!í=zøMJœ¡¾ìç{ö‹&FÌ8Ò¾ÀŒQ3Ž´/0cÔᦱÈäÖ—Õ6k½Äì(BDÞ†‰¨&ŸÏWd™?¯¿þº4kÖ¬PBýúõS_±î¾ûî“åË—Ë7ß|#~x€d;9³þXä^N*(ˆcYгïXûs‰¯äÿ¾ð¬=êvìÔ#í⦭Û¬o;§€¿åv_vl—p×û[g—Òè+Ôzs™©†C1;Ù ±y¤ãÏÛo¿­ŽDyä½$0dC‡RÉIYÆäŠY¼䨸½$òuõͨQ£dîܹ2oÞ<Ù½{·Œ9RÍ”:t¨j4pà@3fŒª›pTƒÉkö©•³gÏÊèÑ£eÓ¦M’-kÖ¬QG7Øa™ç™‰(±ð ‡¼† g|QI †F1ã=33Sš7o.ëÖ­Ssp$HPpÖ„¡ÓO?ýT]JlÑæ˜ôîÝ[š4i">ú¨zE’RµjUÝŠB±¿LvL‰#‘~·<È!¢HÜÑuذaê #LëÔ©“^#j'0þ|åC’óĘÐc«\¹²¬\¹R Ùb6~NNŽz?&™Qñq&™ˆJrˆ(RII¢áˆQé‰÷ƒœD¹¢²'žÿý&lRBDDDñ%n“’xΉˆˆ¨(Ž”QÜòòª›Ïååÿ’Ĥ„ˆˆÿ¸Ç7&%DÄ+•ELJˆˆˆÈ˜”‘'0)!"*F<WvðÆ•ÑcRBDDDžÀ¤„(ðHÛ;8òQü¸}Ë.&%DDDä LJˆˆˆÈ˜”• žþ! ŒI y“"""‹åèš—G똔”2¯þàâååQ"ã÷ÎÛ˜”…À?dD%ƒI yBAR2{öliÔ¨‘TªTIÒÓÓeýúõzMQóçÏ—¤¤¤"åüùóºE>7}Åg£h¹Ý>*)Y¼x±Œ1BÆŽ+Û·o—Ž;J÷îÝåàÁƒª‘?©©©rôèÑBɇ#’>K ÿaQi)Î}÷koTR2uêTýÁANµjÕäĉ’>e³^*’ý|ÏBôƒÅþÖÙÂí ì¾m¡~V(nú¶ã›Æ~ “[_–§¶$ËÞ¬^Û;}›q¨¾ÃQ3Ž´/0cÔÁŒC½×f¯w¶Y=¤B… ®ú7FìØmßÁØïµ…êÛŽOž<)µjÕ*ØŸ”ljEíÚµUâcǎ騰›o¾YíHn½õVõEŸ1c†ÚQìܹS7n¬¾ônû„1cÆÈ¨Q£t”¿ÁèÊ]wÝ%gmÕKEveÜSèшmÎzël¡úŠ%ûgûœÚ‚¿öé™+db«+2nk9Ù6þ^½ô*óg…ê;Üu0ãHû3FÌ8Ò¾ÀŒQg›uíÚUZd}¬–A,ú¶cS´}›"í üõmÇ6ìD‚1GI£¤+W®T£¤Ï=÷œZfÃȈ=ÚjФO"Š?]±S0ù|¾"ËmÛ¶•GyDn¿ýv5Wäí·ß–&MšÈ¬Y³t‹|nú„””•)™qæ^N*(þb»[g—P}ŲØ?+ØÏ ÔÖ‰í’{%ÛâÕïú }E£nÇN=Úu;vêÑÆ¨«Xo37ï £î/6‹³ÎYnì¼ß,ÚºQ÷û+`”tÛ¶mÒ­[7½$â7ꨨ³gÏJƒ ä†n^½z©yhŽHûŒætp Øß:;ÅM_vŒº]ì¶n‹›¾‹ÄÖéà"ëº;õhcÔíØ©G£nÇN=Pl{½y:Ø\ï·m„1êþb³8ëœõáÆÎûƒû½¡ÖÛmíÅÑéüqùî»ïdùò埾±a'îp«Í" &T_ѰûûïµÙí6óg…ê;Üu0ãHû3FÌ8Ò¾ÀŒQs¸µñ¸UjÄ¢o;6EÛ·)Ò¾À_ßvl³‡[MGŽQ§u7lØ íÛ·×KE&Mš$ ,(rŠ6oÞ,ûÛß ¼.[¶¬`ä5’>§ƒ‰¼Ï>\¾bÅŠjÒØêÕ« %ˆ{÷î­£à0‚d;ˆEŸD¿Ü޼¢8p*¸eË–jäuæÌ™z©û‘×hN;Ån[p£n³Ûºå¦o;¶OjïômÆ¡ú7FÌ8Ò¾ÀŒQ3õ^›½Þ<ŒE7}‡£vlжï`ì÷ÚBõmÇöé`uú_\L›7ožìÞ½[FŽ©.Ý:t¨j4pà@õwàèçs÷ï߯’œëÅ«ÓBõID‰#(ÉÉÉEæŽ?~¼È³@Ê•+'wÜq‡ìÛ·OÅ‘öÍéà@q4ï £n»­Ûâ¦ï"±u:¸Èz£nÇN=Úu;vêÑÆ¨Û±SÛÅ^ož6×ûmaŒº¿Ø,Î:g}¸±ó~³`Ù)ˆí÷ÚÅ^o·µc“JJúõë§&Žeffª+iÖ­[§†OqŽLà>$ŽS§NÉO<¡.õÅyÝÇ«÷´nÝZ·Ý'%s”Ô„Ø<õŒ3òZ·n]Ç¢O"Š]‡ &ÙÙÙjr&•uêÔI¯Y³fºÚÆ1mÚ4ÉÉÉQmq´‚Q“víÚéµWë³4᜹Sˆ(¶8òZ|¸ï"býï¢4ÿ$%DD±À‘W"Š“"й²4òZšb}„LTÚ˜”‘'0)!"""O`RÇ8tKDD‰„I Q ˆuÉd”ˆ“"""ò&%DDDä LJb,ÖÃôDD±Â}y“" ˆI6•¤„IJ¸ã$""Šo)!"""O`RBDDDžÀ¤„ˆˆˆ¬[ä»÷Þ{åèÑ£eÙ²ez Qa*)™:uª }úèÅ"Ç—;vÈÚµkõ’À~øá¹þúëU½zõRËpúféÒ¥R±bE©^½ºtîÜY²²²T»@222d„ :ºjáÂ…‚ÏHD¥ïܹsÒ¿9}ú´¤¦¦ê¥…átð”)SÔéO~òu ƒXpPóÇ?þQvíÚ¥bœ>ž4i’´nÝZÅ€ýÉ‚ t”¯M›6²yóf…†ƒœjժɉ'$}ÊÕ÷e?ß³Ðs³‚ÅnÚ‚›u›Û¾lvßfª¯›Æ~ “[_–§¶$ËÞ¬^ÛGÒw¸1ê`Æ‘öfŒ:˜q¨÷ÚìõÎ6ëÑ£‡T¨PÁUßáÆ¨ƒGÚ˜1ê`Æ¡ÞksÓ7œ©ö+˜c⌾â”е×^[ètð¥K—‚žæ5"ï³ç¨•ÇBÌã0`€´jÕJÚµk§\ðÀ*ép NçN}ùå—j¤C­>ú¨zÅ=MªV­ªÚQâñÒéàXÌQ³ãhÞ*FÝ.ÚŠíb¯3c§0¶æ¨YoÔíØ©G£nÇN=Úu;vêb»ØëÍ9jæz¿m#ŒQ·c§mŒº;õhcÔýÅ(¦‚‰®˜h† œ‡Åh§Nôšüs¹óçÏב¨v8ò± FG råÊjø;"$/999êý8J!¢Ä…+bp*xõêÕzI>ÄæéNOœ8QV¬X¡FABÁÑÕ¡C‡TrBD‰£ )!"Šœ2™;w®Ì›7OvïÞ-#GŽ,r:§V8eóì³ÏªöÎé`œ¼Ž=Z´â€I¸¢§ƒ‰“ÁÄBsr!Q¼áé`"Š“"Š9ž&¢H0)I`u!"¢x¤„ˆˆˆûL·™]êÕ«'sæÌQlXc̘1róÍ7«×»ï¾[-Œ’ Ž$§oß¾Ò¬Y3Y°`œ;wN.\¨Úø“››+gΜ)TàâÅ‹’’ì+(ÁbÔýÅfqÖ9ëíØ.ÁÖÙÅî+ÜØ~¿›÷Äå|j{áÕîËŽz´1êvìÔ£Q·c§mŒºŠõ6sóÞP1êvìÔ£Q·c§mŒº;us= QqHÊK|UªT‘%K–HŸ>}ôb‘áÇˎ;díÚµzÉUõë×—‘#Gªâ˜6mšJDrrrdÿþýòãÿX¾øâ iÑ¢…n!Ò»wo©^½ºJPüÁéž &èè*$2øŒDTúppÑ¿9}ú´¤¦¦ê¥Þ‡ƒœjժɉ'$}Êf½T$ûùžÒðéuã †œ¡'"*,‘&ÎÛq4ï Ç¢/»ØëÌØ©ŒLœ/XoÔíØ©G£nÇN=Úu;vêbœžqŠßöÆÄys½ß¶ƨ۱S6FÝŽz´1êþbSRÞÞ‡#¼üòË*áxõÕWåµ×^Sã 4 æ<÷ÜsêM˜3Ò©S'ÉÊÊR“Wÿò—¿È³Ï>+Ÿ~ú©´iÓFµyá…Tû7ÞxC7n¬æ¨¬Y³FÍQ©ZµªjŠy¸$ç”ØçÄâ~¹Ë–-+8ŸI¡q›¹gŸ6áàƒç‰(\öÄy•”`Îcˆ“Jq$‚ÀùÛ† ªÉ­Ž?ÿùÏ*qvHPpã@·Ø!¼òÊ+ò÷¿ÿ]%+øÃTßábRâÿÀºÇmæ^°¤äÈ‘#ê†çKG¨Iúnà»ÁIàîp›¹gOœ/˜è:lØ0ÉÎÎV_âmÛ¶$$€3!x@öìÙ£ŽŒvïÞ](!LhÅ‘ vçÏŸWGHn"Š_n'¹‡ÓÞmŸ^™8_’%Ô$}·%Ñ·Wqn3÷ÅT”E‹ç‰(LJˆ(f8qžˆ¢Á¤„ˆbjÔ¨Q2wî\™7ož:µ‹ ¬¸xèСj=&Îã &Á" ÁäxœÆëG}¤.+œ¢AóRpÿ’]»vÉ AƒÔdUs Å?&%DS¸ç®œÉÌÌ”æÍ›ËºuëÔdb\ÉHP0×ÌÑŽE‹©+õn»í65 W:WòÁSO=¥Ì}kÕª•šôŠD&Ü+ùˆ(>0)!¢˜ãÄy"Š“"""ò&%DDDä LJˆˆˆÈ˜”‘'0)ñÃyàºGDñ„û.ŠwLJˆˆˆÈ˜”‘'0)!"""O`RBDDDžÀ¤„ˆˆˆwîÌœsfæ{ÎwÿÖ„A*‘j†}Ù²ebÆŒ¢~ýúbÝu×uö ¿ýö›øôÓOE»víĦ›nêì͆n ’C6´k`rÒ. {Z1qâD„ ³™ÍlEÞ ½°0tk6³%¿…¡aC»f3[ò[&Ú-º†ýå—_—]v™˜?¾XýõEûöíÅõ×_/6Ûl3爕xá…D«V­ÄÙgO[o½‹Xc !jÔPÿ{¿¯¹æÊýú»ÞW³æÊO6öóyõÕˆaÃFˆµÖRû¸Vüðƒ#G 1`€³# .¸à1bÄç[aPè6Ì‚¡ÔÛX´h‘8ñÄżyóÄ~ûíçìÍšn­IGì²Ë.Î^,[&ÄóÏ QU%Ä AŠFãÀ!‡"ž~úiç[ñaÚ7í'Õ~Ö´Û¸ñDÑ¡Ã.bÎ!n¿Ýùу¯¿âÛo…ØcgG‘ôóôCû̽ †4ö)'íÚl{‘ðÚk¯ÉuÖYGvêÔIZ7JÞ}÷ÝrË-·”ûs΍ªª²¥ > …ÊÊJç¿üðãRvëæ|ɰmäƒB·aÆ ¥ÞF4—ë‹I9dˆ”‡&å‰'J9eŠ”;J¹|¹s@ 8øàƒÿ’iß´Ÿ¢Ð°>÷ÕWÕ¹Ù¦šG‘róÍ¥üðCgGHüý·šþüÓÙფŸ§ÒØ'`îU0¤±O¹h7&}V0ôíÛW4kÖL<òÈ#ºYâ”SN·Þz«øüóÏÅâÅ‹£Jk¯-Äï¿;_ 2â§Ÿ„xôQ!Î;OˆCÍ kÖ< Ä„ Bté"îz¿ý朒ö¿5í›öKX›õç_©ÿ½ø¿ÿâì³…8óL!–/wvæ‰_âä“…¸øb!~þÙÙéƒ4ÞÏ´>cs¯‚¡i´h ûwß}'æÌ™#z÷îíìQ8ꨣlf}»í¶sö~ø¡ó_~À…æ?œ/9¶|Pè6Ì‚¡\Úˆ0æ:ѳ§Ÿ}&D¯^B̘!ĨQÂØ…ø×¿œ-0wÆÉ°D4šiƒaoØPˆ+¯âŒ3„ÈǹöË/…xñE!Žø@ˆwßu¾TcaóÍ7ÅßÿmG¾vëÖMl¸á†bƒ 6°µì?¡‚KeRä¾¶A'¨°mäƒB·aÆ åÒFhÓFˆéÓ…xà!úôbç3Lj¤•aGÀ¸æç‹A5Á§ŸªOvs?°Åt¾Ï>B æü×]'ÄI' qÏ=Bp@öv~üQˆ¯¾r¾Tca_ºt©ýÙ£G±ÞzëÙn1Ç·ôéâð÷KW_}µó_áPm˜1C¹´vÝu¥i=âfØ™câucÇŒçìˆ¸Ú Ó~õn?*† â­·²3Òhĵ•ìœs˜SZól@×pÅB¼ý¶:wë­Õ~ÿlíüúëzbÉgGJÖgœÆ~™>Ń¢1ì8ö®½öÚKŒ3F´mÛVœyæ™bôèÑvdz”h݉3›Óráøãwþ+Ê¡ 3†`(—6ЏöwÜÑù/V¬PÌËUWe÷±õ"®öô_½ÛŠÁƒ…¸è"’Mîv,g7Þ¨²¦ýù§ÚçÅwß Ñ¹³;í$ÄÑG«s`òA6Á€ý[o½£Å#8;R‚´>ã4öËô)aÇýxµé$ˆ .´?ýСCÑ©S§U¶–-[ŠiÓ¦‰?Fk¯Ìf3gδó¢OŸ>bܸqÎ7… ØÇR(ÂÖŒ3tèPç›ÂK´çØw=ŽtŸ|2J\rÉ%Î7…Ö Ï±¤åqcòäÉâÔSOu¾­D×®]íq¸QìqŒeÆ¡QÆÁ¹|oРhÚ´©ý?)#ãB6ºuƒ~MžÜi5†=Êý8p`,÷÷…&‹»ï>U`Ô¸ðBg§…\÷—ö5’xOHYæF±ßwäûÎýO’nõó/ôüsÆgØ¿éí€XíÙ‡A·nÄškvO=ÕÉb®ýiFúÍ7Wö­N!Nñ„ó%E¸æ)_~Yý߯Ÿ”=¤þ70H+¢Ð°>wôhuîé§KÙ¢…”?ü`]7Ü åìÙΤhìÐAÊÏ>svX?^Ê#”rÙ2g‡…Áƒ¥œ3GÊöíÕ÷«®’rÁõ¿=&åí·«c³¥~40(uä¢Ý¢iØ7nl—;F:qãQò½YØÿýíÏ|0¾ë¯/D“&áS,âS_h”Cf ÁP.mÄ‚5ÑŠUV áQR¬†´Ò'úPÈPD† åŒûïG;(DíÚjâ´Ó”ÿ¹h¾µKŒn.Ÿöí«Öd’Âaè!!6ÙÄ9Èvèj«­Ðzæöaç÷½öRÖ ª+ŠÆ°*š¾ôÒKâ¸ã޳òYbäÈ‘¶ ¾sçÎÓmqÝy€ -ÿþ7fh9ÑM b0˜1C¹´,#LLßG•yÁ›a÷sу+V2ì0 7߬˜¿ÿVû2!®öô_½Û \[NIÇJ±b„nÖZ7`°½ ; Ø|£„Øw_•Ö•uÚ|®™pææ†\>ìÿûß2;õ#BDZÖgœÆ~™>Ń¢2ìÇsŒ­Qÿä“O¬  Ò’ć‰^½z‰ûî»Ï9"8ž|RˆŠ !¶ØBˆuÖ òD)0Ê¡ 3†`(—6âÌ:©,â†T^v˜ò±€æFÜ {\V·†4n¬rÈ3–lHÚ bÚ¯ÞíGÅ]w©Bg¸C³uïN¦¥)×Èİ?õ”￯r'Dm5ès¡%¬püïöawƒýãÆõ-ZñòËÎÎ ­Ï8ý2}ŠEeØAÇŽÅ+¯¼b-„¿ÙN ø—Õg¦9"Ò©Ž’ª:šO¡ƒê‹Ôms:iòß|Sˆ;ïT• ItCºD­©Ž›aË AŸjÕr¾8èÓGˆgŸU„LHÚ bÚ¯ÞíG™‘ˆ×kÙRY•¾ù ¹¢_]kÉ5X—û÷‚¸»ÇWL>Üü ÏEÙ†[+ß³iØ;îj›©gžÈ'[S!‘ÖgœÆ~™>Ń¢3ìqàÞ{UZ('ñLb »Af4k&ÄO(s:Â5Œî;(?W,dÐ,&sÜdâfØã²B¸]b4èÿm· qþù™µ‚I[ALûÕ»ý¨€‰ž2EåU'#>ì¦ý¢‹Ôÿn ;õ poiÔHYÑ`ÄI¤1a‚šG÷¹G!Ä;ïdfØ¡±]vQ÷³m[!f϶ÿMi}Æiì—éS<(9†”I€rç0ìa]b¼)‚òE-{Ô6‚ Ðm˜1C¹´öÞ[ˆGQþ°,²­[+m;Â61æ0òß0¿¤‚#5kÚÀ¼óáÅ–[ª9ÈTA5(W ëÖMU*îÒE Ý{ì!DÆJ‹®™n\Z qr·ŸrŠs²4èÇ+„ŸÇ«›aGhÇZ•‰aw›6?vƒb¢äv\aÐÔi,¨a5ìäð ‹š53‰p#JAQè6Ì‚¡\ڈ͛“»Vˆ~ýTõDüV)e¾çžBœ}¶òo§< {Z´gn Q÷LÌ'Ÿ¨lUåˆM7U®-$sÃ5 ûÊ+É[-Ä/¿1b„>¨~'ØÔ Ü„ï¹gõuÒíN³á†ŠÆ(Òä÷±hð?üPýo`PÝPR ;f3`ÐйÅ%æÖ\ÑcY´Ý(mE¡Û0c†ri£ Â!Ál”&'èÍ‹1þíÏ?¯ÔXüñ{êS,+ÄM7)AÄÛߤ­ ¦ýêÝ~\@1“|ØaJA…›Ì·ß*ë´J™;îX=ÎCƒ5ò˜c”Àî†[kHçSïÇÇΘ¡î'Œ}ƒ*UdÒHë3Nc¿LŸâAÉ0ìHè,ä˜Î½¯¤|Ø“j×À ”㎦î²Ë„Xo=!Yš’FZŸqûeúJ‚aÇO”hu|éü¤†= 3a``°²±˜ãƒ¹æ—ôp¸™Ô­«‚SÓ`φáÕ°Aß J:u"ZpæÇS¨T1…¹&]#kn›6Büç?êØlÀ…-»fȱ˜»‹)Á¼£Œós‹au3÷T_…΂Ä”J‚aGŠ'È%SðW†½S§NÎù#h»QÚŠB·aÆ åÒF±c@ð'¨Œ]a±$˜ ³û™g*ŸÙ´‚¾#d\r‰³ÃÀ „A\… a–ñQÇzÓ~ÒIJ°&pü7”›*–°\Ì3Zv*Ÿº5ãîõúÇUŽüí^ 0¸ÝgÀ^{ ñÚk΃j‚’`ØñiÝfç‹`œÃºÄœMšŠʰGi#( ݆C0”Kņ^¼ù$¨f­Üÿ«²B°h“Ε´I¸¿ÚFÜÈ1o`PÊ †d¿ý”ð sLþu]€ ñ3”Öû¹ç„èÚUiÏsÚ…¹÷×bÇ’î…WÃÒâÇn`PL”ÞK¡%­ã¡P~HeØ£´…nÃŒ!Ê¥¤Á}é¥B¼÷ž L}÷]å#OñögCVˆ0•Œ¯»N17íÛ'kIÚ cÚO¶ý¨ #™_ð+æÆ£6ÜÓ(¤„; ÙbÎ=WU+Ƙô¦Ùj)@¿¸³øÑ.ôŽ–~ã…XºÔÙéa½gÏUï'ÁéQ‚Òã@ZŸqûeúJ‚aÏä £Å%& ’j×À ºWÜbÈ ƒIž Œä†&%ä˜1ÎA>ˆÃ ágŠÏ´øùþöÛÙ¡þ¸´Æ´_ÚV0âJއ Qt s­OŸ®¶©SU†$j,p¨}û2nÅÔ³Qù”jÀ0óhä‰Eãw2½yÃN;d¡yê)g§4ì={®z?9E]’1#i}Æiì—éS<( †=’bœYÌ Ãn`Px Uÿüs˜†&åÚlr·ûålà AUeíp!8âˆC3šÿ‹¤­0¦ýÒ¶‚7‚ö¿ò–-U ‰[ÅêµÛnJËþÑGª !ëá-·¬dê© OD÷>PÇçñÐCBTU©Ø4\j(˜Ä¹0ìíÛ¯îRÆþvíV¿Ÿ¸ q~RHë3Nc¿LŸâAY0ìQÒ:N£ÆrH¢´…nÃŒ!Ê¥43<¦z²R íÃÄÎ>J¥ûù¾F‚@† Y$ÀŽÀ<ƒRaš5bèP•¹ M:þìn@{§ž*Ä;(«ï<É!4Ђ“®&Æß`ä©WÃß´©ª¿pÖYªzù#(ÍýgŸ­š}ÍχÀoÍœé|10¨¨ööÉÞly h»QÚŠB·aÆ åÒFšA¶ a˜Ò=¢iCãNP[œn(0ì™*8æÂÖÌzûíª¨ÒòåÎNƒi”¡5„chë‡TÝ7`ì?ýTˆ… …ØuW!æÎâ×_3w6®Õºµr£a:?^µE1&|â÷ß_ˆãWÌ=)&ý\ÓÐÜTT{†} µ–C"h»QÚŠB·aÆ åÒFÚ/;Ì…\-RZö^Pæw¾Ça…ëh惌¤¾+6’¶Â˜öKÛ ¦_á6âšk” SÏ;ï¨ß‚)•&½új¥-GPÍÎÙrKå2£ ¿w4ñá¸×PLöš5›f»Ó è¾ÛFf™%KÔ÷b#­Ï8ý2}Šeð›J§¥|5ä”IÇÌN.2lh箸b²­©‹‚(.1Ú BUÆÍ7WZÄb"i+Œi?Ùö£曵 Íöž{*?s´àädÇ·Ý7BúG˜g4áø¾4êWâŒ6îmšÞµ; =YëÔ¢Kå:³ãŽ“í€T„t\a¨€Œvÿ“Jï˜ÖgœÆ~™>Ń¢2ìÿ³¸êYbô–ˆíÞ6@ŒŽ€š5“©zfvƒø€†M/Úù`ÛmU˜c´¸ÊüðÃÛïvñbç ˆâã¶‚ÀüCžà¼b!i+Œi?Ùö£‚ÂHh»ÉÂMâ£þüóªXÅÁpõrK®_ƒ+¿ö»îr~ÈÖlR3ê Q7íÃüã^C ˜b¿’2¿uÜjøÿÎ;U¶¨$ÜÎÒúŒÓØ/Ó§xPT†ý¿þõ×_–”|Ÿxùå—ÿÙž‹ê çJýXÀ°»ƒc Âmv.Í\&GuÆAƒT:nøÉ²Èc¢ãÛEÃîÌÉèÑÊØÌ¥ÜLÈ„6\츱Œ«h ™t«_~éla»í”f¦-;á¹ÞuQq{0ìîãѬ»]fÜ`­ÇßFÿz¬ëÐ?«劢2ì .´¯š¢sçÎbï½÷þgkF8zD„YÁ©¨B"¨†=JAQè6Ì‚¡\ÚHQv ´êhÛÑŒ£ÁÃEßWLçß|ãQ|ؽ€¡!5ÚIƒ´ã¥—”/9šu 'ÁÀã¶B(Œ6Á¢ì#è[ƒBgÉœCÀèĉÎmâöB̉׺֢…/¿œ{]‡>iëâ‹•¿=LûÉ'¯êgo`P.(:þË.»Øn1iA”\œAöbäû,tf ÁP.m$8v@@*š»ÓOW.2hÛß|SiÛ~Ø9(âÒ°k}´*útÓM΃”—8¾âèÓȃ¾Å*kÑî» qÎ9*« €ÖŽã4öËô)a—•¾õÖ[â£>²ùHñÔSO‰+®¸ÂŽÔíСƒý{D<=LЩA|ˆ“a×V|mñ»=é$U%Í!Y,¨Ò˜«¨Q—˜LV´ÿ¸ ¢Ø“FÒVÓ~²íÇV­Ô{ #/;…“`Ú©nŠàK 'E•æÌY©É&~¤gOõ?¿‘YÆËˆ£IGxÖÀÅæÖ[/.P1˜ Wë~„ê­ºãŽ* ;ýF“ïÖâGEZŸqûeúŠªaŸ>}ºdÚËÃ[Y³Á…^(F-æÍ›'f̘áU:0 »A|ˆ“a÷Z!Úµ#ï®ò›ÅÏ&‚\Ïhá2 ûô%,ÃžÍ ‚Gà½÷ªì1ï¿ïìŒI[aLûɶ(N´÷Þ*¨÷b0~aÖq‰¡*yØÏ;o¥û Å” di¯5 ¦Ù] :|å•ÕÝgnaÚñ‹Ïu?±d Rå?®ÜÑp£¸SHë3Nc¿LŸâAÑöõµnÝÚöawí:x'Ó à˜N:­²µlÙrµÄ÷3gδó¢OŸ>bÑ2.,X°À>ö1"Ô\0`€5 Y³ K–,±}÷Ýw= ÷Ý7JÌž½jÙŠ+ìcB4øK‚Ÿ ¦k×®‰cÔ¨QÖDœ}ú³ã@ˆ[†mÔ…8Çá~&…ß9¶ÆÁ¹|oРhÚ´©ýÿITùq'Ãî|l ¤Ã¼¿óÎ*”L˜åÝ/4èKX—˜\ “íÝw«B3h, Ò„‡R‚,Œ:Ì5 /ïìå— Ñ£‡bÚQXáƒæ¬.¸ÁÎ!(?tdR/ºk"À°»ÃØ`ÌѲ»X5p‹ùâ çKPë—rÁû¾Ðg²×`5`šÃ‚f`PRE—_~)ÇŒ#-&ÅÙ£À~‹™—wÝu—³g%ªªªÐ}ÙŸ¹PYéü“'*Þhá›o¤ìÑÃù’QÚŠB·aÆ ¥ÞF>4— úk¯]Wîºk¥lÓ¦Òî3[‹-äÔ©S#f̘aÿfMò‘Gœz÷î-ÇŽë|SàÚ»téRgBÿþýå!Cœo ‹/¶]´h‘³GaäÈ‘ò¢‹.–“'K¹ÛnRnµ•”l°\î¼s¥|þù¹ÎQR^z©”ÆM’Ý»wwö¬D—.]2ŽÃ‹lã˜;w©l×NÊ_UûóÇÅ_ì|SX¾|¹sÝ•ã“&vQŸ‡‡B¾ãèÙ³§ý›ÞZ·n-ëÔ©š†9‡s7Ø ®Üb‹JyðÁ•²n]uí½÷n!›4™*›6•ò曥lÔHʧžš!÷Ø£R,eçÎR¾õ–ºN¯^½-Ú+÷ÛOÊ뮓֘VÞãwÞY*O;M¸Çƒ‘›o.å×_«}ú¿óÎ"¹é¦Rþõ—ÚŸí_~ù\yÏ=ÎN ÙîqÿþSåJ빨}æ_ 3…4ÒnÑvnŒùW\áìQ1b„¬Y³¦üàƒœ=+A§ƒN<‡îü“'x(añãRvëæ|É‚(mE¡Û0c†Ro#šË}yóªä“OJyá…R¶o/å)§H9aÂÊEÙ ~»ÿ~çKDx'ÙL€Q>÷\i3 l;í$å¬Yê·sΑòãÕÿù"hû`ölÅìüïÎŽOû…€i?¹ö£Ð°û\xšC‘²ysçG L=mÛJ‹I—6ã>p ”ÿ-å 'H9}º:þ?Ô± HÙª•”7Þ(塇ªãÀçŸKyÖYê78¶Oç‹ ;ì åèѹïçO?Iyä‘Η`ý†ï4h¥@’~Ç2!ý2} †\´[4—˜zõêÙ¦û믿^\{íµâ™gžýúõçœsŽØžÐîˆxZ+‚Í;¨{”6‚¢Ðm˜1C¹´pqÁgS9a¸¢@£xûPfœœÉÏ>»’†ât‰F2èXo=eÖ'Ar_}Eö!:vT1Âú°màÃK›YºÔÙù´_˜ö“m?* SÜÆ¦OWï$®0ø˜3õ°ºøüsåJF&‚F¡s\cÈÌ(¤Ä5&OV5žxBí§@’Û‡]cã…øþûÕã:<8÷ý$Àœ59( á"G6™-·â˜cò§½´>ã4öËô)5è”Óþýû‹ &ˆÃ?Ü®x:hÐ qã7:G„‡7k1@›¦r¡A0Ã?R.ñ‰%2Y #G9qç”ï#x{q?‰™óÌ:L;þ­¦‘ÅßÚ,á5‘oû„ò Ðà³GÑ—|Û¦ýdÛŠ /âí·Lp)¡gÐ(ñ¹d_ÁWLK0ä„áðþΚ¥2Æ,X ®CÎvü×Y›©?@°·×‡Ý‰÷q¾8Àw¾yóûÅ'Ÿ8;²€¹äÁ/€ÿüi§©ph/ŸÌMi}Æiì—éS<(*þ–Åá’Ê‘ »ß~ûÍ’¤ß_-¸.,’ÈØB KÌ…Au´Ó´© N#Wº%ËF£Œö4l0Ï_íœ'ÂZ!*+ó±ÿþBüô“¯¿®,0Ô0A•aÚßcÅüÀ,EMš•´Æ´ŸlûQAÕRp²¿ðÎ#h_{­bj)f„²Š<ëüF 'xr2ÊÀàC׬ÇÂDó>“©‰ÔLv@V²¹ <˜}˜êjÙíç–1²ÒxSIæEšˆÑGwȼi}Æiì—éS<(*Ã^HÀ°ë ù .!Ê¡ 3†`(—6Š ´väH§ÀyÒVÂ0Œn5TT$Ã'ùNA€iž¤Käq†±ÀTNF ò§“›zРÂb08S§*¦Á/7µA1€–ü²ËŒ —6q²Ç …faÄ)|ÄúKö´Õh×aÎÑ–ƒóÏWº.ÆñÙŠ“&-;Â4HÛ¸Ë}ø¡sP¾sg²u9;ò.5¸÷Ъ¥eœAÚP6 ;„FÃŽo} ýçBÔ6‚ Ðm˜1C¹´‘Ü>ìø•¢ÕÃô³@ázx40¶a5ð¹]ã&ÃÎÿhÛûô¢eK¥‰£haìãv‹ã>à6„p¸s•w70ˆÐ´GÚSÞ\ÃHŠÏ7 hƶNÅ´“’×,c¶üþÙgB<óŒb毸B¹–‘Uvôèì ;)aþÑÚðëc¹F-;…›ÈÉÍæ Ü|в3ÿœ|r8% A¡PVö0 ;¯…F9´aÆ åÒFÈt À©œ…Í3Ì•Ñ|¸Š ÅZȱŽ6E>.+n*Ï?¯>Ñü¡uÇÏ-#}E Ip58ž~z%sµ}ÆŒ–>Â×ÎI[aLûɶXº(F½E ¥q'ß:®kl¼ço½%DýúB\½½z)ÚÃ……÷+ë1¨rã>CÝ„Q‚K³×a4òhعŸ ¸ºèªª™@Uèÿù°`<'ž¨„ò_~qvzÖgœÆ~™>Ńjϰ¤™v/`fwÚI•§ø üÈ‘B4l¨´ßd|xüñzâÌ3…¸í6!^x!ó¢:Ȇ…À9‚eahЮãk‹Ö!-$Áyüþë¯õbÑΑu¦…l:d‘ùïr i+Œi¿´­`0»Äsð¾óÃãjÂûŽ&}ýõS‹6š8Ü©ôŽ`ÉûŠ+ûÈð‚  £}ÇŠÑÇ=†ãr¹œ @w¸£éûTË~ÐAB,^,Ä8;B·´üŒ‹ƒi}Æiì—éS<¨AnGçÿÔê—Íš5UUU¢¢¢ÂÙë¤ú#ŽÖqÎŽ"Aså€|h.ô5;¬Jl»m…½p»7½àóéÞÐα³HG³içÈbÁ†6¦ÁÆž,²zÛv[e ÷¶aÐþq-´ýh×5`Fp€±AøÀ´Ž–Žsh' h›yŽ1Õ‚kx…†Ýçî²K…õÆœ`RQh÷Su„a\O [tJQš!ÌâÖ²ß~BÌ™#Ä?*¡Æs‰OpO8ÁiØ‚½½úªÊNCªG总 }jÞ\}Ϙu|úÌ]¤, †æ ‰\´[í5ìÞ²ð…@9´aÆ åÒF`‡±daf±?ø`•a³ÍsKžóW^Q¾èø½¢Á†A@³ÇÆÎ'¦i¬—#FŠK¹¨°/_î4ä´ð0‡®mÎ#•$YXN?]ˆm¶QÚêáÕæšãØð›ÇÍ=9¦qÁ?—L˜õçÍSn*œ­3R …$p³=çžrŠbBð}Ç'æàÙ0ÚÆ¢€e í_‰¼ %,^Ð|Aœ¸± ƒ> ÞmRYcýáwÞI4Ѥ[Âûsc`Œ¦ü‹/Ô:mñ%¶p-dS’1†iŸth–>ä @Ś9 á„>0g$»|RJaIrƪOn ®*æ ¿²±ù ÈéQÛ‚B·aÆ ¥ÞF>4— a¯AµÁ#Žp¾8 :" ©ºøÌ3ªê°aRž¾”Ç+eÇŽj£bá5×H9y²”óç¯,õŸhëûï¥ü樂9SUr¼öZ)Ï;OUr¤š²Þh“ÒæµkK¹å–R^}µ”=$åœ9R¾óŽ”?ü°²²#`lT~¼è")›4‘²n])·ÛNUfœ4IÊ_~q ®ýüóª2$Õ%©Öøî»ÎÕQhØï\÷tÃ{7ožªvÚ¬™”/½$åw*š€F»t‘òöÛ¥|ýuõŽï¶›”TkoÓFÃ; n³”{í%åÖ[«ßÎRmÒ¶A!‹vËÆ%†häqFó•–X"s_¦ .1QÛ‚B·aÆ ¥ÞFsºF”k¡'/˜ÁdC㦷—_~WÔ¬¹³¨][å{Çu…m“Mœ“ [_hó×_•Û ¨hýÑ®£M¤/ï½÷®uÌÎÎÑÊå^4“hýx|ÕáÏf=RÛ·w«­TéôÚ¶U.¹€†­?¦ÆNùúõßG±³ÝnÀ ´3e.Bun? ýés/¾¸JœsN…ýžúÑZk\Ex×)v†ÛʤIÊBÅ;H%ÃYÉò‚6ì0¼ãXÚx¯±Daƒ–ð•'p›÷w9maà ëØI'½k½Ë;Ûî0\ ®‹› ™›¨g}²×p=ÚˆƆ%±þøc²ïX&$ýîûÁô)rÑnÙ0ìcÇ*S;&»b" ƒa`VDYì5Ü×hÒ¤ÂöåÆ}…ÿ bón,ª¸ÉàöB˜P|cuá2Eè ÷7ýÉBMj9r§“G™cA'‹0µó‡cA`™eÈuÞºµ°lüÙõ9nÐ../<âìðýÆL» ¾ë0î¸Åôú裬ÏGÿããXΩâ" óLÃÀÐ/~Çmß_„ úI– |ƒñ¥õë·fÞ{õê$öØãQÛõ†û‚ÐÂãÜuWÕŽŸÏ~œÐ÷?)Tçö£Ð°>wĈ*ñÖ[¶[L3B%‚¦Áݸ¿w¦ý曕¿9k0ï4 5Œ4Œ:ñÐÇÀ´ó~ÃxãcNÁ%²Í@#·ß®ÎŸ>]Ñs´ýë¯,!áQ›>˜xq“ƒF ;®Ë52¹¿wkh⬳œ!añy¶ P³f'1cFúÿ¤ß}?˜>C.Ú-†€p²*Ö3·'¿Å3_°ØjæEoÞïî ûïÆÄÇD¥?ÙhÃÍ ±ú¯Ç“€VĽqo ro00K0lL¬0,¥‹(‹½†¾ÆþûWYï‡ :Õï ~±l¼O0©lüÏÆ»ƒO,>缃,Ê|òŽò{ßshƒßZs˜ÀŒöÛoKĶÛÖ³q >ÙÐpÃ` ' ÿtÞ]x˜ m¸àšøÎãÏ1,Òh×`6`¼a$è =6úJ¡³u×]b½ž½ ÚòŽƒÿ5 êkhhztÓ¥ûöq¸gh$ñõ…ñ¡ÿX×Zk‰Øe—z6Åý'µ·¯¡è“¦{ž ZN´ÿÐ2wãúŒ!ÃÒ” Õ¹ý(4ì=—w´M•Δ÷!ÚþШk@Ä¢Àl#Œ’Çœl0°(Ôˆë@ëĹø½C“d—á=EH}â !vÛ͹ ¾“]æçŸ—Xk=[@`HätÇ—z@°¾ï>%Ô×Á:䎥 4@)q%añöÛBœyæk¬õ2¶—’~÷ý`ú ¹h·lvÌÁL,²š1ÕLªÞÜû˜ˆ¼ÿóé·éÅÕý¿þÄ4†ùšóÙǦd>õ¨]>Ý‹®ûX€5óâfdrmn­£ÞÜÌ6‹:ŸzgñÕÌ›Пš±poŒEkIõÆ cƒ¦…O6î =˜#˜ŽÈcMÐ]¾ ¿Aqe±×ˆr à8”¼Ç¼—h?ýtåSÀ<@ ˜TÞeäÐÂÌóîòžÂ˜o´‘¢öÁ¸ÂX`EeXT_Ąϵø 7kÈvºGæ#˜ß h­8¦IM—Ð î5hÃùD¡ïôA„ë0·1§@_ZàfŒšn ÒÞ)դ؈B~碣ï)šv·b±ô ¢Ö*7x‡qQ%k ÷€ãxŸ¡“ñã•p‰€È{L0ÏÐ=Ú|Ör¨kÅ‚5tyñÅŠI†É'XœT‹¬õ¢hîèôε8k’{Õ ²Ü „#@xàêchÚ äªOêY”rÑnI0ì­[W‰ÚµUçé­—Ù‡ôS‰Ä3ʦFͨê}îó•W†Š6m.ýgŸþÝoÓŒ°›!FbÇì‡&J3Ënæ™6‡*.%eFQè6ò½>Ì…6íãkˆvï“OÔ$ÍdŸ.é¿ÜnÚÆ¥ÞF”Å^#Ê5âbØÝ@D«öÎ;+5可ÀDࢃà‰P ­¢ýgñ…aç¼½öR¦{´ŠX”4`¢çÎbþ|!.Tßq5±†mo©0øÛ2_a²gYq`vØ`6˜»hÆMŒ¿{C3¡…l÷渽Ÿ0öМ޴ð͸Ý‚ÎõwæTîÌ'û8cè·{åÐó2ýZ0w÷ǯú÷µÜÐ×Í„l¿i¸ÉÔN&ä{¼†; a±…þüÎ%; ï¯ûýG“Ž–›ù–ÌKnÍ8@È$»Ê 7(Áá˜8¬á¼GT-&£ B(Œ?Y¢`¸¡A<¸°˜q*kp.±N«Š{ Ê!|驺Š+ýâ½EÀ&Ë õøäx蔵ú'+Â:ëm’‘‚u zÌõ~‘!‡1"ÄpMƒ(ÈE»e£a‡PIõ† ; 0@ 8Ðù–?fAZg2Ê„¨mA¡Ûˆëú¼mh8ðù%…4&|‘æÏ Nÿ²¡ÔÛˆ²ØkD¹FX†÷ŠTrš1gûì3Ť²è"<ÃT£ýƒA`qeáG¸f1ßw_eRG«ýÒKªj#ï)Œ:×F«ÇñhÈaäîñGð„€±öM9¥Ùan¸&  3.dj¿X¨ÎíG¡?¿s{ö”ò«¯œ/n½UÊ'Ÿt¾8€žÆŽU4ׯŸ”Ÿ~êüàÂo@RÖª%娴¨k¯-åškªÏ7^™*•Ôú÷5ÖbmˆÎiÚ†øìKÖÆ~•^Ÿ:ur^Ú""í&¬ß‰Hô˜àŠ 4thÞ ÂÍš<ÌŸQN~Ì!;L‰AÛbP½Àt‰f ­/æsüDÑÚ¡}#}Ú>,4hèÐs,5¬l”E'üÃWˆª*eNGK‚n´ìøÅRö\Wn$³fÿ¾}•ï-q)´o*{,hø§£u'¥gæêÈ8At²^ËÂ÷fÍèï 1eŠú®‚@…À(‚ÖŸ¬\ŸëàJ€ëIÜXÁ@@C¸pÿtf MoìGëO%KÜâ‚»ý$PÝÛX£ 7x§¼. ¸ ¢y'xœJ¦h¼5p;ÖРC§häÑšC¬£Älð~â.FÊTþgÿ߯°µí¹€Kk2oÞqÚv9wu–,ÚÖ¿ÿŠU¾S$Žô”î}IlÞ~¥a+Å>eË–ÊÆ%†”mTLÄ®˜`dÑÝi'g‡A,`½ƒqÂ7 $\f (æt ×àùbwo˜ÔÉ>Ëï)¦p\F8¦› ³9 8n¨ÈÉ1¸Ã`Ç=…Œ/º¹MøÙÀb£óJÎg„®û L53$s±é &afž SÀ±ô…ô‹œd×ÀôŸ Œ‡¬3gªëáz@f âaâ Â/‚™4Òsû!”'¢Ð°ß¹øš“JÁSoh-xÇ©ŒàÛ³§ PA£ÐªþæŸâ†@¼.m¸hAc~.-¸Ò ìNIu “Î>ª¯"˜«/:‚Cй ˜'P8µk§2ãä‹\´›(Ã~ôÑG[ŒöëâTe>ÈgâÀ)Ä0t¨³# –-[&6Å93$˜ È3‹æ ¢¶…n#©1àS‹†?1Ï– =,Êá9€B¶e±×Ð×9²JÔª¥r9£1cÓš:´q,¦¤\„9gÁ& _W˜c˜ti4fh~é ߉UAÛ ƒNL)ÚÒôÇÁÐÃ< ÍæÚ:Ø’6É[Î5I]ÇuðÍå;}‚ÑE[‡M> Ú|´†\ÿw´þÖpm°_kõ`48¾wè |ÞýŽCP Žy æfŸ h¾óõ‡AGÓƒE€ûc|Ϋ¢Ð°ß¹(¥Ðœ»kÌ\wÊ®B ‡¼ËÖôd¿ÿ|¢!gƒîЄ~ kh9@¿—hëñ…G çx¯6Ÿu¬l0âlÌ(ÊôiÁ—`Q/°¦ ¤ÇƒŠ.˜ßà>Päƒ\´›Ã>qâDqòÉ'[DV_|Ltˆò™xÐÎ!É“â)DMž3‰6 )?Š‘ ¿Ðm$=™~ýCÅ3’/Êá9€B¶e±×Ð׸ôÒ*kA¯°µàŠ¡mFkmýl3•0Ê,ä˜×ÑL³(³Ð£enÕJ gÈòGF ˜_X‚6µVMƒYŒ´,úlÌ,ü0\[ç(§0 üF† ˜ ´}0,ü0él0ÝhÚ)8D)B}åx„ ú‚ÜDÛŒK $¸çÁ¸‰À ƒOß#ÚtÆÀ¹¾W£Î»NRèÁÀÐwóÈWÍ\“Éu…ûHÖ*ú“Â}7¨~ˆBÃ~ç ãºÃÀ$#ò^ÂXóÞk›yš€>x¯¡ h€cšµûtóÌïœ íi°Ÿ}\ :B»Ï|Á”SŽðˆ«é¡‰l@`'0‡k®É¾VÇæ„xø‘”Ò4H9rÑn" û—Õï¶Ûnbýõ×·ˆ²f, ;)Y¤Xèòm„eLZ_$ißLˆÚFº4Œ7+ e±ño÷ËÌ‘ åð@!ÛàÚa{ }Ù³«,Z¯°>Ù§_jY{´shÈÑR“òi€,OhÏXôÐl# ‘Á –ÖŽñ Ç]3çìÃES{:ËDÆ›Ú »ÇÀü¥˜vRÅѾÈ;Í10óAßs }úó‚P¡ó¼Ã”À|üøã2‹qßÔnF¾£E„ÙÆ¥‡ã`døAÍ;Y0p·9g¡G`¡=´„ø›“ƒ6¸>)ç8–Tz<&¾3ÿá·‹9¾–žl0í'×~Öçž~•%èVØë*´ ½B¸}aÓnV¼§Ð"®l¤1…¡ç}× 8Â2ï74Ï;މ« 7ôË; ˜Ëy×–ùŸ4âd–A ·ÃË,úÙÔHh±d±?[v6/ aÜ+±Äa!Èwýð"Û3F@ÁWËÂK1‘ô»ïÓ§`ÈE»‰0ì,j­m‰ßk¯½¶xî¹çbq‰±î½­y¥0C1¦*ž0€Lä${2,wDYì5ô56Ý´Jì´S…ÍPâ3–ÍŒ'n-lø·²Xøc2'øÓ-óZ9Wn´Î0·c5ã[Ëm…`†#@Z…™G(€ñÈ4rhÂÑjã¦à CŒV=*+;Y×xÔv›Ñ>ú$#Ú-Æ  ceŸô&= ï:}â2^˜„î ÌǰËÃO?uÍ›?j3ZšÉ"E#LLK!ÝdŠaiʆêÜ~ÖçÞqG•hӦ¶ŒA7Ð.ï'iJIŠ•‰÷“wˆ÷ ¾Ç?#ïÇcÙº-p.çñŽSyôT0å7‹5°ƒW¡ó… ;‰7ß|Ô¶ŠÁ¬#t‡} ŠEц/=óRXäzÆzÂ5æ?ÿQ±ô»ïÓ§`ÈE»EgØÇŽ+®ºê*ëe~[\xá…–d>'†ó5*”`1Dc`P<À¤0¹ÃXÁ¼ă(‹½†û»îZa/îέE‘Ád£IÖÚdk€S‚#YXñ{…ÁE(ÖÌ@ Lú°çžö5ÐÄa'x.¨FnÄ¥E§8 >©³y…‚l ý\÷¦«ƒv@é€ö‘}0á¸h{´ñ*c†b𙹹—0.z|J¹ÀúoÕö3ÍôîóØ'V6žþ_[ ا÷ëO½ŸÿW¬X 6Þ¸b•ßÝÿë68‡OÚå7 ÛæSw÷Ýý¿>FYýÏýY¶l%àTØûÜ¿}Ž÷šz¿ì§/~ ¿sÀ‘G.-[†£Ÿ¨ˆBÃúÜ“O®²Þà ›‘æ=äò¬ KkÞCdX²?`ÔQ²@O™¸°~r­aÃh[ÍhÁyÿaª¡[âLn¼qøá‡ [IÖé™Ö-hÿiWµ|„Æ™¿X£àK¢ö9(‚ô«Ø0} M©`Ø/^,öØcq÷Ýw‹£Ž:JtïÞ=6†韅i¶˜ P s4æAƒâs-Œ. Þà'ƒpȇæ2A_£U«*‹é­°rn6²)ù-ð˜Â1«£ÅfFB[3€å*ßtƒœF-.5¸¾ä“y…ó pãý"KyÚ€[A©˜öÉÞCÒëo¸Ÿ::ˆÁ&…}¤¤dÃçf‰O6˜ýó)‚Ööë•Âý¿?xîâAÅDÖ箿~•-ðp:‚–&bK4ÓIuQŠ-Ãxgï 4„ÖëÖ¬K¼³Ð;în0µ0θ9rÏHÍ:}ºJèÀ>˜zææyR­ºcW¢=}Êà­Ôp¯#‹JƒlÈE»ôñ¹ G¢cÇŽ6³®QÑ=0©°àä‹qãÆ9ÿ…“‹^6Dm# ÝFÇ€©À_|™s¡ž(FqÍ6Ϧ’ 5D7³Ž›yÏbÙ3 »ATa¿ÕZ™ß²(„õÖþiqÖl0ñlýõ—ý™ ø¼ãoäÞZ¶l)¦M›æ¡Lvß~;ÓþÍ‹>}ú¬Æä Épì Ì>.Pö}(62–X+Ǿ‹mß…QÖŠ>eÊ%¶vJƒ‚;™ÈmM¶f SO=ÕÙ³]»v]e`¦Åu{—`ßtÁ;Ú…Ç5×\c‚¸‘k˜hÑ`\x!&×ìãÐc…ÇŒ3ìc󇹞G\ãà\¾7hÐ@4mÚÔþÿ¸³m-¯)&o´çhÌðÉfÁ¤«hÂaÑðæ ^SUüÜadÉ ‘¯f^ÒáZ׬™bnÓ ˜ oŽwn2að:àJÀ½åÜHïˆï1>É0óç¿ñ†rÅaç‹BŒq"[”œÇ]††l0ðˆBPÀ5‚6¸ÏÚÅ <@æ„ÝûîS®‡Ð,SÏÍ8tÆ»@P6V1,Z¼G€¥œ÷ ŸwŠx@è›@R,6X¼ßÉÔ  =bÑ|PåT'xÞýB€8Þu„ =a‰ŠÐÓu•çd 9²²²Òþüx)zÈþWöîÝ[Ž¥Ö¹ \›c—.]j×Ï}Ÿ}úË+¯\Yžó/^l»hÑ"g¯ÂÈ‘#åÅ_ì|SïLÿþËí>>ùä\{_¯^R.Y"å¤I“d÷îÝí}ntéÒEN:Õù¦à‡»ßAơѿÿÕÊÚëq¼ñÆ"{Ž{å)ÿþ›òï#å¾û^,[µR¥Ü­Û-›4Y.4¨”G}©umçÂŽÃ|ÆÁ¾LãÈõ<ÀòåËícçÎUÏC#è8ègãÈö<²C_?ê8@¶qôìÙÓþMo­[·–uêÔ MÜ£iW_³iÓJ¹×^•²E‹ÿô­[7)úIÊG™a½•rÔ(iGʃ–²^=ÞÇÞrãÇÊÆÕ±§&åškVÉÚµ+å!‡,µß_ îñUW ±Þ[)+*¸wR^}µºÇ‡²Hž~º´øƒ±6rÈHyÎ9ñ¾+@ßãyó¤<ð@i=[µ?Û»2bÄgB®wåÿþOZt)åœ9…yçãhÒ¤‰óm%ŠñÎkøƒ¶‹=å‡û:…|™Æ†v‹Æ°¿÷Þ{v'ôöšµÒÒÉ­¶ÚÊþþå—_:G®ûó™x’`Ø­çaOVÉcÜ8ˆÔùb ùÒœô5Z·®’;KyçR~ñ…ócÜ¿”&8_²à¿ÿ•ò¸ã¤<ë,)?ûÌÙébüò‹”]»J9z´b‚5˜—-s¾„@Ðöƒ¡âøã¥6LÊ#TÌyýúJXá½÷¬U±·Ÿ/Lûɵ…†ýÎ…¡K7Ž=VÊ+œ/æÏ—²m[) 6ó½ÙfRî°ƒ´w˜uõÛÿþ‡0çœàº;ì0)wÜQÊ뮓ò ƒ¤ÍÜþþ»´„h)ß|såý|òIÅP£$ûóO{Wì€iß^ÊÿüÇÙ‘až1óÍ¡‡JùöÛÎŽ éwߦOÁ‹v‹Æ°ûá”SN±kÕÉ€\÷Â;Ï='åðá΃Ä7}ºóÅ oäKs~Ð×xá…ü¯ñÈ#Ù-V~ȼ¡jþ‚?VÌÁóÏ;;\€‰_¾Üù’ `ÔgÍR ÐFIÙ¨‘”}û*¦ÂÀÀQhØï\?!¡¦ZƒßÿýoŘo¿=Zr)wÝUÊM6Qšs”:)aóúë¥|ë-ŬOœ(å{HyûíX⥜=[]sèP¥±÷ ä´{Ûmê7}lÜ@X8ûl)¯º*~«í×_«{„ÏÀÀ\´[4v?Ô¨Q#¶ SÅ ¾`tjP<G° éÈ ’E˜À;‚ñÅö‚àF|ËñM'>®dš |´ñë&¼Ð^$™åÄI>ýd¿¢ˆ©Ly¯ …0UL Š‚ByÝ …Œ1|nC<ñ¼Ÿ˜æ•‹b‘T& #é ¡Sh´Ž0뙊Í«R»Â´"„Cçd…¡B(YŸ,–Ãþ=4ÍPX Æúž{T&š¸€på–5+W\Øc•=†ñ+½AddØ $&MšdW&ýÚ-¥”¶û Œ;i/GœM¸ÄJEˆ°Gm# ÝF©­ éÃ4Êá9€b´‘0‰cæ&… ® hÁI!˜/¼VÞ ÒÕ1ušÎÇ ³±ë®*5Œúk¯©|ê_,ÄàÁ™5ŒÙ´Æ´ŸlûqÂ˰?ö˜bªI݈5†-7)vˆq‹áFÈö¦Õ€¡ïß_Y”Ð?9›õ”"_¸Îpmþ‡‘oذ“]5È©N!$h:'Mk\ …éý÷«º¤µqï¸Ô`i‚áGK« 5(†Ö·ïÙ¶L9¹Ú3¹¾ \à>Gþxê;ÀÇå €/>ùÚ'þóq=cê œ ¯aŠ?z‘ÆwÏô)ddØqÙ3ƒ zk‹’~p«.S„0Zö(0 {zÁ"€ßáûï;; RLæ`aá×A q,ÒVª&ÂàF°[±Ë ‚Oú^{©b10ê˜ò5`äq@kI[aLûɶ'`‚±|¡é¦H´J©}˜wÞ[b+` Ò$&„ P´ã™S ÓÛÚy´ë0ý¯ä©ÁzŽ5쬳µ…Z,n믯â:(ÄD¡/? ìREaÁaú¨ÀŽÂlè+-ŠïS°ÊÎ=‹Ê´§ñÝ3}ŠöF‰ÇÜù¶*æÌ™#¶ß~{ç[zÀÄ’ïËî­™/‚0ìQÛ‚B·Qªc¸öZ¥iåð@1Ú($ð/Åí…ʤT©Å B0)úLYbÂW´bõê9;.²±0# À¸{ÝpÙ!N­Z΃/:ôI–” T+…1G3ŒœßúõSï3ÿk—‘LÀšFuQüßa¸7ÞXi¯ FE¹ãš ²âKk‚FúæøgžñWÖá'Ît‰°ŽóMTÿvâ£(fz\JB¬møð÷衲ïx‘‘a'ÐtäÈ‘vùõY³fÙûÞ·¨iøðá¶;ûÓ†0ÚnʳGmúEлµ (t¥:¢ñÙx…Ëá9€b´Q áœM×;ï¨Å­fo8vP4ÔaÂѤC¿hµqYÓŒ6¾æ°·Ý¦Ü`x¯³s¯X¡2ÊÀìâgŽ{ɹçªß  Ò•¢x 2Ë`‘×!w™X]i¡ÀÍ ŸxÚ%­kpÍAƒ„Øl3!z÷ŽÁÆ5¦Ceu4–{ƒÕ Ò±ûãºë®“ë®»®¬Q£Æ?ÛÚk¯-¯¢š@+‰¼SñVü+4(ªpÄ΃Tâ§ŸT‘ w¡äKs~Ð×xì1u… ©*§ªÞ{¯*J’ R‰Rí?Tñ¬“NšºJåÒ|µ›·Dõ«¯ªb2}úí7g§TޤŠã?:;"ÀÛ~±aÚO®ý(4¬Ï=úè*»èÑgHùÐCê½lÕJÊPëì:ëPæ]¢Yóæª W.Üx£ªÐ{ÇR~ÿýªÕÉùÿ„œ/4¹ŸT½ùfÕ×»îRsh—*ôÇ­â¨îE£¨BL׸ðøãªÈcÊI¿û~0} †\´›QÃ.»ì2ñÕW_‰'žxBL˜0Á’ž§‹/¿üÒNí˜F$áONpc±ýæ òÙ Ž=Vic Š\‘Ð@Ûƒ†‹,(h޲e=‰’½…¼Ðžï+¯8;" w·nΗˆ˜4IiÖ)Åž ¯½†UÀùb`QhXŸûÚkUò™g¤Ün;)÷Þ[½›÷Ý'åæ›K{íÚRÞr‹Òª¯µ–”‡"eÇŽRžx¢”ƒK9}º”Ÿ|¢,f7Ý$倊°vB¯ÌËࢋ¤|î9¥©v#Š¥ KÞwªvè;Öp?¼ñ†Ò¶Ÿ¾”ß~ëì çŸWsÜwß9;b}£ÿIð5ÅG.ÚͨaG³Þ¦MqÍ5רßo¹å±÷Þ{‹Î;‹vØA¼M"Ö” ;A]ņѰ§4¡ !›Aq@ÕÛµâÎ;•v­iS•e‚ôФ]‹#sË/*M…[(àh3{Éøÿ’‚*Œh+3ÿWî )- ÒR2B£d/Aƒþé§ê=†Ž 䇎Éì S„ +ôÍ;OjÒÏ>bØ05°aeã:¯¼"DýúÊ÷ Pæe|ÎɱN|G®x°|€%í9ªT^eÂÊç]¯ L%@m6ÁàÐ"–„|±ÿþªn–4‹}Šô «÷šuƒêŒ {_‹: 2Ýk¯½UO¯µ¨ôàƒ¯¿þºhܸ±¸”ñ”Ss¾.1§B¡F9´Qc˜=ûT;€ªV¹¼O…ænMx6gÌÈ ‡Šža²7`ÕÄ´M&2WÄö(Zx¿p"“ÞƒÚìŸ wß­‚úp20HöÙGe^Ù}w•µ¡˜Š¢¼×[⾃Ëq0¨”lq¥¦¨0ˤp$Y `ü© ÏÿüNÜØpC‹«xð¸šQÛª 8?º@#‚fqõ! ÙšòuGaŒŒÜ|⮸G<ØT_ddØg̘agƒiß¾½xá…ì¼ìçwžhÒ¤‰ÍÌÏÅ©-eãÃ^Œ\œåÐF9Œá°Ã¨Š{ åò>ÄÀ •0@OaXh™ƒhÙ`Ša†©fHf®¢hØéUZaR$H²œëTP$%žAZ€o7E»Ðcµ†qç“÷-:YVž^Y‚€,.W‚á„ÉGƒO¾uŠ,¡¹Gó OnvjÌôAšÜ蠟üâ çGĽ¡‰y !eÂäW| Áæž{” þÖ[ÎΈ óÖ 2ì EͤePšÈȰÿúë¯b[J‘YxòÉ'ÅZk­e½ÀÖlÿe!Õ”!†a?žh°£Ú(—1›ÉºP(‡ûTl`"§L9‚å(žÂBIš7¿i&—[@àiáüÕ¢X!H=–a‡!€™Ùf›SíÀ±\À½†%S°]X$m…1í'Û~TP·,a;í¤[4Ô "`³ÎR­” NÒ´B¿™˜S˜_tr¬ãâ» Ì:Úh„öÆ•»EŽÐ°“ŸÔ‹¸‘Á¼#(Äy?·ÚJ¹ö XÃüâõëu¥…q‡ÝAð¦H}ýÆí œ­O°NXb X'â .¸÷Xp3ÂRá‡4¾{¦Oñ #ÃŽŸúó–ýLj‡zÈög_ÇIopß}÷YR¤%F¦ t/ vƒÒ&[D?“¨A²€iÅoÍŒn.¸Ðà›®ñwßUî#,¶ä?΄(Vˆ°vLáøÂâ»{òɹÛÿè#e6‡á‰I[aLûɶTòüðC•†z¿ü¢2ÆàÚÓ ó³NVhw®›nbܪâ©Û•W4Ä0éXϸ¦~çaˆa@a5Rî hÜqKA8G«ÿßÿjkçóÑtç ¾ô ×S§ú+°À|ô#¤0ÿàÊsðÁÙŸ1 ]¼ñÄ„b±˜#™s¼}Nã»gúTìéê˜4i’¬Y³¦Üpà åšk®)g̘aïoÞ¼¹\c5ääÉ“íï…D¾ÑîcÆHùÈ#Η""jÎfƒâ‚ˆ{“‘ÃùÒœ¢^ƒ|Ì:»9ËÇ“ò ƒT >¿øBýV(0Õå| ˆ”r·Ý¤;ÖÙ]»Jùþû΃˜…þô¹P%wß]Ê–-UÞm²Ÿ´i£2¡¹„õ–ÌlÔW gû¶ÛJ¹ÙfRÖ©#åúëK¹ÅêXê”´n­hùÑG¥lÚÔiÌÙYÈ‹®á]Kõ÷Ÿ–òᇥ<õT)Û·—òßÿ–òwÔoq€\“¾.ZäìÌîÙ®˜‹Èþ”+³ ™ÉŽ;NÊ{îqvÄ²Þ .å‘Gª,Y¥\´›QÃŽÙý¹çž³s±Ï›7ïi¤uëÖ–tù¸8;QÊÆ%†±åÐF9ʧ˜^ÃäÞÍ…r¸OIƒìÚ«š6´\?ü ¾£Á&`­PÈ×%†à<ñÂÃ/6p›¡¬;U# Ò²¹„I>˜¬­d`ªªRñ[l¡|´ñgG{Œ{ó)ÙX¨‚:c†úþ'Øí9®l¸×àöBìæäEÏ‚\>ZYÛp±9àåÚ[‚;•“£zÇ Hgvê×OYü€•–œŒk—]”¥ dÌ~O¹wøŸ¿öšÊ"—71V´þä”'¨–¸ƒBí¤v°ß~ûY/n?Ñ‚|K†n¢Z̾³'?p×Àå¦V­Z¢iÓ¦Ö¤`Í 1 ŒKÌ0Vÿ£Ú(·10Á19Çr¸OIƒÅSUQJ¼sgåÛÎBÍÆâˆ9˜ÏL~œQK ~ª03ø—‹:¾ë0i®0ÈZ%øeE‰æÏW'ï°7hÀÐ´qá|èuçUài“&Š®¡®³å–Bì¶›òg§Ü`@&ƒT­[«øâ^(„» ®90­Q1dšBÀçWÌÞŽÕ1¸½sC_`ö½Y¯9–õ†OŠ;ù1öaÁÜH¸Ë 8”'22ì0ÖS¦L±¤ÇÞâ´ÓN³ˆ©‡½uïÞÝÎÅ®RóÅUÖ*uÅWXÒwO[SOªÈ­•÷~¨$"ÂhØãh7WEÅ8ÚÈ…B·Qnc@c‹?ôO?9;bB9ܧ¤¡v|gYìI%çŽÚk/¥±¢2(‹ Z;oÀ[+mIëHÚFy´}îy [ûøþ"„£¾PHÚ cÚO¶ý¨À‡½À6Û¨àKò’7h è Æ!•€iÞe|Ñɧî>í»`[¬ a< 4E_xt|å9–J¥üF+L|Ë–ê;Úó¹sýï'Zf„˜wüʹ>w˜í{ïͬ%ÏƇpòÞ{*=ýðÂýŒ¹OŒ‘|ôÌYZ€@àY´HÃüÀýbìTˆ£…×FÏüøñóì>¿þºóc Fz(IÅ/ÆW_}µ¬Q£†¬]»¶\ýõåÆo,7Ûl3{>ìgžy¦sdp,_¾Ü¾V_Ê£¹Ð¦MÙg9òõÅ{òIU}­Ø8ê(U¹Í ´0ujî ”Õ ùÒœ¢^£W/){ôÖ#å/¿8;³ÿÍ3ÎP~¢ ª}•K˜C¨Îš _}E<ò鵦µÕ©}ª¨âûZèù"Êøã€i?¹ö£ÐŸû\|¤o¿]Zk¿”µj)ï—^’rà@)ëÕSô9ožòá¾ñFõ^÷ë'å¨}øƒ3¿â·X'çÌ‘òÊ+Õþ-·”ò?ÿYµª¾mTH¦JéÖ[KÙ ÕT+mŸú /TÕ?ÝçøŸ÷ñãU< sÉ /ä>'ˆy:úh)¯ºJùºkäzÆTqe¼gŸ-åÁKyÙeª짪+±¹ª>‡ýúüsõ|¨ØüúëÎ "izôCû”‹v3jØï¹çqÒI'‰ï¾ûNœþùâðÃß~û­˜?¾Ød“MÄnذòYf^zé%q!l.üë_ÿ¿ç«÷A {Hª]ƒh¨¬TZ¯fÈ 9 )Ç'MZ*´n¹€æÜÊø‡¢é&«Ä•W†·BäòaG3FhµÐhùiã3YAH!G%ŸÓ8z‘´Æ´Ÿlûq?vè ·r“ㆂÖí;öcU.)X¸~üQÑšmÜCÐzãß Xȯ°VâºJŒ ©qᜅ F`}âú´K&¥o¾¹ßÖøã#ö˜l5XÚpË!ëŒø¼£ÝÇÿz£ø»£ÉÇ'ó“%ñ%×3Ö®;dÍÁß#4ð\C§Ã$£8A¿paþÄ 9v¬Ê¾EÛ!=™##ôPŠ4š‘aÿâ‹/lW•5ÖXÃö3‡ÑÍš5³Ã+­—Àz òׂѯ µY Ó‹ºŸyæÛõ&*Âø°Çð—&˜PaÚ1ç$ ‚ÏXLñÇÄî › Òu²H±°SËv£ œšÍ‡ßÓ“NR¦vBoðÉõñ9^àB³x±r1(4üÚ/&Lûɶøc_r‰bŒ¡)\OôÄ·Æœ\æT&†÷èŽbføªÃ0²&¨÷é£k膠H„Uò®ãv‚o;B®6ç·ªò¦žê§ víZöñ¤|$*~긗À–ÀHÓ®(ފɸð\wb´™# gnÈTçÁç.ÔŒD`_º4ø3æþ!`Њýâˆ ÏØð…÷>ò…ûÝ#U¦Î—ÏxZFŒP.NÅDé¡i4#þÞzëY/©rÊ$@ôcKÌý͉£Ú)ߣ`²Eí[n¹¥¸üòË­¶£èF-ß °……"%+“/6Ò6ù^É/2‹) )„ÎÿAˆñf¥ˆÈŰÇÑF.ºr÷øñΗP÷©ØÀO ‹3ÅYÈéìL5¡€O9ú‚ÚXÔ 0Χzb6v²20Á`°s 8ƒ´M:B+U„ÉÚä 1Ù 1ò˜S’¥ë2 !L4Œ7 (UBɃ9ÙL¨Š… €qeFyB6¬žæÞÛ¶ʹ.]”æœv9AZGÈÀ¿ÁÂ=0¿Àt“o€o>ñ3gXÕ‚€|òXòÐ\<Š FIH–X„~ø,FÌ0ïXøŽz`rÂãÛм…~ËÁªQæZƒâ"#ÃÞ¼ysÛ-P$ ·•YDYx÷Ýw-&ÕâR#`Ÿ}ö± 35Êvþ'óL&ðRSæ›ÅAŠçåÃÔÅ¢ŒdŽM±^D¤m˜Ìmî}îí©§ê­v DÍ5Ä)ТÞx£2ãaIa"f“‹Žl÷C=Äè£Ðm”ë6Úˆýñ•.‡ûT,°H¢ac#h FG£‡¥l×]Ãi¦L.dr‰AS…– &„”wùæ&÷ƒ´…Å‚p-ñ‚õNk¾a¨©º «€ÛÌ7•=ùÁZ‚±ÝpCµ–˜Â$’] m¹›>XÑȳÏ*zE œ‰a÷ ;¼ë1 0ma`ªÄ5W4w‚Ü\à'4`epWAG{ŒƒY, aÁ½‚¯8ûl¥XàÜŠ¼eÞ ohá™Ñ”Sô/,“M[ð8Ì‹hÚ¹W>ð;úhY«V-Ùh†˜pï½÷ÚÁ¬ïìQÐøuëÖµÜ[‹-äT¢]?~†lÐ`õ@‚Þ½{˱žŠ&\›ë,]ºÔ٣пyÝuCì`7g>ýTÊY³Ëý÷¯”wß½È.Ì4q¢”£G´0Rî½÷Åv0 "piß~¹ÕßJÙªÕ\Ù³§ T!pçÒK'Y÷®»]<Â.]º¬6ŠTÑ7/òǪ;¸°xñbûØEžÊ#GŽ”_|±óMaŽ;w®³G‚ZÝ»ww¾­D)ãí·U€¨Nσsù^¿~}Ù¤IûÿÖ­[Û4Ç8‚ss]ƒ@´¶mW¤¹G4ïý#àì±ÇT`Ál~etûå—ÎÓ§K¹Ï>t;/¾(­µUaï't?k–”:¨¢NIyÅ*¨Õ‹W_•Ö\ªŠ9tNÐm6è>ýú« ¤%¨6WÑ¥\ ss•ŒƒàzŠGÑ}dLÇ«æ$êX\J|˜{õÍ7êyXˆ]‹gEÀ¬—_ ‹¤éÑiìS.ÚÍȰƒ… Ê &Øÿ¯X±ÂZÈzÊ]vÙÅf¾w—' ˜˜{î¹Çb„W- öÖ[oÙ û”)Sœ= ùNæaý½÷ËV­*å;,²Ò#ÔýŒú® lµUKh˜*·ß^Ê”@íÌë Aj,­Zõ–£Fù¿+×]w³Gáœsú[óÛ‹öT5TæŸ5k®¼àÅËpÿ²½+“&M•óç«9A¤U«rýõw³ù ¼º°U;÷¶îáØU2ådz篼²¿õn ‘×\£ª¨ÂÀŸ~úbÙ¬Y¥%È,ZE ú<8®ØsP.ÚÕ4 ¢¾W ´[ƒ?ÖEÁ’%KDýúõ…õ¢Û™4n¼ñFaÝ,ñÎ;59X°` ÈÕ꼨 ²$0'QŒjhÅ.:,hÞÜÙø~ö™*ü‚þSõü³l˜(t6 |1ÉŒY´:#_šóƒß50oãÃJ>c̽ø½f~ì˜Ê1‹ ˜Çq¡#s9¦m Üé0§cއF ‚%[ npøÎæƒ7ßTãÆüo`P D¡áLçâF¡ƒó)̃ !þânà÷Ž ñ\¸¨@7ø¦³†p p{Áÿ7ò«ã²M}ò‰ògÄ=×3|·qMcme~Æß︀ëþè´…û¾öäŠ×4Žën/wß­ü¾qYÉ6oi”ÊœB¿¹^Xïaî3n>lðù®Nç¸'f€û˧;Ø”1“?7&½q7ß|UW$xrÉ'@6í6„{îFl:ИàZƒðÈE»YvKb¯¼òŠøñÇ­‡æ ½¶pòÉ';ÿÇé§ŸnW64h}Æ’^ÄСCí’cÆŒqŽRÈwâÁ¹ï>gGàïÂ_¸ýöËìךO¤œba2yã E8òà'AdBãȆB_$9|6¹Ï¤¾ÒÁPaPê÷)Êb¯¡¯Ñ¹s•èØ±ÂfZ ,%„L¹@`AæÐr¡ÃŽ=‹j¨Òsƒ-Ïã³Â1ù€)º%¨ÅÐÀ ˆBÙÎu3ìd9n܉Ý`ÒaPɢ±¤1„QÇ÷?l‚¸a€­KÛŸÄ•ÀyXS™íÿýüóŠÙcÍÛ}w5“ º#ÁþÖÄ®Áü;ù0bý`Þgg®"h¸8 iF•^bÛð[϶N@ûø„ãŽâÓ0ë é2Q"!ÌP„‰˜«8À˜Q°Ë}ÕŸß|£î5ÏŠc¸Ïø½´Ês`~ä¹v“y‘¤<'ÎãƉ C¯?µ0$MouF.ÚÍȰ?eQå1Ç#tf?ø1ñ¹ðÖ›pýõ×Û­‹­U™º3Î8ÃÖ°{‘ïÄCv¤s4tAÑÉš]Õ3QHŽŽI&Sº¶(m id2aRƒ0¨Ð ñ{%ý8Æ‘ …¾>Hz hBáƒÉV¥~Ÿ¢,öúݺUY ]…=Q³xso¡Ê~û³iP®œìžr Z1D¼Ð¤XNP:Y§Ð°…‘8׫‰40($¢Ðp¦s­)ÇšsÔÿ0ådiC#­qà J¡„v ,L&iLI¡õpÐZxÖha/P¸Áà³¶Á¢­‡~Èú¢E˜º†ðÏ\‚ö;.–Fd2²Ù`µ''mÀ b5 “ ž=² òð$¤­D€€Ã¸Ãh¡IƒÉüDee‚DãXraŒqÃà£Ä`ÓÙùØxF|jVŽ’ÿÙH€ðsÀýe-€©G ¯ž1Âû~çÙ#´sÜI ífdØÑ~“Öñ‹qc!‡ºì/$òx ‹l>¼ n:Q³n>Š[†Áq´xñѾ‘óÎăÁ$W™Pè냤ÇÀDÄŒ4,Jý>EYì5ô5FŒ¨çWaO²Ð&ZvMÁ³a•"­®_îé…ws0¥¾Ã"ŒúÂì~ùåŠAç;Â8Br¾xùåwÅUWíl/ìI¸µÃÒ“ ¦ýäÚBÙÎu3ì^—5˜7”H¼ë(;°p£ †Ž8O×T@3Næ&r¶£¡öÇPh·4ÚÄ¥ä½÷Þ믿³=—00_Pœ †¾ÀÜ‘a׊®åëºææ(„ Ò+¢yfÌI|27Œû®5Ÿíl»í ¼`aÏÄP"øÃ' |;ë,Uü)_Æþ 1?b ´“/’~÷Ý`ÞGðZ°à]±ÕV;Û÷âs|"poµ€«"‚ç°Áô#0Àìû¥·ts¯ú·<>Ùôolþù®õìv¶ÿç}œþγç]*&rÒ. »ÖYgùøã;ß’ÕiAF|?©¥Ø7N•¹/&”¹ã•æüó¥\²ÄùÁ ÔñÄU+„¡9/‚\ƒŒÏ<#eß¾ê>ùdhJ°çÂ…*€* ü}‚€€*J¦oµ•Êb–®¶Û®RR†<)„\0í'×~Ît.Á‡:³IÈ£A%¨œB6ðû謹r$“ ·„8¿™3Õ>?ô衲³3¤5JýÏý¤Üþ¨öÈÌV§Ž”ûÉðyè¡*™Ãþû«¶™Sn¼QʧŸV )Ü—ù‚àOT6”róÍUöš6mÔ3^¼XeU¡ÍáÃUÐj&p®¿^e‚?>\æ¨/¾òŒ3T¢%; ¬Y^mذRžzª”G-å!‡H¹ß~*;OãÆ*KN½zjŽÛtS)k×–r½õà÷¤\k-)kÖ”rÍ5¥\c•[«oÖ+’çVé³/é-{ŸÎ9ǹáED.Úµn=[ä^¿öÚkű8›%„0š$|LvÅ´hT?KT›Ãÿ?1byÉßjø0¢Q¡¢_uDíœF˜k`1ÂdŽÉm ¦S|¿©Ra¬Ì„äXŸ8Qå…GóF M{~¹Ùý@pÖM7-“&ÖÒ’ Űôdƒi?¹ö£Ðp¦sqÃÀÍ5Ô|ÂDŽO:.dø|SëŽAû­Ýf°\…Ÿ3?3Ų }ÆOµLE Äï~â&B-‚[)¨HÀ*ZZ4±Ìš³Á…­)jþGϼ‚UuÖKÜnØ‚ä}g~"Xuòä%⯿êÙ´ÌÓâßÏ}¢=¬¸Òàú¡AŸÐ.s¸GXs¹_ôƒëjm3šf4Ðh˜µvY±‘Î…,ð?š~´Á<úÎÿýµD¬¹f=û¸7Ž×šdúÇßÂylºŸ\“{¥ÛÕ÷S_C}-ïuÙ¸Ö¶5–ˆ6ªg÷“y”çÀ†›‹þ_ÿæþdã7®Áÿ|êßôµù_÷_÷%’ž#ü‹v32ìwß}·6l˜õBM³™÷$fâq›îŠ F`¾ ƒ+^yEeà`Àï.ß 9"|2SFËEA”Å^#ê5`ðûf#ËAÓ¦Êõ “7r¡À"ŒË‹&Ù›³#þ§˜é)\‚);Û‚ÀbÌDÀþ—ÅFúËt.Ì'.ø“… ¦W$Kn)øj³A3¸ºA7ZÈ…q¥²(‚[·Vî,~ àÂ1´ÏñøGS:ð“‡ÉGÁ¢½@ eaÃ}FšÖ.0¤Ú½‚¾²iFÆÏý©™BÆ¢],4èíÀ€ÃÈr •üÏ\€Ð¢Y7ô>®èm0nÖoâÖ¤ÐY[`Þ ™uð­GÑÕÝ9—vè+çrxX¿¸çrŸÈôB°0n(ìƒ)§ŸôCoôþkÿq„-ÐÐ>õ>Üž¼ã2ˆ†\´»Êín`½ 6´·–¨ü¾õ”ñ…ÚÜzRüæÞ8¦@†š¨€ ñ³Ê„8ÚÈÚÀ×–I?~„‡[oUŠ5†B"èõÑ–ò/ Êá>% ‚ŒXX„ѸwœÒ¾#ÓŒ;ÚŸ8A6‡§ŸVþêî©…Æ„öYð -ÍÌûAƒ÷Ç0ëå˜WMs0z|Gà ¢Y&!švÀ~ü¼5³nñ¢qcõ]Ÿ› üÆ1€Ï\ot‰TB'å"íh_vÖ@R"¢Å~é%•&Ú{´þ(¸È^…uM9É#`tu6a´öhðß}W1ÿÐ?Ì3ÂAõÌø°Ã(à ã‡ÍÿÌWd—áúƒ@ò Jx€¡ç864îWò;qTV'PË=A¼h﹇IX°Lr<‚ýÿì3¥@ä;‚Ï '¨6¹6ÂX æ‡O Õ#ãCˆ¡/]0óìç^2÷8"ƒyk‘4€gÉm˜õâc•[~ÀXÒok{ãÿ­·ŒÔ;vmÚ´±7öë-ð·dÆ ('"˜T²1ìq´‘ î6öß_1iåÌ£¢Øc(‚^.“¨Î7›Êá>% %ÃŒ¢ , ”9Ÿ?_i±Ñ¼‘R/ða`‹F39 ¼Ð<Áˆ#D ¦úÁB÷:; Ên†O64ëÐ% :š]RøhÄò­û™gªÿ9/Îoîv²1÷ÐL*éYéK6 ÑFK cƒ«Zè<Yæ™yóÐv*I˜s}´Ôî žß™HKI0=ûX;`|3Ù§¾Åúe¡m[u?¾%9Ê­ '•$ýƒ¹'ùB‚Ê#”0ÚÌÌUXÑž“m«Y3å KÛX6¸ÿX±j`!­&k‚ +`þ™£¸onkA —˜lxê©§äe—]&Ï<óL»rÔêÕ U9ðýDÐéìÙ*Ø$ †à“ÁƒU%:ƒ`xûmU…¯º! Íyõ~R²<%¨ŒJ|Y=ñ„ vÞ w™]Pa‘ê¦TA%0ª·¹@]ÅAW| ®Ã5@Ðö Ó~õm? ýe:·wï•Ø7Ü ª”RzáÿeËÔoï½§hQã§ŸV]“ 2gnÍ* tÜÉ‚ÜO::JUJ-rõ‰y€P‚L›5SÁ:s£¤lÑBÍ;Ì#Ç'å˜1R~ú©Z³oºI… × 6P¡ë®«E©ÐÊüxË-ª’ºžs4ÜýúäÕ>Ïè´ÓTpêr§Ât1‘4=ú!}ÊE»?üðƒØwß}Åa‡&†.Èûö€TÚL>-–K®½¶Ò¦o³ÒÌx ”;«{CŠÊï¿W×ã>Ž«æ+沓N’rôh)çÏ—ò·ßÔ1™@ß°H2ÿa¤}æÌY³V^ß øÈE»5ì?þ¸2dˆ8âˆ#„.š´æškŠ£>Z\wÝub›e€eDDD. {mäB6ø‰ÜÇŽ@’|üýÓ2†(È÷úø4£µA“åpŸJ (ŸN´W½z­¬JH 8üRO?]i¦ð)%~×m•C†æ+(Ð0âw Má7Jv!²V f`P.@ÓÍG%´Ä¼H 6¾ÔºÜ<&R0j 9&þÄ­QÏ¥aãÃîçèj¤hø£ 6Zr‚j™3ÈÂBð%«h§±ÔáN@ñ‡ÇÇý¢}îšn2«p°üQI• ÐO?UVBRâN\Vp®ƒ¥àW´âøæ„JšL‚W åZÌcô #ýÞ9 ß|ªÆžrŠšãÈœGÆ-,€öâç7âÝè'šü… U/…­°^}µªüJ°mÔX!ƒèÈȰÿe=ÙºDgø`Ûm·¿ BäëӃ莈ÈŰÇÑF.mf„àÒsAÔD†AšÆa®O S¦@D?”Ã}*'àÚD`&g0LËd€fùß v³ sL:A¨\k¼æjƒRL0Á¸vÀDÂlÂ"œ‚, ÔtW0¥R¤ÎîÓ— ç7ͰÉ“ ¸¦‘†@Pò¢mRGº&½/.?|â>‡°Âuq¿C‘C'Y\`”ÙSM`)ssn,¸2ÿú‘c:%Ë ŒºvSEÐç~¬ cO…M˜e‚M™g¸¿¸g’J°™ra° 6%U&çãD[¸úQU}+µZp§áùÑ&®ƒœ‡ë 9c!pw&˜wÜ Ißɱ̉Œ“l]Ô¹Áå‡çŽÀ‚Þ–ç¾x±a苨ÙÿWÁ¹çžk½¸¯Š§Ÿ~Ú’ü,ÑÏÁÿYÔÔÉzb¬§{ ùŠ “rÔ¨*ëåZ='¥x!‰ŠÖ¾¤¹@aóMkJ‰—ÿ5?ÄÑF.„iBcR€‰8φ´Ž!„½>Y(™Mð\(õûĵ£äPq\ƒE!J=¬›ºr+²(Â<0Û¡ubQÄו…E‰Å?\.æÆl@@Gs†(ií¼ ý7ßÜÔ^$ñõe!ÔšÈbÀ;þbôŸ\ûQè/Ó¹dùã}‡yµ³:Í;s$YM Ü%—(fÐ üÙÉb‚ÂÈhé±Ãø#h“é¤yóð÷ 8tOÿñÝvƒ¹€yKåþ¡}r›¬fXXaŽ¡_üÊÝi ÄgÍZf݇MųϪyÐw˜a­UwƒÔ‰Ì9Ì/»í&D÷ð Œãõ× –‰/¿ÜÔÎÕŽBŽ{€fOÆ…PÄD¼Ê #”ܾ£Øãw „Òw2?òëqmî—õhl‹"Bœ›ig¾#ÖǶÎ:Ë,!fSû|6Þ®E[IÄ&=Gø!ífdد¼òJ‹½Õzh5m·˜­-Žn©%æ=a‰^ŸYoÇñÇo=ä•âï]PoÌÐßk¯*‹8*þÉš HHÀ˜ìŠˆ³šëR鞘Шî™P}¬ÔƒÉˆœ¾¸Õ¾–*â`¶ã¸FT†¥ò“/5‹Zo·íš-QfB‚¼Ðð– ˜´aš6´S¤z Ôîñ'Ó~ríG¡?¿sÑ6“îšÀÕ·4º1Ü% /r}k°¦ ÁÅuà ´ÑX¡2¹±†ÂäÁôââAS®å~Â\â^B&j´Î0çhœÑZ3'@ï0©$Œ ^ƒO\EHßȹ¸–à`°xq'K˜xÔÖºsZuÚâzÌüÏ†Û Zo˜jî[›6ª= ͬ"ð¿Þø®÷éÿ½›ßoÝ»w²žÅ£«üÎ'ý¢/SK–ñÅJ{ÿ‚óÍ|Èxuß™¿Ü›\SƒÿÝméOýۊĨ>é}úz|²ßoChЛ0ØÜÿû}×û8O××áÿ:‰nxÔnC 0l5l$êÈf *rÑnF†½¾%Ö°î*?ó©¡×ûôïŸ ýˆîüرU¡TØ>s¹€ÔŠyIG­¼èLNî «”CŠv6ëvøÓ$¦U9”â`¶ã¸†µ>[ ´ó%èC“&¶o§Õ {±‚ðj½Ü +îOø¾cMÁeÍ“¸Z*u´ò™@ûî±³øáçŽ2sñ?u.c‡·ýbôŸ\û´–þ¼çR j¬H³h[ñ}Æ=Dç]G›ŒO6Úe€_5Ì=çzœ .0D~`ŽE)£ŽpPŒkI¾÷:Åe„‚I0Ù0¨hÐÉ=ÃMÓ_â]`ÎÑ ³ŽÃ¸jfÍ1 ,×b· ‡ƒ·@¨¨YsunÅ?  [s ³É5˜{ø ÿp¬Øzíð®!´kÅæý_×ÿkFZwÿÎoK—.uêTü³ÏïÓû¿{ÞïËÊõ±.jÆžÿ¹wlZPaãx½q¿ÿ^`]Eõ èÏd¡ú” XdüÞáB"ífdØÓwç'N¬°ÓeÒhi Áb‘fb)xq™X¼æ¿RE`ði§ê>x«ƒE‰ 袋œeˆ(‹½F׈ʰ£=ÃÕŸf?sÎ\Àw“›yó5‚N°ÜéJ…˜èQ „ýÁRƒï)B×cñ70ˆ QèOŸ;~•xòÉ Û­ÏW\Uvù—Ò7â&A0&Ì»;·µ‹3Á™^ä¢kh ,ãzƒO6®)~€A„ÎÑ£/Ôn-ÂP¸˜Jh,ô5Â?FhÐÕ=a®YDZÌãæÃñŒë ¨rˆòeÏeƒ¾±F \„¾µOz€Kn+z¼X×ѰóNV°p¿¸Ü_Ål¯d°õ'÷‡û§?ÙT˜c¹GlXQ¾Øj´Â=âš0ö´¡Û⻾¦zظ&Ï>õ5ùŸ6ü4ëZ“Φ)·@ŧî3›ƒn?)ä¢Ý’`Ø[·®²N… b}µˆ†~ ôCÀt…_X:+–ûáq®~À|¾øâ8ѱãiöƒw¿`¼úáÚÙÀˇ–`6?Œ7Nœ†Z®€ˆ£ Ò’bêGÛŽ&ÄRC6D½>”BuM$o&p?”ú}ŠƒÙŽã˜Äÿó5æ ´sÌ T$%ÛAP ýcaÃÏ]“?ŒÚ˜üÒ1Ó{µdù€w‰€8\e0Ó#j ¥AD¡?}îVYtSñO…R\&q#W8Ÿ0ìXˆpñ`ÝÓÖ"ª‚x™ÉC6ÃŽ ¦÷•þý•‹ ŒûØX£ ]ÖŸïhwñ‡FIÇzOžsæ üéñA‡á‡¡‡ŽÉ•NÑvCÃð ø§s-, ddÁrÀüιA]œa8™ØnÇ‚V̘îî.0á,Œ•j¬30Ä0Êð2Ì[0¥Ü+>á_à‡4ÿƒ€Á=`C™€EAû¯³q¯Ý<×Å͆öõÆwwÀ=×&‡ Bžökçšðil\^+ÊœZÈE»%£a§ó¤N²x{sƒhiÔmhÃÐð]›kØõÆKÌvÇ}¬‰éVû…fc`cB@Úä“’6Ü/»~é˜hð¹ãeÄìÆKÏ$Æ9}úô±ã ‰¸Úàž¡=„ar3:¥4†Lˆãú¼#Ü0påF©ß§8˜í8®&Íô¯5cdcÈ7.·6//“O4ƒóŽ&¬ ˜î ‹²ÐX·É¶Þ0GaÀ'6I-Ai# ýéswÞ¹JÜv[Å?ÖVÜ`p!`í7îe›¬snk>ê¤ öά£¸^"Ãôë E>qEÓë+Ú^èFT†\†ùƒ™¶ºg3×\Ÿµšâ?\Ÿ5&:…iE‹ XŸwÝUm¸×°>#80ÚƒùįÚ¦­|h™õ7²¥0ga] ÿ…cg¼ï¼£>ÙP˜ï¸‡(!™3#üÌ8¿ÃÃÀ ³Ÿq³q¿PÀHçRJÆÊ3@è¡]x)î7Jž×dã;÷=ʼX‘‹v‹Ê°ÓÔÖ*z›Eõø¼on‰[´8Ðz¹Vwèôëâšÿ‘àY`ÈÉ<Æ…‚ñqoõu¹×Ü÷ HšýÆ>å¤]öbaðàÁ²fÍšòòË/—Ï<óŒ´wI5ÕC(‡æ«Ó«T}¢  ÝÕ Ý4HÊ—_v¾¹*3þðƒ” JùÈ#ª‚Ûyç©Êˆ;JyôÑRöë'å}÷©jrTDKÿ÷T»U}2XT²k×NÊ÷Þsv” üh._Äq^½¤\²Äù’4qðÁªÒÕúôóèM9Á1BUûÌ1C‡Jyî¹™çÀo¯¾*套ª¾\p}émÓPP‰õ©§TõT*í>ù¤ªÞ˜ÂŽ?.˜ö“k? ýésǯ’Ó¦©umƒ ¤¬¨rŸ}T%q*tR‘“ÿÏY©>Ðúƒªê£­[÷^¥ŠkTüô“ºðð8ûï¯ÚiÑBÝî3s|ÄøñªÂiûöRžq†%ÎŒ“òí·ÕÜöÝûðC)ï¸CÊãW×¥“'«ª®Ùæ¿ HšýÆ>å¢Ý¢iØÿ¶ÄB‹9'žx¢Ež(<ð€8î¸ã,Ir¾-Y¸‘IÚ@ó†Ôï—¥ß:1©Q‚äš‘Œ15YC¶%[¤h4ð˜Ý‹ŽÈ/&0£Q_>|Û V ‚цöéSn qhÇã¸>ÝøÏfriAÛD ™ 0Ë,MÚĨ&XÌùøÏâßJq¦$r¨½.³)tL*G|bñÍÄ€ X¾À¬¯ƒ_I‡–ó}-sé@úÓçöî]%–.­°“àf†u 9ï5Úi4åhZ5¨Ð‰KD®uËZíÇSu@ðwF[-0m`¹Æ­M8škb†F®ù•õ m4>긬oœ½dÒãö Má/¯sÈgz‚×™ïÉ ‡¿w0W`¹àž¢ígŽÁ×›{εYûuþ{~瞣ïÃ~Æ…•",¸_hÏá[à;°úã»Ïüf®2ˆŽ\´[4†ý§Ÿ~ ]»v-Éqäà ‹²öÜsO1eÊ‹_•ÏÔy\Ÿuü²Ü@ÀlÆÌQ³ZxÁSÁ³ûœ9já†8!&|í0%54´Ëäi°*¬ðgǔ˻ÇdZʈƒÙŽãT˜e:ðæqF°eÑ$2 = ZXèâ 7?bÈt5c®4¼l˜åY„€q¡É—éf> ¾½ó¸&;nS¼Ai# ýés;uª­[WØ.¨0’0‹¬C¸€Á8C0É„ÔàËÍÚŒ"ƒÀC6*tâR:>ë¼»:ç9[`Ì çš0î0ëøÊÃügK ˆû@˜Å=‘¶`-Ž<2¿ pè¦8²ÇxË®¶ð¸óäë^âë)ô˸ gÜxØÇ=ÀUƒ{‚°Î¸ÈóÏG°; Á±ø¡3Á»ð¢\× ä¤]ö$qõÕWË5jÈ·±çx`uaÂ×<€ è¶Ûœ/.`ÒÁ¬•¹|Y"Ûeâjã‹/¤œ4i¥)ìßÿ–òõו¹*®6ü€‹N½z•òÎ;B!Ç yý>Pn;îX)ßßÙY rÙh.(â¸Æ5×HùÒKÎ \ê¸ã¤lÓFÊýöSî'ÐCÜ8öX)÷ÝWÊO?uvÄÜZæÌQ¦mí wãR¾ñ†2eçÌýƒ+s?×5JÚï]TÓµAé# ýésoºiÕsqÑÂ=‹w —Ü9¯½VÊž=¥ÜtSåÂÁ; ýà¢qÒIRâé -ábq×]ʵ‚©‹÷ô¦›Ô5Ž:J¹ˆ2‚ùó¥8PýŸišÃ fút)»wW®"¸½|ô‘ócHüø£ƒû–}ù¥ëm”ùšœ7OÊ>}T¸¿^r‰ú¯ Ü+5ýC׸qïpïk-ÁÝææ›Wºì-X`æŠ4"í5èÔ‹W^yE´iÓF´k×NLóɉ˜MÚ@»FÙbNsþQf íSÌœ9Sƒ:>›†=®6Ü`ü…Àœ†Y­ví™bÀ€C팅ÀSOÍ=v¨mÅý£(Ä}r£Ð×GÛ~ã3Ňj›zÑþ¤·;S!LJv<ŽkŽÀ&Ü]ÈöB¾d´iÐ5U}bÔ#Y6 ^%Oz&Wœ8APnhÑâa%@óŽ–Ï ÍÜñ(ø„–×´—hÏÐÚÍYõBúÓçöèQe}«°-DÐYIt­Jñ£Æ‚¬hXÂ8æùç•«óY6Þ?Ü\ÐÎðI6æDð»×­í/Úg´Ýî5•õŽwœŠ¡´2·ä›X\`|hÚqïa,l€‚ë8Vè›@\‚`Ñ®cÃZÍ=ÄÊÆ¼F [î –sÜPi3º%€—ÜùX8ȸƒõÁ¸Ó¥9i×fÛÀ—ùX! ´€Ð Z»o¿u~ˆ€0V‚àÐÀ¢‚ä°¢u–”cÇ*úÎÈçÁcM›VÚ\­'ZÈ^ò·ßœƒ ŒB[Ër¡:·…þô¹“'WÉo¾Qš_‚5цcÑá;V®Ñ£¥ÜsO)×]Wim Nt[¼îä4òÜ Þ?‚DsÝ í}ûªÿ9–¹€um³Í*mº  µP`î™8QÊ7VÖƒ\h¿gÌý!0úíÖMÊP‚GY7Ýs ‰(¸§¤îZð8@¿þû_Õ>óVø¤‘4=ú!}ÊE»‰0ì÷[\õ:ë¬c-*M­Å23g©;_·n]û溷-ZÈÿügªí† ‰`ÆŒ²yóJ{sƒh౞\›ë,]ºÔ٣пkb°f[³Ç."…‹ #GŽ”c¿²Ð©“ýa-ºËícçzBÏ'MšdE=téÒEN:Õù¦À8¸†AÆSƒKЮ»ö·îïÛ§'ž ãÐÈ4Žûî›$wÛ­»¼î:g‡ƒ¸Ç¡öyh$ý<4úöí/{õb/~˜FY8`±Üd“Jká[d3¥LÜdžiÜx¤lÔèâLÆ,z:-—[nYi3wÆ5Ê88—ïõë×—Mš4±ÿomu$ìb¯Á¹ù^s9 &t²#4j¤lÕ\ §k.àêEv î¹î*‚Õ¯¿ªÿ£ Hû¹À¸¹/d¥¸òJõ.0ß!\°Ð#œûe•r·#ðôÓÊ…ŽwI 0%̘ûÃÜãlˆcüQPÛCîsy'† “²sg5gíº«zÿ M2ˆÀ’%åòË¥<ýt)gÎT®jÐÓi§IùÐC«3¡®éǸÆp-ÞM\m`Þßz«ð÷W²LᮆàÁre›s÷ —rsÖÆÙ³Õ=€fq'r»¼qýóÏWîl¸ö¸‹ „¢œ!{ôXéf”$M~HcŸrÑnÑ]b†..½ôRѶm[a1¾ù×5‚˜öÈÄ@å5‚ÄÁ]˜È[LPLSzš@à%¥­ÛhçŠ%§zм©ÙÀƒ©B ×\cLî ñÞ‘—˜ s˜Vqwàþð[&pßô¦¿kd»§d6ð[Ç…8ÜY‚\39&gî¸O¸áC°foö*;mH†‹ ©xu LƘ§Óœñ‡÷‹€1²ÑQŠ 4\ÈIMUGÜyì#  —¿B.?ý¤Üptæ €×`#ËŸ›ožý}4H¢Ð°>·k×*‹>+ìK\XÈ¡Î{F%.I"®#O?­\±¨°I=©úé}Éä:ŠëûqI£Ü8¨¦ŠËg!ÁÅu}4/ä ^gKâµD^¶š5U0V£FSíüÙhˆpAÈÇ#( yŸ‚Ò\6èk¸-c‡Žö¾Rn·] YQ1վ͛«Ò#Ž˜!÷Þ»r•÷ס6mâ·Ä|÷mŽ”{ìq±u g§m‰Ùwßd-1Q,J¸»ÌŸ¿\îµW¥ìÓg®­E£Ž&oÏ='Éúõ»Ë‹.Rî ÔWxæ\fºÈ ¦þ£aÿùg‚ùgXϧҞ+ȇÍùn·]oÙ¢ÅX[£JÀ?Úù{æ•J«åiKû8zöìiÿ¦7,duêÔ MÚvkÖ¬+[µZyݨ”[nÙB{ìT;/;®—Ìý—^:C¶k§úF&ï n%™îqݺ«Þcna‹ýå; ±ß)\bpåâsl!ï1yæq¹{ì1ÿ{ -ðÎ_pÁêãà~tî¼ÔÄe=À‚µÃýåþûñ¸-¶h¬RžvÚ"›G`MqãᇧÊ1c”[ÒsÏUw¾:ÓnÑ4ì_ýµhذ¡Øb‹-Ä„ Äšž\MÛ["ᦞ²†A5ÖÏv…@¤r‘ܱA@šIRJFZR®ùtÄÕF6iƒ'Mz.Rp‘¾ŠüÒA*I‚L×üq•‚‹àš¨¹[ }ŸÂ^Í/ÁÌh”´&’À*¬8@R©O#-Ï:,¢hç4ô5FŒ¨ß~[a§}#·2ZkÞA´?Œ8–) ÍéàÎ=×Ù¤n#ý&×E•IkwzÖ4Ë pî²ðú“çãZyè™\òm¤6ž!Ö®E°+šHÎ¥Ú%)ýϘãÐÎBl\ƒOöQ™RoXù4©)ãCÖçÎ[%Zµª°S¢AÇêDÕM¬7¼¬±~V(,=ZÓ‹ÕÛkÑ…¾*%=$A–Tédµš´A+Úç»î*-¢á¦Š* ಥ„å]'@Ôšrí Wø‹nPV'ÒÉr­áÕÅ˜îµ +sc $é\ãZ}ÖpRA’zÙ“–>rÑnÑö», <ýôÓE5Ðê;{Ø7Þâ¸Oö$úÎgâ˜ÈƒÍâƒI£˜ÀÝ—2Ô¤Ü~"×1åa²£è PXPÌÉŠ²îådŠÃLKñrÖrÏ7V÷,jnî4#Êb¯¡¯±ýöU¢nÝ Ñ´©*J‚ ˜÷#ˆ{ÙSpwcñöϦÑo›7ošØyç#m†”Ì d¯`æ=g!åÙ’AOE|Ò/\eÈèú/Øÿõ×ÓÄ–[éìQÇáÆäÞ`Róùßoc‘fsÿÏöÜsÓ,¡èH;‡5ßÝŸ~Ì—{,0*¸8°an‡1×̹þŸ Ʋèµn|õÕ4‹Ù?Ò¾×@ kl‹»ÌǰcÜýaãÀø±Á\¹7÷~I½áÂibÿý´c¿û>ºï“{Ó÷Âý¿Þüžs6õìHü«@Öç}t•X¾¼ÂvaÞƒ¹†EA„‘ÆÕ¬K¸dê5e™QpÕb½¦ ’×#–wŠ¢D&¬ÚN÷“w !aƒ‹”ìæ ˜b\Zè?kŒú¹çN³¾iyó*¾PŒ¡˜ý“NRïs\€VàuÈšƒû ™xÜHòÝËÓ§`ÈE»EcØÃ Ÿ‰-JGüÈî»OùÚ§œ¢Ô-a—`Œð;„™AcTãîÅçŸ qꩪà éºJ0(¤Àbqb±ÆñŠ+œËQ{ }—^ª²õÌ×€Qã^SPEÂò?±‚,ª,â,¶z¦ÒÌŒ ¾ßvã]Å[L±}TY0÷ÛO ÓšÓLœ—‹K«çµ‚°ÈjæTo0úSÿï÷›{¿wƒñåS3¿ºiÓºŠÃ›b×̱ûÓ»yn}_øM3Ù~›þÍûùá‡]EÆSþ9N·Aû~×󻎻}¿ßÝpþùgW‹vÕý÷þÜÿï÷°Ð×éܹ«xðÁÂZÚ2! ës§O¯‡RakˆIãȼ~÷ÝÊ:”F(„æÚƒž 5ÍLÂ_*}£»¨VEëVØÚtÒR²VÀx–ŒuØ„WæÆ@úÅO?í*ydÕ>a‘@ÉÀ¼…V=nB–]­U÷G1¬¼ùÂô)rÑnÙ0ì€ÀOªBìY1ñ`j/VÒ¸­ÚP4a4›ÚÀôs/`ŠJ h ш°H ‰c Xª¢,öúçœSe-p6#Î#é÷X»Jð©7Ü&`ÚY,)‰Ž+Çæw¬k¸¦<É{ÌB›âbØ‹fo˜­ýæZÔn+|êÿ`8 zhí6ŸîMk«ù´þ®ÿwk­½Ÿî Í#Ÿ0'ô>ò,ùÔÿ³Ñg>9F"h¸µ˜\{Ã'›м›ƒþßÛïXøN;|òýz ú;ŸX“âÔªæƒ(4¬ÏíÛ·JÌŸ_aχl¸<¤}çÁh„g…Vž÷Ž \RÃê™Àµ—™8h‘÷… Ì6ëyãsA3êXpuaMã}0@hc1À”w@ƒñ¢øBÉ@ð*Ûq×$ÜoÜV ƒòB.Ú-+†¬0ë¿êbâœsƒPÊ¥éõD…·Ûë“”‰æþ#4ªSœ`ѧP.=­Q÷Ó^”;¢,öúãÆU‰–-+þaÈaŠ‚‚LO¼?˜|³ç…ÆÆ“5š' ¹„§HšaG{ sOo0KìÃ/˜OÆìZ<„6ík®ýÃ\ØôÿK±˜ðB¾ßÌ%º½Û_žgÄÈÜã /ô¾»ÇÁæ‡{c¼SÕ‘N³! ës ªýúUØà™±¾¡eÏ–ç C‰;Úl²“ñ®ávžg 3ž ¼7\ŒJ‹³f)w»vÎÎ@qSŒ€ÁúÇøaÀ)…›- -|ð±â×ábC|ÂÈQGÅÿ>B'\úÁ¥-¿Ay"'í°§V§&2FÌúhiòÃ…_´o}áÝw/ÄÕF6ÄÙ#ˆz'ç.!–-Ëÿú_}¥ŠG‘"hžÙBß'ïõ'Ù2È÷û¯©üßdˆ‚R{Ö^„¡9/â¸ïù˜ý@62œPÄ z'#O\U|úcšÞxCeX5J•!ïÒEe×  íóx/»ŒÌ*;ŔȯL!›´Ü"ûeÓɽ}ç*O<åèã ¤;y¹)C?eŠÉHæà—;Þ D¡¿Lç2/’øÑÙ] W²±vøåõ'›ÊV[©w?ôõÃÒ"uÉN–¤_~qvæÀóÏ+ú#ï;ï'ï7ôÇü2Ã']÷‹/ª‚nÔ3 G}˜ÌkA@q%òÃïì0(kä¢Ý„Œv…+”7ЏJ¼cr%Í…,‡¯gh®Á‡ûÀ•Iô»ïµ÷‚b‹-T~|´ch7pUÈeË)ô}Ò×§h|0+R„‹…†þFA©=ë´-fhÀóúà•ŠlLäN'8_Ô™3•\š,[˜ÇÉqÎ;F, ±”b?üpåŠZâýÃ_—Œ©A#hÉx…f«cmÝzeÀ¬Öx ¸Ø¼ô’ê>¹ 2J¸cECóˆ Ïíc`,Œm,nd²àxÆo/Çã6b^<õ”²öhàþ»Š{ç¬[úÙ£‘F{ÎÚá§e&# ïšo´õ¸@Å hN×V OXb²¬/Z£OÒÞ×¹sÕš…öœûà7Ýb1BóMþy¬zX‚âVFèù˜*‹èÒ‹\Ò†ÈE\·ná$ÞL ü0UËhKÐ@  Dk–o©ãŸ~’rÐ U=Žªo~Ú—b€vI“JÉû6’²V-¥QIª?iDšó"ê5оr*¥Ï©ØÇ{ƒ Í\PY+Úk*ï š}úE•Ö®]UQ´Œ»ïÞ]Þu—´+ S‰¹ØïX˜ñcIC;Jêb=4ˆÐ.U+©8ÉüŰ4eCun? ýés/¸ Jrˆz4Iåe*›ò~Ož¬r±_q…²†U{Ï=WýÏûÄùTêõÂOÞë~R0 –ž uAȇÎx°Òéþ¿òŠzç¡ååËÕ>/ÜíœtRw»Æ Ú|jÄIãh𩛲ة/“’~÷ý`ú ¹h·ì4ìhºIEÚ£b"›†½Ô¶dÿýU² ‰À¿?Æ Z4œ‡fßF´hb´µÐÀÿí,ˆ¤iD»‰"÷ø'Øä€–îÓO•†‹¸´Uh¼xWÐÂRI-ÏßriÌ4ÂX!x3ù‡ÒO²^ ÁCÓL_Ð÷@nsR}’Ö«ïöe—jkÖÉA [±ß±\ãg]inâZ´8´±Ë.R”õêI¹õÖª"œ?ÂÒœ~×àÝ@ÓŒ¥† ¹T3D›ÅóéÕKÊÑ£9oÕʰa}XÃíÚ2€&™whÎкÏѳ§ò×^¸0=¾äù`ÉÕÿOTtË}¿ÿþàRƒÒ@ö;wÁ)›6•ríµ¥6,¿17°Ð›át4`ÚΕë5tÏüMóløüs'…F<[EiæžY³_@Ìt°(]x¡”Ç«b+2 ®ƒ¥)[;ܲ\i•ƒ;îPsP)Î/Ñ‘‹vËNîÚ¯\˜‡º dÓ°ÇÕF6º ïõÉüo*ÚO´Öh¨\I†´Þ~npn¯^Ê×_]ü“Ѫ¶n=ÏN¥ˆ¶•¼îh5‚­9Ùiȵۡƒ² ýÑißHu×±ã<[KZÈ<ñåð¬ã44RXTÐH£™¢ëXÀðËäù³á Í;DP¼;UZ1¯6Å^HËFI-GÆ*¢¢|â 5b°ÎÛ—<  ÒС Ä'ÚDH(è–ûÞµkp ©Aõ‡ª˜ 2”ðÎ`y&°Â0Ÿæ ·†]:"û t…&Ÿ,eÀïX Þk¬¼ø©Ó74â~Ç¢¥'¦‚õ€L.hÐÑ\§Dl së–¿"J´í+CJK,MÙæ'æ/Úc-¤’j¾w¬½ï¾«æ™R˜_ вdØ1¥aí Xæêl„«€l {\mdC¡ÛÈvý]wUÁ:ä‰erdÒeò%½L|&×JÓ“çfiƒ †Ù¦y˜o&b\p½aÃŒÉĉ •‰šëÃjׂ1Y Ǥª™r0‚„>ÿ|XÁ]ÊáYǘ]\Óp­€1gÁD ‚!ÆÔ›¤+î/¿ÑÞ9Ê£Sê›wW¯iÓÔÍ{ä5§0EÐL:©çÏ€ÀQh’àUƒl€.ô΀k#Ì$´‹ûAù0¥(q2¥vÅu E ®*¸ß @û‹ûkï4UX½`­a® (÷:ÖÝÖ t„p¡ýßÀq›ä¸ õ˜+XóP±Àš Ð,÷›~#%•¿ß àhÚS‰\æLÀô0åaÆÎ†å™¢KòÄ„ ʼ쇸ÚȆB·æú›N›&e¿~*5.¸À\½ þ$ÍA5Ú&[˜"9– >\]pÇéÝ[¹Tà®@ZM\k–²aCåúBZ.·›N9<PÈ6ÂÒœq\Dq‰™‹?‹ Íñ¾aÖf~à}ä=dŽÐiG_{M™ç〷ýB÷ÜwT»ê*)ï¹gn¬Apù¢Øã÷¢:·…þô¹=¶ú¹Ð#AÖ眣hfâDåÂÚ$u/îpC‡:_²`Ÿ}¤Üo?5·kÌ™3WÞr‹ÚG:Q?ΑëÓ§1cVHCûôµm[å–ÍÝš7N¹Œ‘ª2r=cR2âvvÖYê?и7ßììˆI¿û~0} †\´[Ö²UÊZuYd?ÔŠI}–MÃWÙPè6Â\&GÌhiЈäƒé@ЧŸVf@Šk õ8î¸ZÿhÔ9Ͻ¤D ä,^,ÄŽ;* ´¡˜+1ý䇦í .5hãÝZÜrx m”:°Bð`:×ïï_›6J‹ÇûˆÙš9Bk´²æ‹bXA˜Û‹¦½öRV.´‰=TxkR6$mªîíGE¦ŠÝ¼sX0¡™nÝ”ö™YXsømq&dÓ°»M8Úm,_¤p=öXõ>£…÷VÅ¥ +XÒŸ²®pmQ䈾±Þ°6`mÍänºBŠJŠzeÒÞ»‘ëS$ m;÷ % Õ],Œ{…[éN; qî¹ÎÎÆwÏô)&8Œ{*VSàÖÌ}ú© L)4yDIõ…{H˵å–R6h 4£ASþdFXšs#Žk€|5ìªQÈGTZn§„¤`AÎAÀ¹Xeâ@!­ vá}§¨ ZG¿ñÃÒ“ ¦ýäÚBÙÎ…ÿû_e1õ‚ÂJ¼“XQ3õ?ù¤z_svH÷ˆ& õf›a9]¾Š-9Ö[Ö‚4Ý©†Y°vcm¢p߯¿:?dÇc±E{ÿÞ{ÎÎÈçc!fìÐ,kc!U-Áöq#éwߦOÁ‹vËÞ[Š· TÐI!QÎiÓ´ø¨ØŠ%ÁPhÙ_~Y¥§#p)hÊ?ƒòÏž’çh°ð9¥hňfάek×ÙGsÄ©a/„ÿ]ÃÏ/E£(‡î7¾¤­0¦ýò´‚¡%÷ ¼$“9˜˜ ´Óø™¿òŠó£ƒ v@ìÚtâ`°”­³N-;ö‹*¾õíÛ«¢Eh­ÇŽ¢iS¥ý§}|׉ƒâ|’O¬·žsQà/Ïuy\ÏšùÈÆ°ÇÕF6ºbŒa“MêÙýhEÉÖï1Z˜3˜6´8Ûnëœ'Êá9€b´‘ c‘×ZtÒ¢;ã •šâ',zhø¢"N { ÅãeŒ(¨Y3çGƒ„éøÀSd ºeÝ…F™¿³ =kÓÏûþóÏŠ±…qÿúk•bñ½÷TJ8Š%‘¸sgµ&`qb^ÈUÜ M:í=‰Â`[måüP` x kA»Ž°€àï?ÂñYÜ_ƒL(K†ÝOóDP é¢Ü8s ÈÆ°ÇÕF6ºB]s'ûAQIõ;/;Úu,"’Ri`Ò n ÙPÏ£$ö -Œ9 ¹“Yï½Wi—1s–MÃÆ ו4Šæ—/ê@h+5r~ ˆ¤­0¦ýdÛ/òqk0î0Ø0¦¸¹ ®ò”»ƒ/I¹ óMšUPE•÷Ÿ P,f‹.^|‰ØxcÅô@ íìŠP‹ ×TFÎòʓ֔ VÒÌ’v1 ò}ÆŒ­nÝUL °%%2B  }BXaìa‘ÆwÏô)¤‚aÿÜâÚj×®-žÏ`Z´Èù' 0mé‚9Hݘ¿Àaã »‘Žƒ&I—†NPšCŠ·ð|æÏW~~hUÒèž`?X„Î`ÌÉ„ÿTܠЪÁ°²?Ÿ…0Vˆ8]b´ B†|Ôq}aì :?扤­0¦ýdÛ èÑëŽr¹ÄdŒ)Zv\Z`F™ûQÔ  ¶aàÑÀSÃá·„uë+k®`Ã\P?{¶rƒf-Á]Ò‹_~¢_?å^‰Œ ‡`žÏ3¦MxL<¢ögÇ¿½m[Å´cÀ5F>¤ñÝ3}Љ3ìŸ}ö™8ôÐC-¢²¨*X¸xƒ2ĆŸ¶»eK•ÖT‚qÃf2Z Ì—˜9ÑœR^á“ ÓŽvûhPþ@hÃïÍ 3ÚsR,Ru”‹h¡ÐÎá³a¬qºÄäÓ> da\žƒNöÞÛù1$’¶Â˜ö“m?*(¾s ƒ‰E3ïA]bü³O¥]ªS5•Ê»h—I³È>\Z(Ýl3E‹(Þpa˜?ÿÛ•·ªaãÓ®v}µ®£½g>!-$xüÓQþÀ3·p¸ôcU`<bË,ð(̸ëpoHX7Ù‡u!Òøî™>ŃÄviÍw[oàžÖ*ýí·ßÚß3Í+>ÍDs#ùçB6æ)Ó“x›Z ÈÖf\mdC¡Û{}ÌûL°:O/ ‚-u˜wòÕ‚´Ž!”KqƒÅFœ9’wÁZ—ÉgQ#ÎÄí óÌBW,ÄéÔˆ R/Ú}è¦Ý“$ \RÐöÂH“ë_W eË·l>bÜZ`˜ÑrS]”@T´áüsÍÀú®m¬j¸ÑÐs}€6²µ­5ó0íäf'¿9×Ã…ŽJ­I~\~Ð°ç ´î(4¨ºÌ½@P"Ó ó…¶F»]‹ ʉ1ìo¼ñ†èÕ«—èÞ½»%[âqˆˆ¦‹}6Í[6æ™Åð–[Ô$@𴾨èb@¶6ãj# ÝF¾×'­E!`È™dñ{$Bž‰‡Éد(EÚÆåÒFxî9•­Œº%—ÛŸ,Îh”a²•É/6Ã^Ì,1Ì_hÜÐ(ÂTp_òe„ ÖJ‚œÑ‚£àÚzkÅhßt“Š ÃJŠÖÜ èœX¦)¬¦+­æ’u`ÊuîÎ;«ãÉêD*VŠ¥ÑÏ>SL6íd*âä¼jñS'ý“O”€PŒ;ŽÎ°„ëY1À§ލB8þûXHÊ€@Òª• n3ðF¸ á›ï÷< ʉ1ìÛm·øè£¬—y¸µH[% ØÀLDš?¤ñLé²1Ï€æX$Iå4|¸Å½Ç€lmÞ‚„P`º ×ÿâ Å|  à9aBe²"ž‰?Ûä›–1DA¹´C`ò‚Ëÿ tñŠÂ°‡±BÐV\ {¶öaV`dš7W °Û¼’¶Â˜ö“m?n@³þ“© AFm/9Ña†ÉêÅ{M (ZebQ¦OW™Žpóbý&3 •®XÜÉò‚Å :>èXÐa@9í;® h™GŽ|wµ„nÀ èjÆø}ãnƒ†k.n=ÌAh¹p1¡ß|GË6ö,Û3f¾C¸A‰Ê¬{ÐC†úϸ ˆ÷áîW›6ïÚ.…ä¤'p? L|é¡i41†}cKdÜ*D>%^~& ¤L$u‚H)ªãfõ\¾¯õë+B4¨^,Á¢Q&†½Á …n#×õÉ…Kª*˜u&mü™ ™40ƒj·—lHz q \ÚˆhºÐ¢…]°¢0ìa¬q2ì~íãŠ&&íZ¿B!i+Œi?Ùöã«hÈ,PŒ6–nüÜ)J³ˆ ~çåhæùŽ ©aØI,€[ÜQG)¦Í7¹ÔÑÞ Ê9̬¥(ÀXG8ßôqãúÚšzmŽEX`ÝÆÕ†}0êø«s,kŒ4à`z ó @ 4òô7ˆ«I¦g _‚;Ñw¨ûQh`MÀ”ÇÌ+nØ×fØáƒp^à^3>,šµ£$à9f Œi¤‡R¤Ñ”;uþO Ï=÷œ8ðÀíÏÖ8¸9X`½UÍ,*®ªª²¤rK,÷Á‹/*išJ‡dW€ØÑ@„hxsÿ°ÛnCk™_•3/c"‚`ªx{˜ä˜œð$>€I‰ ¢Ai!ÍåB×T0dñ ÃØ.Y²$oÁ†9·;˜…¨ð¶cif#j@i„œ0í'×~úÓçŽUe1­6ój ÅžçQHî¾» ò$Œ|é^ Í…!ä=ÿñGåò¦p”hh·Z³UÅ•t*”³®}?aÒqµcÍ~á²Ç¨ R˜o†Š? X¿‚Z~Ö1˜væø²Õð‰¢ÀYà÷ŒÉp€–?)·Lï ƈ?…ùDшÝal5¸>éOž_Ø c7’¦G?¤±O¹h71 {>è`‰Ú,QݽµlÙÒb¶§Ù¥‹aÑŒí½÷L±çžìÌ­íîÓ§%¡s¾)pc¸N«VËlÉI_™ÒXRúªidx°ë5¡Œ5êŸ\žHÒLj+V¬°‡úÁ…É“'‹SI(îA×®]íq¸1sæLû^dDzeËœ= „‡FqàŸ3Ea›µÖêj JÓìÉ mÌz©ŒÃR~nçò½µ26mÚÔþÿœÎS‚(ö01sÌEÐí³ ÀG@iÙ_‚"é…È´ŸlûQÊO9VS 1§ï¿¿ª4 ÃîeÖyÏÑ,³“bFK8Ó VWÎÁ ˆÉ4–‰¶Y¿aîÝŒ"÷wK‚-uÊGkú´SA²‘–ÔhåaàÑ–#ðÓ‰r©%Y¿‰«ÂµpÆL_²É0ƒµÅ´Œë ZýsΩg»Õ¢0D€à^¡¸bêÆêŸ”+J¦wµyŸ}”» 5kú·­}lð@§œ¢ua왯8í<ãÕcƽ wW´ù¤åDƒÏ}BxÂbBö/4÷ÞûFz(E-y »,¸)A1ø½áŠ‘KÊ…‰ºÔ¢4¤iø)˜P´íA\8¼€‚нÐm…nÃ}}´LœHéø¥cþC«ÀD…Š9†B¡ÔÛÈ—æüÇ5fky¤ ÈD¿aõkßW¨Â`Å@úÓçrH•Xg ›ñb EÛMÕi´Ì¼Ëh_a–_]åU‡yÆ5W ˜:¿š 0ï0ÄdÁã\˜v˜{«I;ø”lpø¹Ã@# Z’˜R\`Ѧgs³c}‚Ç:€.áã›oÉyøâ㞃6žï¸ô°±îÓw”¹ÜY¨õ‚^}æ*\{°²Ã¬¿ƒ…ÁiçÚÜ+¬ îýzëÿ£Hpo3ÞçDŸÃº ‚ cf|Œ“g©?™«‰;àÎÍYê{Ï'cB£Ï8õ'côŽÛ½é1g»þ¤€Ÿîÿ yOâDNÚ…aO³gÏ–5jÔsæÌqö(Xæ‘ÛŸùàúë¥<óL)9DÊ .rÁ)ÿþÛùуþýû;ÿ)¼ô’”,åÅKùßÿ:;¢²ÒùÇo…@¡ÛÐ×_¸PÝŸòÛo¥<öX)‡ “ò¯¿ìŸ#¡Xc($J½°4熾Fݺu-š¨\ekÑ¢…œ:uªs¤ÂŒ3ìß¼èØ±·ìÖm¬óMksìÒ¥K= Ü“!C†8ß/^l»hÑ"gÂÈ‘#-ú¶Ü…åË—[ý­”sçÎuö(Lš4IvïÞÝù¶]ºtÉ8Žß—²_?)O=UÊ~²wïÞrìØâƒcã‡f iGÏž=íßôÖºukY§NÐ4Ì9švÛµ«”­ZUÊ=ö¨”Ûn[)kÖl!×_ªõ›”;í$-Z–r‡fÈ-¶¨”o½å\Àß=îÒ¥ÊZ;V¿Ç^Øß¢•!ö:Â-Ùai]s±¬U‹vÉã—rút)¿øBÊ›nŠvY§Ž8¢‹õ¬¦ÊgŸ•ròd)o½•vgÈF*åé§K»½#ŽPëyýú½e“&cíÿ?\íÛÿ*{®8ôÐ¥ö÷Š )·ÚŠ~÷—‘G%å1ÇHÙ¹3sØb¹å–»ÈÞwä‘ê:;í4ÒÛÅÖý•rŸ}¤lÖLÊÝw_.7Ø RÖ«7×¾ J¹ÝvRn¼ñ$¹îºÝåæ›K¹É&RÖ®-å†Jëyt‘k¯=ÕúMÊuÖ‘Öÿì›añR<+)×\så&DokÿXk“ÿlBð¬+­m©µñ]oý­mˆgßbkãØE®}l#­íbϾåÖÆ±s]ûØ&Y[wÏ>¶.Ö6Õ³o†µq ÷>¶ÞÖ6Ö³¯0ã8þøôÑnIhØo½µJvX…­½ÍU~`–B@ ZÌ6o½¥L[Ú× I.¸#–€cKõHçhÞ0 ùùì¹·†.M@S0t¨Š:¿ùfeþBËNmн”âÐŽÇq €¯*tHlD¾c…ˆƒ~ÑèáP·îP1qba--ÙP KO6˜ö“k? ýés-¦T4lXaûnã*†-&ûÐz£íÄõ‘5–4¾üe· ?% WŠL™ÂHÃH‰~Rÿ¢UåZ¤/ÄåòÞ{‡Zý¹ÔÖ”»Bqó`]æ­5©ƒÑs¾ÖÖÒgø´Ï|²¾ã³ÎƵXÛЖó‰vK½ÞpÍaà?õöÆCEÍš—Úgâ帮û:ÞÿÝ›n“öu?ôÿŠ]TÐÿk µF&­±”C­±^úÏï|²i‹w¿þÍýÍ Ý}¬ß9îߨ´¦ûûï‡Z<Ù¥ÿ< ·VœãõsÒZq}ïŸú7}Mþ§ ~ç“ï€ï\Ó}}ýûô÷©S‡Z|Ý¥ÿô™Íý?ŽxŸŠ‰\´›†ý ƒ³gÏöeØ/º¨Ê"– ÛìÆ ÍM…!'H‚m»íÔ$€y "…цxuÀ €8Hý„™Úº¬M|˜ù˜dø$È…kòâ¸Ñâ£Et;¦Ì6DÅS•‘IŒvu±•reØÉ¡{þùÊÇHs|üÌ!Ÿz¶à!ƒÒC̶¾F›6U¢eË {1cc¡×g`‚ÇÝ*H…@/ˆHÅ®<…~™E gà|èb̘üÛaÆ'Lûɵ…†3 Ó‰O:ó>.1d‰q3Þ¬ËlB¸Kr7½ãÚFÁ<­ø‚f¸>ԸȰþ¢{í5U#…àT˜&àw?9 Úãßi>qÇÐÌ6Ÿ0ÇôO3Æðš1ã¦No0{ðlôqÜsM}}6Ü]žzj€Å´‰šÁ§ Í Íœkfœ6é7×§Ú„‡ÀþB3¨œËµ8Ÿ}šÕn$ì£ÿ€ës}X¸p€%Ü ´wƒ¶fàØø_on×®¯ÛПlðVšÎIÓ£ÒØ§\´› †=2už—‰¢ÆŽOüȾya NaT0ἌHIl¼¤¼t¼èl×!FûbA$¼l¼œ¼À\ƒâb?çi¿-|º Àµˆ®Ö×g㟾¦ž(Øè#Ÿ^èßôÿ@›é?=.¸·Ü| ™Ð°3± ($˜BÞ«B Êb¯¡¯ñÒKUÖD_akàØÈJí¼cí"€ ºÊsÙ°äavæ±ä 8s3)ÅFöžK!kRô2ÿ£#Aïz&°^ÄH2ŽÅÒ v„ч!GÇÏœ¹€€F‚U5ƒ‰Bˆù‚l1!§ ¬€G žÁ»ÁüÃXÖu½~ÃhÍ:k8ùÜùŸ~ 1Á0·iF^&¿ø† •յƟö?||¾éçÀoÐ&ë<Ì:ûi_3æ\“Ì8zÃÿÞëƒÏƼÇúoP\ä¢Ý’dØsAkà pÑÄ‘°!ukB`[ºt™E$›Ú„Æï"„«¥h6˜r-!s·8bå“}lü1CtúÎJ¹Ì"¥VˆÊtgzZî6âípŸ˜,˜Hÿþ{™5æMíÉDOq#î1xQèëƒb´ñÑGËÄ–[¦(‹½F¶k@',ÆÏ>«¬]¼cd ª¡{Ñ0øh«YÀ‹0 ûܹhjTðu±2ÀdCÖçVe Ü6ƒˆ+  (#q[¹ì²•UJ³uë˜Õ ; TWè$g8Á¤0²~ éÙ]Ö&d.°VÑ̶ި¶ŠOÂk H#è” %ë8| 8”nðšõÞ€ëÐŒ6ó–”yX¸ÍdÕÙ~{5.f”]³f)ëŠ.´ô´Eû(µf› [ú‚Å Ë~úP¨õÖ }ÈE»eɰSñ Í;UÔ2†›ÅöŒ3:‰Æµ üàÐ$# C< yX‘‚q‹è`Ê!2&Žs9fý|Òå=Fu—âlƒÂhUȶƒÛcïÑ£“xýõGíÉ©P(ô}*µç …l#Êb¯‘Ï5 Ct6èF€Š‰¤ÓiÜ`Ú‹ë¶Z÷Õù’,¼ƒ©ì¤7cá70H¢Ð°>·ví*ë³Âžÿµ8L4 0¾åš)Õ~âÚšŒÂ ËB9Úy˜R\Fpoƒ)†ÎQBim4ôÐΦ}ÄÉe>¾Ê¸B»Ú¦[g"á|7X“a Y¯ùt3½|GëO| î|Â|ŽgÇ2Žñ‘)æïŒ‹>Ñ× Ç2H\ ÷>ƒ ?{²ÞÀ#p ÆÅýÁÝa¥÷Œõ“z‘Ü7/rÑnY2ìhï˜0¼)¥!|ò‹²(CTh 5Z Ž9¦bÍ€I§œ>LþêøïaÌfÂÏ´à3ްÌOPÄÑ“÷ W"´†LÀ˜0aJN=uhÑ"ýcȆRy¹PÈ6¸vØÅ^#Ê5XðÈŒ?,B1 ¡'| SVØ€`$Ÿs†E›|Ìݺ©Íù¶7LûÕ·ý(ô§Ï8±J¼ýv…÷Õ¨‘r[A}Ç„åU3«0æÖpmM´Å]¦T[”Ù°|ãBB’m¹…!Ö̾ö•†ñ%I9Îi¦ÿÏ?—‰úõ7µÝ=poå|/`úY·a¸õƚϱ0Î(´—Ü|$X÷è+Úl4èú; k!BcÔ…ÜV>Öeb56µ™Æо½²2þ¤ô»ïÓ§`ÈI»0ìi…Õi„‰¼ÓSÍ›'åàÁÎ d‘"ÍZûöRŽ­ÒCe«¯JÙ¡ƒ”gœ!åsÏå—®Ð'{OÉ€lD¨Æ~ùE¥·"åU¦”˜凰4çF×à›=[Êí·—ò°ÃTZ·|ÞC¿TZÙðÛo*Ei.®];)?úÈÙ‘ù¶7LûÕ·ý(ôç>zûê+µf’‘´‚uêHyÐA*eá•WJ9eŠ”ï¿l$áu×IÙ·ovZ¾÷^•’ù³ÏœÜ÷óÿ“òÍ7-^u•¢ÛŽUÊÄK.‘ò®»¤|å)úIÏçSO©þêÔŒôáßÿ–²G5¶æÍ]³ö³q=®ËqJÙ¤‰”=$åë¯KyÍ5êØm¶©”“&©ôÆiBÒï¾LŸ‚!í–%Ã>¾”W_½’Q‡É¹š äN† O:IÊeËœy"…Ï?'ëÉ'«ûÓ`F˜”=iñ ªÂÒœq\Àtê$å?ª…žüÿ,Òþéù¶ýÝwŠ2áçŸÕâÎñÇÎÎ,ˆ:ö¨0íWßöi;,ýés[µª²™Vj  üzøa)Ï>[Ê­·–ò„Â1©z}¼å)Ï:+3ß¿” åÇ«*'B{Uòè£#MžsÖ« 诔¿þêœè€Ú>J~wÅXä÷î­j³pÝ-·”v.ù]vQùÖ¯½V ¯½&å÷ß;q0k–”ûí'åE)!â¼ó”"ïÿþ/ùw,ÒØ/Ó§`Ðô—©oeɰs8D¦õ\š9¤u] ( ð!äR÷MZu´O<¡&¦Å‹Õ aiÎ8®¡á‚—/§8zgï¼SiÚâÂ矫ÝXÚ¶U µAÚ…þ²{ÇR¶i£ÖTÖê"…µ@'åå—«ÿ†¡±»ïVí½÷¦XÖ¯¸BÊûîSŒûŠêx/˜Ð~wëFñ!ň7mJ#U”h·Ý¤ÜqGÅ`-@8Ï´òhØ)ˆ„Ð’¯µÝÀ rÑnÙÅ/X R¬áF°$éã²edéÒeœø÷¿Uq¥cuv†Á7ªx1Žä´F>m,\¨RmáÇÿä“*»A5W]¥|xÙr#mcƒr(Fiñ#%âÅ/õ°ÃÇ˼ñ)Å ¬²ÔGÑ5ƒê üÌñ'7:þìø‡wíª‚Iƒ€s‰ 3Fù¨³æ¶l©|Õ\ù¯“¸zSø™ßwŸ×\#Ä '¨82üÊ j…þ/¾X¦XJ0'±VøÏ³ŸðøªãûNàê¨@SÚ8ë,•1àÈ¿;ýÁ'ž•оÉÖb4Êæ$*›´SÇ qÛmŠáÌ•:‘ÊmŸ|²À&h²½DE&†@‚B#HD¾Ÿ}¶ÊþÏG¤;?Í0±DF¿ö´Œ! Êa  m¤¼³,ª,Àd® ¿³Îú0ì,Ð,ÔÚ‘Ñàól‹¼Au ;ë,ôGÀ(yÒYOHÈ€ò|I *ɨˆ ƒ|øáJADulè&› n—Bs0ðT@¥hYÚœ þ$"×8ýt!=TˆfÍTJHr»Ê'ওj’TÎÖœ€Póóž@YE`;ý¤°™dyDˆ{îYuN00HeÁ°30!Àp"•³Èú1ÎnP¸ñW_½5'c™ö[‘ Œlm‹<ÑD÷£¡¬®RG4hIו I!”Ã@1Ú(°˜ò^£UãÝEF6 ¯ëqþí·«lI|RÝ7Ìü´Ä´_½Û/`Øan±n‘Z±ªJ¥^EÃMF§6mT¦¥aÄxÿ}•e…<ìT2E¸FKcÍ1¬ÕdRéß_iØQš]~¹G©2”ÁÃôc †)ÿñÇq¶p0{¶b¨ÑΓ½…ñ¬id©A…ua H#‰ra€þRÄ Z§àÐs!­Ï8ý2}Š%ϰOœ¨&˜Pò7Cphˆuñ?¼÷ž7Ü rÇŬƒL {RÐŒú1Ç(- ©,ý侯´ h6 J¤‰C›F‘3R«Rp)_+vLöh ™;аm·óc$m1íWïöãL9ZðT ;ïT´…&Í9Œ8@Ž« ýС(”ëÅ‘Èo®×X„a,W¤mźËuЄSˆÍ;´Î9¸£q.2¸À4o¾À¶ª! À¸cýÂÍ…~ÑúCÎõ €Ö©@û¤ˆDÀ@G¾t~¤Ž ‚´>ã4öËô)&8¾ì©D6|²ºµN´¸7Гl'¤ò'}ù¥³#FIþÞ{ΗñÍ7*òÀ iÓVº%‹{¤r40p#WÐKÄq |3/‘Y‚`5‚Ú‚ú Ømç¥|ûmg§A‰" ýés÷ß¿ÊÎCV$‚AI•L’‚=öpô) Y[ÉêÈÒöØc*õ"4IZÈsÎQ×yç•%†ôÁ•n±…Jü0dˆÊ-j°Vª~‡NÃÒ(<Aëd@##ÙeÈ&×¥‹ê»AÒÈE»%©aÇ\†&í ƒ”„í-z„Ú2/ð¿CJGª×.!q"I ;Ú‹çžSþ¼Ýb~D£ŽùQk8è&Jü§LQæGƒrR(Ђ‰WoED/( Ö¹³ò»Eë‡ßÀ º÷´ÍTóÅ-Œêžh°ñQ÷û—.U®$¸–P@·²O>Qk5Zz‚Dµf›Âhø¬³^a fMÆ¥ŸsÜe [Ê9º¤(®*hðó¥Qúvÿý*Hí9ס2*Zz,ËüG ›A¡Qr ;L)„Ÿ‰á$š[û²ºqÉ%Ê×Õ]@Š2ïq!Ãg^0!2Ùm¾y'ûÞ À0929¹Ý}( Ÿ?Œ<þùø*ä4 ÝF9Œ£Rô+‹< >¦}/`\©XJ† ˜|b üË‹^Wq+™3Gˆk¯Uë0Sëʾû*—>ùÎÿ”å‡)G8&¹Ág(Å…wLÜ`ˆ£býÂe×”r¸®Þr‹ úFð«nš ô‘s¿üRùÑ#P ÿ{„õ8Ýb ‰’aØ™(X`)Œ)Rx>@¢g’@Ý8›%&dbØãlƒû@yh4íÚ)fý÷žmGÚSJÙwÞQ>ì0ì?¬þƒ8Ç …n£ÆŠÑFZÀžKKž ø¿¢ƒI@°Õxã !:tPißRÛi'57xÓ:(òÚkª¤?ŠŸnÝ„xé%•î 5Ì/¾àXt±lákÎ~ÁaèŒa¸ï½W)”Pœi_qÖ´gžQL=‰HIÐ(´Ô/Ý Ò?¢½ÿÏ”5™~iáœ4­d”3ônPj( † 0r«Â #µ³Ðæ&"Ïar½8”ñ˜‰aÒ}‡Ù ¨¶G¥9G3ÁDI Ú˜Ã[µ ÒláÃ…#yjÃ"Îû” …n£ÆŠÑFZ@æ˜é|¡­hú`Œ›9Sˆ~ý=²9EçV¦8S¸%m1íWïö£â»ïTŠÄsÏUk™WpyÁ E'Œ0´ÔªÕªi€úI1å¤Y%í#Á£¬Ù0Í[o½ª‹<îdi!8õÅ#O(®3^×› ÷“õ­?ký£|Rc€¾á6ÒúŒÓØ/Ó§xP ;ùVIÝÔ·op󌮒þ†—Öƒßy?†=(èóW_©¨xl²ÞÀŒ£¹`R¤ˆþw#FѺµ¿‰æžI f Ytâš  а »Û Õ 38ô#áõYÕiãBÒVÓ~õn?*°fÃ|3 Cdva=bÓB®…“`Èq?#FŒu œŒ^W3Ò4Âé¡S,àÖîõ¹Ÿdªa½¤è¾ð¬—X6p«‰;ZZŸqûeúaØgZÙ¼ys±Þz뉆 Šȱ˜¤Äý# XˆÑB£)(4‚2a^Ä,‹ A4øôáCËFP(~|ùæbF˜ ³å–%§<~€L|˜Ñ‚PEÎÀ ”–a×Vq4„¡ãC‹–F‹¸5ìI[ALûÕ»ý¨ ú7J\Oµ’ v­ùfÃ5×yâDX§Ð¼c†5¥¾ã¬gœGá>Ö(´Ý(à`ÔY×4`øÑì{5ìÙî'“ðƒG{NjH¬Ñ¸ºQ‰}¤}-ÒúŒÓØ/Ó§xPt†ýå—_¶ÓÃEãÆÅÔ©S-‚ï&úöík1®çš^¿ì Г ²Ì:Ì´¦õL\0ä’E;N0 “>‘ò­[O³#Ò±ÀàKGŽZ E0Éa²G  ‹KàîÂïäKÏåÂB»˜aH®»nš­•G{HO܈zŸ‚ Ðm”Ã@1ÚH Â2ìXš`ŠÑ2`¥Bxg´æmŸVƒì@›S cŒŒ{Ì1Å(„äkdzF±^±Ì³Fí½·s€Ð;Œ>î2A€Ð@õSÖ^6´ù0ü´†o00H3jÛÑù¿(h׮Ũþ,^"bÅA¿~ý,w´øæ›o¬Eu¥C‰í›5k&† « TØÚi¿ iÜûI$RS¡ÁfÁkløÕéÏ;ïl)N<ñ%[GÚG6þ‡Çwžï€ëº@À>üî`®‰lG AT:YX˜Àø<bþü•ãs˜¤Ðd ™À¬ˆ°mÛ–«ÜӸѲea¯ ÝF9Œ² MsU–äYáN§”⸆Ú8¥ƒjÉðE³†Ù_VJ½€¶ÑìÁÄ·m«öa%‹T”bIi@úóžËIöLdm!áÅ”êÕsNÈ`4ÝǬ§çŸ¯YϹ€ @Œ–;PÜ Ör á*‹Á:O|×;8”(rÑnQ5ì¿[+åœ9sÄQ¤mpákEþÅâDçQîÌ%“‹-L4 7 3þt0Éðù£Â8ã3 QS B&“ ùa‘ì‘à tAë½ýö›Ù&<"ȉnÇ¥ŸqÜQ˜\`ŽÑ  wozÒ²hï`.˜˜ƒ‰ÿÈæbpA G@'ž„6ât‰ÉÕ~¡aÚ¯ÞíGÅøñÊÅ„aC†âÉíÃî…Ç CÍPS´5šs°4£Xâÿ à8t(ÅP¢¡ü:A¶¯:‰HûøöÛŠÈg}Ži}Æiì—éS<(*Ãþaç6„Kva'ŒW™¸ƒKàL1ÃŽù/ðÑ[°@1 ¤œDð`bBÀX¸pe::4˜ö1ÕP” 21ì²áÒB¼´ƒPÛÒdÄ Á4ý‘±‚lqjØ“¶‚˜ö«wûQ6­81R¤HÄÓaë-!ºwWL= :L6 2/#ËÌ·Xö_xAe¦ GA‡M.wr¼ï¾ûf¶5eÅ”Òo’ÖgœÆ~™>Ń¢2ìgϬáÍ0ë…Nãè ;~ï˜a´ïßÇ+¦ n-lD࣠ä–0A GÔ<é§8K@¾ùæ Ê n†8R¾‘ú !«V'4naöS?«0• ÊhÕÇŒQô†‹ UC¡A¶çŸWí[oâŠ+Ôºåucqe–ks´÷¸³ uÇ‚ŒkåÎ; qÓM* ë7V3\YIà€ÿ[™¸µ¸ÜÙ£ðÊ+¯È5jÈ9sæ8{,FaÂlf3[‘7h/,¬ÉƾŸQÁ”°ÿþRÞ¿”üáì €ÊÊJç¿d`Ú7í'…(ô§Ï½çž*9k–”S§Jy÷ÝRÞt“”HyðÁRví*e§NŒQÊÃWÛñÇKyþùR&å}÷IùÜsR~ø¡”¿ÿî\8Oì¹§”mÛJùòËê{ÒÏÓiì0÷*ÒØ§\´[ô´Žt°wñ"µˆ\zé¥âÎ;ï´¤ó/WIë¸lÙ21cÆ Q¿~}±n¡TÓÿÚüôÓOíô«X½Â –±\(†¥#Lû¦ý¤Úb%Ó´{ôÑ­uwÛWœXÂÌØpÓÄ}ŒÏB|R)—'¼-ñçé‡4ö ˜{ iìSNÚµÙö"âÙgŸ•k¬±†<öØc¥u³ä•W^i¿þúë# JÆ2f6³%¿…±’Ú5›Ù’ß2ÑnÑ5ì€ü— ï½÷žØf›mDŸ>}Ä”500(y˘Arˆb%3´k`rÑn" »A05­£3gÎÍ›7ë­·žhذ¡¸Ä¯90yòd±ë®»ŠZµj‰Æ‹{ %O>ÿüsQ»vmñ<ù®r Mc@^»ýöÛÅ{ìaçÃoÔ¨‘¸ð íʳٶçÀ8†.vØa»OM›6“È5–i}ŸÀÑG-4hà|ËŒ4ÁÀÀÀÀÀÀ  aO/½ô’ü׿þ%O>ùd9cÆŒ|Ù‡ â±:zè!û‹¡”³/{õêeg—¹Ÿ bÉ’%r—]v±ûæÍtãEÚÆ0xð`;sÏå—_.ŸyæyÛm·ÉM6ÙDrÈ!Ϋ#ÏáŠ+®k­µ–:t¨'qÑEÙ}²˜YçˆÕ‘Ö÷ L˜0Áî‹Å°;{ü‘æ1ăÄöC=T¶hÑÂù¦pé¥—Ê 7ÜÐNÿè‡wÜQwÜqÎ7…®]»ÊvØÁùV\üý÷ßrüøñ6ƒË£”‹aOÓþúë/Y»vmyöÙg;{¦L™båµ×^sö¬Š´=‡åË—Ëõ×__öíÛ×٣ЦMÙ²eKçÛê:®_L|ñÅrã7–Ûn»mN†=‰g€½×^{ÉZµjÙýó¦iõäI“dãÆåºë®k ·÷ÜsóKéâ³Ï>“m´QNšå2~æ¼Ñ£GËÝwßݦ¹† Ê .¸@þüóÏÎþ(§ñ“ aûí··ÇÒ¤Iyy s Æ†®‹‰|è­K…DØ÷²˜8ꨣdýúõoÉÞ%ü{ã9& ”Øð,ë­·ž¬[·®<å”Sä·ß~ëüªÃþ¿ÿýO®½öÚ¶6ÔW_}Õ¾yO?ý´³g%>ùäû7˜I7xà{ÿ‡$}-2^ýu¹Î:ëØÚ\2ÞÐl“IÚÆðã?ÊóÎ;O¾øâ‹Î…… Úý¡_^¤ñ9 x¼õÖ[ò믿vö(`%¨¨¨p¾­Š|ÆÁõ‹‰Ã;Lüñ²{÷îY'¸$žE9YÆ¢ ”­jQP.¹°(7KžùÒu1‘½ah Ðó^A-Æ…Æüùóí~ @SÿGo™”“ÅíÃKvêÔÉæï¾ûn¹å–[Ê}÷Ý×9B!†ýwÞ±oÚTª2¸ðý÷ßÛûo½õVgÏJh†&Ù ØûüqgOñ@ц‚Ù³gÛýÈ6™¤q ~¸úê«íþ¼ýöÛΞ•(…1À¸3©2¹;ÖÙ»*Ò:Ž;ï¼Sn±Åò»ï¾³%ìl {c(ËX”ºU- ÊÅ"…¶ä%‰0t] „¡·B", aßËb!‹q¡ÁúŠ`úG>UøŠ€úÈÙSxã7D¯^½D÷îÝÅ„ œ½™QNãç[B¤8ᄜ= ;QgÞÂÇlºQN㧨ßK/½då»a16mø¡Æ†®‹…|é­ÐC…F˜÷²˜8ýôÓEûöíí¢™ÏéìM .´‹ùqoÒ‚ï¾ûΦ¿Þ½{;{ Gx‚í¶ÛÎÙ“P–KjvþóÇk¬Þ­0ç¤ iUî ,2ÅŒ?ÞÙ»*Ò>†}öÙÇÎÔ3jÔ({¡a<~HÛ8˜Èzôèa î…³F–r‚Å‹Ñü!vÜqGgÂöÛoo¾ÿþûö§Tn™Î¡C)É&‹ŒDëÈS]Nãßh£ÄM7Ý$Z¶léìQ ® S‘å4~èi·ÝvuëÖµ¿óÍ7¶rã™gžYm±Õ(…ñ‡¡ëb!_z+4ÂÐ@¡æ½,ÆŽ+^ýuqË-·$άö5×\ÓÎs¾þúë‹M6ÙDœuÖYâ×_uŽ(>Þ|óM{-'ï: Fp(Ý µRN#xSj þÝ0ç¤ iÔ)SÄÁl̀бø!íÏô ”Ö¦×Í7ßl3ïsçÎu~]‰´ãÖ[oo½õ–1b„øóÏ?í Ží¯¿þòìŠ=†0ý´[dòE9ZÕ¢ Ô-raQÊ–]~øáöo‰0ìhp‘r0 º¡¿c²ðB›œò9'mHëx90ñí·ß~6ƒ«%u?¤q Tç»÷Þ{ÿyñ5öÜsOû󫯾²?ÝÈg\¿Ðxøá‡ív˜l×Zk-{Ã̤‡ùnРAΑ+QìgF£Ÿv‹L¡QÎã/‹\X”ª%ÏÕF£  AßËBæ7_‹q1üòË/ÛnV(öp#=z´}¯f̘áU\`Ý{íµ—3fŒhÛ¶­8óÌ3í~ñ~=ýôÓöï JÄçªuëÖ6“âß)>´÷Þ{;{Vó\ƒ ă>èìQàLyõêÕsö¤iÃwÜ!úöí+ºvíjKœZ«’ iÊ+lÇqãÆ9{fΜiRÊ‹|ÆÁõ žÃk¯½öÏ6þ|[º†ç{Ïž=#W¢ØÏ"ŒF¿ØV€´¡\Ç_.¹°(UKžÊõAi ˜ú^a,Æ…Â|§W‘…vàš’4ÏåÕ¦ã¶pãùÖK¤²$wyì±ÇÚÙ.t)r‰k²°SÈ-]ºÔþHuC$vïÞ½å“O>)Ï:ë,û»_úÁbÃ/KLÚÇðÕW_Ù9[-¦OZ¦ÝW÷F¿Kå9œvÚiöXȰ#µ:«ÂâÅ‹=¥‡ ™¡ÊqüÌÑÌÕtýNfC9º#º772)e cò¢Æ†®“@z+ò¡B#Ì{Yh¡†¶3mtŽ,¾üòK9fÌ;E¨ì§OwÝu—³§¸ íßrË-Ξ'ûGåìQOb ­ã{ìaçdoÔ¨‘¼ñÆ_V§·ÀÄwÜa§Ã‚Ûu×]åĉ_’ý…€Ý“IÚÇ0nÜ8»ô›O÷Æ>ú]*Ï4M×^{­B÷‰¾iá”ÚûÈÃŽ0¥‘†1~Ê›*Œtbo¼qÆôo!]ºt‘;í´“ó­4¡ŸG.¢œÆûí·Ûc¦NÀÿýßÿ9{³£\ÆsÍØIëÆ 7Ü`ï_´h‘³gU”ÂøÃÐu±”Þ 04PH„}/ ‰÷Þ{OVUUý³‘î²²²RnµÕVöw˜äbCß'rÖ»1bÄ[`E¸N ¬óÞ´Ž¤¤¦¿ÔÅÑH”a700(-”›e, üˆr9Yä¢-y ]§i`؃Ð@Èõ^¦¹êŠ=zô° L]sÍ5ö}¢æ >*Õ& ]\ ÁžÂI7ß|³Ü`ƒ lztÃ0ìy¡œ,cQÀX™dKɪåd‘ ‹r´äid£ë4ÀÞŠ 4r½—i€×bœ~ÿýw›YǺ-rŸ† æüš,{ì1¹÷Þ{ÛýÚzë­m ÏÕüqÜÙ R“¯ÉÀÀÀÀÀÀÀÀÀ Å0 »AŠavƒÃ0ì)†aØ R ð¤†a7000000000H1 Ãn;}ôQqÊ)§8ß ¢ÀN2ˆmÚ´k¬±†xöÙg=aa4ì‘ JÆBf`Pš0´[Þ0vƒXvýùçŸw¾ ñÜsω֭[;ß Òc!30(MÚ-o »A¬=z´ØsÏ=EEE…xùå—íÿ J Fc`Pš0´[¾0vƒØa¤|ƒÒ„±”& í–?Œ†ÝÀÀÀÀÀ†±”& í–? Ãn`````c—]vl°Øpà ÅÞ{ïmÿo``~Ú-†ÝÀÀÀÀÀÀÀÀÀ Å0 »AìXsÍ5Mà‹AL0 »AìØxãÅûï¿/fÏž-~üñGg¯A†Ý vœ}öÙâ_ÿú—èСƒxê©§œ½¥c!30(MÚ-o†Ý v^êÓO?¿ýö›8î¸ãœ½¥c!30(MÚ-o†ÝÀÀÀÀà ™AiÂÐnyÃN2000000000H1Œ†ÝÀÀÀÀÀÀÀÀÀ µâÿ,’” qG‘#IEND®B`‚pyclustering-0.10.1.2/docs/img/sync_som_image_segmentation.png000066400000000000000000001272631375753423500244750ustar00rootroot00000000000000‰PNG  IHDRǃøBÐ|sRGB®ÎégAMA± üa pHYsÂÂ(J€®HIDATx^í½ eW].þízú=·Ì–žLB%T‘€" "`A}"Š"ˆÁçûßú|>}O¬DŸ(*6,ˆ@¤* ’žI™>·ßÓÏ>»ý¿o»ïœ¹së´L’óÍì{ÎÙuíµö^ßú~ë·~Ëš››K¿üå/#ìܹ®ë⑆µô¹R.+÷Õ:apýjë¶ŠÕ®µ²ë b+×¶, iš¢ÓíâðáÃ8ï¼óð´§= ù|~i±¸¸•c»ÝÆùçŸN”ãÇE ©Á“‰ü˜#ØÊf=É«:Lg+ìWöø@rßVh!â>"|¶̱ڮëg—ÏÒe¶q?UOü0ŠQ¿}ÞÚ¶<•!ob‘ç×~E.Re72¿ë¡ÃÅ"’Dy¬NióØ¥S»w]”`–!á…î¼ývüÒO¼_÷Ô+ðŽwþ‰y©ÖÂÝwß7¿ùÍFAqîáꫯ6äxñÅ›Jõ©O}êÒ–¡þcYn¹åüõ_ÿµ!Ç!Ψá*eñðøÝßý]üÀüßó¥—wè}Ík^cú‘UùnÛ¶miËçd=Uzçwâ/þâ/2ºRSùô"´´t{\"tƒ½K!$ƒDd-ƒßÖi_›À6€!vr" N„76d-bÎ1R†1YηcŒú1ªÜîó$:Þ£²-ZÓ¨;·YžÛ26[yÍbœ¬:ªŠs"ÇS-cˆs +ËÄ£øFJ/ä¶_ú‹úÊtÃÔ, ˆ? ‰èc.% Êœ`‹ûµ91·ñ·vÕþ2Á#@™gµ I¿.®—aŽê/F½òëÀÒ?‡öby3ížÔl_©ù$%‡ÌÓ§cGeè1ûkúß”B‹‰‘éSçÔQô{5dIÒ1 Nçí0ãš” 7Åh.BÞOàR5¦6`‘ sLW…R¶Ä}ü42D¹-—Tûä'¢ÕçòÂ?Êqˆá3pîAer*årªÇqf°²\ 9ê§M5å9ÉE}„f5«Ëôå‰8c~Ä¢4‹ŠÐrI2§R"‘ ¥EŠ)M¹>á)d6Eü§3"´ù‡ÿuÞˆ+²UÇ/Üiáÿåep™1bŸpᔹ˜WÍÕú䜡Oô]Ç‹´›9§ÙŸ¤Ø Çë:K{ æ»Öël:ŽûêXýóx‚œcóú¶1‹::P#Âe¾ª_Ô'V½y*I*X©Ö²C’剔âìÞþbˆ!†â,Cu²*bUê"rŒa2U̦‚Ö6.ªøûÄIÔBr“‰ˆP;¦Z¸ŸY¸NjHÕ»!-úµô]šKN2Z×?cÑUEº"Æþ}’1„Å šEûòÇ%GÂQߣÈG¿ulÿÀìoƒßÅ€¦… rãþÏ]°b”©E´y£@y‡\¯ë²ãQúnSÊ¡Çç=nð¹.Ï} vl̺æ.x^}¦Ì˜¾Ò6tjL¬ž®ÃkHkK‰+'e^ÖùyZ³(ú×Ò±\†bˆ!†8«Põk`F“bÅͯ.kkŸ_r$<}æX‹çY{çH"² b1 ÉœÀp€>M¯ïúä—lw7ëDýíý!Ktk¾«¯P¤#ÏÏɨO>ZúD”çIŠZÔ·Çßýëš?k"“̲+ËëVfã˜Ì¥ûÍóe’ÛˆÝï7y•HbE®/¹ÜÆß_}‰ |jg)lŸL¨üYT}Š¢{)ÑþÐ}ºlȃ5àÒŽ`–žúG¹´Ø2¨…Ú‰ÌÒKäËEw¡OCŽÌôúbˆ!†â¬Aõ°*e)‘žÇŠ?O9¦¥è;(è;׉ú¤Àí\ <@$â‘L…®…¹*vC†\D´Zo>ùE*Ì3ä'Ré/RÙw‘¯°ÌÏQ¨òU~¯RŽä-Ts6F|’•Gcº|²¸%[ç1Ê^ÄQ²©?5ào‹D&Åiœ{Húú#Ñi8ÆIqÄKÌ2šSbßÑÇô•’à’«Tk¦tE¼ Ï)Ï^]£9$G.$ÉVl“¹˜Oy¶ZXÔvªK™ˆ¥|M#BŸJòŽ×‘RÞˆø‡bˆ!†8½`U܇'ªƒû2ŒußÙÆ ÓXZ—uVZ}YcvµeZ¤ì‘CŒTœOT© útI66)Ìþö˜ÄJbóI¼d%\LP\Zô]d,Ó¥¹ ÙÂæ“]›ç‘i·?tdóÈîÁ(ǤO`\Û_/RÌι´ŸÎž©[câå/¥E¦T9¸ÊÇæ"7Öå|1çÒ¾ê‰ä_)SžC— I!õ¨{©cún—nÈ¢e¹1¡ßýö—¥übˆ!†âì`™a48]•¼TXéWÊZwâBÙ”PþˆøxcfAò3ϥȥÌßE²ˆ–’>IˆÚ–7d*sì’:ZZÔ×iú;ùÝ\ºÿg€ 2 ~ß< ¹rÑ:ŽKõ둈¸LDvzÞš¹¿Œää+"–ƒ‘ ´xË2ÅJá––ˆ=ÏO²Ïá}é8C‡†D-£nG܈÷ñ¾ú—p›šü0$hˆKꈠ•ÌO-ÚfŽP) 1ÄC q6‘Õ¿†’úΤÎÔof¢ãˆ1`ÈQ»-­–žË*y-ÿ¨‚Yª’—§¦ˆ"#>ãẠ‚[oŸ>AŸ˜¶¤+‚öCjF…Š•ˆþ9Í×å}šäJ™K –?=õuòfdb–’t–"ÿ˜Cõ…‹Né»1rVhú)usOK¥Ý–¾š}µÆå~E;2&å-8F_Éqˆ!†â,Cu¶*x×(%)§cÕ±b%úÄ¡j»_å¯ m\6Æ ñ­G~Ù6ÓÏÇE¿õ¹4dC‡ô ¿Œ¾Ç±Ž[ÚÆûÑð+»ms.´oœ‘dòa® ¬Á±œ"Q)Ì NLc˜hØ  <Æ,úÎSHMê·Ç«j¾ _š2 G«1?[ÉS÷´¹¼bˆ!†âôà9JMùž19ö—~£°¬¢–>9¬O`[…Ε‘œ9ÐdÄ7]y,æÒölÑ1+÷çŠþ6®Vø»(J… —¾ƒŽ!I-ÚÎýõI.Ëij4×ccÀ(ÌÁ<8ňUð„8bzD¸±…^h£•øèÙ"G9þÄ}G$.>" ÊS¶ìq;/A:DÈsõƒ èjC 1ÄCœm,“ãZIddµ’ˆ„•$q*dBÖ§¶k›ˆ1Òu––>iÊÄÜO“HSXí~û×™*Ä^l3¬ƒ„*RÕbkÂGJBÔ¢Àè’b<~}õÉò7¿\—Ÿê í/æþ–®3ÄC 1ÄÙÁ†ä˜‘!‘bP¥©7ÁÐÙï•KFNÙï•X&#î3­_í¥!;FŸÙoŸkŸE°$.*2I2yÙê !·Eü4çåÿþ9ú¤”]S¼NZÏ{áùƒ^ˆ@×¢âSP„P ¿Ë‘‡¼¸ô™å•ÍË«¯ÈI-ÚÌ‹¥üPßlÁW_fv½þ1ƒWbˆ!†âÌc]r . ðÏàbV.mÌ0[´]Ÿ™ü¾|üŽ' c¤”c=h¿Áý³cŒ’ã"2ÓXFy¬º®m ÓÐl#L8IHéá÷¥4,ŸGÛ´n ‚~õï…‹1Ë’hIŠaj›ðxÚ®E™¬~F3„k<žK=ÆIIéå:µ IG5¹tusìC 1ÄgÇ‘ã I­>‰â‰bô½(áÒV®O ‚7¤Dµó·È©OR"’Œ ûÇgD™A§>OÔœß3Â$½AdÛ‰qå:þáw 9q )‰ÍøE™;IfRiò^•÷©NŸ0mRœä* ƒì_Wûg”§kp»úEdZgÈ•ûcû×ñá‡kòÔ§r°1AÈ”&ÿ1•LÂ’ 7ç×¢¯ýÏ!†bˆ!Î>–Éq-bÌÈH‹¬¿_Ÿø£OŽ\:$Èv/2Ó^‰ C …ä®"BC~$ñŸ–>Íw¥YŽw¢ÉH-[2¢Ëcp_!ÛOȶ žãÉŠ°øD(â3SpIµÙ Ê…ïº$H·žGç2 kuxßF!šô÷Óm~‹Ð¤Hɤ"\/oT=ÈÏÓ¾R=FTŒòTeþéVø§Ÿ›ú},½ýô÷ïaå½1ÄC qæ±LŽªˆ )¬@¶^•´!£òHêSëïÁïT€Rˆf{æ@C¥höã%Ôw&BZ"þ1GÃÚ°| ¡t È ²ýúûˆ,²ŽˆLw&&W˜mæœüªáò"ÙëžD|†Ð¹¹o&í/枸ôç´Ôl%V¿¿ÒìËkS)*€Íûö“N‘/¹èbº®Òdò¡O¬YZ3dé×uDÜj4¬Ügˆ!†bˆ³ƒYf ªÀ—¬¢V]-HD’ÕMG½e¶Ë!E¤¨ÀÞ2·jÎE‘‰ö10@„Ú߬‰.]CK¶mpÉí“¥+C¶_[FÔYºûfSþॗ IQ3oHÍyVÏÓãú1sWò#õò¾tO:ÞÕ õ•¨kJ…R:¼{GêS¸ ¯ jEÞ?óÊÜŸè+VÁxË*-ü§ûPz#åWò{dŽⱃìùbˆ!X&ÇŒp‰Ç¨Àh©²Vȸþž$…„$`8@4Éß$þ3ýxªt¼*~‘‘ΣEÇ‘<—UU„êþþÀy)3’†̘jEºÊñ01 Ü_ý€ÚÁ|pÿ º´!E“f݃V*}G—þ±J“l¾J—efÉ=7ËDl&zæqR„Šî£ÙHúQp¤Xå@Ã{4WÚy=þÖ Ý—¶§ê³äqêŸäf."X̓)«1Œ Àõ¼¶Åï.ÉÕ÷\ä|Ï Ý0yÔ/ÊuŽçRVª~4›M>_ljñ¹bˆ!Î}¬ª ©©ò— Q*Š•¹HCªªñ;k÷€ '$™h?‰2™õâ‹ E ªT§‹¤B’«ú%{"ž¯¥ø»Ë!#ž›ªIä¤óõz<·‰OÇ›¡½÷Ðeº¬d¤Låà£4Hqõ—>)Š|t-õƒ¶‚šÝZÝM2a«— IiXïDhvzh ø•$¦´“™~y–ò 9åÀÓŸ#²Ÿ'ZÔÏØÂ<"銺D…ýþFþÐÙLãŸúML˜?¼u/’uùM¦_‹÷“âà‘Ã8tä ÏFÀ³vâ¾ôÕpó-ÿ…Åú<×ç¾CœËP¿ö›Þô&üÂ/ü~þç~yÑo-×^{-.½ôRó\ëâÑ Ïó†eø8À29b["¸¬ukL‘¶"åð“¼úÞälÓ&û´I0rÀéÉdÊÓ˜C¸Ý/õCHYb%§9ì𸮈‘‹™6ŠŸ"Fy´%FRë’ µt‚䯥ðZ$G’a‹•‹Oçê‘\å%Ûå:íP1JñER„Jg7@½ Ö ±ØŽPëÆXìö?E”J“EE¬þAÏË{ˆÏïê"$¹õçhì¿ú”¢ÖùÕç¨psj8$q}zžÃs8Tšrì¡"ä’ÏÙ(ùý)À<žTñXÛ¼~—y’È<ø >û…࿾øa|äÆà_nøþí³ÿŠ}ö}øü-ÿ†Z}vHŽç(žüä'ã¥/})¾íÛ¾Íßu×]‡ßþí߯ÛÞö¶åE¿µüÔOý.¿ür£‡ë£ŸûÜçðÙÏ~®ëšúrˆÇ.Ž•îàûJ¢ë«À¾ge6¿cΑ²"rƒ“™Iú—ÇòbH¥OƱEJ‹„%¥'R Íw-}âì›!-I„Ú%7;T{T|~×D{Ü.ÅÙáÒ I¤Z/B%Ñtx®66ûq»Q•\'ó©Ò's¨ôš†lä<—ÄåB”B”cŽM¢”™ØÜ3—”ŠWjTÇ*?ô©lÒýØV?’MŽ‹”¦”C£ÝÄÃT€g‘”èR±.6º˜^¨ãÐô8zßçñÕ{¿Œ#3ûÑiupÿ=_Žw7ßö \ÿ¹ãº÷½ òwïÁ½Ó÷¢‰•)3£ßVâ,¡R©à’K.Ùpùßù|èC2ËýÑE±ºÝ®y/†8û‚D«ÕZZs<Ž=Š………¥_ëãƒü þýßÿÝ”õÛ8®t³­ÈÎ@ì(I¨Õ\˜¼à{(Q¼þ¤ÇÚE”Ñ'Ǿ—e?Vip}æCž2fP‘ŸÌ¢2‘vø©ß2‘Ö;=ÌÔ;Xh‡FYµ¤îHŽ2‡¶©ò¤ThI±Ê<qÑ6’'¿·ƒˆDÊ}º ÷Óq=cZé*nlÞwP¦Š«}L”ò+ô‰Ñ&¹‰À’hGÄÍt¦–G¡ì“\ÕÙ7íš…u›É õ‹&R"ÛØD»Ñ{rã­ŸÄ»þö—ñ7þ=|ò–â‹÷Þ‚|æ?ñû|àŸÞ…¿þÀïჟ?þã¦wâνŸÅìì,s5¤ÁŽÎ6qèðtfëhíà¡ûÚxèp‹÷õ|†8c PãFP#è'~â'ð©O}Ê,Ÿüä'OX²mßò-ßbŽUE©Ïõ`¼—Þ¯!Î.î¿ÿ~¼æ5¯Á¿øES"ËÁ†Ê/þâ/âÿïÿ^¯·´fm¼ùÍoÆÞð³¯Î5ÄcËäØ"ѯ ŒBZz‘õ)SW˜Yð½èKûšßüοRVË‹£È’ß#’мW#C–üÍE¦Å.IH} —<‘B—Ä$e¨E¤ÅŸTŽRšR‡TŠÈ±OŒ}“-’¢Òªy‹yåB¥U#·I)ö_(Í2•öÕ¬Ô«æqÔ§îES™PEö2-Û¬Ë<ï‘…‡ñ/Ÿü[\çp´ÑÆáéîßw/îÚn¸õó¸þ³‡ÏßüÜø¥ÅÞ½·Ã騛MÜ|÷©oÂ]·ß‚»î¸G[‡•IÖ£»PIKHjºµ6‰ v—5U6DfbóøŽïø£ÞùÎw¢Z­óçÿøÿcYªŸpå’mÛˆ‡87 Õ~ï½÷šzêïÿþïñ’—¼Äôg8|ø°Qþ"ÉïþáðÏÿüϦA”5¨†xd ò\Ï£mÇxjë &é;¢ìŸÚ‡= ~ãþ#}©>Õw(¥·ÔWŠÜú}„Fj?,ÌÈÏx~Š ’Í'ÉmiÑoQ'Rò{‹¤'¢4ß¹]‹úçºdÇ`ɱG„ªë):Rif¼à—bÞÆhÑÅx)‡Ñr#T‰%ªEE¤ÑËŠX#Å'ç™e•~KçàýçXÑi‘©¸ÇûUú”^‡ç§pǃ·ã“7þ+þý“ïÇ?}ü/ðþ/þõÓÿŒîïð·{;>øÙ?ÀûoAžª³à†˜÷<ôYÔš_B-¼G‚Pë8tpŠiw±Ðiâ‹wÞ‚{=Œ|e Û+àÒê$®Þ=ŠoxÂn¼ô)OÄןª~ÎÜïFÐC JàIOz~ë·~ ?û³?‹ÑÑÑ¥­C|ó7órÿßàò+¿ò+Ë}†ð`Èq×®]KG ñh†ÌÝÿïÿý?lÛ¶Í(½ÿûÿ/fff°sçN¼ë]ïÂÏüÌÏàÿûÿþ?|Ã7|~õWO|â7l`žwÞyؽ{÷)W¼Cœ –IV–'[N¶N Ðý߇{¼ÇÈ KPÜѾ×)–ú©*u yi'’—!;C”ê÷Ó6©;#ÓWŒ">’ˆ“’äwUöZo¶i—¾ì÷!¶D”$/™Låd£a!Æ´ÈóêÃá§Ï4U *yÕ‚±JÛG+Ø51‚I~)5¯¢úH5ž±?–²ï¨ÓﯔçmŸÄ•…åBåbÞâ|³cìá©£¸ùk7ãã7ÿ+>tã_áHŠ÷áwã½ÿðNÜúµ¯"çåÑX<€/rû~ñqðÐ=ðøxN›¤[o/’Ô›80÷nzðFìŸÙ\°#CtÐn,Âëv0ÎtL²ž¼c;^ü¤+ñâ'^…矷O.ïDÉö©º·FŽ¿ôK¿„ŸþéŸ6/ðã z–E‚O}êS—Öôñ‚¼¿ök¿¶ì9:¸|Ý×}ÙGÇþèþ(Î?ÿ|ó{ˆsGŽÁßüÍߘ¾ÄÿüÏÿÄüÇ,méCN3Zn½õVüÓ?ý~ø‡]t‘éO¾ð ÑétLcHNSÏ|æ3ñ?ÿçÿÄýØmØ(óìüÈå84•?²Ð;›•×>ðÜtÓMæ{†ŒOr·äIlÔk5<|ð>³‹‡°Ø8J‹`»9£Ò4Ø?Ö x£ EnRýO©:9Éȹ†Ï‹!BV׬œùE&I^Dd×ãoC žóœç P(˜ão¿ýv³èûzËm·Ý†¯|å+Ø»w¯)£¡iõô#kp¬ÖðPƒ_å055eÄÀ 7Ü€øÃøó?ÿsSî!fÇê÷É’¤uÛ­·¥×^ûFÜ|×ñŠz¾þ9WRuU±}äB<媗`ÇÎËI€=^Ì™¼¨ˆFŸR•â¿„$ªïêÁ9pGVÎðLõFr]hµ0Ïud¤jœzŒ]_‰g¥¯X¦%'AÁsŒ:Ô`ûqëí·âÈ¡ƒ¨VJر}'.ºärø¼¶¼[#n—Ó§Cõk¢Õð"M‘¾KeÙj5ñçÿò—øÚ}·b¬P6Ñ~ EëåF4 Ë‹áÙyóÆBžçé´B7F>Çô¤šè0.Óffpó. %Û*øMcò^Ø °#æ—o†x¾œm\å"ïCŸži(¤V¿ÿsjß>õ¾»ðý/ýQüÞ¾ &wWÃwÞiZµj¿ûÝïÆøø8jlðèaúßø S!ˆ8U©œ T ¼â¯0}5ºŽúpÎÞþö·ãÕ¯~µù¾oß>|×w}:d~o„R©dT‚Ô£*FAÏÏzùv¶077gÆA*ßT"îµ ´«ßS•úŸþéŸâ…/|¡©TëyÄ>^ ŠOù)Suè™Ö:=ó2›J%~á _0¸ú¡Â÷~ï÷Ëž#mÙË^†ßýÝß5~à~À¨Ï!ƒµÊ ^¯›ó«|D¼›©€ï¾ûnóîÈlÿgögرcÇÒ–!2(Ÿµ¨a¨ºk%¹É™êµ¯}­yd%{ë[ßjÞ ÕZ§²Ñ" ÁFV€•˜ŸŸ7Îx*§¿ø‹¿ ÃÈ …nÂÁ¿Š;ïúnûÚ'ñ©Ï¾_¹óSfE ™÷\VìL4U^?žj?TœHQ"TâY·# J|èð>4: ,Ök<ßMØÿЗ`‘d‹®‡2 f¼èbgÉÇ;Gr¯ä16BeH2)QrTX9­KÅâ‘TùÝrÌTO>‰Ó'¡úL³(¥1[Ãý÷ïÅC÷afas¬\,ªF—ÛE .ÿÉ,ÌU¤!¥Ýá9„<ƶ@n»ó«»óðœ6fppáa.R Å(E×ÄÕ*?Ë“¼Þ¶ñ¶.WÖa. ­4WäG".]Œ^á«]œw%w¹ˆ¸½g¬‡Ü(åÈ“K$ʉÒZvˆ:zXÛXè-¢Í / ‘6ÑN:KÍC–*=0ª,Ôߢ~µ²¥ NÖ‰ä;¿ó;ÍÐ…'<á æüg “““&ÍZDô›m™—ËeSQ=ûÙÏ6÷˜ã\ Æ“^îýû÷ãÿüŸÿc*õÿõ¿þ—iô £DHòñÉ.“¨úŽ¿ÿû¿ß£ ÒTcIy§††HP•«TæÿïÿÝX´NêS¤¹Þ"Ïòl‘I7²Rbó$ÕĨºMħ.#˜™r¤Ó¢ñûßÿ~ãA. Ê9;f½e%¯gÝúÕ[Ó{ñÐy/ûþ=ˆüihXCÉŸ„ŸóQ-]„ãOA±\0 +æ.Â;ŸM›4Ÿ†gäóE3à] 'Åâü >q㩞¨¼uÜ~ûç±{r;¾çÛ®Åå<Å‚b>‡ ÓáÃáèâƒ82w€ÝC¡0ÆTmÇ$+µn8KrBØ£r¥òrH$ÆOÈô%ŠðrF…ÎÏ´pÇ=ûLzvŸ7ŽçbÇØ8Ó"…HkH1EDE§òåñva`~¡KU;‡NÐ@·×F+h!ä1 Ya½"ª'ú‰Sc(5öQêXŠ9”- Xyª jdX̃~lT‹é#‘ŒBä*‰ÙÇQú¹]1^µÅ}¤¾-¦QÃOÔ?ºp¨Oÿå½xå·¾¿÷ößÙ”r”YR•èöíÛ—¶ƒÙæ¥B=ê—ù×ýW£Tþå_þÅÔø’F 9½k²¨¬u/ƒXK9ê~7süc•»åÓg>óóN >÷ûØÇŒÉU~¯|å+ _mtÎÁ|—rT£I£õU’ãÞp-ÚÑ~|÷kž «Xc]Qµ ¬ì.UO@b,–àøRs»qáöga¬¼íîŒ9©›a ¿À+Qõ•/¢jóðñÿz/ö¸ SMtHW?åjüÐw\‹g?ùëÑëu©ð¦Ðj/bÿÔ]¸í[°wÿ]Ñä¾Q*S-·ñœJ»ètöáE|âoîÀ÷½üõ›vÈ9ä(ÈD«Jb³}‚wl•5îN}) : xžrÑË«€Rèzô[çRYÈDªX¯2¿Š´4¾Of׌ ¥³²RãF„:¸.ƒ*95zEœêÇÓ~R¡ºžö•“—úÝôè·>ñ‰O˜cµn­JR•ÿc%èú©£:*'uèyP^«"VŸ~6.Yå£~N5Bäi®ß2_kß .¸`™Hµ¬$B­Û(-Y¬U^›9>»NvŽŽy4`%9šœÕPE˜™jÄà~ê>€©Þ!ªÄ:s¢‡ùéf÷‡p $¥í¹ p~ñi˜¿ç]¾ƒ…ÈÊ¿ÛÈ[ÄH!Oz‰P²clË¥˜(&+„ÜÖ‚O‘äF>Û=ˆ^rµÅ½˜ž¿µæQÓ)Šê¦]Ôƒæçê˜;\C}®°ÃB$9:$› /aŠ;3ã…¨¥ÇB’JÔì=l‡$Üë‘(’M˜ 4ƒ÷¸?É“T„¤3*='eEOb7äFòäJ•N® â:ªgG‘u4~RÁÅù‚9n‘GG>)Pëæà’ô¥DõØâäñ®¶XdžJSZ%ò²™’ˆåȤ­©Cb´õÝaÃ3Ìu¬”ä¹UÀCbk05¸n¾ZJQi¡“ۇ¶Cؾk»·ÕqÁxˆ+/,àOqpÙe5\01‹±ò!äGïÆî]wàIOáâÉ..([ØQîG£)RiímbW¾ŸYtl+Y¸ ã2ׯ.*ªI7Ä…:&‹-”ýãýðÁYÜJs¶“8w[G°ËÇ„×À(—q¯‹¢=Ë}fÚ0Õ9‚& ×rfH&3$œY’Ë,Ie·/$iÕ0b/b<×DÎ=ŠRŽ×ô=lsóðÝ%ÝN*Ý«œ},‡íIXiœgæä±ð5£g$O‘‰Uª–ûhhÛM¼n‚ÀüS?&i–ühˆGÚÁ‰6ôTIŽü†Å¸Å¥I%‘2mªìšZâ.Q€zÔ%±w©ÐI²Ì«s‘‡8³È*$9#É;ïÊ+¯4˃>húÕ²=pà€1—Ê]Á³E r€‘j”Ã̘++¶ ” T•±úåà ¾B)‘¤ú enÕòå/Ù÷[ÞòCÄgª’”5ä½ï}¯IÓjÊÁlêW#CÊo%t/g²Ò—‡¬Ô¸îKå&“·ì8Á( j’Jp‚jvÔA%!I– Užw„*²š_ Ùv™Þém%*?[õr$Ì ÆxO¾»Èûì’Xºƒ&³À›,S5–]—ê4q¦¹êY%É8$^žGK‘÷¶Í+aÏužC‚V/#ôD>‡]…vr©ææOÌk3]LóhޤNµ=Æ{®pßy'C3«¢~! ñ¸…Ô‚ñd ¾+ ‚ßÌpðþág ÅÕ±ê÷TLÑA V2 Æ-ÏÕÕ*yÌêxçd¡ÊS,2á®)e)éÍà›¾é›Ì˜8AªWqˆÿë¿þË„ɃTžØ°•Št+ÐI‘£<ŒEŽjxº®”£ò]ÝQéÒød9¾ÉD®õRð‚úÈä0µ‘C” ®ú<åý,ÿ5rD|Z/ ¥¾ëÞE.ƒN]ƒå@ÞíYƒíd Ô½‹ˆW"k¸è· ©r5¦²{Äz ‚•X"G [˜q/ Êq+Žñ$e©/)wqùX»*]ìe^ÈãÒ WŸ×Ãd©mÎO–#\4J¢¥2«L’\ÐD.î¤,ÄTŒ]*ªÅÀB="Ù–I6ªÒd³TNóq ‹1ê-ϱ¥HbôŠ(æJ(ù¾Q¦y—H2 ÒÓ̵"|õpŠ{™w³66ë˜ s—CÈêèÚÓX ²mX³iXÎ>ÖÃØ51‡Ém³¨–fxÎUß":1UrBò¥ò+•áäÚ@ê嵎 —Γ»Ëƒê ˜÷·jr•å.'íy;òELº9LZ?Œ—ŒçІ/%QŽùTÓv ãyçå*¸ 7NÂ÷y¾€ê–Dêz˜¹7çcÒç±T´®Û…¢å°×/¦!†8 ¨OR­t…<Û,þøÿؘJU‘ʬ'3ßÉ@„&ªŠy«ØHÝÈ1&óÎÝ,¤Â44e%W¤pÕ8š;SÐ=©ÒWw”sÎÉ@Ž#rÄ’y{#ìÙ³Ç8É* og©+™Þ#f æ·¬ ÊYVƒú>Õǽ±mj¤(웜Œ„Á²Îò&k¬©ž/Y0… TcIýïª& ‹ÔºÈv+é•û‡±Ú•e*JhÔ"©‘pܰ‡ñUY®‡N”à¢r —ïè ïØÈ%$‡bæ(É ØÛLððb*±ƒVǧBóp¸náæ}EÜh‡æs¨5ó¸ëP·ªàöi7? Üþp¤YÄlXÄ|»B¥:ŽÁ(ö.Äxh&Â<Ïq´iãÎÔË8²h°5ÙN„6BoœXEdWÑ"ÉaCfvÞÆ ‹½ þ–:½ H•&bå½6ºfdêÒ&µYo¡5…^4n¼+ùS úT™þ vU*=’> ÐGɘnÓ¤‰„*1²¤ðBø$@ß‹XmÌçf1eÍ`!™B”e“„Ó6š‰8í¡ÈüQ>2É&xz™?-!gmã5&Xy*J3ò’M”3Ó‚âÑõ Ê{t%¤*T¡­æ¤!¥"åñ—ù—Kkú‘Tηd’•‚È>O§r¼ŽYï8Û”ém-E,ß•y%S¡Ž±êþ3‡%õýÉħŠVózùr: <NÅ!HÇêþ6ã§kh¼²ú§åh%•¬ï«aΠó®ö< rÊR^žŒE +W¥iµ´«1·•DRŠê —S“ 4«|u¬,òàV°5ò2Ý 4ÌŽ'IÑ <,6Š:1|§‹c6.ÉQÚ¨SÉ%‘O"ÐÄÄmÔ©òžÎá¡ZÎx„ζÊp{Êmª¬&Õ\Œƒ|m__¹_Í#ì?ãð\ûö03kc¦“ÃщÅî H¨"ÃvÒæuj˜aÆn˜î¤˜n“è­Ä!z°l¢vá3¶—SCØO©.àj^{7Õ–o)n)IPêSqJIrõ D=qy¦¡æ’´=qDòLв+<ÛÊÈ£…8Ðn¡ÁÖ…Ã4Íwò¼öµK¸s6ÀC‹T£í)Ì@#L“àQyîå õ0ªÑQT­y’ßîž›Â×B«6‹nc^¸€UrÚ:ŠÎ"ª….¬<Œ=ùû¨Î§àxs$f²y2ÍÖ áõ[­ÂH&_STC ÑŸRfÄ•ÁäÕZù©µ¼ªˆe쳓3ŠÎ#µôh…T*xEZ f¢ |°–³‹*ȧ?ýéf ¾úú9¿h½*fUÜy­†õ{³8YB„ús¥þ²™e6Eç!êù‘bÛ ±®5 dz^‹<׃î}½ûW?ºÈW¦ÛÍ@EŒZé°¥rzãßh ªleJÎÂÊm¶ÊYó"zù£åUVŠHcïó6ÚTE3-ª³žc¢æÜ5SÆCS9<Ðtq뢅C‹™iÃQSêñ–Ïã|™Qùp]}i /:ð´ Ú¸|ÂÂù»Ûxú•]\´­j1Å»Ê)vÐF;K ì(Íb6˜Ãt«y’Ûláh'ÀB7DÒ‹P`AŽTЦµ¢þºÝùã¼Vµàb´’ Ìïrœ)c Œ»$–6[‚ÙØƒ¢á,tcÔ¨T;TóqH…ÉVJÈïÍ9;ÆNžË Chj®¤¾H5À.ä0C‚žïlI²£î"v—§I†mDS zÌ‹‘bµ¥û¾.ëeæ'Ÿ»2¢ÂÃÕÛôêÇs*Y æ=2ml©­/dgY ÔÃ9ØùìdY˜‡f1CI†‚P•œoD ƒø‡V&(™å=ªÈ4kA“* ™ÆdfËÖ ~> ™ÂˆÉt–A•µæéTÿÌŽ2'¯Ffê“R_ãÊ>-™‘5ÆSÇ­è醆ÎÈéf%þíßþÍx$¯vM‘œfQeÉTý–ƒÑŒmC’ÌÜú\ RøõWµô«oMQ_²†r“™”§žeÍL$/oõ?Ê*°˜ZWþ†3?ß@Ì>Duu¤™cì«K}Y°=’TÑ-b‘z'òmTüÄxSvI2ó¼ø‘†‡f//×DäÎbçϼÒÅóŸâ9{쨶ñ”+\°½IuJ‚¬‘¡öLóNDòh;è6«èux×Ñ…3|~©þf›5g‹ä[G1·€v¯^;ÅT3‡ý½æ˨¿.ÏY,z&BNÁöIª•^—Ä&’•Bµ ž<ÅI Øúœ¢Â› j°I¾U‡ä˜&ì\Ùj jÏ£Ïc;Z¸´šbrÔÅÎjΘBmŒ´òHáa!eÂw1Yðq~%‡Ëw–°‹ŸòôíåBÓxþ¨÷uØêez‚’.2îÖp±„|±Lö"*Ö,¢Tä¨"CíøxÃZ$¥><ŵ•Gê`«_•º¢çhÚ%© ð_r†Pe¼ <š %¨àòÈÔЙÕäå+5½RŠP^úÒ—š1£™—­¤Hå¿ý·ÿfÂõiè„öYVJ;ú±žºÜ*䨢aê+ËLŠ‚ÈQN4g*od•ójP@‹H4?™­Ë¶?Z ]5ðô™AÊO}ê?TÃn-G ™ÒWsÄÑ”uê? Ù·:v°LImý? M`_8¦80 ’R‘*‹Ò {«?“ÆX‰JÌI2&©üvmóѱBì_´Ñl婘rh¶cLEóh§<4ßÁ׎ĘëQ]Ùœ±ñðA‹êIaÞ:hµÐdbÆÜf6Z,ÀKòsF0Y.’ m4jò4õ±¡‡fg±wfnŠ È96ÆËòµ({$À Ðdî6•ã|¯…ùzˆ8Ej¤¬Ô^XbåïS±åpçQwÍ6б[¸ç+þù"¶mìöz$¥”J+ƨFÍó:^9ÄÈX —î¶Q¥˜õ™ªUm´¨Ö@‘dæ Ñ*`¡=NÕYF×ÉQÓiÜ![ÒvŠíE » !É)"‰]¿…0m GuÙlM çÙè$]Þ‡ÆRå’Ð&ÇÆyfI‡ªŽéÉû)ÓÎFÏÛF;.©`ÏU.•fSÓT¸uªÝN„}- Ó! 6ç‘NmnôH°Tœy¦:‰Ñ¦"n´IàAó¦Fb¬å],x 8Ô­c1ᙟÑö¶FqTÜžöøy,ä&©\©zy×§ïâÑõ§©’Vkw­P€zÑ·4#4…3Ó )£ ƒ„¥~9.è|'ÓW$È\«Ê7sÄÐ53’y$Õ‰†ÈÉD³1He B*RŠAïºÒª1£rPÊf{ÑwU ¶ ~©LuË<+¢•£ÓÎ;ͧ”©¼x…“í¯[ R­ J0¼_$ 3¯ÊQÞ£Ù0” "hõ'K-­lœèw¶nå¶•P´[VBeúH–«Ì§jªR}äë—•ê–c• ­!.êsÖ3¡ç>[¯òÑfÈÆTf$šÁDÈá݃â‰UB›ÄÓ¶\ìžlã©Ûk˜ÌÍãUÛ­{+8BWëäQñ&¨&«8?XáBä ¾X9Ö¬„T”*M©09hÈd§ÿ™òé(oäí¨øÄ0/HÁ©‘"¥¬ãWy|2cï6‘òÊr‘’Qß©òX¦Dô aiˆÂOþäOÇœS‚Ë‹HVb­ü>[Pã@y¯éÑÔ¨SCg-üøÿ¸ñHôœ+v­ÆŠjŽG™ÏEŒjÐ(@À ‡³ò\ý˜jx 6ŒrÔÍS¡× áÇÒK6æÛ6-zØ;›Ã¡fˆ$ׂEâjw¨|Zê|pzQŠ‘Ê(öPååËzaãi„ J\vH!Âþƒ\à7ñÒ'Ù³-`ªÕÁW´qÛ¡µní^ó mDU’¤—X¨Q¶ý.»4=†°ÊF© €¯<*¡…b ?vâÛŸ>Н'‘î.µPÉTxrT©lŠÓØ GD#.ÕmˆÉ’…ËwäqåŽ.œ(š¸§Ïù´ËzxÒÅLó¢[¦ŽªO’nla»ìÎwQÊ•0Ï—ªËĈ7B¥"H|°»$²½Ï¥¸¤ØˆI¦‘Å…¦v¸m:BcÁ§j-Á·Ùˆsp½ Õen‹Š”J´G"Ÿ˜Ã³®hb”dòúC<¾ ŠR-Zß4³eÐ3­Ê\-ê Z'?UjmgYV ïFõÛÈia5¥±èxÅý̼þ>ò‘,Os&‡‘Læ=)âV¿ÞJÏÚ­@ã uÍL1dÄ ÂSe®Êo#¨!¡9/er“ùLN<”2½e½ï¹çžåüÖ}J)ª¢ý»¿û;³MX¯‚>U¨ÏX¼>3ÈÃTêG*]$,å­¶©2E{2PüÖÌ;TÊ[÷>˜Ogƒ„?Í]ªq ϺŸüä' ÑÉÔ,u­Æd¶Ÿ,*2GëñiÉòM]z^Q •»ú¬¬"{®…c¶¦+LŸf=ƒÓ1î§B›içÑH|t‘@„0Jp¸ãà"+ù6 ‘´; ŽpewpÕX…4‡1²±¦Ÿšâ~rš¹¸*ðÆIZ»K]´#j%ª¢".­æ±{Œ‰±btÚæƒ{k-ÜÇ…¼Òø¦ÃR¿FÒ‹Q(æá¨{šB+µQÈk¬^/6CB¬XŠ««Ð…[ì _â:ßá½ÄhF–™ÄŠÛL7 4­‚grŽöú‘|FЬP¸Ïù“yGº˜ #L7‹T¥-œWžC±œbrW {v*Ó£`侇C̃ÛÆføÉo7!Éiè IqÿLJeí`ºã`_#Z‹$ȆF‘×¼Ðk!á=7Xp]îÛâ~ó$þ£ ŠBÄ|ö;>î°ZE1‘›*ì•QcôòËi! §¦ß:—•>Õ¯¢ãV#ÜÍ@Þ°PžTÔ™£)©7Ó%¤j4ƒÇfûæTa‰ÉTçÒ9W:`ÈéFfЬoMê@ªP‘|¤ MËR Š¿*Ôx7MÖ½D8ê_”ÂT^j؇¨‘©æŒ N'”¯2«޳T~«?RQˆ§+S›ßùß1 68Yk€ üÉT"¥!3Ë«Y •§ ''9- d—£ÑJ/\=Ï2f×Z²Èk[È•ž­z†^ýêWs¸B êùȺÔ¯~LYgÔðÈL©² v7³ª^ò ‰ÄEÃfml9È;]ý6É«…™…Ï–1×"¡PᤩGUT Lá0¦©”:H"­»˜ë¹Ø7ážCKèSQæq°UÁçoç÷À%IÆ\ ØUC¹DrñC” ¶OV©Bs$èm›­f~öx­ÙÅë"‰]Ävl”V@‚žE5·‹é ÿ|À—û˜¡ m ²ÃØ‚ï1YÑ`_ ´u°Í áY^´Pï.ð†˜ëj «øøý6nz Â%cl™2ÛsEÄVˆCÝwÍäpï¼GÒm2ÍÎ/‡xòä4.¬¦ÈYU’ I¯¢ÕBµlãyT¼—o0ÁçÕ+åÐakº­r‰ª‘÷Ûá9ËNãe¦aa–LZÆøxM¶pÑ+.ÞçÃÓÌ6@†N9ClrbÈ\ùõn‹嬓 ’>¨%¯Êxµþ6E QßN¦zDBj±o¦¢Dtês“i8SŠŠþ¢ âR3Ç–ÍI©¾A9Ïd*s'g#Uxr<Œš#r‰(_© }ËL”ƒPE)U¥CælU¾‚Lz ®~È, §Ó!'ƒªt }BêU ›Á±ª2Jí)VNaå=mÊ?… BQ\fеåì’5P”÷Ùü¡›œ_VzE+Íj¬d }j‘– ÌÌ›jÌ(:“¼U+X!ÿ2ÈÌ­FƒÂíýÜÏýÜòÄëÂjy urÔÒ5d:—5AÊRÍjðˆP[®võ¬k(Bèiº% š³¨ä,LÏö03Û%ÃK¥EèF]l+˜¬†ðK)ž~¡‹+wæpYÅÆâ‚‹›¢‚#ad‹k¦ÅóTŠèð!ºydWçy´“1*Ç<š-̇lRé-Ô-¿Ud¶½<‚±±2<M’í,‰,ˆjp]7A±(»üt½²‡Ø¥"µóUd›$J‰ŽQt›„滸¯1-Þ¼ÿÚ›b:òqÙ…šq#ÄBÒ&Áu°­ t[x`*Â]‡'pûLdâÂ^D¼bGÕ|SÝQ,Ö|Ìn"è-bÛy=X¹E›ÛíÛÊ9äJEÔâ".¿¢€‰QA—i¶R£ *µGuÚŽìÜÖÃØ6à¦Y S 圃ã>ž0â»xÊùl<°ñ¦áC !hL›Z™ÓÈJ¨‚Q¿™* ™¥:²}Uùe¡ºÖ‚Ž1­’M^ƒ2E †;]BTÅ«þ Á1œ‚ÔŒœ^ò’—˜R·Q#Qï™Â³.nc7Óku[$l•ŠCr‹p÷ŒO*â¶Ù<É?G…kãfæ× ‹=*çÙ&>uo‚ÛvÑl…$T ‡BÌ÷¨°kTÃÜïæCTÔ÷W঴Òw€{pËl·N—°j8à³dÆÛ ñ¸Åà‹žÏôh„*lU:2{IiÉ—õUi¨‚Zå²V²È33ãéSª!«<2dizì—9PÿªîOQ€2Sm™ßä4¢J\û蕟ZþJ—î_Ÿ+ÍuƒPÀm™d³ yª|eÚUÞ)v¨î[×Qc ‹¶¢4§Ó[Uù*¢X RorJÁdûʨ´éÞ3SïZØ(_¤ø3å¹" ]'{ôŒ¬Õ8[ êÿ“%CNEÙ¸Ò왓iX™lÖžò73­+]z5ÜFϽLïtÿƒd¦>×µœŠD‚zþ•j$fÇ) 2ýë½24M÷c“ñ`r!’v#\%kä…ˆINš€7ùÐÛ˜u°½ä !!všEXÌìšBÔ!á¥1ªŸjŒrÑC °â‘TH¶]–[š/ ‘¯RÁÙ˜kq{ÁG~4‚ÅÆ[¨I€ý2PpؚΩÁuMÌ,ΠÞê¡ Ç‹J³ÍsÅT†¾ §œOIt¨$;šVIä"å-›ðá àxU’æ ªÞÐF·­a!Z®^¸)U`H%;×vqh~ɨ„¹ïËŸDY8xľ|´ˆ#Á6,Ä9ì[L0ŸÚX°óØ×(âPS¼,ð&çÛް…qp¡ƒéއû©º§|T¬*v3Ÿsõ.:lp6BÅÛ º\ìJñ†˜ ñ>}G‚ñBŠÛæÊ¸m¦„ÀêjÞcþ ñ8Å ©Gs+ª¯fм6U ô­q|2G©µí+GÍ ±r¾ùP…*YUN+Ç ¦áLA¾Ìm"ÉAó™ ëk›*7åf)9Y’Ve¨Ù t¯Y…ŸA´£*s) UÖ™jR_®Ìjêd«X™ŸªØÕï·Ô’¢•ªRà käHÑŠ´ûWK—Ô™ž ™‘¥C¤³ræ•Ó)O™ôe._9,I )b)råp0,ú–eæÁÊ 28q%ÔO¼2hC™©5þQC8ä}œA×UcIy*sû`†eåÈgQ‡[ÀÚ8ÉÃv,X#$Ë]±1ý%6 R¦J™:•ÑL£íùhÚ»ð•)wΦpü*Æ*G56ºTK‹­­® +ñ¦!Õ`ŠÝ»ò XÓ}¤v«Ž¶ÛFúÕÒ—f-Ü»Q±‘М*Õfž“iª©…4†«) @B­ñÁ²àä4Ó}‰#%÷’€ÓbË1‚çØØæ;¸¬\Ànc zÍÌáÙ—4ñÒK|3ߢn­EÌÕI€©œu|ö.±z|Á©V)·çµÛ­c¡Ó¤õ`{6zN÷ÕEÙµÑL[8Ì2)ñvæ0kæŒjí:¦¡ëò>R­†Mª¾ÅÙ|þv#‡ 2¢š {2ïz¸r·g]à ÄX˜ ‘J¼VŠ^L%ëä°}§…§Ÿç`W!Æ¥~Wšs¨)Ÿgë=Üt8ÆG™S, yJ­Ð"±+¸ÁClªå·•¹å8£¾›Ls+¡Ö½Æ†)*˹ ™ðdZTªŒ¥¤äÌ¡ ZêD}wrÐP_¦U§úeª[Í{*Êqå±ê÷Z/®úêÔ+ïY Ȧ’’Ú_-è¶ ñ˜YºEžR›ƒªI8•{8ÝP¬ùf-ÈñK$·Zð5œÔ0Uã&ƒžqE’e¥uB–ˆã½U304œ.N"/•(sèÚ,‡ëüjN•7 ¯¹¨588¥HçMD±z·!&¤jÔ>­n‚VÛ6“7󔾟'ÙQFqŠŽ”"iÓWüÓ¼…BÉFÎŽPgqÁXQn ’ÝŽJϼÀÂÆIFlÀ¥‰OCÈ^¢xªµU—ÒÛäw¡q]»inÒÏ»è¥5¦­.‰Y³í{$¬¼ŸG!§˜§•a3\ÚT¶]ÞÇb½Æü‘+äIÈ$úVvµˆ _Ÿª4 ¨P©ìL`ñ…&¾ú@7=c®IáY*c´:Ž‘m°!!â½ßת¢42Š'U§–{8¿˜àÁ³xhæïg#,ˆŠ]F—çá”ÕCœSj‘gåZ}Uç dRT?¢Æ8fYHI¨oK^¨RjT¨r–™Yä)S³ú_eÒ{Ö³žu‚ê9›PzäA«€ê›HOi_©†7±LÛ"âs Ž '›AS¨ú45öW] rRž‰@o¸áãù¬Æ‚L¼ÊG™y×ò¯G“U¥ºªW‹ê'M˨S]ì ÅÊúÞÃæ¨,“Ô§Ê#ÙPÕ´IˆàþÕY@ª«w©ê4E"ç™Cm`&è!pbq‹{)Þé¢Ô©Ä"øš²É L,ׇë)n9H²jÄ#©YMŸ¿½‡»¿…£ó tÚ1I®B•êQ.`®ÛF½‘`¾î’Ðtš IRó*Ƽ§.zLS‹×o†]´™fájþîOòœ÷*l”¨œ]Óš(+‰7ŸËÁ#yv-ÍÌ¡›ÖIü-î×E×È,Ø$¾F½ƒOßÑÀM‡,Œ?Ž+žPÁäN£>\V"¦y’yw±c{€‘ñ*Å ¦z=8~Ûí1ìÊWQ®²Qbˆ|¶Ôç8ŽCœ£ÐøÉÕTÕ# ©¾ÁP`+!³±Ô—¯[ëµ±°X@¸0аM%(ä@""iõ¨k¦©d[¤ï&‰Ä)¦ps ìm›™5ò­*j,}¸‡I¸Ù 1·C}Öfú©„IpÍE !9†¤Sۓ阄ßá}š{kS7(£IR=2p­Õ6S^¹ðáDš}ÝE®è™)ª<–E™ê²à娲[T“nsàófjMÜóà"n»¯‰¹Å.š¼ŸzÓ„¦à(¯9ÝÛŽ½ e|a€»jTÔv1¯Y§z?JiÛ©·1é—QöKFÚ«|†â\ƒZïrä‘ÒX "9…È,y6¡týçþçqêOP…š©DA•¤<)W¸_ ‘¨™V‹ÛúX„Ä£Ùx<‘Õ )ièz²²Þ´U‚LjÙl Cƒ¼9åô#¯ØÕ ù[qø:]E@D¶r|©Ê{ê[V_x@~-ÈKæÕ,àÀJrÔczil¼E5ù1ŸfãH#%çR-Ê$Yo²o³¶¦ÞŒù±Øè X IŽ]¢æ}ÌEçå¨ÖdƵ}øHd F+9)•') å¹]*´€d2_³EM@®MÒX@ž$žÏ{h÷¨8ã~$ó¶B q·= ÛHZ%ÝÉØOs˜«T‚.¾´ˆÉ$bª±ÆLíNŒfËaæY(”™æÄ2÷Ó6ëŒTR”F¹.ɘ§2nðe^l7I¬LWâ1O¨ä’E*»€Ôå}·PY;=fQó®P·,”œª¥q$vž›’Ø)5=–µ€4ßbCÁG«Ã‘ùy6:°Ý<*$e݃† ÌŸ¶²ó”ümV,ÝFHe¬¢8{ËCl 8®h-‚žUͨa r|P þl™çdb“÷ì ãŒTœ/dfS%:X‘ÊiCC8Ÿ„5Šqôç–+x|„eóm” 1Îß5 ×'8ßFµ9ªáy `¬ì §ˆ ±‡‚Ïô¸ª4’JBUYãÃÜñð´m)ž»+Ä5W6Q®4©S\<^B©RÂìÁ˜jiHv$×jóGCÔ§I½®…‰ *6;ÆBPG7¨’‹T”#$Oæ€ÓäºkÔæÙ˜MQ«×a‡=TË’R›Áƒ ¦™È#qŒŽå±cb” -*í¼aÇxž×#Ó*‹TÁNʼ©‘pçy¯]”¨r#·(Á”Ðãë½âƒ”Øu×]g¦Z rnѬùò”BSÅùH˜Ý¤hDÌYÐuA&S… Ëf)âD òÔ\ d×ì&(¯}4lBÞ½RŒje¦È³¡¨5 ˆ‹:I)]šØ{5¨1§1­ƒc×Âzé_>:ÖÐÀ$‡b~Œ½Ï Éal$˯tqù f ªêˆ‡qJ3?)£ÂÌÙµs ½ÀF­ÖÅlc Eå8ÕçFFdÚ°¨5磃I7çªß.E«ÝEL¥V)öpÞv›7Ñ›ÚË;H©¢æI²a¯HBóá[.ò%‚¾ºàã3÷Í`ùÑq´Ó£^ãç·qáHnvйÒ©Mæ7Q¥ª%AV %ÒŒæFuzX˜é CE\-E˜ÍcqÚãúm(¹%*¸íæý’ìcMšœKQà¢>P¿è“쩲IŠ5EþéDؾ+K.+`ÏE,òÚ71I•zÉö"QÔ¢Òµ°}¬B…l£ê{˜9ªa$¶ÊœË3‰Ì0˜jÙ&ÙÇË£KÒfHÈÉ:­›!†8ÓZø«¿ú+¶m5¨•.3–¦Ò€l‘ËZõgêCüÚ×¾vܸ7…ŠÓlò¬=Ý8ªéLB yrf³• B¤¡Aö!Ï_9µh¬è`lÓ³9ÒèùŒçª)¨Öj¬.,“£ú8]VÜžÈ o#íH˜ùJ;Hb»F±c2²ï’ü Æ<êåS”I‚Åâ(êàÈt›ÊÌfÅÒ,Õ÷Fåf¨ŒØTimóÆ‰Ë [Ti &*)*eÇè6",¶©òÒÍê‹rrX¡ª;¸Øß²qËáÚ#È“h»$’fØC7íbÛù ƶ³Àÿ>ÓèÉ9NH’'A#Ç´ø˜/ò8 ÄtUIü¥‚¼eó˜ŸrQ›· ž-†$R*¢†¯{L0Nõ7R"ò:õ  ‹Š.'¥œ:ÌãÛRŒNPMçGð⫊ø©‡¸ªÚB£CµJ&T1Š%‡î¢ðÓñ1ZðMÿnGlXü]d9Æ™ ¡+aɇt©€†â‚Bj©ÿppÞAhˆƒ¢Žh@ö`ø­sŠß) Ť}á _¸´v …P¼R)Á•Ó¥,2™‹•‡ š ïg2çw~§IS¦Æ£žIrT¨XҌᬤݶO(Ô-Ì-4Xy7ùs´jÃó;H4ÿa/B£Ö„mQ ˯’0==Xm±ƒ.I$WðRùALòûÓNÙ1JêtÇXñW©ÎÔIîð{húáŽÎ'È‘ÊÜG&ÇJ‘ŠÍ§¢²#8‰›¤Øêh7š&hA“ä¦"’dŽê´JÕV-»$¸‰žÄÌc{h¢Þšçyì>/=WŒ`ÕaJŶP£ŠÓ0‘vŽ×%QûÈi¼â ‘¤˜#™H’y›¢Iãù¹ÛÆ+¼ç ,[ÈI)ÁÎ \z‘‹ñ\Ëi"Ì·xo.U`BÂk¡.užs01Q&ÙºTÇšlHD8Õ™&¥sÕMâ±ip› _`míT˜-TH4¾üJ¨¸tlŽêjl—…ÊxL²%!š¸¤Ü^ ö䌓dBôœ:Bk 8Wæß* ©w16â 2’b.j`¦;Kå4‡.B*CÅmmc¦YG£Ë‡Ê±!¡m¤q‰J³Ì4ˆé&›Dn±Mò£²Ì99”óã$Ìì|—Ħˆ?-Þo—jM&Û]çGØy>Õ-7»»uÌ×’®Î}ë$B1I·?å’Ð2Qtº·i¬"ÉÑô ò³¨l5ý–TqÎ!i–™*`æ&‚^Êóµ‘:!Õ¡gŽ‹c‹­´y½…V·‰®b¾z=-£¹¢ 8 òâñ ™“ÔÂ?W[ðd3ެå€r¶!e¦´¨ôLô‡> Óª¦ Ò”Sr8,‘£HˆXé÷H„A—µI#³ÍÏùÔj$ßDŽ*R\ö”r¨ðå—7h7&Ùq¿”„Ð ;Ë‘´H¨j— ­X, ˆÌ·šFÙ‘?àQaªÿQ³{Ø÷9ã‰y283¢ŽYí¸µÖ±5(z*w…hÓÌôCœ{XVŽê×ËIbdI‹ ,µ¤ò¨í+|R‰!NIž\ºíf_…… ´ÚUÀr›3Öá>EôR©(ª§ndBÆj.Vè9’GJ5¿ƒNàîr°lž›¤ä“LÂÏ—æ0Kõ¶¿mc‘¢UÕ#Ùxnˆ‚L’a­v„F»i†UtBRsOIÈ=9ÊðÚaàó:@+i‘lD´T’T„";©4»ìP¶Û$^Þh®¤ôiNÈÀ¹Ít(í»¼†L±.É•YÌW^q½%µÊ;·Ø õúsNZ134,B I꩟°q`‘Ü]CнˆŠš RSv™T¦±Ë¤ÅL›Ë¼LIìRÞ¬‡bˆÇ4-Æ=?Æ5{¨ÖÚLCg„ªKaìB¤½eªÙÑ ’稃y^¯CR)9(áä¨f©’Nu°ÐŒqáxŠç=¡‡=‹xC8‰&ï— +VŸ"µ`‘t©jumíó¤n“Ü=Zô1_§òE–“ƒÍã-ÞCXg#ƒ*7¦ZT`÷DNK±¦æ¢ffF<_ß»mÍ©I¥L’”óÓÐÒ1Ĺ‚­˜Þ4Að5×\c¯žl#¼úÕ¯6!Ãyuê<Н©i©P¯‡n¸Á Ñ "É|à¸é¦›–¶±UhL¦)ŠÉº6£÷îÝk”ýoüÆo˜I±o»í¶¥-ëcbbÂ4tÔèÑ5|Öš°øT`ÈQ·¡G^Ÿ1Õ•¥! nEEŠi·YùØ3îãë/ÈáÉÛ#l¯D& xÜñ‘†y¸i Õ\ÑÌÙ˜Ë{ÆÛÕ‘3IËÃhB55icû˜ËqÆT‰½AÚASavÚðIPcE¸9‡×JIŠ!•Xù$@Éí§PÃIl[áè,”òELŒl3!欀û6-ôš$ëªA+Á3.` }l÷ÛpóE )…¨O“d“ ίð$¹BÚÂÎJŒg\–âÊÉ”×-à3÷TñÉ;\ÜrbšÃyÅœq¶iCS]ñ!Ydc`!B>\ªà¹¹#¼ÿy¦ïV®Ÿj°ØA;îGÏAäc!¶p˜÷k;.ª…<<»`$È!Î4“†&µUôÍB•žÈJ°×ëû{÷»ßmâ­^}õÕÆ¤9ˆ‹/¾/ùËMÿŸÎ—U¤êT$‘ âf~Çw|‡I£æ]|ï{ßk†?ˆè4Ëÿf¡á/¿üË¿lŽâÔ Õ¦øºïyÏ{Ì„Âka½ÔÇ>ö±åh6"Y©@¸¨×ë›êKÖpCMA¦çO3…hBfÍÉù”§ÚmsY\v±‹ïx’—]ÒÀå$PªÊ^`ë¥mH¥DÖ|øhŠ÷~lü9¿u=[†7~áY—ÖpÉH‚ݾ܄:H˜®B)‡€Ê0æ5=‡DΛ®6ÚpÚ \0YÄ÷=·„ç]èà¾Ëø‹OMàCŸcKda®ÙUÁ·*Ü06®¾Ç"jÍ@VÖM·Ö‡xü@Óò¨b8™y åÔ"U'ÓÔýÑᵯ}­!¬ž3‘˜ZíšAÇ^rÉ%K[V‡”ÚßøFCnƒP4™Gu®Ah2Û_ù•_1óþõ_ÿµ‰ù;¿ó;æxç_þå_ŒT,M È–Ó/õÑ•ÑC=dfFÑTb›AÖ8ÑŒ*"®ì÷J¨1ó§ú§Æÿbµ)ÉŽ9Íù( >K²"ÜyçøÌg>c”¢Ôk¶•¿,‚F[ j®€èŠûz&a›[°RôÌ ª>’b¤iÝÈÂäØN<÷ª\}a v¡‰©:•‰´\‘7˜‡œ¢„.™Ló> Ó“Bswrx&¤WïI0‘ 1ŠÔZ D4I2¨Ï$è¥Âä5jóˆÂvMä0Y,à*É}Ißûô¾ûê/¸ZQP-¶.bÙ—bê@‚é}u]Šó/¹)•ÝB"Õe™¾ÏyŸûÚ">ò¥w$á;TyT¥ÔŸ£‚l7j˜ïµPaÁy.öµ€‡ÌÔ‹xh&Åà œ‹+®\ÀÓŸ¸ˆW¾0Å«¾)ÁWìºO}Â¥/á(‰º—&8oW¡Eå'ܼL¯-$“éì; æ;&Xz7Ö æ3[`p$ C㙫á¤u’¬…¸×EjsÃFC˜å8Ä+¡+2EIim ­JN±ZÕ×#s™œ\d¢ÚßþíßnZî2•ÊT¹T‰j™¼4¿^¶ÜrË-†WÆÃÔ<ŒRßýÝßmÔ¡æ†Ô¢tIµhL ÌzÏ|æ3Y-[^ò’—,a}HÁÎìp.By&RÓçV¡×Ë•ã™0¥¢¯¹hºE’,ç5Ž/ÄýÀb-Wð0ÉãýŸÍ㽟ññï÷ú˜ŽKp=‹:ZQ A¾nfÅH°E…ysk4ÆÝ y|à¶Þñÿp«‡¹ÛŒ‹,•,TÆ,؆`óðI"¹Ø5‘o\Íy81ŽO})Â;>áÏ?[Æ}GF0âæÑ™Î#èA=‹‰í F'==4‹h!&Éð*ë_üŽ^rE ¾ÝÃá ƒ©FB‚²±Ð 15c÷UFv70ðŵGÌŒ™v„½[è’œF'©2Ë’|7ÍÎ㣷[øèmà¿•±/n`&}Gƒýˆ‹FI ¥œÅV 71ߺ ¢÷­ÏÂãyŠ,@7ö¹¾„^×Gm* Œ4äC¶Ð õ Q9Ƽ Í‹m÷BË8VBC q ª@dºT¿ÚV- û÷ï7æ,ÍÖ¯ íýï¿1[ªrÝê³I½êU¯2áÏ6‚Ô­ÂÞ}êSŸÂ'?ùIó©ãï¿ÿþ”îI¦2© UÐ"E}J% 2Êüvß}÷™ Z‹*ãÍ:chÂf©äsêw“G­&Þ*”ϯýërTX:)4Ýóf Ó¤Tºú7zž¤ðµ¬Äw}×w™´¯<þYÏz–)+™·¿í۾͔£žA5° ^–€þá6–û7ó72U9?’0U¯!z6¨ÆÌS˜5¾$Í… ,›ÌkãYŸßkák]¨;ÇÄ=|8ÀÔ\fMõýQ%5[TC$¥Ùz O‘ ;G]Tœ*I‚*“ÕvØš¬¤pÇSŒOhnÅ"É-F»Þ@ètÑu,|îV_¸·ŠOÜ]Ä׎8(Qvxm½0£ã”á“L´ßÅ÷ÌàðÝ6Ú$ò˜Šu<7'LŒáâ]ìØîš+ùrù¼—Õ]Âû£ºm²¥$Ü¢ã‘cì›êàH£‰Ñm Îßébz±[êà–ŠøÌ|úîÌæM@ô©ÎaDn9*Õö󪡘—`£ ¤ªn*´µn~$gúgŠ~Ž#ùÙð½ F Uhxct˜_êµ¶™UD±b‡-Gæ#/?g3¯–Êgˆ! bQ‹|µ‰j7‚TçóŸÿ|¼ìe/ÓŸüdS™Š¸Ì0¥¨¢’³„Æ fw Ì¥"9EyYR™2“Êħ>ª/~ñ‹æS×ÛÌ,í2ÿ^;ƒ*Vy®j‘‡£*ôõ™kUh†Žs2]>ýéO?©ñ˜2¿éMo2}½º_•¯'›b”þìÏþ,~õWuSêZ_ËKTdœ-2•¾èE/ZÚãtnM%ò̆à ÆB}ÞóžgžI™X¥&µ<ûÙÏ6Vƒ0??oH÷dC+®‡å'4V¬ñ~ ûÖRål!©†º!Ê|gÆYVšÖª\æŽ l1Ƥ—Ãó.æKtA„+¨0åɹµy®Fó”<#¹»XÉW¢IOáÜ"ÄTm2ºTª•<*IÛÕ`xª§nZ—“Ã’\Ž„£öN1Eu<ÇÖF‚m“$=®_˜åyRªÉÐ'1†¸}¿¿úì6|äžj\?Ru1Q-PÉúT§˜\:’b~‘÷–jJ@åF‚“I¹G²σƒ 4k‡¢öÈãÕÉw˜³Ì‡‚–"å8(û1Të$ä&×- ±¸8X ¬#áùs<‚V¡ÅÖo[vk;€_ÐÊ>Ïi¡GÒöHš9_c3-8bÃATw¤¼GŸK¿ù¢?C ±*23–Zâ?ôC?d”™µÀWƒö)ʉa='UNêÓÌ”ÛV¡†¡fç—§©*Þl‘JÝŒÙPC1þáþaS¦Áõpá…šJÿ£ý¨iPl"W)±³1e˜‚hkŒe«P~kØ‹ ~ZMNü=ßó=æ÷ ”ùÈG–~õ!òR_¯´6j¸|øÃÆ_þå_âèÑ£¦ŸQæq-ú½¨o³Ùl.ý:9`©«@‹eå·”åŸÿùŸ›¾éLü'“ ’ÁRÂ9òS‰’&´»f§Ù‚h䱣Œ/º$?^!AH"ÒÀõ'Lzøo϶ðò§X¸ˆ$HŠ‚[µP®¸¸b×NX97ÞŸâŸnòð©ûº˜[èÁ‚.G~U1d«_÷ØBÌá“d&# 5ª¼Ùňª0 ùµ±swÎL¸<2NÒðòèurü^€WíQa%èµÜ;à3û¸o6äúšA¤@uuy+‹T‘¼VK÷IŠ BÐä}*,Þ¨³»s nçñÐLaÎBi„Äì.šÉ’sš]îcškQ¡R×!Œ=”Fó(–=P(ãð\‹‰Ê·Me=;×&÷çlìRM[iŒùúfju^—ÄžPÊU01^¦’,ÁëzˆëÀb“÷Ì AáüLù˜¿C чÞ×'>ñ‰'¨ ‘ž*·k¯½Ö,oxÃŒIKý|ƒÐ½H·%—]´"Íp¯ymxŠ6S¡êêôçw¥„NBµn-…~#!Ö]BŒŠ“ÇÅ\¶çINÍv†Žf¨ ‘–Ë<ÕVDe[ª¦Ø¶“ *OSHùT`¡Âß‘˜ZTzÕ1’}%d,TÊ#¼¶€å£¯$§¦1 …)æÑµØ?óÕàœ‰N¥Ž™B*àþn®„‘ •%[ÐíN‡éT€ƒœiQ[n‰ÛŸº*âýIJ«F Õ3•r”Âc^hˆ¿ÒÛîj̨Ò'GMˆ‘T1=ÕDžªÓ²Ê8Äõ•·æ‚Ì™Y?†ºññ =còÆTw‚LQRrR„"™ž¡JTQa4 B};ªë·~Ë„M;³†X5t^÷º×™E}t+=€9´HÊܼžêR³”´ kéþ”G›Å¯ýÚ¯u{²Pÿ¦¬ § 5Z¤”OÖ1çãÿ¸é³^MÅ ŠÞÕÁÝEàÈÁŽÌ¨R•½ù[üÒwÏã•×Â7]5‡KG]tê!+wVéVŠÜXŠõc_‹ð±ÛM,K6\ꢄ q¸SGƒ$`Q%V¨$˹-Å?¥ºÜ1^ÂÎñªy@zͶ9E,îajЇçâ–æ"ó!™(§˜,¹ÈÅEŒäÊfz,Ën#%¡K¬(væ1Æ÷¾4™b÷e%.yÆ,äKyTFs(º1‰ÏA¥JÒ'áå£vã:¿ÛqÊôQölÌ9uD•<×"Áq·/ÌS|Ô›¨µë¼~¶ïš)§‚¨É´¸{.æ)z\W2Ã[Êè5TQ5SÒÎmŒS]6:1¦y¾ÔÌÖá`~–e½Km™é¹ê­>ÚÂÌ Ï?—âàm-¦C²‘ù=ÄãšÎHƒ5ôBN jµkœÙSŸúÔ¥=ŽA•«L[êWS«X&I™§Ôt:  UÌ&È“UÃ?ält2¦7õ“)ìœäTì VszÑðõêZƒÊR¤µ¨ß÷—~é—–¶ƒÌªçŸ¾1¯[: ›È†ÑèÙñoe®P»Ùø¶«AýÈêc_e>wph®Å˜×edùÞíFCÕø8‡Zµ2Y:tÈô±ˆðþøÿØ( È^ªd¥–Ösœ‘‚§ Ì¯ó¸žâ¥*9äüþïÿþw¥?P”úØÖ»·äU«Éfˆ6‘¢ˆEMê•s‘L¡ªè7Ve½ÒÌ'2RE.¢×¢²Á ^°´õÔ e,KƒL&üÉŸü‰i4>íiO;©çPCIÔQ£s­!LÇJœtgŸß—ÑN¿â¡bàÒ±+0^8³3]¶B%?‡ £`äšt8DÞ- åäSE¶13ׯÜQªÓù)`ÿ‘ãyϕښLº®CÄF„‘÷C<.!‡µŽUIkÈ‚>‹˜ä133cö‘cMfòœ…b3Re,Õ©ïë‘ˆÆ ÊÁC¦Jõ%ª¿GN/|á —ö8÷ /F WQ>n2A+/³ˆ+“)¢µLo' ™ËU©‹,¥ò”§">)™ÑB+²ñï_f‹õ¾ޤ|iËŠ;Ķê6äH<‚ÄÁ}Hà]tð·Ù†ÞPŽlTÉìe;©ƒæð†’.Ê£T¹$Â(¬¡8ÑF±â“5¢Ìº"ë13®0¯~R¦»£9% æk)êFáRØ)´[ì¡CõÌwH¤$+Û3c1}ž»2ÞãCÛEB" ÛTÏ‹=LÍ6 ‰$擳R’f³Á’eªÚr‘„ÛË¡[#‰7b~:TåT§]ækM³…8È{|!¨j=MŸEe»¦‰Y’³”bD2·4~ƒ4«ù(Þîj&˜!†È þE©>µ¤·êQ©±mê¿TšiË+h€B¿ BN2a©Å­¡Ú.§ž“ñ¬ÆAg}—YW!9s©_V;"i‘ócšE Á­ô¿/›UeR·X9Ç$VÇÊ#W¤šó"44H}ÖƒÓLj_„5Ú@ìÏÃrYÑS="!hŠ©íÛY±7,,’CLÄu$E’¤;TŒ‰'eYDä†ÍYøú+Kø¡WXøùŠqíK-<íb¥‚Ñ‘ \ÊÔï»óÉ4ÿÐ0Õ$iF>\Ç…ïåQoùh’ØÜ¢½ÌëF¸¢²€×=w×~ÝQ¼ùæðß_¸€'nqðPû,g"Í Rotû·”ÕµÅ6"*´gU=\vÑšVÀsy’|ÔáCÉ4×}Ø Ÿé&‰:µæŽÖÐkÇÌ7—{qŽëãÞÛ±°¯‡qgb’¶¦­õ«á‘`§ïmãÀ}‹TÓ$Ú^JbïPtZ°©(5‡ew‘ ƒžÍöC îP—!9±Ôê—Ú‘óHÛòd!2S%¢!!+ƒ‹x¥n4À\•Œ<+7 ó¥ñ”R!Rš"õµÉ|—[D±–eDëÕ×'¤ñ ?E ŠÎ•-ô}𼺙P×#£S1çeØÌ92 ÍÎB’A÷¤¾aå±L·™•j’bRÜÚ 2Ë\fzõϪ_[ÁmýëAï‡ Y,×ÍÀ<%jÅø|V}§€˜¸†\h¦ÆD1V{ hÖ *,>0~±‡óvb¬RÅB³CUe!èÆT:1Õ"•bÒíoPFDB´\r¤ƒ…ù.ff;æZßü,?øM!®¾`WnŸÃ³v6ñ_<ãÉ R6xõvcÅ;Æb*¯L=<ƒ„©- Tmj\#ïÛpG:ˆ˜ÞÉ|×X »ÊΉpÑX%ªTEéa2x/)fÄãx¿%¾t®¼Leê´ðô={ðâ=—àBÏAOª·ã¡1×E¯“/ݰÙÃäh._¤Q~ŽV«¼×Issy$eºIÖnŽçŒðàÝGM0…R…ê³×Áâ|‹„Ǽpxް›D¨€å!Ït‡ÕCұќ Ͱõaj¶½·Ô­¦°†b5ÈñF­üÕB²mòŒUÿ”¼ËQCfT!„Hq0¬—ˆN}tkA*ñÏx† 6®y5N2Ž þ=Õk©(­×±rˆÑòœçÁ¡}ªì5ãÛ&òhÕ-Ìî·I®6 ã" µ©ªâ¦…öT…vlÁøhIÉ" ·¨ 4ÿã“.LñÔË:˜¨¶qéyE\²k;ªšõßi¡,`¾Ý %“Œ¢¸ËB Ñ ,LS}Ù=äv§84máCŸôñá›Çð…ÛŠøÔWóx`Áâq"¶PÝ„êÂéõØv>FP™°q¤ØÁ>¿oÒA©J2¯õÐmwÁKcl<‡óŸÀ¼!ûyŸ ÞWLìp]·E•MÕLÂ^XÔØF*I~'haüâÆ'ËH™†&Õk}±‡0pØÈ 2eë®HRMc‡ªšê›Ï~¹â!GÒîv"Ô§xµÓ¬8§Ö`bˆMAjIÁ¿3ïVE–‘‰Mž M6)EáQK|½È("l)[‘UBNä"óìfL…RqŠ·ªEJõT JY^¿r>‘Z”C†¼Y‚l³Ð°‡l¬çÊp{§")Bý ªÝ­B}–꣓bÔ=kü«Æø B&دû:*BJUý¡ëŬU?¦,êŸÌ>e†—9w3W®LhÌäVò5è¹t&’–@[µ¢¨A8Øðé£ãƒÒaƒ³Ñjê B)?BUUDHN´-ù 7Œ<=’àû›lA²B§²ÉSui’ãú–@}dÚM’škQ=¦$£"žxñ%xò%{H|Æ'|ܲÏÃû>|ñ6’׿»#$È2K>¯éœHhTpÍ^b‚p7Ã-‹dFr ø]œÅ¼‚ Hu‘\zFÆm<ÔôñÏ_.ácwæñÙ{|üë­9Ü9›¢:—¹T$¹è( ™ÑŸÊŒd»kW„dápØÁ=$kÊU캠ˆV¯Ë“ªuÊÂH¹„—æP#Êqhv*`>4 ‰…T}šc²‡ØxÀ.ÌĬ\Œîä1Œ“SD%ÎXhÍÅfÂäÈ PG‹ÇÈüÞÉ– 2±HÎTζã˜ÕoËV*ß?©Ç!†8ÙM¯¦|Ê U¨~Eõu©b™šš2j@}†ª8¡~-U rüøÀ>°´öDˆˆtN9 iÀõoþæo³­*Å•ãùVƒ±LZä}¹(F§úG‰å}ï{Ÿq\D¼šDÔß*“òZ1I5ŽP [x$ÐÉ@ä¡F@Ó[ÞòS¶+Ç~ª¼D¢òÒ]/¢PHÕ "o©L9s©ñ!¬g×6õ“«lÕÛÈkt#ˆÐÔWœER¹ê~7kŽVcP¯Æ@f‚–ž .•K±ÐEÎO 0§^.ʼnÐîæÙ:,¡uÑêÖ¨Sãjœ³4ÃD“ëº|HBš•ƒd‘C…|?ğ¾“î¼W?ëŒï¨€YP3]|ì~ ó¹ŸýŠ…Ûöqó¾ šÅ|ÃÇCGI˜$`y˜’(J\:sÕ^„QªÕ^7‡·“Û,$|2ïÁ§Ú=ð \L'î#Q=ذ°Èe´\ÄÅ»Gà%Þ‡ƒÊ¤‹RÁáÓÝCy¼….ÉÖNÇq^q&ì*•ðÏâ,IŒêTN6ó‡c3óí¨­'hs{bóþršÃ‘»ƒ2Él[‘÷™çy}‹]´Ó6âñ¥ÑvmÓàWópa6ÆÔaÍää©cpc.@»²1â`t{AámIè*!†8½W¦O² n"GM}$µ¦~LX霡 Eû¬œvj5ÈÔ+¡úµdŽËÌšTY®W™ž,äÌ¢!:·ú,5˜>›ûqØeEA4u’ÌoÚ 3ðjPÚ3S³Îy®AÃ8Œ>óÊØ[QsDb2"Õ/BѺ•fxy®*p„îs½!: *¯|ÐÔX L S¼†÷d‘w6‚BÍÉT."ÞJ'•›ÂŠÄ3hܨ¸ÐFâ˜}0E<_Bã`…rŠœÆ4ò娶ÛC±Êt&£ÈçJØsEßøuÛqù¥cèE1zV„ó®Á3_x.{â(w±pXQ†ØZò"ÄÍÚG\$Tߌ¯±™5ªQ¶èZ5îÆeôýCé’‰ZÙRckEF‘c¦ìT‘®TIR–¯~õ«Í,§Ú¦s¯<9•H垌YQý‰2õÉü©4ªÒ—Gæ  Ve(,ÒV¤Ôö‘éq5(/2µu&ýT¡ˆ††H‘eP:Eür¦Ò°‘ˆÌªrPYFù­†“g£ûyJ…«a¡¼ÕuËi­2´Ÿ[-W©L­™ *Û¬@çRš³Ef{©H¢¬º!kÈJ¨Á$ˆŸzòš”ñTõ?Rÿ`’G«×‚“@¨„Ò¢†¦¯èUÍü…¹‘:œR')’D©rÎwQ9?›`7`‚Òj­oD¦X…œSàíÜbƒ-—2sM7ÙBèøXÌ9˜iˆ›!z _’ g¬Œ´ÅuBÞ¤ƒó.rð¬g&f¡¸$÷rÁFÁeÊóÌ`OND© (.ºwåu ’¹íHèb¢RÀö‰ 4©Ê¦îŸFïp€‰1#;3†±D•›ò:­ZQ‹‹äZJ²¿°€16‚°‹ú"Õ1Õb±­èâÒñ òE™~T¼•Îlˆ‘\ .$iFrÎñ:dä3s±9²ÍBâôÐZè¥tI~š³°T‰Qk¶qhšZÍ3Ãô›Aì! \h ƒí¤È“1=KARÔÛ ïáEO ñòËjxÙUu¼ñÛzxæ Q7ÅœâÇ9ê ¨<1Z$7)[JM'¤êê Î4·RͧÑÅÔ| S³MôÚ3ܤ¸á|ªÉ2c+ì1M$^»€&Óxàp›$KRN}T¶É¡(A©\À®+ª·ðäKLŽTªB¦Eq¶HE³…’F+=ÔósèæZÓÎö4HšVÌTIÊzdºLCÄDÐk#äõFJyŒM” Ñ7ZTØ–æ¡bˆG2£*<Ýjœ¼N¥Gæ4UÄY4™S…*oUdF (0‚œ}Ôê_¯ÿKä¶Þ$ÆRAr ’jИL©+™X¥vä0$Å£q}rD 2+JIÈ)õ)…©}”6™]…3ís2ƒ”nµ±¤ªøU^ ·dbVBùµÙI¤×‚ˆ~-²WƒGù?HF›È\e"ÏSá’K.1éUßñ?øA³Nό̶º†Ê^Ï«ÈþE/zÑqfÓÕ0˜ÞåfƒÃwÀ·ófXB¹T~mt©ŠUÀJ=爾¨~z@³íüHIŒùFŒf=6“õjòÞ( wH@…}ßyøÄÝ»ñ·7Œãs‡4£ršU?ÊS1õ%’î³.óðúØøéoxžø†®¨:ð™žÊ}·àãÈâ¼R<ÓsˆR­½Lgm¾‰NÒ€ã[pyî˜ä›’XK$mÙxn ‰5‚N[CA<®gC"&¹±A‘s‹pã~O*¸„b>f+ Ø~щÕÃb} a‡†‘1>¨yÛ8-=åb’ú‹H[º{ùÛ·bÇy#Ìšþ¼•Fûž‹Žw¨LÎdÅw¦°Z%ª–y6óºÔ£†h¬˜Zñ"S‡Ó)m“Ù+ S'3­b‚¾æ5¯Y³Ïo")ž–§¢‚ ¬yÊ1CÄ|ÓM7-­í÷™ÊÓVÎ*Ù`w©-©)/õ¥ª¼ä¬!3¬—¤2åX$çá±öžýÓ?ý“1EÊ£X5‚ÖƒÈèÆo4y¯¾½ jTÈYKD¨<”óŒAˆÈ²·".õõêX "O•Y¦WBÄ-3¸Î«2’™¼Œ5ŽSªWýª*§A§)}¥K 5ºd¥PÃHýîò¸Ös48²ßçÈ o¡Ì!´Zpì:]ÊO—¤ç”0×ÌS!vÑ¥Ò«Ž’0JLÁôAž¿–îûäÝ‹øÄm]ì;Ú# 1áQ?€w™7‡•ccùžsIT€{ïöpçÝBq—PeïíÀ/ÅX$ î`{ÞÁ·=-·?»…‹Hä9+ü¸‹´Ê¼eRü”•éëSUfg¢E;Ä©á±R.ª+4;‡œqÉf5ÈñE³I¨TªBU¥'b‘H­~9Š"I}_9—ö•ê[9i³ú¸¤FT«ïp5(â‹*ü•c1e6–Ç¥‚}g>‹´UK=©’}ÿûßoœ–DÚúT [ÝO†“mì踓=ötaµë+¥.åͪ<ÈÆ=®Ò¿ýÛ¿™x릛nNâM?‰Û§nÂÓ¾µBæ,ñ$6¦g©ò"TFGH.+ë:rNŒ /ôø°¸xx?IÇ ¹>DiBñ]4¦"!‰m¿ÌF‘äuøAs,™Ù*êE+$Ãùa+9(Q5¶#S5’†Ç ¤ÌHLT‰‹l쾈J5ï¢6•¢Ý Pº …%Å8²I|<~q!ä¾%L”:(wS\82ŽÙ ÌcÖj¢4êc” 1 RÌ,ð˜BŠdçíÈÑ&Â^³å¡ : r?r§ü€Ì–„yø²—½œ…÷¶ãlBæ™6±D­)õ‘¨( Éñ‘EV¨5¬ CÈÕ¢—~­ UªFïäfúòÎe¨òWÈ7=“2ÊÄÔ—”Íü±ª¼TÁŠDV:»Èü©Jk%g!étŒf 8ˆ¸E §é" UÀ21fÎ:ƒPù©R•‰p£i¦5ä8$RÕ3 Ò?—ÞO)}•îUù½^€xEÝÑ~Ê')pÕ?2s‹p”/껓º”yTŽ=êT¿óJõ¿äa,²UX?=C« æÏ†÷ÈQkpu~•£òUÛô)èøJ+‡æ«ïUû¥_üâK„B!ŠxÕH°n¸á†T®»öD±P!‘õ/¤±uú—ˆ}X~J€|3õFi1³*i?þSBô,Ë+X}ÚGE®ßú¦òל„‰>¹NWÐwí£³j›ùÎ · º¬y?¸Aë´Í!±¼¾k=¯×?˜Ç˜x§© egÒ¿ôÛlæ"ƱÈf&…ü¯ÛUúÌý’y Y󺺧¥Ë˜{Ò5cgé·9Žûêü©ÎÉß!_$5.L¨:“0žÃœ·ŸGböì»Î§ã”W Ìn9ýô˜ì6_S’pˆf»a Q/ÕÊ^ôH9Ê$¥~=¤ƒÌÖòTþHuhû`ÃA¥>-U|Y£OP~h½ªØ×:ïf¡ó(ªx3Ç UÀZ§ôë»Ò¯ôè¾ô]êF¦Ù•ãWBÇÈDñMå"Ñ1çZ™Ji)]2/®l  Bù­<Ñ>ÚWÇdå´*•›öÛÌýêyQÉ*r=Uèú+ËGéTg×Òo¥/{ç4²ÅBNÅêºI±ô±6«\³›9ÙÊv£ãµýض•WÝϱÚõŽ¿ÆZÐÇ®»þyŽí;xîcGÛcµã³ýŽm˸LÏŽ¾ë! ‚[¯3ÆTªqIk) A­^p™Tתx‡xd ÷KæR•af^\ ÚW}.2Y©,7ÓÚ>±VE¸VÃmpÿÁ}ÖZ/¬·m«X+½²ók?™ïDä2Å­Õ/6‡”–Ì{™試wˆÓ‹¬üe‰P,Z‹+Ö"†bˆ!†8eH™ÈÄ(•"óºTËçd¹O€Ô³,;Crbˆ!†bˆȺնŒ½×=Öó®Ãæ»À÷âºçYxÞu[8B×°ú}vë.o¼~éˆ%ì½Ïؾ•kn×ãº3rÞG²gàúå´²8ŽaëÏÀ ®ã±k˜eéB{¯{#–OyýWÝgˆcåµ¹Ü?µ²Ê°ú;ü¼åòºþoä›4D†õÊhe^öËæ Ö«‹yŽ{·Ž•ácRŽ[ÃýéÛ¯Q§ÙµéG—ÖlM¯å%qÍÛy–-à£×JÝ.-×=ný5éÛNzÿÛ¯YÞvÍà†Ó„^{fÎûèÀ‰Ï€ò#Ëïk×}0NæX:fÅ3w¬Œ×.{¬Ÿ˜Ç Nö=É÷U|7WÿÛÓk²m'U<±É2È×cõÏI–Óqåpü;ÔG–¦ì>ö{õý[Ø"9žìK6ˆ“(ȵȑ8®"Øv&É1;÷ã“W6OŽÂÖžõò»¿mÅ‹:ø¼<îÉñTßÙS|_×<îtÔ%l!/V%Gá$ÊiCrìCïöã‘·dV½þ—ã­7²?ún¬ºv#¼?ÇÆoÅå§Áäµçå¯϶„;pß™–ú׿—+§8ûÏÀ^|äûù}ã[÷Üž·¼:Õ«ãÔËk‹ï«º4^öž¥×àíï{ ަaÞò¾·¼»_œ‹õªÊñº¥Ó¼ô¤ÝÇ!6OŽÌ¬ß4ÏüµxŪ%Ø·}کײïy˯ð,Ä{~ó¬Ù­û«Ö²ÏŸ`‹_ñ™íË/¾žÃË×Þoó¸â¹ºþºM_Ù|¹o’X{¥©ä8¼JóÞë>ˆ;Öy1³?ùе+ͳ¶"úuç@+Z6oóåZ|tP¯_~Õr%jZ{{¯Ã³RÙÊyuØì30ðàf÷~ÍÛñ¾ú…·ú ¨ŸaÅ<æý˜§ãóvïjj/ý¹eó›úNèâb¥Þsw ^ùH·ÖN 6(¯åg•Z^ÎþÂãógkeuœÙJS›íO<)ÚMÔ5ÇÝ×ø,þ\ö¨l´ýŒc½2Úƒ·,Íú«=ÇP½zõÞ2Ñ—Îc¤¹ªIuàÖsµ<^]}ϼb‡Ì5ž¡Í–{ºY,»ÛžèæÍaÉu¶¿ÝãÖ ºø «¸Ó®‚ãÜìOXÖ9våk¯=>fÝŠ9ázk¸C·ß*ûlö<:¬ó ðåXrÍÞ¬;ÿæž^4=6cŹW;ÿŠgqyŸÖ¯r]íóX)+a½wv '¾c«•ÇfËêDè¹8þüKËjù¼Ú{»2á›®k˜æÊ}06Ú~–°Q­¼7Ûã÷åaÇaså´~½ºÚŽ%¬Èû•e¸µz¯ŸÖÕËwýr8ᙼΆÏÐæË}óäHd‰Z½`¶€,ak–Âç*ÓÏÓôX{$OKy ß×3Ša½znbKäHZ^Øy*-¬¥ÖÍc©…þ¸ÂcèXQ™|ôÚS¹§s§Z^Ã÷õÌcX¯ž‹Ø"9 §RÃ|là±ñ ,›g”–ûíqÖÃÉ–×ð}={Ö«çN‚û0öå-F¿ðOÙt0Ä9ƒGý30Ø?ñ8¨X¶V^Ã÷õ‘À°^=w`é+‡!†bˆ!†b §1BÎC 1ÄC<60$Ç!†bˆ!†X!91ÄC 1ÄqþìHÈp‡á)IEND®B`‚pyclustering-0.10.1.2/docs/img/target_som_processing.png000066400000000000000000003320671375753423500233240ustar00rootroot00000000000000‰PNG  IHDRÆQ¡&¦sBIT|dˆsRGB®ÎégAMA± üa pHYsÄÄ•+ÿ•IDATx^ì]`Eþ’@„Ð;Ò›R”Ž ‚]ÀŠØ+Ø‘_±¡(ˆ¨€ T)R”**½÷Þ’žÜ?ßܾdn³{wIPPîƒ/³;;{»;3»óÞÌ›7a„pÖáüóÏGXX¶oßnÅ„B!„B!„ÂÙp+üÇ®IA:99ÙŠõ1MFF†“;\qÅúwþm ‚q:ðÓO?á†n@… …%J víڸ馛0|øp+•;vìÐyuçwZ1gÎöû !„B!„B8×qÆ¥î]»váÿûŸµ—§KÈ>]¿óo믾ŠvíÚá‡~@Ó¦MñÐCáÞ{ïEƒ °páB<üðÃ> œäÓÙš_gûý…B!„B!œë8£ FñâÅuoúë¯¿Ž£GZ±!œ.ìܹÏ?ÿ<Š-ŠU«VaÊ”)xóÍ7ñÚk¯áÛo¿Å0sæLŸÑ±˜;[-çÎöû !„B!„B8×qFŒèèh<÷Üs8yò$^zé%+68üöÛoèÖ­Ê•+§Í~*W®Œûî»û÷ï·Rd™Ó°§ž)·…W^y¥NÓ²eK}~BB‚Þ\~ùå:Ý]wÝeÅx±~ýzÇwX1^ðžzê)mzT°`A­8µoßsçεRdaþüùú7øÌË–-CÇŽuzÆqDǾþúk}¿õëט–yÄÑ >+ÓÛÁQ€«¯¾ÚÚ^|ñET«VMoñÅú~„Ü'‚¹wnKþÚÑ»woŸ´&ø{=zô@ÅŠQ @mÒÅÑ*C„¿û3fŒŽ=z´Þ—ûµƒÇì÷Æßeü‚ tþ6oÞ… FÕªU­ÐõƒŠY£Fô±˜˜´jÕ ãÆ³R„B!„BMÜÍ64„³ ÿÄÔ3n"õàƒ¢zõê1b¶lÙbÅúÇ矎֭[cÖ¬YhÓ¦ yä4iÒ#GŽÔáîÝ»u:޼ð ¨R¥ŠÞ§ )þ¶mÛ"55¿üò‹Þ'(Lþúë¯zÛ® È>Ïœ8qB ›o¼ñ†¾&ï§k×®Xºt)®¹æ|òÉ'VJ_ðøe—]†””­ÈPøŽŒŒ´ŽfGn»í6-/^¼X+UþPªT)nݺ5¨y,¼iBEP6ó«qãÆ:^èÞý™09ûôÓOuN:—\r üq­¼:t}ô‘Nãïþ¸o"§×'†о}ûêã€СCÏòå==óÌ3ÈŸ?¿NÃç=|ø0n¹å­$‡B!„¿+W®ÔÂf‹-¬_|óÍ7ú8ÉŽ[;u§ ;)OlgýµÃÿH§)IyÓ f§¨[lN×ßùGÊÇs† ÌS©R%½=qâD½ã7ê}R <*=éééVŒÇ³qãFò<5kÖôìÛ·ÏŠõB ÿžˆˆÏ 7Ü`Åxqùå—ëßqÂÏ?ÿ¬¯=pà@+Æã™9s¦ŽSÊ•€nñx®¿þz·gÏ+Æã¹çž{tÜ}÷ÝgÅx±yófOÑ¢E=QQQõRZ±ϼyótzR)V¬/øìJû×Û|þ~ýúéôݺuó$''ëø@8uê”G Ëú<¥ x”bæY»v­'--ÍJ‘¼O¦W ˜ã‹`îÇTÅ·ö|qÇwèã;wî´b<úžòåËç)Y²¤gݺuVlöîÝkm¾¿Q£Féãêe¶b|áto꣠ã .ìùý÷ß­Ø,È=¿õÖ[VŒIIIžöíÛëºåt^!„B!œíÈÈÈð”(QBËV±±±Vlúöí«Û9ò³Ï>³b³ðÓO?é6²]»vVŒÇ³mÛ6Íÿ:D>`ÞQ¦5åU­[·ÖiœdÜ ¯¿³k×.-Oÿ8ã#{ûiªôý÷ßëžy`o¶ñî»ï¢|ùòV¬W]u®»î:L›6 J¸¶býƒ½æÔ¼Í‘ n³§Z̶äGh"T«V-mÆC°ìرÚd†&4&jÔ¨¡{™FLxLpTàî»ï¶öœA[4ûàƒôoÑ\Èß(‡‰B… éöîs„†=ï\p¾W1/yo&T°¶ü#˜{¼õRê‘€ºuëZ±Y ©” ØûË ”¢ˆ† Z{^pnË—ä9ªb‚¦jœ?Ä{¢iUÿ ˜f€!„Bÿu(aUË”­h*lÇÏ?ÿ¬ÓšÛvH-J4:—L¤:uê„={öèy­vд~É’%Z>=[ ”!-Ëþ8+ ‚æ)„]ˆ³ƒ¦9…ÓDFH“ «J3ÓéB"•›ßÿÇ×q|Y(Pr¸°lÙ²™ 'Js®¯ÃáA ¦Åгb³ iùûv4kÖÌÚrMµx¾LÎöçmË ^x¡¾ïåË—ëßèÙ³§ž·Ây)4O£¹M€rŠ@÷žˆ9Úµ×^«Ã3§gb¾‰y™S}›0a‚>ÆÈ¿"Tûr•9MÁ6’ž¤Roñ4šIJZ§.'`¹ðwXÇó6º!„BçD9°+üŽ“4 çÜÔyóæYG²à¤`8ÍÁ0çHòw¨´)RD;¢¡€¾aÃ+eĉNkhJO™†ó\)ÇÐ#fll¬•Òöûõë§çm²™&ã]ºtÁŠ+¬Y6Ãß<Ì@èÕ«—¾/š{ÛÁ8¶'ö9½>Ã[o½¥å½óÎ;OË¥eÊ”Ñ÷+ò‘@òv[(bÒör*À¦M›ôÜVþ^DDDf»hŸƒAÓ6ʽŒc'½·ß~»>6dÈ+&0΃Â<{ê91Y„6'ˆ·)ÆË/¿œT@XÁŽ`|q(ä°ÂSÉ 2 / .y¡DÑ0_"*„}4EÀ—€pâå˜âââ°zõjýr.G^pñÅkåí«¯¾Â¶mÛt>שSkÖ¬ÉUOm {Ï ˜7,3:Spz&©oT4œêG­rZßÎf#T“ÆD¾|ùtþÐŽ× |¯¸ $Óñ·súû§l\ØÐ±q !„B8 ¡vCä§å?þh¥ô…Û<Ì`ÀgáÚb3fÌÀÁƒ­X¯ -Xøln#ë֭óÏ>«Û@Þçc=¦ð°,8וó|~™ëÁû4;<턜KÙšNu8— åIY>´Ú¡ìÍãTL¨  F¥-9(+s.jÐP‚õz°Ì9‚-[¶x"##=Jãô¤¤¤8ÎÁP‚²ŽS·þæ`JCÔ÷Ã9“&MÒÛJ“ÕÇTÖû´±W®çx¨@#þøã}œsœ *ˆ>nÎ ‘y J°·b²Cæ`ðüèèhm©^bëèéúpèûhذ¡ãñ(AOÇšƒáïÞy\}0¬=_(\7ç`4iÒD—ê¬wº?νàq';Q¥<êcv»E™ƒ!enBiòú˜zá­˜ÿ&¤\íycBòžõ2Hzõó(ÜÓ´iSëˆ/ºwïî)P €G}Ì]Ë!'òœ?¾B!œnÈ|·Ñ£G[1!üÛÁï4eœÃ‡[1Ï-·ÜâQB§–Ãþúë/]æï¿ÿ¾uÔã™:uªŽëÚµ«ã…9T u†s(Û˜xê©§ô±7ß|ÓŠñBæ8ð÷vïÞmÅzô\RÊ]<¶lÙ2+ÖãIMMõT¯^ÝS°`AR(¬X/8oW)&ú9͹¬æaúƒÜå©E‹éí×^{Í:êñ|óÍ7:î믿Öór¹mogOž<é#W 8×·B… ¥$Y1Ypú´½¤R¬X_¸ÉÅJÉÐçQ†c™s^l¡B…<åÊ•ó(ÅÉJΚ ‚f<ð€îÍ´¯0- 9“ºï™?pXˆàyN ç)jmÔÔ©1r˜‹×!d´‚Ú5ç‡p:jêŽ0=Gd4ÄŒ~Ø5û`A”6}´¤öh.Ë 8H˜ù"yE3³Ü‚ž´Ä“— þ&G‡Tåµb¼2uëU0èþxmÂÉ ®ÓÐh °7[½„y6·9—Á^öˆ0ÿ•BnÅzqäÈLžŸ=j|žÎ H½²ž—.]Z·n£uN0ÍÄ ·hbÈvJÒ:}ãryrû;üŽ Cøo€2M‚En!¸ÍÖº»§© å$l›–póÍ7gëmç7ž µ€¸¦͇”Ø®æ9A •Fÿþýõ}› ¥ GB¸˜ŒÌ˜pš‡™л)eBz4p”…mç»ïµSûÇ6…çqDÝQ´ÊÑŽ`ÁQŽt(eIuïÞ]·³_~ù¥.ûœà¬R0V"5ÑÎËÉì„CcÊ¡+X¥ Z±Yà¤eÓå,Q²dI-ÀÒ†Ï ¬¨†¢›Ü‰'êJÉk´Á£ÐÂIåœk!Ȧ»õÖ[õ0¡Ý])‡§Þ{ï==)›ÃS¹‡ô~úé'ý!§©T°Â.ו ½^RR’“ÚÛÑ­.Ágˆ€î–WÁ€B9Ïç=›¾wï^ælÛD–Í 8ß—x4[»v-ž|òI­|æªQ?#P2›‰”€î@y\ÈacÇŽÕ¦Tf»îºë<>ú¨Gi«Úü†¦Döá¤#Fèßiܸ±çé§Ÿö(AÖ£´1ë¨*C3¯g¢SÂQæ±~øÁŠÍ‚^õ5yœæ ª0ô9VTÊ‹ç£>²Rz!æ(Á˜H™X½zµG 0ÚdŠnááûï¿××á°Ý©*áKC*ÁKwñX­Zµ<‡²Îð¢eË–zèL5’õBêü¢)̽s¨çsˆ’×âu•Òá)[¶¬Òãù¦‰AS4æ]úÒd†å¤´h*³ ú»?âöÛoÏ|6%8zúô飇Do¾ùfoÿ=&R„Rõ5å7ižÅ2æuhöÃøñãÇ[©ÿrµç‰ÜšH‰¹œú@y”‚èQŠŸÞ'êÔ©ã©]»¶Þfy2½½Ü\*…Þ1ï•§ i«ÆÉÇ}´À­ŽsHõ‘u®¬ Öo¦e= áÜËuÁùþ‘NõË©oJYÖ¦‚7Ýt“uÄJøÑælc˜Þþ Í)ä=æC87°k×.]'ØÎÇ×û«V­Òûć~˜GÙÛN²œ?©œ¸‘—zêTß¾Õ¦¼æF¾›/¿ü²uFÞÌjM)âÈ‘#ú=îÙ³§gРAú]ñn&Rß}÷¾'Êj4§üñÇõ=ñ¹”B§Ï±·gN¿#¶—í“M ŒÃß ¬m.äZÁ -×dà| ÚgQð¥=mÖƒoÜMÁ`CΊ)i»‚AüùçŸ:óX‰)”r ¥qéy¬t&x>VÞ+•§‚áï1ž×³Ïu:ft||¼ë‹'NèÊÄõ9x?¤¸Ž†“"à&À˜8ÿüó9æ;• ïNÊŽ ÎSá½S nР.£|ÖzôÉüÆoèµ2ìà\*nL'e „`î ]&çVðEãuù²ñãÅ2ãï9},–.]ªí8Ë”)£óš¶’lt9/Æ„¿û#X¸® HþËäõ×_×6›NeOá¿áÏöŸs‚hwÚªU«ÌµMX÷(4¿ûö“ÿ&H¹º}°ˆ¼*T¸?f̽OûXîËú"n †˜çLOí&‚U0Þ{ï=+Æþê8ˆ˜˜]G¥#„ @FF†•"„s,{~7œ Nß~û­ã©o·Þz«¶wç7Ë´'Ö¬Y£Ó<ûì³úÛÍmû7”J|‡ø½c'É9‹¬çöúÉóÈvG@„qüöñ] ÐÉïž-Ns0Þyçg·Ç'Ø2¿Ø™ !œ]àü–ç;PØe§­ Εdóû'ßt'AöL)œ/ɸ`eQ"P›ávƒ ¼CÙ‡íßW›‚Q¿~}-G;ÍC•uÖr£`¸ÍU%ü)¿üò‹îðåýówÌõMr‚\+nÙ+N-päÈ‘ú#&nÜ` !„ÎNäFÁàˆ?Ì&9(°+TüJ—.¹OŠ‹Sn •ú!C†h…•£‚ü(2ß! ièÜÁ þ ⫯¾Ê¼6?Àö?C87Àòwk 92ÇãöÎ'H}»í¶Û2·ß~ûmë¨\h• >ß)7ƒ×¤ Â‘UŽT?ðÀztP~Û;U5j¤q„™udg‰@ŒN:éN-޳W“Já&,²ó‡ñìéìß¿_`³‡6g!œ9Ðr€åÇòeG©é F@‹vþIZ»Eq¦ Y¸Ù\<9µþà¤`ül9÷á÷ÁTÀÝ ¶ƒlßì`çx½zõï¿M™Û yQ08ÃÎY*<ìÐf;Íßb'mNqZM¤˜ühñCB!ü{À?"üè¸+Ú3 {¸i,Lš Š]Á ¤w‰£Uvs'ƒ½§4 a<{>Ù ±— …$ÆÛ?ÖÁ*n¦! šPÑaš|Њ á\Ëß©fO=Q!à¨m ˜ Á³ MHHð+VLˆn †“)!G.¤¾ÿöÛoV¬þ7B zt¡u™–Ö eçÈ å‚6mÚè´!Sg?dT‚ß[†N#½i£²H«¾N,gJÁ ©5jhÙÍÊcÉ’%ú½œnƒ Ç”)S|FëÜ ¾ïlSÌ|ä»+fÀÌcû½±³Îž¿‚¼(ÒAÀ©-aøM¢õó-'8­“¼ÕÍêI7NÞ”B!„³ôÎD(á@‡NI² dïÞ½õk“œÜæ²ú;=UÐ3…xq™¤‡õ¡ÔžÚ>þøcí €“³ê#jmõÍÔ qNèæÂOv§!œ;`}Pž<ÊÉÿô†Ö¾}{]·è8€6s :Dà®R¯èx„mª¼;nP†µ•Þýù³gÏÖaNÁ÷ÍÍÛ˜–^´èø€ |Ñ¿?'¼ÒŠƬT!œ­‰Þþù§íŽm% k'=›Ràgz]¥’1Ïp/öû^¹r¥þ~Ðkªéf— âö^@ûôécÅ¥Áä bƒGrH˜€8á9„BøwõøÓÖÚNøã¤{©rrv0p2‘"hƒÍ¡cû‚FN&RãÆÓqö…i®U¹re}Ì>ÜüÁèxÇ;!iˆ›‰ͺè$“]ÅÙƒj´tZÚ©‡pnåÎ÷!”B¡Óš4ë¬ÝDŠà$išxÐ$ÇL{r'©ãÇks ÆÓËM÷h^Á:LOzŒ·›KzÜL(Ì]¸@ÏgqäB!œ;Èó‡v裞=2ôIÏE¨húB!ü»ÀáX.fÇž†4­ y}xsÿþýºGˆ#yG18¬ÌH‡‡kÔ¨wÞyíÚµÓ×g¯M£Ft/©8¤Ïž[®KÀµ8tLææu9üÎõ¢££uü½÷Þ«‡“¹¸ï1„ì`Ϣݔ£_þÀM®ãC¿øJ@hÅGšKpt„#ôÏQšò7þipí%¾/¼w®]ÄÑ ŽŽ†Bç¨eXÛ§ØsA*;hJEóÁpõëBø¯€ÂxÖ1ÿ[A»Z.ùý÷ßkó>Ÿ‡ö \‘öåÁ‚ùÁ•‰iÌâTd¸X‡yÍŹÐ"‡nijBS$ÚÐÒŒ„4%áÂOví«¯¾Ò&*| ;tÄdŠó98 MûáÊ•+ë8¼• kЮ¦ÊÇ©DÐ>ÖDll¬B¦ W?uZê¿É'üúë¯92¥¡ÀüÙgŸiéiÓ¦Y±ÿ.P‰5ëUn!ùJ³;ÖK‚Í2ß;wj“+ÓôïÓ’%Kôû%õ— PÒ”Švóv“š(=ýôÓzÎÔçŸnÅ}ûöÕ 4ovš¿Á÷Š6ÝnÏG³šK0ä¼$´#§I ;(Ø!ÁïÍn(Ð3„B8@ãtBµÛ´i““.ÇK†â•¬ã!„ð_„˜òÐ䆮zMÒµa°X¾|¹öHB/CôXòoó"©@p2‘"¸M ím)M¤x]Ó´‰.$ù\ÍC<žÙM¤hvÅx^ß ¹5‘7¡4̰ÖßE»è:7„B87pÚG08ñ„=‹œxbïÉãRèì}çk²“W]¹êoU1qÔD}üïÐÏÎÅkŸ Ï|cï±³åNï,}݃ífºBÿfHO;½9Mºlnø~°—¦µœŒ9uêTëè¿ ç†?8`Ð|‘yIë.]ºh³ÂÍ›7kÓ=Ž¾Ñ¬Ï>‚A¯RYàˆ Ë3&&F›3ÑãÁ Ž<Ò¤Ë N#¼'ŽæÑÑÂï¿ÿ®½JÌ#ŽJÒ|+/õçߎ¿ùæ›z´†rË„#EN´&L˜ GE9ÒÊ<»à‚ ðÄO C‡VŠ,pÄ£²Ìcz'£ k¿~ý¬£!„p‚ Fn@_ðvÐgýE]¤WuZ!zåʕޞÞ{_T| žšƒjzŽ%³Rü}8“=eçâµÿëϧ`o7WÂ?pà€ö“&¿yóâïÁpƒR0²`œTݹsg½ø#Û`.Ü¥„R½Þ ß>‚ApÑ<®:Î…¾˜Æô«Ïêý=ŸR,ôqÁ`}hÞ¼¹Žãªâvð~¹pW†v›Xþ_€8·àªèœÌÏm§‰ð\_‚ÇøÐòƒ‹”Êâ‡ß}÷•Ê q&Áuƒ¸°±Rèôþo¼a¥!„³¹Á¸á†´ß^öJT¨PªÁÐvÏœÈÅÉ¢ônǪU«´‹0p¾ZýK4žx÷ ,8´š @—:]¼ ÿ°§‡.¶ÎÎÅkÿWŸ99-Ïüü â“ãqøða,¶šð:|þÔëênåBál]‹oذÁÚs]*TÈÚËêi§ ÔøøxÝãJûzº/Ôßõ`{Aw¥ad/-çâÑ.ÿß:‚BNHIIÑ£JÑÓíç¯9ÍSá»À5C8IÀw¤bÅŠú=ãœ/‚óà8bѪU+Ÿw…sÖ˜f÷îÝ™kùChl'ç¡j5# ûÈ«¯¾ÚS®\9mOË^ ®4:mÚ4+EvÈFÕU=½èíÙµo—ç†q7xflšáyjÎSž[¿»Õs(>ûÈÈéGVÎÎÅkÿŸyí¡µž¶cÚz&¯Ÿì8{ ç“Ÿè‘<ÖeÖiÖíÐFg;ä;ˆöºL—©ìA¥í=¿ó´ûW ‰žK±zõj+•;üq½ lmXØuhÆÍ¿×ì‰Ý‡W¡Yí[­#@Õr-Q0Ê}TfßÑ?q"~µç…Gý›½òU®€>í&X±À2›s»¤°bèÍÈW°*´ìŠƒ«~DÌyuq`Å4”¬w.¼3ËÝx³eÖ†…`¯{òÔ>Œ˜Ñ…cÊ£p‘ 8°w%.mó"jÔé¤sf<‚¶³æŠþõûX¬^6iJ&nÚúa\Y1+?ˆœ<óÚìk#f"ñäAü<¬"ò@¡âpÙã­#^ØÏµ×OrNý:7[IÞ¶ûŸ¸ÕgêW0ˆ„Ôô˜Ø·|-+µÄë‹^ǺÃë0¬Ý0”Wt:À•ùBŸ œ‹×þ¯<óÁøƒxà‡pYåËпyL\7s¶ÍÁˆN#|à¼(¡¡ëN‚q—œUWQuÕW V­ú]¿4èºÌ•Ì¿ûî;}m·N!®‘Äõ‘LwÂ!#„³òžøC wÄŸ‚A[¾;T&|gé¶Y” ‚¹GŒÔÔT+& eË–EÛ¶mµyz Èóœ?q% Ôw¾ç-WVFõ¹;°£ÛÅZ¬6c½uÄ‹¾·6öí^†/>n6×¾f—<ªãÒÒ’1òÝ P(º n¿o±ŽT°-$¿yï| Ÿ|ú´ŸˆI‹Æ+wäͬyë¾Ex÷ûËЩū¸æâ'­X`n[kÃÂÆ‰¯bý×ϢͻkS©.fÝ]í>Ý…•ïõÆîùcÐñËãÈ]T§m3G~átÝ´ô$&Ÿ@\Í2د”‹Ñ6E§®£qáEYuàý7*£ß ï3ŸŠ?„OÞ©f—>Ž…sžÓyz}UožúƒÛ3/÷ã1|á‡7c×ÊÉ(]£%’ã ó?­#^Ø2'x22²Õ‘¤µ«tœùNœ q*åºO쎧.y —T¾üÿô8z]Ø ·5¸í´Žf„B0˜±i†ý:L+º–½ v,ÀðeÃ1®Û8ä Ïg¥ò"/ z !„Ó…±cÇ¢W¯^Öž/²êêlܸU)äßYG¼8y2 . º.s>½Ûp=ÎϰƒJ… *!\ QÀÞTöÓ;mÑéÅ(„ÎÈ{Âw©n]o¿`ýúõú›ƒó˜¸¾GJ8‚Á÷‡£T<¸þ½{\¯„#ôNeçÒ['ß­@FÁØÞõbT´»ï¿ÉkW¢ÆÂ}Ö/LãçŸÀò%ÿÃ#ÏCdTÖ{¿tÁëzd£ß»S´¢ëOÁø?.{OôX[»šŒ_ð¯oÛŽ1YëÙŒµcžÄæÉo¢ÃèÈ,Ró»W]©ã·LŠN_Å""ÊÛÑŒ‚áv]bŸzüý{V`ôGͲ)Ÿ¿1úô[©·gLêƒ#‡Ö£ËÍßࣷ«­`¸]ÛMÁ8¸a!f¿Ù1ej¢`Ñ2JÁ8¦Œ?¬£^£`ö:â¤`äy%ïÓ…èÈhŒï6¯þò*–î^ªº·ÌÀøè:¡+vŸÜm¥Ì8ls¦p.^ûßüÌ4ÛëÿC=R1ý–éº.þuè/¼¶è5|qýÙ”‹¼‚=¹ÄرíÕËyK6^viE¬\Ü+æuÊé×cù¸k±ì£«ðÛK-ñÛƒ ñëM5±äòó°øÂRX\©0•(€EóaQ¾0ÌW¿Ëo䊓G+þOñE:£ä¿W+6U¤±LÅrŠìûæS·XB±¤"ãÉ2Še™–cŒdE6'B:¨VRäoóI¹¤›Îk*ÖR¬­Èõ±¹M2žÇ™–çð\þ×âµIÞÉ{²³´å„\öËÇgå3óÙ9PÏþ¬"ŠÙ”šäqžÃgæ=³Ï³bEæ1óú]Å/Y4$bŸe+ÅEùT9E¢’%±¸Je,ip!–^u~½ù&ü6àü6ä%,ûx8–‹?NÆŠù³±rÉ|¬\¶HÕ%Ù8vì(õ«YuÊ?RгgL:҇Æ=gÛ¶mÓ#oNÊ!èš”‹Ç ÷íÛ§•.òF7ž!„p6¢nÝjJ`ªçCÆå7Ýt“ž M×Á|7èF˜ŽhúôÌ3ÏX© ß-Æ9fU§cÔ;#1iÇ ¢H1= §ÍD¡üйãàþÕ(Q²–rA”¯ÈÖ„Ç×a |5÷Nì;¶Ž(ˆ÷”±ëWèÎ ÒÓS±zËT+×:›oG© ¯Ôáªúâäö5ˆ,\{ÇöY£ZÇ™ÊE0ÈÉuíˆ)ÂÃ;ôçê1hÛ‰-sðÈéµ32Ò±llÔ¼ün)Ë–5g:’²kkÐuä¬ÁÄ%Ç鑌—®x Í*zU©G6â‘Yàú:×ëù¹ÍÍÁøgño}æßüŽÇf?†'Z=v5Úé8*·wL¾C+À¥£)¢fG^F0²Î½EKQÙ¯›Œ©:Á“”¦^TxN$Ás8ž½§ãàÙŒ½ñðLŽªøXÕRéRÒ‘–’¬')²ÿë¸âQÅCŠÙ÷ÀmÆñÓ$*òƉ,ß8“ì™0· Ùȶ™NBó|“[¥é應ø%$¹â€lË1ù€9}È‚‰ãsR¡ Ìß2i^‹$$̯H%¥€"*%T8Dñ"©ì0ŽŠ ›c¦½MñÛÈH„ˆ E#¬h„•,°òåV±‚bE„U:aåÊ"¬t)„W¥]Ø›>¿ºjD„ú_¬ZµZÕ¥V~ëaV}›¦Ò\`ÅfaÕª¿Ôñë²ý{VK—ö­ÿkÖ¬Ñ^r¸"7W'èQ^t¸C>¥@QˆZ½zµ>&`³sÏ=÷hEˆÂýÿSé!“ÂòŠœ˜ò~ýu¹ë…w”J½ÿï½Û•r¾Ÿ~ú©¡0ÁuLxm¾7Ä隃!Ïã4‚qàÅûpbÂ'|1õw%æê®(÷ò'ˆˆñš ÌŒOÿw )ž}~²b¼8rp>}ï\{ý4jJ—¡^ØG0¶XŠy¿C½*ðË_¡Qõñóê·‘œv Þ¸ç•În¾é†¿vLÇ'3:£ûåá’ îµb½°`¿‚M“^EzŠjíøÌJ¦¬ÝíYÔ½åe+…F0ü]—ð7‚ñí˜ÎèvÛ|ñQ ”(U»Å‰ã;‚Áðwm§Œ s>ÀÅõomÁ’OïDjRlŽF02ëž­ŽœÕ&R&N&ÔJÆ«W½Š‹+xm Ó•öõÁòt¯òÿÚÿÕŠç¬Ãþ&cý8¯ýo{æ OÞYú–í]†:|©HO<ŽnßvÃ'>AõÞ!k'[·unHÁ)ÿ¤‚1I¥É>pÕªµêx×l¿A×™|¯Z¶l©]p®[·Ÿ|ò ¢¢¢ôjµks º'– ÆQ€£ ‡r;#dRÂéBp¦„³Ô{ÐÀŠõbÕª?Ô±v~ß3ÂMÁàû‰°ü±V´Mp‘=.RÈ>â‡~Ð&T\4‘s™\l‘f†_~ù¥ë3˜çqR0’·oDÚÁ½ˆ›=©ûw#,$ʽðò•ä—+ ¦‚ñÑÛÕQ²t]t¿cºãÅñcÛðñÐhÛñhÚj€›]Á0±bÓ7hR«'ŸÜŠ×Ç5@õ —áëÜFØ1zö-X³í; é½… ð œ'c÷ü±ØóË×(ß²+âv¯EZB,vþ< ú¾‡j¼ M ×%ü)k×|ƒô´$ÌžÚ÷>ºI›“åDÁðwm»‚‘“Ÿ¨…ŸE½ö`ûÒo°iþˆ)RGÈØ™²Õ‘³ÚDÊDÑEuoñSsŸÂêýÞž¯ˆðíiŠÊÅÃ3Æ{¿½§…Â`q¦„]â\¼ö¿é™÷ÆîÅõã®GLdŒÏ(E’zùoýþV¼Ñö ¿ÊE!ü;A³ ªžv:›cÐûGh'ÎÕž¿ýö[tëÖM Q¢\af”9·óêÄüKÌÓì¤ÂGó6*tlú¨àѬŽfv¼KªTìm¢È©´-éóäÅK ^¦x¹âŠ4ª¸J‘4)$¯±ÈqN~1dŸÇ(Ó0=Ïãoð÷x ^‹l¡Èk³-§A Éûa³ÜX‘â,ï“f‹4f Òͧ¦º&f‡TRMóC>ÓòŽKñwø»¼¯Í{0ŸGÈûäýÊ3µW¤ÛQ‘>o®Sìl‘&‰\­Š”8'™–çð\!‹d™”x¹–I®aMò·H–!÷yŒ÷Ç2às0Ùýx¡"M*™?4:OvPìrª#bÔœ)!»5ÒlÌÛêí5kÖÔ+Ásn…‰={öèù\ ]@Åžs”>úè#+Æ îGGGëÑü"ªjmD·¸ E:Þ‚JMƒ'!{`©º#_¾‚HOO¶ö²žÊoû@‚],^˜µX½GE«ãª]°yï<=Ê ’Sâñçö)¨[©£oÇž_Æá÷ïE£Gâü¶}Q¡ùh¬¶+_qÖ~9)qǬ”þ‘ÓëÚQ ` ÌŸõš_ö„Ï\•`Ókÿ>ñYˆ)…:W÷×û…Jzó;':R´ËmAב³RÁ Š(¦'Ó>1ç üq0KÃâÈÅä›'#*" ¾î¤Í§B!·˜´nîœr'Þ¼úMÜÛäÞL¡‡#f}¦ôAÿfýѤ›þBø¯ÁIpržú÷ﯣ’Aó Ct©i7mâ|Šôôt¿£ÄöíÛseÊ(fQœ#DeÂN¾Á²Í‘¥(E ã<‹]œçC“£MœWÃQ%“N)›p“T`Lò:澤3C~Ÿ×´“÷"佑¼OÞ/É{ç3ùLl¼åÙäùü=£y/¤ùŸäŸùÁô¤Y'ì”YtÁ™ØQᦠmÒY ¼ÿþû{S§‰¹¦+’þ\Ž]½©~úbÖ”±fÅgÚ<*>Ö;Êr`ï*mò“pêâãöë¸Â1°pÎ Xºà ½/8·K»p=p<ËðœÕobÁÃ1yñ@+|žú~¤ %õ”b‚NKoI&8â1vîzûí“‘š–ˆ&µzáóY=°f›wBÁ¡ßgã×W© {±}æ‡(Ví"lúvvÌùLOø&Ê5½éÉ X:¤’cè8ÁŒß^ÀO«|ŸcÉú‘HIK@ŠTÙ³ Ïá¥+-[< »wd=ÇOÓú«ïè)Ü÷»¹ ãNzÝÐþ¾|$ýõ‰žg!X¿k¶Î Â|æ ÄÒuŸéxÁÑ«ðó°ÎHŠ;‚Ø›±yÁ§¨Ó¶?V|óVN„5ß½¨Á •χ6/Áœ·Úãä>_—ÌÇÆÇ¡·|Ÿƒó0X_iG éeºŽÐ9ë•g­‚A”PÞ¸®ãðè¬Gõ$[AxX¸?îô±åxsñ›HË`ÃBÁ!>%wO½+ö­Ð¹ë”ÊZ€='¬síª·CûìcûgàQr'Ý“7w¯åïÉð@ý·ÈmO¦ ‘„&%ŽýBN´ƒu H´[_t ãvPx8pº.ãÌø`D 3½l;ý¶ ÉW§r é=\ö3TÊtMµÍ²T…êñ¨Ø ‹é^ªG…*•+ù‹Á‚‚’}ô‚d|!„à…ÓHŸcèСxþùçµ ;­8?‰û/¼ð‚žŸDp‚ë^?~O?ý´V08øÓO?iÓ'÷ß¿6GüóÏ?µÛZšXýïÿÓ^¨rŠJ#~ÀyNõáùã—"¦íõ¨0Ô;¢’‘DCY ôã^áÛD». a“¾([¾1ŽÙ¤¢8”«xnº}* E—¾=¿ét\ã²¶/¡ååƒô¾€’ïí8åŠgµ¹w^3—7èë[¿…£±Û?_ADEFdþB:mõ ¾ùAsª[ÛxC,ßô•Jƒ «vFŸvãѰÚõ:^P¦Ñ5hñtVGFò‰ƒê›šŽ†÷~ G0š<æ}f%Ì×½ùED¡Úœ…ŽÍ_ÂÕù>Çú]³P ².½à~+Æ y¨Æ¢YëGPéü¬ç¨P©9R•µyÃmEŽý”ã¦JA8²A)÷)%,ËMpÝÊ×è¼ Ìgî~ùhYÏwOÉó/ÂULÕ£ Ç÷ê¶dÙW°aÎp¬ýá-Øð3Žl[¦”M˜9ä­XE+d•QâÖþ(3Ð÷9 Òõ¥tÿQôÆ>ê¹Ât¡ç1Ö+;Îjƒ(Y¨$¾éú šùÖöõÉ\¹heLê> e£Ë¢ã×µk[7 hÓ(ÿAœ‹×>›Ÿù7õìüMgôjÐ ¯µ} ‘ìïÊÂÛKÞFÙÂeqG£;¬˜ž4%<¦fçÍ7ÖTÇ”€™š f¤)T)éJ˜Ô¡Fµì©¤YRööEKhQ‰Ÿ>¤(JXHHH°WÔ kÂI 'üËk³‡2XsÓ9¥•xö€ üý¦Óï8¥—üdþ’fž›åA36iRNºütY’Vùª:Àz‘–¦Ê_1MÁ05Õ™*]ðpœ O!„pnÁþæê·UÑËPï0ÉÑ OR ÕB­E6“¦¢aB„g7¡;aûï¯iÞ§I;ü7ãÌ4&ö8ó˜ä£(’ÏÌs)Ò,›duF².7’e™Ž´ô4¤+e!]}È3RRUªdÅ$†I:üfì8UGzøð‘ÇsÒ£)wçÄà@7´%ç*ÝÁ€9aµ|ùòzÝ‹† ê^\ _!„pv‚o©] gÜ¿ž¿»îl‹#¼Œߎđcûõ ¼áw”0X+n¨P©ê^pæÏ~ ófÂj¥h|=ò*Ğ؅+Ûgù°cÔ¬øxz'ÌZ1‹×~ŠI‹Á°I­•¿0:·|ÝJå«6×£Mkžä.¨qý@}Î/Ï\Šßƶ?ÄÒW:`ÿ²)¨Ò¦ ç,ÿæº þx‹Œ5+?×û›×OÕûdrR,ÊUhŒšu;ûðüœ ¥dÞ²õõèDÁH8ú"§Ï\ pIT¾¨ *]Ô9“ÜRñù ÖûÅÎËîìC—:ò¯P0ö(½a,îŸq?¶ÛbÅf+~ÓœªvÉÚèðU¬ÜçëK™öÃg çâµÏ¶gÞqb‡µ8¿Øùøò†/Q¼`vcœŸ¶þ„i›¦áÝöïfÎÅø'ñÖ³Í1éÓ¶>¼©}¤Ç§(¦"ýT*Ò,¦&¦!E)ÉJáHVŠF’R4’”‚‘¨ä´%¨&¨ß³“ƒÞÒ4в! é¤dü Õöm§4„}?7ßæ·Í´vNñ¹¡ÌKéóÅ‚ùÎü'¥<è±+Aåx‚Êt]fJÈNJOWe™†ä”T¤(…"-) i‰‰È8• xÊËøSðÄÇ£Gû«ñý§úpè³9Q0äÎìd|`pÆ«¯¾ª'šó¾P¹hÕª•^ƒ¦ï¼óŽž¿ñÐCáÑG/*,üõé9Õo{\0iì. ¦ t¾¤qJGø;fB&*;ýžw:(ßN$7÷è³v8mÛC¼¦ìéÎÏ;œÞ“àÞ‘³E:ܬ¤Àp÷¼òŽ}1 ùËWÆyïOA‰;¶R¹£ÓMcдÕÃøkõ—˜3ý!x<é¸éöé>¦@nhXíœJ:‚yk†áÛ…â÷-ߢQõnxÓ ”-žå4ÂVnþ1…Ê¢öy®¢\PªÞ¥¸ìµ%(VýblWÊÅ_Ÿ?‚S·£^¯WÑð^߉ônæº?ÿ> ç>¯¯U½ æußëý_æ¾€¤$¯™\n›gvß–ÀoL^êHžÜÔ._¾\Oò›7ovî܉’%K¢E‹z"½$Ø‘åö-ç®<ôøsÛ÷·adç‘®®jŸ:ŒGg?ŠJE*áùËŸG\a…ðßÀW|…±ŽÕîgÝê ½•=óó3zd£`¼_òR·åÜEã; q=Ng´!ÝšGÑíl†R.Òc•Âq\ Ÿ‡¼E${%ÌÐ$!!a?N:G åƒÄP†v2Þd^`žoÿ]7 è,–G9g…æVœxJõÕ> –S1)ÊdTN4Í—??Â"#^°" FD±bÈ_º¤bä/§X¶,ò•*‰|Å‹#¢H  T飖/Â"²÷­Z·Í{ø_a8«®¾¦ÒdßV­Ú®Ž?°.ß|óÍ8zô(Ò”Bĉߴ÷ºã¤KÍýû÷ûLL½âŠ+´[N±M¹æŸ=dÒ3ã…2\&ÿ uþ+²ü˜Î©.’rÌžFh¬RO©lšŠ¼Yw îKÈ8I/J*iÿ 9—çäsH]4)Ï)éxÏ û³H“rŒ0ïÁ|û¶Ìß2¯A˜ÛGžß3SqzG³òLÒKÇŠ þ#¸÷ä#•ÆWžYµj³:vÀwäl‚<¿•¼9©×nwoÂtS›SøsSËIÑÙæ-œ&8¹©5ñ×踠·óµƒYÉÛè¦Ö ?ÿ8W]ëþÌþò+ÜVò¬7Mnv¾v°+yÛqÚÝÔ¾ñÆzòÒÕW_÷Þ{O7 .Ô?¾víZ+ÕéEÅ"õjÊwM½K÷J;&Uì¥æB}œ›Á•ÁC8÷p"énÿþv=â5­ç4Wåbûñíxü§Ç1öƱ¹R.N´Òp81S(*å!åhRŽ)žHFÒÉd$Æ¥ A)ñJ™ˆSÊGlZN¤gà¤jU«TSý.Å6Q ¨`Ä+ʈd6´^Øè’iä¥ñnÇœâMØ÷íë›÷!0ótÓ¦dÛ¤Sz{a AÌ[æ1G*˜ïÌÿ“Š, – •<ò¸ÇƒŠéª SS—œ‚ø¤DU¶§‡”“±H=~iÇŽ#ýÈ1d9ªx‡³Ó£ÒÅœèüÎOš4IO4eU0#´1çšE‹ÒÿOÊ•+—+·ÖTÖLOL¤8&°×eÙ7I¸ÅÙCóx00Ï1ɺ!¡ÐoOë„=N~פ©œ˜û …öãh¦ehÞƒÀþŽ˜$Üö ó˜Sº‘0·í0Óš4ßE·x;ƒGÎL¤¸â=ÝÊnܸQ+„›N¹‰&‚\ Ÿ =MU©REÿ†‰#Fè÷s˜Žîl9ÉûÍ7Ïu„¤µ+±ûîöØÔ´(Žüï쾫’6¬±ŽºcúÄÞxí™pWÆÇzÝÕºaס•øpZ{ ü´(¦ÿú >˜ÚNOò¶#9õ”vË´ƒF–À€ÂñÛg…íÀ±õ:ÝãŸÄ¨´%1fÎíÙ\Îß¼k>釹êcZÏÂØ2åm,»Gæ¤ï@HMOÆ”%ƒð̨ xtD! Øv7ÔÁIðœ¯2üµ ˜7k^Å{û–àÎ=tb3FͺÏ}Q ˆÆà¯ëbæòW’Æn¬œ!51cz‡cê3çÎ%o^‹½ß„­×TÇÆ‹¢±¹Uiì¼írÄÏó]`Ñ ËJÞ†£ÖN*YCާgX‘=ÏÇÜ0çá’CîhѦ Ý^H›L9Mîý;ѹsç\ù{?8S×>S×MMOEýKëãÒA—êEc¢Üûª¨pvЯ·y Ë5´bs‡¼Ôm9wæ€Æ¸°¢XVgA»£%i®ç_$ŸJE’R.9’¡˜p2Éñ)HIHCªR68œ§ÒèeJýEF6‰üQèå(†ôªs[Vðf¦å9æ‡Ál°B¡@¶ÍЉ„=$äÚv!ÊÜ&í0°ïgž/¿gR®)$$dˆi MoØcÊþxY‡€!É8šïˆé Ïˈ|ù?2‘¢P P!*£X…‹Õ,T¤0 DG#ª`AäSéò©ôááJhá/øâ÷½{qÉ{ú­‡YuuJ“½'kÕª]êø®¿ñÁàÙgŸÅ–-[´Y,MœŽ;æØëj‚½µ?ü°–RS½J =éð÷ì«ûƒÜ?ÇAœº X¦$sG籢乓‰”¤#¥>ÈoÈ'ûBRW„"¨3Ê1³>™”óì”óä\¼1‘’ç2i*Îæ}›ç“rÜí9%$ìñd sö8sß)½ä Éü4UcSä義øHžÚÁ´áƒ{O²›ú3#ä14÷ãj÷ó«\УTïɽ1°ÕÀ<+§ ©‡²7Þ•IûœB¢JwêH"âŽ%á¤R2Ž+eã˜R*ޤdà°R*)eä ©>ŽÕï’2ŠÁ 1—¢b!fRfƒL˜ÂIÂ焹 äìßvûï™4»pdîË6i ]æ¶ìû;n'›÷+(sÌcæ5 —˜ÿ2rqÀàA~3UÃ~ˆs”pr,Q•kü)Ä<‰Sª¡O<|É!uÿ¤íÛ‡´½û¾GQ)ÙxÈ·çÓ?(¶Š8f’ñÎàœ ö²’T.rv:qR7MGÆŒ£¬ë®»NûõŸ2eŠ•*x0¿ƒ¥)lrÛ¤[¼II“šç‹’à”Ûn”sLš¿)¿kn“öß¡0.d½ôG~ $ôGóþ®y¿¼>?aÍ÷Åm_Î Dó|¡¼§ö÷׉ÁƒOlŽ^ŒsFdd¤V.ý·trмys­\Pù¦i•8Ç• ü<`ÅxA··õÚ?‚úǵÏz¯»ê[ßë,^A)¶m;ð¦Ÿy¯¾Jm ˜û3ÂÔ7%Œ£¢ã'kÖ(A~´•Há±Ç€;ÿýCHê9Ÿ~ùEUbU‹XÞx¨¨Œ¼ö:ÂÞxawÝ¥¯§•ŸAOX©œ‘—s÷Ïùi§N¢Ñà8¿Ç¨Øá.Ôüs”o{;/ª‹É‹GÕr­P¹L¿õSP±áµhûøhÐå9Ô¼¼/ê^Ý×<9Å+5Äú™ïX©œ‘³÷,puÉ}ªìÑ£‡ó÷¢F‰à‚{·~w+ij¹v]—‰*‚;~ˆnõº¡Ë¸.˜½u¶uôïEÈMíß ¾$Ÿ®üÍ~ #¯‰ûÛú.|cÓ÷ÿ¡?n¨s®ªš}¥Ò3WC)ÉûN!y¿¢¥`$(#þDâb“qR)^)šÙdàHº‡ÕwC„YQ.ÄDŠ Õk6gÒó'‚ù¹a#.aNÈŠ=Ž0·àö©3ϱoÛi¿¶ì3 DS8±óG¹Ág`^2O™·ÌcQ0˜÷¢dˆâ§• Õ¨V¤‰ÔQ¥`W¤×D* Ç#éM¤”‚qà ÒUCë5‡Ú‡ ¥hØéÉ‘‚!wi'ãÁ‘ våÆKÍfiÒñÍ7ßàÖ[oE·nÝðÝwßéEÅ(,Ñô*'`^ç„"ˆÛ)‚±Ð)öß&Ì}I'¿)‚¾„N¾ęé’N÷'Ûæ1Io¿†©˜t*}!d'Ê1IgÞ3ïGòƒ0ß=ú…æ;DÊ{d7év\~Ï~ ÒmD'xðéì9Ǹ܃¦‚´ðhÒ¤‰^dó’è¶¹zõêøöÛo­T^¬^½Z‡Lk‚½ÄTÚé !× `ݶ-ÂØë¯àÙ°aåÊ—]LŸOBÎÌÊ·/ýZ•Q˜R0n±bœqhã/(_¿-¢¢½×å*Ò‹•C™Ú—aÏšéHKκnD¾H„Y ›j¼½¡¾›tê„°ó²¬YÂÚ´8 3A)‚–-U%`-°@sî5€zõ¼Ûþ0q¢÷\cÄ5,*J)*}õ¨ˆg¯Ÿ™Ù¶su^ynZ[ q+,D–(§×îSy ¶ì[ˆß·MÂå h9(·Þ2ÃT½‹.qRý+6|'OhWˆ‚Cy\ÊþŸB­’µ´âÐë»^8tŠÍ·\YõJ=é÷ÇÍ?êÕœ98„'8‡âæI7ë2œró=?'†ü2D+¦=/ìiÅœHãdn¥DØ©ç_(Å"å`’%*3‰Ç¼s0ââR•0š¦ž?ÇS3p,̓£ÖŒ#ê[LÖ®\¸ÍÁpÜH8Å“„Sz ©‡"íÐ!¤<„t¥hdˆ²a§RF‚G²ö—£sçÏ}øÈ#Σ ›7oƧŸ~ª• º¨Ý±c‡&þ¢YçTpUb7|øá‡z«}B7G1Ø)ÅósÖ'J=6Cû¶P„t{œS¼ü¾„lÛÏ1…~»à/¡¹-ÇIó<¹'“òûB3½ùÛvÑXÒ¾OšŠ„¹Oò›a“ßäuä>y_Dnß5yŸœ(ÇÍôv…¤(vò¼àaæ¬ÉÜcëÖ­ZÀ7nœ6Ÿzûí·ÁÎÙÒ¥Kk³©Y³fY)iÁ³_›Ú­B8RÂQD¾;¹†zoQÐpl"=é|Gy,€g8i©Ø¹lJ×lÂ&§§§ Âp¨²r¼÷ºù" ©ßIÁñ=Á_—ÐÂ9ç­\ì«„i4mJ-ÍÚqÀêÚª,pð T&[‘.ø]ýŽRX ÛL™y Ÿ²g?Wò:ˆsK4¼R‡ë‡öEÜÖ5ÚdêÀüñØ;ýcTº~"¢;§ÉPmÌ· û£U½»±dݧVlð Ò—wq·bÝÌaØûçL”¯§8?ÈÙ{æ@ÇŽQ\i•¦öO¯#P§T¼×þ=Ü2é-tBtd4†µ†;ß©íð§n<3s$BÈ=8ÕýÛîÔz¶ˆp›t;F­…c‰ÇðhËÓçwÿt!ýd²v5›J™ SÉIHVŠErl ’âS‘ŠSIiˆ·¼HÅ*åâ¤úV’'”È# É>¹  ` DH"åíµ¿Åf¼¿m“„[˜SÈo §m§}’5Ä eÛ)Þé˜}_BóŽó”yK!Œy-s^X,’¢¸¦jÜèE*–^¤ÒX–)HPB{RB’ãâ‘«ÊýÒŽŸ@ú±ãÈ8v G£l<É+‹tôìYS§v÷á°aÞÅžìØ«qšrpr)M„Ë–-Ó+ W­ZUOnuÃ!¥ 9RÈ| :É $¯í”x3´§å]ˆ0,ÛfœÄ˶IûïºQÎgÈ'Åõ‚”÷ω’–ä¹òŽ¢ÛuHQ Lв`*BÖ[Q(ìÛ’†çÊsðš¼y~Â|Üý¼Ðü ùM*B‰sbðàÓ™¹F2.÷ˆ§½¿MŸhHÇ={öÄܹsµÒ@WÿÎÁ 2ázeãñ\£vmoï9M¢ˆáïÃCÅâ·ß¼û9P^öý5KÏ¡¨Ö*ðpEËÕÆá­Y×mvûûHWŠÅ‘mÞë&Ï¡ÒÄyDùòÞÐã8§ÄúÎd͹•r§Ÿ5å ¯ãv Â_~ÙÏUy­Ĺ%›¶Cõ;^ÁÑU?á·ûcÑ­Uð׫=µrQ뾡V*ÿX´öcß…NÍ_ÁM—åÜ„}Å7bBÿ2ø~PM¥Då‹oD³ÛüÿßË<ã¤jÔ®½öZ=ì7sæLívÐ:tè '›¤WNX21{öl}ÌŽ’Ðe› N`zê®§ð|“çÑsRO-DtGwº¤€ =ñw9âÒªR+̸e†veÛì®fè÷p?+• ª‘gÚE‹Y1^p˜ÿÎ;ï´ö²@Ó0ûsôíÛ7GÏÁ´ô+oBžÃ„ù&¸2îÀõ¶œs:ž#'åA!ät>‡€ÏÑéºNè1TÝ߆ɘ~Ët\Tþ"Ÿç0ß|Ž6ÿ€¹ÛçâõÏiR]°åÁkÕVæzõêécä# ¹OORô|Ã}~ëöºò}6•ºÖä7„B•€ çb)RD›‡ä"È¢Ôm'R 6CÙ6÷Iù3t£yžüi ÿ&™Û¤=^ÞMó7„òÛökržùÛò¾;‘%nnÛ)ß Ù6Cž#÷.÷Ê{"äýÀ‰ôíqrž%¤·+v𠇩x§œa\îAW³•rNpÑJ®tO¥]V·gZŽ:£‡ò[¹Âý›6wõ…gýzÚnwÜÎcïñ(/Û–~ð|‘¨Ò¬»ãŽÚm@ìMXòY_œØ·^{5ZüÉíH<é½nZjð×Õû¤É‘¬uÐÜžEɪñZµRÏÀò†¿‘›k¶sÃÄŒ<˜s ”­‚â^Žº|Š/|‡ íú`û7C°{ÊV wœJ:Š¿=öJ>Ž.P%rá¸n»GpõsÐúî/P±ÁµJ9LSJ¡ÿ÷ Ï^¤XÁ¯¹æm'8gÎ=iÉ Y^Ü=7œ¬9°ˆñÝÆg®ØLÁö¥—^ÒÛnX±ožœó$î½ø^=OãtÂsm'ÐUÝ/>e¿/Sï4õȧfšáÍßÔC©ÁàL];·× „µ‡ÖâáYc@³¸®öuV¬/œ®½|ïr¼´à%½^T>‡D‘—º-çŽ)”uOc3£õª²iãÊÏqjû¸:ÀÞoò˜ÚŽU!‹DÅ%ꤩçÉ ÎPÈß4C;M˜»Ù°“²Ï°‡&Ì8·mrö{:Á¼“„=$Ìß´Ó)Ÿ M˜qnÛíÙH}gØÄVaQÅRŠ¥ÃÃQF…eÃÃP2,ÅÔvŒºÙBêŽ#U˜O…Ùk ð‡دQ ¦¿z˜UW{¨4¾6½ÄªU‡ÔññA×ez‘âäos¡½Þ½{ë‰Ü4¡’ùX_ýµž{AE‚^£ ¨†•Êú¯¿þŠ!C†íªVîŸb•“ È2%¥ŽŠ)ž¤HSÐ$Ísó|ù ¡/ç,_ÖòEQ`lÄIóHaèFBBB®o†¤ýþì¡Àé¸Sœ@žyÁ8*Aå‚hܸ±ínÿ©¼p”CÖÚÈ-ÂhŽuà ðË"à?ö«)p67µnؽr²u¨À{”‰ÆÝ£û{Ñþ™Eè<øO-¨Ò]-aº© bf$¦R&Gwv傿¤×^ëµQß%»rá^ÇÉ”I®«ÊÕy8wÏ´Q¤ÆE>ÊQºÅuHON@ÜV÷ù\?ƒs..»°?NÄïÁÑØšiéIŠ)8» IîsçÜP¥IWÙ¾±Ü×ÉÉ{– \hoÚ´iÚí MHÆŽëÃ3 šÍ ¾r0nžx3b“½3ðƒAdD$^¼âE<}éÓÚýí—k¾ÔÂí?A/ ÂÖÆ[ÎYæ”`i©}Æst!XäTa8×> ¢Çy2G ÊâC`“þï™v^ý½XÀ¾ÂÏ$¸n…VlL³èÝV§Ò$4UúT¥\hRÁ €ªªª¦ú=;MaC„ìBa†öxs;§°¿Mæõ sßž6·°ß§¹ïïyìÇÜö%N ù*Âiò|5]v©d¨ž¤‰QšR0ÒÓRÈ¿¤R<(6ÚM?HƺѴ¯1jÔ(Ýe÷&ÇÑn¦ç7‰£ßô€ÃÄr©'v œâÍ}³þÛ·Ítv:ÁL+¿KJ=0·Ý(iÌóIó7í×mó|!k…¼÷²íDù>˜¡}ÛÜg(×0ïC ï›ó]±ï;‘°ïf)¿ÅPh?æÄàáôžäìq;giLËå(Îɸêª,†Û\œ+~›à>Mª8÷5¯+V a4šn-ž6WÝS¥J«Sǻۖ~…übP©qvjˆŒ.¦×W ç(bÿÚ9ˆ.Q E+w]AXÅŠJÚ.­´._%LƒîaíJ˜úöàºë€-[€îÝ Ÿ”²·i<\cÄÌYñ§ìÙÎõˆ)wç¦?˜©|™ðX£?žt¾‰Î8yj¯’a30é—xéËjš/*î<¸ ‡OlRÛU1s…ûÜ97¤[flþwøµÃQ±ˆºñ³n¿4à²m Ò  Áž{n­Ä9¥÷‡@ÇN÷jÙ¶Çæ1'˜ñþÎ'œŽ‚Ûs:å›'$ÌmÜ )ål¯BSà2>xð Jv2þß3¿ì4aÆÙ˾ ñ&Ìc„™Î|Oå½u£™^Â`h¦•ß2¿²o§ï–Ɖæoʶ\ß þê¿=$ä¸ỷ„S¼( <Ø `W0ç®ʼnڟþ¹ÞçyÜ'9W•à¨]ùòåѵkW=ê>lØ0´nÝZ+æ¯rM 4%¤ó„éJøï®„á‘#GjùŠ^§žyæ™ Ù  ðp­š=ô°éI±‡±ÝT¾øDDZó rz(ÚþÛxݱu¯ îºÙpcW¯k].¸gÁ3w.ÝßyÕptF)wZ°§Kàœ¬ÙÆEúxþ'ŸXê9æ‚y-Zx7ØÏe^yn¡ój#nó*$ìñ-80ïí¦¶pµVLvT(y!îºö{ÜÝar&WïŽr%ê£xL½ß²®wîœX¾vÐcØÖEc´×¯bêY±Ù‘³÷ÌöDñeà0Œ?Ðâ¼xöÒgqãèµä χ'/yR„Ü=ín½ÖBnF3ìƒç=诣T©éã F'8ÑÒ¯²¢â'©wM» /Ο¬ü±)êĵý!7Ïl‚«l?0ãÌß1_Oä¾ ÌÖ‘À൹¢7G ž»ì9Ô/“µ2çÙ ŠuÒ«íD"I–É·Œ4w“NØ,b3Î §P¶Ýàt/ö{õGÂi_B; sÛ„yܧ8BžÑ|V{œ[:Ñt+Ztj±;Ü¿´*¾ÂïðM×o0âºxûš·Q¶PY÷k«…¾!§ÏlbÕþUèôu'½ÞÐvCQ _ÎzExíûgÜ^öÂ¥U.µbÏ~P@´÷“Ùi ’¢h85öÁ‚Õ¬FfèÆ`!÷ —`I˜¡„ÚãüÁéùóB¼>Ÿ[ÄQ,XÞŒ&ùõ"ÙU"Û&YG‚‡[cü¿Nyˆ„„þ`¯#ÁÒº’áŠó¹Q½pÂüF(Ûæ1§øœ>%Hs?_„—eß'ÎJK†+ÒC8ŸO0[”üo“ýö÷Ž œâÜÀËJˆ9ƒ“jï_•ß¾}»Og«tÄ24ÍéEjÒ¤IZéàªÜ?ýô“w"¶îºë.¬_¿^›Ò-4=5æ\”Ž‹¿q’wÿ~Jš\ Lž¢S Ûý‹”Õ ç‹B%ÎCxD>¬S Ʋ/ûáðæ%hÜu®|Èåºï ^xñ±*@U‚JaÓû/¾•y:‰^`oþ€ÞèžRŠ×зõÂ{*SÕKbÌ¿àÊÞü *œ(n2Ë›/ÆxGwÆ~ <¬”!v¦O›Ž°K.±øA.Ï-~á¥hòîÄÔ¼{”r±éãGx`;jôyuøšÎ §yrN8¿ÅÍ*]86ýü~óÖ͆B%+ãʇ§ ^;ÿ£MÁÕ ÿ†¿1·z\ÏÉHÌ© 4…ˆð<Üâa¼Óîôÿ±¿žpœáá'2°‰Ò‹/¾¨C¿ôKv/Aǯ;¢Ìùe7«,ß1¢#b¢b0û·Ùî£J©-X¾ ª©âþ…V`Wè-ÊõÚJþ¸°ñ…9~æ`®4ô7¿‰7¿ 7MÀÕÕýñB™eШ\#t­ç·ñoE;qej§)D²öŠh*f#îÒÈ ùðG{9Ï3Îé¸ÀH¹o“æ13=>·$$$Ì83žç5iÏ3Nöƒ%!×åsQÁ0 ©âÖ–ýuÚÉtÁƒW¥Â¤áÉ=Üp5a{«èãŸÊ?ÝÕÒvœÞ¤8ÿ‚k(åf~¢SžÛ÷`Ö)#³¬œ¨«eÛMòú¢Pä·©"Ýåt\ õd”ž.ò÷2S5š²o³1¿AQN(jÙPÝ?Á< %_X¯Mšy&´ç¯¹ïÄ`ÀÛqbðpzO‚GÎf„U«†°g"ìà!„%$"쯵{â „™+]ÀµÏ-ÁMïíJXÄ”©†¶ÏD÷÷¡×ÈDtym-.èø„V:œ¶m;ÂÒ3¼LK÷R¶ …-¬^=ïóÄÅ#ìÈQ„Q ·{½œ7OU@U•—Œ®¾öæ›ۻϛgKEØÕÁÉ*y9·hí¦hoÙyØQm\Õ èg»OîÆõã¯G‰‚%0®ë8”*”»H¯ø¥j”B¿f¾ë™üÀõœ„FÒ\(OÖµEƒM9’áÖøš «ló`RÉ ÙÜqšÛvÊïØ—P` $ïÕÝ„Ò<ßéwÍ0'ȶý¹HóÙͼðo“}†$Ákò™Yž¦rÁ2—údq>YÜΜ,³ç½kŽY‚«yÓVœÊB0ÂÅ Aƒ°páBmsÎ5n¸b1×À —œƒ\E7‡`þ™õU(yln;QòÞNl›õƒd½2ëf¶zjü{õ)|‹R¥X@ÝXA’…„*ΑJÞòa~ Z‘ái§q`XP1J¥'µ¢¡HY‡£R=3ó&]…NµÌd¶ØÓikz òk¯Õ»[mÅÛKÞÆGÜmì(¤sä@ ûv(‚JÁ¨FiAþþ§îǼåóPªp)Õð·pÞ-“nÁˆN#TÃâõÉMzfóŽÚ´º¶•W±¢9Ïc ±O5Xé1è{C_¼ÙáMäP­T.AÓ2šV}{Ó·y*ÏÜ"/u[Îí­¶¦j1«ø’²¡•Æ™M› Ò´¿g³'7Ï# )*†&Ùt˜ûs[àvÜ)­À.å™HBBÂÜø;nî˽˜¡Ii*e_`n ÜŽ;¥å=˜”¼·ÓLCð~”Læ]pO‘³8e.Úbak_/c:¦—r³ƒ^Ö?V f±•+ë¨4Ù'è­Z• Žoðû‰hÓ¦v3Ëð¹:·ÝUm°àâaW^y¥^K)Èý—TÛN_ æ‹IÉcRÉÀ™¡ÄÛÓ ìñN$$Ô0H!‘²mœKHá\o“*½Ï¾P`nŸ&èŸ4~×é\€Œ W•:L1B1\} "Ô‡G¶yL·Ò²Ò;Ý:C; ü õs™J‡($òM4¿{ê ò×dÝWìæU8²d*vŒ{ 1Õ"-! {7£Ílæ(ÐÔð»wׯ8ql›µçݡΚ|Ноg-¼I¼1ÈÚ°@!“&?¢>nêë÷óÏ\ìC…óÆÅï ¬µÍA~|oOÌŽ„;J>‚*ùkâû“£ðgârŒ®2Ê:woÊ\½­bŠWA‘’U±wË|´é5ušg=óáÝ«°Ûbü2é!œ_¿ο “^Ócíâ8~`=Šç+ƒjëcUÜ|<_m4:”ò-ǃ){pû_Q=Ê À©ô8|¹ï ÄgœÄyç£rDU,M™wŠF·BYçþ™² ¥"Ê ý¡Æ(V} @¼'#âÞFÅ|•±öÔ2õ3¾p=­üzDå'¦åÍ/š|Ùò«böåU´`6ŽÞ©Êÿ‹‘¿I+ä¯Qi;¶°ÐPôé×uš´Ý;p°U5*]…ÊTÅ‘µóqQÿѨ|eÖ}§%Æcz¯"(Q»%Ê5é„È¢eplÃìš§‘ŒtŸw‚Ÿ»sÔþMt¨Ù·7¸]{¢Ç¡Ü"·§#çÁ 7áçí?cý‘õHõ¨kùIozhúqËú>ý!ÐèDÚ u•ˆ'_~Þ€‹7j€Š‡?å‚ )XZFÖ=žyÍý¸ûÅ»ñס¿tÞºŽÚ(e#®`NÌ<‘'åbÑ xaþ {ÃX­\ØËúßöTÛM^Hé¹fÈj’#Å0 –›¿Ù¨J–32ûh av:¥'Íß:A{ÞŸIüÑLkžKÊï:ý¶Ð<î´m§ y&§g—|±ç“¿ü2)¿Íkò~ø%âøË•åË:ÁrgÖ!EqÆ‚YO‚kŒÝÁ‰ªýû÷×ó'ê×Ï›‡¶øøxÄÅÅù¬P,D)s"™ÇeŸuÛT.œÊB(²!Yÿ$‡D¨å»§{uã™FF0hÅy 4wâÈD1ÅŠ%ÕÍ”R,­n®Œ––}¥Ij*­²´b™‚•.èC¥–Vanèô[n,mPöK)–TçW,ªî#Éȯ®žÕ£˜®ž=Eå9N&"²ÏcdfZ”<–ü4·¥,LÊ;+åÆ0ƒ‡y7&ÁEô8¯ˆ½ƒYa›ptCëæŠ#tGÛ©S'mRØ·o_="Ò«W/}žx¥ i랆÷8ßW‘šá¼ÎàŠ)±húÁ2”¸¨­Ê\ûÑ‹Š•[ ~£[|X´øùHMM@½Fþ=Jq”t‡ûÚë{ã „½ü 0W)J)WÞöƒ?—áÇØñx´Ìëx¬ÌèVü.Œªü3*䯂¡‡|Ï-¿îr·¿´­®w~æÒ•. †£l•fèxïTÔo}^ñnxè ‹Æ……[¢e÷rübß«HÎHÄuÆMeû¡w…§0¸Æ8}¬ÌÓx¦¨ó¹F^„áq¯"É“ˆñ¥FïÂýÐ/æ)|TbÖ¥®ÒJ­” ’_J¡×ϸë.¯BÆü BÁ̈‹Åñ‡oG¶×¡ô”%(öÜÛˆîÙEŸz-S¹ "ÊVÀµŸÀ5#¶ã‚ÞÎ÷ž? —½¶Dq1ju} ç·í‹‹ú}†ó¯ö®g´Œ÷jßÕsì°ƒ«A÷¨ßwL¾#›,™(UØPe•Åæq›1âQ¥ï?î7=¿®bJôäè'ñÄÝOøLž¶Ã4gâÈAôÄhSªÍômáhÂQÕ(°ß/xäÏŸ-o=sñ}űcýH!×™¸`¢ûDt%Wäe]}qû´;[®î-£,Neýo•Ó4ʤ(b&eÎÃ`ÍFY_)·"’V„*†¶„ö};å<¡ÌxÞ‡y¯&yÿnéï˜IùmûµÌ}$ÌmóYùìBÉ íñ(¿GðZ¼G>#- _,_–5Ëu@ ’_'2]ð+ÙÉxwÐõ&£p“WÐlŠæ!\t,§P²¬Ù±“#=B¦!©\ê˥ˇ¡½<„fyK=`ÙˆX)J…ǦL%ƒfAœƒ@k zx¢Y”V.Ô P± QNÝ\yÅ j»‚ +’êæ…”ÐNVT¼faµoR}êVTan¨Ï7iü–¯ãŠd±©âÊ«ôe©h”P÷WDÝk!uß‘êyT“ õÌ©êÙ“U^$*Raf}&eÄ•4• æŸÐT4$4i~+Ìw•`¹™d™ÚÉøàÁ;2ß¹[gDªL  Z"*uêÔÑ ƒ¸Gxà+Æ ŽrÄcÆŒVŒä7{ÃýÜWdñ2äÛ“s¬ûýk•·aJÁ¸ÅŠqÁD%p"ù=÷XªL¢Ô5ûô–.…Ça…sÁìØ‰ê·›Šg…®Åúâ÷Ä¥8˜šundX$ ÅxË·–ø"59 ûv¶,\…òÅ @¸ªà~òëçc“кX'”ÌrZk*jczâuU÷sLœ„6:¡|DÖ¹—hƒjùjyM¶ùæ—R6™_ð“_Dâ䯑qäŠ ¢÷3NÁÃIí6„©ºUÌÝ Ï—%j·°ö²Pê‚+tÈ<ßµs|ðµå‹êÞ Ý¡Þ9åÎ\)~=.©2¿°Ö…X¸faæ„蔪êÃä–~ °ÿÀþÌ´§ÊžÂ†+7øLžv• ŽFpT⪧¯ò0Ÿûh¢R0 æLÁàFj?ñYôÌ—Õ¼ ?û o\ý¦Ü<ŠVpÿ¢«̺Nà íâ\suo·²>Û!=ÖvRÈ$ioοƙM4¼üdH£kÂlpMš®Pd†²-”sì¿cÒx_¤Ü£Üïé ý·ít‹w¢@žÇþŒf^Øéož#ä¾ Þ…&¾mXY¾,gs†(æ—I¦ ¬9v1™tžŽ=ªýù“%Kæì[bÍ<¸À•‹+®ð6N9ŠAÈt$Å+R” {Ý–ò‘PÀú eÃwŒåÃrÊ=ý.ª“9ƒs8ù™“º ‹‚¡n¤ŒbYÅò¤ºA*™¤r!І¥`TPB£Õý‹‚ÁŒ4õüÉŠI*/” ù†™yÈü5)ß6¡”ËÄ|§M°ü1xð®LåBî8ï`oï˜1c´¢í†Õ«WësLÐ …s6h¦x6 ==þœ€ŠUZ£h1ßü³áwõLµj!¬°ª@&š6õ†~ži}òjœU Ñá¾ç^PÐ{œçGÅW`׺™øcÁûˆ=ºÇlÀ‚ "!==ʹ¯r(e/N¤FÝhß²!êF7Å_©Þ²sÂþô½8šq òg?·a~õ,V¹kp[år‘_DÒ/sSéûvãàeµ±¿v ö×-ŠO?à]ìï4 %Ž-úÎ ?ò[zÎã¦ú7¡cÍŽè;µ¯v•š2Q ó5¢©Ü\ïq{ú #î%Nä`òtNp,ñXÎG0"²`¸>ó.•~z~,Y¾ÄgÔ%˜‰è9EJzŠ^¥{ðUƒQ»Tm+öß 6ºTÜ(=€Ò0ó³@FaéÔà:AZV1 ƒ¡y!¡À¾/ûÊýKûùv“&`>'iÏÙ6ét\¶ö ^_„'–+ÅÖ Q2H*š¢tŠj’õ$xÈÕìtÿr10š3ÑD*/à 7Üp4h W&Î ¨,(™Ö‘J>ס’w} ~iLƒ”2ÚËEêsE„^S¹qS¿‹ê$*4‘¢)=‚¡.ÈŒâŠ4‹¢‚AåBF.Î3˜9’aŒ^œ§xM%[œ§„úÌðtR)Šr‘ò˜AQ<Ê©û(£¨ u¿ÑŠ4¥×#êYSUæ:`NJÉ<ÊwÍMÉ íßB].(§÷Äý ì!æ{DojÍ›7·b³cÿþýˆˆˆÈfFÈ‘*ùû¸8Þi¾so^¼}Ó,$*£~ó( õL(_ÞÚQy!fÍçç™§íGé|Yç $îPZÎòcÝÒÏpi·÷P¡æøeÒ|ùR5|ýj=l]ý-Þ¯3v/›£)Þ‰ì¥òg¿ÆÈ8†4ëKvŒçl9¥¨Gd?· ãŽS•Ÿµ_Á–_™"¿ˆ´í›ÕŸ4ë{=¢®¼…n…zôÁ©/?ÆñGEó€ÝóÆèŽ?üž† pó7ãšj×àži÷d®o L¥Â“ góöôdž?ÔWÙJL¨1¸jýzůU7*妕Cã㑯¨ú*»™U Δˆ ›w,šHÑ lN G0lsTÌg®5³òªZ”/ÕõL©·§bÓµ›|F]xØÝäˇ+«ÓãWjÿ¯€¥& ®¥!Îh¥¹“ÆVà$0;5´¤V"dɾyÌ$aßöó^Dp¢<ƒNií$œâ…„Ó¾=”mò¬B{~Ù"anËuù¬,K–+Ë׬ÌDÑ4O“Ú‚G ¾ùæ$:w>äÃGq6´¢¹å§Ÿ~ª…"º¨åP8É…¿RRR°sçN?ØHk÷îݸæškP¼xqüðÃÚÍmn@¥AÉãŽä1“T.œ )?§r$ìåÂwe#å“Iu‚¼ú]TûÁà Ž`D«‹Q7P\Q̤d$#“êÆi:¥©” M%´“e•¢QVeSfH*á>s;·äoX¿C…¡œ„6r´"3­¢ÌàyT1u1Š™s0Ô³ÊFŠ"G0¨d°›J…ÐüžIŠ/ù)ûÜšß'° ý1xð®äË+d\ÞÀ‰ßýõÞ M½p• 'DEEey‡: à$ïÜbÝš¯•"‰º º[1~À{¦‰@Ìš °k@ÁÏ3q¾Cd˜q®…¨0﹜Óp’wDdA/Suš÷Fû>qÕ-Ÿ£P‘ò´ùìIÚj¥Ì¹Vþðì÷ëKvlLûK‡þž%3ìù%"¿OB<<‰ (tÓ(öÒÿTý÷ ØËï"úÖ{‘8uœR@¶X)s‡_Åñ-^ù´°1ÊÂojz5è…˪\†û¦ß´’Aš# ¿þù+Â. S—¯w&Ç ÑêÃŒkoUê‹KãóñŸãã÷>FñÂÅÝ¿|ª¤‚1%*S¨ '8›RåÖDÊÉtL̲Z5i…Ôöªà˜íùl¬UƨK QÏ žœó$ZWjε;[1ÿ dZ,š/i6ÀöÆ–pkpMH53ÜR`n›°§#Ì{á- §xÒ„g¦1ãLØãÍãö´ûs˾l»QàO𚤔)ËWêë€Ð.ê˜äñà‘Œž==˜:5҇ÆQÏŽ½{÷‚«sazÉÒ̃+ ÓcN y4±¢rÁy³fÍBÙ²e­#9ïR”t I'å"P¹ðݲ—‹ý}Íœä­BŸIÞŠœäM·´ìC¢’QBÑœèJ–ȤÞ͉ÞN“¶óB™è­÷Õ÷;ó˜l›¡b)µ-ÊEquOE•ŒCó¨Š4óÏT0Ôó3O¤þRb•Pêkfþ4¿oš”ï)ï ¡.4ƒ‡Tz&•¢‘I%¼ ‹™T²KžÈßTa&íû&c²Ž½GR÷Çu0¸ 8Ûc3ÅIîЦ’a§YŸÉÌAS¨mÉëñô>_ÓšNqBõ¾ÔVŒ»ÖÏÆŒÙeα yÔÉ#Û°kÃ,T½°³Í`ÚÄø#(P¨8n?âã»C#²Õ³É»ðáž§ôö‘Ô¬5?&Ž÷v ÔqÅÃK"_˜z1>†eÉYϡ͠FÆgŸ3-q‚úPÄx5v‚¦P›6Q¸ñî h:ÅÉØyGC)®ÂÑ;;#ý˜·ÎÐ;‘8eâ>È*ðRÞ Ýq¾Ô-ô¶€Šƒ}r{Zr~}µ³R(^Ôá‚A-±â[¯@ Ž®_l¥Ê‚úä¹YPæL¡_¿àWvî{Q_4.ß~ •ñêd_ ÎÕýªÚßÞf;FON—tªzeƒÍ<ȯ)Ñ1àÄå'ðëÿšfÙh¥`œò*¼÷]»þ@íÚ£ñì³ëP½nž´Qïwéâ>iÜ„Ó$o®.kùXl`t³¡> J‰àHEóÆÍ˼ñT>8¬²3aí¬=¼/^a}„\“²>›ÀÓ©a5i6ÂÒÀJ(0·5¦rÜ íqû>ÁkÉõÌërÌÂÅ£r6^9!ïFB!á¶oBÊžŸã@Ôi­aðš\Í;¿ÅHRERá 9ºáJõ½ö¡â5íû9¥Óù9ü½(EŽZÐS•(.øÌ]ìŠ:?Th*&yܾíû&MØ÷ ëV<”ÒiÔ%d\îA3Cs$äbzÄwÞ©÷Ï?ÿ|½Ï-ÙûÑG¾ îrŸó—:vÌ®ü“Hˆ?Œ[æ fý/+6ºuS…®Jý“O¬U~4=J¯¦æÇlìš"ÝT}IÇ„Yç¦d$ãû£Ð°` ”ÍïßäÌŽ¢¥kª:ŽÍ+½kWâïÁš¸_P«îýàª]±èÄt½àž`ùɹش r­;®-Øs“¦czÖ¹‹’æb{Úfà&ã\‡üÒ&S\l«2³»Î;/æÔ8ß‘§S_T/p~DµÌ™¿¸ÝëñëàŽˆ.[ -ž™ŽˆüÎ ·úä9]Pæß†“6âd Õl;yuºd+¶ßæþ¥RéØKošÑ,ˆ“À‹}_ 7znÌfdO[sVM½®…˜Õ®T#;ÔsºŒë‚雦[gf&R‡NqI.Žš-CݺzSã°ªkN(AD Œçq'PàG:®ºâ0î¸sžyf]æÈÇOkBïɽÑÿÇþhÜ@½|n£.J9.R¯®ýêZt¸»ëhé!‹Š†}Äèú×ãÅŸ_ĘëÇäiA¾³œC‹t“YÓ¥²Ã©A˜¨[%üý! ¹¤3÷sJÂm[ q&M8Å Ìc²í/.æRÁ’ÐØ”µÑ_}ÉSº³3 Ÿ~û*Þ£TÃG³ŽÊì­´Àv‚qìuµsÛ6߃=ßìäçÅ)^HH(°ï›eoÖR_'˜ëЛ©G3Huc¢ld’qN4)AÞgûtÐü]{¼Ÿ8>ƒI­\¨{å‚ –¦ÚÕJƒÚÖ¡fžÙ÷ÝHØC¼…Ó ¾2Ö"ôÿ’¼ÿþûz•ïÉÃÛèô+g¿†Iï´DRFJEVÀ´#ÞsŸŠÏ÷ªrUŒO§/?àŽ Oƒke<°þJ|{ð}ŒÞ÷žÞrJ寀Céû1>Á{îO‰Sñnì`͸ŒXÜy´³^ˆ¯`X!t?|%FÇ¿÷ã^Ã}ÇnBÝü ¨iêó4$¿žz Pù¥«¬üz3ðÖÈú´×(®‡qì›q°m»¯»žàsß@D”Éró¿í‡÷±ñÛÁØ5×{ß–OÕûdjB,Rã°äåvH=u•.¿UŸ†ÝóÇâÀÊtú?ÿÌZÁ=Ìã¶šFÁáºf*ü-‰Ÿµô¾ûòüg(ÜräÂñ‹¥¾†‘##‘rwŠëq* \“ÂŽå{—ëÞø·¯yÛŠqG¿ú¡_³~¨SÊwø*!5//x{b÷`è5CµbAáüñWïüøù¨µ½vïÞ#híêÅ$¥¤¨ûÚ‘àU2¶lŽF÷v·£^ézšõK××# ?ÜG+éøFÕßúê;§ô,<¢~c‹zî¸z˜8p*ª—¨®¯É­ÉÖ‹ y̧4 çg†*ù»²o U=p²zø•qÉôN¨Õx%¸Æ©ÏþI`¿ *2þdpJeÓ§¨ •ŸæcF¨Ÿæã|Ìüj_1ŸÚæ#º=¦:œ ÙvŠ#ØÝæírËËŽ#~A½'˸æ„iAÂÅJæs;ŸèU‘<ŠZܦ¢m*Þλ içg<úè£Vl¨X :4ó|šs$$XÈóxµ@ )ªíÖ_nǩݞ/«*á•0Ó(T®zn¹ûg½-øò£V8q|;ú=µO?ŸÞðµ”òŽX<÷ð•RZŽõš½ü Â,EËÄZ¯åe&8bñÞáç0-v,bÓ£vTC (ý ZÎ~nóƒUwÜ* «&q®·o{q;ŽÜ€ój·ÁÚE[s2¼•ÊVn†Äíkq,Õkb?÷û†Ûµ™±-qÞÝõ(ÖÄ-Rß(´.Ö«âàP ÍQ²Ÿ»¤ìvlIÛ€Ë \ƒM©ëðòÉG±û,w`:MyqJ} GçGjgõ•e¯¼ª^qäž–œ®Ýnl;Lî1óûŸý¿pçBÌß1Ï_þ¼ã‹ÕûWcМAèX¡#Æ?7]oÙŠÕWùY¥ zèÔ¸ôR+± ÕH R£&ýˆu‡×e’ó76¾³Ÿ¼¯ëÏ—ªžíOTZ¬ªÛ—–RuYÕùaoÔÃܹYŠ•ŒÏÀK~@¹"åT‘e‹”Åø1ã3¿y©PeI\ZõRŒMS/O€ü „Ü”u^‘—º-ç²!Ãzå]a?.û ¥Ñš‚³'ÌßàÂN Uf(˜q$Ó™%CŽIº@°?›æ³Jè{¼ä ©…!‹g¦%äÞå9ä9íÛBÂi›”ô&%ž0ϱƒÂoÐ Æ\%8©6ÊŽUk”ðÔæìW0hÍÌQ7Øó‰¡Û¶ÀÌkSÁ Õ'P‡T2ì †^óB‘&OzQ=Ezƒ¢ëÙŠJ¹Ð †Ú¦kZzÒ †ªPZÁJEêaòÇ´‚Áå[q<ÆŠ¨6õE}`>IÈ<]'ÛZ¡}[¼…T•1T´‚¡ˆcT0T{¸?V)Jj?`)Œ§‚‘`W0ÔOÉãR‘à#1¤‚¡O…ú]³ÒeÞ¦T’L˜Û§8BÝè5¨÷d±zOlV2«V«w¤õÙûŽ8Až§éG+Q¤fîï4Á®`äv#'øÀwôávºßÏ*8úÁ¢’›eHpR0‚EnËøÄÖU˜ÿ¸¯ Ä÷÷œÀ7ß|cm×âhèü­úÐ^­¾°.‹æ™ó+œ®Ý£~=i9.©| íÊò<`'£ÿÐëL9VÏ«¸H½ˆ êC¾C}ð¡°m%´óÇ.¼ 9ª«¢½X=Öê1|Öå3L¿eºŠ«©¸²'îõ;o7n¨èäƦ5 T"z<ÒoŽzoÔ£6¥‹”öm´Ø^|¹xLY¬´Þ<®B䦬Ï0‹ü‘°ï tãíÝÌ„ì;#ì¿eÎNq$0Ù6ã„öc&Íß2ûtÑßïš÷ˆNç;‘üŠ@eÒ®´˜´ŸOH(°§ > Y`fÁý `/7þ¶AòÔ) øÝÔßNÒ,P´ú†iEÁFÝ}Oª“D©‰™T? ©~„ä¬jšTq™´s ü¦lS;ʼžÜƒyOÖ½Z䳄«0B1ŸÚ¦Ã›Hëò9<Ú¤ºŒ&©“Ýõ\Þ†º$M­ôàŒ¢ú¯ÿHY¹Q`n›àï¸1hðÇÍévÁB!ê•>70~üxk+x¸zuZ¢ØF±–¢,šG™–®YÇ5VÕð™_átm.ì7n­ï¤"'„‡…£n©ºøë¯2ôôä9”9™{_ðùàé¾ê;¨>„ô`Æ ‚áÚµtFPÏ>ël»çñ¨ß³> +¥³Œç󸜄Í5Dögöë!KiÛ׾勔wÿò«šÌ: DnÊúl³<'$$4³ÛBÂ~Ì öß6)mªäS7:ït= tŽù»²mÒ¼ó¾dÛüfï½ å/„Ú%kk§@èqAàÑŽ*ÈG¹»º·—”²Q½,ðüóÀ¢EÀÝ÷DâþAÑ2¤6mê)SÜן¸à‚fz„à Œçq;6ݘmžˆ ²Š/)ŽØ&±HçØ»[kÁ´ÿñ:щfCj߷êY‚Žv˜¿e^ÏíÚ¦ .d±¢™^~ÛNó:æ¾æ9&íiÌ´æµí÷bî›”sMš× s[`æ9?²¤’Ÿ2C”ôæo˜gõ¾\GÝ´¦º‡h¹'E¶uŠaê^ÉpÅEÕ”!R‘kyVäªÞE¹_ uù’Š¥ rŸñ\ƒƒ /]P=&G2¨dp¸Î?E–…Y¦B)7¡Öé~4øNÈ!ãþe¿w í‡_º”ÀܫÑ4þ mN#LŸ:Q —a÷«`uß‹ñs»ü:‰óeÁãÉXRCŸ+„¯†·ÀÁ?æø¤‰:z ¿ÍxžkÛÃS²<ª€=¶å <–©…'#ž>‚§q#x¢ ÁSº ¶ûÞ·ð·pû¦h¹¾8.ÙP }7^ŠEÝ‚Ùï´ÇçKàÃþá88S«d8áÉù“±ï‡O1ãÍËñÅ“å0âáøú¹jX<â6<‘ôzh+×”@‹eáó–5E6N­¾^§»luŒJ[÷R⚈ö¨}¤*ï ÇSu¾Àäë‘É—LÆÿZ.CÏâ UÊŨ²?¿N7¾ã)Ü]þ4)Ù^)â%Ô»Žõ¿ÀOm‘Ö~•¢ëª÷¦€z·ÎC×*aÚ• :/íàœ—“CaÿŰ·Z]×I¿Ì±Žfá†ï³³å›±ÿ‘›±°W%üpS4~ë]á/½‚Žß&f¦¹ržõø üÇÁÅ–Äs‚°eË–ÚvÞÄìÙ³õ1;|ðA|ö™¯»-Ú2­}1®Óa_ŠŸ %Ór!(ÇÇÀ­=/×oŒðñáˆø8BOê.úeQ+ p@ÁÉühpâ¨ï"¤4/¡Ð~ÌNþŽü–l“êVˆQ7¬ààµy$ïIîÕK6á*ŒP̯X@=K!VaQE®ò]RÝ‚^…\msò²ÜV—-­(ІV2øˆŠ@á|­`(2Ce= {™ Í2¨ä§NЏ‹N³>§¾r¾*ÛNØæ:2\ÈrÈ!Hæd^°mª[·.¸rw­Zµ´§ªœ€ënñGv¢Deñîà›[Ûý{þø[~¦Ê 1eª«î9:izo,Y6 .¸ ¯yOŸ3f|ìܵèÚ©„Ø¿è`ãÆ¬u. YAcœeÖÜ·ð°’‰š(©}¸z¾çžW•¥4F§~‚Íqa„µ‚Ã=HŽ>‰7£tX¼Tà <ùŽyŽbͺo°ïàj”/ë|mïñßQ²xu\Öbº´ÿêߊÍ[gbÁïaÿ±u¨XÊ9¿ˆãñ{ðî÷—áÈÉm¸®ÅkhÓøq¬Ûù#~þým<¾ÑõÜ•›¿Qé~À¯ëT^«E©"Õõ½Å'Ƭ¯`OÂFTqÞO· ‡› Záx°Ö{¸¤tWLÙ=/ýq£•ÂÇíø‘ÃPèÆÛ¿Nõ}ŠÀÑÛ; yyöòL=µ/ýÐ ÛŽ,CÛ:ýѫ黨Qª%¾ÿý|ô‹w%p7„¼H¹€®Z=T›SÃà¹]e[ö2×_º*+ª`ÇôV„tþ¦3¾¼áK-àoº"ðجÇp{ÃÛѰœÃ¬L®Q!žŸì IÔÚM½pü²t|Ó5¸ù w|u< O`ï–-ªÎ§i†#T.ì#36ÍÐ.{û7ïoÅä5›×Ä–C[¼æg6TœëR«t-l\¦>Rg!òR·å\.‰£ÚYWHuchÒj‹}(m3´“ç²O04oiÌŠ Êm“<.˜û íé„„„ ÷ Ì´æ³ÙÁ8!óƒ¿PÉ=™”83Ïæ¶ìiÌ<`Þ˜2¾ÛÈ¿ü¢ìC1"¨É«¡çlÙ±J}/.îüÖë®»N§5Õ³ãÉ'ŸÄ»ï¾«¿«111z$„fVþ¼Î¸Aî_‰ ð:ò NyfBÊAÈ2ùR:®%Î,šõ°÷¦>–¹Úu)%X—UBwÅEu£å”PÎýâêezöÚsêC~zb>P²&ùC2ׂ¦L2ß‚äRÙL“9YAQÃ|2n˾=H’O µLžÎ¤<%©R¥{ÀÚSU†$ÓKTζñä ÆqŠ §€Du.žåTfþ(eæs›pÊkR—“ÚÈÜV2G0Ô7+L}veÎBÖ¨…"G”òáÃ"êWbÔÉ1êdºšÒ“ÔÉÔX4 z‡\iç¶åwä79Œ@òZê†õuy}ÞÉ{ªçP ·¡©ž£  £UXD±¸z¶RŠeË©Û(¯Â ¤Ú&Ë+–UäèFIuYŽbˆ™.êPÌ?YKÃ,?ß:%3tcŽàôžøyG‚YŒf‚T(/^¬W½çˆ G(8òA…dî\zñ‚¦M\ç+1-®ŒÏõ1Nœðµ˜pC~η@w©n(X¤ŒëÂi&Ön˜ˆðð|hÚø+F•]¾(\ܰ/vïYŠ“qìdyF¢°R84ü½ëÃÞš7×Ê…6•:¥4T…°ÈH­\þî;Þ‡Ra¾òIÉ𒈊ŒQÏ^Èï¹N(U¼†ª+aJاCc÷s×l„ Î\õª´G™bµ±z MÛÝÏ)TF+&˜_Œ'ÜîyÝÉ¥zí‘+Ë*…ÌÀ•å¼û‰S|ç÷&ΘÈÂAt¯¬² Su0úæ¾HY¹T»­uCbŠw½"¬2´P´@9„«\>zzpzó†@ Êœ-ÈéêÎÚcQV}ñE[õ²NW/«“÷¨•Õ1oà<¼Ûþ]¼¿ì}Ü1ù4lí<ê@t©ÝS6N ØÈ6­ÐË÷-wMGÁŸó*8¿âÁ'‹á¥—«ëùÅŠ]¦ã‹/‚H?ÁÄ›‹ßÄ­ý÷ŠÐ5-GM¸Â÷gÓ?À÷Üì³Ò·¿üæ3l9¶_®ùÌx@/Äwç”;‘’–âm€Í9- ¹¯#í‰*ü[WòfÉú#aß6ao@͆Ô)Nàï÷ýÑläM: ¤Óo˜$œâ…NpJçDóúöûr£ý<’ÐÌü6Én J:óœh~&ï4ibkÍš5µIé7ÞÐ\cóæÍÚ¤³OŸ>¸ë®»0iÒ$mrÅv‚ÂSn å Í2t¢ û¾ ³,Lê²SZÑ UDæän~v•Ÿi¥„íLå"SÉP'iª)ØkŸÂ¾¢žM€JÅbê‡| “Lcß·ÓP2ŠXJ†&¯e)ZÉὨûâP‘¾O/©dP¹È§¨ä7PÏQX±¨b ÅRŠZÁPÔ †º Q2´‚¡.MCæbÐ:‹ó͵‚¡.ɼdÆJù™UÓ©L ³Üxº„n 9T0"•@Ì÷ƒpk¯)ìs4Áq¯nšoÓ ñرcxà_«49¤9ÖŒ3¬˜û¬Fɵ”¯ ÛÀyå9¶ì?ø»ƒ‡²âòåÀÅMàyúiU)Šª:Oêð|û­•Ê?.‰¸sÒfâ“”÷±3c6¥oÀc‰"9%­›øš¢»!!á(âOžý+0qƪ¢„¡öyî''â÷j“¦ÊešX1Y¨R¦)ö <Ç67HÍðšÑE†«—È€ì§þE'ÌYH]»ùªÕB8{ äoä-«ÔuîeU·Ü•:üli_ì:¶F›Lý¶}<æmúW×€È|¾÷`B½Êy~a/ÔǬÊ" ßÿ½Þ§&¬fýO gOÿ¶bvhEn_!õA­T¹RæŠÛœOPcV œ¿ÿüLïQ•ŠV§?Å Öƒ°´ØR øq@æ Û&¸2uëJ­±`ç+ÆÌÛ‹Ê]„Uû}+Ž ^—£ í^¾ŸMš­GfÎ\ ãS3RõµaÜ~ìÛ‹&²¿0s¥ïÇžZ‡úµNáÙgÖg®ôM%ÃÌïS)§ôZ¯ýòºN芎_wÄ»¿¾‹ˆð l5_\ý Ï/Œä“ê¥át‰ÍŠœ{áíÀðB)ØÚUÈiYŸ-0L; sÛ fÕõטÚÓ¼–Ó14~û¶ 3”m7Hš’„„„SœDq#?¾Bû±N‚Sá‰à|#ŽH°•JBZZš«Ý¸€&!´ùå—ñâ‹/â†nÀرcµ:M§x<§`H=s" âLØãíÇ )³œ²•ú“©`T2”Ì®I%ƒd{¬„ìLeCB=ƒT'r’µž¡~€6WzŽ„’Äe.'osžgUë‰Üf(ÛvZçÛ÷õïªß×ó=x=u]Þç_dÞ“"euŸa9#Ÿ"'yG)Tä êAÅ9£” ©Hè¹ê’ e²w uYQ.èҖΫ¨`dÎÁP`9˜ej§½ÜL¨;>=à…L\4¿ù 8º'X½Ú+¤Òãš š¡p~Çï¿/ÈŸNÄÅïGLa.ë ‰‹‹s7™Ì†­[U!ªR?øb4ðÖÛÀد(Ôh³©9i³¬„îx³À{ZÉx"iÆWC³Sõ09í[ôí9•*6·RùÇëïWÄkï•ÃG£›a×Þ¥èvé{¨]É]ÁˆMدÃ"…²çC‘èòHH:†ôôÔ\ r´×¡Î_'|ç¢þyâ¦ð‘H?´e²ß£Ä¥p/« +¶Ã^Á_ûÂóÓã±IUôÜ *=› µR9Ãzsfddh¦§§kʶÓj•ÿZ·¡@þzÑ7®ùÀµ6ÿºìˆ)¾s/¸BöønãÑó‚žè3¥^˜÷b“}Gvî¾øn|º*°–îõ»û5“Ž,Œ¸dZ™f!%=%(©·–¼¥…~2dn½u«žï±N= WúVß9½Ë-[õjâcÿ‹g<¨G'8ŠóÛžßкrk=ß„ëv ï0·\x ¢S£õ\—ÑÉ£qòö“À êÕiêÇŽ >G†ŒuEÎE¸UÅ@¶‘5ŸÛ²/Û7NÇü1'p:?§4áï–ƒI~xíqxÚ‘Kƒèjö¶ÛnôiÓ´rÀyþÀ‰©ì$±+ÿ7ß|³6Édæ¿„P!aß÷ɧ2±Çe*JXf3’9Ša(aJÐÖŠ©qí¥Iï3T'Ó‹ý·ê#(«“µÿW%‘ ɶúA3>“LoÒ)ŽT¿/”*4­û0ïMß«ºEv–F(j/R*¤©BêV¨ßp`„Êç›P‘à„ní=JmkÅB]VK¨×𲜿âã¦VÑ4“b99•§xº„n NïÉé—5Þ|óM-ZT+î‚ýû•pá£t))Y²¤ß¹O9ÅâOƒ7/NKKÔ&Qvä˧ Z!UÏZ£˜ÇŽ“§ ìÞ{ÆoÅœ¹ªâ”ÄÛɃ½Çý €z©j†×F¯ü½1¦àD|Pàs” +±ßÝ€£Ç•らӳž¹÷ͳpGqm›¡(V´2’Sýw|¤XϘÏfæDг‘JÓoŒ›{Sî1Q§HsLØùfí‰;°ìÈxwýÈ–ž$ß¼×û‘Y÷xüQïµÃ¢¼÷hOoGÉÂUP§ì帳å§èÅw¸´FLýsæløÀJá õ:‡@°×ýÎïDýÖõõªÓ{÷) Ðmž…Koú3—>ƒ!¿ ±ö|ѲRKLë9 ÍÏk®{ñÙƒŸœæíõ‹JŽÂòKpIûÚhÛ¶¶6;2Í•¿«¬hN£ç4˜FÁàËVõ"ò^ý᯿–¡®5×gÕ o;øÍ.à…µÀ—ª˜{jžú€‡éÅû~¸åLì>ƒ.¤×É {^®s]¸•j„&Õ#Eæº"ÿUØN“„}?§ÈQ£êæ}˜8ÅÛC'ø;æ¹Æé¢ §¸œÂh$ÿÍrp‹3÷ÿ6¤«÷vÐy /y×:$ºvíŠåË—k3(7Ð.([¶¬bJ"nr³Ü‚!afš`!å”Y^ê½à&CõÓ=ñ–¢á³†m¾,b'k`hªõ:êdÒ\«‚“¾íkZhªÉÜfZó˜rœ¿'¿+×"ym¹¹7¹_õ\¤ÚÖë`¨mšì+yWß—ç°¯…¡T¤RA}†ó.xi=Ù]]R+Šêj™²qR2 r®ùyÂ?¤`¼úê«zî'nsŽ’€ 8• 'p.‡¸Ÿ=¨pAðæÅùòÔ“ºíHKó Ôùý˜ÎdC«ÖÞ°jU„5õšíaÑÑ@ÇNX™¾ –¼;îH¸ {=»ñAÁÏÑ9ÿèÙÓ£ç#]É>³¸›aÖ¬šõÌÕ*_ŽZÕÚá’fà–ë¿ÅË_ÂÂ?Ý…h1JKÏž©éV>„{…x;êTÊ›)÷ó &¡Zᆺ¾n_R ÏÿÑW”½Õ•òVÈ×*ŒÚ?½-XˆºÌ{m½4(èã.øuû8Œþõ^ôi9—×ì‹‹+_¾­Fâ’jw`ªAˆOVJ¡ Ô«|nÀîÖÔM~Z¶o©{Ñ×]½›®Ù„“ÝNzÍt”ିhC?½éåcÊ£R¡JèúX{­$ˆ²pÓM´²À¼5;`Ö­³P²PIÝ»ÿÁ¼Ð¥K ´+³µ{n³ÏnÂ3Ϭó17ðüfšaÙ^ÿ+ZëŒï†BÂ,‡Ì83[X%<ëÑ R Ó™T¶#ù™æªÞ”¸eoíYŠ¡%‹W)J|°Çš´®§¯mQîE‡^R¹ÐJ·Ã#ÔÏq1)ú •RŠ(rI†ÏŽ)YÓO»§U—1G/H)“„=ôãç|4ØîÿÍ&R\–îŸ9?éÞ{ïµb½àè_J }˜eGRR’>~ºPµeðæÅ4…Š‹Ï>zBÓ)"&ÆÛ©Ä1‹­B£L¥Ó¥â”Í´/¶glÃÜôY¸6Ÿ¯ûùâaÅQå¼ÖصÇÝkÃúÎÏ\BÉ/ç•jŒ›¾²b²CL£ÄTÊDì©ýˆ.P|9ФVÞL¹KEUÀ°&¿`tËÍxçâ_ðÍ%{qW×q(i—žoa‚¦Pé³ÊªÐõÞkÓtŠˆ(ç^Vs7~ˆóK\„â…|Ó4ªtRÒ°ë˜ûè³z­Ï pèÑ Ž½èT9!%ôÚæº n½éTT~:JÍÒJ‚( 7þè£,puî[ÜŠ{ýˆ)#Ç W¯m¸¡!ðû Uàê‹)æF½zmÅàÁ¾“­ƒ1“ЉÊÁçæF~¶.8špk¯õYÛ TTŽ&ÄjsIâÕ [«¨ÊVÌÛ`Ðs]Ú:å7Ÿ_&†‹òµûÐN÷¯½Ê‡`Wï6ᯬÿ pË.§x{œìç$mY`µw#ág‡/Ûæ9B;ü•]®ÀW‹r‹.¯œ}D•HMMŘ1cP¨P!½. A“NRåÜ ×£!ÌufhJËÅ÷hæAw 9…Sž‘&Üöíanà·<i§ú>ŠÂáCʤÞV )ië}k[ï3T'³‹_»ªUd¨iÅ9nû¡¸Å5·3ã䚤ܛ*ŠÂÄ0Ü¢yKÔ‡´N¤~Šº FÌPë1¼Œu9yL­`¨Ÿ&M˜å”“²³ÿNn0sÐù1_>2Ì:xðÓO?i¶ôʬv”/¯„Ãôôlk|Qéàäoü§Q¡\c9¶ É6sìÝû¸€•ºoYw"„ñÊ•ö:x3Ú¿Õ¿zpÁጃ:L×ÚŸ/Ò•ÌBK¹Aª “,/JN(V¸" ,‡èôØ;-3ÖÀøûP¡Pu\P¬5ŠG–ÁÎøu8žr.mkõ"ýÆHÛ¶ ô'm uµ·¬ò×s¿ÏؤƒŽù—žÁ¡<ʬî2šzµÏ Œçë¶Ë„k/z´b bùŠzžç[øëMçÜ„;{ì@3¥Ô.³Fü©,PÞuR¢òE!ý@¼V&øamP˜@ÏTh†Ds$ Ê6ÀŸ‡þô;\hÎÁçd"õ¿_ÿ‡‡[æR¦v Þ°À…ñÚ¶m«'j9R{€jРž?Ám*ÝnRÙ0mût麲å Þ÷Ýw>üðC=Á›n:gºÐÌ+ìùL(ÛÙ 2”=êü>ó[NjX É>2¾P}®$Þ›& JP'Õv˜ I ïÞmõczŸ!X¶ù#Z?¦ܺ€âÜÈkXaÖMZûBu¦Ô/d&ûaùld„J#·.J Œ‘mQ.ÌË1Ÿ…zî…Ê~$ìûÚ+Ý7¯£|nàÚtxÀ5Äè‚–“¶íhܸ±i†h‚kQIo$‹×ýè_§<éXþû'V ´ÉÔª?F¡RÅ(ÃŬr€î=¸z0Wò¦+sººe§ÃW_}¥ÍBþ.H^ÚC¹ÏíÌ}ëác¢\háYÉóZpfh1RéGb‰Äý|JjöRg ßaJŠÖ”Ó]ÿüÈ«“5$N&oè  §¨·8=œ`íg#@B7š0ãÍó š÷”Ió…èP+‚ó½3Á}.VÉßÈ 6/‰- ½Ë ì^=L¬™’‹ƒ›镾%îèŽ:ÝS‡èýßÿ«÷‰Jšá‚º7aö¼§0óçAX¶ú|öõU8» í®òµ"Xºâ}x¬å 0mªÞ׌…‡fÍO=Åá [Wx^z õ}Á%­µ`\/üB¼•<cS¼çÿ6UžX” /…[ó÷Á¢ôù¸îTíªvhòk¸úTK¤¦& ¦p¬\ã=wýæ©øyñ`ͤäXlÞ>o|P ßýp-{¿­©³úaä×Wª÷½ E•ÀÒõÞsÿÚ13W Ö”õ!®¹øiõÞÂðÉWbÁïcöÊ×ðù¬›P¤Pm&åvîÖ}‹p,vgfÜîCÞ¼žµb>žÞ /ÿÑ ³öyÏ]zx*¾Ú>XóTš÷ºl|ÿÛp¦íùßï~­h…åÇfâ¡:#¢‚oydãf(Øé&ľþN*Yìäà'p¤ÇUHß· EžñoñÑ¡þ@=‚ñêÌK1åÁ˜»áC Û«wOÑ“½‹,g¥ÌŽÓ¶’w0ÈËjÇ'(Àrî…ãWG}HhÅÑ iiÚý*M‘„z^!/y¥å¯•‚Á Ð5c€*x]ô \K/Zg‚fBìÑ7¿ÇÛO©÷p;PYÉÉ{ÆÕÆ‚ÙY>±‰µ‡ÖbÄÊxïÚ÷¬/(€?ñ☿}>âJÄ¡ìö²z2:独‰[ƒõ‡×;®¶Måˆël\[3ËsAÏOƒŒFeáñVcöÖÙ˜´~¾¸þ ÄÕ#2Tš­ôM˜ÏÉÕY_UÙÐAÕËêjÿÁ§}œWÎw‚m?ÞÌF.fÊš˜îõÎ}9['{ç¥n˹ÅÔ¶S?®T †BiÞD ICHhG0ñfCÎ"!Í6–r¨´µBIoÂÜ—m§¸3 yn3™·J>̤ˆt’ç¹îäcC˜C´iS Ï=çbûq?ð­R Ê©ö²¬b)Õˆ|7¼J­ˆƒªâǦ«Lã÷–Ž%h¦&ÈAYüÓÈKÝ–s‹«m'CÀ"%í ¬Êq†„„¹? BV%’"†PD’ÇÌô¤fœÛö™‚ä“ää§/v!†iì$Ì}{yØIH^‘f›ykæ±ä³(ó­`¼¦àªV¤Uª¿ø©‡‚a~ì<˜ûnÛ™;*ô•Ao3dás[Q+"Üf âõœƒÈ0¯«V¥@”(†’J¡(S2eKz•Eõ‚MC¥¥eX>Ú ™ ]RÁˆ´Œ(CÁȧ ¦Ééð^ß[+ÌZäDICXqÚÔVÕ¶LƒJ…¡`@Iúª­LcÕBNdMV!“Ä«0Vñ„¢V03 RGIó ]ý¼(§ÔOR8ªÎ?¬” »‚qB¯Ž'ªë¸), §÷SŽKz'ÐAÐ ÆPõžÐuºUª™½ø1÷ó«V­Š;-Ø(jq[\ûsä‚ûN"XïÞ½3/Ð,‘ëŽñ|Žöë×O++ÁBž§ãK+Qò|çgNKNPÕOÕ9ÔöíÍžõãiÖ“€0?–'Øû–K|ð µá‚”ÔDÚ¼[ b¼ƒ ü]—¨ãÛ¯œ#8)&2Î…kà¤`'ƒïá9®8ë†'ú=˜Ù19òåöàs‚€ß• Š¥—ªeZÝ‚èðULZ7 éüX«—îÙ71vlõlæFýüòUiüÖo’Ò’Ðþ«ö˜·}ž>ΑŠ#AõÎÕµK]ŽÀ´nßÚÙÝëÀÖô­¸ë±»ðüKÏ£â…}¼em¼r#öÅîÓÊÉšíkpÏ´{ðê/¯bÈUCð~‡÷µrÁù«÷¯ÆÈÎ#ƒV.üqüuè/홪˸.Øur¿V¸ˆkËŸ7_ôP÷[­4P¢I ®xú dP‡JD/jvé¡¢5_&ü•õ¿R¤fƒÉm;͆Õ܆vø;ž½IôÆ MØãìÇÏÈ=9…$_M¡)ìsÛ‰f: Ý(¿/×"æ6áV¹åFK®ô!ãÿ°ç§¹oÒ^TH~¿)ÇsdB»`Ur?•‡h%ëë唢PT}£Šª¦£·c¼£E ‡!F1ºP8 Š@Á‚J_ȇüQù•ð–áQ‘W?Æ刄¦úq†T ô(…Ú§I+ýÀ†3T”û´K'¡:ž¹Íî “¦Øm’_ÒØÎ4¹"Õy™Ë«ßÑ!÷¹-¿kíg¦U牗&3ÐdVVs_Qç³Ú”ü¶—…¦Šwz¤ìH*yÐ ¼ ¼ØBÆùA õÁÎ?ÿüÌ}IgÒ®\4%¤Y=GmÚ´)GÊE°ð§\üð§\üÝð'äÿ8S×%Ü”‹Ósfcøðáèß?»yPfÏ%œoWìþã×G5´…Ó cÙl®ù`-úü9‘™ºy ;¥Ô·4Ü»·:¦LYЍ"Qz4`Ú¦i¸®ÖuèÓ¸’c“³™Õ¿  ¶]x/\ûšVlŠã‰Ç1xá`lÞ½kÞ_ƒ]-”6DÓ7Þ+?vc)˜›_Nö ñ;ÅÅë8ªñ“"Åi¤Fiê•#+ãÿì]`E×=!!ôÞ{—¦RAAA¤ªXQlŸ¨ˆŠ¨(¨€ bAQ±‚Š4©JPºôÞ!@H„’ÿžy{_æmö½¼ô?á0³³³mf˽oîÜû}ÏïQ§¨o(—·Æ€Ÿ˜x¯h~m z¢úiãOÆ”jÞ˜yh}Sk\Uá*ã™êñGï :RCåjíÚn& 9&*>Á@o^œp ÁúúÏÄÙÜÛºm¨ ¶¼R?á*¸óvÝ`°ú`/ý€“úeÊ/I.3Õuv}Ò îò`õþØí¦mj·­.+µ}uÂÞ^S»¾’`ª×Ï”í¨T9FÛ\Ézö6nP?àL¥°~™íÔ+ãZX²¨ÿÜù?‚q&à+N§P¹àüi3¨ ò»Ÿ²ÌßY¸ÎÔúæJsD‚¦O>å">w6ä‰D|‘È/Ì—'R–³!.W6äÌ‘ Ùc|ó4"9‚avÄ:‹-†Œáè…3‚Áf\Çzþ ½‹ô²ï›î;Hó²ÎŒLˆViF1œ‘ šF™ )Ó ÝÇIÙŽ¤é“1‘‘òƒ²Ÿƒ’& ͆PvqêDZÀM¤õZpô‚Ü#yŽhøG0¤nªfµúìè³HJKxªSÒ2þú¤Á 3ó°ž‘¾ú(Ÿôz®{l1 • <ç}Û–`á¤g°kãœ:y ñÊ£Æ%wウßѱ”%,³›¡ýòí'H;|QÕ.@üc3x1"V¹¾ýN­ÃÀãOcÁ©98˜–€’ÙJ£Kôx æQä4‘(}HNKÆCÅ_ĺƒ „ åÞ9„ûëÄ¥)ðbÛ‘Õ¹¼V'ÌA”(ãu ·DZ‰’سo9¶ïZ(ÊÙ!tj3õ.ȸíÞý«1qj/lÙ1‘¢ÐW*ßUޔĦäåX“¸I'¡wµ‘hY,ã¶3÷|…o¶½‚í)kÌÄçÒ±ÕP({)lÏ•pÜúµ·åDòÅËGÏ[»÷-3“æŸü4RS“qò•± „ qHþ>ÄHܸý´…%¬·LþèEëTÄiDÊ3 iƒýžjÔ@IJåN©”''£Õå/bËÞزg!Ž?„›šDƒªÇýdZ7üú…ÎtÈSnþ·Ÿ >‡ÿ 8ý.jé6ø*áMÂ…ÝäwU^¾ËSÎ  1q~côéWÒ̹4¨:Šïfʹ>>{¼ñÖ4åæ)(_ ]ÇtÅà%ƒÑëÙþ˜6m¥™£ÁôõaáÓ›?EŸ©}°'iòå̇—¯zÑó£±õBQ.è~YßœìEùîdx“Îò… £”<çþ¤ƒvÁ?Ç(½êì‘Ù1¨ù ùŽe|MÓe-ͦžžþ´‰éñÀ åD ž»ü9¬þx5^¹ê\Uñ*ä”%Gj^{7V„˜NdA=Rþ¨ÈÙAÝ“ÀÿjåâφÝòšgªd÷ÛT]ö¢]GóÊ̬ŽvS¥^å^õþIÐs&yËÚäûÛ¦*\6Ýõíå`´é†¶¿z1lx€Ò+åaíÒ¥ *T¨`&—ò}Ö´iS3A5Ð&ž¨¸]\\œ™¼úÛo¿9k³»­Â¡×ef 4 M碣P £Ž\±¾Q‹¼ñ@¼@Aaá|Âü4¦Py#…"q¹£ì¹b›‘9s ›Ð·"³“²s“ ie IÈ‹á²6›¤à\)'@Ù°Åo[×¼’N}3Z!Ûʾh—1Ϻ²­$CÏOiLÒõÂÉ0z!´ûÁý,y‘õ´o²?yH×a6¨_Q÷²É² ¶®ž‚o^i„cÉûqQë~hÒùu”­Ùɇœ¹!pðánHzÿUÄv¼yž{]º?n½Ç w‚Ø~z.O¾Øл;æ É1 G6ÂóÇû£ûÑÀøûÓöáë5°#i ÊæñÉ':/ÁÆþ£ÛñÔ/—awòFÜR}0ÚWz‹÷ü€Ù ‡b_št·¹²ÌáÄíx÷ÓËph#®j:M<Š5ëÀ×Û†b›( âœm=Žûݶ70hå ÆMì^ÀÍeŸF≘±w4vîù Å ?ç5&aѲM^6òVðŸ[rÊ> Ĭ‘¿:òGxm?Iþ>ÄòG¢‚üyÕq#±ˆ?//´\ÛBd¨ Àžƒk,»Þûä\“[¯üÔ϶ 8kÒÁçï?ÞÂ4É!(Ür>Å 74Êœ«•7»(‡ñÅ3Í/óî‰Éœ;Ñ©z'L¼q"ºÖìŠ~3úecî¶¹~›Ì¼9òš‰ÜÝÇu7Â<ñÇê?¼Ï×ý¦%Ü ï÷½’,d@ÁÑÀº­ëŒ°~[ÛpÛ7·¡B¾ &·M7aÄ¢èòu´ÿ²½1Ûº¦Ê5˜Ðu>ïô¹‘)Ÿñ9Éü’Ç:`ÝÚnFéRå‹#ª|&Bºož|FÈû.!6õ®«`浪Å*³Ì`‰ªdü›aw¡v)©Ô`´ëØÛ‘„W¸—m¸o7z;zÝ–D¨mÿ °Ï]™P‚½Î«˼¨ûõÊ“nh…bØðœBO[·nERR’±ýõ×ѯ_?SÞ®];¼÷Þ{& 4û ·›Ñ£GÓƪáèq³fͰ~½oBfV¡mí6Õ6&=û‰( eeŽVйO¬ÈðF¹ÈíS.¨X)+ècñB†œÌ]„º dCüÙ/_âóD#W|väˆË˜\9%;£‰B„Cä”=SNææ| *µ0 †¤‘’fF(¥L YöÓV6ä¤3˜N©AÚJ…CcòDeÁÙŽ ÷c Ù§?Õ¼C5ßbœ%*ÔÌ8¬B¹0©”ÛÊÅ)IM?8éIIu´TÐOB» ÙÄÐ>$ón²Æ‹-^Ä÷|«?¿ÚÄœ RQ³pM3Á»Ç÷=̯ôë·ÊÇØë|9 ÊK0·ëÚob‚&T_ i6u£Èwž0Âúǹ>ÆŸþˆÎe;ïXã׌Çý“î710^˜ó ç*Œ÷®yÏ(GO7}—¸8`º4ï⼎á‡eË©q+_œïÂy/œÿâ‰3uæÃ4(ÓÛ/’ uÏ5‘eŽDqûù ^Ž ;Ox­ó¢~LÝy%aç ÷úp ·–ûóBfëÿNØç¯yRe ;oÓzì|0º÷cË ÚvŒaƒ• 7YîÖ­[ã‡~0‡»wïnF g̘ڵkã•W^qjyã›o¾Á¼yóŒ ÅíéævæÌ™ˆŒŒ4ÂØŸ»]I»ÍÝ}f–¥Uæ+Kœ*‘Sdjλà|‹üyœÑ‹ü>%ƒ^¢¨d0ådî¢XæÏ‰¼y¢;>±q1¢`dG´(‘¢`DŠh” ã%JhF0rÃŒb£„ª`¨’ TªXØÊ…ÒQÜÊ„!ßÙBcA%ÃQF*H—bá¯C:Ê…ÎÅð^Èî4•"m[½Qr¡”e¦¦/4uh+Jí;…l@¾ïB1lx='Až‚ßû`Íš5~ÏQ^ŒjÙe—aãÆ& ç-Nœ8W^y¥ `iãwÞÁ]wÝ…ZµjÅ¢Q£F~Eýl°vñç8š´ Ú2˱¹‹ MM 2ÁщßÈ-…\7Ýí”ÈuŠ6žë†îH]<§v9’æ“£ EøËÐ Q8¢¨ù5>Æ(Æ>ÄÈý•7»¯^(‹þy;Çà¢mQ0gúœõŠ´’g± –¯þJžïmóÄ—ÆŠ5cP¥b[ɧo[¥B+”Š­‚Y{ƒoK=uy£@ÎS9£r#Zžá`çœWŽ'²T:¸#má\sˆc³Nv>‹a"íçŸE#òž|ocF^˜ý~Úðú=×3 ÆÃiÙ=Šp™ó1~8ý …RyJá…+_À×]¾6ó8±û¥9/¡v\m|=ækŒŠ…Ôœ©Ï—ŠÂnáB¨Î2º ´u>¶B*†¾p ë¹Di*¿õ^­g”«Í‡6›øôZ5¢ít¬ÖÑŒ®„‚ÝÞ='÷Äàæƒ‘‹¿Êe*tEKoQtlGPŸûÃ\¬^±Ú÷Mõ‚3⬯ÿ `7iWi>3²K½Ê• ;oÃ]ÏoÅЯ¡ô:áÔý§@ÏÓ}î|´2£Öso ;oCû X_d<ˆûäõÄÃ-Y²$NÿÅÑ T0Š-jÜu* ,ˆë®»ÎÄÑp Tá@Û)\ê¥i^i «¤‚å¡1#òy0 †Èîqòú2 †c"¥æQÆ ­Q.„4‘¢;Ú|¢`ä‹DQ2â¨`äN7‘Š2&R¢`ä åeF¥Â(rU0T¹0&R’Œ`¨2á&• %… i¤[Á 3´ÊŒ’á(#ªd I%ÃV4XÇÙÆŒ^p_lTÈ›1(^ÉbS¥`¨Q¥#RRöI½ŒÛVÉ}Ö'…6㬷™‰?1vûpì>º[“ÿÀëkz EÆötjeDã ÿZSî´SòÔ<(Ǽó.DȽw¶H=™‚ÞïÆ£Ï{yÑçýøiÉ ÎštðY;cp¨œÁ–n¹å3dÎ_£®¾újõŸ†Çóþe;3“®/”«ZVh‰Ç/}_tþÂür?¢Í4,ÙÐxJš¹À`Ø'Ï$'¦í8*/@yó±|òä¬)]ŒÄÝãâøé–ŸPµ`U\qÏ8”S^"òË $Tèu‰¦‹”­G ‡®^Ç tûÊSQ%ÄmBeC>¢œ“ñíõߚؕ T–oEæ¯e5kÒä"´hQ5n(‰5 –¡|v‡ûA@%ƒ¿Ì ÿt8z¼Ò—<~ ö^²wL½{î þu»™#RÁúúßwp9 ÷²v½sýð»?þçôÜík±©Ž-è¸Ëíuîz¡Hhê…sÒO^‚S&‘’’bÌ86lØ`Þÿ“'O6QºCs-¼&Ã^tÑEfôŠs®a·£RûDûÂ^Ö2’ï3y[äeº’Í.r´Žb¨©T>yGe#O:éš6Ÿ0o|„™ä‰Ø\‘¢?D‹Þƒ¨1ˆÌ‘]dóBÐ eÇtAkâ\Èr´“rRw¤ÃlB öJ„M©ï§£U,¼HÅÀIM^•îCéìÓ”[y“rn+æžÁ›USÂ,ûh+v?¨¡y]¶ËuÓ_¬]û‰` ÔløLØdYĈFª.ßCýâ>fÌ£4PAWð9¢ù G ̨Ÿ ÆÅ 9G=·ö®ÃéS'1é½ö(]½5ZwÿÕÞsF`Úg·;µ¼qjï.DædÐ@hÙ©Ýé‘üÝhuúf€'B“亨™TÆÌ½¸G”‹A9^vj…ƒÇv™4_ŽŒç“;®˜(i æ:½p$É·mî\·ÍŸ½ŽœHÀ©ÓÁ;¼Gå×’ñæÚq˼òè¾ :~Þû5^ª3 ¥‹7pjý0bí\!Z©SpæÈ[-êöÁÍÍG¡[Ë/P«\;ü¶žæ0ÒïTdð<#,\¸_~ù%† ‚^xÁ¸P£&^¦L™¤€Ì^±ßýãgyA1É æ¢6OŽa½ßEmf`“†ùâÈš#銕„ï…ª$"s›õ  ¢Á‰êòã§8×bR®§‚²XH%„£ÁÞ´rglܲ1`òtf°MÅÞx# w?º±vàæRKƒšŠ9~ó·ÏÇ{‹ßCÏzâšÑט"N0_²k ª¨‚þMû›9nœ€q%¿(6ä9"u.lSϸ»O—™zå ]¶y®üsz~¾æ³JÂ+o“p§Á`÷•»íuaÁKpÊDx"…›T¥J•ŒKhŽJdöÌíÚµ Å¥×-cÀ±s¯vUè:’¯DÒÎóWt3‚!¤ŒL3)ÿ(†Èî&ÆEN #>Eƒ#ÆM­a„oYÊãsEoQô&•36 19é¦VÞNnje‡êžÖ(ºìä首îjmµF°—2Ž(JGàWEÁÐV$øÉ×Ti­÷+š ýʆ“×ýûËXõe_f{î“ H2뤄¤Ú¾¶ráW2$5d^h+Á” ¥B6‹aCfÓ>à`ÇŽæ{x!íà] Òm;?м».vŽ þþ{ð‘‚Ìp"5 'O¤ jƒÛФÓk(_»=št†—܃uK¾À¡}ÁçG¥;*·ïÁ@Py&Ìú(Q—D5Åë9Þç9¿5‘¸‡¦Â{©o:5Âç^ÑtëìBuÁÉSôŠ– ¬GDz˜*ÅP±¤jÞÈž-§1¥jY¬úÕüVûÐ(&Ï,ï€78µþ^¤8ôï<ÝøKõÙ¡]£ç ëVìŒz•®Ec$.«åS€§1H¢¾ ÎòŽ’7/½‚(êžÃw´µåôO}Oóv{jóF¼5â-O“œp£FÓ­¬þPQHîÇ»ÊVž¯%¬TÝSMÊ4Ážä=¾p8:|ÙÁÑ7}{ý<ß­þk¬£ƒÛ ÀΉˇ#§¿©$PyБŠÏ…^Š—9rÉQ ÆæÐºTLÚ ©„p}°¥¼DSs¤fiòô A¢Ñ:¦b…‹ÃäÝô@% –´Áu7n@ÏÁwâ³eŸáñ©£ýíMÜ5þ.cfÆQ"Ž”Œ½~¬!Õ~iüˆñBU"¾„|£|Έûú¿¯®W¸óîºÿðÀÇÄ~T4o§î:„]æ^çFfëÏ9(±côêÕ˘ÂÒLƒó2Nžaܬ‚oN|‡ŽÝƒ7r¼[cº£r¶ªžó}Ü}ú냄´§fxˆ¡§5Á‰ÓÏçäIßùDq$ÐIN”ïS'3n›zÚ·mŒ=ôÆs+º`ïñmè-ŠE“Âq•(/׉i©˜òs_§VFì=ðšr?õmRébÓ,¦ý fäV¦Pé|PðÍrF VÍ¡<º´Aí›8­úÏ€ ënïC«O¯Æ ÞƒÌHÅÊ9+MŒ¦ŒŽrA¸ìÙ`yݪpiéKqwý»ñZ«×0®ë8#D¿yõ›¸¼Üå8pô€ñÌÔé«Nþùf À ½nð¹Ðå;\ߦT&HŽN¨K]*î·­¾íQ ÖÍ#Ô·«—¹•‚ú!Gy]“§9ä˸‡Ž®#»°ñàF¬Ú· ‹w.ÆÂßfúMÅÞå‚&bn_Œ‘²¹‡çÈ÷&7Öº_vþÒ´MÎ8Q¼}Õö¨˜¿bÈÉâDf“ÀÃ ŠøOÄáA)v¹?Šî”°óÁà¾E½M™Õq×Wx•ý[q&×êÞÆ^>Óö¤8^Úä=6Îp£J•*ÆÅ,McÇo’¼ ;¤îÇ_·CrŠÏ“WÂñ]ˆ.€É»>Èp¯í9¶½kŽE ?¢qÁvN©Ïmíç[žG<—`Ëöôé³}›·¥_Çäá÷U£ñÍÄŒ¦hŸ½cÓ¯c–ãÚ´ôã(z¤õÀi8K>¤-Y‚´kÛ!mÿ~¤­[¼ÿp¿(<‚´Çûˆ¢q?_¾Òq©H›;i­[eP:¯ûR®9ðª}ü‰rï,xƤʾ¬÷&ù‚¤$&¦OúæáŒðWyŸ øã]¸'4‹~t¶Þ‡BEã~é¥h¤¤óàD鯥ãÎzwš˜ßßð½ºßiû®¬p%V­\å3}²ηà3i+^ŠB0åʉÞ34·âh–‡°nʹžsø&â´ÝÎDåæÈ c^ôŸÙÃæÃG¿d?•d>ÈD ‘n. ×/Æ­|s0òæMwÄ·ÃZó¹òþ31i¤àš³ï jËaÙ²ëqçÑxäQà®GDceõ•WNˆrñEXîj ÆW>¦<ö'øÞ„¶"ÀŸ)9za+^ó2 ©3–­<ð¹UŃJá2!ÍiBES*ŽÆ°œë 9‡â¿7#/ä7×}ƒO:|‚w¯yÃZ3ž¯žiö òå(ì7;ñ Dƒ—„|d Þß4%;`{8üC\Þ÷rÏ'Î :Á®ÎŒnx•y}xƒ}ŒõCþ?ÒÛÝN•nx•ÛË^Ûü%g²k`œ|Çl¾ÚÌY&ô]Ê“Ýu2’°{Òë‚ LÐ>ކg|ýQ¥±y@HèQÜ÷­Wy0*Lÿɤè>J™è †QNšNQ(f3…BÒ“ZÊ…¹`^R.jž©Ã€Q %ߥ¤½ÌT¶õE{YׇC¹?­e¹Àõ,s² k•¿ÜÊû• »Ì¡BóZî^O¸—Ýàg‘¿ÛÌJxÇÉkDü,½~pVž!ô‡XU°m°Œ¦OÑ.°.'κãcPé )ÕÙ(çë]gÒÕó|¿€çÎï3/^5ï}¹=£Q¼Rð—AÎ6E²>…äÏÞuJ¤/DaJþr$bê5Dd1¬‚ R¶*Xzj‰‰æM¨›Ú1'FË]‰šÙ.0ËYA£â°h÷pO±lß4HX‡šU)Ðx#ožÒ¨Y¥þX?ÁÜS¬ß< ;RÖá²ÂÁ·-‘³’y¦gîñÅÌPì;¶Ëý‚âEê:%Áãþ%¨U øö;à;•\®Q(SÆ·Ü=PA …§ŽãX*í-1oÕû&mܸ±I ¾5ÎÔšÿê!ﳙߠ/47¤¶ÔÙbætÛ ½&÷Âs³žÃ Þ0s&­›„yÛæaÍþ5Ø›¼×ôÎ…Û9râÑGOà塲|p÷=@þü@´é®vàÀðGI8âr"ZŽÃ·§*ü9A«4]¦B@å‚=iÏË ¢Ëè¾V˘òc+'Ü7¿M4³¢Ù%M©hR¥Ê!õŒ;ßL`›Š9·«8S±’³töH>‘l¼my^iÎWè·6\º¡[ûCì.;¡òvúo‚W[k™{]n¯s×ûÛÁl³¥ïÇà ðú„vâü±qS^“¯è*úäÉôuîÜ{öìÁ·ß~ë”ÀL_ýµ1¯Ra*+à`4ß(6CM_ u²Ì]®eF'RòIÚy%¬t—‘f[½„\6©U’|¹‡ËÌ”ˆ`І×q•™À]ÅÞÌNÝ$4%ìüYÂ4±Þ'ü ΦÆ(­D×!¯ú¼¬ž1J”(adŽü¹AvŸAÔ­ëRÝu-ZdXÚu³ŠB%ë¯QŒ‡ñãȰüç·0ùÃëÌïºÍ{#W|Q§fFÄÔ½9ÛvAâ'pxP$ú.ö_NíÜŠø¾¡M•Œé-Ë)´Ji‚—ŽÄ{©o¡sÊÕ˜xò{3Ù»H¶ÀãNÚ8_¯ˆi[?4Ë¿îg–É”>“œN•ŸDöÈXô›}¹©?fí`¼´° rÇ7ž¢/õm»zÝ8LŸ3Ðð˜׬Yã'‹÷?¿ó Ç̹ƒ1ú».(SܘIMÞåÛvÞþqøtÓ@Ã䓉ÈS­ŠÝ¥‡fs)ºªý|ó`<¸¸ŽŸJA|®âX´Ì9îúŒÇ=xx‹¿lÇîE¦lÆÜAfù¶´Û00m >”?b¼u\&8"[Ò¶øË÷ý ´AH8iŸÒ•¨,4eÊãdܸÀa!ºg£N(WpßÏ<ó >üðÀÉP âÄßÇã>6s/ÌKŒn£' 9À½å#@3›»¯¿ë7­ÇCO?„„£ 8xì v'ìÆÐG†¢áõ ‘§RSFnþe3ö-Û‡:÷úîhÑöW Ž¢¹çË~ g—I,°y™<“ìeKaè ˜ºÑÙ¢ñj¿WQ£V t¹¥‹YfùËþÀ°†aÃÞ Ø³ANLvÎ7ä D¸EÈQDû:øÆäH'ñ³œ#”ü1‘s—nvÊ8Âú?ñÑä¦V”¨ˆr?|‡é±ŽvÕrNÅV [Žnèzm×ýÁˆ¾©¡2ESâOä~{ôQšËZEî¼)³SмJs<ñøÎÖ²û­[pº¦­j Ó½ñÆfíK|Ë–-hÒ¬ Òò¥áHÝ#(ñG 3±»á 1þ|Œ8Üxýõ×£k×®çô¾b4b–qâ]ÅŠM½ýù矱xñbOwœ¡ ÏoEoK[_*U$PQÁ¦-.šǃ~ùÇ"açmYI­(:jÞ–«ìíÎ7Øm¦Ô¶´ÛUIØ©M­ï¦]džÝîÚŽîÔ® üɇ¿)„ºõ~[ܨçaQ¸DÞ õå]áÞG‡päÈL}ýöÙgÆÅìË/¿Œ‡zÈÔ£ûr*›7oö;\  t饗bÅŠÆó¡}ë­·L°1 NôH.ôüùj²QØí£íFÚ÷¨Ý¦J‚æMœ_Á9tI«1/碸´ã\0ö]ÔÆËÁ9Ñ›s.8×ÂŒ<ðÅÇÉÚô Eo:Œka"u“’ÏžS*ËÎÍ„n9˜1ÒÑ’/yZð:H’¼J.“|C°>É;ŠgΫáS¨"ÝáÀTóª9’܆õímI®³g1+YnµÝPž”4UÒ£².Yê’c’ã% “dÛ£BÖ;q§RO3Á1YLbu©²ï¨|¦’íIBùí”<—:»H‘Ýs󓲯–-Ä+g+°•´¥h7A²œ-¨­CºŸ5‚s•è±=¬çD¾¡õŠ8…–È·µ¾Èo™½ï©PÖa\ Fé¶A·³t”À€|êªVå§#FøèðG[®ç/Ãö7‹s ÆŽ‹mÛ¶˜¥ƒ^Ïu-F¡RéçL÷­‹§<ÕóG"9q'âó—EÍ&=P»ÙƒNtŒõ™ÙûÁ‹Ä—žFÊwŸâô¡ƒˆ®^ñ½ Çe®±Ê÷ûƒ‹OýŠ!ÇŸÁ²S¿!!íÊf+®Ñ·á¡˜Ç̨ŸJ'Ëa_ …ö§¯G9?€ù-7¡P¬ï=³-qF®x«ÌFT¶ì¸°hüvxù‹ªÀŒ¼ (öJ¾÷ÿ6ùGöì_…ISÆ–í³å1ÎŽªÛ`ǺYØwÜ·­û¸Ÿ4Þd̤h5aÇü°óì<êóºÅÈÞ[’Wâ`ªo¹û¸Ýë;îÆ-3ñþè+|ëì:‚ìòwÜ<»½›P:¢4f¦ÍDsø¶·ë˜ß.DИ6Ý”y!í Ñ’@ÄRš°¤#_žr8xÄ×Öîó~æ–MÈ“_ÿò6ïžÃÉ;eÕ)Ê[ •Š7ìåo<g¬`Ð-} sˆŽaî óÔSO™›žZº ÿ›ÉCùg€Þ£8ÁÛ/@Ûû‡6ü4³9SpT£å•ÕпŸÏ-ÙRÚ·ÉË3‡<'|ŸŽŸT÷Ýß×Ô=qZ"ýꩯØJ´T út1Ϧä3Ç`z¶"@Ðfš3>éÅÎ.çå´Úeo Û í2ŽnˆB›áXüžì—õ„(ìX¶ÃïÛ;¨(r¤fÅŠ…r?ž”›/ÊŒlpž ô—~ŒÑ+F›ÉîŒñ‘p¢~ãÖ}siø>æ½ïœ#'xÿs0ÎæÞÖmÙºü@ºá<â&%Ù5¤Š$î¼ÖÓí}ÈÁPóvI¸ó¬CÊ·Þ/Šh^×Ùû9¡íe·Ÿ¶µÝ®ÌÌkjçímlê:».a·³¶µjžÐå`àç(l££Né¿Åø±d¿OßfÜÝ’ðÁX¾|¹|—˜÷>]g2¢7ýù+n¿ýv£`0ИíÑÁ¨\P(¢Y¯¡C‡žñó’™‚¡©Ýž^y»¾*±Ž‚‘O>mŒÚ]L” FëV#¿”û ©o £,ÈSÈѺš¥‚Áz±¬(Ô`z&Þ…ÔñOðÖ§—TÑY ^!i+¡Y—w“^ ŸDUx¨rAªÒ O­Ö··å:Rë*UÁÐíd[Á8&ë¨-¨‚A–ã“ÉŽ‚qœõ-ƒ›H±Q0R\ †¤{¤ŒzJV ]ÖÖ!ùŒésfƒ òÃzNnçÄõé[²Wž‘/‚oϰx¿óGX* tå¬# ŒÀo”kŽNP9èÙ³§QÞùcŸ*Ýö¨ÞÛo¿m~ãH`Ë–-ñË/¿à“O>1òÖã?îÔ ½·‚aƒ“ºë]8g†[ÁÈ Ü †W¿€^Ùƒwº#ƒŸ V;Žg‚aÖ¼д‘÷±/öM'9cüø;zfÍ—ã6 ~Í}ÎÂÒ;’k¤½ð"úxûõ3Œÿ·mß¼øU  ÄgöŒÀvï¾›nG“)þ‚̈ÞnåâïF(ïCå–”;kïC}È‘]•OÔ–RÛb"ßZZKZbgA›îW´Þ“ž»ü9 n1C[5óÞjóÞk÷Jæ šßÛŠŠ¥‡ï„î8îy{×]Æo•]FÅ„£^ÇbºJ6ižË¹£‡«{'Ük\íÎÜ<ÓDwƒþ°a#1mÚJLºÆ¤\f9ío«sÞo÷>žœö$^žûrØ1Aˆ õeùl'êÿÀKñ"/Õ½l85å­.ÙõšfFö»L÷CØù´]î6·I¸—ݰ˃å ]¶ŸsÊŽÁèŽrô&P´ÿ¦’ñã?(¿ü6¸ÝESzï½÷Ìô<ŸIYU.ÜÐ{Ϧ ]¶×Û÷¯W½ß‘|—ÊJC>¤´Oš¶“Êà~y\zÍPò'%=¥”'÷´0MÄÞ4'õ?Ñ*{‘â4IaSS›ªpxå•ZfÓ«œûç1õ¼ä¼îj¤î"\ÚÛ*ì¼ ì'’ДV~V ~¥ý­dYpD¯_¿~F¹àwï»ï¾3Ë´¨ÐÈÛ•˜5k*T¨`”*Û|–~úé§ &ƒÿûßÿŒ¬E垣ý ðÚk¯…­\„‹©yñÑ´¿Ï¬ùĉ¿çØôÈô·á/2#?ã ‚>8ô‹Î‡„Ã}ä0‡ÃÝðÿ"âWƒ? ´÷å¥Rå„nz)༂ÒJ£ÈUE0ê¦ôÐüg F°f9ÇÙÎ}ܾö»a;„qá.¨¿Ñĉ/ašãÝ+¤²@¯hvy'!g´ißm©¥‰ç—Q¹à¾Ü£ QDtt‡í·ãÈ,ß³ÜD0_±o…Q28œI³5 ×4¬Q¨Ž&Íà·Û÷õáobÌê1Öj*¨dwÿÐü‰ÊÆ-ñ›¹¹!ÍÜ8á›}êØÎæÞÖm9í¿ÀyA/™©~™Ú‒ëÜM¤^%*›îõ„»L몜åV<ìºç#ì6Ööu·«Ý¾$a§J÷¶îíHvÛ‘ÚžîvU»{£5PÏcÒÂ’@ýBïã?˜äï"^Ð6bjߣnÚmJš !G0rçòÅ…â¢ùâ¢ù€ÂyüRžGÎz#• pH3(ŽVÄJ¥\R™dÞ˜Iåà"ÏK]3‚AÁžwS þ| ðÊHÎ3#™× RŸ|BŸFJ½Ôrxœ|¯y–s½>µLµul š#¬¯©nG:­æÁ ‰G1[#~Ð g"`CªŒ`È·Ê?‚!ËþŒôÍÍÕªÊEñ›­DÚ#ª6i‹’îgàGÂzN¹Å$~ÐDJ4'àÓO¤CE¸¸à`À@D´ éD:Ò’“qE«±mçlߵǎB§6#Qï‚Àc3¡~[þ±³äM~bs@‰¢l[¿Và¶Ûv.Äâå£Ì1vïó÷3AÊð±èÔ,>µ‡Ez+ÇHܸ­i'pIrm¬9½Ë^) b¶çLìÝ¿§ö–s™-•Ê·D|\I[¿k"éä!ô®6-‹eÜvKòj¼½®Vžƒ¨ˆ4(Øÿ«ø vÖ¼é¶î]Œ úbÓîyÒ(i([´®mü"J¬íÔHǃo8 áôû©Õå/bËÞزg!Ž?„›šDƒªÏ{wÂj|;§6îò]s99Ÿ•[&<ú†:#pœv·ªãµš0a‚§rñwãŽ;î0B*e;ÞÅÿ€<ùó`êFZdž‚¹«eŒ“Ï>«`Ö‡ ÿˆ‹=RÁ”#T$¼â`ptÂŽyÁåŸ\ee„|»²Œ-M£˜wt0•cÛ±%øKLÉø’h]©5z_ÒµÿÈD×þîúïpï…÷·»?¬û·;j\U¿ìˆ¾Óúâ‹_…$õ?V>p_ÝëuLj¶#ðèObàÔhتa†8%èoËÎ-H8îxÕò‚ÜÉêÚŽ}}>B?ˆ^äeÛy¥*(…"»Ög.u[ÂÎÿ›àÕ¶v»ëzw™›6Üå^y{ùO;“r¦›,?á¾7Ý´ïe÷eëèyJ øþ&ÓäÕbHœ¯1ùV§9ôËãǤ×t™ut4ÃŒdÈ“{ZÄc3‚aшÌ$Eb%Ed¥*¤ŠÔJ«™ËÛenrîWEsRÏÉýÆñ€®²©›Ù—ç^Ö2ݽ¦J…íW’°—C1l°Ï½xžáàA_”œ¤ý[¿´N ÏØÀÛ—MÂúŸ?@„(¿¹ W!:áönÀk¯7‹æ1ìuéWéØ6W#M”™ìÛ‡s`Â+â[d/0¢v—vŸúÙ¦ÅkH9šàÛ¶°o[¯sZ³a-û@ôüHÈ+²“ì?9e^L€u§× Vdðmm0ÇŽÓ†èIjj¦çLÏSï~zmÄUM£IƒG±fý˜½p(¶¥¬1nn}ȸ-½M=¼ä2ì:ºÝ+ F—ÒbÁþ‰xì÷+EžN¿Éh~ôÚ·—â@âf´¾è´º¨ö^‡×¿kн‡Ö:µ2A8}%ýôã¢Øsp J ~Þ“¶cØw—aÿḦá`4¯û(6ì¢6y4œ‘ë3ÝÔrb.í iSËI¶œ ôO'åÃóÍŸÇó¿Yú ®ÿæz´ý¼­ $ÈæãÖŒ3ë¾½î[Lúa6^¹ÑÛü©ù\:üRùÀËg!Ø—A„õtª¯ÿÉàe£ûûkSa7;簾\ùÌèÞù_ÝÎ^íï^¯p×S¸—ÿðý` LJŸžþ‡×ýH^)éu_+meƒs挢!+hÅIR¹HÅÁ¯X¥Bò( ¹lRé]£lSåÉ=!<)<%t¿’a+6)àkê¥\x) gKÝ·­dðä<ýoh1S%«“º)SR/O—ÝÔÃè>Àö©B—Ýt÷3Éò°áõœœ'ψ ýŽ_Ñk<ê_Ÿî8Å*ÍïC׉hóÌB«ÞBÚÊ»µÒGáË/ÁCA›þ;ï8©˜®Oû¸Ì•‹ÇîFïû6¡õåÁMDf‹F7úÙ ÞÿÐ÷Ýxì›põÁ·mXï><Ó+=n[ˆ e[È ¦!wîâX·Ëso€¡Kì;½/€‡²ûLÏš7éŸé9ÏœûŸÃÕWŒðíÕWì§Ü±êÑ ø5/Ý05˶E¾¸ôó.SÄ'Mšn ÄGúÿ!hZ¶)N¥žÂU]elý«\RŤœ áåÿ=¶Þ‚ÒgDåý`ð/ƒÑú³Ö&RvŽHù0¸û™ï {ÄaŒÊG{´ƒ/Á«…TF8/„нÙѤ—Ê„šVyA¶-ý[i3ºÃÈÛ«ö­ÂÓ3žFÛÑmÍ(D‰=ðö¯oã—-¿ààQßЫ‚Þžè®–óQžzj•p-úö]e–Yžz$ÕD0ïV§›á5•¯A6†È öA‘U»÷íFÒer‘AL¹rOÉ}Öõÿn¸¿­J«œ íV;µ»Z—I6¡½lÓk^eÿfØmo÷…M…½ìµÞ ™­?g`级ÂXrÎG©_ýuãF“®™©Ð»Ý•‡çéq¾ƒ²ÒTò\þíû–䥣ÿò¥¢)c*ään3ŠAå‚ ˜3ŠáW&H¿r!×cF.$ï7‘’˜*¶™%l“ÚÊ…MøIU(@y1”¡ôª£ûTCMÑ@i#H±XioJ:—š!¯Ômì}Øp-k_Úв¬0lx)âA”p•în¸ÁüÐÆ@’ÕªUÀ2 ^½z5Zµje<²Ñu3]Ùºêý•˜û~Ì‹ÿ ¨\q(,\t‘/ýýw_ÆLL?.']?÷r<¼’^-€q?ÞÔTÚ…ÿ9èqÌwlÎÑ}âc ÉþšY‡ì@JÊ>”,ÆI¬(Yì"¬O ÒqÐÊ®8|b*ÇgܶJî‹°}ú¶'O§":Ц+ˆ‰ŠÅ©S©Øy`¹Sî¾êî´÷ôÕ¡¤H:º¥ g¼öC4¿¸yÆ_íùväœ?q`Lº£+yFħ"Á¹üÈñU·´|QÛo×`¦U„(´ ê4@‘¸"h^¾9z6ìi¼?M¼q¢‰æÍ9¥ò”œmsðÀS×~q-ò(n´#n¾yƒ™ì®òý2ç«|§ hþJ\ýÙÕèòu|»ú[ÎUEb‹¤Ÿ—òµ?–*_p^Ÿ—§+Y.V´Øý“À¦ FBÓÌ ÍèÕœv÷vÝÌHx•ýWànÿpû#ÂÙþl^‚Sáé‘G1qh轆óœúöíkÜe2 Þ!¾áñÌÀ÷ÝtÞvÛm&ÒÙÀ}/* ;OØë•¶r‘RÁ(²`F0Tûà(†Ónþùnšv”ž3m)i€)‡~IÛ-y“¶’AÚŠ†M{ÔA—•îò`u˜ÚDzωä¨tA‹ìT7ÑÍmÚ»u“Ûè~;v_^y]>+x='Až‚.úé‚™óèÂyذahÔ¨‘ñ ŘL º©½ì²Ë°qãF <>ú(&NœhxÛŽý¯DíY0/fr'"y´Œ°ÂDó&¾ã2(Þe û SÛQ¸¾ý¨V©,y #¿j%Ï!Àsdz?cÞK½>€NÑ7à¨ΚÌÁ~Dî\Û!w\19‘€S òìð] &ã¶ù³CÊ1ÙÖ™‡Q8o3¹›#;Š“¢XlÞãó£{8%“¶v÷U§ŸÏ ¯S|×›ñ¼‰ÄÄDÿýËGû?úoº@ÝtÁ&ß<úrcëp@˜.P©„ГԣïÁ[ƒŸEóæ5Ì2?È6èšuÖæYèùCO´ú¬¾Yõ ®­z-&ß<o\ý®(w¢Œg Ýíí7[´NûW{:°ê>©¢©”þÂÏy;Å…4JÅ T*ìúºo¦²œwn^”¹Ú[I¢×¨²yË¢må¶ÆÝî§?5ŠÇ7]¾A÷ºÝ±wãl’¦$Ê·Ã\Ñ æO¯‹tûÑmˆŒˆ4õ²=ËŒ7©£y†TvNEËË…ýâ6åbz•ßJ™õõ?ú FBS…{Ù öG׆ýv×q—ÙËÿEkÅ™ô n½?ü¸…c2ˆlC!)ŠÃìh’¼í_­BAV­Z…Œ4ÂÜá\Á¾w½È×W™)—?¥ÀÐQ2ÈöRÚå~µÂÓBþÊ¢ †Q2”*yÛ¸ ú¶ð¯TeÁÎÛËÁÊí¼Ú´ÏAÎ×Ï ÐUvUÝÔÞM°Ô‹!Àþñ‚]îÎcØàÍ  ¦’eAÀ{œW©,0^ØwÞiµrt‚ò¸Ž` ŽhÐ]3MŸxâ |õÕWXºt© Ì÷w @Ù,˜s4†f6nä %pÖ„B‰¢¾ã^ÕìyÃZU;ã‚jסsÛ‘¸²é lÙ>+Ö0Rð¹GÈzøìÄ(¬>½ÏfÏZð‰'}×ȉénDEùÚ!5ÛQ$‡O¾ŠÎ–qÛ˜lζ§|ûoRó>ì;´ŸOïn¼7í<°ŸL½GRè30ý<‚ÂÕWjF~}ŹDT¤Gß;Б:>æÿ Ðå\(Ð5j€ n£„³>l³ :Ív£×;üfAC†ôǶ]Û0qíDÜ9îNcf4{ëlÜsá=˜|Ódãâgˆ^¹íð6¼¹êM,Ÿ¶Ü¸Š¥ÖÊS*£òÉÊÆ$ȯè‹Ùž¬ÍxœoÏ~¶_Ú¶RÁ7Ö_%üXnô÷¢Qyres¬53× ): ¯/x]V†Æ©V¨ò䈅šeç‹Æ4¾m |Öx§>PoEIŒ¿q¼ Q.ùxIÐ8%,¯PTÖû*H=àMdÖ×ç+´µ»ínUh¹›Ê.Wºa×Q¸ëe¶ü_ƒWØý¤ðªgƒë3«£·^¦àóŒa‚Jž={Âr Í@b}úôÁ“O>yÖ£gÞ³JÂ^öSþÓT ͇6ÝB§M]é1£\8ÔÞ¶ó’w0ªÒ‘UQðb°uöqìó:CØ»Ð]ºS7v>‹`Wiªù³†[‰TE2ø .áL[´hQDFF"†.ŠcÆŒ1q/4Š7ѼysT®\Ù(ÿxä‚®OÝ8æÔ\pÉŽ@W±ë7Sp9÷HLKijǟ@Ïì¡x¶¬ÅoS³¥S'3¶ÃÉ“¾vˆ‰p„xb²ù¶=q:ã¶©§m#}u.­yZÖ‹×~ŽçG×À/.ÀÄMh^Ï÷Ãwöh—™šç°¯bœk>yÊcr:ûã£þŸÀ›o¾éä¼a\œ{±I+í®°ï.~ÖNÀ’]KÌe;HÜ A}üfA{¥Ý ‰rwL>.»å»[ò¡D\6¼1Ö'¬ÇÓ—=nú}/ë‹ê…ªµA>.7ì]ãïݸ–-Q6À½îš…k°añ´8ÞEÇEÌyaéÛTá×¹Ųߴ¶ò¹|Z¾ŽD®Ã¹PµVUŒ0ÌÿË/Ç—®| 6`Ä¢þÑŽÊ´hQÅ?:ãe:ÆèÝ={: ‚lÖ%s3¹14o¢Ç**7•¨Œø‘ñˆy/ñ3ã)º¼ÕCŒpèo"³¾>_aw£~@í2/d¶>3þ~æJ´IDATdö­? Yà¼û¹l—iÞ]N¸—ᔫsÎà%8‘!„'7>ûì3ãE“½3ÃsÏ=gìÑ7éï€ý¼hÞ‹¾ÿ$‘Ô”1e†ï.£0¤§è©TȲ­\x*^äºsA·Œöq™îÔºY0Á–mx•…6¯Ú0MïÁ,ÏD˜£|Äå—_nÒîÝ»›ÑšL1 >ƒîÑ<Â׎;Ì·“‘ðݸ袋ðÛoÁm÷ÿ1 y—i Íqˆâ4¡8{DGå6ˣǜ’s‹7Ž•î<Q×aËé͆;Oû„ ºÇ=xh3NŸò~)Ò Š8’ì\³šOÅG@¤câFì¾m¤fÜ6áø.äÊ!ÛFr”ч¶ bÐ{ðPÇÙxâ†åx´Ë¿ÙX¡¼•Mç°¯Ô4JM¥ÜÈ“'ß¡ß$ÿù<Ø›G>yöæAñÜűóÈN|ÿÇ÷xzúÓèøUG´ÝÎð‡9cPÍq »#ü0d pTúÿÉ:@ùùñfC™¼áÍÍxøÇ‡Ñã¢&€(7¹³ ¾÷nìpcFá[ߤü¡Ð½N•¦À-Wß‚¤•IóÁÌ90W~r%úÍè‡5û×åçµV¯aÁæht_ “¶ÝJFÍšc5°œë½Àkz¡ÿ &žJb‹D¤ÞŠÄ[±¶ÕZlºt"'ȇ2ÈÇù>Á›Ð.ó¢ ¯åpêeý¾‡úÆŸÁ÷ÿ_‹?³-ì}{çœÛKpÊDx²A³¨=z qãÆfNE(¬]»ÖL 饗2D)þ«a?šw—…zvìQ $L^þók(ö²Ò]GS›ö‚ ¯²¬"Ôdï[óvê¢IœÔ†{93Hýsq_›ÓqxNै‡P¯ºê*3¡›¹ëÖ­k¼­qî• Fø& Ÿ(fÛÅ;`YBBÂß2cݬ,˜שËiG­×Âß¼ÔÑ8 ™cÑÒàÇ=~üRRö#WìŸ3ÇrÖ©i8”v ’k vRyÃÖ)œÌ*ëæ>¡o—GÂaÇæÛ…<¹K VÎkû.‚ÁùÒc`dį&#Ot!¬I̸íGZq(Ò›=/ÊkŒbj˜å5Û§"o\)ÍWÕ,…«¯ÒÔŒü ú*o\ Äå,„-{3ž7Q¥J'÷ÿ †æð¿7­ÐÔÌ9¸»þÝxöògñ^»÷ðý ßûM|Jå-êŸÐÜVÞ}¤Ÿ“{ äóçgDø? Žú}ò‹Æ~M•Ð.—îYŠÚEj›Éa9~–ƒØÂ·ÎÓ6Ïb+÷Kœè ަ j>Sn™‚–Z÷±­>meL¤¢g¤ è…û°½¯ÃT7Ak9ZsÓM0p`àü”`¹üÒˆœ¸åþ¾Bp. ç¼dˆ‡‘8Õü*.©è7cÊpbuœïÈÊG3+V6±Ò†]nÓ†{ùß½ÆPmàµÎ^¶S»ŽÂ«Ì ÝÖ®k—Ù ¼Qø|ºÆ ´{÷n´iÓùòåÃ7ß|t$VÁ@¬—\r :t 7Šs÷u+ wjë,Á6æ2É÷Q84õ¥1I}zýC §|y“!‡CÜËžä·…ôZÇãijӫ̃æmZ×á_–Ô}J.ÊºŠ©R—M‹„¤îfk³*Üå6Æ}î6C€JEÓ¦MñÞ{ïáÛo¿5N ä]WuÆsƒÞÕ·Ç©¿ [²`^ܹ³ÜFr½û®S íJ3œQ#† Q"|s£»—àäÉãF™pcúœ&­\®•IÏ5ŠE”Àç9Çðµï˜uõ.¸7w‹xg¤Â 5«tÂë'˜€{ šsHX‡Ë Ó\ÄëŽ,A“°`ÿpO±$av¤¬CÝŠÁ·%¯ûÛö.B³Ú9%!àî«%Kθ¯ˆÚ:aåæ &àž‚‘¿‰Vdðˆ´¿b¦èý`x}þ OoQF¸e[óÁ—ˆ(ü…<3!–&Cüußë;Káš÷#3ÐüjÀÏÌ„i°sƒçI~ùŠXVs j­,ƒM ñFÛ·ñí§ßbò¼ÉÆÎ3WD.ìÚ½ GZÊKs©yBÖ“s‰N‰F§«;¡JÇ*(R¸þwÑÿ¸ë `äíÉë'£÷Í·àÍñòZà"ô¯°LKƒ]›žçŠ rE³(Ž\ÜöÀè=·7Æ\7ÆDþvƒ®éÅËó+#Ç¢RAS±ÎæÞÖm©Sy[kú Mbä‹~YÆ!¡)¡8SÞÒÁ¨^»¾×:îí´Ü®{>ÂnC[N$ƒY©^yÒ®koCLí6³©mên_Raç´Šåo£¡îCÿ½ZX#ŒöÍ9õã°|‡~N ¾NRmÖ¬™ñ‚C/RU«†þõŒ“XùÑ¡ UÇú¥ìÒK/5ÛÒ)Cþüù«Îp çÏc:ÓsCÛEÛŽ¤8­b¸-ŽÛuˆhéèal4È –ƒ—S+),²<¯È†¹¤^ö(Ú@Koò}ÍÙ0‡¬Œ“ sKå¼²ažxÙ¡ä¹+O9×s$'J¶‰¤ …’§ìü1 UKµÄ=mÆg˜¿ûàNÆB¸}Õ©©ôSê!NÞ‰9+Fˆ2ÑÑ?šÒô‚‘3FÚZ‹¿”kΞWÊäšOÁOK†àXj¢ ¸Ý Ï×FÁh×®ñà Šé-jæ¯3‘t"I>,…ÍÈÍo2û…¼gÏn¨\ù#Ôð\@dj\qE7 &ÚbH9`\·~Ýåkˆ-à”¦ƒÉÛ·olæz,/÷Çß˳¸Ë¿®`¢…ý}(n«s›‘àõÔ¿¸>rË×qGÒÊY—Ö¿Ô=tyÖù«Îx¦Ù3&ÖE0pÎÍ¢ݶ×ïò™“·wc9½†BÎ5aÄr´ª½îXˆA¿ 2J'†Û`üºŽ\pJ(„Ó×çgsoë¶œêLÁФ’nÁUér%Å MmÚuwÞ]_©ëìºç#ìöc»*)ÐØ)i·³ÚÔzî”Д°ÛÍnK»}mšºAq’–¶a NeDpò¸á–ˆ`W_Þ-^û8vìZ¶lilÄPI?$¡@8®BžöhBôü©`¸ä>?Ø>Úv"›úÅo7µI"@Áw›Q0ä FÁ9į`ˆî` ‘p³K}£`DJ† 'ñæäJ©'ç¡‚!Ì-y.礂!u(—Ðëó+(É Ç|‡—7!®@iì^=S^¸Â¬³ë4k†F€v`~úià³OƒÚµçD¨¿’f‘7_9%À@‰¥ø)ùÞÿÛ$ÂzŒÿélÝ1GD‘8v óUBí7á>ضݻ y󔯯-3ñþhßyÛuôÜy-îk^· ¥²eŒY¦ FŽùäçÄùò8g—س&M}[¶Ï–G:;ªVlƒ[g!1‘¦#¾czÜOoBúílI^…·×=Œ‡g#ZžÿÛàÞŠ/cWít™sÿáøêçû°mߣÀˆ/UoÃåuöœãá©`„ÙWùò”ÃÁ#ÞmýÌ-›?·ï¼w%¬ÂwsƆ³G©rEaå–‰ÏÄFÁ˜2eŠù0†‚*SwNʼn¨(°³@Ø Æ‹S^ĨÇ_DîÌ\ šñ×}Î9xóÍb˜5kiÈ}pÂxç¯;›IàõŠy· 'UsÞM“fïfìÊÈ7çVh~´vm7ì½ìÞ»æ=ÄÅð¯ôëþzå×òÂND÷zÝM¹boò^tÓãng"š{Á=:“$ˆEr.8À J²¥1ú™qÆ–ŽºdÖÞtÍ;mã4¼Õæ-Ù¯³cÁ¹Á§¯Ï5ÎæÞÖm©`ðCém;µ? ºLè² >äJŠš*íõ$a§¤]ß‹îíÎ7¸Û’TAE-·ÛØ+Oj=»¾’`ênc¥¶§;%4õ‚|B8è–à´¸TC¾‹î}pnTÇŽðóý÷ß›a^ ùÔ¡C‡Œ [ºµå$W÷¤U~v¨¯lÙ²&žFÍš5Q¾|ygmhèùó·¯7–¶Þ—" (¶¨MjÛ’~C¤U£`ˆŽ` ‘ñ‚!ô+¢Œ`0X(•…)äE,+pCvÀÑ *\æ:Žrp´ƒ „Þ]Ž‚A¯3F¡ å€Ù8’Á¼lo<Òd¦`ÈKÙ?*Á;‚y–ÛW¬©³q¥IeB [Ápöa€È6þ ¡*IB£`84 †Ô§6Á‘QHŒ‚!›ø 9ä>9Ìn*¢\ø Y>(ë8‚Á]¤ E?ñ?{l)^= ’ïL͇«`ÐÏÓ|aXÏIyN¤+m,‘f©¿Á{{* š7wî\§ÄŽ^0øŸ~ŸèI#œnƒÛ—.]ÚÌá8—Ðëióì⬹£µðÉ-Næ 0¨¯“9+Ã3Ä}o9™3À›Á­¹ÃÂÅ·3ÁjgNï™ÀKÁ¯?àd²*?/~(é*ËàGäñÇ78´M$êY³f9kÿyÈLàäèM¤Xo{ííØSsOØö}{NÂ̘¼Òù4â¯úL¹œ™rA<;ëY\[åÚ ÊAs#H>KN爼xoq”o–s}Rj’_¹ ôº//w9¦mÊèæAîú6鋞“-·O.¸'mÇɼ™\NŸªr|¹ƒäi`L©è~÷ÖïnÅ+¾ÀEMœ‘AйzgKãÕù¯:%>d6Æö µrq® BŽåûºIhJx­÷‚~€mê‡Ùþ@{цWÙ¿öµi^™Y‘„ײ¦ÁHØi¸ ¶,j“å` ½ñãÇłц?ýôÓ*ø]`l z—"øK-Gm^{íµÆ›…,.‡«\Ø`Û{Q…K7Ãn']É”ªDK镤D«¤¼¯4Ëò´eFË“%‚u¤¼¤³9 Íðßt?Ißöô%"ÅE‘¶•'EÊ>%M†˜r93åbüšñØŸ²ÝêtsJ2⤼ÀL”6ö-ˆž¥B—9bj"yÁØ‚H8š RÁÀ~ÅâŠá³eŸ9%5i{ôç0ü‰‘fâ;Ýï¾Ðâ¤ÈÇòž ÷˜èÞ/Îy+÷®4¿XºñØ%aõ¾ÕøhÁGþ6ýùן‘m²\ÌV© §Êô_ä-*ôƒ™U^e6ì2½½íÔMÞú^åJBÓ+Ü׌ÁÚŠpçÝ©æ {Yón^åÊ,ÁKp !<Ñå&ßñT24̦íEŠuÂùœí÷‚íNÙßM–Ûët™´ÛJé ®°w¤?™«bÁ_´ÉXsÊ“–C^X9D„‘†Œ–ÍF©ZöÓ"ÀŸ¢ò@%B‚TQ8©5U”…ãÂT'ÂáÉÃRßaÚ!‡})Hšn(u™) €HÙ‡Ÿª„–¢£ªˆ¤IJ…ƒçJ%ƒ ‘Q0,Òÿ½?/×v’”ë<)×K(’£†²[RªúS4µî¹ÙÄP6±çÄ¡úI«ñ¡”ÝøÉ[Ù^V²^ØðzN‚<#DïÞ½Íh_“&MÀ€’o½õ®¾új3êGSAÆÃ &66ÖüH;|øpÍ›Šå©Ûo¿ÝÔù+p`ÓbLÚ £ï̓OnÆO/]…„­Kµ¡A³›´>}V¢8ÒrÅ"­QC¤Mê¬õ!-9iýûcä­0àÕüè;8–,ûÈYëÃÇ_·3å^|rp^|»>ü²ž{-?ž’ ‹—nOlÛ¹c¼oŒ¬¾/F›z©©ÉxþXtLn…2‰ù‘71>O Üö†”v&]sjµ©W"17Ê)€î)]1iZïçí#o¿únusÎŽn‰Ço…?çǕӳaÊ®ÀmŸ^ÖΔ»Ùbz„áãDŸ÷óãÁ7³aÁÞÇeн·Æ·Â£ïæ–ºðñÔ[‘tt¿³6}éÙWÁ°÷Ð:Œüñ<ýQ)<òN. ü¼&ÿ:Àt/ÎØD*))IÞ''‘7o^ãEäºë®ÃÌ™3ýa0ø‡C Kþ]Ç4gÆw3иucŸ"B{ÖeëáwnæÁ *(öäçäì§±³N æ<°%‹Fú;"Ÿ7üˆñkÇS¦ÃcØóûd;§‚ üž¯†|wUÅ·×ë”ⱟÃÍÜì9ß‚ Ýík5 • TrJÓá>ï#Ç!ªhnŒ}kFÐkf,_¶þb ®Ú¿ óUD›ÊmpyÙË‘3Ú7æ¼}×vTy®Š|Úä£F—º¼6~ó~’oóžhDˆF™YÒ£²ŽŠÆ šH¥ùL¤¤Ø˜H ÷É!vË¡vÈ;»p—z,”CÒÒê¨ì†VXj"ÅgGŸCÞºJi“JKúŸQ­ïõ¼ñC£½°žÑê¹^ÌKäüêï¾ý¯¿þŠgžyƘ8pÀŒÐQ çnZ{(Õþá‡ÆìÙ³G)zf£+Û?ã;§×óÖE‹Q)ÞwÎë—à¡Å—˜¨ÒmJÜcæü–0Mº3Ã/Zˆ’±ñZº¬¶Ònìʈ¾‰Ã•Dn W"¹vLŸˆKèÂRêlÞ,Ryä‹/ƒ|yËaÓ–™èÔvêÕºÕ¬'Ömœ‚dÁxÇ®_1ç××$ü¹Ë @|9¬ß175…UÓ·'&-|?-Œâk›ÉÆû¯Cÿ›7àÙOäØ!¶]½u Šæ¯îLZÎg&27“–_ýFÞT¾ü^dÏ•{×Ïņ٣Pªn;\Þs¬©w`óLìŽL¤âââŒrq¾`ìX_#Cfö<„žO÷Ì8ÊÁ´`à(‡zl;Ú7ç4<òÄZ¤¶\»‹îÄu›!~Gâخ×pÛØÛÌÄïÁÍ›ÑË/n2¾D™ZÕQ*ž'—ûº›—kŽ©½5Ö(ùȽÓöô˜ÔÃ(nð…gÎ,øe J^_³ñW³Œàq³GeG‹ò-ðj«WñãÍ?⡆aíµ¸aÌ èôU'¼ýëÛèÕ¯RNÊ…?êh›Ò«ƒ|“Úœ@Å«+âã¯?6ÁÿÂ}éfÖ×ÿTð³Šòõ,' wÞ†{™M}¦$ìü¿Á®=îeE¨:^å6 ¯r2lÈ+Ï/‹Údùy43£ ›63m+®dE݉J±4i¥£¢0Vž´œò¤æ©8»4¤Áàû”#òž3#G¤å#/äÈÅñÃI™ÅÂSò~=%ÚÞiIÓhL˜vÀ—ò—-C§ÜO¾“Ý£J¯ ¥EÑ0Ê…çË‘ 3Šá¤§˜·È 3Š!×yB®×Œ^ÒÇ¥-H©æÁpšÂè=ÌK¡÷œl–aCh÷•Ýgv5¾eór—¡6XYŸ e&;`°¼‰'3AzƒZ-hšÚÊASBÎÉà¶TD>þøã¿ôG´QŸFQd‡]8J÷ÂÃÕÞ“ü\¤¥Æ‡ëŸtjy#*ç ‚ˆ^@Äwœ^¦ ÐÇ’…èIk×nô¾oZ_þ’SˆJå[¢N3B3{ýñëdz·nBûÆÞÛMjÞ‡ïNDï. Q¥T 9Á4äÉUƒnßrÛj¥[bÊâçͯñ´Ÿ. ÆýhYÿ ÜÞò ³þòÆO=oIÉ{Kݦ 7ËÍ›ôǼ"›ðT¼÷¶Ms´D‡Ø3ð´ÜÑœÞóÎ!;sîó8)ç|çÓÑèÂûѬñèÚá+ìÞ³”ž5œZ´¯† ¤¯ðê«tïçë+QzCaãÜOzô0®xx"j¶y •šÝ‰Kîü.¹Û~‡Ô¾W¼x·ÿ‹AûÇPÈ,ÐÞiùhLš;É7rá…À‚ß½gôè±íhßÄkë€E(ZÈßa.|­úNïkæE|Òá3qÏ…÷˜M•ÞU+VÈùð*PS¥Ï>«€ö·ÝŒÒŽW…}Ý—–¾³·Îv–2¢TžR¸ÿâûñøTß’¨ø<1í g)^íÍ‘*Œ2êÚQ(WSˆÂ̳è¯ëg¯GÛGÛs4Ž2Ñ”*Ô|"³¾þ'ÃþhºI¸óš+·ÓPÐx¸ü/ÀëZuY×…Cºl—‡SGa¯ ưá%8…!<ýS`ËÿÁ¨u˜zµ™öJݧ’a+J*T,ŒrÁ2y)gÒD*J4R$鑪9"à7‘Až¿rR€¢™”1•ÒtʘG‘òá¦yÔiR”5“¢â`*e“{R [™à¯ªy”“ꨅÎɰçceB®!€Žbá§\'M¤üfRrýœwÁQR6ñSªºî9šHMAH%#hÿXjº‰¡*™‘ußû\óý7`Å¡_P/_ äŽÎ甈,’½(jå½ óLÀ±S¼'‚à›oäþ–ãî»é/ŽÒÝј7i;ènBÊbbQØçÛÞï* 0.ÆŠ5cP¾Ìå(QP­.‚oŸ;¶0¢#‡š¢"cL¹Á·]ºa j–m‹|qé^õ2­P0,_ýUXçýãÌÇQ(UQŒn’û6Ùc|ã«Y¹æãiÇ1åØX4޹ñ"÷…Ú–mS¥b[ä‰O?çŠe›£@þÊô(à”8ðè+3¢ÚÝ×WpúÊ ©Gù‘×^¼Ÿ@#OQDd‹D¶(þòâÿŒ‚áöÔàFf“‹[h…¢ñEƒ¿ñ¤%·ÖÙjÌŒ®}ŸôÐTàÖxrÚ“˜¹p’’öëòÿBŽ9eТ"£}çÁ¨ö£Ð±ZÇ€‰Ú þ²QòžúX¶úº Éé¢ö°ü¹#…Û×M/QŒmAC»*íÌ_yT-P“Ö‰âåBfí;{nt¨Ö…sËMëÕ¦üö‘Ï]쩼Ǹ® wÒ}fÇþ§‚¯’`$4%¼ÊˆÌ–½ Ío§J…{YáUv>"³ëÐëwÓ†{Yᮬž »®MBÓ³F0‰,KÒ×ß~¼Î„v[+è¶‚áÅpS'yÇH#FKcF‰$j&y‹dMaÝLð¡M'u%CH…C•¦å8¥”üi!'v§©áE 6m¥BŽåOݤéÐ(B*F¹ 2aS¾ª\øór}Æu­Ð(B£X0•ÝrYóÒ¼LUP—f2Ê…sáî3»šlæ§î*Y/lxí4K;øçâDZ*b"yã"{d,NJßnJZî”xà÷߀ʕç’U.r¼üþ»/=C¬Ù0 Ç6ûŸ‰CI;ttJ¾Ð)IGÉbaçž@x^àüß–Œ¶-hÎuæ˜~låïúšÙ””}r~Þç —×>³,}…3è«¢Õ.7鼺›¹94™Ú´àKG¥Ú•"*&ãý£àëÓLÀ¥ópøoíû9‰8CÄkkrqf£e~/c¢zï:Þ®_é2ö‰KŸ@ך]EiÈ?--ÿH%9n-àrØ:ùä;fÞ²ÁÁÉÒE Å»o~é9‘|ëá­F0ÜhX²¡‰C /^ù"†/ŽíVdÊ`x¢É:whH¥%‚¶)=ü5ê\‚w«kÒýÚDúA%ìfójÂp Mk§î¼.v™]þoF¨ët·…½l—{Á½Î]?³mƒ1lP¸Ó_dm²ÜÉÉÉèß¿¿ñ"ÅÀx4÷øè£Ð“mÐ6·mÛ¶(V¬˜ñg$$È}ÊÕ»¯ÔŒ<Œ¾*Që*hq׊Ÿ0¡_]Œy¤ ~y»«Q..ìú²SË|}÷²ôf×® í|tNÒî–½›™Ð]éÇJÈõM.³¬“·³êB•^R8AÓ£ZEj!GTnšP©(+ʤ*üÆ2Úu(¼<ïe<Òèg)#¶Þb&D‡B¨y Îxóê7qû˜Ûñ@ÏÛL ÛcÊXö误{Ýîx}ÁëNIÖ´Myˆæh ­$°?–nšvÞ ^ë3ÛÆ†ûã®òÖÿ#x;„Ó>Z'XJ„ÚO¨uY†—Ô¥ôŸû`Íš5þˆÜáz‚¢rѸqcŘ¶è¯¼òŠ™øÚ³gO3ÉõL`+^ä™iª$¼–ý°´’î0˜¢¡Ê†Q,¸,i”0R^êÙH6¨(FP]G8×ÍP{zf¢âa<41úGDБ2@IpSêûS’Ê‚åøvÊó2y’çé&Ï_)×cç©XðF¥â´\7IÅ‚‘Y¥Š_Épš!ýFʦ|Aéè…ékÙ Z¬Ul:»ó§^ øÀYòAf÷ÃÉ_Ü^ठüȱ.]íÚ`ˆºse ·9ßÏA©¶¥0ó™(W¥ÊÕ*‡cG¡ì¢²¾QŽeBž.ß`Ö(Çõ×_ô:Üñ$^{ ˜8Ñ—g9×»Ž^÷Â⯣JA_}Â}ô4U(W!ó£«<)))¦îñMÇñëÎ_Rß|/—xÞñ(V¼û+6”üØLHg$ï«®Z…3F™‰ê¶’1gÄ|4ò#ìNò½”ˆÌúƒÛs>ÅÜ_ç"ê{ùb³;÷úêøv¢1…øýûBÆDÿ§#Øu„ê7½¯x,ú:ç=®#{Ñ3ÃßýXºÓÌ ²”* ÷2açáÔù'BÏ[Ï×^¶I„³l§™!TŸ…Ûg Ê” 30È /^ÜÄ?Ú´i^z)óI6Þyç3âñóÏ?¥â®»î2‘éuß•3ÝÁHx•)ÜË~è ÝÈ­dؤÂá_–ÆÓ4›³–ý/4!…rþâO¡ÝCBó.ªp¯B¿_ÈŒ¬Œ”ŒIÍÛeý „ž³œ¿É;©!ónÊõRÑ0J†¯z@ÞÙ…{®…¹á¹¬yBSAÐ>ØÕÝÔ]:‡ ËÃ7à9ÛdYðC™†ß~ýúáõ×_7£w;,[wÆ¿àý¿qãF㢖½91üÊ+¯Ä û×ç?mKÞƒ®eŸÄŒÝŸã®ù5°8a vÛ„ëÊø,rDf4Õö#gNÑM©¤º –.\&º¶4k^¹f N‰òýg›Gíû\ߟ¤rïÂI*ÿ‚(zvó¡g>Ë<†<¹ƒM&õÆÛù¯yÒ±1òôG‡œ™_st”¯mÙFnè9´¿»¯ÔŒ<Œ¾Ú4ÿ ÌuÝñ>*5íŽÒõÛ£q÷÷QþÒÛ°ä«>8žDÇÞ8'‘¼Ï7µ>GŽé,…½=w´oHwÊмÊ.,‹†5IJ?–É«ø¤¼WÓp<ßq,úhQPïzl ÕÎo¼Ñ7Ñ›%ø>¦rÁIÚœGlüø®«q” >Çù4Ѳá¾nžC£×.B‰…9-ŽšP±árûØ5|‚|,¯, ÔMŸæNÓ,Åâ‹ñö¢·ñ~»÷Ír¨öö·¯ºûå>çžï’çD4J/í»·ãøò@x}]¤ÍBEôÎJ_Ÿ+œÍ½­ÛòGP£ñ[0óG}Y¿¬£d]M5o“ÐÔýë²]îUǦ×wVÉuvÝ¿áG¯?3ØíFRFd›2Uù‘©–¹ë+4ï^¯$4UèuØíGºÛT© Õ} šíÛ†¿E…ºõ~£"]½ºAëÝÆÂPûX´h.¾øb£ðW×Ì Œ<0êÁr*”/èù_*ù<¾¢ `;èýJ±™â?¯$Ep¦*Zë=̶¥gGâfnß.(\@”+y–, “´hA_yÞx —Ô£'ZÒ@;Èt–\§Ý‰§eYó$Á”.j³É]EFÉÁù«$íš³“¹|ärŒ9œP)uX׸¶ÕöU»©ë¬ºæÓ/ë¨0øi™€IÝÒZþÑ g&ˆždÙˆ¼Ùxòf¤œA§Ve=X±œ[NcsІó¾Ë.’dw‡„ûeÝn)ß!ûÙ.‡Ý-Ë{„¥~¢¬?*§æx¹õ?C|õ9Tê3ªëHÓ4Vjƒ§½^Îs²XòîK„õ…^Û'&&¢råʸôÒKl ÷ÝwŸñÅK–ô ×3Ð *äTÂÏ%ôzòÅA•ø@k‹„ã»piáNhTð”«Ö?‰/· Áy›bhýN-Ÿ›Ú´=¤Aäš¿ü˜ÖD¬X‰4Ù7ž}øàCÌ‘ŠWãÆû¼ÅÆ"¢OÉ{û®ExkÔÅòÕÆõíG˳UÕÙ30wÑ8œ¸­¯x Œn»—àÑÿmÂ×ãoA«Z¡BñK±uï" ýúb\Rãœ8u 77üÎøãõ¨_©+ÖlŸŠÙËßÂë=N7´?/ŽÖõ3Ûª›Ú¯fõ@©BõP­t+ôû¨®E£rÉ+Œ»Û›®øq9 ⃙·`íÆÉ¨^©=-û-w±‡o5癜²÷Þ:Ï/ôÓ­îÜEÃЬq_ ^'öžÚö£zTm Èó.ÎÎ7—cSFãçãSðJ¾‘¸a ,?±¿݃ÞŒwI¼-íE7µ¹sżÅÃqk—qfÆ‹ÃK¡Õ/"áÐ&”(ZÖînöùÕ¸[ðûŽ @“&Ò Òå…%÷”1ƒêÜÙô¤? ä~3ë8ƒæ®U«úÝÔ®þé $ØŠýh.—†V}ÁÉã)øù­¿l=ìø}"l^„‚á´(:)wàX➀g‚ÏáY‰îìºg»NeK•6_¼9rä0Âíš9k°vÞZt|°#Ö ŒÚiCMžJĈ)%1pPµ “´ƒ)ÄškB*ÁôDûºÕMnÝ|[ÐêÞ?̨Dß¾«Œ"á•ШáT”wÆf¹Ù8gÐF ·Q¿x}d“Þ¯;|£#¡Ú;CPCºw¼JØM>$]OàDóhÚ¬i–ÌÑlœ¯‘¼éôY^TåâLÁ»ÂûÎðÁþø2Œ ÷2a×û³iÃk½› ¯u¤-ŒØeö²’°Sw¹wCûÁ‹DVÊ•Dçof6³âà’⢊Ÿ6Y~®Á`b¼î¹ç#PmÙ²#FŒ0£O<áí‰.3¬.r1”šâÕ_nþ¼42_«æ‡y¡=ÊÃi:ŸÙOi€ oxÉ( i| ¢²ÇâŠ^ãP§Ã3¨quoéÌ“oûÜb4$£³>·g F©$ù ÔƵ쟆® 2&Œ}ìÿï¬v'nxûto·;UûØù äC¹®u0}Úª°£}sdྋîs–¼±/e É ç†}lu“ÛF„%ü…IÀQަÜpã<üüÝøjåWxjúSØ•´ÕÌÉés¥;F„úÇ–£·Š¢"oX¯¨á¯ˆÇ§<Žn=ºaàðA]ˆl_‘¨ã~ŽÃ§/tÒ}™ÅeŒ9Z0d¥¯ÏgXßâ€<á^¾8Ï”™}øƒ‘Û…K¯íÉÌൠéµïPeî¼ w^¡}a§6y[»Ë‚•î27ß` Jnf|²Ïü5öþûï7“ÂiZX®\9<ðÀÆœ“陀޾éCŦϡwhh?…¢¿!%å÷¶`Â=ÒX©Jy'jžå\¯²¼Êí^–E¦“IϤ’1eL…ðõàfYR¥9!›<µ¬J‚Ÿ²½¦FÂwRÞ¡©GÊy˜eI]4×ÂTèׇ$oë'ºkãLJ)»3#¤s^¢¹L¡ü3ÿÑtÊÝ'¡žÁPÏ&ß˹Î}¢Sõd0L:ñññضm›1¥åüŠzTsƒe É<ŒeÆcKZà«-/ᇠÛÜʲòf\T 5:”êéÔòFÄÅûÙ'Ÿ@ZŸ>H£ðÚü NÁ"ðÀ´áÃ1}Î@,^ú¡Y^½nœY&9á› éó'—®ü ñ¹K |™fN‰È&ˆcò¢˜·Ú·ýŠÍãÌ2y”+ ‰[üeÛör<øqÑ Œ˜ÐüÐ9è¶ŸN»-ë?‰˜¨X¼1örs¬)‹ãû w\qã±)Øy/ZÕ*µ `ŲWšºGÄêË0þ¨o4jʱqvd !'t?|0ýšé=ªh¶hœÝwÍ#“C·Ѭñ“ˆ–s~ÿóË1oÑpÌœ;£¿ë‚¢…Eàwî3?´¯8ZÌŒÆ+œ¾z1øµG*8‚1ùù&Xöý@ü1í-L{ùjlûí{3Ù;gÞàó²³òœe‡ýN‰Vd§š?Ÿ‘™;Ú}U÷¡íçmñÚü×pß“÷ùÌ}h¯`¾J¶jwª ¶/ÀÅ%‚›÷¸ññÒqë·.ÂqQËQ8?P^dô»ËCj‰ò ¬¼© n«sê«‹ j5 ˜NDÉu]$Ûµ‘î½P¹@e3ÚÑæó6xcÁxà©p Ï €Tv·ÅÅÐêÅV¦Ýö%‰¢¢}Mû ¨d0‚·š£1ýæýoðtë§qï„{åcl'ç'x5^TxåÝ©‚ËÁhƒÝd“ÝeÓ«ìLh ¶€ ù`to«çcŸ3iCËìúJ{Ÿ6Õ†ÛM{[ÒÞ·.»×‘6¼ú@nó V'³m¹>\ð-ŒçC† ‘ïØ‹ÆAÂÍ7ߌÎ;Á‹vêt®p&ß mËP´a÷öéÕßfn¶ì€ OÍÏ"HÅâ¨ËÂäàHrF& ¹ŽuŽ ùCá áI ã²Òï˜É4¸ˆ«!ó¤X UtØD©Ã%:tb¤{Rêù¥|‹)6eŸ¶äï×䘆rdŠ“Êù ý­D‰R‡WœWªÊ×QaŠœF²s-Ž¸È²d‡<ê::ˆ¢J†ÝOvÿØýª\ûÑλ.ä2Ì£H–£rÓ©Êm·Ý†×^{Í(Æ 3æt$³~ýz¹‡Ø˜@v/L4Á&´ÎŸ‰B9J"2" _‹‚1|Íý¢ð¥àö ƒðÜß“çLñÑÇ@χ€O?…„Ëø ˆç:¯¼Œi?÷ÃÂßFHÇF`ÕÚïÌò´_úãØ±C¨TÎgÖ¼ïÀ3÷‚._mLÿýeLZÐsVø¶_ºñ;³W8›{[·ekê\Q7´Ë˜Úä'ÀN•„¦ wy°ºšç‹Á¦t¿§0Jr]׆׾3;®ÂÞ§›„;%ì}gFÂN•lO¥[xÑõövöñ‰PçèU׺ÛS©°ó6DŽ¥¯„°&¯ÒÝF¡{ü€¿Ñ4Ô>²:É»téÒhÚ´©|ÛäãfáÕW_Å#¨xl/^5S}.•,WšvuèÑÍžpž:uwЉd ¡×ö5kÖĪU«Œóû;ÄåfÍš™¼ªU«šç‡ÏÃM7šÅ<öØc:t¨1§ŠöÏz=o]´•â³öRp’÷™‚“¼Ï¹}?Úÿå8r–ro ?LP||›“9<ù¼“9è$ï¬âÀæ%˜Ø?PÒ7Ô¿üõ,ÐDhoݽ(ñ«(öÿêŽ6GT´©Ü&x$jBZ—æ>ö±wÙ–rA|÷Çw¸¦ò5™*D° º„}ÉûèôU'T¯Y?è„BÝä*¨ŽW™–kžÔýØûµÃ<¡©öoo/Š •!Õü™ÐîãÌ 2®ÒbØæYÈAASR¯Q 5¡IIV¡mŠ6ì~²û4 ße#ãa–)§kc~9 ‘Â š‰°“pX>¨E(îKë2%Y– BöAa¢ÔMáû¨H´©²ý þâ/û²ãÙ¥S¬“ü&MÒ>ÇH©@ªý•MµÏ2”õÉÂ$áa¢Ãòí!2•}Û<,Ç4”s0”ó¡‡(¦ò$oŠ \œÆxü¸×˜$ט(JÅAá9,•†}r˜}š ÷ È¡ÔS• °S)!õc%d8~ýØ7L½ògBö{¸ LMÀf¨g„"Eè‚2… ‹¬  '5­£¦R6XƘçR¹øü?þð]ûŸ‡&3£QßüÝÍèseü6õ· öÿvÐ=EfæT\¯Ç>rüˆ L 5à„hNŒ®|Iet{»}º(Ã<…]ÿƒqàšv×L¨þeË/H¹6Å\×ä›'ãÍ!ŸâÓO+7³üQ‹`ÊeŽJÐU­ ^'' W}¤YXÒÚˆÒi â¥7_ÂÉ+å‹ÂðŒ÷ò¹“Ê2Ë_ž¹‚@“±·®~Ë\Ÿ@‡ƒé§¯ÏWhó2 •÷¢¼„p¯¼]æUî^çÎÛeöGÞNmºë‘ö¾xÞ¡È:ZÏ}lwJPÑ픺_/ÚÇ%¸LØ}ÀÇŽ.€Z¦ëφá‚uÝç¡çp6`¬ zв•zÆalÚ–+¨pp.'ÄV¨PÁ)Íì¶ F¾/´/Ù¿*¨’=4÷‚lDƒñø#>Í›Ž‰àœ$Bôaª¨Töìap¯;÷<Ë÷ È¥Š,‰DÊ“E?&Û§Šnt‹.À_ö’!yÿœ‡cr`C9¸1m’0J…6WJcƒ%dj(eGHÉSÂ?,<$;&dÛI’§ÔOjžÃ”øý”c“ r rN†rŽLåzÈ4áiQ NrÄB®ï¨´ ©Ãƒrûå4ö ÷Èiìî”C+wÉ!銖ÊF‚£T2xÉT0ØiT0ØÚGì7í¾ FwÛåá‚cœkó)a0èÄmƹ°¡®˜ùý¤‚Áô×_ÓcR).\èdy.¡&W4…ê8+?ZNˆ)»2þÄþÇá…xýûpßÂúh5=ÚÔóBÚÌ™H‹ÌæMº§Í'OÇä}0øâèÿR,Þþ¨!Öo œ*ÌÔŸûã­ñ­ÐçýüxðÍlXðGèaS§N`ÐçÕMÝ=‰ ÂÛžs/~^ ½FäÀÓ£JâëYâÇ™Obä­0àÕüè;8–,Ë¸í¶ ñýäû0|d}<õB´©§ç}ÓV¨±+?Jí̆¯S¼»îÄjS¯Ê®Ü¨¹«z¼ §ã‡á´W¦X²` 0Q`Íl­Z€+øcfX6n>î– ãúʶ™à?c"•Nž>‰[¿»]kvÅ5U®qJ3úpÍ}flša‚Ü=vIÆ_è3Ćà×=#ï(Žš¸Ïú|9ïJÿQÞw!Jæ+‰þÍú#ÎüÜÄ€ÊÇÀañÒ_p$5s󌃡H–¥û¸îø¢sæB{¸mA…ˆ“Àý˜ ¹*sÁb\¸±íð6tû¾Æ^?¹³çvJÿzœÍ½­Û²õùá ”ÜT—$B¥Z—©w×%x *åû ”R|ÔeG.ðSaïÓMÂÎÌëöº/î[÷Ïc¹ËM Ý'©×¨¤`©åZ‡pçu½½­Rëj}ÏAÏÍ>GûœµIx¥îõî2…{™y ü4…cúñµäé‰É šŽÐ‰×>†ŽC‡a‰“V;vìè†|ðA£,tëÖ͘lÞ¼Ù˜FtÝɹT$î¾ûncgÎùóçÏ7î<³âªVÏŸN»ƒY0Øm¦}àEí#mKZEÊMB+$Z$ÑD>GN §|‹c…LsÆ:VK²žæT¬Ï”–Nœ§–]–ssÉúÜ"ÍÆË>ò0/ŒÆJ]Ö‰æqd›Hc"%¤Ù“gf‡ÑRɘJ ùK¶YvÆzÆDJ¶1)ÿ™‹””4Àx…’TçuÐÎÈ\°¤þÏ>óRhÌŸ¤EÔTÊo6Eš$õmc\ÑJ±™ò!Šõ3rACDQ¤8Òcæ ˆBÁzf*‰ìÖœ‚МžJ…_—rRܨ§)^Žn#Wë§\}¥Uüy]O0ï9UP´ç9ùNòn·,ü:uzmÿûï¿›²o¼Ÿ~ú©S ³L›tÑÌ€Åô*E¯jŒŒïŽƒÁg‹ÏɹĄ Œc…œy‹#O±*ØýÇL\rç(T¸4ÝÄqÏÚÙØµr*VLŒ|¥jãıDÙ½·Œ’NıáìX;ß¿q.hÖ…K_ä”úPºÚUÈÇɘéñ?'ãàô]oÇ9AjçÌ–NùÓf â’KLQš¼CÒ*–GÙ´2('3åo$FáÖˆàf™¯¤½‚gÐÉò÷žÄ`<|¹Ë @|9¬ß1ÓC±açl¬Ø<Ó~{ u*vA•’ͱ+a%~Yþ–Üw'‘'_YäÍW[6ÍDÛN£P«^à±™ú æÍŒÂÅj㸴×Áëpï£ðöÐòÈ_ùò–æ-3M, ¡AlÞ6ùò”ÅÖEÎùŒGªã©GÌ\ ºÀݵu!"¬Q¬4¶=¶²½*Uòy뢂:=½½·Z¢ì\>Ó_»ÆÌ¥(Pî"ãýéÈžõòHCýë†8µ€ªüá7è±ê•w«È«'òç)‡櫓 ;v/Á›¢dÙÏ„>‡ÿiœ–è=ãïA»*í²¤\4—*·¤œ ÍË›`ºOƈ8 î7ØW&X°c”ðŽe‘!6ÁT–½&‹{ÖgoÊòÖK¶âôüÓÖzX€rAP‰à(ÄÔ©+P¹WóLG%v%íB±¸Ìݬl‹`®eÕ´Œ8A»Þ`o~¹ãÅ+L”ÊS Ï4}w¿Ëôãù ù†zÒ ¯rw}{Ù.WØ·˜MÞB^t¯ÓåPÛ¡ÖS(ÈŒv=ÝŽû´Oh™u;÷þ”"¶e(s×Ó}Ø´÷í>¦BÛw¦›üd{•“Ü.³2íW›Y<…:Y /¿ü²ñHˆ£ˆŒc¡ž©x,w;¥ pÅ@{¤¼wïÞf",Ši ¯ë'½ÚFûEû‹}Ê~'ù ¹ßÿë¶1“’зŽ`Ú˜G.Á7B±[ÞñµØ!ÜÎ ¡ŽhpƒÁÿ9`“(Í’,‚7G0N$ËûMöÅÉÑœ(í½ å Ç”rp•¶S¤GhödLŸdCÙA²ìHIé^™èðÔ£’äB¸_)û2¶Ki³d(k(Ç&Èyó1”stF1Ò$=-9…=B½` ½’šQ 9$êÑÝ9ç\pƒ¾9'ŠGÕ9‚Á~0&RBÑÑüíCL]05xýÀÚÅkopÞ'gƒš_µ¸µ>ýäSÏxn°-8Òreê•(2¾HÓ²‚ bÂÚ Øqx‡ï«ïù¸¨)U¸hR¦ š–iŠç9‹™Mÿ`k*–{­³Ë‚mK¨¨Â—MšU SÚëí2{Wph öîu¤û8„'tÙM{{¥­<Ø©]NÚÛyí3ÚÚ_r‹û…`wÞ]Ç]¦ùP ö1Ü †M›6‰˜î-Ô¼ŽV0о½¬`Ì3f˜Ñ×cÇŽ™_zÏ&Z1¯Õë܃µ‡ö‹ö¯­`øSÙ@M¤(Eª‚q\ä‘åù+=• ο0s/S)C'ÏršGqÆa©{DïºÉö©²¾v‚!û¥›WŸy”¤œáw+WOPœƒA© ¾qyRò!åIÂ#ÂDáaÙæCι MÒAɛԡÉË1 å¸ä!9‡ƒB¦‡ä¼ åI¹¦4áiáI!'xòéEë°(Ôm¨ËPÙ+)M¢L”n9Ô^IÍ< !§}г”Nè¶M¤´lÅ@©J…{½½Ì|0rßáBNÏï@ɲP þÌ3Ï`Á‚èÕ«–.]jlácÓÖŸ±RηM‹×d)MÞ¥öWÎüFþ'À_Ü rñÄ´'P©@%ÜQ÷§4k˜»m.brÇ`ÒG“ܩҨc¥Ž˜ôü$|4Û"©hþ¸ü\ˆ»wšyOO›7ËãìÔ )Û‡+Ë_‰…k _Ž|8Éaì`õ¥WuÀ뺼~/ 9 m¸×ÙûÔýºËBÑÞæÝ mG~ š·ËÜëÂe¸ðœÂžþ)ðºv›n°´/m%ÃV6˜7±0Øè"ôª÷#ämæaˆ0}P”*„:ÑÛ(’缩\P!I–m8b” !'y›ù"`Éý“¼IJÝr&ð†R6¤Ý ¦š× ÞLý“¼¥¾™è-)'y+Í„n¦NžCä!9Öaa¢—¼I9C9?'õOò–k3“¼…©rTÀÌ Šœ§~P1Ó<ä0:¹Û(r(Rm&yË!²ƒa?øIò`ÈaIU”v™ÖQë[›,rzY~F¢DäÈrzƒ¢MÝ`ÐIŽìѵíŒia0k‚¿ŒÔœULÿìv¼ß;Þí•ß¿~ön]ì¬ ¬\q¾9©±Îq/tL­~ÿÝ—f Óâ|ŒWA8눎Êéä|ˆŽô-ïޱĤ猓‘’²%‹e ¶X²˜´ƒlñ÷Àöòã¢ðÚ‹foÑ9㑜° cûTÁWÁèÿåÁüîÃ)þ‚’ N‹6þ§pQí»P$ qÜø®ýOÀýkÁ_¼ã³ÇãÁüpÀÉÓýfôÃÞCL4cÚßh¿o¤A¥¶8ÍžZl@ƒ×àç-?³¬2ñe¼¿Š„¼ts%çBƒ’ Т| t¨ÖùsäY_G¼®[Aó©ƒr“»ÊüÊË\‹°•’]Õw!¹R²O)99 åŸ(as†á¶ïà™fÏàÕ¯5¥*?µ ;͌ႂ’È{Èòó^×î¦ÂÝ?vŸ«@ê§l¨÷8ÁÙ“†¡’Áy²´Pâ/õœk@eãCæi"Är*"Œ‡A¥„±0REàæw\>~/°¤_Zå ³Ì””¢Σäm‚çIÈp¦<);/4§r‚8R˜ ²½Ÿ®eJøô›LÊqý”ó åÜLsxÚQšè+U®úõœ$9ê7‰r¨ ú‹äM< 9œ ½!¤.¥æQª`˜¾‘TûEƒ¬Òîk›áBNÉo¥dÙ‘QÙQ¡Ng4éü:®¾{.¾f ì\ޱ¯6Áþí™(»wE=L¯5ð 3!>\PVxàùkám† EòU5éÆ]³MªØ°ë“&%†8S0€‘;WÆvÈM³ô„yGÈÃBÐÛ˜GPÆpÛëÈžuò.;‰™ÃڣĭÑìoM¼µ3F`Îû™›ã-øm%nÅ•— pJÂCVž³ó<ð€“óAò’R“ðd“'’¬cèÜ¡è^·;òåÌç”Âoöäu¿çâgÅ£ïe}ÁÀ{ êH¥`¿êËýÍ‘f9Œúîë¶Q>_yl:¸ÉYJGHs­À´Óðûîßq å€_ È ”ðšyw—4: ‘3#Q<·Ï5ŸšRyyéšÿÃ|Œê<ʘpÝ1îŽf\nd—Þ‡í>ÄÜâsq(“ 8ÿt¨ÐE¸ónèz»Ž;ïUFxåC•cfȬŽ{Z?T¹¦îu™Á÷tøÀ¼×²–Ù©æ ÷zBëx1\°.%7ƒí#99Ù̵`4îüùóƒÑ¹9I5pò*íÒéM*W®\Æ,„æQô8õgÂ}-vÿÙ¦Ÿ²Yï4§u™Q ¡ÊðÆB‰Š†Rm’¿Þ«C'Z,±ÞqRnæÍˆ×ÜŸ=:]r•ƒ2¥²Á<%n¹[è´ç¦ì©?r·0 Øžlk(y3“š”e›þ9LúçƒÈù:y¹.7bíIJžt®Qu£ÛÈ¡ü:ŒìÞè1Nžº • žšÆºÐ Ýì4íö‰­(ØŠƒ– ¹ÿp!§ìÓý,²ì¿Ž¢åáªî_¡jÃn([«-ê]Ù™/ùã2™WÅÈ#È œ ƒF+ÏFÉß ù‚œ’ðQªP]”)ÒS—¼€ù«Gá@âf¬Üò¾˜y"³EË㕵s º_*jnD‰üc Á3k/­'Ž%ádj *\z.ºé5”®ßß< •›ÝƒÍ ¾@âž@Oœ6RDΛús?\qI?ÄÆ†ž[㟵ÿ>Xò6܈盟¹Í>]£Ò#T¨yÆL)Ø›LZÞžÌîiEVë{ ÛÁÌÎûxÌqŒY5Ly×~q-Ún‡of}\))ì(-¨d¸£ts™å`œ‹ëª_‡_vÀž¤=ÎV™£XîbÜ|°ñ|Å@…çì!|/òƒª©~(Ió1ÚàwÚNîe¡>º^ÇÐe÷:]¶ËÝenÚ×ñW‘°Ó`$4=`(½Àci{0ÕþV¡Jïƒ` ”D {ƒ& 0æê9Ê=™;úôécuêÔ o¼ñ†™üJµuëÖÅž=á?ß6ìv Fv_*Ù®J¹nèìÄ(ò*¡ç$#Ï uà€ÊƒZ.©%SRëR9á( îÇvÌ”‘r@¦*m¥C yš¡QH¤0 â,3õbÀȉæå<üf[Ì ¥LG_”¼.^¯SsÐÅXx ©¿˜Gö©­PxÝ ^ä}.¼§PÂ}÷sÄvåô•p‚+£uÓSG2(pÑm&• zÐù«`·±RPîte$’¦;F†—ÔÈðÒHîA£L8y#l“R—J…¡l\±°è?¨•ú)ÜäIÙ©æ e¥º«Í å¼3P®ËPò: C%L©úÑqd:‹³[Mͩɮôòx¹ »?ìwœF«Üf¸àùy1\0ÆóÏ?oFîÜò×]vÙeظq£y6}ôQLœ8ѸªÕ ”%rnR.rå+)ÏJ*N2èK0Ð%ʦßM-M¡¼Ì Âl/º&6)ƒ! ´ŸsÄû&¢OÉh*OìOX‡E¿¿‡Fõ@bâv<´Ù ÐIéデ·àèQïm >«ÿ 0ðÓ¸5ã0aÝ3 ž‡Î-¸öÚF¨Režzj•p-ܵäÛ†ž·v éUÉoÆäUe‡¬Ú¿ÝÌYàðµ-×bmëµX_o½h´§0{ìl¬ž»]ztÁmÏßf”*—T ðædÌ7q×ÄaÁï Œ²¢õæÎë0#Œ‰Ô¡@)Î+9šïhXæW6¢"D´±>×,˜¬z†RpRûW]¾Â“Óž4ýØ×·×½GRàë•ôö~€¯‚†¢Û-£­hx}8µKìÔ+O¸ó6ƒA§Ç¶Ix•+î2÷2a—y13$B­÷jÂNƒ•Û)aç½Àó๫RÁ¾ekŸÛ÷ƽÈzáBË ôBLLŒ?qVæG—^ÊpehÒ¤‰1µâóúw¾O2—iÓi * ‰Se{ÍÛƒ ªŒ ¦Ì(²!!SÓ$MaÓ¢”PËœT·QWŠDŸ9]çâA¿%–æy}Îu’FÏ‘¶2 Ûƒ©.{Ðý`hÛ}áPᵬм]v¦K PÀI–… * 76øÜÏ À›>}:î¿ÿ~ã²™#{ô:5ÊrSúW¡Ú•Yÿ•ÚÄýÑÙCüò_·.°v-ÒŽ1‹÷;Ç]¸À—f!ÐàvlÃAù«‰¨€ò†Mq™YÇ‘Ø}pµYöBÓ Ò¯¹PÙºØ%ÆóÔ®„UHJÚ²Z8kÏ-š_ú4bc aû®ŒÁ·ïZØuÛËáµWr¾‰ä)}‚ösÊ!ŸÒ’#·÷Ò‰GvÈ={~zCß.ïçö q a-†¾UÓ矗ž”í¿Ë¦öLqûý·ãã¥cäµ#™Ÿïð0hPÜ|óT¯.¼­8YmÊàþzÀM7m0Aë‚ÁoÆ4^äEkÀt7%)W§„œHMåfìౘœ}²_ ñò椬w¦îÄê+WÔ»òê+=• –õ}¢/>ûá3¿ârk[Ñet xj@–ͯ2Ì ùÉI‰ JI¸([ß^ÿ­qqûâœ3¼¤Ýxì1_Ÿ¼Üòe|´ô£,~ü  ¾’½˜KÈõ$;U˜ôR2úí>[îeÂþˆ{ÑKÐÏ*¹¥W™ ãš·×)uÝ^ ö5öµÛä#açuÙ.·©ð*Ós$yªX°ŸÙßÚ÷¼ô~pß#$ë„ Ijùb3+ÂÓÙ€žsŽÈ“î«ÿj¸ï›nxÕѾRjSí\¾¦t0Áüšïâ~ó!ihÒx¢uòÊž”ïé-!uÙ)Óº~EFCÊñ5õ ·h›/¹i[R‘ZnF&„f´B®ÕoæäPa·™·ÛΦÂÎÛp×SX‡ôë,«¦¿Þ¼g®ÿk¬Åšýk ÿØÿVï[UûV™ /~ò!Z4hò“ˣ̤2&½æô5(P°€¨•ÎNÝ{…s8qzKõ->©AßKì1—7'ÿëܲગÒ*%ƒ×'UH>:þ’ %ù’Oâ>ÁÂÏ⪊W„Ìü*Ü«4 sBBýÆ‘§¨lQ¸sÜòñõ°Gt &ÑòàP¡ì9¹§™þO…FF&Ev1IÖ¥àÉ_³)ŒÚ É«’Ý`§n²Ü®¬žôx6yö¹¸×Ùyw]ͻ˵,˜Ž’aÓ ¯2«BµW°r›6¸lŸ——r¡Êû^?b<Æ™e’ó/êFÔE»ˆv¼Rþˆò—pd+f-{óVû¶_±y&/hx4ÕwÍßüÒ_̼¿¬x3—¾ŽWÇ4Æê­“Q¹FG,_< Kû¶]·zæLhȨÝÄáƒ[üe»wøÚkÎŒAøê£¶øìÛÎX¼Ô·íêuã0}Î@ÃcÇ}Û6kü$¢£bñþç—cÞ¢á˜9w0F×E _XÁM{u…CÚ+Mdo¶šûÚ /d.[å/SÇxÚ4ÿsüüÖ øcÚ[˜5ü:3Á»FëÞÈ™×üÑ Nê®^ùZT«ÔÎO.Çæ,`æ¦p9”ÛÚѪ³ò¬ù1{öì ÃÞ¿üò š6mо}ûšÉ€nhèýPáùÏ5ï\Œ¾Óûâ›ë¾AÜLÖᜠšEü¥¦÷r˜å+®/½… òI¿ûbh0ð¡Ð4TÙ[¼…„ö fÙ q{â3' ¤Ž×VΥꌪX9k%j]ZËŒp«Gå€fT šNqtÃŒž¸!  š^e|YR™¡rÄ9vŒpæ„„‹‰k'âÍ_ß4s@ çÒ :ÁñÛ®ßð̬g0æº1FAù3p6÷¶nËW¢·?2ß*?nò7"€*êGP?¤¼-”öG]?òöÇ^ëÙÐýzLmêzBSÝîSiǦ ÝŸ’Çл}LMmè¾ô8zm6ÝÇÕTá.–z|=¥öƒRËYOÉýè9ñδ͢Ô$ŽË$×¹Ïß ZÃN†ºõ~cȯr¾¢Ðhò)a¨},Z´ËGfœ”šUðÇ)þRÛ¹sgŒ=Ú) zþ<3*]áÀÝV^mGh¿ØýÇgŠÏŸ1Í»û”¯ö(é˜é¤Xé¬8é¸|¢ˆ Ëg‡,(ßü²/›KÖçºÑòðq;žù<0•e²Gý©”1eµîeÞ|½åDÌ<99ÆÖ`?gC”Ðe$×ëIs;xx;%ì¼BçVP¹ 7(Ƴ`¬>ƺàoœ£ýtGK§Tù Âý‘r)†zo“¼×I}¸Þi“*tZn§6v^Áçdª0œç„~‰ÊûŠüàÌÅ>ÂPÛ¿ùæ›";å@qºB9DlÞbòîsÞ(o«ÒçpM¥^ÂP<Ÿû <âÛ^¯Ý<8’æ–MH=™‚-{ˆbñö^/ÅÙP¶H´¬ßÍê†Ã‡¼ý¿Þ›'oilÙ8ŸàÑ^ŽhmÊ\Çíý?ßq ¨Š=ûWaÒÔ‡±eûlDFfGÕŠmкùËüj ÌdF,žvÚë ÜÁµkÏel/â–OœŒB\>þyløe$Rî@\¡r¨Ò¼ªµ ÓP5 ‹Õ÷>»GÀƒw¦[‡ìؽoŽ ”ÎXÁw3ôý×_g´}×<ÔCy.±rïJ<ôãCøªóWA]ÉfNìæÜ ½?lðשAƒªcÚ´tá=\Ð$)”RPuzU?q›Zgt#«È½+7®hv¦šŠäÎÁ'Tåߘ}ïíkâ^=oé‰ÍW ì'Çv+$ÿD¬Ø»þ𠆵†ZE2zæpƒ“ûäïå«^vJÎ-ÎæÞÖm9ˆé¥†ñ•n1TG^5é$…tRÇ2ù®û• ݆ݬä‡X©y»Ì®KèË©’û´S›SÝž°÷Iº£´¡û²eS˘j]¦º{¿zsvj÷-ëóû)7VŒtN‘©@ÄK'æu” *ù$Í+eqÒ¡TB¨ŒDË6‘² Ï…û òÀ”Š• ®cªËÙœ:„ù&É ð ® #3Î èg–¥Ü(¬¯瀻q§î2Bó4‡¢‚A“+Žb$Ê~©d027 * ²|DH—´¬—*õ©˜è¾årü÷<© SU.H^ªn£Ç·—•ÁêŒiÂpž/E<3%œAóhæDƒ‘¼ ·‚¡?ÈÒòƒŠ¶ écÔïC‡!>žc“g½ž6Ï.F²Þ×<ýÕv¸¢Wð¹Žq®)Y[Á°qúÚvÈö}ðãžäMq†xó>'ïLl‡{Úx{gÖR wˆöúøëv¸µKðkîë º}FðR0l„êçp /x)ΫêÜàï´©uƒndœü >ïøù+Œ±7׬ 2?hµ”׬yfs 2ÌY°±hxACäd$I~½¼ /ëRËKaì c3 Ò—ww^Ô+VÏÜ›¼I'’‚¿}åŽ8O5j®‰/;‰Ç§=næfd†®µºš¹7Ÿ,ÍäÉûA‹9TºI¿$Çj¨€°ïhšÉpLŽÂ(?Î|ëÍÛAåˆP”oXåÜŸRaÐy\¥ ^ùPË6µ\ë*Œ¸©B‰¦6ííußöy+½`_3i·‡’í¬ IÝν/¥‚çÀsä5P¡ U$û–}œ_È7*û^ï¯û„ÌŠ—r>å -õª‹Ÿ ÿ,lÛ¶ -[¶D¾|ù0iÒ¤,+Y…Ý·š×>÷¢Þ#6õÞÓ”}Œ&H;\n θ ¬xT[áQ…{“=¤¼Ž•{E Ù'é>I÷ $а.)#‡<ìK9Q™r–™š:R—õÈ~÷ Íqä˜{ùFöh*J€÷z#”í¡› ÅA¡‰Æ-¤ùM¥¨HP‰¡‰”F㎖TÛÈV$lÚÏ(éîBS7ø,Ù$Üen† Öe—ÚÌl{*”ƒBÅ¡Êé¸å(…Ç÷£Zç¯ÂÅ·þuÝlD¼ñ÷—èrÙßsìv-ÿ¾kþ«ú™Ïñ9Ã_mS [oÅÝãïÆÇí?F¡\¾ß„_x!ü,'åËðʼWŒíþûC¿ÆgŸVÀÊ•òbá›EÀ”ËŸ}VA^$™Û¿y;Ü‚©5g!3%D'N‡¬7 ¸¬âehV¶:Vëˆ;ë݉±"ª{CÊ9œ©Ç'Yiï3ûöÛë¾ÅØ?Æš ‡:ìØŒ1fõ3’ñOI*Á¨Êëåò×[ ¢T0Œp#Ôš-áõat3³:ö~4¯Ð¿-ØÔóaêÜËá”+U±…/j{?á+ ½^½~›ªX¨rá^¶iïÇMBÛçË~¤‚A±B *“ìwö?É{A 7³¢`ðÜhýÍmZS Ï)ø«.• ~#~üñG)Â3þk`÷¹›^÷‡.ë=§÷’ É$eö•Ž0!ZH¡šK·­œ˜ÍùGD^¤r±ÏQ(v‰°S‚Ü) ÃnážC>î=(Û (|)­JH-ß/u÷Év{e{H9În9Þ.Q2v’rür;$ÝîPóL•¬Gî Âݲr¯\×~áA¡*œ¬Î9'ª`D9mân+¥¶¥>¯¤W( MƒÍÃgBpÜÛf¨Ÿ©Ö­[‡÷Þ{Ï(tC»yófC* ©©©Ø²e <ˆbNæ]êjÔËhVu®Ì£ÂEÜ9pS{&ð»©ý?÷ßsì¼yþ¾kþ«úÙ˜HQ0óÒ¢½C#ºŽM­Ñ…–<[ìNÚÇ܈Ú}€rùÒ6öÙgŸu–‚céî¥èýSo@ïö:·ƒó&8·€Þ¢8á;"⤲Qfä‚ÊE8s ‚;³9 \ÏÉØf7‡êøÆ¥T Ê•pª^¾‰ù°fÙš€óü³æ`Ø·½Ïxÿ¾<ïe3ÉþÍ6obÐsƒ‚ûàуèôU'Œî4Eâ΀s6÷¶nËÈ¢rf»’‚«|¿9”È Ù"K˜¡~Æ,'E¦€È¦ŸfþBÍm ý@ÛïÌ>è™!³´îÃÞ§Ò>¡© Ý¿ ¼ÍÛ$4uý_¯ãxÁ½_ûX„W^ë$­\ˆF!yå]·LÍS¸pïM\a®ûÛf|„ýËg eßÄä.€|•¢ÚMW¼’Sˇq휌ƒ´_>úH[zQ6ÆŒ 7% ˆˆJÛÖ÷ø=ñtêqì|§üð‰¹–œ•.@‰{"þâ@—´‹.r26(+÷ë'Z¦¨™òžÃ@DNØu*¤Ã¸¹¶`æQpÛO­myÎÛ^û½“q°øõnØ63x_µzrä/†“Ç’qòå±eïlÙ³GÂMÍG¢AÕÀ¾Ú,ëü1ÊÌ?ÙqÀ×W¯÷8i®SÙ·b&æô󾟛™/}æû¡ûІ%˜ùh  dŒpígi[h#\›Z½ÁC=Ôgz ºþ›ë1üêá¨Z°ªSŽ<†³`óáÍÆ½iÑ8üýwât¸õˆp—ó ã׌LjÅ#0êÚQþ‘+/pnÎcSÃw×—e¯bÁp6÷¶nûžä½BúÈwÚ0UxTH%‚Ê• úÆJpR*G„¬Cƒ ·#øÑÕ¶~Ô5Õ¼®#˜õ¡v¯óª«ešê1‚Ñ }73 E…Ï*ÜÛÚûÖ¼»La—)梽ž$(X‘üÙ† f*¥âh©£U|«êh·Ñ¾²Aww Ü–¼Wð}†¾"ôÚ=´Qyعs'FŒŽ;ú£z?øàƒÆ^¼[·nøøãͯ¶’ˆöíÛcܸqƵ9*Œ`|íµ×:K™CÏŸgŽ‚a§^T0¯ýÂTûŒ)Ÿ#;u÷'¡s(ŒÒ ¤ne” é°(R–b!4s*Xß!ûÒ(’R‰ RA#»“×e®£Âú’ø I·*ÉSè7‚½ÐÌ}w²’j¼=nCÜ¡û³S;Oh]nªŠ ÷§îjy ã¾–Ç•Ô(;B£\8Ûx׬©æu½Mº,µáU–ãqÉ{)ô“äµ=GêèGºüŒfS4#6l˜qëOÏR÷ÝwŸÈÉÅ[]Õ2íñùºûn>Íçz=¶‚‘´|>ŽïpÛM;-CîEöâåPcôrSt|çf,ïP1E˘ò#Kf¢l¿Q(Ø&ðÇ…ï>ƒÝ ½6N''âØ¶u¸p¾Ü·‚±ð…Î8¸fŠ7î‚ø²àØÁ]Ø4i8NMÂe/ÎG|étïDŒ.yó|®\)¤sèÍárAIR>–×./cãS]qpúéÚ ÙKUÂþ #‘²êWT~{r׾ĩDÁèÚ•þ…έ¡23r$@…g†ÜQ"ÛÈ `Üèlû³-ÝÌrÛé3áÚÖ­`$¬™ä=®¾’ÿ÷wîE®ÂåpÅ0__%ïÝŒ©÷”G¾ÜeP ¾Öï˜) Æ(Q0ûjÒÂgðÓâÁ&‚ù±ÔDì;¼¯ßw*¨‚Q¡mOä­Ø Eê\…˜x߸¹—‚ÁçÕªU3¿D…âEï3±©½úê«Ñ®]»6jÔcÇŽujø0eʳÎ=zàƒýùþ<ÿgT»´úÖï \ð—t·ÉÌÖ­[Í~5ÀӬͳpõgWc(>¯x€r‘’’bêò…aƒ£4·[nÄ4;›ëàK€u÷ïßo–)ès4¡s‹Î¸£Ýfò5—Yn_‡Öãúûo¸W7¾Ú_°¯ƒeꆶÄèˆ3>ƒÚs}ŠpúCA÷ǽ{ûBÚ+BõÇ·C¾ÅæCŒ’ÉIà„×uìø}ö¾¿ÿH+á^Å_˜ªW¯nÖ‘:‘ïlÀ'ÇívTIAJIÓ5Ò_´UàÔOßknš¼Y®ëì:^õÝàñ¼è¼–•v¹M{]ߦ-”hÞ.SÚûõB°r÷õ“v[e¥Ý‚-ë±õØŸT{Ù·T:t>ûÞëÞ°™ùÛ7üìc0¼üòËf*… Pß}÷YæsMŃ0^ó,áŠ`à0–}øá‡fÄÃæ¹xv2ƒö}0ê=bß+zïh¿|ÎHö‘›,×9BšHq4s0èv–fR‡Dûç ÎàŒrî…¤û%%Íü ‡‡ÈDáaà°¤6Í:­Ëíd?æ8r¼}¤Ÿ&MJoá5ïžoÁIÛš*uþ'ssF¢cÅ ßTh¨Tøç`8í¢fRl'M•Z‡©¶·öÒ†{™às¤©æZæf¸à5r™dY0д‰ ³~H.³<..Î,«ÛÚ'Ÿ|±±±Æ1•wFóîÒ¥‹ÈÌxÊçqµ¢@«ýLݳ 1ÅÊâô±äo•îÙ*ºPqÔþa7.ø~J><ŠáÎ÷¡îŒDTµ¹9 š¬*^û®|o jÝùR÷¡J—¾¸ôù_äÞ9‰ucB»¹ÅÛ· âµ×qLjèÛW„À_|Ü ¡·å(KÂO_¢D!(ùÀ 8yøª¼5]®» ¶¿èÒ?.8Ú4DŽA9æÎ;E9˜”)C×_N%o¤é¶ƒ‡ ‚ÛŠ"Šiζ}29® •†(uÙŒ-\Öxþ*yYz_åÌWƒnßgoÝ„ö½ûê§%/ IÍûðâ݉èÝe!ª” ÝWDjM2_•‹`8+/RÔÔ骖 |ÔÊCA5èP¿œ RN¤ Ë×]ðôeO£aɆNiæ8|ì0Ÿú¸ùðÑ>?O#ü?Îwp"{·±ÝpÿÅ¢hUb@oôŸÑ¥ò”2óRÎgsoë¶ßJÞË£4>ymšÍ£D†0¿ÀQåÙ+¤ç ¦Ñà(†ÈÆLŠAnGè‡Ú˜ìT©õ”6ì²`y…½¬ëmÚÇ"4uC_NL•„;ï†]æµ áÞή§)JaðJµ>S;ÏÔ&AÁŠ•E*|ñ•ÍIÝ:÷ÆžsC…ƒõÙo¤ôýÖQÎ/³=$ïå$e‡ðMá¹~OŸ+èùóÌØ&Á`ß[Ê`÷¸¦„öö“WÚ$Lêì$MRC9yÚIýyÖsêÔŤØÐܲlî Iy_05s$Uœ”Es\ž“Ipx\xŒ”L¹¬ëø.ሂü3à>H[Ó°Þ ºþǼCͤ’øþKßÞÞŸ};%˜·Sî2¯:ÁÀ÷ç,a8ÏIOÉ»Gú8Ê7L˜•g„Je&õ"¥Xµj~øa#CeÏžmÚ´1мþ8x® ×c`¸±ãÝþ8ypö}÷jÝ„ìE3Úê'¯Z„Õ·_ì9‚acËK÷cß7o5‘²ñÇèþ¨ÚÕgÖ<óáúˆÈ– M‡¦G¸v`CÚ…õåæÉ†ˆ…éÛºG0¶½þö~ñêLM@dlœ¹æw?‹] ÁŽ·žÄãEÉ*ì{3fÁ !J™ü$Ê¢T8DYĶmr¡éoU{#Û“m$ B¶MëßÏ>‹4nÛW¶Ýº- `ž{à Kß¹›¦¼ƒ–#6!¶Pz_5§fÁÖ½‹0ôë‹3Œ`L\Ðm¤›‘õóý˜½ü­&Rõþ…ë´DdLNd‹ä›*AG0δ©åH'#qä"3åâÏ®ÝôíMèݸwHåÂýK:'wø²n¬u#ÞjóÖŸª\¸ýWâï:ößyÍÙŽf3æO߬ú¯Î{U>tÖSn¡³þøqØ»m®Sò÷BÍ`¤a ! >âö/üÀÚY^µ÷•§—‡ZoSá®oSó^ËnÚðZmaľ~{’°ó„÷‚×µÿ_{ç_E±ýñs“›žB( ‚±ÂSEx (`iúT@Å^a„êÂF陆Uys:—.\&VîME,òH¥B¾âcìÆAÈIöÄÍå öÒ 9D©Š`YJ6Qº"YBD˜)BH‡"ã™X¼b{LÜ'#Ž‹VÌI8ÂTÄE®7ž„¢.ó¤{oÁ3{Ë.QBð—‹û€û‡û‚ûÃÿUº¨÷—ï7PË@Ç,͸í厸ÌryF0öH7.ZÂ,X »OÁA÷Âò6.|¥Þà‘”²ð+м¤ƒ©qQQ°qwuΉÃ\£ôžHå{“<—àÅ4sûïÒ°¹4.Œ q¾ÛšÈܾQ†¦`òC P p¹a‰lô²íF÷¶0.Œ ‰/ÛšP˜ŸG‰Ë¿¢Z-:x¾ ¾òû;ƒhÞ]Ñ4ç¶0úmTgaP¬7ÖXÃÏr©ÁÄ0k×®•ƒº7oÞLS¦L9)³fù`z•ðö4àûtï¥÷J/IÞ@ß_p0í ÝñíÒ“Ðü»æÓUç\%Ó+>¶?ð×±ý}Í!Î9Ð?¯0î›{åˆ7­F€#@æµx%¦â»­a…ÒLXáT…_Îf/aõEË/^U€ê8dôeõøêùèçx½š±ZÖ󛥫Ôã@[áíÚ×—9T×éq=Ï“•-ÊX-s³º¡ òøŠÐ=ºE± ýLÁ¬¬ù>³5Ÿš¦ŠZ.jù¨!+Õ(\è;P¶1¸ZŽOZ)¼,ÁÐÆ‹økò%=ÛŒ ÍA¨Šš¦Ä‘Ÿ!grrFoqZ‰´m’Æ‚Ý<ÖCÉ`fsõ~©÷Jõ>5Ôõjº|ø’ÄWð<ˆË;cŸ•Ô•?R~ê1ª¥tªLö/™JÙÇÐYÊà‰têT¢ˆnõ¾m^òA Šs{ðRá´¼d/M-ëaxÿò€Óp|+Ne[Žüþ#å¦óèU ]ªþ}éâ{ÆS»gfÓùwŽ¥Ô½›hÙ³WÑñïFží2áï>µ…®Bºgö=Ô÷‚¾^»Á0è#šRsRiþóé’:—k*öcö×±«Ò5÷jÑ‹^ìü"Ýúõ­´%i‹‘ZDóZÍé¡¶ÑðùÃÝͬ~b¬ø£™á!}0Ñ’00âÉPH€P0!Bñ „ QŒŒ`±O(±BÌ †ï€TÜÑ“q+=ó•—uYÍSVË*ê:¾ùުߵlPV2¡QŽ(Ó@g x8O–7ʾ¨.„Ⱥ¡×Ô!_1SœJRžàÎü©§ž¢úõëËÁ©íÚµ£… ¿>€¼ðX#=NµnÝZÎd\v ßU aÔrÓãf ÌÔç@«ÂÏ —±*H?y@CÄkQ Ò¥¬â‘O ¤ÀU±ÜŸ8w]:éíIu½ž—ÓTáíN®×ã‚ ù÷ QPïß3=¥,ð!­ã%Vkâvââö–ê9])ÈL§ãKfQt»®ä¬Q¶É‰ËJêÞÍ´jL Šˆ¥ËŸüF~ôסCD={ÅŠsþºäm!aT˜—c,‰ò<îþðX˜ãþÀ Ö[‚÷1š uŒ‰åz+´m]ÜÜ—m5àiëàšY/N‘¥/«ô¬SëÂQ¯ ÕkÓ‹’ÿZìUg³~Z‹Á<×¹˜´òn©¢ Õ+¿½Bÿô8ï6ž¹â9›³Mõ£eÝ–rî‹Ç~zŒ~Øñƒ‘ZZÁšÄ6¡÷Öbx«Ÿ0¡$šŠPæ "$P(’hÙ,”Ï¡† Å4Lü¹JÁî„ÀÇ¡zâû‰nh¨/|†_Î@ +B„žr2ÔE]¯ ЗÙ:o¢îßêXVb+šø§Q Ü—‡.+†8(D”a°(KL°LNaL ¬¹ÜQPâõ¤4/)¡ZŠpAûæ›oRÿþýiüøñÒÀÅX¼åË—9¬™4iuíÚUd…·œ×^{:vì('#+ õ§ª çºY9A€5Í,]‡Ÿõ™ÑÓ êsÅuB6ð²èyÔý±X¡¯Ó·ƒð>­ö]2Vé*ÞÖ©èe¢ 0Kg©/½ÜU1s¦a…Ùó±]LJ.=EÁkÔ9çœ#½b>­[·R·nݤ«fx™BŠ¿¸cÄ¿iÇc7zÈÖÁWPâ„‘BÉΤš]Ý]nN¬úI®Ó98ù÷UÈø{ƒÌËÊúI„¾vðsO¯‘™I{iõ‹7Ê —q‚–=Ý^޽¨}Ig -òâ™/Îy]š×H×—_’kð raJûwJ*Ñ ˆFŸ¼ã a^ªtà‘ m ú>Ö¬Y#[,`Àë @‹ÆE]Dñññ^ ̉Á¬÷ÝwŸ4PN>̾¡ µô@½×¾ÿzµ|9®‡@£®±ª~ñÎ5q^¼>þ<æ"¦üa€[±“¿²ãøŠÎ,øfª›Ï›¯Ÿñfè,sÈÂçÄ-uªÁ¤C…÷§î[[á­ |ÞöP[}yNîq}JV´”Mb¶=Æ¥®\¹ò¤»Y8 Z â^µjÕIµ0¬1á$\üc™´´4ùlaîé0/«’¼HÁiP»¨xó"eÅšWûÒá ?Ð Óá·²œ½Hùƒ×W¼.[%¼pYûäÏOÒ[«Þ¢©½§Rÿ–ý¥©ÏoP™TÇcWÕkƸ›Ooü”²ò³h輡”W€×®Ô“z~Dc—Ž¥=Ç÷©•G@L ÔªU\jÖ”(^D"SHPAaaa.Œ’Èà`ª!”Q(¢ÑBIׂ†S\œBà' s%@)ãY¡¡´¨­ÿ‰ªàõ`W…ÓêùYT¥Š—}u;ï_ §©yõ}˜‰Ù±ÌDÝâ î!+\Üj¡Îc2€ <¸l¢EYE;¨F`E ¥e‰2 §àÈHYÖÎèhQþ¢~ õ! –‰Äøî J)+¾ªXuÿøæ›oäxuò/´F 2D*T‰‰ÖŽ0o ø^xA.CÙ:Õo[zaQËI.7„Þ„Qã¬üª‚²ægG]†°ÂÍ!ª°Ñ Ç‘Ÿ·…ð¾ù8€CÀé,ê9@ÔxI¢nËqUÔý«iº0úrIð=7+ ]Ô²å²×냙 Ÿ¯”¶‹Ôc=F{öì¡·ÞzK:ùïÿKË–-£üü|z.I Æ Å2++‹-Z$[<žyæÙ]ã[1çXe’—’DikRlç¾^‹òÄUP@ë^»R¶¯¦ËŸúÖÒ¸0ÛÒí·­^-´ã¯- 3b»ô•³V'}ÿ‘\†q™½1Ù^ÄEíN¦ãQöGüȽ­Ýž0ÙfW „bhÛJãÛb²=±­j\x#çD%ý¹êµ½ÙÔ¸ðÕ¸( OçDÂtpílé¶Öøo8-˜°níOÝO/tr¿ ÌX”°ˆzNëIWŸs5M¾y2ÅG}Ÿƒõî/ªã±«ò5Ãxúʧéú&×Sï¯zf€g"‚#èã>¦{æÜ#ÕÊÄc¢n]S ¬SGŠ3>ž‚E¾P¡`† C#2*ŠjE4F(¤5…rŠ/ßµ…/®QŠØ/ºÀqæW€R Ê.æ]€‘…Ê+ú‹»<„_ê!xAs¨ÇUáüÞ—~~ªÂ¡ŠºNͯîOÝ¿ž¦n£Š¾oÜ?ü¡â^âž²qÁ†î=æ´@Y@P.µEAâ„aX3ÐI±¢ £EYF‰2ˆŠeM!¢¬ƒââÈY»69E¨ 1¯'¨C¾¢_—*füþûïÔ¼ysÙíCårÃÍâF/n1ö¢E‹4wî\9c1Æ_ĉkÂ$}e54°•Ù¹«åiV–\^fiº˜¡*ÖfŠ: l4À€ÀóÆ‚ú¡†äaaƒ÷i¦¨«Ë¼Þì|Tƒ…㪠]³4Þ—ºl&|,:féú½V—Õ²à8D-?.gþÏÐÿGÌÄWÔý³ Í L C\¥iÓ¦²OLöÛo¿¥ž={žœÁtéÒE>ce—TVR~ž!•nur=#_½K&Ž¥ä9ŸÊåËfËeHAzªLË9¸çdZæVwÓÁO_”Ëû~"—™¿&=F‡ÖΡøK»Qnj²\¯ŠW„GsæuëŸøäš2ÅC¼yaadÜB‰ï=CûßyŠ’f~DÛ†v¦ÜC{éì_5rYЦ Ñ-·°‰žzÊm,tîìî.õª÷m¼í³ÏKlë¶]Œm_)Ḡ‰ËÝeÕÀ‹÷¨%¾K Ö¥•[Ýeõ×îÙr’•ë.«c©{N¦í;â.«×½HÛ¾ö,«µÂ\9¶§H‘vÿô1múôZúL{r†FÒý½OjxZt‘šòçZ¶gMèéž=V'%+E¶Z ëóF…x›~ÉÆ¦ˆ‡6ʽ1Š:ü/»~¡Ïÿøœ>¿ésÓ:§SÖº xÛ¥âϧ•‰ÿóBñˆÂy¾€åäåQvNefeQZF¥BÒÓe<=3“²²³ežüðCº÷Þ{TO¢££¥Ò…™ø1H¼eË–RÁš6m=ýôÓòk®¯ðùŸ/⸷f¨õwÉ› çfq«P…ë×3VFU¥–ÓÔzø\P/¸q]‚ð2Ö©çÍÇããp+?Ó9ÏÛ¨×áýªûç¨Ëj~Õøàúm¶½Ššfgø^ñ}cáû­§3jœIò»_ž“›D\ŸY=ôÑCÞ×ÿ{¨Y 4 ‹/¾˜~øáÙÚ‡åW…Rúøã¹Ü`|ò”÷XŒ“ÏI©­CÚSîºdþË÷ÝŸ½ %ÜhÙçØ°@¯I¼d1+8âlhpó?+A€ÿÂzÀá©¢î¯$Ñá?4V:XÑ…óé!0[g–°rå¿Hs·(´±¡ÁТܯ‚P¼1`?84Dv‹ŠˆŠ¢ˆ5¤D Å<\,‡ £#$,LêGþ€À9‹Îï‰èÊ÷Þ÷Iqê*âhQÑ9&äG!ú>0™êùçŸ/[!Tà5_hÑ%}ÉÍÀ`pü_¿òÊ+ô„2Ä—,YB‡.Ö2bŸ3·20×Vt¹œTå¢Ö#³ÐJ‡€ë×-~†â™â8¯gØzŽª‘Áqýܱz,Ï/žs,XF:ò¨Ç|-,¼_õª5ä|>7o÷—Ñ—«tÀ猯!×¥¦³Xÿä]TÙŒ¥{–Òë+_§}gxLˆ‡ ö>^ÿ1}¿í{zíº×èÂøÒ8œ³±±ÂK¿½$Çú¼Ýím ¢¬¼,ê5½—ìBÕ´fS#gqJS·uxÛU|@ÿj†ï²ž`@›+?Ÿ Ñ*!^:ùii”âå=J9ÉÉ”›”$ü”ÊOM¥üÌL*J_!ºI‰íð2Ä ¯+´Z &œ×áK5$ÅHÃ:äaM}‰ªÊ™­à?=j\Ý‹ª´°â¢+0 öQ•VH ˆóz>®z|ÆlY>Væ *°Q­ªQ‡3(qr» cN¡TF„ËÝÁ5kRp\- †EHíÚr9]Œ"#)0,”„ât Áðä÷;¨ÝÃ}ú2ÛIÄÑ‚¥;‰Eùã ­¾ë®»Ž8@›7o6RÜüòË/rÝœ9s¨GFª'èWþÏ?ÿHcDý*»`ÁÙŠ1kÖ,ºá†ŒTïðù7ñ¢7C\ôzÃå„ÐJV·åíšåçp¨Ö+ª`,ê±øØœÎÇB¨ÖeÔmUÑVC~ž9¿z|>¦7f!‹z¾ú¹B‡ÀìúAIéúõš‰zVûÃÿfëòå9Aç½¥ÿ›è(XÒÿý¡C‡¨C‡²5¤êÖu»`õg F£oÖSè…îsÎÙ±™’ßMÙ[6P~ò!  §à&P­ÁOPd'´Ýx¢~‘?ðì@:1k²±Tœ¦¿&RPí¢™«ŸòôV+Ù}t}¿q4íHZNyÙy.]Ýü?tÝù9Ä9æeÐÇÇ^¥#{VÓá=k('ë8u¹kµh[4MÞݯþœvýñ%'n¤ìŒcT£Vc:·eoºè|ú;s=mI_CiÇiTãIÔ£¶ç›ÅºyÉŸÑ_é«igÖŸBÏ, Å—¥Ñóa¯Òþ«…¬ÿ]Ç©wÏIté%žÛîë6üù™ÌwèÈŸr|ÄØgQ ‰‹<ÏÒ/_ ¤mk¬ï×€±‰]òr2è÷…¯Òö”Õ”±e ¤§F£&Q\ÏâÓ2d%l¥}o>Bé.'‡3˜b:ô ³yƒâôN}nRwl „É£éø_Ë…~MauÏ¥³zü‡Ü\t¿µN¾Ö‘ìÍhwßÓ cMâzù·—iZïiÆÅ¶ämt×7P^aͽcn©Œ‹á¯ØOTÇcŸŽ×Œ/¬Ï^õ,]{îµÔç«>t,ë˜׃´ûçÞOi9PÇ*Gl,…ÒL…² qBÙ„*ÎШ( Ç—n|ñJg´xÅRÍ€ª)®¥DìWUrñ5]o½À+ J +ügÑ—ÍD̓¸¾ ¿øueÂÊÕ²º>†¯¢o¯îWûr\=Á=ĽÄ=eƒ÷šz³÷( («Qf(;”aTHˆ,ÓðˆH …ÁMA¢n8kÕu –¬µÍÅ‹#øî3ÔÖš\ Ä ¸Ôܾ}»t§©²ž\­ZÁq¬9˜PJ€>ç P[ÔñÒ‚2Â5è µ*j¹²¨e¨ —1 ÃÊ2^šªÁ8 ÙGùs«êÞb¨ h€pk…*¼ùŸ[T£ˆÏÔeõœôs±ä1¾Ux¿| ¾||>€CF]Ǩ÷Z/—ZV(G.sU`XyäñøF[¢‰/ßOœ8AÝ»w§ÔÔTiH³q0– À…­Ò0'Fy»©5#ïà^*ÌL§è›RgÇS­¡ÿ“éû‡ÝHÇ¿úXÆ­ˆ½í~ªÿÊOyi29„ÒôBãÂŒ¿¢±ó¯ ôœdêuÉÿè®6ã©åÙ=)%ÓÓ]jN­ûq ¥ÞFqgñŒgíÉËÍ EÓ Ãâ(]tåtUß·©Î9mÄvc鳃ãhOÖ6jîÞÖlÜŠãóivÒD tÒÙ!MÄÞ”’ŸD¿þ6†’n£zu¬·Ý¾s>­ÿc¢X'Þ½1MÉXãÉ…WÞO×Þ=ÅCºôŸLΠpªY÷Bi\€¬tq½ ÆPöžmÞ̸^“}æÞOÛîëH9‰»èì¡/QÝ~Óñåóhûðë¨0¿x ?ºî'Z÷Дw"™÷ÿ7l<ŵëI9ÉÖÞÿÀ©ÔüT)þ<ü'\4RNŠ>®D_\ú"=»èYú Ç4¼ÍðRO˜7pþ¢:ût¾æÞç÷¦Ñ׌¦¾_õ•FmƒèrùÞ9÷Ê´ŠÂIŽ˜˜b÷µ…Qq Ã"HHpx¸lN iS¡ Ö€ˆ?#éúTì“ ”\|]W»`àÆÊÿ…Y½Øõ¸*z³m8]VôtÅOs~ïWÆl¾º/]ÌÖ›m«¦±ÜCÜKÜSÜ[62X©D@P²lÄQ¢¬j8dùE:)\”%Ê4$,”‚Ѫ!ê…³F”,û€hµNÄ—HìÙ7ÔkÔÅ ø÷Ç—ØøÊŠ ô0?ÆYg¹?}á«-º… õŒÁDc@u!±EØÊ¾¬–Ô Õˆ`át5TE½N³rTEåËeÌåÌÏÇY „£@G=`CƒõB^ÇÆ+ù| ~FÍ0;/6 X°?]8]ͧnÏqoÂÇåsàûÄôe ÆzßÕrÐE-C.Wµ@ bq¨ Ò}¦/œ ªr‘o ¥-r;wî”c–àAMÏ ŒjLʧƒ90¼ëåIdÇîÔà£(nè(Šé;„jö{~¾˜BZ´¤cŸ¿aä2'¬e;Šîy§‡Õˆ\Ù™T£§µ‡#OFýv7µjpü÷ ºþ‚‡éêfCè–Ë^¢[/óôLVŸ½xˆî~>ÚßôFª'ÎêóÈ êóèrºìúgè‚+†Pç»&Rën#åúÿ6þ„lh¾-èSg(-º,•&]¸†.¯q­¨c.ªTŸž~ø=>,ºu¶Þ¶íeCé¥ÒÐAk¨IãkEE -NÝÆí¨ùåwzHZ(?/SÄ‹îWDt}8î]2+Î~Èú¸?G…9YtÞû‹(þÖáToà3ÔdÜW”µã:ø£§›ãüŒTÚòÊÝ ¸Z_A {?Lõ»¡¦÷¼DMïõî êTêþ ª Ûn§G~|„¦õ™FÑ¡xý­M\Kݧv§scÏ¥onù†F7”é¥åúë½ûë­Hªã±O÷k¾´Þ¥r•‡_A~Õ8 Í á0¨Ñ²÷õ×_S[‹9úôé#µUÝ 1ã7ž3áïg³©0 Ó–Žó¦‰8(º¦'´feÂ4JË>B}þå~Ÿ¢”ÕÇ;g`0…Gñ”(ùâI^§i«¾¢®9hwößbSómAÍ x ÀÓWDP@0ESÀà°yœÂÀ) Û×M“ç׬uÑý t*×ëåœSKÑWö¤`QVL6](´as:²ÄÓÍñ¡EÓ(÷øj2Ø}¿ ²2ÈUh~¿}Á×:‚ÿƒ2±téRÙ³NbšüиbÅ #GéØ}|·ì†2åæ)G¹Ò}(l‹ýñþ‡fp>Ÿ‹z>f禦«¡¯¢SÀaiÐËB…ÓXÔ2†¨††¾¬ Öù ž _p€‰ö0 4\̓”*̳Ï>KáááÔ©S'9Ó7 mžý{РAF®Ê¡0+“òS’iï .tì³7)ã·Þ®‹±Ö7\yy”¶à+ ûW ªïýCð–ƒ )4¨ËØGOÏ<î›IC§EÓäU˜üÃðˇÌÔC2ŒqšIo÷Owîyô¤6|EuÏí@Q5K÷á<÷H¢(¯$Š8Z= ¿àrJÛ 'ÌEÛ°œá5(çÈ>Z9ð<úõ†HZÒ+šþ~{¨tÙë \Gr÷þãsÁÿC™€• Åæ_£àËMã;v¤,׃iið¬ÁÒ-”ºŸþùI޵èÚ¤+}ÚëSipØØøŒÁ˜|Ód9cøüáôúõ¯ËI·&m5r”¡PB‘,&øºkâìÏ\JÁ׈Pê‚„ÈPìq]qòÀ! + :ürWCU³e†ãœÇL€Yº™Xám£ïƒãœ^V1ƒ•,Ü[¾×\µ\‚DF§Èrs:Üe‰2 €C#@”5Ê\X'ë‚#ØK]ñ+Ì›ò¯7h­@ë¼Ü`à*x« Û ||R‰ˆˆ 7ß|Sn‹.$ð¥{•* feÁùs¨ÆÕ<,ŒUº—«™èÊ6–Y¸¨¢ÖUx=o«îb†ºNÍ«žƒ¯¢ng¶/5ÍL=®¯×ÑËC‡Ó¸ŒtáòöU|ÅlßH³3qÃÀ†‘×´ª°)€ öà¢îŸÑê‡Ý˜xóÌTÆø •#¯«;õºä9ºªÙ`Z¼mM\^~ÆÕ†…¯Rd`4]ÓÝH)Nß:þéÎߨ egóèå+yÉî±;AqÅǹÕªGyiÇ<Æad%î WA>ýùÜMT«MwjÔÿ9ª×m0%Î@[þÏ·ûÍudW·f>×ü_”‰!C†Ðwß}'›ËamÃjGëúº¯$g&S¿™ý“èEGJCîigß1›º6…§öò_ÏüEu<ö™tÍxYŒºz”ì"uçwwÒ׿AÃæ£ãÙðÅTŽcÁT„‚é! Òdœ•Pq~@„ØM ¢+ fð TU¦¦ëyJÚ–Qóéy­Ò}o¯oÃËjzyÁ÷•ï1ßoˆyyˆ²“¡±,O£lQÆaq£RäRꀹ`/¾Q–Œª—£•_—K?3j¨ÇY¸ÜÕ¸(¥¢ò¶}?}™Ñ·ÑÅjßVéª0zšÙz}™±J×ÑˋÒD5ÌÄWðL”¦cñâÅÒÀ–ói‚tt%Äðôôt:zô¨l!,‹ÃƒS%vÀ#ÔàÓ…Tï¥Ï)âªîRuùøe›I7AÁT£Û­FŠ5Ùyé”›ŸIš  »Ú¼E7ÿk´ߦkšßG«¦ d§‘³ì¬ûqíßþ mð²02¬Ç¦µ‹öOwîã‡þÙÁÔäÒ’ï—Æ^GÚ¿=  •!çYéT“Iu¯@͇¾EMŒ¦ó†½Mgõ¸ÿ:2K¾ße©#ø_)7ÐU*..NzOð…Ù'èÎoï¤7¯“ÖX/çµ@7”7º¾!ò<ù‹êxì3ñšû^Зþ×ñ4ì‡a4ôò¡4dö*(ô|aT_NŸnÄ*÷ì•‹?ŽY~ ò¥ãk#ôgªÔ8ãmYÏÏq}†•c+Åq]tã—½¥sKiàüjh%@_jšÕ:Æ*^ôûmuÿu¼m‡¸™øŠÙsrº<#¾Òø<Šh×™¢{õ§Ì!Wf:íê›ÛhP˜‘Ni‹fQD‡® yÞ vb4šPî{¶`òò?I«dXVv¬ŸAkæ¢ ®¸‡zÇßg¤VòrÒ)aÓ,jp~W /ù~鄸ïŸ+¯øÛ«0Çýå<€ãu;yÞï:ÝË'¶–|¿ËRGðvJÀúÂkúÂG:óy£ï ¾ÔoX?êóez°ÍƒôÂÒhWÊ.š×|jsV#Wùâ¯Lu<ö™zÍ—Õ¿Œ¾¸ù úxÃÇÔ$¶ =>ïq4l¬Ó…¿ (ÞÕå˜À߆Ú-J—Ó©˜S¡²ñÇ1‹;U­xܽèýGu00t¢®ïCÙ›ÖRîîFŠwÒ~ùž\ÙY>u1aî "j„aºÑ"¢Â܃›3r1;SÙØ÷÷Ï´pÊÝtÎE=éšÛ&©U‹]|OùyYeê¸kw•RÉ;z‚jÔ¢gQ7»Zîûëy¿ƒcÜ÷;?­ô÷Û—:rÊÆ­·ÞJñññ²©ï7ÞBFe¬5'¡mMšJ믣ñ+ÆÓØÎcé¿ÿKÁ¾P´±ñõ£êËÁß»öï¢ 3&ÐgŸQB»c­Íé™ât&(O¶QqøCÙ÷·af€C¼÷Íð´V¿~}9nœ.\h¬­º¤-tw/.Æ(H÷±7ÊÜ©E‘}0Ý8Î=89%ÃíAký^÷qgº=ÏE…–í#á¡Ý«iþÇ7S†m¨Û ¯ÜÝKK`IJåwçÞ±n*9aÔèâ² 0Ž?‹œ±µ)cKq7Ç›×PTO7ÇQÍÝ÷;;Ù}¿“–»¯9ç¨û~Å”þ~ûRGäÝÇHtç‹è ; %Á¿9"ù¤‘«jpèÿ¡½ƒ®¥ä÷^ ã_B…i)”pÓ%”ó÷FªýÐX  dI¤þ0Cüq”8¹žÊ95[I¯Q«vM£÷—ÜN9ùôÞ¯·ÊÞÝ/|‚bŠf=.y—Ö-K[W~*—wÿ5[.Cr³R)7;æ¼ß•r²ŽSóËû‰õshÛÚ)RFÿ3€^J¸æ$»·]š2›>M+%½ •bƒjÓÁœ='Ó¶f¬“ù&x‘&ÏèIÓ¾ëKëÿpo»uûlZüÛX)Ù9©2-åÄž“iº·]¼üE¹¼mM‘[bfç†Tè* èÚM”âl×{`âXJžã>î‰e³å2¤ Ý}ÜzŸ¥€ÐpÚ6´ùê]:øÙKôϳ·PXÓK¨^7OÏPQM[Qýnƒå|›ÆÞNÙ´é…[åïsny‚BjzÞo½Ž$0Öç:âp >ì³kÙ›nº‰jÔ°‘qx¨233¥KCXïÒ_zo±`|õm¸ª!Íœ4Ó½PàëÁüùó¥Ê¥:»:\ó̓n¦½íöº’…|GôÛo¿Q‡Üi>ÂÏ|¤ŸþùFjŒAoŠ—åæed+=]ü«¥9"Åe„t칎—y(+K¼ ó¨ ?_¾ 1Î šøk‚ï«cBð]rÔHK’)y± Òàjl"dê2§™Á*ÍYêqqer¦k}ßV^wx=@¨î‹½È°Ò¬ÇùØânÉ Ë \‹¢·+:xbò<œŒ4:ׂ¿ºšFÖá›þ1Çì«N±µøŸÄ<'AŽèhrÄÅ‘#^lOŽ:uÈQKì%6†øßÅÁbklgâ1jëÖ¿©_¿^ëᆠäÌÙèkÖ)^r Y¿~=]zé¥2­*ÁçûiæÌ öXÇu„½6q9!„¨Þœ¸©q^ÇùUáuœÿ!쬗÷£‹~,Àu‘Ŭ¾²`=øYF;šmÂç˜Ó8‹Ÿ‹ŠžïúÿrG=Ö©×¢Æê±õsâuj¸QHK#Î׈낰Â:Ëi|í¼?Þ— ¶Áÿ›·:Îõ óÓëßÂñ™(Äl{ð¤yLüGF9«Áýhß¾}'g½¯Løz}³žB/tŸsêütüÛ‰”³}œoq³"Úv¢Ø»¤ÈN=e‡ÉÍÜ}g{ÊÝŸ@Í–0ÿ†yJk(((̧¹›ÆÑ²“èhú^ªS£)ui1Œ®;ÿ!#GÎiLi){dÓL~‡xÿÑ ärÒÏŸ+—‹MŠgLV‡uú¶3[&Ðk{†Óu¥aw–ëÔ<¼/™Æ×†ý‰øãC(&º!íÚó+}:Õ½­GAýæ×P¯‡É8óíëí)íhÕnКz<0ÇHõä‹çÄõs_¯~Ü‹¿O ºnàY»¶Ð¾·¥ô?~“¥b:ô ³G¼NqÅ»<äÓîiãèà“(ûð^ ?«)Ýk5¸Ùó~'jUS¯#áQvQëbu${óÚÝ÷2gB2VN<òÈ#ôöÛoËI”àQJ“*õë×ÏX²±9ó€‘p×]¥¸e?6å·zÈŠŒ3ʌΪj`°AÕ Ê¾ F¬cež{„º€yXx;yU8?Â5Bx¾f5!ÇyUTð"V…•iNCV K5?B(×¼ nNœ¢£ŸÐÓ¶ 9Ï-¶Ž—ªëô|ê±õó1 Ñg¢™\*º.6"TCƒÓ |/Xt° >f”Õ÷f„c^˜ƒÒ_ýe¤¸Á,ÝX‡ù1zôèa¤Vf†Îþ¡7ÒÙï[O$kf`øŠn`¨¼õË4¢‹õqןOÎgîþˆX€‰ö^kn~ì…ב2’è[mÊü 7Ò¿ï·¾æ5§àï(ÚÝÈaÉ£n¤–cÌ­¾R®  îV9~ü¸œ…þÛwïÞm¤oSh)iÔ¨‘tikcs¦€IÇPç»víZ̰. û¹°)/|©‡¬hXµøòuןعMyQVCÜ›~ÑEQ½zõd—q•-[¶Èu~ø!Ý{ï½FjåaæØ†'UÂÀ@EmРµiÓF{÷î•3¸b6oô?ìÝý lllllª¬hXµð×ݪj`عͩrª†¸7#3s£«ëܹs7»ví¢¦M›ÊîS=T¼PESRW\`w©®<δkÞºu«ü𣶠–ÙÀxÿý÷iúôérþ ´\Ô¬YSz‘zâ‰'JÝÝÆÆÆÆ¦r`Å ýÊõî+/ô1¯ª†MeàÍ÷f„WÕ »åϦ2P[Ë} †MÕ…§’° ›êŒ7CÜ›Žq“«ø{ †ÝògS‘˜µ Ú†M5þÐò\-Z´®Émlª#¾âf¼Ha x‘ŠŠ‚ß87ãÆ£‘#GúÍ‹”MeÃN3*¥K—Ò7ÞH 6”Ö4š»wïN+V¬0rTø’0xð`jÞ¼9EDDÈ>“h²Äø‘Šûúé§©S§Nòƒá1IyâÏD322è¹çž£nݺÉ.s¸¾Ï?ÿÜX[q¬]»–†N^x¡t ã·ÝvíØa=…}y€/T·Ür‹¬?¨Gµkצ«¯¾ºXß[›ªþ •$¶qaS › Nß¾}©  €>úè##Åý^ÆU¼m㦺à· Ìü=oÞ<ºüòË©nݺÒÚGß­M›6Ét4³T­[·–ãF 6kÖŒþùçz÷Ýwå uãÆT§Ó•?¿þú+uîÜY6µjÕ¢•+WÊ´Ž;9N;¾ýö[é.׆?5(à‹/®ð±1h;÷Üs¥‚߸qcymŸ}öÝ}÷ÝFŽŠ踗(Ox1ƒ‹@”gzz:­ZµJÁ?ü gimß¾½4èðeø›o¾¡eË–ù­Ÿ­Á®™3gÊ÷0>@áCÛºuëäÇM9˜MuFUA(h.al¸ºuëf¤T B4bE,]ºÔåp8\#GŽ4RÊŸ´´4WJJŠŒýõ×òxK–,‘ËåÁêÕ«å>_ýu#ÅåÊÎÎv5mÚÔ%”`#¥âÈÉÉÁ¤2.þL幈?V¹\‘¬X±Â•——g,¹Ù±c‡+44ÔÕ¯_?#¥r(((pµjÕÊÕ¢E #ÅÆÆÆÆ¦:÷îO<áªW¯ž|µmÛÖõÓO?kmlª~ë"eºJapȉ˜‹µâ0û‚pÕUWÉn=¾ôM.+è¾§w¾ž;NúÏþc¤`’à2dˆüŸ˜ˆ¹G+Žààà“s£ˆº%ÃÊàŠ+®×­w€\pA…–§èvöÙgWx¶±±±±©šà½ûꫯÊÁÞüŠ–t 𶱩NøÝÀHMM•Þ  b}ôkïÒ¥‹±¶ò@wš´´´RO’V•øý÷ße÷+2*è†Ðý«ºçðáÕRžè…:Œ®vÜ·`Á¿Ôa›ª€ß Œ[o½U~õÆ×æ7Þxƒî¿ÿ~5j”±¶òÀä7yyy²ïäé Æ`°¼§ákJu>¿q½•Qž>ú¨¬Ãó‚y`0É$Æ€ØØØØØØØØTGÊÅÀÀ×âììlŸDç•W^‘Ò`Ð7<,ÀÛ}_9•c3ðhõüóÏKeôšk®1R½SÇ-oЋ¦YÐÐPb}u­aÆ “ƒ¯ `¤VÈO]ÈOhùùù²ÛØØØØØØØTGÊÅÀ€«Ux`òE¶oßnlå¦eË–²;É Aƒ¤¡±fÍ8p ±¶dNåØÊèÍ7ß,½}òÉ'FjÉœêq+Œa1SlÙÈ©“ëÀ0&1Š•cR³¹ŠË—óÎ;Ozëß¿¿œD Ýín¸ác­Mõ¢\ÜÔ¢¯;fˆô…›nº‰jÔ¨a,ã0Ъ~íf_ãuNåØ˜ð®[18yùòå¥rO{ª× åÝÃÊÓMmUšA.ùÚ´iS)nj ¬F Ôþýû¥«X3å•üŸ£«ß¶mÛd·)›j ŒªÄˆ#¤{Ó¤¤$#¥bHNN–®DáwçÎFjåQnjáÏétºRSS7/¾ø¢<–P¼”ŠgíÚµ•æ¦dee¹®ºê*Wdd¤kÕªUFªxë­·äµãØØØØØØØØT7ü6ÈûÈ‘#F¬L~‡Iâ0»wEzÿÁŒÓÿþ÷¿å èùóçˉpÎªë ¢¸fŒŸY½z5 ÃÚ¶mk¬©X„lÄŠÀø¡É“'Ë®qp\`cccccccSÝðÛLÞ—]v5hÐ@v£ž½{÷JE}èg̘!=ñTè²4{ölMŸ>]²†BŠIîð•n>1.¢"iܸ±4hÌ.Êþ®]»Œ¥ò±9ylâøª Ån~§L™B)))rý˜1c*m’ÜÛ={öÈ8® ðµ&$$ÈÖ©ò¦S§NÒ˜Yy–×}5"¼ŸmÚ´‰Ž=*ÓÖ­[Óƒ>H={ö4rÙØØØØØØØT/üf`ØØØØØØØØØØØœyø}¢=›3ÛÀ°±±±±±±±±±±)'ˆþBß@JoÉIEND®B`‚pyclustering-0.10.1.2/docs/img/xmeans_clustering_famous_iris.png000077500000000000000000001265051375753423500250570ustar00rootroot00000000000000‰PNG  IHDRa¼–½r'+›zTXtRaw profile type exifxÚ­¼[’·Ò¥ûŽQüCÀÝáàjÖ3èá÷·IФ¸·õ9Ö¢Ä*UeF ÷uq8Òÿý¿®ûŸÿùŸàcŒ.kµ×êù'÷Üãà›æ?ÿ|¾ŸßßïŸÊÛ¾?ýíçn®ï·‘¯‰¯éû†óù?/ÿ¼Áò÷çó÷Ÿ;[Ÿobû^èû‹Lº³Æð}]û^(ÅÏÏÃ÷ÿ]ÿ¾oä_çû_´7xÝýs³?þ?“± ×KÑÅ“Bòüu—ÄRKƒ¯ú›ï£~bŸïù;§ö÷¹s?¿ýcòæøŽð¹óãûŠôûT8_¿/¨ÌÑ÷ç¡ü}îÞ ý:¢à®Úo¿Ø-þ¸Å¿æîÞÝî=Ÿ§¹2SÕ}Ê/ñ¾ã…LgNïm•?Æ…ïíýéüi<âbÅ6«9ù³\è!2Û7ä°Ã7œ÷u…Ås<Ñ¢wÅô~Ö’Å×[”¬?áFK=mÇZÄ´XµÄãϱ„wßþî·BãÎ;ðʸXàÿúãþöÃÿ?~^è^…nšÌùYbÆÓ C+§¿y îwNË›ß÷Çý\ÖþÑÂ&V°¼in<àðós‰YÂ?±•Þ:'^W|vŸ ÷Áö÷L÷. &$V€tO%ó£…À<6Ög0ò˜rœ¬@(%îà.k“ReqÈîÍ{,¼×Æ??ZXˆ’*©ÒX¡Ábå\ˆË%•ìJ)µXi¥—QS͵ÔZ­ £†%ËV¬šY³n£¥–[iµYk­·ÑcO@Xéµ›ë­÷>7\zðîÁ+Ƙq¦™g™uÚl³Ï±Ÿ•WYuÙj«¯±ãN›ôßu›Ûm÷=N8„Òɧœzì´ÓϸÄÚM7ßrëµÛn¿ãçª}Wõ÷U ¬Ü_µð]5­X~¯³V›ý¸Dœ­+s`ÅM+@@G­™o!稕ӚùIŠYµP´8;hÅXÁ|B,7ü\»Vî¿®›+ùÿÓºÅÿ´rNK÷ÿb圖î»rÿ^·¿¬ÚQÒ[ e¡æÔ§ °ñ¢1’14_Ö>9‹õ†Vo/­/Ë7Ÿ^Œ®‘mϸo?kß5WºgÙNW:¶cÔüìÇÆe2ÇÖ´ÅÑòçÄ0Þ2òÞ½,8ìŽ\ZËiº¸X¥Ý² KÖI¶SWõ›—,–(´;J9{öžÓ¹Ñ×½ø—pe6»Ö$űœo ôôw³Â6ÎH§•úçØ~öŸñ‡K„œY2":¨éô«ñ5Ø)ÅïS{ª¾WK)î±jh1D"q§6v^ÑŒk‹)kÑî§:cJ¥Cê»T8;Ø-ñS‚#쩟.›¹Üsüå.‘—ó»ãÛ°yÚ®µõ˜‹ ºÛÒfŠæi¬É#-ÞÅ%æ­±·‹bP¬øFð´vH@ ;›­Rø%®»ç²Ð—¼ôíëè*š3£.Ú/éÁË7Áj‹øÊ<Ôgì>N¯™±îª?ÌÜ%ò¡r;,’xÇf ‰Y6qÀZN¨AˆU—Ìz:µ0nN°tNsdÞ.³×Õ Ã-Æ$wËJúò¬ t&ã`ioÌ30®ºYZ[¡·6—KiÕ $Ì´Rº‰1 ±3s«Y³Ö¸s¹ .Áú°\÷(sEÞ 1_àqß°R%XÝ„@* g‹ìâD "5;ë5¦*§Âb{üLxA…œ ÊØcDñ4æ’éã­i¥¬¤Íõœ|!ÿÚõ¸]btÍhzܸèë9ææÁÑVdñÏ¥ÁÖ˜…ѹük~¤âXîkŠ8 ž7“¬=Ë»È-ñ•~V/óï—#‘váV·N0£;c2À*ÅýI]Ð'F… aVó£q)p Bš|r ð2ÌO©+îVh R‡-,öÉ`™^`µEòzcÑå~'Q¦ðó“ïØêórg à?üœ JáB(2%ypˆÅ͹¯”|(˜$8T{Ù»µqY xOŽì=~0ls>qG`½Xã±f… HÏÅ$µÈœǹû½åöàê¸<·m"~Àâ¼×éN+‚ÌÕZä™j3€EâŽC®JªgN¾uD ² p¢$±£nx)\¸{-Qs¶-À.^Oá¢ïÐ;À ~ e‚À¥ôÉÈ5”r"‚;¶aHÄ$\&$äÂÌ1"§·ê« ôxák‰µñœ(  iµJ&38©Bsœ¨#x*AáRלÌé!FáDÌp[;Î#©ŠØlwÆó׫¥ÀÏz.ˆ5pˆ¾[³’h„°µz$áÒ›àŽ³‹´‰âùúe†~i²nB»hÆèd¶'‚M14‰è…áþå Ø`¼(‡Cî° ,NOx[À¢ïKŇÈô \ßa®­ £ª°-ªúÁ€ <CKƒ”10ü”{å!vh¨ª„Eö ðP¼Ù ñõà: ‚LKr¬G·„$1SåƒþƒÅIõ2B¶^ ì‚wÊ êÂ@=Hô…Ó5×¼P¾p”¨Æý ­„‰È Þà ¢²A+À Qaå™7Oàwæ;ÁÚP\ÌãžDÞ¨™†š\öWë9Œi*‘M˜çex æ 7Ó‰“¥Éþšb¾\¤5¬ÀÒx¹sD,Ž$†2G¯ž•€dTñhy•ÆdXY€‚AÖŽŒ)Rq©†fˆ¡ŠY´bªÞ`$™Æ9Nbæ]<Ä·ÙÜÉ’#Éùx#†€Ã»Ë‰ð (·t¢u„¿¸q0n4G¬ 9JÃÃÔXo_ê)ÀãýDò3:¦EÏX`¦Žçg‰Èg«xŒõ%ßÌÐIç}YX¬­,õ"UËoÑè²Â0è£L4`”ì‚¥+üTÙjAbÄÈŠ”ŽUZÃDbq=Âr– (âÝ&žQB«Q;†©¶B¸½¾èʘC>”TU‹<åáÏL* [)LVޤãr}Ñ1Þ›x^n†ªUV¦¨{™} ÀóŒ¨+¤Þ³5dHÄÃáÛ°¢r€° bäò=ÒYÇ©2ðz„z,m4 JgRˆÁt0}xÃ#ÆÝއ0ö–@2Ù£bú++›A¦£¢Û­¿jŸ‰M;šô!æ(À}ðÞÞc+“ÄëMP!HõØÆÊRY™%L5DPmÁL h d¾É—;¬ù–%‰ !À VÙæRçõQ ZU“µg’ÈIƒG±¨"S¨€c‰É¾»}GñDHÅ&å.±Mø¡p ošžµáy«ÇÌI@CA!ꢒûàXVaM¡–™cEùBZ%±*yv;i.ù}¡o ¶pB-• ëÝÇÉÚdºÔÆÂ`´œ« CØk„PƒÆ‚•@<$£â6ú·gyB¯c¿ìG™„Â#IÀ$`,2 ÝIÅâ"&frδ±m7ðÜÃ]…_,òb!:yŒ‘×Ñ(†T ðGÒIwÅ l®X±Í z(a\X€‰ò͉i6.¾~Î¥‚GdˆÌ0Ï^ z"¥ø¦Yn8‡*»Jƒ²¼±Øy¾¿Dؼñ®Ü˜„Nâ;*Êðøè~òuÇós&g@ô°Ktüj@7’KÚ}B®ÕŸCDÙ¨²‹kZŽ“Åob ´)î‡Dö^Ç«@—BX‚‡,– ¿æ*äåÉ+’ƶH|Ä‹V”y‚œEįâ[ ì`1D,D…"ÆP]±·èk÷\ídŸóÈØJÙY¾E(9ܹâtA‚’û.¿òJ µàm•P±¾<ˆS¢&p¡d†Hà¹{TÞãâJ‡UCA„ÊæÛMÉ×1,ÿé°Gõ@%J3‹±@qn„y@÷L;\yfŒÈ\>£FnC“ž:E¸Q´!i8³ÊÄ´U€ýÚR F» ´c8ØdF›wŽÉÇîÖ+èfÉJ脘›àå­Ì$2êwÉv;•Ùæv ÈHÚ\è~#¼[š‘„ÇËW‰ôvØ`^€ˆ7rÝ~¼l)¡U/³Š^‹wgPIë›w˜j¿6RE À>&‘SbÜdåðs6éÝ“*F¡ò´5%¢œQâ zé©Ú6Ñ¢UÞðÊ W&örs@Ý„á ~ÄÚœèÂÎá‘uÀÚ¨ ¯8U;™Xò@AH¢»ëRÕþ¢>Ðp¨}$BQÆq·(ÆÈ¾[†tUí±<Çý›’ rñ›ÿ‹ùg8&î]ðãÞSÅ4w.±#ï[&BÍ#ø L¤Sòðí~[»„{_2>kÞ 2y[ñpDñ+1#®+E=ƒe'™+*§b|ÇþJ‹a ù_¹úÏQ«H±ž›Œ÷}¹NUs@L•{¤ÊF³ªÜs‰SæE›x¯‘»jéûåI:´bøóòn|dÈ+m¦±i“á?0ðr ð^G/˜¥6‡­V»„6þážkT Üg_ùN60©¼LØ yÏÿ2ìKE€*[èûÝ È²7H U ²o —¨­lgÄEÿñ˜¤C’[ ª€ êKÂE5ë›_ù§bôð·ˆ9\On]C' f:âCÕ  'uàÎ¥ ¹ÿxcÈ æt¿“øOÑ ÎXL0¼Š×ñ*€|6:Ttdù½!UÈ)œ6Lð ʤ§W*èCCúgñÛïòý~#wHÝ %ÿœ¥¢ g= öyð߆×Zoå?.ïÏq#Ä_aùÛk^ðF€aø5 }BSEY¥zÿH¨’dàÓ Ô ã¢:Ûì£ËÅUÈÜÃà!@³ð¿ÄLk£á_õ Æ 6¤‹â=2¦Ôð¤ ØdH?»zE[7Ÿí&.j«:JOÔá ÓÆ¢L!ú°¦óêh¼¹ŒŸÂâÞ˵†#ú\q¡ ȈK㇌?â…Wj·¶}T¾p¶nî$FA>Ö É`G®¢‘¿òô¬Ô&š Hl¨RÀC­Ùðw }„ržhûÔiyTýD$·¬Ä]Ú€ÒY–_~Ì*kŸQP¹šà¼²ýǬ„7PÒ") ÂgÚ~™4/ÊÅÁrKµ$Y£‚þs8hoM»pÐß0“ ’V«ÊùgàLU…Ï~¤½øv@ @E›Å07:Y@9XTÑ¥ví2l?¥u`ÃÒ:ïMð¯MmjÅ$$EhÉoyV£DƒªBY”ù’G•óªçò¦±«0âAª*!Ú–Óž"³•è†Te^{&›„€Ô ö€%‰GÃÓÜR)ø(£®‹Ê­ÃÔÆ¬¬õ’¼Áb-U >{›öñS]ÛY ‚¿‹³n«Q[ýȨY~•¡P0 âU™&k…Ü“ì‚XfÿeÅ O[‹±…ãËaùްHmuzDÍb¤þ¸KÕnXð*Þ¡Ý^T“Uþ#h-ã“Ñ·"±Ñ–®êÆ/†~¹µnL¦ƒ‹Ð}Ýß—ý9¾öãçî_¨òö(d>S€Æ@Ô¨I´‘»Ü’ƒ8P ?¸$ÁTm¼¶þ3U˜µS8TéÛro0cìd*:¬j»mÒíWU¨0¬<ÀD_@›ØÀ®¬¥>6²š¤Z!…`%º±„LNRRØÂp ÐHVÀy—¤¶¸Ïô*©ìP¥‘À¹ öË|oªêд; ÁÎÿðjc cŽt—?‹¡å©½j¢ùÚ˜>˜ hkÏpÎ@¦®jª'ôëЮ ®·¥šù†±¡ÃÒ˜ L¸©´jGx|Ž®aô•ŠC'¬œžäæíˬÇCm|ýôÚ²èäIxU—pXñrR†óÂ#"EÈÐ3²M®rq>Û.Ž`øˆœïÄ”ßέw@¿ö³êD~t!$¼ú‰¸üZÇç{is]žêÄo¾Xz5˜‹òÆpu(AÞÕV´Ÿ¯â!ÆXþ׻ܷ|–†T2r8ò¾‡ŠÞ×3 UIÆÖ¢²¯Í'žbDqXü|uÞ‡+7º~TI ómÚdaáÔ‚‰&Ô‰r_ ö*`bãÀr‘°è¢W; }8¦›²TRDÓá=ú‚\)ãŸvÆ!¥8Þ­ÿãW¤ÒB]ãdií5Håæ±Ðò3È@5¿;©¸yM(ްf`øc7«qXð~7¸ÂûÊŸ:»×æ3©qäwbV£”;ïÎÚ)@,í¯¨ç¥"k"‰Ð m‡rû¯ÇBFIÄèªÜ`iŒ©kàÁÁ@yƈƒ[~@ØèOÕÐr>LÕÀ’Wˆ<^-½ýnw_h55¸Ìz6ð I#1Ãg«â…~^LS‘!t:ºu&ȼlbÕuíè>úMª&üñŒ£ÍÔFB¶í›ãÌŽœßUµ#© ´^ª½Ìä²ÉGì 6K¥u¹ä×Dèáò* Uü# MžX±X/OzLŠÀqsôkÇg•MÞµ‹YŠ’ÝÛŸ^©Yð4«!C W-“hãÉü 7Önn!GÆã¥ Ö0Kúðá&RØ YÉ™eôŒù#T„À9 >TôHûiV‡)ÛªÅ2䘚>µùÁCorGNf *Þšöƒ—ש ^ì`R¯Ú–Ïê’sÇ$‹ú›ˆàVoF.` +è••> ŽÆ©Ü'lÑk¬>Þ2DªPx¸ÿªøœ´¢Â¼¾y°pÏÂÇ‚#M8…JRqÒ´ñJdžæ;©õ Úê6`®\~êgÚ§Bý›¿„;°ð¸àÌE=ºWd€àìèj %={0¡Í«êûUd[{[Y88$È.ۇƇ«‚—Kê#$0LÍ1ÏDä¬ZüjÈ’ uôð`¶NN°ü<—1­ DzÛÈDú!ÌN}¹¡Z§›æë¨«ªñà Lá'jkÌßüOT‘² ‹¬3­\¦EÂ<-wóQ3 ´•ÁÆY:3ՀŠªº"ö2‹ZŸ«ú)­ö5Bž-jB…WÀl' Õ2U)Æ!âö¾â‡ØØ´Oø@:ªBЦäæg` ªZAX5”2ò.sO•eÆ–Ò˜Ä>ž»ï­²&Á€è¯†aµ·ÕÚÔWp¸–Õ:áªÉ_ªŸt­êwÃl£úqY¯Ð™UÁ+ñ>ôN^WûLw‰’¼ºz"t  éJª?δÇTÉ Ò"›Qù1Mž5—Ô±8³‡€jtrY/‹bSttRWOm(³$sY:OY¡‡g%ëGBfÔö WS‘WÂ%(ñg´þ VR|Ö îÿ³=à¥-L¦ßGWJÝÜÁ±|@ãæ¤ÞŠ_Ù¿Pþ4!|¯­ÎÓþ*(òÑ`Õ §Þ«AÏI"=÷{+ ‡ð7hص!‘U„&^í»b²mÄÓÇK©ÿ(¾†ApÐR‘’2©Â™:bàÃì6­ч—`J[¨4,¨;:¯‹i8|RÚw«DU¯S´ð á3#@Xº4u•»_¤.C”+ #B_]–^}®NRY]¸c„ò=¼Vâ¼íXõòµ¨~u[Æ›©Y£Ï¦þ;jAWG sQpåu‚k©,$ö¤j‹È†ò¦¸2ýŠ•Ehêsèøá\¿è#X`„Ó« î¾3”R‘€"!È$§µE¦<»S§¹>ÕŒáåPÕÉ*‹üÄÈ»emyüà ØS‹zÁ,`”/œ±á5DA3”kÅÁô@÷ð èY=aaîG˜€!×ÀÄߨ_šúõÁŽÕ¤’$q=žº×«ÎQy6« â¯uÙ¿•Ú;½]dOªõIˆ×Õ ^CßS'qP2³|6£CÁêG¯ÚýT:˜Ã¹I Å”ˆnuäŠ;`D|7ép©l…MÆ!â¤TÅÚ“jí­åUÐÀK×dk×$ߣ]mX°§*.y\Õ½ ÏÉ‹"€`«·éQŒµCz1d‡RÒ&†E„¡f;vå¯ÚXš¶‚™Ð‘POùmX€»KmQ¢AæåÓ}ˆHUBV}T#b‡Õ±\ôB¯vFx·–ÈDÚ?˜"Õ?×UUŒÒGjžCÌc…MíÓU;bU…PI€Q2¸Y‹ûi…Ûðí:êgfõÀÞ0cD¶¹¢Ã#¤ ¾8/­ÓMç¼L&³Éš!8¦¶¢>ÌX¨–ˆ™ÿÁ†î'ª”¦s;ÄxB![ªV?Ë8À7LT†¿j.5µm½ZÚé§Ð7dÌ(~™Ò„ü×®­ûé@@+–!'ˆÞ[Å-çÓ??Âg´è©CоËó3˜0e  Ð<Þ^<øŠ‚.Ý‘©WÑÒ>±±,‰ìÀo¢˜HWI7 (‰Xc$°ú¬U2THˆ}G!·tˆ‹0羟M¨Õ ƒ ä7–·«û«uéâ2âD3­ ¾5tºSý¢d©'IâyÀª„ Ö¸Ö^‹¬UþQ13é R:³òš‡¼kÚCÖ67ïfY¼Ê:‡§Å_(Òñ0e¶JÄÁUuÚ$&Ÿänk†˜Õä wÚéN>HŽùècâmµrU°cfª•ŠŠÝvH‰Á©ý£ù©[ÞO ¼ìð9xÂ< ¥š`øvªì؉þ©N 5Ž®SÈ‚¼ô u%Dûñ’È]íoEÛôò(dƒQƒçX·¤‚ãs¢pƒT• J¸wòŒç!ŽŽ˜•DÌÍšÝ €‰J’j§&ßðÚÐ"Rì Û¸ýaiÆ|İcI ’Q Ÿ¬µC3ðš…L•³ÕBY¡ íÉ+ µÕ¯­9¤P‰L"š‘òM;I¥ûH€e¥È«LÕ#…n2?=£#Õ™ÊdŽDKà pÁSlò!ÈZJt*5Œ2•†Äèáu< FVž¿®·ùÄL|¥{—Ë †®¶ú>C£]ó¬ `dæ,yË££–ûŒ0‘‚CQ ­šÿÑ.ß!ú»:°b¦ÕU˜)•&`?¼Ó9.S`•÷T‘àÇmñÙÐÞÙU·(¦·¼&æ¦ChÅ©ö¹J:®FÂàX‰š×“ýEѨ.§šaLÕï7b»%äóÔ-|¿ýz}ïó:€¸$IÇ;óÑ«iâqÚ[ˆd 0QW½õE.Àå¨ÏO£‘ ú{÷ÏF#Þ}–z,à6‚êùyeˆ+!nAmpÙg¸›è:UÞËR¹KG?Ô¬þBL:jUèVuT™,~ƒïøàµˆ×‰y+Š Mĺ©#Œ•Ê©r›&ÇE¾Áˆ`XGw…õv!ñ‚€†ûÖ ƒ¸ÝQG®>XL“4Æa5(ð¤çÇúá…T0wˆ)Í#IBk¶P?$:~ƒEÈÌ VÜtÜ!ßG"iŽ‚Î¼¦€’²y2šŸÄ©S+Œ4éxìñ“’XV`ãóꎅU¡öîÁ­¾ 2^eW¦YëÆ·«‹ê;£át,½ d".šJ\¨E,úPK‡àþÔ™DÑám&. šº†Î¾ö¶Mû­¨€‹¦tù§úVÎ L"ô&馢) g½À3'{Éõñóm{Ä"¹/í (Éëg©>AÇ€£7$²¼zn˜ºÜÆ¡™uD Û¡6ì¤.Å€µ‘*PC6ÿâÐ|SoÑëÀÈóÓ¼4Ù-yÓkÕ¹£‘^-ŒWû¥J$dÚ©¯ýÈÞô¼ÉñþÇôtMâò³]æÞéôÎo|ý¼ö‡¯×Ûóö]]:Æ8rjÚFô ˆžXˆÕÕÈI:Ö¡“FA{ðrKÚË{M¬š2‘“úƒÍ Ž@gºÔ»ÀŒæ±µåƒ,Åø©0Н"ŽÈl†Î%’'EŠ8©U jÚc\KÁ[aHc®«¶uJ ÈU»#ìjhØ©ÓYšÕî >8‡Ñß`6°XÐÂóx湸¥íù¦E 0ÊŒ]J­²½l%p}Ô‰ê*Uv°©‹\›Ÿ3pŸé»:‹úªš‘ ه̖:*Ü⚘ÍÏ1ÆÏ÷8­Ô“ ]D ÷A”¦Jÿ§™y¨~Ó1RŸC>*rjëFça‘ÕI“€m3"lÔžÁDéã\†}ŽÊ<¾ë CÒ=:,©F+‘ÈjVËIÚ}…‘†XZ“àíØµ·ÙpCí™+U•®‹:;¢šºžÎÈú%C&¬7l3ˆÅÛÕÈr¥éÛ ºMч¬1âªÆkƒ ™:ĆÂÒ>¼AAPT"‚󒙙߭t=nØ}iåC1 yÄ)a}?ýšïox@í$M§¶Þ68wµü“ÛE]$Ẩ>xäé}™‡×ÃõïÒdÒRQ2s¤Ê­vÜ °bÒ© uƒjK)é„%™P sxaÙjGh[ÝSÄÓPƒöÖ)]ï £œâ l@wÊ#|T·A,ùOsCýtG\Í@¨–™°+^Í­¹T5Wþtòûøœ¢¾÷Wz•L5bá¯'¬¤£±­¤úJKkÕOªÿq+÷¹W¶ÏÚ .öûª˜hïó60+>ŸðRk¡¦BÍôÕÑ9¹•žTc»å-å|mU ì ~;ÚË«oLŸè˜#Þ¶6·¡8ò =¸ŽYµî´M2›Ž^l“²E¬0³˜¼òÝ$û> —i£µu2Gçoû’ýxFw?øæRíž \¨Ÿ€¸O´(VäÃ@`u™CíÙêÈòNÕ‡š+®ïjÌö$§L#Q^ÞoߎY¦3½–ðN1¤_œWà7ÁY¨£–ŽÈÇóÂd4µÔ½Z‚NñETñgâÕ´’ø~ðûc½}Ó«DªB}ÜhjVV»}Q±˜Oȵ¨Ò€6‰Õ›*u$¥£Ã<{üñìšÅOÓù=›Œý9Rß,×YÉù ˜0ÔaŽ\Z‘˜Íàô¬~yÄsê Ðá;°Ä L^*+‘ÿϦðÔÖjXFuí±àHˆ&øKÚ¤è­ï 0Ò ®c¬¼óÖ/¨ºdŸ:Ö¤Gµ…õVCÖT„[øù¬¹Sµ³ýeb‰¦¡®8è=$õ<€8êúú‚œÒ@I0$3ѰW%y–A2¯ÒÚëEõ"Û…J$Õ§G`]‡Õ/ ”„{Õö`À6TuxÖ®íbºâÑCl:™—v>G@âªy6ñ±ƒÔ .uóô°C×'J,ÕB_;QÖr¾Oß)jpZ’ö9žn¼ T14$I®#ÙEF]y4{Å2/‘ç[:—uCÉO0ðŸ a½‰:CåtV]²'˜$d¤m•Ãç÷4t(¼yê¬&PÚ}«Ë»é`nQß?O:w¤Ñq@ Ð㛣<²Îåç yãÝCoª“tÐ!=õÂhÌÂt03šì¨Ãë:ÓÐfÇ54¬‡7`WS?2rNÍýô‰:YP˜Wfˆï£ú›á®h"`%2fi/WÎpãÎúÜ‹³`wÕ)Uîç}9×ÔeªÆ`Ä ȩӼ„ŽúHµ¸ éñs$Q/ ›£¶X‰¡2…i i³‚1µ3.X3w§=Ù°²¶e—ª! ¤Š:ª ޾‡åUG΃Î^Tu|ÌŒN¤o<ü.½#£œ5%÷Ä–iÛÞ"`¸,p–PAª)W0b A×upN%yú†‹¢ª[`áÄ+çÑ0€2`'dB?$!¾¥6ÏpüMŸ¹¡§vó%LvzúDûâ¤áV ÁΪrÇGÀŸ¦Ù°})*ñH;&鸗Ã0맯ð}VKH¤k« Ù0»Ž9w}:dOu¬¤# o¯=¶Õí¬îÔ ’;Q{8+¾þ@mä¢c½%JJ’©Š®Î9õ;Å,ò?¡…FvÜ™…ƒj1th ÐL‡”´=“Þîfš*7£7°kA¦=:€ñŽ?°©O@Ñ' ð«$׈SlÚ÷‡§u> ¸ÖN@>h}ú ›ŽÜÔE>hב¨¯ÖrÚÇÑJ²†òŽ|d1HžÔQƒ›ºŽ«„Ý‚Akä°AYý"eÖtÖ¨¢eÜéY§5›„9Äv)÷m8 Ë´e‚‰RïRu´ëùô,–íVOÁÕU@Qôz:‰Hxm¬«)ìð8C‰Ë©^³€Æ·°H4‚bó ŽE¯®z,´6aô ¶„A]7TW.|ñî„ñ®ƒ/òw* «ÜœT¾R ÿáô¡G(Â>ôYR*Ès]'‰Žv±°H¦¨©ê>%¼ŽJH¥4´ëÓñ¤' ÚùA,²0AGûôy&’*0äû<Ÿ£S˜•&´¶!éÈ*Ù¶Úp>Y{6®©ÿ~¼“Êï“Ät®OÐѦ°t„\',Fµ”q·¡¢HGÁ“%þÈ-÷I.cûöíªSù|eàËoæÌã¨ô~~SáF$ëpHË@7 EÁâ`ãtNnÖÆ-€¬R–Õ¬ôí½ÈÖäÞÁ5Ùàç¨=‚à?æå16Eg )Q²>e,ÈL_¬:±ðšyš}™±¦cjÓÔ[)‰•Z'¶dÅ’f-¿È`Ì67Óh Æ J"'}ª¬£óÜ8"~—`i¿U&DY@šTQëk7}üÃCVWÞ©µÀ”‘‰ú@°¢pF7ù·æ£¦YÂØ.ðC­ãÕÊôó5.>>ä-d]€zºlw¡ÍŧYmÍíõ bÁÕ^UÕ4Yy¤€\èu³³YgQU ü_}R ÈñûP¯Š‰ú@¡úKÃØûêÞ7]å5YxÈBòòüαš"‡| ³S:‚¶$Ö¢Zùü~»´ÆPƒC  _ƒº–’Œ‚Ž‹µ£úÂPàѱ ÿ5Äš†òKs‚ªpÿJ«þãºD´EbKGDÿÿÿ ½§“ pHYsaa¨?§itIMEâ0 ‹©‰ IDATxÚì½}tw}ïÿž=K‰¼"Ž;†¤¶±!‘‚X*Rk÷WnxHh®·¤½<Ø7¾œÐÞ>ÐcøÅ4¡´¸krNJ!*J®VaM…X ‰Å6É­c¬DñêÁ»+¯¤ÝÙ¹Ìîjgöav´³z¿Îñ53ß™ùî÷3óù>|Þ_AQyFQø|>Rhêëë!BÉÝw8ÆÄÄDÉÞ?)m¢ïðÕ«WÃf³Ñ~Y¦ýØ q^¯W^y% RpfggqÅW”Ü}OLL µµ•? )(çÏŸÇš5kh?„,Ó~òâ„-,,`aaAã„ÀÙ³gQ__Ï_"‚Á Ün7ººº I $Ë2œŸŸÇµ×^[²Ïµ›óçÏ£¡¡?n¿ýðð0zzzh?”a @kkkɾ¿i?´Ÿb±Ÿ¼8aÄþþÌ3Ï ¦¦†¿N†ÔÔÔàÙgŸeAXP†—/_€’ŠˆÞwCC?"¾kjjÐÐÐÀˆ…eHû¡ýìì'/Nؽ÷Þ‹}ûöÅÒ^¯­­­èé願ø].º»»i”a `B)(yqÂ*++QYY™ðwI’èP˜„efM†B!!„‚bcB!„Ð #„B¡Fr@h8ß ¼âP·¡I– !$¯LN½½€Ã¡n'ù"ÅT¹,® Å\ßí¬1yæõ`Î@V·¯­O°\!yc`p¹YV·ÀeüJ%“  Y! ˆ–Q&e%ö÷C ËP\.(ýýM]ÏŠ<âéï12"@–¸\ úû Ê+Ãør¤–oÇT P·óc,BH^9vLuÀu;V毡T2IÃÃÔI2Ëå2<¦wt‘Ê%È2GGñäЩëX‘G<££½åŠH}0:ºˆ¡¡' V†Q‰$:a… ºc©' "PÕÎ2!„ä•ŽŽ¥ž0QÚËü5D™¤ì0#‘$vvB‰öb‰"¤ÎNôõõ™ºžyÄÓÙ)bdD, ERVùe[†ñItÂòÍUNur~LuÀ®r²L!yÅéT‡ ÇÆTÌYæ¯!Ê$YCFåuäH¬r ííœNØÌ–±y$ÏííœN’d+XÆK$Ñ Ë7öÎ#„”––òžFJ¼rY\A‹¹¾3:’BVãã@s3`³©Ûñq– !tÂ!„䜮.ÀãEÝvu±LV*a¾G|˜=4 ß#>„ýáì2,B‰ :a„B †þ›65¥Ý¯O“•ÃÜãs A ( aîñ¹ì2ŒêŸLO/éŸ"sÂ!¤ÌÑë‚Ùí@¼ä“ÃÁ2Z©È2 DJ$ V蟬 ö„BH™£ÿ¦ÕÔMM€ ¨[·›e´RW‹€I‘t6tt¨º'ÀòõO¬ÈƒN!„b@ÿMÛº¸x‡Õm[Ëh¥R»«öõvÕìëí¨ÝU›]†N'ÐÝ­v¯vw/OÿÄŠ<<ŒššP†¸\.ÃczGGQ«d‹££xrh¨`÷üüó½P”ŠˆC&àùç14ôdÂqwߎq¾f/ÃË—/³2B'¬ Mª—cêü³«œjï!qÜ{ï½Ø·o_,íõzÑÚÚŠžž444°€ ƒp¹\èî_òD‡ØÙ %Ú&Š:;Ñ××·ü‹ONB¼ë.ccPÚÛ!ï{jS:Ãã;oücŒüR, ERv÷cAV*’qýÇÀ€:±£C»ki1wÎ}÷û÷§Nëó\Î5-~„¢rÂ8”’æ…?Ñ!02”9” ýW&}ÆoÉò>"¥Zï*++QYY™ðwI’ b²¼ŽQ߸ccÚÛ!8°eSÆ{ö##€,CmÏžôcºãÜòß1ÐýCŒííœN’d+h†B!V&’ÑP\Y^ Å5ËÓŸÓÕÌ̤Nëó\Î5-~„¢rÂ8”’šÞ·¢BŒ }@Æ¢/ýÐG&Ã)$=N!i±rÂuèbË žððg!%ÊrBq“ÉZ(Jê´>O‹ÃsMœ'ŒC)©':¡D{ BªO>ôaf8…$‡Ã)ÄŒÆ&ôû7ož~Z}{gºmv‹¢ÙÛ››±Br¾>gŠ«?§±q©ç+YZŸçr®iñ#•Æ¡”4\}D6?¡ªÂUNØì©Ë„e–=N!Ya46¡ßË-j»:žhÏîtƆCÑÞ,,än,„\£¯Ï™è9èωÎK•Ö繜kZüEå„‘t¿%0))ŒÆ&ôûOœP×Êýp¨ÃAeURº,gx?Y‹tyZ<¥Àê ñP¬•BÌ`¤tºq£6½aƒ6mV –ʪ„”-t²e~x¥8mS·óã,BÊ#¹ìS§Ò§Í.Üh¥<7Yq„ýaøñaöÐ,|øš iÒa8¿74>476›º/½o¦Q;ÊL;‹Ã‘ÙòZŽ 5„=júú‹,BÊ£±‰™™ôi³¡V¹ Y!¬d™¤ÀOÏÊ€„΄à›ðóˆ¥ý?õ£ú£Õió°R"ÉÞÕx<(ÐÕ…ÐÄDI•i¿ˆ‘²,ÀåRÐ߯`pPN»ÿÇ?N.‘D',ëfÆTú4!¤èz柃ÀÊIŠßÃ> :O<IgÓ |QŠøòÍ“E_ß ù½àœ°‚é, ,óš0K&2K¹\õž¬° •É*éà2D¤˜ ¤M’øRuMÑ×÷B~/Ø–€dÎ’êщÀ"PE ³d²Š Wz!–U(«¾Y9I1Qm6‰¸ZD¼˜8ÿZÑ×÷Bš$0=­ÃqŽ—I[ÈUN ¶êö*'ËÜ$™¬â•^ˆe*ª¦(K:a¹®À„ä‰ú;ê—¯êH: _>½©èë{!M’Ñ 5h;°a1‡%Þ´2<=2YÅÅLˆ0a…J[¡ôºaSS¹¯À„äË h±£ñžFËòK”Ĩ/úú^H“dO!„¤Ã¡[£±ÑºÕ{ !+:azŒ$$ôûçÇ)9AH9£× Û¸1}(CsIIµ’‹gx4€­/oEàÑB“!EBúä$|ûܘýÂøö¹~Q2>žw!}v™ÜB¾àp¤ž¨„ä% ‰øáCýþ@žI}ÈgeH²Ú’Ÿ{|.}~z±ÉdÇGßàúŽãP+W’¢þ&ñâ$'Pmú9¢º/‡ ^7·âD´!c¡f„>»LnNX¡0’Ðï¿ÆMÉ B I8Éß]K=^\NǼ@GàÜ´T°\ÒÙ|BorQòO5px®S.LÏMÃuÊ…Ãy=ŸdPÆœ‡L–¾g ´kÓ­Óž¯_ËÒ÷TéWV0¹ÒBÂÚyºûËhâ?)ß÷áiÀ5 L‡ÔíÀi–‰‘Í—³”¼vì÷Ç ‡Õ–¦–1vn,¯ç“ ʘóIè{–EЮM·«6íùµ»´‹EH?ñ^?¿,lî~ÖÎÓÝŸáÄRÞïC¯Fäc^–‰‘Í—³”üpdǺ¸N¹ ‡eˆ6íkÛóz>É Œ9™d¸ZT{À"íūń‰ÁŸI7”QýAm̽­Åù5y)¿·ˆšáITA3‘?!dߨe«[;/ìkò·½Ew}ƒžì '„ègCÂЊîúd…½+€'n`9XiótÂJ˜ñ ãè:Ô…)ÿu|çŽïà¯þ«Xúé}a#¾¦.WTÝ¡Š±ÚÓ„ö…&Õõ#3=žb)ú¡ŒØðb$mk²aæÐŒêœUb“ù©‡'ÍFfé‡C†WR$)=B“!øöc[`ü¯úUqÖ{Æõ¿(ês‡èçÅ [XXÀÂÂB,íõª3ƒÁ ‚Á`A  ë¾.xæ<߃[¼J¤Ùêñ{0qª® C€ eÎåB?äÕƒ©?ý#Ÿ)Ñr*ty•2ñeÈr,_jwÕ&Ì »qˆ~^œ°{ï½ûöí‹¥½^/Z[[ÑÓÓƒ††Â††4¹›4Ž˜A㈿(áÑž0ˆê;Ñ××—2?q¢J´',ƒãÍôâ¸\.twwC’$¾²,Ã@ ÀY©è£«t6l™•,ú2ðT –ß""ôZæ‘]+)Œ” Õ:ÇË Z¸(ës‡èçÅ «¬¬DeeeÂß%I*¸CáÞïN;'lõÆÇ àkÀü„ªvW9a³§¹ç«¨sÂ2=Þ$ÅPf¥Ž$I…B,ˆŠØ,B>/kÒñè‡3†}¾Øœ³Ð™ÄkÄ´ÃzŒ®GH!©¿£¾‡}P „jÁ0Z¸(ë³Ó©AŽ©X…è¯ø‰ùmW·áâý5ûð»?¬;j»‰má‚Þ„1aO8mÚ(2Ë(ú2üfØTôãJŠ#¥‡½ÅŽºÏÖahh(¶€wÉÕç"Ñ·³ŠB2%ëÞåi4üg}¥î2 ©¿¾~¸Q}ÉáDBHư’ÿ(x'Ñû@/Ÿs ÷^Lz'5ûÇ/Œ£yo3l{lhÞÛŒñ ãi÷ýÝQM~ãÆÓæùqà•fà´MÝÎ[ßr÷‡x4€­/oEàÑÂ~Ý:*““@o¯ª†ÚÛ ŒkÓ““¬éÄr±îQžÉÄWͬ+§îŠFC¦kÕç§¿¾Es~ýõ_%mõž¿R·“‹‰ßß#>Ìš…ï_â÷é_<»ÿ7üØvbüßð#42<~æÐ f¾<ƒ™C3X<»¨Ùš ÞÑ=›}¦bFPEÉ÷E½^/®¸â \ºt)ë‰ù½ôj–êÞØ­_mÞÛ iâ}S]“føQ¿_%„•p,¿ÆšFÌ\žI™?^iÂq–¶&àú‹––—ïŸf¢£}½]ÛÝÛÛ«tØØÌÌ,¥»»©– ub~´K=XV •6dǯTg)–¶ž÷å6ÏÙC³P©_SBµvøoæË3 küß)ó×çg´ŸöSüö“L&©µµ§$í?ž/‹™ C€;®T0øŽ¥9GÏÆõü^+¢ú£©g×ë‡íú©Õ@Ýgë2?Þu_ªžã$÷ctÏfŸ©Xì'>0¬©© —.]*ýáH£¸§üS¦ÒAyI?J˘òOÅ¢%“.ðžJŸ¶Ã_}øíÔõ­¹b6±\¬{§Ïó†:µEžü§5v¬ú¿ÁåÿDw飹lo±™Zë1ÛáR’{ŠY&)[Fë{!ÛÔñ{F§14ôdlÿÖs[!)Rìû1nî!wÊüôÇ+Š¢ö"G?ACq²K†Ç‡ãÒŠz~|:ÙýݳÙg*&ôIe¿€·£Î¡éérÔ9Òî7ê KXàÛæÐõ„9,FÃ_}ø­¾'Œ+f‹pnP‡ Ǽªfźwú<ÂKN™kø›ëkñXØŸÖÉI‡Qt—>š !d%¶ª–¤øjá)f™¤lé|YÄȬë ë\%¡oÛ’,RÀ¯í5ªZ[•V6I¼ šž-¡ZМox¼MÐô„ U‚¦•ì~ŒîÙì3cOXÙ8aÎÝN Àع1´¯mOX€Û}V‚Â};íþÇ>õ¾öÄ×bùÝ÷‘û°ÿ±ý)óÇ5nàµ.µÌæPÓS»«þŸúcŠß }øí}÷û÷e8.)mr±î>OǯTLmÙÏ]œ3NÙè®ÐdHÛó<)C¼:uo›áZ•_-8Å,“”-G6Å7b87¤¥žWñÏÄÄe„¤Ô=³úã+·Vbîßç4˜xJu|tY°ÚÿV‹…gÒ÷ëîÇèžÍ>S1¡—H*û¼“IPíßþGÛ5é´ |WµY>L­Î¦QüN¨lÉÂo9Œ”(¹òL‡¾' Ujë:ÚÊV%í2,FkU2Z’²adV2"ÙñÂg…”˜dÇWÜ£ ™®¸¶ÂT#ÊèžËIÖ…!E…sнJ ß½Êš!Ïtè{²EÐD;ƆR"ûõ=[µ»j-IY+^'lÒ;‰Ã8öûcèX×~Œ¦»hih)©g ŸÄÜ7OB®Z qþj?½ ¶kM<Ãø8ÐÕ¥Nðw8·hk£µ‚´ì£!øÑ‰úŸo>r˜  poÚêâê¿n¢|í®Z 2õõæ\^-jZÙúèd}ÏV²V9ç€˾Q9ÐæË†Å³‹˜{dN÷ejo¯Mèé2õ½Jf¯€©`—dy”J0ÌŠï 8<×)¦ç¦á:åBס.Mzàð@É=ÓÜ7O"ÔÐ¥º¡†6Ì}ó¤¹ ººG°ôxÔ4!…²QŽXÏ À –ô®ãºú¯Óõ2ÒÓ÷dé{®Œö’Ïúo…6_Vß—¨áH:›ü’Ø«Ym@³6_L¬øž0½Ä…¡$E W­ÄÈO+Ú!W]c.ƒ©©ôiBòi£^íD}Y'6ÔÕ#I}KtÍ?!¥_ÿǼ¾¡°AÚì÷*•½šv1kóÅÄŠï ëX×Ѧ/ˆ6Ž:‡& IQˆóç9}!‡ οf.‡#}š<²¹1Õ!!IËñ Q«>µÆ®9ãII£Ô ?*¦½†,½qµ˜`¯ú¿¡im:Yeå„:u ëׯ/Ë îÜíD÷Æn8êèÞØ ÷=nM:A’¢¨ýô&ؽãÓ°{ÇQûéMæ2p»¦&@Ô­Û bÌñãÇñ•¯|ßúÖ·àñx4û¼^/vïÞÍBZ&ñâš$ï×øáš¿¹žÃ‡¥È÷¾÷=ô÷÷ã_þå_ÿöoÿ†7býúõøâ¿¸bË%ß*†ß—Ûk—<‡Èœ°¬òK2Üo6Ø¥”§ d4¹¸¸ˆsçΕeO&q‘V’¢<ëk[Pÿщøo3ŸA[pñ"Hæ cçθîºëàóùðÅ/~>ú(º"óéŽ9‚dz°Ì:·~mÚ§i¸7‘JWLR««˜yàðw÷wøã?þcüíßþ-&&&pÿý÷cïÞ½‡Ãøú×¿Ž«¯¾ù—¹âÊ&Ú|ÙPqm*þֺȀTÃýf‚]JyÊ€€FI8ùA&$-_úÒ—pÏ=÷àïÿþï¡( :„]»vá±ÇÇ>ô! ÆýêdûhôãÆà7Þ%ݰF ˜ .¥¯°kמ¼¡N›ßä"ÐRÄh}/:_qèíÀþ3ÅmF€ï|ç;øîw¿‹Ûo¿/¼ð:::ðíowÞy'`Íš5øçþçé„‘òÆßøÆ7°eË–”Ë7øýþ‚Ý ^BB/¡ßÿùÞÏã#ßþˆF!¿íê¶eçŸorj› Yq{ lÿûªkNvt¨Šú-ižyrRUäUä¤Ãßrb”÷¬?Ýèr¥ÈË/¿Œ‡~€ºlÇþýû±fÍÜzë­øáˆŽŽŽ¬òO¶1 .… ˪,»^´Ãž ‚pØq¥‚çünªSppŒ{/ÆÒ¾ðŒ_€º"%¬ ×óÕ2²À±­#³ º^T0R×ÙsM+è?©]ð˜$'ZÏrQçÎ;‡÷½O]µý]ïzDQÄ{ÞóžØþmÛ¶v䘯] |êU ¨’<ØÆçÏÓ6«Â ~þNà†·dþÑKfn £î‰Ôrå,/a™vÝu×aïÞ½ø‹¿ø‹¤½øâ‹¸ñÆ rƒQ 9,Ç$#⇠õûŸ:ýTln߃®C]ióòÏ7zõn+Ö‹JV@´#TQ¹úèZ“.—ê!¥SØXZ›ÒåR%+¢kSº\jó%]U IDATþ«¶¤¼gýéF—+E*++1;;«ùÛm·Ý›Í†üãøú׿žUþå¼±OÃ.u>¢êÒb:¤àîsƒjr xípwôà)àŽú^(‘Œx~V»€±~cOP‰åŸlÁc’ýÄVPSSƒ¹¹%YææfÔÕi»4ã—z!i1ÇUé@ÝÞùJœ#­wÔ9]‚€)ð—x>hâ›|Z»¶ë''Âx4ÍÚ©Fk©æâ›WrNØ7ÞˆçŸ>¥&E)È ê%$ô’úý2´-Ú)ÿTVùç›\„Ú&HV4·© nÇ žùØ1íñSSª†X$-W­M{ÏúÓÇÆÊ϶lÙ·ÛÐXùØÇ>†p8Œþþþ¬ò/Õˆ'»^1æÐ^§à{×ɆCMÏžPt «ìÀƒkw¦ÌãÆ—Dü«ÄzÂn¼R»€±~ãF ˜ ¥^ð˜¤î K¶±lذ'NœÀÆçÏŸ×ì?}ú4Ö­[Ç!¦2餌6rÓ&;ô’¿miå$ÊY^Â2'ìë_ÿºf¨CÏæÍ›‡ rƒë:b=UÉ$#ôûm‚-ÖŽ:GVùç›õn BmÅùsUÔ«Ž˜‚xqEÕ#Eu‘ï´…Ô±Ô•%Š@cãRO˜(ªù×4¦¼gýéííågHwß}7ž~úé¤ûn»í6Àw¿ûݬzÚJqâ=§€‘Yõe=2+`ÏÙ '»·Ä§ø£jõÜTyšo€Á¦]ÀøÈ& ÿd£Ó‹è\%áÐÛmØ&õ‚Ç$=úˆ­àk_ûjkSG´½öÚkøÔ§>ÅÂχ´Ô–%Ò¬(XŽ6x2ü&ëÖv}·Ö¬µª_;Õh-Õ\|óJ ¼õ­oÅÚµk122’òÀï|ç;¹A½„„^2B¿xï0šêš @@S]Ü÷¸³Ê?ßä"Ô6A²âîëînUÿ«»[¤•¶œÚãÝnMºöÓ›ÒÞ³þt§³ü éÏÿüÏqÿý÷§´¡Ûn» ÿøÇWÜa9B“muÀÅ÷áíêöÔåôyè£'OèÒ-Àà;d<ì{ƒïÑV§F›yÞ§n9)¿ð¼÷½ïÅ–-[RÚÏ_ÿõ_Ãn·³ 2À½h’Tÿ§I¾½: P·ß[«ÀV (êöçï4ùMÖIfüàf[Z9‰r–—°%ŽŠŠ eß¾}ÊÂÂBìoo¾ù¦ò§ú§Jcc£b—.]R(—.]RHf,..*?ùÉO”ÅÅE†e˜«:HÒò¡ãŠ"ºnuû¡ãÆç¼± ·ê—ê¶ë…ôydr Úí‡ß ~ŠÑ~4}ðO?ý4ÑÞÞŽ—_~?ûÙÏÐÖÖ¿ßãdz‰Aˆ´¡ô­æL„&õkåéó(61KBû!$S4ý»7ß|3^xá|êSŸÂ7Þˆp8Œ¯|å+Ø¿?A(Ê0+a±ç–=øøw?Ž „$JÞ;Œí´½¼e“¡““ðýpꀠõ·UÁ¾iéøðs'1÷à+ßòNˆo¾„Ú»¯‡í¦M´¦µ¡\²¡Éß\Ò?¾è¦·Y{ Bû)Û×½NBB¯ƒ§ßÿùVà#'—$-Ü›Õ)©Xé’V“Pr¿ûÝï066†5kÖÀn·ãôéÓ–‡#[ITbbzn:&1‘nÿ­Þ›¸”ƒè¹¿§üå¨FÄôô’FDT¬^ñ,Õ«é8æ|¡Ö÷B©Y…Pë{1÷à+´¤¶¡¢kêÞJ"ßï´ÚOæ¯{]OòÀéôû{N¨ù¨Û.ƒǨ¤„Pb’Ä"'ì«_ý*¶nÝŠîînŒcll /¼ðn¸á<óÌ3Eùf%,h¥6â#)˳R&„’¶Y$¿å‰’¤dm¨Øuj8a…eBû¡ýdüº7†ÑïêìËHâb¥KJäÔ ûÆ7¾Ÿüä'øæ7¿‰ªª*¼ãïÀ±cÇðáÛ·o/ÊèX×Ñ&FZÌÉ%,â÷ ºP\I”ÊÿWîèPµ!€Ì4"‚þ%0EQÓñ=o¾È‘õ¨ä)Y*6nnPCßu»¹è=8~¥n'YF´’òu¯³Ÿö†ôû%Ý(¯Ãà“(®—-V ¤DN°—^z ½½½Z'E’pß}÷axx¸(À¬„ÅîþQÌñŠÎ +{LjDÔßV}€‚>5GíÝ×Ã~þ׿¦`?ÿkUò‚”¬ ]uÕM´Ò¯ÚIm?F,Ã7h%-Ü›Óç¿â%%,F31¿©©)åïÿû‹òZZÒ.3”lÿâ·WXSº¥ÅÔ:AöM-hür¬]”è¹ß´ õßNÄ;­¨Äm¨èª«n¢½ãWæµÆí‡ö“ùþ‹ïÍ<[mE-+”k8啲l&s?T¨>¹Ã“„:a9z©{'Ñû@/Ÿs ÷^Œ_פ'½“¦ò¿0Žæ½Í°í±¡yo3Žþù}„^Ÿ £ûÉV¨Ûo†Óš aæÐ f¾<ƒ™C3M†ö‡x4€­/oEàÑÏ.&cŠ£GŠ uÒ}EÂÿ‚ïfÍÂ÷ˆO•¨ØçÆìÎÀ·Ïðs'Þ^u8³·W•¼H[(“ÚãÇÇÍŸÛ숅EbY‡' 6Ë?ÜÏFK1#(yX™{aaA³6etñaÇ“°øðÎÚ‰‘Ó#±µ«1˜‰¥wlØÁÿ1˜ñµWï_ Ïœ'––lÂ[–ÿΗÅȺvêbÀ;®T0øŽ¥h‘¾§w¥² @T\V0+¦>Þÿ ¿vÁÓj@¼J„|V^Z‹KÖS÷ÙºŒïÙ^[ ƒ±å¾üŸ| ¡ë>¸”ÿ‚kbkMÚÏÿuGn… ËPDÊŽS—‘¸s'„‘‘Øñѵ&3=?¡ŒwŠ ËDQ‰[ºRMïØ¡`pÐ8BG¿qSS.]ºTÔ `§ÂëõâŠ+®(øý;~¥:C±´]]¨Ø® 144„¾¾¾¢^k³˜‰/Ã@ Põ¯Ôí'½'´k3v¯2§ƒ§?¿Qf‚ËÏö“[ûÉËb\Äþ><<ŒššÍßF_ÕHJÄ;PrXÆè«£ÊøÚñç@0Ôä—mþ£õ½mªž £Ó‹z2¶ÿùš#rrdÅz%Z’ìømmšN% `þÜ<$%Rñ@Q”„cÌÜ󮈆ˆÏ%¯~—&äX•¨ˆt’F$(„ˆÄ… ËXÅ“i®×;:ŠŠ¸ãgézœŸPÆ£½åHË<ž¥geYÀ訶 p¹\Ô²ýb¾í åyMBòÅrÖ[MwþTpéõÎ9•ÅG^œ°{ï½ûöíKè ëééIh…tžéLÛÖy]'úúú2¾v“»ÉTO˜Ùü;_12«Äz¶:WIèÛ¶tþOÉpÛ]ORïUÛ&T ¨ºªJÓ&‚¦'L¨LÝ3$ J\O˜8ñ‚¶'lѯé /ŽCÅXO–Ô™¾ŒÄÎN(ºž0%®'Ìèü„2î12¢èz–ÒRFùé{ÂHö87¨Ãc^ÕÊÇ’A…¸&!¥Ò°ÑŸ¯ï c£¥¸ÈËœ°ÊÊJ444hþ©¾€”ðïÈG4’îýnMúÈG’ž—êŸ{¿MuM  ©® Ãû†-ÍÿÈ&ºW ‘ù*Žl²iöÿàf] 2VÃèZñów"íñõwÔÕ‘‚«êï¨GÝŸÕA¼VDP B¼VDííµ Ç˜¹gaxB¤KY$Ô~â­ÚUïo«‚Ý;!0 »wµw_!"q!twÃv$}ÙŽÑ/¸Ý¦ÎO(ã#6tw … n· I9bË8¯øzG²'iåyŸº_¥œ®IH>6Ù¬…ª?ß½™k«3y™¦§˜Ç㋎É[[†œÓ²<ôëÎÝ·Ø&õ:u´Úí‡ßRà9a„ò  )CÝvù–†:¢‘Š\L›B2£èuÂô’f%$ ~ÿ„ ë%*B“!­¤„.>«ÕtŸÔî÷‡òO·ßò2™¤ÄD©’lÒ/…T Yþ7áè ÐükÀvTÝŽû­Í_ÿ1ûMš\TUî¨ïÅΗEJ\XLÑ÷„ €ë” rX†ë” ‡Ò*ä—cÏÁÜãsÏÊ òY¾‡}À< Á7¡MÏ=wõ.—ºX·Ë…¹ožDhÕ–¥ýÏiçŸCèL(å~ËËdˆ»= ˜ô'„“~I)’L& P‡ˆ‚Á`^ï¥ÿä’¬‘kZÁSÓ€zý~Ëˤc©'Lövf©lÝ9Î#ÅŽ™¤\£—5² @0ö2WÐ$ÁœäAþz$ýþF ˜ e~¼~?ÉŒTIEï„9w;1pxcçÆÐ¾¶ÎÝÎ×sP»«þŸú1nUk«P³£§'dˆ«ET°Z“®ýÄ&àT·ÚÅÔÞŽÚOoÂÜ3ö¥ýºUïkwÕªCž)ö[^&Nu2r{p:i „ÜQYY‰ÊÊÊ„¿B®æÈ¦øo‚€Ï·9©Ž’8$îÍÈêžôù;7$[ÊýÚoRòãûO†1:½ˆÎURDV‰ËN/I’ …JÇ kih)©9`¹è9°ÕÙPýÑj¸‡Üèëëƒ]²'ÌÙÒ¦ë5“¬lê¯MŸ.ç€%”I ç€BV&ɾ ß›Ûü³ù&µTƒï14ô$ú¶õѳ–&!Ä2²]|˜BVÔ Ë1aX3Ôç}5^ž·Ûpc( ç;†_4C¶ºô¾ñë3a|òÙpÊ<†'¯?[ïû©)Àá@ø‰_`î•ÖŒ¯©†LîÑÔ‡{Rž˜ºa„’ö„嘨üƒP:Bÿsa¸+EÌØmpWŠè.¬Ù?÷øœažŸ|6}¾‡}Ú<|ðxE<Ì=øŠ©kêŸ!“{4õáP'êOO/IVXy<ÉÙ.>L!tˆeèå~[c‡ ¼Pc7-ñ¼Ý–6 Í³¹M{Ooy§©kæZ¬d%.Š—Ž5ê n!„Ð +0âjQ<x÷åÄÈr¢¢à]—Cšý™ÈCÜ §ÍÕÐæyq\{Oo¾dêšúg°Z¢£C•ª2“¬0{<ÉÙ.>L!tˆeÔ}½Bµûz;ŽÜdCׂŒUÁ0ºd¹É¦ÙŸ‰<ÄnNŸGýõÚ<ï¾hjRùššP{÷õ¦®©«%,œN »[]ƨ»ÛX²Âìñ$D#¯<ïS·Å¸˜7!„ œ˜Ÿk/W'ÿPÀuµÎ6)qU£ ®ÙÒæ¡•œØ\¼¨ñ¼ëoZþ3Xþá6)YA‰ B!eá#°!„Bè„Ùêÿâ¹®0lnW/žK\¸5ì#ðh[_ÞŠÀ£„ýá´× ûÃð=âÃì¡Yøñ!|vèíUÇïz{UB!„Ð +f¢ºGÓ¡%Ý#+Ïÿà+6LÛ(‚€i»€¾’ø“Ì=>ù¬ I– Ÿ•ÍKJ|ó$5!„"ƒs ÈV÷Èèü»[Á‚€™$¿ˆY‰ˆ„ã«®¡¦!„Rd°'Ì€luŒÎo )ªˆ*(ŠšÖaV""áøùרé@!„Ð +-²Õ=2:ÿ©ëÃXR ( V…5 !$/ß$ï$zè…ãsô>ЋI/ß·+‰¼ G.,,`aa!–özÕÀ`0ˆ`0˜×î?)bdV€ ®iý' ¾CÎx¿Ùü»¼ÀL±ô''dMÈr(”ÌËìÂ,þñÅÄ«³¯âº+¯Ãg¶|WV^™òøJqïzë?¢±úU̮à o| ò•ESŽ™H¼ã2,5‰—b’I2bôÕQdÅè«£¦$†h?¥e?+Î ëhXê ´[¬á–z¢iB²¥P2/;ÿi'ŽO‡–q|ê8~xá‡i[åâÄNã ã-uÇÑóÎB^]x¡_3/ĸ KM⥘d’Œè<Óë m":¯+¼Dí'wö³âœ0ç†x 5m%îÍêäTPuÀÜ›YùHöJæeìܘ¦UþÜkÏ¥¿Þ¢}Íd‹Ï•¼I!dqÊR”x)&™$#ŽÜy$A²¢Xî‘öc½ýP¢ÂbÚê8Œ”¦…$«;€9b}ÍUž$ÄÔ7Š’+ JTBRâÜíD÷Æn8êèÞØm,$y•¨íD‡º½ÊÉB$„”\Oؤw‡pì÷Çб®ÎÝN´4´,?¿Euxò˜W/æÜ ö–K~Ë!ìcîñ9­*ým’‡V¹½he+žå~Óþ‹Ï£iú#@x °9€kÜ@U[ê æŽç{H@ë0P»=õñ¡Iàõ pLí¹¾Ê©Ú-)%÷eŽ®8?=7[q>«ü"’Ó¡%ÉŠbÊo9Ì=>‡Ð™”€‚ЙæŸcM'yû ˜Ö8š^iNÛÔíüxúãC“Àù^à‡º QG‰”.úošýBöPÔík]é3ˆ9`P·ç{Òÿú€:e <­n_à@',s¬^qÞjÉŠ\K`d‚†»ÒŽÉw¥Ÿ|VëdQ’‚,}4#Íü”á½Ãhªk‚MuM¸¼xY3üí5‹²q•6{p\ùx¾'1²‘Ñ‘¤Dí¥ëP—a4°Qİ~ÿÄ©lqx°ªJÁ‡¿ﲸUOû)&8Yé ú‰Âé ä ) ú!ŽþîhÚý‡u8a… ý1?þí5ó4ïwÝaû÷õ¡ÿ…§†+0õ‚€§†+pìôad…ÇsT;grî¨VâÅûcJ¾”ì #¤ŒqÔ9Ô¹\ô=SïYÿÍPHï½±ž0Ñ&bëú­ C%Ûÿh{ìÿ8ôýÝQ(P @@ûºvüüžŸ§<>)ÕK=a[#žYJWwD^ˆ gv¨s\ì-üñIÖèW„蹿‹ß^L¹ÿÎ#wÆöEW˜¸¸¤9æÖo…Íf‹õ6?ùò“šknîÃ-kÔÈÈ[Ö1{ùN\éPÓõÌ]è*ÈõÏ=…XÔqØLÜŠXXrTò%²¾'úõWæö„RƸïq›ê™ZÎÚ¬ÑáÈtÃ’iÑO¾Æmnâ0uHŽÐ¯a”Ö3åŸJ8Fß­§ý­ÐHT8ªµé†Š ´=ÇÁ‹Ô@É—¢†=a„”1mW·it¾€ô=Sf×f=þ‡ãšô‰ 'Ìßd²‰ÂfZâüˆ!‰RœÈtûõ8êšž0 ÄzÂD›˜àˆ½ìX«:\Á00;\Yµ”ž J¸2Ú1Ò—:>›Áô~}O4%+ò {Â)#ŒtÁ¬ÆH)/P÷ˆäˆá½Ã1ÇK% ïN»ÿûýß×ô<»ïq'󣻤émþ‡þƒ&Ï“Ê~<ý žËÀÓp¶æûÉŠÐÕÃÚžâÖa­ÄËêiÓ×H\P²¢ °'Œ2"ª o2pxÀTÏ–Yœ»8<€±sch_ÛžÑð¥å\åT‡ çÇTŒbÛÿh»fX&ûw¿owÂqúc>üîkÒ{»÷êÎøÿŒ&7¨y.õim×®ŸóÕða^%+è„B,Áh‰«1;|™›·?"„ÒdÅGN.½'ǯÔíä"+)]ÌWìŸ IDATæ{ø’¢þäÀôyþø·?N+{‘%$Êš¼ô„-,,`aa!–öz½€`0ˆ`0XÐè?)bdV€ ®iý' ¾£øÀŽ–S¡Ë«”‰/Ãr-G³Ãƒù¾$¤˜É…=èóü?/ÿŸX$q2Ù‹(!A',[<ˆ$ü}xx555-€Ñú^ȶ € £Ó‹z²h0—ËÅZkA^¾|¹,ŸÍìð`¾‡/ )fraú<‡2Œþ¥–5÷Þ{/öíÛK{½^´¶¶¢§§ -€Î—EŒÌ*!@„‚ÎUú¶õÝ ár¹ÐÝÝ I’Xs³,Ã@ À:|/ÎZèFBÊØôyê—úÒË^$@ :aÙRYY‰ÊÊÊ„¿K’Tp‡âÈ&`à40æÚ87 dÅPf¥Ž$I…B,It#!elú<÷ܲÿîÇ”ƒIe/`ô/°r¦¥xâV²Bë1D7RÆö,Ï´sÀ¾ÒŒþ-g(ÖJ!„B'ŒB!de@±VB!eM1Ë$•”H²¶ ã˱ N˜¢(C ™ý€—/_†×ëåÄ| Ê0­‹¥mˆöCûÉœT2I?ùÉO .“TJüô§?e!XP†Q‰$EQ (°¢?üáhmmå¯A Îùóç±fÍš’»oÚ¡ýd޾'ìÂ… Ø´i@Rpû)ˆ‡111úúz‚À_"¢ÚjçÏŸ/¸¶Z9”a}}=|>V¯^ ›­ô¦FÒ†h?´Úí§ôí§ Ã‘6›­${І†EexÅW”ì3Іh?´Úí§ôí‡Ñ‘„B!…h°!„Bòø¥/}éK,†ù±DÛ·o‡ÝNe–!áoÏ2$üíK½ 21ŸB!d¥ÃáHB!„:a„B!tÂ!„B0B!„:a„B!„N!„B0B!„B'ŒB!„N!„B¡VÚüâ¿À7Þˆªª*¬_¿ßþö·Y(„І¡ýÐ #¹äìÙ³èëëömÛð /à _ø>ó™ÏàßÿýßY8„І¡ý”\À»H¹xñ"Þö¶·aqqÛ¶m<ûì³X¿~=n¾ùf<öØcxã7ðŸÿùŸhnnÆ»ßýn\¸pÿñÿ»îº‹HhC´!Bh?ÅŽBŠ–ŸýìgŠ$IÊØØ˜âóù”·¿ýíÊg?ûYEQeÛ¶mÊg>óÍñ?þñ»Ý®,..²ð¡ Bû)rìtC‹—¾¾>ìÙ³ŸøÄ'ÐÞÞŽªª*|õ«_¼ñÆhiiÑßÒÒ‚P(ǃ«®ºŠHhC´!Bh?E ç„9‡B(£>Šý×EUUUlŸ ú^ͤ'„6D"„öC'Œ˜äÌ™3˜˜˜@8ƹsçbë[ߊ7ÞxCsì›o¾ »Ý‡ÃÁ‚#„6Dí§Èápd³¸¸ˆO|âøØÇ>† 6àÎ;ïÄK/½„––lݺƒƒƒšã‡‡‡qÓM7A’$!´!Bh?ŧÅ/÷Üs²nÝ:åÒ¥KŠ,ËÊ-·Ü¢üÉŸü‰¢(ŠræÌ¥¦¦FÙ»w¯ròäIåûßÿ¾"I’ò£ýˆGmˆÚO @'¬Hq»ÝŠÝnW~ùË_ÆþvîÜ9åŠ+®P¾õ­o)Š¢(GUÞõ®w)ʺuë”|GmˆÚO‰ (Jd&!„BÉœ˜O!„B'ŒB!„N!„B¡F!„B'ŒB!„Ð #„B¡F!„Bè„B!„Ð #„B!tÂ!„Bè„B!„Ð #„B!tÂ!„Bè„B!„:a„B!tÂ!„B0B!„:a„B!„N!„B0B!„•„½ ‡Ã˜˜˜@}}=Aà¯@òŽ¢(ðù|X½z5l¶Òk‹Ð†í‡öCJß~ â„MLL µµ•¿)8çÏŸÇš5kJî¾iC„öCû!¥o?qÂêëëc7ÐÐа? bxx===$©ìˆ•ö¼ÅðÌ^¯­­­±ºXj¤³!Ö'>3í'»ok>w¾ì§ NX´û·¡¡!¥VSSƒ†††ã„­¤ç-¦g.Õ¡ˆt6ÄúÄg¦ýd÷ âoÍçÎW=äÄ|B!„@'ŒB!„N!„B0`rèíu;9É2!¤,š››MÝŽóAH9Ä#û&7 ·y ŽUá¼Û¬¿Pz— eu;0<ñË…ä—……,,,ÄÒ^¯€:q5 jަõ/g¬xf{Wàñ@ x<@WB¦óéï12"@–¸\ úû ÊEùÌÙ^»í§\ë÷Jµk±¿ÂÈY†ârAéï‡<8¨Ù7 Â…-aË©Í&³:a;¦:`€ºc™üsðàA8p áïÃÃè©©IzŽËåZqå”Í3ïŠ8`bŽØÐÐé|FG{!Ë‘w†€ÑÑE =Y”ϼ\._¾\ööSnõ{¥Úuïè(*"qA–±8:Š'#vÝw í!åÍfãí‡N˜K=a¢´·³LHþ¹÷Þ{±oß>MK¾µµ===I%*\.º»»W”\CÖÏÜÔ%ÚI÷õõ™Î¦³SÄȈY Š :;¥eå“—g^&Ñž¤r´Ÿ²­ß+Ô®ÅÎN(Ñž0Q„ÔÙ³Çè¾y .ì€ )§6›Ì~è„àtªCccªæt²LHþ©¬¬DeeeÂß%IJùrJ·¯\Éê™Ýn « ˜š‚àpn÷²ò:r$þ!Àé I¶â|æ,®YîöSvõ{¥ÚuœA ííœNØ¢yEö9ŸÝ‡ñ ߈ö[^l–NX†´´p!+‚¶6àâE¾3Y)ñȾ…2YFGZÌJŒŒb4!„B'¬àD£)§§—¢)ùÌ„dN؆ïfÍÂ÷ˆa¸°­¶2)ì;aÎä;Á"¹:a%ÈJŒ¦d)±’¹Çç:‚P:ÂÜãs…m°•AHAYøÙ‚¹wBDnŠ¢n»ºè„­::Ô(J ³hÊÉI`çNwÜÑ‹;Å’ld›}fBÒ!OÈ‘ðDJ$]ÈÖ[„”Ö;aj*}šNXùâtÝÝêÈEw·q4åÀ02"Àç«ÀȈP’l³ÏLH:ÄÕ"â»ÄÕba[leRZï‡#}ºˆ`t¤Å˜ŒRÙB¤‘-”d#›Ñ`ÄJjwÕbîñ9È2ÄÕ"jwÕ.¿u`…¾ uj)(•R‰Å¡ÅÌß qr3ˆÈÍÐ #)Ù.×’°c{»ÀB!+[ õ·×O뀭 B ûN¨5ùN°Hn&/ÏÆŸ·°8ÀŽ êë°c‡ÂF6!„²RLAaiie<üð“”ÑÒÂ2!åC>Ô&Ç/bçê±ûÿ{v®~“ãÓ_üèQ ¢u{ôhá‚blƒªäĪUÀ> þ‹ÿ[2ûÔÛïøx‚=[mâfò£FJâCKJ“|¨; tý#ž-˜†#ž-èú}ú‹÷ôÁ úÿ`PMú!!)ïºKµ½ÙYUrbfFm<¹ÝÚ¿%³O½ývu%سÕ&n&?:a¤$>´¤4ɇºÃ±©·A†º› cSëÓ_<ê€Eѧ ñ„”ccK6EQLfŸzûšJ°g«MÜL~tÂòD9÷ñER‘u‡ÇA„êH‰¢Ýq&ýÅõ - L‰ B ŠÒÞ¾dƒ1Ï,I[2ûÔۯÑ`ÏV›¸™üè„å‰rî-â7Ф"rN÷:ìhzLaGÓ‹pº×¥¿øðð’ã%IjºÐAI‰ü½ï©¶×Ø45©ó¿¶oW‡ãÿ–Ì>õöëv'سÕ&n&?JTä‰rî-¢ŒIE>ÔZÚš18q%†††Ð××)ê`¥ºøöíÀâbq=!$76˜ì\]ºÖš¸™Û¥–'T=0Õ+·Þ"~£!„óp82OpDƒ 1;rrâÎè½ãˆ;w–Ü„KF’£Ê‘¡e›-°<í-òxÔ-õÀIÙ ”FFPáóA)¹ —Œ.&$F•#CË6[:a…oÄcçNwÜÑ‹;Å¢h³eN ŠÙ ”ÇŽAˆ/”à„KF’£Ê‘¡e›-°Â7â12"Àç«ÀȈP­`¶ÌIA1nÛÑ%r¼R‚.]LHŒ*G†–m¶t ߈‡, ‘ã…¢h³eN ŠÙ ”N'”;°P_eÇŽ’›pÉù¢„äÁ¨rdhÙfËèÈ8àf¢ ÕãȲQTÐÞ.^crRí:vL=ßéŒÌ1K¹#·Ï@ˆ¥˜ ·mi<8ˆ'#6#ñÕ\BÈ2*†–­ýæÅ [XXÀÂÂB,íõzÁ`Á$K†Dÿ4ZN¤yè!à®»D<÷œ€›nRðÐCrÚUQzؽۆßü&„÷¼Çއ ®¢Òß/bdD€, p¹ô÷+”!ö÷C ËP\.(ýýsþ ˡпq)Ö-B!åE^œ°ƒâÀ FMMMÊó\.WIêÝw/ýÿùçÿ›¿Qÿezüèh/d¹€:„9:ºˆ¡¡'Ñ;:ŠŠ¸ Ê‹££xrh(/ϰ\ õ_¾|™Ö_¬˜ìÑÔŠ ¤ÄßB’À¶ø¿‰¢ú·Àέz]Ð ‹R(q¬@Q?]€Læ*ñcAÊ“1ßÎáÕè–ž†tGæ„-'jERâï‹íÛ®.uȱ© XµjéoQ»v»-±s«^”¨ˆR¨¡ˆPQ?]ˆ¤3úõ#ÃŽhoçÇ‚”&c¾[¶oÄãsoOœ;² © jERÞï –Ø¹U¯ ö„E)Tï’áí s82?W?þ=>476›ºçïJ!„)t¢j(ÂíššT¬©IM‘jè´«K¦(ê¶«‹¿+É a¾G|˜=4 ß#>„ýáeç5y6 ÷>Î|aî}>Lž5ÈkrâÎè½ãˆ;wf¶`k-ŽÊµZ Iò.¹oþoø±u|+Ï"¼ëcê0cs³:̘GcIg£ÙÚ/‡#£j(¢­ ¡‰ sáÇ©†N§¦´ÇéÓ¤d1#x\!ÜÀOÏÊ€„΄àÿ©Õ­^V^'¿9¶†ì"P_Âø7ç°êkU)ŠWÈ2”‘„ DŠ­5¶ŠTâËFRð¸ÔÄŽÍ †¥,`žÍ»$Hÿ cîÊ ~öQ(P§îäÓvÓÙèrì7þw¤–W>÷øä âjµ»ja«KÓ8>®ö@MM©®±Û ´µY+™j]!‡Cí‹Ú¤eɳÁã| án=·’i@(Àü¹y¸‡ÜËÊëU·À™`k*CJ#:lV¤ØJQc+H%¾œ)…<.5±ãå †¥*`¾ìwIA„¼Z]Í¡Î£í¦³ÑåØo¼ýäE¬U‘P^1 Óùñ!t&„¨ûm_oGýíõ©OhnÖ:BMMÀÅÿ×Þ¹GÇQÜùþÛÝ3’õ4²$ Œ_%ÈF± ŽElðbåÌ5ËædI€yÍú,äÄaaïÎ= w xœÜ„8r|Ö^ØlDY‰HJä…ÄYlð v× {1½fô°43Ý÷žW¦z¦G­y~?ç€\5=Õ]Õõ«ùUýê÷«~ÓÈn1ëk .¨TEn̯©+€„2Ýï8Û‚5Z xœŽ@¸¯DÌ^%@¹BIz%ì·ÿ;¼æó=nn4[ ³¤8Ó‚oÙžI+І_ KWÀãl vl5`x&®„åKsÃXDóÃñ_P¶÷OÃ+a)”]3MF~#å‡+aqðŸè Z m†È$hgàH‘é´®NWø¬”E²‚d§2®òÇÊôcgr[N—SAÏßañ?Î^T°ü›%pš•µgÔæfL<çºu÷ì1RœaA#kÖHhi‘Ìë›Æ÷yÏ\—ŸL$˜‡Æ’ýÐ$ ÞI/æ\&¡äí** )  ªêëS&»f2šŒüF¾C*añ:Äۦ,PÌ¿ 2 ŠLˆ==p44à6—+¼1¿®N?ëÀ}“½$+V$_ ѽ ± ¹T6_!¶@Í2j¾¯—õ™„¾Pk+^¬¬Æ”3,#c{,‰´˜ÈÛ_ÎH©üÒ;2%·•Àq¥R‘Ç•”ÜVbþ…€·#$Éèí(ò¾ x4JÀtÆ ¥x¦c¡$„B2®„Ù=ÙEêòÀ€1XkÐ|yü¸ñº'8Õ&‹Uß{}ðì¿8Kï(ÊîœÇrÝY„~$„uTÅÄkXÛ»ãƒãP]*p@P¶µ  Ø6P¤sÌáJXºk]¹ÒxÝLÌ‘ DDf™±_ŒÁwÆmBƒïŒc¿3½^WÀÊIœez:@ºN#„dÖ˜âÿÐ§ß õ Lž½[ŠtŽ9TÂÒY°ÖàÁ£±%Í–FòË,ÎRcÿv–†>¢ !Ä0¦D3aï@‘Î1‡JXº kýÅ«¯Âwþ¼nÎtsdäž°™˜#ù«Ffe‚H»z\僧{GCñ|zBˆaL‰¦ÈÞ"c•°d™mŸY¯°zoþª‘YƪKÙs¯ÐTÀëÑÓèGB)¹­Ê ¼ŠòB˜VÀʶ–Ù:P¤sÌáÆüd šøüþ°‰ÏÎÍï--Ó²&{o³²±c6gÑű¼L­§ !D.•QtGºÛºA½í(Ò9æP K»L|¢8af½Âê½ù«F!„dž²É&H»L|fqÂfûÞ„Ø…E¹:ªÂ³Ïƒáç†áÙç:ªÆý¬¯§MÕ‡Q)¢©ú0úzôP0SGú0úÔþðøzŒ>5„©#}¦ÏÔ÷¡Šî=8óè0ºô ïC•ï42õᆾ3„¡¿ÂГCzVÿ÷è®QOCÑ‹¨®d((æÎ Ë~ŒñÀlØJUP*aÉb—Y',÷&Ä.,zàš…´}¶­á#tºVaP›‡N×*lkøH¿¾U$‡îe)9ô´É3½÷÷c¨+÷¡¢HC]¹ïýýß!idlßÔ«4SO+άÀä¿M&'°¨¡;ûx·;,û1Ƴa+UAhŽLVs¯ÀØû€uº*[2^‚¾>ŸÃdá r5âfV~c7ý ü ¯ƒò?GPòïÿG׌‰—ú³× ‰E¹YH Ñg‡>?ô}!~8qxàÊÀìÅÎÅaúLKæøá,$;`ñ?ß!éÄd1Úéw&'Ö"FPö5mÚxpH[© *À•0;4w5 X@‹÷ìõ˜—óX7|°Zñ<øþ`Æ뎯†3îÉ4,šÈÍBZˆ>«¯üo(ðê×À‹5•gƒ²ÏîBó™>SïE¾Ààêóg/*|„¤MÄ«xSYc° È~ŒñÀlØJÕ®*aviîjXñ20a^ŒßSÈ™»ìÐÓñÔpÆý"™†E¹YH Ñg-ÝKÑXu •Ò«Ž¡¥{©~ý-¬ˆi>=mòLË¿Y‚·ƒzÜ,ÿf ß!i¤ä®’°6"(ü»8qå ÞZ˜XœÈ³›N}OXPöcŒfÃVªvýd½9Òê™u"¬š!G)br¸Ó¯"óû*óøz}†tH †¡ˆ¥¢‹>#$XôÀ5 i!ú¬¦®íýÕÁ)o(¿àºHŸó¢­­ÍèÊ.x¦š+dÔ|_/ÿ3|s„¤‚+ PðXÁ´|¯×‹ñ¶qÈ% †ÀÝ$j<¨xØJUP¬_ ³zf«fDƒæ.Ò‘+ +`e[Í;Žu.C( *:!„Bf¬_ ³|f‹fD‘æî¨q â¡Š„o«~ªÆN›©áŒûE2Œ¾)`Ûià¨/Zjš‚ÔÜ[U1ñÚÖö®ÅÄè”?V’Z '„dΑ/rõ5²|fˆ9qÒ1:H¬¸%fñb¾€ùrÌ´ÕrI'ÛNƒÀ Oÿ»ítêî=ö‹1ø?ôë^Tú“^ '„dΑ/rõJ˜Õ3ë„ Q%›¦cuXfP«æQ)ê„Ò`Ú.3+!©à®Aûv§îÞ¶­†B2fŒÈ¹Îzs¤Õ3ëDhši:Ñbµãø?õÇLó‡…dõåúìÖ@°¦…K\ZÑw¸±˜dvYÔÔÀßÚŠ×ÛÚ°yófÈN§­Ïdë³B™7ˆlÉ%6È`†ž¹œõ¿Ävmšµëì;QÜ/Qþ}•…8PáÄSÆ 'î«,´½ÎÜXL!„dY¿fצY»Î¾C$ÈÇ©À/é ™_’pÄ¡Ø^gn,&"|}>xöz€ E@ÙÖ28j¬ v®¶ŠžIt?ö¡ùm GŠ·àº6ö|Þ‡Ë/wX.‡’<ñäêlÏ$¶ …¬>ÿøá8.«–!A‚ÿÓðwÔ15,·2°ë0><Y’ ×åŠÌf½–Lœ­XˆÎµ²j¦=(µ×nE‚_’ h®óù˜Ç&²z¦ÏÖË~&''199J»Ýú,ÁëõÂëõ® ¦£óc1ºwTì`ðìõ ô[¥–Ÿoâµ ø?Ô•}ßF_EÑEIÕUôL¢{4¿­á@¹~IÂr'šßö¢}¾×r9Ù†•÷<[÷ÎEùá»NŽxrµý *rZáÄ(Æ¿œ [e‚ßñâË­ 8à€zV… Õp]6Êl,ùÉz%¬ä¶a¸ â4Á™Ù”[jueë°[WÀ‚çZÍ”~„Í”í+¬?(ÿ“ø‹b G˸ÖãÃƧ8MŸ_T–Õg"ÙÃÓO?'žxbZ~GGŠ‹‹c~§³³3n¹ë'ÖLåÚ„†¶¶6ËÏ·¶w-œZ`/–\콈î¶î¤ê*z&Ñ=Žo1¬&-v ­­Õr9ÙJ"ïÙnÆÇÇs^~ø®íŽ”EÉiY”úøŽÃ}'ÖuÙ,³‘ò#iš¦¥úÜn7æÎ‹‘‘”——ÇÔÛ›lIn²~nÚD¸jR‘„KºÄr9•¿Õ÷‰…Òýì+»=§]ÏŸÉ3™¾ãÙìƒÙ0“_´h\.×´ç÷z½èììDcccܶݱZEHn%ì•ð, \¡$¿&x&Ñ=šÚÂ+aЦaƒÛ‹öÍ’år²Q†}ϳ!?UUU9)?|×I®„Å‘«¦V-´¦h6 y +aÁïVÂb‘Å2K~r6X«]&˜" I IDAT8‘™Ò*¢ý)VÍ—$?),,Daát§ §Ó)”Í> R¶µlz¿tZ”?V¦›ÏÉíÙ=“è{>ïCóÛ^-vàÚqö|^†Óé°\N¶’È{ž{æºüð]Û;ìþì$¶à Y}þñÃq(K”¸{¼ð¢paáô=aY.³ArV ³Ë'2SZ%Ô©€Ðþ”Ї*Pr[ F_ÅÅÞ‹˜³dN\ó%!vâ¨q â¡Š—cgÑ3‰îqùå´Ï÷¢­­5°²êHªBÈì‹ë ÑULþ‹]NPnÓm1IÉœ¯"Qj Ì÷€%ÌDì´\*£èŽ"t·ubÉü¡ „Bòa"Ì&H«^“Ÿ–Ix`qqØ=÷ì8*|2¤âž·€wŠ·`õ¯ýøéõ*.« »<É D^¾fò#úŽ(ß×çÃèÞQ¬ŸXÑÿŠ‚!*IÍï^¬m8r‰’?¹J†¿ß\„µÔ 8:f,“Ù$ãy’Äjp×oÝPnÊú­ôÍe÷¼¥¢»Ð!§ŒîBîyKeã’œA(ØL~Dßåy RÈÔŸL9„{÷bmÉ”?ÿ¹€*€IØ"“Ù$ã\ K«Á]OÊð¼ný’„·'õÄ;Ù¬U¡^LrQ `3ù}GtX`ê·\!ÄÖß½X²i¿XØ “Ù$ã¡_üãÇãÉ'ŸÄ‹/¾—Ëe¸Èívcûöíì¬,5ꎯþ¾) é„ڢ鄞ô¥Û c¤—åç|*Œ¢i¨ós%,[y饗ÐÜÜŒŸüä'€—_~Ë–-ÕW^‰¿þë¿ÎË6Q(A zùŠäÁì;¢|D{ª%Y¡üSÌä6&1dÓ ±°A&³IÆe@XW__þçƳÏ>‹eË–¡»;mbb{öìaœ®°þâåÚ–Z qžg¬q^ØËR®2vŽè4É^xáìܹ£££xì±Çðï|<ð¾öµ¯áÏþìϰk×.üð‡?Ì»v)¹­Ž+Š$8®t„¼|Eò`öQ~ÙÖ2 Р…ö$S¡üsÌä6AÙ *`e[Ë ò§,R€9ÚH!l‘ɬ’qMÓ´µk×j>ú¨¦iš¦ªªö·û·Zii©ÖÞÞ®iš¦]¸pA“eY³‹‘‘ €622óó©©)íÕW_Õ¦¦¦â–uaRÓ¾x\Óæ½©ÿ½0ižoW9óÞÔ4t‡ÿ«|SϯˆÊŸ÷¦ù}Eåä:VÞñl¯Z¥¶¶Vû§ú'MÓ4íÈ‘#šÃáÐ^zé¥Ðç»wïÖV¯^’çOwÛæcÊ·:ç²üð]³Þ©”œ_ªÁëõC m³“hx½>á}Eåä:é> ÍîûöööâÆõ£®½öZ(Š‚/|á ¡Ïׯ_|SiB(?„„pz4áááaÃwÞy'dYÆW¿úU|ï{ß›ÑM’=·+‘s²–5Á/ë>²~H888…¶¶×…ùv•s§Tˆþ¢kñŸÊ%¸Ê?Œ;ÏE[ï$&Êš¹ ¤ˆMLMšÞWTN¾®³Ðì>û®¸¸ccaœêêj”–ÿñù|Yó^ôÐ)*ÞqÈXíSñÓëeÓÐ)V]×Í®?ñ©Š›ße óT ¿ù°b¾Œ#ïO¡±×!§„ ¯†Î%>\wuú¦ôIÔÁ²&¬;©`Ïró{“Ì#×ä'›ID– ›N^MW"ŠÀX;ÐTÉ^=áÆò!5zâR4hð÷ù 4 Êå ã€U«V¡»»«W¯6|ø•¯|ªª¢¹¹yF7yä‘G ³˜à¹]›6mž™è9YëN*èÖB+Iëæ9±yýfa¾ˆÕï*øw· $hX}‰y9=cÀÙF}ÀÙ‚ùX±æÔ•7F]cœûÀŸz½èì|=Pß[ò¢ã¥û,´àj¬]ÔÖÖâĉX¶làܹs†ÏOŸ>¥K—fÍûÑC§(ðKº ÷¼åGçÅ¥ÕƒîÍ®¿ù]`@–I€ Üü®×-@c¯ƒN=Щ§®Ö¿Û5,Á/ kX‹{o’yäšüd3‰ÈrPw”ñÆånûlþë­‘pè‰^£­!>"Ÿ“;àë_ÿ:ÞxãØ+5wÞ 3Ú™ì¹]‰œ“µgyä±BZj%8²0_„$Gn´— Éæål: ¸}Êå6t¢ÿX¾¯Õúæ骳Ý÷|öÙgQR"ÞüyöìYÜwß}Yó^¬†N±êºnvý`@ÓSÂ`àÖCNcþ3²¬À³BŠï6O2Ž\“Ÿl&Yöjq ‰OS"F÷Žü“?ù<ÿüóèêê*b_ýêW3²Ác…\7êƒË¦¢|ÇG飿å Dm) ¦­Þ—ä7ÜpV­Z%”¡ûï¿Gö„å[íS¡B§(š†ëâ„N±êºnvýÂöíÛ±|ùr?~<'*,²w·ÔFšãÿˆt¯Žë+`•N=MH®ÈÐerİøæt«Ý›]¿b¾ ×-Så×]]€«#ó Beµ^ãG[ÛëØ¼~sÂæBù!ÉÉò† `ê&³+$àç²1­*a×_=Ž=ŠûW¯†ªªxòÉ'ñðÃC’¤œ¨°ÈÞmõG¤®è¿ˆÉ"„òCˆ=L›2¾ÿþû8|ø0.\‡ÃÓ§OÛîΟNV–FͺKÙ ˆ½äº Y¡g¨þ ÐÿööZж€:ªÂ³Ïƒáç†áÙç:j¾­o ØrRÁÖ²&l9©Ê"”bA¹­xS—çyòK¦Íä<YÏy%ì™gžÁÚµkÑØØˆžž>|GÅŠ+ðûßÿ>g*-Eý%Ä.òE†¥á8àòêžÇ.¯žÄÇ{ÀØ/Æà;ãƒ6va7#¢Â# kX2”E(?Ä>‚r;ì×åy(B~cÉ´™œ'#빈Á¹k×.¼úê«hjj\sÍ58tè}ôQlذÁõ>[9>j<óñÄ(‹ØG>ÈD^Äfnðþó~ƒÆsagˆ ÊI ‘r‹(ùÕ0]¦cå¾kQÖsÃJØ»ï¾êüAœN'¾ûÝ£#'*lùx›ˆ·,Krƒ|!+ˆ¼ˆÍäPY –«ã¹°3D凤þ÷QòK¦ãýÞZ•õœWªªª„ÞtÓM9Qa«®ôvoY–äù CVè^ T9õq¶*‹ØLKn+ãJ¤¢Ä\Ø¢‚òCRûûY¡èòà\ðA¥þ××gž±ø 8-ë/ö¤®Ò¢gÊwbµËØàt´Ó¼'eü¯gÊpç‹7còÛױMI ¸ÆY™ ½¨&á=`„dõ4`U¥ N(+páXOª×÷[/è“máã±N=½¨]œ¶P]úwU—žþlj*-z¦|'V»Œý€‡¬á_·Œ¢ûl7 káë¶)™WÂrˆ>wš^hBåÎJ4½Ð„>w_jfµVgø„dŸ)€30R:eàÊÒä íå«Q÷QRWiîó´Ð.á$ @>) Èšñ:¶)¡–ÛlÛ½ §:186ˆÎSض{›qö¦gevϣ˟íû’þÛS ¯ªÿÛ«gF+“+¨¨€HDìåËQ÷‘+SWiÑ3å;1Û%¼ÉZÓ€)xûàW%ãulSB%,óès÷aË?lÁÖ_mÅ–ØZ½®j™|&ò‚ôýÞ0óýGÜ{Xbü?Œ3¼‰·8›&9ÃÒºn¨ÂÀ„„cUXZ×\A¢½“¢üÅÝ€\@Òÿ.îN]¥¹Ï3ñvYÔÀ €O•ðå_–aχ ðm0^Ç6%1àž°4³m÷6C ¯m»·¡}g{hU+q9˜üN¬ÏD^ÿ~v¸P7¥xUàÿÃ-µ0½‡%$`ù«„gôš$YNuE]h،֢D{'EùsêR·,ÑgÊû_Ìíâ¨j§ A_k½ÆäûlSWÂÒŒhõÊ,¶—è3‘äÝÿæEW/àºzõt¼{XÕV9›&„B¨„e6õKë¡ÈúÊQäêÕây‹¨ŠEq¿ô‚t=ïBûÎöÐÑDås¡[‚éMŸ]‰ö/ý÷í_¯Zaþ°Wlœ–ô¿c3öUáÂ!sVgW¹ô¿qŽ2²u#?f„m¦ê=k,“þl·EÏÇ=¨þv5ä2ª¿]ž“ !‘ÎPÄÁw.íBÿ-|ЉÓ×3¡–´loÁÆÚ(s–acíÆÐêÕñsÇ ×E¦­ÆýúǛDZq PUl\¢§ ¥ h\"¡ªHÿÛÒçaÏmBØÈHÑ¢þ&ùé0#„Nú¬]§»àñzB&ýT´EÃs pº AƒkÔ…†ç’»A(…EA2’à;äG>ÌUÇŽ?$A¸',ÍÔ”× õ­hkkÃæÍ›CÇhQÊLdÚjܯëæû .ö×Vû…ÞãzèîÔŠïDœ’¼±Ó #&O$×vnä§SÀŒ˜õ£®²èYEåŒCFD§&¡(ˆ%b½ã5—ŽÐrF`¬Ñ4Ž?$!¸–"D&ï@É7Jpû/oGÉ7Jpàý)dÞô´¨,Qþ‘Oû£ýºîí‘–ÁÈ÷©€µ¦åDºbÒv¹^‹ÊIfiŸîà3BdòÎÇg•_YjܦN|Nc( b‰Xïøð„ÆQ†£ TÂ2‘IcÓó›àU½É‹MÏë&¾Ÿ}ýg!ÅK‚„Ÿ}ýgqËå?ð›bÃÆü~S ¸þ'§ÐÈïìÕÓfå]±C Ø¢ýŸvmÀ•“ÌÒ>fĬueó³Æ2éÏv[t?ÔªÒ*HPUZ… !‘ÎPÄÁwÉŽNFäz†£ IAsdŠ™4¼~£‰/˜þÒu_‚ú#ÕRY¢üÿô`óÏÃß—àœîŠÊ2-%€Ú©½È&wvQ9ɘéb?#²éb‘I¶Û¢îò:ô?oC‰t†¢ –°ôÎ9þÈÙ•°Lóî™4œ²ñ#:‹e—-3¤k/­5½‡ÈlòÙʹh xG¶}IO›•c»<„¸´O!„JXöiÞ]"“ƪū ×E§cqêü©˜i«f“–&¼&ƒÞ‘¶™¢ìòâÒ>õ}•¢»»Ûb`÷ow›–¿ïwÏ£½]‚먄öv û~÷<Àå:€áãPOI>^—Ëü¾ÂPÉLV|}PÎoAÓl…r~Küï0dBÒ}¬¨‡ß¬Æà1‡ß(Ão:$ “ðé G%üÇo$Lž” ’à?%a䘄_wHøôäç íMa_Hê4MÓR}S·Û¹sçbddåååÓ>÷z½36-Tî¬ÄàØ aõÇõ¼+ã^@2Ï)ï Þ’$¡éÒŒÁc2æÍ —30!¡òZÕ¾Ê}P©+`A”J=f˜Mïx6û`¦cöüénÛÙ¢é…&ÉËѾ³÷ÌúNʼn©L¡úÛÕ†pU¥Uè¾ÒiZÙÚ4aùíí6. Ÿ8ÑÕ 45i>^€¹^H’î 72åÄ%+Å÷ÅÕPAA®ÒÍ皌'K”4Æ7ek‚6Ö ~hP ÅûN2÷ÈCù‰Õþïê·±ªÒ§ ¨áR¼óà»Âÿ–$ãuÁönúWÄì_‰«2¯õŽì9»–-Þ]Éö™²Ðû—¥ bû—¢ò"¯ ¶w6…}!©#g•°lñîJƳ+zOXt:Ql;˜X„‰·£4Ñ…Åi¢‹ ÉŒ&,N%j_e m5„„¨üÃ`˜¬ÌÜSÎÐ*ˆ¦éiÓûŠBQ$³ç±¨Zà;Z"ßá¾Ê¤ûXädUÕ«\‘ï^‹Ê‹¼.ØÞÙö…P ›1¢#|2ñ9[¿Ñн´­ßhMè9O]0î ;Ýw:©{WWÔaÍú~T^«bÍú~TWÔÙ[9ѱEVgñ„˜L¬:¾ÝrhqÊNt|["Ú ùãæÊ ¦Eå•ßâe¨üûßå™rB ˜"}—›ßWŠ"™=—µ@+ÚˆI_´¢ñ¿Ã}•I÷±ÈÉê;ý¥8p˜ú'€qà­O€)UWÀTÃîs€K­3´w6…}!©#g÷„e }î>4ÿ¸ÿó Ö]µ{îÝWí]ɬîgICÌtòqO˜¬³“ò“ÃÏÏ=aÜFf‰dνËú•ÕYû"›X„+a„B!TÂ!„Bòš# É&''199J»ÝnzDi¯7Ê 0ŽÎÏeXçôÜ;å‡ïšõN¥üP #$ xúé§ñÄOLËïèè@qqqÌïtvvæ];±Î©a||<çå‡ïšõN…ü¤E WœÄÒÇÇÇáv»ó✬|«o&Ô9Ø÷ÒptjR<òÈ#xðÁCé‘‘,^¼k×®EYYÙ´¶íîîFCCC^õ'Ö9ux<žœ•¾kÖ;•òãHç,Z´ˆK$íÂ0wîÜŒÎÂÂBNS"¯¸â ¾DBù¡ü,•IKÃTFUUœ?eee$)æ*Å¢E‹pîܹ¬8á~¦ä[}3¡Îš¦Áãñ`Á‚åìóO1“!ö'Ö™ò3³ß ¾kÖ;Uò“–•0Y–±pá¸ו——çU‡Ë·ú¦»ÎÙ0ƒŸ‰ ±?±Î”Ÿ™ýñ]³Þ³-? QA!„’Ž ›€B!$õ(?þøãù`Š‚ 6ÀáÈ(ùVß|­3Û–uf ß5ë$-ó !„Bòš# !„B¨„B!„P #„B!TÂ!„B¨„B!„*a„B!TÂ!„B•0B!„*a„B!„JXöòÉ'Ÿà®»îÂÕW_ Y–±sçN6 !”!BRÂÏþs466¢ººåååX»v-~õ«_±a¨„å“““¨®®Æc=†•+W²A¡ ’2Þxã 466¢­­ ï¼ó°eË=z”C%,ûéïïÇ¥—^Чžz*”÷Ö[o¡  Xºt)víÚ…{î¹sçÎeƒB"$eòó /à¯þ꯰fÍ\uÕUxê©§pÕUW¡µµ•g› 3©®®ÆîÝ»qûí·cÓ¦M¨­­Å×¾ö5ÜÿýØ´iˆÊ!#?ªªÂãñ`Þ¼yl<*a¹ÁæÍ›±cÇÜ}÷ÝX³f æÌ™ƒgžy† CeˆŒ’Ÿï}ï{ÃwÜÁ†£–;<÷Üs¨««Ã+¯¼‚·ß~sæÌa£B"$cägÿþýxüñÇñÚk¯aþüùl4 pOX†sæÌœ?ªª¢··— BdyÞûIDATeˆŒ‘Ÿ—_~÷Þ{/^yålܸ‘ f®„e0SSS¸ûî»ñ•¯|µµµ¸÷Þ{ñî»ï¢¦¦†Ceˆ´ÊÏþýû±}ûvìß¿·Þz+ŒJXnñØcadd÷w‡ÒÒR´··ãÞ{ïÅ/ùKÀ±cÇ£££èïïDZcÇPPP€åË—³ñ¡ 2kò³ÿ~ÜsÏ=صk¾ð…/àÂ… €¢¢"z#Iww·æp8´7ß|3”×ÛÛ«Í;W{ñÅ5MÓ4Óþ[²d Ê!³*?7ÝtSLùinnfãY@ D„B!$…ü¿*l÷2˜²IEND®B`‚pyclustering-0.10.1.2/docs/img/xmeans_clustering_famous_iris_filtered.png000077500000000000000000000310241375753423500267240ustar00rootroot00000000000000‰PNG  IHDR°×{È|bKGDÿÿÿ ½§“ pHYsaa¨?§itIMEâ /&jY0 IDATxÚípçyç¿‹øS¤+4lZ”TIv$#©±Éž;/kÒCÅÍøâF±†Œ*Í$ÓÌœ­‘Óêf:g›(=)ãdšäÚ‰kCã©›Ö¹œme(…à tIL5¤|‘mØRœZe‹6B” þ{,@»Kb¹À]àû™±W»|÷}_¼ØÅ³Ï³ß÷yY–ed™™™ÌÌÌÌíß¼y;vì!ùÈûï¿õë×[¢/|ðjkkù¥¼Ä™‹FNœ8ãÇkŽ?ûì³(++ã·@ò‚ÉÉI:t–éS²/ï¿ÿ>*++-7fÑhÝÝÝhiiËå²ÍwÍ~¯n¿ÇÆÆP[[›vìØ19rdn?ÙøÃ?lÙ›Êï÷ÃëõÚîKf¿W¯ßccc8tèA°L“}©¬¬´ì½VVV†ÊÊJÛ}÷ì÷ê÷;'¬¸¸ÅÅÅšã.—ËÒƒhõþ±ßÖê·ûNˆqp!„ЀB!4`„B ˜­…€ÖVÀíV¶¡Ç„bóßµY õMÀý+eš¥ËK:;¿Q¶BˆÍ×®þ`$¦l;¯Ð€å%}}€$)ÿ–$ ¿ŸcB±ùïÚøYƒ Œ,/ihDQù·(õõBˆÍ×*ÄÏDõ˜–HfA|>ÀëUÞy½Ê>!„Øúwmà]¸ÊÖ·måu:9¬ÖÃãΞå8Bò‡¡YàbDyv1¢ì{ŠèB±8Moá( CÙ6½±ò:iÀ!„dáèÒûf`‘BHÆ Í*Rù¾1EÀ±Ö©„“¸3:”!„Œ£ž÷µ½ ¨r”m`=0B!D=ïëÊ$¾?³mÐ#„’q²1BHÖÉÆ¼/5 !BÉ8ž"àìÎì¶A,‡0ËÇÄ«%ˆ5"Ê÷•ñÆZ>Ä®5@àÖüþÎ5Ú2 •Š%ayªD³çÑ€R ÌÌÌ`fffnlLyÌF£ˆF£–ëo²OVì[¦û=õʤk ±«1Œ¿2ŽÒ/–Zªßr\„râÿr\F4*¥”ùÑàP\ÄÅq÷­‘ñ£-Œ ƒÙóôúÜÒ€Ù€PHQ9öõ)ïÞ|>Å$D͉'püøqÍñîîn”••Y¶ß~¿ß–㽜~ïØ—ìJX `z`®@Fúኺð‰>ŠÉ DÊ"øíúß"ꊦí·ú¼×wÖBv%º(àõ[³èê:§9ÿkÉ ¯ï§ÙóÔýžœœÌãSáÊèèÑÓ#@’øý2::dœ9#ôÓ¬ûm…þ;v GŽI¹×jkkÑÒÒ‚ÊÊJKŽ¡ßï‡×ë…Ëå²Õw¿Ü~OÏ{`€’%hkkËH¦þu Ò¸R÷ºñu¸æ~”~¾4m¿Õçýñ¬€@‰ DÈh\çBÛm–ï¤ É‰ãSáÊèím…$)OE’$ ·Wÿ©¨žf­ØïäSájR\\ŒââbíºËeiaõþe¢ßâçEí;0WfÞM|8¡Æ„wÿ0¾d¿’ýVŸ÷ƒ+“ø/ÿé6ôõ•|Û¸\Ëwò³åÄ€ñ©pe46Šèé‘!IDQFc£K÷É­žf­ØïäS!!z8Ö8P±¿bÉ2F„zeı«±9ïN¬UÕyw¬ð¯ÁÈ|Ý›Ë"ëŠÕsbÀøT¸2NŸVÞõ÷õõ|¾¥ŸŠ áiÖŠý¶c߉µ˜xubΠĮÆ0ñê„Æèé•)ßW®1jFPŸ‡Ò¶_pŒ¬ Jö ) ¤A)%¤' J†ÊñîŒx…·NÝJÛ> !„ FB‚[€üœ²¯Æìœ3³¡ÈÕ‚™8²H0TW‡² 9&„Å)ßWçf'„RÎÍNÝP`<_r˜3ÊSò\(0SíÓ+šš€pXùw8¬ì q\!‹xFBÓiöa,iº}°Â`xxé}BH~ ¡ó¹Nô]ïCæøúà©LÍ6 Åy!L(ÊÚÊ0Ù59·_q NŸä•Ñ*ѱ[(дÁ祗=Üî¥÷ !ùAçsð_öcdbþË~t>ש)3g¼` ˜ü_“)û‘"†Ú«Ä%÷û…éY@@ +Æ+à˜’ô]ïƒWÂtR\Bÿ€ÎSi*™2ÖV|8¾ä>`¿P ˜©«ã;/B †M ð_öCŠK"ê7ê,XšÆH•Sê…íé>0„H!+ÄwÐïv/ÜkÜðn÷ÂwЧ)Sq B1b cæð¨ SµhH=¨4«:¤Vœ?´´Ñ(àrÝÝÀÞ½ÙkÙçsKhVY¶oLY³È· ð¥/³NàØO¥g_:Û€ÓãÄÚ£kçöoº•ò÷99|õ ^xЬêX4^€²miÉn{€ßŒŒ(ÛÎN~Yï,.£N “øx‘#¸uê"/F×¾§kD ù”ê3‚ú<Ç펴íÓ€êU2²½jF_ % $IÉH²8ÞY\F&fCfÕƒêóRdÑ.WªÑÊvÎÖ†Åó’$@úz~YoKgc9t’¿ é-¦,Äœ†ôÀ²Hw÷¼ÑJ¾Ë&>àõ*Ò{¯WÙ'Yïm€wàv*[ß6seIb$ Å0zj£ObôÔ(b¡XNÛ§V ìÝ ÌÎæ®=fŸÏ-ž"àìÎå—±ÙÒ$‡YÞD=±9òB$Eä‘íöiÀ!„h04‘x*Í~¶Ûχq楖žPhmUBz­­Ê¾‘2FÎ#„(¥Ú}#êE#e æAWQzŒÈÚõÊPOY õÄæŠ†Ô‹…:iY† `DÖ®WF–)‡'„,òã«šØ ˜_‘™Y”†EÎ,.k×+cä`l©”B 32„h#²öÅÊPOˆ5Ñ[„2i¼õ2)R\J9öëk¿6ÔÞ¿]û·´çÅ_r†âCèü}'ú>èCƒ³¾¸¤&K-”0#=0BHA¢ç¹ÄÔ4;ˆ%D—\&ÅéH}îOþ=­·`à<#áA#ž\¡LdΖ)Íz(±½­@lo§öÝ*_ï,Ðú&àþ•² ÍrLÈÊÐ[„²û‰î9#æ]øÉ×~¢Y&%yΜ—7ö~ÉÈyFƒFÏ,”™óÇ€eJ³ÞÙ ¡§E‘„žjß­òõ2Ø‚/þþ‹ŠççʺùcÀ2•½¯B¢Úwë|½ÌOVú¤ ½H»¥¾ƒ>4okF…«ÍÛšá;è3Ö»eŸcKŽkôÛEÅjÁ²½f;^û÷×RöÕ óé©3¡0ôôiBŸ4`ùF]bƒƒ)áÀPªzȃå«ö3¥ô'„X‹Ë¦fÕ¸ò‘6×™Ù0ŸZõ˜É Øv‡*DBHö‰…€÷[wÝÊ6ÊyÝjõ^ðfД*0x3ˆš'kððÏFÍ“5Þ šÈœ®?‹© ÍLÀ.hÀ!ÙçÃN`ÂÄG”í‡9¯[°éT“©|M§šžH('Âh:Õ¤ÉO mÝzù õòÉ}X¨äO1R^0õõ)y}>%f—òèœ{—…Ä»,ÔÕiÊ8›š°/ñ €2÷K]7¶=#Íeìã…æãÛWqúÏOÃSéÑ”‹Ç1ñê¤A bˆÒÏ•bêÿLÍí—ï+×Í€MÈŠ˜êCJ:æéþœ×­Ï Ï­x¼UžZq8<>lh"sºþ,¥&´»ÜX:Œ,§’˜ãYV¶É9^:e`¾Œ^ÝÚ3Ò\Æ>¾ÁeÎÕKG^ˆÄÒãd•)m€’†ʶ¤>»uë„Õ¡8÷·©Ðœ‘œ†za?³ù 3ú¤³2F–S^z?qláœ/ ë×m =#Íeìãœã¡^jS(ˆ¥ÇÉ*s§(÷¢[ÙÞéËnÝ:aEu(.p4`*48@U¹2½¦ª¼J7§¡^ØÏìr.™ }æ#…µœŠÛ­¸B ÷uÊ,œó%¸ÝÀ}÷éצ=#Íeìãœã!Öˆˆ]%>€Ó˜ÛÏ×¥ÇÉjÿÒx€Ú³¹«['¬è©Õ†çÌ„æêîªÃàÉÁ%Õ|z¡@³ù 3ú¤feŒ,§(ïµaþýÖ"eæ&1úuhÏHsûø:‹ìé¡^j¼â@EA,=N Œl†, `DahD©˜|8ÍD蓘•12ɪ®N3ŸK¯Œî<0½ºÓ´g¤¹Œ}|ƒs<’K–/D½OˆíI†§ûã•É¥Œä+Ô[rEÏ#TŸwò?ŸÄ“/=™÷K¥–#„¹_¶,†, `DahD©˜|8ÍDè3¡^Zãû‡ ¶·£õÀˆííŠæe°,øþzzP‰@èé1,™·+ï<ÿêbuXëX‹ºXÞyþÓuE^ˆ(ªF˜JìbÔÊÄ÷[€x€¬lohç¹èM66‚‘ÉÇœ œG›C öýû $äñBR/Ëé%ú6ect#œå2p Nlˆn0_ÙTš}BV“©_#E™Õ”‘xXñÒ>ìTTŒ¥ ¸ú7SKÉ{hf…hb»|ù26oÞ\#ÒÐYTÜz9)ohP¤òÀâ}›2à@LVB}19†®æ++M³Oo¼ñþæoþ?üá§Ê¨ÇÆÆpðàARVH7EÄ¥ñÒ^hs2Ìgw6;;‹ÂŸrs3f** 77–ÌÛ•_Ù 3ˆ‘ø‚Î v|e‡éº*TÌ­ÒÄ>I¡»» øñŒ¿ýۿŶmÛX0¿bjj §OŸæ@e9Í;YG¹fþؽ·Çæ³0N)‹Mê1”+-¸ðx 9ƒs 9ºc)}>|Ü;=ðüW%gâlYÙÅäqbíѵ¼«–à©§žÂÑ£GñÍo~²,ãäɓطo^zé%<øàƒ L1TÞi҇ØÊþ£â]AR¼1ÇZ >:¿_úy˜œ p”îÒ†ùb!ˆƒhÝÚ q°¸+ñÀ± ôˆ;}Š’d߀}ï{ßÃîÝ»]y||œ#EHxûí·ñ /AÀ7¾ñ ¬_¿<ò~üã£~…áé™™ÌÌÌÌí'W‰ŽF£ˆF£–dŸ2Ý7ç& žÈ¨“hÄj1~ÂÌEÈÅ÷ArŸ€8|l~¿êGC @€2Èq’ªoâ`„©‰ä©Äov(ßçTH'üov@ª9S0ãë~'·Nغu+žxâ <öØcº'_ºt ÷Þ{ïêõÞH¦y½2CCËO Aìè@ko/ÄÆFeeõž¤ô–_Wº.3uÂ;Ï¿ƒÑp `Ç£;Pöë²eg¬Wg¾OfùXxl²i?NŸE?4 t^úÆ€†JÀ· ðÙÏ€ãÖ­[)Çöï߇ÃG}ßùÎwVTÿ‰'püøqÍñîîn”••Yv\ü~FëÛwOB"©©@–Âèê~À×”º¡Ú­[_G‘('Γ1;þ:Îuu¥ÔݺµEbBè ³‘^4ÇÔçåóxçºß“““ÊX˲,ùË_Æí·ßŽgžyF÷¤7ÞxôG„x<ž‘NŒá¶ÛnÃǼ¨×—zÅ´¦æôzµ!=½2/¦&#¬ªJŸ£µ²ßA’ ‹"½¶,@ëw[Srz·{ñê_¼š‘ÕVß  .V§àDLŽaR˜D¥P9—/ѹÙi({GäÅHJÞEçfEí¸ðØ%Ç%x¼)ŸCO™Õú&à™ öÀ»8»sõŸ Ž·‘뺥¥---8zô¨æoÿüÏÿŒŽŽH’I2—TYÏ«­­E86v¯­Âúý~x½^ýk6‚øûCfú!×CºýYC¡9絚y UŠ–¦.ñf „éÿ;ï•|Ò]Ý*¬}ÞÛ‚¹´9ÕK³ª¶äx[Ø[Øï±±1TUU)Øw¾ó”‹^Í®]»2f¼La$Ó¼^™‘‘Ô2FÒÁëÉè-ˆÑìófPKë×Èkæÿ¸ŒŒõêÌ÷sç-8¶!ºÁÐçèK@÷Ù3„øµ¯} ¿øÅ/tÿö¥/} ²,ãG?úÑŠ<¼ââbÍq—Ëeé¬Eû÷Ña`ª€aªŽðac66æÞ ‰w`®!u9æLÈÂü{ð$wFüff#½pU4±ðØt?„’zwúàpÚp¼-N²ßɾ;àŽ;îÀÆSÔPjþáþaõzmDÆ®WFþÝH:x=½Éæ,~µ´~\ÇÂ5fŒf¬kDÍyêc7\7 }Ž†Ê”Ô¬¨¯„-ùÓ?ýS<óÌ3‹Þkû÷ïÇŸýÙŸ$0»fIpϰ-®lKêŒÕ5ý†Ê¥}Sǽó@ª9ƒsï½ xYNÏ|ꪻÃÊ–Žœò"ãÁÄ“O>™ò‚/£½½õWµz½4"c×+c&¼žŒÞ‚ds¿ZZ_²¿ÄTÆzuæûò}åšc;¾²ÃP}ß6%lèv*[ß6{ßx–½×¬†Ù¬ò: Zªk•³Ø“e"/àµ×^“·lÙ"ïÚµK~ûí·åŸýìg²Çã‘?ó™ÏÈׯ_—3ÅÇ,?þøcÙŠÌÎÎÊ/¿ü²<;;+Û ö{uû½œëz±{íྲྀèG²|ãAY~×­l£«øÆƒ²|Y”åËP¶ÉsÓÕe°=ÞkÖ¸×RRI566âÒ¥KøêW¿ŠO}êSˆÇãxúé§ño|BRÒCY1¼× b6«¼^¸ÐH]«œÅž¬ „ï¾û..^¼ˆõë×Ãétâ·¿ýíœdÑÒɯWæüy ¨H 3)ûN|<ŽÈ‹Ü:u ‘#ˆð¼óïïàå¿~ï=õ^þë—ñοk‡Þ aàé ÿ÷a <=€Ð{¡‚gÛÞkv dWê~ñNŽI¾°oûÛØ³g¼^/‚Á úúúð›ßü;wîÄ… ¬ýIŒdŒ×+ÓÒ$ßCD£Ê~3ñêbWc§dÄ®Æ0ñꄱäÓïâÓ®Oc¸Ÿv}ïž~WSfúÅiTÈpTȘ~qº ÇØÖ÷šmT[’×ì{ßû^~ùeüÝßýJJJPWW‡¾¾>|á _ÀÞ½{­ýIÌJíÕ3Òm6C=,*OÃ'ÅOÂ)ÌËïëDí¤ñ5òš¹™ ©ýÂÖ÷š˜~)±žšä—{ë­·ÐÚÚšRÀåráäÉ“èîî¶ö'1+µWÏ…°á܈L£'7Â[Ò[)òû ¤] p\‡,+?,²,+ýÄÖ÷šÐSê)Iþ°ªªªE ~ö³Ÿµö'1+µïîž7Z.—²_àèÉßpOÇ=x-ú†¥a¼} ÷tÜ£)S²¿!‚¸GDˆ dIAޱ­ï5;p§(÷¢[ÙÞéÓ.hùa'ÇÉæäÏ‚–Oú”Oze<`v6õX‡k†RE©Ù±uv<­,Dz[õ¿‚-௕»áN 7ö$Ó¿l:jB³“¢‰=<0BɱÄÁv´n=q°=û!=uX±x'CŠ4`FOênD"o„`¨®e jë!¶·£õÀˆííæÛJÜ én¡Ñ úY‘Kôÿ²C£ACçoQýD5‡¨~¢ç{íßoÇŸ@û÷Û iÊoM}ŒÙk³ýæ(FŸÅè7G1{m¡±Z¿Û ÷ãn´~·¡±B†øVW_Eà[„Þ ™’ãëÉøÍJû5—׬’Øý+ešÕ?FrÀ‡‰eI"¦z²ÒS‡†mŽ 'ߨg‘ådÈÛÛ!ôôÌeƒ—›™žUǤ3ËÏô쬩 2TWUA¾÷Þ”º±v-0:ºâ¶ý¬Õê Õ—.Ô`wU.—ÂU¸wã½iÏ«y²á‰ùLû.‡ qÄ粺7okÆë¯§”©*¯ÂàÉÁeŽñÿ1ÄS{¾Tö%ô\éIiï/§þrÉ,öâŠ(ýb©¦~u¦é©‚tMJ9€æ˜^]éh[DÏ-ˆÑüÊå¯>væ?¤W^.–!Ûð* 9`Ù+?ä’wÝŠñ˜»aÜJ.A´¯^‰À.äK¿“×uNÞ-g¢ÖÞ^-È?ÛÛ Ð3³Öξ„ñk…ȩړ–YA[€þºAêºîß /Å›+ˆ§?o¡a€h|þ=’—Ðû»^D¢Í9]&>Ëñ ,˜K#Çeôþ®7%‹|ïïz±Ñ³tûéiºÏG™\ëgÏÀ¸dWÊy4Ç–ªk1z+Z!9”…Ä$è™UFYu¬«ëœá:Õkã!=yÂ?÷ &ä:ï`iCê ÍÌ{h;rbÀŽ;†#GŽh<°––­ÖØyGäjlT~³TÇÚÚÚ–ß‘ªª9•ôÀœ÷Þ›R7Ö®…¼À3Ýq°òOÊU¡­ëÒ…*TÏ{`W#Š–@Õ’Xãݺ˜™Ï2LõÀ‡€Æ»S<°Æ»105€ŠXÅ¢XÉÆÝö5ØxªV²±Dã-VW:ßÑsKžó¶×¹Xê±¶Ò×­ç‘å…ôäË’wúrÞ~r ”Ô+û„LͲÖ(:}ZÉÑß¡¾BR¯:æ0ãþs+4 ‰š…êꔺqò$âGb¶·®ÆF8NŸ6×Üu:íA›>À¥`6¯ÆÕq76}2GEuÚóOÐtª ÃãÃp¯q㥯¾„ow}[YÙøneeã¡ÈPJ™ÀÑ€©°AùþrL¼8¡1‡²Ú}Ïu¢ õë•,ò@ðù 6D7à†ëv<ºÎ_;SWrv-þÚ5y=ˆŸӮ䜮®Å8½CYÙ¹ ¨¯àÛ¦x–êc®eÔ­^£ˆè )×ôTŸâù,0«–ú‘ymONÞ©±t\„hL•IDATŒo³ßæúmÅëÚ2}z¿55\—Q¤„˽¶1(¼×¬q¯åÏ<0BˆuÑ›ƒ%Ë0ÿ®—ó²Èr±Ç<°LÉè­ˆždÞDÊ›ÐXH#£×•º«}¨•ºë§×^º2Y½$(}·z©J 'ŽÉQØÃKf‘—¤ù,ògó$vLo)u.ŠúXšÐJçss¢Šž+=è|N©ÇÙ).ÁÙ¯{ìçßÁîøn@Æ\æùÎßwjÎ;ûøYM{éÊdõ’¸øG”gzÿˆ²–+fX—E«*â 4`9ÁH¦ù< ­,7åMßõ¾Y{ÿ@?dYN{lct㼞È<ß÷¶.#íåô’K!ôShñ_}Á„Tsçï6ÔB%BÒa¢‘LóyZÑK7D› :”sD‡ˆúõ†Ž ¸4™çõÎ3Ò^N/‰Ê”B}%ofBhÀ¬ˆ‘Lóv­¨³fëK7D}hÞÖŒ Wš·5ÃwÐßA¼Û½p¯qûݫ{lÇWvh2Ïë§×^º2Y½$¶Þu€Û©l}Ûx3Rp޽-zi$Ó|ž…V–+'öTzpæëg4Y½÷RšcûUuÁ“ö}–§Ò“Ów^šö‹øÎ‹z`„b¸è$¡³zrtu†úËïŸ7%Y×Ët¯n/x3¨©;ŠaôT"ûü©Q„Þ3'™ÏµÔÞ¬´ž’| ÁE' ˜}HÊÑG&Fæäè׃MØíc]‰ŒÝî0/·hÊA]Ïõ`“¦½¦SMšº#/D€©D%SÀô‹Ó¦Ú×ûlYË„´~$6/­Ïæy$ pÑIBfôäè[*†S2ÔïªŠš’¬«ëÙ¼fXÓÞðø°¶î©ÔzÖÈkLµŸk©½Yi=%ù„—Ѐ‘UBOŽþ^Äh"û{4¼v™’¬«ë¹:îÖ´ç^ãÖÖ­Zfk\7Õ~®¥öf¥õ”ä[ \BFV =9ú¦º. WaxJÀ¥á*Ôlï6%YW׳©. i/p4 ©»â@ż+Jö—˜j?×R{³ÒzJò-DR•{wXÙ:=²øåÂ!X]ôåèT?0p'Žœ}|ï²ë®^[§©G©+µ=Mû•ÀÚ£k—.cú³eq,MJë)É'„!„Bfy25_Å@=ïÞø)¿q ~Y@ø7¼{ã§š2zÙè 'uÇ5ê !„,_ÈÔ|õ¬~îp—ÈX7üˆ¦L2}$IÉFŸ=©ûÄ«ˆ]Až’ç2ÔBˆÕà;0³dj¾ŠzÖ•ÈsË® ‚²¯Æ¬d]ï<)&É&ê !„X¾©ù*ê™”V ¬´22-hʘ•¬ë'Öˆš õ„B–/dj¾ŠzFÜ?Á𴀸 O qÿDSF/½ô¤îåûÊ5ê !Äj0„hzä<ËÎo¶ž{6|Ø )ªÿ©Y,}:“ºWì¯àwL¡F!„ЀÙ£Ò{u¹é )É~®³ÁÛf£'„Œ¤Ã¨ô^]îF“)É~®³ÁÛf£'ÄžðX.1*½W—‹c^×n\²Ÿëlðv…Ùè ¡FÒaTz¯.çpÃŒd?×Ùàí ³ÑBFÒaTz¯.·!`J²Ÿëlðv…Ùè ±' !æt´ JïõÊÕZ?¼]a6zBèB!4`9È´=›™çuŽåRþ¼DõÕpv ú‰joM×Å,ö„\’“âÌÌ fffæöÇÆ™W4E4]Õ; Lõ@€yÂùf¢Õ?ëßbe¤š3i €æXÇOž+=âü—ýèøÇœùzúö’ý]Θ6lBx" ‡Ñt² ƒ'MåÔ+S®)‰€cWce¥_,ÍJ¿­€ºßvë?!4`8qâŽ?®9ÞÝݲ²²U€Ö­½(µ ³‘^ø/ù~¿Ñ2纺2Ò– @s¬÷wH‘¿÷þ®]Ëh/Ùo#$×Âý.Ÿ ö ìKN¤°’éiºYé·•Hö{rr’¿(„ä›;vìŽ9’âÕÖÖ¢¥¥••««Y!'= ˆpU4ÂëõÂï÷ÃëõÂåré–ikkËH[4Çïž÷ÀD‡ˆÆ»µFSúm„ª@UŠ«*¯2õÙ`j|Þƒ”l,ÉZ¿­â-ìw2²@É#V\\ŒââbÍq—˵ú?XwV2[L÷C(©‡p§o΋˜ëŸN‡Ó•‘¶hŽþs%‹Fÿ@?ê7ÖÃwз¬qZθž  éT†Ç‡á^ãFàhÀôw"~^ÄÄ«%ˆ5"Ê÷•Ãárd¥ßV"Ùo;ö0[€Žd]ý.#Û™çUÇ<•È™ü½î®: =3”‘ºkÌbOÉT!B¡#„BrCˆ±òjªOÉAx§Àºì´5T2ËLJ•ü†@I¯B’1¬…Þg4`ÄÚ\»v =ôšššpéÒ%<þøã8tè~þóŸspá}f[˜>–-[0;;‹xÐÛÛ‹-[¶ ±±ÿò/ÿ‚¡¡!¼òÊ+¨®®FCCÞyçœ?=öÞgôÀÈêP]]çž{O=õ.^¼ˆH$‚àë_ÿ:>÷¹ÏáÂ… hnnN9çOþäOpáÂ!¼Ïl 1ÊÚÚÚpøða|ùË_Æ}÷݇òòrœ8qðÑGÁãñ¤”÷x<ÃÔÔJKK9€„ð>£FVS§N!‹á¥—^Â?ýÓ?¡¸¸˜ƒBï30b}Þ{ï= "ãúõësÇï¸ã„B¡”²¡P•••|*$„÷™ma1O˜Åc=†G}ŸøÄ'pèÐ!¼õÖ[¸ýöÛ±gÏtuu¥”÷ûýسgŽÞgöE&yÁÑ£GåM›6Éü±,I’|ÿý÷Ë=ô,˲|õêU¹¬¬L~òÉ'åË—/Ë?øÁdQåsçÎqàá}f[hÀò€@ ;Nù—¿üåܱk׮ɕ••òøÃ¹2»wï–‹ŠŠäÍ›7ËÏ?ÿ<ŽÞg¶FeY¦J!Änü¥>×v6[IEND®B`‚pyclustering-0.10.1.2/docs/img/xmeans_clustering_mndl_target.png000077500000000000000000000544501375753423500250360ustar00rootroot00000000000000‰PNG  IHDRø‹+ž€sBIT|dˆsRGB®ÎégAMA± üa pHYsttÞfx9tEXtSoftwarematplotlib version 3.0.0, http://matplotlib.org/¨æðXhIDATx^í ¼g}÷ÿ{®@¸särL¼P "!HÌýÂ% T[m5ØD¬øyÛê­JýôF!¶µ[mj[ÛkŒ•x‰mjän Ä„Dˆ¦T“H àp Àá\ö}~ÏÌsγsffŸÙݳ;ç÷M†gŸ™Ù™ÝgçÌïù_žgry…B!$S4ø%!üÞïýž´¶¶ÊOúSÍ û·+¹\Nîºë.M4çž{®Þ÷Ê+¯ô×rÛm·éíXxàíÈm´bÅ ¿&òòË/Ëš5kdÇŽþšA°ßرcýZrð; ­_÷º×IXßþ¡‡ø=n½õV­è×X7jÔ(yá…üµƒà¸³fÍòkæ·ÇÒÐÐ &LóÎ;On¸áÙ¼y³¿W!Ø÷£ý¨_«hoœÛæŸÿùŸ Ú mp>œ—JA'¡|éK_’éÓ§Ë>ðéééñ׊ü¿üË¿ÔB³lÙ2m<ãÆÓÂñ‹_üÂ_3È¿ÿû¿ËøñãýÚÈä¿þë¿ä/þâ/üš'ðk×® ø4ÀïñÜsÏÉ}÷Ý篤ØïÑÝÝ-þçî׊sÉ%—ÈücyôÑGå{ßûžoœ{ñâÅòž÷¼§àÚNV®\©?§M¥çÃy ©x nò_ýêWµÈüÕ_ý•^‡›ñõ×_/Ó¦MÓW.½ôR9묳´xØ@ð!üï}ï{ý5#“ .¸@^ÿú×ûµÊóš×¼F.ºè¢!¿ÇÑ£Gå»ßýnìïqíµ×Êúõëå©§žò×Ä3qâD}., ,|ä#ò£ýHw!øI: •àøñãº<ûì³õg¬4ðšœ8qB¿Æùp^B*žD‚òïÿþïËßüÍßÈO~òíNÄÂw«+pÏÂ-ûõ¯]úûûýµžµØÞÞ®ÏÆã?.¿ñ¿!“'OÖ®aáw¾ó«ÇäÿðeæÌ™Úu}úé§ËÕW_­EÄæùçŸ×.Ñ/|á ò÷ÿ÷òÚ×¾Vïÿ¶·½M¶nÝêïåñË_þRÞ÷¾÷É™gž©ÃèÐ\sÍ5±õøC}üíÛ·ûkD Ö½ýío÷×xÌž=[ÞýîwûµB=ÂóæÍÓ¯?øÁê÷‡¹rÿ÷ÿW–.]ª¿Úð“Ÿü¤¶®]Aæ?ÿó?¥³³Ó_#ò­o}K—øîQüñÿ±L™2E>ýéOûkJßçÍo~³|ùË_–“'OúkËã±ÇÓ^%|>\/è4}üã÷·ºáŸxâ í=˜4iÒ@ÇÊl3à7Ùµk—<øàƒ¿ÖºººäSŸú”¾ŽZZZtçzõÕWý=<ð>x-¾ò•¯èð®'ü˜mÁßuçÎòÎw¾S6|‡9sæ ìoÀ5‚÷Þ~ûíògögú:E‡GÏ>û¬¿!xR„›o¾Y[|¸!~îsŸÓ‚¿páB«;¸ž7mÚ¤ë}}}úÆaC Èý÷߯ݻ Üÿû¿ÿ[ßì`]ÚnÓC‡é!Dök_ûšŽ/#&Óÿ§ú'Ù²e‹ö@|ó›ßÔ7då‘#Gü=D×Ñ¡ùüç?¯÷ý—ùݹ°Å0ÈW\!ÍÍÍrÏ=÷økD¿=z´ ãŠ~å•WôM<ªSóÖ·¾UënÜ +ÇBÇ´ Úö‹_ü¢þ}\ˆ766j‘0 ã†ß9ÎE÷>>~Ç0 ư Ñ‘+|žË.»L~õ«_éÜÆõçÜ¿¿¿Ç ¿õ[¿%oxô·×V›à:Âïn~¬øÌø½qýÞxãú\èðàºÄïÌm¸óÎ;õ5´zõêÏÄùâ‹/Ö‹[n¹EwÀÐqÅ߮Šú§ªó!Ö­['ÿöoÿ&»wïÖmŠ¿-B4È¢'$Žõë×㎕Ÿ>}zþèÑ£þZ7Î9眼²`õkuSÌ+ѯ•ç•’î¹çòêF«¯D]oozÓ›òêæšWbæ¯ñxÇ;Þ‘?ãŒ3òê&æ¯)¤··W¿G‰_þ7ó7ýµy}œã-oy‹ÞǰmÛ6½^ ®wttèºêèz.½ôÒüÕW_í×òy%"ùU«VåU&¯D^¯S }üÿùŸÿÑu€6úÀ>à×òùíÛ·ë}”ÐûkÁ~Øöï|Ç_ã¡:%ù7¾ñ~-üÊrÖ¯q¬¹sçê×JTôqU§(ôüxuØÖÝÝWâ§ßÛß߯·ÛÇ5Ø¿}Jôô1¿ýíoûk´2æ?ò‘ø5w”%®—'Nøk†¢:úøJhý5ƒ˜m6ø>ø^A>ûÙÏêßmasÇwèclذÁ_ã}Ÿ &äUGÔ_3¶á¼ÕéÊ+ ?¯:)þ%K–äÇŒ“WL]Çß Þ‹ßÜ×֫Έ¿†ŒthÁ“XàRÿÇüGmeÃú ‹½ÂbP¢9°ØnxXšßÿþ÷åàÁƒÚZ¼êª« Üž¸ŸþóŸËûßÿ~]· ëzïÞ½®HXa°|áÒljjÒ–ô½÷Þ+?ûÙÏü=»–«îr`2À۞ X‚O>ùdä÷ ‹ú‘GÑ1Vß–2<ðXõðˆÌ˜1C×KîÙ`‚#¾GXv{ø=`=#q¿¾÷å—_îo.iäeà½ÁIÔýÇUª³¤ó9>ô¡ék vx¤~ðƒèø]ík‰ƒøm‚ž#„Œàr/<"¸†r±¯¼6ðدeB(ð$ĬqcAbD ¢`’„ ¸)ATÍ‚}€û7`¸“1Ä7ä0Œ[1Nû¸XoÊÒÖ%Døþàä /Ô1oÄÓG2XðsÄgmf_Ü Ñ9ÀÍnQt¦Nª]±HB‹nwÄÁ~øa-èmmmÚÅ‹õÆucG¹ç]QÖÜ!Ã÷Hˆ˜ã7ý×ýWùÆ7¾¡7|ÐqAÛ lÂI1B„r9 ¸&¬qÆþ«ÒÀõùôÓO¹6¾@§Å\›×ó¡ã¶¯il·)v-B'‘<óÌ3:nˆ9û†UŠ›º ¢j–`âÂaøìg?+§všŽ…†aò'Rp\{õþã?þCÇÛã„u¡Ÿ;wnQ1ŽãœsÎÑí¾}û´§àþèô©U«Vù{„ƒs#é bGÇ‚‰Ò|nĈËø4A"Ú¹ é ¾bþ°œÿM „<\ø½Ê0ðâ‹/ê²®˜(p}¾å-o)¸íÅò\ÏÁ†w*rW€ù» Ä < .GÜðqSù‡ø½Ãz>ñ‰Oè:\ц7¾ñú&m–0·»Ö6ÜËè8D¹SqæäV¿ •‘d$A1ð;„ýïxÇ;tÇ‚vmÆ]ÿqàºÀuc݀ɠÐ9®Æ0>’-(ð$XÙˆ±"Cc™ ŸùÌg"]õ.ÀòFV1¬â8à0®rdzc¼<Þ‡ÏõÛ¿ýÛþ^Þͳ¢!‹7GX£x†/•:iäÜ}÷Ýú˜f¬w=€›4âöpÓK™ôÈŽÆçDGCùâ€Xá=ÈòG<¿Cð¦Ÿpÿšv-Xñp‘cÔAy€° üžð„ }!ð¿ó;¿£Ë Ï;î¸cÈ‚A—?D‚ˆvCiò8J¿:™ßþö·µenfuÄp8tBñ="‚Ç¿-þVð0\¯p £“ˆÜüöÈÎÿÝßý]=:^±$CS Ñ ÓŽ›;väÕ&ÿáØ_S²t‘E¬DÚ_M±LjðÝ,z n®yuÃÌ+AÔŸYüÈRÿÊW¾âï‘×ÝŸúÔ§òÊúÌ+K0ÿÖ·¾5¯KgˆãÜ“EóÍ7ûkÁz“ͼÿþüŠ+tÿi§–;vl~öìÙù/~ñ‹Ù÷Qà3ãxªä¯ñøë¿þk½þŸø„¿f`=@V?>¾·ýù°>WlÇ~ÅËv¢ÄL+*‹>ÈòåËõ¶°,z¬Ç’Ëåt["Óÿúë¯ÏoÚ´Éß«³ØbÚ \—È8GÖº²¾uV½}š6RÍ aí÷üóÏç-Z”7nœÞf_OÇŽË«ŽŸþ>---úœ¡óíÛ·ÏßËû>Q£¾“êDä—-[¦‡ãžþùCFS˜,züÝØ˜k<¸?¹ða3„BH¡‹žBÉ xB!$ƒPà !„ B'„B2žBÉ xB!$ƒ„“ÃÃ50±f +wZGB!„TH:¦êÆ$V¡9ƒO4"„BH}°gÏžp?r䈞ž;Œ?Þ_›>x ¦x\´h‘ž¢‘„ÃvrƒíäÛÉ ¶“l'7ªÕN]]]Ú@Ç4Ñ¡0ï1„¾Ò¿aÃýŒo^ѰÜ`;¹ÁvrƒíäÛÉjµ“­ßL²#„B2žBÉ xB!$ƒPà !„ B'„B2žBÉ xB!$ƒPà !„ B'„B2žBÉ xB!$ƒPà !„ R3êÔ)yúé§å‘GÑ%ê„BH¦8p\ä½ßùµÿ畯¨z…¨ÿùÏ.‡–ÞÞ^]¢N!„d‰Æ? òà‘ÃÝ^ùïñ·¤OÍüÑ£GýWÁ:!„Rïäv¼"Òç?¥%êbØ.øgžyF?oåi§æoñ7nœÿŠB©c^9.ïß K>ö’RxUoÄ?~9çtïuÈåÝÝ݂ŀÆ···KGG‡àJQïììôk¢ÏÓÐÐ ÇŽ“±cÇÊÞðiiiñ·ŽlzzzdË–-²páBinnö×’ l'7ØNn°Ü`;âž{èEÉ)‹=³zb«ˆ2ÞóJÜû¾t¥ÈÔ1ÞŽ)ýnkk“#GŽx¿fÍY»v­¿yõëע1é8—Ëéã566ê×X ýýýúƒB!õLë‘>¹àkeÒs=røµÍ2é—§¤å¸ï–Wtm»¿t–_K—ãÇËòå˾Z|Ðj·™8q¢Ìœ9Ó¯öÝ`;¹ÁvrƒíäÛi(;ÜðZDŽœ¨ç/?[ú¾¹Ôß;]†Xðþú°Ã„ ôi <†À!KÞ ¾¯¯O&Ož,çw]òàhÆ ²téRþÅÀvrƒíäÛÉ ¶S‡,yÃÄVé¿àtéÙþ’4Ï;K¾¼Päôô¼ã6¶~W5É.˜8‡ËâN!$\0­0‘î­Ó´Å·¼¶Ü+$îAª*ðozÓ›dÒ¤IÒÔÔ¤K$ÒB!™âˆ\Ñ.2y”W¢> TUàa¥Ïž=[.¹ä]Òj'„’9`¡û7Dž]é•U²Øƒ Û8xB!„T ˆÚWûé²’œ:u*çwê’DÃvr£¾ÛiŸZ®UËd¿D½<öíÛ—¿öÚkó“'OÖ%ê ª°Occ£þÛG‰úH¦¾¯§êÁvr£Zídë7“ì©(ûÕ²D-“Õ2U-“ü:ÖÛ¬P˵òKÔËcÅŠÚb8tè.QcÛ¶mÒ××§_£„%Ÿ&ð,Y²D¦L™¢KÔ !•ƒOHE1Â}X-jéôëA±Ý¦O\½2\\“ˆdRÁž?¾(Ë]¿F9{öìs]}õÕz)GœƒŽY³fQì © xB*Š-ÜÔ7©Å¶äç«ÅW¯œç½ Ä* 6âêqÜzë­:>ÑE ̹î¿ÿ~yàœ½a;Èñ‰<Þ Õ.÷«ö¹cŠW¢NIžŠáa2Û’¿U-U%hºD}(I¬ò `£ê6nܨ…åSO=5p.Ïã3{çÝ´iSbËÛîpØ„~­ª]ö©ö9uÈ+Q'„$‚OHE¨FeÌB<°![}£ZàÆGž½žÄ* vÒŒø  çr9ÿ•'öI-y»Ã,߆ïö3ä{ÀZßw¯:‰ß¹@y(>¼@ žŠQ½F-F(E2ÎER«¼ìs]uÕUrå•Wˆ|1B»Ã±sçNY´hQø÷€µžïõ+>““µ!„OHBà’Fì®ô°lø0nV ²ç!Ž(/QK¼+>Šr­ò8‚ |Àœë¾ûîÓËâÅ‹=qÄ~ƒÈ[ðÂªÝæ  !I À’¸¤;g‹þUjA=DëˆZÆ©%Þ?¸$ðUŃ0%$oaÚ’ ¼ß>V©™ôNDMxÉp) žd€óýÒf¨0Fg}§A˜øCÐ ³Òã;.Öx[´!ìŸüä'å®»î M– &ÒÙ3Ú¡Äbw*’IoÀ¹° o¢Ö—‹åh|h™´æñìBê <É^ÜØŸMU1T£ à8 ; â¬ôøGÐG}Ò¤I:vŽò曇Ž·EÂ>qâDKq‚ç»ð :¦sP‘ä; ™ K¶‹Z_÷ ³DöÞ­=¹ý[ä‚“·ø ©?(ð$<¥OÙá¢Ïç!öåZâqvÄYé…è¤-œpÛ‚nii‘Çë¬w”«V¥;f<è²²Ø+’|•lW‰$<¸ù»Ñæ9é—ÓûŸÐ–^:Æ3€™í° Ã>¾3RL8ƒ.ô°|°“pã7ÊôéÓ‹ºÒ“¸Ý]>GjD lÒä;{ÿ<’3ñ‚>ªDŒâo‹xÒó2 PàI€8n”ÞÞ½²uëj¿pÓU7ß’Üì^§!*^:É=Å„ÓÅ…nwúûû¥««ËÉ•žÄíîêÊO…(Mš|gï0ƒÜþ­m³ákñ·E¼RI~„¤žd˜rÜì^§!|Ø[9$÷ NºÝI°)æJOâvwuå§B”À&M¾ îôàö_ºÓ{sXò9ûÖ©^s¦=RƒPàI†©”›½’{ÒN»“û,öUu»'!JÈ“&ßEí?zšäO¿ZúÍ-Ò>,ùS¯ø´NŽ?OT8 C'5Áþý¯Ê’%w(ú².Q/Üt!¢.bŠ›.âôØe¥nÂéz\cäv'áÉ'Ÿ”9sæ8¹Ò‹y†aM¾‹"fÿ¾ùëä@ÃÉ·ÎtëÙwž¨p!†Oj‚+6Ê–-/È¡C'u‰zùঋ㸈)nºˆÓ›xýuj©†à—GXŒ¼˜èCìW¯^-{÷î-êHÃ{P’ y)Œš&[G¯–Þwî-Õ7]t<¯¿F-¶5ߦ–0««œaxé#¯ÙĸrƱ1¥ìp%­1¦Nê <©¶x÷öÂÅía»ßӻ.ºIššpür\æ¶5­Zvª%Ìê †‡sâÜxo9Ÿ¡tj61®ì8¶ ³ÌUÓšgLÔ xRlñF¨²¹¹aˆû=.îî·ÒظR¦NÝ!¹\¹.sÛšG%vG%ê8'Î=|nûLbDZ[áQ±n]ùÞêZ󌩓:O*BP¼¯¹æ5CÜïz~XÜ=*nG.·]Œ·.ÔJ»NÃ:Ãï¶Ï$v³Ì±ÈX=ÛœŸìV-wybêûóÇeIïF™Òs›\Ýó½à5Öa!¥@'!N¼ z~Xܽ÷}>?O?MÎø̫M˜Ûž¤Š-°˜Z¶\wy dè¯è{P¶ä_’CÒ-÷Ë^y@-xuØFH)PàIEˆo÷{)Ãæð9s]¥À9qîáü #ˆ4ÜåaYñJäñø%¯^_•çÁoË>kh¦y…uÛÕ6BJO*J˜˜»¸ß]<C™¦Ÿ&‡§ÊÅÇ΃àæãC”Q–s3Ç9qîbñ{’ Aw9Hj‡eÅ+‘Çsà[ähøóàSf~nª4< V^aÝ<µR À“Š&æ.î÷8@úàæÍĸLf#,+^‰¾~iR«^{l¯vÓc}© xéƒÄ,$Ä!²„D-RKºs…"ߨ*9%À¹|ȇ<1{«>h±#®nâ팱“JB'ÅÄÒ/¼ð 9|¸[/ˆÅ_wÝB…ÜŽÙoÞü¼Ìšõµ*ˆ=á Åĸº'Ì· ³ð#:wx»ºAúó*1{«ÞÎG‰ÅÄÛc'•„OªB0ÿðÃ/ I¾[·îد_Ý[;:N&šì†XÂ,üÎOš§äÝ¿E1{¯€!rŽö©]õ¿„T <)›(·º½¾A]iv,“ï@S“·-ˆ½!%fáGtßüur aŽä[,1{‘¸¿!“ì©xRq¸Ñï¾ûù!–¶ínÇ‚¼I¬»ôÒ³†$ß#úAì}I•(5M¶Ž^-½ïÜîî7„Yõ&C~WÓ{t³Ô1ÉŽT ø¾éÜsϯä–[ Ç R+“íPŠ~Ò1ñöûMù¥½w=…ž @'N@ȯ¼²]š›ôrÉ%gJwwŸÌœù5½}×®¸ÚÃ(eŠÚ¨÷Ë}Ó¦ç :»wæRKØÓÑš)hÃD? ¶Ûÿö¨éê' ¡—qãZäÁ÷hËôȤ/ºì+?ލ÷ËÝ 0cÆ(¿FHí&úaD¹âƒO¡ÌÌ' <) ¸Î‘o@&}XLÝ&è²³ö Qï±]÷რ^#7ÞX™)B‚T3þ ‹|sþE튿[•³zïÐç3€fëVŽW|Æå ž”\çA’LDc'Ç¡LštÝ/^|®Üu×»dâÄ&½ŽJs]ï}Zlè¢*!üpÅ[ýiéPç„èÀž¦ëäÚÜÙÚÕ?Y-‡å3ó ž ÅE|á*GƼÁŽ»`'Ç…eÇ£w?!iò°vhMÝN|³¶á‡+>ˆí†·]ý蘸<Ýõ# <‚‹øÂUŽŒydΗ"²Å²ã‹QŠ»Ÿt)Œ}›úÖÀã`ñxX%ü.Àߦ,sC\Æ}¹™ù$;äòŠîînÁbèêê’öövuóìñãÇûkÓ§§§G È% ¥¹¹Ù_K‚T»¦OÿW-îøÞ½ÿǯ Ë~åÊ-Jœ÷+ë}š¬[·ÐYh1fÃÚ î°þ/»ì,imm,éX^On°Ü(ÖN‹änyPYírÈé2]6˵r¦Ü®]èóËrÚz»wÜé{ÕzWöË Y)ËãêèsÕQ×É¥2MFû[qÝ/-x=¹Q­v‚~·µµÉ‘#G<_³f¬]»Öß<Èúõëe̘ð¬N’]nºé%Ù±ã¸N¢Ã$6s挑ի½‡dØØûñãä–[ΈƒcÒŒKÇÐ5d·#.j[OO^ví:Qôœ„Ô -ýrËì.Ù=±Gft6ËO—‰§äý È«-ƒ  cOåä?î™*7Íí”m§¤_]ß ê:ŸÓÑ"«ŸèïEH:?~\–/_>(ð´àk›j·“±Ì|¿ÌmM-}°xñ9:Ù ­td¹›mA‚ÇÂX{ ÅKbÍózrƒíäF©í´L¶È=Êf‡{.òʦ¿K¦nYï”ÃÚ‹pPºµ7ÞƒY2ÉßZ=x=¹Q­vbÁûëÀ&LÐ;TZà7lØ K—.å…C­¶ð0Þî|ÄŽ×_âê7Û‚àXˆ÷£3€!oæªDÇñ}ÄÙ‹ÁëÉ ¶“¥¶’ç_Grâ߈ŸGo/‡©=· h¾Á¯U^OnT«lýf’À%{Þ&˜I׺IŸdæ:;+¾©ið²,%áÄuòšrån±çØwbC'$º·¹I9éíLz[´‹eÙãX&+þšk^ãÜ1 ¤ž)gèÜòA8öØPàÉņ®…Yø¶0‡«Åm‹#IÇ€z¦œ¡s÷7¾]»åÑöºÃûN x2@1—zR ¿TJíRoØ‹I*̳¦è˜{ó‡õ£g9ö¡À“¢,gc¹ŸÜÆØ8!å‘Ö¤4å>•Žd < Êr6–{ðÉmA ?i’!#´„¹Z‰}¤¾ ÀMœ8‡=¹-,6^->!Y!-aFrÞÕ=?–ž¯ªe~ÍLzB'š8q{r[Xl¼Üùå !¥ä¼d¯ôH¿Zòr¿zÍLzB'š8qÆæo¾ùŠPkßîÀÊ?r¤[¦Ný²LžütÙbQÎð¸0¬gEÐ4̤'x¢‰Ë ÆæW­z0ÔÚ7L3‹x}oo^½ç¤>ÜM—=!å ÉzÞ_ï ̤'x¢‰Ê #ÊÚ7Ì!„.{B‰Wªeä¼+å iV·ôf%õW©×̤'øÆñý½r×’çeÝ”Ÿéu•AF±ñòövCØ~„ŒT¢†Ç•jÙ#9ï¾æwÈ©æ©e¥~ÍLzBaÜ»âEÙ³å˜têÓ%êaDu@1kßlŸ4©UÏU?y2g¤#Ä&jx\9ß„?ÂØ¿í„äû¼×(_Ù~«ˆë³öÍöC‡þ¯8ðQ9x3Òb5<.­‰oøÆ´ù£%×è½Fyú¼ðçQ»v!éeÙR øŒçR·¹æÖ³¥}áX5¥Q—¨‡áÚ®ç&„ÄeÙR ø A½}ÖnùÕÝžKýW›£cëc¦5ɲçʇ:ÎÓ%êa¸v€k\ŸRi›'# |€ žìðýé ¿|—ºkGÐOHeI{Ü<Pà36HœK¤éVOâÎ'„$Öú½ù—Kή§õ?r¡Àg[`Á¨¶ÆX—z—¾ AwþÅ7OgLž”€µŽ9æ ȱO’]OëäB϶À¾æÚ±rÝα.õ´]úAwþ£«ö1&OHJ`l¼M“’øbÙõ¶Õ~¯uŽ­™Pà3@’x9(Å¥ŸÆä IàØøkrgÍ®·­ö^_ÜÇÖ,(ð#¤.ý¤0&_Ãìß/Ë–É’ë¯×%ꤶ)el¼=#þÅõ[?ò À@’ºô“ŒÉ§Ùy e²b…äî¹GZŽÕ%ꤶ _,qn¨Õ¦ìjz®Ï콃Év# üt£ÔLû¤!RA`¡/Y"2eŠWnÝ*¹>/~¢ËíÛõkR_Kœ ³ú™l7ò ÀץЮ ’Þ\’à\÷#5ÄÎ"S§ª¿lõ§òÝïÙ²EäÐ!‘»ïyõUÉ7zñ]Λ§_kìÎÀÕW{‹éЕ_S{(M˜ÕÏÙŒ<(ðuF¢ëšÇd¹"h‰G îUW‰ttxî”>ªîæþzzD&M’îqã$¿`ýçoPÀ]o:÷ß/òÀÞk¬ så»~&’:¶ tIOQ·{©²) µ ¾ÎHCt]“à˜,WCØâ»y³È¬Yá Q· ‹Ã(Áïœ1CrpÏã¸æýÛ¶vÌ{±î±Ç†Š¹ý™¢:$‚"{sÃ|ízoöãä7å_”ëzïÓõ0JIÖtí×/ø:#Jt“¸î]“àìýμ|Œôuç9yÍpa‹o¿'äaÂÚÜì¿ðijº.—“©O>)9¼nûövϵ?¾2íü‹ ¨ý4X‡%(æögBÉx~ÅŠìªþmÚõ®~$oºcK´%Ìmï]ûõ ¾ÎÀ,q­“ÔÍVý]£D$qÝ»&Áa=Dˆ—>./=ð*ãñÃÅùçû/…utˆ—ny%Ò ¶eípíß|³È„ þJ^Oš$²p¡·-æ÷Þ+rôha'ñ|ºí+B´ÈZ¿£&X/>£¾~¡Àט%®û°ºÁª¿c”¨ƒJÅËMÇ!ðïæøi$ü!’ÚZZ¼¯±Îæ~äï‘#Þ>°ÂO~w#ʸU‘xn¼Qäða…¢³Sä E6nê€àcAG^tχe‚ñ ”@‘/›(‘½T¼¾!XOƒR]ûdø¡À×QBtÝã^†ðÚç³™2»5‘×€ˆ¤6#œHrÃ:,p‰÷Æü†Ø†}`…ã½6¶ËÝ·» yøaO°m`©Ã‡ØG+€iÓ<·=BtðHYD‰ìíMW˵¹³õz”¨§Í×þIõûnQ¹oý•Wž8æïIj |ƒ·ãåpÝŸT¢›†ðÚç@«CŽYöia Š+\ïÁÄ·(°O0Á\v™'ü.„u"Ða€5×Á°A?¾)‹¨øy©qõ²xø‘½¿éVïªlÜz§¿Ôø:#*AÎŽ«ça@ùFT¹ÂkÎW`ò):øôIfÙ§ „Ñij zâZ*mmÊÄ»]ä¾ûD&OöWêŸo¨‹;.à3_z©_QÀMtçcL>É•Á o2 Uæ½ä½&5ÿòê —¹4…לï5‹Ç9fTgƒ”„ñÊ+=q ½‚}É%~%¼.õk¯õbòp›ƒï}oPx›šäðŒ’G]PŒm°-Nœñ9/ö:œï´ÓüŠ< è`pòœê÷y”;=jʻ׉Üö޲髅þÎsþu¡Êü䳼פæ ÀgJoØ1]:Ä#„òškü!˜Ø¶é@4!ø&ÎŽï‡ š˜¸™ÙÎŽÏ+K½ûb Æì Æ2·,ÿð^ˆ»I¬³Eû‚ ü,¼‡¼,öP;RYît]7ÂþÝω¼¼»p›yÏþç<+˾_n—¾GäŒ×‹´ŽÑeßEïò7ZƒŸA*!¼ó b2å1™çQ®rXÓ˜™Îl‡P"ãìX“Éncf¶³ÀôS~þóð˜=€¸_|±×á°æ °ìí¬ùàøx3Àqó¥ey‡p§ËÁ—E߬fÀ{‚˜m`ôXõû«ßù}敨“š„OÈpcD2ÊšІD· ø?ý´g­ÛV» âøÌ\ôïÏ>+2s¦×©°ÝôìÙS˜5o’h?õ”WŸÁžŸ¸c:hy‡p§Ë”³<·Å˜mï b¶‘ºÂúË%„Tc±Ãý ÷9¬v#’a@`‘ ‘ÒÕåmÇqàŽË>ȤIÒ3fLx¢XåXð9Ãâúà¼óü>“Ï•GlIN˜UEÀ®ë¶è¼6ÛÊi¯õÖc™þºÁm ‰ +Ö¯LH8œÐ&eŒÅޏt”›Ü{êTø¾°úaqcÜñ¦óAFBÛkq£ˆ­Ú·ù¸ãCࢇhïÚî!øÙÏü>ð2à³ Ÿ!˜Ä‡ÏòÄáÇ"n„YåQ„¹ÓmÑ?s†ÈoºÐÕŽòŠ÷yû´´*•ð<><&W»PàI(¶¨ß>k7'´)[tQnÝo±€»Œ%‡°"Ž¿i“gycâ¸Ìn}ȽYœ@'"*¶nÏ|gƒilÃ\ðø,W\Álúr°Ú¶¼] ý qa“«(ðuÄöÀMÓåëÓwWÍ‚¶g©;ÙÑÇ mÊ!˜ˆW»׎±êÙ³Ý'š1={Y`F» £6ø=„å ˜M_:.].qa“«(ðuÀƒ+÷J÷Ž1Jlû«fAGMQË mJ ˜ˆ·wÔð³ pi‡M!›t( ×Ü,yße¯K¸Ðƒnô0 ÔÁGÔB˜“x"ÂÀû™M_ʉ•Ç…“«](ðuÀ+ÛO*QðoÊê~X º`ŠZu•Œjkä„6¥b?†¢ŠÄ¸ìöP`¹­`XÍ.œ û!¾h‘— ·gäÕëîqãt©3â1vÞÅ£€€muãñaÃèÂð;¡à˜æá:$=’dÛ‰ TÃ@R_œ>o”ú¥< ®Z´=±Ík•ëvÎàøRÁcX!²–xØp·$,X òÌ3Å-oœ ræ‰pVR[Ü"›bãÅ ±V7âüÇfOÃ&ç±]ûøœæá:$=’dÛ¡ˆg |pź3¤uÎqi­¢͉mRdÕªèd´8¬jˆ$b ËÛx¢,ð  \‰hîž{¤åèQ]jQűÐ@v;؈rX|= ì^LΖSÀ‡Ò¤K’l{’I(ðuÄuêê}ò½oÐb 8l­Ž°cð.@¬1ä V5,ˆ:\íX÷–·xРπ™ÅûÂ2³ÀÀ8ydÕß{¯žÉèÒtDà.ÂźžØ9¤ò”›mOê |bg¸sØZ`Çà]À¾·ÜâYÕÜcö&ûê7Þèí«åW¾2hÝíØqnËêVötáP6tDâbê°ÀƒÇEÇçDç#*/ïAGtL¢,ä&ô ›}ÄC¯Cøö:‰c €°¦ƒ-_ˆ=DÛŒ)‡ÈšPÎA¶ Ö!¼ölraÏr·°WxœÂŒÏhìÙïÌÔ¶øNHЋ¢!dø:¡¯³Q6.Û£Ýò:¬æÿr¶Vã ÆýÈ#Cŵ°¦aíB¸ˆ‡Y¾ycÕÃJ7¡€"!ýi Ö×]çøüˆ#èÂïìô>–`\žˆÇyÓ›¼ãÿøÇÑŸ ân?WžR6¹¼¢»»[°ºTO¼½½]Ý/:düøñþÚôéQ7…-ªG¿páBeL(k‚„‚vZÙOåÔS§i‹¢Þ2I)|>'§ÏmÕIxL‚«Íë©iútÉD1 rD_=L«>?lX-¾øüv]a^£ŒÂÞnØë‡W‰q~Áéûìg¥ ñ|„ð9•h«›„7f^•æ}viÜf—æ;ÔM; ~É%Ò÷oÔÔôµ™¿?8¦§™Í|IòSÎòƳ—àÆç}Üjµô»MuÔ9â üš5kdíÚµþæAÖ¯_/cÆŒñkd8yùús¥ÿè`77¶OZ~í¤ôì%Í3NÊäHãÄx«TŸ‹nºINâ‰!„°u¼å-òèg>#­Êú½à–[dÒîÝräÜseüsÏI˱cÂX -”Ѝ}‹m·ÁØøÎ3dêŽÒÐ߯ߋçÆ÷-M'NHƒe}›ãû»Å'¸ÝÔûäÀœ9²uõj½žT‡‹Ž=+S{hg Hš&ÈÖ±oÔÛHýr\ Ë—/xZðµ Ú)Ì‚?uXÝ„ýúÙ ÆÈ’»ÚõþȪÇìw˜ cèGŠ…_“×Óƒz±e¹æ¯¼Rú6o–ÆeËôP5d³ÛrF ‡ˆ$¬`ü:4°„í ôvu.m•ë5ƒûâsåž~ºÀã ×/^¬_‡}Vs¼àgÇz³Ýi½ú½zùKZðU¤éŽÏIîÔ`þN¾u´ô¾ûÓ~ÍÞÇݨV; ±àýõ`‡ &è*-ð6l¥K—òˆít×úMÒtûL9ðx·Ž¹ïÛz\Nu&naBŒY:‡ìz#þ;o†×e™š¼ž0< ±qļ±e0¦2Ôñ§ŠÉeÔ÷Ô Æ­n:QÓÈÏA¿òžŸüDZT„pŽóÏ÷bú6X‰uO€auêþ0ð¾æË¾/ è$ #d¼!ó÷'L_‹î0 {0”Ùö á}Üjµ“­ß~ª©uà~‡…n&ž™~Ñ-Þ¥hWN–½ý9ޱO°)iÍд¨ás;dÄcx¢„ðb=ÑÌúË/ç ãâÕsQ7Œ•omõ¬gd÷Û±{/ĉøìø öçF¢ÆØŸ? t^8'}uá8ùÌC¯Sì©dƒ³ÛÙóÈÅ¿cŸ2ö”¬"g†¦¡„n *„–ì}÷y žÃþÓŸfÊ?ø h-¨šfÖâ6Š‚9q¢W7@Ü[Zf²+°Â 8npH,ö-ÖÓððlz3õ.@l~¨#°|¯+¯Œîxà3à @ª<ƒ¹é1-f¸ƒ¸K°3¯¹ý3"ßúk¯LúRU(ðuJÜT²qâ_ ޱO™°$UXÃo¦ˆÅ8qŒ‡Un\îìk»Þ!¾°taŇ 4€ØbÈ,k¸×±/J ‹{òÉÁ™ìô?~§À€÷ZÉtÔÍ:”°ä“N½‹ó<õTtG X¤K)¢1ï9uR½ï¸Wª:2ñImBÏ qâ_Œr¬ÂÛÞVèΆa:ÄÌÍÓÓŒÐCÈQÚ‰fÓ p“‡¹þÃDV7¬rc}75IÞŸ·^ï=a‚'þqàóÛß‹`' èpà3„ÍAoرÃARÁXÜæq±‡Õõfê&ö\Dc?¼Æ ê¹C bCª žPŽõOB0nø ¥ 1‡u^ Äéí÷âõ§?íYû®á‡(àkôQaå»XãpÉW01Hcw"HùØVúË»E¾‹W¢n µëƒhì‡×T=?™±©U(ð¤€r¬‚±Îý¡f“Êð¼vdÝÃÂF‰::vbawßý®»àš%òÝbîqXÝèD…lp̆gÄ:رø~Ø'¸-û'åfqiíž`g’òð$æ5R¯GI®ãE=¦ž±øÚƒOÃLû€P]áÁ¤2ÄÊ!¤\”¨£ƒtkCh?÷9/¦^ œÉmV|??ožž\f€0N‚ls$þ¡DçÆ÷°ŸŠ‡ :/èô˜Ž€é|h‚.÷b‚fqiSûDuóðšëþÜ{€ÍÔv‡ÏõœÔæ0_{PàIb˜i_j3Ô  Ä˜vÛb‡¨Û˜8{˜;Ïr/æZ‡˜âœHnCÜsͯX!¹ÿXOV£'¬Á>_\šûï‡pÁÆçGG•Aî€éÀàüsæxºµ1á «óAbHšg,î8‘‹½»žÇòà ŒÅ×x’fÚ—ˆEŽ.zÛbb†¢Á" 0¬ú0×:Dû"+âþÐC^rÛæÍ"\ ür]]zÚYÌf§ÇÏÃàâ °Å ǶñðšM›¼õøÜfŸýI†Ó§‹,[æ‰:¾{0¹ Åv¹£,–g,îßþt¸ÈcbïH¾Ã°·¯+«å_¹Çò`oÆâk &¯)öƒ›î~¸àa­›gћϙ”`¢!‰Æ¸ÜK™yÎXä$ʙػwöµÏ3Wý¶11yÌ_¯Rƒ:©)(ð$1ȬŸÿßçÊ÷'+þì\y÷þ&Ùï #¯É¨·“Ü¢€`ÃÝÝÞî èëÕͶpwc_ÄÖ!ÂÆe6ö€XØx{¼Ï~/>ö3³ÚÝîü¤‰rè,7ŒË nFœ]ïÚÔ5d[åH®3@Èm°sžÇÕ5›$öOj <)‰?W÷u_?Ô땨G`ÉC€]€¨"k¢ê2 û" ·<Þo=4Êû€çÀï Ã~Q“ܸÌGoqgb]y¸&ÄÅYÿ‹WŠ?€o'iìŸÔ xRÛºÔ}Þr»ªGйÛa5]ëՠ؆%À˜OÞb@Ü è¸„âž.‰s#¬àÜúð0±®<\Å7Ìú7LR¿AK«_ñ±SjìŸ ;x2ÜìKžV¿{eœÛ}¾ºÏ B9/æ¾OBˆ‹c›ý0—$„u@Æ ìu$ïEYñA°Oð:6.ÇtͧCZâwœrbÿdX¡À“’¸Ýo}“2&«û€º×£D$À$ÜããÛ–·écÀ•ÎAŒ Îãܘ„cØ/¼°hÇ@ƒý’œPÇœ“®ùtˆ_×ø<ˆ;NœõOj < ‰Û}šÒ ³E:.õJÔILÂý$9”[{x[É}û¢ãøˆ½Ã•!ò°àµ3a£ùn{÷zÙúx .]óé'¾.ñyÓ øï/yõw~Ìwìë:c©Y(ðdºÝ‡#ôöd/ņ·!qãDZ_X6>„Û$ØÅ ûØc^çË €¸£30sæÐIqÐ1ÀsëÑ9 z$à²çD6éÄ"añùà1úö`'¢ùîç”Øÿƒzý¿ÌšÏx2Ýî5‚qßÃú…U˜‰ý`UÃòvMnS˜®€.!ΰ°ñ~ÄïÃŽO@pB;£ç7ÛMçnù¨Ùîˆ;¶Å AZäq˜¸ºy#Þæ76Dz;A‚ w¤® À×)‡>ˆN 5³ãõAyFÂC» : ¡–ºéœÐ-Ÿ¶Õn¸¯‰Ï‡ÀpŒÓÏ)ìxƒlǬùº‡_§ÔÂ8ôJxHQÂiÇëQ^zi¼ÈãæÝÖ¦ÅÝÝ©Üö´Ô+Gâ¤Â[ઈ÷ïó:x Í™3üõoð’íJ™1Ôø:¥âl/ÂfUÎÚN±¯:AËþöÛ=‘ÂÜÛ+§Æ—¼Ët¹¹—\âW|.»Œ–z5ŽO‡('®f\õï3CÄk?êØIãÿ¤& À×)µg{`ctô0dPu’ºÄ{z$×Ù)ÍH𳇰Å«ÿ{ß+·Ž© °Žï^'rÛ_xbÚÜê=¦Twy1ñvÓÕÖ%ø:¥Z qqnxÛ‹`3\!âƒqôEh0‰y¦c…ÐG‹½:À:Þÿœ'¤XN)«,ˆ{)âœi͘Gª >c¤Kæ3^„ÉMÊȰºÃ2 >v\nx µƒåÒwË÷«2?w®~­ ›4ãÛ_¯>°–ƒ û}8Ýâ¶›¿TO©:øŒ'È¥—Ìg¼°äû¬äëIÍÃ2 >v\~Ñ"oXÞ(U=¯Ö˜3GúÖ­óß xðA¯à'áÉOª."uÑZ¯>°–Ès‹W: . 7?©:øŒ‘vv½K2ÎéGç4ðür ý0åN÷×÷îÝ+[W¯.îY³¼1÷pÝ£D °ŽÛ^ãW,âÜâ®Ip̆QPà3FÒìzãÒŸü°ÈÔG”õý£B×¾K2_-dô’`cì:¼)¸ÆãÜâ®Ip®’ (ðÃEmŒKÿp¯2øzD:•Ùo»ö]’ù’ž“R-ØI‡Œ[<Ì wM‚c6üˆ‚Ÿ1\ÙÆvé’ºö“ž“ƒv›[Ö;,y[°Ã¬p×$8fÃ((ð#;Ó¾AÝ;‚Ýì„ #lˆ·càmÁ³Â£’à‚ÖþÜ%̆APàG v¦ýá‘ÉÍÞP·6UNRêæfO{ø!$=L.Â=ŠYᶨýúøÆðŽÉ$øH0Ó¡¾ƒ—ЏD‰>f q³§=üŽA1/掷]ø|ô눆?qÍz·­ö{v Âbô´ò Ib厰Þ!îÆ…oØûˆƒ?qÉz‡8ãá1wûV{2LÚOT§€V>!)'àÅ€õwts‘PàG .Yïg ›³QýØNAÚ“ìB¢ã÷°ÚÞE0)Ogô“z…ŸA’ºÊÃö‡X¹F {\§€Þ2Ìã÷°Ú“z‚CðHÝBÏ I]åaûC¬í‹öÅ&°qqýB*H±ø}18N¦ Àg¤®ò°ý!΋|±¾V•;ñÄÐ«ÝÆÅõOqg×~Yò¥%2åãSt‰z,åÄï'ÂÉø ’ÔU¶?ÅšágÅ¿¯-?Û"‡^=¤KÔ+J¹RSPà3HRWyÜþ®ñ|×ý!ñØVû½?¿Wúú=ÿÊí/lׯ+F¹RSPà3HRë;l#ØíŠlrˆç‹û³@ˆ¶ÕÞÓ78”¥±¡Qæ3ϯ¥3æ3ž„b·3if\<¿XÜßî`l}û)ô„„±íùmV»Í¤1“äÖßSBœ̘Ï<xÊÖ#ƒ‚mˆ‹ç‹ûÛ€‰sâ<„ŒTæŸ;_[ëAòê¿iã§ùµ`Æ|æ¡À“PšWf±‹‹ç‹ûÛC˜¥OÈHVúÂóJsc³ú»óæ4îùÄYõq0c>óPàI(}Æ/ïÓ¤î3°Âaq‡¹Õ‹ÅýM Y½.6å-!#Xé?¾Qö|~,~ób™2vŠ|ªYõ̘Ï<xšw¡eqCáRw8' ÓØs±ÈâK?ìs2Ò0VúÌÕ3u}×Ú]Zð!üv|¾ì¬zfÌg <)H€3n»ÜÕÿ¸¸Õã„:ÎÒ·?ñð°Š<iØVú¦]›¤}Uû€;ގϧžUO2ž„fÀÛBŒ9è5ïâVë0¸LÄÃÃn\ßKHV°­t$Öõô÷ ¸ãM|Þv۞̀/–@¤Ø¹(ð9‚0 Œ4²è;ÞÄç;¾Ø1à¶'$Š\^ÑÝÝ-X ]]]ÒÞÞ.2~|s­ zzTÏtËY¸p¡47#ýŠ„Qév‚|åîFyüXNæŽÍ˺}C’ä’°lW£ÜÓ™SâžS†¼,˜˜—»ÞlÛæáàs\ðd“t(Ë‘ÿõÞ…Žï¼žÜ`;¹1\íWüÊÛVÊ}ÏÞ70Ñ Á›È]½K×k ^OnT« ßmmmräÈOà׬Y#k×®õ7²~ýz3fŒ_#ÄÎ\«Ü2úÙÝ8QfôuÊ'ž”‰ùÁdå¼—,ÑÙÝ)·ì¸Evwî–gÈsn”‰­ý­„„süøqY¾|ù ÀÓ‚¯m*ÝNƂ߮,øy%Zði£\x=¹Ávr£^ÚÉXüpá#énÝ ëªêºçõäFµÚiˆï¯;L˜0AïPiß°aƒ,]º”F •n'dº#ŽpDþgG‚]Ò8F¹ðzrƒíäF½´2ì‘„‡8=\ùH¾C|¾Zðzr£Zídë7“ìHdR¬ò¨ánAJM¬#$k˜qì©Ì6ç@ªcãI¦ À“!Yô³Çz‚ŽÂ`<ºîvÝ3Ñ‚_,Ÿ‘Bª³Í9pþÙç‹™Òå쳪ì:#5 ž  蘽ÎûàáNo}Øøö¤Cé©w¢,õ8‹ºRÖ=ÆËÛ%!€O &µAùÔ±Aw»A[çÊH0ëQÚnøà1ª`GHµ‰²Ôãf›«„uÿÔ‹Où¯<ž~éiÿéPàÉlw;HU~é„B7¼qåÇÜñýÇúåèú£Òù…N]¢NH5‰²Ôãf›«D¼œÓ×’((ðd¶»†Áb`•ß>³Ð ¢\ö•æÕï¿*½¿ì•ü‰¼.Q'¤’Ýëˆ}‡ kÜls.bœÔÏékIx2„bîvå{òh´Ë>Š$™ùqô½¬Îh>ˆ*u t¯ƒ¤Âê"ÆIÝøœ¾–DA'Î"Ó¤®Ûeï’9ëi%ÊÙD¹ñ“Zö„Pà‰3Á±î¨CÔa¹C¸aï<ï‚Ok¼|ÃØ·|œLüÔD-îˆÁûÒ1™õÜ,é• w$}Œ{ÝŒ9i%ÊÙD¹ñ+‘ G² ž86Ö=èr¿ê©p¼‰½?¦:“šÕ¢ÔÝÕê/†I¸““ê¸G'I÷ùp’>ƽ¾øÍ‹‹&Ê•C”ŸÙò$)xâLXò]Ðå~°§°n\ð¦#pXéðaµÏ…ÂøJÁN¸ƒuÕ÷|‡Í‘Šá’(W*qqöJž—d <)‹ Ë}вÎíºqÁWr®ú! vJÛK6ÇñõĈìôUÓå¦Çn’Ìæ’(W*qqöJž—d <)‹ Ûþþó‡ºñAZ±÷0t‚]àJ.uØÇ×[dwtìÐb #ÎÚ.ÆÙIšPàIYÝö³Æuヰø}Z á®éµêÀ) ›ãøúlQL„w¾´S¦þÑTiøpƒ.Q·E¶?ß/¿ð¸~¤Y팳“4¡À“ª¿#©«V|ãk¥§±G—¥›ãøúlQL„¯úÂUÒq¬CyC‰º-² ¹™{Î\ý:HÚÖ6:ݽÝúœÍÍrùŒËg'eA'5IRW9¬øÑ¿3Z~üæëõR@Ç€ãëk—ýÊ_²DdʯD=Žb"|ðØAÿ•êÉl§M‘9msdÝ ëü­…¸ZÛ®®|t>ÚýôôõhÏAkS+ãì¤,(ð¤&©¦«Üö #QÇøzŒ³OÒQ`‚^åY¡ ð-[DòJÔã(&ÂÈH·AÝ$³í½y¯¬¾pu¤Èºfµó"˜À¦]›RõB'5I5]å.ÞñNêu C‰³ÐñúÞ{•øù}=”Û‹h`1¾ÿS÷KÛØ6u‰åt‰º+®Yíż¦`?Ë=Î#@ˆ+x2,ÌjºÊ]¼.â5Iï;€¿­ £`Hž;_-c»ÔÔÏÛÖæn}»Æì]÷K‹`B`Æ;©U(ð¤nâ²vx¼m÷½Ð'½/·ˆ£:#qa†°m¦£PðWx_qç«El—ú¢E";wº[ßqÙô6®û¥…‡lwÌ8Ǹ9©U(ð¤n)pYÿ¢Wޝ;.oÛõ69ñ‘ÖxlS‚EfÛf: >6Aš^Ÿ<<w¾ Õ¶lÃ(Ç¥—MoÜoÓ¦äß7Iœ‡l÷=Ÿßø9©Y(ð¤n"Ö'Dšûš¥ï¹¾Pk¢oO&R@ q\˜¡Ômq$y_µ-[›¸Î…kÇ#.›ÞÆÞ`]Òï[l¦9&Ä‘z‚OꆠK¾átuù—µºÉ÷¾Ô[è¾WïÕ¢o [“Q"Mç$·¤ëW ¸Äu.\;®óf¿œu$ý¾i?4†ZOꆗ¼*5.k¹nnò(Õbï‹÷]ð9¥ ãnHnI—üˆPB¹¸ZÀ• ®s܆z˜EïêÞ7û-^\ú÷u}h !õžÔ .yUö½Ò7ಞðûÄ~\l.¯ÞÞW½·IjI;ØI %¤«\ â:ÁmÈ®w±è‹QÎ÷šh±ø›»I¦¯š^46OH-B'uCœ@Ãú¶ÛxÖÐ}“$©¹’T°‡tR^…´('Á­\âÄ6¸ sËGYûAââ÷å|ߨ¸úÊÛVÊŽŽ©LfCÈp@'uCÛ7I’š+I»^„Z#NlƒÛ.ºHµßAk?ˆkü¸&óÅX<žË›'õžÔ .ÝÜÓ¬‡Éu}¥K×ÇÿþøÔÄ<Œ¤‚¤“’iˆ]¥HâZO’8˜¤3bñ 9ïºalžÔ#x’)Þøâõ0¹JǸ I;m/‚‹xÅnåÊÚñ$q­'IL:Š l,üºÖÉœ¶92å4>†Ô'x’)ÆW•·!mÁŽ#,¡ÏÅR ŠÝã—C}‘ÄÚO:ŠñõÍÏlÖñvK5©Ø%%i¼»A|½ml›_SmÛÐ(sÏ™ëשO(ðdDR À/ôê'Ë%IÌ s—ÛXÛà„÷žrKè«´x»4Þ]•  ¾¾síN¹öÍ×Lxƒ$;Bê <‘ `ƒïú.F˜»Ü&,öoïS̆kB_¥câÁãß|sq/BZT25á !õ žŒH ÜÝ6މyaîrûÇüøö>Å<妆u‚Ç_µÊÝ‹Pnç#*Pîq É"x2")pwŸÓ$çD'æ…YÛaîrXטà¹ïª´÷)æp!JÔÒŒ‰‡uÊ9~¹¨p@¹Ç%$‹PàɈ¤ÀÝ}Ã8ÃøH×w˜µíâ.Ú„‚çÒ[€$®û(QK3&&æå¿ÜÎGTRašB²ž"¤amÛhw|à¹ôƺO⺵0´­ýeË¥³³ÕÛ¹ab%²a½ çŸ_zçD%V3ÑzOHŠÅÛ“ì à¹öƺOÒ™ŠÚìÙžˆÎœé­ÛµkPmkÿž{rrË-x;!LÌ£D6Œ —¸v’¤ÓAÈHOHŠÅÛ“×aHÒ™ŠsÙƒBk?'»wOô*Eps×|€§Ÿvï$!I§ƒ‘ž"¸ÄÛ“`: pÍcé{©Ï9yÏ&(jO=U(¦vºÐÚÏ˹çviW}PKŶÔ7o™5ËûÕTt2O˜K˺F<åÊFýÜù´]MøwçÛÉjµô»Mõ²9â üš5kdíÚµþæAÖ¯_/cÆŒñk„B©eŽ?.Ë—/xZðµ ÛÉ ¶“l'7ØNn°Ü¨V; ±àýõ`‡ &è*-ð6l¥K—òˆíäÛÉ ¶“l'7ØNnT«lýf’!„’A(ð„BH¡ÀB!„O!„d Ã&ð°ÐyäéîîÖåÁƒ%ŸÏëm(R_žB©w”•Þøò2Yò†ë%wâ>µ¢Ï[òävÿuú䔘æ!²X ]]]ÒÞÞ.2~üxmº@Ô8 Å<—ËIss³ôôô Ô§N*—\r‰¿÷Èí²eËY¸p¡n'ÛÉ ¶“l'7ØNŸçNÜ#9%èž›SÿåÕ’½@úμK¯Mèw[[›9rÄø5kÖÈÚµký̓¬_¿^ÆŒã×ÒÅîP ì¶à£$„BêXî-Gýš²Ûû¥·Œtžœ!Oî»Qºû&ú[Êçøñã²|ùòA¯–·üO~ò9|ø°oÄÛ-öxØCvƒíäÛÉ ¶“l§à’e¥äº·K¾užH¾[r'ä[ðé[í6C,xýØa„ z‡4ÙñH ³­tˆüé§Ÿ.]t‘Œ5Êß“ØàhÆ ²téRþÅÀvrƒíäÛÉ ¶SÈŽG޵7ŠŒ¹\úó-ÒsôQiw±4œõu‘¦iz×´±õ»ªIvHœ3ý S¶¶¶jËâN!$œÀ(0+‘®ûim±ßý‹ox–{…Ä=HU~òäÉqu”'¦w „Bj‚ÑóÕ?ÊrרrÔ<ÿuu©ªÀÏŸ?_¦M›&---ºüõ_ÿu !„’θUä´…JÛ§x%êÃ@UnøË/¿\Þõ®wé’nyB!™.øö"3:¼²J.ù Ã6Ñ !„B*žBÉ xB!$ƒPà !„ B'„B2žBÉ xB!$ƒPà !„ B'„B2žBÉ xB!$ƒPà !„ ’Ë›³[àAñx”ëž={düøñþÚôééé‘Í›7Ë¢E‹¤¹¹Ù_K‚°Ü`;¹ÁvrƒíäÛÉjµSWW—´··Kggg¸À¿øâ‹zB!„Ô0ÐC¾¿¿_^~ùe7nœär9mú˜žF¥=õÛÉ ¶“l'7ØNn°Ü¨V;AÒ=*gžyf¸ÀW |á &è/ŒhØNn°Ü`;¹ÁvrƒíäÆp´“ì!„ B'„B2Hã…ÿzXhll”+¯¼Ršššü5$ ¶“l'7ØNn°Ü`;¹QívÖ™FFŠh÷&¥'çSà–P^à}sµ4»yó¦<<<¬–P¿ýûeY ³ÒÞZ©„\}\þêìÔŽC»7GPÛÝœa,¼5ÑÑ£DDü.{{IéÁµ×¸Ü±C{ P„Ü„Ãúû‰:;µ’ëò Dׯký6—kÖ24Ô¾7—ÇëÔ!79x”y)se­äz£Œñü[{ÌåÇ8A”Ëi¥ÕJ;@µrsðÆÇµÇ€á9x!7ñ2x<ßµ‹WÕ•ÿå‚799=€pBÈM8x^Í‹y8ó…:x»†è½÷;=€p eÈí×8x^΋½œ@8…2äv‹k^®®3ÌË¡ÑBr»ÞÓËÕuæåôÂ)”!·ë=½>ó(ßDø{òÏÀǶ¸-”!·ë=½>G 'OÝ¿wÓP†Üjq­<ÿðCíSþjôðÙ8jàvþy¼š&@x„2äVʽ*Ÿ^Ê_<²|uÝíE9ã¨Á¨ÑÓ„\çd.n^;ímíތӆ®.ï¦ .¹ÎÉ\Üî`áâM¿6­–Fvo ÆiÃ'Ÿ¬¼NP„\g·WöÐCú݃*aŸ*Òâä"ͽ3G¥\I-¹ÎÏ3§«õVën@ÈuNCV¾=\¹œye†f‡f©8©%™K®óó '»@³!äUøè#í³ßŒKþhhâqëëà-îÖžw2Bh¤Ð„Ü•q«^9þ@œâ½qíIÝëÄé©Ãqõûlݪ=wþ<†áС ¹qìw¿#â·–Ãîô ÀªW–•.½0¦]óÿlQËgwèý?Ê– n«}/§? €S¡ ¹qŒñG;Ëá³[7²œ·ë‹écWcôįÚhä¯ÚU=×*…Õ‚ÛjßËéÏàThBnuâI9|NWÀ­Hk$êx±ƒ¶ý¸UíÝxª•Rê ¯?—UÖŽá’ê¸w~ûmûïUÏÏ`%4!/µù*,å•qoƒñUYÊÊsíj™{ù7߬ íùYî™ùkqQÿ «ï…Õxp[hB^áÄѾ}•y5ãð•q W[w2o6†žÏKç/Æ«òüFÖ/ýÄ—|2þ=Vó~€z„&äfå­°³g+dü¼:×¶Qí¼ÙÜ;?ö˜~¾ô_òÉø÷˜G«ý,« ]ÈÍmi©~x\í¼y¥ÞóoðBèBn÷âæÚ Çùqµsø•zgÌ¿Á ¡ ¹9X\7Ðn8ÎÎáíÞ,˜¹‡çÛ&ÙP‹Ð…|¥¡³‘Ý0š_s:‡·{³`æžo›dw<@-Bò•†ÎFvÃèj†ØNæÜÆÞ~µ=t€Z„.äNØõöNFeNÞŒ½ýj{èµæççåoÖêøæÝÝÝJO—Ón`n€›áW‡{éÁÁ(9#Ñöí2 —6lhQ®Ÿ£ˆÅd¥ÝiÉñh÷æj»s†»ººhzzZͰ”N§åL&£¿\‘Íf)‘°þ%¸çÈ‘tîÜ:ež¡H¤DÛ¶}N‡ ¿ P½|>O©TªrôäÍ夷G»7‡0=¹ÌŸ•4à’Éä­Œø=::JøeóÚ½9‚Úîæ cá @p9€àrÁ!ä‚Cȇ!B 8„@p9€àrÁ!ä‚Cȇ!B 8„@p9€àrÁ!ä‚Cȇ!B 8„@p9€àrÁ!ä‚Cȇ÷'´{sµÝ—ÝŸ†p@ȰZˆÿ8íùÚêlíTK®Cx äX-ÄëïXO'ž?A¹ŸæÔ’ë¹b°ƒ!B 8„<pÆ[¸!ä!€3Þ !¯ÎxÈÁŸò€s,ãÉ2»×î¦w»Þ¥…‹ jÝM1øBpN‚Å'Ç<½ùiÚ•ÜEG×¥M¥M4÷Î-N.RqJëáÝ€säý !8'Áâ“cŽÝ8FÃÉaº·t¯ú\q²H³C³4óÊŒZwΑ÷'„<àœ+ñ¸õ¥¼Vz¾8GÞŸò€s¬øqŠ÷Æõš†ëü¼[pz­?!äc^hcæ`Y-ÆñU¾ cÚµüZîiQK®›®þBÈÆÉB›å1úbzlKŒÚ¾ÛF±Íú5ËÜ_dŸAÈÆÉB›Õ1Ò‰:^ì Ö'ZÕç[ŸlUëü¼SN¶ëÀò€q²ÐÖ¨Un'£ð„<`œ,´9]Œ«öÁƒ !'+ØZåÆ>x0!äàX£FÐX¹ÏñâÖŸ g~ÿŒZ6s±«Q#h,„Üçxqëô§§ivaV-±ØÕBÈ}.h‹]Øfó„Üç‚¶Ø…m6ÿAÈ}Ž·ú¶ôQ[¬M-ý¾Ø…m6ÿAÈ}Ž·F~0Boì{C-ý¾Ø…m6ÿ‘æççåBAûàã{wwwS.—³¼?9n†ï½ µ;ÏÁ9Hg>;CÛïÞNCß ì*|Pß9Ã]]]·îO.¥Ói9“Éè/Wd³YJ$Üû¬1x#ŸÏS*•ª„=¹ÿ¡Ý›C˜ž\6} ˜H&“·0âôèè( à—ÍCh÷æðM»/^!š×Cr-ÛXsc$Ë%*üãYµÚ²þ}µ,Œ”ç—\§¥árgÿ{ˆäµ}ÕÏ¡y»¨Ý >v×[ÔÖÿ*Å6ëW—YÐ ¯ ä6 Åv*n©~­¼HÉoRÇwz¨uOV­·>ÙJ/v´FÒòBà¦òm·jõ{Î{¶À¶„ÀMÕœÑæ„ÀM.}¨ÄM9€›\úP‰›r7ñê» *qBà&—>Tâ&„@p9@£TsˆBÈÅ'Ûi9@£˜·Ón¼Ý”^!h”%Ûil±)½º;÷'¿r…¢ƒƒ$“¼c‡†ˆÖ7UQA½OvÐÕÝîJoýŸ’‹Â%Ü3$>™"G:iñžI½æ®e÷'O§Ór&“Ñ_®Èf³”H$ôš½GŽÐºsç(R*Q)¡Ï·m£Ö_­]|jŠ>vŒ:.\ ë==töÐ!*´·ë¯Çλ”ŒÜ®dDR2"+¹¡dä?õgÄJ>Ÿ§T*U ¹=yˆ $]S†!:¹Sy—š¬ÿ]*zàI§O“T,’’Ü×GÅ‘ýÕð@OÞ®¶»¡W—ãÛ©øe´Û =tsOÎ`_By?Ñ®–f7oÞ”‡‡‡Õr‰ýûe%„üQx­äºî¼Sû;Ë_ú á²b»CCµÝÍvgáíøqRÞ\-¹nE™»S¿v—\·ÓÛ«tçú—Ê|ªãNÈy‘íÄ RÆøZ¹Ò¢ÛÁƒ¤ŒˆxhÏ%×í8}ó€y»…66F¤Ì¯U\ޝò1¼ò›ÇùóZ}ëVg#¸ÅÛ×:ü¶T;oC^ëðÛnPí d¼ ¹Ó¹»™Ý Ú)@ÈxòZÙ°`+!·Ô: ß…|Ém^¨u ¾ ¹åm^•:?µóMÈ-oóªÔùyl‹ÔÎ7!Woçj!ñ›ç°-Pß„œoçÊ·u5Šÿùç?÷kl‹ÔÁÝ×qö™,Ëêm]YËÔ_Ô²ðçH޶`[  ž³ÏôÅôØ–µýh3Å®òõ±û¾m1€:Ôr«^»Ž³Ïøv®|[×Ö'ZÕm°Ö—÷i·yýí0¶ÅêP{È­zmœ}à;µ‡Üª×ÆÙg¾S{È­zmœ}à;µ‡½6@ ÔrôÚP{È rÁ!ä‚CÈ'nÈë8@$↼žóè"nÈqW•¸!7ž‘Çff0l‡P7äå3òø–³’Ä÷¡Å°BIÜ—ÏÈkkÓn|Ì0l‡’æççåBA»" ã˜wwwS.—Ón`nÄ›áG éôi’”€ËÊð]îë£âȈþj0±ÝEÔvç wuuÑôô´ša)NË™LF¹"›ÍR"a}qÅ ‰OMÑÃÇŽQû… 4ÕÓCg¢B{»þ*€xòù<¥R©JÈEïÉE€voazr™¯ hÀ$“É[ñ?ztt”ðËæ!´{sµÝÍwá T9€à– ×¹‹ooo§‰‰ ËáúÉ“'iïÞ½6zíÞAm÷òºÚÔÔ”:l_òK—.©@°qG½iÓ¦å!/•Jtùòejkk#‰Ï3(¿CXõòÐ8h÷æj»s¤gggiãÆ‰D–‡ÜŽyÕ¼voQÚ o‚CÈ}I¡?v$Ò£>J---ú3à´{sˆÐîUÍÉ x0\Ñÿ†ѲM;,NIEND®B`‚pyclustering-0.10.1.2/docs/logo/000077500000000000000000000000001375753423500163675ustar00rootroot00000000000000pyclustering-0.10.1.2/docs/logo/pyclustering_logo_01.png000066400000000000000000002200661375753423500231530ustar00rootroot00000000000000‰PNG  IHDR12S­¯bKGDÿÿÿ ½§“ pHYs  šœtIMEâ ;'S- tEXtCommentCreated with GIMPW IDATxÚì½YŒeY–¦õ¯}ÎÝÜÍ="2£+«2³*Ç ¨Õ4h‰@¢Kâ©Å/Hˆ—L!@ˆ–º%j x@H4bB¢Z ¢»iMuWVfTeFUfDÆ<ºÛè6Üñ,Îp÷^{íkînæë“®Ûµk÷œ³Ï>ûºÙúÏZÿ Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ãxjè rLÃø¢À6†a†a†aÜVè3>}ÆÇ6Œ/ üÏ Ã0 Ã0 Ã0žkòkÚ¯+H¼NÊû Ãødð_‘øÞ0 Ã0 Ã0 ã¹âY‹šHQ?œø^{¿aOŽÌ¸ð…÷\{¯a†a†aÆsdz14Ñ¢.´)Ã0ž†.^hÿ=þö†a†a†aÏ ŸVÄX'^dkRÐð÷eÆÕø¾X±L<ꟙ˜a†a†aÆs =ƒmeÖE†RÉ´¼Gî}­îge|ÚñÆ ™}±°¨sïëÜ{}• ±®ÜÄ0 Ã0 Ã0 ãFBŸr;M¼È´½GÇ{´±5ê÷[6†a<2 £Î¶¨E‹€)€Iõuæ=Rb†¿_Ã0 Ã0 Ã0ŒÉ')'©…†Z|¨KDZX‰ÝêÑóõ÷„BF-‚†ñtÔ™uÆ¥hq‰RÀ¸¨ž_Tß_b%jÔbF½Ÿ¢ú<›a†a†aÆåiE _À¨µ ÑÁJ°ˆÇ@@okë›Ä^¨Ä`oÇ«ç«Xйz¸yîm¦ò Õ?a€©þƒ_­zV}˼zÌZL'ÆEåWªÓòÞ/ÇÀÕùÒê¨+êÉÉgÌÕ\` 'ÞOÕû™b7Cj.w-¼—øZždùþr_«óQcëj·DÞÁ{eùHe–E¿+†ÆFõ×­­oþ5  ø«€g¾8Pƒ 2$TņàÍÔáâë”±Úo-*ͪ†Jhb<_\Y±D«ª4ÃQ Oä‰.ˆ¢é`Ìqüωˆ“UA( ¤µ¸ÙŸ)˜ "V¢R}=BAÉâ›çÑyq -5¿2|±+!š[(ÂL¨Æp,,xן=Aƒ˜¯”2HVãŸR£æ ×ʵâ}°|ñÅ»ZrM×¢±\B,# (æÿ€GŽ«¯§ž q‰UV†_^2 Ã0 Ã0 ÃxžE éQ—ÔÙu¶ÅFõذ±½ý­¿ÞÜ©ö¢«µYµXÑ„Ò$Ä% ]¥Â{‡§Œ¬ž{Ág´RÀ×w½S"‚¨7ûñ#âz !ºøŽW(âG¤r(s<‡£ CîÕF^Fq¢ T¢„®æ“êc§—úpòµJZî´š+ÿrƒôÖ…±VÇy2Q T*AÀSfôäEü²M|+% ­”¯F4óH&dȵVgû4SÅÊgAfý4bÆà€‡V¢ÆV¥&uy‰yd†a†a†q+D )`´Qf_ Pf\lذ½½ý­¿!"Ê °n2+°ŠS×¥ý7a#‰ì 5Ö¬ƒDjî¬×Â'‚on„• Ïb5¶æ˜)á…àŸ_¶ñ$åå6~ŠÖdZ°—ñ°ëz‰"ž’ {'¬JšhD^®Eðº¯Cñ*y#N•ÇÓ‹/jÁb5bE OÒ„ÀŸµCY$þn‘¯H®Öf­Qµ,Í•pákj‰e¾¢ÇâóC«¬_Mc]À"ŠbñøÀG>®ºädŠÒSc‰¸s‰a†a†aÆ { £6ñ¬KHê ŒJ¼Ø°·½ý­ÿ<ت HáÝI¦fÏè(¤”P³ ˆB†Ü­&’±jùC&ÿX« ¹.w!¢2Û€üQ‘*ý0ªÒ€úxT‰âÀœD) ­&…ª“Wª‘<à‹(8Ÿf3b]§bTóVË ÛÉõj®šÒ‘fÎ98„œŸ ÷np( °)Þ¢9Çò2P)ðx* EDÁ`êl‘z0h5²£oµo¦0™gu=µ­ê}úk‚¼sõ²xüÒêÚÕcªV3Õâaõª?IÞü2ù³Ñ¬ëø#[­~¿ûsŒâçÕ瘰*‘Â…‰†a†a†a<÷"†ôÀ¨30¶jcgçÛÿiðWÑ!yrA|SmLI"ÊnD /œ£@ÅhR÷£ãùQ§ðShë¹PÂ:¢Ué…¯P#YˆxÔÛ®®-ðÂ|/¥`¬þ]{"ò²ªŸÓêÎ~¬¯xc…gIÞ{é¥UI‰_(C‚ˆ?P^Åèµ8ॖ GA5ü}‘”?|ï\ÅšXe&x”+q¡^ož©hZªg‹›ÒÕ:e.¹Êxu9<ñHÓº¨¬<áKÑüÏBw@ÌóNw•ñBáõO¶ÚÖ¹Œ¹x§ú<3Ve$ !f ±#Ã0 Ã0 Ã0Œ+bhe$”e$µ€±[ žÑ‚0W1´¼ N« @òsúA=iÑŸÌÈ?o‚À•ÈÐt¤€²m-D4‚y!½”>X=×zÌ ÄY^¿ÒHÄæž¢\‰@äeqDÕ$äE¼Rhð´â`Hbc‚Ú#¬ë1o, qPç¡‹P«p¼•ˆ=ñ9‘Ð|@á~¢ŸERTóF_ aý"¬Š5›àÚå/\ã&Dê8DákuþÇÊ…¶Y£ñÊOÍ~²ï2ŠªW—(ËHæXyb°l Ã0 Ã0 Ã0n OÒbUfbÔ"Fmä¹] OC Nx¢×µ~Ûññ« reŠ=99¬ÊEn)ôìw÷<Ü6l)ø Þ‹È÷SÓºi¦0‘G]Ýõ~\|yè©/!%¾~ú‹_›Õ23Ëe˜­½ú'¯çZÿZQÌÿûJ°˜ !£ÎȈšÕ†a†a†aÜTÿ¿\gbø¥$#[Û;ßùM·„Z ¨J1ü‚?Aƒý¸,ò¼çrdYYÖ†Ëreç}†b€¶ëµâ€LS gwÜ+}Í }Î;£g;­O=O×2­ôtç̬ôÄaFQ`.°\.°\Îqqq¶j“âu‘YµûÔ8—ÿ«E±øoQ¶Y¡ìRâ·\5Ã0 Ã0 Ã0ŒçFÄð㪔ÆFã§XL”ˆTùF¼ R¬p-äyy«‡V«v{€V»<ï"s-8—)·ÎŸ &LD¿OŒ^¹&ë§ NŸ&à}ê š>¡~ }D®k›Ô®>©j!,2žv®è)ŽIŸ`þŸèm‰mü;Ì¥€ÁÌ(Š%–Ë9æó)¦Ó L&ç˜N/p|üheÕÊbm†›~ eg’Kç•1õ„ Ã0 Ã0 Ã0Œ/bøyð²­jÝ•d¼³ó¿\i$Gþ‚sy#\´ÛCt»èv7Ñím–_»c´ÚƒJäȽΠ«¸lmðGO˜¹€«³+èIµ ºBPyšýðšsP&áª,ú4óݰò‰Ï›=¿Iå¼é ‚þh;zzAàI¯ËU×C]{ë~®ÍÇMvاgÕ"–Á\ àÅrÅb†éô§8??ÂùÙ1F£m\\œâðàCï3X;‹x*QÕQǹÖoÅ|Z §Õ㫌Œ–‘a†a†aÆ 1ê8Ê÷èM=kcä¿5¶¼h‰qxøÇp”Áe-´Z}t:côûÛèî`0ØÃp¸‡^ÝÞ&:1Úí~)bP8JÀµY#qØ 4u7ß¨é ‚ÀÒÚé,Z/$ü5u I;Γf—$š†]?Ÿ"û@;ºBøÐæSžÃÔmК÷&J/jÙRþuN¨-òÐÚùƒ;èö·ÐíŒÑj÷‘edY^zf€°¦IÇÕ¥#´>¶•ºÜ¦Iå—Ûi;•wåõæ)}"êr*#G§Œ5êŒZïŸ×ÏOJT!Z?$ÆæûÈs¿2›ÃËPPχÃF&~—šu¢B]Au©Å"ÑBÔU"ÄÚ¬“ú=ÞXg|q®6ìDYJÂ(ÀË%Ë9æ³ &“3œ_ãôôNN>ÆÑáû8é¹eºZ¤z*‘‰DrÄ“de1c]FL!á·»iûZu%)ÅŒ²¤d¹˜c6Ÿ`4ÙÁx´‹ñxÃÁúýMtº´Z¼úêÿÛ¬-Ì>«¶µ¥?Æ6€½êñJ±².+Y&´+Ã0 Ã0 Ã0ŒÏ]Ä~š'FeXß× ÛtS鑵ÐîŒ0íckû°{ç«ØÞù ÆãÐì¢ÛÙ@Þî!smdY ä\”‘ È¡g$øï ^C"KÀ· ðƒ÷tÜßÝ—‚‰Ÿ™Až§"%²?DÐOkÒG’wý×%”41Fd1ªéâ„ òAaBHJ¸H‰7)ñÈ/mᔇ‰Ì®áPž#ŽE,>Ô¬Œ” !ÏGˆ`É’ÄÙ>ZöÀÅ*#ƒÀ•7ÆíNNîn¿|Þé£Õj#Ër¼úê?h.hyžT€'?°S‰;>D™Qÿ`Ù†a†a†aÜHC2êLŒ€ÎÎίþÕt+CñèЄ€f.”R–Y,B, h€Š`@ á¢úÆ -ʼnù®ƒ9?ó£Ùî |Aä~\* EŽ›âý@WŠY”ÈìpñúIe‹òz0YyḺ€™ËAE†ÌåȲÎe We2(Š¿õ[ÿ þï¿ÿ?UNü U çZŠb~X Û†(3¯2ûoÒ0 Ã0 Ã0Œ›.bøá›1Ze@¶j©ºjªŠ ¢«}0†Ã{ØÜ~[Û_ÁæÖËî£ÓU­TsséâEs—Û)?ÖÔ €00N $]Z¢«¬{qš "QùEt—]lhŠ’ ÞÅ;‚âó¥5B‰ œâóŒ²]O¤Wx•á˜{Š"öæÛEêHZ¨iÄ.!,¨Z†¸&‘°ð$þ!W­û®~à´,5Ç×w™EQšu–¥%yÖBá\)Gt+¡cY`±Xµ`õÅ%âpÀoiØ» ` e åNõ¹w°v«†a†a†aÜܼG++i¢G"nŒ:ö:8üQ™…‘÷Ðëmc4¾—0ÞxýÁÚÝ1òVÙ.«JH¨)¹r<Šð{æ8¤~­yÝûÞ75 ¶ã8?ž9>qöÞÛø xß7ž¦,ÞçÇ­\ ,ƨ§${ßG´´óâø\ü×§yLyQ8œk_ì?Ÿ7Äøåøê÷þ<ø…C'5¾vÌž™¥XÄáù±8göÇáùÉ)¬Çª™Fw½å5„˜/mGó_I/DW•_9Êàò­¼v§‡noˆÁ`£ÑÆã;øßù]¨‡š}†»‹²ëÐFõµW}æÕ†>†a†a†a7MÄðÛ¬:”we3òo;ó*]•z8d®…v{ˆþà†ã_@¿ÎyÖAFy%‚PÄ1‡-“),à ×ÌéR‰,‚ÒX]ˆ¿úAm½ÿÆ Ñ;/Ö„qÜäø¼˜S 42Ȇüð3” Ù»¤aðÏáYv=ñÅ y®Êy2‡«ÓÎBÒ*9Ï‘AñuѾ×DMÀ`Š×Bá§\ßÁ.)!d%©ò‘'Reˆ›#ËÚhµºh·ûèõǶ1í¬Þ뛉òJA™yQ·OöËILÀ0 Ã0 Ã0 ãÆ‹¢°b•QvG¨ãŸ0Ïžk#ï ÓÝÀ`°‡ápýÞ.ºÝ äYŽò0SJüR¨$E„a°/gC@f=p¨³ ´‘£¹©]QÈó‚2f3X¾‡âlö Šš@âä‰Rlð3)„¨¤fpÔÏ QV‡Ÿ‘!31¤XBÐ… H]еIYÞ˜¢löæ+±IÍ>ñÇBâÚ±.š©©žÔÚãuëÚÏ4i²€ÊÕ™¥F+o£Ýî¢Ýé£Û¡×¯Z¶RÙ¥¤#½¹ÈQfcôQfa´+Ùa†a†aÆM1dÖ<¨ €ªðÿðð8—#Ï{èv7Ñì¡_µQͲ.ȵÊî#έ7Ò…-P•e~Àª»ÑÝoÿ½…x/ÅA3i5‹;é2c‚WAf$®ÈÒ hQºrŽš´Q ±&‹AHM2ˆÅ »wjBJ\¢£ˆ,Ä%¤D(öÞSè%'RH‘ó¯*!ˆ×Lõƒøú°\b}i"4QŒôË­' WpX BñJeŒ[™{fY ­¼ƒv»‡^wˆ¿ðÿÍjêëÌ)^ «ÿêVÊíê¹eb†a†a†qcx’î$kT…0¸&PYŸ_u%ét7Ñëí ×ÝB«5@–µA”bÐöÒ+Áð²ˆ? ò<Äþü€„„Ö"˜Uý$E Ξ¡¤ðK æ'ø¹·ßzÕ˜)P7e*^[Ï` Åþ¢`ÙŸM'Ùï âí§à°sHm¦ÉbŸ¤] ,_@\â™%âÍ!…R®K"ãþ\ÈÎ/Ô‘8ô¶§@Ê:öMDxåøý5eMkΰåçKçÊŽ%yÞF»ÕE»ÕC§;ðÖT´šá9ñ0Ã0 Ã0 Ã0Œƒûd›•©è 1‰€™Êšüö-´;cäyäZL^ Å~ ¬ë%M#zAx䱯„Q+Ñ2+ ùø%X bì$Ëð™y…F¾‘ñ§'p¤2EÈÏ^梔ÎjÐ^W *幨õ ˆ|NÔùV– LRæLÍæ)‚%íXËhi®e¯ y:Z Ö˜³FÓâ™mR(sCŲR†‚ 3ÃÁeYÙº8Ë‘·:h·º¡$GæÊƒ"ÓÌ< Ã0 Ã0 Ãx.E ÙU’êtôU&5qš£ εÊLŒÎÚí² e­2 EÁi3”ø|?s<Ð(Ð Zp(²fÀ¡$@t-aÅ ”ãq«TÖt‘AõºyˆxÅ›!ÕeEˈ> j ®+6zÉMä“´gGJÄ‘&¬$ SS¥=žQ®‘Bm*Ç“k3Uöx‹Ô¡”†CBl!/ ˆ I'ÕQ‡\m’[‹¥AYé‘‘e9²¬µ¯|ƒOFJ¯0Ã0 Ã0 Ã0ŒEþï%íIywœWw¸‰e-äy­Ö­V™ëÀQV¾¨2d¬”qˆÍü“D†“þ>ÿî{T–ÁkÂ5Û¯3¤ô³ó½ÿ®?%Ž̅ߎ•”ò¿TAž“ܯR’"Ës¢ã)þ °,"*ïi(a‰Ñêºr}äyh™,B_‰Dß[ÃówÅRæ›ç„Õxƒ±Ká@–,‘^JÃBð Ö8é¦*…ž¹ìý\- «Ú´“àP––¸,Gž·jùÑ[0, à Ã0 Ã0 Ã0n…ˆ¡F–äw(iÂ'çZȲ6ò¼—µ@”©iþ2M•H¯ ß8¥„Á"!¢ _ñм‚L …€àü„øÐªˆÇ©ñЇ«„ž+µR¦‰¡v ‘¾"¢‡z,Ò;¿QC_—T²HpHyÇÂi‚™æ+QJBñº"áyDgP8öü9êm5{ RÌFIŠ(þ,ð³QVB5ϺXH[¸†a†a†a7Oâ‰Á«[ĤB¥¹ QV XQDµßTµYç„°!½*D”WÈÀÓ-YƒîJÇ ©2P¢U¦z^ >ƒ_ú= åÔÕN,ÉÒ¼s<‡Dçqlöý4—6D%Q9I™öïßf/•Â*PJ™2úÁhà7AJö¾RÆ‘ôË€r‡Ú/Õ`ÅË€…@¢” Ï /àMzn(ãSÇ)˼©”â@=_õé=3"Ϭ—%¥:ò<=O‰h?©2(þÂ+²,”Ä?Àâ×d{[’ãõ3i´rÖ× x‚$Zè¥(¬ ¢dŠ“2%Í·J™R·›¹S#ÕÙ†a†a†a7›O”‰ÁUäó¤}9ѲÔÿ¹¼s½õòƒè9­Ùçš¶«~ «µÜÔºi,Ç~M}†< 7Èf£Z™I§b½-£–|Àœ.Ï©÷IJY4©TË:´Ž-©qÉìÿ\IY#JG“¨‹Š"x@Éf $®·"4Díe•sãTIŠòZ4…œþ| Q^¹ÞÄöRGªË¹â³W­ Ã0 Ã0 Ã0ŒçXÄ  P%OÔ 8fdUÐÛ\Bø1P|wYDX)Pb´B‹ì¯ éjÏCNøðå)jKP%ƒCŠ;Q{QŽïÒ«AyõZÁú9øc(àù^SËzŸ…Ò¦¢¼§ÐÚ½²âUAŠ÷ˆ"j98îî!U›TUPˆÎ%šÿH$ŠW Çבá)hËñ¶òÚiËT>¢ò)(yÇ]eñ -Ã0 Ã0 Ã0Œ[*b4]AD•½T¢;äJæ±×ýƒc‘CARÁZå© ^{JUDàX0hü+Ø3îôc‘þd(p,lßS’6W‰n.ÉŒN*š9jâEÆœ¼ Þ¡e$¶#$¼4Å`ÔNgj›áõHytÈãÑ:E8Ç׊™¾6 ‰j)NS3£%eADk:òþ d·Ã0 Ã0 Ã0Œ[)b”­")òóÿñAš$‹T@ÇJà ¨f¡2kY Ô•; 6Y?S|¬(OÜÔŽÊFIG¹áUâ†f$ª™UBdÑ,Ëî/ʼDeuÖ‹Œ”“T‰F ÎhÙ7e8P‘0ôd¥¤Èï~²®5ˆrl&eΤÉ'®X»R°B,ªIóVͬSf"ïqn¡_ŠŸa™†a†a†aÜR£ñà ÿ»5xwÔýl… ¾ƒôÀŒû¤º`D°¿ïDWÕÛ@ ¶9!^ˆqÈþHÅ DÀ›ØáÏÈXH $Õ4f˜œðñÇ¥ˆHAµ¯)ùPº­ÈN”ºVªÚã fq÷ùþB7’h 5Z‡™ùu€I‰\)ñ º`Ç)qnØ=Q#¸N…æ£B¡¸bú…a†a†a·_ÄÐo\Óš „d)@"ˆ|4Ñ Ñn5i  ‘ªB¢ # h)ÜŸÚÏZ€É±ñ$4q þž®V ·ç”ÙÁáu Åq7˜d™…&æ°^X’å@“Q)òÈù_'†pXv\³„˜Â a,):¬C#ž$®¹20•¯!ÙCÖå14á„B‘¤ ÒðQze$E¬ Œ«m‹Ôù‰@™8ašØ7Cv@‰e®¤­‚,!)®Ü kÅDS êgUø£~ P$.hâ J®‘­Â‰¹)SO™…CJŸí¢y\h0¬ÍããÓès%Ê·V¢­Z«ò•RŒa†a†aÆó,bT¢E#fp(m$2¨Áâ2 ŒJBFú™RÐà”¨Àº©'„GŕޢGʧ€ ]ÕAwÊÈ3*W2gâ{ø¢N4ŸD)U Ú…jûU‚äHèîó ¥tžâÚD õ8 o<ŠÁÂ4Öžª™#ð2!x}QT¦á™‰JsNR|18¡b¨Â'ÊrÄÉQµó•Øç»ag]‰ IDATX6†a†a†a7Ÿümååâ7òéŒA Nq XoGFÉ,D‹¨‹¦—/è@è 0`õû ¤€âV¥²Ý)!,](°ê®lVŸ§4•"€&`2Òç“€d-Å:“PMá‘»!_ ò} Äü5דâv§ä]Kò÷KºrÀ¤ì[ˆbDˆ/DµO"íD⬠’"ƒgÈJkZ„2sÆÏôóJ\Ä|6Û±"Ò¬’ ‚ùôO+¸þ¯Cˆ×’‚š-DÁ\–Ç X&†a†a†aÏŸ,£ŠÀH|R"h–»„ ÑBÛ6U–A¬ j§Žd÷ ñžBˆ$šðì¤!öÏ~[RiÊ©µ %‘9¥ƒ‹’¡ yyhׂ€5*“ÒED9'R„—+«8ìÁµó³„ÀÁJ)ˆ_*¢µUKB´çÒGB)ímV¥“ˆÈ )‰=#UÞ#E.ãdñYI.¬^w ÆOŸa†a†aÆM%ÿä›ÒZ½âIÄBá1yÙí 2£DI„ûû)o¡#¸‹]«‰,?SÀÏÌ`Š4œèî>8~ŸÌ!oŒ¤ˆ/ªƒ¦zü¬?cƒŠ ÚIÁƒÃŸ‘˜s^›óð¶:Ј±¼~F‚(Ά@"KÆ_cÍ8®Ê4añJ¯¹d6Œ‚õNâ:%h™#Ð3.H¾Eä¸C ¤ˆ¢“9ÙØ0 Ã0 Ã0 ã&á>ý.<‹ÏD×Õt‘Â;ßš§ƒf m_^–KA S–Ÿ0ÅÆ™¬ˆ/²«‰ ú‚L…”˜y^ˆ;ô@ÂLRÌ«4·”~ÌéV®ÌJ›N(¥#©Ö¨š‘j¢miPJÂJÅ&¢”ò",Èö¬¢=/” ™éBrþx±¦kŒ÷"iígdZ‘Ö¢Vm¬t·á+öèbbòeŽi†a†a†a|AD _! d x+ N¿'Ž’*ÔÌÂÿ}¡•kHßbËšçZÙ”¬ ))sÆf¼H¨4ÐýE´Ö­ÁPŒ7RcÚ®ñÏ`Ísƒ¡¶h•ÝCü²üÌë;·Ô‚˜Vâ£urÑZÔFþšÁaY’Úq)‡\¿Í† ´RªDy•˜Ö `, YIÆ"ÑÌ3A¥ÊÃ1¯É†a†a†aÜRƒ x.°ny”ðBðÇÊŠ(ÁZ9‡¿ )]8]Êã{DÚ%åt9ˆÚfTëÒ"²SR­JµÖ¦Ä^¦¥#Õ×bÍõ‰ºâ_—À[„×ø“ˆÏA”žHÓN¥¬……B,Ä<­µ%c†a†a†q›E ƒ«hÙ·ˆû®†A™4RÔÒàÕmd -EZµšôgõ8´¦•%⬠ÑîU´õ$%pm„ Š…šàn9ébKw+­DU#T(FÒœñä­Ù/<‰ŽÉÛ;±.t×Z¹fœhAª™ye>P 0·Ûe¥„$BŠXäà5ã—þ'RÀH­wMÀÓÖlËË´¦Í.tÚPmñÄ Ã0 Ã0 Ã0Œ[)b0•ÙUdLDêsN´…Œ"}'=•õµLk.ÉcÊ’Y¢A¡g¨çwE—¤¬:‹¨%RÈ‘ââHjµàW ì½} 1Š`lcê‹Úþ´N(¾HÄÊ9'æ³^h$Ç)J2¤‚ĺU;›ÈõD†¨Z’*fˆëWˆÏ 'Î9j3,?CM&UUZb™†a†a†a<|"O ?JKÖÓ'„YLj¾ï„ð‘X'†‡­¿qS-j‘©$bƒGF˜'Çž¾÷ܯ™"Í‚„#;†DûPLDIx€ÔûmƯøCsJáù±Oƒ6§ò¸2³Å߆(¾ÒË"ê Cá8¤Ï„ïE¢Ù…wm¤A§¶h§ Ò^'b\É5柧¿îÅy×s׬i@Ï$I)*Õ\úaT5 Ã0 Ã0 Ã0Œç÷©÷Àe@DQ$ç½E¹³ è~ê]z¡ŸÔ¥#ª¿„ÿ‚¸ã]øÇ(A)'7ÚGBÇŠöÏ¡H!³qäyHÁ‡´1h¬¯KÿTÔ1“R&B±×‹l¬è0kÒ+¼Ô#Š;Ù†a†a†aÜ*ƒšDvZ?¬GB¬†Š·‚–UÁTy^­‰èU ÄéàW †¯èðῬ•y0¯RÁ,+%Hzû#o¾ d)PœÑ ÛjA°Ö=&* JӬͥ÷ùª‰ÌØàXIªJ6Œk`„éeJp±ú^v¾Ñ®”¿‡–‰ÅØÖ¡‰`´¥¤xD¼~½>]mH-h˜Œa†a†aÆ-1Xæ¬C‰â%#*±À&Wd2%)cÎ(¸öõ5Qà˜:®ä¦Ì3£l_àt^'€@éÌR‹J¯SÁs”áq…P‰”jTÁŸŠm˜Ë§hŠ#Êf°. ÅïÚâŸ7Òf™šHåï“”yÕJ¢r!>˜wù=+ûà” "ýc‹cé m†a†a†q D Àù9^ DzÀ˜œ’:8!$b.MIŠmFe$®ÜÍÖ²?XOr:¼²Ë†k¡d Êø9ŒïÕd¿Mkr¬šø£uOѲh”RY ¤–Bo EHhÞ“H´²–HÐRÊ:Ô–©@²C‰æŸQ-¤0‚´Ø“òì(ÄZ[çñ¡eÉz ¨ëIå]ÃRÒ°L Ã0 Ã0 Ã0n«ˆAà•FÐ:!+d7ŠŠ¿ Z@¼Æ_a]`¥õk~ÕÀ}¯„zö8îÂ)‘Ešc&]2EwÄ¥5¤8FèŠ9#Y&¡tÍPMR51E 8´j9‰"¾A§l÷™0t]W*²öµúº`dˆHè%&rÝ©9VæM3‡]gl N_¤ÖtBøkŒkSsŠ5β†a†a†a·MÄ(;@¸ rÀ×Á…A%#6%”"„ߪZ0/UVÌ¥§B+ 'd,ôÀ5Ø—7&zèI‚Pån|ä•€tAý iY(W•à@ñçY·«-¼ïý÷j^ ”CßfExð~J‹QÁ8AÉ/i.HÊß‚ãv¥,E J ?Áµ•íjY7¢õ·Ó´BÉ€Ášµ(^&b(È¥², Ã0 Ã0 Ã0n±ˆÁ~ÿK?}Aqxd%p…¨£»ÙÒ¼P1w$å®¶Ú¾TŠ#¬—¬DÁ®/\ám?P*QXß{eIñCÌ“Düýˆ‘T‡)êÈ,&ExÂJ­á”ÐâíÈ3T 9O¤Ì•ßQÅ«‰‰²„ORé¨Ò§…µý+ÂVt}µù…nºÊÊõ-å2‘¯ˆìF’Ϙåš.Õ ªÊÁغ“†a†a†ñœ’¨ŠjëxšˆÀ¾³¦O‰6 AòJ” 60T”"‚÷½ß1C ~I¤L -F–øb …" (,}hÆ%Œ!‰¼s÷ÞÓ<÷36ȼ¹RÇãmÏäù„P(–ûAÚHÕŸ?¤ω¶¨RñçJíÊAÞüyÛÅ×ß{¿-K±'UƒAÑî‚5ëÓßù×P®+¥:—þÈyÖ Ò,>Î^HÉXIjV\{–íV‰9ü<†a†a†aÜ6~Lš2 „Nq…¸ë]TÁžüqÛQ-˜ôƒi_0‘A-)¿Á²ZÉ Âƒ€Ÿ„x=[¡Þ'É."ˆ÷5 ?óƒd™‡6v¬‹À8ÒmXT<1„I\Ry’¾€CŠàe»X«PßÚúT•¼Pr'Šhå]sÒ„ Od€¤”5\3R„ ‚†/jiÂ…"âX¿ÁÜú볈….i*ªf&UÍšHxò†a†a†aÜDܧښ¨ I‹ÕÎZik^JЈÊ>’^©v¥Ð³ð™ã'eœâ}¬ Þ{¹ç¤yB(PZ ßÿ$YášÙ)<¿ ’]@ túïÑŒKÕÎÊüçBáë~ÖŒïAÊuóƒvµÃ ŸK/Æš¾­›‹X4©n7QG1W)o éW¢Î£\ÏÕ¼ôªò€E«UÃ0 Ã0 Ã0Œ[+bÔ‘.y>¤jZE” õë|&X ‘\5óJEÑü)4ÃÇd ž|£®´&`; üxÍû Fª ¤ öI1LÕ.·66éëÁ‰ë¢Ì§l+*·‹2 kE3èâEÔ¸(Ÿr^µsSæ5(?Q.4§ NÅ\ ¡@5$„èâZ$EMÈ0 Ã0 Ã0 ãÖ‹µÁHŽë‚XVî.kF‡MYÀº»ýš!-:]:T±BEXdV0ëA(+Á/)ûvÇ]b"±Ä߆҂NªMhôzBHˆÌ3z1çÚ`^#hÑtÚPÆï^w—hßò5ÍÀ•Ä5¥¸;KÊ+Em%[Äë ê.ƒxÔÙ:A†Ö´ƒ•Â\¢sͪDË3ݨ` J Ã0 Ã0 øå"†4¨ ´%ƺ2x&ŽÅVZWbP"[¢ûõµu‚ô¶›$ƒQŽVN”{0Ç¢G”™%0ööD $Df$;X@+sšìÐáâ‰ùR·.ä4å-œÈ†‘×@iÏ«u”–¥ÃW‹J5EªüCyÍ«˜EY›þZÍ•]oBja$e÷i©†a†a†aÜZƒ¢'Ñ·œÈ–ˆ| $=0dµ!l«Ö€Z– y2$^ü¤·Œ5e"(d]ωE1‡‘X E ¥\A=–(”¥Ú6QËš¬Q‹Óĸ¥ñ$³ 7ïõ²4 Ö³äy’Pá­;ÒÛ±çOÊ:’~‰2ÖÊ?ªý…¾`å1ÕyYã»!Å£¸T$5Èw¡nsb†a†a†a·WĨ"ü+ÖïÞC °£€MQ28µOVRú9lªbJÃË&àÕÊ+(Þ,)×Ò””ì€&ÐNÍ‹rž²ËHd®ÉŠ`Áqð-“¤Éä:@ñ^€ÒÚÓÿ>2|%½ìEŽžÀ¥ E¬g°®Ã%=žŠ+ˆ¯™o2tÑÖïšù%Š×‚&€¨ã¸j]¤ö¥‰&A?ZAÃ0 Ã0 Ã0 ãfó [¬>a_ÆD‰‰ÖA³( 0/ÑÜ®ZABøZHãDR†@Ú6^ÛPÙÆ•´ÓòZïóZjÊ횉­õ˜Ùv“8‚#·Ú%Ç­Oƒ–ž%èÆ®Œ ,—ÀKpÕó–ѤRâÒSâ\´¹R¦7hCJ¬¿æÜ‘UsĤ,(í•5Dzª”ë/Ûù.‹Ì¸J± GakZmm±XŸ!®˜W$ÖüšëApÁ`(Š%–‹EymÅÐñÅ0 Ã0 Ã0 ã–Še8$ÿÞ¥•}xA[ôñrÅr‚ùô1–Åà¢Ìó :ýÝW (Š5Ñ !JDñÅŠŠúº#'ŽG‰ˆ“(œ”úGÎeȲ6òVYÞUB†ƒ!s.üiàØÏÀ¿Ù® Õ>‹–Ë)¦³ÇX..ÁË¢ Æ{v«ëŸw4g¬ઘáoF¢´ËïÉ9d­.:í²V¹Ë“Ϋõt Q4ŽÀÜÓ5ä5dŽ36ˆ€åb‰ùü³ù9³K•ðF•Rå¤<ö„⛲™.†x®zÌ 3Wu+• å2,‹øM6 7…$–‡a†a†aÆ-1HÆCXçë©™<6f‡Eùb‚óÇïàøä5\ž ^Î@Î\\¦Š~ ¬ÞÝÇ*óáʳ#¯ ìH )q»œÖÈ@ƒˆà\Ž^o ýÁ]ôº›pY ”eÈ\­VEÖFF9@ç\T¢áŸ;{"G-XÈÌ  Ì$X.gx|ö!Ž_Çã“w1›_ÀÁÁ¹ T?*1ƒˆHæ•uxj2)™=Q4*L–µ1îb{ûeŒ7ÀµúpÎ…™)$2]<³òJqüŒx¯±² ™Â¬’åb‰ÙüGGïàààuœ?~„e1/³DªœRj¥d%§ÄÏ®@¼¾‚Ì‘ª~‰™Á\ à%2ÊÐlaccnËe ¶Ü7éF†a†a†a·JÄð£å*Ò⤌áÜJ«KFùì ÇǯáÁÞßÁÛ¯cV̹í¬…¼Õ*ƒêºÊ'åsŽÓŠbu“|Y‹%0Ÿ1æ €¹ç¶Ðê<@¯·‹|ÿÇxÿýÿ™{ óÙ yž£Ýnù .sQÆÊu,×R¸@#`,—K03ºÝ.vw^ÆáÑÛÛ/¡î÷ÚŠÕ‚h(«%1 Ã0 Ã0 ãV‹~¤%‚ä+£Xqœ Ær1ÁåùGxøñÏñÎ;?Ãl6C§ÓA¯×C§ÓAžçȲìS†7f´2 Ë2 GÑÃÅ%áì”p0£ÓÝG¸‡~ƒÁ]ôû»èv7åËÊÌ /‹ 0¤ô»^0©däà(Ãáá“‹G8<|óùívÝn7šûÏrþ¹É.(ív›[„££}Œ7_@§;Fær¸Ì­2rür/+ÃÏF‘^~¶ƒß†”5»\,pqy‚ÃGoà½÷~ˆóǯàðð03:ºÝ.Úí6ò<ÿLæ‹«]Q(ŠRÄ(н^››}\Î^ÂÖæ²yàÍ‹g Âk?À†a†a†aϽˆÁ Ð*8jZWPZÈð»~ø~\aËbétŠÙlfFžç ‡M0ýYÒ×|ÖÏ©* pñ­lñp‰lãä>Æl6£¶pÒy€ñÆK ÛÛA·;F–•bFF® ¸ÉÏ2@¤eÙ²ƒÞ`ãÍqx¸‡^ïÀ9Z­z½ƒ:N•a°Ê.¸ÎkàÏMœE"Âhè0_áñãÐïï Ë:È©Ìñ»q9A,ºË@”¯xå#œðÒÅr‰ùâ'Çïâ½÷^ÁùÙq|ü¦Ói#¸F#ôz=´ÛíkÝê9bæ@ÀX,X,h·Ûè÷û˜-Z+_¯+WšEýœAVQb†a†aÆm1|3ÇÆ‘)퉥B±Š­Ê2Bžç`q÷î]ìííawwý~? Ÿg!Ã@ë¯u0º\.1›Í0™L0™L*A§@§}ŒÍ3'¸˜~Œ÷ßûãÑ mÜG·»nw Ê:py¶èT!WÁ:e9º-ìì~çqvºÄææ‡ "ŒÇclmma<£×ë¡Õjùu ~ö…œÏçs8çÐïo¼uŒÉå1:\–}‚e¹HÐúBÈ@˜­âgj„¦žŒ¢Xàòü?ú)>þðG¸8Óéý~»»»¸{÷.vvv0Ðív‘çùª çšÖN-`ÌçsÌçsL§SL§Säy޽½»˜ÌÇÈ\ ‹ÅÔûüqhƒ!üB Ã0 Ã0 Ã0nˆÑô$a*;4=8/‘°Q;q-F]é)Pgܽ{/¿ü2îÝ»‡ÍÍMt:dYöÌÛ føÁèl6Ãååeð˜L&˜N§X.çt†ƒ£‡øðý0¿€áø {ha¢ Yæ¢@Þâ›×œC«5ÀæÆKX<øu¼W,1ìÿÝÎ%F£Q#"mll~VÆuÍMÙr—ãòòÓéD„,ŸãƒOÑ›#ouÁTއ…÷…ôɈŽã­ÇÈ+Ã{ºX˜ÎÎq|ô.>úøOQ,߯ÅÅ9Úí6vwwñÒK/áÅ_Äþþ>666Ðëõ®EÄF-ðÈ5“ç9ŸßÁ`° çZfÁÅoÖ‚—²Cl©†a†a†aÜV£î–P•èõéßñ–Yji—ªF‰1±³³ƒýý}¼øâ‹ØÞÞF¿ßoDŒÛTRâgøwÔëlŒ‹‹ \^^âìì ggg¸¸¸Àl6ÃþÞCÜÙ>ÅÛï`:yŒåöýÁº1Àmdy^í_ú.ËÑélbsó˘ÍÎpðp†»{`0hc4agg'È0ðKK®ã:Ôs ȸ¼¼Äùù9...°µÅ8<>Ãtz†vgçrä”I "ô ¡ø5 V‰AQ—•å²Àr1ÁééGøè£?ÁÅÙŸb29„s[[[xðà^~ùe|ùË_Æþþ>¶¶¶ÐétÐjµ®=K¥½êurvvV “Þû`£ñvi;¿ UO´á*­ŠÌÝÓ0 Ã0 Ã0Œ[+bøa°WSRBZ_âg?b<ÞA»ÓÇr±ð:ù'ÎÁGØ0 Ã0 Ã0 ãöŠCM×F„a+5†/pDeÔ”*Ôí*;úý>úý>F£Q“¢›º”ȲfÆr¹ J‹E#dÔ"Æññ1ŽŽŽðøñct»Ø¿‰Wz‚éä1ŠåÃñ>ÚÀey`ôéïM÷çÐr ûw±ÜžááÃN¿‰^oËËKÌf3E,Ëš²’ZÈ¸ŽŒ ?`_.—˜Ï瑹kžOp÷Î)zpYʪ’¿\"ÌÊhÖnáefÔÇôô¸z-—ǾÄññ{øàƒc9 çç§ÈóÛÛÛØßßǃ°¿¿½½½&cHú‡ó- Ðîa<;ÁÛïœbkó É~‡ èõzØtÝþµpRX•˜,—KüòW'ø;ÿ×&“òVT8ä. –'+KV××x€Zx+Í~`>Ÿckk wîÜÁþþ>ö÷÷ßÁ`p-Y¾ˆQ?äkD„‹ËÞû`„~ ­V‹ùlÍ88êÚb†a†a†qKE /2ôn_Ge$œÖ?Ø ¢ýüÿî¾ –¯Ó‹á¦PŸ›Ÿç9Š¢@·ÛE¯×C¿ßÇp8Äp8lÊ<prr‚oóü“÷prœÃ¹ CwzȲ,è¸Ñ”]ø .C§=Âp°Éäo¼5Ã7¾~‰ããc ôûýÆÃ÷'¹®l Ùf¹\b04^óùc|å+gxýçÇh·pÔ*M>kãYß@ÖÏBQÊGš¤„êËbÉå ŽŽÞÆG½ ð;¸¼¼D·Ûm²0îß¿½½=lmm5¥6×áÛ¢µ­;ÙÔ™:EAxåzèö6Ðn÷A [¬ùŸv‘eôû9—¹pškŸŒê9d®ÞpËK||>| À):z½ºÝnS.Q #|-íVëówÎ5‚F»Ýn„Œ:€ÿ3_šàÝwO1¹¡Õê\†<Ë‚,yÎä—’ˆV¬  (–˜Ï.q|ü.ÞïG˜M~‚ÓÓG "lnnâîÝ»Øßßǽ{÷°½½Ýyž_K‰/jÕ™(µ_Êt:3ãµ×{Xðz­²¬…¢X®>ƒì¼ZLý´b=áëÚk)YW6@f»†a†a†q"FÕ”uId¸€°|„D‹¿µ¥/ni!@f¤ÔbF«ÕB»ÝF·ÛE§ÓA§ÓÁññ1~ã×&øý?xˆË‹ ´ò\7Ã!h$#õ'ªËJúè÷î`::Áoa<>@çôèõz¹g]âáù:¦Z,©=9‹úý>&“ ‹¾ù þᜢ3Âe-UO-z!¤lÇŠZô`Ær¹ÀùÅ=ü=ü&ob2™`4aww÷ïßÇþþ>vvv0¯ÍtÖ7ò”-U§Ó)¦Ó)æó93¼õîƒÁ­v·êT„çLž8ä/©ì˜háuXYàÖßC¼Ž5¢†'ä£Pž“xÿó4wŸöÃ0 ðßu†a"Æ'ø\†/d¬ù SO° O+hÔ²3üGìŸá׿;Ã^9F§»<ï 4OÍš’ ßȲÀª¤€(C»3Â`xÓé)Þxs†AÿGGGè÷ûèõzA6Fí]q]ç_gdäyfn²B†Ã!f³öv'¸»w‚ÃÃ.²V޼2¿L¤^†~‡„BóEYFr|ð>üð'àâM\\œ£Ýncgg÷ïßÇýû÷q÷î]looc0\«€Q?÷ÛÍÖY³Ù ‹%ðÊõÐéŒç=8ÊÁÄ(Í><ƒÝU•×¶ÆD Àõû_Þ$~Ù½ÐKDx‘™^hŸˆ‡Ì®K„3ºDÜ%r-f^0ó  Ϙq‡|Åò¢˜üœùäõùüèÀRyÕ×ZÔ(Äÿœ|çP>®û:ù0 ãæü?zSÿ¯2 û]g&b”YeÌñ'‹×*›ßvJi<¹ Q—-ø¾~fDÙ­b‚ÓóS¼ýÎ#dY=·"Ýu÷ - e·’¬h£×ßÅx9ÁÁà ¼ÿá›ðËJüò _XI‰/Ÿö¼ë²çZ­ºÝ.f³úý>æóyiòù÷ŽpyÑCæ:eiL%¬øÝrVÙCá‚$‹å‹ù%NŽßÅûïÿ—ç?ÆùÙˆ¸{÷n“…±»»Û´S½Ž2’? Ã0ê2’Ÿ¾ÖÃr¹^¿,kUŠ{bˆø 6zÆðn^ã_g΃¿Æì~Õ9zY.aí9y]ˆ¨MDíz×åÏBâò£1°ƒv{ù1sñcæù+E1ýÃéôƒ—§fæÞcé |ƒ‚„:%«~d³UžùG¡:ç¥7/ì =†a|þA]aB†q˰ßu†q›D í6¯Q-êšüÀÌ¢(Ü~Ý=UP_ôÐjµ¼y\‚âë¿8Å»ïb2¢ÕêùÄYÔ6Y ^×MW—•tw1ÞÃobct€N§,+© >?˲’ºc 3£Õj¡×ëye¥ÉçkµÉ§kÈÁ9!Øx•Aî>—^“ËcþøÌ.ßjÊHîܹƒàþýû¸sçÆã1z½^Óö÷Yâ_C_À¨ËH&“ æó93¼ýÎÃá¨ìÎB.6Z`!â1£TpD}ÍíýƒÝî¯ÜϲÖ_bv‰ˆ›ÈuCaâ³ø g{DÙÐúí,ë#Ï7fE±øóôïÏçÿŸËåñÛ&ÕcV=jQ£4ŸÓšáð×>ÓcžýÁתsž˜¸¨¾ÎñE“á ãü_Úï÷Ÿðý‹‹?ü‹UPçªÏ¡/Àša<רï:ø…"ÆJˆXÕ%§]ìüü ™½wûd>á_h:˜ôz=EÑ”0ŸâÛßœà~xŠYwŒ<ïp GÑ5 bZäê²’}L§ñó·Ïq||Œ^¯×”•Ô™×]VR u6F»ÝM>¿<Á;ïbZ™|:—\¯GQÖD¼2ó<9}þ(ÞÂÅÅÚívФ6óFM6ʳ,%ñËH| YF2›3~øJÝÎyÞEF9È .Ÿ™ú:†·ïË ì·8¾Åå$€Æã_/ùïî/;ç~mµ¤è†|ž];ËÚ¿ ´3ÏGÿNQÌ_Y.OÿÖtúÎÿ,œ¸¬D9VÙÅ$PøjuÎN8Ýõ5ŒÏX¼øÎoô=çÜŸ«^ßЩDŒEõÔVw’ísiö»Î0nŽˆª´º»­xì³@²ßöÒ>‘ŸšºÔ¢Õj¡( t: ƒÆøñK/Nñúg˜LÏ0o Ñne ΂ëÀfÉ€¸6zýŒ/áèpŠ?~YvŽƒƒôûý&Ão‡ze%RÄH™|~ëüþ?:Ek:,Ë+–„̹UÖEÐc¶2ŠÒÌóòò‡o`zùfÓ#Àx<ƽ{÷ðàÁƒÀÌÓ÷ù<ÊHþôg=,‹ ´;}¸¬&Š –U n> ø¥`|ëd @ƒÁ7~hý[‹þuçÜðy»s­o;·óí,Ûü·‹ââoÏfoÿwE1yÀc!h̰òÓø¬²2>¥ò ”w£N|X½6óÎß~…Ƶ‹îûÎÑo‰Ÿ?ЯÞw ภ¸ê4x»{l<Ïkß~ׯm1šO81˜Iï/è—œø©ü~kËú±ä§¬qù¬[¿ÊÒ’ZÈX.—MëÕÙl†år‰¯ýâÿßÎО]¢•wÊN%L‘!(Êräèc0¸‹Ùüo¼uŠÍñÇȲS“@yùÒ ðßu†qEŒ2%½¹iÏé¢rY.R‹¤[7L¼àOaÔñY ²Ô"Ë2´Ûm,—˦Ôb2™àÁý º?>Ã|qörªÊ¢¦Žž°´ò È· îa6}Œ×~~‰_ùú ŽŽŽ‚–«¾Ùhí]qBÆ“˜|þÞß=ÂdÒƒËJ“OÊ2Ot[õ‹b‰ùüÇGïâƒ÷„åü'899€s›››™gÝd8~¾e$3ƾÒE§=D–wá\G.øœÐCÙU’M•=U ¨ÊLžó?º»Ý_yà\ç?tŽþ2®Ïtëó3ºÎÿ¥,ûÚŸŸÏýÍÙìÝÿ£ú#ç¨4êìŒÛZ‹¾_F„òNo@ŸK¼a|QÅ‹ï;GÿÔïÿ*Êr’Iõ÷äiõÙ´ Ë0ìwaÜ<£Ì¨¨#\¾Rž¾'ÆMúS[/ü»ã© úª@öºTpßn·ÑívÑív±X,ðK¿°À«?›‚‹%¸º÷.V¥Ù%Uû·Ðîlb4~Gøèá Yvƒƒt:ÆèÓïÔñ¬3ÂÀn½ÉçWé?}ýyk€Ìµà¼®,#"3ŠbË‹ºÝnTjáw+yÖç~•Éç·¿9Å?ø‡Ñj‘çeÖBæ@Àb±Ä|v㓲Œd6}O@DØØØÀÞÞî߿ߘy~ÞÝH¦3Æ~ØE«=@žwAYèɈŒ¨µ*¯ù0×Kž·?¾{½_ýÝ¢Àæ¾p‘eÃvûÅ¿BÔý…ÙìÝ¿U ½JÌ8®Þ6¯‚‹ç]È ñ€ýagÏB¼øî?àûιâîg€U)‰‰†a¿ë ãf‹«Ï7·µÕO‹Àªþê”·Ý!ÿ^·)],‘˜!ƒè:X÷³ êŸùmP붨ŸEyI=–<ÏÑjµÐjµ0›Íðâ Küôõ9Šb ÎT]¼ún¾,'iþe #‡"k¡ÓÝÄhã\âá£9ò|Ò”•Ô¾?Ïú|ŸÄäs>ŸcïÎ÷îãà04ù£,#™áàÑk8|ô#L'ob:b8boo<Àýû÷±»»‹ñxܘy¦2m>-W•‘¼ú'=06Ðn÷á\«¼nµa§áµ/^û ¦àú>?|­Õï÷þ çèßøBÿµCεÛwÿy¢|k:}óAy'´íuyÉm2 ÃxFAR¯÷Ý–ßûâEM eÖ—]†aÆs bTF Ü”\uV¥P‹Y–áþ=àO~VTQÄ-¤§xsÍ rÈó.ý;XÌ'xó3lŒßÑi#"hmWŸõy¯3ù¬E€Ùl†oüò¿÷wO0™ôe]˜ L§q|ø>þèUÞÆÅÅ9Z­VSFrÿþ}Ü»w¯1ó¬ÏçY–’Ëýšpa†a<"סЪ—’°ˆ‡™Ë¿ªý¶ž7åOj¿„¤$ë¯uzÿb±PËKül‡<Ï› ¾~03òzý]L.ï᧯Ÿà_?ÆÉÉ z½^SVâûGÔçŽ4ù¬ÛËÎçs0Ÿák¿tŸ¾öíöDE1Çã“÷ñÑGŒÙäU\\”e$›››¸wï^xáìïïcww×bæùÄe$SÆ~ÔE«3@žuA.ÕÝHÈ«Baóñ«Ï$?ww‡¿ºÃLÿþ¬ý×-þ#Ï·¾Ù鼌éôÿ«ºZÿ?2 ã +^|çŸ#¢ï=CñÂ0 Ã0ž?£L_—-Àõ€¨ð„Œºý£™Ÿ×_Ô~ Y u Y‹‚v¡µˆQvÁ(ßSgøe­V«)¯èt:M€}Y Úþ|OŽ:C¤|>Å Eã‹•O …ÁnÓfÕ‚«×(ËÑín`8~€ãÃK<|´@ž_6mW»Ýn#bÔówçëgt: ƒ&{æaŠ·ß;ÇlvçrÌfqtü&=ú Šù;˜Íf‡¸{÷.*• qüøqœ“DÎAǨÕjˆãB¸n€{NuqáBŒVë{–¡Û©Áó¼>€¡—‘xž7¶2’^ñô—R7« !l}{X“=Ó/%‘Úß…@¥ #ÀSÂóðï‰èíåíú–æ9ΉwÄq{MÊNŒÄþP±f”ŒŒ2ʸˢV;û>!¬B„¼(£Œ2Ê(£11âÂû$wÀ1”Р®‹A†Ƥˆ{šIe'¡€a9©%àÌØv ’¥&É-Å>þúYàÕW{øÀû[¨Õzý²Ó~u/“ù’|"ê !07g—©ÏŠÑóØœðª8ÌDYcÒ,TÝÂÆ1l¬5qc5À »ƒõõõ>áºn_àt?ËJ”ȧeYp]7À›ÎFxåü‚Þ&î;áêÕ>ŒùùyÜsÏ=8uêŽ=Šùùù¾ɸÊH¾òÕ¤ŒÄu¼” D¹y¥¤icèÄŠþüËÍݬ ºèdæ³õúSÿ‚ˆ¾³¼Ußê#l»Z½ïÝÎW[GH¬Vƒ %QFwOX–õ‡e+”QFe”Q‚Ã’F•PQV’+)Âe74XwŘ‹U•Xö51 K°“h€Aéî7@ aA¤'ÞÇ„ f‰ÍfŸø³Þþ¶&|ßW Œ¾Ð樬VóÉMRV2;# û"%È‹&è:†Þgšä»¨y‹ˆ£Ó¸x¥…¹|Y‰bcŒª¬Hº%nò½m<ùh7V$ªnRƒ” 8uêŽ;†……4 ¸®;¶2’kË®,ÏÀóf`;U u#1WY—HžÌ©¨;–äl3kæÉccÔë羈þëò6½›yPwÝ{Þ‚ÀðÓCœ%ˆQFwG”!e”QFe” ÆÎÙ˜žá2œ&I4ô­údZ«ŽùÑ«‹{êÉe,†„f"›K¾•/KÓ@ÂíÔáVfñâù5œ8ÞÄ¡…äsuñÏ"ûÑý2t} "‚ëRޛ´è¤!à“^NB:añ=ÔjKðjÇðÂËëxìõkØÚÚ‚çy#q+1E>™®ë殞:bee««GQ«Õóóó8zôèD¸‘ôzŒ§Ÿ©Âuëpì*%e$Ùçh]f–“p^Ŧ[‰.âš"" {œ´Õ¯ç=z?WÞ¢wŽsèÁ(Z» eËÐÐÐK ÅÈw5_e”QFe”‘_•lÉ2ÊØƒ5G„¤¼ž†O³"ëÇ"Û„1MSÀÐ µ‹Ï’!Á° ¶HQâ—ä…‚l‘”3|éË[xôu]ÄqÜ·þT ½.ð¹ß@†þ»m'HRfØÐ@ 2vü)‡gYp+3ðǰ¹ÖÄÊjçXð<¯/ô9в OU@†þï–E¨Õ*èt: "Ôëu:t‡B½^ß×¾¹YÉ—Ÿ­‘”‘áä?2ú¨èéÇàÓ@;¡ß©l”•LNT~އË[ôÌA•Êé7w»Ï­j F'ý=Dž‰Q.”Ê(£Œ2Ê(c|¡J>õ²ÏòÙ\F{ bS¿|$ÑÃ`]ë3[kÉWa’D“µ|Öéþ Ì õº–Ø“¶£MÈ1Ì._ÞÆ‘ÅM03fgg1??F£(Šà8ÎHÊJÌßq()àìštQOݬ¬2`ãß²2åVÒÃ…ËmÌÍŒ§¬DwQ ]TÕ¶mÔëuø¾"B¥RÁÌÌ êõ:*•Êž³dnµŒäòU Wt7A’Ž ¦ !ºÃLî1Hàô?R&sκuÜQ«û>!ÄËÛó‡eysŽsôñ0¼Þа  •AºPŠË–*£Œ2Ê(£Œ±†¾Ñà#ÙlP…ße”QÆ^€ ‘%¿*1"*)ØØëÓwös»Çc,Ì×À h6–é5hRYrih€ N'F«Õ‚eYØÜÜD»Ýî;–H)S­ƒÑýĦ@«’d>f !„2KM´¾dö=Ô¼%x½ãxñå <þèèËJôöÔ ¥ âº.‚ @'¹›ëºýC  ŽºŒ¤Ûc|á‹i‰U‘ "‘_ýö6€‹~i‰¦1ÃÃÜð}ñÏË[óÞ…ë{( Wβ   `+2zHv~dþ]Fe”QF;Z­Œ(Dƒ IDAT§5‹ÎxÀ½–Ò×-ìÝêIéTu¬¥Ïé®d”Ïç2ÊØƒò¿&»óé¯9%9ÿ+e™S`L¸ç>#y/Xý3™z”ÆqŒn· !Z­ºÝn¢·Ç ʨ" ûÄÔ(¡\˜í _¸j²àº3¨7Ža}­‰ë+!N9ã++QÖ«êPª•J¥0(v†:§ýˆ›•‘|éË5@ÌÁu=íh–0yÀˆ†´}‘öLQÕú /ÚgÆ6Íèõê?F„#å­y/çƒ]qÝc¯‚«Š‰±©:£\$•QFe”QFXðÓgærúú&€ Yü½1¤ñ][H6Êçse숡%Cɯ • á‰”©'ÁydÔ³³OÓ×’7];Al œn´KÖ}f°Œ…0o¡Ùl‚™Ñíváû>¢(‚”2÷]û~'Ö®3Œ“25Jú×uå ê#„¹¨yK˜‹z¸tu|n%Eî,Š‘a&íû!´zËe$—-\»>ƒš7˪ÐÜH·´5õsɢ̾d.‚ð5KdU"EãGëõ³KÀdº‘$ýØkGQkCÊnKÊÎsØ¢.3D9Q­aYµ9ËjÂ;B$¬‰¸ÑÛ‡ï Ãë¯0Ç­t¶„•¡ëc”"Ÿe”QFe”‘-"dìF²àp´eØ^~gˆ¤¤¤ `=ýî¨|6—QÆž‚ÉÜåT#In¹0±Õ]R‡Ò~È ›–:€AB XV’nm©Ý½2= FÌ¢ …no ޵†íím¸®Û/Tƒ .ŒÀ`fDÑï-غg¸Ðu3rUZ©‘æVâÇó/màÉÇF[V2ì³T¹É°ÛkعŒ¤Óe|þ™*\'-#6,yÐŒñAÒK³xx7ÞʳE5žÙ÷SD4;YàE†áÚõ0\¹Æ´ì’ôÒ……:|æ(`Ž" +ÓéMDVÍqŽ?iY o²,÷Ð8¯CÛ¶í#„áµ&*ìZº@j"Ûé‰ÊGbSû…Æ– Dû1ÎÊq5ž¾áÛèŸ8}F"¶Rc/Yú÷Éô{Ô:CgbpÙ—z>•í± F–7q®ØïdZgè@ÆfS&%/”Ýu±Ò¾¤DÁLœõQÀù„[X€‹ª·„Ù´¬d~Le%£O€o­Œäâe Ë7’2Ûª‚H(¯Ÿ0©HЈ P2±1}ZæŒ>Éc×¥‰¢Ê!Õ&¡ÿ¤ìvz½ó/IÙSâ—-$»/н°Ž¤$£‰LI<@&’ÉéÇB²cSõýK¯ ±úGÕêý¢úúq\—eUª¶½x*ŠÖ¶‘•-¦@†ÎÆ8HN%£õ\^Þ/èÔn¨þ;Œ×o–xòE`Ñ!Dc\‹Dš€±p³>¢Û<'ž°ûÂÍÆ™9æè®«hMʘšÄûßäôù^t}^lüÖîE÷‚XûÜýf}í¥Åê$ô×­Ì5¡Í)Q0ßv1¤v°1·¦ºY{ˆî9laÒßf{ÜNMêøÙˆÁzV5仹àÖK¸ôD˜Ç¼22–eÁqX¶ÝŸ9,eººÏúž9†”>¢¨ ˆ¢ºÝkX»ñ zíÏÁuÎ£Û °¸¸ˆF£F£jµš|v* 9* C1¤”Øj2dÚ謹ª h/@Ûõ/rÇÐÁmW"BØpœÄ­¤Þ;Ž^ÚÀOYɨŒ$Þ¡Œ¤Ãx:u#±í*„ÈÜHȘ;E8ýÙ§YýBïí¶×¥¡AJÝ`•„ ˜„þ Ãæ†ï¿ò2 ýœØLÁ‹®§?×SP£&ÿ:€!µa¥÷X@UÊîr§óìß­Õ^ÿã–å½×ç8‹§£hí"€ùÄX@ÂÆÐE>%“v™híöÁlå5ÜÞuötžwfž¨ñ3=LD§™ÅI€Ž|ˆ‡˜EIÍz•6,€,€cfÈä'…Dì3sˆZ̲ pÀ³\%Š®Æ±¼H´}¾×»v ÙŽ¨:¤ñ»:hŸÛg§~§ ˜O¸ïÝÊÂt\ckØ8#¢^¿^ÊúSBàafqš§qŠ™Žðˆ¸ÊŒª)Ã1bF”Ž•7Þfæ €—™ã«Ìñ5)»/ÁúË@«mŒ%ýïAâ1Í÷Λ ¯ÕëÎ{™ùk‰è-Ìt à!h†™C[Ìò 3¿ eðL­}*ŽW–Óvµ#2úp÷0&¥¿všov­öÄ9@ „Ö·‘vÄȳYx‚û Àáj½~âÍÌô6á~fq7˜Q‚ªÌ2Sà.·™ù*¿Æ¿ÆÜ{¡×»ü4ö ÚávÇú¤ŽŸ;1ˆÍz©|ò›ÎqƒDÔ0â8†–A؉XF€Œ ƒe„8î¡×]E¯³‚ l"Ž:èõ–Qq^„뼊v»F£ùùy,..b~~333¨V«{nåY”LK)~@³I TWe%nRV²4qízˆ{N·¬dq³2’/ë ÑLjŒDÆ|è‹zÀF·ûÜ?¬ÕíXVí;F}B4æ‰Ü9æ ™ ªÈØw³À§0& ã¡Ë~ 7[Ð¥?ÏØõúì›ñÌô"œ#§RìúO “ö±V h8D¨4“}†Ùt$¸ú <ïx/á—˜»†×>EÝ­t±$Cûµ`¾Y¿ãÁ©ƒÇ/=€› Žzl ]¤W*ž±,ûDâmÌô‘xÀ²Òý*_d¼N*éŸsNÇ\÷°”R^¢¯J|!Ž»ŸË_IÇSQ2(÷}‡ `'WNQ©Ð/¶ÔˆÄ1o´,ç{§)?'e÷ÂðÊïÆqgš®•6—#ã9Hr¿å)ì/.šo³³ÏF‘õA"ñ~f¼Gqh0/3×.¨¨Ö!g’w`Yu8Ρ6~ZÊÎÇ{½ bµ>ëis*ÔæÑ¤€€êõ3߈ï"Â[ª ÞsH{æ‘•>ÃÔ¿?œ¥óWVSðbÀL bØÈjïºh4Þ8Ò‘Þj=ý2‘6_¾ÂÝEwÃ5ÜÂêBÔjox¯â»™ñÍDbagpb¿?ªÖÉQý^!æ× >EÍÿ—>¬¤¬§-šCä)½L„o!ÝÛÃa%ÄiÀ=-„û^ÛnÀumJþ%s÷½ÞÅ?¢––t艇™ˆñúy$ã¯×;ÿ¶(ÚXKŸ­= `ûE£1û£€ø'y»é#!œ× á¼Þ²?$eïÏÂðú¯FÑú H˜ˆ-m.‡¢FãÁ4Þo' ¿ã\ fgÏÝÇøûqLß/D"â¾sMQ*ß$D囈d“kŸYî[…pßjY÷ÿ}){Ÿ õߌ¢_NÛBµ‡Î$NÁŒGìF£LËxß½&QN­S«°/2LÝ… ÚëÓËIˆEB|ßGšØnnbeõ:n¬,c}u­ö‚ ‹0è Ýn¢ÙlÂ÷}tÚ?e,..baa'NœÀ™3gpòäI,--avv¶Ÿ´+ÏýH¢Õß*™V,Œí–0®Ã«T@y‘NÕ†f‰™$çl=u •ÿNZY‰ïÇó/oàì]VV¢·}ÇCËHÚmÆç¿X…ãÖaÙU¥n$@¾LD›b¦¨*å(YåìTu ]ã³)g;n-dz6 >0Þ¾‹¢^ïü++EðM$ Œ‹^pÀ 2툢ݾ 䫬ÚúTÖ0<ÿÃŽóÐÿ'„uj”×kÛóGƒàŠ…l×´–þngÐØ]ÇÄÇMäu´ËÛB¾d‡Ø5 ½¶ÙÙÇç¢Èù>€þ®ôà8‹× Â%ª¾Ëu«ï²íÅëQ´õëAðêï!/ö«/ÆîtÁL¸;cTcËhË“Ï;ü]ý°âm“3®¬y˲ÞTßïy³Û̽?Ž¢µÿ; Wž×-©ï?OFQÂ4’ÒÀ!sLT«-1ó1€Þ±Wsز¼w qï»çÈ_úþÕ_–²ùRúìßJçqwJçÄØûKKLÕê',Ëþ§RÒGˆh_mç…° 1ÿž×øö(Zû÷Apùãi¿nj÷çžvoõ˜êõ³0Ó?B|Ë~÷W:ÖßcYÞ»£èÐ'‚àÕÿCJÿJÚO[)È£ÀÒ¨OÍxßaÏ!Öªú lî›z cX2÷ ÒUΠ˜Õj€#‡%À=lmmrA°ŠvkNA Š"!ày*• <ÏC½^ÇÜÜ–––pìØ1œ8q'OžÄÂÂêõz.YßϤZ×dˆ¢qcùºË®@X ’$³_ 0ÚëDy‹Ï¢[¦n©›•œ$n%^ý6ü&®,‡8súî++Q@†`t»]ôz=H)ñù/V!¬9¸†IÿÿëJÀ@Å­¡oN<8ûõƒr`bö©ãjézÞF„…qöY¯wñ-8 ÛW„èü7BÌüêþ.4dÌÜÝŽãöV·7¤Ü^E&F*‘‹º[¦qÄãé˜ÚBÂê2jk<%@Ñ~_'+õúÑcü”43M,„uÔuý¨ãÌ|8Ö~% ¯|IšZ0wƼ`.çGœÝãzÞâÑOÑá W3@ý[…ð>hÛ‡?†7~5ŠVŸ1€2õsWŒ-æød¢ÙËÈqŽ4,«ñ1¢½/9%²êo¯Vï}°Óùò?F¶¼ž®6ËgÆm÷—y¾²^?÷_ô?%Ì‹ÑÍ!{Ñu~TˆÆ×õz/ÿ]MûW%ÊzIðˆæÎ=•z}ñ'‰Ä?ÔJÏF–òÚvý-ëõo Õ_ ‚+OÛc-íÃÌh1F·$¿ãñ¾;aÏø‚rY/Ë÷\å ;Ê2+…`f!à8¤”¨T*¨V«¨×ë˜Åüü<‚ €õz=-9,˂뺨Õjý÷ÎÎÎbaaKKK}VÆÜÜ\×݆‘´ä4ˆ!¥ÄÕk+—¶šE¬ Õ±l&ÍdŒοÆZû‚]Ô¼%ÄQW®¶qhþî(+1ÅSU{+†*#yõ‚«³¨Õf`YU€ (àåÊu4b@ƒZ%ˆ¡W2 ”«Í3ÖT‰¶Íx·Ý™é?g×FQs#Ž7654xIéÈed Œ-d Œ;¾dmZ…Ø÷_üO–uö3BXoÝ«kŠã ÇÜnÆqg3Ž·7¤ìl¬»ª¤¥•>À6Óëq0}è÷3JÁ¢µôïí4Áµ¦,ÚÏk Zíìûˆè_ÑCÓÜÑDÎñJåØOXVýApþ¥Œ® ³0nŽgÁ\ÎôsÈóÎ~ *„¸oºÆ‘eÕÞ"Ä=o¶íÅOÁÅ_’²ûZÚNjµ«­I/¼•Õëé3i=ùÛ çÄÿ¨—úìÏ:`ýµt<Î!¡õ³6WËgÆ-÷WßÉ­åyg ?O$þóqž¡m×ßìyœév_ù7ÌÝ—”Ñ*öí=ZÛÝ4fg»?ŽÝÿ‹Hœï=Ū»î±$ª¼Î÷Ï,ndëÁN8Mã}מH¥=û5öÀ€BgN`°À’3G{ßC¢ŸˆcG(} ×u1;;‹v» úe¶m÷qÏóÐh4P¯×133Ó5<ϰXÝDÚÔdP uÂÄ`œ¿`'N"#}ÐrÞ\ÒÌl8éRž  ´rKƒ²l8œ”•xþq<ÿâÎ>1Ýe%f›«¶t#ž~&)#qœ*„eChe$¦$F®¤§ÀM¾<2Á }Îé%%}!“ñ ôþqö]\ºŒñí¥ÉÆJ bè½=NòÕgDzRF?#„õ›»»†XƱ¿-e«)e{3Ž·×™Ã24;Ѐ %XÚI›éõ®§¯E(“«½Œãi»RÚÖ^º@ž&ÆË>]ÃY»^§I$~ônêpÛžy›¾Î÷_û¹8n~ٮpîû‚¹œÉó¥R9{Ú¶Å/Ñ»¦$#²íÆ× ñÈ›¢hå7‚àò`pUi9L3+ã(’ÒF`«V{Ý· a=µ¯i¸Œã0\ÞB"Ī´«šcÚž¹þBR‡àT«¼˜ý5!Äý“p’BT×j~Ô÷_ùÅ8î<‡¤„ÖAÆ@Usg?æ yÞÙwűø "Zœ”Žsœ…w=rª×{éX‰»»@М¦ñ¾KaOÖv† ¤o £À^U+ÈHn“15U‚¬’gõ·b¸®‹™™>|Ýnq÷K{@17*•JÿwU&¡lU÷[ÐÓ0”°¤”7VD¡‡šWMì<9Õ”äü®?‰6h¡ÁÆïKC/LÆ-8•Ä­d½—”•ÜwÏô—•˜n$Š¡ÜHþêé*ÍÁq+îõ¾òûž÷Ô%!èôÍÏ9ð™;Ë¢­³,`¡ÄIhÑÕÀ‹.²šý6òôäƒb±:ªP JsÄÁþªÚOÅ5ÔëOè7‰Ä7Ü.„s¨R¹ï£¾ñWâxãéta_Iï)Y)×(]8Úü Ï{껉èg‰0÷Œ-QuÝ£[ˆÆ›ƒàüÏK\L2嚥ÊLâé¼—³—>ËZŽsìœeÕÞ»ÿë€渂d‡¾‘ŽG74ÊgÆ-ö—:ßJåÞ·1÷¿ As“5wÜY×}àû{½ç~‰9RmkaP·lOŒzýÜ·ÑoäLZïÙvýZíu?Üí¾ðK@œŽ¹xešÆû.51HK¸XË‰Š­-t=Œ"Z<Ù !õøî'Ë:Р’éJ¥‚z½Ž0 ûB™êÿ˜Î&Žãô õÿÕgîGBn²#@aBJ‰W^­Ár<Ëèa€­p&Õßå—:®]-9Ûà/ÒnU@G¹¨Õ–0;;Ýe%z›+AOÕæ Ĉ¢¯¼fcumµZâF’ªÔ ..1¦]Rh`™­³j @ì#Æ»¾±,ñ5ãüþ0\½‘.öüô!¼ž‚kÈ»ì_L}nÄìÏ/KÙkJÙÙŽãÖVoo0m °(bYt5 B/z°¡[)Ð#@YR²çk„t‘daz5Göô<ï±#€ógDôº»¹ã…°«•Ê™ïªGÑú絚¾8 pwÛi~<âxž÷³BÐܵ g×%zÝ? ‚ ÿg7¿œeŠ"¯³§ ȰØDNÝuí;€ÁÌÃë7éB)«Çã)'™¶g†¥Žsâ)Û>ôˆ¨2‘'k¹³ÕêƒêvŸÿ˜–ÿê%X½½2êõ§¾“¿6‰FÖ&µ“µÚƒ»Û}ñ×v®NÓxßµ&ú¶ PD¼(ü[+;˜¤ê=ÈP¥%D)e_'CéJè zŸ),Ë꿦ÿEnj2AÐ1z>ðÂË8n‰…6%†ð£–SAßåZ¬_"Ÿ­À !l8¶Ï[B/HÊJÎ=9]e%;•‘(#´ÚÀÓ_¨Á­6`Û5°AB m›œÆ…XäÄTÉФ1–Áæ´2Es•”+øº éܸºRÊ0Šã­&2k0¥Œ¼ŽL'bÌ™´Eü1fñæøËRv/Åñz+ ×À Hv…tªžV˜L ÝA¯ôÈ8ÔŽÝ´MNSq` AŒ=»†ùù§f£ˆþ‰"ù]BÛuïùæ^Ç}×O¿UOc¢9±ócqñáF¯Wû-"zßÝÞx–åªTîÿ‘ ¸ðkQ´ñ9ä[˜NÆ ×=ý$‘µï Rno¥lL™¶UyáÔò™q‹çkÛ‡pÝ£&ÎdÏ›ú1Ç9ñÎ0¼úI ´ ÖCw`œýúI0²6iœªÕúP·ûâoìNÓxß&†±í›«³Ç`BÕw1 U×Ï2E‹’cJX–Çqú ì°ÿ¯ûż(J¦u6€ÎÂð}qã«Ï;ˆe U«’êa Ld€ú(c¹ø(;ô$UY‰w ½&._ qÿ™é++ÑËHT{ëe$Ÿý| š…m{° ÜHdDEn/ÈJrHû]ï¤þ3,Iòo¥þP¿Ãy\+èsãê·8nm †rh§É¿ÌÊÝîWþ:Mîœp/€SébÔF¦Ûa–†è …:”_`€}gmakÙ”QÆ>ÄY; ñˆðƃtÕBX×}àÛz½çæHhsMsåü»³ð¼ÇŽø~õÒÂr]÷Ì÷¢EkŸAf•m¥Ï3 «õ—ÓqMõ†mÏ?0Šï ‚•뀡D)•³P·œU·–:YÖìR¥rê&ÀPá8GŸŒ¢õKÌ=ÅÄUë¦@['íúž\©œ»‡HüöÝT„eÍœqÝÓï‚ËŸ˜¦Á·{‹UÊ'O´Cw÷wö ˆ¥ŸlMØ>„™hêâŸ7¿®t­ˆ  J|߇ïûIù‹$|é+5¸n$Üôz(Ïœà"TCž mÝ]fŽA†¨v"¤n%aW—Û8´0e%féNQIÇx弃•µ™´Œ$µ´¥¬¡X+¿!½‡DýSðš)ä9P ±˜Ì£fBÐAŒí&²PåQ­{fG#^ô)¦E ÄNª $4»YɈ X(–Eˆá 9d–—ÉSûõºõßá]ñÚ-ËuÝ{ÞíûçÿP›“úΣdBÝQÌͽa.Ž­?ðÔA»ö”ñómRÆ,妣êÁ®X…SQºT©œ¼ŸF°À‹ã^/Ž77‘mdl§ÏÞtà—3ëVÆ_µV©ÜwnZŒtÎX®{â)ß?¿•ö³¾1¤€Œ]Þ“¿Árœæo82m}é8Kg㸽9Mç¼Kƒµßh( Dgað@†¥ýŸ ½µ3&!T" gôz î+ÏÖEs¨Ö<a§b¬EùþÊÈÞ#a”90k`€9ñJ½<…JËJªõ%xSRVR䣳^”j«Møü35¸î ·•–*imÀ@ 1?Š€¦Pˆo’–2 W†L{¥\ExÞc‡‘¨ Ähn#«}UÒ"ËQÜ™ú"Ÿébj3ý}è{‰G€…žíIJ6JÊ(csý©Ç‰ø¿¾Jš½\.ÜE‡ãu`èZ4jîR9?wçjQ„ß%¢§j !ìjõÌ{½C);–v¯×Ÿûå¾°gaY33–53‡(Z½®­ C±1[éëeì˜#Ùv¥òàë…°+Óvî¶=w2*Ç™}`5‘Ùa+—ŸÛ¾'{ÞÖGñæéìOA•Êé¯; F–ú‘ÑîÔÛLÙ³e¿°ç´Å0£HT²Ý¶ð¹gfຳ°ìÄ•„ˆò#z‚kŠsêB“fbŒ<[`@ÃHÔM`#ù> wžw ~ZVòÀ}“YVRÔîzéŽ*#‰c‰Ï|ÎKËHj ²û†©ç©³Vrsy†† ‘81Š‹a’3YûSÔà‘ß,+kþHF̾o€­ô§Ñ³0ú§†Œ¡¿- àƲ0kžK–E´0⟄}ÐÛ¡R9ù–NëfXY IDATgó: õ²°ž¶`Ë9{ûÃËóð+Dâ½!„°*ÕêýßÒé|µ£¤–0X¶Mòsœc#ÙØ2Š£heyaïôØF^ౌ¡÷´û°¬Š7­ »ã{8.l8<¤ÿo‹1;ûø}q,þû龨Î4$õS *ösÌ) f`Œd¹ŒÝ%Òq÷:€ˆö‰&ƒe¥É4DaùÌÒm0’ëdÚü7L²sìU¢"\xÞd4e%¦€ªïûèv»™É«.VVgPó°íÄB»_’d?`1PZ‚A­ÓÖv8"ÜDhW·Wì›ÑŒcœ±‰Ùïj €¼¶DˆñP»u6†Zlö´( À¢dY”1ñÑhœ{+ ÞS¶ „[uÝãOÁu¯i¥‡~ß)-Žo#<ïì !¾£l 5Æ*s•Ê}ïñýWþ0}†˜Œ½‰.]²,¯>Šï‰ãUf©Ú¦„…¡D½u6f;÷WcšÏß¶çŽfh‘-!±Á^CÆÄ¹-6F»?M„z92¦Ä(²E:ò®$úŽ2•Æ® SA0:z½¤”xö¹*.\žC¥âAXN¿C˜òN¹R îìçr_Λ*«D”ŒÏÑ­=ÉHt D6lÛCÕ[BÝ?Žç^ÜÀß••( C••(˜QEe$ÊF•‘A€V‹ðù/ÔP©ÍÂq’2¡³0$ k‘|YHŽq¡Ï7Ì>Ò˶X;¦eÚYºØçèÅuùä¸èåRú]äU©ˆ¡Xãt CÞä=%hQÆ<³ð_ ¬”2Š¥ÜÞˆ¢íM)»Mf›9îÜ#²‰È¶,Ë›¢>/Dã¤ÕÅQƒà¶½ô@.ŸgŽ•O™ã-ËJn!ªÕ7¼Y럕-‘Ç™?E‹OÄñZ¨©²tI[Ë…á %èi²0”µú¸Ø˜eŒ0„p\Ëš;Ç[­È8`™CÿnÆøpÙªSbädÈD*òKl2©"Û‹ÐØñ†kþ4KTÝétÐétVV|òÓ Tª3°ì*@‰¯Y†@j«z²kC2'†Va|œù=º…¨nñJdÁugàÕÁ÷›¸x%ÄC÷ge%Õj®ë¶íœíèà¬íMƒøËÏÖ`Ûs°í„°Í‚«ëZ]À3ÇÆ(°W5I »­€1Ã9ÑO¥Ë‘·‹¡ Dtj|sÊ÷‘±Lejµx×-É.%`QƔƹ ¾}߆«×ƒàò%æX9õt쨶t˜CŸ9 ¥ìJ`eÕçÔ×YVãq¢Ñ(r aÛŽsâ‘ ¸ÔDB[ÞDVƒ¯JÜJ‘ϛƞeY¿ŽÄRtäÇvo­Åq{+Ì¢€€Èµˆ˶ëóBÌÂ;*’¤<'ÞÔél-3G:Ó°,]ÇÛ›©­ªÚÀh"_Jà—sð%Áöüá8Þº `À|úÓCÆÆ¸¥õ ”ÎO AVÙ¢SbèÉTö+.Åûôv¾d/ï·^è,]£Ûí¢Óé Ýn£×롹 üÞÿ[…eÏ$É´*#1»GËvYËŠsl CÃ|b9ñIóoDÁúÌœ´¬¤æ-!Žz¸v½E£¬¤Z­ÂqX–5Ò²…aÚØêvª/Ÿ¯b}kÕê ,Ë…^F¢Û„¹…¾v³KÚaŽ™ì½Óû%`4‘ŽïSãÒ6‘2T&E·ÕÅ2'‰Î]ÞË˜Ú¨ÕøFA­õýK¯¥;«A Zl"¡†¯!¡‰«gÝ6YÄq׎ã—>oY ÷W*§ÿŽÎáÑ,š ‚ËϬ(Ìki¥hì»”;HQ¯»?A„Fý½qÜjúþå‹R¶7‘•"¶hÆÜë1÷ ؎€e95×=õµ–5÷&!¬‘.DnÕqNœ ‚‹md¥Km È5QÃ릭ê†v¯ÐEË8aYõy$êÀP †ô§ïdz³.HI³lÍ)1ô.5w•Í8k‰ ”OêXQb(ðÂL   Ûí¢ÝnÃ÷}lo3~ç?Õø³¨Öê á$i«Ù7œ×´ !›f¢¬»j0 TF§`”¿TU…0>_ˆ¤¬¤V[B½‘¸•¼éÜ:¶¶¶P¯×û"Ÿ:C/+Ùÿä7 )Û(аÝøÂ3 ¸•8VB¹‘ cQ ˆu¢Ø‘d(,r/¡ýh¶Åâ”R`’sã 8í$$'Æ7×üùr’ƒþàe”QÆ%RâûýQ´¹†7VY%¯XpÀõôobè»j"]ÿ¸q¼ñZ¯ç¿P­>ô? aï»-ž¶cÛ‡OGÑM$; fÒ$JQÙË$jHT*Ož!âŸ%òÎË ¸z1 o\C&ÝDƤÙDVŠ ÊÁZ¾ÿê—‰¼ß­Õîÿ{BTNêœçÐ}axý|ªÕB¾t):ˆ`™”½n7·Òëï¦÷åH¢³0Ê80Ï©jȪ2ÇÕȘPGÂò²neŽÄqõÃD¨”­9% iÛÉœfN ß:f£â„vNà¦hØoÃ/tCi`(AÉ0 ã÷ëèú‡P©Ìòª ­äGß|À8cT ³ÝÌ9‹ ½­\DI8ÿïzaf_[œÊ êÞ1~.…xøÁ.666P¯×Q¯×Q©TúŽ%BcïÇξÉÂRæ,UÃ0„”ŒO¦²f`ÛU°“òÎ £] `ÏÔÃPœœô65þÝQ0¿2ÆŒ*!áûrÿ˜ß<Žu;RbèÂg%®ZFw<Çùì~ßYÒ]Uå2ÔpÀÅôXN”ò ¥ºëZ Ȳs= WþëûeEÌu—NGÑg‘ìzÆ¢Yà`|2†Ê¿˲þ%@µÑ%¾qìûç_Œãæf ´Rpl%o+ÈJ:Úói_:Ì×:^¨Õþ)˪¾e4óÏ®{üõ¾ÿš:·Í(kc—î Óa˜³UU¬-bèL¨r p`žS!ê³)¸å¥@F-½7ë÷ãâo•-9E kÜ÷¾ëÂMžû¤ {ê;Ñ“|§ƎدïÒäá)s"’&€¡´â8ÆUÿñÂ9T*spœz?™´öÐeæ4¢Pœ±ú"¦håÐ1“g˜-*„ÈEÕ[ÂLÜÃò–/‚hkkk¨×ë}}ŒQ²1t†ê‡0LÊJ_z¥†µYTk,r*°6Ú,ÇÎÐúE½n:ÓJ¦ÖHÑwš¿êbž0æâhçjãs'‰CdLŒyëÒrñRF{°6Ä™ý¿/w:È\†¶Ó„ò*€Ëi‚¹]`hç+=šaxõOl{éw,Ëù¶]ÜSdr_‰Cæ8`V?#?ûúÌQ9ì1ÛÈt0¤q.%Ô=Wï›ï¿õú¹GˆFçFÂ,Ù÷_}I0ô1vÀµôoUŠ [t+Æ•Tár·ûüxÞc?/„óÄHøöü‰ p™C½Ìj+{ªlâ@°1¤Œ£0\YEæü¥X:[+B®ø·ŒƒBTëqÜtTSÃKæ,ìt #ž÷èQ"zÛ¸sU)»­(ÚZãíMæ Í´ˆ(&òœD£gî„eÕO‰»j\ïZسÿÛîªæßz²œÿ‡Éºƒšzûb˜å"Ù@”âª|A/aPì xñ•*>þ§3 Ñ@¥R‡•²(eèL‡œ%§&®Ù/{@ÐdÁ®N F¹ òšb•È-óÖÀÙ°5ï0üîž{aoyã¶··±¾¾ÏórlŒI)àB{ÚGæ¡Iqc»eáé/6P©ÌÀ€D&’©7ÆÄxB*ðB¿ág«÷ƒx Vp$ÌÙàªÿ@š› ÞbU1Fê]¤3.$ŠY%˜QFwÇGp'!@ªúv•¨)‰[qˆÒ;ª ˆãοbæýo²ËE̘#–2Š™£9 2@"ð™Ã. u`T±¼ô]OØuW$UŠ „R9[™µµŸ^?ïÔÌôc4Bê ¸v)Ž·¶Òsk¥€Åe$LŸËHØ>ÊÉÀdô©§µ2 Þöýå©TNþ¾ÂÛw$‘,á8Gî ‚+ÈôW”þÃbcDÑúu@*mœlUËgÿ1j^š»)ˆ¡˜6òäó‚±Qy÷8/){ß¿ðZ·6•ºµ´™¹ÍÜêA+®Ç–U_pœÓï±íúÃÄ0‹ôs¥fbfü„¸µ]æI/Š{ñEŸ­3/t†JšÕ¡tZmàSŸ©ãÕ ‡àº³°„pð"϶àý ³ÌƒŒ„™n’ÍéeF ñ€–€ðàk CÁ‚ëÌ >s A´ó"<öH›››˜™™ékd8ŽÛ¶G26t&FÇ |òSU«˪BÆ|ÑÁ*µ6Vm(o—º%1 G‰A&‡ æ"Cd•ÒÆfË\«KØ“³I(¤£\À”QÆž%P\ßï'»eÍÎDÑú626FO;BäwÅyÈSLÝ d¼üé À=œpOúsÉ.Ø P¯ë€…ù»~øé‚s+M,u #w®­ÖÓNº°^pÀƒîMÓZš$S£ñÆŒ²[­§?¬,O]›‹$+À§«%Õ] Èøž÷Ø!FGÛŽãn; ——Ósj§ÀصÀx-0ÖQ\®T4Î~ßøkàÈÏ•Žâ:,ëÐqàJ=ËHl$ב¹/L#Ž{½8Þ\‰ãæFâwˆ„Lw焘9"Dý¸r†a–†×_Ñ@³M Ði"ô,5±öt­%YÊv3Š6W㸳ÅÜk'}å0QÅqœÙ%!æNYVmq¼gê¸é½ÝIÁ‹ 2&ÆMœ«è=ã:ë0\_ñý×^X‰ ëì¢ ml¢8n‹8~þ³•Êé¿aÛK!SÏüÛ]ögì¨SºÝ~³dH šÉ´.þ9)†bDèìˆ"ǽøS÷¢HÿBßýcÆWŸ·ñ©¿ôÀ4·2Ûöú–žª…s^fBlàŠ%%4¼ßuçÁ1@²!€´Ä\g„ E¯ÒïO˜.ªÕC˜™9…kËM<òÐ%lnn¢^¯cff¦ÏȰm{À­d¯ÇF‘;ÌÆ†ÀÊjžW…6 ¶ˆLáM1ÁðЗ cÍ×…DéÌh¬ /rúî$Ôÿ{K¥†à ÕqÎvä™q `”QÆžÏò}ŸO®{üToÝ`ŽÕŽwÑ¡ÃÃûtÛí:\§×IÊG„*)Àˆ †ô…¹KøÁÃqŸU“a[¸-¤¹“¨¿GüØ'ˆ!uü7¡0—QF»šgëÛÏo¢Z«V~Ò÷_ûœ”ÝÌ$âl>2]‚" ’‡$ÖQºð[KßFR#­ÖKr`Býy‹‡_"ÇA¦K¤Ø2aϘŸj6Šè¾ÑD–ï¿ú²²Ät<_JAVuRóA=“Ô5ºaxeUˆšã8sÿèÀTJ±V¨HE‰Ü€Õ£‘ÐMCOT•…:ô×w[^R$ÚY$Þ©³3 Ýøê‹.¾ø%nŽí¡Võ`Ù•$Ɇ“©]¡E ÙãØÞ2†èZPø02¬>U¹‰©¹A\`ÏÛ$€,@J´Z-lnnÂq,--¡Óé`vvQÁq°&4»_cC×)áô¤ 4àbºððªA›Ud:!TTb’~®^¾£÷ÔÚ›eqIIn^æè7£Ÿqã+"3½sJŒ2ÊØûDB`ߤ–åÍÔj|CoŸ‰¢æ|­wÈOŸJC/-Ñ“N.H@c QZ޶˜5Ö>S?‡} žJ켬3ž×–v^„ñ21ü´­—\@Vß$¹W¥(½ôý½"P Z}ìÔ(ÅóÂp}E;7}—s™†BˆÛw´ê_3s<2Cˆ™CibÖHŒYdŽ8]cu2÷’8öý—^²§œU6Sf9=nK¤%¤JçÀMÛ¿¥õeW0Ê5ÀׯÁe`´Ò~¹®õ“œôò9KÊÖ+Ape­R9ýóDÂå9 !kO9V©cÇ{kÅöHï»ÌŒ ¸pY ß2W®×°ÅV‘YëฮÑÓòý—Á²ž|»λˆ‘‡*·ˆ‹¶Œ·d Ù„€:°  iªC•v˜@Æí|ú“ñAD}ÑÈd‡ŸÐéZ¸xÙÅWŸwpùŠ˪@ØTk•ä÷¼ ˆi€%AI/Œ’†@ŽÜûô~Õè"vajê^è£0Nrâ ý¿)eÅØÞÞÆÖÖjµ¶¶¶ÐívS‹S9²r}Œ°É÷š`VôÛFf·ÃÍb9lZÕšË!ó×&Š¢ä4G>}$»#ã1†% åB¦Œ2îx–ñU€^?šï¶çî·í¹û™O}HÊð>+eô%){Ï2¯=EÝM ̈ àAb‘¥@Å.ÖEŒ.óŽËCîÌE÷Ü$ágmѯÒÀ•q¡Â:£Bé{,cV…þHEÞ)ª¢òí£¼¾(Zß@Þõf™`¬¾»¹›çànwù“žwº%„hì?ÐW­ Q•²·„©4›J¼0œäç^\zUÊ^GËV‘ì:_Dæc ùê;ë®v­Ðæ® R>÷ïxÞ4·‚àò% ü[GV‚¥ ôäÚŽ¢Õ×=ò DµmØ+t Cà&ezÌôĨIÌq¼½)e§Žs%f½œ¶ï•´›Èá"†‘PÏÂ0\ý¨ãû”43cn—žz‰‚VVÂ7I°†$[<î$z ‰.¤Yf¨ò’Û2†¹8Ž!l´Ú®. \¸\¼ä`c˃m×`§ÀEZXd ¼ÐËwØHœYcX˜ŒÊëZ Ôh nîÿ!¯é ÒAóéL&je²o 5h˜‘´›D̺Ý.Z­šÍ&Úí6ºÝ.¢(ê·§eYûÎÆÐ É²ïºcây&èƒxl"Ô1!C½'Ç%0ls¹ dˆMªÿ–”W5â;13Dã1ˆˆ˜Çºè/£Œ»>˜ñWDøc˜ß–e¹÷îý–…$ÏG™9^ä%)ù2Q|)ŽåE"ÿbù¯EÑÕ+´üÔ)ö&SBIø­Ø¼¸¥eŠv1¸C8.&†Î¨PâžJ« º…k܉£ÞòÎQ]^÷zÌ¡rÑËt‹Ûe`\óªOtÏg¼{×%ÄÌ‚”½5d%Wu$bµ*a›H?Ž[ÛQ´¶®e*1¾‚ª|I×”‘ZRª'¦Jã@•pwF•‘»ßK‚KgfÝHÁ¦ i‚½†ÁÖ';6ÿ]µZýÁ„‚=ªg†Zro;­c5ˆEk+Èkõ茤U»r™úþ3. ¯¾âºK¿8?x`@ b32#[Œ9ŸøæJh\“.,˜bšQ%dÛý÷lÛ¾)#ŽQ”˜9FQrtºÀv‹±½Íh6%¶·6¶*XÛðÀœÙs ËFÍ«Â.HXÉÑOÎIe°ŒüÎ>ç'J7¸@ÀÓÀtAŽI¡ëVè@ç­þÛ½n*5Ü9`0HúËË\êõzèõz}‡ÅŒQ}¸×F‘Í/½ôv" ¦HªDžBŽ&9u:ÝÚ˜‹ÁÀÕÿ.3¥?1Ô"yÿ}½±ÀQ!^TFeìúÞùçt:Dd¬Ã–…§’¤ê°m€ùhÈKÌ|‘9~…9zAÊîsApíE T;ZQÐa–‘ì ¸]Рè–=N&†)”¬»°Ü) CBˆ·Žêb¤ìl#Ó6饉B3ý¹WV¸Éʆåg‰¬‘€–Õ˜¢årÓ(1&RÂ÷¯\2ãÕĸ‚„…±®fEŒ Ò 2Æì‚Qeôsžæ†”=eÛ«À¦ki?]FÆ–ñQl{°¢èêËÌG>Ed½s„ †~ïT —eŒŸ¢‡Ê‰Ñ>ScE›MäYbkiÛ®§+g®JûÝ ²÷¿[Ö18—¥íÄWÏÀ .Ø±ß w˜¡ôëâòÆÏül–H¬‚™€—•. Ú±„0K HÙËhŽ%8NB¸‰»ˆˆDêСp kT )ôäYרtÑ’àœëÅAŒfUÔݦNƒYbd!ÔÙ(aQ?e\(~Çñ¾Ž‰@/fKƒ!ÝjÖt æJ‘NH®ß TÒ˜5Eº$êÿô™†[ gȱâNa°öet!%w…Ïš›È¶™#óá4®šò2ʸ+£RÙú‹(ZèWÄ÷–±.  €óÉ« 8ÎRD¯H?ËìQÊ­ÏÁÊ«HvpC –§è,ÚÇΤ&]\lð£7Ü`dÉ‚”Ý2ÁRÝU¡[|Ýá3ƒ¿2ªë²¬Úlºæ¯¦†1”3Ãx;&ƶ”­2UUÿ¿Œ¼>ÉNî"ú>Ð0®Œ;Œ0\[E¦Û£’k¥…¡l”ÈQ”8*†3Ó§‰ðÎ_íp {ÿñÑ®›»m@FÚ|P‚©›H@V½}o…q·ûâ—=ïÜg…o9 F?Ë)7ˆ}%ªFÎpË4Eˆ!Y@¶] »Ÿ)r–æG¸¹Ÿ«'õ)Ú@Æ{„•9‹(j?iHz¹€þÅ(°OÕÞ—Ûñ§á®®§fiG8a€%&h“cRÐp‡’aç’ci ¿mÑgÀ܉ÀêÞŸü€7¯O/ïÐOµoµŠâ’ BÎ/uVL!Hˆ¼Í˜s㙀DXpïxz̲µ¡vK´Á2Ê(ãön‹››¯¶êõùß&¢ïÖ‹ "p±,ç úÀlûÔuæà³ÌÝ?ïõ®~è)'==Ô@ Ù®™Î°mëÍ£MzÊU%Jû³‡¬~Èvhï´?IÊà!ìåJ `W2”c‡… d jÔù™ÆÂ $lŒMäKHn¶ó\´Ü-cOÖÀ±Œã-“!°žö“r#¹™ŽL¿tˆÿz\·| nníôö‘:©Äq§…¼r+m[Å‹p{,±>ð§ #£½›[ô;7µü…®%c1tgdD‘•´ÙHÄr“ Õ7Éô"5q£ár ˆôE"Íâ’²rs”QA¹‘fÃi¸U0çÏ¡ÿºYýcˆGš,Š€RœcçûVgŸÉ”–éãBûЄŸóý´[‹Û;#·z7ÈA3ƒ0د}ÃC£]ríÏ«Æß¦mò™‰ÍꘫãKLl“&¨‹:•QF{·ìúw€øÞ»éŠ„Gê€ê3ÑW¾-@adãùqß—+áA&Æ;‚MƒŸEl&˜HyÞ2L×JÙAc+£^Wõ‘­î{zí£…É*)v.¥lÓÜnÿõ_yÞS!}íÝxBP¨~½ëV¿Þ¶®ÆñæÇ|ÿ ¡No§‹Låª`Zr–søÖÖfgh„ç=öäÝÚ–BÔ<)»6§ÄП1.¥ì¶™Cym=1öQjZLˆ1ÀP:2J£á–²8Ʀ˜‚-%f®Ž4I‡ IDATòÞÄÜSc>B^DùNÜ’€£(üœãXS7öv5LòŽ J«ß %¡¬'·fÕä:¡Jdƒå ¸+óð¬ÂÜ×ŇåÞl”а† šÂ vî¼LvFAÚuš¯çÊ<ŠA©Êø..ʺӃŒ×'ù •+þ²<%”|p^;#§e<¥ÿoÚkR×½Pÿ& À­Ü¹RzzI‡õýmhä-|clè¹m†)ôÓ˜a*ª;é¡|Ë-äÙ#¥ŽG½¾e~HDhîæÂ>á8K?æyOþšëžü$ ‚ÓŽX@fii•s÷vî×t_Ù {Õ–•ªö\©"³µ&m£xà‚x.`5&¶ª%<¬$]LÌïS¸øoý}\T…D w|Ü|ü 4\ú°!¬Z‚ô›‹Û.f{&ªT…on81çMiÊi”xä«Ç—l8®`Ø1¶…\µzîžzý©ç<ïÜ?«×;/M|æÌ"«a®”€FS ÝîW¾,eü¿”‹Â9âºÇ>Z«=òÓBÔÎ8à$€¥t×Ò$R”söV >U6ÃžÍ ²Ò7}–¸ˆ1c2ŽÛ­ô¢@Œíôèì"1.c_AŒÀd¨’º]±ešÍ¯nOÃuñHE«™#Ü)uÄw@(ÙÁæÁ1(I…@fêÓýiˆC‰>|i̓ñ'¤yûL™ºH­6€Q )¶XÔ%‚ëFú£[ $-;‹€ Â²’"€E3`” ³ìdœ(¼+™B2Θå :à¡+¦(,O°{ÞýÃø7.î³ñÈ`e t,6LÑ|2ûˆYdÔ(MˆG>×â—Æ×i®^lkÇXÁ!èëˆèuBˆ'ª|²^?÷b­öø¿qÝû¾°ïpÀ"€ùÜðì¦9Úù‹Ô(c€Œ¸Ó¹þ?0ÇϤ ·¬ú¹ZíáaÛKïð !ãcéü­kÉc fì¸Ü²öüÙg#cù9Ú8œ˜ˆãV[KŒ»ÈJ³tF `LDî1ü;è§)aŒV¹ƒY*@HÍ‹° ï`NðÔwh±ªÛGRA†ª%Zúnª@¸-‡},v1˜9Ÿ€§C–Õù›¬ `@©‘ *YäAS Õ¶¦ØcΪ” ËÍïÒ|WPØ@ HÃÝ"'• [{j}EFŸ³EÕE>ÉhÕ^:p£km˜.˜|/9¬Òu*†„áò’0Æ’Á²€ö¹9ÑÔ ¥¨Ñ¸H‡„S'œÑ#DlYòåqõ›ÕšÊ3íH©…Ü“ ~GNò—Ä˪|Ȳ*²í¹.}.Ž;E×ÿ$ŽÛב4% Ü—ËåVc¸M2°Ü ‚ÊßtÝÅOÑу“€ÛõJåô‰¥0¼ñçÈl-WÒ¤QßU.çgñZ­NTb<{óì³”B½*)1Ÿ}¡‰!e,™}å¤ †ªÿ¿cê|{=GC=¹‘•8Ä»¼·Mɽ}€j#œ¬<Š‘±Û6.jó­b$w¹¼8é¶Èï $Ãf"5ÊA@CrÂÂ0’A*`Ô¯'—jèD.› A1Ë  >æS…´¶ض‡á@bž» & ²`à … ˜$4è|¢†l°a~Á†µIÎ1…ÅP'ýNÆ<ÈÑÇiíeZ©ö]KxÐa¦ènNƒ‰M·d‚ìLâË[ùŽ2Z­ök†%–o£^È9ÊjÎ\ÈélŒÑç;Dß´Ãâ³X_/Dåëm{î'™Ã/KÙûd®þQo^D¶CUhÄ% qwäÄS dÄaxá¢î÷XÖÌ‚f!l×=ùa@̆áòŸ"cOé*jJÂ!í¯l…½jK[/A´µçÞ„ib=äió=d†»ua(cß"Ö¥}`LêúŸ|"ÔFù•ÈÙ¢î€1µq e£’†ƒ·lˆ’±#ÌŸ¥º…À¬f«9úÎÝþG!œ‡ç!Ëšù~Ç9yMJÿÓÌ­?öýKŸCæ!nq hLW,,T0œêKß?ÿ…8>ñÁJåð/Ù CT*÷~sw»Ì¾U°èWN å<Ì?*b€DÙ{òäÓÁ UN9qJRö5ôò„@{~•¬¥ ƒ1bïz#§ØÇFø ±˜% 2nڛϧCÓÖwð`Hïy”eÅ<ÌáÀÔ9b#9MS5ÇÔ/Îï hɃ¥$f{qQ» )€ÍŽÜkúdÓ˜9”°É<ç@‚AÄ,ÐfÆ2áÁ÷ ©™hpk¨å®)ÖɃí¥;µH‚!¿m–“ðà÷õ¥i£—ôÏ Ë"þÜØ–rVc.]Ĺˆak÷E][àC{rCÖqÛö¾ÓqŽüÛzýì×jþ«jõÞï¬ûE±0¨Òöqâ£Û­ÌMó*š_]}¡Ýþêâ¸ó‹©XÙ2ìZ¥rﻑ¸•œN0ƒ¼ýjýçùe+ìéš_·ñVVÞb²ú< 5C·’,ŒÉ½¿y6Ùè'¾1Úç‡ëäð½\³=àÑâ´õÀ.512G’\ÁÁvn‘à ›¢˜<]#=Ç¢@1A]kNÈQT[š;é¤íºéC˜‚”ßÝ(Ùé³0Xî‘cjèà$Çú˜ÐKIÈ( áüëd° Ú À I¾m´}+e ä§À½&÷1EZ"æGpŠo¶­žÑø ")é³–5¦•œh̦ºЉ¡Û— Œ‰Ñh<õ5ÀÞ3Rˆ¬9˪½¨½Ïó{Ìþ¤ì~"Š–ÿ$Ž;ËÈlДÚq•±ïcÖ94å— ÆTê6®v»Ïý´ãûSÛ^ü{–U}óAHàm{æ¸e-<Çz½OKÒ$&D`qB†M Ò¡dOž ¤¯ðtc¢=1L…òù4ù÷w½¬dhxÅÊhוД2æïžßõzýÁi|þŠ;«ôÿ³÷¦Q–eYyØ·Ï}c¼È¡²²*+kª§ÊÄRÓ4àÆ-$hš¹‘0 $ƒ@22“&²ä¶…l£µÄ²dL#3#£B@K h÷TÝU]™UYSÎsÄï=Û?î½ï³Ï¾/2##^¼ˆ<»Ö«ˆ|ñÞÎ=çÞ³¿óíïƒo1A\íÕ¨-¾k¦&s92å º¼d —ù `’Uvšî/Ò:³Š5á­ð³ÌÛVMñ”ãÖ®:Oì@·e}·\ÁV Ú—§%âs4+m¯šô(ú)ÌÓíwyÊuO_¨2 'Gçòàö¡éz½}ÒZ»¼? a’ÔjÇïDξX(@ŒÒö°†®LY‹ïÜûó¥V’´ÞQ¯ßñ#­Öÿo»ýæŸð0&+ÁÇ0aeDFÆå·øº÷Lt˲‰.€•ÑèòôzŸþ®~ÿÕïNÓ­?´6;ô+ïÆ}Oãî4€{‹ßc0²¢¼~Ï˱vÆóšÇ¾VXv¡•dÔÃ8÷øÃ^”£éõÙî/pÖ+_· d0'o=ˆ×`‡«eä01`À‚‰!©ö̹,  cÞGbù;MÓ@…í¨ü£t P)db«•XPx0Ö•ŽªÈ¤.4ÑRø–žU¥".³Æ’à`ÿ\UÝ çøÇ›v·}`&\ð…Qe»kÙ û%$3FK*Ê‘ÜrYf4ˆ(§¥ÆxÛû2‡±Dø0°;¥7}ó«Ýy*MW. Æ"&% äÌM6uW£Ù|æcè/ÏöAhÀð&+®¸â q'‹»ÑÎIœÉ¼ã„Á Wà=Ú’¹RBA|p¤ð½cV’L‚D”å ˜ÑÄ1e3Êv S A‘ÀåÅa$Dqõ.h›$¨‚ubÅvÉo3À± Ö¶•÷¥¾„Žâ0Áu@•Çœq ÉÞ}àDY ³®E™SÚª|ivËíï½hæÂb…íთ— ãxdtc×{àÂÂ[ßl þú~4üh´4@Nco Å*ür’·Ü¿ê5æQ9¼Œø¹ƒI=}Øæ€NRU2ÅØ[G°ͲµKY¶öÿcs1IŽ<”$G!j?˜$­SD;ˆÌs¯H’Î ¢úqæÑ&€Åk©8÷>"X>_¢xGÚÍè¯Òµ*7p€9u[ºD0#ÆþvSÆgf¹Ccjµ$9~G–­®F)Îî–Aß40Ùéœy'¾}@ „`„;/óJ*¬5uúÀ<ÎDÃd´¼Sž/B«MoÂVÓðöj3º€O”ÁH9Nv"+…@p!„½´Æµ“ ÚCŠ[Ê„Þé_4ï%GZ§zcDÁbJ›AxŽÛ[AÕJs¤V‹òïü§VŸ2ûè÷?u©Ó9óˆÌ—ìË °vÇ=£Ñõ»¬Ý\+’ˆ;‘¯ˆnÉý^Ѻ¢Æÿ~«÷àD– J‹ÇÅb"ë"ù1vmÂÑn+"\fgíüÖ6>ÿ0N‹ŸШHâ73\ÍšÅ,Ûx%Ë6>ŠqùWr´V;ò€1û‰Ú÷$Iã.¢Æq¢ý’ ¾QËP’½+M—V‘¨w SÛÈËJ†qÌüÙY> ¶¶>ñqæ´’,Ùi}LØ1ö€·¬8§0ëaî\?ÆŽE.Ã"21bÌQôzŸ¸ÜéœyÈ<0«}ÖëwβՋÅsB–AïüfÆ÷T øÖÜIˆ¡'àrUºò³szËŸVê¢ sÊdÖ?ê!”ªZ¡'ùTÝf›ƒÂ¤Õ+)L-vÁ'é’°4dÅM´9´%‘œW•¹Œñd¸ ƒŠÓQ5å– xÍJz?!ÅeF}X/M©Ô&™mÓ‘µü/“ûbjµzk·ûÜ5ÀGNí^*¨3yÚÕVêtžù;ûUƒhíú&”Ä2t…Óì¾öŠÃb,ì¬_­c²ZrSõ«‹‹É—"_y9”yªxr”b~.+£‰ u¶í¼€¬¦«/« îß’dñ´1ÓÆ,ÜcLã.cšwÕçª%I:ÇÓt©ULD FËé'·}ÒÆl?=K|Õ˜…f–­—,…õH[-úâ[“¡d6 —.].~–ÉÏÏaŽŸMÒ¶3FŒ9 úcävÙ3zf9aÌ‘Ön¬b ^,ž=L@¿œ‹~Îá}µõw&ìI‡ r“(ö….¤sC™`[„Ö¢ózgòÜ>£`l«nªéO°°"Õži6«NXrºz‚ CÛ‚ÐÃÓ(‘ÌLarh ‹ØG`JzòLаèÜ?±¸QBH:+Zˆv’"Ÿ$€$Áš!è™bDã_õ ÷¡ëõ뿚¦wÿ´1´/~Æ´:­Ö£ŸßïŸ]Gî°Šœ‰á‚é.ݪhaáíï&Â?Þ¯–—‹ópE—Z'Š»“ )ÑR€«‰ºßXKßb?OF‚¥+A¹^sÀ ºÓž.¸1þ™e›/fÙf«x¯ EÔ:Y«}И…ûŒY¸×˜ÖIšeQ³¼ÐÂL’ÜUµ:nQ¨í°ô‰~å“‹‹'{µgôÐ{PÇYé´ŽœyØ›§{?s`×Y1æ3Edþ}ýìž„VëÁ7u»Ï])Úï@Î"^ãxÛñräÈ'¬ÅÏä pkå$Ee=©€‡ €ÃD™@9‰Ç(¡I µ¤S‡dWbŽÊîà~¡à§´ÎÔäI¸¢ô p<‘Ä¡h#‰ €ëjB¸ºä[«BPÞ]Íö0Hk?ÉBQ­WIèk(ìŒ@CÑË GRˆ‹Ò’ýkðõõ×7Nþüõ}»ÖŽÞÝj=öÅýþ‹=€·0Yu+W§ú˜Ôï´‡ÒââÛÞÁœü @ûBu·¶×³vsÓ0¶³N¶0Y;¤“ETŸ8Ö9JÔh2k"Ñn`RZ²íŠI§óö'‰è}¸}Â3\q„‰¦HÉnI°Ñp€ ÷ÕÐbî·F£þ'&€Gr´V»ãñ\àÀQŒCÆd¿ ˜Ÿší>[VëÑÏë÷Ïm|'òÅ·u1ŽS1~Ä\ôñY¶ð!c¦Æ-$²mf®~Öº4öŠdo®×ØO²I,­—ìMೊaá%¬M¯ÿm6úKµÚñ/$šM…0Q­då¸@W;`ë[Ì0)›ÉtÚÉ-wl|]á÷ÌÄX<êü³›Ý@^f¸êŒÛƒ|Ÿ,?sžisD~euú‚ÈĈ1g±¹ùÉ;3Ï™'g;_=zW»ýÆw÷û/ö˜ÓMøöÜ_ÇÇ7­Ö›îg^øMcèm½ýwÈÄ "I*Y2›õ“¸ò–$™D€óGA(z ·Ê„_Æ8à…€„ÔAàiIñwSlS b2‰U{„Ü. ‹—T8g¸@JÆ|ijXe9¬/ðK#潸/â ÁMűÄJŽJàN"û…%<%A<%§_ož ‘·¶>svaáéß2&ùÊý<$éÜÕn¿é›Óôê>ä$uÈBg,hwBj·?eÌâˆÌ7ïï´Ðrš^_r&æ›Å¤¼1†8ÔzÜh¦R½~ò¾4½~ÁÚÞ*rwR÷`“úú¬¢Í©Ó9óO‰Ì»où!Ýà{å ­Ÿ#nHÖFYâÓp…Áà¥sÌ<ßhÜý_ÏÄ0‰¾ÔWù>ÝÜçÍ̲™ÈfKb&³Û`ÃÿÀÌæÐj5[ÌWŒ·\Ù,™ {¡1kÉ8V^ó8½*ÖdbĘƒ>JÌü«DxrÖ;O’Å“ O}ãpxõF£Ë%€Q>ï6ß•,,ÜûÝ€ù‡D´x.ÀÎËI(¬÷çíîÊÒV³à˜çD58i(eÒŠ>‡Ö™,6èê%HNš’=É»>+™±—W“Ž[Œ®8a l Tbç\µ3™œÓlžä·ŽrMÀ Èp™(¬•ÀÁF謰ìäúÀ jÑè·Ýr;4/õ\ÖÚÑŒIÞ‹}¶ø4¦Öh4î}O’Üõ¹Ö®üÞhtõCÖ^p½H>ËR“SÊ/ž|ЍõíÌô­Dû£÷áF–m¬0§CLXëÈEÝÖŠ1Wân» âð&œi&NÆ4›¼½ß?·ÎiKVW"^fgýzH6£þ]o0§òÚÈ×-ßO67?ñ§Î™«DæîYœW½~ç©áðâ2<ÖÎx¾\²xÇmbÜè¾vrLå~Á‹sÙ/“¤ÿóÌÞ¹+Q½ÕlÞ÷žzýîÏ·¶û‰,Ûü#`ø¼µƒ—Œáµ$9q8r:Iï’¯ ¢{SãïÄ(²+*èL%]¬ú3ûE®n²ºÏîÛÞ2g EÛ#°QuYÂ"Ýt¾OÚ ;ب§n¢ìì‹~ºÛò@„¶±RÀÓqH´jö¨*sC”ähå$J#æ¸ÒÈ»Fc\1Ô€ÃʶáUÈ6ÕÊW*€-M_e|)9gSí3Á¨ßÿôŸu:O(ùÆy¸¾IR?‘$w]­vò}ÌóÖ>Œ>•eƒ˜‡¯§éæ2€a£Ñª1éÔëû¬måyO»Y¢ÑOÿ{çfL-i6ßp¦ßa°'Ü]Ü;·œkt3׊Ž=óˆµô[Ý•/Õs–’9­¥Zí8€ÓÌœ­|•9:ˆø²µÙ% »È<¸À¼yq8\^+Ú·töIo‡û~Œ3š»ZæÑÍ_Í1ï † Î—YU0WQÖ?3VÖÜ¹ÈÆ˜yürß¿õ ­¿}¹¯ñ{Ø2`tñKm¤ vº, p“YwS¤ ¥íPÁ^À$‘&:þžõ™%®SHž 6¼28⦢Ì"ÐöpÁ!ÙGhnéö¼sÒ? ‹aYÚQž‹=ÕZ]  !B¥M^¿`Å)Gh‹p0hy?-VØs½—eÝïL’ö¿/Ôûcì¸gv8¼ø:&z¥Uà5LVµ §“|:öˆ=Š~—ß9ÓILmñ©4½ãZ–­` ¶[ñ=qíó6§t›Ÿ‡AÚï?ÿgÎ[hü`¼Mï<†Ã+¬í—n*›ÈW«¯!_±]Ã.ÔwœÈ>Ô¦bÑ1n-™b¶¿ $31ˆ µZ¾£×ëu­í‹m¹FFÙ·oÄ>˜`aáíï6†þÚ^wšv·˜ƒâKÇ &,’›“ÌôÚ~°jµÎñZ­ó®fﺱãäÏðÙ¨ÙD¬ò6à e0œÝ¹¹«Ý~ÓW ‡/ÿv–u{ÈDÅ=´¿ÍqS§sæk™ÍÏáŽY_kíp08ÿÞXŒ‹e§½ËÒ¥,Þ¾bĸå¹k6uÿv½Þy—1f16ÉÞÇÎׯÉ.«¸¤^R ¯Ô;˜–o–É¢µvü³üýV_î¶´mŽ÷_œD ëÁÂ…¾“ɸŒC”oHQO×½ÅÝ.‰éKÀ¨Pœ]XÓ­ºUVãÒ „ò®—Ø7WU„RxüÀ1eÝ‚µŒŸç¯ ì¯­dC°H‚+íëM¬]ÑçXÆãËÛÆ„.CÄ R ƒæêAÀF[[Ÿú'Ìöâmz§IÒÖæhté’“ ­ÆULl>o ÞÚúÄ2³lŒ=lã^¯ûaf¾4sô„jvûï6æÈãîpÀ)ä:‹ÈËL\ÁI)8jŠdó«ŒI~ý–æF7 ©eK׊²%-WÈ{˜”ÂàfƦ1Ù¹ÑQؼÀ“ð€“ÈKPê¨v7á|ò׬µÿq–Ç›$í;šÍ'Þßl>ôUDõ'"K°„Øêø3Úw5ÀÈ™4kZ*‡7­L6›°ú£Ñåo«×ïù#"sW¼]ßLßÍìpøÊyLÊHÖ³/® †+èy;YØý>€·Ä²WñBÆ|æ_ÑÌȨ7ÛíÇ¿,MW/þæAI“/­S{hçét:O>´þ‘yÿLnnÖÚ4]ZrÆçòR…MĸÙqÉ€ùìÁè'æ1´©c«í1-Q°Ì[ß˼øŸ\›=?bcjÆœüóIrâs™{ÏfYïO¬í~œ¹û|– ®ÖëMf>Ñi6ßÄ\ÿ< y‘yx?ux²lki8|ý:€ûŠ{¾-ž51õŒ¥$1bì‘mm=ûó o{‡1õ¿›dAŒI‚EEâD  6ÁI´åŠºñ³÷ Ðëõ°¹¹‰F£4MQ¯×w=I-KÊ$µÜg–e ›`›å:\XV1` 0Ò1Bº‚¸I¾“$JÃKôÉuWäIw!Y–åÑ/˜",³éŠ* ÷\´á)uA¨Bƒ(´h•¬÷ü½Ä‹[žÇþ‘NúG€ä65iõE¬»Òp…4=aÕ:Ö=áp"ÂBseO¢= ô{½OÿÄ›[Æ´¾?>'ð¶×í÷_>ëãBš$Ku¯…À—;f4ýŒñ&ì¤ Y\^” ÿò“Ç.šs £×í~ú OcÚ;>'}£×;û<³íF9q}ÀkÎ䵋Ú7–ÉÅææ³/v:Oÿk¢ä/¨çѨßñ,@Á1ëõ>ùv:OÿE¢ä}q„Ö¦épøòK˜¸‘¬câTZ—ìt|öûûÓ……3g1Ï1ˆQÇĦæ¼nÀ€sÿJûýç~³Ý~Ë&IóÇn÷>–ekýþK/*ÆëÈÁlȾÝDcĘõÜ50 ^ýX–¾¢Ù<õ/ˆ’¹¸/[›¦ýþKŸµv£Ï7nNbëfÚ¤=b47Oç`Læ]xÃÞ€v»N§ƒÓ§OãÎ;ïÄ‘#GƉ«1fל'ªÕF£F£Øì…1-›àNï%ˆ²´CÓ –¦ZÉ,ãpsÜÀ D¤þ) ƒû]’å=î>+fý: ­ö5P“e†r¬î”÷v{þúGxIÒ‚a0*ÆmAá J… r‘v)?âóPÊ•dß30 )^fçúÓ¼? l‘|w»ÝÏ| Ý~bÕ˜…@d’8qÝ\ï÷ϽÀœõà30^ð*€K˜”‘”«o·óÄÕ Œ¹ùUD¦}0àÌöû/žµv°iLkÞuaÊÛNjí«ßIôЛ1ÝÖ³Y¶<¼ü¢µý-ønA—‘SüËÕñ[µ<.}ª~Àÿ<¿ †!¢z“y”ÀgcÜŒåg™$ {½gºÝ~ëÉ$i|ïíüèõνð@0^/úY™°D#FŒ½¢ký4½ô<ÑÚ×Ôjþt’4¾xï[[ýþùÏ2JKïòytŽšgQ\28ôJ„è'ÆtÐ^x¿ñ» ²t Æ4P«A­q ‰éÀ$M%cA" Lñ{aÂ$}ò0-õl¾ Ž \Ìñ“¤…ZýŒiçŸéàºrÀO<µÕvÇ$ °„ÂÛ†‚LÁTö…°¸@Ç;XV’f•ÌŠÃI•hi…iÂãÓ60õŽ}ÿùã †ƒ¼<ÿâ4ZÇP«uP¯5J`ˆÆÚ,r›¤l_{Oµ‰ƒ­ÃÚ‰;_­ÖB£q ¦ÞÈÁ8äòX0Â>Öed±ø»Û§H Â·¶e‰òä~׳Þ=„RY}«×ûì?k4¹R«ûŸŒ1ܦ1­® /¸´i\-&®¯xùêÛuä({¬.Î{só3/¶Ûoû'IbþÑü'À™ ^|ÁÚ­b¥žÒÒÎY¯·¼\¯ýÚFãøï%§o_ã•se·d`\GN￸Ée·ûÚÏu:þ·Dæþù2Z æQÉÄ(ËI\6Æv&Qnø©k·ßÒH’æß¸ÝúXš®¯öûcc³Å.ÏÈv™x±Œ$FŒÙ½Ñ¨{q4úÔ·µZÿ5c:ßgL²8ëgÑhtýÒpøú+Åœ±0®Ï¢ÛÄ(D=Ì*_iW²Ð@-ÒIv10ÔB÷¡V;ðD ÈÔªÁ˜ÜΚ„)‰² ÏýBIF50ƒ\Û‡qF8ɪ‰ L’—n’“íj™@hÎ.8Á¬èbH0@¸‹h‰¨ËÞ`­lE´¹[êá KV03XnC€El†ø¼'xé#ºÐ¥ãˆBdPOZ0‹÷¡Þ8¶#À$HLdòþAD9³€0¾N„°È÷µÏxø±×ŸÊ’²pŠÈ ©56€!Ÿ•S±Ž$ík]§OïBb0~»x¥& ¡†l”'§}@P dl‡/ýÑ=ç‰îþ_ˆêOÜn‰Ñht­xÁ]y»‚ ãõâáTÒÔãêÛ$²^ïÕŸêtþ²Â^s.ÃZkƒ—ÎfÙÆÊdÂAƒ2V±¸Ùƒ_›$'~…(¹çvêdyÍñËç²lu ÆUäàâëEr¹ŒÝÕ(``©Otß7Ïš$ÆÔ›ÖÂ1J&†ÙA?èõzÏþÃvûÉÕ$YøAÜ&NV£Ñõ+ƒÁ«çã’ó¸X€f·*#FŒÏ[K‘]î÷Ïþó$9òÍæƒ?lLë‹fq¯Ê²õÕÁàõ—­í•óÁrÑë&€úíbì '–šÞ†ÐBˆZ j°‰Iš`b'Íùø$“L%á#Å T]i×YE#‚œO›BYS²%H–mPødõœ#(|ô2B&‰†«¸à€GÌÐŽ‰…ƒRÞ"·Q ¤(Mè±€RåÝÉ ;BÚ‚ Mˆò}SƒA³ÕÌû9=ÄCÏQY:Û_H~]h„LŽ¡²ŸUØÚBéZÛ¹}*î$Ñ0mûŒQÌ¿ÆsákÖ¬2ƒËŸ ®C«õØ%Iûn‡ò’,†Ãóç²ls¥060)!)©Ãeýs0*† °:HÓåoJ’`Lòà&Àé`ðÒ Y¶^®Ò¯¸Jdz¨…¸Y­6üŠfóÔÿET»-Ç,ë÷ƒóg­í®Á×À¸d\ßå1Êxsó“ÿÇ™÷c¾|Û‡¨Ñ(H |6ÆØ¬jý¬`é=÷Síö£¯û€1´xhobœÙáðâ+£ÑÕKÅsÀµÓ.Œò9°Ÿ1bÌÁl–m<×í~úoÕjw~n­v×·$ÉÂ;ˆ(ÙÝ{„å,[»>^~­x ŠgQÉÖºVÜ/.!_»M@ O}ÒIΈ+ÓŽq²laL§Ü„ŒÁx5ü$’Ó*¦…—€nh•]&ª¥uh`õI‚æ¯ D~sÈDÙpÜd_–m¸íâ&Þ¦8d•߇‚HpìxÇQƒŠrNy¥0Ö¢$-fE»©L¡õaŒÛÚx`ˆR‰>@Úù‰¿“¦¦:@V–M‘âZC JÄU×D7H~G–í@?®œ®H¬‡ dl)÷ûÏÿh­vêwSϘúã8¤1-__9Ïl{˜ˆ1-aâBr¡øýú$G‡mR‘ ¯^i·k_cí±_7ÆÜ7O@Õ`pîyk{.€à‘´vÐOÓËçˆ6¾ºV{Ãÿ$Í÷Þä’‘¦+לqÚuŒ‹ErYŠíî•FȬ½òÀ=l Í]Y Q½ _ܳ1Ê÷äçF’„!€Í^ïÅ_n6ï9 œúIcjO>€¬·5œ?gm¯¼ÇËçÀk˜00âs FŒù2@š¦KIӥϳøD½~ò=I²ðyD͇vê¶Äl­µ[kiºv-M—®2§Ý¼èàÅz`”®X¥°ôêíbð„)Á@:”°†uÔx;H7;a%‘Öjÿ]0!Ðe¶uŽ l*+Ê&¤c+‰¥L~Y= ”Oh˜ƒX¹gÇÖt»c w‚€%¡9x‘Ò¡„ürí¤Ü„Üuáðö-SÄ1Zåzym-JS¼2 ª…ç€êëõš8€ˆ§Bú¹ƒBÀÉ+ÕÑ`)êö#R®ù ª`¶¨`TP“DõaP\ܘ³4½ò‡iz囚͇¾:IŽ«1µCSƒŸekƒÁ…W­Ý*Ù›˜ˆ1])&¬—ŠÒJñ÷8qݾ¥½ÞKÏ×j÷¿¯Ñ¸ë—Œ1ì÷¥éÚê`pþ¬#ÔºgŸ¨Î±ôG£­Ë£Ñ³ßÛj½á#IrüˆÌ‰ÃÔ©¬íuƒ ç ý‹~qýJÊî%äì‹Rc¯Ý‚l¿ñZ»Ýzó±ß$2÷ÎS[ã114MŒ>†6ƒËŸ.¿¿Õzãw³øW¡ÖÁï_i6]}}4ºü:ÀC +Eb/bd/Åç@Œsû<,Áë!€¾µ››ƒÁæy¿lLëÁZíèÛˆÚÓeðÁÜìàE `,hh/©änÇe`l9¯´(Ðáä¼ß8sp—Ès¦7|ÿ¯í¸õ‹ì‰Àµ>t'á0‡’|yØRC¾àc¬—¸I"ñ”’ƒ2 §[Ž€ JÂ(-MU¶t`E–nh,@Rc´Àg>ȶQÙ Å?¡%¼PÀ!rŒK6¶WÀA¨ÐçpÁ‡‚¡ÚåNaaxz—,ú… ™t”‘ç 4ˆó÷Ž»2i/B[q}5䆠Á aö.¯?ÃDª…É2ܦcç&Þ°‘eË«Y¶üq'ëõ;ÏsôcÞhLãU©²Î¸°Ön­§éêµ4]¾"êKÊðj‘]/^KÅD¶ÔMÀ_u;,“¾ò¡[ž£“ï*Ñ@ýþ‹¿4ÿ¨Ù|àÛkµÎûˆjwìÅIYk³,[¾:]¹`m¦Íº`”+¬W‹ë½aL£s@Û^2fY¯Ÿe/ÿ3¿’$wœ©×1·5NÍG²-¯[o3M×–Òtùr¡I0ÄÄ!¨dÏ”@ãµâçJq]{ŘÎf0N½R¨qæ= IDAT`óZ·ûéj6ïÿ·IrüûŒi¾m?Û±Ðç8ië<¥hλLl TZ»ÖëõÖÎæç{¾Ä˜£ï4¦õ˜1Is~úW¿›¦›ËY¶|5Ë6–‹ñR&$%½ê<Jð¢dáõö<¨Ï½¼çÇóŽÇ½×ç@SîKÚ¿3ç>å–‰5‘³/ZÎï øúA.ˆQncä<—úÎkX¼F`SÜ#ö… I xqS÷þ11„=(ñ ˜ysXHоLúeò¥ !ºÉ¨·ò­X…Jð€*˜.ðai¢ïPÅ/ÒÊ/d^\eù ñy õ „EIvm‘ ÀÆkOaã*-JԼטú ¢zg–À†µ6³¶·ÅÜ_ϲÍÕ,[_bvÉ L.ËëWŒ«˜¬ŒïK*(å ^ÿ0ðú'jµ;?'IîøŠ$i?CT¿w¯Ú•Ù²µÃ>óp+¯Ùî®gÙÖ*ó tÌXuîenûìÆy3|–^AÛ¶ÃáÅkÀÅt²V;ñt’y’¨õ`’´î!šÍ„ÞÚ4³v°™÷¯­µ,[_fl9ý«6·0©i_qž%8¶U|n¸Ù!¼çêó> ×뀞ƒ›„ÓM€îx-Ù%ëªæ¼Ü’;W ¡½Üù±—™/,ÌÞɉÙÞò½¾¶ÓË]–”‘ê­iyá´%¹Å€ÁÛžRÿ047 ×!E0X»D•6‡HÀÝä_Õ„à¼ÂŠð%iº.€ ´­Zº¢NJ Äkw±_ÍÃK+J…dâ®YѺå%žs‹6 •—¸Ú(ÓŽE´»ç$#A\"…¥"û£Ú¾¤èmÈë*ÏÁ-W)ªÝ!W„`XP½¥Ü2ýñz µ0¶{¹CMC¶WSóŽ0.¤éµÒôÚ䔽 9j̽I²pQí8Qc‘(éÕZD¦ÁlêÆ˜:3%ù¤ŸŒÃÓaffÀZæ,%²)s6dN‡ÖŽúÌ£®µ½Mk»EÙ@æL¬ËÉž“•´ôu'r'¬}çÁ4KöÅØq¢xØ_.Þ_)’kƒÝ\Ø¢}Ê}•¶±v×ÍA²F€í‡>\øw€¹§V;þVc:OÓ¼?Ûª!2ÜÍÀZ€3k³ŒÈ¦ÖŽzÖºÌýÍ,ë®[»¹¢¬”l cºèV©s‘˜®"gkdÅw»bìEÛWŽžÞ óèRš^;—¦×Ž8’Ûä¨1‹÷&IãN ~Œ¨q„¨¶@”´òëÔS¨ÉWû M&{Ìù0…%*¯S–2gCk³!óhÓþsÃÚÞ¦§åX-'˜Z½q 0nL/xÆ÷E·¿0€,M—þcš.p—1û9úfcÚS¿¨#ª-I‹ÈÔóþ]Þëòö¬%Êå€tÄœ˜Óaþsسv°emoƒyÐuîS©sOvïË%Ó¨Ôq°»dXñ<(ÇÜz¾O¾š¦KÓté#ÈëÏ5îN’Î}Æ´ïêljjGŒ©-I0ü`"€(§EÛâ.ï@–Z›¥@6bÎÌÃ>ó¨oí |tEÿrÁ ·¹Ï·•Ì —Ͳýë0Þóóy†ëuÐΡ0\‡%ª¸É™•cqËCÈÙžtoÒ€[+¶ÃʽÁ£ Ú,ËTÁœY=K™ˆ1Îý‰sƒFÅ-C½¼pÜID²I’!€¨ ø¥!bÓ®¦~b'Üôá—ÈN6ì HV ˆ«ð$R*Fé ­´Ã-ñ ©¡”cT‚9ì'ï$˜Áèà°½ÇÀ‹bÅJ#B°0··ýXÑ~]JêWƒDzàk‰Œ•vÔô0¬Ó—”þn¡0-¨¢-…‹Ö]Æ$x%À¦‚õÂ!àän`Ò÷¨Ú1æp€ ¡“QLúÈW«œW'emk7ÎZ»ÑÆ„ÂW )¹(¸û"ñÀ’x’û@Êà‹/ ¤¨¿†qSüì9ÖýNŠÊ„h¹xo£hÇú cåjj™ð,÷¥Ü‹dO²Ö»œ¦Ëå?A.¸U$Öã:Õ†X%¡Š ÉЬÊ$e£#Öœd¥/d‚péÉ_V|·]ÍyÛ»OÇ‘s>nM°›èÙ‚µkg­…;>ëNÛ×§ŒOÎHÔ‰_Õ8uYRîµÛrÍ®H,G˜:ñ =kÖ—¬½þj‘Äýº)Vµ@mò-Ûp¤Üó\ÔRÛg V ÷ây Yz×1©?_d¾’¦ÃÏ+ ðéÜîs l‹ZÅ3@&/²¹+¤£Šþµ¥¼ÊçÄÀ6÷šÝsXïù‡õ¼Ãõ:0çÐé<ó|òÚ‹.3gW˜í5`t%Ë—¬í_JÓËWà³Â¸`pïUÐÙnî2 ™z?µ¶v’Ìô‘dűÚÌgwÆÄpDóÄ”  ` ¼,Þªµ&² è: "‘žªa zº’=¡Ø†JqP­»x‰¹«¯€‰X(+‰g PE"-@†òIhêF¸©‘ÏpÐDO=ÀH)%Aű“¬"•¬$ë¨tÔ"Rœ\•Ò“@ƒC8whî#¬ˆÄR9C°ÁcJ•åOnŠ(Ý!­N­iQrΟ¡ëƒxÛ âØ9ge&Úr¨À @O*ÅÑêÎD]«?” F]3\Ô*&Ïrâ*WuÝÚÅžX¸uŒ)ö‡yQÕ¦ýâ÷a‘ÔwyuDKÀúÐuö²Ï þ²ì&;N¢íÖª–ýB‚X©¸æe¢â&ìJÅJ{·/鯌 -¿†½Y¡Ú«¶wÛÛyJ6Rã&Çg­"áNœñ)ÛÆ*×\&ßÄè‹1ÚÇ„Må‚Nó¤K A:—¥VÚøºýº _ ¿}•QND­’¤E;ʶtÁÚöfÅ]Žm·¯m8ý©íô³6ÂzôÆ”~øÒêÏî-ÛDÖ±ËþåYEÒïù·ïy†ëuÀÎNá8`ÏsºòVÐD’,óöÓÀ×™qÈ®¸Äœ]b¶—€Ñ`x©ß¿rö £ 䦗­T†1˜©‹ŸµÃòÜç²G †Ì÷Šÿ‘d†ˆ¤Uupx€b™ZµYM»¡Ã„«÷ÀJâì%þ¬QW³e‚¨e‹ŠK’ΰ(¡`¥œDa¨BZˆüÕ;L! М=4ÇÙDSÊhä9HÍaÓ RJOKk—ÁT€VÙRûEž£ì‹¬X£UØÂÂTT`ˆªK¡\PÄ",!bž¼Â ‰::\LŒª8‹‰üÐIpLVr%X¡%H‰ó]—æWõ`œdŒœÉéHLTS1ù 3†_k^ÚVµÁ®<óà׋îådV²´•[7¡–É©1$c €X2A©«Ü WV|?Ù£ÉÝ^·½ÛÞ™|úÎø¬+c´&~¯M§µÍ°R1NG ¸˜ÍÑ8½Yn]FU,´í@ ÙWÜûös(Ú6ÑØ–õç}¥Ÿ5œŸ.ÛgZ?«Ú§ Æ´g|/À˜xq;ÝóÛy†ëuPΈ°­í9‘Iœ"Â)z0‰ÅÅ»ÙZ^%Ê®2ã2sv™ˆ/Ù%k³‹Ìý‹Ön^VÖ*î­;e°3Î,u´­ôœ6ÏÄ\÷†ûÍ-Vý\0ÿ§-O}œ:ÎgY$œÒµBêH¨J*› ؉ºÇ@uæ*™^iGC@Zb’ š ¨X¥Ç¸\p…ª’Ì{Ç©¹pHÀ)˜B[Õn$€à^ƒ W©ŒGFÕ¬Vƒrlymµ>¬ò} aÏbYù¿-|¶†bþá¹Îh®'$ö/tD,*tT §‰Ô†î1ä{®B×µ9¤`†L–½Þ0‡ö{…˜” ¦œÄfb2›‰$hh1ËŠDàVnfR3+JUÂ× —–Ð@¹­IFÜJo"AÑŽm/¯Á,Ú¾ p,ÇYÿÇ')ãÓ›Tqn@XC,Ç©ãTÒ‚çmœÞh"?ýúF-Z—m(ÙVtò~gg8¶5àÌ€†QúWMéoFyTÕ©W­:j÷ÿªvÙÏþu;ÜóÓy†ëuPΡ¾Kû&cè vžpStc€¼Òïn¯|Ýhtý%LXÅåk¸S ƒˆÞ9Ó‡÷zYª7-ì¼C&9‰1y髹ãSc]L£‡}œÞ ˜QN&IômÙ¾˜’¬C·Z·–$ð>Žï*p[ëct6vØ6óÒ.·ó=ÿ0÷a¸^àxÐÌ,J9úµÀõ_‡oém—Åm§ŸD§sæ "zb–›eÝ.|±ei·½wLŒñe#‡–®p1TeBX¡V’fA*’9ªHUBKniJ‰ O$yI¼8`¢lÀµ,€‡ËRÐX#$À¯-*˜$L¨4Ò”–³ªÖ†ðhà$ à81¶É…þ²Oë×ÒÝû7V@?yNÁq±¯‡ Ô*JÀgf1bĈ#FŒ1bÜ\¼0ë&I£Ýj½ñ‹ˆê§‘«}žp€ãÈÙ®[Zð:zô©ãÎécÞ5Ëã¶6³iº´ŒÐN}>coÝI˜&‚$²­ ùšl0•âï2 TŸ¤ýk AXôJK#ëˆ 2L̬*É.)mB:ÞïÒj“ýÂUú$AIôU©!˪ºÑD«Ák„×™Øÿ]–ëé z­+¬WTñ9W0Ó=Ç ÏP"`ºXçóÛÒ–úUŒML–¤ÛŠs}Ü&ÕHù}ÂHábìqq)FŒ1bĈ#FŒ› fû§DÉÌ÷›$ícíöS_ž¦Wÿt8¼Ü¸[€Tä÷=L,jǂŠOCšÒc™õ1gÙêsVj_ô³GÖl9 ÆÞº“°Dª²LT'T²|d\²ÁÕnƒLĽÄw;›Ö ÛP†.2IЏ#;É©,We¬ ‰ŠJÖ l(’°#]ZÚI†ˆ³ŸèWæ¸5ªÅ4­(B§²WqxìRÇD¹”ÀŒS €Й=SK{*Æ„'œi'b¦cÁúàF U¢ˆ–V}ÌÕšžL‚äô=*ÆÅ^–øÆˆ#FŒ1bĈq8ÃÚÑ¿7&Ù—}Sk4÷~A½~ê™,Ûú˜µ½2wÿÌÚÁ+Y6¼\¯o$É‘#Æ´"ª!³y1æÑýj«ÑèêUL´0¶ c9c€Y{æiÏ6:Z¢À{kšž…–¸)+éŒ ™ámN®Šk9½bÙ*YÒÁ °èaL9'ò ½§Sá€'S57X„Ü„›B6‰¦¸ µÂ ìr3€%»F*¦"Êk<M„N$L!+ÆeS%FÐ¯ÇøtIéwm)¯¿‡ª@ØórEiˆbÙÊî4%›ƒ ÷·®jè'ÐaaªW™KRp¢9ª”¬éb4ƒÐAªÀ}”ú׉§ °F©Ñ”ý“tb©2‚ãaÝÆíSnâÏjSüªæú{ 0¥OKÀOôufHòÎÕê×®ê=‚[òÄj¿Œ#FŒ1bĈ#Æö±µõÒ23~&¶DÖ‡Ã᫯a"æ¹V× £72Üä’êΘÈY¥Õ*…ÈûŒ–Tó4{Pª`ÁNÉÚäg5vKßgEhÔ4”–§0ª{®8 ,<e¼?+þ­Øz€Ý EK98" ÄI=–,ÔÄݵ@­Ò“TX!¨j#ÖKNPÅð!E3Bc-°^"â‚Ì}Ca[È2*V®µºo­Äˆ”k‡°O•kç|!%O4FŒ1bĈ#FŒ7Å,{åÇ­µË±9ü ^;Ïœ ³-6,¸Zk°qS‚ž·b”‚‡„²”„§å¢“äÌaXík;‚t}R4/P‘Tºoº@ s¨GÀrE+â2É•I< dñNNY% ©´u¯Êœ*òYMÏAÄy‘>:óë¦è9hÀ‹«[á]N “u­ü'¥»…”Çž‹ö ``50CèT£$åñ‘¨g’mG6ͽtˆYÔˆÂÒ®|x’${Tz«€!Z¬í ú "3ç 0EM†+ÀŒ ag=Ù”`‡ÊÏ[èb•ãÃ#0R@©ãà9V8Ç2ÖväPBõÔ„E4qÒª2 ¢ÄºÐ+o‡®T?UýP~ÞË÷·Ñ ˜ìkµ¸ššÞ†Wvâ¨Á–ím¡‰Ë²rÝ<¦† Ž•ʱ;áÉ .±¬$FŒ1bĈ#FŒ„íõžýEæô—bS£ÑêÊpøÚ«È;·—Ž\p±ø¹Šœ…1ÂÕùÌ­`ž”ÑؘZï_Q^  ŠhŽ#ãÐôˆu!J@IØ5ñJT¸qðôd™ªÊÀ$H°¦W¯“´J Õ½E¸ X-U:ÐKI¸â¿,(`(ú 2ÑJk‚ žn„tƒ©røPPY"%…=«F ÆJ*ÝgÆŽ;4P<ÖD‰u¸¥8Ó@VÜwœkTð.@Eï` Šzƈ#FŒ1bĈ±³(gÜÙÖÖ…¿imöÑÛ¹1Òtks08'’e— ãrFÆ&&‚ž;ÊDvbpIA'¯ƒ*œ8 “7(@ª“ù€¯±(AY† ¼r «',€( DÕùh` “&𠇊ý‚Cg–ñ¥‚V¾½´Ð÷IÐAu¢:e°"šÊÕZ"ÖµÐ­ÒæÐnؾ0^/^% £ja܈Q,¤ôq1 {â 0Qõ Ý ‘xÉ'm‹)¢”2±ó€gå[[—“¤‰6*I%ª÷¥ê"ÁšÎ€ƒ¤ì{Ê÷hš€¦á±\Pfð¦8¬ ºô…mÅ1s…à)BËXᣠ® ˆJR>·½þ¨¶›å*KX«Z¬Ÿ×—ËØàïâ7¶ž&Ê#FŒ1bĈ#FŒiQÎÌÓáðÂ¥Ñèò{­M?~;5Àh´|­ß?÷<`{˜ˆx^ðZñº„Ü^µ‹[(#¹5Ãñ4pó?’f}õžI '^BF~Rè+8b7ÄtPÜ/\ Áeyxº˜ÒäÖ¡šG ¤©9Ÿ@/­± Àš `AsTaÅDÕÚÐq莼 h¡{©*DÞÆFºË‡v<ÚñJÐ¥BïÃUX=X˜*´8dŸãià”2n*uÔ¾:ѯ™hÛ0"#FŒ1bĈ#FŒ[2FÃáå‹ÝîK_gíà·ûI[›¥ýþËçƒó/ܰŽÜBõ€W¼\ü~Ëbž·b8ˆEþ+©‰<*’1Õ¹P-GQeWYÅШ”„Oß×ì9ÙK`ŠöB sÀzù”„ž*@ƒò;„jr¤´UX¼z¬ª4‡™”7¯µ$ì’…Qa÷©êx@\¯Š¾1>U®îbêµR5’ÀªÝfX´W켊õÁaGd,ÊÉÐK‡¦\—àoBã…+Ø+ìm¼¢h°#FŒ1bĈ#Æn€°q­Û}ö»Ót嬵ë‡ñdÓt}¹×{îãiºt“ò‘K^ð€óÈËH®àÆ-—‘”QÛñåñ"áŸ:å{ÞÇdbJaNTñïi‹›Ì !΀-✆[Žàf?IÊ>ØI¸y›}xšò} A Ûw-GÉi-ùwu3‚} ÂÛ+çÉûÇ[^·?¸×Ìm³q_¦Â„D‰9@”IDATicĈ#FŒ1bĈ± £€³l+ëõ^ø“¤ýKµÚé¯O’ÎÓ¸ÿ ”µi–ek×G£ë­Ý\-À‹^P¬"ga\E.äyyùÈ*r‹Õán;1J#‡2€-þU}Y”&h娲 ¼I%I± ë$œN¢é~–+XAVHúg‚y÷ã‚ÀðY¤°‚6à‚@p# y²íı•çOâ"Œ™(ßU& ¯­ô` ûÌ/ñŸÂ¾€Ó>€PpÐ3f:Ø  …óʆF9v ´û-û¦ºi ·µÒP5(ç:U–èŽ(t1bĈ#FŒ1bìÑ/þfY¯Ÿe/ýoþu’{[½~â]D OÓ¸—Ș¹; NGY¶¹’¦ëKiºt¥pàEɾXEζ¸Ž\ c ¹€çFñ¹&»¶jº3&•€Å™Ðt .¶cCÀOÈ”ÜÒÛŽ¤áCNbHZBW±Ê_&Ÿ²”ºekàAä'¼ì¤3$Ô}) J0HPƒ@Bº®9†Ç’Z ¤] (à +åX!€íت Èc«hQûžÊꈒÖ¶Iê%ð*–}æ U€  G¹¾Ì!¦&]q¤Um)z냂%ËIbĈ#FŒ1bÄØ# £ÔÊ Æf–­­dÙÚ§œ JîN’oI’Έ§‰Z'©!šÝ*#³eæa7ËzÖöÖ³lcÅÚÍåâøGÈ™}äÌŠâU20VŠŸkÅû]LØv·Œƒ“x%«ÕHõ&ÜϺ‰¾÷u 68¥r3¨LpÅöJ¾¢[Ápl]]}VÎÓJRœ„ÙPÔ¤]&ýPŽS–c@°Mà·!„^†Ël'ò’Í!–} Dm{è×NMäÅ9ìq½Ô„^0IPÈKáêgx%3¢¬D³r•×S2sHEÂ> ^oöÛUgÙÌSÊP(gP1Oj¥JKä¼Ä$–“Ĉ#FŒ1bĈ±@FV$ó%ÑCÎbXp9»˜¦×Χéµ#ŽèÉqcÚwÓ¼Ó˜Æq q”¨Ö!JšD¦AdÌIÝSc&ÈEò4™k‰˜­µ)`GÌÙ¬MÌ£®µý.ó`ÃÚÞÀ%k¢.†˜”ôc³,ÖŠóØ(þÖ+>Ÿ:à vÀØ1ˆ1¦ã;Ù§.ÖÉ€­.‘z™àº.^Ò¨±- '¸å±J Ä4aFëU%€^ž&~Û‘Æjp\M÷@&ÖN’¯–™í ï{¬$Ìš(ùɳÄ$øæ€ý éRhÀ˜OÔ2¥ ¡×Ï`TcEÄS 9¹J·‚«-…ƒãjÆŽ÷wi뺣XÀ;`™= +FŒ1bĈ#FŒ» d”³ûQf”ŒŒ-äl†絘ÿ̬Ý\°v³      ^¼j’âUC^õnŠýTÓ¬Kf„uÀ•ÔXFÎñ¹F·8Þòµé¼?À„yá–ŽìY†±c&†´Ç`ÅÂ#(`€BÉ×4*!*$¿ìÉO–e¢ªä†Õåä0"4¡HÖƒ"þ(A ¹ª>–êp\éÜÖWå5áLMGÀŠdsW¸ŸTdíå9Èr‰"h ÊtÚ’.°¤2&8dµn'ŠE¬W&C¾Öˆ<7UŸÄú}T2D‚vgè!sK§¸¤3UXÒJÇÈcÉ~ÀöP.`¡‰eB]X³.-ûšõA“* [V@žÀ±FTQ¹ št¡!Ùo5pI)ýÑ?éÂpY¯/3ÊÿòïM60Ç‘‰#FŒ1bĈ#Æ^ål>u~–ÌãuVÔÅû·ÂÄ(Ù. ’:Ç¢½RZ¤Î¶0+ðâV@ ?9.Ó ‘û‰Ñ䜪ì?½ä›CáÄ`%¾Â‚"ÒTpٓܤŠf Õ @à àBSð78ÐIÞFCÂXE0à³SA2\Ý혉E™)•î3Ž;ŒWŽB×Cº¢ßî¬ØJ«Wr†ç`à)×P]@ªDK!û„h. tPKdªÊ]4YÞ¦Ÿ‹N˜k`ðT,0¿Ž%€‘—”D]Ï1bĈ#FŒ1ff@IþË’r@‰¤øwÍùw¢üÝe`@ù)Ó f¸ì ÷å¾Ï pìCazm'ík °*( 8É“e/µÌ9}]+Upái(Š,•"‘ÎßÀB'R,q¼I'¹w“xM7Áu‘‰0k¨"¹ÊO¦ 0Òåb*Ä!P z•­¿ÌB&ÖÌ:2¥¹Ïxëׄ:«h® AÇ”I½Â”™6¼<ë` U†ðúyýEN¨î´°rÍ @/#·É9xË[0[XÎ`9åKùAFIŒ1bĈ#FŒ1ö ÌpÓ Y,.KCJð¢êï€) ƒ[bRhÎ"û\Ü,ˆœ$”ôR2ÐÇ#òódþÿÛ;›9Žä ¿QÝCQõÁÙ/­Iö¶/࣯|õÝú¾0à“Œ}ðþ ð­5 ÚÕJ"µ\j%N“œÎtwU†•Y™Ù=äj—3ÖûƒÕÔGfV5¡x+â@¥¹§À*ÖH-0«DSE׆ŠÁ¤÷ERï"Õ¶&Ñøy‰Fv‡t÷ÛöiŸÊ÷fI J¯ƒ”-P (»¤"K¥5§÷o(†¡å§ÒÑÊzW²6Š6ª‚j¶LMÀÑŠ¡  /ˆóßPi&ä¥Fþ¹¨•Tî{!zI).x±§jþª¥`’•9iE|i °%ãwKT¢€4`Ôü31!„B¹l¢F-rÅ„ yÆkí&n{/žç*'™¿Ù8@Š…b1B2t”Zo[­B½D-ó£Òzµ0øÔÝwºÈ°Á¦½®–^Å5]kÒZ M©d7Lã4ËjMH²Žht*qBƒ:2AírˆLT©i‡ÚxòÝšÖZ€¢! y£Ë]â—õå(ºÌ¸}k™™øÓ0w­ [UÄ »ô:ŸÁâüGj‚œAEÕ<—:~ë4 PB¶õåiýkÇ B!„B^œ JÄõûþÿôK,/ 휸H\“x¡4l¡Úa@ЀNu4ì+&–@áß0ýYË€ÑgCP’8êf—5_DfÝT$O5˜m >PM†ò¼µî$¾ãG­SÆ4o_"â¼"¬×‰ïäRø` ÒžÔ¯î“j]RlHMHšÏM¡øûÊù¥’uQ+GB}¿]ϰ4<0¼×Š4|2ªæ¡•²¥IDÓ±L : A{„a‹aØ`Ö†Mñï^#ŠB!„rùÅï$Ý3,–ù³I ªÆÏ?~ï¯cþ6Ãfü]û±V! jÐü.hÐ&/Boê¨Î/@+çQÛ©AÝ1i?¯Pì2' ¨f{d×2«#Òpl‘ü8+ he±«wÁ‹*š¯Cv.uÙ•µó™ S ®î<~­\çõÇØy"Ïp™Îç…)-3<ÔÏÝÍÉ®¿ß¾+K»Æë®¼0Óšïž5¶×ä÷Î>»Ù¼üs㦂f7E£ÿE&`ôk|ñéO‹¾¸’}‹«Oÿ¡$„B!„\ ÃÇvÖÁ´` …PíÂ!Dèa§P]#h?ÆS*!Œ?¨ZKÏ÷Æ^Ñ.g¨–%ìPo qË(-1Âe>%µ )'®ZÛYpîöõë8ÝAT£TO%.‚,  Yþús€JiH6OTæV)òŒkaÇÖð*)®ëćâ™Q—ñÑ ª ;ÒXjbMQŠ¢¥xR9–êØ>5„ÙÀsØ¢Öèûsl·§è·'ØnOðŧeJ•hV ¶K¸$„B!„KÃrx¡¹x-€­˜`(ëqiCxŠ¡„¾ÿýö!Ëƒ%BPtèº齸B¡±?ª 7,üd~[m»XLBCË¿Õt»(;dtÅ( ÕXÿ·AzÑÃlÏÆf =]—àŠW)B:GÈM*­b·Û ŒÂ|²b Zˆ6RvîèÌÚ‡Š‘56q¦­"­têHû‡Z›J‰QÍÓCPš‹ZÁ@¤~/ŠÌÉ×Y+f°¾í¯í°bÛ¯ªk«ÞôTr’tpP¥Ä˜ô£ÿEŽ¡?Ãv{‚Íæ›í16›cs^IM§ï\™2}ç™A!„B¹T,*ÛRDÓ™Ÿ%€k^pcµºóñááû9·W(û€¾þú»xòäºÅ ,7±X¼Y\G‡%Ðus@)ƒ4×èZÑñSbɆI¬=ä²!å>°ûÆýÄäê bÇ¿­r\gW“óï¯W¹>ì5ÒßÅÑ\×n›k,Ü6˜ë¸1Ù5Räã)®×Mã¸jÇÔŽ)+¤Q‘ i~êö3Á¸ß>m ¶~ÜSóãÔlu÷*nËëòsª:ƒL7?ÏÊäë¢ñÉkTóñª?·YwUs>7¦é¸éï!î¦@A¨Žž¡?G?œb³9Ævýëó‡XŸ}Ï~ñÏSÕˆGŒ6±ZÝI"åc|à׎œQƒB!„B^µL ûÒß–‘ll¬cP“[)DACMÄ0vîYvi;šµQ5Ù;M\7“ZÛ^?Ýìy¨µV5÷B¥Ì$™†ã2oòì—9eþFH&žÉã›Í#œ¯WجWX¯eÛÃJž>2_­ßñóø=ï±ÇЗB!„B^´ˆaÃ9_N²pàTáòãM0—Ú­¾óö_àþƒÿÆvs‹ÅÅË, :`±¸ à: èd ÅbJKDíòýTb—)dƒöI!Þ·Ã µck~Y©…uÍ;ÌÝ+²X\ʯbÆQÐÍÏŒK̸BŒÚÅÅ–“xñ¤(9qs'Mã¯Í§q½Ú”yy\ù‹«ž)N nýý>þ8iý]*¥F•µ€+L§AýšÅ¯•qìÜÇw’mÏ[²0Æ.@[„°ÆÐŸ£ßž`³}2Šçßàüü!¾üü_Š/ÏÃH™OQÀx àÀiü®oÁv«„B!„+ bX!#ebœÇ çäWŸþÓ?Þ¾ýá?¤(OS»Tûz^·Þ|¾þ]÷ ¤»@p [ ¬ tÝuhwÁ2,€N è¢6"e\Qlð.Ám«ˆ +'ZÁkÊ6pw1F/Tæ#;‚]+(ˆõÚ0 "õ±]hNÒžkmÅ‚úÀ¿±–âÄAéé!zAq ¡˜øìÚ£# Á -AÄë‚"Kî…xÁJ+ë,m1dÚ4¥ÄŒ “‰gØBuƒ¡?Cß?²0Öë6çq÷W!32‰t“âórtt'‰”gžx?Ï1gcB!„BÈ¥1|&Æs&Æ1€Çöÿœ²/E›7¿ÿ¾zx"KŠα\žb±| ÒÝÀB^ºkYBB´áˆÑ¤ØHSÚ±^a^)ÎÈQêlçMk'öÁ§´õÙ#{íšQEw3‹ÔÅŠg7²lŠÆø­È’e !êÈîycϲùh[ Úµ>5¥>èR˜@m^õ¿è=Êÿ[cùÉ\ÝB £Æ0œcžb»=A¿=Æz½Âv½Â—wˆD¯“üäÏiú“¤,ŒS+1zc<5"³0!„B!/Ùó7Áhþyà%7¼àGÞð§?¹ýáßeozUœ)Dû¬Nppðc,~€ÅòÝâUtÝËè/ÅÒ’ÅxÉ$b4¢?Ù<‹¤)( ˜ª âkE| ï…3 ÝS¡hdah^R¢-G÷Ì×ú[ì[_Ù#êì âeÏÃVËb¨ý÷.Á§q®lm:d%6µ©íûVx1«ù¼ìûÂUîemîIp€*BVF²AÖcÆöÛþÛÍ1î}ö‘k S~­×ÆêèçC0V>ðŸþÀa4ö|ŒQÀd6!„B!ä…³¼À>©œÄšþcL9ÿfnM)10ÒÒ9ÒøAܺ¹pŸ>Âbù=,–¯¡ën¢ë®£ë®2} ºîŽZåJ&ªèŽ`5Bå$^È@åeþž2Ù“ u1íL”Ö„dßz&ºüzÏšMP+;‘æµ3gj¥*5¦ê˱#ë£Xßg_ö;³MëæÏ£ªQ¼ “™g[hØ`ÖöÛSüú‹Ÿb4ÕÌÍuAR+U{­ÌNt¿Óßø*~žÄí/!„B!—†‹¼×NmVS6Æ+³1~à=rûö‡Ÿ.¸ ªõ68:i@8^¿‰®ý1$–•Ýè!Ò,i ŠgÏrØ)t\$•¹»Æ>ñ@q±¬„½^ Ø/´„˜sÚ;Èç.šêÁÅλ÷þšn4ÕT ´ËvÝ·–Ù볈C»æ&;OjZ®j³0´G6¸÷gÙ÷JÙ³±ìô­ƒ8ʳ0>ǘ}ñoñóF¡2 ,'!„B!„\ #  ×\ð*€[~ àüÙíÛþm¹¦Z|SV’¿ä¯ô²œZgjÖÏ3½S®†xª¦äD綘Åþ«^FµAÕö¸´]L[Ê©Í%ÊÖžs/R/Ó”ñ(D§3ŠªuAæþ8 "³qªØ™4¯WK´NëZ9óšûÉüûÎù¨Sò~¢­cçQYQB§®6s˜­nt~ÝãúHÊXwÝöØ5;™={ëè9hn“«E·šâéÓùù73©œ;÷>qsQm 6ßÂ>¯ÚxN¢€Ñc̸xàÿ±œä¿Åè‘AcOB!„BÈ¥añ;VàX®Vw¾¼uøÁŸÛ¼ [zQz%H.Š1Œ®2û ÄL µýC[F*1°7íDãõT¤pδÕ)¸HÜMÜ›wÙ¡ÉdÊ(‰ŒEâ64Ú¿Š5^tFúKåÕ~^1ûЍQåÕ¿DgNlÊíoë‚a)SKTòû7;ªñ>§ÓK>nÑÚ™¸“wg·æõÇWͽÿð5R"æ»(³¯ˆÌ¥N¹åŠLÏË|ÊxïãócÛêfs'`¨_œ¼¼JÝUS¹ÆgÝý-Îïèèçɬ÷ cÆ=¿ŒâÅçËIN‘·W%„B!„+!bHCðIû‹ÕêÎo?ø ³¢³ "Y8˜þ"*¦UåìÃ`™!D Ç3óLÍDÉ¢D1N²tг֭bÄYl1CšÇÙ­ž¤#²x9Ϭ°ŠŠT§uóªæRÒQl¨k#àw¦Il‘xoò8ß:ƒæ†À–0 QŸ3'D n{¦N  ôç5JcŠO‰äe‡þ–Ýâé¡‘ü¹qk3ŠOj»þ}ÌÜ#3NMçfÁ&-pVö‘?7IpÑI8I÷"7UmÕǪ:c\ŽŽ>Œ€ñ£yç§þ7~ÞÇhæ¹ËH!„B!WPÄhÌgjÇŠÕêÎý[·>x_L4[vÐ(]ez­SEÅÒ×ú›º rzë¬2#MÓ…Š+æ$~ˆ¼’öU#`äbŠ4uu¦“³˜R ±'ÑÁý^´jÕFÖ­Kßàë¼6./`XdMlã™2{F²™O±y,íðSµB4²ô5™óIkoE%›ÕRÌf}ÄöÓ53Aij¡Åýø©K}µ,Ô„‡új¤­8¸Jõ>ˆU”b¶ÏL0z'`ü2 ¿ð%ÆÌ ÛZ•B!„B®œˆQ‹”Õü¤àhV«;÷V«;Oßw2˜Rêç·ÃR;¥JîL`ÓC›mæÒ{ ±¥&(‰¢Í¥MÙ¯ÿfÄ̱o*´œ[n1Åëb2K 5Áå(Àf­ˆLe7µ²’äa3F¼ðÔ^³Kæû0®åü³ ßfš˜sÛš’”y`U¡J+Õi™Ä”œ´žÈX"¤±3‡úÊ—,{ÅKM21+ÿ€À´˜iºV:¥Ìš&2'M"›ø¡åE)s‡N‚Δ‘‘çÜd÷cÊŠbÒÑÑÇÃÙÙWÆòÓ(T$ã0–‘Üð5FŒ­& !„B!䪉>òO”-X·ñ¿‡ÕêÎÑjuçé­Ã~Uä…ºóR¾;ˆ­ï÷% yœjd@§²ˆY:ˆVˆqÿfkOTÚ¼ªõÔˆù ©Á”;”Ú‚TjÝ4D*k4•hÑ#)Cŵ´cbF†VüIïe÷3×T‚çZ¿ZØyUZ²ýL%·Tf‰¡”LÆÁ”#SVE³ü3æŠ=âyÕ XsùŽ{ЦììÚl-Å4¤°)[Ä–[Õ¬+|¤µÌ-oˇ'ýðèãáììA/Î0·QýsÆ'¾ˆÆ1æn$Ì „B!„\:ä9÷OmW–»–¼ à5‡ÞðƬïøQÜþêíŸüÍÛêƒZ×2óº˜+7æÐM[=$djG™R j]_ç+Ìs7Ž9›ÍîURgŒ"†V7LµM+&Á"ïL;÷±¨®‡Í’hޝÒq#]ßZOèŽy©Î×ËvtœÉº¬h6×ÔîSWîGZSÛ­w×ÚN÷`ÎDÈ„)×¹d*•‰÷ö?)Ç[^kîú25dqíLóåŸ:ܤ±‰mCc»Á”ß…©ÛŒVîlÚ‚‡ÿ½›ƒ“€q„±É]ŒþŸa4õüÀ“(` 0!„B!ÿ_D /dˆ20¶_½ à ?ŒbÆ[ÞŽÿý½ø·Wâ¾/Åc»ç !¤T®’xqޱ<ä F¡âÆ2’{ñç7…“¸/30!„B!—šåsLsü-@6€:ðÀWE +d¼ŠYÌHB!äù¾“ÖŸfƒÑœó Fÿ‹ô|¾ŠÛž`ôÈØ€!„B!ä ß±©0?•˜¤ò’—0–˜¼ àuŒÂÅaü¹·½÷¹†1£ƒÙ„\5Ÿ¶„$ ˆ0Šögÿvб|$u!¡€A!„B¹ôÈ·t¼ïñ¸Ä(J`(®¸±ÔäU÷™D –”òlÔDŒ-Fqâc¦Åãø™„‹3ÌâÅ`Ž#„B!„K|ËçñbƹgFòÍHF é÷ø„}hå'u#9Ç(X<Å(Z¬ãvŠ„B!„+‹üžÎW+5Y ïh²p?0y6¼¡§õ¦I‚E-R׊„B!„+‹üÎk3,:ó)æ“!ϺO+V·B!„B®,ò¾FKÜ „ünhåwuÛ !„B!äJ#ß‘kò]¢!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„BÈ·Ïÿeû.Ö†Éè7IEND®B`‚pyclustering-0.10.1.2/docs/logo/pyclustering_logo_01.xcf000066400000000000000000007762471375753423500231700ustar00rootroot00000000000000gimp xcf file1BB:G gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) Ò3dV@î.ŸMל šsší ôà1Drop Shadow #2Ì     )‰1±3(343@3L3X1!1AQaq‘¡±ÁÑáñ!ZO>°ÀÐàð 0@P`p€§&*™//$/4/D/T/d/t/„/”/¤/´/Ä/Ô/ä0G0–0ð1H1X1h1x1ˆ1˜1¨1¸1È1Ø1è1ø222(282H2X2h2x2ˆ2˜2¨2¸2È2Ø2è2ø33 @ @ @ @bþ ø    õ#,-*'%#""ó #DVVOIDA@?>>ó -Vlj`WPLIHGGó-VjeYME@=<;;ò *O`YJ>5/,*)((ò 'IWN>0'!ò %DPE4&ò $BL@/  ò #@I=, ò "?H<* ò ">G;) ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(ýò ">G;(ýò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(@!  ÷ þ""ñ#$$# ý>>?ï@ACA9-%#" ýGGHíJKMMIB?@@:/%  ý;;ê<=>@BCDFILKFA:-  þ(()ê*+-0259=BFIKKD:,  þè!$(,05;AGJIC:- é $*07>DIJE9'   ê  &-5>FKI>.é %.7@HIE:( ê '1;EKK?*#ë ",7CLL?*(í )4AKL@(*î '4ALL: -ï &4CKE..î (7DI>(.ï ,;HI: 0ð "1AKE-/ð (8GJ;  ð  /?JE-ñ &7GK: úþò  0AKA% é æ );HE. ò æ #4EJ9   ñ æ /AK?"   &*.00ð.,)%! Ô *;H@%  ").48:<=?>:50*# Ó&7FD. "')*.247=DHF@;50)! Ó "3DJ:!))!!*6==95454-# é 0CMA#  '0+  ì !!$/75-" ã .AMC$  ,60   ñ /74* è +>KA$  "1;4 ò /60$è*=I@#  $4@8 ò$45* è);H?# %7B: ó 49.  è);G?" '8D" '9E=! ò/:2$ è(;G>" '9E=! ò,71$ è(;G>" '8DKB$  -60 í  085* ô .AMC% @þ(÷      ü ô#141-*'%$#""#÷%')( ò>ô?@BDHMM># ò>g{zodZSNKIHGGóHIKOU\_R5ò-VrxobULEA><;;ò<=?DJSZXE( ï7WhfZLA82.+*))((ò)+-18ALSM7  ï :T]UG9.'!ñ!'0GB, ð/EJ@1$ ð %4AF:# ð 8GF9* ñ *9DD3  ð'G@* ð-BG=. ñ &6CF7 ð 7FD8) ð ,G@* ð&;FA4& ñ &6CF7 ð*?F>0" ð ,F?1# ð !/>G?)ð 2DF;, ñ &6CF7 þ ï"9FC6( ì ,LMHDB@?>>ó?ACFKRYYF$ ó5R^\UOLIHGGòHIKNS[epr[/ò+FWYRJC?=<;;ò<=@EKUbpt]1ò /! ð (7DF7  ñ 7FC5& ð $2@E;& ð,@E;+ ð -1$ ð (7DF7 ô=>4' ð $2@E;&õ;5* ð -G;(þò ">G;(þò ">G;(þò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(þò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;(ýò ">G;) ýò "?H<* ýò #@I=+ ýò #AL@/  þ ó %DPE4&þó 'HVM=0& þó *O`YJ>5/+)((þ)ó-VjeYME@=;::;õ '0,  í  &086." à 0CNB# !))! #,5977õ5.# Ô "4EJ: #()+/36789>BB>82+" Ó&7FD. #)06;>?>>=<93,% Ô *# ùöñ ):HI5ð"1BLD* ð *:HJ: .ï %4CH>(-ï !/>HC.-ï +:FG8 -î (7DH='*î '5CKD.)í (5BML: &ë  *6CLM@)ì #-8BJL@+ é  (2BGJJE;. ñ "$&'( (è)*+-/258=ADGHHD@9-   ï !',14789::;ê=>@BCCEIKJE?8-%  ï #)06;?BDEFFêGHIJLMIB?@@9.$ ï #()+048:<=>>?î@ACA9-%#" ð!))! !" "ñ#$$# ó '0,  ø ó ,60 ô "1;4 3ô $4@8 3ô%7B: 3ô'8D" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô(:F>" 3ô );G>" 3ô *0! 0ñ+?B8( 1ñ 4@2" 2ó 9A5% 2ò !;C7&1ò !F:(1ò ">F:(1ò ">G:(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;(1ò ">G;)  'ò "?H<*  'ò #@I=+  'ò #AL@/   'ó %DPE4& 'ó 'HVM=0&  'ó *O`YJ>5/+)( ('ó-VjeYME@=;: :ð $2@E;&.ð -F?*.ð +:ED3 .ï &5BF:#.ð #1?G?*.ð ,;FD2 /ð '6BE9".ð"1>D;&/ñ +:D@,/ñ$3@C5 0ñ +:@8$/ñ #2=;)0ò (6<1 1ò ,98'1ó  0<7 2ó #4?8 2ó %6B: 2ó&8D" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" 1ò(:F>" +ò );G>" +ò *>þ?õ#--*'%#"" ø    þ þÀôIKPV_jlV-3ô@ADHOVVD# 3ô"#%'*--#3 ø  4þö'ó -Vlj_VPKIGF F'ó #DVVOHDA@?> >'õ#--*'%#" "(ø   )þÀFóGIKPV_jlV-+>ó?@ADHOVVD# +"õ#%'*--#+  ø  ,þî @ @ @ @ÔÔÔÔŠ E†"C!1Drop Shadow #1ÿ     #414CVVVV(V415£5³5Ã5Ó5ã5ó666#636C6S6c6s6ƒ6“6£6³9v=“B)E E0E@EPE`EpE€EE E°EÀEÐEàEðIþLªP·R8RHRXRhRxRˆR˜R¨R¸RÈRØRèRøSSgS–SõT$T4TDTTTdTtT„T”T¤T´TÄTÔTäTôUUU$U4UDUTUdUtU„U”U¤U´UÄUÔUäUô @ @ @ @bû ûö7JPOMLKKõ7n’›™”ŽôJ’Áʸ±­ª©©ôO›Ê;­ ™•””óO™Â¾¥zpkihhóM”¸­ŒlUGA?>>óL‘± zU:*# óKެ™oG*  óKª•jA#óKª”i? óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> @!ý ÷ þKKóJF8& ýñŒ…sZID@5%ý ©©ï¨¤˜ˆ~}{mVC3! ý””î’‹Œ“Ž‚udL4 þh hîikpx„……q]F0 þ>>ë?@CHOW_fmrtpfVB-  !ë #&,28?FOYbgh`P6! ê!&-7AMYa`Q;' "ê $.;ISWRE0 #ì !,9FPRE-+î !-;GI=(.ð #0 úúòO¨•lB#úúñ2k¢²˜mC#úúí-]”·µ•i@!úþé 3^’¹Ã¯Š_9 ü@ý%ýü"ûø/ENOMLK KùJD3ö$R–™–’Žù‹b4õ"W•»Ã½µ¯¬ª©©ø§}Kõ@~­¼¶ªŸ™•””÷“yT+ ô #Qœ}rlihhøg`M1 ó)Sxs_OEA?>>?ú:-  ó1VjcO:,%!÷ #%$ ó7RYL6#  ö  ó :QP=& ö ó&DQG2ö   ò0HN@) ö ó 7ML9"ö ó&CPF1ö  ó0GM?) öó 7ML9"ö  ó&CPF0ö ó/FL>) ö ó 3HI8"ö ó !>ù=8) ðPÀ˸–rR:+$ ú  ð:x²ËÁ¢{V8#  ú  ï (`ŸÅÇ®Šb?% ú ïFˆ¼Ëº™qK- ï1k©Éħ€Y7-ï &Z—ÁɳhC' -ïE‡»Ì¾žwQ1 .ï1lªÊÆ«…^ 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óJ‹§’g= ã -?LVm•¹È¼ŸxP. ûã ,9BIUk„“š¦¸Ã¼¦…a>#ýä"9Sk|‡’¢³»»¹·¯ž…fG, ä )Ed€•¡©®²±«¢—‰w`G/å# 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óK©”h> 2óJ‹§’g=  ”ù=þ<;ý:û:û:ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú9ú, ú, @ @ @ @óC™†_9 ó2^rcG+ ó/92$  ö !ù×ý4ý4þ58'óC™†_9  'ó2^rcG+  'ó/92$  (ö  )ùÏ ý, ý, þ-0 @ @ @ @ÔÔÔÔŠ E†"C!Ç Clusteringÿ     /+gimp-text-layerq(markup "Clustering") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode dynamic) (box-unit pixels) (hinting yes) XˆÇX¬íþî îî"ÇYˆ[>\½]]]m]}^^^Ÿ_7_×_ç_÷`hQq-u5xæ‡i¢”E›§¢iª¿±´·ó»¾¾ñÃäÈËÍîÓ4×=ÙÜvá+é5í6íFíVífíví†í–í¦í¶íÆíÖíæíö mô   ü 'û  $ü  !ü   þ  þ  ý $ ý # ý $ þ &  mô   ü 'û  $ü  !ü   þ  þ  ý $ ý # ý $ þ &  mþ0332ý3233÷23323232&û.03233$û323233!ü61233ü03233þ033þ/3!3ü3223!3ý123#3ý323$3ý323&3 mì6SqŽ«ÆÒÛåî÷ýøñêãÕÀ&ù >r¦Úþÿÿ$ûe³öÿÿ!û kÉþÿÿü)”òÿÿý/·ÿÿüžýÿÿü}õÿ!ÿý#Éÿ#ÿý^òÿ$ÿýÿ&ÿ @ û 8 ü 4 ü & þ $  þ!  þ  ý ! þ " þ # þ   @ û 8 ü 4 ü & þ $  þ!  þ  ý ! þ " þ # þ   @2ü32683ú2334.3 32ý3-&3ý1$#32þ*!3ü2333 3þ5!3þ4!3ý21#3þ2 3 @ù«–}X2 8ÿúã­v? 3 ÿû÷´g&ÿûþ¼W#ÿüìƒ!ÿüñÿýåSÿý² ÿýå:!ÿýúk#ÿþ‚ ÿ À - - - - - - - - - À - - - - - - - - - À3-3-3-3-3-3-3-3-3- Àÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ- ÷ ;  9  7  5  3 1 / -ý   ÷ ;  9  7  5  3 1 / -ý   ÷ý32:239þ2337þ1335þ1333þ03 31ý023 3/ý323 3-ý3233 ÷ý@À:ûAÀÿÿ8ýAÁÿÿ7ýBÁÿÿ5ýBÂÿÿ3ýCÂÿÿ1ýCÃÿ ÿ/ýDÄÿ ÿ-ýEÄÿÿ ñ 0 0 0 0 0 0 0 0  ñ 0 0 0 0 0 0 0 0  ñ30303030303030303 ñÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ À 2 2 2 2 2 2 2 2 2 À 2 2 2 2 2 2 2 2 2 À 32 32 32 32 32 32 32 32 32 À ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2@@@@þ ' ý ( ý ) þ * þ + . /  . þ . þ / þ 0 2 ý %  ö  & þ þ # þ ! þ! þ ! þ ! þ  þ  þ þ  þ  þ þ  þ  þ þ  þ þ  þ  þ þ  þ þ þ  þ   þ þ  þ þ   þ þ  þ þþ      þ  þ þ  þ þ  þ   þ þ  þ  þ þ  þ   þ þ  þ  þ þ  þ þ  þ  þ  þþ  þ  þ þ  þ ' ý ( ý ) þ * þ + . /  . þ . þ / þ 0 2 ý %  ö  & þ þ # þ ! þ! þ ! þ ! þ  þ  þ þ  þ  þ þ  þ  þ þ  þ þ  þ  þ þ  þ þ þ  þ   þ þ  þ þ   þ þ  þ þþ      þ  þ þ  þ þ  þ   þ þ  þ  þ þ  þ   þ þ  þ  þ þ  þ þ  þ  þ  þþ  þ  þ þ  ý.23'3þ53)3,3ý823*3þ23+3.3þ23-3þ,3.3þ23.3 þ23/3 þ*303 þ2303 ý323'3ö01*3*4122 þ23"32þ/ý-23 3ü23 þ23 3ý21þ23 3þ."3þ@þ233ý2$þ@3 3þ233 33þ/þ133þ2þ233þ13ý2333þ.33þ03þ23þ2þ2333þ1þ233þ233þ0þ233þ2þ233þ43þ0þ233þ2333 þ233þ2333þ633þ433þ1þ233þ2333þ2þ133þ2þ033ý3233ý2 3þ2þ233þ2þ133þ2þ433þ*þ233þ1þ233þ233þ533þ2þ233ý233ý23ý ´ÿ'ÿýÆÿ(ÿýÕÿ)ÿýÄÿ*ÿýªÿ+ÿþ‹ÿ,ÿþPÿ-ÿýêÿ-ÿþ¯ÿ.ÿ þ_ÿ/ÿ ý éÿ/ÿ þ}ÿ0ÿ ýñÿ#ÿòþ̆Y/ !Gs¶ þÿ"ÿüè}ýöÿ ÿü÷{þnÿ ÿýÎ#þÔÿÿý­ þ;ÿÿý­þ ÿÿý¿ýîÿÿýéþ<ÿÿþJþ†ÿÿþ®þÐÿÿýý%þÿÿþ°þPÿÿþGþÿÿýëþ²ÿÿþžþäÿÿþ]þÿÿþþ;ÿÿþëþXÿÿþ¾þsÿÿþ”þÿÿþuþ«ÿÿþXþÅÿÿþ>þÓÿÿþ-þÜÿÿþþäÿÿþþíÿÿþ þõÿÿþþýÿÿþþüÿÿþþõÿÿþ þïÿÿþ þéÿÿþþßÿÿþ!þËÿÿþ1þ·ÿÿþBþ¢ÿÿþTþŒÿÿþqþmÿÿþŽþHÿÿþ¬þ$ÿÿþÖýûÿÿýüþÑÿÿþ2þ›ÿÿþnþfÿÿþ°þ0ÿÿýïýìÿÿþMþ§ÿÿþ©þ_ÿÿýùýýÿÿþ–þ»ÿÿýú1þ]ÿÿýÓ  & & þ ( ' ý ) ) þ * þ * þ , , , þ , ý  ü  þ  ý  þ  þ      þ þ   ý   þ  ú þ  û  þ  ý  þ  û  þ  û  ú $ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 û $ þ  ý ! þ  û  þ þ   ü    þ   ý  þ   þ þ  þ þ  þ þ  þ  þ þ  þ    & & þ ( ' ý ) ) þ * þ * þ , , , þ , ý  ü  þ  ý  þ  þ      þ þ   ý   þ  ú þ  û  þ  ý  þ  û  þ  û  ú $ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 û $ þ  ý ! þ  û  þ þ   ü    þ   ý  þ   þ þ  þ þ  þ þ  þ  þ þ  þ   3þ2&3&3þ2'3þ2'3ý24)3þ$)3þ2)3ý21*3þ2+3þ1-3,3þ1 3þ23 3ý26 3þ*3!3þ2 3þ233þ2 3ý,233þ2 33þ2 33þ- 3þ233 3ý'233þ2 3þ233ü235 3 þ2332ý0@ 3 3ú2323. 3 3û2313 3 þ2332ü311 3 ù32232$# 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 3 û1221$ 3 32ý1$ 3 þ233û2330 3 þ2332þ/ 3 32þ/ 3 3þ4 3 þ233û232  3 32þ- 3 32 3þ433þ2 33 3ý/233þ0 33 33þ2 3ÿý’%ÿþ‹&ÿþn&ÿýýP'ÿýð!(ÿýË)ÿþ‰)ÿýû.*ÿýÈ+ÿþf+ÿýå ,ÿþu ÿþ÷ÿ ÿýí  ÿü gÕÿÿþo ÿüeêÿÿýÝ ÿý»ÿÿþP ÿý”ÿÿþº ÿþÿÿýý ÿý¯ÿÿþw ÿý ÜÿÿþÓ ÿþFÿÿúó½ƒJ ÿ þÀÿÿúÛ¢i/ ÿ þJÿ ÿúõÁ‡N ÿ ýßÿÿúߦm3 ÿ þ„ÿÿú÷Å‹R ÿ ù,ãªq7# ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ5 ÿ ú؈8# ÿ þYÿÿûæ˜H ÿ þ–ÿÿûñ¨Y ÿ þÝÿÿûú¹i ÿ þ'ÿ ÿûþÉy* ÿ þ{ÿÿûÚŠ: ÿ þÒÿÿûèšK ÿ þ6ÿÿûó«[ ÿ þŸÿÿýú¯ ÿýùÿÿþ± ÿþ•ÿÿþh ÿý*ûÿÿþ ÿýÂÿÿþÖ ÿþvÿÿþ ÿ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-33ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿÿ• # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # "þ  "þ  "þ  "þ  þ þ  þ þ  þ  þ þ  • # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # "þ  "þ  "þ  "þ  þ þ  þ þ  þ  þ þ  •3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3"þ 33"þ'33"þ-33"3"þ133þ3þ133þ-3þ43þ33þ3þ133•ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ"þÿÿ"þÿÿ"þ ÿÿ"þÿÿ"þ,ÿÿþþGÿÿþþfÿÿþþÿÿþ+þÁÿÿþTý øÿÿþþMÿÿû  þ   û  ü ü   ü ü $ þ ü ( ý ý - þ ý 0 ý 5 ý 8 þ  8 þ 9 ; þ : þ ; = ý < þ  ó   ý  þ ý  þ    þ   + þ þ  þ  þþ  þ  þ    þ % þ# ý "þ  þ  ú þ # ú þ *  þ 0  þ 4  þ þ 5 ü þ 7  þ 9 ý þ : ; þ 9 ý 7 þ 7 þ 6 þ 4 ý 2  0 ý -  )  þ % ü ü  û  þ   û  ü ü   ü ü $ þ ü ( ý ý - þ ý 0 ý 5 ý 8 þ  8 þ 9 ; þ : þ ; = ý < þ  ó   ý  þ ý  þ    þ   + þ þ  þ  þþ  þ  þ    þ % þ# ý "þ  þ  ú þ # ú þ *  þ 0  þ 4  þ þ 5 ü þ 7  þ 9 ý þ : ; þ 9 ý 7 þ 7 þ 6 þ 4 ý 2  0 ý -  )  þ % ü ü  ÷0312332233ï232323223223213.þ@33þ233ü21*ü1223"32þ1ý323+3ü$323,3ý23 ý12303ý2*ý@2343þ4ý02353þ2ý.2373þ6393þ@3:3<3ý423:3þ23;3ý23<3ý2332õ31,.35113233þ833 ü.3233þ133þ1 ý423+3þ2ý.233þ233þ0,3þ* 323þ0þ1223ü21.þ233þ1$3ý26#þ233ý2/"3ü23.þ2332ý1*þ23!32ú32314þ23(323ý2* ý'23.32ý1. þ2343ý23832:3þ2ý32383ý21þ23:3ý82393þ1393þ4383þ4373ý32353ü*22333 ý02323 ü4223/3 û83223,3ý323*3þ422$3þ83323ú1232233â6\y•­ÀÓßêôøüÿüùöïçÞÐÀ¯™ƒfE ú6w®áÿÿúôÆL ûG íÿ"ÿû÷¥BünÚÿ(ÿüÛ^ üvòÿ,ÿýÔI ýHÙÿ0ÿý˜ ýŽÿ3ÿýÚ&ý¾ÿ5ÿþëýØÿ7ÿý Ìÿ8ÿý¼ÿ9ÿþ€ÿ:ÿý+ûÿ:ÿþ¹ÿ;ÿý7ÿ<ÿý¡ÿÿòð¢]3 #L|Èþÿÿýôÿÿý ü ™úÿÿþHÿÿþf ý+Øÿÿþ…ÿÿþ§ýÜÿÿþµÿÿþ9ý1ýÿÿþÖÿÿþ þžÿ ÿùöãÏ»¨ïÿÿþñ3öãÏ»¨”€mYE2 þúÿÿþR$þùÿÿýÔ #þçÿÿýÈ%"þÕÿÿûø¡J þ»ÿÿùùÇ‘_3 þƒÿ ÿöþ㿞~]=þFÿ(ÿø÷Ó®…Y- ý ÷ÿ-ÿúøÊ–\ þ ÿ2ÿûß™P þ6ÿ5ÿûô§FþÂÿ7ÿüÖZý,ûÿ8ÿýÙQþˆÿ:ÿýÊÿ9ÿýäÿ8ÿý0îÿ7ÿý+äÿ6ÿýÎÿ5ÿü‚ûÿ3ÿ ü/¯þÿ1ÿ ü+œñÿ/ÿ ûOæÿ,ÿû,n­êÿ(ÿú&`˜Íúÿ#ÿù6h™Êöÿÿù(V†¶èÿÿ$ý  )ý  'ý  %ý  #ý  # # # # # # # # # # # # # , , , , , þ , ý - ý . ý  / þ 0 þ 1 2 1 ý  2 þ 2 þ 3 þ 4 -   þ , ,  # # # # # # # # # # #      þ   þ   þ   þ   þ   þ   þ   þ   þ   þ      $ý  )ý  'ý  %ý  #ý  # # # # # # # # # # # # # , , , , , þ , ý - ý . ý  / þ 0 þ 1 2 1 ý  2 þ 2 þ 3 þ 4 -   þ , ,  # # # # # # # # # # #      þ   þ   þ   þ   þ   þ   þ   þ   þ   þ      $ý3233)23'þ233%þ133#þ133#3#3#3#3#3#3#3#3#3#3#3#3#3,3,3,3,3,3þ4-3þ4.3þ4/3þ6 /3þ2 03þ2 03ý23 23 13ý20 23þ2 33þ 43 33þ2 13ü21. ,3,33#3#3#3#3#3#3#3#3#3#3#3ý233ü32233ý21332333333þ2333333þ23333ý2,3 333þ23$ýEÅÿÿ)ýFÅÿÿ'ýFÆÿÿ%ýGÆÿÿ#ýGÇÿÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ,ÿ,ÿ,ÿ,ÿ,ÿþ5,ÿýó:-ÿýê!.ÿýÖ /ÿþ› 0ÿþF 0ÿýâ 1ÿþv 1ÿýí 2ÿþ‚ 2ÿýê 3ÿþ^ 3ÿþÊ ,ÿ÷”€mYE2 ,ÿ,ÿÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿý§ÿüÿè<ÿÿýöMÿÿýüZÿÿýø6ÿÿýäÿÿþ°ÿÿþEÿÿýÖÿÿþKÿÿþ²ÿÿýüÿÿþSÿÿþÿ0õ   +û  ý    þ  " þ $  % þ & þ ( þ ) þ * , þ + þ , þ - þ  ÷   þ  þ  þ   þ  ý    þ  þ þ  "þ  þ !þ  "þ  "þ  þ !þ  þ " þ !þ  þ ! þ ! þ!þ + - - - þ + - - - þ + þ + þ + þ + - þ + þ  "þ  þ 0õ   +û  ý    þ  " þ $  % þ & þ ( þ ) þ * , þ + þ , þ - þ  ÷   þ  þ  þ   þ  ý    þ  þ þ  "þ  þ !þ  "þ  "þ  þ !þ  þ " þ !þ  þ ! þ ! þ!þ + - - - þ + - - - þ + þ + þ + þ + - þ + þ  "þ  þ 03ü122332þ3*û012233 ü13233ü$2233ý*23 3ý123!3þ43$3'3)3ý*23'3þ.3)3ý323)3ý823*3þ23+3þ13,3þ03-3ý3233ù212/381133þ03 ý0233ý23 3 þ233ý23 3 3ý24 3 3þ2 ý.233"þ133þ0!þ233þ2!þ-33"3"þ233þ2"3"þ133"3þ1!3"þ23+3-3þ23+3-3þ23+3þ23+3-3þ23+3-3þ23+3þ23+3-3-3-33"þ133þ40ï@fƒ ½Õßèòûü÷òíß*úk¥Ùþÿÿ ü.…ÒÿÿüZÄÿÿünéÿÿüWÝÿ!ÿý¼ÿ#ÿýYïÿ$ÿý™ÿ&ÿý ¶ÿ'ÿýÌÿ(ÿýÍÿ)ÿý¿ÿ*ÿþ«ÿ+ÿþpÿ,ÿý4ùÿ,ÿý ÜÿÿöÉzA 3fÿÿþ€ÿÿý¼4ÿ ýöÿÿý÷c ÿ þªÿÿýò; ÿ ý'þÿÿýú? ÿ þ™ÿÿþo ý÷ÿÿýË þpÿÿþ9!þÅÿÿþÍ!ýþÿÿþh!þmÿÿþ!þ¬ÿÿþØ"þåÿÿþ™!þÿÿþl!þSÿÿþG!þvÿÿþ"!þ–ÿ+ÿþ·ÿ+ÿþÓÿ+ÿþàÿ+ÿþëÿ+ÿþõÿ+ÿþýÿ+ÿþúÿ+ÿþóÿ+ÿþëÿ+ÿþØÿ+ÿþÁÿ+ÿþ¨ÿ+ÿþ…ÿ+ÿþ^ÿÿþ!þ3ÿÿþ: ú 7 û 2 ý " ü  ý   !  # ý $ ý % ý &  ' ý ( ý * * þ + þ    þ û  þ  þ  þ þ   þ   ý    þ  ý  þ þ   þ  þ þ  þ  þ þ  þ þ  þ  þ  2 1 þ 2 1 þ 2 2 2 1 þ 1 þ 2 2 2 2 2 2 2  ú 7 û 2 ý " ü  ý   !  # ý $ ý % ý &  ' ý ( ý * * þ + þ    þ û  þ  þ  þ þ   þ   ý    þ  ý  þ þ   þ  þ þ  þ  þ þ  þ þ  þ  þ  2 1 þ 2 1 þ 2 2 2 1 þ 1 þ 2 2 2 2 2 2 2 2ú3220863ü2142 32ý3*!32þ33ý20 3ý2."3þ1#3ý23$3ý24&3þ0'3þ1(3þ4)3þ1+3*3þ2,3 3þ233ý26 3û63233þ2 3ý1233ý23 33þ2 3þ*33ý20 3ý1233þ1 3þ233 3þ633þ4 3þ233þ2 3þ133þ2 3ý3233 33þ2 3þ233 3þ233þ2 3þ033ý23 3þ-33þ0 13þ1 23 13þ2 13þ2 13þ2 23 13þ2 23 23 23 23 23 23 23 32 32 3÷Ï¿¬sV/6ÿùýÚ¦k01 ÿûèO!ÿüëŽ'ÿüýª/ÿüý›!ÿýï\#ÿý«$ÿý×&%ÿýï9&ÿýôB'ÿýô5(ÿýê#)ÿýÐ *ÿþ+ÿþJ ÿý­ñÿÿýã  ÿû €òÿÿþ„ ÿýÊÿÿýö ÿý ­ÿÿþ“ ÿýÁÿÿýõ ÿýòÿÿþz ÿþ}ÿÿþÚ ÿý óÿÿþ: ÿþ˜ÿÿþŒ ÿþBÿÿþØ ÿýòÿÿþ" ÿþ¸ÿÿþ_ ÿþ‚ÿÿþš ÿþUÿÿþÓ ÿþ/ÿÿýú ÿþÿÿþ) 1ÿþR 1ÿþq 1ÿþŽ 1ÿþ« 1ÿþ¿ 1ÿþÐ 1ÿþá 1ÿþî 1ÿþó 1ÿþø 1ÿþþ 2ÿ 2ÿ 2ÿ ÿ2 ÿ2 ÿ0 0 0 0 0 0 0 0 0 0 ™ú   ý /ü  þ þ  ý  ý  þ   þ  þ  þ  ý    þ  þ  ý   þ  þ 6 þ  þ  þ 5 ý 6 5 þ4 þ 4 þ 4 4 2 þ 2 þ % õ   þ # ý ü " ý ! ý " !  þ    þ     þ þ    þ  þ  þ  þ  þ   þ  þ þ 0 0 0 0 0 0 0 0 0 0 ™ú   ý /ü  þ þ  ý  ý  þ   þ  þ  þ  ý    þ  þ  ý   þ  þ 6 þ  þ  þ 5 ý 6 5 þ4 þ 4 þ 4 4 2 þ 2 þ % õ   þ # ý ü " ý ! ý " !  þ    þ     þ þ    þ  þ  þ  þ  þ   þ  þ þ 03030303030303030303˜ú83223223þ1/þ03 32þ* 3þ0ü312332þ03þ032þ33þ0ý3233þ23þ0ý 233þ23þ03ý233û0133þ23ý033þ/3ü0233þ23ý0133þ13ý0233þ23þ133þ13þ233ý2'53þ26343þ243þ033þ2 43 33þ. 33 %3ñ23033*41223320 $3þ2þ$33 #3þ4"3þ0"3!3 3þ43þ23þ1 33þ2333þ13 3þ23 3 3 3þ23þ03þ43þ13þ/3þ-3þ'30ÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ0ÿ˜òN‡¾ÛìûõãÕ]/üîÿ ÿüÈn ÿþüuõÿÿüö›$ÿþýÁÿÿüü ÿþýÒÿÿþÓÿþýÅÿÿþoÿþþ™ÿÿýòÿûRÿÿþ’ÿûéÿÿýþ%ÿü˜ÿÿþµÿü.ýÿÿþGÿý¶ÿÿý×ÿþMÿÿþkÿþÊÿÿýð 5ÿþŽ4ÿýý"4ÿþ±4ÿþC3ÿþÔ 3ÿþg 2ÿýî 2ÿþŠ %ÿñÙ{90f§ñÿÿü #ÿüï`ûO³© "ÿýß& þ !ÿýî$!ÿþT ÿþ½ ÿþ5ÿþÊÿþfÿýþÿþÊÿþ‹ÿþTÿþÿþóÿþÎÿþ¨ÿþŠÿþrÿþZÿþCÿþ5ÿþ(ÿþÿþÿþ ÿ 2 2 2 2 2 2 2 2 2 3            ý  þ  þ   ý   ý   ý   þ  - - - - - - - - - -  þ  ý  ü  ü    þ           þ   þ   þ   þ                     2 2 2 2 2 2 2 2 2 3            ý  þ  þ   ý   ý   ý   þ  - - - - - - - - - -  þ  ý  ü  ü    þ           þ   þ   þ   þ                     32 32 32 32 32 32 32 32 32 33 33þ0 33þ0 33þ0 33þ0 33þ0þ13 33þ0þ13 33þ0ý123 33ú0323 33û012333ü0/2333ý0233-3-3-3-3-3-3-3-3-3-3-3-33ý23 33ü23 33û233 33þ2 33þ1 33ý2  33þ2 33þ2 33 33 33þ4 33þ/ 33þ* 33þ* 33 33 33 33 33 33 33 33 33 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ3 ÿÿþ ÿÿþ ÿÿþ ÿÿþ ÿÿþþ(ÿ ÿÿþý=ïÿ ÿÿþýGöÿ ÿÿúD÷ÿ ÿÿû8õÿÿÿü%ëÿÿÿý$ÙÿÿÿþÇÿÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿÿþ…ÿ ÿÿý„ÿ ÿÿü´ÿ ÿÿûû"ÿ ÿÿþ¦ ÿÿþH ÿÿýö ÿÿþ¾ ÿÿþ ÿÿþc ÿÿþE ÿÿþ+ ÿÿþ ÿÿþ  ÿÿþ ÿÿþ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ   ý   û *û  ü %ü   "þ  ý ý  þ ý þ þ ! ý $ ý & & þ & ý þ & þ ) þþ ( þ ý ) , þ þ , þ , þ - þ 0 þ . þ / þ  ø  þ þ  ý  þ þ  ý  þ þ   þ   þ  þ  þ    þ    þ  þ   þ  þ  þ  þ         þ     þ   þ   þ       þ   þ         ý   û *û  ü %ü   "þ  ý ý  þ ý þ þ ! ý $ ý & & þ & ý þ & þ ) þþ ( þ ý ) , þ þ , þ , þ - þ 0 þ . þ / þ  ø  þ þ  ý  þ þ  ý  þ þ   þ   þ  þ  þ    þ    þ  þ   þ  þ  þ  þ         þ     þ   þ   þ       þ   þ       ü2332232û3113)û312233û233@$ü42233ý18 ü12233223þ.ý-233ý21þ23!3ý2.$3ý2-%3þ2&3þ2'3þ1(3þ2ý@23&3ý23þ23)3þ.3*3,3þ0ý/23+3.3þ-3.303þ23-3þ1 þ,3/3 þ2332ø4,$311233þ2 3þ0ý3233þ2 þ233 3 þ633 ý3233 þ033 þ233þ2 þ133 ý1233 þ233þ233 33 33 3þ433 3þ433 þ233þ033 33 þ2333 33 þ2333 33 þ2333 33 þ2333 þ2333 þ2333 þ2333 þ1333 33 þ2333 3 í2^†¯ÏÜèõüôêÙºšk3)û\¥ìÿÿûð£O$ü!Žñÿÿüßp ü üÿÿýÞPýdñÿÿýŸ ý°ÿÿýÒþÜÿ!ÿýÜ $ÿýÙ%ÿýº&ÿþn&ÿýóþÿ&ÿþýÊÿ&ÿýúþsÿ(ÿþŠý ôÿ(ÿýäþ¤ÿ*ÿþCý%üÿ*ÿþ‹þŸÿ+ÿþÌýøÿ+ÿýý þgÿ-ÿþ; þÅÿ-ÿþf ýþÿ-ÿþ þZÿÿõûºd03uÈÿÿþ¬ þŸÿÿýÂ)ýNãÿÿþà þÝÿÿþ ýÖÿÿþÛ ý þÿÿ ý'÷ÿÿþé þ9ÿÿ þ~ÿÿþñ þfÿÿ ýüÿÿþø þ‰ÿÿþºÿÿ þ£ÿÿþ€ÿÿ þ¼ÿÿþSÿÿ þÕÿÿþ+ÿÿ þåÿÿþÿÿ þíÿÿþÿÿ þôÿÿþÿÿ þüÿÿÿ þýÿÿÿ þöÿÿÿ þïÿÿÿ þçÿÿÿ þÖÿÿÿ þÀÿÿÿ þ«ÿÿÿ þŽÿÿÿ þiÿÿÿ þBÿÿÿ þÿÿÿ þáÿÿÿ þ¨ÿÿò  +þ  û $þ    ý  ý  !  þ ! þ   # þ  (  þ ) = > þ = þ = þ ì  ø  4 þ ý 0 þ þ . þ þ , þ þ + þ þ ) þ ý ) * * þ & þ þ & þ ) þ & þ ( þ % ' ' ' þ % þ þ % þ ' þ ( þ þ & þ ( þ þ ' þ * þ þ ) þ  ò  +þ  û $þ    ý  ý  !  þ ! þ   # þ  (  þ ) = > þ = þ = þ ì  ø  4 þ ý 0 þ þ . þ þ , þ þ + þ þ ) þ ý ) * * þ & þ þ & þ ) þ & þ ( þ % ' ' ' þ % þ þ % þ ' þ ( þ þ & þ ( þ þ ' þ * þ þ ) þ  ù$432232232ý0$)û*23233ü233$þ03323ý3233ý2-3ý$2333ý.23 3þ23ý123"3ý2.32&3ü833ü323&3ü2$33ý123)3þ3}3ý213=3þ23î34ù*'3122333þ2þ4333 ý123-3þ2 þ13-3þ@-3þ0þ23)3þ2þ53*3þ23'3ý28þ13(3þ23&3þ2þ23&3þ2(3þ1þ13&3þ/(3'3þ8'3þ@'3'3þ8þ23%3þ,þ23&3þ*3&3þ2þ03&3þ2þ23&3þ2þ23&3ý2@*3þ23(3þ2þ23)3þ4þ433í:r—ºÚçòüöêßÒ´Ži>)ûe¼öÿÿûôµm$ü/¨ùÿÿüöœ-þÿÿü'±þÿÿüþ˜þÿÿüøÿÿýéSþÿÿý Îÿ ÿý„þÿÿýBìÿ"ÿý± þÿÿýPúÿ$ÿú¼ÿÿüSúÿ&ÿûµÿÿý=úÿ(ÿü¨ÿÿþéÿ*ÿývÿ<ÿýüGÿ=ÿþíÿëÿôþÇr5 ,a±üÿ2ÿýÑ7ý!­ÿ0ÿýš ýaúÿ-ÿýœ ýGùÿ+ÿýÆþ^ÿ*ÿýþ/þ¯ÿ)ÿþ±ýïÿ(ÿþNþŽÿ'ÿýöþ(ÿ'ÿþ½þÅÿ&ÿþ‰þˆÿ&ÿþ_þSÿ&ÿþ=þÿ&ÿþ%ýýÿ%ÿþþïÿ%ÿþþàÿ%ÿþþÑÿ%ÿþþÑÿ%ÿþþØÿ%ÿþþëÿ%ÿþ,ýþÿ%ÿþKþ)ÿ&ÿþtþVÿ&ÿþ¬þ“ÿ&ÿýìþßÿ'ÿþEþ<ÿ(ÿþ°þ¯ÿ(ÿýþ5þ?ÿÿ2                                              2                                              233333333333333333333333333333333333333333333332ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ý  þ þ  þ þ þ  ý þ ! ü ' ô  þ 0 1 0 þ . / . þ , þ + þ * þ ) * ) ( ý $ þ $ þ " ý ý  ý  !þ  $ü  'û  -ü  ü   À ý  þ þ  þ þ þ  ý þ ! ü ' ô  þ 0 1 0 þ . / . þ , þ + þ * þ ) * ) ( ý $ þ $ þ " ý ý  ý  !þ  $ü  'û  -ü  ü   À þ*33þ2þ233ý2$þ033ý21þ2332þ23"3ý23þ23"32õ35$@'-0232 ý-23/3 13 þ*3/3ý323-3þ23-3.3ý,23+3ý123*3þ23*3þ23)3þ23(3þ13'32&3ý123$3ý423#3ü$223!3þ13!3!33!ü32233$þ1223'û-13233,ú303132232À ý óÿÿý¯þ–ÿÿý¥ý$ýÿÿý¿þ¬ÿÿüí`ý2þÿ ÿüÖeþ¢ÿ"ÿñö¹yK' 9_•× ýõÿ/ÿ þ|ÿ/ÿ ýÐÿ.ÿý1ûÿ-ÿþ}ÿ-ÿý¼ÿ,ÿýæÿ+ÿý8÷ÿ*ÿýUþÿ)ÿþsÿ)ÿþyÿ(ÿþzÿ'ÿýdûÿ%ÿýHðÿ$ÿý!Êÿ#ÿü‡ûÿ!ÿý.Çÿ ÿüTÕÿÿüTÁÿÿ!ü,Œáÿÿ#ú8ƒÈüÿÿ'ùG|±àþÿÿ,ì /Tp‹¥ºÊÙçðõúþýùôëÜ¿þ  þ ý     þ  þ þ  þ - þ , þ , þ , + þ * þ ) þ ) þ ( þ ' þ ' & þ% þ $ þ" þ ! þ  ý  ý  þ   "  $ & û 3 û øþ  þ ý     þ  þ þ  þ - þ , þ , þ , + þ * þ ) þ ) þ ( þ ' þ ' & þ% þ $ þ" þ ! þ  ý  ý  þ   "  $ & û 3 û øý0233þ4 3ý0233þ2 3þ233þ2 3ý,233þ5 3þ03"3-3þ2-3,3þ4+3þ2*3ý20*3þ2)3þ2(3ý24(3þ1(3&3ý2@%3ý2'$3ý25#3ý23"3ý2  32 3þ13þ*3ý203þ2!32þ1#3ü210%3û231322ü31-øýCüÿÿþ5 ÿý9òÿÿþÒ ÿýUóÿÿþn ÿý ÿÿýø ÿü)óÿÿþ¨-ÿþ2,ÿþ®+ÿýý++ÿþ¥*ÿý÷$*ÿþt)ÿýÅ(ÿýö&(ÿþk'ÿþ•&ÿýµ%ÿýÏ $ÿýÏ#ÿý¾"ÿý« ÿüü‚ÿýÛ8ÿýš ÿý»4ÿýÇA!ÿüû«B#ÿûøºf%ÿúG 2øÍº¡‡hBø - - þ + þ + þ + þ + þ + - þ + - þ + , , þ * + + þ ) * þ ( þ ' ( ý % ý $ ý # þ # # þ 1 þ 4ù  þ ¿ - - þ + þ + þ + þ + þ + - þ + - þ + , , þ * + + þ ) * þ ( þ ' ( ý % ý $ ý # þ # # þ 1 þ 4ù  þ ¿3-3þ23+3-3þ23+3þ23+3-3þ23+3þ23+3þ23+3þ43+3þ53+3þ23*3,3þ23*3ý@23)3+3ý323(3þ23(3ý423'3þ23'3ý@23&3ý523%3'3þ43$3þ*3#3ý323 3ü3223 30ý313 33þ$22þ322û3232¿ÿ-ÿþúÿ+ÿþóÿ+ÿþëÿ+ÿþÞÿ+ÿþÇÿ+ÿþ¯ÿ+ÿþ“ÿ+ÿþjÿ+ÿþ?ÿ+ÿýþÿ*ÿþÒÿ*ÿþÿ*ÿþFÿ*ÿýèÿ)ÿþÿ)ÿý"ûÿ(ÿþ¢ÿ(ÿý!õÿ'ÿþtÿ'ÿý¾ÿ&ÿýÜÿ%ÿý"ßÿ$ÿýÕÿ#ÿý £ÿ"ÿýSáÿ ÿü tâÿ ÿ0ûR¨óÿ ÿ3ó7nœ½ÜìöýõéÝ¿þ þ  ý  ý     ý   ý   þ  ü # 0 ü / þ 1 þ 1 þ 1 2 þ 0 þ 0 1  þ   ý   û   þ    þ   ý þ   ý þ   ý þ   ý þ   þ þ   ü þ   û 5ú úþ þ  ý  ý     ý   ý   þ  ü # 0 ü / þ 1 þ 1 þ 1 2 þ 0 þ 0 1  þ   ý   û   þ    þ   ý þ   ý þ   ý þ   ý þ   þ þ   ü þ   û 5ú úþ2þ233ý3/ý12333þ2333þ0 þ2333ý23 þ2333þ13 332ø5*.01323 303 ý61303 þ2313 33 þ1313 þ@313 23 ý323/3 13 3ý24333ü2.0333ü10333ú200333þ0þ0333þ4þ0333þ4þ033 3ý2-þ033 3ý23þ033 3þ-þ0333ý20 þ0333û232052þ0úþ¾þ¬ÿÿýýý(üÿÿýÿ ý»ÿÿüÿø) þŒÿÿÿýØ ýŽÿÿÿýäNý.ÇÿÿÿõÈt2/f¼üÿ ÿ0ÿ ü (Dÿ/ÿ þÜÿ1ÿ þ•ÿ1ÿ þHÿ1ÿ ýåÿ0ÿ þ†ÿ0ÿ ý÷ÿ/ÿ þÿÿþÌÿÿ þÿÿýÓ0ÿÿÿüç $ÿÿÿûó3$ÿÿÿúõ>$ÿÿÿýôCþ$ÿÿÿýî:þ$ÿÿÿýÛ&þ$ÿÿ ÿý°þ$ÿÿ ÿýògþ$ÿÿ ÿüý¤þ$ÿÿÿüó“$ þ$ÿÿÿûí¨_5ùϯˆ`4ù$û  )ü  ,þ  -þ  . õ  ÷  þ þ  û  ý þ ( þ þ ) þ þ * þþ , þ 2 þ 2  ø  U þ = þ = þ = ü ; þ ; þ : þ 9 ý 6 þ 7 ý . ý ü *  þ ( þ ý    ü ý  þ   õ Î$û  )ü  ,þ  -þ  . õ  ÷  þ þ  û  ý þ ( þ þ ) þ þ * þþ , þ 2 þ 2  ø  U þ = þ = þ = ü ; þ ; þ : þ 9 ý 6 þ 7 ý . ý ü *  þ ( þ ý    ü ý  þ   õ Î$û-12233(û.12233+ý8233-þ233.3õ,213232321þ233÷$03232323 3þ*33ù23232233þ5þ63)3þ13(32,3þ.þ03+3ý23 ý323-3ý23 þ0313ó2331-'@-.3223S3þ23}3þ3=3ý'3<3ý323:3ý02393ý12383ý*2363þ2þ1333ý24ü.223.3ý21 ý613,3ý1@2'3ý24ú31322332þ5û342233232þ322ú32334Î$úQˆÄùÿÿ(û H–ìÿÿ+ü„ýÿÿ-þ[ÿÿ.þ£ÿÿô2Mh„Ÿ»Öò3þ<ÿÿõ;Vr¨Äßùÿÿþ™þÿÿø_{–²Íèþÿÿýôþ ÿ(ÿþšþ8ÿ(ÿýüAþšÿ)ÿýé ýCýÿ*ÿýæ1 ýNõÿ,ÿüùŒ ý$¤ÿ0ÿòú²m=  Dx¾þÿRÿþëÿ=ÿþ^ÿ=ÿý©ÿ<ÿü Öÿ;ÿýáÿ:ÿý$âÿ9ÿýÎÿ8ÿý ÿ5ÿýþ›ýRäÿ2ÿýÒ?ü òÿ.ÿüÜa ü kÕÿ*ÿüÁWû-}Ëýÿ#ÿüÌ}&ùG´ÞýÿÿúóÅ’Uâ 0Pj…Ÿ²ÁÐßëñõùþþû÷ñåØÊ¶Ÿ‡hE!Í þ   þ   þ   þ  þ  þ   þ þ  þ  þ    þ  þ  þ  þ ú   þ þ ) þ ' ý þ ' þ þ & þþ % þ & þ þ # ý þ " þ þ "  ý þ   þ  þý  !þ  "ý  $ %þ  'ý  *û    þ  þ ¿ þ   þ   þ   þ  þ  þ   þ þ  þ  þ    þ  þ  þ  þ ú   þ þ ) þ ' ý þ ' þ þ & þþ % þ & þ þ # ý þ " þ þ "  ý þ   þ  þý  !þ  "ý  $ %þ  'ý  *û    þ  þ ¿ 333þ2þ2333þ23þ83þ2þ233þ53þ23þ13þ2þ2333þ23þ23þ23þ$ 33 3þ233ú23/**33*3þ2þ13(3þ6þ43'3þ2þ@3'3þ6þ23%3þ2þ23$3þ2þ43#3ý24þ23"3þ2þ23 3ý23ý$233ý21þ23323þ'þ-33!3"3#3%ý1233'þ433*ü64322ù32323322þ1¿ÿþÂÿÿþÙþüÿÿþÿþìþùÿÿþÿþúþòÿÿþÿþìþéÿÿþ(ÿþÙþÞÿÿþIÿþÄþÐÿÿþÿþ“þ½ÿÿýÛÿþXþ©ÿÿý™ÿþþŽÿÿúÃTÿÿþÇþqÿ(ÿþdþMÿ'ÿýô þ&ÿ'ÿþ„ýôÿ%ÿýé þÀÿ%ÿþjþÿ$ÿýÄþ5ÿ#ÿýí!þÙÿ!ÿýùAþjÿ ÿýúOýáÿÿýòHþ`ÿÿýÙ-þ®ÿÿþ ýßÿÿ!ý"àÿÿ"ýÖÿÿ#ü ýÿÿ%ý8»ÿÿ'û&€Ëýÿÿ*ê ?l’°ÉÝëöûþûôìåÚů˜‚f¿ #þ  #þ  þ "þ  þ" # #þ  #þ  ý ü  þ   þ þ  þ   ý   þ þ  ü  þ þ  õ   . þ þ + þ ý + þ + þ * þ þ ) þ þ ) þ ' þ ý % þ ý %  $ ý ! þ ü  ü   ü ! þ  ý +õ   À #þ  #þ  þ "þ  þ" # #þ  #þ  ý ü  þ   þ þ  þ   ý   þ þ  ü  þ þ  õ   . þ þ + þ ý + þ + þ * þ þ ) þ þ ) þ ' þ ý % þ ý %  $ ý ! þ ü  ü   ü ! þ  ý +õ   Àý*233#þ233þ2"þ233þ2"þ233þ1"þ233þ2"3ý23!þ033þ2"3ý24û513 þ133ý28 ü43233þ4 þ233ý23 3þ1 3ý24 333þ2 þ/33ø10@'01233þ23,3þ2ý*23,3ý423*3þ2ý323)3þ2þ23*3þ/+3þ4*3þ1þ23(3þ13&3þ2þ43&3%3þ2ü5223!3þ43 3þ2û 12233ú23213 ý31330,ý.122ú32332¿ýöÿÿþb"þÃÿÿþ“"þ‚ÿÿþØ"þ7ÿÿþ!ýèÿÿþy"þÿÿýã!þ/ÿÿþe"þÆÿÿýðûf· þRÿÿýà ÷+YŽÐþÿÿ! ý×ÿÿý´ ÿþ= þOÿÿýÉ! ÿþX þÁÿÿüó|ÿþt ý*ùÿÿõô£]. M‡ÿÿþþÿ,ÿþ«ýÈÿ+ÿþÇý!ðÿ*ÿþâýIüÿ)ÿýûþnÿ*ÿþþÿ)ÿþ5þ…ÿ(ÿþQýoþÿ&ÿþlýMïÿ%ÿþˆý!Æÿ$ÿþ£üqóÿ"ÿþ¿ü˜ûÿ ÿþÛü‹îÿÿþâûR«ðÿÿùùØ®}M ú=|³éÿÿüC*î=d‚œ¶ÉØçò÷ûÿüøóí¿2 2 2 2 2 2 õ þ    ý  þ   ú  þ  þ ý  ý  ü  þ  þ  , ý , þ , + * ) ' þ ' & % !   ü  ü  ý   ü 0   ý ö2 2 2 2 2 2 õ þ    ý  þ   ú  þ  þ ý  ý  ü  þ  þ  , ý , þ , + * ) ' þ ' & % !   ü  ü  ý   ü 0   ý ö2 32 32 32 32 32 3õ323232313, 3ý123 3÷2323230* 3ý42332ú32316 3ý4233þ2 3 3 3ý433þ1 3þ233þ2-3þ4,3þ1+3þ2+3*3þ*)3þ.'3ý2 &3ý23$3ý23$3þ1!3ü233 3ý2.32þ53ü232 323þ40þ322ú3221/ö2 ÿ2 ÿ2 ÿ2 ÿ2 ÿ2 ÿôcòÖ»Ÿ„hM1 ÿý3÷ÿÿõùßĨqV; ÿý!èÿÿõþèͱ–{_D( ÿý&âÿÿþ° ÿýSîÿÿýô ÿü?Áÿÿþp ÿþÜÿÿý¾,ÿýï+ÿýþL+ÿþ}*ÿý¤)ÿý·(ÿý¼ 'ÿý±&ÿý’$ÿýöb#ÿýË(!ÿüðqÿüôŽÿüÙyÿüÓŠ7 ÿúñÄX0öàÒñ™dBö ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !  @ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !  @3þ83 3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3 @ÿþÿþÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ!ÿ @                                                       E                                                       E 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 E ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ ÿÿ E þ   þ     þ   þ     þ   ü  ü  ý  ý  þ  # # # # # # # # # # # # # # Ï  þ 9þ  : : : :þ  :þ  : : :þ  :þ  ; ;þ  ;þ  <ü ;ü <ý =þ ? þ   þ     þ   þ     þ   ü  ü  ý  ý  þ  # # # # # # # # # # # # # # Ï  þ 9þ  : : : :þ  :þ  : : :þ  :þ  ; ;þ  ;þ  <ü ;ü <ý =þ ?3 33 33þ2333þ2333þ.3333333ü2333ü1333ý233ý423þ23#3#3#3#3#3#3#3#3#3#3#3#3#3#3Ïú2323293:3:3:þ233:þ233:3:3:3:þ233:þ133;þ233;3;û-233;3<ü023<ý13=þ2=þ3ÿÿ þlÿÿÿ þ"ÿÿÿþÔÿÿÿþ‚ÿÿÿý þÿÿÿþ¸ÿÿÿþIÿÿÿüÉÿÿÿüGÿÿÿý¯ÿÿýòÿþ`ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿ#ÿÏúØÚ¾£‡9þïÿÿ:þùÿÿ:þþÿÿ:þ÷ÿÿ:þëÿÿ:þÚÿÿ:þ·ÿÿ:þÿÿ:þ[ÿÿ:þÿÿ;þÎÿÿ;þlÿÿ;ûõÿÿ;ü…ÿÿ;üìÿ<ýWÿ=þ¡=þ ÿ ý + þ ý . þ þ 1 þ  3 ÷  Û þ = þ = ý ' ý  þ & ý  %   þ ! ý  ý  ý  ý  þ  þ  þ  ý  þ  ý  þ       þ  , , , +þ  + û &þ   ú ! ö þ ( þ þ ( þ , , þ þ + ý þ ,  þ / ý  5 ÷ Ø þ = þ < û 9 þ 8  ý 3 ý ü 0 þ ý +  þ  þ & þ ú   þ ü   û   þ  ú Ñ ý + þ ý . þ þ 1 þ  3 ÷  Û þ = þ = ý ' ý  þ & ý  %   þ ! ý  ý  ý  ý  þ  þ  þ  ý  þ  ý  þ       þ  , , , +þ  + û &þ   ú ! ö þ ( þ þ ( þ , , þ þ + ý þ ,  þ / ý  5 ÷ Ø þ = þ < û 9 þ 8  ý 3 ý ü 0 þ ý +  þ  þ & þ ú   þ ü   û   þ  ú Ñ3ý28þ*3,3ý2 ý*23-3ý26 þ-303ý21ü@223232ø0/6*/323Ú3þ23=3ý 23(3þ233þ3(3ý2433þ13%3ü2333ý023"3û2333þ13"3þ43ý*233ý233ý32332þ$3þ,33ý2/3 ý12332þ33 þ1223ü21, 3ý51223ú2312' 3,3+þ@33+3+þ.33+þ133ü201&32÷3232324$"3÷23232306þ23(3þ/þ23)3,3þ23+3ý423*3ý23 ý 23-3þ. ý323.3ü23$ý32343ý1-332Ù3þ23=3ý523;3û252393ù2332373þ1þ1353þ4ý32313þ4 ý323+32þ1û02323&3þ.û*13233þ233þ2ø./11223223þ233232û314$ÐÿýÒýßÿ+ÿý± ýÉÿ-ÿý» ýÐÿ/ÿýæ\üoòÿ2ÿõÝŒC% %E’åÿÙÿþ›ÿ=ÿýÍÿ(ÿþçÿÿüàÿ&ÿýñ0ÿÿý#åÿ$ÿü÷@ÿÿý)èÿ"ÿûò@ÿÿýÐÿ ÿýê5ÿý ¬ÿÿýÈÿýbíÿÿüú‡ÿü£þÿÿýµ*ÿ ü(ùÿÿüú ,ÿ ûn¾ûÿ ÿûø¶f ÿïLy§ÍÞìú÷éÚÈŸpA ÿ,ÿ+þÿÿ+þ ÿÿ+þÿÿ+þ(ÿÿúlP4%þEÿÿõûâÆ«sX3@F5MìTÖ\ldTkÄrÑzV‡Xʘ<›€›› ›°›À›Ð›à›ðœœœ œnžì.($ñ ûì !$(*,./0110ú.,*(%ß "(.5;BGMRVY\^_`aa`^\ZVRNå !*4>HR[dmu|‚ˆŒ“–—™™ø˜–”‘ˆƒã "-:GTbo{‡’›¤«±¶»¿ÃÅÇÉÊÊøÉÈÆÃ¿¼·× )7GXhy‰˜¥°ºÃÊÐÕÙÝàãåçèééêééèçåãàÝâ ->QdxŒ­»ÇÑÙßåéíïñóôõö÷øøþùøøú÷öõôóã -@Ul‚˜«¼ÊÖßæìðóöøùúûüüýýþýüç)=Tm‡ž³ÅÔßèïó÷ùûüýýþþ ÿþê "6Nh„ž¶ÉÙåíó÷úüýþþÿê *B]{™³ÉÚçïõùüýþþÿÿì2Mk‹©Ã×åïöúüýþÿÿí!9Vw™·Ïáíõúüþþÿÿ î$=]£ÁØèòùüþþÿÿ ï%@b‡«ÈÞíöûýþÿ!ÿ ð%Ae‹¯Íâðøüþÿ#ÿ ð#@dŒ²Ðåòùýþÿ$ÿ ñ g•¾Üïùýþÿÿ þÿò 2Y‡³Õì÷üþÿÿþûýüûûúúúûüýýþó&Iv¥Ìæõüþÿÿõþýüûøöóñïîííùîðòõøúó 8c“¾ÞñúþÿÿþìüùöñëåßÙÕÒÐÐÑÓ×Ýãéïó)N~­ÓëøýþÿÿéþýúõîåÛÐŰ©¤¡¡£§­¶ÁÌØó :f˜Äâôûþÿÿèþü÷ðå×ǵ¤”†{smjikpx‚ ±ô(O°ÖíùýÿÿçýûõëÜɲ›„p_RG@;879=DN[kó 8e—ÄãõüþÿÿæþúôèÕ½¡„iR@2(! &0=Oô$I{­ÕíùþÿÿåþûóæÑ´”sU=+  (ô1\¿áôüþÿÿîþûôçбhH0 ú ô @p¤ÏêøýÿÿîþüöêÓ³ŒdB( üô(PƒµÛñûþÿÿñýùîÙ¹fA%  ýõ3`•ÄåöýÿÿòþûòáÚmE' ô ?p¥Ðìùþÿÿóý÷éÏ©{N, ô%M€´Ûñûþÿÿóþûñݺ]5 õ.ZÀãõüÿÿôý÷éΤrE#õ7gœËéøýÿÿóþüóß½[1õ As©ÔîúþÿÿôþùíÔ«xG#ô #K³Ûñûþÿÿôý÷çÈše8 ô)Tнáôüþÿÿôþüô໊U+õ0]”Åæ÷ýÿÿôþûðد{H" õ6fÌêøýÿÿôþùìФn= õ 4*! ÷ (.122벬¤œ“ˆ|pbUG9,! ö&`‡¯Ñèöüþÿ ÿþòýüú÷ïÞ¿’_3õ3cœÍëùþÿÿó #>b¶×íøýÿÿþîýüûù÷ôðëãÓ¸a6 õ3cœÍëùþÿÿò$Bk™ÂáóûþÿÿþéýüûúøõòïêåßØÐÆ¶ž|U0õ3cœÍëùþÿÿÖ*M{ªÑê÷üþþýüûù÷ôñíèãÜÕÍĺ°¤—ˆtZ>#õ3cœÍëùþÿÿØ 6_½Þð÷ùøõóïëæàÙÒÉÀµ«Ÿ“‡{obUG6% õ3cœÍëùþÿÿÚ%Hw§ÍãëìèãÝÖÎÅ»±¥šŽui]RG=4+# õ3cœÍëùþÿÿÛ 5^Œ²ÊÒÐÉÀ¶« ”ˆ|ocXMB90(! õ2cœÌëùþÿÿÝ$ElŽ£¨¤šŽ‚vj^SH>4,% õ2cœÌëùþÿÿâ .JcrtndXNC91)"  õ2cœÌëùþÿÿå +:BB=5-& õ2cœÌëùþÿÿì  õ2cœÌëùþÿÿï õ2cœÌëùþÿÿþõ2cœÌëùþÿÿ !õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ.õ2cœÌëùþÿÿ÷õ2cœÌëùþÿÿò õ2cœÌëùþÿÿ€/ û, ù + 2÷1.( * cöa[O=') œõ›˜}_= ) ÌõËǼ¤}O() ëõêæÙ½[/) ùõøóæÈ˜a1) þõýøêÌ›c2) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3) ÿõþùëÍœc3  ÿõþùëÍœc3 ûûÿ ÿõþùëÍœc3ù ú ÿ ÿõþùëÍœc3÷ (.122ù1.( ÿ ÿõþùëÍœc3ö'=O[accùa[O='ÿ ÿõþùëÍœc3õ =_}˜›œœø›˜}_=ÿ ÿõþùëÍœc3õ(O}¤¼ÇËÌÌøËǼ¤}O(ÿ ÿõþùëÍœc3õ/[½ÙæêëëøêæÙ½[/ÿ ÿõþùëÍœc3õ1a˜ÈæóøùùøøóæÈ˜a1ÿ ÿõþùëÍœc3õ2c›ÌêøýþþøýøêÌ›c2ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿùþùëÍœc3S!ûû þ ù ù  ý ÷ (.122÷1.(  ü ö'=O[accöa[O=' ü  õ =_}˜›œœõ›˜}_=  ü õ(O}¤¼ÇËÌÌõËǼ¤}O( ü õ/[½ÙæêëëõêæÙ½[/ ü õ1a˜ÈæóøùùõøóæÈ˜a1 ü õ2c›ÌêøýþþõýøêÌ›c2 û õ2cœÌëùþÿÿõþùëÍœc3ú õ2cœÌëùþÿÿõþùëÍœc3ù õ2cœÌëùþÿÿõþùëÍœc3ù õ2cœÌëùþÿÿõþùëÍœc3ø  õ2cœÌëùþÿÿõþùëÍœc3ø* õ2cœÌëùþÿÿõþùëÍœc3÷ ? õ2cœÌëùþÿÿõþùëÍœc3÷-U õ2cœÌëùþÿÿõþùëÍœc3ö >l õ2cœÌëùþÿÿõþùëÍœc3ö(O‚ õ2cœÌëùþÿÿõþùëÍœc3ö3`” õ2cœÌëùþÿÿõþùëÍœc3ö >o¤ õ2cœÌëùþÿÿõþùëÍœc3õ "H|± õ2cœÌëùþÿÿõþùëÍœc3õ'Q‡º õ2cœÌëùþÿÿõþùëÍœc3õ+XÁ õ2cœÌëùþÿÿõþùëÍœc3õ.\”Æ õ2cœÌëùþÿÿõþùëÍœc3õ/^–È õ2cœÌëùþÿÿõþùëÍœc3õ/^–È õ2cœÌëùþÿÿõþùëÍœc3õ.\”Å õ2cœÌëùþÿÿõþùëÍœc3õ+XŽÁ õ2cœÌëùþÿÿõþùëÍœc3õ'Q‡º õ2cœÌëùþÿÿõþùëÍœc3õ "I}± õ2cœÌëùþÿÿõþùëÍœc3ö >p¥ õ2cœÌëùþÿÿõþùëÍœc3ö3`• õ2cœÌëùþÿÿõþùëÍœc3ö(P‚ õ2cœÌëùþÿÿõþùëÍœc3ú >m×#ï ð ê "%(+-.011221ë0/.,+(&#  é "(/6]Ÿ»Ñáìóøûüýþþÿÿþãýû÷òéÜÈ­jH,&Ac‡ªÆÛêóøûýþþÿ"ÿþèýû÷ðäѶ”nJ$@eŒ°Íáï÷ûýþÿ(ÿëþüùóèÕº–n FQ`tŒ§ÂÚì÷üþÿÿþýüúúÐëùýÿ ÿãýùìÕ³‹eG2% (4E\zœ¾Úí÷ûüüûúóùøø÷õôóñÙðûþÿ ÿÎüõãĘjB'  "5Ps›ÀÜìóôôóòñðïîíëêçåãáÞÜßôüþÿ ÿóþûòܶ„S- Þ/Ow ÂÖßáàÞÜÚ×ÕÓÐÍÊÇÃÀ¼¸´äöýÿ ÿóþûðØ®zH#á 2U{²¼¾»¸´±­©¦¢žš–‘‰„€ç÷ýÿ ÿòþûñÙ°}K&â 6Tp‚Š‹ˆ„€{wsnjfb^ZVSOKèøýÿ ÿïþüóÞ»‹[5 ã1CPUUROKGD@<9520-*(&#èøýÿÿíýöçË£xS7% ä"(**(&#! ç÷ýÿÿëþúðÝÀ{_I:/'!  ì  üäöýÿÿÙþü÷ìÚ¨zi[PF>71,'# ûßôüþÿÿÙþüöíßϾ­ž‘…zpg_XQJD>83.)$  ûÙðûþÿÿØþüøòêàÖ̸¯§ž–އxqib[SLD<4-& ûÐìùýÿÿÐþýûøóïêäÞÙÓÍÇÀº´®§ ™‘‰€wmcYND:0' ÄäõüþÿÿÒþýüúøöóðíêçãßÛ×ÓÏÉü´¬£™Žƒwj]OB5) ´Ùðúþÿÿþý×üûúø÷õôòðîëèåàÜÖÐÉÀ·¬ ’ƒtcRA1#ŸÊæöüþÿÿþýüûçúùøöôòïìèãÝÖͶ¨—…q\G4# ó7ö3ó  0ñ(+&.î"1AMOD/ +ì"1EZn{ydC#)ê"1E[s‹Ÿ¨ž~S+'è"2E[sŒ¤¹ÈÉ·]0%æ"2E[sŒ¥»ÎÜãÞŘa2#ä"2E[sŒ¥»ÎÝéðñçÊ›c2!â"2E[t¥»ÎÝéñ÷ú÷êÌœc3à"2E[t¥»ÎÝéñ÷ûýýùëÍœc3Þ"2E[t¥»ÎÝéñ÷ûýþÿþùëÍœc3é#2E\t¥»ÎÞéò÷ûýþÿÿõþùëÍœc3ê "2E\t¥»ÎÞéò÷ûýþÿÿõþùëÍœc3ë0D[t¥»ÎÞéò÷ûýþÿÿõþùëÍœc3í 9UqŒ¥»ÎÞéò÷ûýþÿÿõþùëÍœc3î 5Y~ŸºÎÞéò÷ûýþÿ ÿõþùëÍœc3ð$Hv¢ÄÚéñ÷ûýþÿ ÿõþùëÍœc3ò,W‹ºÛíöûýþÿ ÿõþùëÍœc3ô0_–ÆæõüþÿÿõþùëÍœc3õ2bšËêøýÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ3dœÍëùþÿÿõþùëÍœd3ûõ 7gžÎìùþÿÿõþùìΞg7  í 'Co¤ÑíúþÿÿõþúíѤoC' ì (.1237B[‚¯×ïúþÿÿõþúïׯ‚[B7322 ë'=O[acdgo‚ Ãàóüþÿÿõþüóàà‚ogdcc ì =_}˜›ž¤°ÃÙì÷ýÿÿöý÷ìÙ𤞜œþ ì(O}¤¼ÇËÌÍÐÖàëõûþÿÿ÷þûõëàÖÐÍÌÌýí/[½Ùæêëìíïó÷ûþÿÿøþû÷óïíìëëü î1a˜Èæóøùùúúüýþÿÿúþýüúúùùû õ2c›Ìêøýþþÿþú, õ2cœÌëùþÿ(ÿùH)õ2cœÌëùþÿ(ÿùjB$õ2cœÌëùþÿ(ÿøa: õ2cœÌëùþÿ(ÿ÷­‚U0 õ2cœÌëùþÿ(ÿ÷È¡sF$õ2cœÌëùþÿ(ÿöݼa7 õ2cœÌëùþÿ(ÿöêÒ«|M(õ2cœÌëùþÿ(ÿéóáÁ•d8 2cœÌëùþÿ(ÿéõèЩyI%2cœÌëùþÿ(ÿéîåÒ²†V-2c›ÌêøýþþÿþéØÑéƒX11a˜Èåóøùùûúûýþÿÿûþýûúùùá°ªŸ‹oL+.[¼Ùåêëëíïó÷ûýÿÿùýû÷óïíëëà{um`M5(P}¤½ÈÌÍÎÑ×àìõûþÿÿ÷þûõìà×ÑÎÍÍßGC=6+ =_}˜›œž¤°ÂØë÷ýþÿÿöý÷ëÙ𤞜œö! ì& ô(R‡¹Þóüþÿÿõý÷æÆ–`3  õ0]“ÄåöýÿÿõüõᾌX/   õ8iŸÍêøýÿÿôþüóß»ŠZ5   õ @s¨Ôîúþÿÿôþüóà¿”jL;532 2 õ !G{°ÙñûþÿÿöüöæÌª‹uiec cÀ<7ó #ï(%! û íRMHB;5.(! ù  눂|tld[QG<2( ÷ (.12 2é»¶±«£›‘†zl^PB4' ö'=O[ac cèàÝÚÖÐʹ®¢”„s`N<, õ =_}˜›œœæôóñïíéåß×Ïͧ”€jT?, õ(O}¤¼ÇËÌÌüûéúøöóðëåÜÑò†lS;' õ/[½ÙæêëëþêýüûùöòìãØÉµ‚fJ2õ1a˜ÈæóøùùÿþýîûùõïæÙȱ•vX<% õ2c›Ìêøýþþ ÿíþýüúöïäÕ¿¤„cC)  õ2cœÌëùþÿÿþðüùôìÞʯŽkI-  õ2cœÌëùþÿÿïþýüøñåÒ·•pL.  õ2cœÌëùþÿÿðþýúôéÖ»˜qK,  õ2cœÌëùþÿÿðþýûõëØ¼˜oH) õ2cœÌëùþÿÿþÿòþûöëØ»”iB$ õ2cœÌëùþÿÿüûýþÿÿòþüöêÕµa: õ2cœÌëùþÿÿúðöúýþÿÿòþüõèÑ­‚U0 õ2cœÌëùþÿÿùÚæð÷ûþÿÿóþûóäÈ¡sG%õ2cœÌëùþÿÿøµÊÜëõûýÿÿóýúðݽ’b8 õ2cœÌëùþÿÿ÷†¡½Õèôûþÿÿóþý÷ëÓ­~O*õ2cœÌëùþÿÿöVs”µÒèõûþÿÿóþûôãÅ™h< õ2cœÌëùþÿÿõ0IiµÕë÷üþÿÿôýùîÖ±P)õ2cœÌëùþÿÿõ)Di”¼ÜðúþÿÿóþüõäŘf9 õ2cœÌëùþÿÿô )Hs¡ÉæõüþÿÿôþùîÕ®|J%õ2cœÌëùþÿÿô 0V…´Ùïúþÿÿôþüôá¿\1õ2cœÌëùþÿÿô >lžÊç÷ýÿÿôýøêΣn> õ2cœÌëùþÿÿó-V‰ºÞóûþÿÿôþûñÚ³€M&õ2cœÌëùþÿÿó !Ew«ÔîúþÿÿõüõãÁ[/õ2cœÌëùþÿÿõ7fœÊè÷ýÿÿõýøêÌŸi: õ2cœÌëùþÿÿô.ZÁãõüþÿÿôþúïÖ¬wD õ2cœÌëùþÿÿô +S†¹ÞóüþÿÿôþüóÝ·„O&õ2cœÌëùþÿÿõ2U…¶ÜòûþÿÿõýöäÁY-õ2cœÌëùþÿÿ2õ4:Jg»ÞòûþÿÿõýøèÉ™c4õ2cœÌëùþÿÿcõdhsˆ§ÉäõüþÿÿõþùìТl: õ2cœÌëùþÿÿ¯,û +ù  *÷ (.12 2*ö&IRX\^]ZTLB8-"   2Ó1.) (9L^o}ˆ”–•‘Š€tfWG8)  (.12 2cÓa\P>(   4Ke}’¤±»ÂÆÈÇýµªœŒyeP<) '=O[ac cœÑ›™‘b@" $3cœÌëùþÿÿñþúîÖ´”‰˜·Öì÷ýþÿ ÿíþûòÞºŠX/ 3cœÌëùþÿÿòþúðÛ¿¨£´Ïæõüþÿ ÿíýøëЧtD! 3cœÌëùþÿÿóþûóâͽ½Ìàñúýÿ ÿìþüôâÀ’_3 2cœÌëùþÿÿóþüöëÜÓÕàîøýþÿ ÿìþùîÕ®|K%2cœÌëùþÿÿõýùòêåçîöüþÿÿìüö寙f9 2cœÌëùþÿÿöþüøôòó÷ûýÿÿëþúðÙ´ƒQ)2cœÌëùþÿÿ÷þüûúúüþþÿÿëý÷èËŸl> 2cœÌëùþÿÿþýþÿêþûòݺŠW.2cœÌëùþÿ ÿþÿêýøëЦtD! 2cœÌëùþÿÿþüýüûúúûüêûóá¿‘^32cœÌëùþÿÿþÞüùöóðîíîïòôöôêÓ¬zJ%2cœÌëùþÿÿÛþüùõîæÞØÓÒÓÖÛáæåÚ¿•c8 2cœÌëùþÿÿÚþüøðå×Ⱥ®§¤¥«³½ÆÈ¾£zM(2cœÌëùþÿÿÙþü÷íÝɲ›ˆypmnu‹—œ–\7 2cœÌëùþÿÿåþü÷íÚÁ¢„iTF>;(  œœõ›˜}_= õ =_}˜›œœñ›™‘b?! ÌÌõËǼ¤}O(õ(O}¤¼ÇËÌÌñËȽ¦€S, 3ëëõêæÙ½[/õ/[½ÙæêëëñêæÚ¿“`2 %ESg ¿ÚíøýþÿÿõýöãÀW+á.ZÂäõüþÿÿ6( *;TvœÂßñúþÿÿõý÷æÄ’Z-õ5eœËéøýÿÿí  2Py¥ÌçöüþÿÿõýøèÇ•]/õ =o¥Ñíùþÿÿü ó 4ZЏÜñûþÿÿõþøéɘ`0õ Dw­×ðúþÿÿüó!Cr¤ÏëøýÿÿõþùêËša1ô #K´Üòûþÿÿþó3^“ÃäõüþÿÿõþùëÌ›b2ô'P†ºßôüþÿÿô(P…¸ÞóüþÿÿõþùëÌœc2ô*UŒ¿âõüþÿÿô Fz¯ØðûþÿÿõþùëÌœc2õ,YÃåöýÿÿõ ?q¨ÔîúþÿÿõþùëÍœc3õ.\”Æç÷ýÿÿÏ /ùû&õ ô ñ  %),.00ð/.+($ ûÛ !*3Ulƒ™«ºÆÐ×ÝâåçééãèæäáÜ×ÐÆºª˜‚jQ:&  =`}˜›œ œì "6Oj…Ÿ´ÆÔÞæìðóõö÷øøä÷öõòðìæÞÔŲ›dH/ *P}¤¼ÇËÌ Ìî(A^|š´ÉÚåîó÷ùûüüýýüèûùöóí䨯¯“sS7!2]‘½Ùæêë ëò-IiŠªÄØæïöùüýþþ ÿþêýûùõïäÔ½ ~[=)&:ešÉæóøù ùóNq•µÏâîöúüþþÿÿþíüùôëÜÆ¨…aD7DkŸÍëøýþ þõtš¼Õçòøüþþÿÿíþýû÷ïáË­‰gQUt£Ïìùþÿ ÿ÷œ¿Ùëõúýþÿÿïþüùñäͯsmƒ«Òíùþÿ ÿù¿Ûì÷ûþÿÿðþýúòäβ—Œ˜·Øïúþÿ ÿúÙì÷üþÿÿñþýúòäк­²Çàòûþÿ ÿûëöüþÿÿòþýùòåÖÌÌÙéöüþÿ ÿüõûþÿ!ÿôþýùóêããéòùýÿ ÿýúþÿ#ÿõþýúöóòõùüþÿ ÿþýÿ%ÿ÷þýüúúûýþÿÿþþÿÿþÿþüýþþÿ'ÿþüýüûúúûûüýþÿ/ÿîþýûùöóðîíîðòõøûýþÿ,ÿëþüøóìåÝ×ÓÒÒÖÜãëò÷ûýþÿ)ÿéýûõíáÓŸ­§¤¥«µÁÐÞêóùýþÿ'ÿçýúóç׫–…xplnu’¦¼Ñãðøüþÿ%ÿåþûóåе—{cQE>;9768;AITbsˆô.U…³×îùýÿÿçþûöïãÔñ ƒxpkhhimt}‰—§¹ó >i™ÄâóûþÿÿèþüùôìãØÌÁ¶®§¢  ¡¥ª²»ÆÑÝô*O}«Ñê÷ýÿÿêþüùõðêãÝØÔÑÏÏÐÒÖÚàæìòó 7_ŽºÛïùýÿÿþíüúøõóðîíììíîïñô÷ùûó#DoÅáòúþÿÿþùýüûûúúùùúúûüýþþò-Q}©Îçõûþÿÿ þÿò 6]‰³Õëöüþÿ(ÿ ò!?g“»Ùí÷üþÿ'ÿ ñ'Gp›ÁÝîøüþÿ&ÿ ñ -Nw Äßïøüþÿ%ÿ ñ 1S{£Æßïøüþÿ$ÿ ñ 4V}¤ÅÞî÷üþÿ#ÿ ð6V|¢ÂÛìõûýþÿ!ÿ ï5Uyž¾×èóùüþÿ ÿî3Qs–¶Ïâïöûýþÿÿì /JjŒ«ÅÚèòøûýþþÿÿê )A^~œ·ÍÞêò÷úüýþþÿÿè #7Qn‹¥½ÐÞéðõùûýýþþÿÿç-B[u¦»ÌÙãëñõøúûüýþþÿã !2G]t‹ ²ÂÏÚâéîñô÷øúûûüüýý þýß#3EXl€“£²¿ÊÓÚáæêíïñóôõö÷øøùùûø÷öõ× "/=M^oŽ›¨³¼ÅËÑÖÚÝàâåæèéêêëëêéèçåâÙ &2>KYfr~‰“œ¤«±¶º¾ÂÅÇÉÊËÌËËÊÈžå $-6@JS\emt{‡Œ“–˜š››ùš™—”‹ç #)/5n¢ÍçòôòíçßÕʽ¯Ÿ~n]N@3( õ2cœÌëùþÿÿÚ&M€³Ùðùûûùöóîèà×ÌÀ²£’‚qaQC6* õ2cœÌëùþÿÿÙ3_“Âãõüþþýýûú÷ôïéâÙδ¥–…tdSB1! õ2cœÌëùþÿÿô Cs¦ÐëøýÿÿþéýüúøôðëäÛÑÅ·¨˜…oV:"õ2cœÌëùþÿÿô.W‰¹ÝòûþÿÿþëýüûøõñìåÝÓÆ´œ{U1 õ2cœÌëùþÿÿó @nŸÊçöýþÿ ÿíþýüûùöòìäÕ»•g; õ2cœÌëùþÿÿò/W‡¶Úðúþÿ ÿðþýüûøòäÉŸm= õ2cœÌëùþÿÿò$Fr¢ËçöüþÿÿþõüöçÉœg8õ2cœÌëùþÿÿó:b»ÜðúþÿÿôþüõâÀ[/õ2cœÌëùþÿÿó 4W‚®Òê÷üþÿÿôþûðÙ³€M%õ2cœÌëùþÿÿô2Rz¤Éäôûþÿÿôýøê΢n> õ2cœÌëùþÿÿõ"7TxŸÃÞðùýÿÿôþüôá¿\0õ2cœÌëùþÿÿõC^~¡ÂÜîøýþÿÿôþúîÖ®|J$õ2cœÌëùþÿÿöoŒªÆÝî÷üþÿÿôýöæÇšg9 õ2cœÌëùþÿÿ÷ ¸ÏâïøüþÿÿôþúðÚµ…S+õ3cœÍëùþÿÿøÊÛéóùýþÿÿôýöçÊ n? õ3cœÍëùþÿÿúçð÷ûýÿÿôþúðÚ·ˆV.õ3cœÍëùþÿÿû÷úýþÿÿóþüõæÉŸnA õ3cœÍëùþÿÿýýþÿÿôýùî׳…U.õ3cœÍëùþÿÿóþûóâÙi> õ2cœÌëùþÿÿóþüöéϪ|N*õ2cœÌëùþÿÿòþýøíØ·Œ^6 õ2cœÌëùþÿÿóýùðß™lB" õ2cœÌëùþÿÿòþúòãɤxM+ õ2cœÌëùþÿÿòþûôæÎ«‚W3  õ2cœÌëùþÿÿñþýúóæÐ°ˆ^9  õ2cœÌëùþÿÿðþýúóæÑ²Œc>" õ2cœÌëùþÿÿðþüùñäϱŒeA% õ2cœÌëùþÿÿþñû÷ïáË®ŠdA& õ2cœÌëùþÿÿïþýúôëÛŧ…a@% õ2cœÌëùþÿÿîþýúöïäÓ»ž|Z<#õ2cœÌëùþÿÿþîýú÷ñèÚÇ®‘qQ6 õ2cœÌëùþÿ ÿþìýüúöñéÝ͸žcG.õ2c›Ìêøýþþÿþýëüú÷óîæÜͺ£ŠnS:% õ1a˜Èæóøùùüçûúù÷õñíçßÕÈ·£ŒsZB- õ/[½ÙæêëëçôòñîëçâÛÒÈ»¬š†pZD1! õ)P}¥½ÈÌÍÍèàÜØÔÎÆ¾³§™ŠxfSA0" õ =_}˜›œœêºµ¯§Ÿ–‹rdUG8+ö'=O[acc솀yqh_UK@5+! ÷ )/233íPKE?81*$ ù ï'#   ûó & 6¼ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœc3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍœd3ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùëÍd4ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþùìΞf5ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþúìÏ h7ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþúíÑ£l:ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþúïÔ¨r?ÿ ÿõþùëÍœc3õ2cœÌëùþÿÿøþûñÙ¯zFÿ ÿõþùëÍœc3õ2c›ÌëùþÿÿøþüóÞ¸…Qÿ ÿõþùëÍœc3õ2b›ÌêùþÿÿùýöäÔ_ÿ ÿõþùëÍœc3õ1ašËêøýÿÿùýøëÐ¥rÿ ÿõþùëÍœc3õ0`˜ÉéøýÿÿùþûñܹŠÿ ÿõþùëÍœc3õ/^–Çè÷ýÿÿúýöèͦÿ ÿõþùëÍœc3õ-[’Äæ÷ýÿÿúþúñßÂÿ ÿõþùëÍœc3õ+WŽÁäöýÿÿûýøíÛÿ ÿõþùëÍœc3õ(Rˆ¼áôüÿÿûþü÷íÿ ÿõþùëÍœc3ô$M‚¶Ýóüþÿÿüþü÷ÿ ÿõþùëÍœc3ô Fy¯Øðûþÿÿýþüÿ ÿõþùëÍœc3õ >p¦Òíùþÿÿþþÿ ÿõþùëÍœc3õ6e›Êèøýÿ!ÿõþùëÍœc3ô-YÀãõüþÿ ÿõþùëÍœc3ô%L€´Úñûþÿ ÿõþùëÍœc3õ @p¥Ðëøýÿ ÿõþùëÍœc3ô3_“ÂãôüþÿÿõþùëÍœc3ô&M°×îùýÿÿõþùëÍœc3ó ;i›ÇåõüþÿÿõþùëÍœc3 ó+R‚±ÖíøýþÿÿõþùëÍœc3 ó l£ÐìùýþþõýøêÌ›c2â ÿþþýüùõïåÖÁ¥…dD*:iŸÌèôøùùõøóæÈ˜a1ãüúùöòìäØÇ±–xY=% 5c–ÁÛæêëëõêæÙ½[/ äòïëåÝÓIJœ‚gL3  .Vƒ¨¿ÉÌÍÍõÌȽ¥}P) åÜÖΟ©–jR<(#Bd€‘™›œœõ›˜}_=  æ´¬¡•†ubO=,  *?Q\accöa[O=' æ€wl_RD6(  !*/233÷2/)  òKD;2)  ø ù  ô$ üû ö  ù8¾ù‡µÙîùýÿÿþýãüûúùøõòïêäÜÒÆ¶¤Žv]E0k›Äâòúþÿ"ÿþýèüúøõòìåÛν§ŽrVGPYcmwŒ–¡¬¶ÁËÕßèðöûýþÿÿ Ý !'-4;DLV`kvƒ¬»ËÚèóùýþÿ ÿÞ %+2:DNZhxŠ ¸Ðäòúýÿ ÿØ   &.9FXpŽ®Íåôûþÿ ÿÏ  $&'%  "0Ec‰²Õìøýÿ ÿã!%(,/38CHMRX]chntz€„…~mQ3 ó +QƒµÛòûþÿ ÿáOTZ_ejpv|‚ˆ•𠥫°µ¸¸¯˜vN+ó !Ex­×ðûþÿ ÿà„‹‘—œ¢§­²·¼ÁÆÊÎÒÖÙÜÞÜÓ¼—k@!ô Ew¬×ðûþÿ ÿ߸¾ÃÈÌÐÓ×ÚÝáäçéìîïñòóñéÕ´‰[5 ô)O´Ûñûþÿ ÿîÝáåèêìîðñóôö÷øùúúûûàúôæÍ§{Q1 !n£ÏëøýÿÿôþùìÐ¥p@  õ2^“ÃäõüÿÿôþûñÛµƒQ* ÷ô'N³Ùðúþÿÿôüö寙g<  öô >m¡Ìé÷ýÿÿóþùîÖ±‚S. ó'.44,ô/Y‹»ÞòûþÿÿñþüõäÇŸqH( óPZ`]N6 ô "Et¦Ïê÷ýÿÿñþùïÛ»“iD) ñ …“ŠrO,ô3]޼Þñúþÿÿñþü÷ëÕµjI0 ð %¸¿¾°c8 ó#Ft¥ÍèöüþÿÿßþûõèÒµ”sW@/$!*7IÞàÜɤrA ô2Z‰·ÙîùýÿÿàþûôèÕ½¡†nZKA;8:>GSdyòòëÖ¯{H" ó !Al›ÄâóûþÿÿáþûõëÜʵ Žtmjlqz‡˜«ûúñÝ·ƒN%ó,P}ªÏèõüþÿÿâþû÷ðæÚÌ¿³ª¤¢£¨¯ºÆÔþüôὉS)ò 7^‹¶×ì÷üþÿÿãþüúöðéâÛÕÒÐÑÔÙßæíÿýöäÂX,ò"Aj–¾Üîøýþÿÿøþüú÷ôñïííïîðóöùÿý÷çÆ•^0ñ)JsžÃÞïøýþÿÿþüýüûúúðûüýþÿþøêË›c4ñ /Qz£ÆàðøüþÿÿþÿõþùìÏ¡i8ñ 4V}¥Æßî÷üþÿÿõþúîÓ¦o= ð6W}£ÄÜìõûýþÿÿôþûðÖ«uB î6Vzž¾ÖçòøüýþÿÿôþûñÚ±{G! í4Rt–µÎàíõùüþþÿÿôþûòܵL$  ë/JiЍÂÖäîõùûýþþÿÿóýüùñÜ·„O& ê )@\z—±Æ×ãìòöùûüýþþÿóøöòéÕ²‚O' æ !5Lgš°ÃÒÝæìñô÷ùúûüüýý þòýéåßÔÁ¡vH# ä)1" Ô  )4>IT^gpx…Š“–˜™š›šš˜—”‘3.(# è ")07>DJOTX[^`abbña`_]Z ì #&),./01221ô0.-ð ü$ü.€œöŸ¦³ÆÜíøýÿÿôþúïÕªtA õ2cœÌëùþÿÿÌ÷ÎÑ×áìöûþÿÿôþûñÙ°{G! õ2cœÌëùþÿÿëøìíïóøûþÿÿôþüóݶ‚M$õ2cœÌëùþÿÿùúüüýþÿÿõüô່R(õ2cœÌëùþÿÿþÿõýõ㿌V*õ2cœÌëùþÿ'ÿõýöåÑY,õ2cœÌëùþÿ'ÿõý÷çÆ”\.õ2cœÌëùþÿ'ÿõýøèÈ—_0õ2cœÌëùþÿ'ÿõþøéÊ™`1õ2cœÌëùþÿÿþõýøéÊ™a1õ2cœÌëùþÿÿùõøóåÇ—`1õ2cœÌëùþÿÿëõêæØ¼[.õ2cœÌëùþÿÿÍõÌȽ¤}P)õ2cœÌëùþÿÿœõ›˜}_= õ2cœÌëùþÿÿcöa[O='õ2cœÌëùþÿÿ3÷2/) õ2cœÌëùþÿÿ ù õ2cœÌëùþÿÿûõ2cœÌëùþÿÿü õ2cœÌëùþÿÿé   õ2cœÌëùþÿÿÜ "'(&$  õ3cœÍëùþÿÿÛ '9HPRPKFA<83/,(%! õ3cœÍëùþÿÿÚ ,Gbx…ˆ…€ztnhc]XRMHC>940-)&" õ3cœÍëùþÿÿÙ -Jn©·»¹µ°«¥ š•ˆ‚|vpje_ZTOIA8+õ3cœÍëùþÿÿÙ0Lp–¸ÏÜßßÜÙÖÒÎÊÆÁ¼·²¬§¢œ—‘Š„{p`J2 õ3cœÍëùþÿÿÙ8St™»ÖèðóóòñïíëéçäáÝÚ×ÓÐÌÇý·­ž†fC%õ2cœÌëùþÿÿÙaŸ¾Øêõúûüûûúúùø÷öôóñðîìêèäàÚκ›sI'õ2cœÌëùþÿÿ÷’¬ÆÜìöûýþþýüûïúùù÷õòêÚÀ™lA! õ2cœÌëùþÿÿø¿Òâï÷üþÿ ÿþýóúõéÓ±…X2 õ2cœÌëùþÿÿùàëóùüþÿÿòþýùïܾ•h?!õ2cœÌëùþÿÿúóøûýþÿÿòýúñáÆ tJ)õ2cœÌëùþÿÿüûýþÿÿòýúòã˧}S0 õ2cœÌëùþÿÿþþÿÿñþýúóåͬ„Z6 õ2cœÌëùþÿÿðþýùòäή‡_; õ2cœÌëùþÿÿðþüøðâÌ­ˆa>"õ2cœÌëùþÿÿïþýûöíÞȪ†`>$ õ2cœÌëùþÿÿþðüùóèØÁ£]<# õ2cœÌëùþÿÿþîýüùôíáÏ·™xV8! õ2cœÌëùþÿÿþíýûøôíäÕ©‹lM2 õ2c›ÌêøýþþÿþêýüúøõñêáÕį–z]B+  õ1a˜Èæóøùùýüçûúù÷õòïêãÚο­˜fL5" õ/[½ÙæêëëäöõôòðîëçãÜÕÌÀ³¢{eO:(õ)P}¥½ÈÌÍÍæäáßÜØÔÎÇ¿¶ªžn\J9) õ =_}˜›œœèÀ½¸³®§ —‚uhZL>1% ö'=O[ac c鎉„xqi`WMC9/% ÷ )/23 3ëWSOJE?82+% ù  í+(&# û ñ !4º ÿõýöäÃ’]1õ2cœÌëùþÿÿôþüóÞ¸…P'õ2cœÌëùþÿÿôþûð×­xE õ2cœÌëùþÿÿõþùìУm< õ2cœÌëùþÿÿõýøéÊšc4õ2cœÌëùþÿÿõýöåÄ’[.õ2cœÌëùþÿÿõüõὊT)õ2cœÌëùþÿÿõüóÞ¸ƒN%õ2cœÌëùþÿÿôþûòÛ³}I" õ2cœÌëùþÿÿôþûðØ®xE õ2cœÌëùþÿÿôþûïÕªtA õ2cœÌëùþÿÿõþúîÓ§p= õ2cœÌëùþÿÿõþúîÒ¤m;õ2cœÌëùþÿÿõþúíТj9õ2cœÌëùþÿÿõþúìÏ h7õ2cœÌëùþÿÿõþùìΟf5õ2cœÌëùþÿÿõþùìΞe4õ2cœÌëùþÿÿõþùëÍd4õ2cœÌëùþÿÿõþùëÍd3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ3cœÍëùþÿÿõþùëÍœc3õ3cœÍëùþÿÿõþùëÍœc3õ3cœÍëùþÿÿõþùëÍœc3õ3cœÍëùþÿÿõþùëÍœc3õ3cœÍëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿÿõþùëÍœc3õ2cœÌëùþÿ ÿþõýøêÌ›c2õ2c›Ìêøýþ þùõøóæÈ˜a1õ1a˜Èæóøù ùëõêæÙ½[/õ/[½Ùæêë ëÍõÌȽ¥}P)õ)P}¥½ÈÌÍ Íœõ›˜}_= õ =_}˜›œ œcöa[O='ö'=O[ac c3÷2/) ÷ )/23 3 ù ù   ûû  !ÿõþùëÍœc3õ2cœÌëùþÿÿôüóß¹†Q'ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþûñÚ²}H" ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþûðÖ«uB ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþúîÓ¦o= ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþúíÑ£k9ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþúìÏ h6ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùìΞf5ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍd4ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœd3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ3cœÍëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ3cœÍëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ3cœÍëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ3cœÍëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ3cœÍëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3ÿÿõþùëÍœc3õ2cœÌëùþÿÿóþùëÍœc3þþõýøêÌ›c2õ2c›ÌêøýþþóýøêÌ›c2ùùõøóæÈ˜a1õ1a˜ÈæóøùùóøóæÈ˜a1ëëõêæÙ½[/õ/[½ÙæêëëóêæÙ½[/ÍÍõÌȽ¥}P)õ)P}¥½ÈÌÍÍóÌȽ¥}P)œœõ›˜}_= õ =_}˜›œœó›˜}_= ccöa[O='ö'=O[accôa[O='33÷2/) ÷ )/233÷2/) ù  ù ù û ûû õ:l£ÑíúþÿÿõþùëÍœc3õ0_—Èèøýÿÿõ7h ÏìùþÿÿõþùëÍœc3õ1`˜Êéøýÿÿõ4ežÎìùþÿÿõþùëÍœc3õ1ašÊêøýÿÿõ3dÍëùþÿÿõþùëÍœc3õ1ašÊêøýÿÿõ3cœÍëùþÿÿõþùëÍœc3õ1`™Êéøýÿÿõ3cœÍëùþÿÿõþùëÍœc3õ0_—Èèøýÿÿõ2cœÌëùþÿÿõþùëÍœc3õ/]•Æç÷ýÿÿõ2cœÌëùþÿÿõþùëÍœc3õ-Z‘Ãåöýÿÿõ2cœÌëùþÿÿõþùëÍœc3ô*V¿ãõüþÿÿõ2cœÌëùþÿÿõþùëÍœc3ô'Q‡»àôüþÿÿõ2cœÌëùþÿÿõþùëÍœc3ô $LµÜòûþÿÿõ2cœÌëùþÿÿõþùëÍœc3õ Ey®Øðûþÿÿõ2cœÌëùþÿÿõþùëÍœc3õ >p¦Òíúþÿÿõ2cœÌëùþÿÿõþùëÍœc3õ7gÌêøýÿÿõ2cœÌëùþÿÿõþùëÍœc3õ/]“Äåöýÿÿõ2cœÌëùþÿÿõþùëÍœc3ò(Q†¹Þóüþÿÿõ2cœÌëùþÿÿõþùëÍœc3ò !Fy­×ïúþÿÿõ2cœÌëùþÿÿõþùëÍœc3ó :jŸÌéøýÿÿõ2cœÌëùþÿÿõþùëÍœc3ó/Z¿âôüþÿõ2cœÌëùþÿÿõþùëÍœc3ó$J}°×ïúþÿõ3cœÍëùþÿÿõþùëÍœc3ó ;jžÊè÷ýÿõ3cœÍëùþÿÿõþùëÍœc3ô-V‰¹Ýñûþõ3cœÍëùþÿÿõþùëÍœc3ô Cr¤Íé÷ýõ3cœÍëùþÿÿõþùëÍœc3õ1[ŒºÜñúõ3cœÍëùþÿÿõþùëÍœc3õ"Dr¢Ëæõõ2cœÌëùþÿÿõþùëÍœc3ö0W†³Öíõ2cœÌëùþÿÿõþùëÍœc3ö >h–ÀÞõ2cœÌëùþÿÿõþùëÍœc3÷(Kw£Éõ2cœÌëùþÿÿõþùëÍœc3÷ 2Wƒ­õ2cœÌëùþÿÿõþùëÍœc3ø :`‹õ2cœÌëùþÿÿõþùëÍœc3 ù#Agõ2cœÌëùþÿÿõþùëÍœc3 ù'Eõ2cœÌëùþÿÿõþùëÍœc3 ú *õ2cœÌëùþÿÿõþùëÍœc3 û õ2cœÌëùþÿÿõþùëÍœc3 ü õ2cœÌëùþÿÿõþùëÍœc3 ýõ2cœÌëùþÿÿõþùëÍœc3þõ2cœÌëùþÿÿõþùëÍœc3õ2c›ÌêøýþþõýøêÌ›c2õ1a˜ÈæóøùùõøóæÈ˜a1õ/[½ÙæêëëõêæÙ½[/ õ)P}¥½ÈÌÍÍõÌȽ¥}P)üõ =_}˜›œœõ›˜}_= õ  ö'=O[accöa[O='ô "&&$!÷ )/233÷2/) ô#6FNOLGB ù ù ó 8Wqƒ€{u ûûó&Kv™®µ´°«  ó-XеÏÚÛÙÖ2ó/^”Ãàíñðï2ö0^–Çæõúú3ó.]”Ææöüþþ2ó,XÂäöýÿÿ2ó(Sˆ¼àôüþÿ2ó #K´Ûñûþÿ3ô Bt©Ôîúþÿ3ô7f›Éè÷ýÿ3ô-W‹¼ßóûþ3ô "Gx«Óìùý4õ 7c•Ââôû4õ'M}¬Óë÷4õ 8b’½Ýð5ö&Ht¢Èã5ö 0U¬Î6ø 9_‰° ÿôþûïÖªtA  õ =o¦ÒíúþÿÿõþúîÒ¥n<  õ6gŸÎëùþÿÿõþúíТj8 õ2bšÊéøýÿÿõþúìÏŸg6 õ0_—ÈèøýÿÿõþùìΞf5 õ/]•Æç÷ýÿÿõþùìΟf5 õ/]•Æç÷ýÿÿõþúìÏ h6 õ0_–Çè÷ýÿÿõþúíÑ£k9 õ3bšÊéøýÿÿõþúîÔ§p>  õ7hŸÎëùþÿÿôþûðØ­xD  õ >p§ÓîúþÿÿôþüòܶM% ô !G{°Ùðûþÿÿõüõâ¿X- ô*Tˆºßóüþÿÿôý÷èÊœg9  õ 7d˜ÇæöýÿÿôþúîÕ¬zI$ô$HxªÓíùýÿÿóþüóà¾_5 ó 6_½ßóûþÿÿòýøêШyM+ ò ,O{©Ðê÷ýÿ ÿòþûòàÁ˜lE( ò *Ho›Ãáòûþÿ!ÿãýøí×·iG-  0Jm”ºÙíøýÿ"ÿãþüõèÒ´’oR<,""->Ut–¸Õêöüþÿ#ÿåþûôçÓº€hUH?;;?HWk„ ½Öéõûþÿ%ÿçþûôêÚÆ°›‰{rmmr|‹ž³ÉÜëõûþÿ'ÿéþûöïäÖÈ»°©¥¥©±¼ÊØåð÷üþÿ)ÿëþüùôîçßÙÔÒÒÕÚàèïõúýþÿÿþþÿÿîþýüú÷ôñïîîïñô÷úüþÿÿýüþÿÿûþýüûúúûûüýþÿÿüøýþÿÿþÿüðùýÿ#ÿþüýþþÿÿûäóûþÿ ÿ÷þýûúùûüþÿÿúÐçõûþÿÿõþüùôñðóøüþÿÿù³Óéõûþÿÿôþü÷ðæßßæñùýÿÿ÷‘·ÕéõûýþÿÿòþûöíÞÎÃÆÕçõüþÿÿök“·ÔèôúýþÿÿðþýûõêÙ¬¡ªÂÞñûþÿÿõGk’µÑäñøüþÿÿïþüùóçÕ»ž…~²Öîúþÿÿò*Fh®ÊÞìõùüþþÿÿþîüúöîâÏ´”u_`{§Ñìùþÿÿï(Bb„¤ÀÕäïõùüýþþÿÿþëýüùöðæØÄªŠiM@Jn Îëùþÿÿî $;Ww•°ÇØåíó÷ùûüýýþýüéûù÷óîåÚʵ›}^A.*=gÍëùþÿÿÏ2Kf‚œ³ÆÔßçíñóõ÷÷øø÷öõóðìçßÔÆ´Ÿ†kP7#6dœÌëùþÿÿÏ (Rfy‹š§±¹ÀÄÇÉÈÇþ¸¯¥˜‰xeR?. 3cœÍëùþÿÿÓ *8GVdq|…’–——•‘Œ„zobTF7* 3cœÍëùþÿÿÓ ",6?HPV[^__]ZUOG>4*! 3dÍëùþÿÿÖ "'+-/00/-*&! 4ežÎìùþÿÿú ô ó õ6gŸÏìúþÿÿó ùõ9j¢Ðíúþÿÿç=83/,(%"  õ =o¦Óîúþÿÿæoic^XSNHC>951-)&#  ô Bv¬Öðûþÿÿ妠›•‰ƒ}wqke_ZTOJD=3' ô #J³ÛòûþÿÿåÓÏËÆÂ¼·²­§¢—‘‹…~wm^J2  õ+UмàôüÿÿäîìéçäáÞÚ×ÓÐÌÇþ¹³¬¡tR0 õ5b—Ææöýÿÿäúùø÷öôóñðîìêèåâÞÛÖ̺›rH&ô !Dt¨Òìùýÿÿþýüûëúùù÷öõóñîç׺‘b8 ò 2YйÝòûþÿÿþýüñûùõéѬ~R/ ò +Ku¤Ìè÷ýþÿÿþòýûóâÅrM1 ò .Hl–¾Ýñúþÿ"ÿãýùîÛ½™tU>-#",;Rp”¸Öë÷ýþÿÿþþÿÿäþü÷ëØ¾ „kWI@:9:?HUh€ºÕéõûþÿÿþþÿÿæþüöìÜȲ‹|rljlr|‰›°ÆÚêõûþÿÿýþüÿÿèþû÷ïåØÊ¼±©¤¢¤¨°»ÈÖãîöûþÿÿýýùÿÿêþüùõïçàÚÔÑÐÑÔÙßæîôùüþÿÿûþüôþÿÿ÷þýüú÷ôñïíí÷ïñó÷ùüýþÿÿùþý÷ëýþÿÿþüýüûúúúûüýþþÿÿùýùïÜùýÿÿþÿ÷ýúòáÆòúýÿ4ÿóþýúòä˨åóúýþÿ1ÿñþýùòäÍ­…Ðæóùýþÿ/ÿ÷þüøðâÌ­ˆ`@@@ÿ€ºþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœc3ÿÿþùëÍœd3ÿÿþùëÍd3ÿÿþùìÍe4ÿÿþùëÍe4ÿÿþùëÍd4ÿÿþùêÌ›c3ÿÿþøéɘ`1ÿÿý÷æÅ“\.ÿÿýõãÀV+ÿþüóÞ¸…O&ÿþûðدzG! ÿþùìФn= ÿý÷æÆ—a4þüóÞºˆS*þùíÓªvE! üõåÅ—d6õúïÙ³‚P)õöçÊŸl> öïÙµ†U-öäÇœl? ÷Ó¯R,÷¼’d: øŸrG&ø~S/ ù[6 ú< €€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€8ø"?c‹7ø%Ac8ù%?9ú":û;ü<ý¿€€€÷°Îãð÷ûýþÿ+ÿéþýúõìÞȪ†`>‰«ÈÝëóøûýþþÿ%ÿþåüúöðæÖ¿¢€]=#^¡½ÒâìóøúüýþþÿÿÝþýýûùöðçÛɲ–vU8!9Us‘¬ÂÓàéïô÷ùûüýýþþÿþýÙüúùöòíåÚË· „gJ10Ga|•«½ÌØáèíñôöøùúûüüýþýüÌûúùøöóðëåÝÒÅ´ ˆoU=(  %8Lcy °½ÉÒÚàåéìîðòóõö÷÷øøùùøÇ÷öõôòñïìéäߨÏŸ¨—ƒmWA.  '7HYk|Œš§²»ÄÊÐÔØÛÞáãåæèéêêéÅçæäâßÜØÔÏɹ®¢•…ucP?.   #/PY") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.000000 0.000000 0.000000)) (justify left) (box-mode dynamic) (box-unit pixels) (hinting yes) ¡˜1¡À×`×l×xׄ×1£ £0£@£P£`£p£€££ £°£À£Ð£à£ð¤¤¤ ¤0¦¸­ð´›ºº º°ºÀºÐºàºð»»» »0»@»P»`¿`ÇX̤ÓÐÓàÓðÔÔÔ Ô0Ô@ÔPÔ`ÔpÔ€ÔÔ ÔÐÕÕ@Õ€ÕÕ Õ°ÕÀÕÐÕàÕðÖÖÖ Ö0Ö@ÖPÖ`ÖpÖ€ÖÖ Ö°ÖÀÖÐÖàÖð××× ×0×@×P @ @ @ @#þ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#þ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#þ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ#Ð"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿþýüüø€"ÿþýýô&ÿþþø)ÿþýýÀ,ÿüþýÀ.ÿýþû /ÿþþã 1ÿýþö 2ÿýþú 3ÿýþú4ÿýþú5ÿýþó6ÿýþ€7ÿþý7ÿýþø8ÿþþ9ÿþû9ÿþþ9ÿýþø:ÿþþ:ÿþþ;ÿþú;ÿþý;ÿþþ;ÿþþ<ÿüùÿÿþþ÷€àðøüýþþÿ&ÿüüÿÿþþ üãýþÿ$ÿüýÿÿþþ ýúþÿ#ÿüþÿÿþþ þýÿ#ÿüþÿÿþþþþÿ"ÿüþÿÿþþþýÿ"ÿüþÿÿþþþúÿ"ÿüþÿÿþþþðÿ"ÿüþÿÿþþþæÿ"ÿüþÿÿþþþøÿ"ÿüþÿÿþþþýÿ"ÿüþÿÿþþþþÿ"ÿüþÿÿþþ þýÿ#ÿüþÿÿþþ ýûþÿ#ÿþýþýüüø€"ÿþýýô&ÿþþø)ÿþýýÀ,ÿüþýÀ.ÿýþû /ÿþþã 1ÿýþö 2ÿýþú 3ÿýþú4ÿýþú5ÿýþó6ÿýþ€7ÿþý7ÿýþø8ÿþþ9ÿþû9ÿþþ9ÿýþø:ÿþþ:ÿþþ;ÿþú;ÿþý;ÿþþ;ÿþþ<ÿüùÿÿþþ÷€àðøüýþþÿ&ÿüüÿÿþþ üãýþÿ$ÿüýÿÿþþ ýúþÿ#ÿüþÿÿþþ þýÿ#ÿüþÿÿþþþþÿ"ÿüþÿÿþþþýÿ"ÿüþÿÿþþþúÿ"ÿüþÿÿþþþðÿ"ÿüþÿÿþþþæÿ"ÿüþÿÿþþþøÿ"ÿüþÿÿþþþýÿ"ÿüþÿÿþþþþÿ"ÿüþÿÿþþ þýÿ#ÿüþÿÿþþ ýûþÿ#ÿþýþýüüø€"ÿþýýô&ÿþþø)ÿþýýÀ,ÿüþýÀ.ÿýþû /ÿþþã 1ÿýþö 2ÿýþú 3ÿýþú4ÿýþú5ÿýþó6ÿýþ€7ÿþý7ÿýþø8ÿþþ9ÿþû9ÿþþ9ÿýþø:ÿþþ:ÿþþ;ÿþú;ÿþý;ÿþþ;ÿþþ<ÿüùÿÿþþ÷€àðøüýþþÿ&ÿüüÿÿþþ üãýþÿ$ÿüýÿÿþþ ýúþÿ#ÿüþÿÿþþ þýÿ#ÿüþÿÿþþþþÿ"ÿüþÿÿþþþýÿ"ÿüþÿÿþþþúÿ"ÿüþÿÿþþþðÿ"ÿüþÿÿþþþæÿ"ÿüþÿÿþþþøÿ"ÿüþÿÿþþþýÿ"ÿüþÿÿþþþþÿ"ÿüþÿÿþþ þýÿ#ÿüþÿÿþþ ýûþÿ#ÿþýÐôÎÆ¾¶­˜~eJ#"ÿúôȘX&ÿûþ΀!)ÿûþÀZ,ÿüÙ].ÿýÒ5 /ÿüüŠ 1ÿýÉ 2ÿýä2 3ÿýð24ÿýë*5ÿýã6ÿý·7ÿþw7ÿýö8ÿþ«9ÿþ:9ÿþ®9ÿýý":ÿþ‰:ÿþÜ;ÿþ/;ÿþ};ÿþ¸;ÿþí<ÿü%ÿÿþÐ÷#Bk¥îÿ&ÿüMÿÿþÐ ülñÿ$ÿülÿÿþÐ ý/óÿ#ÿü‹ÿÿþÐ þZÿ#ÿü§ÿÿþÐþÌÿ"ÿü´ÿÿþÐþkÿ"ÿü½ÿÿþÐþ*ÿ"ÿüÇÿÿþÐþÿ"ÿüÍÿÿþÐþ ÿ"ÿüÃÿÿþÐþ"ÿ"ÿü¹ÿÿþÐþ`ÿ"ÿü¯ÿÿþÐþÀÿ"ÿüŸÿÿþÐ þXÿ#ÿü€ÿÿþÐ ý=öÿ#ÿþ`þûþ'þþúþþÿ&ÿþþýôþÿ&ÿþýþüÿ&ÿýþíþþÿ&ÿþþýóþÿ%ÿýþúþüÿ&ÿþþþþÿ&ÿþýýòþÿ%ÿýþíþüÿ&ÿþþþþÿ%ÿýþúýðþÿ%ÿþþþüÿ&ÿþýþþÿ%ÿýþíýðþÿ%ÿþþþüÿ%ÿýþúþþÿ%ÿþþýíþÿ%ÿþýýüþÿ$ÿýþíþþÿ%ÿþþýìþÿ$ÿýþúýüþÿ$ÿþþþþÿ%ÿþýýêþÿ$ÿýþíýûþÿ$ÿþþþþÿ$ÿýþúþòýèþÿ$ÿþþþþýûþÿ$ÿúýüÿþþÿ$ÿúþíãþÿýæþÿ$ÿþÿýûþÿ#ÿþÿþþÿ'ÿýàþÿ&ÿýûþÿ%ÿþþÿ%ÿýÛþÿ$ÿýûþÿ#ÿþþÿ#ÿýÛþÿ"ÿýúþÿ!ÿþûþ'þþúþþÿ&ÿþþýôþÿ&ÿþýþüÿ&ÿýþíþþÿ&ÿþþýóþÿ%ÿýþúþüÿ&ÿþþþþÿ&ÿþýýòþÿ%ÿýþíþüÿ&ÿþþþþÿ%ÿýþúýðþÿ%ÿþþþüÿ&ÿþýþþÿ%ÿýþíýðþÿ%ÿþþþüÿ%ÿýþúþþÿ%ÿþþýíþÿ%ÿþýýüþÿ$ÿýþíþþÿ%ÿþþýìþÿ$ÿýþúýüþÿ$ÿþþþþÿ%ÿþýýêþÿ$ÿýþíýûþÿ$ÿþþþþÿ$ÿýþúþòýèþÿ$ÿþþþþýûþÿ$ÿúýüÿþþÿ$ÿúþíãþÿýæþÿ$ÿþÿýûþÿ#ÿþÿþþÿ'ÿýàþÿ&ÿýûþÿ%ÿþþÿ%ÿýÛþÿ$ÿýûþÿ#ÿþþÿ#ÿýÛþÿ"ÿýúþÿ!ÿþûþ'þþúþþÿ&ÿþþýôþÿ&ÿþýþüÿ&ÿýþíþþÿ&ÿþþýóþÿ%ÿýþúþüÿ&ÿþþþþÿ&ÿþýýòþÿ%ÿýþíþüÿ&ÿþþþþÿ%ÿýþúýðþÿ%ÿþþþüÿ&ÿþýþþÿ%ÿýþíýðþÿ%ÿþþþüÿ%ÿýþúþþÿ%ÿþþýíþÿ%ÿþýýüþÿ$ÿýþíþþÿ%ÿþþýìþÿ$ÿýþúýüþÿ$ÿþþþþÿ%ÿþýýêþÿ$ÿýþíýûþÿ$ÿþþþþÿ$ÿýþúþòýèþÿ$ÿþþþþýûþÿ$ÿúýüÿþþÿ$ÿúþíãþÿýæþÿ$ÿþÿýûþÿ#ÿþÿþþÿ'ÿýàþÿ&ÿýûþÿ%ÿþþÿ%ÿýÛþÿ$ÿýûþÿ#ÿþþÿ#ÿýÛþÿ"ÿýúþÿ!ÿþ9Ð&ÐýÏ+þ«ÿ&ÿþÀýêÿ&ÿþZþSÿ&ÿýæ þ¨ÿ&ÿþýèÿ%ÿýû+þPÿ&ÿþÀþ¤ÿ&ÿþZýæÿ%ÿýæ þMÿ&ÿþþ¡ÿ%ÿýû+ýåÿ%ÿþ¿þJÿ&ÿþZþžÿ%ÿýæ ýãÿ%ÿþþFÿ%ÿýû+þšÿ%ÿþ¿ý áÿ%ÿþZýDþÿ$ÿýæ þ—ÿ%ÿþý ßÿ$ÿýû+ýAþÿ$ÿþ¿þ”ÿ%ÿþYý Üÿ$ÿýå ý>þÿ$ÿþŒþ‘ÿ$ÿýû*þý Úÿ$ÿþ¿þŸý;ýÿ$ÿúYBÿþÿ$ÿúå Ûÿý Ùÿ$ÿûŒ†ÿÿý9ýÿ#ÿûÿþŠÿ'ÿýÖÿ&ÿý6üÿ%ÿþ‡ÿ%ÿýÔÿ$ÿý3ûÿ#ÿþƒÿ#ÿýÑÿ"ÿý1úÿ!ÿþùþ%þý€þÿ%ÿþýÿ&ÿýõþÿ%ÿþþþþÿ&ÿþýþüÿ&ÿýþÀýìþÿ%ÿýþùþþÿ&ÿþýýûþÿ%ÿýþªýÌþÿ%ÿýþùþýÿ&ÿþýýøþÿ%ÿýþ€þþÿ%ÿýþøþýÿ&ÿþýýôþÿ%ÿýþ€þþÿ%ÿýþøþüÿ&ÿþýýèþÿ%ÿýþ€þþÿ%ÿýþøýúþÿ%ÿþýýÀþÿ%ÿþþþýÿ%ÿýþ÷ýøþÿ%ÿþýþþÿ%ÿþþþýÿ%ÿýþöþþÿ%ÿþý&ÿþþ%ÿýþö%ÿþý$ÿþþ#ÿýþõ#ÿþý"ÿþþ!ÿýþô!ÿþý ÿþþÿýþóÿþüÿþþÿýþóþùþ%þý€þÿ%ÿþýÿ&ÿýõþÿ%ÿþþþþÿ&ÿþýþüÿ&ÿýþÀýìþÿ%ÿýþùþþÿ&ÿþýýûþÿ%ÿýþªýÌþÿ%ÿýþùþýÿ&ÿþýýøþÿ%ÿýþ€þþÿ%ÿýþøþýÿ&ÿþýýôþÿ%ÿýþ€þþÿ%ÿýþøþüÿ&ÿþýýèþÿ%ÿýþ€þþÿ%ÿýþøýúþÿ%ÿþýýÀþÿ%ÿþþþýÿ%ÿýþ÷ýøþÿ%ÿþýþþÿ%ÿþþþýÿ%ÿýþöþþÿ%ÿþý&ÿþþ%ÿýþö%ÿþý$ÿþþ#ÿýþõ#ÿþý"ÿþþ!ÿýþô!ÿþý ÿþþÿýþóÿþüÿþþÿýþóþùþ%þý€þÿ%ÿþýÿ&ÿýõþÿ%ÿþþþþÿ&ÿþýþüÿ&ÿýþÀýìþÿ%ÿýþùþþÿ&ÿþýýûþÿ%ÿýþªýÌþÿ%ÿýþùþýÿ&ÿþýýøþÿ%ÿýþ€þþÿ%ÿýþøþýÿ&ÿþýýôþÿ%ÿýþ€þþÿ%ÿýþøþüÿ&ÿþýýèþÿ%ÿýþ€þþÿ%ÿýþøýúþÿ%ÿþýýÀþÿ%ÿþþþýÿ%ÿýþ÷ýøþÿ%ÿþýþþÿ%ÿþþþýÿ%ÿýþöþþÿ%ÿþý&ÿþþ%ÿýþö%ÿþý$ÿþþ#ÿýþõ#ÿþý"ÿþþ!ÿýþô!ÿþý ÿþþÿýþóÿþüÿþþÿýþóý&ÎÐ$ÐýÀÿ%ÿþdÿ&ÿýîÿ%ÿþøþ©ÿ&ÿþwþKÿ&ÿýÈý áÿ%ÿý÷'þÿ&ÿþsý5ýÿ%ÿýÅýÐÿ%ÿýö%þxÿ&ÿþpý#öÿ%ÿýÂþ¼ÿ%ÿýõ#þ_ÿ&ÿþmýìÿ%ÿý¿þ¤ÿ%ÿýó!þFÿ&ÿþiý Þÿ%ÿý¼þ‹ÿ%ÿýòý1üÿ%ÿþfýÌÿ%ÿþ¹þsÿ%ÿýñý ôÿ%ÿþcþ·ÿ%ÿþ¶þZÿ%ÿýðþêÿ%ÿþ`&ÿþ³%ÿýî%ÿþ\$ÿþ±#ÿýí#ÿþY"ÿþ­!ÿýë!ÿþV ÿþªÿýéÿþRÿþ§ÿýè @ @ @ @"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿ"ÿÿþþ üæýþÿ$ÿüüÿÿþþúêúýþþÿ&ÿüóÿÿþ+ÿþþ;ÿþþ;ÿþý:ÿýþô:ÿþþ:ÿþý9ÿýþí9ÿþþ8ÿýþõ8ÿþþ7ÿýþæ7ÿþü6ÿþþ5ÿýþÕ4ÿýþö3ÿýþø2ÿýþù 1ÿýþö 0ÿýþã .ÿýþý ,ÿþþð*ÿþþù(ÿþþø%ÿþýüª ÿþýýúÿþýýûèÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ üæýþÿ$ÿüüÿÿþþúêúýþþÿ&ÿüóÿÿþ+ÿþþ;ÿþþ;ÿþý:ÿýþô:ÿþþ:ÿþý9ÿýþí9ÿþþ8ÿýþõ8ÿþþ7ÿýþæ7ÿþü6ÿþþ5ÿýþÕ4ÿýþö3ÿýþø2ÿýþù 1ÿýþö 0ÿýþã .ÿýþý ,ÿþþð*ÿþþù(ÿþþø%ÿþýüª ÿþýýúÿþýýûèÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ üæýþÿ$ÿüüÿÿþþúêúýþþÿ&ÿüóÿÿþ+ÿþþ;ÿþþ;ÿþý:ÿýþô:ÿþþ:ÿþý9ÿýþí9ÿþþ8ÿýþõ8ÿþþ7ÿýþæ7ÿþü6ÿþþ5ÿýþÕ4ÿýþö3ÿýþø2ÿýþù 1ÿýþö 0ÿýþã .ÿýþý ,ÿþþð*ÿþþù(ÿþþø%ÿþýüª ÿþýýúÿþýýûèÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþþ6ÿþÐ ü u÷ÿ$ÿü?ÿÿþÐú ._¡ðÿ&ÿüÿÿþ÷ÐÐûÑÕàðÿ*ÿþÚ;ÿþ ;ÿþd:ÿýü:ÿþ¾:ÿþh9ÿýï 9ÿþ‡8ÿýø8ÿþ„7ÿýà 7ÿþN6ÿþ“5ÿýÇ4ÿýá3ÿýä#2ÿýå& 1ÿýÊ 0ÿý¢ .ÿýçV ,ÿüü™*ÿüúž%(ÿüäŠ%ÿûæžC ÿúýݬl*ÿóüôíåÜȰ—~_5 ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6ÿþÐ6þþÿ!ÿýÕþÿ ÿýúþÿÿþýÿÿýÌþÿÿýúþÿÿþýÿÿýÀþÿÿ ýùþÿÿ!þýÿÿ!ýÀþÿÿ"ýùþÿÿ#þýÿÿ#ýªþÿÿ$ýùþÿÿ%þýÿÿ%ý€þÿÿ&ýøþÿÿ'þýÿÿ'ý€þÿÿ(ýøþÿÿ)þýÿÿ)þ€ÿÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿþþÿ!ÿýÕþÿ ÿýúþÿÿþýÿÿýÌþÿÿýúþÿÿþýÿÿýÀþÿÿ ýùþÿÿ!þýÿÿ!ýÀþÿÿ"ýùþÿÿ#þýÿÿ#ýªþÿÿ$ýùþÿÿ%þýÿÿ%ý€þÿÿ&ýøþÿÿ'þýÿÿ'ý€þÿÿ(ýøþÿÿ)þýÿÿ)þ€ÿÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿþþÿ!ÿýÕþÿ ÿýúþÿÿþýÿÿýÌþÿÿýúþÿÿþýÿÿýÀþÿÿ ýùþÿÿ!þýÿÿ!ýÀþÿÿ"ýùþÿÿ#þýÿÿ#ýªþÿÿ$ýùþÿÿ%þýÿÿ%ý€þÿÿ&ýøþÿÿ'þýÿÿ'ý€þÿÿ(ýøþÿÿ)þýÿÿ)þ€ÿÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿþ€ÿ!ÿýÏÿ ÿý/úÿÿþ}ÿÿýÌÿÿý,ùÿÿþzÿÿýÊÿÿ ý)øÿÿ!þvÿÿ!ýÇÿÿ"ý'÷ÿÿ#þsÿÿ#ýÄÿÿ$ý%öÿÿ%þpÿÿ%ýÂÿÿ&ý#ôÿÿ'þlÿÿ'ý¿ÿÿ(ý!óÿÿ)þiÿÿ)þÿÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿÿþüÿþþ ÿýþñ ÿþü!ÿþþ"ÿýþð"ÿþü#ÿþþ$ÿýþî$ÿþü%ÿþþ&ÿýþí&ÿýþü'ÿþþ(ÿýþì(ÿýþü)ÿþþ*ÿýþè*ÿýþû+ÿþþ,ÿýþæ,ÿýþû-ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþüÿþþ ÿýþñ ÿþü!ÿþþ"ÿýþð"ÿþü#ÿþþ$ÿýþî$ÿþü%ÿþþ&ÿýþí&ÿýþü'ÿþþ(ÿýþì(ÿýþü)ÿþþ*ÿýþè*ÿýþû+ÿþþ,ÿýþæ,ÿýþû-ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþüÿþþ ÿýþñ ÿþü!ÿþþ"ÿýþð"ÿþü#ÿþþ$ÿýþî$ÿþü%ÿþþ&ÿýþí&ÿýþü'ÿþþ(ÿýþì(ÿýþü)ÿþþ*ÿýþè*ÿýþû+ÿþþ,ÿýþæ,ÿýþû-ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþþ.ÿþOÿþ£ ÿýæ ÿþL!ÿþ "ÿýä"ÿþI#ÿþ$ÿýâ$ÿþE%ÿþ™&ÿýà &ÿýþC'ÿþ–(ÿýÞ (ÿýþ@)ÿþ“*ÿýÜ *ÿýþ=+ÿþ,ÿýÚ ,ÿýý:-ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ.ÿþÐ. @ @ @ @"ÿ"ÿ€"ÿ"ÿ€"ÿ"ÿ€"ÿ"ÿ€ÿþþ6ÿþþ·ÿþþ6ÿþþ·ÿþþ6ÿþþ·ÿþÐ6ÿþз*ÿ*ÿ€*ÿ*ÿ€*ÿ*ÿ€*ÿ*ÿ€ÿþþ.ÿþþ¯ÿþþ.ÿþþ¯ÿþþ.ÿþþ¯ÿþÐ.ÿþЯ @ @ @ @ÔÔÔÔŠ E†"C!   Drop Shadowÿ      ØP  Øp v ‚ Ž  Øàß%ß_ß™ãeåŒìì)ì9ï‡òø£ø³øÃüþ 6\‚ 0 µ | œ ¼ kX&$ø"õ ñ   î  "##$$ ì  $)-14678899 ë #*18>CHKOQRRSSì $,5>GOX_dilnp pð !*5@KVblu,ò $0VrðýúõëÝ˶ ŠwgYOIFEEö  1GbïýúóåѹŸ„kVE7-&" ö $8Okïýúòãʬ‹mR=,!  ô)>Xuðüõåʧ€\@, õ -C_ðüøëѬ€X7! õ 1Hdòûñݹ‹\7ö !3Kióý÷èËŸm@!!ö "5Olôûòܶ„Q+"ö #7QoõùëÍ k= #ö $8Rpõüõ⽊V,$ö $8RpõúñØ­wE!$ö $8RpõùëÍžf7 $ö $8SqõöæÃX-$ö $9SqöõỄN&%ö $9Sqöôß¶~G! %ö $9Spöóݳ{F %ö $9SpöóݲzE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE %ö $9SpöóܲyE $????? ??$?9?S?pÀ?ó?Ü?²?y?E?? ?? €????? ??$?9?S?pÀ?ó?Ü?²?y?E?? ?? €?0. -þ+  ô +ï *$#ì"  9)9ê87641-)$  S(SRëQOLID?92*# p*pëonkgb[RJ@7-% /ð}uj]QD7," 2ó‚sbRA3& 4õˆt_L:* 6÷„lU?, 7ø“w\B.8ùž€`C,9ú¦ƒ`A)ó'óôþõû§[<Ü#ÜÝùÞßáãçì ü£{U²#²³ö´µ¶¹¾ÅÏÚä üœry#yzô{}ƒ‰“¡²ÂÒà ý»‘E&EóGIJNU_m€”©¿ÓýÓ­$ ò!"$',4@Pdz”®ÇþÅ %  ò"-Yz5ö &;Uu5ö %:Ts5ö %9Sq5ö %9Sq5ö $9Sq5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp€€€Yþüûûú ù ùø$ ø4øJ, €¸d;::99õ %7Rt õš‡yme]YVTTSSõ ,A`…ø‘‡yusqppô "3Ll“4ô &:UxŸ3ó *?\€¦3ó ,C`ƒ§2ó .C`£Ã1ò ,@[|œ»Ó0ð );Ur‘®Å×ä% ???? ??$?9?S?pÀ ???? ??$?9?S?pÀ/ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sp5ö $9Sq5ö %9Sq5ö %9Sq5ö %:Tr5ö &;Us5ö(=Xv4õ+@[y4õ .D_~4õ !3Jf„3õ&9Qm4õ ,AZv2õ$5Kf0ô ,@Wr(ó '8Ld'ó &4F\uþû%ò '4DWm…þú $  ò$,8FWk€þø$ó!&,5?L\m€ýüô$#$%ó&(*.39AKWdu† ýúî9#9:õ;=@DJQZfr üüöåS#ST÷VX[`fmv üúïØp#pøqrsuy}ƒûüöåÅ9úüøìÔ®8ùýùïÜ»7øüùðß›m6÷üøïßÄŸuL4õüúöìÜŸvO/2óüúöïåÔ¼›uO0/ñûúøôî娯®mL/ €€€€$óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyE óܲyD óܲyD óܱxD óܱxC òÛ°wB òÚ¯v@ òÙ­s? ñÖ©o< íСh8çÆ”]/Þ¸„O'Ó§q@ Ä”^1ø°}J%ø˜d7 ù}M'ù`6 úC"û+û ü ý€€€ë $4Jd~™¯ÂÒÝåìðòóó ì ,=Qg}“¦¶ÃÎÖÚÜÜ ì !.=M_q‚‘Ÿ¨®±²² í )5BN[gpvxyy ï !'08>CDEEô ö þ"&?€€€?ó?Ü?²?y?E?? ???€€€?ó?Ü?²?y?E?? ???€€€-óòðñíçßÓŰ˜}`C* Ü,ÜíÛÚÙÖÐÆ¸§”}eM6# ²*²±í°¯­©¡”„q^K8'y*yxíwvtoh]O@2% E*EïDCBA@=80' +ô -   ù.þ 0Ncccþa……BB!!1 PY Borderÿ     L1ts^sjsvs‚sŽ1Ôúä¼'¬+++%+5+E+U+e+u+…+•+¥+µ+Å3%353E8Ì=à=ð>>> >0>@>P>`>p>€>> EúF FKßQ Q0Q@QPQ`QpQ€QQ Q°QÀQÐQàZo\&]Åe iÃiÓiãiójjj#j3jCjSjcjsjƒlnLp~rŽržr®r¾rÎrÞrîrþsss.s>sNœûúþþüüüþþþ ü  üúþþüýüûþü ûû þýýþ-ýþ12ü3ø35þþ556ú6þý6þ6þ7ø7ø7þ8þ8û7ý78ý8þþ7ý7þ8ø7þý7û7üþ78ú7ý78þ7888ø7þ8ý88ý7ú7þý*œý þþýýýþþþøüþüùûýþýûýûýûûüýûùø-þ1û2û3 4ü56þ466û77÷6þ7ü7û7þþ7þ7þ8þþ7ø7ý8ý88þ8ý88þ788þü788þ78ýý788ý8ø7þü7ø7ü*œþ-,,+*)ù()(('(''û&'&&-,+ý*+**ø)*))(()(('&ý'&þ.--û,-,-,,+ý*+**)ø())(''(''&.-ý.-,,ü+,,++û*+**))(þ)((ù'(''&&.ý-.--,þ-,,+ü*++**)(ý'(''þ&ü/./..ý-.--,ü+,,++ü*+*))þ*))('/.-,ø-,,+,++**ò)**))())((''(''/ý./..-.0/ý./..10ý/0//.20ý/0//þ.30÷100//00/31ý0100þ/410þ/5ý121105ü21211þ052ü122116217ú32212117217ý2322þ1728328þ43328þ433283þ27ü434338438ø434343374û34337484þ544þ37ü4554485û454475û45447þ655þ476û54557658ü6565586586586ý5676þ57768û7677668þ8776876ü7667ý7877887þ677+œ#ÿ&ÿ(ÿ*ÿ+ÿ,ÿ-ÿÿ. ÿ1 ÿ2 ÿ4 ÿ4 ÿ5ÿ6ÿ5ÿ6ÿ6ÿ7ÿ7ÿ7ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ+€þú    û     ñ ûú        þ  þ  õ   þ   þ   ø  ý   þ  þ   þýø     þ   ü  þ  ý ÷ û   þ      ù  úþû    þ   þ  þ  ý  À€ýû    þ    ú   þ  ö  û   ú   ý  ü   ý ú  ù ø     ú  ÷ þþþ  û  ú  þ   þ  û úþü   ô  ù  þ  þ  þ ý ý   þ  ù  ú    ý  ¿€&ù%&%%$%$$#"ý!"!! ý þþ&%ù$%$$%#$$#÷"#"!""!"!! þ &%&%$#þ"##ü"!"!!ý !  ø þýý&'&&%ý$%$$ý#$##"! þ!  ýù'&&ü%&&%%$#ü"##""ý!"!!ý !  ÷&&û'&%&%%$#"! ú!  ýú''&&ý%&%%$ý#$##"þ#""ý!"!!  À€Àÿ À€ ù  þ  ý  þþþ    ü  ú    þ ý  þ     þ  ú  þøý  û    ýþ  þ  õ þ þü þ   þ þ þþþü   þ  ü úû À€þ   ü  û  ýúü   ø  þ  ûùþ   þ  þ   û ùþýù   þ    þ  þ  þ þø þ  þ  þþþüú  ý  þ  ü  üþú  ý ü  þýþþ ¿€þýýýüþûýüùþýþýþþ÷ýýýþòýüýýýýþø À€Àÿ À€ý þþù þ øúøþøþ þòúûýþöù þýþüþøúý üþüþýþ0ü 2 3ý5üþ5ü7ú8þ8ü8ý8þ9:ú9ú:þ;;;;;;þ;þ;þ;;û:þ;þ:û:;û:;ý:;;;þ:ý:û:;ý:û:;;€þ û þþü ù üúýýýüýüþüþþü þùþùýúþþ þþþý÷ýþ ùü÷ þ/þý1þþ2þý4üþ5þ7þ8û8ý9û8þ9ú9þþ9þ;;û:û:þ:;;;;;û:þ;þ;û:þ;û:ý:þ:;ý:þ;;ý:þ:þ;;þ:;;;þ€    ý  þ     ý  ýþý     ü ý       öþþ   ÷  ý úýþ     ýýü  û  þ   ýýü/þ23þ5õ57ý7þ7ý8þ9þ:þ::ü:þ:;;ý:þ;;;þ ;;û :û : þ: ;þ  ;þ  ; þ :þ  ; ;þ  ;þ  ; ;û : ; þ : ; ;û :û : ; €3ÿ 6ÿ8ÿ:ÿ;ÿ<ÿ=ÿ0ÿ2 ÿ3 ÿ5 ÿ6ÿ7ÿ8ÿ8ÿ9ÿ9ÿ:ÿ:ÿ:ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿþ=þ=ý<==ü;<<þ;ü;ü;ü;ü;<ü;<<þ;<<ü;<þ;ü;<ü;þ;ü;<þ;ü;<<<<<<ü;ü;ü;þ=þ=ý<ý<=<<ü;þ;ü;ü;ü;ü;þ;<þ;<ü;<<<<<ü;þ;ü;ü;ü;þ;ü;<<ü;ü;<<<<ü;þ;þ=þ=ý<=ý<<þ;<<<<<þ;<þ;<ü;ü;ü;þ;<<þ ;þ ;ü ; þ; <ü ;ü ; < þ ;ü ; <ü ;ü ; þ ;ü ;ü ;ü ;ü ;þÿ=þÿ=ÿ=ÿ=ÿ=ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ< @ @ @ @ û78þ7þ8þ88ý8þ88ý8û7ý8þ8ú78û7þ8ý788þ8þ88ú7þ8ú7ø7û7ø7þ78ü7þ788ü8þ8þ8ü7þþ7þý7ýý7þü7þý7þý788ú78þ8û8þü7ý88ü7û8þþ7û7ü7ü7þ8þ8þ8+ ý7ý7þ8þ7ý78þ7û8ú7ý8ü88þ7þü7þ8ü7û7ý7þ7þ88888û8ø7þý7û7þ7ø7þþ78û7ü78þ8ý888þü7ø7ø7þ7þþ7þ7þ7û7þ88þ8ø7þ88ü78û7ø788þ78ü78þ+ 8û787778û787778ü78878ý7879888û98877û:9898889ü8987ü:998889ý897ü9::998ü:9:998:98þ;::ý9:7þ;::ü9:97ü;:;::þ97;:8;:8ø<;:;;::7þ<;;:8ý;<;;:8<;8ø;<<;<;;7<û;<;;7þ=<<þ;7þ=<<þ;7ý<=<<ý;<7ý<=<<8=<þ;7=ú<==<<7=ü<=<7ø=>>=<=<7>=ý<=7>=8ü?=>==8ø?>>=>=>7>þ=7?>þ=7?>þ=7?>þ=7?þ>7?ü>?>7þ@??8@?8@?8@ü?@?7ø@A@??@?7@?8øA@A@@??7A@8A@8þBAA@8Aþ@7BA@8BûA@@A7BA8þCBBA8þCBBA8þCBBþA7CBüABB7CBþA7CB8CüBCB7ûCDCCBB+ ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ+;ý:þ:;;;û:;;û:;û:;û:û:ý:;;;;þ;;;ý:þ:þ:û:;þ;;;;;þ:;;þ;þ;ý:;;þ:û:ý:;þ:þ:;þ ;û :û  :ý :û  : ; ;þ ; ;û  : ; ý : ; ;þ  ; ; ;û:;þ:;;;þ;;;;;ý:ý:þ;û:û:;;;þ;û:;þ;û:û:þ;;;û:;;;;;;;þ:û:û:;;þ:;;;;;;;û :;û :û  :ý :û  : ý : ; ; ; ; ;þ  ; ;ý ; ;û :û : þ : þ : þ : ;þ  ;þ : ;;þ;þ:þ;;þ:þ:;û:;;;þ:þ;;þ:þ;;þ:;;þ:;;;û:ý:;;þ;û:û:;ý:þ;þ;û:;ý:û:þ:û:þ:;ý:;þ;;þ;þ:þ:þ;ý:;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ<þ;ü;<<<<<<<ü;þ;ü;<<þ;ü;<þ;<<þ;<<ü;<ü;þ;<þ;ü;ü;ü;<<<<<<<þ;ü;ü;ü;<ü;<<<<<<þ ;<ü  ;ü ; <ü ; þ; <ü ;ü ; þ; <þ;<<þ;<þ;<<<<<ü;ü;ü;<<<þ;<<<<<<ü;ü;ü;ü;ü;<<ü;<þ;þ;<<ü;ü;ü;<<<þ;ü;<þ;<<þ;<<< þ;< þ;ü ;ü  ; þ;ü ;ü ; þ;ü  ; <ü ;ü ; < <ü ;ü ; <ü ; þ ; <ü  ; <<<<ü;þ;ü;ü;ü;ü;ü;ü;<<ü;<<ü;þ;þ;<<<þ;ü;<<ü;<<þ;<<þ;ü;þ;<<<ü;<þ;<<<ü;<þ;<ü;<ü;<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ< @ @ @ @ þ8þ8þý7þý7ø7ú7ø7888ü788þ8þ8þ8þ8ý7888þ7þ78ý7ý7ý8þ8888ø7û78üþ7þ7ø7ø78þ7þþ7ü8þ788þ8û8ø7ø78ý8û7ý78þ8ýþ78þ8ü7ø7ý7þ8ú7ø* 8þ8ý8ý8ú7þ7û78ü8ø7ü78þ7ý88þ8û8þ7û8ø7û8ý8ú788ý7þþ7þ8ý88þü7ýý7ø7þ8ü8ý8ü7þ7þ8þ7ü7þ7þ7þ7þ88þ8þý7þü78ø7þ7ø7þý78þý7ý88ý8þ8þþ7ø7ú7þ* þDCC8üDCDCCþB7DC8DC8DþC7þEDD8DûEDDC7ED8ED8øFEEDDED7øFEEDDED7EþD7øFEFEEDE7FýEFEE8FE8FþE7FE8FE8GüFEF7GýFGFF8GF8þHGGF8þHGG8ýGHGGýFG7þHGG8HG8HG8HþG7HúIHHGG7IHþG7IHþG7IûHIIH7IH8IþHII8JIH8JIþH7üJIJII8JûIJII7JûIJII7üJKKJJ8KúJKJJI7JúKJJIJ7øKJJKJKJ7KýJK7KJ8K8LK8LKþJ7LûKLKK7LKýLK7MLþK7MLþK7ûMLLMLL8MýLMLL8üNMMLL8ML8ML8NML8NúMNNML7NýMNMM8NM8NM8ýNONN8ONýMN* ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ+; ;  ;û :û :  ; ; ;û : þ : ; ;û : ; þ :û : ;û :û : ; ; þ :û : ý : þ : ; þ : ;û :û : ; þ : þ : ; þ :û :þ  ;þ  ;þ  ;û : ; ;û : ; ;û : ; ý :û :þ  ;þ  ;û :û : ; ;þ  ;û  : ;û  :û  : þ:þ  ;û : ; ;þ  ;  ;û :û :û : ;û :û :û : ý : ; ; ; ;û : þ : ;û :  ; ý :û :û : ý : ; þ : ; ;û : ý :û : þ : ý :  ; þ : þ : þ : þ : þ : ; ; ;þ  ;û :û :û : ;þ  ;  ;û : ý : þ :û :û : ý :û  : ; ; ;; ; ; ;ý :þ ;þ:;;þ:þ;;;þ:û:þ:;û:û:;û:þ:û:þ:ý:;þ;þ;;þ:;;þ;û:þ:þ:;ý:û:û:û:û:þ;;û:þ:û:û :þ ; þ: ; ; ; ; ; ;!;!;!;û!"! :!;"!;"ý!":";û#""!:";"ý#":#þ":#ý"#:#;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ < < < þ ;ü ;ü ;ü ;ü ; þ ; þ ; þ ;ü ; þ ; < þ ; < <ü ;ü ;ü ; þ ;ü ; þ ; < <ü ; þ ; < < < < <ü ; þ ; <ü ; <ü ; < þ ; <ü ; < þ ; < < < <ü ;ü ;ü ; þ ;ü ; < þ ; þ ; <ü ;ü ;þ ; < <ü ;ü ; <ü ;ü ;ü ; < <ü ;ü ;ü ;ü ;ü ;ü ;ü ; þ ; < < þ ;ü ; <ü ;ü ; < þ ; < þ ; þ ; <ü ; < < < < þ ; < þ ;ü ;ü ;ü ;ü ; þ ; <ü ; < < < þ ; < <ü ; < <ü ;ü ; < < þ ; < þ ; < <ü  ;ü  ;< þ;<<þ;ü;þ;þ;ü;<þ;ü;<<ü;ü;<ü;<<<<<<þ;<ü;ü;<<ü;ü;ü;<ü;<<ü;<ü;<<ü;þ;<ü;<ü ;ü ;ü  ;ü ; < <ü! ;ü ! ;!þ ;!<!þ ;ü"!!;ü"!!;!<"<"<"<"<ü"#";ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ< @ @ @ @ ú7ü7þ7ýý7þ7þ7þ 88þ 8þ 8ø   7 ú 7û   8þ  8ø   7 ý 7û    8ü   þ7 ü 7þ!  8 ü 7þ!  8 8þ!  8ý !  þ!7!û ! 7ø !! ! 7þ!  8þ !! 8!ú ! !7! ý! 7! þ!7! 8! !8!8!8þ"!!8!ú"!!"!7ü"!"!!8ü!""!!8þ"!!"8!8ø!""!"!"7ü"!"!!8!"!þ"7þ"!!ü"!"7"8"þ!""8"ü!""6"7ý"#""7"þ#""6#"7#"6þ#""#"6"ü#"#""6#"5#"5 "3þ"##"ü!""1# "ü!"!/#"þ#""!þ"!!þ !! ú þ"##ù"##"#"!!"ý!"!!û ! !  þ  #þ"##"ø!"!""!"!!ø !! ! !  û888ú7þ7þ ü788þ7ø  7þ 8þ 8 ý 7 ý 8 þ  þ7 þ  þ7 ú  7 ü 7 þ7þ!  8 8ý !  þ7 8 8 þ!  8ø! ! ! 7ø! ! ! 7þ!  ü! 7ø ! !! 7!ú !! 7! !þ 7þ !!8!8!8"!8!ý !7!8!8"!8þ"!!8"!8"û!"!!7"þ!7ý"!""ý!"7"ü!""7þ!""8"þ!""8"8"ü!"!6"ü!""6ý"#""7ü"##""ü!""5ú"##"#""7ö#"#"#""!"5ù#"#""#""6#"þ#""6#"ü#""4ô"##""#"#""!4ù#"##"#""3û"#"#""þ#""2#ý"#""þ#""þ!/#ý"#""û!"!"!! ! û #ú"#""#""ü!""!!í !! ! ! !   #"þ#""õ!""!!""!!"!! ! ! þ  ON8ON8øOPONOON7þPOONþO7üOPPOO8ýOPOOþN7PO8PûOPOO7QPþO7üQPQPP8üQPQPP8QP8QýPQPP8QP8QþP7QP8RQ8RúQRQRQ7RQ8þSRRþQ7SR8ûSRSSRR8ûSRRSRR8SR8SR8þTSSýRS7þTSSþR7TúSTTSS7TýSTSS8TûSTSS7TS8øUTUTTSS7ýTUTT8UT8UûTUTT7UúTUTUU7þVUUýTU7øUVUVTUU7VU8VúUVVUU7VU8øVWVVUVV7þWVVU8ûWVVWVV8þWVV8WV8WüVWW7WûVWVV7þXWWýVW6þXWW7XýWXWWþV6ûYXWXWWýVW5ùYXXWWXWW7XW6XW6YXþW5õYXYXXWXWWX4YXW5YXþYXXW3YXW2YûXYXYXXWV0YýXYXXWVþWVVýUVUUTüSTTSSRQþRQQYXWV÷UVUUTTUUTTSRQYýXYXXWVWVUýTUTTSþRSSRQ ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ8ÿ7ÿ7ÿ7ÿ6ÿ7ÿ6ÿ6 ÿ6 ÿ5 ÿ5 ÿ3 ÿ2ÿ0-ÿ,ÿ+ÿ@ õ  þùó þ÷þþýüþ þþ úùþþ@ý ûþüþþýû  ü ý þ÷  ù þõû@þQPPýOPOONML÷KLKJKKJKJJýIJIIHGøHGGFGFFEEQPOùNONNMNMMþLMMLKJIýHIHHGFüEFEQQPOþPOONMýLMLLKùJKJIJJIIH÷GHGGFGFGFF@Àÿ@û öõý þúþúþü þüþþ@üþ  øýþöûþý ÷þþ û@EDþEDDCBüABBAA@?ø>??>?>>==<ý;<;;:EùDEDDCDCCýBCBBüABBAAý@A@@?>=<;ý:;::þFEEDCBAú@A@@?@@?÷>?>?>>=>==ý<=<<;:@Àÿ;û  :þ :þ :;;;;;þ;þ;;;û:û:û:þ;þ;;;;;þ;þ:û:;þ:þ:ý:þ;û:;ý:;;;;þ;;û:;û:û:;û:;ý:;::ý:9þý8þ8þ77ü5þ4þü2 þ0ýþ-þüüúþ ù þüûþþøþýþþú;þ ;þ :;;;;þ;þ;;þ;;þ;;û:û:;ý:;ý:;;þ;û:;;þ;þ;û:þ:;;;þ:;;þ;ý:;;þ;û:ý:û:;;;;:ý::ú8ü9ü88û66þþ4þ2ûü0þ.ýþý ýý ýûþüþþöüþý úü;#;û$#$#:û$#$#:#;$ý#$:$;þ%$$;þ%$$;þ%$$;%;%;û&%%$:%;&ý%&:û&%&%:&þ%:&;&;þ'&&;'þ&:';'ý&':';(';þ('';(;(þ':þ)((;þ)((;)þ(:û)(():û)(():);þ*));û)*)):);*þ):*;*þ):+*;*þ+:û+*+*:+ý*+:+þ*:+;+;+;,+:,þ+9þ-,,:þ-,,9-û,--,8-ý,-7-ü,-,7ý-.--ý,-6ü.-.--6ö./.--..--4ý./..-3/.1÷/00/0/./..-.þ100/ö./..9989887654þ544321ý0100/.98ý787765ü45544ý3433ô2332212110100ü/00//:987ü67766ü566554ö3443433232210/þ0//;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ:ÿ:ÿ:ÿ9ÿ9ÿ8ÿ8ÿ7ÿ6ÿ5 ÿ3 ÿ1 ÿ.ÿþÿ<ÿ<ÿ;ÿ<ü ;þ ;ü  ;ü ;<<<<<<<ü;ü;ü;ü;ü;ü;ü;<<<<<<ü;<ü;<<ü;ü;þ;ü;<<<<<ü;<þ;þ;ü;þ;ü;ü;ü;<<<ü;<==ý<þ=þ¾ü  ;ü ;ü ;þ ;<<<<<<<<þ;þ;þ;þ;ü;<<<<<<<ü;ü;<<ü;ü;<<þ;<<<þ;<<ü;ü;ü;ü;þ;<ü;<<<þ;<<<==ý<þ=þ¾#þ";#<#<#<ü$##;ü#$$;$<ü$#$;ü%$$;$<ü%$$;ü%$$;ü%$$;%<ü&%%;ü%&%;&þ%;%<&þ%;ü'&&;ü&'&;&<ü'&&;'<'<'<'<'<ü('';(þ';(þ';(<ü()(;(<)þ(;ü)();)þ(;)<ü*)*;*þ);*þ);*<*<ü+**;*<ü+**;+<+<ü,++;ü+,+;,þ+;ü,++;,<,=ý-,<,=þ,=þ-¾ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ<ÿ=ÿ=ÿ=þÿ=þÿ¾ @ @ @ @þ"##û"#"#""þ!"" ! #"ú#"#"#"" !ú ! ! !! "#"!û"!""!!ü !!  ! ý þ#""þ!""!þ"!!ý !  "# "!þ"!! þ!  ý#"##ý"#""!"! û! !  þ#""!"ý!"!!þ"!!ö ! ! !!  ú"#"##""þ!""! !û ! !  YýXYXXýWXWWVýUVUUTøSTTSRSSRRüQRQûXYXYXXWýVWVVUTþUTTûSTSSRRúYXYXXWWVþWVVUýTUTTSTSúRSSQRXWVUúTUTSTSSüRSQÿ*ÿ(ÿ&ÿ#ÿû  þ úþþüþ ø   ø  úýù  þ ùþþû÷      úûü ýÿü   ù þüõ  ûüýþþþüý  ü þ ýùüþþþ  þ öú ûÿQPOüNOONNMNMLKJIHþIHHùGHGHGFGGûFEFRQQPýOPOONMLýKLKKJIHGFQPOþNOONýMNMMýLMLLKJýIJIIHýGHGGýFGFFRQPONMLKýJKJJIHýGHGGFÿþûöþ þþûúýû úýþ þøþøþÿ ûûþþúú þøþüþ þùþþ ýüø ùúEýDEDDCùBCBBABAAü@AA@@?ú@??>?>>ø=>==<==<<;ý:;::EDCùDCBCBCBBýABAA@üA@@??ü>??>>=ü<==<<;ú:;EFFEEDCùBCBBABAA@þA@@ý?@??ý>?>>=<ý=<;;þ<;;ü:FFEEDCBþCBBA@?>=ü<==<<;ÿþ þ þþýùý÷þýþû ùþýùüùþþüý úùþýú ýþýýýûþü ýþüöúþøýü 9:9ý898876543ý232210/:9ý89887ý6766543ý23221÷210110/0:ü9::99ý8988765ý45443ü233221þ0þ;::98765û45454432ý12 :ÿ8ÿ6ÿ3ÿ ÔÔÔÔŠ E†"C!1 PY Backgoundÿ     tO1twìÐìÜìèìôí1u×…K–¨>»½M½]½m½}½½½­½½½Í½Ý½í½ý¾ ÔTìgcÀ"!"1"A"Q"a"q""‘"¡"±"Á"Ñ"á8ìPÍh݃†`†p†€†† †°†À†Ð†à†ð‡‡‡ +´e˽åè.è>èNè^ènè~èŽèžè®è¾èÎèÞèîéêië'ììì ì0ì@ìPì`ìpì€ìì ì°ìÀœ#$&$($*$+$,$-$$‚ƒ„…†‡ˆù‡ˆˆ‰‰ˆ $‚ƒ„†‡üˆ‡‡ˆˆ $þ€ú‚‚‚ƒƒ„…†ý‡†‡‡ˆ $ü€€€‚ƒ„þƒ„„…†ý‡†‡‡þˆ $ý€ü€€‚ýƒ‚ƒƒú„ƒ„…„……†÷…††‡†‡ˆˆ $þ~€ý€‚ƒ„…†‡ $ü}~~€‚ƒý„ƒ„„…†‡ $~ü}~~€‚ƒü„ƒ„……ú„…††…†† $}~€‚ý‚ƒƒù„ƒ„„…„……† $}~€‚ƒ„…þ† $|}~ý€€€‚ƒ„… $ù|{|}||}}~ý€€€ü€‚‚ƒ„… $ü{|{||}~€‚ƒý„ƒ„„ $zû{|{{||}~€ù€€‚‚ýƒ‚ƒƒ„ $úz{{z{||ù{}||}}~~û~€€‚÷ƒ‚ƒƒ„ƒ„„ $þyzz{|ý}|}}~ý~€ý€‚ƒ $ýzyzz{|ý}|}}ý~}~~€ü‚‚‚ƒ $üyzyzz{|}~€þ€€‚ƒ $÷yxyyzyzz{{ý|{||ý}|}}~þ€€ú‚‚‚ƒ $úyxxyyzz{|}~€‚ü‚‚ $xyz{ý|{||}~ý€€€ý‚ $úxwxyxyyz{ý|{||}~€ú€‚ $wxüyxyzz{|}~ø€€€ $wxyüzyyzz{|ù}|}}~}~~ø€€€ $vwýxwxxyzþyzz{ý|{||}~ý~€ $vwýxwxxyz{|}~û€€ $vwxyz{|}~þ€ $þuvvwxyzý{z{{|ý}|}}~ $uvwýxwxxyz{þ|}}þ|}}~ $uvwxyzý{z{{|õ}|}}~}}~~ $tuvwüvwwxxyýzyzz{|}~ $tuvwxøyxyyzzy{{ý|{||}~ $útsuutuuûvwwvwwxyýzyzz{|} $þsttuvúwvwxwxxyzý{z{{|û}|}} $stýutuuûvuwvwwxþwxxyzüyzz{{|} $stuvúwvwxwxxyz{| $úsrrssttüuvuvvûwvwwxxüyxxyyü{zz{{| $rsuþtuuúvuvwvwwxyz{ý|{ $rýsrsstýutuuvwxyz{üz{{ $qrstuvwþxyyüzyyzzþ{ $qþrqqþrssûtsttuuvýwvwwxyzûyzz{ $þpqqrstuvwývwxxyz $ýqpqqrstuvüwvvwwxyzœ#$&$($*$+$,$-$$ˆ‰Š‹ŒŽ $‡ˆ‰ýЉŠŠ‹Œ $†‡ˆ‰Š‹÷Œ‹‹ŒŒŒ $ý†…††‡ˆ‰Š‹Œ $ü„……††‡úˆ‡‡ˆˆ‰‰øŠ‰ŠŠ‹ŠŠ‹‹Œ $„…ý†…††‡ˆû‰Š‰‰ŠŠ‹Œ $òƒ„„…„……††…††‡††‡ˆý‰ˆ‰‰üЋЋ‹Œ $þƒ„„…ü†……††‡ýˆ‡ˆˆ‰ýЉŠŠ‹Œ $ú‚ƒ„ƒƒ„„û…„……††‡þ†‡‡ˆ‰üˆ‰‰ŠŠý‰Š‹‹ $ƒý„ƒ„„…†ý‡†‡‡ˆ‰Šü‰ŠŠ‹‹ $û‚ƒ‚‚ƒƒ„…õ„……††…†‡‡†‡‡ùˆ‡ˆˆ‰ˆ‰‰Šü‹Š‹ $‚ƒý„ƒ„„…†ü…††‡‡ˆ‰ýЉŠŠ $þ‚‚ƒ„üƒ„„……†‡þ†‡‡ˆý‰ˆ‰‰Šþ‹ $ü€‚‚ƒ„…†þ‡ˆˆù‰ˆ‰‰Š‰ $þ€‚ƒû‚ƒ„ƒ„„…†ü‡††‡‡ˆ‰þŠ $€‚ƒ„…†ý‡†‡‡ýˆ‡ˆˆ‰ýˆ‰ $ý€€€ý‚‚‚ûƒ‚ƒƒ„„…ý†…††‡ˆ‰ $€‚ƒ„…ý†…††‡ˆþ‰ $€‚ƒ„ý…„……ý†…††‡ˆ $€‚øƒ‚‚ƒ‚ƒ„„û…„……††‡ $ý~ù€€€€‚þ‚‚ƒ„…†‡ $~ü€€€‚ƒ„÷…†……††‡†‡‡ $ù}~~~€‚û‚ƒ‚ƒƒ„…†‡ $þ}~~€ý€‚‚ƒû„ƒ…„……ý†…†† $}ü~}}~~€‚ƒý„ƒ„„…û†…†† $}~ú~€€ý‚‚‚üƒ‚‚ƒƒ„…þ† $þ|}}ú~}~~~~€ý€‚ƒ„ü…„„…… $|}~ý€€€‚ƒ„… $û{|}|}}ý~}~~ý~ý€€€ù‚‚‚ƒ‚ƒƒ„ü…„… ${|ú}|}~}~~€þ€‚ƒ„ ${|}ý~}~~€‚ƒ„ ${ý|{||}ý|}~~þ~€‚ù‚‚ƒƒ‚ƒƒ $ý{z{{|ù}|}}~}~~û€€€û‚‚‚‚ƒþ„ $zý{z{{ú|{|}|}}~€‚û‚ƒ‚ƒƒ $üyzz{{|}~€û€‚‚ƒ $yz{|}~ý~€‚þƒ $ûyzyyzz{|}ý~}~~€‚ $þxyyz{|}ý~}~~ý€€€‚ $xyz{|ü}||}}~€ $xyzü{zz{{|}~€þ‚ $þwxxyz{|ý}|}}~ý€€€þ $ýxwxxøyxyyzyyzzù{z{|{{||}~€ $ýxwxxýyxyyz{|}~þ}~~€œ–ý•–••û”•”•””“÷”“”““’“’þ—––•–•þ–••”ü“””““þ’—–ü•––••þ–••”•”þ“””“ý’“–•þ–••û”•”•””ü“””““’—–ü•––••”þ•””“þ”““ü’““’’–ý•–••”•”ù“””“””““ý’“’’–• ” “û’“’“’’–•ÿ–ù•––••–••!ÿ–•þ–••–•#ÿ–•%ÿü–•–••ü–••ÿ%ÿ –•ü–••ÿ&ÿ –ü•––••(ÿ •–•þ”ÿ'ÿ •þ–••ý”•ÿ(ÿ ý•–••)ÿ •þ”ÿ)ÿ •û”•””ÿ)ÿ •”þ•ÿ)ÿ ý”•””þ•ÿ*ÿ ý”•””+ÿ ”+ÿ ”+ÿ ”+ÿ ”+ÿ ”+ÿ ”ú“””““ÿ*ÿ ”û“”““ÿ*ÿ ”“+ÿ ý“”““+ÿ ”ú“”“’“ÿ*ÿ þ”““ý’“ÿ*ÿ “û’““’ÿ*ÿ “û’“’’ÿ*ÿ “’+ÿ ø“’’““’’ÿ*ÿ ü’““’’+ÿ þ“’’þ‘ÿ*ÿ þ’““’+ÿ ’‘þ’ÿ*ÿ ’‘’+ÿ ’þ‘’’þ‘ÿ*ÿ ’û‘’’‘ÿ*ÿ ’ý‘’‘‘+ÿ ü‘’’‘‘+ÿ ý‘’‘‘+ÿ þ’‘‘þ‘ÿ*ÿ ‘+ÿ ‘þÿ*ÿaÿ!ÿ#ÿ%ÿ&ÿ'ÿ(ÿ(ÿ)ÿ)ÿ*ÿ*ÿ*ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ€À$ú‰Š‰‰Š‹‹Œþ‹ŒŒýŒŽùŽŽ‘ý’‘’’“”ù•”••–•––—ý˜—‰‰Š‹üŠ‹‹ŒŒŽúŽŽŽ‘’û‘“’’““ù”“””•”••–—úˆ‰‰Š‰ŠŠô‹Š‹Œ‹‹ŒŒŒŽøŽŽ‘’ý“’““”û•”••––þ—‰‰þˆ‰‰Šý‹Š‹‹ŒŽøŽ‘’“”•ý–•––ˆ‰ýЉŠŠ‹ŒŽýŽ‘’“”•–ˆþ‡ˆˆ‰Šþ‰ŠŠ‹ûŒ‹ŒŽýŽú‘’ú‘’’“’““”•‡ûˆ‡ˆˆ‰‰ûŠ‰ŠŠ‹‹ŒŽ‘ú’‘‘’’““”•‡ˆ‰Š‹ŒøŒŒŽŽŽŽþ‘ý’‘’’“”•ú†‡†‡‡ˆˆ‰Šý‹Š‹‹ŒŽ‘’û“’““””ü•”•††‡ˆü‰ˆˆ‰‰ýЉŠŠ‹Œý‹ŒŽþŽŽ‘’“”þ…††‡ýˆ‡ˆˆ‰Šþ‹ŒŒŽù‘‘‘ý’‘’’“”…†‡ˆ‰øŠ‰‰Š‹ŠŠ‹‹ŒüŒŽŽøŽ‘õ’‘‘’““’““”……†ù‡†‡ˆˆ‡ˆˆ‰ùŠ‰Š‰ŠŠ‹‹ŒŽý‘‘‘÷’““’““„„……†‡ûˆ‡‡ˆ‰‰ýЉŠŠ‹ýŒ‹ŒŒŽ‘’ú“’“„„……†‡ûˆ‰ˆˆ‰‰Š‹ŒùŽŽŽ‘ú’‘’’“„„ý…„……†‡ˆý‰ˆ‰‰Šü‹ŠŠ‹‹õŒ‹ŒŒŒŽŽŽþ‘’ý‘’„„þ…„„…†ý‡†‡‡ˆý‰ˆ‰‰Š‹ŒŽø‘‘‘’‘‘ƒƒ„…†ý‡†‡‡ûˆ‡ˆˆ‰‰Šý‹Š‹‹Œü‹ŒŒŽü‘ƒ„…†‡ˆ‰øŠ‰‰ŠŠ‹Š‹‹ŒùŒŽŽŽú‘‘‚ƒƒý„ƒ„„…†‡þ†‡‡ˆ‰Šü‹Œ‹ŒŒŽû‘‚ƒ„ý…„……†‡üˆ‡‡ˆˆ‰Š‹ýŒ‹ŒŒþŽŽý‘‚‚ƒý„ƒ„„…†‡ˆ‰üЉ‰ŠŠ‹øŒ‹ŒŒŒŽ‚ýƒ‚ƒƒ„…†‡ˆü‰ˆˆ‰‰Šý‹Š‹‹ŒüŒŽŽû‚ƒý‚ƒ„„ý…„……†‡ýˆ‡ˆˆ‰Šù‹Œ‹‹ŒŒýŽŽŽûŽý‚‚‚ƒü„ƒƒ„„…ý†…††‡ˆ‰þˆ‰‰Š‹üŒŒŽý€‚ú‚ƒƒ‚ƒƒ„…†‡ˆ‰Šþ‰ŠŠ‹ŒŽþ€€‚󃂃ƒ„„ƒ„„…„…††‡ˆ‰ýˆ‰ŠŠ‹ŒþŒŽý€€€‚ƒý„ƒ„„…†‡ü†‡‡ˆˆ‰úЉ‰ŠŠ‹‹ŒŽ€û€‚‚ƒ„…†‡üˆ‰ˆ‰‰ûŠ‹‹Š‹‹Œ€‚ƒ‚ƒ„…†ý‡†‡‡ˆ‰Šþ‹ŒŒýŒ€‚ý‚ƒƒ„…†‡ˆ‰Š‹Œþ~~û~€€€‚ƒ„…†ý‡†‡‡ˆ‰Š‹Œþ~~€‚ƒú„ƒ„…„……†ý‡†‡‡ˆ‰úˆ‰ŠŠ‰ŠŠ‹Œ}~€û‚‚‚ƒƒ„ý…„……†ý‡†‡‡ˆ‰Š‹ûŒ‹}}~~€‚ü‚‚ƒƒ„ýƒ„……ý†…††ý‡†‡‡ˆ‰Š‹ú|}}~}~~€‚ƒþ‚ƒƒ„…†‡ˆý‰ˆ‰‰Šü‹||}}~ý€€€ü‚‚‚ƒ„üƒ…„……†þ…††‡üˆ‡‡ˆˆü‰ˆˆŠŠþ‹||}~õ}~~~~€€€‚ýƒ‚ƒƒ„ý…„……†ñ‡†‡‡ˆ‡‡ˆˆ‰ˆˆ‰‰ŠŠö|{||}}|~}~~ý€€€‚ƒ„øƒ„……„……††û‡ˆˆ‡ˆˆ‰îŠ{|{||}|}}~~}~~~ý€€€‚ƒý„ƒ„„û…„……††‡ˆ‰Š{|}~€‚ƒ„…ý†…††þ‡ˆˆ‰{|}~ý~ý€€€‚ƒ„…†‡ˆz{ûz{|{||}ú~}~~€ý€‚ƒ„þƒ„„…†ý‡†‡‡ûˆ‡ˆ‰ˆ€À$Žýü‘‘‘’û“’““””•–—˜þ—˜˜™ýš™šš›ôŽŽ‘‘’‘’“÷”“””•”••––—ü˜™˜™™÷š™šš›š››ŽŽýŽ÷‘‘‘’’ü“’’““”•–û—–——˜˜™šú›šš›ŽŽ‘’“”ò•”••–•––——–——˜˜™šö™šš›ŽŽŽŽø‘‘‘’’“”•ý–•––—û˜—˜˜™™šû™šŒŒŽý‘‘‘’“”•–—˜ú—˜™˜˜™™üšŒŒŽýŽ‘’ø“’““”““””•ø–•––—––——ý˜—˜˜™ýŒŒŒþŽŽýù‘‘’‘‘’’“”þ“””•–—ý˜—˜˜™õ‹ŒŒŒŒŽŽŽú‘‘‘’“ü”““””•–—˜™û˜™‹‹ŒŒýŽŽŽý‘’“ý”“””•ú–•——–——˜ù™˜‹‹Œ‹ŒŒýŽŽŽöŽ‘‘ù’‘’‘’’““”•–—þ–——˜‹ŒõŽŽŽŽ‘’õ“’““””“”•”••–—˜Šý‹Š‹‹ŒŽû‘‘‘‘’“û”“””••ý–•––—Š‹ŒüŒŒŽ‘’“”•û–•––——þ˜ŠŠ‹ŒýŒŽý‘’ü“”“””•–ú—––‰‰ŠŠ‹ýŒ‹ŒŒüŒŽŽü‘‘’“ú”“••”••–û•––—‰‰Š‹ŒŽ‘’“”•þ–••–ˆ‰Š‹ŒŽ‘û’‘’’““”•–ˆû‰ŠŠ‰ŠŠ‹ŒýŽŽŽ‘’“”ü•––ˆˆù‰ˆ‰‰Š‰ŠŠ‹ŒŽýŽ‘ü‘‘’’ù“’“’““””•þ‡ˆˆ‰Šø‹ŠŠ‹ŒŒ‹ŒŒŽý‘‘ý’‘’’“”•‡üˆ‰ˆ‰‰ýЉŠŠ‹Œú‹ŒŒŽþŽö‘‘‘‘’‘’’“”ý•”‡‡ˆ‰Šõ‹Š‹Œ‹ŒŒ‹ŒŒŽùŽù‘‘‘’‘’’“”‡üˆ‡ˆ‰‰Š‹ýŒ‹ŒŒýŒŽ‘’þ‘’’“”†‡ˆü‰Š‰ŠŠü‹ŠŠ‹‹ŒùŒŒŽŽŽ‘’“”†ý‡†‡‡ˆ‰ûŠ‰ŠŠ‹‹ùŒ‹ŒŒŽýŽ‘’“†‡ˆý‰ˆ‰‰Š‹ýŒ‹ŒŒùŒŽŽŽ‘þ’‘‘’“ý†…††ý‡†‡‡úˆ‡ˆ‰ˆ‰‰Šû‹Š‹‹ŒŒýŽŽŽ‘’ú“…†……††‡ˆý‰ˆ‰‰Šý‹Š‹‹ŒýŒýŽŽŽý‘ö’‘’„……†……††‡ˆý‡ˆ‰‰Š‹ýŒ‹ŒŒŽýŽ‘ù’‘’‘„„……ý†…††‡ˆ‰Šþ‰ŠŠ‹ŒúŒŒŽŽü‘„ý…„……†‡ýˆ‡ˆˆ‰Šö‹Œ‹‹ŒŒŒŽøŽŽ‘þƒ„„…†‡ˆ‰Š‹þŒ‹‹ŒŽûŽ‘„þƒ„„…†‡ˆþ‡ˆˆ‰Š‹ýŒ‹ŒŒþŒýŽŽŽö‘ƒ„ƒƒ„„…†‡þ†‡‡üˆ‡‡ˆˆ‰Šü‰ŠŠ‹‹ŒøŽŽŽŽ‚ƒ„ø…„„…„……††ý‡†‡‡ˆ‰ýЉŠŠ‹ŒŽûŽ‚ƒ„ý…„……ý†…††‡üˆ‡‡ˆˆ‰ùŠ‰ŠŠ‹Š‹‹ŒŽû‚‚ƒƒ„î…„„……†…††‡‡†‡‡ˆ‡‡ˆˆ‰Š‹ýŒ‹ŒŒýŽŽŽùŽ‚‚ƒƒþ„ƒƒ„…†‡ˆû‰ˆ‰‰ŠŠ‹ŒþŒŽþ‚‚ƒ„ù…„……†…††‡ˆ‰üˆ‰‰ŠŠ‹ŒêŒŒŽŽŽŽ‚‚‚ƒ‚ƒƒ„„…†ú…††‡†‡‡ˆ‰ûŠ‹ŠŠ‹‹ŒŽû€€‚‚ƒý„ƒ„„…÷†…†……†‡†‡‡þˆ‰‰þˆ‰‰Š‹ðŒ‹‹ŒŒŒŽŽ€€‚ƒý„ƒ„„…†‡üˆ‡‡ˆˆ‰ýЉŠŠ‹Œ€ú’“’’“’’ ‘þ‘øŽŽûŽŽŽùŒ’’“’’ü‘’’‘‘ú‘‘‘üŽŽùŽŽŽþŒ’’‘þ’‘‘þ‘ŽüŽŽ Ž󌓒’‘‘’‘‘’‘‘ü‘‘ýþþŽŽýŽûŒŒ’ú‘’‘‘’‘‘ý‘þŽŽŽŽýŒŒŒü’‘‘’’‘ú‘‘‘ ýŽŽŽúŽŽŽŒþŒŒ’‘þ’‘‘þ‘‘ ŽŽŒŒþ‹ÿ ¿ÿ@ Àÿ€À$ü—˜˜™™š›œûžžžŸŸ ¡¢£¤ý¥¤¥¥¦ü—˜—˜˜™š›œžõŸžŸ  ŸŸ¡  ¡¡¢ü£¢¢££¤¥þ¦——˜™š›œþœžþŸ  ¡¢£¤¥÷–——˜—˜—˜™™š›úœœœžŸû Ÿ  ¡¡¢ú£¢¢££¤¤ü¥¤¥——˜™ý˜™šš›œýœžŸ ¡¢ý£¢££ú¤¥¤¥•––—û˜—˜˜™™þš™™šý›š››œžýŸžŸŸð ŸŸ ¡¡ ¡¡¢¡¢¢£¢££¤þ•––—˜û™˜™™šš›œùžžžŸžŸŸ ¡ý¢¡¢¢£ø¢££¤£¤•––ü—–—˜˜™šù›šš›œ›œœžõŸžŸŸ Ÿ ¡  ¡¡ý¢¡¢¢£ø¤”••–•–——ü˜——˜˜™þš™™šõ›š››œ››œœžþŸŸ û¡ ¡¡¢¢ý£”••ý–•––—˜™šý™š››œûœžžžŸý Ÿ  ü¡¢¡¢¢£ù¢”•””•––—˜™š›üœ››œœžŸ õ¡ ¡¢¡¢¡¢¢£””•–þ•––—˜™šþ™šš›ýœ›œœžŸ ¡þ¢””•–þ•––—ý˜—˜˜™ýš™šš›œžŸý Ÿ  ¡ý¢¡““”•–þ•––ý—–——˜™š›œþœžŸ ¡þ’““”ù•”••–•––ü—˜—˜˜™šõ›š››œ›œœœžŸ þ¡’’“”ü•””••–—˜™š›œûœœžžŸ ûŸ¡ ¡’’“ý”“””•–—˜™š›üš››œœýœžŸüž Ÿ  þ‘’’“”•–—˜ý™˜™™š›œžŸë Ÿ  ‘‘’’““’““”“””••”••–—˜ù™˜™™š™šš›œžŸ‘’ý“’““”•ü–—–——˜ú—˜˜™˜™™š›œýœžŸ‘ý’‘’’ý“’““”•–—˜™šù›š›œ››œœûžžžŸŸ‘’“”•–—˜™š›ýœ›œœž‘’“”•ý–•––—þ–——˜™š›œûžŸ‘û‘’‘’’û“’““””ü•”•––—˜™ü˜™™šš›œúž‘’“”ü•””••û–•––——˜ý™˜™™š›œžüŽù‘‘‘’‘’’“”þ“””•û–—––——˜™üš›š››œþŽû‘‘‘’“”ý•”••–—ú˜——˜˜™™ýš™šš›œýœŽŽù‘‘’‘’’”•–—˜™š›ùœ›œ›œŽŽþ‘’’“”ú•”•–•––—˜ú™˜˜™™šš›œŽù‘‘‘’“”ù•”••–•––—˜™üš›š››ýœ›ŽýŽ‘’“ú”““””••ö–••––—–——˜˜ý™˜™™š›Žü‘‘’“”•ý–•––—˜™ýš™šš›þŒýŽŽŽõŽ‘‘‘û’‘‘’““”÷•”•–••––——˜™šŒŽ‘’“”•ý–•––—˜ú™˜˜™™šš‹ŒŽû‘’’‘’’“÷”““”•”•”••–ü—–—˜˜™šõ‹ŒŒ‹ŒŒŒŽŽü‘‘’’“”•ý–•––—ú˜—˜™˜™™‹ýŒ‹ŒŒüŽŽŽø‘’‘‘’’““ý”“””û•”••––—˜™‹ýŠ‹ŒŒý‹ŒŽüŽ‘’“ú”•”••––þ•––—˜ùЋЋЋŒŒŽþ‘’“ü”“”••ý–•––—˜Š‹üŒŒŽúŽŽ‘’ü“”“””•–ö—–—˜—˜˜‰‰ŠŠú‹ŠŠ‹‹ŒŒýŒŽý‘’“ý”“””ý•”••–—‰Š‹ŒùŒŽŽŽ‘’“”•ü”••––—þ˜‰‰Š‹ŒýŒŽ‘ý’‘’’“ù”“””•”••–—€À$œýœžýŸžŸŸ ¡¢ù£¢££¤£¤¤¥þ¤¥¥¦ý§¦§§ð¨§§¨¨©¨©›œ›œœœýžžžŸ ¡ý¢¡¢¢£¤ý¥¤¥¥þ¦§§ú¨§¨¨©››ûœ›œœžøŸžŸŸ ŸŸ  ¡¢õ£¢¢£¤£¤£¤¤¥¥ý¦¥¦¦§¨›œžøŸžŸŸ ŸŸ  ¡¢£¤ý¥¤¥¥¦§¨›œžúŸžž Ÿ  ¡ý¢¡¢¢£ý¤£¤¤¥¦§¨š›œžŸ û¡ ¡¡¢¢þ£¢¢£¤¥¦þ¥¦¦§ý¨™ššú›œ›œœžŸþžŸŸ ý¡ ¡¡¢ý£¢££¤¥¦ü§™™šš›þš››œþœžŸý Ÿ  ¡¢£¤¥÷¦¥¥¦§¦™™šš›œžŸý Ÿ  ý¡ ¡¡¢£¤ý¥¤¥¥¦™š›œüžžžŸ ú¡ ¡¡¢¡¡¢û£¤¤£¤¤¥¦˜™š›œ›œžŸý Ÿ  ú¡ ¡¢¡¢¢£¤ý¥¤¥¥˜™šú™šš›š››œþ›œœžŸ ¡¢£¤þ£¤¤¥þ¦˜˜ý™š™™š›ðœ›œœœžžžŸžŸŸ ¡¢£¤þ£¤¤¥˜™š›œýžžžýŸžŸŸú Ÿ ¡ ¡¡ý¢¡¢¢£¤—ý˜—˜˜™øš™™šš›š››œžþžžŸ ¡¢ò£¤£¤£¤¤–——˜˜—˜˜™š›œþ›œœžŸ ¡ý¢¡¢¢ü£¢£¤¤—˜þ—˜˜™ýš™šš›œþœžŸ úŸ ¡  ¡¡¢þ£¢¢£þ¤––—˜™üš™™šš›õœ›œ›œœœžžþŸžžŸ ¡û¢¡¢¢££–—˜™š›þš››œüžžžŸ þŸ  ¡ý¢¡¢¢£ø•–•–—––——˜ý—˜™™šý›š››œùœžžžžŸ ý¡ ¡¡¢ý£¢••–—þ–——˜ý™˜™™š›œöžžŸžŸžŸ  ¡¢ú”••–•––ý—–——˜ý™˜™™š›œüœžžŸù Ÿ ¡  ¡¡û¢¡””••–ì•–—–——˜—˜—˜˜™™˜™™š™šš›úœ››œœýžžžýŸžŸŸ ¡”•–—þ–——˜™šõ›š›œ›œ›œœžüžŸžŸŸ ¡ý¢“””•ù–•––—–——ú˜—˜™˜™™šü›šš››œûžŸžŸŸï Ÿ  ¡  ¡“”“””••”••ù–•––—–——ý˜—˜˜ù™˜™™š™šš›þœ››œýžžžŸ ¡ü ““””•ý–•––—˜™š›þš››œžŸû Ÿ  ““”•ý–•––—˜™š›ûœ›œ›œœžûŸžŸŸ  þ’““”ý•”••–ý—–——˜™ýš™šš›œøœœžžžŸûžŸŸ ’’“û”“””••–—˜™š›ýœ›œœžŸ’“þ’““”•ý–•––—˜þ™ššö›œ›œœ›œœýžžžüŸ’‘’’ü“’’““”ý•”••–û—–——˜˜ü—˜˜™™š›þš››œžùŸ‘’’‘‘’’ü“”“””•–ü—–—˜˜ü™˜˜™™šý›š››œüœœžûžž‘‘’ý“’““”•ü”••––—˜ý™˜™™š›œžý‘‘‘’ý‘’““”•–—˜ý™˜™™šý›š››ýœœœýž‘’“”ü•””––—ý˜—˜˜™úš™š›š››œ‘û’‘’’““ú”““””••–ý—–——˜™š›œ‘’“”þ“””•–—˜ý™˜™™š›œ‘þ‘‘’“þ”““þ”••ü–••––—˜™šð›š››œ›œ›œœù‘‘’‘’’“ý”“””•ý–•––ú—–—˜—˜˜™üš™™ššý›š››œŽú‘‘‘’’ý“’““”•–ý—–——˜ø™˜˜™™š™ššý›š››úœŽŽŽ‘ý’‘’’“ý”“””ý•”••–ü•––——˜ý™˜™™šû›š››ŽŽúŽŽ‘’“ý”“””ý•”••–ý—–——ù˜—˜˜™˜™™š›€Œù‹ŒŒ‹‹Œ‹‹Šü‹Š‹ŠŠ‰Š‰ˆþ‰ˆˆ ‡ý†ŒŒý‹Œ‹‹þŒ‹‹Šþ‹ŠŠ‰þˆ‰‰ˆý‡ˆ‡‡ù†‡‡††‡ŒŒ‹üŒ‹Œ‹‹þŠ‹‹Š‰þЉ‰ˆû‡ˆˆ‡ˆˆ‡þ†‡‡†Œ‹þŒ‹‹ýŠ‹ŠŠ‰ûŠ‰ŠŠ‰‰úˆ‰ˆˆ‰ˆˆý‡ˆ‡‡þˆ‡‡†û‡†ŒŒ‹‹úŒ‹Œ‹Œ‹‹Šþ‹ŠŠ‰öЉ‰Š‰‰ˆ‰ˆ‰‰ˆõ‡ˆˆ‡‡ˆˆ‡‡†‡‡ò†‡†‡††ŒŒ‹Œ‹‹Œ‹‹ûЋЋŠŠú‰ŠŠ‰Š‰‰ˆþ‰ˆˆü‡ˆ‡ˆˆ‡ü†‡‡††Œ‹þŒ‹‹Š‹Š‰ýЉŠŠ‰üˆ‰‰ˆˆþ‰ˆˆú‡ˆ‡ˆˆ‡‡†ü…††ÿ ¿ÿ@ Àÿ€3$ 6$8$:$;$<$=$¦§¨©ª«¬­®¯°ý±°$$þ¦¦§ü¨§¨©©ª«ý¬«¬¬­®ü¯®®¯¯°± $þ¥¦¦§þ¨©©ýª©ªªý«ª««¬­ý®­®®¯°þ¯±±þ²$ $¥¦§û¨§¨¨©©ýª©ªª«üª««¬¬­®ý¯®¯¯°± $¥¦ý§¦§§ù¨§¨¨©¨©©ª«¬­®ý¯®¯¯°ý±°±±$¥ý¤¥¦¦§¨©ýª©ªª«¬ý«¬­­ý®­®®¯°±$¤¥ñ¦¥¦§§¦§§¨§¨¨©¨©©üª©©ªªü«¬«¬¬­þ¬­­®¯°±$¤ú¥¤¤¥¥¦¦§¨©ª«¬ø«¬­­¬­­®®¯°ý±°$$þ£¤¤¥¦§¨©ªþ©ªª«¬­÷¬­®­®®¯®¯¯°$ü£¤£¤¤¥¦§ý¨§¨¨ý©¨©©ª«¬û­¬¬­®®ý¯®¯¯°$£¤ý¥¤¥¥¦ô§¦§§¨§¨¨©©¨©©ª«¬­®¯ü°¯°$$¢£¤¥¦§¨©ª«¬ý­¬­­ý®­®®ü¯°¯$$¢£¤¥¦§¨©þ¨©©ª«¬­ó¬­­®­®®¯®®¯¯$$û¢¡¢¢££û¤£¤¤¥¥ú¤¥¥¦¥¦¦§¨©ªý«ª««þ¬­­®¯$¡¢£¤¥¦§¨©úª©©ªª««ý¬«¬¬û­¬­­®®¯þ®$$¡ù¢¡¢¢£¢££¤¥¦ü¥¦¦§§ü¨§§¨¨©ª«¬­®ü­®®$$þ ¡¡¢£¤ü£¤¤¥¥î¦¥¦¥§§¦§§¨§¨¨©©¨©ªª«¬ý­¬­­®$ ¡¢£ù¤£¤¤¥¤¥¥¦ý§¦§§¨ö©¨¨©©ª©©ª««¬­þ®$$ ý¡ ¡¡¢£¤¥¦§ý¨§¨¨©ü¨©©ªªý«ª««¬­$Ÿ ¡¢£¤ü¥¦¥¦¦§¨©ª«¬ü­¬¬$$Ÿ ý¡ ¡¡¢ý£¢££¤û¥¤¥¥¦¦§¨©ª«÷ª««¬«¬­­$$Ÿ ¡¢ü£¢¢££¤ý¥¤¥¥¦§¨©ª«ú¬««¬¬$$úžŸžŸŸ  þ¡  ¡¢£¤¥ù¦¥¦¥¦¦§§¨©ýª©ªª«¬$žŸý Ÿ  ù¡ ¡¢¢¡¢¢£¤¥¦§¨þ©¨¨©ª«$žŸû Ÿ  ¡¡¢£¤¥¦ü¥¦¦§§ù¨§¨¨©¨©©ª«$žŸ ¡¢û£¢££¤¤¥ù¦¥¦¦§¦§§¨©ª«$žŸþž  ¡ý¢¡¢¢£¤¥¦ü§¦§¨¨©ýª©ªª$ýœžžýŸžŸŸ ý¡ ¡¡ý¢¡¢¢£ý¤£¤¤¥ý¦¥¦¦§¨û©¨©©ªª$œžŸýžŸ  ¡ü¢¡¡¢¢£¤¥¦§¨ý©¨©©$œýžŸŸ ¡¢û£¢¢£¤¤û£¤¥¤¥¥ý¦¥¦¦§¨ú©¨©©ª$$œøœœžžžŸ ù¡ ¡¡¢¡¢¢£¤þ£¤¤¥¦ù§¦§¨¨§¨¨þ©$$û›œœ›œœžŸ ÷¡¢¢¡¢¢£¢££¤¥¤¥¦ý§¦§§û¨©¨©$$öš›œ›œ›œœžŸ ¡¢£¤¥¦§¨ü§¨¨$$û›š››œœžûŸžŸŸ  ¡¢£¤¥ü¦¥¥¦¦§ü¨§§$$ûš››š››œýœžûŸžŸŸ  ¡ü¢¡¡¢¢£¤¥ý¦¥¦¦ý§¦§§$þ™šš›œýœžŸ þ¡  ¡¢£ù¤££¤¥¤¥¥¦§þ¨$$þ™ššö›šš››œ›œœžùŸžŸžŸŸ  ¡¢£¤¥¦ü¥¦¦§§$™šý›š››œžýŸžŸŸ ¡¢£¤¥ý¦¥¦¦$þ˜™™š›ýœ›œœžŸ ¡ý¢¡¢¢£þ¢££¤ý¥¤¥¥þ¦$$ü˜™˜™™š›œžøŸžžŸŸ Ÿ  ¡¢£ü¤££¤¤¥ü¦¥¥$$ü—™˜™™šü›šš››œýœžŸ ¡þ ¡¡¢£¤¥$˜™ûš™šš››œžŸ ý¡ ¡¡¢£ü¢££¤¤û¥¤¥¥$$þ—˜˜™š›ýœ›œœþžžŸ ¡ü¢¡¡¢¢£¤ý¥¤$$€3$ 6$8$:$;$<$=$û©ª©©ªª«¬­®¯°±²ú±²²³²$$þ©©ûª©ªª««¬ù­¬­­®­®®¯°ý±°±±²³ $ø©¨¨©©ª©ªª«ü¬««¬¬­®ù¯®¯®¯¯°°÷±°±°±²²±²²³ $û¨©©¨©©ýª©ªªú«ª«¬«¬¬­û®­®®¯¯°±²³ $ù§¨¨©©¨©©ª«¬­®¯°þ¯°°±²ü³²³$$þ§¨¨©ª«¬­ý®­®®ù¯®¯¯°¯°°±²³$§¨©ªû«ª«ª««¬­®­ü®¯®¯¯°±²þ³$$¦§¨©ªý«ª««¬ü«¬¬­­®¯ø°¯¯°°±°±±²þ³$$þ¦§§û¨§§¨©©ª«ý¬«¬¬­®¯°±²$¦§þ¨©©ª«¬­þ¬­­®¯°ý±°±±²$¦§¨©ýª©ªª«ý¬«¬¬­®¯°±þ²$$¥¦§¨©ýª©ªª«ý¬«¬¬­ó®­­®®¯®¯¯°°¯°°ú±°±²±$$ò¥¦¥¥¦¦§¦¦§§¨§¨¨ý©¨©©ª«ü¬««¬¬­®ý¯®¯¯°±$¥¦ø§¦§§¨§§¨¨©ªü«¬«¬¬ý­¬­­ü®­­®®¯°±$þ¤¥¥¦ù¥¦¦§¦¦§§¨ý©¨©©ªý«ª««þ¬­­ý®­®®¯û®¯°¯°°þ±$$¤ý¥¤¥¥¦þ¥¦¦§¨þ§¨¨©ª«þ¬««¬­®¯ý°¯°°$¤ý¥¤¥¥¦§ú¦§§¨§¨¨©ª«¬ú«¬¬­¬­­ù®­®¯®®¯¯°$¤ü¥¦¥¦¦§¨©ªþ«ªªþ«¬¬­®û¯®¯¯°°$þ£¤¤ø¥¤¥¥¦¦¥¦¦§ý¨§¨¨û©ª©©ªª«¬ü­®­®®¯þ°$$ú¢££¤£¤¤¥¦§¨û©¨©©ªª«ü¬««¬¬­®¯ý®¯$$þ¢££¤¥¦§ý¨§¨¨ý©¨©©ª«û¬«¬¬­­®ú­®¯®¯$$¢£ý¤£¤¤¥¦§¨©ýª©ªª«ó¬««¬¬­¬­­®­­®®$ý¢¡¢¢£ú¤£¤¥¤¥¥¦ò¥¦¦§§¦§§¨¨§¨¨©©ýª©ªª«¬­®$þ¡¢¢£û¤£¤¤¥¥¦§¨©ª«¬­$¡û¢¡¡¢££ü¤¥¤¥¥ù¦¥¦¦§¦§§ü¨§§¨¨©ýª©ªª«¬­þ®$$þ ¡¡¢£ý¤£¤¤¥¦§¨©ª«¬ú­¬¬­­$$ý¡ ¡¡¢£ü¤££¤¤¥¦ü§¦¦§§¨©ªý«ª««ý¬«¬¬þ­$$ ¡ý¢¡¢¢£¤¥ý¦¥¦¦§¨©ª«¬ý­¬$$þŸ  ¡¢ú¡¢¢£¢££¤¥¦§¨©ýª©ªª«¬þ­$$þŸ  ý¡ ¡¡¢£ü¢¤£¤¤û¥¤¥¤¥¥¦§ý¨§¨¨©ª«¬$Ÿû Ÿ  ¡¡ú¢¡£¢¢££¤ù¥¦¦¥¥¦§§ú¦§§¨§¨¨ý©¨©©ªý«ª««þ¬$$Ÿ ¡¢£¤¥¦§¨©ª«$þžŸŸý Ÿ  ¡¢£¤¥ü¤¥¥¦¦ý§¦§§ý¨§¨¨©ª«$öžŸžžŸŸ ŸŸ  û¡ ¡¡¢¢£¤¥ý¦¥¦¦û§¦§§¨¨©ªý«ª$$žŸ ¡¢ü£¢¢££ý¤£¤¤¥¦ý§¦§§ü¨§§¨¨©ªý©ª$$žŸ ¡ ¡¢ý£¢££¤ý¥¤¥¥¦þ¥¦¦§ù¨§¨¨©¨©©ª$žþžžúŸžžŸŸ  ¡¢£¤¥þ¤¥¥¦ý§¦§§ý¨§¨¨©þª$$žŸ ¡þ ¡¡ö¢¡¢¢£¢¢££¤¤¥¦§¨ý©ª$$žýŸžŸŸ ÷¡ ¡ ¡¡¢¡¢¢ù£¤¤£¤¤¥¥¦§ø¨§¨©¨©©$$œýœžýŸžŸŸý Ÿ  ¡ý¢¡¢¢£¤¥¦ü¥¦¦§§¨$œûœžžŸ ¡¢£ý¤£¤¤¥¦§¦§û¨§¨¨$$ýœ›œœžžýŸžŸŸ þŸ  ü¡ ¢¡¡¢£¤¥¦ø§¦§§¨§¨$$û›œœ›œœýœžýŸžŸŸ ¡¢£¤¥ü¦¥¥¦¦§ý¨§$$€ü‡†‡††…þ†……ý„…„„ƒþ„ƒƒ‚ý‚ † …ý„…„„þ…„„ýƒ„ƒƒý‚ƒ‚ ‚ù‚‚†…þ†……þ„……„ƒþ„ƒƒü‚ƒƒ‚‚þ‚‚ý‚þ€†ý…†……û„…„…„„ ƒ‚û‚‚û€€†ü…††… …„ƒþ„ƒƒ‚þƒ‚‚þ‚ú€€€† …ý„…„„ƒþ‚ƒƒ‚þƒ‚‚ú‚‚‚€ù€€€…þ†……ü„……„„ú…„…„„ƒƒû‚ƒ‚ƒ‚‚þƒ‚‚ü‚‚þ€€.ÿþ€€þÿ0ÿü€€€û€€ÿ2ÿ€5ÿ€6ÿ€ø€€€ÿ6ÿþ€8ÿ€ü~~ÿ7ÿþ€~9ÿþ~9ÿþ~:ÿ~:ÿý~~~:ÿ~;ÿ~þ}ÿ:ÿ~ý}~ÿ:ÿ~};ÿû}~}}ÿ:ÿ~};ÿ};ÿþ~}};ÿ};ÿû}|}}ÿ:ÿ};ÿ}þ|ÿ:ÿ|;ÿ|;ÿ|;ÿ|;ÿ|;ÿ|;ÿû|{||ÿ:ÿþ|{{;ÿ{;ÿ{;ÿ{;ÿ{;ÿ{þzÿ:ÿû{zz{ÿ:ÿû{z{{ÿ:ÿ{ýz{ÿ:ÿûz{zzÿ:ÿz;ÿzy@.ÿ1ÿ 3ÿ 5ÿ 6ÿ7ÿ8ÿ8ÿ9ÿ9ÿ:ÿ:ÿ:ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿþ$=þ$=$=$=$=$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<þ$=þ$=$=$=$=$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<þ=þ~=ý~<=ý~<~þ;ü~~;ü~~;ü~}~;~þ};~<}þ~;}<ü~}};}<ü}|};ü|}};}<}<ü}|};ü}||;|<|<|<ü{|{;ü{||;ü|{{;{<ü|{|;ü|{z;{<{<{þz;ü{zz;{<z<z<z<z<üyzz; @ @ @ @ $pqýrqrrúsrststtuvwxyþz $opqrstuvwüxwxyy $opqýrqrrstüuttuuvwxy $opqôrqrrsrrstssttuvýwvwwxýyx $nopqrstuvüwxwxx $nopøqpqqrrqrrstýutuuvwüxww $ønmmonnoppqûrqrrsstuvwþx $ómnmnnoonoopoppqrsýtsttuvw $mnoýnoppùqpqprqrròsttssttutuuvuvv $lmnopqrsútstutuuv $lmnoüpqpqqrstûutuuvv $lmùnmnnonoopûqrqqrrýsrsstùutuuvu $lmönmmnnonooppýqpqqrûsrssttúuttuu $klòklmlmmnnmnoonoopqrýsrsstu $klömlmmnmnonoopûqpqqrrst $üjkjkklmnoýpoppqrsütst $jükjkllýmlmmnûononoopqrst $ýjijjklmúnmnonoopqrsþrss $ýjijjklûmlmmnnopqrsýrs $þhiijklmünonoopqpqr $ijklmnopýqpqqrþs $hijklmnopqúpqrqr $hýihiijýkjkklmnopqþr $hiújijkjkklþkllmünonooùpopqppqq $ghiîjiijjkjjkkllklmllmmnopþq $ghijökjkkllkllmmnopþq $ghijklmûnmnnoop $fgüfgghhijkülkkllþmnnýonooþp $fghüihhiijklmnúonoop $ýfeffghýihiijýkjkklmno $ûefeeffùgfgghghhiþjiiþjkkýlkllmnþo $þdeefgûhgghiijklmn $defgühgghhíihiijijjkjkklklkllmmünmn $defýgfggýhghhiýjijjklmn $ýdcdde÷fefggfgghhiýjijjkûlkllmm $dcüdedeefghiôjijjkkjklkkllm $cdefghýihiijùkjkklkll $bcdefghijkþl $bcdefghijkl $býcbccdýedeefghijýkjkk $abcdefýgfgghijk $abýcbccdýedeefghijk $þ`aabcdýedeefþghhiþhiijþk $`abcübccddýedeefûgfgghhiþj $`aóbaabccbccdccddefgýhghhiþj $_`abcûdcddeeýfeffghùihhiij $þ_``abcdýedeeýfeffgýhghhi $_ù`_``a`aabcdefýgfgghýih $õ_^__`_``a`aabýcbccdefgþfgghþi $^ü_^`__`þabbcdüeddeefýgfggþh $^_ý`_``ûabbabbcdùedeefeffgþh $þ]^^_ý`_``ùa`aababbcdeõfefeffgffg $]ý^]^^_ý`_``aýbabbcûdeddeefgþf $]ý^]^^_÷`a``aababbcýdcddeýfeff $þ\]]^ú_^^__``abücdcdd÷edeefefg $\]ü^]]^^_ü`__``abûcbccddef $\]^_`abcde $þ[\\]^_`abcýdcddþe $[\]^_þ^__`abcdþcdd $úZ[[\[\\ö]\]]^]]^^__`abcdþe $þZ[[ø\[\\]]\]]^_`aü`aabbcd $Z[ü\[[\\]^ù_^^_`_``abcþd $þYZZ[\ü[\\]]^_`abûcbcc $YZû[Z[\[[\]ý^]^^þ_``ùa`aababbc $wüxwwxxyzñ{z{{||{|}}|}~}~~÷~€€€ $vwùxwxxyxyyzý{z{{|}ý~}~~ù~€€ $vwxýyxyyz{ü|{{||}~ü~ $výwvwwxyüz{z{{|ý}|}}ø~}~~~~ $þuvvwúvwwxwxxyzþyzzþ{||}~ $üvuuvvwxyz{|}~ $uvwxyz{|}ü~}~ $uývuvvwùxwxxyxyyzù{z{z{{||ý}|}}þ~ $tuvþuvvwxyz{|} $tuvwxýyxyyýzyzz{|ü}|} $ýtsttuvwxýyxyyz{ú|{|}| $stýutuuvwxûyxyyzzý{z{{| $úrsststtuvwxyüxyyzz{| $üsrrsstuüvuuvvwöxwxxyxxyyzz{þz{{ $þrsstuývuvvwxyz{ $rüsrrsstuvwxyzû{zz{ $ýrqrrsûtsttuuvýwvwwxýyxyyzþ{ $ûqrqqrrstuüvuuvvwxyz $qrúqrrsrsstuvwxyz $üqppqqrûsrssttuûvuvvwwxyþz $pqrstuvwxûyxyy $pýqpqqrsýtsttuývuvvwxùwxyxyy $pqùrqrrsrsstýutuuývuvvwýxwxx $þoppqrsþrsstuþtuuvwþvwwx $opqrsûtststtuývuvvwþxww $ýonoopýqpqqrsýtsttuývuvvùwvwwxw $þnoopþqppüqrqrrstuývuvvw $nýonoopþoppqýrqrrsùtsttutuuvýwv $þmnnýonoopüqppqqrsúrsststtuývuvv $ùmnnmnnoopqrsötssttuutuvv $mýnmnnoýpoppöqpqqrqqrrssûtststtuüvuv $þlmmnoýpoppqørqrrssrsstuþv $ýmlmmýnmnnopýqpqqrsýtsttu $lmnoùpoppqpqqrstûutuu $lmúnmnonoopqýrqrrùsrsststt $kýlkllmnopqrùsrrststt $klmnùonoopoppøqpqqrrqrrsütst $þjkklýmlmmnøonooppoppqrûqsrrss $jklmýnmnnôonooppoppqpqqrs $jýkjkkýlkllmýnmnnûonooppqrs $iüjkjkkûlkllmmýnmnnopüqrqrr $÷ijijjkkjkklýkmllmônmnnoonoopoppúqpqrqrr $iüjiijjklúkllmlmmnüonnoopqr $þhiijklmnýonoopqþr $hijýkjkklùmlmmnmnnopûqpqq $hiùhijijijjklùmlmlmmnnoýpoppq $hijklýmlmmönmmnnonopoop $ghijklýmlmmýnmnnop $ghijklmýnmnnoýpo $þfgghijüijjkklmýnmnnùonoopp $fghij÷kjjkklkkllmônmmnmnnonoo $fgýhghhijklþmllümnmnno $þeffghijklmülmmnno $üfeeffgûhghhiiýjijj÷kllkllmlmmnþo $efghijûijkjkklm $þdeefüghghhijkølkkllmlmmýnm $ødeedefeffghþghhijklm $defýgfgghijklûmlmm $þcddefgýhghhijklýml $øcdcddedeefghþghhúihijijjþkjjkýlkll $cdüeddeefghüijijjkl $cýdcddefgüfgghhiújkjkjkkþl $cdefýgfgghiüjiijjýkjkk $þabbcdýedeefgýhghhiýjijjýkjk ‘+ÿ ‘ü‘ÿ*ÿ þ‘‘+ÿ ü‘‘+ÿ ‘ýÿ*ÿ û‘+ÿ +ÿ +ÿ +ÿ øÿ*ÿ þ+ÿ +ÿ ý+ÿ +ÿ þŽŽþŽÿ*ÿ úŽŽÿ*ÿ Ž+ÿ ŽýŽÿ*ÿ þŽŽþÿ*ÿ þŽŽ+ÿ Ž+ÿ üŽŽŽ+ÿ ŽýŽ+ÿ þŽ+ÿ þŽýŽÿ*ÿ Ž+ÿ øŽŽŽÿ*ÿ øŽŒÿ*ÿ ûŒŒÿ*ÿ úŒŒÿ*ÿ Œþÿ*ÿ üŒŒÿ*ÿ ýŒŒŒ+ÿ þŒŒ+ÿ Œþ‹ÿ*ÿ üŒŒŒþ‹ÿ*ÿ Œ+ÿ Œ‹üŒ‹Œÿ*ÿ Œ‹+ÿ ý‹Œ‹‹ýŒ‹ÿ*ÿ þŒ‹‹+ÿ ý‹Œ‹‹+ÿ ý‹Œ‹‹+ÿ ‹+ÿ ‹ûŠ‹‹Šÿ*ÿ ý‹Š‹‹Š+ÿ ýŠ‹ŠŠ+ÿ ‹Šþ‹ÿ*ÿ ø‹Š‹Š‹ŠŠÿ*ÿ ýŠ‹ŠŠ+ÿ Š+ÿ Šú‰ŠŠ‰Šÿ*ÿ Šþ‰ÿ*ÿ ЉýЉÿ*ÿ Љ+ÿ ‰þŠÿ*ÿ ‰þЉ‰+ÿ þЉ‰þˆÿ*ÿ ‰ˆ+ÿ ‰ˆ+ÿ ‰þˆÿ*ÿ ˆû‰ˆ‰ˆÿ*ÿ ˆ‰üˆ‰ˆÿ*ÿ û‰ˆ‰‰ˆˆ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿzû{z{{||ý}|}}~€ý€‚þƒ„„…†‡þ†‡‡ˆyz{|ý}|}}~ý~€û‚‚‚ƒƒ„…ô†…††‡††‡ˆ‡ˆyyz{|}~ù~€€€‚ýƒ‚ƒƒ„ý…„……û†…††‡‡þˆyyûzyzz{{|ý}|}}~€‚ƒ„…†‡üxyxyyz{ý|{||}~ó~€€€€€€‚‚ûƒ‚ƒƒ„„…†xyzý{z{{ý|{||}~€ý€ý‚‚‚ûƒ„„ƒ„„…†xùyxyzzyzzú{z{|{||}~€ý€‚ýƒ‚ƒƒü„ƒƒ„„þ…††þwxxyz{|}þ|}}~€ü€‚‚ƒ…þ†wwýxwxxyùzyzyzz{{ü|{{||}~€ý‚‚ƒõ„ƒ„„…„„……vwwx÷yxyxyzyyzz{|}~þ~€ø‚‚‚‚ƒƒ„ú…„„…vwwùxwxxyxyyz{|}~ü~€€ü‚‚ƒƒ„þuvvwxúyxyzyzz{|ù}|}|}}~~þ€€ý€‚ƒ„ûuvuvwwxyýzyzzý{z{{|}~€‚ýƒ‚ƒƒ„úuvuuvwwûxwxxyyzúyzz{z{{|ú}|}~}~~ü~€€ü€€ý‚‚‚ƒû‚ƒ„tuuvwxùyxyyzyzz{|}þ~€ý‚‚‚ƒuvwxøyxyyzzyzz{|}ý~}~~€ø‚‚‚ƒƒttuvýwvwwxýyxyyzý{z{{ò|{||}|}}~}}~~€ý€‚øƒssttutuuvýwvwwxyýzyzz{|}~ý~ý€€€‚týutuuvwþvwwxyzûyz{z{{|}~€‚stuvwûxwxxyyýzyzz{ý|{||}~€ü€€ô‚rrstssttutuuvüwxwxxyüzyyzz{|}~ý~€ýrssûtsttuuvýwvwwúxyxyxyyz{|}~þ}~~€þrrüststtýutuuvwxyzü{z{||}û~}~~~€þqrrsürssttuvwxyýzyzzý{z{{|ý}|}}ü~~û€€qrrsýtsttýutuuvwxyýzyzz{ý|{||ø}|}~}~}~~þ€qqrstuývuvvûwvwxwwþxyyzþyzz{|}ý~}~~ýqpqqrstüutuvvwývwxxy÷zyzyzz{z{{|}ü~}}~~pqrsürssttýutuuývuvvwxøyxyyzzyzz{|þ{||}~ü}~~ppqþpqqürsrsstuvwxyz{|ý}|}}oûpoqpqqrìstssttututuvuvvwvwwxxyz{|ý}|}}û~opoppqrstuvüwvwxxyz{|}þ~oopqrstuvwxýyxyyûzyzz{{|ú}||nnoopqrsýtuttuøvuuvwvvwwxyz{|þ}nnopúqppqqrrsøtssttutuuvwxyz{ôz{{|{||nmnnoopqýrqrrýsrssûtsttuuvwúxwwxxyyz{|ýnmnnopqpqrýsrsstuvwxyz{mnopqrststuývuvvwxyz{ü|llmmnopqrstùutuuvuvv÷wvwxxwxxyyzö{llmlmmnmnnoýpoppûqpqqrrstuvwxyzù{kllmlmmnopqrstüsttuuvwýxwxxyþzkk÷lmllmmnmnnoýpoppqrstuvwøxwxxyyxyyklmnoþnoopûqpqqrrústststtuvýwvwwýxwxxyùjkklkkllmnoýpoppqýrqrrùsrstssttuvwxyþjkkýlkllmnopqrsøtsttuttuuvîwvwwxwxyxxjjkkjkkllmnúmnnonoopúqppqqrrstuúvuvwvwwxijklmnüonoppqírqqsrsrststtuttuvuvvýwvwwôxwxiijijkkjkkýlkllmýnmnnøonoopoopprstuvwijklmünmmnnopqrsûtsstuuîtuvuuvwvvwwhhiijijjklmýnmnnopqrüsrrsstuvwýihiijûkjkkllýmlmmnopþoppqüpqqrrstuvhijkølmllmnmnnoüpooppqrstuvhijüklkllmnopqrstuþghhiïjiijkkjkklkllmmlmmnoýpoppýqpqqrýsrssøtuutuuvgghûijiijjkýlkllmnýonooþpqqýrqrrstýutffghýihiiýjijjkülkkllmnýonoopqrstþuffgûhgghiijklûmlmmnnopqrsteüfgfgghiüjiijjkýlkllmnùonoopoppqýrqrrsútsteeffghiüjiijjkýlkllmnþonnþoppqürqrssýtdeefûgfgghhiþjkklmþlmmnoünooppqrsýedeefgýhghhiýjijjklmnoüpooppqrsdefghûihihiijküjkkllýmlmmûnonnoopýqpqqrdefgýhghhiùjijkkjkklýmlmmnoýpoppqrþcddefghýihiijklmnúmnnonoopqýrqccdûefeeffghiýjijjõkjkklklmllmmnýonoopq€ý€‚üƒ„ƒ„„…†‡ˆý‰ˆ‰‰ýЉŠŠ‹Œù€€€÷‚‚ƒƒ‚‚ƒ„„ý…„……†‡ˆ‰Š‹Œþ€€ù‚‚‚ƒ‚ƒƒ„…†‡ˆ‰üˆ‰‰ŠŠþ‹ŠŠŒ‹Œ€þ€‚ƒ„…†‡ˆ‰þЉ‰ü‹ŠŠ‹‹ýŒ€û€‚‚ƒø‚ƒƒ„ƒƒ„……þ„……†‡ˆ‰ýЉŠŠù‹Œ‹ŒŒ~€ñ€€‚‚ƒ‚‚ƒƒ„…†‡ˆ‰Šü‹ŠŠ‹‹~€‚ƒú„ƒƒ„„……ý†…††û‡ˆ‡‡ˆˆ‰Šö‹Š‹Š‹‹}~~€‚ýƒ‚ƒƒû„…„„……†‡þ†‡‡ˆý‰ˆ‰‰Š‹}~ù~€€€÷‚‚‚ƒƒ‚ƒƒ„…†ý‡†‡‡ˆ‰Š}~ü~€€ý€‚ýƒ‚ƒƒý„ƒ„„…†‡ˆ‰Š}ù~}}~~€‚þ‚‚ƒü„ƒƒ……þ„……†‡ˆ‰Š|}ý~}~~ü~~€÷‚‚‚ƒƒ‚ƒƒ„…û†…††‡‡ˆ‰|}~ý~€‚ƒ„…†‡ˆ‰|}ú~~~€‚ü‚‚ƒƒ„ü…„„……†û‡ˆ‡‡ˆˆû‰ˆ{{||ý}|}}ý~}~~ü€€€ü‚‚‚ƒ„…†‡ü†‡‡ˆˆ{|}~ú}~~~€ù€‚‚‚ƒ„ý…„……†‡ˆý‰z{{|}þ|}}~€ù€‚‚‚‚ƒú‚ƒƒ„ƒ„„…†‡ýˆz{{|}õ~}~~€€€þ€‚ƒü„…„……†‡þ†‡‡üˆzz{{ý|{||}~€ý€‚ýƒ‚ƒƒý„ƒ„„…†‡z{þ|{{ô|}}|}}~}}~~€ý‚‚‚ƒý„ƒ„„…†ú‡yyzyzz{|}ü~}}~~ý€€€ý€û‚‚‚ƒƒý„ƒ„„û…„…„……†yzý{z{{ý|{||}ý~}~~þ~€‚ƒ„…ý†…††þ‡yyüzyyzz{|}~ü€€‚ƒþ‚ƒƒ„õ…„……†……†xxyyzý{z{{ý|{||}~ö€€€€‚ƒü„ƒƒ„„ý…„……ú†xxyxyyzý{z{{|}þ|}}~ý€€€‚ƒ„þƒ„„…xûyxyyzz{|û}||}~~û~€€þ€‚þ‚‚ƒü„ƒƒ„„ü…xwxxyýzyzz{|}~ø~€€€€ý‚‚‚ýƒ‚ƒƒ„ø…„wwxwwxxõyxyzyzz{{z{{|}ó~}~~~~€€€‚ƒ„úƒ„„wwxxyzû{z{z{{|}þ|}}~€ý‚‚‚ƒ„vwxyýzyzz{|ý}|}}ù~}~~~€ý€‚ƒþ‚ƒƒùvwvvwwxxüyxxyyzû{z{z{{|}ý~}~~€‚ƒù‚ƒ„uvvwwxyüzyyzz{ý|{||}~ý~ý€€€ó‚‚‚ƒ‚ƒƒuuvvúwvvwwxxyýzyzz{ý|{||}ý|}~~€ý€‚ƒuvwýxwxxyzþyzz{|}û~~€ý€þ€‚ûƒtuuvvøuvwwvvwxxyz{|ý}|}}~ü€€€ü€‚‚tuvwxyzý{z{{|}ù~}~~~ý€€€õ‚ttutuuvuvvwxyzyz{ý|{||}~ü~~€sþtuuvüwvvwwýxwxxyzý{z{{|ú}||}}~~€ýtsttuvöwvvwvxxwwxxyz{|ù}|}|}}~~ý€€€stuvûwvwwxxüyxxyyz{|þ{||}~€÷€€rsststtuvõwvwwxwwxxyxxyz{û|{|}||}~ù€€rrsstuvwxyz{|}ü~}}~~ù~€€rsstuývwvvwýxwxxyzý{z{{|}þ~rstuþtuuvwûxwxxyyz{÷|{||}|}}~~ú~qrrsútssttuuývuvvwxy÷zyzz{z{z{{ú|}|}|}}~ûqrqrrstöutuuvuuvvwwxyz{øz{{|{||}}~þ}~~qürqqrrsûrststtûutuuvvýwvwwxyz{ü|{{||}~üpqpqqrsýtsttuøvuvvwvvwwxyþxyyz{|}pýqpqqrstuvwxþwxxüyxyzzýyz{{|ô{||}||}}oppqqrsýtsttuvwxyz{ý|{||}pqrstþsttuvwûxwxxyyýzyzzý{z{{|ý}oppqrstuvýuvwwývwxxüyxxyyz{|þnoopqúpqqrqrrstuvwþvwwxyøxyyzyzz{{|oüpooppûqpqqrrsútssttuuüvuuvvwxyz{ü|{{nnoýpoppýqpqqrsýtsttuvwxyýzyzz{ùmnononooûpoppqqrñqrrsrsstststutuuvwxýyxyyz{nýonoo÷pooppqppqqrýsrsstýutuuvwýxwxxýyxyyzýnmnnopqrstýutuuvýxwxxøyxxyzyyzzmýnmnnopqýrqrrsûrststtuvûwvwwxxûyxyyzzþlmmúnmnonoopqýrqrrsûtststtuvwýxwxxymùnmnnonoopqørqrrsrrsstüuttuuvþuwwûvwxwxxylmnopýqpqqrstuüvuuvvýwvwwxyüxlkllúmllmmnnúonnooppqrstûutuuvvýwvwwxüykkllmnoûnopoppqöpqqrqrrsrsstuývwvvwxÿÿþˆ‰‰Šú‰ŠŠ‹Š‹‹ýŒ‹ŒŒŽþŽ‘ü‘‘’’“”ý•”••–—ˆ‰Š‹þŠ‹‹ŒûŒŽŽü‘‘‘’“”ý•”••û–•–‡ˆˆü‰ˆˆ‰‰Šþ‹ŒŒŽø‘‘‘’ý“’““”•–‡õˆ‡ˆˆ‰ˆ‰‰Š‰ŠŠ‹ŒŽúŽŽŽû‘‘’“”ý•”••þ–‡‡ˆ‰Š‹ýŒ‹ŒŒŽþþ‘‘’ü“’’““”•ö‡†‡‡ˆ‡‡ˆˆ‰‰Š‹ŒýŒŽþþ‘‘’“ü”““””†‡ˆ‰Š‹ŒŽ‘û’“’’““”÷•††‡‡†‡‡ˆˆüЉ‰ŠŠ‹ýŒ‹ŒŒŽ‘’ù“’“’““””ý†…††‡ˆ‰øˆ‰Š‰‰ŠŠ‹‹ŒŽýŽü‘‘‘’“þ”……†‡ü†‡‡ˆˆü‰ˆ‰ŠŠ‹ŒŽúŽ‘’“û”……†……þ†‡‡ˆ‰Š‹ýŒ‹ŒŒýŽŽŽýŽ‘’ü‘’’““„…†ý‡†‡‡ˆ‰Š‹ŒŽ‘’ø“„„…„……††‡ˆý‰ˆ‰‰Š‹ŒüŒŒŽýŽö‘‘‘’‘‘’’„„ü…„„……†‡ˆ‰Šü‰ŠŠ‹‹ŒýŒŽûŽŽþ‘’öƒ„ƒ„„…„……††‡ˆ‰Š‹ûŒ‹ŒŒþŒŽû‘‘ƒ„…†‡ˆ‰Šò‹Œ‹Œ‹ŒŒŒŽŽŽŽ‘þ‚ƒƒ„…†‡ˆ‰Š‹ŒûŒŽŽýŽú‘‘‚‚ƒƒý„ƒ„„…†‡ˆ‰Šú‹Š‹Œ‹ŒŒúŒŽŽŽüŽ‘‚ýƒ‚ƒƒ„…†þ‡††‡ˆý‰ˆ‰‰Š‹Œý‹ŒüŽŽŽþ‚‚ƒû„ƒ„„……†ú‡†‡ˆ‡ˆˆ‰Šû‹Š‹‹ŒŒýŽŽŽþ‚ƒû„ƒ„„……†‡üˆ‡‡ˆˆ‰Šý‹Š‹‹ùŒ‹ŒŒŒ÷ŽŽ€‚ƒü„…„……†‡ýˆ‡ˆˆý‰ˆ‰‰Š‹ŒýŒŽ÷Ž€€‚‚ƒ„…†‡ýˆ‡ˆˆ‰Šý‹Š‹‹ýŒ‹ŒŒŽú€€€‚ýƒ‚ƒƒü„ƒ„……†‡ˆ‰ýЉŠŠ‹Œü‹ŒŒüŽŽŽ€‚ƒ„…ú„……†…††‡þˆ‡‡ˆü‰Š‰ŠŠ‹Œþ‹ŒŒŽþ€€‚ú‚ƒ‚ƒ„„…ý†…††‡ˆ‰Š‹úŒ‹ŒŒ€ü€€‚ƒ„ü…„…††û‡†‡‡ˆˆ‰Š‹ŒýŒþ~ö€€€‚‚‚ýƒ‚ƒƒ„…ü†……††‡ˆ‰Š‹Œþ~€‚ƒü‚ƒƒ„„ü…„„……†‡ˆ‰ôˆ‰ŠŠ‰ŠŠ‹ŠŠ‹ŒŒýŒ~~€ü€€û‚‚‚ƒƒ„…†ý‡†‡‡ñˆ‡ˆˆ‰ˆ‰Š‰‰Š‹‹Š‹‹÷Œ‹ŒŒ}~}~€‚ƒ„…†ý‡ˆ‡‡þˆ‰‰ýЉŠŠ‹Œ}~€þ‚‚ƒ„…ý†…††‡ˆý‰ˆ‰‰Š‹ú|}}~}~~ú€€€ý‚‚‚ƒ„…†û‡†‡‡ˆˆ‰Š‹þ|}}ó~}~~~€€‚úƒ‚‚ƒƒ„„…ý†…††‡ˆ‰üˆ‰‰ŠŠý‹Š||}~€þ€‚öƒ‚ƒƒ„ƒƒ„„……†‡úˆ‡ˆ‰ˆ‰‰úŠ‹‹||}}ù~}~~~€þ€‚ýƒ‚ƒƒ„…†ü‡ˆ‡ˆˆ‰Šë{|{||}|}}~}~~~~€€€õ€‚‚‚ƒ‚ƒƒ„üƒ„„……ù†……†‡†‡‡ˆ‰Š{|}~þ€€‚üƒ‚ƒ„„ù…„……†…††‡ˆ÷‡ˆˆ‰ˆ‰‰z{{û|{||}}~€ù€€‚‚‚ƒû„ƒ„„……†‡ýˆ‡ˆˆ‰òˆzz{z{|{||}||}}~€û‚ƒ‚‚ƒƒ„…†‡üˆ‡‡ˆˆzû{z{{||}þ|}}~ý€€€þ‚‚ƒý„ƒ„„…†û‡†‡‡ˆˆþyzz{|}ú~}~~€‚ƒþ‚ƒƒ„…†ø‡†‡‡ˆˆyzz{|ø}|}}~~}~~û€€€ý‚‚‚ƒ„…û†…††‡‡þˆyyýzyzz{|}~€ü€‚‚ƒø„ƒ„„…„„……†ö‡†‡xxyyzyzz{|ý}|}}~€ø‚‚‚ƒ‚‚ƒƒ„ý…„……†û‡†xxyyz{|}ü~}~€þ€€‚üƒ„ƒ„„ù…„„…†…††þ‡xxýyxyyz{|ý}|}}ù~}~~~€‚ƒ„…†þwxxyzý{z{{û|{||}}~€ý€‚ûƒ‚ƒƒ„„…ø†wwxwxxyyz{|}ý~}~~€û‚‚‚ƒƒ„…wxyz{þz{{|}~~€ü€‚‚ƒ„…vwxþwxxyz{úz{{|{||}~€ü€‚‚ƒ„…vûwvwwxxýyxyyzý{z{{|}ú|}~}}~~€‚ý‚ƒƒ„uvwxyýzyzz{|}ý~}~~ý€€€ô€‚‚‚‚ƒ‚ƒƒ„uvøwvvwxxwxxyùzyzz{z{{|}ý~}~~€‚øƒ‚ƒ„„uuvvwxyz{|û}|}}~~€ð€‚‚‚ƒ‚ƒ„ttuuvvüwvvwwxyzõyzz{z{{||{||}~ü€€€ý‚‚‚þƒttuvýwvwwxyzý{z{{|}~€ü€€‚üƒttuuûvuvvwwxyz{|ú}||}}~~€‚þsttuvwxyz{|}~ô€€€€‚‚sstuþvwwxyþxyyz{|}ý~}~~ý€€€stuûvuvvwwxyz{ý|{||}~€þrsstuvwxyz{ý|{||ý}|}}~õ€€€€rsrsstuvwýxwxxyzù{z{{|{||}~ý€€€þqrrsýtsttuvwxüyxxyyz{|}þ~ý€€üŽŽŽùŽ‘ý’‘’’“”•–ü•––——ý˜—˜˜™šú›š›ŽŽ‘þ’““”ý•”••–ü—–—˜˜ü™˜˜™™šüŽŽŽþ‘ý’‘’’ý“’““”•–—ý˜—˜˜™ûš™šŒŽýŽý‘’“”•–—ý˜—˜˜ò™˜™ššŒŒŒŽŽŽ‘’ý“”““”•–û—–——˜˜™ŒŽý‘‘‘’“ý”“””ô•”–•–•––——–——˜û™˜™‹ŒŒŽüý‘‘‘’ü“’’““”ý•”••ý–•––ü—––——˜þ™‹‹ŒýŒóŽŽŽŽŽ‘’“”•–þ•––—ù˜——˜˜Š‹‹ŒŽ‘ý’‘’’“÷”“”“”••”••–ó—–——˜—˜˜‹‹Š‹ŒŒñ‹ŒŒŽŽŽŽŽý‘‘‘’ü“’’““ý”“””•–—üЋЋ‹ŒýŒŽûŽŽ‘ý’‘’’“”•–—Š‹ŒýŒŽúŽŽ‘’“”þ“””•ü–••––—Šý‰Š‹‹ýŒ‹ŒŒüŒŽŽúŽŽ‘þ‘‘’“”•–—‰Š‹ŒŽúŽŽó‘‘‘’‘‘’““’’““”•–û•––ˆ‰‰òЉЋЋЋ‹Œ‹ŒŒýŽŽŽþû‘’‘‘’’“”•–ù•‰‰ˆ‰‰ŠŠ‹ŒýŒŽþ‘’“”•‰Š‹ŒýŽŽŽ‘ý’‘’’“”•þ–ˆˆ‰Š÷‹Š‹‹Œ‹ŒŒýŽŽŽ‘’“ñ’““””“””•”••ˆ‡ˆˆ‰Š‹ŒŽ‘’“”“”ü•ˆ‡ˆˆ‰Š‹ýŒ‹ŒŒþŒŽûŽû‘‘‘’“”‡ýˆ‡ˆˆû‰ˆ‰‰ŠŠü‰ŠŠ‹‹ŒŽùŽ‘’“”û†‡†‡ˆˆ‰ýЉŠŠ‹ýŒ‹ŒŒøŽŽŽŽö‘‘‘’’“ø”“††‡†‡ˆˆ‰Š‹þŠ‹‹ûŒŒŒŽý‘’“†‡ˆ‰Šü‰ŠŠ‹‹ýŒ‹ŒŒýŒŽüø‘‘‘’‘‘’’“þ…††‡ˆ‰Šþ‰ŠŠü‹Š‹ŒŒþŒŽýŽýû‘‘‘’’þ“……†‡ˆ‰Š‹Œþ‹ŒŒûŽŽŽöŽ‘‘‘’…†ú‡†‡ˆ‡ˆˆý‰ˆ‰‰Š‹ŒúŒŽŽŽ‘ú’‘’’„……†‡ˆ‰Šý‹Š‹‹Œþ‹ŒŒŽü‘‘‘„…ý†…††ô‡††‡‡ˆ‡ˆˆ‰ˆ‰‰Š‹Œú‹ŒŒŒŽüŽŽý‘„…†‡ˆü‰ˆ‰ŠŠ‹ýŒ‹ŒŒýŒŽýŽýü‘‘„„…†‡ˆ‰úЉ‹‹Š‹‹ŒýŽŽŽ‘„ƒò„…„…„…†…†…‡††‡‡üˆ‰ˆ‰‰Š‹úŒ‹ŒŒŽûƒƒ„…†‡ˆ‰øˆ‰Š‰‰Š‹ŠŠ‹üŒ‹‹ŒŒŽþŽŽ‚ƒ„…†‡ˆý‰ˆ‰‰Š‹ŒûŽŽþƒ‚‚ûƒ„„ƒ„„…†‡ýˆ‡ˆˆ‰Š‹Œþ‹ŒŒŽýŽ‚ƒ„…†‡ýˆ‡ˆˆú‰Š‰Š‰ŠŠ‹ýŒ‹ŒŒŽþ‚‚ƒù„ƒƒ„…„……†‡ˆü‡ˆˆ‰‰ôЉ‰ŠŠ‹Š‹‹Œ‹ŒŒŽ÷Ž‚‚‚‚ƒ„þƒ„„…÷†…†‡‡†‡†‡‡ˆ‰ýЉŠŠ‹ŒŽ‚þ‚‚ýƒ‚ƒƒ„…†‡ˆ‰ýˆ‰ŠŠ‹ŒŽþ€ü‚‚‚ƒ„ø…„„…††…††‡ˆþ‡ˆˆ‰Šú‹Œ‹ŒŒüŽ€€ý‚‚‚ƒû„ƒ„ƒ„„…ø†…†…†‡†‡‡ˆ‰Šý‹Š‹‹ŒûŒ€€þ€‚ûƒ‚ƒƒ„„…†‡ˆþ‡ˆˆ‰Š‹Œþ€€ü€€‚ƒ„…ú„……†…††‡ý†‡ˆˆ‰þˆ‰‰Š‹ŒþŒ€‚ƒ„…†‡ýˆ‡ˆˆ‰Š‹Œú~€€€ý‚‚‚ûƒ„ƒƒ„„…†‡üˆ‡‡ˆˆ‰ýЉŠŠý‹Š‹‹üŒ~~€ý€‚ýƒ‚ƒƒ„ý…„……ý†…††‡þ†‡‡ˆù‰ˆ‰‰Š‰ŠŠ‹ùŒ‹‹~~ý€€€ý‚‚‚ƒþ‚ƒƒ„û…„……††‡ýˆ‡ˆˆ‰Š‹~€ü€€‚ƒ„…†û‡†‡‡ˆˆ‰Šþ‰ŠŠ‹~€þ€€ú‚‚‚‚øƒ„ƒ„ƒ„„……û†…†…††‡ˆ‰üˆŠ‰ŠŠû‹}~}~~ý~þ€‚ú‚‚ƒ‚ƒƒý„ƒ„„ù…„……†…††‡ˆþ‡ˆˆ‰Š‹}ý~}~~€ý‚‚‚ƒ„ú…„„…„††‡þ†‡‡ˆ‰Šý‰Š||}ý~}~~€ý€‚ƒ„…†ù…††‡††‡‡ˆ‰úЉ‰}|}}~€ü‚ƒ‚ƒƒû„ƒ„„……†‡÷ˆ‰ˆ‰ˆ‰‰{||}~€ü‚‚‚ûƒ‚ƒƒ„„û…„……††ý‡†‡‡ˆù‰ˆ‰‰{{||}~€‚ýƒ‚ƒƒ„û…„…„……†‡ˆû‰ˆ{{||û}|}|}}~€ý€ý‚‚‚ƒö„ƒƒ…„„…„…††ó‡†‡‡ˆ‡‡ˆˆ‰z{||}~€û‚ƒƒ‚ƒƒ„…†ü‡††‡‡ˆüz{z{{|ü}||}}~ø€€€€€‚ƒ„ü…„„……†ý‡†‡‡ˆøz{z{{|{||}~€‚ö‚ƒƒ‚ƒ„ƒƒ„„…†ô‡ˆyzz{z{|{{||}~€‚ƒý„ƒ„„…þ†……†ú‡†‡‡yzz{|}~ý~€‚ƒø„ƒ„„…„„……†ç‡yzyzz{zz{{|{{||}||}~}~}~~€ý€ý‚ƒƒú„ƒ„…„……†ù…††xyzyyz{ý|{||}ý~}~~€‚ƒ„…þ„……†yzþyzzý{z{{|}þ|}}~ý€€€‚ýƒ‚ƒƒ„…ÿÿ—ý˜—˜˜™š›œùžžžŸžŸŸ ý¡¢¡¡¢£û¤£¤¤$$þ–——˜™š›œþ›œœžŸý Ÿ  ¡ý ¡¢¢£û¤£¤¤$$–—˜û™˜™™šš›üš››œœžŸ û¡ ¡¡¢¢£$ö•–——––—˜—˜˜™ùš™šš›š››œøœœžžžžŸý¡ ¡¡¢ý£¢££$–—ý˜—˜˜™š›œùœžžžŸ ¡¢£$û•––•––—˜™š›ýœ›œœ÷žžžžŸžŸŸ ¡¢þ£$$þ”••ý–•––ü—˜—˜˜™ü˜™™šš›ýœ›œœýœžŸ ¡¢$”•–—˜þ—˜˜™šý›š››œžŸ ¡ý¢¡$$”•–—ú˜——˜˜™™š›þš››œžýžŸŸ ý¡ ¡¡$þ“””•–ø—–—–—˜—˜˜ö™˜™™š™™šš››œòžžžŸžžŸŸ Ÿ  ¡¡$ü“”“””•–ý—–——˜™šý›š››œžŸ þ¡$$ø’““”““”••ý–•––—˜™šý›š››œžŸ $þ’““ý”“””•–ø•–——–——˜˜ý™˜™™šö›š›œ›œœœžŸ $’“”•–ü•––——˜™š›œýžžžýŸžŸŸ$ù‘’’““’““”•–—˜™šû›š››œœžýŸžŸŸ$ü’‘’““”ü“””••–þ•––—ü˜——˜˜™š›œüœžžŸ$‘’þ‘““þ”““”•–—˜þ™šš›ûš›œ›œœžýŸž$$‘’“ý”“””ú•””••––—˜ý™˜™™š›œöœœžžŸ$$þ‘‘’“ý’“””•–ý—–——û˜—˜˜™™šý›š››œýž$$ö‘‘‘‘’’‘’’“”•ü–•–——˜™šû›œ››œœýœ$‘ý’‘’’“”•–—ò˜—˜™™˜˜™™š™šš››ýœ›œœ$þ‘ý’‘’’“ý”“””•–—˜™š›ýœ›œœ$ý‘‘‘’ý“’““”•–—˜™š›œ$Ž‘’þ‘’’“”ú•”•–•––—ü˜——˜˜™šþ™šš›þœ$$üŽŽý‘‘‘’“”•–—˜ø™˜˜™™š™šš›þš››$ŽýŽ‘’ü“’’““”•–—þ–——˜™š›$ŽýŽ‘ý’‘’’“ü”•”••–ý—–——˜™šý›š$$ŽüŽû‘‘‘’’“ý”“””•û–•––——˜™šþ›$$ŽùŽ‘ü’“’““”•–ô—–—˜—˜—˜˜™˜™™š$ýŒŽŽõŽ‘‘‘’“ø”““””•”••–—˜™üš™š$$ŒùŒŽŽŽ‘’ú“’’““””•–ý—–——þ˜™™$ŒýŒùŽŽŽ‘þ‘‘’“”•–—ý˜—˜˜þ™$$ýŒ‹ŒŒùŽŽŽŽ‘’“”•ý–•––—˜þ™$$‹ýŒ‹ŒŒùŒŽŽŽüŽü‘‘‘’“”•–ü—˜—˜˜$‹ŒŽ‘þ‘‘’“”ø•”••–••––—þ˜$$øŠ‹‹ŠŒ‹‹ŒŒûŒŽŽú‘‘’“”•–ý—–——þ˜$$Šý‹Š‹‹ŒŽ‘ý’‘’’“”•÷–•––——–—$$‰Š‹ŒŽý‘’ü“’“””•–—$‰Š‹ŒùŒŽŽŽûŽú‘‘’‘’’ý“’““”•–þ•––þ—$$ûˆ‰Š‰ŠŠ‹ŒýŒûŽŽŽý‘‘‘’“”•û”••–••þ–$$þˆ‰‰óЉ‰Š‹ŠŠ‹‹Œ‹‹ŒŒŽ‘’“”•ý–•$$ˆ‰óŠ‰Š‰ŠŠ‹Š‹ŒŒ‹ŒŒûŽŽŽü‘‘‘’“”ü•””••þ–$$þ‡ˆˆ‰Š‹Œü‹ŒŒŽý‘‘‘’“ú”““””••$ü‡ˆ‡ˆˆ‰Š‹ŒŽýŽ‘ö’‘’’“’“”“””þ•$$û‡ˆˆ‡ˆˆ‰Š‹ýŒ‹ŒŒýŒŽùŽ‘ù’‘’’“’““ú”“”•”$$‡ùˆ‡ˆˆ‰ˆ‰‰Š‹ŒýŒŽ‘’“”$þ†‡‡ˆþ‡ˆˆû‰Š‰‰ŠŠ‹ŒŽúŽ‘ø’‘’’“’’““$†‡þ†‡‡ˆ‰úˆ‰ŠŠ‰ŠŠ‹ùŒ‹ŒŒŒŽøŽŽ‘’“”$†‡ˆý‰ˆ‰‰Š‹ŒûŽŽô‘‘‘’‘’’“$…†‡ø†ˆ‡ˆ‡ˆˆ‰‰Š‹ŒŽþŽõ‘‘‘‘’‘’’þ“$$…†ø‡†‡‡ˆˆ‡ˆˆ‰ýЉŠŠ‹ŒŽö‘‘‘‘’’$þ„……†ý…†‡‡ûˆ‰ˆˆ‰‰Š‹ŒŽ‘’$„…ý†…††‡ˆ‰þˆ‰‰Š‹ŒýŽŽŽýŽù‘‘‘’‘$$úƒ„„…„……†‡ˆ‰Šû‹Š‹‹ŒŒŽþŽŽ‘$ƒ„…†‡ýˆ‡ˆˆ‰Šû‹ŒŒ‹ŒŒýŒŽ$ƒý„ƒ„„ü…†…††‡þˆ‰‰Š‹ýŒ‹ŒŒŽý‘$$ƒ„ù…„…††…††‡ˆ‰øŠ‰Š‹Š‹‹ŒŒŽ$ü‚ƒ‚ƒƒ„ý…„……†‡øˆ‡‡ˆˆ‰ˆ‰‰Š‹ŒŽ$‚ûƒ‚ƒƒ„„ü…„„……†ý‡†‡‡ˆõ‰ˆ‰‰Š‰Š‹ŠŠ‹‹üŒ‹ŒŽþ$$ü‚ƒ‚ƒƒ„ü…†…††ü‡††‡‡ˆ‰þˆ‰‰öŠ‰ŠŠ‹ŠŒ‹‹ŒŒýŒŽþ$$ú‚‚‚ƒƒø„ƒ„…„……††‡ˆ‰Š‹ŒŽûŽŽ$$ú‚‚‚ƒƒ„…û†……†‡‡ˆ‰ýЉŠŠú‹ŠŠ‹‹ŒŒýŒûŽŽŽ$$‚ƒ„…ü„…†……ý‡†‡‡ˆ‰Š‹ýŒ‹ŒŒŽ$€ý‚‚‚ƒ„ø…„…†…†…††ˆþ‡ˆˆ‰Š‹ŒýŽ$$›œþ›œœýžžžŸ ¡þ ¡¡ú¢¡¢£¢££þ¤¥¥¦§$›ýœ›œœûœžþžŸŸýžŸ  ý¡ ¡¡ü¢£¢££ý¤£¤¤¥¦þ¥§§$üš›š››œžüžžŸŸý Ÿ  ¡¢ø£¢££¤¤£¤¤¥¦$š›œþ›œœžŸ ¡¢ý¡¢££¤¥¦$ú™š™šš››œžýŸžŸŸ ¡ú¢¡¡¢£¢¢£¤¥û¦¥¦¦$$ýš™šš›œýœžŸý Ÿ  ¡¢£¤¥þ¦$$™šý›š››ýœ›œœüžžžŸ ¡¢£ø¤££¤¥¤¤¥¥$þ˜™™šý›š››ýœ›œœúžžŸžŸŸý Ÿ  ¡¢£ý¤£¤¤¥$ý™˜™™š›üš››œœžŸ ¡£¤¥$˜™š›œžŸþžŸŸ ý¡ ¡¡¢ü£¢¢££¤$ú˜—˜™˜™™š›œžùŸžŸŸ Ÿ  ¡¢£¤$ý˜—˜˜™šø›š››œ››œœžŸý Ÿ  ¡ü¢¡¡¢¢ù£¢¢£¤¤$$û—–——˜˜™š›œžŸ ¡¢û£¢££$$û—–——˜˜ý™˜™™šý›š››œþžþžŸŸ ûŸ¡  ¡¡¢û£¢££$$ü–—–——˜ù™˜™™š™šš›œýœžŸý Ÿ  ¡¢$û•–—–——˜™š›œþ›œœüžŸžŸŸ ü¡  ¡¡ý¢¡¢¢$–ö•—–—–——˜—˜˜™šý›š››ýœ›œœüžžžŸ ý¡ ¡¡þ¢$$ý–•––ú—––——˜˜ý™˜™™ùš™šš›š››œôœœžžžŸžŸŸ ¡ý¢¡$$•û–—––——˜™šû™š›š››þœžŸ ü¡ ¡$$þ”••–ý—–——˜™šþ™šš›œöœžžžŸžžŸŸ ü¡  $$ü”•”••–—ü–——˜˜™šþ™šš›œžŸý Ÿ  $þ“””•–—ü˜—˜™™õš™™šš›šš››œœžýŸžŸŸ $“”•–—˜™ýš™šš›œžŸ þŸ$$“”ø•”••–••––—˜ú™˜™š™šš›œþ›œœùœžžžžŸ $ý’“””þ“””•–ö•–—––——˜—˜˜ý™˜™™š›õœ›œœžžžýŸžŸŸ$“”þ“””•þ”••–—˜™ýš™šš›üœ››œœžŸ$’“”•–ý—–——˜ý™˜™™šý›š››œøœžžžž$’“”ú•”•–•––—˜û™˜™™šš›œûžžž$$þ‘’’“ý”“””ø•”•–•––——˜û™˜™™šš›ýœ›œœ$þ‘’’“ú’““”“””•–—˜™š›œýž$$‘’“”•–—ü˜——˜˜™š›œ$‘’ó“’“’“”“”“”•”••–—˜™šý›š››œþ$$‘ù’‘’’“’““”•”•–—˜þ—˜˜™ñš™š™šš››š››œ›œ$ö‘’’‘’‘’’““”þ“””•ú–••–•––—˜™øš™šš›šš››œ$ü‘‘’þ‘’’“”ý•”••–—˜™šý›š››þœ$$þ‘ü’‘‘’’“”•–—˜ø—˜™˜˜™™šš÷›š››š›œœ$$ý‘‘‘ý’‘’’“”•”ù•–•––—––—˜þ—˜˜™šû›š››$$þŽ‘’“”•–—˜™ýš™šš›$üŽŽ‘’“”•ý–•––û—–——˜˜™šû™šš›$$ŽýŽû‘‘ü’‘‘’’“”ü•””••–—˜™š$ýŽŽŽ÷‘‘‘‘’“ú’““”“””ú•”•–•––—˜™š$Ž‘ü’‘‘’’ý“’““”•ý–•––—˜™ýš™$$ýŽŽŽý‘’ø“’““””“””•–—˜™$ùŽŽŽŽ‘’“”ø•”•”•–•––—˜™$ŒŽö‘‘‘‘’’“ý’“””•ý–•––ü—–—˜˜$ŒüŒŒŽù‘‘‘ù’‘’’“’““”ü•”•––ý—–——ý˜—˜˜$ŒúŒŒŽŽýŽù‘‘‘‘ý’‘’’“”ü“””••–—ü–——˜˜$‹ŒýŒŽý‘‘‘’ü“’’““”•–—$‹ŒýŒŽ‘’“”þ“””•–—$ý‹Š‹‹ŒþŒýŽŽŽý‘’“ü”““””•–—$Šû‹Š‹‹ŒŒþŒŽý‘‘‘’ý“’““”û•”–•––$Šý‹Š‹‹üŒ‹‹ŒŒŽ‘ý’‘’’“ý”“””•–$‰ýŠ‹ŠŠü‹Œ‹ŒŒüŽŽŽ‘ú’’‘‘’’“”þ“””•ü”••––$Šþ‰ŠŠ‹ŒŽúŽ‘’“ü”““””•þ–$$‰Šù‹Š‹Š‹‹ŒŒýŒŽ‘’“”ý•”••$þˆ‰‰Š‹üŠ‹‹ŒŒýŒŽýŽø‘‘‘’“û”“””••$þˆ‰‰Š‹ýŒ‹ŒŒøŽŽŽŽ‘’“”þ“””þ•$$ˆý‰ˆ‰‰Š‹ýŒ‹ŒŒŽú‘‘‘‘’“”$ýˆ‡ˆˆ‰Š‹ŒüŒŽŽý‘’û“’““””$‡ˆ‰Šò‹ŠŠ‹‹Œ‹‹ŒŒŒŽþŽ‘’ý“’““$‡ˆ‰ûЉЋŠŠ‹ýŒ‹ŒŒŽü‘‘‘’ý“’““þ”$$†‡ˆü‡ˆˆ‰‰þЉ‰Š‹ôŒ‹‹ŒŒŒŒŽŽö‘‘‘’’‘’’““$‡õ†‡‡ˆ‡ˆˆ‰‰ˆ‰‰Š‹úŒ‹‹ŒøŽŽŽŽ‘þ‘‘’“$ü…††‡‡ˆ‰üЉ‰ŠŠ‹üŒ‹‹ŒŒþŒŽ‘ü’“’$$;ÿz;ÿz;ÿzþyÿ:ÿûzyyzÿ:ÿþzyy;ÿþzyy;ÿy;ÿyþxÿ:ÿy;ÿûyxyyÿ:ÿxýyxÿ:ÿx;ÿþyxx;ÿx;ÿþyxx;ÿx;ÿþwxx;ÿx;ÿþxww;ÿûxwxwÿ:ÿþxww;ÿþxww;ÿw;ÿwþvÿ:ÿwþvÿ:ÿw;ÿþvww;ÿþwvv;ÿv;ÿþwvv;ÿvýuvÿ:ÿvþuÿ:ÿvþuÿ:ÿvþuÿ:ÿvu;ÿvýuvÿ:ÿu;ÿu;ÿuþtÿ:ÿu;ÿu;ÿuýtuÿ:ÿûtuttÿ:ÿt;ÿþutt;ÿt;ÿt;ÿt;ÿþtss;ÿtþsÿ:ÿsýtsÿ:ÿs;ÿs;ÿs;ÿûsrssÿ:ÿsþrÿ:ÿsýrsÿ:ÿþsrr;ÿþsrr;ÿr;ÿrþqÿ:ÿr;ÿûrqrqÿ:ÿþqrr;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<z<üzyy;y<y<üzyy;yþx;yþx;x<üyxx;üyxy;x<x<x<x<x<üxwx;üxwx;w<w<w<w<w<üwvw;wþv;üwvw;wþv;v<v<vþu;vþu;üuvu;u<üuvu;uþv;u<u<u<uþt;tþu;tþu;ütut;t<t<ütst;üstt;t<t<ütst;ütss;s<s<s<s<sþr;rþs;r<r<r<r<ürqr;r<rþq;üqrq;ürqq; @ @ @ @ $YZ[\]^ù_^^_`_``aúbabbc $þXYYZ[ý\[\\]^ý_^__`aübac $XYýZYZZ[ý\[\\]^ý_^__`ýa`aaþb $WXYZý[Z[[û\]\\]]^ý_^__`a $þWXXýYXYYZ[\]û^]^^__`a $ýWXWWXYZ[ö\[\\]\\]]^^_`þa $þVWWXYZý[Z[[\ý]\]]^ý_^__`þa $ýWVWWùXWXYXXYYZ[\]^_û`_`` $VWXYZü[ZZ[[\û]\]]^^_þ` $þUVVýWVWWXYZ[ý\[\\]^_ $UVýWVWWXýYXYYöZYZZ[ZZ[[\\ý]\]]^_ $UûVUVVWWXYZý[Z[[ü\[\]]^ $þTUUøVUVUVWVWWXþYXXûYZZYZZ[ô\]\\]]^^]^^ $ûTUTTUUVýWVWWýXWXXYZ[þZ[[\]þ\]]þ^ $TUVWýXWXXYýZYZZ[\]þ^ $SüTUTUUVüWVVWWXýYXYYZ[\] $STUVýWVWWýXWXXYZ[\] $þRSSTUVWXöYXYXZYYZZ[[\ $ûRSSRSSTUúVUUVVWWýXWXXYZ÷[Z[\[[\\ $RSTþSTTUVWXYZ[þ\ $QRSTýUTUUVXYýZYZZ[ $QRSTUýVUVVùWVWWXWXXYZ[ $úPQQRQRRSýTSTTUVWXYZ $PQRSýTSTTUVWXýYXYYZ $þPQQýRQRRSTUVWüXWWXXYüZYZ $úOPPQPQQRSTUþVUUüVWVWWXýWXYYýZY $PQRSTUVWVWýXWXXY $ùOPOPPQPPüQRQRRSTUVýWVWWXüYXX $NøOPOPOPPQQùRQRRSRSSýTSTTUVþUVVûWVWWXXþY $þNOOPùQPQQRQRRûSRSSTTýUTUUVýWVWWX $NOúPOPOPQQRøSRSSTSTUUVWúVWXXW $NOýPOPPQûRQRRSSTüSTTUUVûWVWW $MNOPýQPQQRSTUVW $MNOôPOOPQQPQQRQRRSTUV $þLMMNOPýQPQQRýSRSSTUV $þLMMNýONOOPQRSTUV $LMõNMNNOONOPOPPQüRQQRRSTúUTUVV $þKLLMNOPQRüSTSTTU $üJKKLLMNOPüQPPQQRSTU $þJKKLûMLMMNNOýPOPPQRûSTSSTT $þJKKLMNýONOOPýQPQQýRQRRST $JKýLKLLMýNMNNOPQ÷RQRRSRSSTT $JKLMüNMMNNOPQRS $þIJJýKJKKLM÷NMMNONONPPýOPQQRùQRSRSS $üHIIJJKLýMLMMNOýPQPPQRýSR $ýIHIIJKLMNOûPQPPQQRþS $HIüJIJKKLMNOPüQPPQQüRQR $HýIHIIJûKJLKLLMNOýPOPPýQPQQþR $HIJKLMþLMMNOúPOPQPQQ $GHIJKLMNOPQ $þFGGHüIJIJJKLMýNMNNOP $GýFGHHIJýKJKKLMýNMNNOP $FGHIJKþJKKþLMMþLMMNOýPO $FGHIJKýLKLLýMLMMNO $EFGHôIHIIJIJJKJJKKLMNO $üEFEFFGHýIHIIJKLýMLMMNO $þDEEFúGFGHGHHIJKLMN $üDEDEEFGùHGHHIHIIýJIJJKLMN $DýEDEEFýGFGGHIJùKJKKLKLLMN $DýEDEEFýGFGGHIJK÷LKLMLLMM $CDEFGHýIHIIJKLüMLM $CDEFûGFGGHHIJKýLKLLþM $ýCBCCDüEDDEEFGHIJKL $BCDEùFEFGGFGGHIJKþLK $þabbcdeôdeefeefgfgfgghýihiijþk $abcþbccýdcddefþeffghij $abücbbccdefgþfgghihij $÷`aabbaacbbcdefûghgghhýihii $`aýbabbýcbccýdcddefghiühii $`ýa`aabcdefghi $þ_``ýa`aabúcbbccddýedeeýfeffgýhghhþi $_`abýcbccdûedeeffgûhghh $_`ýa`aabcñbccdcdeddeeffeffgh $ò_^__`__``a`aabbcdýedeefþeffgh $^_`û_``a``aûbabbccdeýfeffúgffgg $^_`aý`abbcdeýfeffügff $þ]^^_`_`abcdefþg $ù]^]]^^__ý`_``ùa`abaabbûcbccddeýfeff $]^_`ýa`aabcdef $ý]\]]^_ù`_``a`aabcýdcddeýfe $ø\]\]]^]^^÷_^_``_``aabýcbccdeþdee $\]ý^]^^_`abcdþe $[\ý]\]]^_`abûabcbccýdcddþe $þ[\\]^_`abcûbcdcdd $üZ[[\\ý]\]]^_`aùbabbcbccd $[û\[\\]]ý^]^^_`abcþd $Z[û\[\[\\]ý^]^^_`ýa`aabûabcbcc $Z[þZ[[\ý]\]]^_`abþabbc $Zû[Z[Z[[\ý]\]]^ú_^^__``aùbabcbb $Z[ü\[[\\]ý^]^^ý_^__`ab $YZ[\]ü^]]^^_`a`aþb $YZøYZZ[Z[[\\]^ù_^_`__``aýba $þXYYZþ[ZZ[\þ[\\]^_^_`a $XýYXYYýZYZZý[Z[[ý\[\\]^_`a $þWXXýYXYYZ[ý\[\\]û^]^^__` $ýXWXXYýZYZZ[ý\[\\]ý^]^^_`þa $öWXWXWXYYXYYZ[\]^_ù^`__`` $WXýYXYYýZYZZ[\þ]\\]^_ $VWXYþXYYZ[\]^_þ` $VûWVWXWWXæYXXYYZYZZ[[Z[[\[\\]\]]^]]^^þ_ $VWXYýZYZZ[\]^þ_ $üUVUVVWXþWXXYZ[\]^ $ûUVUUVVWXYýZYZZý[Z[[\ý]\]]ý^] $UVýWVWWýXWXXýYXYYZ[ö\]\\]]^]^ $UVýWVWWXYZ[\ù]\\]]^ $þTUUVWþVWWXYZ[\] $TUýVUVVWXYüZYYZZ[\] $þSTTUüVUUVVþWXXYZ[ý\[\\ $SùTSTUTTUUVþUVVWXYZþ[ZZ[ü\[\ $STUüVUUVVWXýYZYYZ[\ $þRSSTUûVUVVWWýXWXXóYXXYZYZYZZ[Z[[ $RSTUVWXYZ[ $øRQRRSSRSSTUVùWVWWXWXXYZþ[ $þQRRSøTSTUTUTUUüVUUVVWXYZþ[ $QRSýTSTTýUTUUVýWVWWXYZ $QRýSRSSøTSTTUTTUUûVUVVWWýXWXXY $PQRýSRSSTýUTUUVWüVWWXXùYXYXYY $PýQPQQRSTUVWXýYXYY $PQRSTUVWXY $ùOPPOPPQQRSýTSTTUðVUUVVWVVWWXXWXX $OPüOPPQQRSTUVöWVVWXWWXX $OýPOPPQRSTUVøWVVWXWX $üNONOOýPOPPQRSTUøVUUVVWVWW $NOûPOPOPPQRüSRRSSúTSTUTUUVWýVW $MûNONNOOüPOPQQRSTUþVUUVýWV $NþMNNOPQRSTUýVUVV $MNûONONOOþPQQRòSRSSTSTUUTTUUVV $ûMLMMNNOPQRSýTSTTûUTUUVV ø‰ˆˆ‰ˆˆ‡ÿ*ÿ þ‰ˆˆ+ÿ ˆý‡ˆÿ*ÿ ˆ‡+ÿ ˆü‡ˆ‡ÿ*ÿ ˆþ‡ˆˆþ‡ÿ*ÿ ˆ‡+ÿ þˆ‡‡+ÿ ‡+ÿ ‡þ†ÿ*ÿ ‡+ÿ ‡†+ÿ þ†‡‡†þ‡ÿ*ÿ ‡†+ÿ †‡†+ÿ þ‡††+ÿ þ‡††+ÿ †þ…ÿ*ÿ †û…††…ÿ*ÿ ø†…††…†…ÿ*ÿ ø…†…†…††ÿ*ÿ †…+ÿ ý…†……+ÿ †…+ÿ …+ÿ þ†……þ„ÿ*ÿ …þ„ÿ*ÿ …„+ÿ þ…„„þ…ÿ*ÿ „…þ„ÿ*ÿ þ…„„+ÿ þ…„„+ÿ „ýƒ„ÿ*ÿ „üƒ„ƒÿ*ÿ „ƒ+ÿ „ƒ+ÿ ýƒ„ƒƒ+ÿ þ„ƒƒ+ÿ ƒþ„ƒƒ+ÿ ƒü‚ƒƒÿ*ÿ ƒþ‚ÿ*ÿ ƒ+ÿ ýƒ‚ƒƒþ‚ÿ*ÿ øƒ‚ƒ‚‚ƒƒÿ*ÿ ‚ýƒ‚ÿ*ÿ ‚+ÿ ‚+ÿ ‚+ÿ ‚ý‚ÿ*ÿ ‚ü‚ÿ*ÿ ø‚‚‚ÿ*ÿ ‚ý‚+ÿ ý‚+ÿ +ÿ +ÿ þ‚€+ÿ €+ÿ €þÿ*ÿ €+ÿ þ€€+ÿ €+ÿ þ€€+ÿ €þÿ*ÿ €þ€€þÿ*ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿïcbcdccddeddefeffgghûihiijjkülkkllmûnmnnooüpopqqbcýdcddúedefeffghijýkjkkölkllmlmnmnnoýpoppýqbccýdcddefgûhgihiijklmýnmnnopýqabbcdcdefüghghhijûkjkkllmþlmmnoþnooþpaabcdócdeedeefefgfggýhghhiýhijjýkjkklmùnmnonnooþpaaùbabcbbccdefghüihhiijklýmlmmnùonoop`aabcdøedeefeeffýgfgghijükjjkklmnùmonoo`aabcdefgýhghhýihiijøijjkjkkllmnùo``aa`aabcýdcddefghijklþkllmúnmnn_``÷a``aabaabbc÷dcdeddeeffþghhijkëlklkllmlmmnn__`_``a`aabücbcddefgõfgghhghhihiijküjkkllýmlmmü_^_``aýbabbcdefýgfgghûihiijjklm^þ_``abýcbccdeøfeffgffgghijklþm^^_`abcdýedeeûfeffgghijkl^ù_^__`_``ûa`aabbûcbcdccdeûfeffggýhghhijñkjkklkll]]^^_^__`abþabbcdüedeffýefggýhghhiüjiijjkølk\]^^]^^ò_`_``a``aabbabbcûdcddeefþgffghýihiijkû]\]]^^_`aýbabbcdeýfefføgfghghhiijkñjk\\]]^]^]^_^^__`aùbcbbccddûedeeffgýhghhijþk\\]^ý_^__`abcdýedeefýgfgghüihhiijù\[\]]\]]^_`ýa`aabcdûededeefghij[\]ü\]]^^û_^__``úa`a`abbúcbbccddefgûhghhii[\ü]\\]]^_`ûa`aabbcdefýgfgghi[øZ[\[[\\]]^ù_^__`_``abcdþefføgfghgghiiZü[\[\\]þ^__ü`__``aübaabbcdeþdeefghZ[ý\[\\]û^]^^__`abcdefóeffgfgghghhYZZý[Z[[\ø[\\]\]]^^ö_^__`__``aabcýdcddefgýhXYYZ[\]^_`ûa`aabbcdúedefeffýgfggþXYYýZYZZ[\]^_û`a``aabùcbccdcddef÷gfXXYYZYZZ[ü\[\]]^_`ýa`aabcüdccddefûgfWXYYZ[\]^ý_^__`abcûdcdcddeûfefgXXYýZYZZù[Z[[\[\\]^_ý`_``aûbabbccdeüfWWXXYZ[\ý]\]]^_`abcýdcddefWXýYXYYZ[üZ[[\\]^_`abúcbdccddeWúXWXYXYYZ[\]^_ü`_`aaübaabbcdVWýXWXXYZ[\ý]\]]^ù_^^_`_``abcdVWXûYXYYZZ[\]ý^]^^_û`a``aabcùdcddUUVVWXûYXYXYYZ[\]^ý_^__`abýcbccþdUUVWXYZý[Z[[û\[\\]]^_õ`__``a``aabbýcbccýdTUUVWûXWXXYYZ[\]^_`abþabbcUTUVWXYþXYYZ[\]^_`abþTUUVüWVVWWXYZ÷[Z[[\\[\]]ý^]^^_ú`__``aabüTSTUUVýWVWWXYZ[\]ñ^]^__^__`_``a`aaübabTTUVWXYôZYZZ[[Z[[\[\\]^_ü`__``aþbSSTñUTUVUVUVVWWVWWXXYZý[Z[[\]^`þ_``aSTUVýWVWWXýYXYYZ[\]^ù_^_``_``üaRRSSTUýVUVVWXYZ[\ø]\\]]^]^^_ü`__``þQRRSýTSTTUVWXYZ[÷\[\\]\]]^^õ_^__`__`RQRRSTUVWüVWWXXYþXYYZ[\]^_ý`_QQRSTUúTUVVUVVWXþWXXYZû[Z[[\\]^_QRSTUVWXûYXYYZZ[\î[]\\]\^]^^__^__PPQQRSûTUTTUUVýWVWWXYZ[\ü]\\]]^þ_PPQþRQQþRSSTUVýWVWWXYZ[\ú]\]^]^^PQúRQQRRSSýTSTTUVWXYZý[Z[[\]þ^OOPýQPQQRSýTSTTUVýWVWWXYùZYZZ[Z[[\ü]\\]]þ^OOPQRSTUVWüXWWXXYZüYZ[ZZù[\[[\\]]þNOOPúQPPQQRRSTUVWýXWXXûYXYYZZ[ý\[\\]ùNONNOOPPQþPQQRSûTSTTUUVWXYZ[\NOüPOOPPQRþQRRüSRSTTýUTUUVWýXWXXYZ[\NýMNOOýPOPPQûRQRRSSTüUTUVVúWVVWWXXYZ[û\[\MNNOPþQRRüSRRSSTUVWþVWWXYZ[MNOPýQPQQõRQQSRRSTTSTTüUTUVVWýXWXXYúZYYZZ[[ýMLMMóNONONOPPOPQPQQRSTôUTUTUUVVUVVWWXY÷ZYYZZ[[LMMýNMNNOüNPOPPýQPQQRSþRSSTUVýWVWWXYZklþkllmnop÷qppqqrqqrrûsrssttýutuuvñwvwwxwxxjjkklkllmnopqrúsrrssttuvwþxjjkýlkllýmlmmnopqýrqrrstüuvuvvwþijjkülkkllümnmnnýonooûpqppqqrstuvwývwjjýkjkklýmlmmnopqrýsrssûtstuttývuvvþwiijkýlkllmnopøqppqqrqrrýsrssûtsttuuvùwhiijijjklýmlmmnoúnoopoppqrstùsttuttuuvþhiijklùmlmmnmnnopqrstuþtuuhijýkjkklmünmmnnopqrýsrsstþsttuütuuhhùihijjijjküjkkllmþlmmnopqrûsrsrsstuýhghhijkýlkllmnopoüpqpqqrstúuttgghhijþkllþkllmnýonoopqýrqrrstþugghijýkjkkülkkllmnþmnnoýpoppqrûsrssttûgfgghhijklmønmnnoonoopqrýsrsstügffgghiýjijjkýlkllmnopqrýsrssþeffghùihijjijjkýlkllþmnnopûqpqpqqrsefgþfgghijûkjjkllþkllmúnmmnnooúnoopoppqrûsreeffghýihiijýkjkklmönmnmnoonnoopqrefùgfgfgghhiûhijijjkùlklmmlmmnoþnoopqrýedeefgþfgghijúijjkjkklmýnmnnopqþpqqdefghøghihiihiijkýlkllmnðonooppopqppqqrcddefýgfgghijklmnopqdüeddeeýfeffýgfgghijklmnoýpoppòqdccdcededefeffghýihiiûjkjjkklýmlmmnoúpoppqccûdcddeefghøihihijijjkýlkllmþnmmnopþbccdeúfeeffgghiýjijjklmülmmnnýonooübcbccdefgùhghhihiijklmünmmnnöonoopbbcbccdefùgfgfgghhijökjkklkklmllmnõonooababcbccdef÷gfgfhhgghhijýkjkklmnþmnnüoaabbcdeùfeffgfggýhghhijýkjkklmnþoaabýcbccdüeddeefýgfgghýihiijþijjüklkllþmllmnabücbbccdûedeeffûegffgghijþijjklm`abcübccddýedeefgúhgghhiijklúkllmlmm`aùbabbcbccdefghiþhiijklúmllm_``ûa`aabb÷cbcbcdccddeýfeffýgfgghijýkjkklûml__``ýa`aaòbabbcbccddcddeefghþghhiüjiijjklþm__ý`_``abcûdcddeefþeffýgfgghiþjkklþ^__`üababbcüdccddýedeefgýhghhúihijijjýkjkkþ^__`_`abcdeþdeefþgffþghhijùkjkkll^^ý_^__`abùcbcbccddýedeefghijk]^_`a`abcdüefeffûgfgghhùihiijijj^ý_^__`aýbabbcdeüfeeffghij]^_`abcúbccdcddefýgfgghýihiij]^ì_^_`_`_`a``aabaabcbccdefghiûj\]\]]ý^]^^_`üa``aabcüdccddeþfeefgþhgghi\ý]\]]^_`aý`abbýcbccdefghiþ[\\]^_`abcdefghûih[[\\]ü\]]^^÷_^^__`__``aûbabbccdefýgfggýhghh[\]ü\]]^^_þ^__ý`_``abcdefüghghhZ[ý\[\\ú]\\]]^^ù_^__`_``aþ`aabcdeýfeffgýhg[[\]^_`þ_``ûa`aabbýcbccýdcddeüfgfggøYZZ[ZZ[\\ý]\]]^_`abcdefgZ[\]^_ô`_`_`a`a`aabbcdefgþYZZ[ý\[\\]^ü_^^__`þa``abùcbccdcddýedeefYZ[ý\[\\ý]\]]^_`ö_`a`aabbabbýcbccdýedeeûfeffYYùZYZZ[Z[[\ý]\]]^_`ýa`aabcdeXYýZYZZ[\]þ\]]^ü_^^__`abcdeþfXXYZ[\]^û_^__``abýcbccdeXýYXYYýZYZZ[\]ý^]^^_`abþabbúcdcddeeüdWWXXøYXYZYZYZZ[\]^_ü`__``abcdWýXWXXYZû[Z[[\\]ý^]^^_ý`_``ýa`aabûcbccddWXþWXXYýZYZZ[\]^ý_^__`aýbabböcbccdcdVVWWXYúXYXYYZZû[Z[[\\]^_ý`_``abýcbccVWX÷YXYXYYZYZZû[ZZ[\\ý[\]]ü^]]^^_`abcÿÿqrsýtsttuvõwvvwxwxwxxyyþzyyz{|}ý~}~~€üpqqrrýsrsstuvwýxwxxyýzyzz{|ý}|}}ý~}~~pqrsýtsttuývuvvùwvwwxwxxyzû{z{{||}~ûpqpqqrûsrssttuývuvvwxyþxyyzý{z{{ý|{||}õ~}~~ppqqpqqýrqrrsøtstututuuvûwvwwxxyûzyzz{{|}~þoppqrsürssttuývuvvwýxwxxyzû{z{z{{|}~üopoppqrøsrrstssttuvwxyûzyzz{{|}oôpoppqqpqqrqrrýsrsstuövuvvwvvwwxxyzüyzz{{ý|{||}þnooýpoppqrstuvþuvvwûxwxxyyýzyzzþ|{{|}noüqppqqrüsrrsstþuttuvwxýyxyyzý{z{{|þ}nnopqpþqrrýsrsstuývuvvwxýyxyyz{|ý{mnnoýpoppqrýsrsstýutuuvüwvvwwxyüz{z{{þ|mmnopqrstuþtuuvwûvxxwxxyz{þlmmnoüpooppqrstuvwxyýzyzz{lmn÷opooppqpqqrstõsttutuuvuuvvwxyüzyyzzü{llmmýnmnnoúpooppqqrstuvwxyzlmnopýqpqqrsþrsstuvýwvwwxyþxyyklmnopq÷rqsrsrssttüuttuuvwxýyxyyklmnopqûrqrrsstuývuvvwxyýkjkklmnopqúrqqrrsstøuttuuvuvvwxjõkjklkllmmlmmnoûpoppqqrýsrsstuývuvvwüvwwxxjklþkllmünmmnnopqrstuvþxwwûxjjijjklmønmmnnonoopq÷rqrrsrssttuvwijøijkjjkkllmnopqörqrsrsststtuvwýxhiijklmn÷onopopqpqqrýsrsstuvwhi÷jijjkjkkllmnopqýrqrrstuvüwhhiijklmnopqrstuvgþhiijükjjkklûmlmmnnýonoopqrýsrsstuvghijklmnopqrstuùvfghhghhüijijjklmnoûnopoppqrstughiýjijjkýlkllümlmnnopqýrqrrstüuttffýgfgghijklmnopqrsñrsstsstteffgffgghijklmülmmnnýonoopýqpqqrsøtsttefeffghýihiijkølkllmlmnnýonoopõqpqqrqrrsrssýtdffghijýkjkklmùnmnnonoopûqpqqrrsýedeefýgfgghiîjijijkkjklkkllmmlmmnopýqpqqñrqrsrssddedfeeffghiýjijjklmnopöqprqqrssrddefûgfgghhiøhiijiijkklmýnmnnopúqppqqrrþsddýedeefghýihiiýjijjkýlkllmnopqýrcddeýfeffghijkýlkllmnoùpopqppqqcdøedeeffeffïghghghiihiijjijjkklmnopqöcbccddcddeeûfeefggýhghhiüjiijjkýlkllmnûonooppùqpbbcbccûededeefgüfgghhýihiijk÷jkklkkllmmýnmnnopüopqbbcdefg÷hghhiihijjkûlkllmmnopabcùdcdcddeefghijýkjkklmnopabüabbccdeþfeefúgffgghhiøhiijijjkkýlkllmnoýp`aabcdefýgfgghúihhiijjklmnoüna`aabýcbccdefýgfggþhiijýkjkklmùnmnnoo``abýabccdeófefgffghgghhiiüjiijjklýmlmmnûo_``aaýbabbcdefghýihiijkýlkllþmnný`_``abcdþcddefügffgghijúkjjkkllm_`abcdefghýihiijkülkkllmþ^__ý`_``aûbabbccdefúeffgfgghij÷kjkklklkllûm^_^__`øa`aababccdefýgfgghijûkjkkll^ý_^__`aübcbccdeýfeffghûihiijjûkjkkll^ý]^__`aýbabbúcbbdcddefgýhghhiþkjjkl]^_^_`abcdefgfüghghhijþijjk]^_`abcdefgþfgghijþk]]^_ü`_`aabcûbcdcddeüdeeffýgfgghýihiijúijkjk\\]ý^]^^_ü`__``abcdefýgfggñhgghhihiijijkj\\]^ý_^__`abþabbcdefghüghhiiûj\\[\\]^_`ùa`aababbcüdedeefgúhgghhii[\]û^]^^__`aýbabbcdýcdeefûgfgghhiýjZ[[\]ü^]]^^_þ`aabcüdccddefgüfgghhixyz{|}~€ü‚‚‚ýƒ‚ƒƒ„…þwxxyz{ý|{||}~ý~€ü‚‚‚ƒ„…xùyxxyzyzz{|ý}|}}~€ý€ý‚‚‚ƒú„…„…wxxyz{ý|{||}~þ}~~€ü‚‚‚ƒý„ƒ„„wxþwxxyýzyzz{|ý}|}}~€‚ƒ„þvwwxúyxxyyzzý{z{{|ý}|}}ý~}~~ý~ý€€€ý‚‚‚ƒñ„ƒ„wvwvwxwxwyxyyz{þz{{|}ø|}~}~~}~~€€ý€‚ƒû‚ƒƒ„vvwüxwwxxyz{|}~þ~€‚øƒ‚ƒ‚ƒuuvvwùxwxxyxyyz{÷|{|{|}||}}ý~}~~ü€€€‚þ‚‚uüvuvwwýxwxxýyxyyz{|}÷|}~}~}~€ý€ü‚‚‚uvýwvwwxyz{õ|{||}||}~}~~ú~~€€ý‚‚‚þtuuývuvvwûxwxwxxýyxyyz{|}~ý~€‚tuúvuvwvwwxyz{|}þ|}}~€ú‚ttutuuvwxúyxyyzyyý{z{{ý|{||}~þ~ý€€€ûtsttuuvwýxwxxyzü{zz{{|ø}|}}~}}~~€ù€€€sttuvwxyþxyyz{|þ{||}ù~}~~~€þsstuvwxyzý{z{{ý|{||}ü~}}~~ø€€srsttuvwxýyxyyzû{z{{||ý}|}}~þ~€ýsrsstuvwþvwwxyzþyzz{|}þ|}}~ü~~úrsrsrsstõutuuvuvuvvwwýxwxxyz{|}~ü~rrstuvýwvwwúxwxyxyyzþyzz{ý|{||}~÷rqqrrsrsstûutuuvvwxyz{|}ü|}}~~qûrqrrsstuývuvvwxýyxyyýzyzz{ý|{||ý}|}}~qýrqrrstuývuvvwxyzþyzz{|}þ|}}û~}ppqqrûsrssttýstuuývuvvwxyþxyyûzyzz{{|}pýqpqqrsþrsstýutuuvýwvwwxýyxyyzü{zz{{|}þoppqýrqrrstôuttuuvuvvwvwwxýyxyyz{|ý}oppýqpqqrþsrrstuvwxyz{|opýqpqqrùsrsststtuývuvvwxþwxxôyxyyzzyzz{z{{|oýpoppqrsþrsstuútuuvuvvwýxwxxüyxxyyz{þnoopqrüsrrssûtuutuuývuvvwxyøzyyzz{z{{þ|nnopqrþqrrstuvwüvwwxxýyxyyz{mnopqrstýutuuvýwvwwýxwxxyz{númnnonoopqùrqrrsrsstuþtuuvwxýyxyyzmýnmnnoýpoppqrqrsýtsttuvwüxwwxxyzþlmmýnmnnopüoppqqýrqrrýsrsstuvwxyøzyzzlmlmmønmnnonnoopýqpqqrýsrssýtsttuvuþvwwýxwxxylmýnmnnoõpoppqpqrqqrrstýutuuvwxýyxyyþkllmýnmnnopýqpqqrýsrsstuvwxüykkllmnúonnooppqøpqqrqrrsstuvøwvwwxwwxxklþmllmnùonoopoppûqpqqrrstþsttuvwxþjkklmnop÷qppqqrqqrrstuvuûwvwvwwþxjjklmnýonooþpoopqrsörsststtutuuvwjklmnýonoopüqppqqýrqrrsütssttuývuvvwüijjkklmþlmmnopýqpqqûrqsrsstþuttuvõwvwjijjkjjkklmnoýpoppqrs÷tsttutuuvvüwiijjöijkjkklkkllmünmmnnopqrstuvþhiijklmýnmnnopqrstüuttuuùvhihiijjþijjklmlmýnmnnýonoopqrûqrsrssütssttuvhýihiijklþmllýmnmmnoýpoppqûrqrrsstuûtuhghhiýjijjklùmlmmnmnnopüqrqrrstûutuuhhijklmnúononoppqrsýtsttþugghiýjijjklûmlmmnnopqrstþfgghiöhiijijjkjkklýmlmmýnmnnopýqpqqrsútssffggh÷ihhiijiijjýkjkklmønmnnonnoopqrsþrssüfgfggýhghhiþjiijkýlkllmnýonoopqrsùfefgffgghýihiijükjjkklmùlmmnmnooüpooppqýrqrrse÷feffgfgghhijklmnþmnnopqürqqrrüseeffgùhghhihiiûjijjkklmýnmnnopqrúdeefeffgùhghhihiiüjiijjýkjkklmnúonnooppqþreefügffgghijúkjjkkllúmllmmnnopýqpqqdeûfeffggýfhgghijklýmlmmnoúnoopoppqþrddefýefggùhghghhiijklümllmmnopþoppþqccdeþfgghþghhøihhiijijjkôlklmmlmmnmmnnopqÿÿ€ù‚‚‚‚ƒƒý„ƒ„„…†‡úˆ‡‡ˆˆ‰‰Š‹ŒýŒ$€û€‚‚ƒ„…†‡þ†‡‡ˆü‰ˆ‰ŠŠ‹ŒþŒ$$€ö€€‚‚‚‚ƒƒ„…†‡üˆ‡‡ˆˆ‰Šþ‹ŒŒ$€‚ƒ„…†‡ˆ‰Šý‹Š‹‹Œ$þ~€‚ƒ„ý…„……†‡ˆþ‡ˆˆ‰Šü‹ŠŠ‹‹ýŒ‹$$ü~~€ý€‚ƒþ‚ƒƒ„…†‡ˆý‰ˆ‰‰Š‹$~€ú€€‚ƒ„ý…„……†‡ˆ‰Š‹$}~€‚ƒ„…†ü…††‡‡ˆ‰Š‹$}ý~}~~ü€€€ü‚‚‚ƒû„…„„……†ý‡†‡‡ˆü‡ˆˆ‰‰ûŠ‰ŠŠ$$}ð~}~~~€€€€€‚ƒý„ƒ„„þ…††‡ˆ÷‰ˆ‰‰ŠŠ‰Š$$ü}||}}þ~€ü€‚‚ƒ„…†‡ˆ‰ýЉ$$|ö}|}}~}}~~€ù€‚‚‚ƒ„ü…„…††ú‡††‡‡ˆˆ‰$|û}|}}~~ý~ý€€€‚÷ƒ‚ƒƒ„ƒ„„……†ü‡ˆ‡ˆˆ‰$÷{|{{||}|}}~€ý€‚ûƒ‚ƒƒ„„õ…„„……††…††‡‡ˆ$û{z{{||}ý~}~~ý~€û€‚‚÷ƒ‚ƒƒ„ƒ„„……†ø‡†‡‡ˆˆ‰$${ý|{||ü}|}~~ý€€€ý‚‚‚ùƒ‚ƒ„ƒƒ„„…ý†…††ù‡†‡‡ˆ‡$$z{|}~€ý€ý‚‚‚ƒ„…†ý‡†‡‡$þyzz{|}~õ€€€€‚‚‚ƒ„…†û‡†‡‡$$yz{|}~€‚ƒ„…†‡$yz{|}~þ}~~ø€€€‚‚ƒ„…†þ‡$$þxyyùzyzz{z{{û|{||}}~€þ€€‚ƒý„ƒ„„…†$xyz{|ö}|}}~}}~~€‚ûƒ‚ƒƒ„„ø…„„……†…$$xyz{|}÷~}~~~€€ý‚‚‚ƒ„…$xyz{üz{{||}~þ}~~€ý€‚üƒ‚ƒ„„$ûwxxwxxyz{|}~€‚ýƒ‚ƒƒ„$wxýyxyyz{|}ý~}~~€‚ƒ„$vüwxwxxyz{|}~ý~û€€€‚ƒþ„$$þvwwxýyxyyz{ý|{||}ú~}~~€þ€€‚ýƒ‚ƒƒ$vwüxwwxx÷yxzyzyzz{{ô|{{|}||}}~}~~€þ€€‚þƒ$$ývuvvwøxwwxyxxyyz{|ý}|}}~€‚ƒ$þtuuþvwwxyzü{z{||}ü|}}~~ý€€€‚þƒ$$tuvwúxwwxxyyüzyyzz{|}ú|}}~}~~ù~€€€€û‚‚‚$$øtutuuvuvvwxyz{|}ý~}~~ý~€ü‚‚$$tþuvv÷uwvvwwxwxxûyxyyzzý{z{{|ý}|}}~€þ€€þ‚$$tuvwxyz{ý|{||ú}||}}~~ý€€€$þsttuvýwvwwxyzö{z{{|{{||}}ý~}~~€$stuvwxyþxyyzý{z{{|}ý~}~~€$ûsrstsstuvýwvwwxýyxyyz{|}ü~}}~~€$ùrssrssttuvwxyz÷y{z{z{|{||ý}|}}~$rösrstsstutuuvwýxwxxyözyzz{{z{{||û}|}}~~$þqrrsýtsttuvwxyþxyyzõ{z{z{{|{||}}ú~}}~~$qýrqrrstuþtuuvwxyz{|ý}|}}~$øpqrqrqrsstuvwxyz{|}ü|}}~~$þpqqrsþrsstuvwxýyxyyz{|}þ~$$pqþrsstuývuvvûwxxwxxyz{|}~$opqrsýtsttuvûwvwwxxyzù{zz{|{||}$þoppúqpqrqrrstuvwüxwxyyz{|þ}$$ünpoppüqppqqþrsstøutuuvvuvvûwvwwxxyz{|$nopqrstuvwxöyxyyzzyzz{{|$nùonoopoppqýrqrrùsrsststtuvýwvwwùxwxxyxyyzý{z{{$ømnnoonoppqürsrsstuvwxyz{$mnoûnopoppqúrqqrrssýtsttuvþuvvwxùyxyyzyzzü{zz$$mûnmmnoopqrstuûvwvvwwxyýzyzzþ{$$mnûonooppqrstþsttuvwxýyxyyz$ømlmmnmmnnopqrsòrsststtuutvuuvvwxyüzyy$$lmnýonoopqûrqrrsstuvwýxwxxyz$ýlkllmnop÷rqqrrsrrsstuþtuuvýwvwwxy$ýlkll÷mlmmnmnnoopõqppqqrqqrrsstuvwýxwxxýyx$$þjkklmünmmnnoýpoppùqpqrrqrrs÷tsttuutuvvwúxwxxy$$klýmlmmnop÷qpqrqqrrsstuvwx$þjkkýlkllmnüopoppqrsþrsstúutuvuvvwþx$$jklmnopqýrqrrsùtststtuuvw$jkýlkllmnopqýrqrrþsrrùtsstutuuývuvvw$ijklýmlmmýnmnnopöqpqqrrqrrssýtsttùutuuvuvv$ý†…††‡ˆü‰ˆˆ‰‰Š‹ŒŽþø‘‘‘’’‘$$…†‡ˆ‰ýЉŠŠ‹ŒöŒŒŒŽŽŽúŽ‘ý’‘$$…ý†…††‡ýˆ‡ˆˆý‰ˆ‰‰úЉ‰ŠŠ‹‹Œ÷ŽŽŽŽ‘$…†‡ˆû‰ˆ‰ˆ‰‰Š‹ýŒ‹ŒŒþŒŽýŽü‘‘$$þ„……ý†…††‡ˆ‰ùˆ‰‰ŠŠ‰ŠŠ‹ŒþŒŽ‘$ú„……„„……†‡þ†‡‡ˆ‰Šù‹Š‹Š‹‹ŒŒýŒŽý$þƒ„„ý…„……†ó‡†‡†ˆ‡ˆ‡ˆ‰ˆˆ‰‰Šý‹Š‹‹ŒŽ$þƒ„„ý…„……†‡ˆ‰Šû‹Š‹‹ŒŒüŒŒûŽŽŽ$ƒ„…†û‡†‡‡ˆˆý‰ˆ‰‰Š‹ŒúŽŽŽüŽ$$ƒ„…ý†…††‡ˆ‰ýЉŠŠ‹÷Œ‹ŒŒŒŽŽ$ü‚ƒ‚ƒƒ„…†‡ûˆ‰ˆˆ‰‰ùŠ‰ŠŠ‹Š‹‹üŒ‹‹ŒŒùŽŽŽŽ$$ú‚ƒ‚ƒ‚ƒƒ„…†‡ýˆ‡ˆˆ‰ýЉŠŠ‹ŒûŽŽŽ$$þ‚‚ƒý„ƒ„„…†ý‡†‡‡ˆ‰Š‹ŒýŽ$$‚ƒ„…†þ…††‡ýˆ‡ˆˆ‰Š‹üŠ‹‹ŒŒþŽ$$‚ƒû„ƒ„ƒ„„û…„……††ù‡†‡ˆ‡‡ˆˆ‰Šý‹Š‹‹Œ$ù‚ƒƒ‚ƒ‚ƒƒ„…††‡††‡‡ˆ‡ˆˆ‰‰ˆˆ‰‰ûŠ‰ŠŠ‹‹Œ$€‚ƒþ„……ö†……††‡†‡‡ˆˆ‰ýЉŠŠõ‹Š‹Œ‹‹ŒŒŒ$$€ý€‚ýƒ‚ƒƒ„…†‡ˆý‰ˆ‰‰Šþ‹ŠŠ‹Œ$ù€€€€‚û‚ƒ‚ƒƒý„ƒ„„…†ý‡†‡‡ˆ‰Š‹Œ$€û‚‚‚ƒƒý„ƒ„„ù…„……†…††‡þ†‡‡ˆ‰Š‹úŠ‹‹ŒŒ$$€‚ƒý„ƒ„„û…„……††‡†‡ˆ‰þˆ‰‰Š‹þŒ$$ý€€€ý‚‚‚ƒ„ý…„……÷†…†…††‡†‡‡ˆü‰ˆ‰ŠŠü‹Š‹$$þ~û€€€€‚ƒ„ý…„……†þˆ‡‡ˆ‰ýЉŠŠþ‹$$~ý~€‚ƒû„ƒ„„……†ý‡†‡‡ˆ‰ýЉŠŠ$}~€‚ƒ„þƒ„„ô…†…†…†‡‡†‡‡ˆˆ‰ùˆ‰Š‰ŠŠ$$}~€õ€€‚‚‚ƒƒû‚ƒ„ƒ„„…†ü‡††‡‡ˆü‰ˆˆ‰‰þŠ$$}~€ý€ý‚‚‚ƒ„ü…„„……†‡ˆý‰ˆ‰‰$}~ý€€€‚ƒ„…†‡ˆû‰ˆ‰‰$$ý}|}}~ý~€ý€ü‚‚ƒƒû‚ƒ„ƒ„„…û†……†‡‡þ†‡‡ˆ‰$|}~€‚ƒû„ƒ„„……ø†……†‡††‡‡ˆþ‰$$þ{||}ý~}~~€þ€‚ƒ„ý…„……†÷‡†‡‡ˆ‡ˆ‡$$þ{||}ü~}}~~ü~€€‚ƒ„…†ý‡†‡‡$û{||{||}~ý~€ý€‚ƒ÷„ƒƒ„„…„„……†‡$z{|}~€û€€‚ƒ„…ú„……†…††‡$ø{z{{||{||ý}|}}~€û‚‚‚ƒþ„ƒƒ„ý…„……†‡$zý{z{{|}~ý€€€ü‚‚‚üƒ‚ƒ„„…†$z{óz{{||{|}||}|~~÷€€€€‚‚ƒý„ƒ„„…†$ýzyzz{|þ{||}~€‚ƒ„þƒ„„…†þ…$$yzý{z{{û|{||}}~€ý€ú‚‚ƒ‚ƒƒ„…$yz{ý|{||}~ú€€€‚ƒ„ý…„$$yûxyzyzzý{z{{|ý}|}}ü~~ý€€€‚ƒ„þ…$$xyzþyzzý{z{{|}~ý~€ú€‚‚‚ƒ„$xyzö{z{{||{||}}~ý~ý€€€‚ƒ„$ýxwxxyüxzyzz{ù|{|}||}}~€‚ƒ‚ƒ„$wxyz{ý|{||}~ø€€€€€‚ƒ$úvwwxwxxyýzyzz{úz{{|{||}~€‚ƒ$ýwvwwxyz{|}ý~}~~€‚þƒ$$vwýxwxxýyxyyz{|}ý~}~~ý~ý€€€‚þƒ$$öuvwvwwvwwxxyz{|}~ü€€€ü‚‚$$úuvvuvwwxyz{|ý}|}}~€ý‚$$uùvuvwwvwwxyzü{zz{{|}~û~~€ý€$uývuvvwxýyxyyýzyzz{ø|{||}||}}ü~}~€$tuývuvvwxýyxyyzý{z{{|û}|}|}}~€þ€$$ûtuttuuvwvwxyzû{z{{||}~ý~€$týutuuvwxýyxyyz{|ý}|}}~ü~€€$øststtutuuvýwvwwxyþxyyúzyz{z{{ý|{||}~€þ$$stuvwýxwxxyz{ý|{||ü}|}~~÷}~~~€$$stþsttuvwýxwxxyzý{z{{ý|{||}÷~}~~~$$úrssrsttüutuvvwxyz{þz{{|ü}||}}~þ}~~$rstuvwxyzý{z{{|ü}||}}~þ$$rsõrsttsttuttuuvwxûyxyyzzü{zz{{ú|{|}|}}~$þqrrsþrsstuvwxyzö{z{{||{||}}~$qrstuývuvvwýxwxxyùxyzyzz{{|}þ~$$ùpqqrqqrrstúutuvuvvüwvvwwxyz{ùz{|{|{||}$;ÿûqrqrÿ:ÿq;ÿûqrqqÿ:ÿq;ÿþrqq;ÿqp;ÿûpqqpÿ:ÿqþpÿ:ÿþqpp;ÿpq;ÿûpqppÿ:ÿp;ÿp;ÿpýopÿ:ÿûpoopÿ:ÿûpopoÿ:ÿûopooÿ:ÿo;ÿoýpnÿ:ÿo;ÿoþnÿ:ÿon;ÿûononÿ:ÿoþnÿ:ÿûnonnÿ:ÿþonn;ÿûnonnÿ:ÿn;ÿnþmÿ:ÿmýnmÿ:ÿûmnnmÿ:ÿm;ÿûnmnmÿ:ÿûmnmmÿ:ÿmþlÿ:ÿmþlÿ:ÿûlmlmÿ:ÿûmllmÿ:ÿlýmlÿ:ÿl;ÿl;ÿþmll;ÿl;ÿl;ÿl;ÿlþkÿ:ÿlk;ÿk;ÿk;ÿk;ÿk;ÿkj;ÿk;ÿûjkkjÿ:ÿj;ÿûjkjkÿ:ÿjþiÿ:ÿj;ÿjýijÿ:ÿþijj;ÿþijj;ÿûijjiÿ:ÿi;ÿi;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<q<q<qþp;q<üqpp;üpqq;p<p<p<p<p<üpop;p<üopo;o<o<üpoo;üono;oþn;ünon;nþo;ünon;n<n<üonn;n<n<nþm;nþm;mþn;ümnm;m<mþl;m<mþl;mþl;m<l<l<l<l<lþk;lþk;ülkl;k<k<k<k<kþj;ükjk;ükjk;üjkj;ükjj;j<j<jþi;j<j<üijj;i<i<i<i<i< @ @ @ @ $þABBCDýEDEEFGHIJýKJKKþL $þABBûCBCCDDEFGHIýJIJJKýJK $ABûCBCCDDEFGHIüJIIJJ $þ@AABýCBCCDEüDEEFFGýHGHHIùJIIJJK $@ABüCBCDDúCDDEDEEFúGFFGGHHIJ $@AýBABBCõDCDCDEDEFEFFGHIþJ $þ?@@ABCDEFGHI $þ?@@ABCüDCDEEFGýHGHHI $?@ýA@AABCDþEDDEFGH $ý?>??@ABýCBCCDEFGüFGGHH $>?ö@?@@A@A@ABBCDEFGþH $>?@Aü@AABBCDEõFEEGFGFGGH $=>?ý@?@@ABýCBCCDýEDEEFG $=û>=>>??@ABþABBCûDCDDEEüFEEFF $=>?@ûA@AABBCDEF $<=>?@ýA@AABýCBCCDEF $þ<==>ý?>??@ABCDEF $þ;<<=>?@ýA@AABCDEþF $;<=õ>=>?>>??@?@@ABCDüEDE $ú:;<;;<<=>?û@A@@AABüCDCDDþE $;ý<;<<ý=<==>ý?>??@ABCD $:;<=>?@ABüABBCCD $:ý;:;;<þ;<<=ö>==>>?>??@@ABüCDC $9:ý;:;;<=þ<==>ý?>??@ABC $9:ú;::;;<<=>?ý@?@@ýA@AAùBABBCC $ó899:9::;:;:;<<=>ý?>??ý@?@@ABüABB $9þ899:;<=ù>==>?>??@AûBABB $89:ú9:;::;;ý<;<<=ü>=>??@AB $89:ü9::;;<=>?@A $þ7889ý:9::;þ:;;<õ=<==>=>>?>??@A $78ö7889899:9::;ý<;<<=ý>=>>?ý@?@@þA $789:;<ü;<<==>þ=>>?@ $ù676677889ü:99::;<ý=<==>?þ@ $6ý7677ú8789899:;ø<;;<<=<==>?þ@ $þ566ú76787889:;<=>? $56ý767789ý:9::;<=þ>?? $þ4556û767788ý9899:;<=>þ? $þ455ý656678ý9899:;<þ;<<=> $45ý6566789ü:9:;;<=>þ= $3456û767788ø9:9::;:;;<= $þ3445ý65667ö877899899::;÷<;;<<=<= $3û45545567ü877889ü:99::;ý<;<<þ= $2ö343344554556789:;ú<;;<< $ý32334ü544556789:;< $2ý323345ý6566789ø:99::;:;; $12345678ý9899þ:;; $12û3233445678ü98899û:9::;; $þ01123456789:þ; $01234ü34544ý6566ý76778ú989:9:: $ý10112345ú455656678û9899:: $1ü011223ù43445455678ú9899: $1ú011212234û545566ý767789þ: $1û0100112û322344û54556678ý98 $ø101101011234ö545565566778þ788 $ý1011ü010112345678 $0ú10110112ù3434345567þ8 $ø010011011234567þ677 $ý0100û1010112345ú4565566ý76 $ü01100ý10112þ12234ú5446566þ7 $01þ011234ý54556$0û1010112ù32334344ø5456566-$,$+$ $ùMLMMNMNNOPQRSTýUTUU $LþMNNüMNNOOPúQPPQQRRSûTSTTUU $õLKLMMLMNMMNNOPúOPPQPQQRST $þKLLMûNONNOOPQýRQRRSTþU $KLýMLMMNOóPOPPQPQQRQRQRRSþT $úJKKLKLLùMLLMNMNNOPQRýSRSSþT $üJKJKKLýMLMMN÷MNNOONOOPPQRSþT $JýKJKKLMNOùPOPOPPQQRS $úIJJKJKKLMNùONOPOOPPýQPQQýRQRRþS $IJKûLKLLMMNOPQýRQRR $IJøKLKLLMLMMNOöNOPOPPQPPQQüRQR $IøJIJIJKJKKLýMLMMNOPQüRQQ $HIJKJKLMûNMNNOOPQþPQQ $HýIHIIJKúJKKLKLLMþLMMNOPøOPPQPQQ $þGHHIJöIJJKKJKLKLLMNOýPOPPþQ $GHIþHIIJKøLKLLMMLMMNOPýQP $GHþIJJýKJKKøLKKLLMLMMüNMMNNOP $þFGGHIJKúLKKLLMMNOþP $FGHIýJIJJýKJKKýLKLLMüNMMNNýONOO $üFGFGGHIJýKJKKLýMLMMNúONNOO $FGùFGHHGGHHIJKLùKLLMLLMMNþO $EFGýHGHHýIHIIüJIIJJýKJKKLýMLMMúNMMNO $EýFEFFýGFGGHIýJIJJKLþKLLüMLNMMþN $EùFEFGFFGGHüGHHIIJþIJJKLMþN $DEüFEEFFGýHGHHIüHIIJJKLM $DûEDEEFFøGFGGHGGHHIýJIJJKLM $ýDCDDEýFEFFGHIJKLüMLM $ýDCDDýEDEEõFEFFGGFGHGHHIýJIJJKúLKLMM $CDEFùGFGGHGHHýIHIIJKL $CDEFûGHHGHHIJõIJJKKJKLKK $BCüDCCDDýEDEEFGHüIHHIIJüKLK $BCDEFýEFGGýHGIIJþK $úBABCBCCDE÷FEFFGFFGHHIþHIIûJIJJKK $üABABBCDEFGþFGGHýGHIIJ $ABüABBCCDýEDEEFGHöIHIIJJIIJ $ú@AABABBCDûEFEEFFGHúGHIIHIIJ $@ABCDüCDDEEFGHI $@ABþABBCþBCCDEDEüFGFGGHøGHHIHII $þ?@@ABCþDCCDEFüGFFGGHIþH $ù@?@@A@AABCDûCDEDEEFþEFFGHI $þ?@@ú?@AA@AABCDEFGH $?@ABCDöCDDEDEEFEFFGþH $û>?>@??@ýA@AABCôDCCDEEDEFEEFFG $>û?>??@@ýA@AABCDEFG $ü>=?>>?@AþBAABCDEFG $þ=>>?÷@??@A@A@AABCDEúFEFFG $=>?@AùBABBCBCCDEFþG $=û>=>>??@ýA@AAýBABBCýDCDDEýFE $þ<==>?@üA@@AAýBABBCDEþF $=>?@Aü@AABBCDE $ü=<<==>?ý@?@@ýA@AABCþBCCDüEDE $=<=>?@ùA@AA@ABBCýDCDD $<þ=<<=>ý?>??@AýBABBCD $=þ<==ý>=>>?@þ?@@ùA@AABABBCD $û<==<==þ<==>ý?>??@ABûABCBCC $=ý<=<<=>þ=>>?ü@??@@ABC $ý=<==<=<=>ý?>??@üA@@AABþC $þ<==ù<==<=<==ü>=>??@ABC $=<=þ<==>?ý>?@@üA@ABB $=ù<==<=<==>ý?>??@Aú@AABB$ý=<==þ<==>?@A-$,$+$ €ü€ÿ*ÿ €ú€€ÿ*ÿ ø€€€ÿ*ÿ ü€€+ÿ þ€+ÿ þ€+ÿ +ÿ ü~~ÿ*ÿ þ~þ~ÿ*ÿ ~ü~ÿ*ÿ ~+ÿ ü~~~+ÿ ~+ÿ ~þ}ÿ*ÿ ~}þ~ÿ*ÿ ~û}~~}ÿ*ÿ ý~}~~ý}~ÿ*ÿ þ~}}+ÿ ~ú}~~}}ÿ*ÿ þ~}}+ÿ ý}~}}+ÿ }+ÿ û}|}|}}+ÿ þ|}}ü|}}ÿ*ÿ }|ý}|ÿ*ÿ }|+ÿ û}||}||+ÿ }|þ{ÿ*ÿ |+ÿ |û{|{|ÿ*ÿ |û{||{ÿ*ÿ |{+ÿ þ|{{+ÿ þ|{{+ÿ |{þzÿ*ÿ ý{|{{+ÿ {+ÿ {þzÿ*ÿ ý{z{{þzÿ*ÿ {ýz{zz+ÿ {z+ÿ þ{zz+ÿ þ{zz+ÿ øz{zzyzyÿ*ÿ zúyzyzyÿ*ÿ zy+ÿ zyzþyÿ*ÿ zyüzyyÿ*ÿ zùyzyzyyÿ)ÿ ýyzyyýxyÿ)ÿ yxþyÿ)ÿ öyzyyxxyxyÿ(ÿ yùxyxyyxÿ(ÿ yxüyxxÿ'ÿ yx(ÿ xþyxx'ÿþyxxýwxÿ%ÿxüwxwxxþwÿ$ÿxúwxwwxww#ÿxwþxwwûvwwvÿ ÿüwxxwwvþwÿÿwvwvþwvvüuvvuuùtutututtþsttswvwvþuvvutþuttústsstsswvþwvvuþvuututþstts+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ*ÿ*ÿ*ÿ)ÿ)ÿ(ÿ(ÿ'ÿ&ÿ%ÿ#ÿ!ÿ ÿÀúKLMMLMMþNOOùPOPQPPQQRSýTSTTUùVUVVWVWWXYZüLKKLLMNOþNOOPûQPQQRRSTýUTUUýVUVVWXúWXXYXYYKLMNOPQRýSRSSTUýVUVVWXYKLMNOPQüRQQRRSõTSTUTUUVVUVVüWVWXXYKLMþLMMNOPQRýSRSSTUVýUVWWX÷WXXYJJKJKKLýMLMMNOPþOPPQRSûTSTSTTUýVUVVWXIþJKKýLKLLMNøONOOPOOPPQRSTUüTUUVVøWVVWXWWIIJKLMNOPQRSTUVùWVWWHIJJþIJJKýLKLLMNOýPOPPQRSTUVWúHIHIIJJKJþKLLMNOüPQPQQRýSRSSTùUTUVUUVVüWHHIIøJIJIJKJKKLMûNMNNOOPQRSþRSSTUVHIJK÷LMLMMNNMNNùONOOPOPPQRSTUûVUVVGGHIJKýLKLLMNOPüQPQRRSTUüVUVGGHIJýKJKKûLMLLMM÷NMNNOONOPPQüPRQRRSòTSTTUTUUVFFGGHHIJKLøMLMMNMMNNOPQþPQQýRQRRûSRSSTTþUFFGHIJKýLKLLMNOPQRSTûSTTUFFGHûIHIIJJKLMNOûPOQPQQRSôTSSTTEEFGFFGGHüIHHIIJKLMNOPQRSTFüEFFGGHIøJIIJJKJKKLýMLMMN÷ONOOPOQPQQýRQRRûSTSDEEFGHýIHIIJKLùMLMNMMNNOPQRSþDEEFûEFGFGGHIùHIJIJJKKLMýNMNNOüPOOPPýQPQQRüSRSDDEF÷GFGGHGHHIIùJIJIJJKKLMNúMNNONOOPQüRQQRRúCDDEDEEFGHIJKLüKLLMMNOPQRCDEFûEFGFGGúHGHIHIIJKLMûNMNNOOPýQPQQüRCCDDEFGúHGGHHIIýJIJJKLMNOPöOPPQPQQRBCCDýEDEEFGûHGHHIIýJIJJKýLKLLMýNMNNûONOOPPþQCCDüEDDEEFGHIJKLMNOPBCýDCDDEFGHIJKLMNûONOOPPþABBúCDDCCDDEFGHIJKüJKKLLMûNMNMNNOüPAABBCDEFýGFGGHIþJKKýLKLLMôNMNMONNOOPOAABCDEüFEFGGþFGGHIJKLýMLMMNOþ@AAôBABBCBCCDDCDDEFýGFGGHIûJIJJKKLMNýA@AAýBABBCþBCCDEFGHIJKýLKLLMüNMMNN@ýA@AABCDEþDEEFûGFFGHHIJKûLKLLMMN?@AýBABBCýDCDDýEDEEFGHýIHIIûJIJJKKLM?ù@?@AA@AABCþBCCDEûFEFEGGüFGGHHüIHIJJûKJKJKKLûMLMM??@û?@A@AABCüBCCDDEüFEEFFGHIJKLM?þ>??@ABýCBCCDEþDEEFGûHGIHIIýJIJJKLþM>>û?>??@@ABCýDCDDøEDDEEFEFFGHùIHIHIIJJKLó=>>?>>??@?@@AABþABBCDEFGHýIHIIJKL=>ý?>??û@?@@AABCüDCDEEFGHIJKþL==>?ü@??@@ABóABCCBCCDDCDDEEFýGFGGHIJúKJKJK==ý>=>>?@ABCDûEDEEFFGûHGHIHHIJøKJK<==<==>?ú@?A@@AABCDEüFEEFFGHIøJIJKJ;<==ý>=>>û?>@?@@AýBABBCüDEDEEFýGFGGHIýJIJJ;<=>?ý@?@@ABCôDCCDEEDEEFEFFGHþGHHIúJ;<<;<<=ù>=>>?>??@Aþ@AABCûDCDDEEýFEFFGýHGHHIýJ:;;<=>?@ABCüBCCDDEûFEFFGGHIþ:;;<=ý>=>>?@þ?@@ABþCDDEFGHüI::;;û<;<<==>?þ@AABýCBCCDùEDEFEEFFGHüGHI::;<ý=<==>?@úABABABBüCDCDDýEDEEûFEFFGGHþ9::ý;:;;<=>þ=>>?ü@??@@ABCüDCCDDEFGûFGHH99:;<=ý>=>>?û@?@@AABCýDCDDEûFEFFGGüH9899÷:9:;;:<;<<=>?@ýA@AABCDEýFEFFG89:;<=>?@ABCüBCCDDýEDEEýFEFF8ý9899:;<û;=<<==>?@òA@AABABBCBBCCDDûEDEEFF89û:9::;;<=>?@A÷BABCBBCCDDEF8ø7898899::;<=ý>=>>?@ýA@AABCDEþ67789ü:99::;õ<;<<==<=>=>>?ý@?@@òA@AABABBCCBCCDDýEDEE6ý787789ý89::ý;:;;ý<;<<=>?û@?@@AABCóBCCDDCDDEE667789:ù;:;;<;<<û=<==>>?ý@?@@ABøCDDCDDE$¿$VýWVWWXWXYZþYZZ[ü\[[\\]^_ý`_``abùcbcUVUVVýWVWWXýYXYYýZYZZý[Z[[\]ý\]^^ý_^__`abUýVUVVWþVWWXYZù[Z[[\[\\]ý^]^^_`aùbaabbTUUVúWVVWWXXYZ[\]û^]^]^^_ù`__`a`aabùaTUTUUVVúWVVWWXXYýZYZZ[\ý]\]]^û_`__``aTUVWXýYXYYúZYZ[Z[[û\[\\]]^_`a÷TSTTUUTUVVþUVVWXYýZYZZ[ý\[\\ø]\]]^^]^^_û`_``aaþSTTýUTUUVúWVWXWXXúYXXYYZZû[Z[[\\]^_`þaSSTUVWXYZþ[ZZ[\]þ^]]ü^_^__`øSRSTTSSTTUüVUUVVWýXWXXYùZYZ[[Z[[\]^_ú`_`RRSSýTSTTUVWVWXýYXYYZ[\]^÷_^_`_RSRSSTSTUVWXYZ[ý\[\\]÷^_^^__RQRR÷SRSSTSTTUUVüWVVWWXüYXXYYZ[\]^ù_^^QRQRRýSRSSTüUTUVVWûXYXXYYüZYZ[[\]þ\]]^ü_QQRRSTUùVUVVWVWWüXYXYYZ[ú\[\]\]]^ùPQQRRQRRSTùUTTUTUVVûWVWWXXYZ÷[Z[Z[[\[\\ú]^]]^PPüQRQRRSüTSSTTUVýWVWWXYüZYYZZ[\]PQRýSRSSTýUTUUVýWVWWXYZ[\]ûPOPPQQRSýTSTTUVWXYZ[\]üPOOPPQþRSSTUVWXYZþ[ZZú[\\[[\\OýPOPPQRùSRSSTSTTUùVUVVWVWWXøYXYYZZYZZ[û\[\\OOPþOPPQRSTþSTTUVýWVWWXYøZYYZ[[Z[[\NOPQþPQQRSTUVWXYZ[ý\[NNOPýOPQQRüSRSTTUVýWVWWXYþXYYZ[MNOPüQPPQQRSþRSSTýUTUUþVWWXYýZYZZú[Z[MMNNýONOOPýQPQQûRQRRSSTýUTUUVþUVVûWVWWXXýYXYYZþ[MMNüMNNOOýPOPPQýRQRRSTýUTUUVýWVWWXYZûMLMMNNOPQRúSRSTSTTUøVUVVWVVWWXYZþLMMýNMNNOPQRSTúUTUUVUUVWùXWXXYXYYLMNOýPOPPQRSTUVWþVWWXYLöMNNMNNONNOOPQRSTüSTTUUVWXYLMNOPQRýSRSSTùUTUUVUVVWXK÷LKKLLMLLMMNOüPOOPPQýRQRRýSRSSTUVûWVWWXXþJKKýLKLLùMLMMNMNNOPQRSýTSTTUýVUVVWûXWWJKKLMNOPQRýSRSSTýUTUUóVUVVWVWWXWJJKKýLKLLMNOPQýRQRRSTUüVUUVVûWVWWJJKLýMLMMNOPQRûSRSSTTUVWIJKLMNýONOOPQýRQRRSTýUTUUVWIJKþLKKLMNOýNOPPQRSýTSTTýUVUUVþHIIJKüLKKLLMüNMMNNOPQRSTUùVUVUHHIIJKLMNýONOOûPQQPQQR÷SRSSTTSTUUHIýJIJJ÷KJKKLKLLMMNþMNNOPQRýSRSSTUþGHHIøHJIIJIJKKLþKLLMüNMMNNõONOPOOPPQPQQüRQRSSöTSTTUUTGGHHIJKûLKLLMMNOPýQPQQRùSRSSTSTTGHûIJIIJJKLMNOüNOOPPQRSTþFGGHIJûKJKJKKLMýNMNNOþNOOPQRSüTSFGGHýIHIIJKþJKKLüMLLMMNýONOOPýQPQQýRQRRSFGþFGGHþIHHIùJIJKJJKKLMþLMMýNMNNOPQþPQQRSýTEFFGúHGGHHIIJKLMýNMNNøONNOOPOPPQRSþEFFGHIJKLýMLMMNOôPOPPQPQQRQQRRþSEEFGHIJKLMNOýPOPPùQPQRRQRREFGHýIHIIJKLüMLLMMNýONOOPQüRQRDDûEFEEFFGHIJþIJJKúLKLMLMMNýONOOPþOPPQþDEEFûGFGGHHIJýKJKKLýMLMMNýONOOPQDEýFEFFGHûIHIIJJKýLKLLMNOýPOPPQCDEFGHIJKLMþNMMNOüNOOPPýQPCCDEüFEEFFýGFGGHøIHHIIJIJJKLMùLMMNNMNNýONOOPþBCCDúEDDEEFFýGFGGHIJKLMNOPCDöEDDEEFFEEFFGHIJKýLKLLMýNMNNOüPOBCCýDCDDEüFEEFFGHIýJIJJùKLLKLLMMýLMNNOBDþCDDEøDEEFEFFGGHIýJIJJKLMþLMMNüONO$¿$@ÿsürssrrýqrqqpoüpopoonümnnmmsýrsrrýqrqqþpqqýpqppúoppopooünonoonmnmrþsrrqþrqqüpqqppoþpoonõonnmmnmnmnmml@ÿÀþZ[[\ý]\]]^_`a`aýbabbcdeüfefgghZ[ú\[\]\]]^ü]^^__ü`__``abücbcddöeffeeggffgghþYZZ[û\[\\]]ý^]^^_ý`_``abücbcddeüfeeffgúhZYZYZZ[\]^þ]^^_`aúbaabbccdûedeeffgþhYYZø[Z[[\\[\\]^ü_^_``ûa`aabbcdùededeeffgYüXYYZZ[\]^]þ_^^_ù`_``a`aabcýdcddeýfeffügXXYYZý[Z[[\ü]\]^^ö_^^__``_`aabücbbccdeûfeffXXYZ[ù\[\\]\]]ý^]^^_`aübaabbcdefþWXXYZû[Z[[\\]ý^]^^ý_^__`aübaabbcdýedeeWXýYXYYZ[ý\[\\]^ý_^__`abcdeþVWWXYZ[þZ[[\]^ý_^__`abcdeüVWVWWXYZ[\]ý^]^^_`a`abcdVúWVVWWXXYýZYZZø[Z[[\\[\\]^_ý`_``abcdUVWXýYXYYZû[Z[[\\]ý^]^^_ù`_`_a`aabcüdUUVVWXYZý[Z[[ý\[\\]ý^]^^_`ûa`aabbýcbccýdTUUVWXóYXYZYYZZ[Z[[\\]û^]^^__`abþabbcUùVUVVWVWWýXWXXýYXYYZû[Z[[\\ý]\]]^_ý`_``aûbabbccTUVüUVVWWXüYXXYYZý[Z[[\]^_`òa`aababccSTUTUUVWXYZ[ù\[\\]\]]^_ô`a`aabaabbSTTùUTUUVUVVWýXWXXýYXYYZý[Z[[\ø[\\]\]]^^_ú^_``_``abSTûSTUTUUVWXYZüYZZ[[\]^û_^__``ùa`aabRSSTUV÷WVWWXWXXYYüZYYZZ[\]^þ]^^_ö`_``a`aaRSSýTSTTUVWýXWXXYZý[Z[[\]ý^]^^ü_^_``øaRRSRSSTTUúVUUVVWWXYóZYZ[Z[[\[[\\]]ú^]^]^__`ýaQRRSTUVWXYZ[\]^]þ^__`ýRQRRSTUûVUVVWWXYûZYZYZZû[\[[\\]û^]^^__QRüQRRSSTUVWýVWXXYZý[Z[[\]þ^__QRSýTSTTUVüWVWXXYZü[ZZ[[]^_PüQRQRRýSRSSþTUUüVUUVVWûXWXXYYZ[\]ý^]^^PQRSTýUTUUVWüVXWXXYZ[\ý[\]]^þOPPýQPQQRSTúUTTUUVVùWVVWXWXXýYXYYZ[\ý]\]]ý^OPPýQPQQRSúTSTUTUUVWXYZ[ýZ[\\ò]\]]OOPOOPPQPQQRSTUVþWXXYZ[ü\[[\\]NOPQRSTUVWXYZü[ZZ[[\ó]NNONOOPPOPPQQRSTUVWXYZ[\NOPþOPPQRýSRSSTûUTUUVVWXYþXZZüYZZ[[ü\MMNNOüPOOPPQRSTUVWXYýZYZZ[\MNOPQûRQRRSSTúSTTUTUUûVUVVWWXYZ[ùMLMMNMNNOPýQPQQRSTUVWXYZö[LLMLMNNMNNOûPOPPQQRûSRRSTTUVWXYþXYYZþ[LLMNOPùQPQQRQRRSTûUTUUVVýWVWWXYZýLKLLMNüONNOOPQRýSRSSTUVWXýYXYYúZKKLKLLMNýONOOPQR÷QRRSRRSSTTUTUVWXýYXYYKLMýNMNNýONOOPQýRQRRSùTSTTUTUUýVUVVWýXWXXYþJKKLùMLMMNMNNOPQýRQRRüSRSTTUüVWVWWXYJüKJKLLMýNMNNOPQRSTUüVUUVVWXþIJJKLMþLMMNOPQRSüRSSTTUVýWVWW÷XJIIJJKJKKLMNOöPOOPQPPQQRRSTUVWIJKþJKKLMýNMNNOýPOPPQRSTýUTUUVWþHIIJýKJKKLMüNMMNNOPQRýSRSSTùUTUVVUVVþHIIJKLMNOPûOPQPQQRSTUVWHIJKþLMMNOPýQPQQôRQRRSSRRSTSTTýUTUUVýHGHHIJüKJJLLþKLLMýNMNNOPQýRQRRSTþUVVGúHGHIHIIJKLNMNOPQRùSRSSTSTTUþVGGHýIHIIJKLþKLLMNOPQRýSRSSTUFþGHHIJKLúMLLMMNNýONOOPQRSTUFGHIJKLMûNMNMNNOPQûRQQRSSýTSTTþUFFGHüIHHIIJùKJKKLKLLMNOPQRSýTEFFGýHGHHIJKLýMLMMNOPüQPPQQRSüTSSEEþFGGHIüJIJKKLûMNMMNNþOPPüQPPQQRSEFGHýIHIIJKLMNýONOOPQüRQRSSÀ$ûcddcddefgþfgghijklømllmmnmnnopcdýedeefþeffgùhghhihiijklmnoûpopbccýdcddefghijkþlkklmünmmnnoûbccbccdþcddefghiýjijjýkjkklmýnmnnobcdeýfeffghijklýmlmmnûonoabbcdúedefeffghijkjþkllmnþmnnaübaabbcýdcddëedeeffeffgffgghhghihiijklmûnmnoaabcdeýfeffgýhghhijýkjkklýmlmmn`abcûdcdcddefgûhghhiijklýmlmm`abýcbccdeþfeeüfgfgghúihihijjklm÷lm`_``a`aabcðbccdccddeedeefeffghýihiijýkjkklúmlmm_``÷a``aabaabbcdefgýfghhýghiiýjijjkl_ý`_``abcýdcddeýfeffghijklùm^__`_``abþabbcdefghi÷jiijjkkjkkl^_ø`__``a`aaýbabbcdefghijõkjjkkl^__^__û`_``aabcýdcddýedeefùgfgghghhiýjikk]^ù_``_`_``abùcbcdccddefghijkü]^]^^_`abücdcddeføgfgghhghhúihijijj]^û_^_^__`abcùdcddedeefghijüij\]]^_û^_`_``aùbababbccýdcddefûgfgghhi\]^_`aþ`aabücbbccdeþdeefghýihii\ü]\\]]^þ_^^_`abcýdcddýedeeýfeffghiõhiij[\\]\\]]^_`abcdeüdeeffg÷hiihi\\[\\]ý^]^^_`abcdefgühgghhþi[[\]^_ú^__`_``üa``aabcdefgýhghhý[Z[[\]ý\]^^_`abcødcddeedeefghügZZ[[\]þ\]]^_`ýa`aabcdüeddeeýfeffghûZ[ZZ[[\]ý^]^^_ü`a`aaýbabbùcbccdcddefgZ[\]^_`aýbabbýcbccdefgüfYYZZ[\]^ý_^__`abcdefûgfYYZZ[ý\[\\ý]\]]^ý_^__`ýa`aaýbabbcýdcddúedffeffYZ[\]^_ú`_`a`aabcdeXYZþYZZ[\]^ý_^__`abcdüeddeeþfXXýYXYYùZYZZ[Z[[\ü[\\]]^_`abcdeXõYXXYZYZZY[ZZü[\[\\]^_`abýcbccdþcddeþWXXYZþ[ZZ[\]^þ]^^_`øa`aabaabbcdûcedeWWúXWXYXYYZ[þZ[[\]^ý_^__ý`_``aøbabbccbccdôeVVWXXWXYXXYYZ[ý\[\\]þ^__ú^__`_``ýa`aabcüdcVWWXýYXYYZ[\ý]\]]^_`aü`aabbcVùWVWWXWXXYZ[ô\[[\\]\]^^]^^û_^__``aùbabbcbccýVUVVWýXWXXYZþ[ZZ[\]ý^]^^_ü`__``abýabccUVWXYZ[ý\[\\ý]\]]^ý_^__`ëa``aababbcbcUUVVUWWVWWXþWXXYþZ[[ö\[\\]\\]]^^ü_^^__`aøbabbTUUVVWXúWXYYXYYZþYZZ[ý\[\\ø]\]]^^]^^_`ï_``a`abbabUTUUVUVVýWVWWXYZ[þZ[[\]^_`aþ`aaýbTUUþTUUVúWVWXWXXüYXXYYZ[\ý]\]]ý^]^^_`aTUýVUVVWXYýZYZZ[\ü[\\]]ú\]^^]^^ý_^__`þa``þSTTUVýUVWWüVWWXXYZ[\]þ\]]^_`üaSSTTýUTUUVWXýYXYYZ[\]û^]^_^^ü_`_``þaSSTýUTUUVWXúYXYZYZZ[þZ[[\ô]\]]^]^^_^^__`RSTSþTUUVWýXWXXZYZý[Z[[\]ý^]^^ø_^_``RRSSTSTUVýWVWWXýYXYYZ[ûZ[\[\\]þ\]]ù^]^_^^__RSTûUTUUVVWXYZý[Z[[\]^÷_^_QRQRRSSTUVWXýYXYYûZYZZ[[\ý]^]]ø^__^QRQRRúSRRSSTTýUTUUVûUVWVWWýXWXXYýZYZZý[Z[[\ü]\\]]^þPQQRSîTSTTUUTUUVUUVVWWVWWXYZ[\]û^]]^PPQRSTùSTTUUTUUVWXüYXXYYZ[ý\[\\ø]\]]^PPQQRSTUþTUUVýWVWWXYZ[úZ[[\[\\]þOPPQRüSRRSSTUVôWVWWXWXXYXXYYZý[Z[[ý]\]]þOPPþQPPRþQRRûSRSSTTUþTUUüVUVWWXYþXYYZý[Z[[ñ\[\\]\\OPOOPQPQQRSTöSTTUTUUVUVVþWXXýYXYYùZYZ[ZZ[[\À$@ÿmþlmmlþmllkþlkkþjkkjþijjiþjiihüihihhgþhggúmlmlmllúkllklkküjkkjjiýhihhgþhggýflmmlükllkkþlkkjkjúijjijiiühiihhþghhgþfg@ÿÀijýijkklõkllmlmmnmmnnëonopooppqqpqqrqrsrssttuøtuvvuvv$$þhiijkólmmlmmnmnnonooþpqqrsýrsttuüvuv$$hijüijjkklmülmmnnûonooppýqpqqrstu$hiýjijjklmnopqrstu$ýhghhijúkjjkkllmnopüqpqrrstuþt$$gýhghhiùjiikjjkklmnýmnoopqýrqrrstþu$$ghúihhiijjkúlklmlmmnoûpoppqqrösrsstsstt$$fghûihiijjklmnoüpooppqrüsrstt$fgüfgghhijklmnoþnooüpqpqqrûsrss$$ýfeffýgfgghiüjkjkklmnýonoopqürqrss$efghiýjijjkýlkllmnopqþpqqr$þdeefgòfghgghiihiijijjklmûnmnnoopqr$eüdeeffghiþhiiþjkklýmlmmnopqýpqrr$defghýihiijùkjjklkllmnoýpoppqþr$$dùedeefeffghûihiijjkýlkllmýnmnnùonoppoppq$dûedeeffghijkølmlmlmmnnopq$cdøeddeffeffghijk÷lmllmmnmnnop$þbccdefghiühiijjklmülmmnnop$þbccdeüfeeffghüihhiijýijkkølkkllmlmmnûopoo$$übcbccýdcddeýfeffùgfgghghhijkûlkllmmnümnnoo$þabbcdefýgfggúhgihhiijküjkkllýmlmmnþo$$abcüdccddþeffghijøkjjkllkllmnþo$$abcdþcddefgýhghhiýjijjklýmlmmûnmnn$$abýcbccødcddeedeefghijükjjkklmnýmn$$`ûa`aabbücbcddùeddefeffghijýkjkklûklmlmm$ù`_`aa`aabûcbccddýedeefghijklümlm$$þ_``aýbabbcûdcddeefghiýjijjkýlkll$_ý`_``abcõdcddedeefeffýgfgghijklþm$$_û`aa`aabûcbccddþeffghþghhijkûlkll$$ø_^^__`_``abcdûedeeffýghggihþijjkl$^_`abcdeófeefgffgghhghhijkþl$$^_û`_``aabcdúeddeeffghijk$]^_ý`_``abýcbccdefghúihhiijj$]^_`abûcbccddþcddefþeffghij$\]ý^]^^û_^__``a÷babcbcbcddefefgûhghhiiüjij$$\]^_`óa``aabbabbcbccdefþeffghýihii$\]^_`ababcýdeddefghûihii$$[\]^ü]_^__`abþabbücdcddefghûihih$$ü[\[\\]^_ý`_``ýa`aabcdefghþi$$þZ[[\]ý^]^^_ù`_`_``aabücbbccdûedeeffgh$[ý\[\\]^_þ`aaþ`aabcdeföeffgfgghg$$Z[\ý]\]]^ü_`_``aõbabbcbcbccddýedeefýgfgg$ýZYZZ[ù\[\\]\]]^ý_^__`abcdeøfeffgfg$$YZû[Z[[\\]^_ý`_``abøcbccddcddefg$YZ[\]^_`ü_``aabýcbcceüdeeff$þXYYZ[þZ[[\]^ü_^^__ý`_``aþbccdef$XYýZYZZ[\ý]\]]^ý_^__`aböcbcdcddedee$XYZ[þZ[[\ü]\\]]^_ü^__``abcde$ýXWXXYüZYZ[[ôZ[[\\[\]\]]^^_ü`__``aöbaabbcbccdd$WXYZ[û\[\\]]^ý_^__`abcýdcdd$ûVWXWXXYZø[ZZ[[\[\\]^_`ab÷cbccdcdd$$ûVWWXWWXýYXYYZù[ZZ[\[\\]^_ý`_``abcþd$$VWXYZ[\ü]\\]]^_`aýbabbþc$$þUVVWXYZ[\]þ\]]^ü_^^__`øa`aabbabb$þUVVWXYZ[\þ[\\]^_`aø`aababb$$UVWûXWXXYYZ[\]^_`úa`aab$$þTUUVWúXWWXXYYZ[þZ[[]^_`þa$$üTUTUUVWXYZ[\]^ý_^__`þa$$TUVWXYúZYYZZ[[üZ[[\\]^]^_ $ýTSTTUVWXYýZYZZ[\]^_ $TþSTTûUTUVUUüVWVWWXþYZZ[\]ü^]^$$þ$<$<$;$pqrstýutuuvwxyzý{z{{|$pqrs÷tuttuvvuvvýwvwwýxwxxyþzyyz{|}$pqórqrrsrsstststtuvwxyz{þ|$$üopoppqrsúrsststtuvówvwwxwxwyxyxyyôzyzz{{z{{||$$opqrsýtsttýutuuvûwvwwxxýyxyyz{$þnoopqrsrsýtsttuvwxyz{$þnoo÷pqqpqqrqrrsûtsttuuvwýxwxxyzü{z{$$ünonooýpoppqrstuvwxyz$þmnnopûqpqpqqrýsrsstuvwýxwxxyz$nþmnnoýpoppqrsûtsttuuvwþxwwxýyxyyz$mnopúqppqqrrstýutuuvýwvwwxyþz$$lmnopoüpqpqqûrqrrssýtsttúutvuuvvwxy$ðmllmnmnmnnoonooppqrüsrrsstýutuuývuvvýwxwwxþy$$ölmlmmnnmmnnopqrüsrrsstuþvwwývwxx$lmýnmnnoýpoppqrsýtsttuývuvvwx$þkllmnoþnoopqrüqrrsst÷uttuuvuuvvûwvwwxx$kýlkllmýnmnnopqrýsrsstüuttuuvwþx$$klmnopqrùsrsststtuûvuvvww$kþjkklmúlmnmmnnopþqrrstûuvuuvvþw$$jklmúnmnonoopqrüsrrssýtsttuv$jkýlkllmölnnmmnnonoopqþrqqrstúutuvuvv$ijkýlkllmnþonnüopoppqrsýtsttuþv$$ijklmønmnononoopûqpqqrrstuv$ijkülkkllmünmmnnoópoppqpqqrqqrsstuþv$$ýihiijkülkkllmnüonnoopýqpqqrøsrrsststtu$høihiijiijjkýlkllmünmmnnoúpopopqqûrsrrsstþu$$hiýjijjklümllmmnopqþpqqrst$þghhiøjijjkjjkklmnoüpooppqrýsrssþt$$÷ghghhiihiijklklýmlmmþnooþnoopqr÷qrsrssts$$ghiýjijjklmnmnopüqppqqrsrþt$$üfgfgghiûjijjkklþmnnümonoopýqpqqrs$ûfggfgghýihiijklmünmmnnopqúrqrss$$fgýhghhijékjkjkklkllmllmmnmnnonnoopqr$efýgfgghüijijjklýmlmmnopýopqqûrqrr$$eýfeffghþghhiüjiijjklmnopùqppqqr$$ûdefeffghiõjijjkkjjkkllmnþmnnopq$defüeffggýhghhýihiijûijkjkklmþlmmnopüqpq$$defghijklmnýonoopq$þcddefghýihiijklýmlmmônoonopopoop$$þcddýedeeýfeffghiùjijijjkklmýnmnnop$ücdcddeýfeffgýhghhiýjijjûkjkkllmþnmmnoýpo$$úbccdcddeõdefeeffggfgghiþjiiþjkkýlkllmülmmnno$ùbccdccddeýfeffghij÷kjkklkllmmno$bcdefgýhghhijükjjkkýlkllþmnn$bcýbcddefügffgghiýhijjklmn$bcdøeddeefeffghijklýmlmmýnm$$abýcbccdefghiþhiijklúkllmlmm$abcdeýfeffûgfgghhijklm$þ`aaübaabbcíbcddcddedeefefefgfggýhghhijýkjkkl$`abc÷dcdcddedeeýfeffghihijkl$ü_``aabücbbccdefýgfggühgghhijkûlkll$$_`aþ`aabcdefýgfgghýihiiýjijjýkjkk$_`ýa`aabcýbcddþcddefýgfgghijúkjjkk$$þ^__`aýbabbýcbccdeøfeefgffgghij$þ^__`ýa`aabcþbccdeþdeeùfeffgfggýhghhýihiij$õ^_^^__``_`aabcdefgþfgghýihiiýji$$^_`øabababbccüdccddefghi$]^ý_^__`abcdefghþi$$]^þ]__`ab÷cbcbccdcddýedeefgýhg$ $]^_`aýbabbcdefg $\]ü^]]^^_`abcdef$þ$<$<$;$;ÿi;ÿiþhÿ:ÿih;ÿûhiihÿ:ÿiþhÿ:ÿûihhiÿ:ÿh;ÿh;ÿhýghÿ:ÿh;ÿûhghgÿ:ÿhþgÿ:ÿhþgÿ:ÿgþhÿ:ÿgýhgÿ:ÿþhgg;ÿg;ÿûgfgfÿ:ÿûfggfÿ:ÿûgffgÿ:ÿûfggfÿ:ÿf;ÿf;ÿfýefÿ:ÿfþeÿ:ÿfe;ÿe;ÿeýfeÿ:ÿe;ÿe;ÿe;ÿeþdÿ:ÿeþdÿ:ÿed;ÿûeddeÿ:ÿûededÿ:ÿûdeddÿ:ÿþedd;ÿdþcÿ:ÿd;ÿd;ÿdþcÿ:ÿþdcc;ÿûdcdcÿ:ÿdc;ÿc;ÿc;ÿþbcc:ÿcb:ÿcübccÿ9ÿúcbcbbÿ8ÿcbþcÿ8ÿþcbb8ÿcbþaÿ7ÿcbþaÿ6ÿbüabbÿ5ÿbûababÿ4ÿbýabaa3ÿbüabbaa1ÿbûabbabba.ÿcböabbabbaaggfefedþeddøcdcdcddccþbccbabag fefe dcbþcbbúabbabaaþgffeüfefeeýdeddþeddcüdcdccþbccúbcbbabba;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ;ÿ:ÿ:ÿ:ÿ9ÿ9ÿ8ÿ8ÿ7ÿ6ÿ5ÿ 3ÿ 1ÿ .ÿÑ$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$=$=$=þ$=þ$¾$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$<$=$=$=þ$=þ$¾iþh;iþh;h<üihh;h<h<hþg;üghh;üghh;ühgg;ühgg;g<üghg;g<ügfg;üfgf;fþg;üfgf;f<ügff;f<üfef;üefe;fþe;üfef;üefe;üfee;e<eþd;eþd;eþd;e<üedd;d<d<d<d<d<üdcc;c<c<c<üdcc;c<c<c<übcc;übcb;ücbb;bþc;b<b<b<b=ýab<ýab<þb=þb¾ @ @ @ @*$($&$#$*$($&$#$wüvwwvvýuvuuþvuuøtutuututtstsrþsývwvvýuvuutþuttsûrssrvuv utþuttûststssürssvuþtuutstsürsrÿ$$ûsrrsrrýqrqqüpqqppþqppoþpoononúmnmmnmmlúmssrsrrqúpqqpqppýopo o nmþnmmlümllrrüqrrqqûpqpqppýopooþnoonþmnnmølmlmrrsrr qpopýopoonoýnonnúmnmmnmmlümllÿ$$lkþlkkýjkjjþijjýijiihþihhghgûfggmllkþlkkjkýjkjjijiýhihhýghgg÷fgfgfflmllükllkkýjkj jiühiihhüghghhgflþkllkjk jihþihhúghghhggýfgff:$8$6$3$ :$8$6$3$ ýfgffýefeeýdeddùcddccdccbþcbbþabbýabaaf eýdeddcþdccbþcbbaübabaaþgff eüdeeddücddccþbccb÷abaabbaafúefeffeeþdeedücddccþdccúbcbccbbþabbýabaa ÔÔÔÔŠ E†"C!1White Backgoundÿ     8íÌ1íôô¤ô°ô¼ôÈôÔ1ïTïdïtï„ï”ï¤ï´ïÄïÔïäïôððð$ð4ðDðTðdðtð„ð”ð¤ð´ðÄðÔðäðôñññ$ñ4ñDñTñdñtñ„ñ”ñ¤ñ´ñÄñÔñäñôòòò$ò4òDòTòdòtò„ò”ò¤ò´òÄòÔòäòôóóó$ó4óDóTódótó„ó”ó¤ó´óÄóÔóäóôôôô$ô4ôDôTôdôtô„ô”ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÿÔÿÔÿÔÿŠ E†"C!1 Backgroundÿ     õ“1õ»üküwüƒüü›1÷÷+÷;÷K÷[÷k÷{÷‹÷›÷«÷»÷Ë÷Û÷ë÷ûø øø+ø;øKø[økø{ø‹ø›ø«ø»øËøÛøëøûù ùù+ù;ùKù[ùkù{ù‹ù›ù«ù»ùËùÛùëùûú úú+ú;úKú[úkú{ú‹ú›ú«ú»úËúÛúëúûû ûû+û;ûKû[ûkû{û‹û›û«û»ûËûÛûëûûü üü+ü;üKü[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ @ÿ @ÿ @ÿ @ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÿÔÿÔÿÔŠ E†"C!pyclustering-0.10.1.2/docs/logo/pyclustering_logo_01_small.png000066400000000000000000000201401375753423500243320ustar00rootroot00000000000000‰PNG  IHDRÈ3Ò GDsRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEâ}š.}tEXtCommentCreated with GIMPW«IDATx^í\ xTE¶>Ù7Bdƒ„°  ˆŒ <”E!¸ Ë("*.ˆŠ¸²©(Ê Œ0¢ˆ *8( ê(²È@v$aIÂBBöît’wþº·nªoß ðÌ{¯ÿï«®íÔzÏ©:§nÝöªd z¨fÂËËK8<¸Öp+ eeed‘Ucà®9œÁÝ»÷ÒÊ•?ÐÅ‹…úJ­g h¤â×(¦ ‘žï&OiIû~T:@ÆËTVVáMHH [n¹…ÂÂjS“&MÈÛÛ[§ñÀƒ« C@Àxï¼3‹¦M›C~"³&£°ð}ôÑC:uò‰×^,•Ø)Öü¼ôŒZ´¢¦Ín¡´´ýäëHþAL¦-ãr7qòÙÉMÆ*îRFÿÑ£ÎeL¾øÞd·P™=—Ö¬YNmÛ¶¡·ÞšJqqqÔ¾}{È®"¼Žr¢QŒ£•ßn žw>Jë×Î¥Û{½N ã; æôbÕF2²X¨‘ÆÂ"_wÞJXM“L.âæ2È–i¨SüTå 5Ì] ¥K_¤5?-g«%ÿ=ôÐCäïïÏ…=ðàêAˆÃQFƒ=JüJáu»QówRËÄ»Ây ­†q-ÓÔ²ºqÔƒºõ°e=²-stwþ|:~´µ¤¤ÛiÒ¤IT·n]ŒÉ®˜õXb3ÄÛG™ý(¦~¶IØ.aÍÊðeXºrç8,8×éyã©¢ÑÓÌq”)WÒœê‘i’ž}™ï†ÞŠ>Ûl6*/çyàÁU† qZ¥3›¯O9˜c &f¼g0¬tzž «L.…Ç) >§—«åô4U\Ú’u#] çpˆ~P»¾õî}+½öÚk!ê÷Àƒ«©ÎÒ~4yU|A­[yÓ AƒxÕ.ÕÉ­æÅ÷#§OŸ¦ÔÔLÊ<Ùˆü{¯Ÿ/åœ_M-š¤Q=ÈÏÏ…·„$77—R9èlNÎóá<ùúúÒñ£?QÊþé4nܳâ:»|KŽ2999tèð:“Ý’¦LèÄï®\$$,‰®ãÄßç[Jº£Ý{oòñÑ©/¸ö±aÃÚ°%œU®Nb'¡²Õ4°µk×N#R’’B+W{S¥wKÂm›­Öÿ4œìM£FÒ©4`ÇÙ»ïmNŽdÍF¯¼Ðê’áUƒSSQVÖIÊÏ/;SXX(5mÚbcˆËŽfz )ÚW7øúš ô¹¦Ý2Àü¢_êÕ ôýÄâXÓ`Ø r¡ÉˆEž}ì f ƒ”; ¤ûùЭ·ÞJ;:¨¸(WÔUd»‰Öü|Μ9£îP—44jÔˆZµÈ§ââž4˜}P\\( 2Dä«´'Ož¤={ý¸¯uE?pýÝd9Œ«¨¨˜^zéoÔ±ã½Ô½ûP0àY6ìU>|"ýå/ã¨[·!Üç4cÆl:þ¼(§¶›•u†ú÷Š<‰®¿þnjß¾ÝxãÝ4qâTXX(hTúš^Ù.^, I“Þ§¹sˆùû£ú)Û1c>uíúuèp—˜Ë6múÒ}÷=D‹-²ä©?.†qH±^I<Ñx%Ï cÇ2™±‹5z†¶àsØ@JlEaµóÅK½À Ê8ÙšÖ­ÛJŽ2;(µŒÀÀ`jß.Šb럣£ééìÙõôÄOp:¾CÑêDý.\`á(¢¼üx× ÷+£ìûÒ¥?Pbb_š={1ï'¨  TÈqÚlå”—WJž¤)S>¥{îN[¶lq{aa1mܸ‹NÊcaÉáñçÒñã9´ys2ÛYOÍ€Êü8̘ç]â¶u´U^ùÒ©@tß¾34rä ,|oo/ a oïÊùý cæÌl»õàÕz w‰6¨140—®p~5 –;ˆà 7}.))¡ó9^d/ £óyq´|E2¯õÜ*`ö÷ÓV\€„_ZÖ•6nÎä•#K§Ò˜ÜÇÇ—Z¶Œ¥çžy€†}Љñ†ñ¿kO0÷¶®&\„Î `´Ué…Þ3ÒT _: •&#£ˆÞzk¦¡n © Ìõ«¨.ïjãÉÈ8I&Ì2C¦ûùù _óÿ$d»]ºt`Uµ9ÛŽuY½®G „QÛ¶ ¬þbQücúV\v˜ÏÝ.È*T)åå¦ÓÙKèÌ© –+ôÉ’M@Ê˽¨œu-|Ãq<« møe›“j‚y±‹OgkÕ ÑS5@µÚ¾£H£6݉ c®òÍyZÇŸþmá˜xÉ,°o»-‘æÏŸ@‹O£¤¤®"]¥Axûöãôí·ßŠø¥ ,( rªÎlÇaÜfu.TÊË˧””TVå¶ÑÏ?onË–dÞMн,÷¬ÌAÁÁUê©楨¨ˆý q*)˨åììÚ½{?­_¿‰Ö®ý…¶mÛÁB—aÙžêTǃv0 ;v,K¨¢XDñ,|0}ÿý\V·¿nãÆ%lÌ¡ûï¿ßà#”CÕ:±0Kåôés¬‰ì¦ 6ñB¸Î;'ÒU¨ýÄNzúqÚ´)™ÛÛªv*ÛfEhP·Ú–:?ƱœL¤ëý°T§.rèüéU¬ºdQæÁõ{p¯Ùç5UH¤h/kÕ¾Žö8Aâ·‰&qô£Œí•´ô3t0µ>«3¾ÌbÑUä+Ï߀7íÙs˜'ð€ž¢ãóñ©¤¿þõ¿hÚ´×Xk‰ô¤¤ž¼[|Lo¾ù±1ÞÌ“e7Š>_n±dÉwôÆÿ`f/}´ÛJ/¿üõéӗӇ㶠Þg[à¼0 ñ³nÝ zòɿаaÃÄCA~ýõMŸþ1?ÐÝ,$Îê+x($ÄZµªÏêãŸÙÀ½WŒ¥¸¸„ÆŽ}“Ö¬Ù,Â*PoZZ ø,—  ì%NÃÂÂŒ1/Zô ò_±@ã–À‚R«–?5mÅL܇úõë+TbeÉd¦ŸÂ6Å qÊû®qãº<æ[iÕª_y,)‚¶V-êÖ-:°ðída9/ÊC ›6 zóx†³M’Ã6èkÌÐG£búcbB©oßÎlÐßÄêãBÚ¹3…ÓµâÃéÑ<x.îü  n»½Œí¯Oy1üšíGMÀpëÖ  ®]¸?Ý髯ÖñóÈmáÅxBB$ót'aW ˆ×DÜñƒŸŸ?uèДZ´É Z›$åp1å4 &wù\ÖQv+­ß°Š6̧XÖ¨“¾e[-òö©#êÅ©•æs;•üc±ƒ7îàÌùHhÐ ˜FŒb‡ÄÓOåUå3F>Û?­©S'¨‰n¬jh³::t”WÚ³zLCaa=zT0(päH8pL„%.^Ä.qH„ñPW­ZÇBü¼Áf`üe¼Ãer¹™\ç7î9Á˜?þ¸•ÕBmeTz‹Š´$;»PØ>UV;á1âeZ½z£Ní œlçåÙ™)Opß?¦ï¾û‘^zé9êÜÿWàÅy¼CìÑ©5””p¿Î1ãU jaa93}:ÏqïP©zª†’’¬NkíÉt›Í‹ŸãlãLáAj+õýR…¨]»’zõêî²8IÈ9@·ÌóTRRI‡ç鱪þ2Œºýk©PŸ€×_Ÿã"rÌ€ÃáEgÎ੪.@k¿êðÅet eœË@t]lIÒA‡ƒŽš™™I[“Óè«u(ïb}M0˜^25|0;Ò† ¥ýû÷k  ·Ï( ý) 8Æ»7*Ë AC˜?.ÈÉÉÕCUÀü×­&l(u¢Ôð­[÷Š?ìd¿bc}é£&ðªûo~à XÀ²ÀÔÆ-Œ\Ü4ÀNÕ2!¡‘ÁÔ*ÀxŸ ¦ bõ¬•øgÊùó—±·K§ÒÚoôìÙ’ÛšÇLù=Ûk7‰tÉH0©RS³Y5ùŠŸ…þ0€N'ðóÓʶhÅõöt»è¸{([Q¡åyyáäP{ñ)é¥Ï,ÈÏý"÷ù0‡m¬2®éêÐÊß›û#wmªpvX©ÕAª°Ûm”švŽ’·eÒ–­Gió–£´fíúzÅIš· ‚.nBryÕgŒ÷ò*—¼ÈˆË‹ðó Âé—_6¹L4$7[ë“<L¨‡ë)êsèžf`.°2Y­x5VïTrs+èÓO¿b†\Ƶœ¾ùæ}6NÑ®]+yqùÃKyèÏ‚@‹Ï … ßaæw^ÁÍš…Ð'ŸLaÃûszæ™g„ý1{ö:…ÆD@LŒ«œQÛ¶myA g!zÓ…™`ßîØñ«PïÌtØ…Ú¶ §Y³ž§¥KgðN÷êÒ¥Ëož^×èÆ£éóϧÒ# ÔSUT½/KNÞã´HÊ>EF—íÇ*á×ôÁ“DÚ¥„Äè­$Ä<¡!7ò!¬ÿ¯WTÐÇ šÓ??K y‹hñ²–´~K"en,.-¢¼æ°zhŒ-„ÎH×\yy©|8*p F¹øzeõ~©ÎÝà\ßO <Þ˜¯‹Ú*…›Çšº‡8ŒG«~]K´nÝ\0# Û.,¬¤•+wÓÃOe{þô§AlŒŽb&~‰í•Ubç-¯víZ¢+& ö啳)ï@„p¤§ã¸ý´ž«Í%1üýhß¾CôÙg_±[ÂÌý Õ¯_O§Ò€çš•uNˆyŽd¼NbûÛSƒèÎ;»³!ÞT½W ùŒëq èÇuõbõéiËg¦±Èœð@_6î›ë¹î¡Ìd•€ép·¬îÞ¾Ì<\ÔÛÛ'•Wev 7˜—èLj«NO—ójeÇHðÆèZ^·¦ªY Hd¤ëÿcaÊͽ(TBx ˜ì±c§Ò=÷Œ W_Ê«ó.Þ¦‹-•B­ãRõá€à‰'‹°+­¶‹Â@?|8›w‹Ml\O¢§žz†ÒÒÒÆ#×Ì´’À<2×g®PŽãÓÓKéÅ?fc÷v¸0:KƒÅÅa'š›’ý !JLLa,>V}º@ElÐ*7„=P¨”f m8+ l[6ìKóæñ¯–¢2°*ØB æ¾P$ëyj\Ö+vËÅ-tzÐõ(uhý³f¸–-›ê!^tâÄ9:uê”Gšpœ?ŸK |ËúøaV –QRÒh^iÒÌ™³ÅÉÏïê—ÄÌVxã§Ù~Œ¤ö.à ²>¼gZ½z7« P^^žÁœ—ƒßË´xVwõÔÀ«¾¶ó\I¿¬ ‹ËÅôRý†i>°@¨ dAÁ¥Ÿ­«rÛ—š7–SQg|A(ÓW}StÕµƒ,£ÊB0tCúa…ž=»ð æÊ`'O°û%¯~Å".Ü3ϼÉõiú€#É´´Öï7ÿ.&‚†UVžÊà(¸:@¥ÆI§OÿB{÷®àmÊ)>>ÊÒ/-õbƒz+8àüÞÇ ª—Ò ¢\TQð_t´ Ò‹{ì>9ò.5ênzòɼ³ `ýý^VõJâ~=G·ß~»Á¼*|}¡®ùPP{!¿VÀ3ÅA†|Y*a·ãóŠR¶yÏôܹ ´u«óñ´\ æ‡ZI>&Y2(h%½ ñEN§QÃB Ø—uª@»šVj‚$ËÂɺط’0Y‹©k×zŠL ˜iÞ¼ïø!¡>šOÿüç"ºûî‘´bÅZª ÁÁ•4pà]Ʊ$ÆYp]ÆŒÒÒJ¶ÖÓ?üÀ†öRúòËë9ÖÀtŸ>}†¶mÛÉåþÃåÖ°šÒ€ë©,«…ëÝ»‹Ës))qˆwò¬lòò2±zÊãèÄĦ¬Š²¡ óƒ]?8ØAƒõ¦éÓ_¡÷Þ›Dï¾;‘}t0 zÛ=ÒäÉchÆŒWhøðÁâ–pmâ×:ïÚ£S§ë(..ZicÃó;{–XSXÁvÑh^t†ðBYýwN€µŠÅ®¼ŸÅ–ð¤iÛ¶(¬¾••¯—Q™X:™ŽUŸ}©. †åÊÅ{ùzN^ר(·1­~UEÖ£´ƒ6G™€Ëp˜éÓÇë) ÕT)øÐ˜V­ÚÍzö?è¹çfÒÚµ»u*gÜpCêÓ§³lÊ ázHÚBÿºÈ+ò+Ì\ÓŒ‚<è3TžQ£&òÃD}û>Ê ù2=ÿü,^ɧðX¦‹ûhõê…QÆ1z©*DE…‹k:N°p¢eî—;k8Í;WÌõС÷è¹UÌ|æL%Íž=‡Ö­[GÇg²ºùÝxãV9‡QçÎéºë’8Þ‡Þÿ}ñœj*F¾_iÀœã0+«ŒŸÿ¯”™©ÙUæga†! r‚@¯1ceçTКµY´v}&­]—A?¯;NfÓ…<~ø:Óôªã4§t„‘¦Ç uŒBÉf¥­Û²h㦠¶2„¿kwež‚A‰;\zÒ)õZ©X>‚Z¸pš‘f³ÜÍMƵèõ×_§=f¸›Ð®]oàÕWÓ}Aƒ6ნyQë/w‹»ÌSU?66š.^,æEŸ#kéÄ;ÈO¬6fÛª'ï€ËœÊVÒ½÷ÞÁy-E<&&‚š4Ñ®‚¨tùù^”œœAë×ïe·^ØVãÆ çrMt ï~üñï"ÏÓõ×÷g5s'÷ï½H¨žyy6f´Bñ.Å|*e“ä³­J/ÃÈWiÜáR4#G࢟«uJàÄ'{æt3\öb4‡6s‹ÑÚÍýiÎ'±ôáüxúha#úðÓxZ°¤=Ëhl0=¼`b×Ó Çq¹cÈ<4‹4ÿö”_:š–®ˆ§åÿnDËW7¢«ãé›ïZÐþCí¸úû¦EŸàdZ=Õî¾ûz²j3Õ`ÜKM˜M‹½Ë«ä=T=ylX•†Óí½V¨,C‡Þ-â’FmïzõjǶ‘ÆT2c,-ÕŽ—'LÍ*ßm"¬ªaff«,- Y';C‡öw˜ä 8èÞ7 ¶/ùħÎPÉ ”K—΋  ö o¯øgÚ´©Ç»Çë¬êõqi»²<æF^V4ø€Ví_Õ\b®«h¡js]êWˆ8†Ô:¸çÜçªcü?œL'>NõëGê)""iذÛèæ›¯×SÜ£jÑ}ƒ +‚¨Ô^›JJ5WH¥6„ñçÖ¾:&ª`üG–Lç¸!@ÈcéHãGÌ~8ÙÁ¼“’½Lse/whõèýÁܘw«D&µÿ;hçÎelhÞÏ;C¤iB5øúâ-t Mš4‚ Þ%¬^Ýàôp!`mÛ6g'”ØpžàPViê1Ã÷'&`4ÐÿíoãéÙg‡F¹Dýúa¼#bÕæ=qöQ[ÔÂöR#êÖ­› ƒ}ðÙgo³îÿ"¯Ðy•sY¿BCX‡¾Žmš·¸Í·¸>çOa+Œÿ0÷Ëu¬¸¬Ø¹sa@C°7ŽeÃõ3±›ÄÄ8¿ïðá&†¦LNË–ÍÂ!ç§m°ùbbÂŘ"#Ã(>>’ èïÒ/oûcc#Y- 3æwßð–Ï×_ŸÈõÕ1hðÜpIׄ$@!hêׯû}ÝqGo§Ïº³³³YúñιX¸åËgÒ7ßü¶o_A3gNçùu~NÆ¥òˆñMú°a/ÑŽ?’­"‰6Mþl€1¸h(ÔÍ©ÅüË4¦QóTµ¼HCEõ°Q‡â sYÝ·ÙÎТyyk_ÑŸ6àeazú1q´‹É€^߸qCª];T§p¤ËZ+`JJ:«#ùü£˜aâXh\_^šan«äñã'xçÈuBPqúiy” ˜ûÛ¶(ÛÐXIcb¢„pHs›øDep‰o6¢ÅÅT+ã¿&"77ŸÆŒ™*.ÚlùBðããcxÑiĪpWñFèÖm(íÚ¥Ý6–ˆŒ¬¤;ïìÌ‹Ô{â…¢" ¯°€ü@¥, qY@iLÊsçÄÀz:¦Ë``öwbv=Í g‡|ÖÓDèôtAËi".iؙ۷³€|ñÉŸ(*:ô²Œ¨Ì`†™YÌu¨°¢·ªGM3×ã®À].•Xõ£:\оº6ežŠË©KÂL{¹õYÑá.V«V}… ¨À…ÉŽciìØ±tá‚FŒ˜h”‡úqÖ1fÌÃläéÌjÎj—A9Uzc¨8ºeœ.éiÈ—å Õˆ}QNú QËI:·ªq%,Óñˆ´N_0x9Á˜ ÕIX=²ÕYéÕÕ­–WÓUÈ<µŸæúÜ••0—¿d}îÊTצÌS]u¸­9ߊ0Ó ÏØi;uj«STwÈ6o>I<ð=üð§ñ¡lPP¥øÚQ=½TDNŽÎäªã4ÉÈj؉Næ›hP§a˜é¦ÓuëiFjùº/û|¥0OêµÀÕª[íço©ï·”ý-ej dŸ§M{Î8‘@®ìk7ATàŒ£cdžl¿qúFI$IV,¸Rÿ ™R_Õ æÖãNŽÓ &×ãjžô­v‘¦”S…Nžd©Îëwˆÿw!ù‡ßÿ1õíÛÍ8Å´‚ŸŸ75iRž}v Í™3“n¾ùf§…A±A^eä{*´ÝA±Ç¯_<¢AvÒà†íÀ¾° P‰ ›ž\ÒžQÓG:êF\ÖƒtÄÙÙíhÙ(**øŠŒtþ'tòP!#ã>MGfŠkð8¼ ¤ØX ÄRëÖ âE-#¡ÈDÕT\>˜êDô§àZ ̈Øf­Ú%]M“4Ü€*F>œž®Ö!Ã((N8MéšÓv;GY2-ûr°^½n‰ ÿxð jQ*¼‘ˆiÝ:žU›ÖtC»0*È[Geör8l̈¥ìJ¨Œðíºã°NÎÁNÒ ¬æ±3èáÛô¸îPŸ >;éÛ™a#nÇU”JÝ7…O;ÇÆK¦šøUüï•p^,9B›OMM£ûïŸ(,ýÄ6m©°¸ŽøvÜÇGdbWÀj®ûZ˜%qeÚªˆî)ùšÁ=¤o@¤Uµ© €m£ÊÊ<¶†ÒÓÓ(¢ž/ $.¾úê«‚Ö®& ·råhîÜåtðà&‘YÓáÀ7ȳfÍ2.ëyàÁÕ„! {÷î¥7Óû 7>/ïí©SÕB“Fìšù%5h;‰VªqãÆâO®Ýÿuü>¸¾ ÿ¶^®§Ô @8dwqÕ=ä×–âDÿ ~\§OI„z·IEND®B`‚pyclustering-0.10.1.2/docs/logo/pyclustering_logo_02.png000066400000000000000000000102251375753423500231460ustar00rootroot00000000000000‰PNG  IHDRK7D®·P„iCCPICC profile(‘}‘=HÃP…OS¥b+íPÄ!Cu² *â(U,‚…ÒVhÕÁä¥ÐĤ¸8 ®«.κ:¸ ‚àˆ“£“¢‹”x_RhãƒËû8ïÃ}÷B³ÆT³gP5ËÈ$b¾°"^D˜*ˆ¨ÄL=•]ÈÁs}ÝÃÇ÷»8Ïò¾÷çPŠ&|"ñ,Ó ‹xxzÓÒ9ïGXERˆÏ‰Ç jø‘ë²ËoœË <3bä2sÄb±ÜÅr³Š¡OÇU£|!ï²Ây‹³Z«³vŸü…¡¢¶œå:Õ0’XD iˆQG5XˆÓ®‘b"Cç ÿãO“K&WŒóØ€ ÉñƒÿÁïÙš¥É 7)”z_lûcì­†mÛvëð?WZÇ¿Ñf>Iot´Ø0¸ \\w4y¸Ü¢OºdHŽä§J%àýŒ¾©„oþUwnísœ>9šÕÒ ppŒ–){ÍãÝ}Ýsû÷N{~?HXr–ÞΊxbKGDäää-›„} pHYsaa¨?§itIMEä  8’Õ4tEXtCommentCreated with GIMPWmIDATxÚíšiŒ]åyÇÏ{Î]fæÎæÝÆ6¼’–ŦØc' –ªRH+µ‘høÖmÚª[h>4‹ÔV*”ª‹Ú’¦ i+Ô&ÐôK jh ÆÆª¥6ÆÆž3ãufîÌ]ÎyŸ§Î9wó€cr¡£Ê¯<¾Ëóž÷ž÷þÏþÂåqy\—ÇåñÿrH·Ú’Çl§8w3F¯‰üYöÞÀÐÆ÷É?Óäšs;®M^ìzk\Yòš©ëo‚îUõãé䮌°+@ nY…¯*ú˘æ\X¨– 5?g@$O0H¾h®} mÌiز.€W€Aø£jµü3ÿ] ¶(Àêí]ã‚0ÿÅ8®Þ›Ë24¼V‡ÖÉÒ"É_ó½Öò½$ïÄRyóºt Bû:mßISEDQTãàÁ'®7³/ת³ÃïÃ~b°rai£“à T6_{·Ü¸ý3 ­!pqà8I^Åœœ ¹4åé\ç׊´ÈÓù¹ÉâÀT9{öV¬XŸ{äá?ߊ¸_ÀüAàÔÿ½ ë½Æƒýý+åúïeé²M-›H@‘NPÞCÞðÅåm§òµ}ƒŒìú~÷ëê}}“÷~õâËÈ H_i=½+ñ>¹ñÌP›\jRÌf `Ö*§)w&‰ rï"0iÈ ¸v¹aph¹\Á€л8 |j\DBT¯ f h­& Z6ié\YXN‡¼Të[ ¨˜Ð´xÝñúáO®…Éÿf  ê›n²ÈÒM\ËÌÒùïƒe^3gÒµè¨Ìr °¼7¼Ò΢tà 9pH×YÖ)W% DXÙ³3@ Ô·³ˆ–]Ì–ñ>Y–šÉÕwªnÙ¬”)Þ'ôT-qSNA&·ï\ÂÂ…X hª–ÎLÁË…,kÈS€3œ *à­«æª[|bà“6¼ÃýϳbÙ¹$6’°¢Øð~€Jí*"¿gBT}‰ÒQúzúÚr±ùªR‹n¢·wm ªPëĵ=.·üˆ=Óå+éí]³øÔ0ÌH˜¥ ù“Üqû===ïzE½^çÔ©S:t““/Sï¢^/aZæÎ;n#‚ÆÜ©©)}ì)rù{ ƒ3#®ícå Ƕm#Í(ÆŒ^`òô Åâjé*\]°YMfyM ¼8À9—&Ê4á,¥Yµj[·neß¾ýì?°‡|ñç9sþo¼q”;n&—Ë088ÈG¯åµÃ¡7šzåMFF~‰R©„ˆà½gllœW^býGngnî\;•»0\7X%™ÝÑÔÀg‹;G†8qÄqL½^'Š"âØ#"äóy …;wî`ÙÒóT+§‘àVöí?Âää$fFär9vï¡ûjµsTçÀÍ7ßD__a""Ôëuâ‡ôÝ‚sET¥«@u,Icß@+³#Þ366Æ_ûßxðßÙ¿ÿyêõ:ªÚcÓÆõÄÑ8âz¨F#ìÙó,Õjµ1§¿¿Ÿ]#×15ñM†‡`óæÍ„aˆDQľ}8}vƒƒÒx/u‹ ,Á!’†jxV”Ëe&&¯âÈ[wñܾ7˜™™i¨¥sŽáá!ÌæošÛÄØÄ|(Š{†\wÝOsç۹喓Ëåõ‹cÆÇ'xnÿÛ,_ykb |ÆHwKvÝ`–4ƒRMkéZ€¡?ÃÊåGéï÷„aØf˜kµ:Þ¨O<ª—[8ðÂ1&&&ˆãç…BÝ»w³|ùrÂ0DU©T+<ö½g(öÞŠsÔ7m§-:5LÈÀò~ U„5«Wsç'Vðñ‘:Ÿºû.J¥RbüÍPUFŸ$Š—$€{)0Wá©§ØPÇ0 ) är9ÌŒ(ŠØ»÷y&O­¦4ð‘F¡ž4(]t¡C3(Õôf­Cƒ `xx˜]»Fjd!@355Å+¯ž"Ìßž«i"l`üä[8p}lwã:U%ŽcNœã¹ý'Zzê[Sª$ÝYl6KRUjªáÅÒîŒÕj•ãÇóí‡ÿƒóå]˜åÆÙk²^=¾…_z‹ÉÉI¼÷ &FQÄ÷Ÿ|Ž w H®i«4SÃfF°¨‚RÁ%ùŸOÔÐð†ÓÓÓ:üz#g+ÏÍ3::ÅÑcåÊ.нW5Ë;\#).æ7röìYÖ¬YÓ»^¯s~:¤§ïª„E9¤Ê" J¥•YFÐɬ4ã¡}‹X·$ÞÓJ˜l¥_BwI0›%Þ-õ0Ì /x™b$åÂÄ=±ÒUMìŠÍ̤aàÛ6&M¯„k©V·¦õö¤dœ€ÔÜpR³R‘U,ÒZbÌ[‹Œ)^x³E˜HgÅH³4‘îÜPK‘Ú!³ Ä gj—ì¾uäIs+VFÛ‡æz.ë&ë©§ë|Ø!‚‘0+HëYPªÚ,«wÑRv.k¬6m­,3C[×óÍõŒ4½Ê@ÏX™–lÄeÕ!Ûø€FH077Gj ð±G3&`i!¯´lÃæRÕLå¨z*•JªòÉú™îdaV³ÅVVZ#x#ðpl´È?|ãÉF \€ùJ•ÙòõI¹·:lU¶V+ËNŸíç{O¼Hï3¯·=œ³çúè)µªn“e^Y„•Ò†ƒ–”YƉw~–ñÉz|"¸´ÑÐ0Þ´³ÈÌRƒÝ­<¿‘¹êÆŽ†­[DªÆ)Ë>ˆ ´ ¡C{w'ñ†Ù77ÜhµÙ*é`™´Ìíd¶Œ–~a‡­#í2-ÆtGD{ä ´n²£]•Ú*Ò g,ꔿËÚY˜…íªk&xkšˆEÕ°°–ªƒÓl“íMÏv–- ¿$–µÈéC2½Ñål§+ÞÐ¥ihÀ{¶Ö/•e¼+ËR¾ ¨Qâ-eQ1ËÔO»\¾N4Fõ9q®tÑÖz+‹.Ʋ´‹±ìBÕ=5u˜(šw¦qˆXó•“G ÅUûB™»mnúé>A.7˜Ôª4õ`™g\è˜P»ÇlùÜ!—ÎS3óÅ "žs§ñ£—¾a6í}­ L/ °ÊåãÓÅÂÒ¿è+]³ÎW~°¡\Mq}i¥9«íf~)=¥'Y‚Üz09à†eפy“b`biÃ-]'ýžì8¦$ï}T‘Ù™Q‹ãJu¶|ü%3ïNu¥;k¬îë½bÇÀàæÛòùá@z.?øØmQTþ|­väë—z#¥ÒöÀ}q<÷rµzøOù1Ì–JÛ‹À#f¶3Žg¯V{㡲?vEtðG`K¼¯}_$<ê\ð÷;`¾Dý¬§TÚ¶ä*ï«Çƒ 0ò3f>ªÕ&_,×,n2³SÞׄa¾|R$tÅâµÌü¹\i3p=˜3ÓõÚÔ«Åâê"p“Y\ƒ`Ð,V3žWŽ•JÛ7ƒ­õ¾>…k̬à}eoµzh²TÚ¾1ÓY° ·,Ž+G«ÕC£Ýö†»€åªñÛµÚÄ}ùüÊ#fácªU3«¿Þí¯¿ofß4³¯‰ÈÃÀ¼s}¿ü±™î;&âÖ9îéBaÅÙ ~¬ªz(ˆK€­@ÝÌžUÿÙûú£q\}ì?“æFõ Õú#"ò›`뼯~ìÏ@ŠÎ¿¥Z»2]¯7Žçô¾ò%WòfäRÌâ3ªÑß$ê,»D‚Û€]ªñT—?2ž^Sø Za'’ÔÆ †áòáRiÛ€Hð·aXz0ŠÊ7¼‡—,d¿ã}yÔLïF îq.÷aØóÛªÕäDR§ÒcaXz X â‚ pÈgÍôŒ™Í›YúÐt:ŠÎÿc>?´w!#®½ üPO=d1­Sœó¾üÔû‰½.A íC"á–|~ÙßT€Ÿ?£Zý”Z'Ï&*U‘e$¹ è]#"«Ìüóªþç Ÿ¹ìêÔƒá\n‹j}“sá+`?¥=)¾*"7¨Æÿí\x$½Ÿlþ=nØ·ú/ÕèHßt.¼ºX\õOÀ X“µ\þ¯7ÍôwÁö‰Èfv«j<Çs_Û öŽ™›éØã`/ËT£efþu3=i¦3À:‘àErhæû¼¯~'ŽÏ¼¶lT$Ü öi³ø«Àç w‹¸/&¿WGÄ͘é 3;™æ|vÒLÇAçÁN›é¸™«™é ГÞÏŽšé—Íô)ïëgÌü .1ô»äX¨PØ4$"ëÌ´à}åtq±¸e¹jTò~ú¬÷§§‹Åk¯0‹VÄñù‰0Í¢°^(6„"îJ3í7‹æ£hbÔ¬V.69‘àj³xÈû¹É8ž8Q,nYoæ¿ÕÓóQS­_aK½>:‹›W¨Æ}q|îL>¿BT£%ªó³a8tÞ,^£K>?Ø'ü½™VÌüÃÎå> v}½>ý¹zýÍ¿ú0#øE?úúnì‘?>mfÀTkûjµÉûTÏ» ÖZ±!ÁZ°A³¨E§ÆÍÊ3\Ýÿ ¤¼çO‰ØÚOIEND®B`‚pyclustering-0.10.1.2/docs/logo/pyclustering_logo_02.xcf000066400000000000000000033775111375753423500231630ustar00rootroot00000000000000gimp xcf fileBBQG gimp-commentCreated with GIMPgimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) Ò¼êY§ù‹åÃô d•) ìB úŽBig PY Shadow #1ÿ     N‹¯¼º¼Æ¼Ò¼Þ_oŸ¯¿Ïßïÿ/?O_oŸ¯¿Ïßïÿ/?O_oŸ¯¿Ïßï ) a 2º ­½ÍÝíù%c,ž5h>ÚI9SKY½YÍYÝYíYýZ bg´pnx {fõŠéŠü‹ ‹‹,‹<‹L“X›Šœ¢œ²œÂ¤Ü¬è¬ø­­­(­8­H°²Á²Ñ²á²ñµ·¸j¸z¸Š¸š¸ª¸º¸Ê¸Ú¸ê¸ú¹ ¹¹*¹:¹J¹Z¹j¹z¹Š¹š¹ª¹º¹Ê¹Ú¹ê¹úº ºº*º:ºJºZºjºzºŠºšºªºººÊºÚºêºú» »»*»:»J»Z»j»z»Š»š»ª»º»Ê»Ú»ê»ú¼ ¼¼*¼:¼J¼Z¼j¼z¼Š¼š¼ª€€€€€€€€€€€€ %ý#û"ù8LSTTSRQ P"î8q˜¦¨¨§¦¥¤££¢¡¡  Ÿ"êL˜ÎàãâáàÞÜÛÙØ×ÖÕÕÔÔÓÓ"êS¦àôöõóñïíêèæäãâáààßß"éT¨ãöøöôñíêçäáßÝÛÚÙØØ××"èT¨âõöôðìèãßÛ×ÔÑÏÍÌËÊÊÉÉ"éT§áóôðëæàÛÕÐÌÇÄÁ¾¼»º¹¹¸"èS¦àññìæàÙÒÊľ¹´°­¬«©¨§§þ¦!éS¥ÞïîèáÙÐǾ¶¯¨£žš˜–•““’"æR¤ÜíêãÚÑǼ²¨Ÿ—‘‹ˆ…‚€~}}"æR£ÛêçßÕÊ¿²¥š†yuqnmljjiiþh!æR£ÙèäÛÐ͍šŒwngb^\YXWVUUþT!åR¢Øæá×˽¯Ÿth_WRMKHGEDDCC"åQ¡×åßÔǹ¨—†xj]SKE@=:976655"åQ¡ÖãÝÒó£‘n_RG?830-+)((''"åQ ÕâÛÏÀ°ž‹yhYK?70*&$" "èQ ÕáÚξ­›ˆtbRD8/'#"åP ÔàÙ̼«˜„q_M@4)" ???P?Ÿ?Ó?ß?×?É?¸?¦?’?}?h?T?B?4?&??? #ü"ú ý"PùNG8&û ý Ÿ ù“}eUPOOòJ=*  ÓÔúÒ˼ªŸœœï–ƒiVOMG9(  ßàûßÝØÒÎÎÏëË¿¬ œ™‘}eTJ<) ×ר×èØÙÚÚÖÑÍÍÌǺ©”fO<( ÉÉÊËåÌÍÎÏÐÒÓÓÔÕÖ××ÓÎËÇ»©–€eN<(¸¸¹º»ä¼½¾¿ÀÁÃÅÆÈÊÌÎÐÑÒÓÓÑÌŸ¦”~dN¦¦§¨©äª«¬­¯°²´¶¸º½¿ÂÄÆÉËÍÎÏÍɶ¤“’’“”â•––˜™šœŸ¡£¦¨«®±´¶¹¼¿ÂÅÈÊËÊÆÀ}}~僄…ˆ‰‹“•™›ž¡¤§«®²¶º¾ÂÅÈÉhhijáklmmnpqsuvy|~„†Š‘”˜œ ¤¨­²·»ÀTTUVWXäY[\]_`cegjmprvy}€„‰’–› ¥ª¯BBCDEâFGGHIKLNPRUVY\^beilpuy~‚‡’˜ž4456â7899::<>@ADFHJLPSUZ]aejoty…‹&&'()+æ,-/012478:>?BEIKOTX\aglrxä !""$$&')*+-02479& !á/f¢ÇÐÊÀµªŸ’¤ª°¶»¾¾¸«–z[NSTSSRQPï %U„Ÿ¦§¦¦¥¤£¢¡¡  ŸêGŠÁÛááßÞÝÛÙØ×ÖÕÕÔÔÓÓê2o´âòôóñïíêèæäãâáààßßé ']ŸÔïööóðíêçäáßÝÛÚÙØ××çF‹ÈéôõòïëçãÞÚ×ÔÑÏÍÌËÊÊÉÉæ -l³áòôòîéäÞÙÓÎÊÆÂÀ½¼º¹¹¸¸åN”ÐíóñíèâÜÕÎÇÁ¼¶²¯¬«©¨¨§§¦å8w¹ãññíçáÙÒÉÀ¹±ª¤Ÿœ™—•””’’ä (`£ÖíñíçàØÑƼ²¨ ˜‘Œˆ„‚€}}ãGŒÈèðîéâÙÑÆº¯£˜Ž†ytpnljjiihá1n³àïðêãÚÐǺ­Ÿ”‡}skf`]ZXWVUUTTà $Y›ÑëðíæÝÓɼ­Ÿ‘ƒwkbYSNKHFEDCCBBàB†ÃæðîèàÖÊ¿±¢’ƒuh]SKE@<98765544 â *h®ÝîïêâÙδ¥”„tfYND<61.,*(''& áHÌêðíæÝÒǹ©™ˆwhYMA81+'$!  â2n³àïîèàÖʾ®Œ{k[LA6.&" á &\žÒëïëãÙÎó£’€o^OA6-% ,ý+ûPQRùQJ7 Ÿ ¡¢£ù¡”n7 ÓÔÕÖ×ôØÙÙÚÛÙÇ”J ßàáâðãääåæçèéëéÖŸP רÙÚîÛÜÝÞßàâãåæèçÕžO ÉÊËêÌÍÍÎÏÐÒÓÕÖØÚÜÞáàÏšM ¸¹ºè»¼¼½¿ÀÁÃÄÆÈÊÍÏÒÕØØÈ•K ¦§¨©èª«¬­¯°²´¶¸»¾ÁÄÇËÏÐÁH ’“”æ•–—˜™›Ÿ¡¤¦©¬°´¸¼ÀÅÆ¸‰D }~倂ƒ…†ˆŠ“–™ž¢§¬±¶»»ªz< hijãkllnoqrtvy|ƒ‡‹–›¡§­±¬’a,  TUVWãXYZ[]^acfilpuy~…‹‘—ž££”o@ BCDáEFFGHJKMOQUX[_chms{ˆ–™‘tI!  456á7889;<>@CFHMPTZ_emsz‚‰ŒyS) &'(á)*+,-/0258;?CGLQX`gnv}„…x[4  ã!"$%'(+.158=BGMT\ckrz~u\9 ã"$(+/38>DJRYairxvb? á!$(-27=CKRYajqshK(€€€€"åP ÔàØË»ª–n[K;0&  "åP ÔàØÊº©•mZI:.%  "åPŸÓßØÊº©“jXG8+" "åPŸÓß×ɹ§“~jVE6)  "åPŸÓß×ɸ§“}jUD5( "åPŸÓß×ɸ§“}jUD5( "åPŸÓß×ɸ¦’}iUC4' "åPŸÓß×ɸ¦’}iUC4' "åPŸÓß×ɸ¦’}iUC4' "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& ? ???€Ày5 5 // , *('&% $ø  #ï !ì !ë  è  é è  !"#$æ !#%&()*å  "%')+-.01æ !$'*-/24689ä "&),0369;=?Aå #'*.26:=@CFHJã #'+/37;?CGJMPRã #'+/358;?CGJMPRâ "&+032/-/258;=?Aâ  %*/45/# !ê #(-388-   ç  %+17<DE6"è !&,3;BHH9 "è #(.6=ELL< "æ $*08@IPP?! "æ  %,2:BKSSA" "æ !'-4GPXXE$ "ç ")/7?HRZ[G% !ç #)08AJT\]I& !ç $*18BKU^^J& !ç $*29BLV__K' !ç $+2:CMW``L' !ç %+2:CMW`aL' !ç %+2:CMW`aL' !ç %+2:CMW`aL' !ç $+2:CMW``L' !ç $*29BLV_`K' !ç $*18BKU^_J' !ç #)08AJT]^J& "ç ")/7@IS[\H&    ê #%(,038  ê  "%(-ì  #þ ó ó &ö " ÷ (û -ú# ü* þ/35þ5 -*)  &þ  % # !þ        ñ î þë ç  ã %à$##"! +,+ß*))'&%#"  232Þ10/.-+*(&$"  ý:;<<;à:987420.,*(%#  ýBCDDÝCBA?=;9742/,)&#  üKLMNNÛMLKJHFDB?<:730,)&" ûSTVWXXÞWVTRPNKHEB?;730,'$  ÔTUWZ^aa`_^\ZWUROKHD?;72.*&" ÓBDGOY`ba`_]\[\[XUQMID?:61,'" Ó"$(2@JMMLKJJOVZYXXVRNHC>83.'# Ò %'(''&)1>EHMSXYWRMGA;5/(# û  Ý$(0>KTXYVQJC=6/)# Ý  />LV\ZTMF>7/)" ß !1FX`_XPH@8/(" á .J`gc[RI@6.'!  ã 7Ylng]SI?4,& !ä &Jhtri^SH=3+# !ä4Xs{uj^RF;1(! "å Em‚€vi\PC7-% #æ5e…‹‚ugZK?3)! #æ )Z„“rcUF9.% #åL™˜‹|m]N?3)  #æD~ ¢–‡vfVF8.# #æB¨¬ €o]M?1& #æ@€«³©™ˆweSC6)  #æ6t¦·°¡~kYI:.# #æ +ež¹·¨—…q_N>1% #æ ,h£¿½¯ŠwdRB3& #æ;~´È´¢|hUD5( #æHÃÏǸ¦“€lXF7) #æN™ÊÔÊ»©–‚nZI9+  #æV ÍÕ˼«š„p[J:,! "æ +j®Ó×ͽ¬š†q]J:,   ç=BHMU\ckt}†™¢ª¯®yK$ Ý:qœ®«ž15:@FLS\cmvˆ’œ¥«ª™vJ$ Ý K}¡¬¥'+/3:?FMT\fox‚Œ–Ÿ¦¦–tI# Ý )YŒ¨ª"&*.4:@GNW_ir|†‘›££”sH# Ü9n™ª"&*/5;BIPZdmw‚—Ÿ ‘qG# ÜJ{Ÿ"',06>DLT_is~‰”œpG" Ý )XŠ#)-39@HQ\fp{†‘šœoF" Ü9n !&+07>FNYcny„™›ŽnCÜJ $(/4;CLWalwƒ˜šŠc3Ü ( "'-3;BJU`kwƒ˜•{N$ Ü "&+29AKU_kvƒ•‹mD Ü !%+28@IU`kw„Ž’‡i@Ý !%+28AJU`ly…’„_1Ü  %+19AKWbnz‡vHÝ !&+29CNXdp|‰ƒ_0ß !',4;DPZfr‰‰rFþß #(.6=FR]iv‚‰^2â $*08?JU`my„…rJ" â  %,2:BMXdq}…~a7á !'-4=FQ\iu„sM# â #)/7@JUamz‚}^2â  %,2;COZfr~€lBã "(/5?IS_kxwW,ä %+2:CNYeq|}h@ã !(/6>IS^kw~uS( ä %+2:CNYer|z`4ã "(/6?IT`lx{iAä %,4;DOZgszrQ' æ ")08@KVbnxw]2ä  &-4=GQ]iuxg@ã $+2:BNYeqxpO& å "(/7@JU`mwuY.å  &-4=GQ]itu^4 ã $*2:CNYeptd>å "(08AKUamtmM% ä !'-6>HR^jtrW,  ä %,4HS^jqiK$  æ  &-4=FP\hrpV+  æ %+2;EOZfppX-  æ $*1:BMWcnnW- !å #)09AKValmV-!å "(/7@JT`jlW0!ä !'.6?IS^im^; æ  &-5>HR]hohJ#  æ  &,4=FP[gqoU+  æ %,36.("     å —ˆyk[OD91)#    ã Ÿ‘rdUH>4,% â ¦šŠ{l^OC8/(! 㪢”…ufWI>5-$ 妨ŽoaRE;0)" 㘩¥˜‰yj\NA7-% â{ž©¡“ƒteVI=3+# ãXЦ¨Ž~n`QD:/'! á9m˜¨¥˜ˆyi[M@6,% àIzž¨¡“ƒsdUI=3+" á (WЦ¨Ž~n_QC9/'  à9m˜¨¤˜ˆyi[M@6,$ àIzž¨¡“ƒsdUI=3+" ß (WЦ¨Ž~n`QD:/'! Þ9m˜¨¥˜ˆyi[MA6,% ÜIzž¨¡“ƒteUI=3+" ß (WЦ¨Ž~o`QD:/'! ß9m˜¨¥˜ˆyj\MA6-% ßIz¨¡“ƒteWI=3+" ß 'U‡¤§Ž~o`RE:1)! ß5i”§¥˜‰zj\MA6-& ßFw›§¡“„ufXI=4+$ ß %Rƒ¡§paRE:1)! ß2c‘¦¤™‰zk\NB6-& ßAs˜¦¡”„ufXJ=5,$ ß #N~ž¦€pbSF;1)! à,\Œ¤¥™Š{l]NC8.& ßHR]iu|w^9%æ  %*08@JU`mx}sT,%å !&,2:DNYer|}h@$ä "'.5>HR^jv~uV,#ä $*08BLWcoz{hC #ã !&,2;EP[gs{v]8"ã #(/6?IT`lx}sT+"â  %+1:CMXdq||h@!á !&-4=GQ]iv}uU, ã #*07AKVbnyzgB  â  %,2;EOZgs{u]8ß "'.6>IT_lw|rT,ß $+19CMXdq{|hB â !&-4=GQ\iu}v[5ã #)/7AKVbnz}pN' â  %,2:EOZfs|{e>â "'.5>HS_kx~uU,ä $*09CMXdp{|iC â !&-3=FQ\ht|w^9ã #)/6?JUamy~tU,â  %+1:DNZfr}}iAþâ "'.5>HR^kw~vV,ýá $*09BLWcoz{hC ýâ !&,3;FP[ht|v]9ü &ã #)/6?IT`lx}sT+ûFä  %+1:DNYeq||h@û0mâ !'-5=GR]iu}tU,ú "V™á #*07AKVbnyzgB ú@ƒÁâ !&,2;EOZfrzt\8ù *f«Ûã "(.6>HS_kv{qR* øHŽËéä $+19CMXcoyzf? ø2n³àïâ !&-4=FP[gszrS+ ÷ &\Ñëïã #)/6@JT`kvwd@  ÷EŠÆæïí â  %,1:CMXcovqY6ö +j°Þîîé ã "'.5=GQ\grvlO( õHÌéïëä ä $*/7@JT_ktta;õ1n²ßííæÞ ã  %,2:CMWbmskN(ô %[›Ïéíéá× ã "(-4=FOZeno]< ôD‡ÃãìêäÛÐ â #)/6?HR\gmhQ1ó )f¬ÚêëæÞÔÈ ã  %+18AJT^hlbG% òD‰ÅãêçáØÍÁ Õ !'-3;CLU_hhW5-f§ÔåæáÚÐĸ Ô "(-4FOX^YF* !S»ÏÔÔÐÉÀµ§—Ö  $)/7>FNW[S< 4jŸ½ÉÌËÇ¿¸ªœ‹Õ  %)06>FOVWI/$I|£·¿ÁÀ»´¬ž×  $)06>FNSO@4?`‡ ­³µ³¯ªŸ’‚sØ  #*/6=EMPMKXpˆ˜¡¦¨¦¤’…vfÚ #).5ELRW[\[WRJA9/à "'-3:@EILMLJE>6/'á $)/38<>?><82,&Þ !&)-0221/-("ë  #&''÷%"å é  õ ù ÷    ú ýýþü áEŠÆæïíæÞÓȺ©—†ucSE7-$   Þ +j±ßïïéá×Ë¿¯žŒzhYH<0'  àHÍëðìäÛÐĵ¤“€o]M>3(  Þ2o³àïîçßÔÈ»«™ˆucSD6*! à &\ÑêïêâÙÍÁ± Ž|jYI:/$ áEŠÆæïìæÝÒÇ·§–ƒq_O@4( à +j±ßîîéàÖʾ­œŠxfUE7*! àHÍêðëäÚÏô£‘l[J1' à +j±ßîîéàÖʾ­œ‰weTE6*  àHÍêðëäÚÏô£‘~l[J1& Ý +j±ßîîèàÖʾ­œ‰veTC6*  ßHÍêðëäÚÏô£‘~l[J1& à +j±ßîîèàÖʽ­œ‰veTC6*  âHÍêðëäÚÎô£‘~lZJ1& â²ßîîèàÖɽ­œ‰veTC6*  âÐêïëãÚÎó£‘~kZJ;/$ ãäïíçÞÓÆº©˜†saQA4( âíïêâØÌ¿°ŸzhWG8," âðìåÜÑÆ¶¦”‚o^L>1& ãîèßÕɼ¬›‰veSC6*  â ëãÙβ¡~kYI:.# á æÝÒǹ¨—…r`P@4( ã á×˾®ž‹yfVF8+" â ÛÏõ¤’n\L=0% á ÔǺª™‡tcRB5) ã ÌÀ°ŸŽ{jYH:-# á Å·¦”‚p_N?2' á ¼¬›‰weSD7+  ã ²¡}lZJ;.$ á ¨–…r`PA3) á ‹ygVF8," ã "‘n\L>0& á  %†tcRC5*  á #)yhWH:-# à "'-m]M?2' â  %+1cRC6+  á $)/5WH:-$ à "'-3:L?2' â !&+18?A6*  à $)/5FMU]flkY9 â #(.3:AHPXahj`F$ ã  $*/5EMU^ddS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5ß #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5á #(.4;BJR[be[B"  ã !&,29@HPX`e_J- â  %*06=EMU^dcS5!ã #(.4;BJR[be[B" "ã !&,29@HPX`e_J-"ä  %*06=EMU^dcS5#å #(.4;BJR[be[B" $å !&,29@HPX`e_J-$æ  %*06=EMU^dcS5%ç #(.4;BJR[be[B" &ç !&,29@HPX`e_J-&è  %*06=EMU^dcS5'é #(.4;BJR[be[B" (é!&,29@HPX`e_J-(ê %*06>EMU^dcS5)ë#(.4;BJR[be[B" *ë!',29@HPX`e_J-*ì %*06>EMU^dcS5+í#(.4;BJR[be[B" ,í"',29@HPX`e_J-,î %*07>EMU^dcS5-ï#(.5FMV^dcS5/ñ.5FNV_edT51óGQYZG% "æ !'-4=FOWXE$ "æ  %,2;CMUVD# "æ $*19AJRRA" "è #(/6>GOP?! "è !&,43 â  &,28<6*""&*/49=Aâ #(.4:;:@CEåFŠÃÚÙ;¬™…p\J:+! "å/k¬ÕßÙ̽«™„o[I9+  !ä #V—Êàá×Ê»©—‚mYG7)  ãBƒ¾ÞåßÔÇ·§“~iVE6( ã2k¬×æåÜÑò¢zfSB3& á 2a›ÌäçáØÌ½¯œ‰uaN>0# Þ +GmÈáèäÜÒÅ·¨•n[I9,  Ù ,Gh°ÍáèæßÖ˽°ŸzfTD5) Ù +@Tm®ÉÛåèåàØÎ¶§–„p_N=0$ Ò*>KQYlˆŸ³ÉÚäèçäÞ×ÎÄ·«›ŠygVF7* ÒDGJLMNPWj†™ ¦³ÆÔÝãççåáÛÕÍø­Ÿ~n]M=0% Ї’–˜š¢°ÃÑÕ×ÛáäåäâßÛÖÐÉÀ¶¬Ÿ‘‚qbRC6*  Ó²ºÁÅÉÌÎÑÖÝâãââáàÞÛØÔÏÉû´ª‚tdUG:.$ ö»ÃÊÏÓÖØÚÛÜÜÝÛÙ×ÕÒÏËÆÁºµ­£™€seWI<1' ø³»ÂÇËÎÐÑÑßÐÎÌÊÇÄÀ»¶²«¤š‘‡{pcVI>3)  Ò¦®´¹½ÀÂÃÃÂÂÀ¾¼º¶³°«¦ ™‘ˆtj_SH=3)! ø—ž¤©­¯°±±ß°®®«©¦¡˜’Œ…}vlcYOE<2)! Óˆ•™œžŸŸ Ÿžœš—”‘Œˆƒ~xqjbZQI@7/'  ùv}…ˆ‰‹‹ÝЉ‡„‚|xtoic]VOIB:3,% ×einrsuuvuusrpmkgc_[VQKE?93-(! ØTY[^`abba`_^\ZWTQMID@;71,'" ÙCGJLMNNONLLKIGEB?<851-*%! ú57:;<==<;æ97430-*(%! Û*+-./00//..,**(&$"  û !"##"!ê þé þê   þ  ø þ þþþ! !þ #  $%(þ )-þ1þ/ý,ý(ý" û *ù &õ !ö $õ ò  ñ   ð     î  #%     í!#&(+     ç!$&),/2    ç!#%'*,/259 æ!#%')+.036:=Aå "#%')+-/258;>BEIä !"$%&(*,-02479@CFHKNQTW[_bfij()*++,,-- ./012Ü3456789:<=?ACEGILOQTW[^adgjkhb./012334 56789Ø:;<=>?@ACEGIJLNQSVX[^adgijihbWH679::;<<== >?@AB×CDEGHIJKMNPRTVX[]`cehijigbZQE5$?@BCDEEFFGG HIJKL×MNOPQRTUWXZ\_acegikkjgbYQF7,! GIKLMNOPPQQRSTUßVWXXYZ[]^`acdfgikkiihcZQE7+!  æ  &,4GQ[ehZ8 å "(/6?HR]fgS.!å #)07@IS^ghR+  æ $*19AKU`ihR*  æ %+2:CLVajjS+  æ  &,3;ENXcljR*  ä !'.5=GPZelhM&  ä "(/6?HR\fk`Aå #*18@JT^hjX5æ %+2:CLV`iiT- ä  &-4GQ[ekcF! å $*18@JS]giZ8ä  %,3:CLV`iiT.å !'.5=FOYckhO( ã #)07?HR\fkcF! ä  %+2:CLU_hjZ8å "'.5=FOXbjhQ,ä $*08@IR[ejbF! ä  &,3;CLU_hjZ8ä #)/6>GPYcjhQ,â  %+29AJS]fkcF" ã "(.5=ENWaik[8ã  %+29@IR[eljR,ä "(.5ENV`hmdI% â #(.4;BJS[dkjX7â !&,28?GOXaikaF$ á  %*06=DLU]fkdN/ß $).4;BJRZcjiX8â #(-39@GOW`hlcH% Þ "',28>FMU]fljX6ß "&+17=DKS[dklaF$ ß "&+06CHMRX^dilkbM1 )ë59=BFKPU[afjkeYG/ *ì=AEINSX^dhkjaN8$+íEINRW\bfjkeZG0 ,îNRV[`eikiaP;' -ðV[`eilkdWF0/ñ`dilmkaO8% 0òhkmkeYG/ 1ôjidYI7% 3öZQF6% 5÷8," 6ù 8û:þ=!á9m˜¨¤—ˆxiZL@5,$ !âIzž¨¡’ƒsdUH=2*" "ã (WЦ¨œ}n_PC9/'  "ã9m˜¨¤—ˆxi[L@5,$ #äIzž¨¡’ƒsdUH=3*" $å (WЦ¨œ}n_QC9/'  $å9m˜¨¤—ˆxi[L@5,$ %æIzž¨¡“ƒsdUH=3+" &ç (WЦ¨œ~n_QC9/'  &ç9m˜¨¤˜ˆyi[M@6,$ 'èIzž¨¡“ƒsdUI=3+" (é (WЦ¨Ž~n`QD:/'!(é9m˜¨¥˜ˆyi[MA6,%)êIzž¨¡“ƒteVI=3+"*ë (XЦ¨Ž~o`QD:/'!*ë9m—¨¤˜ˆyj\MA6-%+ìIzœ§¡“ƒteWI=3+#,í 'T…£§Ž~oaRE:1)!,í4f“¦¥˜‰zj\NA6-&-îDv›§¡“„ufXI=4+.ï %Qƒ¡§paRE:1/ð1c‘¦¤™Šzk]NB7/ðAr—¥¡”…vfXJ>0ñ "Jy›¥€qbSF1ò (V‡£¥š‹{l]N1ò8l•¥¢•†vgY2óHyœ¦žrc3ô (Wˆ¤¦›Œ|m3ô8l–¦£–‡w4õHyœ§ ‘‚5ö (W‰¥§œŒ5ö8m—§£—6÷Iz¨ 7ø (W‰¥§7ø9m—§8ùIz9ú (W‰9ú8m:ûI;ü (;ü<ý=þ=þÿü ûúú! ú& ù5ø4ø4÷ 3ö 2ö 2õ 1ô 0ó 0ó /ò .ñ .ñ -ð$ ,ï)! ,ï-& +î5,$ *í<1)! *íC8.& )ìK?5,$ (ëSG<2)! (ë^OC8.& 'êhZK?5,$ &ércTH<2)! &é}m_OC8.&  %è‡xhZL@5,$ %è’‚sdTH=2*! $çœ}n_PC9.&  #椗‡xhZL@5,$ #樠’‚sdTH<2*! "奧œ}m^PC8.& "å—§¤—‡xhZK?5,# !äz§ ’‚rcSG<1)  !äW‰¥§œŒ|m^OB7-%  ã8m—§£–†wgYJ>4+"  ãIz§Ÿ‘qbRE:/'  ã (W‰¤¦š‹{k\M@5+# â8m–¦¢•…ueWH;2(  âIzœ¦žo_PB7-% â (Vˆ£¥™‰yiZJ=3)  â8l•¥ ’‚rbSE9.%  ãHxš¤›Œ|k\L?3)" !ä 'U†¡¢•…udUF:.%  ã7j“¢~n^M@4)! !äGw— —ˆwfWG:/& "å 'U…Ÿž‘€o_N@4)! "å8m–¢™ŠxgVF:.% #å #VŒ¥¡’p^N?3( #æI†¨©›ŠxfUF8,# #æE‡®±¤“€n\L>0& #æFŠ´¸¬šˆvcRC5) #æH޹¿³¢~kYH9-# #æJ‘¾Å¹©—…q_M=0% #æK”ÃÊ¿¯‹wdRA3' #æL—ÆÏÄ´£}iVF7) #ãM™ÊÒȹ¨•mZH9,! "ãN›ÌÖ̽«š†q]L:." "åOœÎØÏÀ¯‰s`N=/# ýã !&,29@HPX`e_J-â  $*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  $*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â  %*06=EMU^dcS5â #(.4;BJR[be[B" ã !&,29@HPX`e_J-â $*06=EMU^dcS5ä #(.4;BJR[be[B" â !&,29@HPX`e_J-â $*06=EMU^dcS5á "(-4;BJR[be[B" â !&+18?GOX`e_J-ä $)/6=DLT]ccS5ã !'-3:AIQZad[B" á %*07>FNW_d^J,ã "(.4GOUTE, å $*19AJQTJ3 !å  &,4;DLRN<"  ç "(.6>FORF-!è #)08@IQRB% "è $+2:BKSTB# "è  %,3FMM< "æ $*18@IPP?! "æ  %,2;CLTTB" "æ !'-4=ENVWD# "æ "(.6>GQYYF$ !ç #)07@IS[[H% !ç #*18AJT]]I& !ç $+29BLV__K' !ç %+2:CMW`aL' !ç %,3;DNXbbM( !ç  &,3;EOYccN( !ç  &,4HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* ç "(/6>HS^ghQ* ç "(/6>HS^ghQ* ç "(/6>HS^ghQ* ç ")/7?IS^hhQ* ç ")/7?IS^hhQ* ç #)08@JT_hiR* ç $*18AKU`iiR* õPRTVWXYZ[[\\]^_`ÔabccddefgijkjihihcZTOF7+! Y[]_abccddeefghijãklmmkhggijicZTRPF8.)! õY[]_abcdeeffghijæklljcZSQRRPF8.+(! øFHIKLMNOOP QRSTìQG8.**+(! û$%&'(()*+,û)"  ÷    û #ZåOÐÚÑñ ‹vbO?0$ "åPžÑÜÓij¢xdQ@1& "åPžÒÜÔÆµ£zeR@1& "åPŸÒÝÕǶ¤zfSA2& "åPŸÓÞÖÈ·¥{gSB2& "åPŸÓÞÖÈ·¥‘{gTB2& "åPŸÓÞÖȸ¦’|gTB3& "åPŸÓÞÖȸ¦’|gTB3& "åPŸÓßÖȸ¦’}hTB3& "åPŸÓßÖȸ¦’}hTB3& "åPŸÓßÖȸ¦’}hTB3& "åPŸÓßÖȸ¦’}hTB3& "åPŸÓßÖȸ¦’}hTB3& "åPŸÓßÖȸ¦’}hTB4& "åPŸÓßÖȸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}hTB4& "åPŸÓß×ɸ¦’}iUC4' åPŸÓß×ɸ¦’}iUC4' åPŸÓß×ɸ¦’}iUC4' åPŸÓß×ɸ§“}jUD5( åPŸÓß×ɸ§“}jUD5( åPŸÓß×ɹ§“~jVE6)  åPŸÓß×ʹ¨“jWF7*! ç %,3HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç !'.5>HR]fgQ* !ç "(/6>HS^ghQ* !ç "(/6>HS^ghQ* !ç "(/6>HS^ghQ* !ç ")/7?IS^hhQ* !ç ")/7?IS^hhQ* !ç #)08@JT_hiR* !ç $*18AKU`iiR* !€€€€"åPŸÓß×ʹ¨”€lXG8,# "åPŸÓßØÊº©•€lYH9-# "åP ÔàØË»©•n[I;/%  "åP ÔàÙË»«—ƒo\K=1'  "åP ÔàÙ̼«˜„q^N?3*""åP ÔáÚͽ¬š†s`PB6-% "åQ ÕáÚξ®œ‰udTF;2*%!"åQ ÕâÛÏÀ°žŠxfVI=5.(%" "æQ ÕâÜÐÁ² Ž|j[NC:2.*(&$#""þ!!æQ¡ÖãÝÑô¢‘n_SH@84/.,*)((þ'!æQ¡ÖäÞÓŶ¦”ƒsdXNF?;65310//þ.!æQ¡×åßÔǹ¨—ˆxj^TLEA=;98766þ5!æQ¢×åàÖɼ¬œ~qe[TMIFCB@@??þ>!æR¢ØæâØÌ¾°¡“†yne^XTPNLKJIIþH!æR£ÙèãÚϵ§™Œvnga]ZXVUTSSþR!çR£ÚéåÜÒÆ¹¬Ÿ“ˆ~vpkgdb`_^^]"æQ¡ØçäÛÒÇ»¯£˜Ž…~xsomkihhggþf!çJ”ÆÔÒËú°¥›’‰‚{vrolkiihhg"ç7n“žœ—‘‹„|uoic_[YVTSRRQQ"è7JONLIFB?<8531/-,,++**#ð $ý  €ç !&,3:BLVajjS+  ç "'-3;CMWbkkS+    ç #)/5DKR\envtZ.!"æ#$%&')+.159=CIOW`hryw\/'(æ)*+,-/147:>CHNT[dlv}z^0./æ0123468:=@DINSZ`iqz~a156æ7889;<>ADGKOTY_fow†‚c3>?@èABDEGILOSW[afmu|„‹†f4HIJèKLMOQSVY\`diou{ƒŠ‹j6RSTèUVWXZ\_aehmqv|‚‰‘–m8]^ç_``acdfhknrvz„Š‘˜œ•q9fghèijklmoqtvz}†‹–œ¡˜s;ghiéjklmnprtwz~†Š•™m7 QRSëTUVWYZ\^acfjmqsmR* "*+,î-../0134689:7*( û .ý ˆåPŸÓß×ʹ¨”€lXG8,# åPŸÓßØÊº©•€lYH9-# åP ÔàØË»©•n[I;/%   åP ÔàÙË»«—ƒo\K=1'   åP ÔàÙ̼«˜„q^N?3*"åP ÔáÚͽ¬š†s`PB6-% åQ ÕáÚξ®œ‰udTF;2*%!åQ ÕâÛÏÀ°žŠxfVI=5.(%" æQ ÕâÜÐÁ² Ž|j[NC:2.*(&$#""!æQ¡ÖãÝÑô¢‘n_SH@84/.,*)(('æQ¡ÖäÞÓŶ¦”ƒsdXNF?;65310//.æQ¡×åßÔǹ¨—ˆxj^TLEA=;987665æQ¢×åàÖɼ¬œ~qe[TMIFCB@@??>æR¢ØæâØÌ¾°¡“†yne^XTPNLKJIIHæR£ÙèãÚϵ§™Œvnga]ZXVUTSSRçR£ÚéåÜÒÆ¹¬Ÿ“ˆ~vpkgdb`_^^]æQ¡ØçäÛÒÇ»¯£˜Ž…~xsomkihhggfçJ”ÆÔÒËú°¥›’‰‚{vrolkiihhgç7n“žœ—‘‹„|uoic_[YVTSRRQQè7JONLIFB?<8531/-,,++* *ð% ý) €ç !&,3:BLVajjS+ ! ç "'-3;CMWbkkS+ !  ç #)/5DKR\envtZ.!þ!""æ#$%&')+.159=CIOW`hryw\/!þ'((æ)*+,-/147:>CHNT[dlv}z^0!þ.//æ0123468:=@DINSZ`iqz~a1!þ566æ7889;<>ADGKOTY_fow†‚c3!þ>??@èABDEGILOSW[afmu|„‹†f4!þHIIJèKLMOQSVY\`diou{ƒŠ‹j6!þRSSTèUVWXZ\_aehmqv|‚‰‘–m8!]^ç_``acdfhknrvz„Š‘˜œ•q9!þfgghèijklmoqtvz}†‹–œ¡˜s;!ghiéjklmnprtwz~†Š•™m7!QRSëTUVWYZ\^acfjmqsmR* !*+,î-../0134689:7*! û "ý ¤€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ääää‹‹ÅÅbb11X&Drop Shadow #5ÿ     SAD½¡X&½ÅYwYƒYY›X&¿9ÆÇ½È ÈUÈ¡ÈíÉ9É…Ï‹ÒÚ¹ÚÉÚÙÚéÚùÛ ÛÛ)ß‚ãÒì`ìpì€ìì ì°ìÀìÐñõlýúþ þþ*þ:þJþZþj¸”¤´ÄÔäôR !.!>!N!^!n!~!Ž!ž%ì*:2È2Ø2è2ø333(387†;ÔD¡E–E¼EâFF.FTFzK¶P"ScT)T[TT¿TñU#UUX¿ü630þ-ø +ó (ï &í  $ë !$'),#é  $'*.148;!ç  $(,049=ADHLå "&+05:?DINRW[_â #(-39?EJPV[afjoså #)/5;BIOV]ciouzæ #)/5IT`lx)î %-7ALXdq*î &/9DO[hu*î &/:EQ^ky*î &0;FS`n{+ð &/;GTao,ð %/:FTbp,ð #-9ESap,ð ",7CQ`o-ñ  )5AO^n-ð '2>L[k{-ï $/;IXhy-ñ !,8ETdu-ñ (4AP`q.ò $0=K[l!ü„|uñ !+8FVfxú‚yqiaò '3@P`rø„yof^VOò "-:IZk÷|qg]TLE>ò (4CSdvõ‚vk`VLD<60ò #.3)! ñ &3BRexíwgXJ>2)  ó  +9HZmìzjZL?3)  ñ $0?Oauî~m]N@4)  ò (5EViì‚qaQC6+! ó  ,:J\píveUF8-# ó $0?Pcwð|kZJ0$ ‚@?<98 ù 6ù6ø5 õ"#%'()**++,4,÷.0246789::4;ô=@CEGHJKKLLM3MôORUWY[\]^__`3`ôbfikmoqrsttu3uýwzFö‚}{yxwvvu,uñ€|wtpmjhfdcbaa`,`í‚|vqlgc_\YVTRQPONNM,Mínhb]XTPLIFDB@?>=<<;,;ð[UOJFB>;86320/.---,îIC>:62/,*(&%#""!! - ñ94/+(%" .ò+'# /ò   / ô 1õ 1÷ 4ù4ú59<þþ€????? ??? ?,?;?M?`?u@?u?`?M?;?,? ??? ????À€????? ??? ?,?;?M?`?u@?u?`?M?;?,? ??? ????À€????? ??? ?,?;?M?`?u@?u?`?M?;?,? ??? ????À€????? ??? ?,?;?M?`?u@?u?`?M?;?,? ??? ????À€????? ??? ?,?;?M?`?u@?u?`?M?;?,? ??? ????À€????? ??? ?,?;?M?`?u@?u?`?M?;?,? ??? ????À€)#   ð ë  æ  ,+*å)('%#"   ;:á9876420.,)'$"  MLKàJHGEC@=;841.*'$   `_Ü^]\[YWUROLHDA=940,($   utÚsrqomkifb_[WRNID?:50+&" àzwsojfa[VPKE?93-(# "ázuoic]VOIB;5/)# $æwpibZSKD<5/)# &åume]TLD=5/(" &æxof^ULD<5-'! 'éypg^TKC;3+% (êzpf\SI@80(" )éxndZPF=4,$ *ëvk`VKA8/'  ,írg[PF;2*" -îxl`TI?5,$ /ðqdXLA7-% 0ñuh\OD9/& 1òyk^QE:0& 2ó|n`SF;0& 4õpaTG;0&5öpbTF:/%6÷paSE9-#7øp`QD7,"8ùn^OA5*8ù|k\L?2uuvøwxy{}‚*úyhXI;``aóbcdfhjmpsw|€&ûudTEMMNïOPQRTVY\_cglqv|‚#üq`P;;<=î?@BDFILPTX]bhnu|„!ýl[,,-ë./02368;>BFJOU[aiqy‚ýxg  !"ë#%&(*,/26:>CIOV^foy„þré "%(+/49>ELT]gq|è #'+06JWet„'î !)3>JWfu*ï  )2>JXgw+î  )3>LZjz,î  )4@N]m~,ð !+6BQ`q‚,ð #,8FUev-ð %/Oau þþûúùø ÷ ÷ ö  õ  õ   ô'  ó/$  ó8,!  òA4(  òK=0%  ñVF8+! ñ`P@3' ðkZI;-" ðvdSC4( ðn\K/#  ô &4EWkñq]J:+   ô (6FYmñ€lXF6(  ò )7H[oñ|gTB2%  ò *8I\qñwcP>/"  ò *9J]rñt_L;,   ò +:K^sòp\I8* ò +:K_tñ‚mYF6( ò ,;L_tñjVD4& ò ,;L`tñ}hTB2% ò  ,;L`uñ{fR@0# ò  ,;L`uñydP?/" ò  ,;L`uòxcO>.! ò  ,;M`uòwbN=.! ò  ,;M`uòvaN<-! ò  ,;M`uòvaM<-  ò  ,;M`uòuaM<,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,  ò  ,;M`uòu`M;,   "ò +9I[n‚0ñ &4CUh|0ó #/>Obv0ó +9J]q1ñ (6FXl€0ó %2BTg|0ó "/>Pcw1ò  ,;L_s1ò *8I\p1ñ (6FYm‚0ó &3DVj0ó $2BTh}1ò #0@Rf{1ò "/?Pdy1ò !.=Ocx1ò !-=Nbw1ò  -.! ò  ,;L`uñydP?/" ò  ,;L`uñ{fR@0# ò ,;L`tñ}hTB2% ò ,;L_tñjVD4& ò +:K_tñ‚mYF6( ò +:K^sòp\I8* ò *9J]rñt_L;,   ò *8I\qñwcP>/"  ò )7H[oñ|gTB2%  ô (6FYmñ€lXF6(  ô &4EWkñq]J:+   ô %2BThñvbO>/#  ó #0@Rezð|hUC4'  ò ".=Obwð‚n[I9+   ò  ,:K^sðuaO>0$  ò )7H[oð|iVE6)  ô '4DVjï„q^L2)  ó "-;K\oîufWJ>3)! ò (5DTfyî„tfWJ?4+# ñ #.ò '3@P`rø„yof^VOñ !+8FVfxú‚yqia ò $0=K[l!ü„|u ñ (4AP`q# @þ=<9ú5ù4÷ 4õ 1ô 1ò   / ò+'# /ñ94/+(%" .îIC>:62/,*(&%#""!! - ð[UOJFB>;86320/.---,ínhb]XTPLIFDB@?>=<<;,;í‚|vqlgc_\YVTRQPONNM,M @????? ??? ?,?;?M @????? ??? ?,?;?M @????? ??? ?,?;?M @????? ??? ?,?;?M @????? ??? ?,?;?M @????? ??? ?,?;?M&ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  ,;M`u1ò  -Pcw0ó %2BTg|0ñ (6FXl€/ó +9J]q0ó #/>Obv0ñ &4CUh|/ò +9I[n‚.ò $0>Oau/ò )6EVi|.ñ #.LZjz(ï  )2>JXgw&î !)3>JWfu#í #+4>JWet„ ë %-6@LXftƒ ì !'/8BNZgu„ ê $+3ELT]gq| !"ë#%&(*,/26:>CIOV^foy„þr,,-ë./02368;>BFJOU[aiqy‚ýxg;;<=î?@BDFILPTX]bhnu|„!ýl[MMNïOPQRTVY\_cglqv|‚#ýq`Pòu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`M;,   òu`L;,   òu`L;,   òt`L;,   òt_L;,  òt_L:+  òs^K:+  òr]J9*  òq\I8*  òo[H7)  òmYF6(  òkWE4'  òhUB2% ñzfR@0# ñwbO=." òs_L;,   òo[H8)  òjVD4' ñzfRA1$ ñu`N=.! ño[I9* òiVD4' ñwcP?0$ ñp]J:,  ñiVE5( ñubO?0$ ñmZH9+  ðxeSB3& ño\K;-" ðyfTD5( ñp^L<.# ðzgUD5) ðp]L=/# ðxfTD5) ðn\KL[k{.ñ  )5AO^n.ð ",7CQ`o.ð #-9ESap.ð %/:FTbp.ð &/;GTao-î &0;FS`n{,î &/:EQ^ky,î &/9DO[hu,î %-7ALXdq,í #,5>IT`lx*í ")2;EP[fr*ì  '/8AKV`kv)ë $,4=FPZdnx(ê !(08@IS\fpy(é %+3;CKT]gpy'ê !'-4 áöùúûûúøöóîéãÛÓÉ¿³§›‚vk`VLD<60àõøúûûúùöóïéãÛÒȽ±¤˜‹~qeZOF=5/)$à÷ùûûúù÷óïêãÛÒǼ¯¢•ˆzmaUJ@70)#ßöùúûúù÷ôðêãÛÒÇ»¯¡“…wj]QF<3+$Þõøúûúù÷õðëäÜÓȼ¯¡’„ugZNC8/'! Þ÷ùúûúøõñìæÞÔɽ¯¡’ƒtfXL@6-% þýöøúúâùöòîçßÖË¿±¢“„tfWJ?4+# þÝ÷ùúúù÷ôïéâØÍÁ³¥•…ufWJ>3)! ýöùúúáøõñëäÛÐͧ˜‡wgXJ>2)  þÜ÷ùúúùöòíæÞÔȺ«›‹zjZL?3)  þßøúúù÷ôïéá×̾¯Ÿ~m]N@4)  þÝ÷ùúúøöñìäÛÐô¤”‚qaQC6+! Þøúúù÷ôïèßÕȺª™ˆveUF8-# þâùúúøöñëäÚÎÀ± Ž|kZJ0$ ‚@?<@úùø1÷úùø÷ö1õóùøø÷ööõôóóòòññ0ðòöõôóòñðïîíìëëêê/éñòðïíìêéçæåãââáàà.ßîëéçåãáßÝÜÚØ×ÖÕÕÔÔÓ-ÓðãàÞÛØÖÓÑÏÍËÉÈÇÆÅÅ-ÄíØÕÑÎËÇÄ¿¼º¸·µ´´³³²,²íËǾ»·³°­ª¨¦¤£¢¡  Ÿ,Ÿí»¶±­¨¤ ™–”’ŽŒ‹‹Š,Ší©¤Ÿš•Œˆ…‚}{yxwvvu,uí–‹…€|wtpmjhfdcbaa`,`í‚|vqlgc_\YVTRQPONNM,Mínhb]XTPLIFDB@?>=<<;,;ð[UOJFB>;86320/.---,îIC>:62/,*(&%#""!! - ñ94/+(%" .ò+'# /ò   / ô 1õ 1÷ 4ù4ú59<þþ€???@?÷?õ?ð?é?ß?Ó?Ä?²?Ÿ?Š?u?`?M?;?,? ??? ????À€???@?÷?õ?ð?é?ß?Ó?Ä?²?Ÿ?Š?u?`?M?;?,? ??? ????À€???@?÷?õ?ð?é?ß?Ó?Ä?²?Ÿ?Š?u?`?M?;?,? ??? ????À€???@?÷?õ?ð?é?ß?Ó?Ä?²?Ÿ?Š?u?`?M?;?,? ??? ????À€???@?÷?õ?ð?é?ß?Ó?Ä?²?Ÿ?Š?u?`?M?;?,? ??? ????À€???@?÷?õ?ð?é?ß?Ó?Ä?²?Ÿ?Š?u?`?M?;?,? ??? ????À€)#*,-ï .ï .ï -ï -ï -ï  .ï$  .ï&" -ï-(# .í/)# -ï5/)# -ì=5/(" ,ìD<5-'! -ïC;3+% -ïI@80(" -íPF=4,$ -îVKA8/'  .ï[PF;2*" .ïl`TI?5,$ ÷÷+ðqdXLA7-% õõ'ñuh\OD9/& ððñò$òyk^QE:0& ééêëûìíîï!ó|n`SF;0& ßßàöáââãåæçéêóŒ~paTG;0&ÓÓÔÕõÖרÚÜÝßáãåôpbTF:/%ÄÄÅòÆÇÈÉËÍÏÑÓÖØÛÞõŽpaSE9-#²²³´ñµ·¸º¼¿ÂÄÇËÎÑÕØõŽp`QD7,"ŸŸ î¡¢£¤¦¨ª­°³·»¾ÂÆËÏö~n^OA5*ŠŠ‹íŒŽ’”–™ ¤¨­±¶»ÀÅöª›Œ|k\L?2uuvìwxy{}‚…ˆŒ•™ž¤©¯µ»÷©™‰yhXI;``aêbcdfhjmpsw|€…Š–œ£ª±¸÷µ¦–†udTEMMNéOPQRTVY\_cglqv|‚‰—Ÿ§°ø²£“‚q`P;;<=ê?@BDFILPTX]bhnu|„Œ•ž§ø½¯ŸŽ}l[,,-é./02368;>BFJOU[aiqy‚Œ–ùº«›Šxg  !"ê#%&(*,/26:>CIOV^foy„Žùͦ•„rè "%(+/49>ELT]gq|ˆúÀ±¡}è #'+06JWüÚÏÁñ !)3>JüàÕÈò  )2>JýÚÎò  )3>ýßÔó  )4ýäÚõ !+6ýèÞõ #,ýëâö %þæ÷ þéø !þì÷ þîø þðù þñ ú þó ù ôþþûúùø ÷ ÷ ö  õ  õ   ô'  ó/$  ó8,!  òA4(  òK=0%  ñVF8+! ñ`P@3' ðkZI;-" ðvdSC4( ïn\K/#  þåúù÷óíåÛξ­š…q]J:+   þæúùöòìãØË»©•€lXF6(  üæúøöñêáÖÈ·¤|gTB2%  üæùøõðéßÓÅ´¡ŒwcP>/"  üæùøôïçÝѰˆt_L;,   üçù÷óîæÜÏ¿­š…p\I8* üçù÷óíåÚͽ«—‚mYF6( üçøöòìäÙ˺¨”jVD4& üçøöòëã×ɹ¦’}hTB2% üçøöñëâÖÈ·¤{fR@0# üçøõñêáÕǶ£ŽydP?/" üèøõñêáÕÆµ¢xcO>.! üèøõðêàÔÅ´¡ŒwbN=.! üèøõðéàÔÅ´ ‹vaN<-! üèøõðéàÓij ‹vaM<-  üèøõðéßÓijŸ‹uaM<,  üèøõðéßÓijŸŠu`M;,  üè÷õðéßÓijŸŠu`M;,  üè÷õðéßÓijŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,   "ú þõ"ù þö"û þö"û þ÷#ú þ÷#üþ÷#üþø$ûþø$ûþø$ûþø$ýþø$ýþø%üþø%üþø%üþø%üþø%üþø%üþø%üþø%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ü÷€ÿðéßÓij ŒwbO=." ñêáÕǶ£zfR@0# òëã×ɹ¦’}hUB2% óìäÙÌ»©•€kWE4' óíåÛͽ«—‚mYF6( ôîæÜÏ¿­™„o[H7) ôïçÝÐÀ¯›†q\I8* ôïèÞѰœ‡r]J9* õïèÞÒ±ˆs^K:+ õðèßÒñž‰t_L:+ õðéßÒòž‰t_L;, õðéßÓIJŸŠt`L;,  õðéßÓIJŸŠu`L;,  õðéßÓIJŸŠu`L;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,   &üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ü÷€ÿõðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,   &üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ü÷€ÿõðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,   &üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ü÷€ÿõðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,   &üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ü÷€ÿõðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,   &üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ü÷€ÿõðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓIJŸŠu`M;,  üè÷õðéßÓijŸŠu`M;,  üè÷õðéßÓijŸŠu`M;,  üèøõðéßÓijŸŠu`M;,  üéõðéßÓijŸ‹uaM<,  üéõðéàÓij ‹vaM<-  üéõðéàÔÅ´ ‹vaN<-! üéõðêàÔÅ´¡ŒwbN=.! üéõñêáÕÆµ¢xcO>.! üéñêáÕǶ£ŽydP?/" üéñëâÖÈ·¤{fR@0# ûéòëã×ɹ¦’}hTB2% ûéòìäÙ˺¨”jVD4& ûêíåÚͽ«—‚mYF6( ûêîæÜÏ¿­š…p\I8* ûéïçÝѰˆt_L;,   ú êéßÓÅ´¡ŒwcP>/"  úêêáÖÈ·¤|gTB2%  üëãØË»©•€lXF6(  üêåÛξ­š…q]J:+   û ëÞÑòŸ‹vbO>/#  û ëÕǶ¤|hUC4'  ú ëØË»ª–‚n[I9+   ù ëÏÀ¯‰uaO>0$  ù ìŵ£|iVE6)  ú 컪—„q^L2)  ÷ "-ðWJ>3)! ÷ (!òJ?4+# õ #.#õ6-% ö )5&ù! ô #/=*þõ )5D2õ #.<3õ (4C2ô "-:I2ô '3@P1ó !+8FV1ò $0=K[l/ñ (4AP`q# @þ=<9ú5ù4÷ 4õ 1 @??? @??? @??? @??? @??? @???&üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%üþ÷%ýþø%ýþø%ýþø%ýþø%ýþø%þþø%þþø$ýùø$ýùø$þýùø$þýùø$þýùø#þùþø#þüúù÷;üúù÷"þüúù÷:úýùö:úýùö:úýøõ9úùúú÷ô9úüù÷ó8ùùúúùöñ8ùùúúøõð7øøúúù÷óî7øùúúùöòì6÷÷ùúúøõðé6÷øúúù÷óîæ5ö÷ùúúøõñëâ5öøúúù÷ôïèÞ4õ÷ùúúøöòìäÚ4õùúúù÷ôïèßÔ3þøúúøùöòìäÚÎþó÷ùúúù÷ôïèàÕÈ "óùúûúøöòìäÚÏÁ þ#òøúûúù÷ôïèßÔǹ'ñ÷ùûûúøõñëãÚÎÀ°+ð÷ùúûúùöóîçÞÓÆ·§.ï÷ùúûûú÷ôðêâØÌ¾®.ïùúûûúøõñìåÜÑĵ¥“-îøúûûúùöóîçßÕÉ»«šˆ,íøúûûúù÷ôïéáØÍÀ±¡}+ýøúûûñù÷ôðëäÛÐͦ•„r*ýøúûûðúøõñìåÝÓǺ«›Šxg(ü÷ùúûûïúøõòíæßÕʽ¯ŸŽ}l['ü÷ùúûûïúøõòíçà×ÌÀ²£“‚q`P€¦õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`M;,  õðéßÓIJŸŠu`L;,  õðéßÓIJŸŠu`L;,  õðéßÓIJŸŠt`L;,  õðéßÒòž‰t_L;, õðèßÒñž‰t_L:+ õïèÞÒ±ˆs^K:+ ôïèÞѰœ‡r]J9* ôïçÝÐÀ¯›†q\I8* ôîæÜÏ¿­™„o[H7) óíåÛͽ«—‚mYF6( óìäÙÌ»©•€kWE4' òëã×ɹ¦’}hUB2% ñêáÕǶ£zfR@0# ðéßÓij ŒwbO=." îçÝÐÁ¯œˆs_L;,  êíåÚͽ«˜ƒo[H8) êëâ×ɹ§“jVD4' êéàÔÆµ¢zfRA1$ êæÜÐÁ°‰u`N=.! êäÙ̼«˜ƒo[I9* ëàÕÇ·¥‘}iVD4' ëÜбŸ‹wcP?0$ ëØË¼ª˜„p]J:,  ëÓŵ£}iVE5( ìÍ¿®œ‰ubO?0$ ìǸ¦”€mZH9+  ìÀ°ž‹xeSB3& í¹¨•‚o\K;-" í±ŸyfTD5( ƒp^L<.# zgUD5) î•‚p]L=/# ï‹xfTD5) ïn\KL[k{Œ-ï  )5AO^n~,í ",7CQ`oŽ+ì #-9ESapŽª*ë %/:FTbp›¨µ)ê &/;GTao~Œ™¦²½'è &0;FS`n{‰–£¯ºÄ&ç &/:EQ^ky†“Ÿ«¶ÀÉ%å &/9DO[hu‚Ž›¦±»ÄÌÓ#â %-7ALXdq}‰• «µ¾ÆÎÔÚà Þ #,5>IT`lx„𤮷ÀÇÎÕÚßäçë× ")2;EP[fr}ˆ“§°¸ÀÈÎÔÙÞâæéëîðñòôØ  '/8AKV`kv‹•Ÿ¨°¹ÀÇÍÓØÜàãæéëíîÙ $,4=FPZdnx‚Œ–Ÿ¨°·¿ÅËÐÕÙÜßâäçÚ !(08@IS\fpyƒŒ•ž¦®µ¼ÂÇÌÐÔ×ÚÝÛ %+3;CKT]gpy‚‹”œ£ª±·¼ÁÅÉÍÐÞ !'-4[y–²Ë×ßèðøýùóíçÛÉ"÷Cx«Ýþÿÿ!øi¶÷ÿÿùnËþÿÿú,—óÿÿü1¸ÿÿû ýÿÿü~õÿ!ÿü%Êÿ#ÿü_òÿ$ÿýžÿ&ÿ @ ü8 û 4 û & ý $ ü ! ü  ý  ý  ý ! ý # þ  @ ü8 û 4 û & ý $ ü ! ü  ý  ý  ý ! ý # þ  @ù.-+( 83ú0.)" 3 3û1-&&3ü. #3ü0&!3ü0%3ý03ý*  3ý0!3ý1#3þ  3 €82ö þ(븥nL) "ûÿîé¾_/! ù  ÿðùÇŠH*" ÿòþЄ>.# ÿóó«Q7*þÿÿó÷¯X=.  þÿÿôñ–Q>- þÿÿô×rN:'þÿÿôó”^F1 þÿ ÿôý·kR:% þÿ"ÿõÈvZ@) þÿÿ À - - - - - - - - - À - - - - - - - - - À3-3-3-3-3-3-3-3-3- )û&ù %ÿ÷'% $ÿöNI?1#ÿözsdL1 #ÿöŸ–ƒd? #ÿö¸®—sI&#ÿö¸ zN'#ÿöÆ»£|O(#ÿöǼ¤}O)#ÿöǼ¤}O)# ÷ ;  9  7  5  3 1 / -ý   ÷ ;  9  7  5  3 1 / -ý   ÷1;û01338ý02337ý/2335ý/2333ý.2331ý.13 3/1 3-13 y7ö3ôBÁ  1òCÁÿÿ " /ûCÂÿÿø4>?6&-ûDÂÿÿøXbaP6 +ûDÃÿÿø†~eB")ûEÃÿÿø ¡’rJ&'ûEÄÿ ÿø¶²žzN(%ûFÅÿ ÿøÁ¹¢|O(#ûGÅÿÿùÆ»£}O) Àþ=þ=ý<ý<ý<ý<ý<ý<ý< ñ 0 0 0 0 0 0 0 0  ñ 0 0 0 0 0 0 0 0  ñ30303030303030303 5 2û1ù 0ÿ0ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ À 2 2 2 2 2 2 2 2 2 À 2 2 2 2 2 2 2 2 2 À 32 32 32 32 32 32 32 32 32 .û+ ù * ÿ÷'% ) ÿöNI?1( ÿözsdL1 ( ÿöŸ–ƒd? ( ÿö¸®—sI&( ÿö¸ zN'( ÿöÆ»£|O(( ÿöǼ¤}O)( ÿöǼ¤}O)(ÀÀÀÀþ ' ý (  * þ * þ + þ , þ - ý - þ . þ / þ 0 þ 0  $ ò  þ " ü þ ! ý þ ý ! þþ  þþ  þ þ  ý þ  þþ  þ ý þ  þþ  þþ  þ þ  þ þþ  þþ  þ þ  þ þ  þþ  þþ  þþ  þþ  þþ  þ þþ      þ  þ þþ  þþ  þþ  þþ  þþ  þþ  þþ  þ þ  þ þ  þþ  þþ  þþ  þ þ  þþ  þþ  ý þ  þþ  ý þ  þ þ ' ý (  * þ * þ + þ , þ - ý - þ . þ / þ 0 þ 0  $ ò  þ " ü þ ! ý þ ý ! þþ  þþ  þ þ  ý þ  þþ  þ ý þ  þþ  þþ  þ þ  þ þþ  þþ  þ þ  þ þ  þþ  þþ  þþ  þþ  þþ  þ þþ      þ  þ þþ  þþ  þþ  þþ  þþ  þþ  þþ  þ þ  þ þ  þþ  þþ  þþ  þ þ  þþ  þþ  ý þ  þþ  ý þ  þ ý)13'3þ23)3þ03*3ý123*3þ13+3þ23,3þ13-3þ*3.3þ13.3 þ13/3 þ&303 þ1303 ý023#3ò2*  ' þ13"3ü.ý*23 3ü0þ13 3ý*þ233ý%þ233þ%þ133ý'þ033ý/þ133þþ233þ%3ý2þ/33þ$þ133þþ233ý.þ233þ"3þþ+33þþ233þ.þ233þ'þ133þ þ233þþ133þþ133þ þ133þ þ133þ3þþ233þþ233þ3 þ233þþ233þ3þ3þþ233þþ233þ þ233þþ133þþ133þþ233þþ/33þ$þ-33þ,ý"233ý1þ233þ þ133þþ033þ$þ133ý0þ133þþ133þ$þ/33ý1þ-33þ þ133ý1 þ033ý+ý µÿ'ÿýÆÿ(ÿýÕÿ)ÿý Äÿ*ÿý«ÿ+ÿþŒÿ,ÿþQÿ-ÿýêÿ-ÿþ°ÿ.ÿ þ`ÿ/ÿ ý éÿ/ÿ þ~ÿ0ÿ ýñÿ$ÿóôã×Ⱦµ¯°³¿Îæ þŽÿ"ÿðúãʾ·¯¦”‡ƒ‚ ýöÿ ÿîýäÈÀ·¬Ÿ‘ƒvkb\WUTV þoÿ ÿíõÐļ°¡Ž|jZLB93/-,.ýÔÿÿìîÊúª—jTB3( þ<ÿÿïîʸ§v\D1"  þ¡ÿÿïòÊù¦ŽqS:& ýîÿÿîûÏÅ»©pP5   þ=ÿÿñÙǾ®”sR4þ‡ÿÿòîÉ´œ{W7ýÐÿÿóÒÆº¦‡b>#þÿÿóïÉÁ±•qJ* þQÿÿôÙÆº¥ƒ[7 þ‚ÿÿóû˲—qI'þ³ÿÿôëǾª‰`9 ýäÿÿôÝÆ¹ {Q-þÿÿõÐó–nD"þ<ÿÿôûÉÀ­Œb: þYÿÿôòǽ¦ƒX1þtÿÿõéÆº¡zN*þÿÿõâŶšrG$þ¬ÿÿõÜò•lA ýÆÿÿõÖ¯f; ýÔÿÿõÓÀ­‹`7 ýÝÿÿõ慎\3ýäÿÿö˾©…X0ýíÿÿöʾ§‚V.ýõÿÿöɽ¦€S,ýýÿÿöǽ¥R*ýüÿÿöȽ¥~Q*ýõÿÿöɽ¤~Q*ýïÿÿöʽ¥~Q*ýéÿÿö˽¥~R*ýàÿÿöϽ¦R+ýÌÿÿöÓ¾¦T-ý¸ÿÿöÖ¾§‚V.ý£ÿÿöÚ¾©…Y1ýÿÿõῪˆ\3ýoÿÿõçÀ­‹`6 ýJÿÿõí¯d: þ&ÿÿõö²“j? ýûÿÿõþƵ˜pD" ýÒÿÿöѸžvJ&ýÿÿöß»£~R,ýhÿÿõ†Z2ý2ÿÿõü®Že; ýíÿÿöÕ´˜pF#ý©ÿÿõ캢|R-ýcÿÿõþŪ‰`9 üýÿÿõæ²–pG&ü¾ÿÿõþÇ£‚Z5 ýaÿÿõô²’nG(  þ% þ& þ& ý ' ý ( þ ) þ) ý * þ + þ+ þ , þ þ ý  ü  þ ý  þ  ý  þ þ  þ  þ  ý  þ  þ ý  þ þ  ú  þ  û  þ ú  þ  û  þ  ú  ú $ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 û $ þ  ü ! þ   ý þ  û  þ ü  þ  ü   ü   û  þ  ý þ  þ þ  þ þ  þ þ  þ þ  þ  þ% þ& þ& ý ' ý ( þ ) þ) ý * þ + þ+ þ , þ þ ý  ü  þ ý  þ  ý  þ þ  þ  þ  ý  þ  þ ý  þ þ  ú  þ  û  þ ú  þ  û  þ  ú  ú $ 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 û $ þ  ü ! þ   ý þ  û  þ ü  þ  ü   ü   û  þ  ý þ  þ þ  þ þ  þ þ  þ þ  þ 3þ"%3þ!&3þ&3ý2'3ý/ (3ý+)3þ)3ý1 *3þ)+3þ+3ý/,3þ 3þ13 3ý/ 3ü-33þ 3ý033þ, 3ý +33þ 3þ)33þ& 3þ*33ý2 3þ-33þ 3ý 033þ+ 3þ&33ú1( 3 þ033ú-"  3 þ,3 3ú0) 3 þ233ú-#  3 þ/33ú1) 3 ù,1.%# 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 3 û121,$ 3 þ233û1,! 3 þ133û0,"  3 þ233û1,$ 3 þ13 3ü.& 3 þ233ü0) 3 þ233û0* 3 þ233û2+" 3 þ233ý1+ 3þ233þ) 3þ233þ 3ý-233þ 33þ, 3þ233þ 3ÿõÒ~aD+ þÿ$ÿõÒ‚eG-  þÿ%ÿöÈ…fG,  þÿ%ÿõþ¾†fF*  þÿ&ÿõû«ƒbB& þÿ'ÿõïŸ]<" þÿ(ÿöÚ™yV5  þÿ(ÿõþ»’pL-  þÿ)ÿõð§‰fB$þÿ*ÿöÓž~Y6 þÿ*ÿõø±“pJ*þÿ+ÿöÚ¦†`; þÿÿþüÿ ÿõû·švO-þÿÿü‹¹íÿÿöÚ©Šc= þÿÿúZ`iªõÿÿõ÷¶›wO,þÿÿù16>IeÖÿÿöÒ©Šb; þÿÿø&1A¶ÿÿöï´šuL*þÿÿ÷  .¬ÿÿöæ†]6 þÿÿø %Àÿÿöݯ’kC"þÿÿõ )ãÿÿöô²™uL)þÿÿùZÿÿòüïàÏ»©“sN+þÿÿúÇÿÿî÷éÙȸ²­¦ž’~cD&þÿÿûUÿ ÿéýðâÒÀ¶°ª¤•ƒym]H2þÿÿû âÿÿåøêÚɹ³®¨¡š‘‰vlbYND9+þÿÿüŠÿÿáüîáÒÁ¶±«¥ž–Ž„{rg^TJB91*"þÿÿ Û2帛‘¢¨¦¡š’‰€vmcYOF>5.&  þÿÿ Ý 7Vr‚†ƒ{rh^UKB:2*# þÿÿ å%;O[]XPF>6.'!  þÿÿ ê ".551*$ þÿÿ ï  þÿÿ ô þÿÿ þÿÿ!þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿ4þÿÿþþÿÿ òþÿÿ îØŠ> þÿÿ þZÿÿîé©i2'  þÿÿ þ—ÿÿîöÁƒA*" þÿÿ ýÝÿÿîüÏK-#  þÿÿ þ(ÿ ÿîþÚžZ/&  þÿÿ þ|ÿÿïæ«h3' þÿÿ þÒÿÿñð·w9)  þÿÿ þ7ÿÿó÷Å…C+" þÿÿ þ ÿÿõüÈB5'þÿÿýùÿÿöÖjYE. þÿÿþ–ÿÿõÆ}bD'þÿÿý+ûÿÿõ¿ª–wR/þÿÿýÂÿÿôö¶¡W1þÿÿþwÿÿõçŹ¡}R-þÿÿ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-3-33ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O)#ÿöǼ¤}O) ÿöǼ¤}O) ûÿöǼ¤}O)ù ÿöǼ¤}O)-ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿÿ• # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # "þ  "þ  "þ  "þ  þþ  þþ  þþ  þ þ • # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # "þ  "þ  "þ  "þ  þþ  þþ  þþ  þ þ •3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3#3"þ33"þ$33"þ+33"þ033"þ033þþ033þþ233þ 3þþ-33þþ033À ûûûø  ù ù ÷'%  ÿ÷'% öNI?1 þÿÿöNI?1özsdL1  þÿÿözsdL1 öŸ–ƒd?  þÿÿöŸ–ƒd? ö¸®—sI& þÿÿö¸®—sI&ö¸ zN' þÿÿö¸ zN'öÆ»£|O( þÿÿöÆ»£|O(öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)õǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þ ÿÿöǼ¤}O)öǼ¤}O) þÿÿöǼ¤}O)öǼ¤}O) þ.ÿÿöǼ¤}O)öǼ¤}P) þHÿÿöǼ¤}O)öʼ¤~P* þgÿÿöǼ¤}O)öͽ¥~R* þ‘ÿÿöǼ¤}O)öѽ¦€S,ýÁÿÿöǼ¤}O)öÚ¾§‚V.ý øÿÿöǼ¤}O)õ俪†[2þNÿÿöǼ¤}O)û  þ  þ   û  û  ý   ý ü " ü ü ( ý  - ý  ý 0 ýþ 3 ý  6 þ ý 7 þ 9 þ 9 þ : þ ; þ ; þ = ý  ò   ý  ý ü  þ  þ ý  þ  þý  þ  þý  þ  þþ ù   þþ  ö  þ$ ý # ý "þ  ü  þ  ù þ !  ú þ (  û  þ .  ü  þ 2 ü þ 5  þþ 7 ý þ 9 ý þ : þ 9 ý 8 ý 7 ý 6 ý 5 ý 3 ý 2 ü / ü , û ( ú # ú  ú  û  þ  þ   û  û  ý   ý ü " ü ü ( ý  - ý  ý 0 ýþ 3 ý  6 þ ý 7 þ 9 þ 9 þ : þ ; þ ; þ = ý  ò   ý  ý ü  þ  þ ý  þ  þý  þ  þý  þ  þþ ù   þþ  ö  þ$ ý # ý "þ  ü  þ  ù þ !  ú þ (  û  þ .  ü  þ 2 ü þ 5  þþ 7 ý þ 9 ý þ : þ 9 ý 8 ý 7 ý 6 ý 5 ý 3 ý 2 ü / ü , û ( ú # ú  ú  ÷ ,-.010022ð32212101/..,(&ú .01133ú20+" ü/113"3ü1+ü,123(3ý0! ü223,3ý. ý01303ý&ý01333ý.ý-1353þ/ý+2373þ2393ý02393<32;3þ13;3ý13<3ý133ò/"  *233þ133ý ü %133þ033þ ý.33þ233þ#ý /33þ133þ ý23)3þþ.3 3ú0-*'$33þñ$10.*&" þ233þ$3ý+#þ233ý) "þ233û1$þ133ù2-($ þ13!3ø0.-*(!þ03(3ø1/.+' ý!23-3ú2.+$ þ1323û1+"þ.353ü2+þ2373ý/ý,2383ý.þ/3:3ý0393ý2383ý%2373ý"1363ý/353ü)1333 ý+323 ü(03/3 û&/3,3û(03(3ú #+13#3ù$*033ú !'.33]#ö ñ Ñ>dœ´ÆØãíõùüÿüú÷òëã×É»¨”z\:  ù;|²ãÿÿñ÷Ò£l1"  úJ£îÿ"ÿõù½o4*!  ûpÛÿ(ÿøèB4'ûxòÿ,ÿúæ‰J9)üIÚÿ0ÿüÆeJýÿ3ÿýí†ý¿ÿ5ÿþ÷ýØÿ7ÿýÌÿ8ÿý½ÿ9ÿþ€ÿ:ÿý,ûÿ:ÿþºÿ;ÿý8ÿ<ÿý¢ÿÿóüëÛÍÀ¸°±´ÁÑìÿÿý ôÿÿïè˺°¥š‰„‚‚•ÑýÿÿþIÿÿíßÈ·§•‚sf^WUTVZaƒêÿÿþ†ÿÿëíÊø¥s\J=5/-,.28A\éÿÿþ¶ÿÿêÖǽªoQ9( *]þÿÿþÖÿÿóÌĶzU5 ù ®ÿ ÿùýøóíèïÿÿõͰ’jB$ç E÷êáÝÝÜÙÔÎÇ¿¸¯ª©¦¤¢úÿÿôÚÀ­‹b: é (Db~Ž–˜–“ŽŠ‡…‚~{ùÿÿóöÄ®d<ê +CZhnomjfb_\XURNçÿÿôò½–oI* ë '6@DDB?<9630.*(ÖÿÿïýݦfB, ì  "" ¼ÿÿðüݲƒX/ ü ô …ÿ ÿæþêͱ”vX8 ýHÿ(ÿîùܾ›tK% ü÷ÿ-ÿîú׬{E$ £ÿ2ÿóè²u5& ;ÿ5ÿõøÁt7*!Åÿ7ÿ÷åC43ûÿ8ÿùéŽÿ:ÿúÏÿ9ÿû'èÿ8ÿú Bñÿ7ÿú Aéÿ6ÿù8Ùÿ5ÿø&žüÿ3ÿ÷"]Éþÿ1ÿö3iÂøÿ/ÿô+?Z˜Íôÿ,ÿñ "2DVgŽºÜ÷ÿ(ÿí $1?N\jv•·Õìýÿ#ÿ é  *5@LWbnx†£¿×ìüÿÿ æ  (1:CMV`js|…ž·Ïä÷ÿÿ$ý  )ý  'ý  %ý  #ý  # # # # # # # # # # # # # , , , , , þ, ý - ý . ý  / þ 0 þ 0 þ 1 þ 1 ý  2 þ 2 þ 3 þ 3 þ , ø , ,  # # # # # # # # # # # ý  ü   ý   ý   ý   ý   þ  þ  þ   þ  þ  ý   þ  þ $ý  )ý  'ý  %ý  #ý  # # # # # # # # # # # # # , , , , , þ, ý - ý . ý  / þ 0 þ 0 þ 1 þ 1 ý  2 þ 2 þ 3 þ 3 þ , ø , ,  # # # # # # # # # # # ý  ü   ý   ý   ý   ý   þ  þ  þ   þ  þ  ý   þ  þ $13)ý0133'ý0233%ý0233#þ033#3#3#3#3#3#3#3#3#3#3#3#3#3,3,3,3,3,3þ,3ý1-3ý0 .3ý- /3þ" 03þ 03ý- 13þ 13ý/ 23þ 23ý/ 33þ 33þ* ,3÷!  ,3,33#3#3#3#3#3#3#3#3#3#3#3ý( 3ü3/33ý133ý133ý133ý/33þ&33þ33þ,33þ33þ&33ý133þ33þ3"ûGÆÿÿøÇ¼¤}O)ûHÆÿÿøÇ¼¤}O)ûHÇÿÿøÇ¼¤}O)üHÇÿÿøÇ¼¤}O)ýHÇÿÿøÇ¼¤}O)ÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}O)þÿÿøÇ¼¤}P)ûþÿÿ÷ǽ¥~R,ö ÿÿõȾ§ƒY6,ÿú  þÿ+ÿù  þÿ+ÿø6%  þÿ+ÿ÷ZC.þÿ+ÿöšgN5! þÿ+ÿõû¥qU:# þÿ,ÿõø vX;#þÿ-ÿõñšxX:!þÿ.ÿöÞ•vU5 þÿ/ÿöÁ’qN. þÿ/ÿõ÷ªŠhD&þÿ0ÿöØ \8 þÿ0ÿõû¶–sN,þÿ1ÿöÞ¨‰c> þÿ1ÿòú¶šwP-ÿ2ÿóÓ¦‡a: ÿ2ÿóð¨ŽkE$ÿ+ÿìâÛÕÎÇ¿·ªœ‡iF'ÿ+ÿìŸœš–“ˆoY="ÿ+ÿâxtqnjfb^WM>*  @dƒ— £¤ÿÿÛËÉĽ³¬§KHEB?<961+" 1Ldsz|}ÿÿéÊÆ¼®œƒ&$"  õ0?INNPÿÿêɳ›€hY õ!&()*ÿÿõÈ¿¬hI6ö ÿÿøÈ¾§ƒY6 ûþÿÿøÇ½¥~R,þÿÿöǼ¤}P)þÿÿôǼ¤}O)þÿÿòǼ¤}O) þÿÿðǼ¤}O)' þÿÿïǼ¤}O)J9* þÿÿîǼ¤}O)ÎjJ7&þÿÿìǼ¤}O)ÿô“[E0 þÿÿìǼ¤}O)ÿÿû§jP8# þÿÿøÇ¼¤}O)ÿÿõþµtX=&  þÿÿøÇ¼¤}O)ÿÿõý«z]?&  þÿÿøÇ¼¤}O)ÿÿõö¢}]=# þÿÿøÇ¼¤}O)ÿÿöæ˜zX8 þÿÿøÇ¼¤}O)ÿÿöÄ•tP0  þÿÿøÇ¼¤}O)ÿÿõôªjE& þÿÿøÇ¼¤}O)ÿÿöÌ¡Z6  þÿÿøÇ¼¤}O)ÿÿöì°•pH' þÿÿøÇ¼¤}O)ÿÿõþÀ¤‚Z5 þÿÿøÇ¼¤}O)ÿÿöÕ°’kB"þÿÿøÇ¼¤}O)ÿÿö帞zO*þÿÿùǼ¤}O)0ò  +û  ü    ý   " ý # ý $ þ & ý ' þ ) þ * þ * þ + þ , þ - þ  ö   þ  ý  þ  ý   þ  ý   þ  ý   þ  þ þ  þ !þ  þ!þ  þ !þ  þ!þ  þ!þ  þ " þ!þ  þ!þ  þ!þ  þ!þ + þ + þ + - þ + - - - þ + þ + þ + þ + þ + þ + þ  þ!þ  þ0ò  +û  ü    ý   " ý # ý $ þ & ý ' þ ) þ * þ * þ + þ , þ - þ  ö   þ  ý  þ  ý   þ  ý   þ  ý   þ  þ þ  þ !þ  þ!þ  þ !þ  þ!þ  þ!þ  þ " þ!þ  þ!þ  þ!þ  þ!þ + þ + þ + - þ + - - - þ + þ + þ + þ + þ + þ + þ  þ!þ  þ0÷"--//12211þ211+û*.0133 ü.1133ü0133ü1233ý013!3ý023#3þ23%3ý(23&3ý&13'3þ+3)3ý/23)31+3þ13+3þ03,3þ/3-3ý-233ö) 333ý' 3 ý.233ý0 3 þ133ý0 3 þ133ý1 3 þ233þ ý+233þ*!þ033þ !þ233þ)!þ+33þ!þ233þ!þ133þ+"3þ!!þ/33þ!þ233þ!þ233þ!þ13+3þ23+3þ13+3-3þ23+3þ23+3-3þ23+3-3þ23+3þ13+3þ23+3þ23+3þ23+3þ133þ!þ/33þý<ý<ý<ý<ý<ý<ý<ý<ý<ý<ý<ý<ý<ý3ý.ý!õ ý ûèGmЧÃÙãëôüüøôðäù ÷#p©Ûþÿÿ÷'% ú1ˆÔÿÿöNI?1û]ÆÿÿözsdL1 ûpêÿÿöŸ–ƒd? ûXÞÿ!ÿö¸®—sI& ü½ÿ#ÿö¸ zN' üZïÿ$ÿöÆ»£|O( ýšÿ&ÿöǼ¤}O) ý ·ÿ'ÿöǼ¤}O) ýÌÿ(ÿöǼ¤}O)ýÍÿ)ÿöǼ¤}O)ý Àÿ*ÿöǼ¤}O)ý¬ÿ+ÿöǼ¤}O)þqÿ,ÿöǼ¤}O)ý5ùÿ,ÿöǼ¤}O)ý ÜÿÿöôáÒĺ´·ºÊÿÿöǼ¤}O)þ€ÿÿôñÓü³¨ž“‹†‚ÿÿöǼ¤}O)ý öÿÿòý߯À¶¨˜ˆxjaZVÿÿöÆ»£|O(þ«ÿÿñüÖÆ¾² ‹u`OB82.ÿÿö¸ zN'ý(þÿÿðþׯ¾±œ‚hO:+!ÿÿö¸®—sI&þšÿÿïáÈÁ²œ€bF. ¥¤¤õ£ —„d@! ý÷ÿÿíôÉö¡ƒbB*~~}}õ|zsdL1 þqÿÿíÖÆ¼ªŒiF* RPOOöNI?1þÅÿÿòõɳ™vP/ ý-*))÷(&!ýþÿÿóàǽ¨ˆa;ýù þnÿÿôÏĶ›vN*ý ûþ­ÿÿô÷ÉÀ®Žf> ýýåÿÿôêǼ¦‚X2ýþÿÿõàÆ¸žxM)ýþTÿÿõÙÄ´˜pF& þþwÿÿõѲ–nH*ýþ—ÿ+ÿýþ¸ÿ+ÿý ýÔÿ+ÿý ýàÿ+ÿý ýëÿ+ÿý ýõÿ+ÿý ýýÿ+ÿý ýúÿ+ÿý ýóÿ+ÿý ýëÿ+ÿý ýÙÿ+ÿý ýÂÿ+ÿý ý©ÿ+ÿý ý‡ÿ+ÿý ý`ÿÿ÷ÏÊžµ­¨¦¤¤ý ý5ÿÿöÖÆ¾°Ÿ…~}}  ü 7  ý2 ü " ü  ü  ü ! ý # ý$ ý % ý & ý ' ý ( ý ) þ * þ+ þ ý  ý  û  þ ý  ý  þ  þ þ  ý  ý  þ þ  þ  ý  þ þ  þ þ  þ þ  þ þ  þ þ  þ þ  þ þ  þ þ  þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 2 2 2 2 2   ü 7  ý2 ü " ü  ü  ü ! ý # ý$ ý % ý & ý ' ý ( ý ) þ * þ+ þ ý  ý  û  þ ý  ý  þ  þ þ  ý  ý  þ þ  þ  ý  þ þ  þ þ  þ þ  þ þ  þ þ  þ þ  þ þ  þ þ  þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 1 þ 2 2 2 2 2 ÷0/.-*' 63û1-'2 3û0+"!3ü0(3ü2*3ü2' !3ý1#3ý($3ý-%3ý0&3ý1'3ý1(3ý0 )3ý,*3þ#+3þ 3ý&033ý- 3û!033þ 3ý ,33ý0 3ý+33þ  3ý.33ý0 3ý133þ 3þ,33þ- 3ý233þ 3þ/33þ 3þ,33þ+ 3ý133þ 3þ233þ 3þ033þ! 3þ/33þ* 3þ)33ý1 3þ33þ 13þ 13þ 13þ 13þ$ 13þ' 13þ+ 13þ- 13þ0 13þ0 13þ1 13þ2 23 23 23 32 32 3@61ò #éÖɸ †mI% ûÿîý⸆R&  ù  ÿñï¶v4(  ÿòò¯]5* þÿÿóþÉn>0# þÿÿóþÃcC2#þÿ ÿô÷ VB/ þÿ"ÿõÕpR;(þÿ#ÿõí‹^F0þÿ$ÿõùŸjO6!  þÿ%ÿõûªrV:$  þÿ&ÿõû©wZ=%  þÿ'ÿõø¤zZ<# þÿ(ÿõðšzY:! þÿ)ÿöß–vT5  þÿ*ÿöÑqN. þÿ ÿýãúÿÿõ÷«ŠhD&þÿ ÿû‚‹ÅùÿÿöÜ \9 þÿ ÿúVY^vâÿÿõýº—uN- þÿ ÿù.05>OÉÿÿö㩊e?"þÿ ÿø&7Òÿÿõý¼žzS0 þÿ ÿ÷ @õÿÿöÝ«Žg@!þÿ ÿú Žÿÿõö¶žzR.þÿ ÿúõÿÿöͪ‹c; þÿ ÿûŸÿÿöä´™sJ'þÿ ÿüIÿÿõö»¥‚X2þÿ ÿü óÿÿöÉ®f> þÿ ÿü»ÿÿöÚ¶šsI&þÿ ÿý…ÿÿö軣T.þÿ ÿýYÿÿõö¿«Š_6 þÿ ÿý6ÿÿõþñ’j? þÿ ÿþ!ÿÿöζšrG$þÿ0ÿöغ¡zO*þÿ0ÿöས‚V.þÿ0ÿõ翪ˆ]4þÿ0ÿõíÁ®b9 þÿ0ÿõò±’h> þÿ0ÿõõó–mB þÿ0ÿõùĶ™pE" þÿ0ÿõûÅ·œtG#þÿ0ÿõýƹžvJ%þÿ0ÿõþƺ yL&þÿ1ÿöƺ¢zM'þÿ1ÿöƺ¢zN'þÿ1ÿö·ŸyM'þÿ1ÿö¸­–rI%þÿ ÿ$¤õ£ —ƒd@! þÿ ÿ$}õ|zsdL1 þÿ ÿ0 0 0 0 0 0 0 0 0 0 ™ó /ü ü  þ ü  þý  ü  þý  þ  þþ  þ þþ  ý  û  þ û  ý  ü  þ  ü  þ ý  þ  þ  þ þ  ý 5 þ4 ý 4 þ4 þ3 þ 3 þ 2 þ 2 þ % ñ   # ý ü " ý ! ý ! þ þ  þ þ  þ ý  þ  þ þ þ þ  þ  þ þ þ þ þ þ þ þ þ þ 0 0 0 0 0 0 0 0 0 0 ™ó /ü ü  þ ü  þý  ü  þý  þ  þþ  þ þþ  ý  û  þ û  ý  ü  þ  ü  þ ý  þ  þ  þ þ  ý 5 þ4 ý 4 þ4 þ3 þ 3 þ 2 þ 2 þ % ñ   # ý ü " ý ! ý ! þ þ  þ þ  þ ý  þ  þ þ þ þ  þ  þ þ þ þ þ þ þ þ þ þ 03030303030303030303˜ò,10121211/.(/ü-223 3ü.%  3þü"0233ü1)3þ ý%233ü1(3þý133þ-3þý033þ3þþ*33ý03û33þ3û033ý23ü"33þ%3ü 233þ3ý&33þ+3þ33þ3þ)33ý/53þ43ý243þ%43þ33þ+ 33þ 23ý0 23þ %3ñ+  %0331 #3ý0û)' "3ý- !3ý0!3þ 3þ' 3þ 3þ)3þ3ý23þ)3þ3þ3þ3þ03þ*3þ$3þ3þ3þ3þ3þ 3þ 3þ3þ3þ3/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/þÿ ÿ/õ @dƒ— £¤¤/õ 1Ldsz|}}0ö0?INNOO ÷!&())ù ÷ ö ûûÞ Q‹ÁÝîûöçÌ¥u9!  ô !’ïÿ ÿìÖ‘B-$   ÿõ8%! võÿÿõù»`9-! ÿÿ÷\J@2 Âÿÿ÷ýÄe@0! ÿÿø„tfN3,ÔÿÿùèfR;&ÿÿù§—…fHÍÿÿùÈ‹uX:"ÿÿú¾®™v¸ÿÿøü¹¦ŽnJ*ÿÿûȹ¢§ÿÿøçÀ²šwP-ÿÿû˽­ôÿÿøÑ´™tJ)ÿÿü̾Ûÿÿ÷ðÈÀ®g?!ÿÿüÌÊþÿÿ÷ÙÆº¢€W2ÿÿýÌìÿÿö÷ɲ•nF&ÿÿþÙÿÿöàÆ¼¦†]6 ÿÿþôÿÿõüÌõšuL)ÿ4ÿõèǾª‹c< ÿ4ÿõÑÅ·žzR.ÿ3ÿôïÈÀ®iA!ÿ3ÿôØÆº¢V2 ÿ2ÿóöɱ•nF%ÿ2ÿó߯¼¦…]6 ÿ1ÿòûË´™tK)ÿ1ÿòäû©Šb; ÿ$ÿå÷âÑù·¼ËáúÿÿþÁ·®™wO-ÿ"ÿãüÞÆÀ·¬ •‹†ƒ‡®ÞÜž ˜‚b> ÿ!ÿâøÒƾ±¡Ž|maZWX^fpy}xfJ,ÿ ÿåüÑÆ¾®š‚jTC82/05 þÿÿõׯd: þÿÿõÔÀ­‹`7 þÿÿõÑ¿ªˆ]4þÿÿöZ1þÿÿö˾¨ƒW/þÿÿö˾¦‚U.þÿ ÿ 2 2 2 2 2 2 2 2 2 3  þ  þ  þ  þ  þþ  þý  þý  ú  û   ü   ý   þ  - - - - - - - - - -  þ  ý  ü  û   þ  þ  þ   þ   þ  þ  þ  þ  þ  þ                     2 2 2 2 2 2 2 2 2 3  þ  þ  þ  þ  þþ  þý  þý  ú  û   ü   ý   þ  - - - - - - - - - -  þ  ý  ü  û   þ  þ  þ   þ   þ  þ  þ  þ  þ  þ                     32 32 32 32 32 32 32 32 32 33 33þ 33þ  33þ 33þ 33þþ#3 33þý23 33þý13 33ú13 33û1333ü/333ý,333þ)33-3-3-3-3-3-3-3-3-3-33þ3 33ý3 33ü%3 33û13 33þ# 33þ 33ý0 33þ' 33þ 33þ 33þ 33þ  33þ 33þ 33þ 33 33 33 33 33 33 33 33 33 ÿöǼ¤}O)( ÿöǼ¤}O)( ÿöǼ¤}O)( ÿöǼ¤}O)( ÿöǼ¤}O)( ÿöǼ¤}O)( ÿöǼ¤}O)( ÿöÆ»£|O(( ÿö¸ zN'( ÿö¸®—sI&( ¤õ£ —„d@! ( }õ|zsdL1 ( OöNI?1( )÷(&!) ù * û  û ûú ù  ù ù ÿ ÿ÷'% ÿø8%! ÿ ÿöNI?1þÿÿø\J@2 ÿ ÿözsdL1 þÿÿø„tfN2 ÿ ÿöŸ–ƒd? þÿÿø§—…fB#ÿ ÿö¸®—sI&þÿÿø¾®™vM(7ÿ ÿö¸ zN'þÿÿøÈ¹¢}R^ðÿ ÿöÆ»£|O(þÿÿù˼¥€„øÿ ÿöǼ¤}O)þÿÿú̽¦£úÿ ÿöǼ¤}O)þÿÿû̾ºúÿÿöǼ¤}O)þÿÿüÌÇøÿÿöǼ¤}O)þÿÿýÐõÿÿöǼ¤}O)þÿÿþóÿÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿ,ÿöǼ¤}O)þÿÿþæÿ ÿöǼ¤}O)þÿÿýæÈÿ ÿöǼ¤}O)þÿÿüðÉÃÿ ÿöǼ¤}O)þÿÿûþÑÆ¼ÿ ÿöǼ¤}O)þÿÿûíɲÿ ÿöǼ¤}O)þÿÿûÙÆº¥ÿ ÿöǼ¤}O)þÿÿúýËó˜ÿ ÿöǼ¤}O)þÿÿúòÈ¿«Šÿ ÿöǼ¤}O)þÿÿúçÆº£~ÿ ÿöǼ¤}O)þÿÿúßŶ›tÿ ÿöǼ¤}O)þÿÿúØÂ²”kÿ ÿöǼ¤}O)þÿÿúÒÁ®Ždÿ ÿöǼ¤}O)þÿÿúÏÀ«‰^ÿ ÿöǼ¤}O)þÿÿúʾ©…Yÿ ÿöǼ¤}O)þÿÿúɾ§‚Vÿ ÿöǼ¤}O)þÿÿúȽ¦€Sÿ ÿöǼ¤}O)þÿÿúǽ¥~Rÿ ÿöǼ¤}O)þÿÿúǼ¤~Pÿ ÿöǼ¤}O)þÿÿúǼ¤}Pÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿûǼ¤}O   ú  û *û   þ%ü  ý !ý  ý   þ ý þ ! ý $ ý % þ & þ& ý þ & þ( ý þ ( þý ( þ þ * þ- þþ + þ þ , ý  þ - þ þ - þ þ . þ þ  õ   þ þ  ýý  þ þ  ý  þ þ  ý  þ  þ  þ þ  þ  þ þ  þ  þ  þ  þ  þ  þ  þ   þ  þ  þ  þ         þ     þ   þ   þ   þ   þ   þ   þ   þ   þ     ú  û *û   þ%ü  ý !ý  ý   þ ý þ ! ý $ ý % þ & þ& ý þ & þ( ý þ ( þý ( þ þ * þ- þþ + þ þ , ý  þ - þ þ - þ þ . þ þ  õ   þ þ  ýý  þ þ  ý  þ þ  ý  þ  þ  þ þ  þ  þ þ  þ  þ  þ  þ  þ  þ  þ   þ  þ  þ  þ         þ     þ   þ   þ   þ   þ   þ   þ   þ   þ   û-/00112ù0/.()û,/1133û1,"$1þ233ü0# ü-1233ý/ý1233ý(ý 133ý, þ13!3ý- $3ý-%3þ(&3þ&3ý1þ13&3þ"ý@23&3ý1þ13(3þþ,3)3þ.þ23*3þý-23*3þþ23+3þ*þ*3,3ý2 þ23-3þ þ23-3þ þ*3.3þ þ133õ1&  *33þ$ þ233ý( ý.33þ( þ233 ý /33þ- þ233 ý133þ/ þ/33 þ*33þ/ þ033 ý233þ1 þ133þ033 þ233þ133 þ233þ033 3þ033 3þ033 þ233þ*33 33 þ2333 33 þ2333 33 þ2333 þ2333 þ1333 þ1333 þ1333 þ1333 þ/333 þ/333 þ1333 þ233Q /'ö ö !à7dŒ´ÓßëöüöíßÄ©€O$ þù_¨íÿÿòô¹u1'  ÷#ñÿÿóêšF4( ù¡üÿÿôìŽJ:* ûeñÿÿõÊfL8& ý±ÿÿõê€[D.þÝÿ!ÿõñgM3$ÿõñ‘nR6%ÿõçrR5&ÿöÎqO0 &ÿõü±ŒjG) þÿ&ÿö㢅`=  ýÊÿ&ÿõþ»šxR/  þtÿ(ÿöáªgA" ý!ôÿ(ÿõù·ž{S.þ¥ÿ*ÿöÏ«Œe= ý&üÿ*ÿö䵚uK(þ ÿ+ÿõô¼¦ƒY2ýøÿ,ÿöÄ®f= þhÿ-ÿöÒµ™rF$þÅÿ-ÿöݺ¡{P*ýþÿ-ÿõç¾§„Y1þ[ÿÿõþðÜ͸·¼ÐìÿÿõíÀ¬‹`7 þ ÿÿòòÑļ²§œ’Š…ƒ«òÿÿõó°‘f= þÝÿÿñȸª™‡vi^YWZrçÿÿõøÃ³–mB ýþÿÿ𶥎v`N?61/27_úÿÿõúŶšqF" þ:ÿÿ𷤊nR;+ "–ÿÿõüƸuH$þgÿÿ祈mN3   .üÿÿõþƺŸwJ&þŠÿÿ÷—uR2ü Àÿÿöƺ¡zM&þ¤ÿÿö„^:û…ÿÿöÇ»¢{N'ý½ÿÿørJ)üWÿÿöǼ£|N(ýÕÿÿùb: ý.ÿÿöǼ£}O(ýåÿÿùT.ýÿÿöǼ£}O(ýíÿÿúI&þÿÿöǼ¤}O)ýôÿÿúA þÿÿöǼ¤}O)ýüÿÿú: þÿÿöǼ¤}O)ýýÿÿú5þÿÿöǼ¤}O)ýöÿÿû1 þÿÿöǼ¤}O)ýïÿÿû. þÿÿöǼ¤}O)ýçÿÿû+ þÿÿöǼ¤}O)ý×ÿÿû* þÿÿöǼ¤}O)ýÁÿÿû* þÿÿöǼ¤}O)ý¬ÿÿû) þÿÿöǼ¤}O)ýÿÿû) þÿÿöǼ¤}O)ýkÿÿû) þÿÿöǼ¤}O)ýDÿÿû) þÿÿöǼ¤}O)þÿÿû) þÿÿöǼ¤}O)ýâÿÿû) þÿÿöǼ¤}O)ýªÿÿï *   ý$ý  ü  ý  ý þ  ý  ý þ ý " þ þ % þ  ý ' þ  þ ) ü < ý < ý  = þ ë ô  2 ý ý 0 þ ý - þ ý + þþ * ý þ ) þý ( þþ ' þ þ ' þ þ & þþ & þþ & þþ & þ' þþ % þ % þ % þ % þ % þþ % þ' þþ & þþ & þþ & þ þ ' þþ ( þþ ( ý þ  ï *   ý$ý  ü  ý  ý þ  ý  ý þ ý " þ þ % þ  ý ' þ  þ ) ü < ý < ý  = þ ë ô  2 ý ý 0 þ ý - þ ý + þþ * ý þ ) þý ( þþ ' þ þ ' þ þ & þþ & þþ & þþ & þ' þþ % þ % þ % þ % þ % þþ % þ' þþ & þþ & þþ & þ þ ' þþ ( þþ ( ý þ  ý/00ò21121210/,)!)û#02233û2-'$ý.233ü1)þ(33ý0133ý(þ"33ý133ý0þ33ý+13 3þ"þ 33ý023"3ý(þ33ý123$3ú*33ü223&3û'33ý023(3ü&3<3ý3<3ý13=3þ/3ë3ô2)  &1323ý+ ý (303ý! ý13-3þ! ý23+3þ)þ$3*3ý2 þ.3)3þ%ý23(3þþ.3'3ý0þ&3'3þ'þ13&3þþ03&3þþ03&3þ þ+3&3þ'3þ'3þþ23%3þ23%3þ23%3þþ13%3þþ23%3þ þ#3&3þþ.3&3þþ13&3þ$þ13&3þ/)3þþ13(3þ%þ13(3ý2 3U /'÷ õ   ß ?x¿Ýéôü÷íäÙ¿ŸX% û ùi¾öÿÿñ÷ÇŒ?)" ù ü1ªùÿÿòùºd7,! ÿÿû)²þÿÿôþ¾[@1"ÿÿü€øÿÿöô™UA. ÿÿý"Ïÿ ÿøÀhP:&ÿÿüCìÿ"ÿùÜ{\B,ÿÿýQúÿ$ÿúä„eI4ÿÿüTúÿ&ÿûã‰jQÿÿý>úÿ(ÿüߊpÿÿþéÿ*ÿýÎŽÿ<ÿýþ¾ÿ=ÿþúÿìÿõóßÏĸµºÊäþÿ2ÿòõÕľ´©ž“Іƒ”Ùÿ0ÿïêɹ¬›‰xj`ZVX^¡üÿ-ÿíëÉ·¦‘ybOA72/05>}ûÿ+ÿìóËŦŽqU>-!*‚ÿ+ÿëÔÆ½ªpP6"  ½ÿ)ÿóïɲšxT5ú.òÿ(ÿòÚÆ»¦†`  ýßÿ'ÿöÔµ™qF$ þ=ÿ(ÿõíº¢}R. þ°ÿ)ÿö̪Šb: þ@ÿÿV                                              V                                              V3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3   û ù ÿõ'% ÿÿõNI?1ÿÿõzsdL1 ÿÿõŸ–ƒd? ÿÿõ¸®—sI&ÿÿõ¸ zN'ÿÿõÆ»£|O(ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿõǼ¤}O)ÿÿöǼ¤}O) ý  þþ  þþ  ý þ  ý þ ! ü þ " ñ   ý / þ / þ . ý - þ - þ , ý + ý * þ * þ ) þ ( þ ' ý % ý $ ý # ý ! ý ý  ý  !ü  $û  'ù  -õ   þ ¿ ý  þþ  þþ  ý þ  ý þ ! ü þ " ñ   ý / þ / þ . ý - þ - þ , ý + ý * þ * þ ) þ ( þ ' ý % ý $ ý # ý ! ý ý  ý  !ü  $û  'ù  -õ   þ ¿ ý233þ%þ033ý$þ*33ý(þ033ý/þ+3!3ü.þ03"3ñ1+$&,01 ý!13/3 þ/3/3 ý23.3ý(13-3þ-3-3þ13,3ý13+3ý%13*3þ)3*3þ+3)3þ+3(3þ*3'3ý'13%3ý"13$3ý.3#3ü(13!3ý.3 3ý/33ý,33!ü$.33$û!+133'ù '.233,ò !$(*,./0122ü1/,¿üôÿÿõ餃^;!üšÿÿôä›xT5ü)ýÿÿóêœqP4 ü±ÿÿôù¹pR8$ û9þÿ ÿôí«bB.   ü§ÿ"ÿñúÕ¤wQ5#!,GjœÚ û$öÿ/ÿ ü„ÿ/ÿ ûÔÿ.ÿ û=üÿ-ÿ û ˆÿ-ÿ ûÃÿ,ÿ ú&êÿ+ÿú Iøÿ*ÿú fþÿ)ÿú„ÿ)ÿúŒÿ(ÿú Žÿ'ÿù ~üÿ%ÿù gôÿ$ÿø FØÿ#ÿ÷ .¦üÿ!ÿ÷ &^Úÿ ÿö !5†æÿÿõ,BÜÿÿó $5Iz¿ñÿÿñ (9J^Áçþÿÿî )7FVf¥ÅàôÿÿÝ &1>KYfr|Ф¹ÉÕàèîóøûüþÿþýüúöß (2 þÿÿùWóÿÿôáÆ»¥‚X2þÿÿû¢ÿÿôþÎô™rJ&þÿÿü0”ôÿÿôíȾ«‹c; þÿ,ÿôÔŸŸ{R.þÿ+ÿôîÈÀ®‘jB"þÿ+ÿôÓŹ¢€X2 þÿ*ÿôíÈÀ®’mE%þÿ)ÿóýÑĸ¡X4 þÿ)ÿôâǾ¬jD%þÿ(ÿóóɵœzT2 þÿ'ÿóýÒź¦ˆc>"þÿ'ÿóàÆ¾­’pK+ þÿ&ÿóéÇÀ²›zV5  þÿ%ÿòðɶ¡ƒ`>" þÿ$ÿòõÌø¥‰hF)  þÿ#ÿòõ͸¦mK.  þÿ"ÿññ˸§ŽpO2  þÿ!ÿñîÉÁ¶¦ŽpQ4 þÿÿðþåÆ¿´¢‹nP4 þÿÿðøÔü¯ž†jN3þÿÿðéÈ¿¶©–~cH0þÿÿïðÒÁº®Ÿ‹tZA+þÿÿîóÔÁº±¤“~gO9% þÿÿìþìÒ¾¸°¤•‚nXB. þÿÿêýïÚù²ª ’‚p\H5$þÿÿèûîàÏ»µ¯¨ –Š{kZH6' × !@d„— £¤òìæÞÔÈ»°­ª¥ž˜†zn`RB4& Ù 1Ldsz|}¢¢ ž›˜•‘Œ†xof[PD9-" Û1?INOO{zyvsokfaZSLD<3*" Ý!&())NMKJGD@<72-'" ù é'&&%#!  ûí &0 6 - - þ + þ + þ + þ + þ + þ + þ + þ + þ + þ * þ * þ * þ ) þ ) + þ ( ý ' þ ' þ & ý % ý $ ý # ý " ý ý 1ü 4ù  þ ¿ - - þ + þ + þ + þ + þ + þ + þ + þ + þ + þ * þ * þ * þ ) þ ) + þ ( ý ' þ ' þ & ý % ý $ ý # ý " ý ý 1ü 4ù  þ ¿3-3þ23+3-3þ23+3þ13+3þ23+3þ13+3þ13+3þ13+3þ23+3þ/3+3þ13*3þ13*3þ/3*3ý 13)3þ13)3ý,23(3þ03(3ý*13'3þ.3'3ý03&3ý03%3ý"13$3ý13#3ý -3"3ý#/3 3ü$/3 30û)13 33ó$)-/020/,¿ÿöǼ¤}O)þÿ,ÿöǼ¤}O)ýúÿ+ÿöǼ¤}O)ýóÿ+ÿöǼ¤}O)ýëÿ+ÿöǼ¤}O)ýßÿ+ÿöǼ¤}O)ýÈÿ+ÿöǼ¤}O)ý°ÿ+ÿöǼ¤}O)ý•ÿ+ÿöǼ¤}O)ýlÿ+ÿöǼ¤}O)ýAÿ+ÿöǼ¤}O)üþÿ*ÿöǼ¤}O)ýÓÿ*ÿöǼ¤}O)ý“ÿ*ÿöǼ¤}O)ýJÿ*ÿöǼ¤}O)üéÿ)ÿöǼ¤}O)ý“ÿ)ÿöǼ¤}O)ü'ûÿ(ÿöǼ¤}O)ü¦ÿ(ÿöǼ¤}O)û(öÿ'ÿöǼ¤}O) ü|ÿ'ÿöǼ¤}O) û Äÿ&ÿöǼ¤}O) ûáÿ%ÿöǼ¤}O) ú3äÿ$ÿöǼ¤}O) ú 3Ýÿ#ÿöÆ»£|O( ù(¶ÿ"ÿö¸ zN' ø wëÿ ÿö¸®—sI& ÷;Ÿîÿ ÿ¤õ£ —„d@! õ.HÏùÿ ÿ}õ|zsdL1 ë &9Me’¹ÕæóùüþüùöOOöNI?1ì +;K[jw‚‹’˜œŸ¡))÷(&!í )5AMWaiotwzù ï  (08>DHJMûò !$&&ö 4þþ8þ þ  ý þ  ý þ  ü  þ   ý  þ   ý ý   ö  ! 0 ü / þ 1 þ 1 þ 1 þ 0 þ 0 ý / þ  þ  þ  ý    ü    û    ú    ý þ   ý þ   ý þ   ýþ   ý þ   ü þ   ü  þ   û 5ú úþ þ  ý þ  ý þ  ü  þ   ý  þ   ý ý   ö  ! 0 ü / þ 1 þ 1 þ 1 þ 0 þ 0 ý / þ  þ  þ  ý    ü    û    ú    ý þ   ý þ   ý þ   ýþ   ý þ   ü þ   ü  þ   û 5ú úþ'þ133ý2ý/233ý3þ133ü31 þ1333ý+ þ1333ý.ý+2333õ*!+123 303 ü6.13/3 þ2313 þ2313 þ0313 ý&2303 þ1303 ý*13/3 þ133þ*33 þ%33ý* 333ü.333û0 333ú0 333ý1þ 333ý0þ 333ý- þ33 3ý$þ33 3ý0þ33 3ü2#þ 333ü1 þ&333û/$5ú*% úõñÁ®Œb8 þ­ÿÿöǼ¤}O)õÿȲ“jA ý)üÿÿöǼ¤}O)ôÿâ¶œvL)ý¼ÿÿöǼ¤}O)óÿýǦ„[6 ýÿÿöǼ¤}O)ÿõö¹”nI* ýÿÿöǼ¤}O)ÿòøÀ…bA( 4ÉÿÿöǼ¤}O)ÿõé¹~U34DsÁüÿ ÿöǼ¤}O)þÿ/ÿöǼ¤}O)ü *Fÿ/ÿöǼ¤}O)þÜÿ1ÿöǼ¤}O)þ–ÿ1ÿòǼ¤}O)Iÿ1ÿöǼ¤}O)ýæÿ0ÿöǼ¤}O)ý‰ÿ0ÿöǼ¤}O)üøÿ/ÿöǼ¤}O)ü•ÿÿþõÿÿöǼ¤}O)ýÿÿýöÔÿÿöǼ¤}O)ýÿÿüúÑÎÿÿöǼ¤}O)ýÿÿûýÕÅÆÿÿöǼ¤}O)þÿÿúýׯ½¹ÿÿöǼ¤}O)þÿÿùýØÆ½®§ÿÿöǼ¤}O)ÿøûÕż®˜ÿÿöǼ¤}O)ÿ÷øÐú¬–{tÿÿöǼ¤}O) ÿöïÊÁ·¨“xZYÿÿöǼ¤}O) ÿôüÞľ²¢rV;EÿÿöÆ»£|O( ÿóëÊ¿·«š„jP6"5ÿÿö¸ zN'ÿðüæË½¶­ŸŽx`G1-ÿÿö¸®—sI&ÿäûê×À·±©Ž}hR=)%Ei†™¡£¤¤õ£ —„d@! ßòéßÓÅ´°«¥ž“‡xgUB0   5Pftz|}}õ|zsdL1 ࢡŸš–Šwk^N?1#"2AJNOOöNI?1zâxvrmf_VLB6+   "&())÷(&!MîKIFB<6/(! ø ù î'&&%"  üûõ   38$ú  )ü  ,ý  -þ  .þ  ü  û þ  ö  þ þ  ù  ý þ ( þ* ý þ ) ý þ + ý  þ - ü   1 ó  S þ = þ = ý < ü ; ý : ý 9 ý 8 ý 5 ý ý 2 ý ý . ý  ü * ýû # ü ù  ú ø   õ Î$ú  )ü  ,ý  -þ  .þ  ü  û þ  ö  þ þ  ù  ý þ ( þ* ý þ ) ý þ + ý  þ - ü   1 ó  S þ = þ = ý < ü ; ý : ý 9 ý 8 ý 5 ý ý 2 ý ý . ý  ü * ýû # ü ù  ú ø   õ Î$ú *233(û#/33+ü"233-þ33.þ,33õ(+..0021!þ!33õ #*,./002233þ+þ33ù/0/10133ý1 þ#3(3þ%þ.3(3ý1þ23)3ý/þ/3+3ý. ý123,3ü2! ý)1303ó1*! *.03S3þ13=3þ.3=3ý03<3ü13;3ý 03:3ý0393ý/383ý ,353ý2!ý!1323ý*ü&03.3ý, ü .3*3ü(û!,23#3ü* ù!(-233ú1( ò $'),./0022ó100/,)&# Î ã "(/7@HQYbjrz‚–´Ïéýÿÿæ %+29@GOW_gpx†«Ò÷ÿÿç $*/6=EMV^iwÁþÿÿüî "(.6>HS™ÿÿà  %.8¼ÿÿä !=Wr§ÁÚóK õ Yÿÿï *Fa|•°Êâúÿÿö²A=4& ú "ÿÿøc¸ÒêþÿÿõùweWA) üÿ(ÿõÔŒz^>"ü;ÿ(ÿôþ¿–yV3 ý›ÿ)ÿôùµnI* ýDýÿ*ÿõøµ†bA' þýQõÿ,ÿôýÓˆ^A* ý*¨ÿ0ÿòýØ¥uK2!'2R‚ÃþÿRÿþíÿ=ÿþgÿ=ÿý °ÿ<ÿüÛÿ;ÿû.æÿ:ÿú 9çÿ9ÿù3Øÿ8ÿø)²ÿ6ÿõê wíÿ2ÿüõÔÂ÷<¦÷ÿ.ÿú÷ܼ²ö.N èÿ*ÿøñ×Àº²¦˜ó &9Nºçþÿ#ÿõóàȺ´­¢–†sï ,=Oaz¤ÇáóþÿÿðüñãÓÀ¶°ª¢™~o^KÆ ,:HVdq|Ф·ÆÓÝåëðõùûüýÿÿþýûøõñëåÞÔɼ°­ª¥ ™’ˆ~rdUF7*ä &0;FQ[env}‚ˆŒ‘”—šž ¢¢£¢ê¡Ÿž›˜•‘Œ†€yqh^RG;/%ã $+3;BJQW]bfjnrtvyz{||zëwurokfa[UNF>5-%  è !&*/48<@CFHJKMNNêMKIFC@<72.(#  ë !"$%&&'((é'&&$"! õ ò  !  þ  þ   þ   þ þ  þ þ  þ þ þ  þ þþ  þ þþ  þ  þþ  þ þþ  ú  þþ ( þ) ý ) þþ % ý þ % þþ $ þþ # ý þ ! ý þ ý þ  ý  ý þ  þý  !ý  "ý  $ý  %ý  'û  *÷   ø ¿ þ  þ   þ   þ þ  þ þ  þ þ þ  þ þþ  þ þþ  þ  þþ  þ þþ  ú  þþ ( þ) ý ) þþ % ý þ % þþ $ þþ # ý þ ! ý þ ý þ  ý  ý þ  þý  !ý  "ý  $ý  %ý  'û  *÷   ø ¿3þ(33þ+þ2333þ/3þ3þ1þ233þ3þ/3þ 3þ+þ133þ3þ(þ233þ3þþ233ý-3þþ233þ!3þþ133ú( 33þ)þ23(3þþ/3'3ý1þ13'3þþ&3&3ý/þ13%3þþ03$3þ(þ13#3ý/þ13!3ý1þ03 3ý1ý133ý0þ.33ý+ þ133þý233!ý"133"ý133#ü +233%ý,33'û$-233*ê"&*-/01211//-)%!¿ÿõò¾¨†[4þÿÿøÇ¼¤}O)ÿÿõ÷Á¯f; ýüÿÿøÇ¼¤}O)ÿÿõûó–nB ýùÿÿøÉ¼¤~P)ÿÿõþŶ›sG#ýòÿÿøË½¥~Q*ÿÿõûƹžvJ%ýéÿÿøÑ½¦R+ÿÿõ÷ƺŸwJ&ýßÿÿøØ¾§‚V.ÿÿõóÆ¹žvJ%ýÑÿÿøã¿ª†Z2ÿÿõéÅ·œsG#ý¾ÿÿø÷®Žc;ÿÿõÜô—nB! ýªÿÿùç´—qI)ÿÿõϯf< ýÿÿúïÁaKÿÿôôȾª‡]5 ýsÿ(ÿõ߯º¡|R,ýOÿ'ÿôý̲–nF# þ(ÿ'ÿôåǽ©ˆ_8  ýôÿ%ÿóûÍõ›wN+ ýÁÿ%ÿôàÆ½ªŠd>  ý‚ÿ$ÿóóȲšvO. ý8ÿ#ÿóûÑŤ…`; üÚÿ!ÿòþØÆ¼ªmI* ýnÿ ÿòþÚÆ½®–vS2  ü ãÿÿñüØÅ½®˜{Z:  ügÿÿñ÷Òú¬—|]>$ü´ÿÿòÉÀ¶¨“y[>& ûãÿÿóº° ‹rV<% ú2åÿÿô¦•€hN6" ú 2Þÿÿô†qZC.ø%§þÿÿõ_J6%øbÑÿÿ÷:* õ3f²äþÿÿø Ý,AVr½ÓâìôùüþÿþüúøõðéãÜÓ ì #2CTbp{„‹’–šž ¢¢ø¡Ÿš ì #.:FPYagmrvxz{{øzywur"í #*17=BFIKMNNúMLJIF&ç  "%&''(''&&$"(ñ ,0 þ"þ  þ"þ  þ " þ"þ  þ"þ  þ "þ  þ"þ  ý ü þ  þ û  þ þ  þ  þ þ  ý   þ þ  ü  þ ý  õ   þþ , þþ + þ  + þ ý ) þ þ * þþ ) þþ ( þþ ' þý % þý $ þý " þ ü þ ü  þ ü  ù !û  ý+ú  ö ¿ þ"þ  þ"þ  þ " þ"þ  þ"þ  þ "þ  þ"þ  ý ü þ  þ û  þ þ  þ  þ þ  ý   þ þ  ü  þ ý  õ   þþ , þþ + þ  + þ ý ) þ þ * þþ ) þþ ( þþ ' þý % þý $ þý " þ ü þ ü  þ ü  ù !û  ý+ú  ö ¿ý233þ"þ133þ"þ033þ+"þ/33þ"þ133þ"þ133ý-!þ+33þ"þ233ý/û(.2 þ-33ý( û*.233þ þ133ý& 3þ þ.33ý* 3þ þ133ü13þ ý&233õ1(  ).33þ!þ.3,3þ$ý03+3þ)ý$13*3þ-ý)13)3þ1þ,3*3þþ-3)3þ þ,3(3þþ)3'3þý#23%3þý/3$3þ#ý&23"3þ'ü(13 3þ-ü&133þ-û(033ù1+% ú (033ý+ò#'*,.001311þ/¿ýýöÿÿöÞÄ·¢‡n]TQOOýýÅÿÿõé²—uT=0**))ýý…ÿÿõ÷²”nG*ýý:ÿÿöÊ´—pF& ýüéÿÿöḞxN*ýý“ÿÿõù¾¦„Z3 üý4ÿÿöÚ¯‘iA"ý ýüüÉÿÿõü¿žzR0 ð lº üXÿÿõð®ŽhB%ïKk˜ÔþÿÿA**#üÚÿÿôê¢Z: ÿötMJ>+ üVÿÿõî¤vT6! ÿö£vn[?#üÅÿÿóûÆ{U:& ÿÿöǘsO-û3úÿÿõúΗg?)(3[ÿÿõÞ°¡ƒ[4 üˆÿ,ÿõ뼫Œb: ûÎÿ+ÿõóÁ±’i> û/òÿ*ÿõùô—nB! ú Yýÿ)ÿõþŶ›rF#û }ÿ*ÿö̹žwK&ú‘ÿ)ÿöÒ»¢|O*ú—ÿ(ÿöÙ½¦T-ù ‡þÿ&ÿöß¾©…Y1ù kóÿ%ÿõæÀ«‰^5 ø FÕÿ$ÿõìÁ®Žb9 ÷ ,–÷ÿ"ÿõñ°‘g=  ö &Mºýÿ ÿõ÷Á°’j?  õ !3^¸öÿÿõøºªŽh?  ó*=W˜ÔøÿÿïþöëÝÏ¿²ªš^:  ò !0BTh˜Áß÷ÿÿíÈ»±­ª¦¢œ–Œ~hK. Ð"/>N]kxŽ©¿ÏÜæíóøûýþÿþýüú—”‹†{tmcWF2Ò *6BNYdnv~…‹”˜šžŸ¡¢¢£njf`[UOIB:2'Ô !*2:CKRZ`fjnrvxzz{|B?;72.)%  é !&,26;?CFIKMNNð! Þ !#%&&'(( ò ü$/ 2 2 2 2 2 2  ý  ý þ  ö  þ   ø  ý  þ   ý  ü  þ þ  þ , ý + ý + þ* þ) þ ( þ ' þ& þ$ ý # ý ! ý  ü  ü  ü   ú 0 úö2 2 2 2 2 2  ý  ý þ  ö  þ   ø  ý  þ   ý  ü  þ þ  þ , ý + ý + þ* þ) þ ( þ ' þ& þ$ ý # ý ! ý  ü  ü  ü   ú 0 úö2 32 32 32 32 32 320ú-+&" 3ý0233õ21/.,+'# 3ý1233ö0/.,+(% 313þ- 3þ133ý1 3ü0233þ 3þ133þ(,3ý0+3ý2+3þ*3þ#)3ý&(3ý''3ý%&3ý$3ý0#3ý* !3ü/3ü13ü+3ü+ 3ú/( 0ö.+(%"ö%OöNI?1þÿ ÿ%)÷(&!þÿ ÿ&ù þÿ ÿ ûþÿ ÿþ  þÿ ÿí  þÿ ÿãdò׿§‘zcI0 þÿ ÿý4÷ÿÿæúæÏ·Ÿ†mT9 þÿ ÿü#èÿÿîþí׿§v\A' þÿ ÿý(ãÿÿöÂ4-" þÿ ÿüVîÿÿõùtZM;( þÿ ÿüDÃÿÿõŠ~kR6 þÿ ÿþßÿÿô쮥•|\:þÿ+ÿóûÉ»®šzV4 þÿ+ÿóØÄº©ŽjF(þÿ*ÿóäÇ¿°˜wS2 þÿ)ÿòìÈÁ´ž€];!þÿ(ÿòðɶ¢†dB&þÿ'ÿòñÊ·¤ŠjH+ þÿ&ÿñïɶ¥‹lL/ þÿ%ÿñèÇÀµ£ŠmN2þÿ#ÿðýÞž² ˆkM2 þÿ"ÿðôк­š‚gJ0 þÿ ÿïüàľ´¦’z`E- þÿÿîýæÈ¾¶ª›‡oV>(  þÿÿí÷àÅ»´ªŒxbJ5"  þÿÿëõãÍ»¶®¥™ŠzfR=*þÿÿçüðâÓÁ¶°ª£š‚sbQ?.  õ !@d„— £¤¤à÷óïêãÛÓǺ°­ª¥Ÿ™’ˆ~rfXJ;.!õ 1Ldsz|}}⣢¢ žš—“‹†€yqh^SH=2' ö1?INOO{åzyvtrnjf`ZTMF>6.& ÷!&())NçMLJHFB?;72-(" ù ç(''&%$"  ûò !. 4 ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !  @ ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !  @3þ3þ3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3!3 @ÿöʽ¦€S,þÿÿöȽ¥R*þÿÿöǽ¥~Q*þÿÿöǼ¤~P*þÿÿöǼ¤~P)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöǼ¤}O)þÿÿöÆ»£|O(þÿÿö¸ zN'þÿÿö¸®—sI&þÿ ÿ ¤õ£ —„d@! õ !@d„— £¤¤ }õ|zsdL1 õ 1Ldsz|}}OöNI?1ö1?INOO)÷(&!÷!&())ù ù ûû! €                                                       E                                                       E 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 E ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöǼ¤}O)þÿÿúǼ¤}Oÿ ÿöÆ»£|O(þÿÿúÆ»£|Oÿ ÿö¸ zN'þÿÿú¸ zNÿ ÿö¸®—sI&þÿÿú¸®—sI¤ ¤õ£ —„d@! õ !@d„— £¤¤ù£ —„d@} }õ|zsdL1 õ 1Ldsz|}}ù|zsdL1O OöNI?1ö1?INOOúNI?1) )÷(&!÷!&())û(&! ù  ù û  û ûü þ     þ   þ   þ   þ   þ   ü  ü  ý  ý  þ  # # # # # # # # # # # # # # Ï þ 9þ  : : : :þ  :þ  :þ  :þ  :þ  :þ  ;þ  ;þ  ;  <ü ; þ <ý =þ ? þ     þ   þ   þ   þ   þ   ü  ü  ý  ý  þ  # # # # # # # # # # # # # # Ï þ 9þ  : : : :þ  :þ  :þ  :þ  :þ  :þ  ;þ  ;þ  ;  <ü ; þ <ý =þ ?3 þ1333 þ.333þ1333þ0333þ(333þ2333þ/333ü1333ü,333ý033ý&13þ,3#3#3#3#3#3#3#3#3#3#3#3#3#3#3Ïú2311.93:3:3:þ233:þ233:þ233:þ233:þ233:þ033:þ+33;þ133;þ133;û"133;ü133;ü 13<ý,3=þ/=þÿû) þÿÿöǼ¤}O)ýoÿÿû) þÿÿöǼ¤}O)ý%ÿÿû) þÿÿöǼ¤}O)üÖÿÿû) þÿÿöǼ¤}O)ý…ÿÿû) þÿÿöǼ¤}O)ü$þÿÿû) þÿÿöǼ¤}O)ü»ÿÿû) þÿÿöǼ¤}O)üOÿÿû) þÿÿöǼ¤}O)öÌÿÿ) þÿÿöǼ¤}O)öNÿÿ) þÿÿöǼ¤}O)÷µÿ) þÿÿöǼ¤}O)÷&ó) þÿÿöǼ¤}O)øk) þÿÿöǼ¤}O)ø ) þÿÿöǼ¤}O)ù) þÿÿöǼ¤}O)ù) þÿÿöǼ¤}O)ú) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û) þÿÿöǼ¤}O) û( þÿÿöÆ»£|O( û' þÿÿö¸ zN' û& þÿÿö¸®—sI&ú!  õ !@d„— £¤¤õ£ —„d@! ø  õ 1Ldsz|}}õ|zsdL1 ÷ ö1?INOOöNI?1÷ØÚÀ¨‘ ÷!&())÷(&!þïÿÿý ù ù ýùÿÿþûûýþÿÿ ý÷ÿÿ9ýëÿÿ9ýÛÿÿ9ý¸ÿÿ9ý’ÿÿ9ý]ÿÿ9ýÿÿ:ýÐÿÿ:ýoÿÿ:úöÿÿ9úŠÿÿ:ûíÿ:û`ÿ:û©;ü;ü<ý=þ=þÿ þ ý + þ ý - ý  ý / ý  3 õ  Ù þ = ý ( þ  ü & ý   ý $ ü   ý " û   ý ý  ý  ý  ý  ý  ý  ý  ü  ü  û û   û    û  , , , +þ  +þ   ý&þ    þ þ  ö þ ( þþ ( þþ ) þ þ * þþ + ý þ , ý  ý . ý   2 ô  Ø þ = ý ; û 9 þþ 6 ý ý 3 ýü / ý  ü * ü û # ü ù  ú ó   ö Ñ þ ý + þ ý - ý  ý / ý  3 õ  Ù þ = ý ( þ  ü & ý   ý $ ü   ý " û   ý ý  ý  ý  ý  ý  ý  ý  ü  ü  û û   û    û  , , , +þ  +þ   ý&þ    þ þ  ö þ ( þþ ( þþ ) þ þ * þþ + ý þ , ý  ý . ý   2 ô  Ø þ = ý ; û 9 þþ 6 ý ý 3 ýü / ý  ü * ü û # ü ù  ú ó   ö Ñ3ý+þ'3,3ý% ý%13-3ý' ý(23/3ý.ü/1323õ.$ )/23Ù3þ.3=3ý 03(3þ.33ü 13&3ý/ 33ý13$3ü033ý03"3û033ý03 3ý/ 3ý -33ý(3ý%033ü13ý +33ý% 3 ü(233ü1" 3 û *13 3û1& 3ï&+-/10/-)# 3,3+þ&33+þ)33+þ*33+þ.33û,' &þ233õ100--*(#þ233ö2//,+(%þ13(3þþ23(3þ"þ13)3þ-þ13*3þ2+3ý- ý13,3ý* ý*13.3ü/ý01313ô0% "*/13Ø3þ03=3ý03;3û%/393ù! ,363ý0ý"1333ý%ü &13/3ý' ü "-3*3ü/ û!+13#3û/#ù &.233ú1+" ó #&(*-/0112ó1/.,*'" Ðÿõôµ˜sL*ýßÿ+ÿôꨆa>"üÊÿ-ÿõëŸzV7  ýÑÿ/ÿñ÷¹sT9$  tóÿ2ÿõðÁ…];,' ]Ýÿ1ÿôöÅ’^?'-:Y–ÜÿØÿþÌÿ=ÿý#Úÿ;ÿûï 'Ïÿ9ÿùêÇ #³ÿ6ÿõûÛĽuñÿ3ÿòíËÀ¸«=¤õÿ/ÿîðÑÀ¹¯¡Ž.N£ãÿ*ÿçüèξ·®¢’€j &9N|ºãýÿ#ÿòúéÖ¿·±¨ž€mYDï -=Oaw£ÄÝñþÿÿíþôçÙȶ²­¦ž“†yiWF4%à ,:GVcp{‹¡´ÄÒÝäêðõùúüýþÿýüúùõðêåÞÔʽ²­ª¦¡›”‹‚wj^O@2%ã &0:FPZdmu|‚‡Œ“–šœžŸ¡¢¢ç Ÿš˜”‘Œ‡‚zsjaWLA6*! ã #*2:BIPV\afjnqtvxyz{{æzywurnkfb\VOH@80(  è !%*.38PY") (font "Sans") (font-size 18.000000) (font-size-unit pixels) (antialias yes) (language "en-us") (base-direction ltr) (color (color-rgb 0.137255 0.133333 0.345098)) (justify left) (box-mode dynamic) (box-unit pixels) (hinting yes) öOÞ¨öodqd}d‰Þ¨÷[÷k÷{÷‹÷›÷«÷»÷Ë÷Ûùsù›üÿ™- -û›ÿë' +Q.23¨6y;mAñBIYIiMiTiTyT‰X‰X™_™_©`ia¥aµaÅb…b¥cácñddd!d1dAdQda€€€€ Ö)þ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ Ö)þ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ Ö)þ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ Ö)€)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ À?þÿ À?þÿ À?þÿ À?€ÿ À þýüüûøí(ÿþûýüùÀÿþüýüî"ÿþýýö'ÿþýüÌ*ÿþýüÌ-ÿþþú 0ÿüþýÛ 2ÿüþýê4ÿüþýè6ÿüþýÀ8ÿýþû9ÿþþò;ÿûþüÿ<ÿýþæÿ=ÿþþÿ?ÿ À þýüüûøí(ÿþûýüùÀÿþüýüî"ÿþýýö'ÿþýüÌ*ÿþýüÌ-ÿþþú 0ÿüþýÛ 2ÿüþýê4ÿüþýè6ÿüþýÀ8ÿýþû9ÿþþò;ÿûþüÿ<ÿýþæÿ=ÿþþÿ?ÿ À þýüüûøí(ÿþûýüùÀÿþüýüî"ÿþýýö'ÿþýüÌ*ÿþýüÌ-ÿþþú 0ÿüþýÛ 2ÿüþýê4ÿüþýè6ÿüþýÀ8ÿýþû9ÿþþò;ÿûþüÿ<ÿýþæÿ=ÿþþÿ?ÿ À €ó{wrng[NB5" (ÿö÷âÊ«ŒmM%ÿùøÑ§uA"ÿúþØšZ'ÿûØ@*ÿûï£H-ÿüé’- 0ÿüÃY 2ÿüäq 4ÿüëz 6ÿüæe8ÿýÕ>9ÿüþ;ÿûéKÿ<ÿý• ÿ=ÿþÓÿ?ÿ àþùþþýÌþÿÿ ýúþÿÿ!þýÿÿ!ýÀþÿÿ"ýùþÿÿ#þýÿÿ#ýªþÿÿ$ýùþÿÿ%þýÿÿ%ý€þÿÿ&ýøþÿÿ'þýÿÿ'ý€þÿÿ(ýøþÿÿþø'þýÿÿýþü'þþÿÿýþý&ý÷þÿÿþþ&þýÿÿýþª%þþÿÿýþ€$ýöþÿÿýþ€$þýÿÿþþ%þþÿÿþý$ýõþÿÿýþü$þýÿ ÿ àþùþþýÌþÿÿ ýúþÿÿ!þýÿÿ!ýÀþÿÿ"ýùþÿÿ#þýÿÿ#ýªþÿÿ$ýùþÿÿ%þýÿÿ%ý€þÿÿ&ýøþÿÿ'þýÿÿ'ý€þÿÿ(ýøþÿÿþø'þýÿÿýþü'þþÿÿýþý&ý÷þÿÿþþ&þýÿÿýþª%þþÿÿýþ€$ýöþÿÿýþ€$þýÿÿþþ%þþÿÿþý$ýõþÿÿýþü$þýÿ ÿ àþùþþýÌþÿÿ ýúþÿÿ!þýÿÿ!ýÀþÿÿ"ýùþÿÿ#þýÿÿ#ýªþÿÿ$ýùþÿÿ%þýÿÿ%ý€þÿÿ&ýøþÿÿ'þýÿÿ'ý€þÿÿ(ýøþÿÿþø'þýÿÿýþü'þþÿÿýþý&ý÷þÿÿþþ&þýÿÿýþª%þþÿÿýþ€$ýöþÿÿýþ€$þýÿÿþþ%þþÿÿþý$ýõþÿÿýþü$þýÿ ÿ àþ(€€ýËÿÿ ý+øÿÿ!þxÿÿ!ýÈÿÿ"ý(÷ÿÿ#þtÿÿ#ýÅÿÿ$ý%öÿÿ%þpÿÿ%ýÁÿÿ&ý"ôÿÿ'þkÿÿ'ý½ÿÿ(ý óÿÿþ#'þgÿÿýîF'þºÿÿýým&ýñÿÿþ…&þcÿÿýœ%þ¶ÿÿýœ$ýïÿÿý˜$þ^ÿÿþ‡%þ±ÿÿþf$ýíÿÿýüH$þZÿ ÿ À8þþý8ÿýþú9ÿýþ€:ÿþý:ÿýþñ;ÿþþ;ÿûþûÿ;ÿüþªÿ<ÿýýÿ<ÿýþôÿ=ÿþþÿ=ÿþþÿ?ÿ À8þþý8ÿýþú9ÿýþ€:ÿþý:ÿýþñ;ÿþþ;ÿûþûÿ;ÿüþªÿ<ÿýýÿ<ÿýþôÿ=ÿþþÿ=ÿþþÿ?ÿ À8þþý8ÿýþú9ÿýþ€:ÿþý:ÿýþñ;ÿþþ;ÿûþûÿ;ÿüþªÿ<ÿýýÿ<ÿýþôÿ=ÿþþÿ=ÿþþÿ?ÿ À8€þ[8ÿýü.9ÿýÄ:ÿþ`:ÿýê;ÿþ—;ÿûý4ÿ;ÿüËÿ<ÿýhÿ<ÿýîÿ=ÿþžÿ=ÿþþÿ?ÿ €þû=ýþÀ<ýÿý<üÿþõ;ÿþþ;ÿþü:ÿýþÕ8þòÿÿþý8þþÿÿýþ÷6ýûþÿÿþþ5ýªþÿÿþü4þýÿÿýþà2ýôþÿÿþý2þþÿÿýþø0ýûþÿÿ €þû=ýþÀ<ýÿý<üÿþõ;ÿþþ;ÿþü:ÿýþÕ8þòÿÿþý8þþÿÿýþ÷6ýûþÿÿþþ5ýªþÿÿþü4þýÿÿýþà2ýôþÿÿþý2þþÿÿýþø0ýûþÿÿ €þû=ýþÀ<ýÿý<üÿþõ;ÿþþ;ÿþü:ÿýþÕ8þòÿÿþý8þþÿÿýþ÷6ýûþÿÿþþ5ýªþÿÿþü4þýÿÿýþà2ýôþÿÿþý2þþÿÿýþø0ýûþÿÿ €þ:=ýÐ<ýÿo<üÿñ;ÿþ¦;ÿþA:ÿýÖ8þÿÿþw8þ˜ÿÿýô6ý5ýÿÿþ­5ýËÿÿþH4þiÿÿýÛ2ýîÿÿþ~2þŸÿÿý÷"0ý;þÿÿ Êþýþ3þþüÿ4ÿýãþÿ4ÿþþÿ5ÿýùþÿ5ÿþþÿ6ÿþüÿ7ÿýêþÿ7ÿþþÿ8ÿýùþÿ8ÿþþÿ9ÿþýÿ:ÿýîþÿ:ÿþþÿ;ÿüúþÿ;ÿý€þÿ<ÿþýÿ=ÿþþÿþÿ Êþýþ3þþüÿ4ÿýãþÿ4ÿþþÿ5ÿýùþÿ5ÿþþÿ6ÿþüÿ7ÿýêþÿ7ÿþþÿ8ÿýùþÿ8ÿþþÿ9ÿþýÿ:ÿýîþÿ:ÿþþÿ;ÿüúþÿ;ÿý€þÿ<ÿþýÿ=ÿþþÿþÿ Êþýþ3þþüÿ4ÿýãþÿ4ÿþþÿ5ÿýùþÿ5ÿþþÿ6ÿþüÿ7ÿýêþÿ7ÿþþÿ8ÿýùþÿ8ÿþþÿ9ÿþýÿ:ÿýîþÿ:ÿþþÿ;ÿüúþÿ;ÿý€þÿ<ÿþýÿ=ÿþþÿþÿ Êþk€3€þKÿ4ÿýÝÿ4ÿþÿ5ÿý$øÿ5ÿþ·ÿ6ÿþSÿ7ÿý âÿ7ÿþ‰ÿ8ÿý)úÿ8ÿþ¾ÿ9ÿþZÿ:ÿýæÿ:ÿþÿ;ÿü/üÿ;ÿýÅÿ<ÿþbÿ=ÿþëÿþÿ’þïÿþþÿÿýþíÿÿüþüÿÿüþÿÿûþìÿÿýþüÿþþÿýþèÿýþûÿþþÿýþæÿýþûÿþþÿýþàÿýþûÿþþÿýþÛ’þïÿþþÿÿýþíÿÿüþüÿÿüþÿÿûþìÿÿýþüÿþþÿýþèÿýþûÿþþÿýþæÿýþûÿþþÿýþàÿýþûÿþþÿýþÛ’þïÿþþÿÿýþíÿÿüþüÿÿüþÿÿûþìÿÿýþüÿþþÿýþèÿýþûÿþþÿýþæÿýþûÿþþÿýþàÿýþûÿþþÿýþÛ’€ïÿþ›ÿÿýá ÿÿüþCÿÿü–ÿÿûÞ ÿÿýþ?ÿþ’ÿýÛ ÿýý<ÿþŽÿýÙ ÿýý9ÿþ‰ÿýÕÿýü4ÿþ…ÿýÒ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ%ÿþþ ÷Ìèðõùûüýþþ&ÿþþüðüþÿ#ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ%ÿþþ ÷Ìèðõùûüýþþ&ÿþþüðüþÿ#ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ%ÿþþ ÷Ìèðõùûüýþþ&ÿþþüðüþÿ#ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ%ÿþ€ ó (:LhŠ«Øþÿ%ÿþ€üCÿ#ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€@ÿþþÿ=ÿûûþþÿ:ÿýúþÿ9ÿýÀþÿ8ÿþþÿ7ÿýªþÿ6ÿýôþÿ5ÿþýÿ5ÿýªþÿ4ÿþýÿ4ÿýîþÿ3ÿ þþÿ3ÿ þýÿ3ÿ þüÿ3ÿ þùÿ3ÿ þðÿ3ÿ þÕÿ3ÿ þàÿ3ÿ þóÿ3ÿ þúÿ3ÿ þýÿ3ÿ þþÿ3ÿý€þÿ3ÿþüÿ4ÿþþÿ4ÿþüÿ5ÿýîþÿ5ÿýªþÿ6ÿý€þÿ7ÿýæþÿ8ÿýúþÿ9ÿ@ÿþþÿ=ÿûûþþÿ:ÿýúþÿ9ÿýÀþÿ8ÿþþÿ7ÿýªþÿ6ÿýôþÿ5ÿþýÿ5ÿýªþÿ4ÿþýÿ4ÿýîþÿ3ÿ þþÿ3ÿ þýÿ3ÿ þüÿ3ÿ þùÿ3ÿ þðÿ3ÿ þÕÿ3ÿ þàÿ3ÿ þóÿ3ÿ þúÿ3ÿ þýÿ3ÿ þþÿ3ÿý€þÿ3ÿþüÿ4ÿþþÿ4ÿþüÿ5ÿýîþÿ5ÿýªþÿ6ÿý€þÿ7ÿýæþÿ8ÿýúþÿ9ÿ@ÿþþÿ=ÿûûþþÿ:ÿýúþÿ9ÿýÀþÿ8ÿþþÿ7ÿýªþÿ6ÿýôþÿ5ÿþýÿ5ÿýªþÿ4ÿþýÿ4ÿýîþÿ3ÿ þþÿ3ÿ þýÿ3ÿ þüÿ3ÿ þùÿ3ÿ þðÿ3ÿ þÕÿ3ÿ þàÿ3ÿ þóÿ3ÿ þúÿ3ÿ þýÿ3ÿ þþÿ3ÿý€þÿ3ÿþüÿ4ÿþþÿ4ÿþüÿ5ÿýîþÿ5ÿýªþÿ6ÿý€þÿ7ÿýæþÿ8ÿýúþÿ9ÿ@ÿþÛÿ=ÿû8¨üÿ:ÿý/Æÿ9ÿý•ÿ8ÿþÿ7ÿýµÿ6ÿýéÿ5ÿþcÿ5ÿýÖÿ4ÿþgÿ4ÿýùÿ3ÿ þ¸ÿ3ÿ þ{ÿ3ÿ þHÿ3ÿ þ(ÿ3ÿ þÿ3ÿ þÿ3ÿ þÿ3ÿ þÿ3ÿ þ1ÿ3ÿ þYÿ3ÿ þ˜ÿ3ÿýàÿ3ÿþCÿ4ÿþ»ÿ4ÿþFÿ5ÿýáÿ5ÿý³ÿ6ÿýšÿ7ÿý ¤ÿ8ÿý0Óÿ9ÿÿýþø$þþÿÿýþã#ýôþÿÿþþ$þýÿÿþü$þþÿÿýþó#ýóþÿÿþþ$þüÿÿþû$þþÿÿýþÌ#ýòþÿÿþý$þüÿÿýþê$þþÿÿþý$ýðþÿÿýþì$þüÿÿþý%þþÿÿýþÕ$ýîþÿÿþý%þüÿÿþþ&þþÿÿþù%ýìþÿÿþþ&ýüþÿÿýþ€&þþÿÿþû&ýêþÿÿþþ'ýûþÿÿþþ(þþÿÿþú'þæÿÿþý(ÿþþ(ÿýþÀ'ÿþú'ÿþý'ÿþþ'ÿþþ'ÿýþà&ÿþú&ÿþý&ÿþý&ÿþþ&ÿþþ&ÿþþ&ÿþþ&ÿþñ%ÿþù%ÿþû%ÿþü%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþü%ÿþû%ÿþú%ÿþô%ÿýþ€%ÿþþ&ÿþþ&ÿþþ&ÿþþ&ÿþý&ÿýþø$þþÿÿýþã#ýôþÿÿþþ$þýÿÿþü$þþÿÿýþó#ýóþÿÿþþ$þüÿÿþû$þþÿÿýþÌ#ýòþÿÿþý$þüÿÿýþê$þþÿÿþý$ýðþÿÿýþì$þüÿÿþý%þþÿÿýþÕ$ýîþÿÿþý%þüÿÿþþ&þþÿÿþù%ýìþÿÿþþ&ýüþÿÿýþ€&þþÿÿþû&ýêþÿÿþþ'ýûþÿÿþþ(þþÿÿþú'þæÿÿþý(ÿþþ(ÿýþÀ'ÿþú'ÿþý'ÿþþ'ÿþþ'ÿýþà&ÿþú&ÿþý&ÿþý&ÿþþ&ÿþþ&ÿþþ&ÿþþ&ÿþñ%ÿþù%ÿþû%ÿþü%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþü%ÿþû%ÿþú%ÿþô%ÿýþ€%ÿþþ&ÿþþ&ÿþþ&ÿþþ&ÿþý&ÿýþø$þþÿÿýþã#ýôþÿÿþþ$þýÿÿþü$þþÿÿýþó#ýóþÿÿþþ$þüÿÿþû$þþÿÿýþÌ#ýòþÿÿþý$þüÿÿýþê$þþÿÿþý$ýðþÿÿýþì$þüÿÿþý%þþÿÿýþÕ$ýîþÿÿþý%þüÿÿþþ&þþÿÿþù%ýìþÿÿþþ&ýüþÿÿýþ€&þþÿÿþû&ýêþÿÿþþ'ýûþÿÿþþ(þþÿÿþú'þæÿÿþý(ÿþþ(ÿýþÀ'ÿþú'ÿþý'ÿþþ'ÿþþ'ÿýþà&ÿþú&ÿþý&ÿþý&ÿþþ&ÿþþ&ÿþþ&ÿþþ&ÿþñ%ÿþù%ÿþû%ÿþü%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþý%ÿþü%ÿþû%ÿþú%ÿþô%ÿýþ€%ÿþþ&ÿþþ&ÿþþ&ÿþþ&ÿþý&ÿýî!$þ­ÿÿýÍ#ýëÿÿþ—$þVÿÿþJ$þªÿÿýç#ýéÿÿþ¢$þQÿÿþ>$þ¥ÿÿýÔ#ýæÿÿþj$þMÿÿýç $þ¡ÿÿþ|$ýäÿÿýï $þIÿÿþr%þÿÿýã$ýâÿÿþZ%þEÿÿþÁ&þ˜ÿÿþ(%ý ßÿÿþ&ýAþÿÿýã&þ”ÿÿþ<&ý Üÿÿþ“'ý>þÿÿþá(þÿÿþ*'þ ÿÿþr(ÿþ¹(ÿýò'ÿþ2'ÿþn'ÿþ¤'ÿþÓ'ÿýû&ÿþ2&ÿþZ&ÿþ}&ÿþ¡&ÿþÄ&ÿþß&ÿþ÷&ÿþ%ÿþ)%ÿþ:%ÿþI%ÿþW%ÿþf%ÿþn%ÿþs%ÿþx%ÿþ|%ÿþ}%ÿþx%ÿþs%ÿþn%ÿþh%ÿþZ%ÿþK%ÿþ<%ÿþ-%ÿþ%ÿýú%ÿþâ&ÿþÈ&ÿþ§&ÿþ‚&ÿþ]&€ÿþþÿ=ÿýûþÿ<ÿýþÿ<ÿüãþÿ;ÿýûþÿ:ÿþþÿ:ÿýÛþÿ9ÿýûþÿ8ÿþþÿ8ÿýÕþÿ7ÿýúþÿ6ÿþþÿ6ÿýÌþÿ5ÿýúþÿ4ÿþýÿ4ÿýÀþÿ3ÿ ýùþÿ2ÿ þýÿ2ÿ ýÀþÿ1ÿ ýùþÿ0ÿ þýÿ0ÿ ýªþÿ/ÿ ýùþÿ.ÿþýÿ.ÿý€þÿ-ÿýøþÿ,ÿþýÿ,ÿý€þÿ+ÿý÷þÿ*ÿþýÿ*ÿþþÿ)ÿý÷þÿ(ÿþýÿ(ÿþþÿ'ÿýöþÿ&ÿþýÿ&ÿþþÿ%ÿýõþÿ$ÿþýÿ$ÿþþÿ#ÿýôþÿ"ÿþüÿ"ÿ€ÿþþÿ=ÿýûþÿ<ÿýþÿ<ÿüãþÿ;ÿýûþÿ:ÿþþÿ:ÿýÛþÿ9ÿýûþÿ8ÿþþÿ8ÿýÕþÿ7ÿýúþÿ6ÿþþÿ6ÿýÌþÿ5ÿýúþÿ4ÿþýÿ4ÿýÀþÿ3ÿ ýùþÿ2ÿ þýÿ2ÿ ýÀþÿ1ÿ ýùþÿ0ÿ þýÿ0ÿ ýªþÿ/ÿ ýùþÿ.ÿþýÿ.ÿý€þÿ-ÿýøþÿ,ÿþýÿ,ÿý€þÿ+ÿý÷þÿ*ÿþýÿ*ÿþþÿ)ÿý÷þÿ(ÿþýÿ(ÿþþÿ'ÿýöþÿ&ÿþýÿ&ÿþþÿ%ÿýõþÿ$ÿþýÿ$ÿþþÿ#ÿýôþÿ"ÿþüÿ"ÿ€ÿþþÿ=ÿýûþÿ<ÿýþÿ<ÿüãþÿ;ÿýûþÿ:ÿþþÿ:ÿýÛþÿ9ÿýûþÿ8ÿþþÿ8ÿýÕþÿ7ÿýúþÿ6ÿþþÿ6ÿýÌþÿ5ÿýúþÿ4ÿþýÿ4ÿýÀþÿ3ÿ ýùþÿ2ÿ þýÿ2ÿ ýÀþÿ1ÿ ýùþÿ0ÿ þýÿ0ÿ ýªþÿ/ÿ ýùþÿ.ÿþýÿ.ÿý€þÿ-ÿýøþÿ,ÿþýÿ,ÿý€þÿ+ÿý÷þÿ*ÿþýÿ*ÿþþÿ)ÿý÷þÿ(ÿþýÿ(ÿþþÿ'ÿýöþÿ&ÿþýÿ&ÿþþÿ%ÿýõþÿ$ÿþýÿ$ÿþþÿ#ÿýôþÿ"ÿþüÿ"ÿ€ÿþÚÿ=ÿý:ýÿ<ÿýŒÿ<ÿü×ÿ;ÿý6üÿ:ÿþ‡ÿ:ÿýÔÿ9ÿý3ûÿ8ÿþƒÿ8ÿýÑÿ7ÿý0úÿ6ÿþÿ6ÿýÎÿ5ÿý-ùÿ4ÿþzÿ4ÿýÊÿ3ÿ ý)øÿ2ÿ þvÿ2ÿ ýÇÿ1ÿ ý'öÿ0ÿ þrÿ0ÿ ýÃÿ/ÿ ý$õÿ.ÿþnÿ.ÿý¿ÿ-ÿý!óÿ,ÿþiÿ,ÿý¼ÿ+ÿýòÿ*ÿþeÿ*ÿþ¸ÿ)ÿýðÿ(ÿþaÿ(ÿþ´ÿ'ÿýîÿ&ÿþ\ÿ&ÿþ¯ÿ%ÿýìÿ$ÿþXÿ$ÿþ«ÿ#ÿýêÿ"ÿþTÿ"ÿÿþþ/ýÌþÿ ÿþü.þýÿ ÿýþè,ýöþÿ ÿþþ,þþÿÿýþù*þüÿÿþþ)ýÕþÿÿþý(þýÿÿýþí&ý÷þÿÿþþ&þþÿÿýþú$þüÿÿýþ€"ýãþÿÿþý"þþÿÿýþð ýøþÿÿþþ þþÿÿýþûþüÿÿýþªýèþÿÿþýþþÿÿýþóýùþÿÿþþþþÿ ÿýþûþýÿ"ÿýþÀýíþÿ#ÿþýþþÿ$ÿýþõýúþÿ%ÿþþý€þÿ'ÿþüþýÿ(ÿýþÕýñþÿ)ÿþýþþÿ*ÿýþ÷ýûþÿ+ÿþþ ýªþÿ-ÿþü þýÿ.ÿýþà ýóþÿ/ÿþý þþÿ0ÿýþøýûþÿ1ÿþþýÀþÿ3ÿþüþýÿ4ÿýþæýõþÿ5ÿþþþþÿ6ÿýþùþüÿ8ÿþþýÕþÿ9ÿûýýÿ:ÿûþì÷þÿ;ÿþ=ÿþþÿ]ÿÿþþ/ýÌþÿ ÿþü.þýÿ ÿýþè,ýöþÿ ÿþþ,þþÿÿýþù*þüÿÿþþ)ýÕþÿÿþý(þýÿÿýþí&ý÷þÿÿþþ&þþÿÿýþú$þüÿÿýþ€"ýãþÿÿþý"þþÿÿýþð ýøþÿÿþþ þþÿÿýþûþüÿÿýþªýèþÿÿþýþþÿÿýþóýùþÿÿþþþþÿ ÿýþûþýÿ"ÿýþÀýíþÿ#ÿþýþþÿ$ÿýþõýúþÿ%ÿþþý€þÿ'ÿþüþýÿ(ÿýþÕýñþÿ)ÿþýþþÿ*ÿýþ÷ýûþÿ+ÿþþ ýªþÿ-ÿþü þýÿ.ÿýþà ýóþÿ/ÿþý þþÿ0ÿýþøýûþÿ1ÿþþýÀþÿ3ÿþüþýÿ4ÿýþæýõþÿ5ÿþþþþÿ6ÿýþùþüÿ8ÿþþýÕþÿ9ÿûýýÿ:ÿûþì÷þÿ;ÿþ=ÿþþÿ]ÿÿþþ/ýÌþÿ ÿþü.þýÿ ÿýþè,ýöþÿ ÿþþ,þþÿÿýþù*þüÿÿþþ)ýÕþÿÿþý(þýÿÿýþí&ý÷þÿÿþþ&þþÿÿýþú$þüÿÿýþ€"ýãþÿÿþý"þþÿÿýþð ýøþÿÿþþ þþÿÿýþûþüÿÿýþªýèþÿÿþýþþÿÿýþóýùþÿÿþþþþÿ ÿýþûþýÿ"ÿýþÀýíþÿ#ÿþýþþÿ$ÿýþõýúþÿ%ÿþþý€þÿ'ÿþüþýÿ(ÿýþÕýñþÿ)ÿþýþþÿ*ÿýþ÷ýûþÿ+ÿþþ ýªþÿ-ÿþü þýÿ.ÿýþà ýóþÿ/ÿþý þþÿ0ÿýþøýûþÿ1ÿþþýÀþÿ3ÿþüþýÿ4ÿýþæýõþÿ5ÿþþþþÿ6ÿýþùþüÿ8ÿþþýÕþÿ9ÿûýýÿ:ÿûþì÷þÿ;ÿþ=ÿþþÿ]ÿÿþ´/ýÑÿ ÿþP.þqÿ ÿýà ,ýòÿ ÿþ†,þ§ÿÿýù'*þBÿÿþ¼)ý×ÿÿþW(þxÿÿýå &ýõÿÿþ&þ®ÿÿýû,$þIÿÿýÂ"ýÜÿÿþ_"þ€ÿÿýé ý#÷ÿÿþ• þ¶ÿÿýý3þQÿÿýÉý áÿÿþfþ‡ÿÿýíý(ùÿÿþœþ½ÿ ÿýþ8þXÿ"ÿýÏý åÿ#ÿþnþÿ$ÿýðý.üÿ%ÿþ¤ýÄÿ'ÿþ?þ`ÿ(ÿýÕýêÿ)ÿþuþ–ÿ*ÿýóý3ýÿ+ÿþ« ýÊÿ-ÿþF þgÿ.ÿýÚ ýíÿ/ÿþ} þžÿ0ÿýö!ý:þÿ1ÿþ³ýÐÿ3ÿþNþoÿ4ÿýß ýñÿ5ÿþ„þ¥ÿ6ÿýù&þ@ÿ8ÿþºýÕÿ9ÿûUvÿ:ÿûä ôÿ;ÿýŒ­ÿ<ÿþýÿ]ÿÿÿþþÿ=ÿþýÿ<ÿýþÿ;ÿüþôÿ;ÿüýÿ:ÿþþ:ÿýþó:ÿþü9ÿþþ8ÿýþò8ÿþü7ÿþþ6ÿýþð6ÿþü5ÿþþ4ÿýþî4ÿþü3ÿþþ 2ÿýþí 1ÿýþü 1ÿþþ 0ÿýþê /ÿýþû /ÿþþ .ÿýþæ -ÿýþû-ÿþþ,ÿýþã+ÿýþû+ÿþþ*ÿýþÛ)ÿýþû)ÿþþ(ÿýþÕ'ÿýþú'ÿþþ&ÿýþÌÿÿþþÿ=ÿþýÿ<ÿýþÿ;ÿüþôÿ;ÿüýÿ:ÿþþ:ÿýþó:ÿþü9ÿþþ8ÿýþò8ÿþü7ÿþþ6ÿýþð6ÿþü5ÿþþ4ÿýþî4ÿþü3ÿþþ 2ÿýþí 1ÿýþü 1ÿþþ 0ÿýþê /ÿýþû /ÿþþ .ÿýþæ -ÿýþû-ÿþþ,ÿýþã+ÿýþû+ÿþþ*ÿýþÛ)ÿýþû)ÿþþ(ÿýþÕ'ÿýþú'ÿþþ&ÿýþÌÿÿþþÿ=ÿþýÿ<ÿýþÿ;ÿüþôÿ;ÿüýÿ:ÿþþ:ÿýþó:ÿþü9ÿþþ8ÿýþò8ÿþü7ÿþþ6ÿýþð6ÿþü5ÿþþ4ÿýþî4ÿþü3ÿþþ 2ÿýþí 1ÿýþü 1ÿþþ 0ÿýþê /ÿýþû /ÿþþ .ÿýþæ -ÿýþû-ÿþþ,ÿýþã+ÿýþû+ÿþþ*ÿýþÛ)ÿýþû)ÿþþ(ÿýþÕ'ÿýþú'ÿþþ&ÿýþÌÿÿþíÿ=ÿþZÿ<ÿý­ÿ;ÿüëÿ;ÿüVÿ:ÿþª:ÿýé:ÿþR9ÿþ¦8ÿýç8ÿþM7ÿþ¡6ÿýä6ÿþI5ÿþ4ÿýâ4ÿþE3ÿþ™ 2ÿýà 1ÿýþB 1ÿþ” 0ÿýÜ /ÿýþ> /ÿþ .ÿýÚ -ÿýý:-ÿþŒ,ÿý×+ÿýü7+ÿþ‡*ÿýÔ)ÿýû3)ÿþƒ(ÿýÑ'ÿýú0'ÿþ&ÿýÎÿýþú ÿþþ ÿýþÕ ÿýþú ÿþý ÿýþÌ ÿýþú ÿþý ÿýþÀ ÿýþù ÿþý ÿýþªÿýþùÿþýÿýþ€ÿýþøÿþýÿýþ€ÿýþøÿþýÿþþÿýþ÷ÿþýÿþþüÿþöýÿýþþþõTÿýþú ÿþþ ÿýþÕ ÿýþú ÿþý ÿýþÌ ÿýþú ÿþý ÿýþÀ ÿýþù ÿþý ÿýþªÿýþùÿþýÿýþ€ÿýþøÿþýÿýþ€ÿýþøÿþýÿþþÿýþ÷ÿþýÿþþüÿþöýÿýþþþõTÿýþú ÿþþ ÿýþÕ ÿýþú ÿþý ÿýþÌ ÿýþú ÿþý ÿýþÀ ÿýþù ÿþý ÿýþªÿýþùÿþýÿýþ€ÿýþøÿþýÿýþ€ÿýþøÿþýÿþþÿýþ÷ÿþýÿþþüÿþöýÿýþþþõTÿýû1 ÿþ ÿýÏ ÿýú/ ÿþ} ÿýÌ ÿýø+ ÿþx ÿýÈ ÿý÷( ÿþt ÿýÅÿýö%ÿþpÿýÂÿýô#ÿþkÿý½ÿýó ÿþgÿþºÿýñÿþcÿþ¶üÿïýÿ^þ±þT)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ$ÿþþ$ÿþþýùýÿ#ÿþþùÕøüýþþÿ%ÿþ,ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþýùýÿ#ÿþþùÕøüýþþÿ%ÿþ,ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþýùýÿ#ÿþþùÕøüýþþÿ%ÿþ,ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþ€$ÿþ€ý'nÿ#ÿþ€ù"Hx§âÿ%ÿþÀ€€õ…Š˜©¹Êåýÿ+ÿþ€$ÿþ€$ÿþ€$ÿþ€ûúþþÿ:ÿþþÿ }ÿþþÿ<ÿýþòÿ:ÿþýªÿ9ÿýþû8ÿþþê7ÿýþû5ÿüþýÀ3ÿþþð1ÿþþõ /ÿüþýò -ÿüþýæ *ÿþþú'ÿþýüÀ$ÿþýüÌ ÿþýý÷ÿþýüõÿþüýûó"ÿ þýüüúñ*ûúþþÿ:ÿþþÿ }ÿþþÿ<ÿýþòÿ:ÿþýªÿ9ÿýþû8ÿþþê7ÿýþû5ÿüþýÀ3ÿþþð1ÿþþõ /ÿüþýò -ÿüþýæ *ÿþþú'ÿþýüÀ$ÿþýüÌ ÿþýý÷ÿþýüõÿþüýûó"ÿ þýüüúñ*ûúþþÿ:ÿþþÿ }ÿþþÿ<ÿýþòÿ:ÿþýªÿ9ÿýþû8ÿþþê7ÿýþû5ÿüþýÀ3ÿþþð1ÿþþõ /ÿüþýò -ÿüþýæ *ÿþþú'ÿþýüÀ$ÿþýüÌ ÿþýý÷ÿþýüõÿþüýûó"ÿ þýüüúñ*û-¦þÿ:ÿþËÿ }ÿþÞÿ<ÿý·ÿ:ÿûü€ÿ9ÿýÛ88ÿüþ• 7ÿýÍ75ÿüìl3ÿüô„1ÿüô /ÿüë~ -ÿüÈa *ÿüê“.'ÿûïžF$ÿûÕŠ@ ÿûÛ_ÿúæ³OÿøòÕ´e="ÿîüøôñìâÖʾ±ŸŠvaK/*ÿþû&ÿýþí&ÿþþ'ÿþþ'ÿþý'ÿþû'ÿýþÛ'ÿþþ(ÿþþ(ÿþû(ÿýþ€(ÿþþ)ÿþü)ÿýþÛ)ÿþþ*ÿþü*ÿýþ€*ÿþý+ÿýþð+ÿþþ,ÿýþø,ÿþþ-ÿýþù-ÿþþ. ÿýþõ. ÿþý/ ÿýþà/ ÿþü0 ÿþþ1 ÿýþð1 ÿýþû2 ÿþþ3ÿýþÀ3ÿýþó4ÿýþú5ÿýþü6ÿýþý7ÿþý8ÿþý9ÿþý:üÿþý;ýþü<þú~ÿþû&ÿýþí&ÿþþ'ÿþþ'ÿþý'ÿþû'ÿýþÛ'ÿþþ(ÿþþ(ÿþû(ÿýþ€(ÿþþ)ÿþü)ÿýþÛ)ÿþþ*ÿþü*ÿýþ€*ÿþý+ÿýþð+ÿþþ,ÿýþø,ÿþþ-ÿýþù-ÿþþ. ÿýþõ. ÿþý/ ÿýþà/ ÿþü0 ÿþþ1 ÿýþð1 ÿýþû2 ÿþþ3ÿýþÀ3ÿýþó4ÿýþú5ÿýþü6ÿýþý7ÿþý8ÿþý9ÿþý:üÿþý;ýþü<þú~ÿþû&ÿýþí&ÿþþ'ÿþþ'ÿþý'ÿþû'ÿýþÛ'ÿþþ(ÿþþ(ÿþû(ÿýþ€(ÿþþ)ÿþü)ÿýþÛ)ÿþþ*ÿþü*ÿýþ€*ÿþý+ÿýþð+ÿþþ,ÿýþø,ÿþþ-ÿýþù-ÿþþ. ÿýþõ. ÿþý/ ÿýþà/ ÿþü0 ÿþþ1 ÿýþð1 ÿýþû2 ÿþþ3ÿýþÀ3ÿýþó4ÿýþú5ÿýþü6ÿýþý7ÿþý8ÿþý9ÿþý:üÿþý;ýþü<þú~ÿþ8&ÿýþ &ÿþÚ'ÿþ¨'ÿþv'ÿþ<'ÿý÷'ÿþÁ(ÿþ(ÿþ7(ÿýé(ÿþŸ)ÿþO)ÿýî)ÿþ›*ÿþ@*ÿýÙ*ÿþp+ÿýõ+ÿþ–,ÿýû ,ÿþ -ÿýü'-ÿþ˜. ÿýó. ÿþ}/ ÿýÙ/ ÿþA0 ÿþ 1 ÿýá1 ÿýý>2 ÿþ…3ÿý»3ÿýß4ÿýó/5ÿýúF6ÿýþ]7ÿþo8ÿþp9ÿþp:üÿú^;ýóF<þ0~þþÿ!ÿýóþÿ ÿþüÿ ÿþþÿÿýñþÿÿþüÿÿþþÿÿýðþÿÿ þüÿÿ!þþÿÿ!ýíþÿÿ"ýüþÿÿ#þþÿÿ#ýìþÿÿ$ýüþÿÿ%þþÿÿ%ýèþÿÿ&ýûþÿÿ'þþÿÿ'ýæþÿÿ(ýûþÿÿ)þþÿÿ)ýàþÿÿ*ýûþÿÿ+þþÿÿ+ýÛþÿÿ,ýúþÿÿ-þþÿÿ-ýÕþÿÿ.ýúþÿ ÿ/þýÿ ÿ/ýÌþÿ ÿ0ýúþÿ ÿ1þýÿ ÿ1ýÀþÿ ÿ2ýùþÿ ÿ3þýÿ ÿ3ýªþÿÿ4ýùþÿÿ5þýÿÿ5ý€þÿÿ6ýøþÿÿ7þýÿÿ7ý€þÿÿ8þøÿÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿþþÿ!ÿýóþÿ ÿþüÿ ÿþþÿÿýñþÿÿþüÿÿþþÿÿýðþÿÿ þüÿÿ!þþÿÿ!ýíþÿÿ"ýüþÿÿ#þþÿÿ#ýìþÿÿ$ýüþÿÿ%þþÿÿ%ýèþÿÿ&ýûþÿÿ'þþÿÿ'ýæþÿÿ(ýûþÿÿ)þþÿÿ)ýàþÿÿ*ýûþÿÿ+þþÿÿ+ýÛþÿÿ,ýúþÿÿ-þþÿÿ-ýÕþÿÿ.ýúþÿ ÿ/þýÿ ÿ/ýÌþÿ ÿ0ýúþÿ ÿ1þýÿ ÿ1ýÀþÿ ÿ2ýùþÿ ÿ3þýÿ ÿ3ýªþÿÿ4ýùþÿÿ5þýÿÿ5ý€þÿÿ6ýøþÿÿ7þýÿÿ7ý€þÿÿ8þøÿÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿþþÿ!ÿýóþÿ ÿþüÿ ÿþþÿÿýñþÿÿþüÿÿþþÿÿýðþÿÿ þüÿÿ!þþÿÿ!ýíþÿÿ"ýüþÿÿ#þþÿÿ#ýìþÿÿ$ýüþÿÿ%þþÿÿ%ýèþÿÿ&ýûþÿÿ'þþÿÿ'ýæþÿÿ(ýûþÿÿ)þþÿÿ)ýàþÿÿ*ýûþÿÿ+þþÿÿ+ýÛþÿÿ,ýúþÿÿ-þþÿÿ-ýÕþÿÿ.ýúþÿ ÿ/þýÿ ÿ/ýÌþÿ ÿ0ýúþÿ ÿ1þýÿ ÿ1ýÀþÿ ÿ2ýùþÿ ÿ3þýÿ ÿ3ýªþÿÿ4ýùþÿÿ5þýÿÿ5ý€þÿÿ6ýøþÿÿ7þýÿÿ7ý€þÿÿ8þøÿÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿþ¨ÿ!ÿýèÿ ÿþOÿ ÿþ£ÿÿýåÿÿþKÿÿþŸÿÿýãÿÿ þGÿÿ!þ›ÿÿ!ý áÿÿ"ýDþÿÿ#þ–ÿÿ#ý Þÿÿ$ý?þÿÿ%þ’ÿÿ%ý Ûÿÿ&ý<ýÿÿ'þŽÿÿ'ý Ùÿÿ(ý9ýÿÿ)þŠÿÿ)ýÕÿÿ*ý4üÿÿ+þ…ÿÿ+ýÒÿÿ,ý1ûÿÿ-þÿÿ-ýÏÿÿ.ý/úÿ ÿ/þ}ÿ ÿ/ýÌÿ ÿ0ý+øÿ ÿ1þxÿ ÿ1ýÈÿ ÿ2ý(÷ÿ ÿ3þtÿ ÿ3ýÅÿÿ4ý%öÿÿ5þpÿÿ5ýÂÿÿ6ý#ôÿÿ7þkÿÿ7ý½ÿÿ8þÿÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿÿÿÿÿ%ÿýþú%ÿþý$ÿýþÀ#ÿýþù#ÿþý"ÿýþÀ!ÿýþù!ÿþý ÿýþªÿýþùÿþýÿýþ€ÿýþøÿþýÿýþ€ÿýþ÷ ÿþý!ÿþþ"ÿýþ÷"ÿþý#ÿþþ$ÿýþö$ÿþý%ÿþþ&ÿýþõ&ÿþý'ÿþþ(ÿýþô(ÿþü)ÿþþ*ÿýþó*ÿþü+ÿþþ,ÿýþñ,ÿþü-ÿþþ. ÿýþð. ÿþü/ ÿþþ0 ÿýþí0 ÿýþü1 ÿþþ2 ÿýþì2ÿýþü3ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4%ÿýþú%ÿþý$ÿýþÀ#ÿýþù#ÿþý"ÿýþÀ!ÿýþù!ÿþý ÿýþªÿýþùÿþýÿýþ€ÿýþøÿþýÿýþ€ÿýþ÷ ÿþý!ÿþþ"ÿýþ÷"ÿþý#ÿþþ$ÿýþö$ÿþý%ÿþþ&ÿýþõ&ÿþý'ÿþþ(ÿýþô(ÿþü)ÿþþ*ÿýþó*ÿþü+ÿþþ,ÿýþñ,ÿþü-ÿþþ. ÿýþð. ÿþü/ ÿþþ0 ÿýþí0 ÿýþü1 ÿþþ2 ÿýþì2ÿýþü3ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4%ÿýþú%ÿþý$ÿýþÀ#ÿýþù#ÿþý"ÿýþÀ!ÿýþù!ÿþý ÿýþªÿýþùÿþýÿýþ€ÿýþøÿþýÿýþ€ÿýþ÷ ÿþý!ÿþþ"ÿýþ÷"ÿþý#ÿþþ$ÿýþö$ÿþý%ÿþþ&ÿýþõ&ÿþý'ÿþþ(ÿýþô(ÿþü)ÿþþ*ÿýþó*ÿþü+ÿþþ,ÿýþñ,ÿþü-ÿþþ. ÿýþð. ÿþü/ ÿþþ0 ÿýþí0 ÿýþü1 ÿþþ2 ÿýþì2ÿýþü3ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4%ÿýù-%ÿþ{$ÿýÊ#ÿýø)#ÿþv"ÿýÇ!ÿýö'!ÿþr ÿýÃÿýõ$ÿþnÿýÀÿýó!ÿþiÿý¼ÿýò ÿþe!ÿþ¸"ÿýð"ÿþa#ÿþ´$ÿýî$ÿþ\%ÿþ¯&ÿýì&ÿþX'ÿþ«(ÿýê(ÿþT)ÿþ¨*ÿýè*ÿþP+ÿþ£,ÿýå,ÿþK-ÿþŸ. ÿýã. ÿþG/ ÿþ›0 ÿýá 0 ÿýþD1 ÿþ—2 ÿýÞ 2ÿýþ?3ÿþŸ4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4€€€€)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿÿÿÿÿÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4€€€€)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ @)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ @)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ @)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ)ÿ @$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ Y$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ Y$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ$ÿþþ Y$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€$ÿþ€ Y9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ @9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ @9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ @9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ9ÿ @Àÿ @Àÿ @Àÿ @Àÿ @ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ uÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ uÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ4ÿþþ uÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€4ÿþ€ u€€€€                            °°°°ïÔwj;5Big PY Borderÿ     >eKeoùhh/h?hOh_hohhhŸh¯h¿hÏhßhïhÿpÚ}[ˆP“.ž'©"´/¾ÐËØÓžÓ®Ó¾ÓÎâ ââ+â;âKâ[âkâ{â‹ðÆðÖðæðöÿÿÿ%ÿ5ÿEÿUÿeÿuÿ… ¿ Ï ß ï]m}­½ÍÝ*á*ñ++8‡8—8§8·8Ç8×8ç8÷9FïFÿGGUjUzUŠUšUªUºUÊUÚUêddd$d4r—r§r·rÇr×rçr÷ss€ø(¬‘‘‘!‘1‘A‘Q‘a“J¡¡Ÿ¡¯¡¿¤E¯HºJÅÐfÛmæ^ñ&üUþiþyþ‰þ™þ©þ¹þÉþÙþéþùÿ ÿÿ)ÿ9ÿIÿYÿiÿyÿ‰ÿ™ÿ©ÿ¹ÿÉÿÙÿéÿù )9IYiy‰™©¹ÉÙ退€€?þ;;9þ7ø66þ4ýù2üü1÷0ü/þþ// .þþý,ýþý+û+ùþü*ýþ*þþþ* ü(þþ )ú(û (ú'ýþ'ù&÷ô%ü%üþ$ ÷%þûú%ó%þþü%ý ü&þú'ý( û'ý ü'þþú?þ;;987þ5þ3ý3 2 1ü0þ 0ù/þûþ.ø-þ,ð+þú+ûû)ø*þûþþ(þþú)úø' õ'üú&ý õ&ý% ò%þ ö$þþ ý$üþþ$ý%ýü ú%ýþ&úþþ&þþþ'ó (ñþ'(þ÷þ?þ1;1þ0:þ10091û010171ý016÷212101005ú12112114þ211þ211ý012ø1221122112212112ý121121021210321/ 21þ2-3ý2322û1211,32þ322û1221+3 2ý12+32ú12212*ý3433232*ü34433ø232322322ý12)34ó34332322322322þ1(4343û2322332ü322(43ý2322(43þ4332ü32322(4ú34334332'4ý34332ú32322&ø544344344 323&4ú34334332&54ý3433432þ3$ý54554ü34433ý23$5ú4554544þ344ý3433ü233$÷54545445443&5ù454455443ü43433& 54ù34433433& 5ý45443ü433&5454þ5443'65û45454 4þ3'5þ4554ú5443344'þ655þ655ü45544þ544(ù56565655þ455ý4544þ544?þÿ;ÿ;ÿ9ÿ8ÿ7ÿ6ÿ4 ÿ3 ÿ2 ÿ1 ÿ0ÿ0ÿ/ÿ.ÿ-ÿ,ÿ,ÿ+ÿ*ÿ*ÿ)ÿ)ÿ(ÿ(ÿ'ÿ'ÿ&ÿ&ÿ%ÿ%ÿ%ÿ&ÿ&ÿ&ÿ'ÿ'ÿ(ÿ'ÿ(ÿ ü þþ üüþü û ÷þþþýþþ ô ýýüüùùüþüþô  ýüþ ýüüüþþûû üüþ üüüþôþþûýþûþüúüþý÷þüøöþûúþúþþþ ùýøþýþõþþ þüôûûòþ÷ýþþþþüüúþþ þýý"þ þ'þ,ù/þþü0ó2ù3þ5ü7ý8ý8ý:ü;==þþþö þýïþ üþ ýöùþ øþþñ þüþ÷þüþûýþ üùûþ ÷þþþûþþþþýþùþþ ùùþüûýþþýþ ôüøþþþ þû þþþ ý úù þþþ ýûøþ÷þúüþõþúü þþü þþþþþþ üýü þþ úú÷ õü÷" õ' ú, / þ1 3 4þ678ü8;ü;=ý<þþ.û-.-.--ý,-,,+þ,++ú*+*++þ/..-.-þ.--ú,--,-,,û+,+,+ +þ* ú/..//..÷-..--.-.-- ,û+,+,++/.þ/..þ-..ý-.--þ.--,ù+,,+,,++ü0/0//./ .-þ.--,-,+þ,++ü*++/0/þ.//.-ú.--..--ý,-,,+ú,++,,++þ*0 /û././..ý-.--.ý-.--þ,--ú,-,--,,ù+,,+,,++û00/00/ý./..ú-.--.--,þ-,,ü+,,++0þ/00/þ.// .ú-.--.--,þ-,,þ-,,+þ,++10ü/00//þ0//./.-.-ø.--,--,--,ý+,++0ü/0/00û/0/0//ý./..þ-..ý-.--,-,þ-,,+,ü+,+00ý/0//ü0/0//./.÷/..-.-..--þ.--,ü-,-,,+,ú+010100ù/0/0/0//ü.//..þ/..þ-..-,-ý,-,,ü+,+110ü/00/ /ù.//../..ù-..--.--þ,--ý,-, ,þ100þ/00/û././..ö/..--.-..--þ,--,ò+,,+,++01100100ú/0/00// .ø-..-.-.--ù,-,-,-,,+10ô100/00/0//0//./.þ/..-.-þ,--ý,-,,ö+1101101100/þ0//ü.//.. -ü,--,,ü+,,110û100100ý/0//ú./../..-û.--.--ü,--,,þ-,,1þ011ý0100/þ0/ /ý./..û-.-.--û,-,-,,10þ100î/0/0/0//0//./././..-û.-..--ö,-,-,-,,-,,ú+1210110þ100ü/00//#þ211 0þ/'1ü01100,1þ211ü01100/ú1221211û01100ü21122132ý121142ü1215÷1221121261þ2118ù21212282þ1:2<2=3=þ3þ*ÿ/ÿ 3ÿ6ÿ8ÿ:ÿ<ÿþÿšÿ#ÿ(ÿ,ÿ/ ÿ1 ÿ3 ÿ4ÿ6ÿ7ÿ8ÿ9ÿ;ÿ<ÿ=ÿ=þÿþ÷ ûúþþ þô þþþ üþ úûþñþþüüûþþ ýûþþýþþ ýøþùû ù úþù þüþþþþ ûýþüýýþüþþþúýþ þþüîùö íþýþûøþúþþóüþþúþþ þøþ þþþýýþ ùþ þþûûþ øüþþúúþþøûþþþöþþ þÀþ þþýþüýþþþõ üþüþú óþùùýþþûþ ûþþþþýþûþûüýþþþüþûù øþ þüúúýüþþýúþþóþþûüþõùþ þþþþþüþúýþüø üøþñþüýü öý öþûþþõþ þöþþþþþþüø ýþþ úþÀ*)*)(þ)(('û(''(' '&ö%&&%%&&%%* *)ü())((û)(()(('(ý'(''þ&''&ù'&&%&&%%þ&%%þ+**þ)**)(þ)((þ'(('('ü('&''&'&ö%&&%%&%%+**ü)**) )(þ'((ý'(''&þ'&&õ%&%%**+**+**ý)*))þ())()('ü('(''ü&''&&þ'&&%ü*++**þ+**)()ü())((þ'(('û&''&''&ù%&%&%&++ý*+**)*ý)*))()(þ)(('('ú&'&&'&&%+ *ý)*))()( 'û&'&'&&þ%++*þ+**þ)**ý)*))þ())(ü'((''ù&'&&''&&÷+*+*+*++**ù)*)*)*))(þ)((ø'((''((''÷&''&'&''&&û%++*++û*+*+**ü)*)**)(þ)((þ'(('&þ'&&+ý*+**þ+**þ)**)þ())('( 'ý&'&&þ%++ø*+*+*++**þ+**ø)*)*)**))(þ)(('þ(''þ&''&+þ*++*þ+**)*)(û)(()((ì'(('('(''('&''&'&&'&&+ø*+*+**+**)*)(ü)()((ý'(''ý&'&&ü',,++*+ü*++**)þ*))ý()( ('&'ü&'&,, +*)* ) ('þ(''ù&''&'&+ +*+*)ú*))**))()(ý'(''þ(''ü&'',,+*ü+*+**ú)*)**))(þ)(('( ',+þ,++ú*++*+**ø)*)**)*))(þ)((ù'(('((''ý&+,,ý+,++þ*++û*+*+**)ü*)*))(ü)()((ü'((' 'þ&¿@ÿÀùþ    þ  ó ü ý   ü   û   þ   üüý   þ  û þþ þ ù    þ ôþû   þ þ úú ö     û  õüþ ü   û   þ øûþ  ý ý   þ þ ý ú    þ ÷þ ð       ÷ü û  û   ü   ïû   û   þ  þûüþ ÷    ü   þ  õýþ þ  ü  þ  þøù     ý üù ü   û   ýþ þ   þ  þ  þþû þ  ú    þþûú û   ú þûþ þ õ     ýþþþþþ þ ú  ¿þþ ý    þ  þ  þ    þ  þ  þ  ù  ý  þ   ô úþ  ö     ù   þ  øö     ÷     þ  þ  ü  ý ý þ þ  û   þ  ü ø ÷    þ  ÷ þþû   ý þ   ü ü þ  ö     þ  ï þ ü   þ  û  ÷    ù   ü øþ      ü û ü   ü   ø  ú  û    þ  þ  û ù   ù    þ ýúø     þ  ù þýþû  ó      þþü  û  ú    þ   ùüûú    þ  þ  ý öþþ ü  ý   þ  ý þþþþ  þ À%ú$%$$%$$#ü$#$##ü"##""#"ý!"!!þ"!!ý !  %ö$%$%$%%$%$$þ#$$#þ"##ý"#""!þ"!!þ !! %þ$%%$%$#ý"#""þ#""! þ&%%ü$%%$$#ü$#$##"# "û!"!"!!ó !! ! ! ! %%$þ%$$÷#$#$##$$##÷"#""##"#""!û"!""!! û! ! %%þ&%%$þ%$$û#$#$##ü"##""þ#""!þ"!!þ !!ý &%%$þ%$$#þ$##÷"#"##""#""ý!"!!"!ý !  &%ý$%$$þ%$$#$#ü"##""!þ"!! &%þ$%% $ #"þ#""þ!""ý!"!!ù ! !!&%%û&%%&%%ú$%$%%$$ý#$##ú"#""#""ú!"!!"!!ú ! &%&&%þ$%% $û#$#$##ý"#" " !÷ !&%%&%&%%þ&%%$#ù$#$#$$##ú"#"##""ý!"!! &%ö&%%$%%$%%$$ù#$$#$$##"#ø"##"#""!!"!ù"!! !!&&ø%&%&&%&%%ý$%$$þ%$$ý#$##ú"#""#""þ!""!ý !&&ü%&&%%ù&%%$$%$$%$ö#$##$$##$##þ"##"÷!"!"!"!"!!&%&%ú$%$%%$$ý#$##ú"##"#" "ø!"!!"!!&&ü%&&%%ù$%%$$%$$#û$#$$##"û#""#""þ!""ý!"!!&þ'&&%þ&%%ý$%$$û%$$%$$#$#ý"#""þ!""!þ'&& % $ý#$##ü$#$##þ"##"÷!""!!"!!&&%þ&% %$þ%$$þ#$$#"ü#"#""û!"!"!!ú"'&&'&&ý%&% %þ$%%$û%$$#$$ú#$#$$##"þ#""û!"!!¿@ÿÀý  þ  þ þ   þ  ö      ý  ö ú  ù   ú   þ  þ  þ  ý  þ  ý  û  þ  þ   þ  þ  ü  ü   þ   þ  þ  þ  þ  ù  ü    þ  ü  þ ý   û   ú  þ     þ ø    ý þ  û    þ  þ  þ   û  þ  ì  þ  þ   ü    ú  þ  ù   þ ø  þ  þ  ó  ü  ý  þ  þ  þ  þ  þ   þ  ü     þ  þ  ý    ü   ý   þ  þ  þ  þ  ý  þ  ú  þ  þ  ý   ü   ü  ó   þ  þ     þ  þ  þ  þ  ý  ú  þ  ô  þ þ     ü  ý     ý  ý  þ  þ þ  þ   þ    þ  ù   þ  ü þ   ü   ÷  ú     þ  ü  þ  Àþ þ  þ  û  þ  õ     þ     þ  þ    ö  þ   ð   ÷   ù   þ  þ  ý þ    ü  ü  ú  þ  ü  ü  þ    ù  ù  ú þ    ü  þ ü  ÷   ï  þ     û ÷  ù  û  þ    ü    õ      ý   þ  þ   þ   ý  ù  þ  û  þ  ô    þ  ø  ù  þ õ  þ  þ  ü  þ    þ  þ  ø   ù    ý     þ  þ ý  þ  þ  þ  õ   û   û  þ  þ  þ      þ  þ    ÷    ú  ú  ü  þ   þ   ü  ø û    û   ü  ý    þ þ  ý  ù   ð þ   ý  þ   ü  À þ û ÷þüö   þýþþûý  û üþþþûþ  ûúþþþ  ù  þþþþþ þ  ú  þ þþþþý  úþùþ  ü   ýþüýþþ þ  û  øþþô! !  þ  û ýý þ!  þþûü! !  ý þ þþþù!  þ!  þ  þ üý !! þ!  þ  üþþ þ!! þ!  ø  üûüþü! !  ! û  ú ý!!þ !! ü þ ú ð! ý þ þ þ ! þ!  ø   þþþþ!ü !!  ø   ø ÷ö!"!!ý !  û! !!  ü  þøûÀ@ÿÀ ü þ  ü   ý  þ  ù    ÷   þ  þ  û  ö  þ  ÷   þ   ñ  þ  þ   û     þ   þ  ý  û  þ   þ  ý  ø  þ  þ  ü  ý  ú  õ      þ    þ   þ  þ  ù    þ       ü  ö     ý  ü    þ  þ  þ  õ       þ  þ  ü    þ  þ  þ  ú        ÷  þ  þ   ò  þ  û  û þ   ó  þ ð   ô  ý     ø  ú  þ û     þ  ü  û  þ  ù   ú  û  ù  ú   þ  þ  û    ú ù    þ  ü   þ ð  þ  ü ý    þ ó  þ       ü     ù   þ  À þ    û  ü  ü   û   ü   þ  û  þ  û  þ  þ   ÷    ý   ü ø    õ  ý  þ  þ   þ ü   þ  ü  þ  ý  þ ú    û    ú  þ  þ  þ     þ  û   û   þ    ù   þ ö    ÷  þ  ö  ü    þ û  ý   þ   û  ü  û  ú   ü     ý ü   ü    û þ  þ     þ  û ü  ü  ü  þ  ô      þ  û   ý   þ  þ  û     þ  þ  þ    ý  þ  í  þ  ü  ù  þ  ý  ý  þ  þ   þ  û  þ  þ  ú  ü  þ  þ  ï  þ  ý  þ   ü   ü   ø  þ      ÷  ô   ý  þ   þ    ý  þ  û  þ   ü Àþü ýþý üöþûþùþýþúùý þþøüùùûþþþüûýýþõþûöþúþýýùþþýþþþüþþþþüýùþþüýîþýþý þùþûüüþ üþýþú úþýüúôýþüûþþùþøûûüüûöú ýþý òþýüýþþú À@ÿÀ þ  þüþþûò  üúü ûü  þþü þ û   þý ûù  û  þùþ ö     þ þþü  û  þ÷þú  ý þ þ þþþ ô     þ üþ ö    þ  þþ  û   ý þ úýþþþü   þüþ ï       þ  úü þ   þýþþû   ý ü  øþ û  í       ùúþ  þ  ü õ     üýüþ  þ   ý  þ÷ ü  ý   þ  þ þüþ ý ð      þóþ ò      þ þþûÀþ þüýû  ûýüþþþþþù  þýú÷ýþ þõúþüþ  üþþþú þþ þï  þ þþüþ úþþ þþú þù  þ  üüþû þ þ  õþ þú  þþòûýü  þ ò     ú÷þüõ    þùþ÷  û  úùþ÷    ý õ û  ò     þ ü ö   ú   þüþþü   ø   þ  ûüüþ÷    þ  øþü  õ    þ ýþþÀþþýðþü ü üüúþþüöü ü÷üî üþûþúþú÷þúþýøúúùþþþûûû÷ ýúþüþþþþüýþ þþþ ûþþùúý ýýûùù þýû ûþúüûú þ úøùþþüþõþþþþýüþúýý þýþþþýùùþÀ@ÿÀþûüûþõþþþ þôýôùþ þýþþ ýø þðþþþþ ú þöýûý þúþóý õ þûúþ÷þþ þýõþþ öþ þùù÷ þù þþýûþþýöþþþü ü üúýúþþýü ýûûùûþüùþüþ ôþþþ  úþ úýÀýûþ öúþþúþúüûþúþ þýþ ü÷ú þúþþþþþþþþ þû þþüþþýþûüþüøþýýþþõ þøü þûüþ ûüþþúþýýøûûþþþþ ý÷þùþþ÷þ þó þûüþ ùþþùþþúý ôþþü þ þùúûüþ ýöþþúþþ Àúþ   ú   ü  þ þý  û  ø  þ üþþ  ù    ü   þ  üþø þ  ü  þ  ý  ÷ ü  û   ô ü  þ  û  ýù    ö úþ ü    ô  ý ü   ú  ö þù ý  þþýþ û   û   ø þüý   þ  ü     þ  þ  ú  ó üùü   û  þ ý ü þ   þ  ó úýü      ô þþ ý  ú  ûþý   þþýýþô       ýþ ýþ  û  ù þýþþþ  þ ¿@ÿÀþþ þýþô ýþþþþ þ þ ýþ  þþýû üüø ûúþþ þýûþýûüûþþüúýùö ùûû ýþ ôþ þþó ÷þöþøþþ÷üüþþüþþüû þüý þò÷þýûþþûõ þùþ üùüþþú ûôþûùþøüþþõ ü þþþ%þþ*þ-þþ/ú1þþþ1þ45ûý57û9ü9;;ý;ü<>þ?ý þùþúþþ ü û þþ þþúþþþô þ÷ýþþúþþþýö ûþýþþüýþýûþûþþòþóþþþþþõþúþýû þþþþþ÷úöþ ùþýþúþþù÷üýþ ñûþþôýõþ ûüþþ÷ üùþýøû ýý%þüþ*ýþ -û ü.þ1üþ1ýþ4þ5þ67þ9ý9þþ:;þ<ü<ý=þ? ÷    üþ    ü  û  ý   ü  þ ûü   ý  û    þ úü   þ û  úþþ ý  ü   þ  ùþý ù  ü ü  ý  û   þ  ü ú÷é  þ úþþ  ü  ú  ü þú þ     þ  ý ùûþ  ý    ù  þ ú    þ     ý û÷ ý  ù  ü  þüý  þ   þ  ú  þ  ý ûû   þ  ý  ý þ øö  ü  û  þúú  þ  ý  þ     ü þúø  ý  ø  ý øû   þ  ø  ü    ú  ú  ü  þ    ü  þ  ø þ þ& þ  ú*ý   ü þ- þ þ/ü  û0û  2þ3þ ú4þ5ý 7þ 9:þ ;;<ü <>þ ?(ÿ-ÿ1ÿ 4ÿ 6ÿ8ÿ:ÿ<ÿ>ÿþÿÿÿ!ÿ&ÿ*ÿ-ÿ/ÿ1 ÿ2 ÿ4 ÿ5 ÿ6ÿ7ÿ9ÿ:ÿ;ÿ;ÿ<ÿ=ÿ>þÿ?@þ=ý<;þþ9ý88ö5üý4þ4þú2ö2þþ2þ1þ0þ/þûý-þý-ûý-üü,þû+þù*ù+ ý)û* ú( þù(þþü'üø(þùü&ûü' ýý%þ'þþþú'þþ&ùþú'û(þ )ûþþþ'ô$@þ==;ü9ù8ø7ûþ5ú54ø3÷2ý2ù0ûý/ý÷.ó.úý-ûù,þýü+þþû+þþ+úü*þø)þþþþ)þù(ý ú) û' ø'û&þø'ü ù%ü 'û ÷'þþ÷&û(þþþ'ùþû(þü'ý þþ#@þ==ý::9û86ø4ü4úý22üþ2þ1ù0ù/ü.ýú.þþ-þýü+ýü,þ+þþ+ü*ýþø)úþ)ùþ(þýþþ(ýö'þýù'ý þ&þ úþ&ý ûú&ý þ (þ ùþü&ü ýþþ'þ üý'úþ(ü úþþ'ý þ$@þÿ=ÿ=ÿ;ÿ:ÿ9ÿ8ÿ6 ÿ5 ÿ4 ÿ3 ÿ2 ÿ2 ÿ1ÿ0ÿ/ÿ.ÿ.ÿ-ÿ,ÿ,ÿ+ÿ+ÿ*ÿ*ÿ)ÿ)ÿ(ÿ(ÿ'ÿ'ÿ&ÿ'ÿ(ÿ'ÿ(ÿ(ÿ)ÿ(ÿ$€€€€"(ýþ þ(þ(üù(þþý'ýþ)üþþ)üþþ)÷ü)ýû(ö *ú*þ*õþû)ýþ *ùþ*ýõ*ýþþþ)*ý þ)þú* û*þú)þ** *þü)þú)ú)ûþ÷)øþ*þû)ü þ*þý)ù þ)û þ*ú *üþþ*þ *üû*þþþ*û*üý*ýúþ*óû)ó*ê)þû*ú*þý*þþ*úý)þü)þú)þþú) û)þü*ó)ýû* ý*ý)þ ú)þ) þû"ý÷(üýþ)ö(þù(þþü'ýü) þü( úý(þý)þúý) û) ýý)þþ)þò)þ*ý ü*ú)þ *ûþû*úþü)þþ *ýþ û)ü þ)ùþ)ýþ *ù*ùþ*úþ*û *öû*ýýþ*ýþ*ùþ*ø*ýý*þþø)ýõ)ù÷)ýþý*þý*úü*ü* þ*ýü)þ û) þ* *þ)þþ þ) û*ùþþ*ýþ þ)þ þ*÷*þ*þ **þ *ýþþþ)ý *ø*û*þþ*þýö"6 54(65þ6554þ544)6ú56566554ü545'6ú56556554ü544'6ù56556655ý4544(þ766ù56565655þ655ú45545(þ766ü5665 54)ý6766ú5655655þ4(ü767665654)ý67665ü65655)6þ766ú5655655*þ766þ766û565655*676þ766565*÷76776767665û655655*7ù67676766565ý65)767ý6766þ5665*7û676766ý5655*7676þ5)7ü67766þ5)7û676766þ766ý56)87ú6767766þ566*÷87887766776ý56)ú78778776þ766þ5) 7676*87þ877ü67766*ü78877þ877676*87þ877þ8776*87þ877þ677û6766)87þ877ù676767)8ý7877þ8776*8787676*8ý78776þ7)ý898878ý7877þ6)8787þ877ý67)ý8988ø788787877þ6)ú8988988ü78877* 8ü787887*9ü89988ý7877*98ý7877ý87)98þ988ú7878788*9ý8988þ988ú7878877*9þ899ý8988ù788787)ý98998ú78787)98þ9889ú8988788ý78)9þ:998þ788*98þ988ü788)û:99:99ý898 8þ7)9þ:99ú8989988ü788)9þ:998÷98899878)9þ:998ü98988þ7)ú:9:9:99ü898998*ü:9:99ý8988*:9þ:9 98þ9)ú9:9::99þ8998*:9:9ù898898):9û:9::99ú89899):9ü:9:99þ8):ü9::99:989*:þ;::ý9:99ý89);:ü9::99þ:99ü899) :û9:9:99* :9þ:99*;:þ;::ý9:99*;û:;:;::9:9"ÿ(ÿ)ÿ(ÿ(ÿ(ÿ)ÿ)ÿ)ÿ)ÿ)ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿõú(ü)ýüú(ûü'ûþ þ)÷ ý(üþþ)öü(þþý)ø *þúþ*þ*üþ*üû*öþ)þü)þøù)öþ*õ*ýý)þ*þúú) ø*þû* þ* ýþ)þûþ*þþü)þþ) þû)ú þ) ø)ú)ý þ*ù *þ þ*üþû)ý*öþ)û *þþ *ý *øþ*ø *þûþ)ü*ùü)þø*þúþ*öþ)þ* ø)ùü*þ ý* ú* ý* ýû)þþþ*þþ)þ÷)þþþ*þþþü)þþ*úþþ" þ)÷ú(ýþ(ù (ûþþ(ûþ)÷ )ûû)þú )ôþ)ô*ýþ*üüü)þþü)ö*õþ)ú *ýú*ýü)ýü*ý*þý*þ*þñ)þü)üø)þþ*þû)þ÷)þû*ü)þü*üþ)þü*þ û*þþþ*þ*ùþû)ý *üþý) þ*ýþ*þüü)þûþ*ø*õ*øû*þýþ*ýþü) ý)þõ)þþ*û)þû) þû* þ*þþù)þøý) þü)þýý) þû)þþ÷)þ þü) ô"þ  þú(ú  ÷) þ þ) ý þ( ü) ú  þû(  þý( )  ø( ü  * þ * û  ü) þ *   ý *ú  * ý *þ ý *  þ  *÷  þ  *  þ * þ * ú   ú  ) û  þ ) ý  þ  ý *þ   û  * þ) *ý     þ  *  þ   *  þ  û  *  þ  ù  *  þ   û ) û   þ  *ø  ÷ ) þ  ý  û  * ù    *   ý  ý )þ  þ    þ ) þ  *þ  þ   þ  *ý  ý  þ  *þ  þ  ý    * û    ý  *û   ø ) ü     *þ  ý  þ  ü )þ     ú ) ý  ú  * þ  ý  ý  *þ  û    ü )  þ  ý )  þ  ü )þ  *   û  *õ  ý  *  *  û  ü )þ  û )  ÷  * ý  * þ   ú )  þ  ü ) ù  þ  * ü  ý "ÿ)ÿ)ÿ)ÿ(ÿ)ÿ)ÿ)ÿ)ÿ)ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ#€€€€!þ*üþ *ûþ*þþ*þ ü)üþ*ü *þ**þü *þþü)ûû*úþ*úû*þ *ûþ)óþ*üþõ)üû)ýþý*þþü)ø)þù)ø*ûü) þü)ý*þþû)úþ*þ*üþý)ý þ)üþý)ý*úþû)þ)þþü)ú*ýþþ*þüþ)þû)ò*ùþ*þþú*ûú*þûþ*þ *ýþ *þüû*þþü)üü)þþ*ýüü)þù)þý)ûþ) ø) ø)ò)þ) üý)þ *þ *öù!ýûþ)þþü)ýüü*ýþ*üû)üý*ö)þ*úú)ýþü)þý)ø)þ**ý*ù)úþý)*þý*þþõ)þ ø)üþ*ù þ*ú*ü*õ *ý þ)ù * *þ *ûþ*úû*þ*úû*üþ)õ*þøü)ýþý)ûü)ýû*ûú*û* ô)þü) ú*ð)þ)þüþ)þ *þþþ)þ þþ)þþý)üý)÷þ*ý þ)úþü)ýù*ûþ)þü ü)*þþû)û*øùþ)ô!þ:;;:þ;::9:9*;:ü;:;::9*;ý:;::ù9::9:9);:þ;::þ9::9*;û:;:;::ø9::9:99);þ:;;:ý;9::*;û:;::;;:9*;þ:;;ú:;:;;::*ü<;<;;ø:;::;:;::ü9::);þ<;;ý:;::*þ<;;<;ø:;:;;:;::þ9);<;û:;:;::*< ;:þ;::*<þ;<<;þ:;;:*ù<;<<;<; ;û:;:;)<;ü:;;::ý;:)ö<;<<;<<;<;;ý:;::þ;)<ý;<;;ù:;;:;:)<ý;<;;þ<;;:*<õ;<<;<;;<;<;;þ:;;*<ú;<;<<;;ü:;:) < ;*<=<;þ<;;:*þ=< <ý;<;;*ý<=<<ü;<<;;ú<;<;;)<=<;þ<;;*=ü<==<<ú;<<;<;;*=û<=<=<<þ;<<;*=ü<==<<þ=<<þ;<<;*=<ü=<=<<ù;<<;<<)=<ø;<;<;<<)=ü<==<<*þ>== <þ;)ý=>==ü<==<<*=þ<==ý<=<<þ;)ý=>==<=<þ;)>=<=<*ü>=>= =<*û>=>>= =<*ý>=>>ý=>= =<*ý>=>>ý=>==þ<==þ<)>ú=>==>==<=<*>þ=>> =û<=<=)>ú=>=>>= =*>ü=>>= =ý<=)>ú=>=>>==þ<)>ö=>>=>>==>==*>û=>>=>>=þ<==*>=>=ü<==)?>þ?>>=*>þ?>>ú=>==>==*ø?>?>?>?>>=>=*?>þ?>>=þ>==*?ø>?>?>>?>>û=>==>>þ=)ý?>??ý>?>>=>þ=)þ>??ý>?>>ý=>==þ>)?>û?>>?>>ù=>==>=)?ü>??>>=ü>==)û?@?>??>þ?>>ü=>=)?þ>??û>?>?>>ü=>>)þ@??>þ?>>*û?@?@??þ>??ü>??>>*@ý?@??>?>*?þ@??þ>??ý>?>>!ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿþþ)ûþû*ûþû)þþþ)û *üþ*þþ)þ *üü *ùþ*þþþ*þþ*óþ*ü*þ *þ*ùü)ü*þø)û*ûû)þþú)þþù)ö*û*þþ)*þ)ý þ*ü þþ) ú)üþü) þû)þ ù)ü þ)üýû*þþ*ýþþ*þþ*þþ)þþ *þþ *þþü*þþ*øü*ýþþ*ð*ùû*ñ)øýþ)úü*ûþ*þ ü* õ)ú*þýý)þ*þ÷)úþ)ý* þø)þþú)þþù)ýý"þýþ)þþþ* *üþý)üþþ*þý)þ*þþû)ö*þý)þöþ*ýýü)þ *ûþ*øü*þþý) *ûú*üýþ*ý ü)þý)øþ)þþ*þüù)þø)÷þý)þþþ)ûý) þ*ó)þ ý) ú) ÷)ù þ**þ ù)þ*þý)ûþ*þ*þþþ)ø *ý þþ) þþ)ùþ*úþ *üþþ*ü*þûü) *üü*ï*üý*úù*ú*þúü)ú*ýþþû) û* õ)þû*þùþ)þþû*þþþ" ü  þ  *ý   *þ  þ  þ   þ )û       *þ  þ  ý  þ  * þ  ú  * þ   ü ) þ ü ) ý   þ ) ý )ýþ   ú )û    ý )  * þ  ü )ýþ   ý )ý û   ý ) þ  ü )  *ö *ý þ )ûü÷    )üý   *ú *þþû  )öþ )þ*üþþ* *þþþþ )þþ*ýþüü)ûý*þþ*ý÷)ùø)ý þ*þ*þý*øþ)þü)ý*þû*ûú*ýþ*ü þ*ýüþ*þý)þý)þûû) *ý ý) ü)ýþ*ûù*ùþ*ûû*þý*ô)úþ)*üûü) û)þü)üþ"ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ#€€€€!ûþü)þþþ)÷ *þü *ûþ *þû*÷þ)ü *ù *ùþ*þýþ*÷ü*ø*÷÷)øþ**ôþ*ù*þþü)þþþ)þ*÷*þ û)ûý)þý*þûþ)þþûþ)ý)ýþø)ûü) þ* ÷)þ ú)üþ*ûþü*ø *þ*ù ý)üþü)*ýþþþþ)ûþ*ü *ú*ô*üý*þý*øþ)øúþ)ûýù) ù*úû* þ)þö)ùþ) ú)ó)þýý) ö) þü) þú)þþü)þþþ)!üþ*ü)þø*þþ*þý*þûü*þüþ)þýü)ü÷)þþú)üüý)þúþ*þ*þþù)üø) û) úþ)þþ*ý* þü)ýúü)û)þ *þþþ*ý *þþþ*þ *ü*÷ *õþ)ïþ)ûþþ*øþþ)üý*ýþþ*þûþ)øþþ*ó*ùþ*þú)ýþú)þ ý*ûúþ)þú*ýþý*ûþ)*þþù)û*þþ)þþ*þø)ùû)þ þý)*þþþý)þ û)ù þ)þþ þ)ýþü)þþ ý)ú*þ ú)ùþ !@?>?>*@?ü>??>>ú?>>?>)þ?@@?÷>??>??>>)@ù?@@?@@??>*@þ?@@?û>?>?)@?@?þ>??þ>)@ù?@@?@@??ú>?>?>)@ü?@@??ý>?)þA@@þ?@@?>*ý@A@@?þ@??*@þ?@@ü?@@??*A@üA@A@@?þ@??*A@þA@@?þ@??*üA@A@@ú?@@?@??*Aý@A@@ú?@@??@@?*ûA@@A@@þA@@ú?@@?@??*Aþ@AA @ü?@?)Aý@A@@þA@@þ?@@?*A@ú?@?@?)Aõ@A@@A@A@@A@@ý?@)ýABAA@ûA@AA@@ü?@?)ABAþ@AAý@A@@þ?)þBA A@A@þ?)üBABAA@A@þ?) Aô@AA@AA@@A@@) Aý@A@@*øBABABABAA@A@ýA@)BüABBAAú@AA@A@@*ýBABBýABA A@*BABA@üA@@)BþABBA@*BûABABAA@þA)BýABAA@þA)þCBBAüBABAA@*BýABAAþ@)þCBBþCBBAúBABABAAþ@)þCBBAþBAA*üCBCB BA*C BûABABAAþ@)CþBCCBþABBABA*BCBþCBBAûBABA)õCBCBBCBCBCBBüABB)CüBCCB BA*CBüCBCBBüABBAAýBA)CBýCBCC BþA)óCDCCBCCBCBBCBB*þDCCûBCBBCCýBCBBûABBA)CBCBþCBBüABB)ýCDCCúBCCBCBBþCBB*DCòBCCBCBCBCBABA)üCDDCCþDCCB*DýCDCCB*ùCDCCDDCC÷BCCBCCBCBB*DûCDCDCCBþCBB*öCDCDCDCDDCCBCBþC)DCBCýBC)DüCDDCCýBCBB*DõCDDCDDCDCDCCB*DüCDDCCüBCBCC*þEDD C* DCüBCC)þEDDüCDDCCþB)EøDEEDDCCDDC*DþEDDCþDCC!ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿýü)ùü)þû* ý)þ *ýý)ö *þþ*þ *õ *û*ýø*õ*ûþ*õ*ü*üü)þý*ú*ýýû)þþ*þû*ýþüû)ù*þþ)þ*þ*üýþ) ø) þú)þ ø)ú)û   þ*þ ô) þ þþ)þ þ*ý  þþ)ý þ þ*ý  þ *ú  ü  *û   * þ  *þ þ  ý þ) þ   * ÷    *ü   þ *ý   ü    * û  þ * þ  þ  þ)  þ  *õ     ü )ý    ù   ) õ    *ó      þ ý ) þ    * ù    ü  ) ü   û  ) ù    ø  ) þ  ú  ) ü   ü )þ þ *þ  þ þ) þ  * ü ü " û*þþ)þûù)þ *ý ù)ü)ý þ*þ**þ ü)ùþ)ù *ù * *þ*þþ *öþ*ùö)þú)÷ú)ú*øøþ)üþý)üü*þüþ*ù *þø)ýþ*û* þý)*úü) ö) þ*þ ô)ü *ú) üþ)þ * ý)þ þý)þ  ü*þ ü  þþ)ü û  ü)þ þ þ*ù   *þ  þ *þ ü  *ø   þ *ù   þ *û   þ * ü   ü )   ý *  ü  ü  * þ ú   *   * ú   û  *û   þ  * ý   ö   )ý   þ  ý ú  ) û  þ ) ü   ù  * ø    * û   #üý)þý*üý*úø*ýü*ýý* þ)ûþ*úþ*þý)ýþþ)þ)þû *ýùþ*ýü*þúþ)ýü*úþú)þþüû)þ÷)þû*ûý) þ)þþ*üþ)ü*ûý)û*þ *þû*þú*þõ)ü*þø)þý*ûþ)øú)þþ*þþ *úü)øþ)üüý)þú*úù*þý*ýý*ýø*ï*úù)þü)üþ*þþþ) ý*ùýü)ø*ú*ü*þþý*úþü)û*ý*ø*þþü)þþþ"ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ#€€€€! þ*þ)þý)û ý)û*þ *ø *ú*þþ)øþ*üø*þþ*ý *õ)ø*÷þ*üþ*ýþþ*üû*þ*ûýü)úüù) û*û)þú* üþ)þýýû) þü)ý *ý)þ)ý ü*ù * ú*þ ý)û þ*þþýþ)ù *ù **þþü)þþþ*þþþ*õ*ý *þù *þý *þý*ýþ*÷ü*ùý*þó)þú*ü*ýùþ)û*þþû) þþ) þ) û*þ*þ ø) þù)þ ú!üþ*þþþ*úþþ)úþ*þý *ýýü*ú*û*üþ*þ)÷þ*øþ*ýû*óþ)ú*ùü)ò) þýþ)þþý)þ*þþø) * þ*þþ)þþ*ý þ*ýþû)ø ý)þþú)ý*ú*ù *ý*ûþ*úþ*÷þ*ü *øþ*ù *þþ*øý*üüþ)úþû)í)þ**þúú)þ ý*þø)øþ)þû*üýþ)þ * þ*þþþ) þ*üþý)þ û) þü)þø)ý)þ *ú þ*þ!ùDEEDDEDDCþDCC*E DC*EýDED DC*ýEDEEDþEDDþCDDýCD)EúDEDDED DþC)öEDEEDDEDEDDûCDCC)EDýCDCC*EýDEDDüCDD)EýDEDDüCDD)EùDEEDDEDD*EýDEDDþC)EFEýDEDDþEDD*FýEFEEøDEDEDEEDD*üFEFEEDþEDD*þEFFýEFEEùDEEDEEDD*FþEFFED*ýFEFFEùDEEDEE)ûFEFFE ED*FüEFEFFEúDEEDD)FýEFEEDEþD)FþEFFýEFEE*FþEFFE*FEFEþFEE*þFGGF÷EFEEFEEFEE*ýFGFFþGFFE*ûGFGGFFE*øGFFGGFGFFüEFFEE*GýFGFFEFE*þFGGýFGFFE*G FE*GýFGFFEF*GFGFýEFEEýFE)GýFGFFE*GþFGGFþGFFþEFF*GFþGFFþE)þHGGFüGFGFF*þHG GFþGFFþE)H GFþGFF*üHGHGGúFGGFFGGF*HGFGF*HGùHGFGGFGGF*HýGHGGõFGGFGFGGFF)H GF*HGHGúFGGFF)HGþHGGþFGGFþG)HýGHGGþFGGþF)þIHHþGHHGûFGFF)HüGHHGG*üIHIHHýGHGGüFGG)þIHHþGHHGþHGG*ýHIHHýGHGG*ûHIHIHHüGHHGG*I HG*þHIIHIHýGHGG*öHIIHIIHHIHHGüHGG)IþHIIHùGHGHHG)IþHIIHûGHGG)IúHIIHIHHþGHHþG)IýHIHHG*IúHIIHHIIHûGHGH)IþJIIúHIHHIHH*ýIJIIHþIHHýGH)IJIHþIHH*JýIJIIýHIHH!ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿý  þ  ú  ) ø  ) þ û )þ  þ  ý )  þ  *  *÷  þ  *  ý *þ  û   þ)þ  þ  ü  *ø  þ  * þ * ü    * ú      *í  *þ    þ  ù )ñ  *ü  þ  * þ  *  þ   þ )ù  þ      *û   þ  *ý  ÷  * ü  õ ) ú  ü ) þ    þ )   ú ) þ    þ )ý  þ  û )   û )ý  ø  ü )þ ø ) þ   ý   þ )  ý )   *þ  þ ) þ  þ )þ ù )  þ    *õ * þ þ ) þ  þ  þ  *  þ  ý )ø  þ  *  ù  *ø *   û  þ  *  ý  þ  þ  *þ   û  *ö * þ  þ   þ  *    û )þ  þ  ÷ ) û      * ú  û  * þ  ý  ý ) ü  ü  ù )   ü   * þ  þ  ü  * þ   ý  * ö ) ú ) û  ÷ ) þ  û "  * þ  ö    ) ú  * û ) ù  ) ó    )þ  ô    )ý û   * þ  þ)þ þ  *û  þ  û )  þ) ü   þ  * ü ý )ù    * ü  *þ  þ  þ  þ  *ù *þ  û  þ  * ü  þ    *ò  *ý  þ  û  þ )  ü  þ  *þ  õ  *þ   ü  ý )þ     þ  þ ) ú  *ý  ù  û  * ú  * û   ý ) ü   þ )    * þ   þ ) ü  þ   * ö  *þ   * þ  õ ) û ) û   *    þ  þ )ý  þ  ù )ù  ø  *û  þ   *ú ý )þ  þ    *þ   þ ý )ü  þ )ý  þ  ü ) ý )   ü  *þ  ý *ü    * ü  þ  *ý  *   ú  ü  *õ  þ  *ú  ù  * û   ü ) þ  ü  *  ÷    *    ý ) þ   ü  *  ð )þ  ù  þ "þþ)ýþþ)ö þ)þü* ý* þý*ûþþ)üþþ*øû*ôø)þü) û) þ*þü*üýþþ)ý *üþ*þù)þù)þû*ø*þ*üýþ)÷*þþû)û*ù*üü*ú*þþ*ýù* *ýö)þü)þø)þûþ)ø* ü)ýý) û)þ ü*þþþ)ýþþ*þüþ*ýýö)úþ* ü*üû)úþ*ñ)úù)üþ*þþ*ô*þþü) *÷*úö*ýú*ýýþ*ü ü)úû)ú*þû#ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ#€€€€!ûü)üþø)þþü* **þ ü)úþþ*ýþ ý)ü* **þþþ*öþ*þø*þþ*ýþý)ùüú)ùþ*ù*ûû*÷þþ)þþþþ)þõ) þ) ý*ý*üþ)üý) û)þþþþ) þý)þ ø)ü)û*þüþ)þ þþ)þ)üü)þ ü)þüþ*ø *ûú*ü*ýþ *þþ*þýù*üþ*øþ*þû)õ*ýü*óü)þúü)üþ*üö)ü* þ* üü)ûþ* þû) þþ)þø) û*þþý!ú*÷þû)ýþþ*ü*÷ * *ûþ*ú*ùü*ú*þþþý)ûýþ*üþþ)ûü*û *÷ý*ýþ)üþ)ú*þö)þúþ)ù)þû)þüü*þþþ) þý) þú)þ þþ)÷þ*þþþ*ý þü)þ *üþ*þ ý)ý)ø þ)þþ *þþ*þû *ûþ*ûüþ*ý*û *þý*þþþ*øþ)þþ*÷ý*û*þþú)þþý)þ*ùþ)þö)þþþ*ûü*÷) û* þý) þþ)ûþþ) þ*ûþü) ø!IþJIIùHIIHIIHH*JIþJIIùHIHIHH)IþJIIþJIIúHIHIIHH*JþIJJIøHIHIHIH)ýJIJJýIJIIþHII*JIJýIJIIHúIHIIH)JþIJJIþHII*JIüJIJIIHþI)JIþJIIùHIIHII)JIûJIIJIIüHII)þKJJIþJIIJIþH)þKJJIþJIIþJII*ýKJKKJIþJII*JþKJJþIJJýIJII*KJþIJJIýJI)KüJKKJJIüJIJII*ýKJKKJþKJJùIJIJII)K JI*KJüKJKJJIüJII)KþJKKJþKJJüIJJ)þLKKJþKJJúIJJII)KJKJþKJJþI)KJúKJKJKJJýIJ)üKLLKKJKJI* KýJKJJ*KþLKKúJKKJKJJ*þLKKJþKJJ*ûLKLLKKJþKJJ*ùKLLKLLKKüJKKJJ*LKLKJþKJJ*LKLKüJKJKK*LKþLKKJKJ*LùKLKKLLKKJ*L÷KLLKLLKLKKúJKJJK)LþKLLKJýKJ)LKüLKLKKýJK)LýKLKK*ýLMLLKúLKJKK)MLþKLLKþLKK*LùMLLKLLKKûLKLLKK*MýLML LýKLKK*ûLMLMLLúKLKLKLLþK)MüLMMLLûKLLKLLK*M LþKLLýKLKK*þLMM÷LMLLMMLMLLûKLKK)MLüKLLKK*MþLMMLþMLLþK)MþLMMLüMLMLLKþL)MûLMLMLL*MþNMMüLMMLLþMLLþK)MþNMMLþMLL*NýMNMMúLMLLMLL*N MýLMLL*ýMNMMNMþLMML*üMNNMMNML÷MLMLMLML)NúMNNMNMML*NüMNMNNMLM*NüMNNMMøLMLLMLM)NýMNMMúLMMLL)NþMNNMþLMM*ýNONNMþNMMþNMML* NMþL)ONþMNNMþNMMþL)NþMNNýMNMMúNMMLL!ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ þ    þ  * þ  *þ  þ  * þ  * *  *ù ý ) ù )þ  *    ü  *  ü  ü )ý   þ  þ )þ    þ  þ  þ )ý   þ  þ  *ú  *ó  þ  *ö  þ  *  þ * þ   þ  ý )     ú ) ü  ý   ü )ù  ü  ú )      ù )ý  þ   * ü     ý )  û  ü )    þ ) þ  þ )    ü ) þ  þ    þ ) ü  û )ü  ö )ù   ú )û    *  þ  þ  * þ     *þ  þ    ý ) ý )þ   ü  * þ  þ  *ø ü )þ  þ   þ ) þ   * þ  û  *ö  ý  * ý    þ  * þ  ø  þ )ü     þ  ü ) þ     *þ   þ    * ú   ü  ü )ò  þ  *÷  þ    þ )    ü )þ   ü  ÷ )ü  û  ý )  ô ) û  ö ) ö  þ ) ü  *   þ   *  *þ   * ü  þ "  þ  * þ  þ   ü )   þ  ú ) ô  þ ) þ   ý ) þ  ú   *þ  ü  þ  þ ) þ  ö ) þ  ü  *ý  þ  þ  * ö ) ü  ø ) þ  *û þ  *ý   *û  þ  ü )ü   þ  þ  *ö * þ ü )÷ * ÷ * þ    þ )ú  ø  *ó  þ  *   þ   þ )ý   þ  þ  *ú  ý  þ  þ  *û  ÷  *ý  þ    ý  *û  ý   *  þ  * þ  ú   ü )ý  ü  ÷ ) þ   ø  *    þ  *  þ  ü ) þ  ÷  * þ     û ) þ   * õ ) ñ ) þ  þ  ü ) þ  *ý  þ ü )     *ý ù )þ  û *ý  ü ) ú * ÷  þ )  *  þ    ý )  û þ )þ   *   þ *  ü ) õ  þ )  þ  ü  * þ   þ  *  ý   ÷ )þ  ý   þ  *ú   þ  * þ   þ  *þ  û  ý  #þþ*þþ)þþ)ûúþ)û*þ*üþû*ýüþ)úþ* þ)ü*þþý)ûû)û* þý) ýþ*ýþ*þ *þþþ*ýú)þþ*øü*÷ö)ýþ)ùþ*üþ*üý)ûþþ*þþþþ)ýü* * û*úý*ùþþ)úþ)þý*ý þ)þþù)þý)þ ýû)þ*þ ú*ý ü*ü  ü*ü  þ*þ  þ*ù   û) ú  ü* þ ù) ý õ ) ü *þ!  ù  ý) ü  þ)ý !  ý  *ý !  þ þ)ü! !  þ  ü þ)! *ü! !  þ  ý *þ!  ù  þ )!ý !  þ *!ý !  ú  þ )! ! *!ü !!  þ  ý )! þ!   #ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ#€€€€!ü)þ  ýþ) þýþ)ü  *ú) þ)ù   þ * û  *  *ú  * þ þ *þ  * ó     *ù    û  * ù    ü *ú   þ  ú  )þ  û   ý * û  û  *û   ú  *ú    ü  * þ    þ)  û   * þ  þ þ *ü   ý þ *ý   û   ø   ) û  û  ) þ   * ÷   ) þ  ÷   ) û   *ü! !  ô     ) ü ) þ   *þ!  þ  ú ) ü! ! ú  )û! ! ü ) û! ! ý )û! !  þ!  þ)þ !! *!ý !  ú  )þ!  ! ý )þ !! *! ü! !  *þ!  ! * þ!  þ! *ý! !! ü! !  *ù! ! !  ! *!ý !  ! ü! )û! ! !!þ !!ý !  þ!  *ü! !! þ!  *!ö ! ! !!  ú! ! )!ñ !! !! ! ! ! !  *!ð !! !! !! ! )ý! !! ! þ!  *!ú !! !!û ! !)þ !!û !! !! þ!)!þ !!ý !  !ú ! ! )!ý !  ü! !  þ!)!þ !!ú !! !! ý! )!ý !  !ý !  *!þ !! *!ý !  *!þ !!þ !! !* !õ ! !! ! !!!þ*þ)ý* ý)*ðþ)þ *ú þ)ôü*û*ùû)ýü*úþ)þö)üüû*öü)þýü)þ*÷ö)ýý)þ*ö*þþ*üþý) þ)þ þý*þ  *þõ)þø)ü þù)ý þ  û)ü  þüþ)þ û   *û  ü**ý û  û) þ  *ý  *þ þ ý)ý û   *õ    *õ    ý)þ   * û   *ú   ø   *ò     þ *   ÷   ) ó     ü ) ÷     ÷  )ú    ü )  ú  ý )  þ ý ) û   ú   * þ  ö    * ù    ý )ý   ü  ý ) þ  *  ú    * ü   ù   )  *ý !  ü ) þ  ü )ý !  þ  þ  ü ) ô   !õONONONNMMNMMþNMM*üONONNMNM*þONNþONNþMNNúMNMNM)øNONONNONNüMNMNN*OùNOONNONNøMNNMNMN)OýNONNMNM*OýNONNùMNNMMN)ONþONNûMNMM)OúNOONON N*OúNOONONNýMN)þPOONþONNüMNM)þPOONþONNþM) OüNOONNM*OþNOON*úPOPOPOOýNONN*ûOPOPOONON*POþPOOþNOON*PýOPOOýNONN*PþOPPONON*PýOPOOûNOON)POüPOPOOùNOONNO)PúOPPOPOOüNOO)QPüOPPO ONþO)þQPPOPOûNONO)QPOþPOOýNO)PQPûOPOPOO*þPQQýPQPPþOPPOþPOO*ûQPPQPPþOPPOþPOO*øPQPQPPQPPüOPPOOýPO)PQPõOPPOPOPPOO)QøPQQPPQQPPþOPPO*QúPQPPQPPüOPP)QPþQPPøOPOPPOO)QþPQQPþQPPOþP)þRQQþPQQPO* QýPQPP* QPþO)üRQRQQûPQQPQQPO*RýQRQQüPQQPPüOPP)RQRQóPQQPQPQPPQPP)RQþRQQP*RþQRRQPQP*RQþPQQúPQQPP)RQRQüPQPQQP*R QPQP*R÷QRQQRRQRQQP*RýQRQQRQùPQPQPP)RQRýQRQQ*RùQRQQRRQQP*RúQRRQRQQþRQQýPQ)þSRRQúRQRQRQQ* RQ*SRøQRRQRQRQQ*SüRSSRRùQRRQQRQQ*SRþSRRQRQ*SûRSRSRRúQRRQRQQ*SþRSSRQRQ*SRûSRSSRRúQRRQQ)SRþSRRøQRQQRQQ)SùRSRRSSRRQ*SRúSRSRSRRþQRR*üTSTSSRúSRSRSRR*ýSTSSþRSSRSR*ûSTSTSSûRSRSRR!ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ þ  ý ) þ  þ  ý ) þ ù ) ü  * þ  ø ) þ  ý )ú   ú )þ ý  û )  þ  *þ  *û   *÷    * ü   ý )þ  þ  þ *ü  *ô      þ  ü )õ      þ  *ü   *ý   ü )ó     û  )ü   ü   þ  *þ  ü   *ü þ ù    ý )ý þ  þ  þ)  ö    ) þ   þ)þ ú   ý ) ý    *þ þ  þ )þ ü   *þþ ú  )þó     )þ û ) þ  þ)  û ) þ  þ)þ þ  *þ þ *ýþ*þþ *þ þ *þþ )þý )ûþ )þþ*ü*úþ*þ *ýþ*ýüú)þ *ú*þþ*ûþ*ýû*þû)þüþ*þýþ*þù* *þ÷)ûý)þøþ) ü" þ   þ  * þ  þ     * þ  þ   û ) ý    * ò  *    þ ) ø  þ ) þ    þ ) ý   ú ) ö ) þ  ý ) õ ) ü   þ   þ ) ø ) þ  þ  ü )ú   û )   þ ) þ  *þ   ú )ü   *ý   þ  û   *þ ü  *þ ý  * þ  * û   þ  *û   *ú   þ  *õ      ú  )ü   ö     *ô      þ  *þ ü   þ  *ù     û )þ þ  *ü  ü    *þ   þ  þ)  ü )þ  ú    þ)ü  ý   þ  * ú    *ô     *þ þ  ý )þ  þ  *þù    þ) ý )þ ü   * þ  *þ ÷    ) þ )ü*û ú  )  þ)þ þ *þ *üþý )þú*þþ*ýþû  )þøü )üù*õ *þ *øü)õý)ö#!þ !!ý !  *! þ!  þ  *! þ!  ý )ý!"!!þ !! þ!  *þ"!!ù !! !  *þ"! ! *þ"! !þ !!ý !  *" !ý !  *"!þ !!ú !! !)ü"!"! ! ! *"ý!"!!þ !! þ!)" ! ý! )"ý!"!!þ !!þ )"ø!""!"!"!! *þ#""!þ"!! *þ#"" !*"#"!ý !)ü#"#""þ!""!þ"!!*ü#"#""!þ"!!*"#"ü!""!!*"þ#""!þ"!!*ù"##"##""ü!"!""þ!)ù#""##"##"!*#ú"#""#""þ!""û!"!!)#ú"##"#""*#ü"##""û!"!")#"ö#""#"#""!""*#"þ#""*þ$##ù"##"##""*$#"þ#""!*$ #"*ü#$$##"#"þ#""*ù$#$#$$##ø"##"#"")ù#$#$#$##þ"##ý"#""*ý$#$$#þ"##û"#"")$þ#$$#"*ú$##$#$$ý#$##"û#"#")$ú#$##$# #þ")$ #ý"#)$#û$##$##"û#"##)þ%$$#þ")$ú#$#$$##*þ%$$#ü$#$##*þ%$$ú#$#$$##ý"#)û$%$%$$#þ$##þ")%$÷#$$#$$#$##*þ%$$ü%$%$$ù#$#$##)÷$%$$%$%%$$#$#þ$)%ý$%$$þ#$$û#$$#)%$%$þ#$$þ#)%ú$%$%%$$û#$##)%$ü%$%$$ü#$#)&%ú$%%$%$$ù#$$#$#) %$ú#$$##)þ&%%þ$%%ü$%%$$þ#)%þ$%%$þ%$$*%&%ü$%%$$þ#)ö&%&&%%&%$%%ý$%$$*%þ&%%ú$%%$%$$*þ%&& %ý$%$$*&ú%&%%&%%$þ%)&%&%ù$%$%$$)& %$*&û%&%&%%û$%$%"ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ#€€€€!!þ"!!÷ ! ! !!)ý!"!! *þ"! ! ü! !)! !þ )ü"!"!!þ !!þ !!*!"!þ"! !*þ"!!þ )!û"!!"!!þ !!*ü!""!!ý !)!þ"!!þ"!!ý !)þ!""!þ"!!"! *þ!""û!"!"!!þ"!!*þ"! !ü"!"!!*"û!"!"!!þ"!!*ô!"!"!"!!"!"!!þ"!!*þ!""ý!"!!þ"!!*!"ù!""!!"!!*"!þ"!!û"!""!!*"!þ"!!ý"!)"þ!""û!"!"!!*"ö!""!"!!"!""!ý"!)"ô!""!!""!"!"!!þ"!!*"!÷"!"!"!""!!þ")"ü!"!""þ!""ý!"!!*"÷!""!""!"!!"ü!"!)"ý!"!!û"!"!)"ú!"!""!!"!û"!"!)þ#""þ!""þ!""!þ")"ü!"!""þ!""!"ý!")þ#""!"û!"!"!!*"ù!"!""!""ü!"!(ý"#""ü!"!""þ!""þ!("þ#""þ!""þ!""ú!""!"("þ!"")"þ#""þ!""û!""!""!)"þ#" "þ!""!(û"#"#"") "þ!"")þ#" "ü!"!"")ú#""##""þ#""þ!""!þ"'ü"##""ü!""'þ#""û#""#""þ!""þ!("þ#" "!"ü!"!'"þ#""û!""!'"þ#""þ#" "!ü"!"&#ý"#""þ#""þ!""(#"ö#""#"#""#""ü!""&ý"#""þ#""þ!""þ!%#ü"##""û#""#" "'þ#""#"þ#""&ý#"##"û#""#""þ#""ü!"!%#"#"&#û"#"#""#"þ#""'#÷"#"#""##""#"ü!""&ú"#""#""þ#" "(ø#""#"##""þ#""þ#""(#þ"##ü"##""#")#"ü#""##"#")#þ"##þ"##"*÷#"##"#"#""þ#""þ#""*#þ"##"#"+ë#"#"##"#"#""#"#""#""+þ"##ü"##""þ#""ü#""+#"#ø"#"#"##""!! ý )ú !! !  þ  *ý !  * þ  * ø! !! !  ý )ý !  ! *! ù! ! !! *ý !  û! ! *ü !!  þ! *û ! !  ! *û! !!  þ!  ü! !  *ú ! ! !! *!þ !! û! !!  *!ý !  þ!  ! *!ý !  þ!  þ!  *ñ ! ! ! !! !  *ñ! !! ! ! ! !! *! !ý !  û! !  *!ü ! !! ü! !  þ!)!ñ ! ! ! !! ! !)ü! !!þ !!û ! !  ý! )! ñ! !! !! ! ! !)!þ !! ú! ! )!þ !! !þ )!þ !!þ !! ù! !! !)!ü ! !! !þ ) ! ú! !!  *!ö !! ! ! !! þ!)!ö !! !! !!  !* !þ !! þ!)!þ !!ù ! !!(!þ"!!þ !! !)!û ! (ý!"!!û !! !! ý! (!þ"!!þ !!þ !!)ý!"!!þ"!!û !! 'þ"!!þ"!!û !! !!)!ü"!"!!ü !!(!þ"! !ü ! !!)þ"!!("ý!"!!(ø!"!"!!"! !þ ("ú!"!!"! !þ 'ü!""!!þ"!!þ !!(þ"!!þ"! !ü !!&ø"!"!!""! !þ !!(÷"!!""!!"!!'þ!""!&"þ!""û!"!"! !'"!þ"!!þ"!!þ"!!þ %!"!"ú!"!!"! !&÷!"!""!""!!&ø!""!!"!""!þ"!!'"ý!"!!þ"!!þ"!!'"ý!"!!"!"!("û!"!"!!þ"!!("þ!""ý!"!!þ"!!)"ü!"!""!"!)"!þ"!!þ"!!*"!ý"!""ü!""!!*!"ú!"!!"!!"!ü"!!*"þ!""!þ"!!ù"!!"!!+"ý!"!!"!þ"!!ý"!+ö!"!""!!"!""ù!""!"!"!ûTSTTSSþRSSRþQ)ûTSSTSSýRSRR*üTSSTTSþRSSüRSSRR*üSTSTTýSTSSþRSSR*ûTSSTS SüRSSRR*TSTSýRSRRýSR)TSþTSSüRSSRRýSR)T SR*þUTT SýRS)TSTSûRSSR)þUTTøSTSTSTTSSýRS)TSTSþR)TþSTTSýRS)UýTUTTSTSþR)UTùSTTSSTSS*úTUTUUTTýSTSSüTSS)þTUUüTUUTTSTSûTSTT)UTþUTTúSTSTS)UýTUTT÷STSTTSTS)U÷TUUTUTTUTTSýTS)UTüUTUTTS*UûTUTUTTýST)UúTUTUUTTýST)UTüUTUTTüSTT) UýTUTT*UþTUU TþS)üVUVUUTüUTUTTþUTTþS)üVUVU UþTUUT*VýUVUUTþUTT*øUVUVUVVUUýTUTTýUT)VüUVVUUT)VUûVUUVUUýTUTT)VUüVUVUUüTUUTT)VUûVUUVUUTúUTUTT(þWVVùUVVUVVU U)þWVVUþVUUT(þWVVUûTUUT(þWVVýUVU UýTU(WVþUVVU)W VUúTUUTU'úVWVVWVVUüVUVUUýTU'WýVWVVúUVUVVUUþT(WýVWVVùUVUUVVUU(WVþUVVU(VþWVVþUVVU'WVüWVWVVûUVUVUU(ûWVVWV VU'WVþWVVUVU&WûVWVWVVUþVUU'WVW VýUVUU&WýVWVVþWVVþUVVUþT%ýWVWWVUVUþVUU&WýVWVVWVøUVUVUUVUU'WþVWWVUûVUVU&WVþWVVU(W VUýVU' WýVWVVùUVVUVU(W÷VWVWWVWWVVýUV(WþVWWVþWVVûUVVU) WVþWVVûUVUU)üXWXWWVþWVVýUV*XWV,üXWXWWVWV,úWXWWXWWVþWVV!ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ)ÿ)ÿ)ÿ)ÿ)ÿ(ÿ)ÿ)ÿ)ÿ(ÿ(ÿ)ÿ(ÿ(ÿ'ÿ(ÿ'ÿ&ÿ'ÿ&ÿ&ÿ&ÿ'ÿ'ÿ(ÿ(ÿ)ÿ)ÿ*ÿ*ÿ+ÿ,ÿ,ÿ Àþ"="="="<";"9"8"ü!"!6"ý!"5"þ!""ý!"3"!"3"!"1"ü!"!""/ Àþ!=ý !<!=!<!ý !:!9!ü !!7!ü !!6!6 !4 ! 3!þ !!1þ"! !/ ÀþT=ýUT<U=U<U;VUþT8ýUVUU8úUVUVVUU7þVUU6VUøVUUVUUT3UùVUUVUVUUþT2VUþVUU1V U/ Àþÿ=ÿ=ÿ=ÿ<ÿ;ÿ9ÿ8ÿ7ÿ6 ÿ4 ÿ3 ÿ1ÿ/ þ<<;;:þ9ù66ö4õ3ûý1þ1ý.þþ-þþþ þ<ý;þ:þ;þ9ý8þ7ý5þ4þ4ý1þü0 /þþ-ý  þ+<ý+*;+;+þ*:+:+9ý+,++7,ü+,,++6,+5,ý+,++þ,3,þ+,,þ+1þ-,,ù+,,+,,0ù-,-,,-,,û+,++.-ü,--,,ü+,,,þ.--ú,--,-,,þ+,, þÿ<ÿ<ÿ;ÿ;ÿ:ÿ9ÿ7ÿ6ÿ5 ÿ4 ÿ2 ÿ1 ÿ/ÿ-ÿýó) þ) þþ) ú)þ þþ) ø)ûý)üþþ)þþø)þ *ýþ *þ *ü *þù *þ*ø*þþ*úþ*ýþ*ýó)û*þøý*õ*üþü)þüü)üö)þù*ùü)þ*þþû(þ ü)þ üü(þþø( þ)ü'û ú'ü'þ)úü(úþþ(þ þ(ü 'ý(þþþþ'ûþ þ&þùþ&þþ&ýýþ &ýþþ&üýù'ø'ùþþ'þü'ûþü( úþ(øùþ)÷) þý*þþ+ýþ,ü û+þ-þ.ú .þþþ*þýþ*þøþ)÷ü) ø) þ*þû*ø*ýþ*û*û) ô)ý*þ þ)ûò)þ)üþø)þ*þù)üþ *ýþ)ü*þ þ)ù *þþû) *ùþ*üþ*þü*þ)þ÷)öþ)þü(øý(þ(ý÷(þüþþ(ûüþ(þóü'þ(þþþ(þú' þþ' þþ''þ ý&ú þý%þý%þ û%þ'þþ'ü(þü(ûþ)þþ )ú*ûþ*þþù*þ+þýú+öý+úþ,ýþ-ú.&û%&%&%%þ&%%û$%$%)þ'&&%þ&%%þ$)ý&'&&ü%&&% %ý$%)ü'&'&& %ý$%)'&%&ý%&%%þ$)'&þ%&&%*ú&'&&'&&%&%þ$)'þ&''&ü%&%&&%ü&%%)ý'&''&%þ&%%*'&þ'&&%û&%%&)'ü&''&&ý%&%%*'û&'&'&&û%&%&)'ý&'&&þ'&&%&ý%&)'ý&'&&û'&&%&&ý%&)'ý&'&&û%&%&)þ(''ý&'&&ú%&%&&)ù('(''&''&þ'&&þ%&&*ü'((''&ü'&'&&ý%&) '&þ'&&*(ý'(''&'&*û('((''þ&''&*('þ(''ø&''&'&&)(ø'((''((''ý&'&&*( '&þ'&&*('ý&'&&*(þ'(('ü&'&''þ&)('þ(''û&''&))(þ'(('ú&''&')ý()(( '*þ)((þ'((ú'(''('')û)(()((þ'((')(þ)((þ'(('))û()()((ý'('')(þ)(('('))ý()((ù'(''((''() (ý'(''þ(')ù())(()((þ'((þ'')ú()())((þ'(('))()(ü)((''ü('(')(û)(()((þ)(('()*)(þ)((þ''ü*)*))û()()((ü'((&ü)**))ú()(()(((ý)*))ü*)*))('*)þ*) )ý()(('ù*)*)**))þ*))(ý)(%*)* )(&*)þ*))ú()()(%þ+**ü)**))þ*))þ())&þ+**þ)**)þ*))ý()&+ý*+**)þ*))ü())&+*þ+**)(*+*ú)**)*))(þ+**þ+**÷)*))*)*)(ú*++*+**þ+**))+ü*++**þ+**)ü*)))+ý*+**þ+**ü)**))*+*÷+**+**++**þ)*+ü*++**)++*þ+* *,+ú*+*+*++*,+þ,++*-+þ,++*þ+-,ú+,++,++ý*+**.ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ*ÿ)ÿ)ÿ)ÿ)ÿ)ÿ(ÿ(ÿ(ÿ)ÿ(ÿ(ÿ(ÿ'ÿ(ÿ'ÿ'ÿ&ÿ&ÿ&ÿ&ÿ'ÿ'ÿ(ÿ(ÿ)ÿ)ÿ*ÿ*ÿ+ÿ+ÿ,ÿ,ÿ-ÿ.ÿ.€€€€-#þ"##"ù#""#""-÷#""#"#"#""#"/#"#"0#ø"##"##"##"0ö#"##"##""##ü"#"0#"û#"#"1÷#"##""#"##þ"2#û"#""3"ü#"#""ý#"5#ù"##""#6#ü"#"7ü#""##9#";"þ#;#>þ# ÿ-"!ö"!!"!!"!!-û!""!""!"û!"!!."!"ù!""!""/ð"!"!!""!"!""!""/õ"!!""!""!"!!1"!"ü!""1ý"!""!ú"!"!!2"û!"!"!!ý"!3"!ý"!""6þ!""!7"û!""!7"!9"û!""!:"<"þ!=þ! ÿ-þXWWøVWWVWVWVV.ýWXWWVþWVV/ WýVWVV0üWXXWWþVWWûVWVW/XWûVWVVWWþV0þXWWVüWVV1WþXWWVW3WþXWWùVWVWVW3WþXWW6WýVW6W8ýWXWW9WþXWW;W<üWXW=þW ÿ-ÿ.ÿ/ÿ0ÿ0ÿ1 ÿ2 ÿ3 ÿ4 ÿ6ÿ7ÿ8ÿ9ÿ;ÿ<ÿ>þÿ ÿþ#" "!,"þ#""!"!"(# "ò!"!"!!"!"!"!!""þ#" "þ!""!"!"ý!"!!ù !! !  ü! !  ü!"#""þ!""!"!ü"!"!!þ"!!þ"! ! þ!  ! þ#" "þ!""û!""!""þ!""!þ"! ! ! ! "þ#" "þ!""!"ý!"!!þ"!!þ"!!ø ! !! !!û ! !  ý"#""#"þ#""þ!""þ!""ú!"!!"!!þ !!ï !! ! !!#"#""#"#" "ü!"!""!þ"!!þ"!!þ !! ! ö!##"##""#" "ø!""!!""!!"!þ"!!þ !! !#ý"#""þ#" "!"ü!"!""!û"!!"! !þ !!ñ ! !! ! "#"##" "þ!""!þ"!!"û!"!"! !þ !! þ!  þ#""þ#""#"þ!""ú!""!"!!ù"!"!!"!!ú ! !!  "û#"##""#"þ!""!"ý!"!!"!ö !! ! #"#""þ#""þ#""í!""!""!""!!""!!"!"!!þ"! ! !ü !"##þ"##ü"##" "ú!""!!""!þ"!!" !û !! !!ú #""##"# "þ!""!"!þ"! !þ !!ò#""##"#""#""#" "þ!""÷!""!"!""!! !#"þ#""þ#""ù!"!"!"!!þ"! !þ !!ö#""##"#"#""ü!""!!"!þ"! !ü !!þ#""þ!""!÷"!!""!!"!!"!û !! !! ý"#""þ#" "!ù"!""!"!!"!þ"!!" !"þ#" "!"÷!""!""!"!!þ"!!"þ#" "!"!ù"!!"!"! ! þ"!!þ !!þ +" !ø ! !! !!þ '!û"!!"!! ! ! ! #!þ !! ! !ý !   ý þ  û"!"! !þ !!û ! !  û! ! þ  ù   !!þ"! ! !ý !  ! þ! þ  !þ"! !û !! !! !ú !! ! þ  ÷   "!!þ"!! !ü ! !!ý !  !ü !!  þ! ú   ""!ü"!"!!ü !!  !þ !! ! û! !   ñ   !!""! !þ !! !þ !! ! þ!  þ  þ  ÷  "!!ú"!"!"!!ï ! !! !! ! ! ! !  ú "!!þ"!!ú !! !! !ý !   ø "!""!!"ý!"!! ! !ü ! !! þ!  þ   û!"!"!!û"!!"!!þ"! !þ !! ! û! !  þ  ö  !"!""!!þ"!!þ"! ! ý! !! þ!  ! þ  þ""!þ"!!ù ! ! !  þ! þ  ý"!!þ"!!"!þ"!!þ !!ú !! !! û! !  þ  "!þ"!!þ"!! ! ! þ!  þ  þ!""!÷"!"!!"!"!!þ !! ! þ! û  "ù!""!!"!!þ"! !þ !!ù !! !!  ! ü   !"ý!"!! ü! !  ! þ! ö"!!"!!"!"! !ü ! !!û !! !!ý ! ý "!÷ !! ! !  þ! ý! !!ý !  VùUVVUUVUUúTUTUT+VýUVUUTUTUþT'VýUVUUüTUTUUT#VüUVVUUùTUUTTUTTþSTTSRûSRSSRRøQRQRQQRQQþWVVUþVUUTSüRSRSSRþSR RQþWV VUúTUTUUTTõSTSTSTSTSTSSRþSRR÷QRQRRQRQVVUVUþTUU TSRSRQVþWVVýUVU UTþUTTöSTSTSTSSTSSýRSRRQúRQRRWVVþWVVúUVUVVUUýTUTTUùTUUTTSTTýSTSSýRSRRþQRRW VUTûUTTUTTþSTTSþTSSRþSRRþQRRVþWVVøUVVUVUVUUTùSTTSSTSSüRSSRRþSRRQRûQWWVWWVùUVUVUVUUTþUTTöSTTSSTSSTSSþRSSRWýVWVVþUVVUþVUUýTUTTþUTTýSTS SùRSSRRSRRýQWVVWVûUVUVUUþTUUTýUSTTüSTTSSRSRúQRWWVWWþVWWVöUVUVUVUVVUUúTUUTUTTþSTTSRSRWúVWVVWVVþUVVUþVUU TSTSRþSRRþWWVþWVVùUVUVUVU UTSTSþTSSþRSSRüSRRWüVWVWWVöUVUVUVUUVUUTþSTTSþRSSRýSRWVWVUüVUVUUþTUUTüSTTSST SûRSRRùWVWVVWVVUþVUUTþUT TSþTSSùRSRRSRVWVþUVVýUVUUTUTSþTSSR úWVVWWVVûUVVUVVUTþUTTúSTTSTSSüRSRSSþRþWVVUüVUVUUýTUTTSþTS SRVùUVUVUVUUTSTSþRSSþR ÿÿ,ÿ(ÿ#@ÿþÿ=ÿ<ÿ:ÿ8ÿ6ÿ 3ÿ/ÿ*ÿ Àü !!  ô      þ þüþü !!  þ  þ  ÷   ü   õþ  þ! ù    úüý !  þ  ü   ü ùþ÷! ! !  ú   ø   ùù !  ü   ý ù    þþô ! !!  þ  û   ù   ú û   ø   þýþþ þ! ù    ù   þü! !  þ!  þ  û   ý þü!!  þ!  ÷   þ þ  üþ÷ ! ! !    þ  üþ!  û! !! þ  ó    þþ!!ú ! !  ù   þ û!!  ! ü   þ ù   þþþ !! þ!  þ!  û   ý þþ!÷ ! !! !  þ! ÷     þ  ñ ! !! !  þ!  þ!    þ ü !! ! þ!    þ ú!!þ !! ü! ! î       þþ!!þ !!õ !! ! ! !  ò     ü ÿÀü÷ þú øþúþûþúúüõ  ôöû   ûþþô þ ûüð   þúúþþ÷   þ ýþúþþõ   ý  ýù þò    ÷þþþú    ü  ùýü   ú  þ  ôþþüý   þ ô üý  þ  üúþ üþ  õ      þþþû   ü   øú ú  þ þ  þý ø     ü þ þûüý   ÷     þûþþþ þ  þ  ý  þûþþ  þ  þ  ü  þüý  ÀQüPQQPPúOPPOPOOùNOONOONNüMNNMMNýMNMMLMLQôPQPPQQPPQPOPPOþPOOüNOON N MýLMLLþMLLQPQPþOPPOþPOOùNOONOONNMüNMNMMLþMLLþMLLQëPQQPQPPQPPOPOOPOPOPPOOùNOONOONNMþLMMLQþPQQüPQQPPþOPPOþPOOúNOONONNýMNM MLùMLMLLRQQPþQPP OùNOONOONNýMNMMþNMMþLMMLþRQQýPQPPûOPOOPPOøNONONNONNûMNMNMMLMLQþRQQPúQPPQQPPOPONOûNONONNýMNM MLûMRQRQQðPQQPQPQPPOPPOPPOOþPOONMNMþNMMLýMLRRQþPQQPûOPOPOOùNOONNONNMþNMMLúQRQRRQQýPQPPùOPPOPPOONûONNONNMNMøLMLMRRQRR QPþOPPOPOùNOONNONNôMNNMNMMNMLLMMûRQRRQQþRQQ PþOPPOýNON NþMNNMúLMMRQRRQþRQQPQPúOPPOPOOùNOONOONNMþNMMúLMMLQRRQþRQQþPQQPþQPPõOPPOPOPOOPOOúNONNONNþMNNMRQþRQQ÷PQQPQPPQPPýOPO ONONýMNMMRþQRR QPOþPOOùNOONNONNMüNMNMMRQûRQRRQ QPOþPO OúNONNONNüMNNMMRýQRQQþRQQýPQP POþPO OýNONNýMNMMRþSRRüQRQRRQùPQQPQQPPþOPPüOPPOOþNOO NM RùQRRQQRQQþPQQPOþPOONþONNøMNMNMNM ÿÀ@ÿ À öþ øþþüüþþûþý þýþýþþúýüþüþþüþùþþþþþ÷ þóý øþ þüþþþïûø ü÷ þüûþþüþ þðûýüúüöþüúûþþþþó þ÷þþûõ ùýþþþüþðþýý üþûþüøíþùþ øû þúþþþþ÷þ Àýûû øùüöþüþý òþ öúùüþõþú÷ þ þ ýûüýú úþþüþúýþ óïþ þûþþùýþýüúþ üþõùýþ þýüýþþþþúþüõþùþþüüúþþõ÷ù þûûþþ þþþ óþþ þý÷ þ÷þþþüþ  ÀKþLKKJþKJJøIJIJIIJII HGHGôFGGFFLLKKLLKKûJKJKJJþKJJIJ IHGþHGGúFGFFGLLýKLKKJþKJ JúIJIIJIIþHIIHGûHGGHGGùFGLLKLKKüLKLKKJIþJIIüHIIHHGþHG GþFLLKLKùJKJKJKJJøIJJIIJJIIþHIIHIHüGHHGGLþKLLKýJKJJúKJJIJIIüJIJIIHIýHIHHýGHGGLþKLLõKLLKKJKJKJKKJIJIHþIHHùGHGGHHGGþFLLKL KJþKJJþIJJIþHIIþHIIHüGHHGGL K JIûJIIJIIHþIHHúGHGGHGGLþKLLKþLKKýJKJ JIþJIIHIHþIHHGúHGGLMLLùKLKKLLKKJKýJKJJýIJIIúHIIHIHHGLþMLLýKLKKLKúJKJJKJJþIJJýIJIIöHIIHIHIHIHHGþHGGLþMLLKLKûLKKJKKJùKJIIJIJJýIJIIHûIHHIHHþGHHGýLMLLüKLLK KýJKJJüIJJI IýHIHHûGHGGMMûLMLMLLýKLKKJþKJJIJýIJI IHüIHIHHþGMMLMLKL÷KLKKJJKKJJþKJJIþJIIýHIHHGMLþMLLýKLKKþLKKýJKJJûIJIIJJ IHIHúMLMLML LúKLKKLKKJKJüIJJIIýHIHHþIHHMùLMMLLMLLúKLLKLKKJþKJJþIJJ IHþGMMüLMLMML÷KLKKLKKLKKþJKK JüIJJIIùHIIHIIHHGMüLMMLLûKLKLKKúJKKJKJJIüJIJIIþHIIH À@ÿ À þþ  ûþ úýþþþ óùþþúù üüþþþôþ þþü ôþþøþ ûþðþ þùþüõüþú þýüüüöú ùüþþøþüõ û ýþþ ûýþþïþþøô þþþüþü÷þùþ þô þ õ þýúþ þþüþ üüþýþûûüüý þþ ÿÀý ýùíþþùþõýûþùþ øþø ûüþþ÷þûþöüþþûþþ þö üþþøþúþþùþþþýþñþ þþýþ ûþþþþþþ÷ üþþþûþþþðþýþþþþþþûüþî ð þþ üõ öõ÷úþûûõüþûýúü÷óþ÷ þùúþþ ÿÀþGFFEùDEDEDEDDúCDCDDCCøBCBCBBCBBABAýFGFFEüFEDEEDñEDDEDDCCDCDDCDCCúBCBCCBBAþBAAGFúEFFEFEEûDEEDEEDþCDDCBüCBCBBAùBABAAGFFøEFFEEFFEEþDEEDûCDCDCC÷BCBCBBCCBBòABBAABGGFGFFGFFEDüEDEDDCþDCCúBCCBCBBþABBAGýFGFFEFEþDEEDþEDDþCDDCøDCDDCCBCCBCBþABB÷AGFGFGFGFFýEFEEüFEDEEDüEDEDDùCDDCCDCCòBCBBCBBCBCBBABBFGFüEFEFFEþDEED CýBCBBCBýABGGFüGFGFFüEFFE EDþEDDþCDDCþBCCýBCBBAGFEFEþDEEDEDûCDCDCCBûCBBCBBþAGGFGFúEFEEFEEüDEEDDýCDCCþBCCüBCCBBG FüEFFEEFýEFEE DCüDCDCCüBCCBBþHGGùFGGFFGFFöEFFEFEFEFEEDEDCûDCDDCCúBCBCCBBGþHGGFüGFGFFüEFFEEþFEEDþEDDCþDCCúBCBCBCCBHGFûGFFGFFEûFEEFEEúDEEDEDDþCDD CB GûFGFGFFþEFF EúDEDDEDDþCDDûCDCDCCôBCBBCBGHHGHGGüFGGFFþGFFEFýEFEE DýCDCCþDCCôBCBCBBHHGHHG GýFGFFûEFEFEEýDEDDöCDCCDCDCDCCBHGûFGFGFFüEFEFFEDûEDDEDDCþDCCýBCHH G FEþDEEýDEDDüCDDCC÷BCBCCHGHGGþHGGþFGGüFGGFFEþFEEýDEDDCþDCCûBCBC ÿÀ@ÿ Àøýþ ý÷ úû üö þþþþûü  ÷þþøþöþþ þüþþþûûûþýþ÷þ þû ûüýúþýüþ þûþ þüûùù þô þýû ñ úö  þøù ýûþ þ þþþù ùþ ó þöëïþ üûþýøþúüþþüþ÷ ýþüþö ÿÀþþþþê þúþþýþ ÷ùúôüýòþþýþþþùþùþþþýú ûþúûþýýþûþûþûûû ýùþ ö þþþþ þýúþõþþþý ïþþþþúüý þþû þùýû þüû þ÷þûû þïþþþ þýþü üûüüû ûý þ ùþúú  ÀAþ@AAý@A@@û?@?@?? >ù=>=>==>>=û<=<=<<þ;AA÷@A@A@@A@??@?þ@??ü>??>>þ=>>ý=>==þ<==<Aý@A@@?ú>??>?>>ü=>>==þ<==<Aþ@AA@þA@ @ ?>ü?>>==þ>==ú>==<<==<ú=<=<? >þ=>>=ü<=<==<þBAA@A@?þ@??>ü=>>==þ>==ý<=<<ü=??û>?>?>>ù=>>=>>==<ý=BAAB÷A@AA@@AA@@ý?@??þ>??>þ?>>=ü>=>==<÷=?>?>??>?>>ý=>==<=þABBA@Aý@A@@þ?@@ý?@??þ>?? >=<ö=BBABABABAAú@A@AA@@þA@@ ?ù>??>>?>>ú=>>=>==üBABAABýABAAü@A@AA@?þ@? ?>þ?>>=<BAþBAA@ûA@@A@@ø?@@?@??@@?þ>??>þ?>>þ=>>ü=>>==ý<=BBAù@A@@AA@@ü?@@??ö>??>>?>>?>>ü=>>==ú>==<?>=>=BúABBABAA@üA@A@@ûA@@A@@?ü>?>??>=þ>==BúABBABAAö@A@A@@A@A@@ú?@?@@??þ>??ý>?>>=ý>CBBAþBAA@üA@A@@ü?@@??ý>?> >=þ>B BAü@AA@@?ü@?@??ý>?>>ö=>>==>==CBBüCBABBAþ@AAý@A@@ü?@?@@?ú>?>??>>=û>=>=CCBþCBBüABBAA÷@AA@AA@A@@þ?@@?>þ?>>û=>== ÿÀ@ÿ Àþúþûûùþûü þðþýüúùòýôüþþ÷üþúþþþþü þüþþúùþýüþô  þþþ ùþþô÷ü ÷ýþ÷ úþþùþþþþý üõþûù óûøýôû þùôþ÷üü þû ûþþ üþüýþ ó  þþý ÿÀüóüþüþýþýþþþø ñþþò þþ þþúõûþøý ûþöþú÷ þüûþþøþûüüùþóþûúþ þúùüúþþþûþþüþûùóþþýý÷íþ÷ùõ þüþ üûýüþþ üü üþþþýùõþ üûþ ÷þþýüþþþ Àù;<<;;<;;þ:;;ú:;;:;::ù9:9:9:99ú899898878 7<ü;<<;;þ:;; :ý9:99 87þ877þ8776þ7<<ý;<;;ü:;;::ý9:99ý89887þ87 7ú<;<;;<<;ý:;: :þ9::9þ8998þ788ù78877877ý<;<<þ;<<ý;<;;þ:;;:þ9::þ9::9ü89988þ7887<÷;<<;<<;<;; :ø9:9:9::9987þ877<û;<;<;;÷<;;:;;:;::þ;::ý9:99898787þ877þ=<<÷;<<;<<;<;;ú:;:;;::þ9::9þ:99ù89988988ý7877÷8=<<=<<;<<ý;<;;:; : 98þ988û787877þ8<<;û<;;<;;:;:þ;::9þ:998ø989887788û=<==<<û;<;<;;:ü;:;::ú9:9::9987þ8==<þ=<<;<;þ:;; : 98þ788=<þ=<<ü;<;<< ;:ú9::9:998þ988þ988ú787==<<þ=<<ù;<<;;<;;ú:;;:;::ö9:9::9:9:99þ899ú8988988ú7878<==<þ=<<ü;<<;;:;:þ9::9þ:99þ8998þ988þ7==ü<==<<þ;<<;þ<;;:þ;::9ü:9:9 9ü89988û7=<=<<þ=<<;<ú;<;;<;;:; :ý9:99ù89988988= <;þ:;;ý:;::9þ:99þ:99898=<þ=<<þ;<<;þ<;;ý:;::;:ü9::99÷8988989988=<û=<==<<;÷:;:;:;:;::9þ899ý8988þ>==<=<;<ý;<;;þ:;;:9þ:998þ988 À@ÿ Àþüóýûû ôþöþþýüþþëüûþ þùüþþúþ þþùú üýþù üúþ þùúþþöþûþû ýõüüþþûþþþûþþþ öþþôþü ýùþþüþ þú ûüýð þþþþò þüýþþøþø÷þ ÿÀþôüþúþüþþüù üüðý üþõ ûüþþþüþúý üûþûúùý þôþ þûýþ þø þþûþþúü ûþù üýüüýþþôþüþþþþ þýþþ öþùþþþþüþûüöþþþþ ïþü þ óü úûü öý þýþ ÷ýü þòþþ Àþ7665þ655ü45544ý343 3ý23221ý21776565þ4554þ344û343433ù23223322176þ566ý5655ú4544544ý3433þ233 21ü677665þ6554þ544343þ4332þ322÷122127767765û6566554ü54544ø343443433ø233223322÷12212766776ý5655ü656554ö544544344334323ú2321122þ677 65þ4554þ544 32þ3227þ6776ú5655655õ655455445544ú34344332þ3227ý6766þ766ù5665665 54þ544ý3433þ433ú233232276þ766û565655ý4544þ544þ3443ü43433þ233ü23322þ877676ú5655655ý4544ò54434344334343327ý6766ü56655þ6554ü54544343ú2323322ü78877ý6766ü766556ý5655þ455ý4544û343433ý232276ü76766ü5665565ü45544þ344 3ø233223877ý6766þ766þ7665þ455 4ý3433þ433ý2322þ877þ877þ6776þ566þ56654þ544ù34433433ø232278877þ6776ü565665þ6554ú5445544ý3433ö23287787877676ù56655655ý454454ø343443433ö28878877877ú6767766ý5655þ6554ü545443û43343387û877877ü67766þ766565þ655ý4544û3433443õ238877878877676þ766ý565545ý454 43ø4334332 ÿÀ@ÿ *þþ&û þ!úø ûøðþýþñþý þüþûþ÷þîþþöü ö øþþýþþüþ úþþø üþ ýþýõ þþúþùû þýþþþþ ÷  øþþ ú üþþýýúþöþþþöü üöþúþüþû þô ýþþ þúûþþ þþø *ý&øýþ! ýþþøþýö þýþñþûþþþýþüùûþþý þýþþùýþýúþ úþ þþþþøûþó þþûþþþñ þúþþ þù þýùþ øúþþþøþ õþüþþþúþ üûþ ûýøûú þþþþùûþþ þüþþþ ö õþû þþùýýýôú *-ý,-,,þ-,,&.ý-.-- ,!.-þ.--þ.--ý,-,,+1þ011ý0100÷/0/00//0//û././..û-.-.--þ,--ý,-,,1010û/0//00ý/0//ú./../..ù-.-.-.--ù,-,-,,11þ2110þ100ý/0//.þ/..þ-..þ-..-ü,-,--,ý-,11ý0100/0/././.-þ,--,1010/þ0//ú.//./..-þ.--þ,--û,12211÷0110100100ú/0//0//ý./..þ/..þ-..-þ.--,ý-,22 1 0 /.ü/./..-.-ü,--,,þ122 1ú0100100ù/00/00// .-þ.--þ.--õ,--2212212110þ100þ/00/ø././/./. .-ø,--,12211þ211ý0100/0/ø./.././..þ-..-þ.--ø,21221211û010100/0/ü././/.-û.--.--2ù121122110þ100/ù0/0//0//ú./../..-.-,2ý1211ü01100þ10 0/û././..ø-..--..--ú3221221þ011ü01100/0/./.ü-..--2121þ2110þ100ù/0//00//ý./..û/../..þ-..2 1þ0110ù/00//0/ /ý./..þ-3 21 0/ü0/0//þ.//ý./..þ322121þ0110ü10100ü/00//þ.//þ. þ322þ3221þ211ú0110100ú/00/0//.ü/.. 232þ1221210þ100/ü0/0//2ü32322121ö01001100100þ/ *ÿ&ÿ!]ÿþÿ;ÿ:ÿ8ÿ6ÿ4ÿ 1ÿ -ÿ(ÿ ýþ/ù0üþ1þ2ûý13 4ý4þú5ø7þ9þþ9;=þ ~ýú.þ ü/ö0þû1þ2þ2ü3þ5þ5þ8ü9þ:;=þ ~,ü+,,++ù*+**+*.+ý,+,,+0,+þ,++þ*0,+,+þ,++2,ú+,,+,++2,ú+,++,++3,+,þ+3,û+,,+4ù,-,,++,,6þ-,,þ+7ü-,-,,9ú,--,,9û,-,,:ý-,<þ, ~ÿ/ÿ0 ÿ1 ÿ2 ÿ2 ÿ3 ÿ4 ÿ5ÿ6ÿ8ÿ9ÿ:ÿ;ÿ=þÿ ~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ääää‹‹ÅÅbb11Big PY Backgroundÿ     =ã ì ì ì* ì6·Ç×ç÷'7GWgw‡— Q0êEXàl€^”6¢Ô¦D¦T¦d¦t´œÖ!ø×Ö;4\Ï}ΟmÀŒÌ`ÌpÌ€ÌÚ^û{`=¢_#€¨¡¬ÂÍä{ñ^ñnñ~ñŽþÁÔA"bp„–¥©Ç:è‘ Ë · Ç × ç %$ Få g´ ‰\ ªô Ìž íü / 0d =[ =k ={ =‹ Kf lx ª ¯6 к ò þ 4ë VP c c c" c2 pª ’ ³¡ Õ§ öŸ C 9Ë [n |› ‰2 ‰B ‰R ‰b –z ¸ ÙÝ û ê => _ €š ¡¦ ­™ ­© ­¹ ­É ®3 µÑ ½f ÄÍ Ì Ów Úð â> éR é‚ é’ é¢ é² é éÒ éâ éò ê ê ê" ê2 êB êR êb êr ê‚ ê’ ê¢ ê² ê êÒ êâ êò ë ë ë" ë2 ëB ëR ëb ër ë‚ ë’ ë¢ ë² ë ëÒ ëâ ëò 쀀€€ ?þ„<ý‚ƒ;ƒ;‚ƒ:‚þƒ8‚8þ‚‚7‚ý‚5‚ú‚‚‚4þ€‚þ4þ€þ‚3€û€€þ‚2€û€€2ü€€€þ€€ü€1þ€€1ú€€€€1ý€€€þ€/÷~~€€€û€€/ü~~ü€€€/~þ~~þ€þ€.þ}~~ü~~ü€€-}~þ€-}~þ~.}~ü~~-þ|}}ý~}~~-ý}|}}~û}~~~~-|}~}~ý~+ü|}|}}~þ}~~ ?þ‰<‰<‰;ˆý‰ˆ9ˆ‰9ˆ8ˆþ‡ˆˆþ‰6þ‡ˆˆ6þ†‡‡ûˆ‡ˆˆ4ý‡†‡‡ˆ5þ†‡‡4†‡3ù…††‡††‡‡2…†‡þ†‡‡2ý†…††÷…†‡††‡†‡0…†…†1…†þ‡/…†0ü…„„……û†…†…††/„ü…„„……†ý…†.ý„…„„…†þ…-þƒ„„…þ†-þƒ„„…þ†-úƒ„ƒ„ƒ„„…þ„……ý†…,ƒ „ù…„…„……,ùƒ„ƒƒ„ƒ„„û…„…„……-ƒ„ú…„„…„+ƒþ‚ƒƒ„þƒ„„… ?þø<ý÷ø;ø;û÷øø÷9ø9÷ûø÷ø÷7÷ø÷7÷þø5ý÷ø÷÷ø÷5÷þø÷÷5 ÷4 ÷3÷þø÷÷üø÷÷1÷þø÷÷2 ÷1 ÷ýø÷0 ÷ûø÷÷ø/÷0÷þö÷ ÷/ö÷þö÷÷/÷.þö÷÷þö÷÷þö÷÷.ö÷ùö÷÷ö÷÷-÷úö÷ö÷ö÷÷-üö÷ö÷÷þö÷÷-þ÷öö÷þö÷÷üö÷÷,ýö÷öö÷þö÷÷þö÷÷,÷þö÷÷üö÷ö÷÷þö÷÷ ?þ0<ýXø;üvÿÿ:þŠÿÿ:þ”ÿÿ9þ”ÿÿ8þŠÿÿ7þvÿÿ6þXÿÿ5ý0øÿÿ5þËÿÿ4þ”ÿÿ3þSÿ ÿ2ýßÿ ÿ2þÿ ÿ1þ5ÿ ÿ1þ²ÿ ÿ0þIÿ ÿ0þ¼ÿ ÿ/þDÿ ÿ/þ­ÿ ÿ.þ&ÿÿ.þ…ÿÿ.þßÿÿ-þDÿÿ-þ”ÿÿ-þßÿÿ,þ0ÿÿ•þ‡ˆˆû‰ˆ‰ˆ‰‰øŠ‰ŠŠ‹‹Š‹‹ðŒ‹‹ŒŒ‹ŒŒŒŒŒ‡ ˆ‰ûЉЉŠŠ‹Œþ‹ŒŒüŒŒ ‡ùˆ‡‡ˆˆ‡ˆˆ‰ùˆ‰Š‰Š‰ŠŠ‹Œ †þ‡††‡ˆ‰úŠ‰ŠŠ‰ŠŠ‹Šú‹Œ‹Œ‹ŒŒ†ú…†‡‡†‡‡ˆþ‡ˆˆý‰ˆ‰‰ûЉЉŠŠ‹Œþ‹ŒŒü…†…†† ‡ˆû‰ˆ‰ˆ‰‰üЉ‰ŠŠý‹Š‹‹ùŒ‹‹Œ‹Œý…„……† ‡ˆþ‡ˆˆ‰þˆ‰‰Š÷‰Š‹ŠŠ‹‹Š‹‹ùŒ‹Œ‹ŒŒ„…þ„……ü†……††ý‡†‡‡ˆý‰ˆ‰‰Š‹þŒ‹‹„ý…„……†û‡†‡†‡‡ûˆ‡ˆ‡ˆˆ‰ûˆ‰‰Š‰‰ýЉŠŠ ‹ýƒ„„…þ„……†‡ˆ‰Šý‹Š‹‹ƒ„…†ú‡†‡††‡‡úˆ‡‡ˆ‡ˆˆ‰þˆ‰‰Šþ‰ŠŠ‹ƒ„ú…„„…„……†…†‡þˆ‡‡ˆ‰üˆ‰ˆ‰‰Š‰Š‹ýƒ„ƒƒú„ƒ„„…„„…†þ…††ý‡†‡‡òˆ‡ˆ‡ˆ‡ˆˆ‰‰ˆ‰ˆ‰‰ýЉŠŠ‹ƒþ„ƒƒ„…†‡þ†‡‡õˆ‡‡ˆ‡ˆˆ‰ˆˆ‰‰Šû‹ŠŠ‚ƒƒý„ƒ„„û…„…„……ü†……††‡ýˆ‡ˆˆþ‡ˆˆ‰Š‰Šþ‰ŠŠƒþ„ƒƒ„…„…ý†…††ü‡††‡‡ˆ‡ˆý‰ˆ‰‰ýЉŠŠþ‚ƒƒù„ƒ„ƒ„ƒ„„ý…„……ý†…††þ‡††‡ýˆ‡ˆˆ‰Š‰ûŠ‰ŠŠ‚‚ýƒ‚ƒƒü„ƒƒ„„ù…„…†…†……†‡þ†‡‡ˆü‰ˆˆ‰‰Š‰‚ƒý„ƒ„„û…„…„……†‡ýˆ‡ˆˆý‰ˆ‰‰üЉЂ‚ƒ„üƒ„ƒ„„…ü†……††‡ú†‡‡ˆ‡ˆˆ‰øˆ‰‰Š‰‚‚‚ƒþ‚ƒƒ„üƒ„„……þ„……†þ…††ø‡†‡††‡ˆ‡‡ýˆ‡ˆˆý‰ˆ‰‰úŠ‚‚‚‚󃂃ƒ‚ƒƒ„ƒƒ„ƒ„„…þ„……ü†……††ý‡†‡‡ýˆ‡ˆˆü‰ˆˆ‰‰ý‚‚úƒ‚ƒƒ„ƒƒý„ƒ„„…ú†…††…††ý‡†‡‡ˆþ‡ˆˆ‰ü‚‚‚ƒü‚ƒ‚ƒƒí„ƒ„„…„„……„……†…†…†…††ù‡††‡††‡‡úˆ‡ˆˆ‡ˆˆ‰ˆþ‚‚þƒ‚‚ƒý„ƒ„„û…„…„……†û…††…††‡ˆþ‡ˆˆý‰ˆú‚‚‚‚ƒ„þƒ„„…ø„…„……†…† †‡ûˆ‡ˆ‡ˆˆ÷‰ˆ€€‚‚úƒ‚ƒƒ‚ƒƒ„…†‡þ†‡‡òˆ‡ˆˆ‰€€€‚‚ƒþ‚ƒƒý„ƒ„„ú…„…„„……ü†……††‡†‡ˆ÷‡ˆˆ€€€‚ƒý„ƒ„„þƒ„„…ý†…††‡þˆ‡‡ˆü€€€þ‚‚ƒþ‚ƒƒý„ƒ„„þƒ„„ü…„„……ý†…††ü‡††‡‡þˆ€€û‚‚‚‚ƒý„ƒ„„ …†ú‡†‡‡†‡‡þˆ€€ü€€û‚‚‚‚ƒý„ƒ„„ú…„……†……ü†……††‡€ ‚ýƒ‚ƒƒ„…„…†ý‡†‡‡ý€€€þ€ý‚‚‚þƒ‚‚ƒý„ƒ„„…ô„……„…†…†…†…††‡ú†‡‡€€þ€€þ‚‚ýƒ‚ƒƒ„û…„…„……û†…†…††‡ü€€€‚þ‚‚ƒ„þƒ„„…†ü‡†‡€ý€þ€‚üƒ‚‚ƒƒ„…þ„……ù†……††…††ý~€ý€€‚ƒþ‚ƒƒ„ …†þ…††•ŽþŽŽüŽŽþú‘‘’ ŽýŽþ‘þ‘‘ý’‘’’ ŒþŒýŽŽŽúŽü‘‘‘ù’‘‘’’‘ ŒþŒŒüŒŒŽŽþŽþýû‘‘‘‘’þ‘þ‹ŒŒþ‹ŒŒüŒŒŽþŽŽúŽŽþ‘‘‹øŒ‹‹Œ‹Œ‹ŒŒüŒŒ ŽýŽú‘‘‘‘‘üЋЋ‹ŒüŒŒýŽŽŽýŽ‘ü‘’þŠ‹‹þŠ‹‹Œþ‹ŒŒùŒŒŒüŽŽŽùŽŽŽ‘Šþ‹ŠŠ‹÷Š‹Œ‹Œ‹Œ‹ŒŒûŽŽŽŽûŽŽüü‘ŠŠ‹úŒ‹Œ‹‹ŒŒ÷ŒŒŽŽŽ ‰Š÷‰ŠŠ‹Š‹‹Š‹‹ýŒ‹ŒŒþŒŽúŽŽþ÷‘‰‰ŠŠ‰ŠŠ‹ŒøŒŒŒŒ Žü‰õЉЉ‰ŠŠ‹Š‹ŠŠ‹ ŒýŒŽþŽŽýމŠü‹ŠŠ‹‹ŒþŒøŽŽŽŽŽŽùމþˆ‰‰óЉ‰Š‰ŠŠ‹ŠŠ‹Š‹ ‹ŒŽ‰þˆ‰‰õŠ‰ŠŠ‰ŠŠ‹ŠŠ‹‹þŠ‹‹Œ Žþˆˆ‰Š‰Šü‹ŠŠ‹‹Œþ‹ŒŒýŒþŒŽ ˆû‰ˆ‰ˆ‰‰þЉ‰Š‹Œü‹ŒŒüŽŽŽþŽˆý‰ˆ‰‰þЉ‰ýЉŠŠ‹þŠ‹‹Œ ýŽŽŽý‡ˆˆ‰ñЉ‰ŠŠ‰ŠŠ‹ŠŠ‹‹Š‹‹Œ÷‹ŒŒŒŒŒûŽŽŽŽòŽŽ‡ˆ‡ˆˆ‰ˆ‰ˆˆ‰ýЉŠŠü‹ŠŠ‹‹üŒ‹‹ŒŒþŒŒ Žý‡ˆˆ‰ûˆ‰‰ˆ‰‰ýЉŠŠ ‹ ŒŽýއˆü‰ˆˆ‰‰þˆ‰‰Šý‹Š‹‹Œü‹Œ‹ŒŒ އûˆ‡ˆ‡ˆˆ‰þˆ‰‰þЉ‰Šý‹Š‹‹Œû‹ŒŒ‹ŒŒþŒŽýއ‡ˆþ‡ˆˆü‰ˆˆ‰‰Šõ‰ŠŠ‹Š‹Š‹‹Š‹‹Œþ‹ŒŒüŒŒŽ‡þˆ‡‡ˆý‰ˆ‰‰Šþ‰ŠŠ‹Œþ‹ŒŒŽþŽŽþ†‡‡ ˆ‰Š‹üЋЋ‹ŒþŒŽ ‡ˆø‰ˆˆ‰ˆ‰ˆ‰‰Š‹þŠ‹‹üŒ‹‹ŒŒþŒŒýŒú‡††‡†‡‡ˆù‰ˆ‰ˆ‰ˆ‰‰üЉ‰ŠŠ ‹ŒôŒŒŒŽŽ††‡ýˆ‡ˆˆü‰ˆˆ‰‰Š‹þŠ‹‹þŠ‹‹Œö‹ŒŒŒŒŒú…††‡‡††‡ ˆ‰Š‹Š‹Œ‹ŒþŒŒþ…††ý‡†‡‡þ†‡‡ýˆ‡ˆˆ‰üЉ‰ŠŠø‹ŠŠ‹Š‹Š‹‹ Œý†…††‡ˆ‡ˆý‰ˆ‰‰ûЉЉŠŠý‹Š‹‹úŒ‹ŒŒ‹ŒŒöŒŒ†…†…††ú‡††‡†‡‡ˆ‰þˆ‰‰öЉЋ‹ŠŠ‹Š‹‹ýŒ‹ŒŒ…ý†…††ú…††‡†‡‡úˆ‡ˆ‡‡ˆˆ ‰Š‹ýŒ‹ŒŒù……†……††‡ýˆ‡ˆˆ ‰Šþ‰ŠŠû‹Š‹Š‹‹ýŒ‹ŒŒýŒ…… †‡†‡ýˆ‡ˆˆ‰ûˆ‰‰ˆ‰‰þЉ‰ýЉŠŠ‹þŠ‹‹Œø‹ŒŒ‹Œ„„……û†…†…††‡ˆý‰ˆ‰‰ýЉŠŠ‹Œ•øþùøøþùøøþùøøùøùþøùùøýùøùùøøþùøøùûøùùøùùøùüøùù øþùøøùøùýøùøøù÷øùùøùøøù øþùøøþùøøùûøùøøùùþøùùþøùùþøùùþøøþ÷ø øþùøøüùøùøøùûøùøøùùþøùùøùýøùýø÷øøþ÷øøþùøøìùøøùùøøùùøøùùøùøùùøùùþøùùøþùøøöùøøùøøùøùøøùüøùùøøùûøùøøýø÷øøþ÷øøþ÷øøþ÷øøùøüùøøùùûøùøøùùøùúø÷ø÷÷øøúùøùøøùùçøùøøùùøøùùøùùøùøøùøù÷ø÷øøþ÷øøþ÷øøþ÷øøøùøøùøùùøøüùøù÷÷øþ÷øøþ÷øøùùøøùøùøøùùøøùøøùùøùøñ÷øø÷ø÷÷ø÷ø÷øø÷øøû÷øø÷ø øþùøøþùøøüùøùøøùþøùùøùø÷øý÷ø÷÷þø÷÷øþ÷øøþùøøùøùþøùùùøùø÷øø÷÷ø÷øû÷øø÷øøþùøøûùøøùøøûùøøùøøüùøø÷÷þø÷÷øþ÷øø÷øþ÷øøùùøøùøùøøòùøøùøø÷ø÷øø÷ø÷÷þø÷÷øþ÷øøþ÷ø øþùøøùøüùøùøøþùøøñùøøù÷øø÷øø÷ø÷÷øøþ÷øøþ÷øø÷øþ÷øøþùøøöùøùùøøùøùøøôùøùøø÷ø÷ø÷÷øøû÷øø÷øøþ÷øøü÷ø÷øøþ÷ø øùýøùøøþùøø÷ùøùøùøùø÷÷ûø÷ø÷øøþ÷øøù÷ø÷øø÷øøþùøøþùøøù÷øþ÷øøû÷øø÷øøú÷ø÷ø÷ø øþ÷ø øùøüùøøùùø÷ø÷ø÷÷ø÷÷øü÷øø÷÷øû÷øø÷ø øöùøùøøùøøùøøþùøø÷üø÷ø÷÷ýø÷øøú÷øø÷÷øø÷øùûøùøùøøï÷ø÷÷ø÷ø÷÷øø÷ø÷ø÷øøþ÷øøþ÷øøü÷ø÷øø÷ø÷úø÷÷øø÷÷øü÷ø÷øø÷ýø÷øøþ÷øøþùøø÷þø÷÷þø÷÷ýø÷øø÷ø÷øüùøø÷÷þø÷÷ùø÷ø÷øø÷÷øü÷ø÷øøþ÷øøü÷ø÷øøþ÷øøþùøøþùøø÷úø÷÷øø÷÷øü÷ø÷øøü÷ø÷øøþ÷øøû÷øø÷øø÷þø÷÷ñø÷øø÷ø÷÷ø÷÷ø÷ø÷÷øþ÷øøþ÷øøþùøø÷þø÷ ÷ø÷üø÷ø÷÷øþ÷øøý÷ø÷÷þø÷÷üø÷ø÷÷ïø÷øø÷ø÷øø÷÷ø÷øø÷øøþ÷øø ÷ýø÷øø÷øý÷ø÷÷ø÷ø÷øþ÷øøýùø÷÷üø÷ø÷ ÷üø÷ø÷÷ùø÷ø÷ø÷øøü÷ø÷øøþ÷øø÷ø÷üø÷ø÷÷ûø÷øø÷÷ø÷ø÷ø÷þø÷÷ø÷þø÷÷ø÷øþ÷øøü÷ø÷øøþ÷øø÷øù÷øø÷øø÷÷øù÷ø÷øø÷øøþ÷øø÷øþ÷øø÷þø÷÷þø÷÷ýø÷øø÷øþ÷øøö÷þø÷ ÷ùø÷ø÷ø÷øøô÷øø÷÷øø÷øø÷ø ø÷úø÷ø÷ø÷ ÷üø÷÷øøü÷øø÷÷øþ÷ø ø•öIq”²Ëßîøÿ ÿû0q­äÿ)ÿ üD”ßÿ-ÿ ü&…ßÿ0ÿýD­ÿ3ÿýI¼ÿ5ÿý5²ÿ7ÿýÿ9ÿýSßÿ:ÿý”ÿ<ÿþËÿþÿ€ŽþŽŽüŽŽüý‘‘‘’û‘’’“’’“”•ŽüŽŽ‘þ’‘‘ý’‘’’“þ’““”üŽŽŽŽüü‘‘‘ü’‘‘’’“”“”ú•”ŒŒüŽŽŽý‘þ‘‘’þ“’’ú“’““”““”þŒ÷ŒŽŽŽŽŽýŽý‘‘‘’þ‘’’“”ü“””ŒŒýŽŽŽ ý‘‘‘’þ“’’“ñ”““””ŒŒŒŒŒýŽŽŽüþ‘‘’þ‘’’ñ“’“’’““”““””Œ‹ŒŒüŽŽŽþŽŽ‘þ‘‘’ü“’’““ý”‹ŒŒþŒôŽŽŽŽŽŽü‘‘’‘’ú“’“’’““‹ïŒ‹ŒŒŒŒŒŽŽŽŽüŽŽý‘þ‘‘’þ“’’“Œ‹ŒúŒŒŒüŽŽŽþŽŽ‘‘þ’‘‘’ü“’’““‹úŒ‹‹Œ‹ŒŒýŽŽŽý‘‘‘ù’‘’‘’‘’’“‹Œ‹ŒŽþŽŽùû‘‘‘‘ü’‘‘’’ü“’’‹‹þŒ‹‹ŒûŒŒŽþŽŽþŽý‘þ‘‘ú’‘‘’‘’’þŠ‹‹ŒûŒŒýŽŽŽûŽŽúü‘‘‘’Šü‹ŠŠ‹‹Œ‹ŒüŒŒŽþŽŽþý‘‘‘’øŠ‹ŠŠ‹ŠŠ‹‹þŒ‹‹ŒüŒŒûŽŽŽŽþŽû‘þ‘‘’Š‹Œþ‹ŒŒþŒŒŽŽýŽýý‘‘‘û’‘‘‰ŠŠþ‹ŠŠ‹ Œ÷ŒŽŽŽŽŽû‘Š‹þŠ‹‹ŒýŽŽŽö‘‘‘ø‘‘ŠŠ‰‰ŠŠû‹Š‹Š‹‹ŒúŒŒŒŽþŽŽ ýú‘‘‘‘‘Šþ‰ŠŠ‹þŠ‹‹Œþ‹ŒŒýŒŽþû‘‘‘‰‰Šþ‰ŠŠ ‹ŒùŒŒŽŽ ‘‰Š‹üŒ‹‹ŒŒþŒŽýŽþñ‘‘‰‰ˆ‰‰Š‰‰Š‰ŠŠú‹ŠŠ‹Š‹‹þŒ‹‹ŒþŒŒŽþŽþ‰ˆ‰úЉЉ‰ŠŠ‹ŒûŒŒŽôˆ‰‰ˆˆø‰Š‰‰ŠŠ‰ŠŠü‹ŠŠ‹‹üŒ‹‹ŒŒþŒýŽŽŽîŽŽˆˆ‰ˆˆ‰‰üЉ‰ŠŠü‹ŠŠ‹‹ýŒ‹ŒŒ ŽüŽŽ÷ˆˆ‰ˆ‰ˆˆ‰‰óЉ‰ŠŠ‰ŠŠ‹Š‹Š‹‹üŒ‹‹ŒŒüŒŒ ŽýŽþŽþˆˆ ‰ýЉŠŠ‹ŒýŒþŽŽˆþ‡ˆˆ‰ùˆ‰Š‰ŠŠ‰‰Šú‹Š‹‹Š‹‹ýŒ‹ŒŒúŒŒŒŽöŽŽŽŽŽŽò‡ˆ‡‡ˆˆ‰ˆˆ‰ˆ‰ˆ‰‰Š‹úŒ‹ŒŒ‹ŒŒþŒýŽŽŽþއýˆ‡ˆˆý‰ˆ‰‰Šù‹ŠŠ‹ŠŠ‹‹ŒýŒýŽŽŽõއˆ‡‡ˆ‡ˆˆü‰ˆˆ‰‰Šû‹Š‹Š‹‹ ŒŽþŽŽüއ‡ˆþ‡ˆˆü‰ˆˆ‰‰úЉ‰Š‰ŠŠ‹Œþ‹ŒŒþŒŽü††‡‡ˆ‰þˆ‰‰ Š‹Œ‹ŒŒüŽŽŽ‡þ†‡‡ûˆ‡ˆ‡ˆˆ‰ˆ‰Šþ‰ŠŠú‹Š‹ŠŠ‹‹ŒúŒŒýŽŽŽ‡÷ˆ‡ˆˆ‡ˆˆ‰ˆˆ‰Šý‰Š‰‰Š‹Œü‹ŒŒŽŽ€ý“’““ý”“””•þ”••–þ•––—þ–—— ˜™þ˜™™šü™’’““þ’““ý”“””•þ”••–þ•––ù—––——–——ý˜—˜˜™þ˜™™’ü“’’““ü”““”” •ý–•––þ•––—˜—˜™ü˜™™’’ý“’““þ”““ý”“””ý•”••–þ•––—þ–——þ˜——ý˜—˜˜™‘’“’“ü”““””õ•””••–•––•––û—–—–——˜þ—˜˜™˜ ’“ü”““”” •ý–•––û—–—–——ý˜—˜˜ü™˜˜‘‘’“”þ“””•– —ý˜—˜˜™‘’þ‘’’“þ’““”þ•””ý•”••õ–•–•–—–—––——ú˜——˜—˜˜ý™˜‘‘’ý“’““”•ü”•–••–þ—––—˜ú‘‘’’‘‘’ü“’’““”ý•”••þ–••ý–•––ý—–——ý˜—˜˜‘’ü‘’‘’’ý“’““”•ý–•––—ö˜—˜˜—‘‘‘‘’þ‘’’û“’“’““”•þ”••–þ•––—û˜—˜‘ý‘‘‘’þ“’’“ü”““””•þ”••ù–•–•–•––—–—þ˜‘þ‘‘ý’‘’’“”þ“””•ü–••––—ý‘‘‘ý’‘’’þ“’’“”ü“”“””•þ”••–ü—––——þ˜‘þ’‘‘’“þ’““þ”““ö”“””•”•””••ý–•––ü—––——û‘‘‘‘ý’‘’’“þ’““”û•”•”••ý–•––ü—–—‘þ‘‘’þ‘’’ “” • –ü‘’“þ’““ ”•–ú•–—–—ü‘’‘’ü“’’““þ”““”•þ”••–þ•––ý‘ý’‘’’þ“’’“ü”““””•ü”•”••–þü‘‘‘û’‘’‘’’ý“’““”þ“””ü•””••ý–•––ûŽŽýþ‘‘ý’‘’ ’ý“’““”ü•””••ü–••––Žýý‘‘‘õ’‘’’‘’’“’’““ý”“””•–Ž÷ŽŽŽþ‘‘’þ“’’“þ”““”•ù–•ŽŽŽý‘þ‘‘ü’‘‘’’“ý”“””ý•”••þ–ŽŽþŽŽùý‘‘‘’ü‘’‘’’“’“”ü“”“””•ú”•ŽŽŽŽ÷ŽŽþ‘‘ë’‘’’‘’’“’“’“’“’““”““””ý•”••úŽŽŽŽüý‘‘ ‘’“þ”““”ü•ŽŽŽüŽŽü‘‘‘û’‘’‘’’þ“’’ý“’““”ý•”Ž‘’ý“’““þ’““”þ“””ý•”ýŽŽŽ‘þ‘‘’þ‘’’“’“”þ•ŽýŽŽŽü‘‘‘’ö‘’“’’““’’““”ù“””““”ŽŽþŽüþ‘‘þ‘‘’ú“’’“’““”üŒŒŽŽýŽþ‘’‘’ý“’““þ”““ý”ŒýŽŽŽûŽŽú ‘ü’‘‘’’û“’“’““Œ÷ŒŒŽŽüŽŽþŽ ‘’þ‘’’ù“’“’“’““ŒŽþ‘þ‘‘ú’‘‘’‘’’þ“’’“€ùþúùùþúùùþúùùúùõúùúùúúùùúùúúüùúùú úþøù ùþúù ùüúùúùùüúùùúúûùúùùúúùúþùúúùþúùùýúùúúýùúùùûúùúùúúþùúúþùúúüùúúùùúùúùýúùúúùúùþúùùúüùúùúú ùþøùùþúùùúýùúùùþúùùúùúûùúùùúúþùúúþùúúùþøùùúøùùøøù ùþúùùöúùúúùúúùùúúüùúúùùúùùúúùùúùùþøùùöúùùúùúùúúùùúùúþùúúûùúùúùùþúù ùþúùùõúùúùúúùúùùúúùøùüøùøùùúüùúúùùþúùùúúùúúøùøøùþøùùþøùùúýùúùùúöùúùùúùùúùúúüùúùúúùøùþøùùø ùþúùùùúùúùúùúúúùúùúúùùúúùúúùúúþùúúùþøùùûøùùøùùûúùùúùùþúùùùúùùúùúùùþúùùúùþøùùøùþøùùþúùùúùúùúþùúúùþúùùûøùùøù ùþøùùþúùùþúùùúùþúùùüúùúùùúùùúúùøøùùþøùùüøùøùùþúùùþúùùñúùùúúùúùùúùùúúùùþøùù÷øùøùøùùøùùøùú ùþúùùùúùúúùùøøùþøùùüøùøùùûúùùúùùúøùúùúùúúùùýúùøøùþøùùþøùùþøùùüúùúùùúùøùøùøùúøùøùøùùôúùùúùúùúùùúùùúýùúùùøþùøøþùøøþùøøùøùþøùùýúùúúùúùûúùúùøøùøùðøùùøùùøùùøùùøùøùùþøùùúùýúùøøùøùøùúøùùøøùùþøùùúøùúùúùúùøøúùøùøøùùøùøùþøùùøùþúùùîúùúùúùúùùúùùøùøøùøøùøùþøù ùþøùùþúùùüúùùøøþùøøõùøøùøùøøùøùùøùøýùøù ùþúù ùúùûúøøùøøùøöùøùùøøùøøùùþøùùûøùùøùùþøùùþúùùþúùùúþùøøüùøùøøùûøùùøùùøùþøùùûøùùøùùþúùùøùùøùøøùøùùþøùùþøùùþøùùýúùøøóùøøùùøøùøøùøùùþøùùûøùùøùùüøùøù ùúùûúùøùøøùøýùøùùþøùùøùôøùøùøøùøùùøùùþøùùþúùùþúøøþùøøþùøøþùøøùøùüøùøù ùþúùùþúùùþúø øùùøùøøùùøøùþøùùüøùøùùøþùøøûùøøùøøùýøùøøúùøùùøùùøüùøøùùûøùùøù ùúøùøøùøøþùøøøùøùøùùøùùøøùøøùøøùùþøùùøþùøøþùøøùøøùøøùùøùùúøùùøøùùøýùøùù øþùøøþùøøùøúùøùøøùùûøùùøùùþøù ù øüùøøùùôøùøøùùøøùøøùùûøùùøùùþøùùþøùùþøùù øùýøùøøþùøøúùøùùøùùþøùùþøùùþøùù€ €ÿ€•û–•–•––ý—–——ý˜—˜˜™˜™þš™™š›þš››œø”•””•–•––ø•–—––—–——ý˜—˜˜™þ˜™™üš™™šš ›œ”ý•”••–þ•––—þ–——˜þ—˜˜™ýš™ššþ›šš›œþ›œœù•””••”••ù–•–•–—––ý—–——ý˜—˜˜™þ˜™™üš™™ššü›šš››œù”•””•”••–ý—–——ý˜—˜˜õ™˜˜™š™šš™™šš ›ûœ›œœ””•þ”•• –ý—–——þ˜——˜þ™˜˜™š™š›þš››÷œ””“””•”••ú–••–•––ú—–—––——˜þ—˜˜û™˜™˜™™šþ™šš›þš››ýœ›””•–þ•––—þ–——˜ý™˜™™õš™™šš›šš›š››“ý”“””•þ”••–—û˜—˜—˜˜ü™˜˜™™š›ûš›š›““ý”“””•–—˜þ—˜˜™þ˜™™š™š›÷’“”““”““””ý•”••–ù•––——–——˜þ—˜˜ü™˜˜™™šü›šš““ý”“””ý•”••þ”••–ü—––——˜þ™˜˜™šû›šš’““ü”““””•þ”••–ú—––—–——ü˜——˜˜™þ˜™™úš™™š™ššý›’““”•–ü—––——ù–—˜˜——˜˜þ™˜˜ ™íš™š’“’’“’““”“”“””“””•–ü—––——˜þ—˜˜™úš™šš’““þ’““ü”““””•”•–þ•–– —˜™˜™šþ™’’“ú’““”“””•þ”••ü–••––—þ–——ý˜—˜˜™ýš‘’’“”“”•þ”••ñ–•–•–•––——–—––——ý˜—˜˜™’‘’“ý”“””•–—˜—˜þ—˜˜™þ˜™™þš‘‘’“’“”ü•””••–•–ý—–——ý˜—˜˜™‘’“”•û”•””••–ü—––——˜þ—˜˜™ý˜™‘‘ý’‘’’“þ’““ü”““””þ•””•û–•–•––—˜™ý˜™‘‘’þ‘’’ó“’““’““””“”“””•÷–••–•––•––—˜—˜‘ú’‘‘’‘’’û“’“’““ü”““””•–þ•––û—–—–——˜÷—˜—˜™˜‘‘ý’‘’’ý“’““÷”“”“””““””•ú–•––•––—õ˜——˜˜‘‘‘‘ý’‘’’þ“’’“”“”•–•–—þ–——ý˜—˜˜‘’‘’û“’“’““þ”““”ý•”••ú–•––•––ó—–——––—˜——˜˜‘’‘’ù“’’““’““”þ“””• –—˜û—˜‘ ’“ý”“””•”ý•”••–þ•––—‘þ‘‘’ø“’’“’“’““ü”““””ý•”••ù–•––••––ü—––——ü‘þ‘‘’‘’þ“’’“ü”““””þ“””û•”•”••–þ—––ú—–——þ‘’þ“’’ü“’’““”“”•þ”••–û—–——û‘ý‘‘‘’þ‘’’õ“’’“’““”“”““”ü•””••–þ•––ö‘‘‘‘’“’“”•”•ý–•––ü—ŽŽþý‘‘ ‘’“ó”“””“””••”•”••–þŽŽýý‘‘ ‘’ý“’““û”“”“””•ü–•–••–Ž‘ý‘‘‘ ’“”“”ý•”••–Žö‘‘‘‘û’‘’’““ö’““’““”““”” •€þ™šš›üœ››œœýœžþžžŸþžŸŸ ¡ýš™šš›œüžžžŸžŸ þŸ  ™÷š™š™šš›š› ›œþœžýžžžŸžŸ ñŸ  ¡  ™™š™™šš™ššú›šš›š››üœ››œœ÷œžžžžŸžŸ þŸ  ™üš™™šš›œþ›œœþœüžžžŸ þŸ  ™šù›šš›šš››œúœœœžþžžýŸžŸŸ ùŸ ™™˜˜™™üš™™šš›þš››úš››œ›œœðœœœœžžžžžžŸø ŸŸ™™˜˜™™ýš™šš›ýœ›œœúœœœžüŸžžŸŸû˜™˜˜™™ýš™ššý›š››ýœ›œœþœýžžžùŸžŸžŸžŸŸ˜™þš™™š›œ›œ žŸ˜þ™˜˜™þš™™šý›š››ûœ›œ›œœûœœžýŸžŸŸ˜™þ˜™™š›þš››œñœœœžžžžþŸžžŸõžŸ˜—˜˜—˜˜™˜˜™šý›š››üœ››œœœñžžžžŸŸžŸž——˜˜û™˜™˜™™ š›þœ››œûœœþžžöŸžžŸž——˜—˜˜™šþ™šš›š›üœ››œœúžžžž—˜þ—˜˜™þš™™š›öœ››œœœœþžžûžž–——þ˜——˜ý™˜™™ýš™ššû›š›š››œþ›œœþœžþ–——˜þ™˜˜™òš™š™šš›šš›š›š››œýœþžžþ–——ú˜——˜—˜˜þ™˜˜™š™šú›š››œ››œøžžž——–——˜™þ˜™™öš™™šš™™šš››üœ››œœþ›œœýœ÷ž––——––——˜ü—˜—˜˜™þ˜™™ýš™ššý›š››œüœœ–ý—–——ô˜—˜—˜™˜˜™˜˜™™üš™™ššü›šš››üœ››œœþ•––—þ–——ý˜—˜˜™šü™š™ššû›š›š››ýœ›œœ –—˜—˜ý™˜™™ýš™šš›þš››œýœ –—ý˜—˜˜ý™˜™™šý›š››úœ››œ›œœ–þ•––—þ–——ý˜—˜˜ý™˜™™šþ™šš›ûœ›œ›œœúœ•–•–– —ý˜—˜˜ú™˜™™˜™™šû›š›š››œýœ••ý–•––ý—–——ù˜—˜˜——˜˜™û˜™™š™™ š›üœ››œœ•–þ•––ú—–——–——ý˜—˜˜™þ˜™™þš™™šþ™šš›þš››œ•ü–••––ü—––——þ˜——˜™˜™š™šî›š››š››œ››œœ››••”••–•–—ü˜——˜˜ý™˜™™ýš™ššú›šš›š››þœ””•þ–••ý–•––—˜þ—˜˜™þ˜™™øš™š™š™š››þš››õœ›””•”••””••ü–••––ý—–——þ–——û˜—˜—˜˜ý™˜™™š™š›öœ›””•”•””••ý–•––û—–—–——ú˜—˜˜—˜˜™ûš™š™ššþ›šš›”ü•””••–•–ý—–——˜þ—˜˜ý™˜™™šþ™šš›”ü•””••–û•––•––û—–—–——ý˜—˜˜™˜™šþ™šš›”þ“””•”•–—˜—˜™ü˜™˜™™þš™™šú›“”““””ú•””•”••–—ü–—–——ý˜—˜˜þ™˜˜™˜™šü™š™šš€ úûúûúõûúúûûúûûúûúúýûúûûúûþùúúþûúúöûúúûúúûúûúúûúþûúúûúøûúûûúûúûûþúûû úþûúúüûúûúúüûúúûû÷úûúúûúûúûûúûþúûûþúûûýúùú úþûúúûýúûúúóûúûúûúûûúûúûúúûûúûûúûûþúûûþúûûúþùúúþûúúüûúûúúûúùûúûûúûúúýûúûûú ûúþûúúûþúûûõúûûúúûúûûúûûúûùúûúûûúûûúùûúûúúûúúþûúúûýúûúúüûúûúúüûúûúúûüúûûúúþùúúñûúúûúúûúúûúúûûúúüûúúûûøúûûúûûúûûûúûûúûûúþùúúüûúûúúùûúúûúúûûþúûûúûùúúùú úûúûüúûúûûûúûûúûûúüùúùúúþùú úþûúúûúûûúûúûúúûüúûûúúûþúûûúüùúùúúþùú úûûúúûúúûúúûúúûúûûúýûúûûúùúùúþùúúöûúûúúûúúûúúûúúûúúûúúûþúûûþúùùúùùúùúùúùúúþùú úþûúúû÷úûûúúûûúûûúûúùûúûúúùúúüùúùúúþùúúýûúûûúûúüûúûúúûúûúúûúúùùúúùúþùúúüûúûúúûûúúûúúöûúûúûúûúúûûýúùúúþùúúþùú úûúþûúúþûúúûúõûúúûúúûûúùúúüùúùúúþùúúþûúúøûúúûúûûúúùûúúûûúûûûúùúúùùýúùúúþùúúþûúúþûúúðûúûúûûúúûûúúûúùúúùûúùúùúúþùúúþûúúõûúûúúûûúûûúúúûúûúúûûýùúùùñúùúùúùúùùúùúúùúúþùú úûûúúûúúþûúúûúùûúûûùúùùþúùùúøùúùùúùúùùúþùú úþûúúôûúúûúúûûúúûúúýûúùùþúùùôúùúúùúùúùúùúúþùú úþûúúûýúûúúóûúúùúùúúùùúùúúþùúúþùúúþùú úüûúûú úûúýùúùùúùþúùùúþùúúþùú úþûúúûüúûûúúùúùúþùúúüùúùúúþùúúþùú úþûúúóûúûúúûúúûûúúùùýúùúúðùúùúùúúùúúùúúùùúúþùúúüûúûúúþûúúûúüûùúùùûúùúùúúùõúùùúùùúùúùúúúûúûúûúúþûúúúûúùúúùùþúùùþúùùúôùúùúúùúùùúùúúùúþûúúþûúúþûúúýûúùùúûùúùúùù÷úùúùúúùùúúþùú úþûúúûûúûûúúùüúùùúúùûúùúúùùùúùùúùùúúùúþùúúûúýûúùùúùùúúùúúùùýúùúúþùúúùúõùúùúùùúúùúùùú÷ùúùúùúúùúúüùúùúúùýúùúúöûúúûùúúùúùùþúùùúùöúùúùùúúùúùùúüùúùúúùþúùùúùþúùùúþùúúþùúúùúùüúùúùùûúùúùúúùþúùùñúùúùúùúùùúùúúùúúþùúúùòúùùúùùúùúùùúúùùú÷ùúúùúùùúùùúþùúúþùúúûùúúùúúùþúùù÷úùùúùùúúùùúùúþùúúüùúùúúþùúúþùúúþûúú€ €ÿ€žŸþžŸŸ Ÿ û¡ ¡ ¡¡ú¢¡¢¢¡¢¢£þ¤££¤œüžžžŸþžŸŸý Ÿ  ¡ü ¡ ¡¡¢¡¢ù£¢££¤£¤¤ùœœœœþžž Ÿý Ÿ  ü¡  ¡¡ý¢¡¢¢ý£¢££ù¤£¤£œœüœœžŸü ŸŸ  ¡¢¡¢ý£¢££ú¤££¤¤œœýœþž žŸý Ÿ  þŸ  ¡þ ¡¡ý¢¡¢¢£þ¢££þ›œœýœýžžžŸûžŸŸ ŸŸû Ÿ Ÿ  ü¡  ¡¡ ¢£ü¤››œœûžžžžŸþžŸŸý Ÿ  ü¡  ¡¡ý¢¡¢¢£ü¢££››œüœœžüžŸžžúŸžŸ  ŸŸ ¡þ¢¡¡¢£¢ø£œ››œœ›œœ žûŸžŸžŸŸü ŸŸ  þ¡  ý¡ ¡¡ý¢¡¢¢ü£¢£››œþ›œœýœžþžžŸþ ŸŸ ¡¢ù¡£¢¢£¢››œ›œþœžŸý Ÿ  ü¡  ¡¡¢û£¢šš››œúœœœýžžžþžžüŸžŸžžŸ ö¡ ¡ ¡ ¡¡¢¡¡¢ûš›šš››œþ›œœþœþžýžžžýŸžŸŸý Ÿ  ¡ö¢¡¡¢¢¡¢šš››ùœ›œ›œœþœžúŸžŸžžŸŸ û¡ ¡ ¡¡¢š›œ›œýœýžžžýŸžŸŸþ ŸŸ û¡ ¡ ¡¡¢š›þš››œþ›œœžŸ þŸ  ü¡  ¡¡ü¢¡¢™™šý›œ››œ›œþœžþžžþŸžžŸû Ÿ Ÿ  ¡ ú¡¢¡™™šš›œþ›œœüœœžþžžŸ þŸ  ¡þ™ššü›šš››œþ›œœþžžŸü ŸŸ  ¡þ ¡¡™ûš™š™šš ›œžžŸ ¡™þš™™ š›œ›œþœþžžŸý Ÿ  ¡ü ¡˜™™šú›š››š››œúœœžþžžûŸžŸžŸŸ ¡™šþ™ššü›šš››œþ›œœþœœžŸý Ÿ  þŸ  ø™˜™™˜™š™™ýš™šš›œöœœœœž žŸþžŸŸþ ŸŸ ú˜™™˜˜™™šþ™ššô›š›š››œœ›œ›œœþœýžžžýŸžŸŸ÷ Ÿ Ÿ  ˜™˜˜™š›þš››œûœœžþžžŸþžŸŸü Ÿ—˜˜™þš™™ýš™ššý›š››÷œ›œ›œœœýžžžŸžŸ˜ý™˜™™ýš™ššü›šš››ýœ›œœþ›œœþœûžžžžýŸžŸŸü Ÿ—˜˜ý™˜™™ýš™šš›œüœœþžžŸ—˜þ—˜˜™šþ™ššú›š››š››œþ›œœþžžŸí—˜—˜—˜˜—˜˜™˜™˜˜™™š™™šþ™šš›éœ›œ›œ›œœœœžžžžžŸ—ú˜—˜˜—˜˜™þ˜™™š›þš››œþ›œœýœýžžžŸüžŸ–——ù˜——˜——˜˜ý™˜™™ýš™šš›þš››œþœúžžžžþŸ—— ˜ý™˜™™š›üš›š››œü›œœþœûžžžžýŸ–——þ–——˜™ýš™ššý›š››þœ››œø›œœœœž–—÷˜—˜˜™˜™˜™™šõ™š™šš›šš›š››œþ›œœþœœùžžž–—––—ü˜——˜˜ü™˜˜™™š™š ›ýœ›œœþœþž––ý—–——ú˜—˜˜—˜˜ö™˜™™š™šš™ššý›š››œþ›œœýœþž€¡¢þ¡¢¢þ¡¢¢ü£¢¢££¤¥¦þ¥¦¦§ý¨§¨¨þ ¡¡¢û¡¢¢£¢¢£ý¤£¤¤¥û¦¥¦¥¦¦ý§¦§§¨§ý¨ ¡¡¢þ¡¢¢£þ¤££¤ü¥¤¤¥¥ý¦¥¦¦§þ¦§§¨þ ¡¡ ¢ü£¢£¤¤¥þ¤¥ ¥¦ü§¦¦§§þ¨  ¡¢û¡¢¢¡¢¢ý£¢££¤¥þ¤¥¥¦þ¥¦¦§ô¨§§  ¡ ¡ ¡ ¡¡¢£ü¤££¤¤¥ü¤¥¦¥¥¦þ§¦¦§þŸ  ¡þ ¡¡¢þ¡¢¢û£¢¢£¢¢£ü¤££¤¤¥þ¤¥¥¦ý§¦§§ ü¡  ¡¡þ¢¡¡¢ø£¢¢£¢£¢££¤£¤ý¥¤¥¥ü¤¥¥¦¦¥¦§þ¦§§ þŸ  þ¡  ¡ü¢¡¡¢¢£ú¤££¤£¤¤¥¤¥¦þ§¦¦Ÿ ù¡  ¡  ¡¡ ¢£ ¤¥û¦¥¦¥¦¦§üŸ Ÿ  ÷Ÿ  ¡ ¡¡ ¡¡ ¢£¤þ£¤¤ý¥¤¥¥¦þ¥¦¦Ÿú ŸŸ Ÿ  ý¡ ¡¡¢£þ¤££¤þ¥¤¤ù¥¤¤¥¥¦¥¥¦Ÿ Ÿ ¡þ¢¡¡¢£þ¢££¤þ¥¤¤ý¥¤¥¥ù¦¥¦¥¦žŸŸ þ¡  ¡ý ¢¡¡û¢¡¢¡¢¢£¢£ý¤£¤¤ú¥¤¤¥¤¥¥¦þžŸŸý Ÿ  ¡ý¢¡¢¢¡¢£û¢££¢££¤ü¥¤¤¥¥ü¦¥žŸŸ  ý¡ ¡¡¢þ¡¢¢ü£¢¢££ ¤¥¦ø¥žžŸžŸžŸŸü ŸŸ  ¡þ ¡¡ü¢¡¡¢¢ü£¢¢££¤ð£¤£¤¥¤¥¤¥¤¥¥¦¥¦žžýŸžŸŸ  ø¡ ¡  ¡¢¡¡ý¢¡¢¢þ£¢¢£¤ý¥¤¥¥žŸžŸú ŸŸ Ÿ  ¡ ¢£þ¢££¤¥žŸøžŸŸ  ŸŸ  ý¡ ¡¡ù¢¡¡¢¡¡¢¢þ£¢¢£û¤£¤£¤¤ù¥¤¥¥¤žžýŸžŸŸ ¡þ ¡¡¢ú£¢¢£¢££ý¤£¤¤¥ü¤¥žžþŸžžŸ øŸ ¡ ¡  ¡¡ü¢¡¢¡¡¢ü£¢¢££û¤£¤£¤¤žþžžýŸžŸŸó Ÿ  Ÿ ¡  ¡¡ ¡¡¢ü£¢¢££¤£¤þ¥žþžž Ÿý Ÿ  ¡þ ¡¡ ¢£¤žŸžŸý Ÿ  ¡þ ¡¡þ¢¡¡¢£ý¤£¤¤þœžþžžýŸžŸŸþ ŸŸ ¡ ¢£¤û£¤œûžžžžŸ ü¡  ¡¡¢þ¡¢¢ý£¢££ü¢££¤¤þ£þœžþžžŸû Ÿ Ÿ  ù¡  ¡¡ ¡¡¢¡¢û£¢£¢££ö¤£¤¤œœœžþžžŸûžŸŸžŸŸ üŸ ¡  ¡¢ú£¢££¢££þ¤œœýœ žýŸžŸŸý Ÿ  ¡þ ¡¡¢þ¡¢¢ü£¢¢££œüœœžôžžžŸžžŸžžŸŸþ ŸŸ ü¡  ¡¡þ¢¡¡¢£ú¢££››œœýžžžýŸžŸŸ ô¡  ¡¡¢¡¢¡¢¡¢¢›œþœýžžžŸþžŸŸ ¡û¢¡¢¡¢¢£›ýœ›œœüœœýžžžŸþžŸŸ  ¡ü¢¡¡¢¢£ú›œœ››œœþœýžžžúŸžŸžžŸŸ ü¡  ¡¡ý¢¡¢¢›œþ›œœþœœžýŸžŸŸý Ÿ   ¡¢û¡¢¢š››œþ›œœþœœžŸþžŸŸ ¡¢ý¡¢››þœ››ýœ›œœþžžŸþžŸŸ þŸ  ¡ù ¡¡¢¡¡¢¢€ûûüûûüûûþüûûþüûûüûüùûüûüüûüüþûüüþýüüûþüûûþüûûþüûûüûþüûûüþûüüúûüûüûüüþûü ü ûüûüúûüûûüûûüûüþûüüüûüûüüþýûûþüûûþüûûþüûûüüûüûûüþûüüþûü üýûúûûúüûüûüûûüúûüûûüûûüüûûüüþûüüþûü üûþúûûþüûûþüûûûüûûüûûûüûüûüüûüþûüüùûüüûüûüü ûþüûûüñûüûûüûüûûüüûüüûûüþûüüûüþûüü ûþüûûûüûûüûûüûýüûüüøûüüûûüûü üûñüûüûüüûûüûüûûüûûüüûüûüüþûüüûþúûûþüûûüðûüüûüüûüûüüûüüûü üûþúûûüûþüûûüûúüûüüûü üýûúûûþúû ûüüûüûûûüûüüûûþüûûþüûûüüûûüüýûüûûþüûûþüûûûüûüûüüóûüüûûüûûüüûûüüþúûûþúûûúûþüûûúüûûüüûûþüûûóüûûüüûûüüûüüûûüüûûüüúûüüúúûûú ûþüûûüûúüûüûüûûñüûûüüûüûüûûüüûüüýûúûûþúûûþúûûûüûûüûûþüûûüþûüüöûüûüûüüûûüüøûüûúûûúûûþúûûòüûûüûûüûüüûûüûûüüûûüüûóüûûüûüûüüûúúûûýúûúúûüûúüûûüûü üüûüüûûúûþúû ûþúû ûþüûûûüûüüûûüûóüûüûûüüûûüûüûûüúûúûûþúûûúüûüûüûû÷üûüüûüûûüüýûüûûûúûúúûûþúûûþúûûüüûüûûúüûûüûüüüûüûüü÷ûüûûüûûúûûþúûûúûþüûûþüûûäüûûüûüûüüûûüûüüúûúûúúûúûûúúûûüúûúû ûùüûüûûüûûüûøüûûüûüûüüùûüûûúúûûþúûûûúûûúûûúûþüûûüûþüûûûüûûüûûüúûöúûúûúûûúúûûþúûûþúûûûüûûüûûüüûüûûüùûüûûüüúúûûúûúû ûþúûûþúûûþúû ûüûûüûüûûüûüõúûúûúúûúûúû ûþúûûþúûûü÷ûüûüûüûüûûùúûúúûûúúüûúúûûþúûûûúûûúûûþüûûýüûüüûúûúþûúúûúûþúûûûüûûüûûüûúüûûüûúúûüúûúûû÷úûúûúúûúû ûþúûûüûþüûûþüûûüûúûþúûûúûúûþúûûüüûüûûüûúûúùûúûúûûúúûüúûúûûþúû ûûüûûüûûüûòüûûüûüûúûúûúûúúüûúûúúûþúûûúûûúûúûûþüûûúüûúúûúúýûúûûþúûûúþûúúûúûþúûûþüûûþüúúøûúûúúûúûûþúû ûúúûúûûúú ûþüûûþüûûþüûûúþûúúñûúûúúûúûûúûúûúûûþúûûþúûûþúûûþúû ûýüûúúûúýûúûûôúûúûûúúûûúúûûþúûûþüúúýûúûûýúûúúûûúûúûûþúûûþüûûþüûû€ €ÿ€ü¥¤¤¥¥ ¦§¨§¨ý©¨©©ýª©ªªý«ª««¬¤¥þ¤¥¥þ¦¥¥¦ú§¦§¦¦§§ý¨§¨¨©ªý«ª««ý¬«¤¤¥û¦¥¦¥¦¦ý§¦§§¨ü§¨§¨¨© ªý«ª««ú¬««¬£¤¤¥þ¤¥¥þ¦¥¥ý¦¥¦¦§û¨§¨¨§§¨©ªþ©ªªþ«ªª«¬ý«£¤¤¥þ¤¥¥¦þ¥¦¦ü§¦¦§§ý¨§¨¨ù©¨¨©©¨©©ûª©ª©ªª«þª««£¤þ¥¤¤¥ù¦¥¦¦¥¥¦¦ý§¦§§¨þ©¨¨©ªþ©ªª«õª«ª««¤£¤££¤¤¥¦§ý¨§¨¨ü©¨¨©©ª©ªø«ªª«ªª«££¤ú¥¤¥¥¤¥¥¦ð¥¦§¦§¦¦§§¨§¨§¨§¨¨©üª©©ªª£¤ü£¤£¤¤¥þ¦¥¥¦ü§¦¦§§¨©ªü«£¢££ý¤£¤¤ü¥¤¤¥¥þ¦¥¥¦þ§¦¦§û¨§¨§¨¨©¨©ªþ«££ü¤££¤¤¥ý¦¥¦¦ú§¦¦§¦§§ü¨§§¨¨ú©¨¨©¨©©ªú«¢¢£¢££ý¤£¤¤ý¥¤¥¥¦þ§¦¦§¨ü©¨¨©©üª©©ªª¢ü£¢¢££¤þ¥¤¤¥¦¥¦ý§¦§§þ¦§§ý¨§¨¨ú©¨©©¨©©ª¢£¤þ¥¤¤¥¦þ§¦¦§ù¨§§¨¨§¨¨þ©¨¨©ûª©ª©¢¢£þ¢££¤û£¤¤£¤¤¥¦ý§¦§§¨©þ¨©©ª¢£ü¢£¢££ü¤££¤¤¥ý¦¥¦¦§ú¦§§¨§¨¨ü©¨¨©©þ¢¡¡¢£þ¢££þ¤££¤ü¥¤¤¥¥¦ý§¦§§¨ú§¨§¨©¨¨©ù¨©¡¢¢¡¢¢ý£¢££þ¤££¤¥¤¥ú¦¥¦¦§¦¦§ü¨§§¨¨©ø¡¢¡¢¢¡¡¢¢ü£¢¢££¤¥¤ý¥¤¥¥¦§¦§¨§¨©¡û¢¡¢¡¢¢£ý¤£¤¤¥¦ü¥¦¥¦¦§þ¦§§ü¨§§¨¨ý©¨¡¡¢þ¡¢¢ù£¢¢£¢¢££¤û¥¤¥¤¥¥ý¦¥¦¦§¦§¨þ©¡¡ý¢¡¢¢ú£¢¢£¢££ý¤£¤¤¥¦û§¦§¦§§¨ý© ¡¡þ ¡¡¢£¢£ý¤£¤¤þ¥¤¤û¥¤¤¦¥¥¦ý§¦§§ü¨§§¨¨ ¡¢ £¤ý¥¤¥¥ü¦¥¥¦¦§þ¦§§þ¨§§û¨  ¡  ¡ý¢¡¢¢£ ¤¥þ¦¥¥¦ý§¦§§¨ ý¡ ¡¡¢ù¡¢£¢£¢££¤¥þ¤¥¥¦û§¦§§¦¦§ú Ÿ  ¡  ¡¢£¤ý¥¤¥¥þ¦¥¥õ¦¥¦§¦§¦§§¦§§Ÿ ¡ý¢¡¢¢ý£¢££û¤£¤£¤¤û¥¤¥¤¥¥¦÷§¦¦§§¦§§ŸŸ ý¡ ¡¡ù¢¡¡¢¢¡¢¢ý£¢££¤£ý¤£¤¤ö¥¤¥¤¥¥¦¦¥¦¦§Ÿý Ÿ   ¡ý¢¡¢¢ £¤þ£¤¤û¥¤¥¤¥¥þ¦¥¥¦û§¦§¦ŸŸ þŸ  þ¡  ¡û¢¡¢¡¢¢ý£¢££¤þ£¤¤û¥¤¥¤¥¥¦§Ÿ üŸ Ÿ  ¡¢þ¡¢¢ý£¢££¤¥¤¥¦þ¥¦¦ýŸžŸŸû ŸŸ ŸŸ ¡ú¢¡¢¡¡¢¢£þ¤££¤¥¤¥¦ýŸžŸŸô Ÿ ŸŸ  ¡ ¡ ¡¡ý¢¡¢¢ý£¢££þ¢££ý¤£¤¤¥÷¤¥¤¥¥¦¥¥¦¦žüŸžžŸŸþ ŸŸ ý¡ ¡¡ú¢¡¢¢£¢¢£ú¤£¤¤£¤¤¥ø¦¥¦žžŸžŸŸ ý¡ ¡¡¢þ¡¢¢ £¤¥û¦¥žžžŸžŸý Ÿ  ú¡  ¡ ¡¡ ¢£ý¤£¤¤ý¥¤¥¥þ¦žžŸžŸ þŸ  ý¡ ¡¡ü¢¡¡¢¢£ý¤£¤¤ý¥¤¥¥€û©¨©¨©© ª«¬­þ¬­­®þ­®®¯¨þ©¨¨©þª©©ª«û¬«¬«¬¬ý­¬­­®ü¯®®¯¯¨©þ¨©©ªþ©ªªü«ªª««¬ú­¬­­¬­­®¯¨©ü¨©¨©©ªþ©ªª«ü¬««¬¬ý­¬­­®¯þ®¯¯§¨ý©¨©©ª«þª««¬«¬­®þ­®®¯ý¨§¨¨þ§¨¨©ªü©ª©ªª«ý¬«¬¬ù­¬¬­­¬­­®ü­®­®®÷¯®®§§¨¨§¨¨û©¨©¨©©þª©©ª«þª««ú¬««¬«¬¬­þ¬­­®ú­®®¯®§§ú¨§¨¨©¨¨ý©¨©©ùª©©ªª©ªª«þª««¬þ«¬¬­®þ­®®§¨ü§¨§¨¨ý©¨©©ûª©ª©ªª«þª««¬«¬­®§ü¨§§¨¨©ü¨©¨©©ûª©ª©ªªþ«ªª«þ¬««¬ù­¬¬­­¬­­ü®­¦§§¨©÷¨©©¨©©ªª©©ª«û¬«¬«¬¬­û¬­­®­­¦§þ¦§§¨þ©¨¨©ª«ª«þ¬««¬­ü¬­¬­­þ®­­¦§þ¦§§¨ú©¨©¨¨©©ªþ«ªªý«ª««ü¬««¬¬ü­¬¬­­þ¥¦¦§þ¦§§¨þ©¨¨©ûª©ª©ªª«¬­¦ý§¦§§¨þ§¨¨©ýª©ªªû«ª«ª««ú¬««¬«¬¬­þ¬­­¦ §ý¨§¨¨©øª©©ª©ª©ªª«þª««¬«¬­þ¬¦¦ý§¦§§¨ý©¨©©ªü«ªª««¬«¬ö«¬¬­¬¬­¥¦¥¥¦§¦§¨þ§¨¨©ª©ªü«ªª««ú¬««¬«¬¬­ú¬¥¥¦¥¦¦ü¥¦¦§§¦§ó¨§¨§§¨¨©¨¨©¨©©ªü«ªª««þª««¬þ«¬¬¥ý¦¥¦¦§þ¦§§ý¨§¨¨©þ¨©©ªü«ªª««ý¬«¬¬þ«¬¬¥¦¥¦§¦§ý¨§¨¨©ýª©ªª«þª««¬¤¥¦ü¥¦¦§§þ¦§ §¨þ©¨¨©üª©©ªª«¬ú«¬¬¥¤¥¥¦þ¥¦¦ü§¦¦§§ù¦§§¨§§¨¨þ©¨¨©ªì«ªª«ª«ª««¬««¬«¥¥¤¥¤¥¥þ¦¥¥¦ú§¦§§¦§§ú¨§§¨§¨¨©ªú«ª«ªª««¤¥¤¥ý¦¥¦¦§þ¦§§ý¨§¨¨þ©¨¨©ýª©ªªü«ªª««ý¬«¤¤¥¤¥þ¤¥¥¦§þ¦§§ý¨§¨¨þ©¨¨©üª©©ªªü«ªª««ûª«££¤¤¥þ¦¥¥¦§þ¦§§ý¨§¨¨©þ¨©©üª©©ªªý«ª««ý¤£¤¤û¥¤¥¤¥¥¦ô¥¦¦¥¦¦§¦§¦¦§§¨ù©¨¨©¨¨©©þª©©ªõ«ªª««££¤££¤¤ý¥¤¥¥ù¦¥¦¦¥¥¦¦ý§¦§§÷¨§¨¨§¨¨§¨¨ü©¨¨©©ªü«ª«££¤ ¥ý¦¥¦¦ú§¦§§¦§§¨þ§¨¨©ªû©ªª©ªª£ü¤££¤¤¥¤¥þ¤¥¥¦þ¥¦¦ü§¦¦§§¨þ§¨¨ý©¨©©ªþ©ªªü¢£¤££¤ù¥¤¤¥¥¤¥¥ý¦¥¦¦ú§¦§§¦§§ô¨§§¨§§¨¨©¨¨©©ýª©ªª£ù¤£¤£¤£¤¤¥¦§þ¦§§þ¦§§¨þ©¨¨©ñª©©ª©ªª£¢¢££¤£¤¤þ¥¤¤û¥¤¥¥¦ ¦ý§¦§§¨ý©¨©©ûª©¢¢££¤ü¥¤¥¤¤¥¦¥¦§¨ý©¨©©úª©¢¢£¢¢£ý¤£¤¤þ¥¤¤ý¥¤¥¥ü¦¥¥¦¦ü§¦¦§§¨§¨û©¨©¨©©ªý¢£¢¢£ü¤££¤¤ý¥¤¥¥¦þ¥¦¦ý§¦§§¨ú©¨©©¨©©¢£þ¤££ý¤¥¤¤¥¦ü§¦¦§§ ¨û©¨©¨©€üþýüüûýüýýüüöýüýýüýüýüýýüýýüýýüýþþüüþýüüþýüüþýüüýúüýüýüýý÷üýýüýüýüýýþüýýüýýüýüüûýüüýüüþýüüøýüýüýýüýýþüýýüþýýü üýüýüýüýüýþüýýüþýýüüþýüüúýüýüüýýüüýýüüéýüýüýýüüýüýüüýýüüýüýýüý ýüþýü üûýüýýüüüýüüýýüýýþýüüûýüýýüüôýüüýüýüýýüüýýþüýýúüýüýüýýüþýüüþýüüýüýüûýüýüýýüýüý üýüõýüüýüýüüýüýýüýþüýýýüýüüýýüý ýþûüüþýüüùýüýüüýüüùýüýüýüýýñüýüýýüýüýýüýýüýýþüýýüýüóýüüýýüüýüüýüýýüýþüýýüýüüýüýüüýüøýüüýýüýüüýþüýýþüýýüþûü üþýüüþýüüýüüýüüýýûüýýüý ýüþýüüüýüüýýüüýüýýüýýüýýüûýüýüýýüýüþûüüþýüüýüýüüýüüýýûüýüûüüþýüüýüøýüüýýüüýýüýýüýüüûüþûüüþýüüóýüýüüýüýüüýüýýþüýýõüýýüýûüûüûüüðýüüýüýüüýýüüýýüýýþüýýñüýüüûûüûûüûüüûüüþûüüþýüüýýüýýþüýýõüýüüýüýýüýüüþûüüþûü üýýüýüüüýüýüüýüüýüüýýûüýüüýýýüûüüûûüüûüüýüýüüýýüüþýüüýûüýüüýýþûüüûýüûüüþûüüüýüýüüýþüýýüýöüýýüýûüüûüüþûüüþûüüþýüüùýüýüüýüüþýüüþýüüþýüüýüüýüýüüõûüûûüüûûüûüüýÝüýüüýüüýýüýýüýýüýüýüüýüýüýýüýüüûüüûûüþûüüþûüüüýüýüüýõüýýüüýýüýýüüþûüüüûüûüüýüþýüüúýüüýüýýüýüöûüüûüüûüûüüûüþûü üøýüüýýüýüüýúüýüüýüüýþüûûüøûüûûüüûüüþûüüþûü üýüûýüüýüüýüýúüýüüýûûüûýüûüüýûüûûýüûüüþýüüþýüüýüûüöûüüûüûûüüûûüþûüüþýüüý üûýüûüüüûüûüüþûü üþûüüþýüüþýüü ûûüûüûüüûüþýüüúýüýüüýýüþýüüþýüüýûüûûòüûûüûûüûüüûüûü üûüþýüüþýüüýüüûüûûþüûûþüûûüûüþûüüþûüüüýüýüüüýüüûûýüûüüùûüûûüüûû÷üûüûüûüûüüüûüûüüþýüüþýüüûýüýüûûóüûüüûüüûûüüûüüþûüüûüþûüüûýüüýüüöýüýüüýûüüûûþüûûýüûü üþûüüþýûûþüûûþüûûüóûüûüûüüûüûüüûûüþûü üþýüüþýüü€ €ÿ€¬­¬­®þ­®®û¯®¯®¯¯°±°±û²±²±²²ý³²³³ü´³´¬¬­û®­®­®®¯þ®¯¯°ý±°±±²³õ²³³²³´³´´«¬¬ú­¬¬­¬­­® ¯ °± ²³ü´³«¬¬­®þ­®®ý¯®¯¯ý°¯°°ý±°±±²þ±²²þ³²²³þ¬««ý¬«¬¬­þ¬­­ú®­®®­®®ü¯®®¯¯°±°±²ù³²³²³³¬¬«¬ý­¬­­ü®­­®®¯þ°¯¯°±²³«¬þ«¬¬­¬­®þ­®®¯ý°¯°° ±²þ±²²û³²²ª««¬þ«¬¬ý­¬­­®ý¯®¯¯ý°¯°°ü±°°±±ý²±²²³ú²ªª««¬¬þ«¬¬­ü¬­­®®þ­®®¯ý°¯°°±þ²±±²üª«ª««¬þ«¬¬ü­¬¬­­þ®­­®¯þ®¯¯°þ¯°°±²ªý«ª««ú¬«¬««¬¬­¬­®þ­®®¯°±°±ø²±²²±±²ªª«¬þ«¬¬­®ü­®­®®û¯®¯®¯¯ý°¯°°þ¯°°þ±°°±ªý«ª««¬«¬ý­¬­­û®­®­®®¯þ®¯¯°ý±°±±þ°±±ý²±ªªþ«ªª« ¬­®þ­®®¯þ®¯¯°þ±°°±ûª©ª©ªªü«ª«¬¬ý­¬­­ü®­­®®¯°þ¯°°ý±°±±ü²±©ªªþ©ªª«þ¬««¬­®þ­®®þ¯®®¯°±þ°±±©ªü«ªª««¬ü­¬¬­­ü®­­®®ò¯®¯®®¯¯°¯¯°¯¯°°ü±°±©©ª«÷ª««¬««¬«¬¬­û¬­­®­­®û¯®¯®¯¯ü°¯¯°°ù±°°±©¨©©ªú«ªª«ª««ý¬«¬¬ú­¬­­¬­­®¯®¯ý°¯°°©ø¨ª©©ª©©ªªû«ª«ª««¬ü«¬«¬¬ý­¬­­ý®­®®¯ù°¯¯°°¯°°û±©©¨©©ªþ«ªªú«ªª«¬««¬­ ®ü¯®®¯¯°û©¨©¨©©ªø«ª««ª«ª««¬û­¬­¬­­ ®¯û°¯°°¨¨ý©¨©©ûª©ª©ªª«ª«þ¬««ý¬«¬¬­®ø¯®¯®®¯®¯¯û°¯°°¨¨ý©¨©©ªþ©ªª«ª«ý¬«¬¬ú­¬­­¬­­ü®­­®®ü¯®®¯¯¨©þ¨©©üª©©ªªù©ªª«ªª«« ¬­û®­®­®®¯ý®¯®®¯°¨©þ¨©©øª©ªª©ªª««þª««¬«¬þ­¬¬­ü®­­®®¯þ®¯¯ý°§¨¨ ©ª«¬­þ¬­­þ®­­ý®­®®ý¯®¯¯ö§¨¨§§¨¨©¨©©ýª©ªª«ý¬«¬¬­þ®­­®¯®÷¯®§¨§¨§§¨¨ý©¨©©ýª©ªª«ª«þ¬««¬ø­¬¬­¬­®­­®¯§¨ü§¨§¨¨ü©¨¨©©ª«þª««¬ú«¬­¬¬­ ­®¯þ®§§ý¨§¨¨©û¨©¨¨©©úª©ªª©ªªý«ª««ý¬«¬¬­®þ­®®ý§¦§§ü¨§§¨¨ý©¨©©ûª©ª©ªªõ«ª««¬««¬¬«¬¬­þ¬­­ü®­­®®¦§õ¨§¨¨§§¨¨©©¨¨©ýª©ªª«û¬«¬«¬¬­þ¬­­ý®­®®ü­®®¦¦§¨þ©¨¨©ªú«ªª«ª««ù¬««¬¬­¬¬­÷®­®®­¦¦§¦¦§¨û©¨©¨©©üª©©ªªú«ª«ªª««¬þ«¬¬­þ¬­­®¦ü§¦¦§§¨©û¨©©¨©©ª«þª««¬þ«¬¬þ­¬¬­ü®¦¥¦¦§þ¦§§¨§¨ ©ª«þª««ý¬«¬¬ý­¬­­¦ú¥¦¥¦§¦¦§ý¨§¨¨þ©¨¨©ª©ª«þª««ü¬««¬¬­þ¬­­€û°¯°¯°°±ú°±°±°±±²þ±²²ý³²³³´ü³´³´´ýµ´µµþ¶µµ¶·¶¯°±²þ³²²³þ²³³ø´³´´³´´µµþ´µµú¶µµ¶µ¶¶÷·¯°°¯°°¯°°ý±°±±²þ³²²³ý´³´´üµ´´µµ¶¯°±° ±ý²±²²³²³´³´µ¶ý¯®¯¯°þ¯°°ý±°±±ý²±²²ù³²³²³²³³´ûµ´µ´µµù¶µ¶¶¯®¯¯°þ±°°±þ²±±²û³²³²³³ý´³´´úµ´´µ´µµ¶üµ¶®¯¯ü°¯¯°°±ú²±²²±²²³²³ù´³´³´³´´µù¶µ¶¶µµ®®ù¯®¯¯°¯°°þ¯°°±²³þ²³³þ´³³´µ¶ùµ®®¯®®¯¯°þ¯°°ý±°±±ñ²±²²±²³²²³²³³²³³ý´³´´ýµ´µµþ­®®¯°÷¯°°±°±°°±± ²ý³²³³ü´³³´´ûµ´µ´µµ®û¯®¯®¯¯°þ¯°°þ±°°±ý²±²²þ³²²³ü´³³´´µû´µ­­®®¯þ®¯¯ü°¯¯°°±²þ±²²³÷²³³´³³´³´´öµ´´µµ®­®­®®¯þ®¯¯ý°¯°°þ¯°°þ±°°±ü²±±²²ü³²²³³´µø´µ­­®®­®®¯°±þ°±±²³þ²³³û´³´³´´ûµ´­­®®þ­®®ý¯®¯¯°±°±²ù³²²³³²³³û´³´³´´­ ®û¯®¯®¯¯û°¯°¯°°ý±°±±ü²±±²²ý³²³³´þ³´´­®¯°þ¯°°ý±°±±²ý³²³³ý´³´´ ­®¯þ®¯¯ú°¯¯°¯°°±°±²þ±²²³þ²³³´þ¬­­®­®þ¯®®¯þ°¯¯°ú±°±°°±±²þ±²²³þ²³³´ý­¬­­ø¬­­®®­­®®ý¯®¯¯° ±²³¬­û®­®­®®¯ü®¯®¯¯°±°ý±°±±²³²³¬­þ¬­­®­®¯ü®¯®¯¯ü°¯¯°°±þ°±±ý²±²²õ³²²³²²³³««¬¬ý­¬­­ù®­­®®¯®®¯ý°¯°°±ý²±²²ú±²³²³²²û³¬««¬¬­ý®­®®¯ù®¯¯°¯¯°°ý±°±±²þ±²²ü³²²³³û«¬««¬¬­ ®¯ù°¯¯°¯¯°°±²ú³²³³«¬¬þ«¬¬ú­¬­­¬­­ý®­®®¯®¯þ°¯¯° ±ü²±±²²«¬ý­¬­­þ¬­­ ®¯°ü¯°¯°°ý±°±±²«ü¬«¬««¬­ù®­®®­­®®¯°þ¯°°ý±°±±þ°±±²«¬þ«¬¬ ­®¯þ®¯¯ °±þ²±±ú²±²ªª««ú¬«¬««¬¬ý­¬­­þ®­­®¯þ®¯¯°þ¯°°±²ª«¬ü«¬¬­ ­®ý¯®¯¯ °±ù²±±²ªª««¬þ«¬¬­þ¬­­ü®­­®®¯õ®¯¯°°¯°¯°¯°°ü±°°±±ªý«ª««ü¬««¬¬­ò¬­­¬­­®­­®­®­®®ú¯®¯®®¯¯°ú±°°±°±±þ²ªª«þª««þ¬««¬ù­¬­¬­¬­­ü®­­®®ý¯®¯¯ý°¯°°±°ý±°±±þ©ªªú«ªª«ª««û¬«¬«¬¬­ý®­®®¯û°¯°¯°°±ýª©ªªü«ªª««¬ù­¬­¬­¬­­®¯°þ±°°û±©ª©ªªý«ª«« ¬­ý®­®®ü¯®®¯¯°þ¯°°þ©ªªþ©ªª«þª««¬ý­¬­­®¯ù®¯¯°¯¯°°€ýþýþñýþþýþþýþþýþþýýþþøýþþýþþýþþüýþýþþÿþúÿþþÿþýýþþýýþýþûýþýýþþýüþýýþþþýþþþýþ þþÿþþþÿþþùÿþÿþýþý ýþýþýýþýþþþýþþüýþýþþþÿþþùÿþþÿþÿýýþþýýüþýþýýþøýþýýþýýþþûýþþýþþþýþþþýþþþÿþþüÿþÿýýùþýýþýþýýþýýþýýüþýýþþýüþýýþþüýþýþþþÿý ýþþýýúþýýþýþþþýþþþÿþþÿþþýýþüýþýþþýýþýýúþýýþþýýüþýýþþþÿþþýýþýýþþýýþþýýóþýýþþýýþýþþýþþþýþþûýþþýþþýþþýýüþýþýýþýõþýýþýþþýþýþþþýþþ ýþþýýþýþýþýýþýþþþýþþþýþþþýþþýþþýýþþýýþþýýþûýþþýþþýþþýþþþýþþþüýýþýþþýýþýþþýþþùýþýþþýþþþýþ þ ýþýþþýýþþýýõþýþþýþþýþýþþûýþþýþþþýþþþýþþýûþýþþýýþýöþýþþýþýþýþþýþþýýþýóþýýþþýþþýþþýþþýþþýþþûýüýüýýúþýþýýþþöýþþýþýþþýþþýýþýýþüýþýþþýýüýýþþýýþýúþýþþýþþüýþýþþýýþýþþþýþþýþüýýþüýýþþýýþþýýþýýþýþþýþþýþþþýþþýýüýýþüýýþüýýþýýþýýþþýýþýþýþüýþýþþþýþþýþüý ýþþýýþþýýüþýýþþýüþýþýýþýþýþþýþþ ýþüýýùþýýþýþýýûþýýþýýþýþýþþýþþýþüýýþüýýüþýþýýùþýþþýýþþþýþþúýüüýüýýþüýýéþýýþþýþýþýþýþýýþþýþþýýþþúýþýþþýýþüýýôþýýþþýþþýþþýýþýþþýþþôýþýþþýýüýüüýýþüýýüüýüýýþþýýþþýýþþýýúþýþýýþþîýþýþýþýþýþýýüüýýüýýþüýýþýûþýþþýýþþýý÷þýþýýþüüýýüýþþýýüþýýþþýþýýüýýøüýüüýýüýýþüýýþþýýþþýýþôýþýýþýþýþþýþþýúþüýüüýýýüýüüýþüýýþüýýþþýýþþýýóþýþþýýþýþþýýþþúýþýþüýýüùýüýüýüýýþüýýðþýþýýþýþýýþýýþýþþüýþýüüûýüýýüüýüýýüýýþþýýþþýýýþýþþùýþýüýýüüþýüüýþüýýþüýýþüýýüþýþýýþýþýûþýýüýýûüýüýüüýþþý ýþýýþýýüöýüýýüýýüüýýüýûüýýüýýþþýýþýóþýýþýþþýþýýþýýþþýýøþýüýýüýüüýþüýýþüýýüþýþýýöþýþýþþýþýüüùýüüýüýüüýýüýýüýýüý ýüüýüý ýðþýþýýþýýþþýþüýüýýü÷ýüüýüýüüýýü ýþüý ýþþý ýüþýýüüùýüüýýüýýùüýüýüüýýþüýýüýþþýýúþýþýþý€ €ÿ€´µþ´µµ¶û·¶·¶··¸ü¹¸¸¹¹ý¸¹¸¸þ¹¸¸ý¹¸¹¹ý´³´´þµ´´µ¶·ü¸··¸¸¹ý¸¹¸¸¹¸¹¸ú¹¸¹¸¸´´µû¶µ¶µ¶¶·þ¶··ü¸··¸¸ý¹¸¹¹þ¸¹¹¸¹û¸¹¹¸´´þ³´´µþ´µµü¶µµ¶¶ý·¶··ý¸·¸¸ü¹¸¸¹¹¸þ¹¸¸ù¹¸¸¹¸¸¹¹³´þ³´´þµ´´µ ¶ý·¶··ý¸·¸¸¹ý¸¹¸¸ý¹¸¹¹ð¸¹¹¸¸¹¹²´³´³³´³´´ýµ´µµþ¶µµ¶þµ¶¶·þ¶··ý¸·¸¸ü¹¸¸¹¹¸¹þ¸¹¹þ²³³´üµ´´µµ¶ü·¶¶··ò¸·¸·¸¸¹¸¸¹¸¹¸¹¹¸þ¹¸¸¹ý³²³³ý´³´´µ¶þµ¶¶·þ¸··¸¹þ¸¹¹¸ü¹¸²³³ü´³³´´üµ´´µµ¶þµ¶¶û·¶·¶··¸û¹¸¹¹¸¸¹¸ö¹¸¹²³²³³²³³ø´³³´³´´µµþ´µµ¶ü·¶¶··¸ü¹¸¸¹¹ü¸¹¹²²ú³²²³´³³´µ¶·¸þ·¸¸¹¸¹þ¸²²û³²²³´´ü³´³´´ùµ´´µµ´µµý¶µ¶¶ûµ¶··¶¶·ü¸··¸¸ü¹¸¹¸¸¹þ¸¹¹²³ý´³´´ýµ´µµ¶ý·¶··ü¸··¸¸ú¹¸¹¹¸¹¹þ±²²þ³²²³´³´ýµ´µµ¶µ¶·ý¸·¸¸ý¹¸¹¹ú¸²±²±²² ³´µþ´µµü¶µµ¶¶ü·¶¶··¸¹¸þ¹±±²³þ²³³´úµ´´µ´µµý¶µ¶¶ý·¶··ü¶··¸¸¹þ¸±±²ý³²³³´µ¶µ¶·¶ý·¶··ü¸··¸¸þ·¸¸ü¹¸¹±±²þ±²² ³ý´³´´µý¶µ¶¶·¸·ý¸·¸¸ý±°±±²ú±²³²²³³´þ³´´ýµ´µµý¶µ¶¶·¶·ý¸·¸¸þ°±±²þ±²²ý³²³³´þ³´´üµ´´µµ¶ý·¶··ü¸··¸¸°±þ°±±ý²±²²³ü´³³´´ µ¶·¶·¸°û±°±°±±²þ±²²ý³²³³´µ÷´µµ¶¶µ¶µ¶¶þ·¶¶·ú¸·°°±°°ý±°±±²þ±²²ú³²³³²³³´µþ´µµý¶µ¶¶ý·¶··¸þ¯°°ü±°°±±û²±²±²²³þ²³³´ú³´´µ´µµ¶ó·¶¶·¶¸··°°¯¯°°±þ°±±²ý³²³³´þ³´´ýµ´µµ¶þµ¶¶·ü¸·°¯¯° ±²³´þ³´´ýµ´µµý¶µ¶¶û·¶·¶··¯ü°¯¯°°±ú²±²±±²²ú³²²³´³³ü´³³´´ýµ´µµ¶þµ¶¶·¶·¯°ý±°±±ý²±²²ú³²³²²³³´µþ´µµö¶µµ¶¶··¶·¯¯þ°¯¯ý°±°°±²³ú´³´´³´´ýµ´µµþ¶µµ¶ý·¶¯¯°þ¯°°±þ°±±²ü±²±²² ³´µþ´µµ¶þµ¶¶û·¶®®¯¯°þ±°°±²þ±²²ü³²²³³û´³´³´´µ¶ù·®¯®¯®¯¯°þ¯°°ü±°°±±²þ±²²ý³²³³´þ³´´µþ´µµ¶µ¶û®¯¯®¯¯ý°¯°°±ù°±²±²±²²³ü²³²³³ú´³³´µ´´µú¶µµ¶¶®®¯°ü±°°±±²ü³²²³³þ´³³´µþ¶®®ý¯®¯¯ü°¯¯°°±°±²ø±²²³²³²³³´þµ´´µü¶µ¶®®¯ô°¯°¯°°±±°±°±±²³ ´ýµ´µµû¶®®­®®¯®¯°ü¯°¯°°±ü²±±²²ý³²³³ð´³´³³´´µ´´µµ´µµ­­®¯þ®¯¯ °±ý²±²²ý³²³³ý´³´´µ€¶·þ¸··ý¸·¸¸¹ºû¹ºº»ººý»º»»ü¼»¼»»þ¼»»·þ¶··û¸·¸·¸¸ü¹¸¹¸¸¹þº¹¹ºý»º»»þ¼»»ý¼¶··þ¸··¸þ¹¸¸¹úº¹¹º¹ºº»þ¼»»þ¼»»ü¼»¼»»¶·ý¶·¸¸û·¸¸·¸¸û¹¸¹¸¹¹þº¹¹ýº¹ºº»¶·û¶··¶··¸þ·¸¸ ¹º»þ¼»»þ¼»»þ¼»»¶·þ¶··¸þ·¸¸¹ºü»ºº»»þ¼»»þ¼»»þµ¶¶·ø¸·¸·¸¸·¸¸¹úº¹ºº¹ººý»º»»þ¼» »¶þµ¶¶ý·¶··ù¶··¸··¸¸¹¸¹ºø»ºº»»¼¼»»þ¼»»ø¼»¼µ¶¶µ¶¶·ø¶··¸·¸·¸¸¹ºý»º»»ûº»»¼»»þ¼»»þµ¶¶·ü¶·¶··¸þ¹¸¸¹üº¹¹ºº»º»ü¼»¼»»¼ù»¼»¼µ¶µµ¶·ý¸·¸¸ý¹¸¹¹ºþ¹ººý»º»»¼»ü¼»¼µµ¶þµ¶¶·ý¸·¸¸þ·¸¸¹úº¹ºº¹ººý»º»»¼»¼µ¶þµ¶¶þ·¶¶·ý¸·¸¸¹ûº¹º¹ººü»ºº»»þ¼»»þ´µµ¶µ¶·ü¸··¸¸ü¹¸¸¹¹ºþ¹ººü»ºº»»´µ¶þµ¶¶·þ¶··¸¹þ¸¹¹º»þº»»ú´µ´µ´µµþ¶µµ¶þ·¶¶·ý¸·¸¸¹õº¹¹º¹¹ºº»»ºº»´úµ´µµ´µµ¶üµ¶µ¶¶ü·¶¶··þ¸··¸¹þ¸¹ ¹º»´µ¶óµ¶¶µµ¶¶·¶¶·¶··¸þ·¸¸¹þ¸¹¹ ºû»º»»´´µû¶µ¶µ¶¶ý·¶··¸ü·¸·¸¸¹þ¸¹¹ïº¹º¹¹º¹ºº»º»º»»³´´ýµ´µµ¶þ·¶¶·ú¸··¸·¸¸ý¹¸¹¹º»ùº»³´³³´´üµ´´µµ¶µ¶ý·¶··þ¸··¸þ¹¸¸¹º¹ºû³´³³´´µþ¶µµ¶·þ¶·· ¸¹þ¸¹¹ýº¹ººþ»³³´þ³´´µþ´µµ¶ý·¶··ý¸·¸¸ù¹¸¹¸¹¹ºº÷¹ºº¹ºº»²³³´³ú´µ´µ´µµþ¶µµ¶û·¶·¶··ý¸·¸¸¹þ¸¹¹øº¹¹º¹ºº³³´øµ´µµ´µ´µµ¶µ¶·þ¶··¸þ·¸¸ú¹¸¹¹¸¹¹º²³ý´³´´þ³´´µþ´µµú¶µµ¶µ¶¶·ù¶·¶·¸·¸¸ú¹¸¹¸¸¹¹þº¹¹²ü³²²³³ ´µ¶þµ¶¶ý·¶··ú¸·¸··¸¸¹þ¸¹¹þº²²³û´³´³´´ýµ´µµ¶µ¶·ú¶··¸·¸ ¸¹þº²²ý³²³³ü´³³´´µô´µµ´µµ¶µµ¶µ¶¶ý·¶··þ¶··ý¸·¸¸¹²þ³²²³ø²³´³³´³´´úµ´´µ´µµ¶·þ¶··¸·¸ý¹¸¹¹þ±²²³þ²³³þ²³³ý´³´´øµ´´µ´µ¶µµ¶ò·¶·¶·¶··¸·¸¸·¸¸¹²þ±²²³þ²³³´þ³´´ùµ´´µµ´µµú¶µµ¶µ¶¶ý·¶··þ¸··¸¹¸²þ±²²³þ´³³´ýµ´µµ¶þµ¶¶·ü¸··¸¸û¹¸¸±²²ý³²³³´üµ´´µµþ´µµü¶µµ¶¶þ·¶¶ ·¸û·¸¹¸±±ý²±²²þ³²²³ö´³³´´µ´µ´µµþ¶µµø¶·¶··¶¶··¸ü·¸¸±±²þ±²²þ³²²³ ´µ¶þµ¶¶·¶·ý¸·¸¸±û°±²±² ²³ú´³´´³´´úµ´µµ´µµ ¶ý·¶··¸° ±²ü³²²³³´þ³´´ýµ´µµ¶þµ¶¶ü·¶¶··ü¸·¸·€ñÿþþÿÿþÿþþÿþÿÿþÿÿþþÿ)ÿóþÿþþÿþÿÿþÿþÿþþÿüþÿþÿÿþ"ÿþÿþþÿÿüþÿþÿÿûþÿÿþÿÿþ%ÿ÷þÿÿþÿþÿÿþþüÿþÿþþÿþÿöþÿÿþÿþþÿþÿÿþÿþÿýþÿþþþÿþþÿþþÿÿþÿþþÿÿüþÿÿþþÿúþÿþÿÿþþÿüþÿþÿÿþÿþøÿþþÿÿþþÿÿþÿþþÿÿôþÿþÿÿþÿÿþÿþÿÿþþÿþþüÿþÿþþÿþýÿþÿÿüþÿþÿÿþÿþþÿÿþþÿÿþþÿþþþÿþþþÿþþÿýþÿþþÿþþÿÿþþÿÿûþÿþþÿÿþðÿþþÿþÿÿþÿþþÿþÿþÿÿþöÿþÿÿþþÿÿþÿÿþþÿÿþþÿ ÿþþÿþþÿþþÿþþýÿþÿÿþùÿþþÿÿþÿÿþþÿÿ þüÿþÿþþÿôþÿþÿþþÿþÿþþÿÿþþÿÿþþÿþþóÿþÿþÿþÿþÿþþÿþþúÿþÿþþÿÿþûÿþþÿþþÿþþÿþþÿþþÿÿûþÿÿþÿÿþþÿ ÿþÿþÿþÿøþÿÿþÿþþÿÿúþÿÿþþÿÿþþÿ ÿþþÿþþÿþÿþúÿþþÿÿþþÿûþÿÿþÿÿþÿüþÿþÿ ÿþþÿþþþÿþþõÿþþÿÿþÿÿþÿþþÿúþÿþÿþÿÿþþÿÿþýÿþÿÿþþÿÿþýþþþÿþþòÿþþÿÿþÿÿþþÿþþÿÿþÿüþÿþÿÿþþÿ ÿýþýþþþÿþþÿôþÿþÿþþÿþÿþþÿÿ÷þÿÿþþÿþþÿÿûþÿþþÿ ÿ þþÿþþÿøþÿþþÿþþÿÿþìÿþþÿþþÿþþÿþþÿþþÿÿþþÿÿþþÿÿþýþþþýþ þôÿþþÿÿþþÿþÿþÿÿûþÿþÿþþôÿþþÿÿþþÿþÿþÿÿþþýþþþÿþþþÿþþþÿþþûÿþÿþÿÿþÿþþÿÿþþÿÿûþÿÿþÿÿþþýþþþÿþþÿýþÿþþþÿþþýÿþÿÿúþÿþÿþÿÿûþÿÿýþþÿþöÿþþÿþÿþÿþÿÿûþÿÿþÿÿþùÿþÿÿþþÿÿüþýýþþþÿþþÿþÿþïÿþÿþÿþÿþþÿþþÿÿþþÿÿþøýþþýþýýþþýþøÿþþÿþÿÿþþþÿþþÿþþÿþþûÿþÿþÿÿûþÿÿýþþþýþþþÿþþþÿþþõÿþÿþþÿþÿÿþÿÿþýþþýþþýþ þþÿþþþÿþþûÿþþÿþþÿþþÿÿýþýþþþýþ þþýþ þþÿþþþÿþþÿþþÿþþÿþÿ÷þÿþþýþýýþþýþþýþþþýþ þþÿþþùÿþþÿþþÿÿþøÿþÿÿþÿþÿÿþùÿþÿÿþÿþþþýþþþýþþþÿþþÿþþÿþþýÿþÿÿþÿþþÿÿþþýýûþýþýþþþýþþøÿþþÿþþÿþþýÿþÿÿþûÿþþÿþþøýþýýþþýþþþÿþþþÿþþÿûþÿþþÿÿþùÿþÿþÿÿþþûýþþýþþûýþþýþ þÿþÿþúÿþþÿÿþþýÿþÿÿþúÿýþþýþþþýþþûÿþþÿþþÿþÿýþÿþþøÿþÿþýþýþþþýþþýþþýþþþýþþÿêþÿþþÿþþÿþÿþÿÿþýþþýþýýþþýþþýþþþýþ þþÿþþÿþÿöþÿÿþÿþþýþýýþþýýþýþøýþþýýþýþþþýþþÿþÿúþÿþþÿþþ€ €ÿ€¹¸¹û¸¹¹¸¹¹ú¸¹¹¸¹¸¸¹ú¸¹¸¹¹¸¸ý¹¸¹¹¸û¹¸¹¹¸¸ü¹¸¸¹¹¸¹þ¸¹¹¸ ¹¸¹¸¹þ¸¹¹þ¸¹¹þ¸¹¹¸û¹¸¹¸¹¹¸÷¹¸¹¸¹¸¹¸¹¹÷¸¹¸¹¹¸¹¸õ¹¸¸¹¹¸¹¹¸¸¹¹þ¸¹¹¸ü¹¸¸¹¹û¸¹¸¸¹¹¸¹û¸¹¹¸ ú¹¸¸¹¹¸¸¹¸¹û¸¹¸¸¹¹þ¸¹¹¸ü¹¸¹¸¸¹ü¸¹¸ ¹¸¹¸ý¹¸¹¹ý¸¹¸¸ý¹¸¹¹¸ú¹¸¹¸¹¸¸¹¸þ¹¸¸¹¸¹ý¹¸¹¹¸þ¹¸¸¹þ¸¹¹ý¸¹¸¸¹ü¸¹¹¸¸ö¹¸¹¸¹¸¸¹¸¹¹ü¸¹¸¸¹þ¸¹¹þ¸¹¹ü¸¹¸¹¹¸ë¹¸¹¸¸¹¸¹¹¸¸¹¸¸¹¹¸¸¹¸¹¹û¸¹¸¸¹¹¸þ¹𸹹¸¸¹¸¹¸¹¸¸¹¹¸¹¹¸¹¸¹ü¸¹¹¸¸þ¹¸¸¹¸¹¸ù¹¸¹¸¸¹¸¸¹ý¸¹ý¹¸¹¹õ¸¹¹¸¸¹¸¹¸¹¸¸ý¹¸¹¹¸¹¸¹ý¸¹¸¸ý¹¸¹¹þ¸¹¹þ¸¹¹¸¹û¹¸¹¸¹¹ù¸¹¸¸¹¸¹¹¸õ¹¸¹¹¸¹¹¸¸¹¸¸ö¹¸¸¹¸¹¸¸¹¸¸¹õ¸¹¹¸¸¹¹¸¹¸¹¹ö¸¹¹¸¹¸¸¹¸¸ö¹¸¸¹¹¸¹¹¸¹¹¸¹þ¸¹¹¸¹¸ø¹¸¹¸¸¹¹¸¸¹ñ¸¹¸¸¹¸¹¹¸¸¹¹¸¸¹¹¸¹þ¸¹¹þ¸¹¹¸¹¸ý¹¸¹¹õ¸¹¹¸¹¸¸¹¹¸¹¹¸¹¸¹û¸¹¹¸¹¹þ¸¹¹÷¸¹¸¹¹¸¸¹¸¸¹ü¸¹¹¸¸û¹¸¸¹¸¸ø¹¸¸¹¸¹¸¹¹ü¸¹¸¹¹¸ô¹¸¹¹¸¹¸¹¹¸¸¹¹õ¸¹¸¸¹¹¸¸¹¸¹¹¸¹þ¸¹¹¸¹ü¸¹¹¸¸ø¹¸¹¸¹¸¸¹¹¸¹þ¸¹¹¸¹ü¸¹¸¹¹þ¸¹¹¸ý¹¸¹¹ð¸¹¸¸¹¹¸¸¹¹¸¹¸¹¸¹¹þ¸¹¹ú¸¹¸¹¸¹¹ü¸¹¸¹¹ü¸¹¸¹¹ü¸¹¸¹¹¸¹¸ý¹¸¹¹ø¸¹¹¸¹¸¸¹¹ù¸¹¸¸¹¸¹¹þ¸¹¹¸¹¸û¹¸¹¸¹¹¸¹¸¹þ¸¹¹ñ¸¹¹¸¸¹¹¸¸¹¹¸¸¹¸¸¹¸ý¹¸¹¹¸ü¹¸¸¹¹þ¸¹¹¸¹ý¸¹¸¸û¹¸¹¹¸¸û¹¸¹¹¸¸ú¹¸¹¹¸¹¹ù¸¹¸¹¹¸¹¹þ¸¹¹¸¹¸¹þ¸¹¹¸¹û¸¹¸¸¹¹ù¸¹¸¹¹¸¹¹ü¸¹¹¸¸¹¸ö¹¸¹¸¸¹¸¹¹¸¸¹¸¹¸þ¹¸¸¹þ¸¹¹ý¸¹¸¸¹¸¹¸û¹¸¹¸¹¹¸¹¸ú¹¸¹¸¹¸¸¹¸ù¹¸¸¹¸¸¹¹þ¸¹¹þ¸¹¹¸ý¹¸¹¹¸ö¹¸¸¹¸¹¸¹¸¹¹ý¸¹¸¸ü¹¸¹¸¸ú¹¸¸¹¸¹¹þ¸¹¹ñ¸¹¸¸¹¸¹¹¸¹¸¹¸¸¹¹ú¸¹¹¸¹¸¸¹¸þ¹¸¸¹¸·¸¹þ¸¹¹¸¹ü¸¹¸¹¹û¸¹¹¸¹¹¸¹¸¹¸¹¸û¹¸¸·¸¸¹ñ¸¹¸¹¹¸¹¸¸¹¹¸¹¸¹¹ø¸¹¸¸¹¸¸¹¹¸þ¹¸¸þ¹¸¸¹ú¸¹¸¹¸¹¹·ý¸·¸¸û¹¸¹¸¹¹¸¹ö¸¹¹¸¹¸¸¹¹¸¸¹þ¸¹¹¸¹ù¸¹¸¸¹¹¸¸ü¹¸¹··¸¹¸¹þ¸¹¹¸ù¹¸¸¹¹¸¹¹¸ù¹¸¹¹¸¹¸¸þ¹¸¸¹¸¹þ¶··¸ê·¸¸·¸¸¹¸¹¹¸¸¹¸¹¹¸¹¹¸¸¹¹ù¸¹¹¸¹¸¹¹þ¸¹¹ý¸¹¸¸¹þ¸¹¹¸¶·ý¸·¸¸¹ù¸¹¸¸¹¸¹¹¸¹þ¸¹¹ü¸¹¸¹¹û¸¹¹¸¹¹¸¹ý¸¶··¸þ·¸¸þ¹¸¸¹û¸¹¸¸¹¹þ¸¹¹¸¹¸¹ý¸¹¸¸ø¹¸¹¸¹¸¹¸¸¶·ü¶··¸¸þ·¸¸ý¹¸¹¹þ¸¹¹þ¸¹¹ù¸¹¹¸¹¸¹¹þ¸¹¹¸¹ü¸¹¹¶¶·ú¸·¸¸·¸¸þ¹¸¸¹ú¸¹¹¸¸¹¹ò¸¹¹¸¹¹¸¹¸¸¹¹¸¹¹¸ö¹¸¸¹¸¸¹¹¸¶¶·¸¹ö¸¹¹¸¹¸¹¹¸¹¹þ¸¹¹þ¸¹¹þ¸¹¹¸¹þ¸¹¹ü¸µµ¶¶ü·¶¶·· ¸¹þ¸¹¹ú¸¹¸¹¹¸¸¹þ¸¹¹ö¸¹¸¸¹¸¹¸¹¸¸¶þµ¶¶·þ¶··¸ý¹¸¹¹ú¸¹¹¸¹¸¸¹ü¸¹¹¸¸ü¹¸¸¹¹þ¸¹¹¸ûµ¶¶µ¶¶þ·¶¶·¸þ·¸¸ó¹¸¹¸¹¹¸¹¸¸¹¹¸¸¹ü¸¹¸¹¹ý¸¹¸¸¹ö¸¹¸¹µµ¶µµ¶¶þ·¶¶·¸¹ë¸¹¸¹¸¹¹¸¹¹¸¹¸¹¸¹¸¹¸¹¸¸¹þ¸¹¹ù´µ¶µ¶µ¶¶ý·¶··¸ü¹¸¸¹¹¸ý¹¸¹¹ö¸¹¹¸¸¹¸¸¹¸¸¹¸€û»¼»¼»»þ¼» »þ¼»»»þ¼»»û¼»»¼»»¼ý»¼»»þ¼» » »þ¼»»þ¼»»þ¼»»þ¼» »þ¼»»ü¼»¼»þ¼»»þ¼»»¼»¼»þ¼» »ü¼»¼ þ¼»»ù¼»»¼»¼»»¼ý»¼»»þ¼»»¼» »þ¼»»¼û»¼»¼»»þ¼»»»þ¼»»þ¼»»¼»þ¼»»þ¼»»þ¼» »þ¼ú»¼»»¼»»ü¼»¼»»þ¼»»ù¼»¼»»¼»»þ¼»»ü¼»»»û¼»»¼»»þ¼»»þ¼»»þ¼»»þ¼»»¼»þ¼» »»þ¼» »ù¼»¼»»¼»»þ¼»»û¼»»¼»»þ¼» »þ¼ »þ¼»»¼»þ¼»»ù¼»¼¼»¼»»÷»¼»»¼»¼»»þ¼»»þ¼» »þ¼»»ü¼»¼»»¼»þ¼»»þ¼»$»þ¼»»þ¼»»¼»þ¼»»ü¼»¼» »û¼»»¼»»û¼»»¼» »ø¼»»¼¼»¼»»ü¼»¼» »þ¼»»þ¼»»þ¼»»þ¼» »¼ »¼»û¼»»¼»»þ¼»»þ¼»»û¼»»¼»»þ¼»»þ¼»»ü¼»¼»»ü¼»¼»»¼»þ¼»»þ¼»»þ¼»»þ¼»»ü¼»¼»»þ¼»»þ¼»»þ¼»»þ¼» »þ¼»»÷¼»¼»¼»»¼»»þ¼»»¼»þ¼»»þ¼»»û¼»»¼»»û¼»»¼»»¼÷»¼»»¼»»¼»»þº» »û¼»»¼»»þ¼»»þ¼»»þ¼» »ûº»»º»»þ¼»»þ¼»»þ¼»»û¼»»¼»»ºþ»ºº»þ¼» »þ¼»»ü¼»¼»»ºý»º»»þ¼»»þ¼»»þ¼»»þ¼»»þ¼»»þ¼» »¼»þ¹ºº»ûº»»º»»þ¼»»þ¼»»þ¼»»þ¼»»ý¼¹º º»û¼»¼¼»»þ¼»»¼»þ¼»»þ¼»»¹ º»þ¼»»ü¼»¼»»þ¼»»þ¼»»¼ »þ¼»»þº¹¹ºþ»ºº »þ¼»»þ¼» »û¼»»¼»»þ¼»»ü¼¹¹ºº¹º»þº»»þ¼»»þ¼»»þ¼»»þ¼»»ù¼»»¼»¼»»ü¼»¼»»ü¼»»¹¹ºþ»ºº»ýº¼»»þ¼»»û¼»»¼»»¼»ü¼»¼»»þ¼»»¹þº¹¹º»û¼»»¼»»þ¼»»þ¼»»¹úº¹¹ºº»»º »þ¼»»þ¼»»ó¼»»¼»»¼»¹¸¹¸¹¹ºý»º» »þ¼»»þ¼»»¼»¸¹ýº¹ººõ»º»»º»¼»»¼»»þ¼» »ü¼»¼»»¸ý¹¸¹¹ºþ¹ºº»ü¼»¼» »¼»þ¼»»ü¼»¼»»¼¸ý¹¸¹¹º¹º »þ¼»»¼»þ¼» »·¸¹¸¹º»þº»»þ¼»»€(ÿ,ÿ/ÿ2ÿ 4ÿ 6ÿ8ÿ:ÿ;ÿ<ÿ>ÿþÿÿþþÿ7ÿþ;ÿüþÿþÿÿþþÿ6ÿúþÿÿþþÿ=ÿþþÿ9ÿþþÿ:ÿþþÿÿþþÿÿþþÿ3ÿþþÿÿþþÿÿþþÿÿþþÿ-ÿüþÿþÿÿþþÿ3ÿüþÿÿþþùÿþÿþÿþÿ2ÿþÿþÿþ1ÿþÿþ4ÿúþÿþÿþÿÿþÿøþÿþþÿÿþÿ(ÿþþÿÿüþÿþÿÿûþÿÿþÿ1ÿþþÿÿûþÿÿþÿÿþþÿÿþþÿ!ÿ€ÿöøîß˲”qI(ÿûä­q0,ÿüß”D/ÿüß…& 2ÿý­D 4ÿý¼I6ÿý²58ÿý9ÿýßS;ÿþ”<ÿüË0ÿ<ÿýøXÿÿ €þ¸=¹=ü¹¸¸;¹þ¸:¹þ¸9þ¹¸¸¹9ø¸¹¹¸¸¹¸7÷¹¸¹¸¹¸¹¹6û¹¸¹¹¸¸7¹¸¹6¸¹5ý¹¸¹¹¸¹ý¸¹3ú¸¹¸¹¹¸¸¹4¹¸¹¸¹3ö¸¹¸¸¹¹¸¹¸¹¹3¸¹þ¸¹¹¸¹2¹¸ý¹¸¹¹¸2ö¸¹¸¹¹¸¹¹¸¹¹1¹¸ü¹¸¹¸¸¹þ¸0÷¹¸¹¸¹¸¸¹¸¸¹0¹þ¸¹¹þ¸¹¹þ¸/ý¹¸¹¹þ¸¹¹ü¸¹¹/ù¹¸¹¸¸¹¸¸¹¸þ¹.û¸¹¸¹¸¸ö¹¸¹¸¸¹¹¸¹.¹þ¸¹¹¸ü¹¸¸.¸¹þ¸¹¹¸þ¹¸¸þ¹- €þ¼=»=ü»¼»;»;»ü¼»¼9þ¼»»ý¼»8ø»¼»»¼¼»7»þ¼6»þ¼»»7þ¼»»þ¼»»6þ¼»»þ¼»»5»¼»4»þ¼»»ü¼»»3þ¼» »3ý»¼»»þ¼»»3 »2»ú¼»¼»»1»ú¼»»¼¼»»1»þ¼»»1»þ¼» »0»¼»0»þ¼»»¼ú»¼»»¼/ »þ¼»»/»þ¼»»þ¼»»/»þ¼»»þ¼»»/». €þÿ=ÿ=ÿ<ÿ;ÿ:ÿ9ÿ8ÿ7ÿ7ÿ6 ÿ5 ÿ4 ÿ4 ÿ3 ÿ3 ÿ2 ÿ2 ÿ1 ÿ1ÿ0ÿ0ÿ0ÿ/ÿ/ÿ/ÿ. €þv=ýÿŠ<ÿþ”;ÿþ”:ÿþŠ9ÿþv8ÿþX7ÿýø06ÿþË6ÿþ”5ÿþS4ÿýß3 ÿþ3 ÿþ52 ÿþ²2 ÿþI1 ÿþ¼1 ÿþD0 ÿþ­0 ÿþ&/ ÿþ…/ ÿþß/ÿþD.ÿþ”.ÿþß.ÿþ0-€€€€,|}÷|}}~~}~}~~,|}þ~}}~,| }~+{|}û~}}~*ú|{{|{||ý}|}}+{û|{|{||}|}þ~*{ý|{||ý}|}}þ~*{øz{{|{|{||}þ|*z{|{|ù}|}}|}*û{z{z{{|þ{||ý}|*z{|}+z{|þ{||+ýzyzzü{zz{{|{|+üyzyzzý{z{{ù|{{||{*ûyzzyzzû{z{z{{ý|{*yz{þz{{ü|{{*yzüyz{zz{+y÷zyyzzyzyzzü{zz{{+xyþzyyz{+yxyüzyyzz{+xyz{ýz{*xyùxyxyyzyyýzyzzþ{*xyþxyyýzyzz+wxyþxyyýzyzz+þwxxyþxyyzy+wxûyxyxyyüzyy*wxyþxyyþz*wxûyxyxyy+wxûyxyxyy+wüxwwxxøyxxyxyx*þvwwxþwxxyþx*üwvvwwxüwxwxx+vwþvwwxþwxx+výwvwwxwx+þuvvwx+uvwúvwxxwxx+þuvvüwvvwwþvwwx+u vwþx*uvwþvwwx+uúvuuvuvvw+þtuu÷vuvvuvvwvvw+ùututuuvvuvw+ütutuuvûwvvw*ýtuttuüvuuvv+tuvþw*tùutututuuývuvv+ûsttsttuv+þsttýutuuþtuuþv*stþsttüuttuuv+sýtsttu+sútsststtu+ststýutuu+rstüutu*rsýtsttúuttut*rúsrsrrssútsttstt+rþsrrýsrssýtstt+rsýtstt+þqrrsùrsstsstt+þqrrsþrssütss*órqrqrqrsrrsrssütss*qrþqrrs+qýrqrrüsrrss+pqþrqqrúsrrss*ópqqpqqrqqrrqrrs,‚ýƒ‚ƒƒý„ƒ„„…þ„+‚ƒ„,‚þƒ‚‚ƒ÷„ƒƒ„„ƒ„„*‚ƒù„ƒ„ƒƒ„*‚þ‚‚ýƒ‚ƒƒû„ƒ„„*‚ƒü„ƒ„*ú‚‚‚‚õƒ‚‚ƒ‚ƒƒ„ƒ„*‚þ‚‚ƒ+‚ƒü‚ƒƒ* ‚ƒ+ý€‚úƒ‚ƒƒ‚*€ý€‚ü‚‚‚+þ€€‚þ‚‚þƒ*€þ€þ‚‚+€þ€€‚+ý€€€þ€€‚+ý€€€þ‚þ‚*€þ€€ý€ü‚‚*€€+ø€€€€þ€+þ~€€ü€€+ý€€€ý€*ý~€ý€*ú~~€þ€€+~ý~þ€€ý€*~þ~~ø€€€€*~þ~€+~ú~~~€þ*þ}~~ø~~€þ€*ô~}}~}}~~~~ü€€*}~ý~+}~+}þ~}}~+}~û}~}}~~û~~*}þ|}}~þ~*þ}||}þ~}}~ý~*|ý}|}}~þ}~~+|ý}|}}ù~}~}~~*ý|{||ö}||}}~}~}~~+{|ý}|}}þ~}}+ü{|{||}ý~}*ý|{||ý}|}}ù|}}~}~*{|{ü|{|}}þ|}}+{ý|{||þ}||}+þz{{û|{|{||þ}||þ}*{|{ý|{||ý}|*ûz{{z{{|þ{||}+zþ{zz{|û}||}*z{ý|{||û{||}*z÷{z{z{{|{||ý{|*ýzyzzû{z{z{{|+zþyzz{þz{{ü|{|*yzþyzz{þz{{û|{||*yzþyzz{þ|*yz{z{+yþzyyzü{zz{{+yz{+÷xyxyyzyyzz{üz{{*üyxxyyzþyzzþyzzþ{*xyþxyyz+xûyxyxyyz+xyþxyyz+ýxwxxyóxyyxyzyyzyzz*ýxwxxyýzyzz,ý÷ö÷÷ö÷÷öö÷÷ö÷ö÷÷,þ÷öö÷÷ö÷ö÷÷öö÷÷öþ÷+ùö÷ö÷öö÷÷üö÷ö÷÷ýö÷*þö÷÷øö÷÷ö÷÷ö÷÷ö+öû÷öö÷öö÷ö÷üö÷ö*öþ÷ööú÷ö÷ö÷öö÷+öù÷öö÷öö÷÷ö÷+ö÷ö÷ö÷úö÷÷öö*öô÷ö÷ö÷ö÷ö÷÷ö÷÷+þ÷öö÷üö÷÷öö÷ö+ûö÷ö÷öö÷ö÷+ö÷öý÷ö÷÷öþ÷*öþ÷ööü÷ö÷öö+ûö÷ö÷ööü÷ö÷öö÷þö*þ÷ööþ÷öö÷ûö÷ö÷*öþ÷öö÷öþ÷ööþ÷öö+öþ÷ööþ÷ööþ÷öö+ öþ÷ööü÷ö÷öö+öþ÷ööû÷öö÷öö+öþ÷öö÷öþ÷öö+öþ÷ööù÷öö÷÷ö* öþ÷ööû÷ö÷ö*þõööú÷ö÷ö÷öö+öü÷öö* öþ÷öö+þõööþõö öþ÷*ö+ö+úöõööõööþõö ö+ýöõöö+úöõõöõö ö+ûõöõõöö+ûõööõöö+õöþõööúõöõöõöö+öõöõö÷õöõõöõöö*ùõööõööõõöõö+öõöõöþõöö+õöþõööüõöõööýõö*ôõöõöõõööõöõööþõöö+ýöõööüõöõööõö+öþõööþõööþõöö+þõööõöõøöõööõöö*ýöõööýõöõõúöõööõöö+õöùõööõöõööõýöõöö+õþöõõýöõööýõöõõöþõ*ùöõõöõõööþõööõö+øöõõöõõöõõöõ+ûõöõõööõöþõööýõö*õöõþöõõüöõöõõþö* õöúõöõõö*õöõþöõõöùõööõöõ*ýõöõ õøöõõööõö*õöõöõýöõ* õøöõõööõöõõ+õþöõõþöõõ+õûöõõöõõþöõõöþõ*õöõþöõõúöõöõõ*õþöõõúöõõööõõ+õþöõõöýõö* õöõþöõõ+þôõõýöõ* õþöõõþö*õþôõ õüöõöõõ+þôõ õþöõõ,þqÿÿ,þ­ÿÿ,þäÿÿ+þÿÿ+þIÿÿ+þqÿÿ+þ”ÿÿ+þ²ÿÿ+þËÿÿ+þßÿÿ+þîÿÿ+þøÿÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ~ý~ø€€€€€ù‚‚‚‚‚ýƒ‚ƒƒ„ý…„……ý†…††~û~~€ú€€€‚‚ƒ„ú…„„…„……†ý…†~~€ë€€€‚‚‚‚ƒ‚‚ƒ‚ƒƒü„ƒƒ„„…†~ý€€€ü€€€û‚‚‚‚ýƒ‚ƒƒþ„ƒƒ„ý…„……ü†…†~~ü~~ü€€€ý€û‚‚‚‚ƒû‚ƒƒ‚ƒƒû„ƒ„ƒ„„…þ}~~ú~~€€‚þ‚‚ƒü„ƒƒ„„…þ„……}~€þ€€ý€ý‚‚‚ƒþ‚ƒƒ„ƒ„ô…„„…„……}}~}~~ü~€€ö€€€€€€ó‚‚‚‚‚ƒ‚ƒ‚‚ƒƒö„ƒ„„……„„…}}~}~€ù‚‚‚‚‚ýƒ‚ƒƒ„üƒ„ƒ„„…ý„…}}þ~}}~ü~~þ~ý€€€ý‚‚‚õƒ‚ƒ‚ƒƒ„„ƒƒ„„û…|}|}}~}~ü~~€þ€€ý‚‚‚ƒ„}þ|}}~€þ€€þ€€ý€‚þ‚‚ƒþ‚ƒƒ„ƒ„}|}~þ~€ù€€€€‚‚ûƒ‚ƒ‚ƒƒù„ƒƒ„ƒ„||}ý~}~~ú€€€€ý€þ‚‚ƒ‚ƒ„þƒ||ý}|}}~ý~€û€€‚ƒü{|{||}ý~}~~ü~~ý€€€þ€€‚‚ƒ{|ü}||}} ~€þ€€ú‚‚‚‚öƒ‚‚ƒ{|{|{||ü}||}}ý~}~~þ~~û~€ý€€€þ€ü‚‚‚ýƒ‚ƒƒþ‚{{|}|ý}|}}~~€‚þ‚‚ƒ{ü|{{||}þ|}}ý~}~~û~~ý€€€ú€€ü‚‚‚üƒ‚‚{{|}|}ü~}}~~ý~€ü€€‚ƒ{þz{{|û}|}|}}þ~}}~þ~~€þ€€þ€‚zû{z{z{{|ø}|}|}}~}}~þ€€‚z{ü|{{||}þ|}}~þ}~~ €ý€‚ü‚yzz{|þ{|| }~€þ€€ü‚‚zz{|ý}|}}~þ€€þ€€ýzyzzú{zz{z{{|}~þ~~ü€€€ü€€ zü{zz{{û|{|{||}ü|}}~~þ~€þ€€zý{z{{|þ{||}û~}~}~~ý~€þ€€ö€€€yyzzûyz{z{{|ù}|}}||}}ü~}}~~€€þ€yyýzyzz{zý{z{{|}þ|}}~þ}~~€þ€€û€yyýzyzzþ{zzú{z{{|{{ý|{|| }~ù}~~~~ü€€€ûxyxyyzþyzzý{z{{|þ{||}þ|}}ü~}}~~€€ûyxxyyz{|}þ|}}~þ}~~€xýyxyyþzyyzý{z{{ú|{||{||}ú~}~~}~~ý~€ø€€wxyxy yúzyzz{zz{ý|{||}~þ}~~û€€xxúyxxyxyyzøyzz{z{z{{|÷{||}||}|}}ü~}}~~ü~~€wxyþxyyüzyzyyz{|þ{||ü}||}}ü~}}~~þ~û€wwxxyþxyyúzyyzyzzý{z{{ø|{|{||{||ý}|}}~þ}~~ý~úwxxwwxxùyxyxyyzzþyzzú{z{{z{{ý|{||þ}||}ù~}~}~~þ~wwxýyxyyýzyzz{þz{{þ|{{|} ~þwwxwxyþxyy z{þ|{{|}þ|}}ù~}~}~}~~ý~wwxyøzyzz{{z{{ü|{{||ü}||}}ý~}~~üvwvwwxþwxxyzyøzyzz{zz{{ý|{||}|}û~}~}~~þvvwýxwxxyz{üz{z{{ü|{{||ü}||}}~vwüvwvwwxþwxxyýzyzzþ{zz{ü|{{||}õ|}}~}}~}~~vvüwvvwwxþwxxyþzyyñzyzz{z{zz{z{{|{{|}|ý}~}}þ~vvwùvwwxwwxxyþxyyüzyyzz{ý|{||ý}|}}ú~}~~uvvùwvvwwvwwxyzþyzzý{z{{þ|{{|}uvwùxwwxwwxxyþxyyz{ý|{||}ñ|}uvvuvvuwvwwvwwûxwxwxxyxýyxyyz{øz{|{|{{||ö}||}}|uuvuuvýwvwwxwxûyxyxyyz{|{|ý}|}}ý|tuuývuvvþwvvwûxwxwxxyýzyzzü{z{zzü{|{||}þtuuvüwvvwwxýyxyyýzyzzý{z{{ú|{||{||û}tutuuûvuvuvvwþvwwþxwwxúyxxyxyyzþyzz {|þtuuvwüxwwxxyúzyyzyzz{þz{{|tûututuuüvuuvvþwvvwýxwxxþyxxyzyzý{z{{ø|{{ttutuuvuvwxýyxyyýzyzzý{z{{|tuvýwvwwýxwxxüyxxyy z{|ýtsttûututuuvþuvvw xyzyzû{z{z{{t uývuvvýwvwwxyþxyyýzyzzý{z{{stuþvuuvþwvvwüxwwxxûwxyxyyüzyyzzñ{zz{zz{sststssttuývuvvwxþwxxýyxyyýzyzzþ{zzûrsstsstu vwþvwwxþyxxyzý{z{ …ý†…††‡úˆ‡ˆˆ‡ˆˆ‰ùЉЉЉŠŠ‹ûŒ‹ŒŒ„„…†‡þ†‡‡úˆ‡ˆˆ‡ˆˆü‰ˆˆ‰‰Š‹Š‹Œú‹„…„„……†ù‡†‡†‡†‡‡þˆ‡‡ˆü‰ˆˆ‰‰Šþ‰ŠŠý‹Š‹‹„ô…„„…„……††……††‡ûˆ‡ˆ‡ˆˆ‰ýЉŠŠ‹þŠ‹‹„…þ„……ó†…†…†‡††‡†‡†‡‡ýˆ‡ˆˆù‰ˆˆ‰‰Š‰‰ôŠ‰Š‰ŠŠ‹ŠŠ‹Š‹‹„ù…„„……„……†‡ˆþ‡ˆˆý‰ˆ‰‰üˆ‰Š‰‰ýЉŠŠý‹Š‹‹„üƒ„ƒ„„ý…„……þ†……†ü‡††‡‡ýˆ‡ˆˆ‰úŠ‰ŠŠ‰ŠŠù‹ŠŠ‹ƒ„ƒƒ„ó…„„……„……††……††ý‡†‡‡ˆú‰ˆ‰ˆˆ‰‰Šù‹ƒƒ„„ƒ„„…þ„……†û‡†‡†‡‡ˆþ‡ˆˆ‰þЉ‰Šƒþ„ƒƒý„ƒ„„õ…„„……„……†…††‡†ú‡†‡‡ˆ‡‡ˆ‰ˆ‰ûˆ‰‰Š‰‰Šüƒ‚ƒ„„þƒ„„…„…ý†…††‡þ†‡‡ˆþ‡ˆˆ‰Š‰Šýƒ‚ƒƒ„…„…†þ…††‡þ†‡‡úˆ‡ˆˆ‡ˆˆý‰ˆ‰‰ùЉЉ‰‚ƒƒþ‚ƒƒ„…ü„…„……ú†…††…††ü‡††‡‡úˆ‡ˆˆ‡ˆˆ‰ˆ‰Š‰û‚ƒ‚‚ƒƒû„ƒ„ƒ„„…þ„……ý†…††ú‡†‡‡†‡‡ôˆ‡ˆ‡ˆ‰ˆ‰‰ˆˆ‰‰Š‚ƒû‚ƒƒ‚ƒƒü„ƒƒ„„…ù„……†……††ö…††‡‡†‡‡†‡‡ˆþ‰ˆˆ‰þˆ‰‰‚ûƒ‚ƒ‚ƒƒû„ƒ„ƒ„„…ù„…††……††þ…††‡þ†‡‡þˆ‡‡ˆ‰‚ûƒ‚ƒ‚ƒƒ„üƒ„ƒ„„ý…„……ý†…††‡ýˆ‡ˆˆþ‡ˆˆý‰ˆ‰‰‚ƒ„…„…†…†ü‡††‡‡þˆ‡‡ˆõ‰ˆˆ‰ˆˆ‚‚‚‚ƒü‚ƒ‚ƒƒ„ƒ„…þ„……ý†…††ý‡†‡‡üˆ‡‡ˆˆ‰ˆ‚û‚‚‚‚ƒ„þƒ„„þ…„„…†‡þ†‡‡ˆ‡ˆþ‚ø‚ƒƒ‚ƒ‚‚ƒƒü„ƒƒ„„ý…„……ú†……†…††ý‡†‡‡ˆþ‡ˆˆý‚‚‚þ‚‚ƒý„ƒ„„…þ„……†ú‡†‡‡†‡‡üˆ‡‡ˆˆ‚‚ýƒ‚ƒƒù„ƒ„ƒ„ƒ„„…þ„……û†…†…††ý‡†‡‡ˆþ€‚þ‚‚ƒþ‚ƒƒ„…û„……„……†‡ùˆ‡ˆˆ€€ú‚‚‚‚‚ƒ „…†þ…††‡ùˆ‡ˆ‡ˆ€€þ‚‚ü‚ƒ‚‚ƒ„…„…ü†……††‡†‡ûˆ‡€€‚þ‚‚ýƒ‚ƒƒü„ƒƒ„ „…†…ý†…††û‡†‡†‡‡€ú€€ú‚‚‚‚øƒ‚‚ƒ‚ƒ‚ƒƒü„ƒƒ„„…ü„…„……û†…†…††ü‡††‡‡€ý€ý‚‚‚þƒ‚‚ýƒ„ƒƒ„ø…„…„…„„……ý†…††‡€ü€€‚ƒþ„ƒƒ„…ú„…„…„……†‡ó†‡†‡€€€€€€€ü‚‚‚ýƒ‚ƒƒ„þƒ„„ý…„…… †ù‡†€€€þ€û‚‚‚‚ƒþ‚ƒƒ„üƒ„ƒ„„þ…„„…†ù‡€€€€ú€€€‚þƒ‚‚ýƒ‚ƒƒý„ƒ„„ý…„……ý†…††ø‡~€€€ú‚‚‚ƒ‚‚ƒþ‚ƒƒ„ý…„……ý†…†† €ú€‚‚ƒ„ý…„……†þ~€ü€€€þ€€‚ƒþ‚ƒƒþ„ƒƒ„ý…„……ø†……†~~€€ü€€ ‚ƒ„þƒ„„þ…„„…þ†……~þ~~ü€€€ü€‚‚þ‚‚üƒ‚‚ƒƒû„ƒ„ƒ„„ü…„„……~þ€ý€€€ý€ý‚‚‚ýƒ‚ƒƒ „ý…„……~þ~ø~€€€€û€€‚þ‚‚ƒþ‚ƒƒ„󃄄…„…„……„……~~ý~~ý€€€ü€€‚üƒ‚‚ƒƒ„…þ„……ü}~}~~þ~~ý€€€ü€€ñ‚‚‚‚‚ƒ‚‚ƒ‚ƒƒ„þƒ„„…„}~þ}~~€þ€€þ€€û‚‚‚‚ƒþ‚ƒƒ„…}~þ}~~ù~~~€ý€ ‚ƒ„ƒ„ü…„…}}ý~}~~~€þ€€ü‚‚‚ƒ‚ƒù„ƒƒ„„ƒ„„}~~ü€€€þ€ý‚‚‚ƒþ‚ƒƒü„ƒƒ„„þ|}}ý~}~~þ~~ý€€€ù‚‚‚‚‚ƒú„ƒƒ„„}}þ|}}þ~}}~û€€€€ü€€‚þ‚‚÷ƒ‚ƒƒ‚ƒƒ„ƒƒ„ù|}|}}|}}ú~}}~}~~ü~~€€‚þ‚‚ƒþ‚ƒƒö„ƒ„ƒ||}}|}}ü~}}~~ý~€€ý€þ€‚þƒ‚‚ƒþ„||þ}||}~€ ‚ƒ|} ~ö~€€€€€€ ‚ƒü‚ƒ‚||ý}|}}û~}~}~~þ~~ý€€€ù€€€ù‚‚‚‚‚üƒ‚ƒ||} ~ý~€ý€ý‚‚‚ûƒ‚‚ƒ{{ý|{||}~þ}~~þ~€þ€€û€‚‚üƒ‚ƒ{{ý|{||û}|}|}}ô~}~~}}~~~~ ý€€€ý€‚þ‚‚{|{|ý}|}}~}~ü~~ø€€€€€ü€€ú‚‚‚‚{|{|}~þ}~~ý~ý€€€þ€‚ú‚z{zz{{ |}ô~}}~~}~~~€ý€þ‚û‚z{z{{| }ý~}~~û€€€€ö‚‚‚{{zz{{|þ{||ý}|}}ý~}~~ý~ü~€€þ€€ûz{zz{{ü|{{||ý}|}}ý~}~~ú€€€€€÷€€€€€z{|ü}|}||}~ü~~ù€€€€€û€€ûyzz{zzý{z{{|{|}~þ}~~ý~ €÷þø÷÷üø÷ø÷÷ø÷øù÷øø÷ø÷øø÷þø÷÷ýø÷øøî÷ø÷÷ø÷ø÷÷ø÷øø÷ø÷÷øø÷þö÷÷þö÷÷þø÷÷ø÷þø÷÷öø÷ø÷øø÷ø÷øø÷øû÷øø÷øø÷þö÷÷þö÷ ÷õø÷ø÷ø÷ø÷÷ø÷÷ùø÷øø÷ø÷÷ø÷øù÷øø÷øö÷÷þø÷÷þø÷÷þø÷÷øú÷ø÷÷ø÷÷úø÷ø÷ø÷÷øþ÷øø÷þö÷÷þö÷÷þö÷÷þø÷÷ùø÷ø÷÷ø÷÷öø÷÷ø÷øø÷ø÷÷úø÷øø÷øøù÷öö÷÷ö÷÷õø÷÷ø÷÷øø÷ø÷÷þø÷÷øý÷ø÷÷øþö÷÷öý÷ö÷÷ûø÷÷ø÷÷þø÷÷ø÷÷ø÷ø÷øø÷÷øøú÷øøöö÷÷þö÷÷ûö÷÷ö÷÷øü÷øø÷÷øù÷øø÷ø÷øøöû÷ö÷ö÷÷öý÷ö÷ ÷þø÷÷þø÷÷úø÷÷øø÷÷øþ÷øøò÷ø÷÷ö÷öö÷ö÷öö÷÷þö÷ ÷þø÷÷ø÷øü÷øø÷÷ûø÷÷ø÷÷øö÷þö÷÷þö÷÷þø÷÷þø÷÷ø÷øñ÷ø÷ø÷øø÷ø÷ø÷öö÷÷þö÷÷þö÷÷öø÷ø÷ø÷ø÷ø÷÷üø÷÷øø÷òøöö÷÷ö÷÷ö÷÷öö÷÷þö÷÷þø÷÷ø÷üø÷ø÷÷øû÷ø÷÷öö÷þö÷÷üö÷ö÷÷þö÷÷ö ÷üø÷ø÷÷üø÷ø÷÷þø÷÷øø÷÷ö÷öö÷÷úö÷ö÷ö÷÷ùö÷öö÷ö÷÷ø÷úø÷ø÷ø÷÷øö÷öþ÷öö÷ö÷ö÷þø÷÷þø÷÷ùø÷÷ø÷ø÷÷÷ø÷÷öö÷ö÷öö÷þö÷÷ö÷þø÷÷øý÷ø÷÷ûø÷ø÷ööý÷ö÷÷öý÷ö÷÷þö÷÷üö÷ö÷ ÷ûø÷÷ø÷÷ø÷öû÷öö÷ööû÷ö÷ö÷÷üö÷ö÷÷þö÷÷ö÷ø÷ïø÷ö÷ö÷÷ö÷÷ö÷ö÷ö÷ööü÷öö÷÷ö÷ö÷ûø÷÷ø÷÷ø÷þø÷÷öþ÷öö÷úö÷÷öö÷÷ö ÷ö ÷þø÷÷ø÷øùö÷öö÷ö÷÷þö÷÷ûö÷÷ö÷÷öö÷ö÷÷ö÷÷ö÷÷þø÷ ÷ø÷ýö÷öö÷öù÷öö÷ö÷ööú÷ö÷÷ö÷÷þö÷÷úö÷÷öö÷÷øø÷ø÷ø÷÷ööû÷öö÷ööö÷ö÷÷ö÷÷ö÷ööý÷ö÷÷öç÷öö÷÷ö÷ö÷ö÷öö÷÷öö÷ö÷ö÷÷ö÷÷üö÷ö÷÷ö÷þø÷÷úø÷ö÷÷ööù÷ö÷öö÷ööþ÷öö÷úö÷÷öö÷÷þö÷÷þø÷÷ø÷öþ÷ööü÷ö÷öö÷öú÷ö÷÷ö÷÷ùö÷÷ö÷ö÷÷þøööþ÷öö÷öü÷ö÷öö ÷þö÷÷þö÷÷öþ÷öö÷öü÷öö÷÷ö÷öý÷ö÷÷öþ÷öö÷öý÷ö÷÷ö÷þö÷÷ûö÷÷ö÷÷þö÷÷þö÷÷ö÷öø÷ö÷öö÷÷öö÷ö÷þö÷÷ö ÷ö÷þø÷÷öþ÷ööû÷ö÷ö÷÷öý÷ö÷÷þö÷÷þö÷÷þö÷ ÷öþ÷ööþ÷ööü÷ö÷ööý÷ö÷÷ýö÷öö÷ö÷üö÷ö÷÷þö÷÷ öþ÷ööþ÷ööþ÷ööö÷ö÷ö÷öö÷ö÷÷öý÷ö÷÷ö ÷öþ÷ööú÷öö÷ö÷÷úö÷÷öö÷÷þö÷÷üö÷ö÷ ÷ö÷þö÷÷üö÷ö÷÷þö÷÷þö÷÷þö÷÷öþ÷ööù÷öö÷ö÷öö÷îö÷ö÷ö÷ö÷ö÷ö÷ö÷÷ö÷öö÷þö÷÷öþ÷ööð÷öö÷ö÷ö÷ö÷ö÷ö÷ö÷÷ö÷úö÷÷öö÷÷öþ÷ö öþ÷öö÷ö÷þö÷÷ö÷þö÷÷þö÷÷öù÷ö÷öö÷ööþ÷ööú÷öö÷÷öö÷öú÷ö÷öö÷÷þö÷÷öþ÷öö÷íö÷ö÷÷öö÷öö÷÷ö÷÷ö÷÷ööñ÷ö÷÷ö÷÷ö÷ööõöõööþõööþ÷ööþ÷öö÷öü÷öö÷÷ùö÷öö÷ö÷÷ö÷öþ÷öö÷÷ö÷ö÷ö÷÷öö÷ö÷þö÷÷ûöõöõööþõööõö÷ýö÷ööþ÷ööø÷ö÷ö÷öö÷÷÷ö÷÷öö÷öö÷÷ûö÷ö÷ööõöõöþ÷ööþ÷ööþ÷öö÷ö÷÷ö÷÷ö÷÷ö÷÷þö÷÷ùöõööõõööûõööõööþ÷öö÷öþ÷öö÷þö÷÷öü÷ö÷ööûõööõööõö÷ö÷ö÷ö÷üö÷ö÷÷òö÷ööõöõöõõööõööþõööþõööþ÷ööþ÷ööõ÷ö÷÷öö÷ö÷ö÷÷þö÷÷úö÷ööõööõöþõö öö÷ö÷öö÷öö÷ööò÷öö÷ö÷ö÷÷ö÷öö÷÷öõöòõöõöõööõöõöõõö öû÷ö÷÷ööþ÷ööô÷ö÷öö÷ö÷÷õõööõöþõööþ÷ööû÷ö÷ö÷÷ö÷÷ö÷÷ö÷öö÷ööõöõöþõö öþ÷ööõ÷ö÷ö÷÷ö÷ö÷öö÷öù÷ö÷÷ö÷ööõþöõõöþõööõöõö÷ öþ÷ö ö÷üö÷öõõýöõööõúöõöõõööþõööþ÷öö÷øö÷ö÷ö÷÷öö÷ùõöõõööõõöþõööõöþ÷ööþ÷ööü÷ö÷ööù÷õõöõöõõöûõööõööþõööþõööþõööþõö öþ÷ööì÷öö÷ö÷ö÷ö÷öö÷öõööõöõõöúõööõõööúõööõõööþõö öþ÷öö÷ö÷öö÷ö÷ööõõöõõöõöþõööûõööõööüõöõö öû÷ö÷÷öö÷õ÷öõõöõöõöõõöõöþ÷ööþ÷ööõ÷ö÷öö÷÷öõöõõöõûöõöõööõöþõööþõööþ÷öö÷ýö÷õõöúõöõöõööüõööõõöþõööþ÷öö÷÷ö÷öö÷õöõõþöõõöõ÷öõöõöõöõööþõöö÷öþ÷öö÷öõþöõõöþõööüõöõööúõööõõö ö÷öþ÷ööü÷ö÷ööÿ†‡ˆþ‡ˆˆ ‰Šü‹ŠŠ‹‹úŒ‹ŒŒ‹ŒŒüŒŒûŽŽ††‡þ†‡‡ˆþ‡ˆˆþ‰ˆˆ‰ýЉŠŠý‹Š‹‹Œþ‹ŒŒýŒþŽþކ†ø‡†‡‡†‡†‡‡ˆþ‡ˆˆ‰þˆ‰‰ýЉŠŠü‰ŠŠ‹‹üŒ‹‹ŒŒ…†‡ˆú‰ˆ‰ˆˆ‰‰ Šû‹Š‹Š‹‹ŒþŒŒýŒ…†ý‡†‡‡ˆû‰ˆ‰ˆ‰‰Šý‹Š‹‹ŒüŒ……†ú‡††‡†‡‡üˆ‡‡ˆˆ‰þˆ‰‰Šü‰Š‰ŠŠü‹ŠŠ‹‹ŒþŒ…†ý‡†‡‡ˆü‰ˆˆ‰‰Šü‹ŠŠ‹‹ ŒýŒ……ø†…†…†‡‡††‡ˆþ‡ˆˆþ‡ˆˆ‰þˆ‰‰öŠ‰Š‰ŠŠ‹‹Š‹‹õŒ‹ŒŒŒŒ„„……†þ…††‡ ˆ‰þЉ‰Šþ‰ŠŠý‹Š‹‹Œþ‹ŒŒýŒ„„…†ü…†…††ý‡†‡‡ ˆ‰Šü‹ŠŠ‹‹Œü…„……û†…†…††‡üˆ‡‡ˆˆþ‰ˆˆ‰þˆ‰‰ýЉŠŠü‹ŠŠ‹‹þŒ‹‹Œ„ü…„„……†þ…††‡þ†‡‡ýˆ‡ˆˆü‰ˆˆ‰‰Š‰Šý‹Š‹‹Œ„…ü†……††‡ýˆ‡ˆˆþ‰ˆˆ‰þЉ‰Šü‹Š‹ŠŠù‹Œ‹‹ŒŒ„„ý…„……û†…†…††‡ˆú‰ˆ‰ˆˆ‰‰ùЉ‰Š‰‰ŠŠ‹öŠ‹Œ‹ŒŒ„„ƒ„„þ…„„…†…†ý‡†‡‡ýˆ‡ˆ ˆ‰Šþ‰ŠŠý‹Š‹‹ýƒ„ƒƒ„þ…„„…ü†……††‡ˆü‡ˆ‡ˆˆ‰þЉ‰Š‹ûŠ‹ƒƒ„„…û†…†…††ý‡†‡‡ˆ‰þˆ‰‰ýЉŠŠþ‰ŠŠý‹Š‹‹ƒú„ƒ„„ƒ„„…þ„……†…†ü‡††‡‡ˆý‰ˆ‰ ‰ïŠ‰Š‹ŠŠ‹‹ƒƒ„„ƒ„„ƒ„„ý…„……†…†ý‡†‡‡ýˆ‡ˆˆý‰ˆ‰‰Šú‹Šƒƒ‚ƒƒý„ƒ„„ý…„……ü„…†……†ü‡††‡‡øˆ‡‡ˆˆ‡‡ˆˆ‰þˆ‰‰ýЉŠŠý‹‚ƒƒý„ƒ„„…ü†……††‡†ý‡†‡‡ˆû‰ˆ‰ˆ‰‰Šþ‚ƒƒþ‚ƒƒý„ƒ„„ý…„……ý†…††þ‡††‡ýˆ‡ˆˆý‰ˆ‰‰Šø‰‚‚ƒ‚ƒ‚ƒƒ„ƒ„…†ý‡†‡‡þ†‡‡ˆû‡ˆˆ‡ˆˆ‰ùЉ‰Š‰‰‚‚ƒþ‚ƒƒ „…ý†…††ý‡†‡‡üˆ‡‡ˆˆõ‰ˆ‰ˆ‰‰Š‰Š‰‚‚ôƒ‚‚ƒ‚ƒ„ƒƒ„ƒ„„þ…„„…†þ…††‡þ†‡‡üˆ‡‡ˆˆý‰ˆ‰‰þŠ‚‚ø‚‚ƒ‚ƒ‚ƒƒý„ƒ„„…ý†…††‡þ†‡‡ˆü‰ˆˆ‰‰û‚‚‚‚ƒü„ƒƒ„„…þ„……†ý‡†‡‡üˆ‡‡ˆˆ‰ûˆ‰ˆ‰‚‚ƒþ‚ƒƒ„û…„…„……†ú‡†‡‡†‡‡üˆ‡‡ˆˆù‰ˆˆ‰ˆ‰‚ýƒ‚ƒƒþ„ƒƒ„ý…„……ü†……††ü‡††‡‡ˆ‰û€‚ý‚‚‚ƒ„ƒ„ü…„„……†ý‡†‡‡üˆ‡‡ˆˆ‰þ€‚‚üƒ‚‚ƒƒþ„ƒƒ„…þ„……þ†……†þ‡††‡üˆ‡‡ˆˆþ‰‚þ‚‚ƒ‚ƒù‚ƒƒ„„ƒ„„…†ý‡†‡‡ýˆ‡ˆˆþ€‚ýƒ‚ƒƒü„ƒƒ„„…þ„……ý†…††‡†ý‡†‡‡ˆ€ý€ý‚‚‚ƒ‚ƒ„ƒ„ü…„„……†÷…††‡††‡†‡‡þˆ‡‡ùˆ€€€€‚ú‚‚ƒ‚ƒƒþ‚ƒƒ„…†ú‡†‡‡ˆ‡‡þˆ€€ú‚‚‚‚ƒ„ƒ„þ…„„…ý†…††ü‡††‡‡ûˆ‡€€€û€€ü‚‚‚ƒþ‚ƒƒý„ƒ„„…ý†…††‡þ†‡‡€ñ€€€‚‚‚‚‚ƒ„ý…„……û†……†……ý†‡††‡û€€€€ü‚‚‚ƒ„þƒ„„…ü„……††þ…††ù‡††‡‡†ü€€€ü€€ú€‚‚‚ƒþ‚ƒƒú„ƒ„„ƒ„„ý…„……û†…†…††‡€þ€€ú€€€‚úƒ‚‚ƒ‚ƒƒ„û…„…„……†…†‡þ~û€€€€þ€ý‚‚‚ƒü„ƒƒ„„…„…†þ…††û~~ €þ‚‚þƒ‚‚ƒû„ƒ„ƒ„„ …†ø‡~~~~ý€€€þ€‚ý‚‚ûƒ‚ƒ‚ƒƒ„ƒ„þ…„„…ý†…††~€ú€€€ü‚‚‚ƒý„ƒ„„ý…„……þ„……û†…††~~ý~€þ€‚þƒ‚‚ƒ„÷ƒ„„ƒ„„…„……þ„……†û}~~~~€þ€€ý‚‚‚÷ƒ‚‚ƒ‚ƒƒ„ƒƒ„…ó„…†……†~~}~~~~ý~ý€€€‚‚üƒ‚‚ƒƒü„ƒƒ„„ý…„……~ù}~~~ú~€€ý€€€ý€ ‚ƒ„…û„……„……ú}~~}}~~þ~~ý~€ü€€€û€€þ‚‚þ‚‚ƒ„…ø„…}}~}}~~ø~~€€€þ€€ü€‚ý‚‚‚ýƒ‚ƒƒþ„ƒƒ„þƒ„„û…„„|}} ~ù€€€€‚‚þ‚‚ýƒ‚ƒƒò„ƒƒ„„ƒƒ„„…„…|}}~þ}~~ý~€þ€€ü€€‚ƒý„ƒ„„ý}|}}þ~}}~þ~€ü€€€‚üƒ‚ƒ‚‚ƒü„ƒƒ„„øƒ„„|}}|}}~û~~€þ€‚ýƒ‚ƒƒ„|ü}||}}ý~}~~ú~~~ù€€€€€€‚ƒþ‚ƒƒ„|}ü|}|}}~û~~€ú‚‚‚‚ûƒ‚ƒ‚ƒƒû„ƒƒ{||}|}~ù~€€€€ý‚‚‚ýƒ‚ƒƒþ„||}þ|}}ý~}~~þ~ý€€€ú€€€‚û‚‚‚‚ƒ‚ƒü„{{||}~ý~€ý€‚þ‚‚ƒ‚ƒú{|{|{||}ú~}~~}~~û~€ý€€€€ö‚‚‚‚‚ƒ‚ƒƒþ‚{{|ü}||}}ü~}}~~þ€€€ý€ý‚‚‚üƒ‚ƒ{{û|{|{||þ}||}~þ~€€ú‚‚‚‚‚þƒ{{ú|{||{||ý}|}}ü~}}~~ý€€€ú€€‚ŒüŒŽŽþŽŽùŽŽŽûü‘‘‘ü‘‘’’þ‘’’“ýŒ‹ŒŒþŒýŽŽŽüŽŽüŽþú‘‘‘‘ó’‘’‘‘’’‘’“’’““ô‹ŒŒ‹ŒŒŒŒŒŽüŽŽŽýý‘‘‘’‘’û“’‹‹ŒŒûŒŒûŽŽŽ Žþ‘ü’‘‘’’ü“’’‹‹ýŒ‹ŒŒüŒŒþŽŽùŽø‘‘‘‘‘’ý‹Œ‹‹ýŒ‹ŒŒþŒŒþŽŽþ‘’‹Œþ‹ŒŒþŒþŽŽû‘‘‘‘’þ‘’’Šû‹Š‹Œ‹‹Œú‹ŒŒŒþŒŽþŽŽúŽŽŽþü‘‘‘’ý‘’‹‹üŒ‹‹ŒŒþ‹ŒŒþŒþŽŽüŽŽû‘‘‘‘ù’‹ŠŠ‹Š‹‹ýŒ‹ŒŒþŒŽýŽþ‘ù’‘Š‹ŠŠ‹‹þŒ‹‹ŒþŒŒüŽŽŽûŽŽŽ‘û‘‘’ŠŠþ‹ŠŠ‹ŒüŽŽŽûŽüü‘‘‘Šý‹Š‹‹ŒýŒþŽýŽŽŽüŽŽúú‘‘‘‘‘‰Š‹þŠ‹‹ýŒ‹ŒŒþŒüŒŽŽþŽþ‘ú‘‰‰Š‰ŠŠþ‹ŠŠ‹úŒ‹ŒŒ‹ŒŒýŒŽþŽŽüŽŽ‘û‘ЉŠŠþ‰ŠŠ‹Š‹ŒþŒŽûŽŽŽŽýŽþ‘‰‰Š‹þŠ‹‹ýŒ‹ŒŒþŒŒŽõŽŽŽŽŽŽý‘ˆ‰‰þЉ‰Šû‹Š‹Š‹‹ ŒýŒŽ‰úŠ‰ŠŠ‰ŠŠý‹Š‹‹úŒ‹ŒŒ‹ŒŒùŒŒŒ Žüþˆ‰‰Šü‰Š‰ŠŠû‹Š‹Š‹‹ýŒ‹ŒŒŒýŽŽ Žþ‰þˆ‰‰Š‹Œ‹üŒ‹‹ŒŒþŒüŽŽŽþŽüˆˆ‰ûЉЉŠŠ‹Œ‹ŒýŒþŒþŽŽþŽŽõŽˆˆ‰‰ˆ‰‰Š‹þŠ‹‹ŒùŒŒŒ ŽüŽŽþ‡ˆˆý‰ˆ‰‰ýЉРŠ‹Œü‹Œ‹ŒŒþŽŽýŽþ‡ˆˆû‰ˆ‰ˆ‰‰Šþ‰ŠŠ‹þŒ‹‹ŒþŒúŽŽŽŽŽýŽþ‡ˆˆú‰ˆ‰ˆˆ‰‰ýЉŠŠü‹ŠŠ‹‹ûŒ‹Œ‹ŒŒýŒþŽŽ‡ˆ‰öˆ‰ˆˆ‰‰ˆ‰‰ŠŠ‹üЋЋ‹ŒþŒûŽŽŽŽ‡ˆþ‡ˆˆ‰üˆ‰ˆ‰‰úŠ‰ŠŠ‰ŠŠ‹ýŒ‹ŒŒýŒüŽŽŽ‡ˆ‰þЉ‰Š‹úŒ‹Œ‹‹ŒŒŽûŽŽ‡‡ˆû‰ˆ‰ˆ‰‰ûЉЉŠŠü‹ŠŠ‹‹üŒ‹‹ŒŒýŒ÷ŽŽŽŽ‡†‡‡üˆ‡‡ˆˆ‰ûЉЉŠŠþ‰ŠŠý‹Š‹‹ŒùŒŒŒúŽŽŽ‡‡þ†‡‡ýˆ‡ˆˆ‰þˆ‰‰Š‰Šý‹Š‹‹öŠ‹‹Œ‹ŒŒ‹‹ŒŒþŽüކ‡††‡ˆ‡ˆû‰ˆ‰ˆ‰‰Šù‰Š‰ŠŠ‹ŠŠ‹üŒ‹‹ŒŒø‹ŒŒŒŒûŽŽ††ý‡†‡‡úˆ‡ˆ‡‡ˆˆû‰ˆ‰ˆ‰‰Šþ‰ŠŠ‹þŠ‹‹Œ‹ŒþŒŒýŒ†‡üˆ‡‡ˆˆ‰ýЉŠŠý‹Š‹‹þŠ‹‹üŒ‹‹ŒŒþŒ†‡û†‡‡ˆ‡‡ˆô‰ˆˆ‰‰ˆ‰‰Š‰‰ŠŠþ‹ŠŠ‹Œþ‹ŒŒŒþ…††ú‡††‡†‡‡ˆþ‡ˆˆ‰ùˆ‰‰Š‰‰ŠŠý‹Š‹‹Œü‹Œ‹ŒŒùŒŒŒ††þ…††ù‡††‡‡†‡‡üˆ‡‡ˆˆ‰Š‹òŒ‹ŒŒ‹ŒŒŒ†…††þ…††ü‡††‡‡ˆ‰þˆ‰‰ýЉŠŠý‹Š‹‹ýŒ‹ŒŒþŒ……†ü…†…††ý‡†‡‡ýˆ‡ˆˆ‰÷ˆ‰ˆ‰‰Š‰Š‰‰Šû‹Š‹Š‹‹Œû‹ŒŒ‹ŒŒ…õ†……††‡†‡‡†‡‡þˆ‡‡ýˆ‡ˆˆ‰ýЉŠŠ‹Œþ„……†‡þ†‡‡üˆ‡‡ˆˆ‰Š‹ýŒ‹ŒŒ…ü†…†……ù†…†‡‡†‡‡ ˆ‰þˆ‰‰Š‹ûŒ‹ŒŒ……†ü‡††‡‡ˆû‰ˆ‰ˆ‰‰úЉ‰Š‰ŠŠ‹þŠ‹‹þŒ„„…†þ…††ü‡††‡‡ýˆ‡ˆˆý‰ˆ‰‰Šþ‰ŠŠý‹Š‹‹üŒ‹‹„„…†‡üˆ‡‡ˆ ˆ‰úˆ‰‰Š‰ŠŠ‹þŠ‹‹þƒ„„…þ„……ü†……††þ‡††‡†‡ ˆý‰ˆ‰‰ýЉŠŠ‹„þ…„„…ü†……††ý‡†‡‡üˆ‡‡ˆˆþ‡ˆˆ‰Šþ‰ŠŠý‹Š‹‹þƒ„„…ô„……„……„……†…††‡†‡ˆû‰ˆ‰ˆ‰‰úЉ‰Š‰ŠŠ‹„øƒ„ƒ„„…„……†ý‡†‡‡þ†‡‡ˆþ‡ˆˆ‰ Šƒ„þƒ„„…ø„…†…††…††‡ü†‡†‡‡üˆ‡‡ˆˆù‰ˆˆ‰‰ˆ‰‰Šþ‰ŠŠø‹Š‹ƒ„ƒƒ„„ý…„……þ„……ü†……††‡ˆ‰þˆ‰‰õЉ‰Š‰Š‰‹ŠŠƒƒ„…þ„……†þ…††‡þˆ‡‡ˆø‰ˆˆ‰ˆ‰Š‰‰Šþ‚ƒƒ„…þ„……ý†…† †‡ˆþ‡ˆˆù‰ˆˆ‰‰ˆ‰‰Šý‰Šƒƒ„…„ú…„……†…… †‡ˆþ‰ˆˆ‰õŠ‰Š‰ŠŠ‚ƒƒ‚ƒƒý„ƒ„„ý…„……ý†…††þ‡††‡ˆü‡ˆ‡ˆˆ‰Š‰þŠƒƒþ‚ƒƒ„ƒ„û…„…„……þ†……†ü‡††‡‡ˆô‡ˆˆ‡ˆˆ‰ˆˆ‰ˆ‰‰øŠ‰‰‚ƒƒ‚ƒƒû„ƒ„ƒ„„ý…„……ý†…† †‡ˆ‰‚úƒ‚‚ƒ‚ƒƒý„ƒ„„ý…„……ý†…††ü‡††‡‡ˆþ‡ˆˆþ‰ˆˆ‰üˆ‰‚‚ýƒ‚ƒƒþ‚ƒƒ„ …†‡†ý‡†‡‡ûˆ‡ˆ‡ˆˆþ‰ˆˆû‚‚‚‚ƒþ‚ƒƒý„ƒ„„û…„…„……†ø…††‡†‡†‡‡ˆø‰ˆ‰ˆ‰‚‚‚úƒ‚‚ƒ‚ƒƒù„ƒƒ„„ƒ„„ý…„……†þ…††‡þ†‡‡ˆþ‡ˆˆ‰‚þ‚‚üƒ‚‚ƒƒ„þ…„„…ý†…††ü‡††‡‡ýˆ‡ˆˆø‚‚‚‚‚ƒ„…þ„……†ú‡††‡†‡‡ˆþ‰ˆøüùøùøøùø ùþøùù øüùøùøøðùøøùøøùùøùøøùøùøøþùøøùþøù ùøþ÷øøþùøøþùøøþùøøþùøøùûøùøøùùøùùøùøøùøùùøþ÷øø÷ùøùùøùùøùùøùøùþøùùþøùùúøù÷ø÷øøýùøùùûøùùøùùøùøùøøùøùøøùøùùýøùøø÷ øþùøøþùøøþùøøùøúùøùùøùùøùþ÷øøû÷øø÷øøþùøøüùøùøøýùøù ùøùþ÷øø÷øþùøøùøùøùøýùøùùóøùùøùùøù÷øø÷øøþùø øùøþùøøýùøùùøýùøùùþøùùøùøþ÷øøþùøøþùøøþùøøûùøøùøøùùøùøøùøùù÷øùøø÷øø÷øøþ÷øøþùøøþùøøþùøøþùøøùøüùøøùùúøùøùøùù÷øþ÷øøùøûùøøùøøüùøøùùüøùøùùñøùùøùùøø÷ø÷øø÷øøùøüùøøùùøùúø÷øø÷øø÷øþ÷øøþùøøþùøøùøøùøùøøùùøøùøü÷øø÷÷øþ÷øøþ÷øøùøùøùøþùøøöùøùùøùø÷÷øøü÷øø÷÷ øþ÷øøþùøøúùøøùùøøùüøùùøø÷ø÷ýø÷øøþ÷øøþùøøùøùôøùùøøùøø÷ø÷øøû÷øø÷øøú÷ø÷øø÷÷øùøûùøøùø øùýøùøø÷öø÷ø÷øø÷ø÷øøþ÷øøþ÷øøþ÷øøüùøøùùþøùùøþùøøùþø÷÷øü÷ø÷øøó÷ø÷÷øø÷øø÷ø÷ø øþùøøûùøùùøøùùøùùøøùùéøùø÷øø÷÷øø÷÷øø÷øø÷÷øø÷øøþ÷øøþ÷ø øþùøøùøûùøùøùùúøù÷ø÷øø÷ø÷øþ÷øø÷øþùøøþùøøþùøøù÷ùø÷ø÷øø÷÷øó÷ø÷øø÷ø÷øø÷÷øøûùøøùøøüùøøùùõø÷÷ø÷÷øø÷÷øøú÷øø÷÷øøü÷ø÷øø÷øùýøùøøùýøùøø÷þø÷÷íø÷ø÷÷ø÷øø÷ø÷÷ø÷øø÷øøþ÷øøùýøùøøýùø÷÷õø÷÷øø÷ø÷ø÷øøþ÷øø÷ûø÷ø÷øøü÷ø÷øøþ÷øøüùøùøøûùøùøùùøùùøø÷÷ø÷÷üø÷ø÷÷÷ø÷÷ø÷÷ø÷øøþ÷øøþ÷øøùýøùøø÷øã÷ø÷÷ø÷øø÷øø÷ø÷÷øø÷ø÷øø÷øø÷ø÷øøýùø÷÷þø÷÷øò÷ø÷øø÷ø÷÷øø÷÷ø øþ÷øøüùøùøøûùøøù÷÷þø÷÷ùø÷øø÷ø÷÷øû÷øø÷øøþ÷øø÷ øþùø ø÷þø÷÷ø÷üø÷ø÷÷øþ÷øø÷øþ÷øøþ÷øøþ÷øøþ÷øøùøýùø÷÷ø÷øý÷ø÷÷ýø÷øøþ÷øø÷øþ÷øøþ÷øø÷þø÷÷þø÷÷õø÷÷ø÷øø÷øø÷÷øþ÷øøþ÷øø÷øþùøøûùøùø÷÷ø÷þø÷÷øø÷ø÷ø÷÷øøþ÷øøñ÷øø÷ø÷øø÷ø÷ø÷÷øøþù÷÷þø÷÷÷ø÷÷øø÷øø÷÷ýø÷øøü÷ø÷øøö÷ø÷÷ø÷øø÷øøþ÷ø ø÷üø÷÷øø÷îø÷ø÷÷øø÷øø÷÷ø÷ø÷÷øøþ÷øøû÷øø÷øøþ÷ø ø ÷ùø÷÷ø÷ø÷÷øþ÷øøù÷ø÷ø÷÷øø÷øþ÷øøþ÷ø ø÷øþ÷øø÷øõ÷ø÷ø÷øø÷ø÷øøü÷ø÷øø ÷üø÷ø÷÷þø÷÷øþ÷øøü÷øø÷÷øû÷øø÷øøþ÷øø÷÷ø÷øø÷÷øø÷÷úø÷ø÷÷øø÷ø÷ø÷ø÷ øþö÷ ÷ø÷ø÷ø÷ø÷øü÷ø÷øø÷ñø÷ø÷ø÷ø÷øø÷ø÷ø÷÷ùø÷ø÷÷ø÷÷üø÷÷øøú÷øø÷ø÷÷øþö÷÷ö÷þø÷÷þø÷÷ùø÷ø÷øø÷÷öø÷÷ø÷ø÷ø÷øøþ÷øøþ÷øø÷þö÷÷ø÷þø÷÷ø÷øø÷÷ø÷ø÷øø÷ýø÷øø÷ýø÷øøþ÷øø÷ùø÷ø÷÷ø÷÷ø÷ø÷þø÷÷ðø÷øø÷ø÷ø÷ø÷ø÷øø÷÷þø÷÷þø÷÷þø÷÷ø÷ø÷øü÷ø÷øøù÷ø÷øøö÷÷þø÷÷ø÷üø÷ø÷÷ø÷ùø÷øø÷÷øøþö÷÷úö÷ö÷ö÷÷þø÷÷øø÷÷ø÷øø÷÷øø÷÷ø÷øø÷÷øø÷øø÷÷ø÷øø÷÷øø÷ö÷öö÷÷úø÷ø÷ø÷÷úø÷÷øø÷÷ø÷øþ÷øø÷øþö÷÷þö÷÷þö÷ ÷ùø÷ø÷øø÷÷îø÷ø÷÷ø÷ø÷ø÷ø÷ø÷øø÷÷üö÷ö÷÷þø÷÷þø÷÷þø÷÷þø÷÷ø÷øù÷øø÷ø÷øø÷þö÷÷þö÷÷þö÷ ÷þø÷÷ìø÷÷ø÷øø÷øø÷÷ø÷ø÷øø÷øøý÷ø÷÷ö÷þö÷÷þö÷÷þö÷÷þø÷÷ø÷ø÷õø÷øø÷÷ö÷÷ö÷÷þö÷÷þö÷÷þø÷ ÷þø÷÷÷ø÷÷ø÷÷ø÷øøþ÷öö÷þö÷÷ùö÷öö÷ö÷÷ûø÷÷ø÷÷ø÷÷ø÷øø÷÷ø÷÷ûø÷÷ö÷#÷÷ø÷÷ø÷ø÷ø÷÷þø÷÷øô÷øø÷ö÷ö÷÷öö÷÷üö÷ö÷÷ø÷ø÷èø÷÷øø÷ø÷÷ø÷ö÷öö÷÷öö÷÷öö÷÷þö÷÷ö ÷þø÷÷þø÷÷úø÷ø÷÷øøú÷ø÷ø÷øøöþ÷ööý÷ö÷÷ö÷þö÷÷þö÷÷þø÷ ÷ø÷þø÷÷ö÷ö÷öö÷ö÷÷ö÷ö÷ö÷÷þö÷ ÷þø÷÷óø÷÷ø÷ø÷ø÷øøö÷÷öþ÷öö÷ûö÷öö÷÷þö÷÷þö÷ ÷ø÷æø÷ø÷÷øø÷øø÷ø÷ö÷ö÷÷ö÷÷ö÷öö÷÷ûö÷öö÷÷ö÷þö÷ ÷þø÷ ÷üø÷ø÷÷éø÷ö÷ö÷öö÷öö÷öö÷÷ö÷öö÷ö÷÷þö÷÷þö÷ ÷þø÷÷÷ø÷ø÷ø÷÷ø÷÷øüö÷÷ööú÷ö÷ö÷ööý÷ö÷÷ûö÷÷ö÷÷þø÷÷ø÷úø÷ø÷ø÷÷ÿŽúŽŽŽþþ‘‘’þ‘’’ý“’““”ú•””•”••–ŽýŽ‘’ý“’““ý”“””û•”•”••ýŽŽŽþþ‘‘’“þ’““ü”““””•öŽŽŽŽŽö‘‘‘’ø‘’‘’’“’““ü’““””þ“””ø•”••””•ŽŽü‘ü’‘‘’’“þ’““”•ü”ŽŽþŽŽüŽŽ ‘’ý“’““ý”“””ŽýŽþ‘’þ“’’“ú”“””“””ý•”ŽøŽŽŽŽþý‘ù’‘’‘’‘’’þ“’’“ü”““””ýŒýŽŽŽþŽŽþþ‘‘’‘’“þ’““”ŒúŽŽŽŽ÷‘‘‘’ú“’’“’““ú”“”“”ŒŒýŒ Žú‘‘‘‘’ý“’““þ”““ŒŒýŽŽŽüŽŽþ‘þ‘‘’“ü”““ŒŒþŒŒýŽŽŽû‘‘‘‘’“û”ŒŒ‹ŒŒúŒŒŒûŽŽŽŽü‘þ‘‘þ’‘‘’“ù’“”“Œ‹ŒŒúŒŒŒŽþŽŽ‘ý‘’ ’“û‹Œ‹‹ŒŒþŒŒýŽŽŽþŽ‘‘’“‹ýŒ‹ŒŒþŒŒûŒŒŽŽþŽŽý‘þ‘‘’û“’’Š‹‹úŒ‹ŒŒ‹ŒŒýŽŽŽùŽŽŽü‘‘‘þ‘‘’ú“’“’Š‹‹ŒŽüŽŽŽþ‘þ‘‘’󊋊‹‹ŒŒ‹‹ŒŒ‹ŒŒýŒŽüŽŽŽúû‘‘‘‘’ü‘’’ŠŠý‹Š‹‹ ŒŽ÷ŽŽŽŽŽü‘‘‘ý’‘’’Š‹üŒ‹‹ŒŒŽþŽŽø‘÷’‘’‘‘‰ŠŠ‹‹þŠ‹‹ûŒ‹Œ‹ŒŒýŒŽŽýŽþ‘û’‘’‘ŠŠ‹ŒûŒŒüŽŽŽþú‘‘‘‘þ’‰‰Šü‹ŠŠ‹‹Œþ‹ŒŒýŒ Žûú‘‘‘‘‘‰ýЉŠŠ‹Š‹þŒ‹‹÷Œ‹‹ŒŒŒŒýŽŽŽþŽý‘ü‘‘‰‰Š‹Œð‹ŒŒŒŒŽŽŽŽþŽŽýþ‘‰ýЉŠŠü‹ŠŠ‹‹Œ÷‹ŒŒŒŒûŽŽŽŽýŽþú‘‘‘ˆ‰‰ýЉŠŠ‹üŒ‹‹ŒŒýŒŽþŽŽô‘ˆ‰ˆ‰‰Š‰Š‰ŠŠù‹Š‹Š‹Š‹‹ýŒ‹ŒŒ ŽýŽþüˆ‰ˆ‰‰ýЉŠŠü‹ŠŠ‹‹ŒþŒŒúŽŽŽŽûŽŽþˆü‰ˆˆ‰‰ýЉŠŠþ‰ŠŠý‹Š‹‹ûŒ‹Œ‹ŒŒûŒŒýŽŽŽèŽŽŽŽˆ‰ˆˆ‰‰ˆ‰‰þЉ‰Šý‹Š‹‹þŒ‹‹ŒýŒŽ÷Žˆˆý‰ˆ‰‰þˆ‰‰üЉ‰ŠŠ‹þŠ‹‹Œþ‹ŒŒþŒüŽŽŽúˆ‡ˆˆý‰ˆ‰‰Šü‹ŠŠ‹‹úŒ‹ŒŒ‹ŒŒþŒŽýŽþˆˆý‰ˆ‰‰þˆ‰‰ýЉŠŠ‹üŒ‹‹ŒŒüŒŒŽýŽþ‡ˆˆú‰ˆ‰‰ˆ‰‰Š‹þŠ‹‹Œ‹ŒŽþŽŽýŽþˆ‡‡ˆ‰ˆ‰úŠ‰ŠŠ‰ŠŠý‹Š‹ ‹ŒýŽŽŽ‡üˆ‡‡ˆˆ ‰Š‹þŠ‹‹ýŒ‹ŒŒýŒýŽŽŽûŽŽ‡‡ˆ‡ˆ‰þˆ‰‰Šþ‰ŠŠ‹Œ‹ŒŽŽý†‡‡ˆþ‡ˆˆü‰ˆˆ‰‰ Š‹Œü‹Œ‹ŒŒøŒŒŒŒŽþŽŽü††‡‡ýˆ‡ˆˆ‰ Šý‹Š‹‹ýŒ‹ŒŒüŒŒýŽŽŽ†‡üˆ‡‡ˆˆý‰ˆ‰‰ýЉŠŠ‹ŒüŒŒŽþ††‡þ†‡‡ýˆ‡ˆˆý‰ˆ‰‰Šþ‰ŠŠ‹üŒ‹‹ŒŒýŒþŒŽ†û‡†‡†‡‡ýˆ‡ˆˆþ‰ˆˆ‰Š‰Šú‹Š‹‹Š‹‹ŒþŽþ…††‡þ†‡‡þˆ‡‡ˆý‰ˆ‰‰Šþ‰ŠŠ‹ýŒ‹ŒŒüŒŒþކ†‡ˆ‡ˆü‰ˆˆ‰‰üЉ‰ŠŠ‹üŒ‹‹ŒŒúŒŽ…††‡†‡þˆ‡‡ˆú‰ˆ‰‰ˆ‰‰Šú‹ŠŠ‹Š‹‹ýŒ‹ŒŒŒ… †‡ýˆ‡ˆˆ‰ôЉ‰Š‰Š‰ŠŠ‹Š‹‹öŠ‹ŒŒ‹Œ‹Œ‹ŒŒöŒŒ……†…††‡ýˆ‡ˆˆü‰ˆˆ‰‰Šþ‰ŠŠø‹Š‹‹Œ‹Œ‹‹Œ…†ý‡†‡‡ûˆ‡ˆ‡ˆˆ‰õˆ‰‰ˆ‰‰Š‰Š‰ŠŠ‹Œþ‹ŒŒþ„…… †‡ˆþ‡ˆˆý‰ˆ‰‰Š‹þŠ‹‹ýŒ‹ŒŒ„ø…„…††……††‡üˆ‡‡ˆˆ‰ˆ‰Šþ‰ŠŠþ‹ŠŠ‹þŒ‹‹Œ…ù„……„……††þ‡††ý‡†‡‡üˆ‡‡ˆˆû‰ˆ‰ˆ‰‰Šþ‰ŠŠ‹þŠ‹‹ýŒ‹ŒŒü„…„……þ†……†‡üˆ‡‡ˆˆ‰ˆ‰ýЉŠŠþ‰ŠŠ‹Œ„ú…„……„……†‡ˆù‰ˆˆ‰‰ˆ‰‰Šý‹Š‹‹ýŒƒ„„…ý†…††‡ø†‡‡ˆ‡ˆ‡ˆˆú‰ˆ‰‰ˆ‰‰Š‹úŠ‹‹Œ‹„„ü…„„……†ý‡†‡‡÷ˆ‡ˆˆ‰ˆ‰ˆ‰‰þЉ‰Šý‹Š‹‹üƒ„ƒ„„…þ„……†þ…††ý‡†‡‡ˆû‡ˆˆ‡ˆˆû‰ˆ‰ˆ‰‰ûЉЉŠŠ‹ƒ„þ…„„…ü†……††‡òˆ‡‡ˆ‡‡ˆ‡ˆˆ‰‰ˆ‰‰Šþ‰ŠŠ‹ƒ„þƒ„„…û†…†…††ú‡†‡‡†‡‡ýˆ‡ˆˆ‰ýЉŠŠ‹üŠ‹‹ƒƒ„þƒ„„…†‡†‡øˆ‡ˆ‡ˆˆ‰ˆˆ‰ùЉ‰ŠŠ‹ŠŠƒû„ƒ„ƒ„„…þ„……†ý…†……†‡þ†‡‡ˆ‰Š÷‰ŠŠ‹Šƒƒ‚ƒƒ„þƒ„„ý…„……ý†…††‡ˆ‰þˆ‰‰üЉ‰ŠŠ“û”“”“””ú•”•””••–þ•––ý—–——˜—˜ ™š“ý”“””•þ”••–—˜ú™˜™™˜™™ýš™ššý“’““”þ“”” •ý–•––—ú˜—˜——˜˜ý™˜™™šþ’““ý”“””•–•–—þ–—— ˜™úš™š“’““”ü•””••–—˜þ—˜˜™þš™™’“þ’““”ô•”••””•”–••––—þ–——ü˜——˜˜þ™˜˜™þš’’“þ”““”ú•””•”••–ý—–——ú˜——˜—˜˜™þ˜™™þš’’“’“”ý•”••–•–ù—–——––——˜þ—˜˜™˜™’ý“’““û”“”“””ó•””••””••–••––—û–—––——ù˜—˜—˜—˜˜™û‘’‘‘’’“ú’“”“”““”ý•”••ü–••––—–—þ–—— ˜™þ‘’’û“’“’““ý”“””•–ü—––——û˜—˜˜——˜ý™˜‘‘ý’‘’’“”þ“””ý•”••–þ•––ü—––——˜þ—˜˜ü™˜˜‘‘ ’ “”þ•””• –—ü–——˜˜‘’‘’“’“”þ“””ý•”••ù–••–••––ý—–——þ˜——˜ü—˜˜‘‘ü’‘‘’’û“’“’““”“”•þ”••–þ•––—ü˜——˜˜‘’‘’“þ”““”•þ”••–þ•––—ù˜—˜—‘‘’“”•”ù•”••––••–ù•––——–——þ˜‘’þ“’’ý“’““”þ“””•þ”••–•–ú—–——–——þ˜‘þ‘‘’þ‘’’“”þ“””•ü–••––ú—–—––——þý‘‘‘ý’‘’’“ù”“””““””•þ”••–û•––•––—ú–——–—‘’ú“’’“’““ý”“””þ“”” •–—ý–—‘’ú“’“’’““”þ“””ý•”••–•–—þ–ýû‘‘‘‘’þ‘’’ú“’“’’““ý”“””•þ”••–þ—––ô‘‘‘ ’“ú”“””“””ü•””••ü–••––—þý‘‘‘’‘’“þ’““ ”•þ–••–‘þ‘‘ü’‘‘’’ý“’““û”“”“””ø•”•”••”••–þŽü‘þ‘‘ð‘‘’’‘‘’‘’’“’“’““”ú•”••”••þ–••÷‘‘‘‘‘’“’“ù”““”““””û•”•”••þ–••Žù‘‘‘‘’‘’ý“’““ý”“””•”•ûŽŽŽ‘ý’‘’’“þ’““”ü“”“””•”ò•”••–•ŽŽŽŽýû‘‘‘‘ý’‘’’“þ’““”ø•”•”••–ŽŽþ ‘ý’‘’’“þ’““”•ŽþŽ‘‘’‘’“û”“”“””•ý”•ŽŽŽûŽŽþ‘þ‘‘’ù“’’“’’““ý”“””þ“””û•ŽŽŽõŽý‘‘‘’û‘’’‘’’“”ø“””•””•ŽŽùŽŽŽŽŽýû‘‘‘‘ü’‘‘’’û“’“’““û”“”“””ø•”ŽŽŽŽüý‘‘‘’þ“’’“þ’““ý”“””ŽþŽŽþý‘‘‘’þ‘’’ü“’’““þ”““”ŽüŽŽŽûŽŽ ý‘‘‘ý’‘’’“ú”“””ŒŽüŽŽýü‘‘‘’‘’ý“’““”ø“ŒŒŒŽüŽŽý‘÷‘‘’‘’’‘’’ü“’’““ü”“”ŒŒýŒŽŽú‘‘‘‘’ý“’““ŒŽúŽŽŽŽŽû‘ù’‘‘’‘‘’’“þ‹ŒŒ üŽŽŽýŽþ‘’þ“’’“þ’ŒŒþŒŒŽü‘þ‘‘û’‘’‘’’þ“ŒŒþ‹ŒŒþŒŒýŽŽŽþŽ÷‘‘‘‘‘’“úŒ‹‹Œ‹ŒŒûŒŒŽŽúŽŽŽý‘ù‘‘’‘‘’’‹Œ‹Œ ŽúŽŽŽý‘‘‘ö‘‘’’‘’’‘’’‹þŒ‹‹ŒþŒŒýŒŽþŽŽþý‘ü’‘‘’’þŠ‹‹ûŒ‹Œ‹ŒŒþŒýŽŽŽŽþü‘‘‘þ‘‘’‹ýŒ‹ŒŒüŒŽŽþŽŽýŽýû‘‘‘’úЋЋЋ‹Œþ‹ŒŒûŒŒŽŽþŽý‘ú’‘‘’’ŠŠù‹ŠŠ‹‹Œ‹‹Œû‹ŒŒŒŒŽŽýý‘‘‘ø’Š‹ŠŠ‹Š‹‹üŒ‹‹ŒŒþŒŽþŽŽüŽŽúŽ‘þ‘‘Šý‹Š‹‹Œþ‹ŒŒŽüŽŽþ‘‘Š‹þŠ‹‹Œþ‹ŒŒŒŽýú‘‰‰ŠŠ‹þŠ‹‹üŒ‹‹ŒŒþŒŒüŽŽŽýŽ‘þЉ‰Šù‹Š‹Š‹Š‹‹üŒ‹‹ŒŒŽýŽŽŽýý‘‰‰Šþ‰ŠŠý‹Š‹‹Œþ‹ŒŒúŒŽŽŽþŽý‘‰‰Šþ‰ŠŠ ‹ŒýŒúŽŽŽŽüŽŽþ‘‰‰ Š‹ŒŒŽþŽŽûŽŽþˆ‰‰Šþ‹ŠŠ‹ŒýŒýŽŽŽûŽŽþˆ‰‰Šù‰ŠŠ‹ŠŠ‹‹þŠ‹‹Œþ‹ŒŒüŒŒ Žüþˆ‰‰Š‰Š‹üЋЋ‹ŒýŽŽŽùŽŽ ùóúùùúùùúùúúùúùùúùöúùùúùúúùùúúþûùùþúùùöúùùúùùúùúùùúòùúúùùúúùúúùúùúúþùú ú ù÷úùúùúùùúùù÷úùúùùúùùúúúùúùúùúúþùúúþùúúþùúúùþúùùþúùùúùúùýúùúúùúþùúúþùúúþùúúùþúùùöúùùúùùúùùúúýùúùùþúùùúùýúùú úùþøù ùþúùùþúùùùúùùúúùúúùúûùúùùúúþùúúùþøù ùûúùùúùùúùûúùùúùùüúùùúúþùúúùûúùúùúúùûúùùúùùþúùù÷úùúúùúùúùùúùùúùùúùùúúùúùïúùúùúùùúùúùùúùùúùùýúùúú÷ùúúùúùùøùùþúùùþúùùðúùùúùúùúùùúùúúùúúöùúùùúùøùøùùø ùüúùúùùúùøúùúùùúùúúùúôùøøùøøùøùùøù ùþúùùúùûúùùúùùýúùúúùþúùùúüùúúù ùþøù ùþúùùøúùúúùúúùùúùõúùúùúúùúúùúúûøùùøùùúþùúúùþúùù÷úùúúùúúùúúýùúøøùøùþúùùþúù ùøúùúùúùúùùúøùúùúúùøùùþøùùüøùøùùþúùùúýùúùùúùúôùúøùùøøùøùøùùüøùøùùþúù ùúùþúùùüúùúùùþúùùüøùøù ùþøùùþøùùþúùùúùúùþúùùúùñúùøøùøùùøùøùøøùùþøùùþøùùþúùùþúùùôúùùúùùúúùùúùùþúùùøøùøùøùøùùøùþøù ùþúùùúùþúùùúúùúúùùúúþùúúûùøøùøøùþøùùúøùøùøùùöúùúùùúùùúùùþúùùøúùúúùúùøøûùøùøùùþøùùþøùùþøùùþúùùüúùúùùúñùúùùúøùùøùùøùùøøùþøùùùøùùøùøùùúùúùúüùúùøøöùøùøùøùùøùùøùñúùùúùùúùúùùúùúùùøúùúúùúùøøýùøùùøöùøøùøùøùøùùøúùúùùúúùùúùúùþúùùøùýøùøøúùøùøøùùøùûøùøøùùþøùùúùþúùùþúùùøúùùúúùùøøùùøøùøùøøùøùûúùùúùùýúùøø÷ùøùøøùùøùùúøùøùøùùøùþúùùþúùùôúùúúùùøøùøùøøþùøøýùøùùøùøùø ùûúùùúù ùþúøøùøúùøùøøùùøùøùøùþúùùýúùøøþùøøùùøøùøùøøùùøùùøøùùþøùùþøùùûúùúùøøùøùøüùøøù%ùþúùùþúùùøðùøøùøùøùøùùøøùøùùûøùùøùùøùþøùùûúùúùúúøþùøøüùøùøøöùøùùøøùøøù ùüøùøùùþøù ùþúùù øùûøùøùøøùûøùùøù ùþøù ùþúùùøùøúùøùøùøøùøùþøùùöøùùøùøùùøù ùúùøùýøùøøþùøøùûøùùøùùþøùùþøù ùþúùùøùøùøùöøùøùùøøùøùùøýùøùùýúùøøþùøøüùøùøøùøûùøøùøøýùøùùúøùùøøùùþúùùøùùøùùøùøøùøùûøùøøùùþøùùþ÷øøùøùøþùøøùüøùùøøùøùþøùùþøù ù øþùøøúùøøùøùùøýùøùùþøùùøýùøùùþøùùþ÷øøùøùøóùøøùøùøùøøùøùùøüùøøù ùøþùøøþùøøøùøùøùøøùùþøùùûøùùøù ùø÷ øþùøøøùøøùøøùøøùþøùùøøùøùùøøùùøþùøøúùøøùùøøþùøøùøùø÷ùøøùøùøøùùøû÷øø÷ø øûùøøùøøüùøùøøùùøùøùøøùùøùþøùùþøùùü÷ø÷øøþùøøþùøøùøùþøùùþøùùþøùùøþùø øúùøøùøù ùøùøùøü÷ø÷øøþ÷ø øþùøøüùøøùùìøùùøøùøùùøøùøùùøùùøùùøùøþ÷øøùûøùùøùùøùøù÷øùùøùøùùøøþ÷øøþ÷ø øþùøøþùøøùùøùøøùøø ùüøùùøøþ÷øøþùøøþùøøòùøùøùøùøùøùøùøøùùøùøùøùùûøùøø÷÷üø÷÷øøþùøøýùøùùøýùøùù÷øùùøùùøøùùýøùøøü÷ø÷øøü÷ø÷øøù÷øùøøùùøøùùôøùùøùùøùùø÷øøþ÷øøþ÷ø ø÷ùøùùøùøùøøùüøùùøøùùøùøùøùùøû÷ø÷÷øøù÷ø÷÷ø÷øøùûøùùøùùôøùùøøùø÷÷ø÷øøüùøùøøüùøøùùýøùøøùýøù÷÷þø÷÷øý÷ø÷÷øùøþùøøóùøùùøøùøùù÷ø÷÷ýø÷øøþ÷øøþ÷øøùøþùøø÷ùøøùùøùùøø÷ýø÷øøþ÷øøü÷ø÷øøüùøùøøùøùø÷øþ÷øøü÷øø÷÷ýø÷øø÷øþ÷ø øøùøøùøùùø øùöøùø÷÷øø÷ø÷÷ùø÷÷øø÷øøþ÷øøùøýùøùùôøùùøøùø÷÷øø÷÷ýø÷øø÷ûø÷ø÷øøùøøùøùøùùøùÿ–þ—––—˜ý™˜™™š›œýœõž–•–•––——–——þ˜——˜ú™˜™™˜™™üš™™ššý›š››œýœú–••–•––—þ–——ý˜—˜˜ý™˜™™þš™™š›þš››œþ›œœþ–••–—˜þ—˜˜ú—˜™™˜™™šþ™ššü›šš››ýœ›œœ÷œœ••–•––ý—–——ý˜—˜˜ü™˜˜™™šþ™ššý›š››œ›œ•–—˜þ—˜˜™þ˜™™šü™š™šš›þš››üœ››œœýœ••ü–••––—ú˜—˜˜—˜˜™˜™šü›šš››œþ”••–þ•––ý—–——ý˜—˜˜ü™˜˜™™šþ™ššý›š››œ›œþ”••ö–•––•––—–——ü˜——˜˜™šþ™ššü›šš››üœ››œœ”•”•ý–•––ý—–——û˜—˜—˜˜ý™˜™™ûš™š™šš›œþ“””•–þ•––—˜ü™˜˜™™ûš™š™ššü›šš››”ø“””••””••–þ•––—˜™þ˜™™šþ™šš›ü“”“””•ý–•––û—–—–——˜™û˜™™˜™™š›þ”““”ü•””••ý–•––þ—––—˜þ—˜˜™šþ™ššþ›šš“”•þ–••–—û–——–——˜—˜ý™˜™™þš™™š›þ’““ù”““””•””•ù–•––••––—þ˜——˜™û˜™™˜™™ûš™š™ššú›šš“’““”•û–•–•––ü—––—— ˜ý™˜™™šþ™šš“ý”“””ý•”••þ”––•–ú—–—˜˜——˜™ýš™šš’“ó”“”“””•””••”••ù–••–••––—û–——–——û˜—˜—˜˜û™˜™˜™™õš™š™š’“’“’““ ”•ý–•––þ•––—˜þ—˜˜™ùš™š™’’““þ’““”ý•”• •–—˜þ—˜˜ü™˜˜™™þš’’ý“’““”ú•””•”••ü–••––ü—––——˜ý™˜™™ ’“ý”“””ý•”••–þ•––ò—––——–——˜—˜˜—˜˜ý™˜™™úš’‘’‘’’“”“”•þ”••–—–—û˜—˜—˜˜™þ˜™™‘’ý“’““”þ“””ú•”••”••–ø•––——––——˜—˜ý™˜™™‘’“”þ“””•– —˜™ù˜™™‘‘’‘‘’ý“’““”þ“””ü•””••–þ•––ý—–——˜þ™˜˜þ™‘‘ú’‘’’‘’’ú“’’“’““ý”“””ü•””••þ–••–ý—–——þ˜——˜þ™‘‘ý’‘’’“þ’““”þ“””ý•”••–þ•––ü—––——þ–——ü˜——˜˜þ‘‘þ‘‘’ù“’’““’““”þ“””þ•””•þ”••ý–•––—˜‘’“”þ“””•þ”••–ù•––——–——û˜—˜—˜˜ý‘‘‘þ’‘‘’ý“’““”þ“””•þ”••þ–••–ü—––——ý˜—ý‘‘‘ý’‘’’“’“ü”““””ý•”••þ–••–ü—––——˜ù‘‘‘‘‘û’‘’‘’’ý“’““þ”““” •ý–•––—ú˜—‘‘’ý“’““”þ“””ý•”••–•–—‘þ‘‘’ü‘’‘’’ý“’““þ”““”•–þ—––— ø‘‘‘’‘’’ü“’’““”þ“””û•”•”••–ú—––——ýý‘‘‘þ’‘‘’“”“”•þ”••–—þŽþý‘‘‘ú’‘‘’‘’’“þ’““”• –þŽ‘þ‘‘’þ‘’’ü“’’““ ”•–þ•––þ‘ý’‘‘ý’‘’’ý“’““”ü“””••–ú•––ŽŽŽùŽþ‘ý’‘’’“þ’““”“”þ•””•û–•––ŽŽþŽþü‘‘‘ý’‘’’“û’““’““ü”““””û•”•”••û–•––ŽŽýŽó‘‘‘‘‘’þ“’’“”þ“””•þ”••ŽýŽŽþŽý‘þ‘‘ ’“”•ýŽŽŽøŽŽ‘‘þ‘‘’ü‘’‘’’“þ’““ü”““””ü•””••ýŽŽŽþŽŽø‘ý’‘’’“’“”ü“””••ø”••”ŽŽüŽŽ‘ü’‘‘’’“”“”þ•””•ŽŽþ‘þ‘‘ø’‘’’“’’““”õ“”“””•””••ýŽŽŽûŽŽû‘’þ‘’’“ý”“””ü•”ŒŽýŽ‘ü‘‘‘÷’‘‘’‘’‘“’’“ù”““””“””þŒŽŽ÷‘‘‘ý’‘’’“ý”“””ŒüŒŒŽ ‘‘þ’‘‘’“”“”ŒúŒŒŽþŽŽöŽŽŽþ‘û‘‘’‘‘’ú“’“’’““ø”“””ŒŒŒŒŽþü‘‘‘’“”‹ŒîŒŒŒŽŽŽŽŽŽŽýŽýü‘‘‘ö’‘’‘’“’“’““ŒúŒŒŒŽþŽŽúþ‘û‘‘‘’’þ‘’’“þ‹Œ ŒùŽŽŽŽŽ‘þ‘‘’þ‘’’“ú‹ŒŒ‹‹ŒŒŽûŽŽü‘þ‘‘’“ü’““‹‹Œþ‹ŒŒþŒûŽŽŽŽ‘ü’‘‘’’ü“’’‹‹ŒýŒŽõŽŽ ‘÷’‘’’“’’Š‹‹ýŒ‹ŒŒþŒŒŽîŽŽŽŽ‘‘’Š‹Œ‹÷Œ‹ŒŒŒŒŽý‘ü’‘‘’’Š‹þŠ‹‹ ŒüŽŽŽù‘ý’‘’’þš› ›œžöžžŸžŸžŸžŸŸ Ÿ ý¡ ¡¡¢¡û¢š›š››÷š››œ›œ››œœùœœœžžŸúžŸŸ Ÿ   ¡ýš›šš›þœ››œùœœžžýŸžŸŸþ ŸŸ û¡ ¡ ¡¡š›þš››üœ››œœüœœýžžžŸý Ÿ  ù¡  ¡¡ ¡¡þ™ššþ›šš›œþ›œœ žþŸžžýŸžŸŸ ÷¡ ¡¡ ¡š™ššþ›šš›ûœ›œ›œœžøŸžžŸžŸžŸŸ þ¡™™šû›š›š››œ›öœœœœœœžþžžŸþžŸŸü ŸŸ  ü¡ ™ššþ™ššú›š››š››üœ››œœžþžžúŸžŸŸžŸŸô Ÿ  ¡  ™™š™ššú›šš›š››úœ››œ›œœüžžžüŸžžŸŸü ŸŸ  ™þš™™úš™šš™šš›þš››ýœ›œœþ›œœüœœýžžžŸòžŸŸ Ÿ Ÿ Ÿ  ™˜™™úš™™š™šš›ýœ›œœýœ žùŸžžŸžžŸŸü ŸŸ  ü™˜˜™™š›þš››œþœùžžžžýŸžŸŸ ˜ ™ýš™šš›üš›š››œûœœýžžžýŸžŸŸù˜™™˜™˜™™š› œüžžžþžžýŸžŸŸ˜û™˜™˜™™ýš™šš ›œúžžžžþŸžžŸ˜™˜™šþ™ššþ›šš›þœ››œýœžþžžýŸžŸŸ˜û—˜˜™˜˜™÷š™šš™šš™ššü›šš››œ›ýœ›œœ žŸžŸþž˜˜ú™˜˜™˜™™š›úœ››œ›œœþœœúžžžžŸžþ—˜˜þ—˜˜™û˜™˜˜™™ýš™šš›þœ››œþœ žüŸ——˜˜™þ˜™™šû™šš™ššý›š›› œžž—ù˜——˜——˜˜™þ˜™™šú›š››š››üœ››œœœžüžžž—þ˜——˜™ýš™šš›ýœ›œœüœœœýžžþ–——˜ý™˜™™šú™šš™™šš›š›÷š››œ››œ›œœýœžýž–——þ˜——˜™šü™š™šš›ûœ›œ›œœž–—þ–——˜þ—˜˜ú™˜˜™˜™™üš™™šš›úœ›œœ›œœûžž––þ—––—˜ ™ýš™ššü›šš››œþ›œœ–ý—–——˜þ—˜˜ ™š›œþœ–ý—–——˜™þ˜™™šü™š™šš›œþ›œœ–þ•––—ù˜——˜——˜˜™þ˜™™šö™šš››š››š››œûœ–•––—ú–——––——˜ý™˜™™šù›š›š›š››ýœ›œœþœœü••– –—˜û™˜™˜™™üš™™ššý›š››œü›œ›œœ•–þ•––ú—–——–——˜ý™˜™™þš™™šù™šš›šš››ýœ›œœ•ý–•––—þ–——ü˜——˜˜ü™˜˜™™šþ™šš›œþ›œœ•ý–•––ü—––——˜ö—˜˜™™˜˜™˜™™š™š›üš›š››üœ›œ››üœ””••–þ•––ü—––——ý˜—˜˜ü™˜˜™™þš™™šú›š›šš››œþ›””•ü–•–••–—ý˜—˜˜ý™˜™™ š›üœ››””•ú–••–•––—ý˜—˜˜û™˜™˜™™šþ™šš›ùš›œ››œ””•–þ•––—þ–——˜ý™˜™™ôš™š™šš›šš›š››÷“””•”•””••ü–••––—–—˜þ™˜˜™þ˜™™šþ›ššù›š››““””•ý–•––÷•––—–——–——˜ü™˜˜™™þš™™š›ý”“””•þ”••–õ•––—––——––——ý˜—˜˜™þ˜™™þš™™šþ›šš›“”ü•””••û–•–•––ü—––——ü˜——˜˜ü™˜˜™™ûš™š™ššö›š›““”“”“””ý•”••–þ•––—–—˜—˜û™˜™˜™™šø›š›““”“””•ú–••–•––—ü–—–——˜ý™˜™™šþ™šš“ú”““”“””ü•””••–÷—––——–—–——˜ý™˜™™úš™™š™šš“”þ“””•þ”••þ–••–ü—––——ý˜—˜˜ý™˜™™š’“þ”““”ý•”••û–•–•––û—–—–——ý˜—˜˜™öš™™šš’’“’““þ”““ý”“””•þ”••–ý—–——ü–—–——˜™þ˜™™š’“ý”“”” •–þ•––—ô–—–——˜——˜——˜˜™þ˜™™÷š™™’“’“’““”þ“””•þ”••ý–•––—þ–——˜—˜™’ý“’““”þ•””•þ”•• –—ü˜——˜˜™û˜™™‘’’“û’“’’““”ý•”• •ü–••––—ú˜—˜——˜˜þ™˜˜™‘’“þ’““”•”•–û—–—–——˜þ—˜˜™ý’‘’’ù“’’“’’““”ý•”••þ”••ú–••–•––ý—–——þ–——˜™ù˜‘‘’‘’‘‘ú’““’’““ý”“””ý•”••–þ•––þ—––—û˜—˜—˜˜þ™‘‘ú’‘’’‘’’“ý”“””•þ”••–þ•––ü—––——˜‘ý’‘’’ý“’““ý”“””•–þ•––ù—–——––——˜‘þ’‘‘’ü“’’““”þ“””ú•”••”••ü–••––ü—––——˜ù—˜—‘‘‘‘’ú‘’‘’‘’’“ö’““”““””“””•þ”••ý–•––—þ–——˜þ—‘‘ý’‘’’ý“’““ý”“””•ý–•––—–—ù˜‘‘‘‘ú’‘’’‘’’“þ’““ý”“””•–þ•––û—–—–——ý‘ù‘‘‘’‘’’þ‘’’ü“’’““”ù“””••”••–—þ–—— ‘’‘’“û’““”““”•þ”••–ø•–—––—–——ý‘‘‘’“þ’““ý”“””•þ”••–ý—–——üûúûúúþûúúöûúûúúûûúûúúþûúúûþúûûþúûûúûúþûúúûúûøúûúûúûúûûüüûûúúþûúúûôúûúûúúûûúûûúúûþúûûþúû ûúþûúúûüúûûúúþûúúûôúûúúûúûúûûúûûþúûûþúûûþúûû úþûúúû÷úûúûúûúúûûúûþúûûþúûûþúû û úûûúûûúúþûúúüûúúûûþúûûþúûûúþûúúûþúû ûúþûúúþûúúûýúûúúûúûþúûûþúûûúûþúûû úëûúúûûúûúûûúúûúûûúúûúûûúýûúûûþúû ûúøûúúûúûúûûúúûúûûúûûúù úûúþûúú÷ûúûúûúúûúúþûúúûþúûûú ûúþùúúûúþûúúþûúúùûúúûûúûûøúûûúûûúû ûúþùúúüûúûúúþûúúüûúúûûúûþúûûùúûûúûûúúûûúúûúúûúûúõûúûúûúûûúúûûþúûûúûùúúùú úûúúûúúûú úþûúúúûúúûûúúûùúûûúúùúúùûúúûúûúúøûúûûúûúûûúûþúûûúùýúùúúûûúûúûûúûúûþúûûúþùúúþûúúùûúûúûûúúû÷úûúûúúûúûûýúûúúüûúùúúûùúúùúúþûúúøûúúûûúúûûúþûúúûúûûúûúûûüùúùúúþûúúþûúúòûúúûúúûúûûúûúûûùúûûùúúùùýúùúúù úúûúúûûúúûûúûúûûú÷ûúûûúûûúûûùúûûúúùúúüùúùúúþûúúþûúúþûúúûûúûúûûùúûûúûûúúùúùúþùúúþûú úþûúúûþúûûúùúù÷úùúùùúùùúúþùúúþûúúþûúúûöúûúúûúûúûúúûúûúöûúúùúùùúùúúúùúùúùúúûûúûûúúüûúûúúûúýûúûûúùúþùúúþùúúþùúúþùúúþûúúþûúú÷ûúúûûúûùúúûùúúùúúùüúùùúúûùúúùú úûøúûúûúúûúúûøúûûúûúûúúþùúúùúúùùúùúúþùú úþûúúûûúúûúúþûúúþûúúùúüùúùúúùýúùúúùýúùúúþûúúüûúúûûúúûûúúùùþúùùúùúþùúúþùúúþùúúþùú úþûú úøûúûûúùùúúùúùúùúù$úúûúúûûùùúùúþùúúûùúùùúúûùúùùúúûúüûúûúúýùúùùðúùúùúùúùùúúùúùùúúúùúùúùúúþûúúûúþûúúýûúùùðúùúúùúùúùúùùúùùúúùúúùúúùúúûúþûúúûþúùùûúùùúùùúþùúúüùúùúúöùúúùúùúúùúúùúþûúúúûúùúúùù÷úùúùúùùúùùúùýúùúúþùúúþùúúþûúúùþúùùþúùùúúùúúùùúúüùúùúúúùúúùùúúþûúúþûùùúùüúùúùùøúùúúùúùúúüùúùúúþùúúþûúúþûúúùøúùúúùúùúúùùúùùúúùúúöùúùùúùúúùúúþùúúþûúúüûúûùùþúùùúóùúúùùúúùúùúúùùúþùú úþùú úóûúúùúùúùúùùúùùúüùúùúúùýúùúúþùúúûùúúùúúùþúùùùúùúúùúùùúùüúùúùùúþùúúþùúúþùúúþûúúþûùùþúù ùú÷ùúùùúúùúùùúûùúúùúúùýúùú ú ùþúùùôúùúúùúúùúùúùùúþùúúùúùúþùúúùúùúþùúúþùúú ùúù÷úùúùúùúúùùûúùúùúúþùú ú ùþúùùþúùùúýùúùùüúùùúúùúúùúúùùúúþùú úùùúùúúùùúúûùúùùúúùúùúùúþøùùúúùùúúùùõúùúùùúùúúùúúùúþùúúüùúúù ùþúùùûúùùúùùùúùùúùúùùúþùúúûùúúùúúùúùûúùùúùù÷úùùúùùúúùùûúùúùúúþùúúø ùþúùùúùþúùùþúùùûúùùúùùúôùúùúùúúùúúùúúúùúùúúù ùþøù ùûúùùúùùòúùùúùúùúùúúùùúú÷ùúúùúùúùúúùûøùùøù ùþúù ùþúùùúþùúúùúùùúùúúùúúýùúùùþúùùìúùùúùùúùùúúùùúúùúùúùùúúùúùùøùùüúùúùùûúùùúùùùúùùúúùúúþùúúùøùøùøøùùþøù ùþúùùûúùùúùùüúùúùùúþùúúùùúùúùùúúùøùøúùùúúùúùùúùüúùúùùúþùúúùþøùùþøùùûúùúúùùúùúùüúùùúúùúøùùøøùùþøùùþúùùúùþúùùýúùúúùýúùúúøûùøùøùùþøùùþøù ùþúù ùúùøúùúùùúùúúûùúùùøøýùøùùøøùùøùùøùùþøù ù÷úùúùùúùúùùþúùùóúùúùùúúùúøùùøøùþøùùþøùùþøùùþúùù÷úùúùùúùúùùúòùúúùøøùøùùøùøùùþøùùþøùùúùúùúùúùøøùøùøùøøùùþøùùüøùøùùþúùùúùõúùùúùùúùùúùÿûžžžžûŸžŸžŸŸû Ÿ Ÿ  ¡þ ¡¡¢þ£¢¢£¤¥û¤¥¥ž žŸþ ŸŸ ¡¢þ¡¢¢£¢£þ¤££¤ù¥¤¥¤¥¥žþžžŸþžŸŸý Ÿ  þ¡  ¡¢ü¡¢¡¢¢þ£¢¢ý£¢££¤¥üžžžýŸžŸŸ ¡þ ¡¡¢¡¢ú£¢££¢££¤¥žþŸžžŸ þŸ  ¡ý¢¡¢¢£¤£¤ú¥¤œœžžŸžŸø Ÿ ŸŸ Ÿ  ¡¢¡¢£¤þ£¤¤œüžžžýŸžŸŸ Ÿ ¡þ¢¡¡¢ý£¢££ð¤££¤££¤¤œœœžŸ Ÿ þ¡  ¡¢ý£¢££þ¢££û¤£¤¤œœýœžýŸžŸŸ þŸ  ¡þ ¡¡¢þ¡¢¢þ£¢¢£¤£þ›œœüœœýžžžŸþžŸŸ Ÿ ý¡ ¡¡ü¢¡¡¢¢£ü¤œ›œœøžžžžžŸü ŸŸ  ¡ü¢¡¡¢¢£ûœ›œ›œœýœýžžžüŸžžŸŸ ú¡  ¡ ¡¡ý¢¡¢¢£¢£ýœ›œœþ›œœýœžþžžüŸžžŸŸý Ÿ  ¡ý¢¡¢¢ý£¢££œþ›œœþœžþžžúŸžŸžžŸŸý Ÿ  ¡ý¢¡¢¢›ýœ›œœþœœþœžžŸæ Ÿ  Ÿ Ÿ  ¡  ¡  ¡¡¢¡¡¢¡¡¢¢££›ýœ›œœúœœžþžžüŸžžŸŸ þŸ  ¡ú¢¡¢¡¡¢¢ý£š››ýœ›œœþœœýœúžžžžžŸþžŸŸ þŸ  ¡ý¢¡¢¢þš››œýœžýŸžŸŸ þŸ  ¡þ¢¡¡¢ûš›šš››œ›œžŸüžŸžŸŸü Ÿ ŸŸ ¡ ¡¢÷¡¢¢šš››š››œúœœœ÷žžžžŸžžýŸžŸŸ þŸ  þ¡  ¡š›üœ››œœúœœœžþŸžžŸ Ÿ ¡þ ¡¡ý¢™ššý›š››œœžŸþžŸŸý Ÿ  ý¡ ¡¡ó™š™šš›š›š›šš››üœ››œœþœžüŸžžŸŸ Ÿ ¡™šþ™šš›š›œþ›œœôœœœœžžžþžžýŸžŸŸþ ŸŸ ý¡ ¡¡™š›úœ››œ›œœüœœûžŸžžŸøžŸŸ Ÿ Ÿ  ¡þ˜™™üš™™šš›œ žŸú ŸŸ Ÿ  ü¡™˜™™šþ™ššý›š››úœ››œ›œœþœžûžžžžŸ ü¡™˜™™š›ûš››š››øœ›œ›œœœœýœžþžžúŸžžŸžŸŸý Ÿ  ˜™þš™™šþ›šš›œþ›œœžþžžŸþžŸŸõ ŸŸ Ÿ  ˜™˜™™üš™™ššü›šš››þš››œü›œœþœüžžžýŸžŸŸ ˜ý™˜™™šþ™šš›œù›œœœœœüžžžýŸžŸŸü Ÿ—˜˜™üš™™šš›øš››œœ››œœœùžžžžûŸžžŸ  þ—˜˜ý™˜™™š›š›úœ››œ›œœüœœžþžžŸžŸý Ÿ——þ˜™™þ˜™™ýš™ššü›šš››œþ›œœþžžüŸžžŸŸ—˜ý™˜™™ýš™ššþ›šš›øœ›œœ›œ›œœüœœžõžžŸžŸžŸžŸ——˜™ýš™šš ›œûœœžþžžýŸ–——ý˜—˜˜™šü›šš››ùœ››œœ›œœœžþŸ——˜þ—˜˜™š›ýœ›œœýœýžžž—þ–—— ˜ý™˜™™ýš™ššú›š››š››üœ››œœþœûžžžžû–—––——˜™úš™™š™šš›œüœœž–—˜û—˜˜—˜˜ý™˜™™þš™™š›þš››øœ›œ›œœ›œœûžž––—þ–——ú˜——˜—˜˜™ùš™™š™™šš›š›œþž––ý—–——ý˜—˜˜û™˜™˜™™šð™š››š››š››œ››œ›œœüœœüž–•––—þ–——˜ý™˜™™þš™™šü›šš››ùœ››œ››œœþœúž•––•––ý—–——˜þ™˜˜™ú˜™™š™šš›þš››œþ›œœþœœ÷œ•––•––—˜þ—˜˜ý™˜™™ýš™ššü›šš››þœ››œ•–û—–—–——ü˜——˜˜™þ˜™™ýš™ššý›š››œýœ••ú–••–•––—˜™üš™™ššþ›šš›œúœ”••ý–•––—–—ý˜—˜˜ù™˜™™˜˜™™šþ™ššý›š››œü”•”••–þ•––—þ–——˜û™˜™˜™™šý›š››ûœ›œ›œœ”•þ–••–—ü–—–——˜û™˜™˜™™ýš™š š›úœ›œ››œœ”•ý–•––ü—–—––—˜þ—˜˜™þ˜™™ýš™ššþ›šš›œú›œ””•””•–þ•––ø—–—–——˜——˜™þ˜™™šþ™šš›þš››úœ›œœ“””•–•–— ˜™ýš™šš›œ”•þ–••–—û˜—˜—˜˜ü™˜˜™™š›ý”“””ý•”••–þ•––ñ—–——–——˜—˜——˜—˜˜ý™˜™™ùš™™šš™šš›“”þ“””•–þ•––ü—––——û˜—˜—˜˜ý™˜™™ýš™šš›ø”“”“””“””ý•”••–ù—–—–—–——þ˜——˜þ—˜˜ý™˜™™š™ýš›šš›“”•”•ý–•–– —˜™šþ™šš›“”“”•þ–••–—þ–——ý˜—˜˜™šü›š’““ý”“””ü•””••–—þ–——˜ý™˜™ ™š“þ’““”þ“””ú•”••”•• –—ú˜——˜—˜˜ü™˜˜™™ýš™ššþ’““þ’““”ý•”••ú–•–••––—˜™˜™š’“ý”“””•ü”•”••–þ•––ð—––——–——˜—˜—˜——˜˜™šþ™šý¢¡¢¢£ü¤££¤¤¥ù¦¥¥¦¦¥¦¦§þ¦§§ý¨§¨¨þ§¨¨ý©¨©©ý¢¡¢¢£¤ü£¤£¤¤¥¦¥ý¦¥¦¦ú§¦§§¦§§ý¨§¨¨ý©¨©©¡ý¢¡¢¢£þ¢££¤ü£¤£¤¤ú¥¤¤¥¦¥¥¦ý§¦§§þ¨§§¨ü©¡¡¢¢ £ø¤£¤¤£¤¤¥¥þ¤¥¥¦ù§¦¦§¦¦§§ý¨§¨¨¡ý¢¡¢¢£¤þ£¤¤û¥¤¥¤¥¥ý¦¥¦¦§ý¨§¨¨¡ý¢¡¢¢£þ¢££¤þ£¤¤ú¥¤¥¥¤¥¥û¦¥¦¥¦¦§þ¨§§¨ý¡ ¡¡¢¡¢£¤ü£¤£¤¤ý¥¤¥¥ý¦¥¦¦û§¦§¦§§ö¨§¨§¨¨ ¡ ¡¡¢î¡£¢¢££¢£¢£¤¤£¤£¤£¤¤ü¥¤¤¥¥ý¦¥¦¦ú§¦¦§¦§§ü¨¡ ¡¡þ ¡¡¢£ü¤££¤ ¤¥þ¦¥¥¦ý§¦§§þ¦§§ ý¡ ¡¡ý¢¡¢¢þ£¢¢£¤þ£¤¤ü¥¤¤¥¥ý¦¥¦¦§õ¨§  ¡  ¡¡ ¡¡ý¢¡¢¢£¤ý¥¤¥¥û¦¥¦¥¦¦§ þ¡  ý¡ ¡¡¢¡¢ý£¢££ý¤£¤¤ü¥¤¤¥¥ý¦¥¦¦§ú¦§§ Ÿ  ¡¢¡¢ó£¢¢£¢££¤¤£¤£¤¤û¥¤¥¤¥¥ý¦¥¦¦§  ¡¢þ¡¢¢ý£¢££¤¥¦§Ÿ ý¡ ¡¡¢£þ¢££ú¤£¤££¤¤ü¥¤¥¤¤¥ù¦¥¦¥¦¥¦¦ú§¦Ÿ Ÿ  ¡ ¡÷¢¡¢¡¢¡¢¢££¢£ü¤££¤¤ú¥¤¤¥¤¥¥¦Ÿ þ¡  ¡¢þ¡¢¢ü£¢¢££þ¤££¤ý¥¤¥¥ý¦¥¦¦Ÿü ŸŸ  ý¡ ¡¡ý¢¡¢¢£¢ý£¢££¤û¥¤¥¤¥¥¦þ¥¦¦û¥žŸžŸŸý Ÿ  ý¡ ¡¡ü¢¡¡¢¢þ£¢¢ý£¢££ý¤£¤¤¥¦û¥¦¥žŸŸþ ŸŸ þ¡  ¡¢ü¡¢¡¢¢£þ¤££¤¥÷¦¥¦¦ŸžŸžŸŸý Ÿ  ùŸ  Ÿ¡ ¡¡þ ¡¡ ¢£¤ú¥¤¤¥¤¥¥¦žŸþ ŸŸ  ¡¢£þ¢££¤ú¥¤¥¤¤¥¥þ¦žžöŸžŸžŸŸžŸ ŸŸ ¡þ ¡¡û¢¡¢¡¢¢£û¢£¢¢££¤£¤ü¥¤¤¥¥žŸþžŸŸ ü¡  ¡¡ü¢¡¡¢¢ü£¢¢££¤þ£¤¤¥žýŸžŸ Ÿ  ¡¢£¢£ý¤£¤¤¥úžžžžžýŸžŸŸù ŸŸ ŸŸ  ¡þ ¡¡¢¡¢£û¢££¢££ý¤£¤¤¥žþŸžžŸü ŸŸ  þ¡  ¡ü¢¡¡¢¢ü£¢¢££ý¤£¤¤þžüžžžŸü ŸŸ  ¡ ü¡  ¡¡ý¢¡¢¢£¢£¤£ü¤¥¤žŸú Ÿ ŸŸ  ý¡ ¡¡¢þ¡¢¢£þ¢££ý¤£¤¤ýœžžüŸžžŸŸý Ÿ  ¡þ ¡¡¢ò£¢£¢£¢££¤£¤¤£¤¤þœûžžžžŸ þŸ  þ¡  ¡ú¢¡¡¢¡¢¢ý£¢££õ¤££¤£¤œœœüžžžŸüžŸžŸŸû Ÿ Ÿ  ù¡ ¡¡  ¡¡¢ú£¢£¢¢££ù¤£¤£œœœýžžž÷ŸžžŸžžŸžŸŸ þŸ  ü¡  ¡¡ù¢¡¢¡¢¡¢¢ü£¢¢££÷¤œœœœúžžžžžŸþžŸŸ þŸ  ü¡  ¡¡¢¡¢£œýžžžŸõžŸŸ ŸŸ Ÿ Ÿ  û¡ ¡ ¡¡¢ú¡¢¢£¢££œòœœœžžžžžûŸžŸžŸŸü ŸŸ   ¡ý¢¡¢¢£›úœ›œœœœžžõžžŸžŸžŸŸžŸŸ þŸ  ¡¢ý£¢££ œùžžžžžŸ Ÿ õŸ  ¡  ¡ ¡ ¡¡û¢¡¢¡¢¢þ£››œüœœúžžžžžŸþžŸŸ  ¡¢÷¡¢£¢¢£››œœû›œœ›œœýœžþŸžžŸ þŸ  ¡ú¢¡¡¢¡¢¢þš››œýœúžžžžþŸžžŸþ ŸŸ  ¡õ¢¡¢¡¢¡¢¢›š››œùœœžžøžžžŸŸþ ŸŸ ¡þ¢¡¡¢ý›š››ýœ›œ œûžžžžŸý Ÿ  ¡ ¡¢ø¡¢¢š››š››úœ›œœ›œœþœžŸ þŸ  ý¡ ¡¡ü¢¡¢šš÷›šš››œœ›œœýœýžžžŸ þŸ  ¡š›þš››œþ›œœžžúŸžŸžžŸŸ ¡šý›š››œþœœõžžžžŸžŸŸ þŸ  ¡š› œýœžþžžýŸžŸŸþ ŸŸ ¡™š›š›œþœþžžŸþžŸŸü ŸŸ  ù¡ ¡¡š™ššú›šš›š››üœ››œœþ›œœžŸþžŸŸý Ÿ  þ¡  û™š™™ššû›š›š››ùœ››œ››œœžžéŸžŸžŸžŸ ŸŸ Ÿ  Ÿ  ¡¡™™š™™šþ™šš›œþ›œœþœžþžžŸþžŸŸü ŸŸ  ™ýš™ššý›š››œü›œ›œœúœœüžžžúŸžŸŸžŸŸù Ÿ  Ÿ ™™üš™™šš›š› œúžžžžžŸ ûŸ ˜˜™™šø›šš››šš››œýœýžžžŸþžŸŸ ÷˜™™˜™˜™š™™š›ýœ›œœýœžþžžŸù Ÿ Ÿ˜˜™™û˜™™š™™šû›š›š››œ›œüœœþžžŸþžŸŸ˜™þ˜™™š›š›þœ››œùœœœžŸ˜™˜ü™š™ššþ™ššþ›šš›þœ››œýœþžžŸþ—˜˜™šô›š›š››œ››œ›œœüœœúœžžžžŸüžŸž˜˜ù™˜˜™™š™™šþ™šš› œžžùŸžŸ—˜—˜˜™ù˜™š™š™ššú›šš›š››œþ›œœýžžžûŸ—˜—˜˜û™˜™˜™™üš™™ššþ›šš›œ›øœ›œœœœžüŸ——˜˜þ—˜˜™üš™™šš›þš››œùœœœœýžžžûüôûüûûüûüûüüûüüüûüûüüþýüüþýüüúûüûûüûûþüûûúüûüûûüüöûüûûüûüüûüüþûüüûüüûüûûüûýüûüüûüüûüûüüûûüüûüü÷ýüýüýüýýûûþüûûúüûüûüûûûüûûüûûþüûûûüûüûüüþûüüþýûûõüûûüûüûûüüûûüûþüûûüûýüûüüþûüüýýüûûüûýüûüüûüúûüûüüûûûüûüüûûüþûüüþûüüþûüüûþüûûþüûûüûþüûûüûüøûüûüûüûüüþûüüûþüûûþüûûüûüþûüüûüþûüüþûüü ûþüûûüûþüûûýüûüüùûüûüûûüüûüûûüüûü ü ûþüûûûüûûüûûøüûüüûûüûûü÷ûüûûüûüûüüþûü üûþüûûüûüûþüûûüþûüüûüþûü üûþüûûõüûüûûüûüûüûûüüûüûûüûüþûü üûòüûûüûûüûüüûûüûûýüûüüüûüûüüþûü üýûúûû÷üûûüûüûüûûüúûüûüüûûýüûüüûüûûüüûüüûüûþúûûüüûüüûûüûûüûüûûüûüþûüüûüþûüü ûûüûüüûûøüûûüüûüûûþüûûüüûüûüüûûüûûüüþûüüýûúûûüûüýûüûûûüûûüûûüûüþûüüûøúûûúûûúûûûüûûüûûþüûûüþûüüþûüüúûüûüüû ûþúûûþüûûüûûüûüûûøüûûüüûûüüûûüüûüüøûüüûüûüûûþúûûþúûûþúûûþüûûüûüüûüûüüûûúûûúûûþúûûûüûûüûûüöûüûüûûüûûüüþûüüûþúûûþúû ûþüûûüüûüûûþüûûüûüûþüûûúýûúûûþúûûûúûûúûûþüûûüûü÷ûüûüûüüûüüþûüüöûüüûúûúûúûûüúûúûûþúûûüüûüûûþüûûþüûû÷üûûüüûüûüü÷ûüûûúúûúûûøúûúúûûúûûüûüúûüüûüûûûüúúûúúûúúûûúúûûþúûûþüûûüûþüûûûüûûüûûüüûüúûûöúûûúúûûúúûûþúûûüüûüûûüüûüûûüûüûúøûúúûúûûúúûúûþúûûþüûûþüûûþüûûüùûüûûüûüüûþúûûúûþúûûúûüûüüûüûûüüûüûûúûûúûúûûþúûûüúûúûûüûüûñüûüüûûüûûüûüûúûû÷úûûúúûúúûûþúû#ûüûíüûúúûûúúûúûúúûûúûúûûþúûûüûþüûûþüûûüþûúúûúþûúú&ûþüûûþüûûúþûúúëûúûûúúûûúúûúûûúûûúûúû ûþúûûüûþüûûüýûüûûþüûûúþûúúûþúûûúúûûúúûûûúûûúûûþüûûüûûúúûúúþûúúûúõûúúûûúúûûúûûúüûûüüúúûúûúûþúûûþúûûüúûúûûþúû ûþüûûúüûûüûúúýûúûûúûûúûúûûú÷ûúûúúûûúûûûúûûúû ûüüûüûûüüûüúúþûúúûúûúüûúúûûúûúûúûþüûûúþûúúþûúúýûúûûúûúûþúûûþúûûþüûûúûúöûúúûúûúûúûûúûúûþúû ûüüûüû ûúûûúûúûûúûûúúûúúûüúûúûûþúûûþúûûþüûûüüûûúúþûúúüûúûúúýûúûûýúûúúûþúûûþúûûþüûûúþûúúúûúúûûúúûúûþúûûþúûûþüûûúþûúúûúþûúúþûúúûúúûúûúûûþúûûþúûûþüúúþûúúþûúúûüúûúûûúûþúûûþúûûúûþúûûúþûúúþûúúûúûóúûúûúûûúûûúûúúû÷úûúûúûûúûûþúûûýüûúúþûúúûúüûúûúúýûúûûøúûúûúûúûûþúûûûúûûúû ûúþûú úñûúûúûúûûúúûûúúûûþúûûúýûúûûûúûúúûûú÷ûúúûúúûûúúþûúúûþúû ûûúûûúûûþúûûþùú úûúþûúúûúýûúûûüúûúûûþúûûúûúþûúúûúòûúûúûûúúûûúúûúúûûúûúû ûüúûûúúþùú úþûúúþûúúû÷úûûúûûúúûûúûþúûûþúûûúúûúûûúúþûúúðûúúûúúûûúúûúûûúûûüúûûúúûþúûûþúûûúþùú úþûúúûûúúûúúñûúûúúûúûúûûúûúûûþúûûþúûûþùúúù úúûúúûûúúþûúúþûúúûüúûúûûþúûûþùúúþùúúþûúúþûúúûúüûúúûûüúûúûûúùúþûúúþûúúþûúúöûúûúúûûúúûûøúûúûûúùúúüùúùú úþûúúùûúûúûûúúûûúûúúûûþúûûýúûú úþùúúþùúúþûúúûûúûûúûûúúùúùúùúúþùú úþûúúû úüûúûúúúûúûúúûûúûùúúùú úù úíûúûúûúûúúûûúûúúûúúûûþúûûúùýúùúúþùú úþûúúû÷úûúûúûúúûûþúûûþùúúþùúúþûúúüûúúûûúûûúûúúûûþúûÿ¥¦þ¥¦¦§¨©þ¨©©ªü«ªª««ý¬«¬¬­¥û¦¥¦¥¦¦§¨ú©¨©¨¨©©ýª©ªªü«ªª««¬ù­¥¥¦¥¥¦¦ý§¦§§¨þ©¨¨©óª©ªª©ªª«ªª«ª««¬þ«¬¬ý­¤¥¥ý¦¥¦¦§þ¦§§ý¨§¨¨û©¨©¨©©ùª©©ªª©ªª«ª«þ¬««¬û­¥¥¤¥¥ ¦§ú¨§¨§§¨¨©üª©©ªª«þ¬««¬þ¥¤¤¥ü¦¥¥¦¦ý§¦§§¨§¨û©¨©¨©©ªú«ªª«ª««¬þ«¬¬ù¤¥¤¤¥¤¥¥¦§ý¨§¨¨ý©¨©©þª©©ª«üª«ª««¬¤¥þ¤¥¥¦û§¦§¦§§¨§¨ ©ªþ©ªªý«ª««¬¤¥¦ù¥¦¥¦§¦§§ý¨§¨¨ý©¨©©ª©ªþ«ªª«þ¬¤¤ý¥¤¥¥ü¦¥¥¦¦ü§¦¦§§þ¨§§¨û©¨©¨©©þª©©ªü«ª«ªª«¤þ£¤¤¥þ¤¥¥û¦¥¦¥¦¦þ§¦¦ý§¦§§¨û©¨©¨©©ûª©ª©ªªþ«ªª«ñ£¤£¤££¤¤¥¤¥¤¥¤¥¥¦ü¥¦§¦¦§¨þ§¨¨þ©¨¨©üª©©ªª«£¤þ¥¤¤ý¥¤¥¥þ¦¥¥¦ü§¦¦§§ü¨§§¨¨ù©¨©¨©¨©©þª©©ýª©ªªþ«££¤þ£¤¤¥û¤¥¤¤¥¥¦÷¥¦¦§¦¦§¦§§ü¨§§¨¨ú©¨©¨¨©©ªþ©ªª«£ ¤¥ú¦¥¥¦¥¦¦ø§¦§§¦§§¨¨©ûª©ª©ªªû¢££¢££¤þ£¤¤ý¥¤¥¥¦þ¥¦¦§¨ü©¨©¨¨©üª©©ªªþ¢££ ¤¥ý¦¥¦¦ý§¦§§ú¨§¨¨§¨¨ý©¨©©ªþ©¢¢£þ¢££ý¤£¤¤¥þ¤¥¥¦¥¦§¨þ§¨¨©þ¨©©ªù©¢¢£¢¢££ù¢££¤££¤¤¥þ¤¥¥¦þ¥¦¦§ý¨§¨¨©þª©©þª¢¢£¤¥ü¦¥¥¦¦§¨þ©¨¨©¡¢ú£¢££¢££¤£¤ü¥¤¤¥¥ý¦¥¦¦ö§¦¦§¦§¦§§¨¨ý©¨©©ü¡¢¡¢¢£þ¢££ü¤££¤¤ù£¤¤¥¥¤¥¥¦§¦§¨ü§¨§¨¨ü©¨¨©©ù¡¢¡¢¢¡¢¢£¤¥û¤¥¥¤¥¥¦ý§¦§§¨þ§¨¨©û¨©¨©¡¡¢ü£¢¢££þ¤££¤¥¦¥¦ü§¦¦§§÷¨§§¨¨§¨§¨¨ü©¨©¡¡¢£¤ú¥¤¤¥¤¥¥ ¦§¨¡ý¢¡¢¢£ý¤£¤¤ü¥¤¤¥¥ý¦¥¦¦þ§¦¦§ý¨§¨¨þ©¡¡þ ¡¡ý¢¡¢¢ý£¢££ý¤£¤¤¥ú¦¥¦¥¥¦¦þ§¦¦§û¨§¨§¨¨ü ¡ ¡¡ù¢¡¢¢¡¡¢¢ü£¢¢££¤þ£¤¤¥þ¤¥¥ý¦¥¦¦§¨ ¡ý¢¡¢¢£ú¤£¤¤£¤¤¥ý¦¥¦¦ý§¦§§ü¨§¨  ¡þ ¡¡ü¢¡¡¢¢ý£¢££ú¢£¤¤£¤¤ú¥¤¤¥¤¥¥¦û§¦§¦§§ü¨§¨   ¡ü¢¡¢££¢£ü¤££¤¤¥þ¤¥¥ ¦§þŸ  û¡ ¡ ¡¡¢þ¡¢¢ý£¢££ý¤£¤¤ü¥¤¤¥¥û¦¥¦¥¦¦ý§¦§§þ¨  þ¡  ¡ý¢¡¢¢£þ¢££ ¤¥þ¤¥¥¦§Ÿý Ÿ  ü¡  ¡¡ý¢¡¢¢£¤û¥¤¥¤¥¥û¦¥¦¥¦¦§Ÿ þŸ  ¡ý¢¡¢¢û£¢££¤¤ù¥¤¤¥¥¤¥¥þ¦¥¥¦§¦û§ŸŸ ŸŸý Ÿ  ¡¢£ý¤£¤¤ú¥¤¥¥¤¥¥ ¦ýŸžŸŸ ¡þ ¡¡ú¢¡¢¢£¢¢£¤¥¦þ¥¦¦ü§¦žŸŸü ŸŸ   ¡¢û£¢£¢££¤ú¥¤¥¤¤¥¥ý¦¥¦¦úžŸŸžžŸŸ þŸ  ú¡ ¡¡¢¡¡÷¢¡¢¢£¢£¢££¤þ£¤¤¥þ¤¥¥¦ûžŸžžŸŸ ¡ ý¡¢¡¡¢£ý¤£¤¤ý¥¤¥¥ý¦¥¦¦žýŸžŸŸ ¡þ ¡¡¢£þ¢££¤þ£¤¤þ¥¤¤¥þ¦žžŸžŸý Ÿ  þ¡  ¡ý¢¡¢¢£¤ú£¤¤¥¤¥¥¦üžžžŸý Ÿ  ý¡ ¡¡¢¡¢ü£¢¢££¤ù¥¤¤¥¤¤¥¥žûŸžŸžŸŸú ŸŸ Ÿ  ü¡  ¡¡¢û£¢£¢££¤¥ü¤¥¥žŸý Ÿ  û¡ ¡ ¡¡ý¢¡¢¢ü£¢¢££ø¤£¤¤£¤¤¥¥ö¤¥¥žžžžžþŸžžŸü ŸŸ  úŸ  ¡ ¡¡ý¢¡¢¢ü£¢¢££ø¤£¤£¤££¤¤¥žûŸžŸžŸŸ üŸ Ÿ  þ¡  ù¡¢¡¢¡¡¢¢£þ¢££ ¤þ¥ýžžžŸþžŸŸ Ÿ ý¡ ¡¡ú¢¡¢¡¡¢¢£¤þ£¤¤þœûžžžžŸ ùŸ  ¡  ¡¡÷¢¡¡¢¢¡¢¢££þ¢££÷¤£¤£¤¤œžýŸžŸŸ  ¡ü¢¡¡¢¢ý£¢££ý¤£¤¤œøœœžžŸþžŸŸý Ÿ  ¡ ¡ý¢¡¢¢£¤£þ¤œœúžžžžýŸžŸŸ þŸ  ý¡ ¡¡ú¢¡¢¢¡¢¢£ü¤£¤œœþœ žŸþ ŸŸ þŸ  ¡û¢¡¢¡¢¢£ù¢££¤£¤œœžþžžŸþžŸŸý Ÿ  ü¡  ¡¡ ¢£œýžžžýŸžŸŸ ü¡  ¡¡ú¢¡¡¢¡¢¢ö£¢££¢£œœ›œœžŸü ŸŸ  ¡þ ¡¡ý¢¡¢¢þ£¢¢þ£›› œøœžžžúŸžŸŸžŸŸ þŸ  ¡þ ¡¡ô¢¡¢¡¢££¢¢££››ýœ›œœûœœœžþžžŸžŸ ø¡ ¡¡¢¡¡¢¢û£››š››üœ››œœžýŸžŸŸ þ¡  ¡¢ý£š››üœ››œœýžžžŸý Ÿ  ¡û¢¡¢¡¢¢þš››œõœžžžžüŸžžŸŸ   ¡¢›üš›š››œþ›œœöœœœžžŸžŸ  ¡¢šû›š›š››œ›œþœžþŸžžŸü ŸŸ  ¡û¢¡¢¡šš›÷š›š››œœ›œœžŸüžŸžŸŸý Ÿ  ¡©ûª©ª©ªª«ý¬«¬¬­®­®ü¯®®¯¯þ®¯¯°©ª«úª««ªª««ý¬«¬¬ý­¬­­û®­®­®®¯ý°¯°°þ¨©©ýª©ªª«üª«ª««ý¬«¬¬ ­®ý¯®¯¯°©ª÷©ªª«ªª«ª««¬þ­¬¬ý­¬­­®­®ø¯®®¯®¯®¯¯°¨©ª©ªú«ª««ª««ý¬«¬¬û­¬­¬­­®­ý®­®®ø¯®¯®¯¯°¯¯¨©üª©©ªª«þ¬««¬ý­¬­­ø®­­®®­­®®ý¯®¯¯°¨þ©¨¨÷©¨©ª©©ª©ªªþ«ªª«ù¬««¬¬«¬¬­þ¬­­ ®û¯®¯¯¨¨©ýª©ªªþ©ªª«þª««¬ú­¬­¬¬­­ ®¯¨ý©¨©©ª©ªý«ª««û¬«¬«¬¬ý­¬­­ ®ú¯¨§¨§¨¨©þ¨©©úª©©ª©ªªú«ªª«ª««¬ú­¬­­¬­­®ö­®®¯®¯¯®¯¨¨§¨þ©¨¨ý©¨©©ª«¬ü«¬«¬¬­ý®­®®þ­®®þ¯§§ý¨§¨¨©úª©©ª©ªª«¬þ«¬¬ý­¬­­®þ­®®§¨©þ¨©©÷¨©ª©©ª©©ªªý«ª««¬«¬­®§ ¨ú©¨©©¨©©üª©©ªª« ¬­®þ¦§§þ¨§§¨û©¨©¨©©ªþ©ªª«¬þ«¬¬­®­þ®¦¦§ý¨§¨¨©¨©ªý«ª««ý¬«¬¬û­¬­¬­­ø®­¦§¦§¦§§¨©ýª©ªª«ü¬««¬¬­®¦§ý¨§¨¨©ª«þª««¬«¬ú­¬¬­¬­­¦§þ¨§§¨þ©¨¨©ªû«ª«ª««ú¬«¬««¬¬­þ¬­­¦ §ý¨§¨¨ý©¨©©ªþ©ªªú«ª««ª««ý¬«¬¬ö­¬­­¬¬­¦¥¦¦§þ¦§§¨þ§¨¨©þª©©ªü©ª«ªªü«ªª««¬þ«¬¬­ø¬­­¥¥¦¥¦¦ý§¦§§ò¨§¨¨§§¨¨©¨¨©¨©© ª«¬þ«¬¬ü­¬­¥¥ý¦¥¦¦§þ¦§§ü¨§§¨¨©þ¨©©ªþ©ªª«þª««¬ø­¬¥¥¦¥¥¦ ¦§û¨§¨§¨¨©ýª©ªªö«ª«ª««ª««¬¬¥¦ý§¦§§¨þ§¨¨ú©¨©©¨©©ûª©ª©ªªú«ª««ª««û¬«¬«¬¬¥ü¦¥¥¦¦§¨ú©¨¨©¨©©üª©©ªª«ý¬«¬¬«þ¤¥¥û¦¥¦¥¦¦ú§¦¦§¦§§¨©üª©©ªªý«ª««þ¬««¬ü«¤¤¥¥ú¦¥¦¥¥¦¦ §¨ò©¨©¨¨©©ªª©©ª©ªª«þª««û¬¤¥¤¥¥ü¦¥¥¦¦§¨ú©¨¨©¨©©ª«þª««¤ý¥¤¥¥ý¦¥¦¦§ü¦§¦§§¨ü©¨¨©©ªý«ª««¤þ¥¤¤¥ù¦¥¦¥¦¥¦¦§ý¨§¨¨ý©¨©©þª©©ªü«ªª««ý¤£¤¤þ¥¤¤¥ý¦¥¦¦ù§¦¦§¦¦§§þ¨§§¨ú©¨©©¨©©÷¨©©ª©©ª©ªª«¤þ£¤¤û¥¤¥¤¥¥¦þ¥¦¦§¨©þ¨©©ªþ©ªªü«ªª««¤¥þ¤¥¥ú¦¥¦¦¥¦¦ú§¦§¦¦§§ü¨§§¨¨ý©¨©©üª©©ªª ¤û¥¤¥¤¥¥¦§ü¨§§¨¨ü©¨¨©©ª©ª£¤ü¥¤¤¥¥ü¦¥¥¦¦§¦§ú¨§¨¨§¨¨©þ¨©©ª£ý¤£¤¤¥¦þ¥¦¦ú§¦§§¦§§¨ü©¨¨©©ª©ªþ¢££þ¤££¤¥¤¥¦§¨§¨©þ¨©©ùª©©ªª¢££ú¤££¤£¤¤ü¥¤¤¥¥¦û§¦§¦§§ü¨§§¨¨©ª£þ¢££¤þ£¤¤ü¥¤¤¥¥ü¦¥¥¦¦§þ¦§§¨ý©¨©©üª©ª¢¢ý£¢££þ¤££ ¤¥ ¦§¨ø§¨¨©¨¨©¨¨©÷ª¢¢£¢££¢££ü¤££¤¤¥þ¤¥¥ü¦¥¥¦¦§¨ù§¨¨©¨¨©©þ¡¢¢ô£¢¢£¤£¤£¤££¤¤¥þ¤¥¥¦¥¦ü§¦¦§§ù¦§§¨§§¨¨ú©¨©©¡¢¢ü£¢£¢¢£¤û¥¤¥¤¥¥þ¦¥¥¦û§¦§¦§§û¨§¨§¨¨ü©¨¨©©¢¡÷¢££¢¢££¢££ù¤£¤¤££¤¤ü¥¤¤¥¥ý¦¥¦¦ú§¦§¦¦§§þ¨§§¨©¡¢£þ¢££¤¥þ¤¥¥¦§þ¦§§¨§¨ü©¨¨¡¡¢£þ¢££¤£¤ú¥¤¥¤¤¥¥¦§þ¦§ §¨¡ý¢¡¢¢ý£¢££¤¥þ¤¥¥û¦¥¦¥¦¦§þ¦§§¨ü§¨¨¡¡ý¢¡¢¢û£¢£¢££ý¤£¤¤ý¥¤¥¥¦þ¥¦¦ü§¦¦§§¨ü§¨¨¡¡ù¢¡¢¢¡¡¢¢ý£¢££ú¤£¤¤£¤¤ý¥¤¥¥¦þ¥¦¦§ö¦§¨§§¨¨§¨¡¡¢þ£¢¢£¤þ£¤¤¥ü¦¥¥¦¦ý§¦§§ø¨§§ ¡¡ ¡¡¢ü¡¢¡¢¢ £¤¥¦þ¥¦¦û§¦§¦§§ü ¡¡  ¡þ¢¡¡¢ö¡¢£¢£¢£¢¢££¤ý¥¤¥¥ý¦¥¦¦ú§¦¦§¦§§ ¡þ ¡¡ü¢¡¡¢¢ü£¢¢££ü¤££¤¤ú¥¤¥¤¤¥¥ý¦¥¦¦§û¨ ŸŸ  ¡ü¢¡¡¢¢£ø¢££¤¤£¤££¤ü¥¤¤¥¥÷¤¥¥¦¥¥¦¥¦¦§ý Ÿ  û¡ ¡ ¡¡þ¢¡¡¢£þ¢££ü¤££¤¤ý¥¤¥¥¦þ¥¦¦§Ÿ ¡¢ü£¢¢£ £¤þ¥¤¤¥¦þ¥¦¦§¦ø§¦ŸŸ  Ÿ  ¡ø ¡¡¢¢¡¡¢¢þ£¢¢£¤£¤ü¥¤¤¥¥ý¦¥¦¦þ§ŸŸ þŸ  ¡¢£ù¤£¤£¤£¤¤¥¦¥¦Ÿý Ÿ  ü¡  ¡¡¢£þ¢££ý¤£¤¤ý¥¤¥¥ý¦¥¦¦Ÿ þ¡  ¡ý¢¡¢¢£þ¤££¤ü¥¤¤¥¥ý¦¥¦¦Ÿý Ÿ  ¡¢þ¡¢¢þ¡¢¢£¤ñ¥¤¥¤¥¥¦¥¥¦¥¥žžŸŸû Ÿ Ÿ  ý¡ ¡¡þ ¡¡ý¢¡¢¢£¢ù£¤¤£¤£¤¤¥þ¤¥¥ü¦žžŸŸþžŸŸý Ÿ  ¡þ ¡¡þ¢¡¡ý¢¡¢¢þ£¢¢£ü¤££¤¤ý¥¤¥¥þ¦¥¥üþýüüôýüýüýýüüýüüýýüýþüýýüýþýüþýýüüýüýüýüýþüýýüþýþýýþþýýöþüüýýüýüýüüþýüüýüüýüýýýüýüüýüþýþýý üýöüýüüýüýýüýýòüýüüýüüýýüýýüýý÷þýýþýüýüýýüþýüüýüüýüýýþüýýþüý ýùþýþýýþýýüýýüýýüûýüýüýýúüýýüüýýüýþþýýùþýþýüýüüýüýýüýüüûýüýüýýüýûüýýüýýü ýüþýýüüþýüüþýüüúýüüýüýýüüýüýýþüýýþüýýþüý ýþþýýýþýüüúýüüýýüüýüýüûýüýüýýüþýüüþýüüýýüýýüüýüýüüýüüýüýýþüýýþþýýüþýüüþýü üýõüýüýüüýüýüýýûüýüüýýþüý ý üþýüüþýüüýüý÷üýüýüýüüýýûüýýüýýüþýýüüþýü üþýüüþýüüýþüýýüüýüý ýüþýüüýüîýüýýüýüüýüüýýüýüüýýþüýýüþûü üøýüüýüýýüüýüýýüýýüýüüýüý ýüþýüüýüýþüýýùüýüýýüýýþûüü÷ýüýýüýüýüüöýüýüýüýýüýýþüýýøüýýüýýüýý üþýüüýüúýüýüüýýüüýýüüþýüüýüýþüýýûûüüûüüþûüüüýüüýýüþýüüþýüüýüýýüýýüýüýýüýýþüýýûüþýüüþýüüûýüüýüüðýüýüýüüýýüýüýüüýýúüýüýüýýüþûü üþýüüüýüýüüþýüüùýüüýüýüüõýüüýüýýüýüýýüüûüûüüþýüüøýüýüüýýüüëýüüýüýýüýüýüýýüýýüüûüüüûüûüüþýüüþýü üýüýýüýýüüýüýýýüûüüþýüüþýüüþýüüýü÷ýüüýüýüýüüýüýüþûüüûýüüýüüüýüýüüþýüüùýüüýýüýýûüýýüýýúûüûüüûûüþûüüýýüýýüýùüýýüýýüüøûüûüüûûüüþýüüïýüýüüýüýüüýýüüýüýýûüýýüýýüüûüûûùüûüûüûüüôýüüýüüýüýüýüüýüýüüûûüüûúüûüûûüüþýüüùýüüýüýüüþýüüýüýþüýýûóüûüûûüûüûüüûüüýüþýüüüýüýüüþýüü÷ýûûüûûüüûûüüûüûüüýüýýüýýüüýüýü üûýüûüüýýüýüüýüþýüüþýüüþýüüõýûüûüûüûüûüüúûüûüüûûüþýüüûýüýýüüýýüýýüôûüûüûüûüüûûüüùûüûüüûüüû üûýüüýüüýüýýüýýüüýýüüùûüüûûüûû üüûüûüüùýüýüüýüüýüüýüýüüùýüýüûüûûýüûüüûüüûüûüüüýüýüüûüûóüûüüûüüûüüûûü"üðýüüýüýüüûûüûüüûüüþûüüþûüüûûüüûüüþýüüýúüýüüýûûüûüùûüûûüûüüüûüûüüøýüüýüýýüüüýüýüüûûüûüûûýüûüüþûüüþûüüþûüüõûüûüûüüûüûü üþýüüûýüýüýýûüûüüûûýüûüüùûüüûûüûûüúûüûüûüüþûüüþýüüþýüüýþüûûþüûûüûüûûüüûüüûüýüþýüüûìüûûüüûüûûüüûüûüûüüûüüþûüüûûüüûüüûýüüýüüþýüüþýûûûüûûüûûüüûüûûþüûûóüûûüûûüüûüûûüüþûü üþýüüûøüûüüûûüûûüûüüûûüüþûüüþûüüþûüüþûü üþýüüûüûøüûüûüûüûûüýûüûûýüûüüþýüüûþüûûþüûûüüûûüüûûüûüûûüûûüüûüüûüþýûûþüûûþüûûüüûüûûþüûûüþûü üþûü üþýüüûþüûûþüûûüûüûüûüûþüûûûüûüüûûüûüûüû÷üûûüüûüûü üüýüüû ûþüûûüûüûþüûûþüûûüüûûüüüûüûüüþûüüûþüû ûûüûüûüüûöüûûüûûüüûüüûþüûûüüûüüûûþüûûýüûüüû÷üûûüüûüüûûüþûüüþûüü ûþüû ûþüûûüüûüûüüþûüüùûüüûüûüüûûüüûüüûþúûûüûûüûûüüþûüüõûüüûüûüüûûüüþûüüùûüüûûúûûþüûûüûüøûüûüûüûüüûüþûüüùûüüûûúûûþüûûùüûüüûûüüûüòûüûüüûûüûûüüûüüûüûþúûûþüûûüûþüûûóüûûüûüûüüûüûüüûûüüûüüúûúûûúûûþüûûþüûûûüûûüûûüûüúûüûüûüüþûüüþûüüþûüüûùüûüûüûüüûùüûüûüûü üûþúûûþúûûúüûüüûüüúûüûüûüüôûüûûüûüûüüûüüûþúûûþúûûüöûüûûüüûüûüüüûüüûûüûüþûüüþúûûúûþúû ûùüûüûüüûûüûýüûüüûüûüùûüûûüüûûùúûûúûúûûþúûûþüûûþüûûþüûûûüûûüûûúüûüûûüüüûüûüüÿ­ý®­®®ü¯®®¯¯ý°¯°°ý±°±± ²³ü´³³´´úµ´´­¬­­®¯ö®¯¯°¯¯°°¯°°±þ°±±²ý±²±±²ü³²²³³ý´³´´üµ´¬­­®þ¯®®¯ú°¯¯°¯°°±þ°±±ø°±±²±²±²²ü³²²³³´¬ý­¬­­®¯ý°¯°°ü±°°±±²÷±²²³³²³²³³´¬­þ®­­®ü¯®®¯¯°¯û°±°°±±þ°±±ú²±²²±²²³ø²³³´³´³´´¬­þ¬­­þ®­­®ü¯®®¯¯ý°¯°°ú¯°°±°±±þ²±±²³þ´¬¬û­¬­¬­­ ®¯°þ¯°°ý±°±±²³ô´³³¬«¬¬­¬­¬­­®ü¯®®¯¯°þ±°°±÷°±²±±²²±²² ³û¬«¬«¬¬ý­¬­­ü®­­®®ê¯®®¯®¯¯°¯¯°¯°±°±°°±±°±± ²³«ý¬«¬¬­®¯þ®¯¯°¯ù°¯°±°°±±²±²³÷²³³««¬««¬¬þ­¬¬û­¬­®­­ý®­®®¯ù®¯¯°¯¯°°þ±°°±²þ±²²û³²³³««¬÷«¬¬­­¬­¬­­ý®­®®ý¯®¯¯°ü¯°¯°°±°ú±°±±²±±²ý³ª««¬÷«¬¬­¬¬­¬­­®¯þ®¯¯°þ±°°±²û³²«ª«« ¬ý­¬­­ú®­®®­®®û¯®¯®¯¯°þ¯°°±þ°±±²þ±²²þª« «¬þ­¬¬­®ý¯®¯¯°±û°±±°±±²ª«ý¬«¬¬û­¬­¬­­®¯þ®¯¯°¯°±ú²±²²±ªªü«ªª««¬ø­¬¬­¬­¬­­ú®­­®­®®¯ý®¯°°¯ý°¯°°±þ°±±þ²ªª«þ¬««¬­þ¬­­®ü¯®®¯¯ô°¯°°¯°°±°±°±±²©ªý«ª««ú¬««¬«¬¬ü­¬¬­­®þ­®®¯ú°¯¯°¯°°±þ°±±²ü±ª©ªªú«ª«ªª«« ¬­®þ­®®¯ý°¯°°ý±°±±ý²©ªªü«ªª««ü¬««¬¬þ­¬¬­®ý¯®¯¯þ°¯¯°±ô©ª©©ª©©ª««ª««þª««ü¬««¬¬­þ¬­­þ®­­ü®­­®®ü¯®®¯¯°¯°û±°±±©©ªþ©ªª«þª««þ¬««¬û­¬¬­¬¬­®­®û¯®¯®¯¯ü°¯¯°°ú±°°±¨©©üª©©ªª«üª««¬ ¬­þ®­­®ý¯®¯¯þ®¯¯ü°¯¯°°þ¨©©ª©ªý«ª««¬­ú®­®®­®®¯®¯°¨©ªþ«ªª«û¬«¬«¬¬ü­¬¬­­ü®­­®®ý¯®¯¯°þ¯°°û¨©©¨©©ªþ«ªª«¬­ ®¯þ®¯¯°ù¨©¨¨©¨©©þª©©ªû«ª«ª««ý¬«¬¬ý­¬­­ü®­­®®ý¯®¯¯ú°¯°°¯¨¨©ü¨©¨©©þª©©ªþ«ªª«¬þ«¬¬ý­¬­­®þ­®®ý¯®¯¯°¨©üª©©ªªý«ª««¬ü­¬¬­­®ý¯®¯¯ü°¨§¨¨©ü¨©¨©©ýª©ªª«þª««¬þ«¬¬­ý®­®®¯þ¨§§¨ ©ªü«ªª««¬þ«¬¬­û¬­¬¬­­®þ­®®¯ý®¯§§¨©þ¨©©ªþ©ªªû«ª«ª««ý¬«¬¬ ­®¯§ý¨§¨¨©ü¨©¨©©ªú©ªª«ª««û¬«¬«¬¬û­¬­¬­­®­®¯û¦§§¨§§¨û©¨©¨©©úª©ªª«ªª÷«ªª««¬¬«¬¬­þ¬­­®ø¯¦§¦§¨§¨¨§¨©¨©ªý«ª««þ¬««¬ý­¬­­ý®­®®¦§ý¨§¨¨ý©¨©©ªþ©ªªý«ª««¬­ý®­®®þ­®®§¦§ü¨§§¨¨þ©¨¨ý©ª©©ªü«ªª««ø¬«¬¬«¬«¬¬­®¦ý§¦§§ý¨§¨¨©ªü«ªª««ý¬«¬¬­®ý­®¦¦§þ¦§§¨©ýª©ªªü«ªª«« ¬­ö®­®­¥¦¥¦¦§ §¨©þ¨©©ª«þª««¬û­¬­¬­­®û¥¦¥¥¦¦ú§¦§¦¦§§ü¨§§¨¨þ©¨¨ù©¨©©ªª©©úª©ª«ª««¬ô«¬¬«¬¬­­¬­¬­­¦þ¥¦¦§¨ù©¨©¨©¨©©ªý«ª««ü¬«¬««¬­¥¦¥¦§¨ø§¨§¨¨©¨©©üª©©ªªý«ª««¬«¬ý­¬­­¥¦þ¥¦¦ú§¦§§¦§§¨õ©¨©¨©©ª©ª©ªª«þª«« ¬þ­¥¥ú¦¥¥¦¥¦¦§þ¦§§ý¨§¨¨©ªû«ª«ª««¬ú­¬­¥¤¥¥¦þ¥¦¦§ø¦§§¨¨§§¨¨©ªü©ª©ªª«¬«¬û­¬¬¤¥¥¦ý§¦§§ý¨§¨¨©ªú«ª««ª««¬þ«¬¬¤ ¥¦§þ¦§§¨ü©¨¨©©ªþ©ªªý«ª««¬¤¥þ¤¥¥ý¦¥¦¦§¨þ§¨¨©ûª©ª©ªª«þª««¤ü¥¤¤¥¥ú¦¥¦¥¥¦¦ý§¦§§ý¨§¨¨©ªþ©ªª«þ¬««ý¤£¤¤ý¥¤¥¥ý¦¥¦¦§¨þ§¨¨©þ¨©©ª«þª««ý¬£¤¤û¥¤¥¤¥¥þ¦¥¥¦ü§¦¦§§û¨§¨§¨¨©üª©©ªªù«ª««ªª««ý¤£¤¤¥ü¤¥¤¥¥¦û§¦§¦§§þ¨§§¨©ªò«ª«ª«ª««££¤££¤¤û¥¤¥¤¥¥¦ô§¦§¦§¦§§¨¨§¨¨©¨©ýª©ªª«£ ¤¥¦§¨ü§¨§¨¨©þ¨©©ªþ©ªª«£¤þ£¤¤ ¥¦ú§¦¦§¦§§¨§¨ý©¨©©üª©©ªª÷«ªª¢¢££¤££¤þ£¤¤¥þ¦¥¥¦ú§¦¦§¦§§¨ù©¨¨©¨¨©©ª©ª÷«ª¢££¢£¤££ý¤£¤¤¥ô¦¥¦¥¦¦§¦§§¦§§ü¨§§¨¨©üª©©ªª¢£¤ü¥¤¤¥¥¦ü¥¦§¦¦§¨ý©¨©©ªþ¢££ü¢£¢££¤þ£¤¤¥ý¦¥¦¦ú§¦¦§¦§§ý¨§¨¨ ©¢£þ¢££ü¤££¤¤¥ú¦¥¥¦¥¦¦§ý¨§¨¨þ§¨¨©ýª©¢¢ý£¢££ý¤£¤¤¥¤¥þ¦¥¥¦ò§¦§¦§¦§¨§§¨§§¨¨©ýª©¢¢£þ¢££û¤£¤£¤¤ý¥¤¥¥ü¦¥¥¦¦ú§¦¦§¦§§¨þ§¨¨ü©¨©¨¨©ª°±þ°±±þ²±±²³ù´³´´³³´´ýµ´µµý¶µ¶¶ý·¶··þ¸··°ü±°°±±ý²±²²³þ²³³´µü´µ´µµû¶µ¶µ¶¶·þ¶··ý¸·°°±²±²³þ²³³ü´³³´´ µý¶µ¶¶·¶·¯°±²ü³²²³³´öµ´µ´´µ´µµ¶ ¶ý·¶··°±þ°±±²÷±²±²²³²³²²ý³´³³´þ³´´µþ´µµ¶ù·¶··°¯°°±°±²±²÷³²³²²³³´³³ô´³´´³´µ´´µ´µµý¶µ¶¶ö·¶·¯°¯°°¯°°ý±°±±û²±²±²²þ³²²³ý´³´´ýµ´µµþ¶µµ¶þ·¯¯ °û±°±²±±²³þ´³³ý´³´´µü¶µ¶µµ¶¯ü°¯¯°°ý±°±±û²±²±²²³´³´µú´µµ´´µµ¶þ®¯¯°±ü°±°±± ²³þ´³³´ýµ´µµü¶µµ¶¶þ®¯¯°ý±°±±²þ³²²ø³²²³³´´³³´µô´µµ¶¶µ¶µ¶¯®¯¯°ü¯°°±±ü°±°±±²þ³²²³ý´³´´ýµ´µµý¶µ¶¶¯°ü¯°¯°°ý±°± ±²³þ²³³´ýµ´µµû¶µµ®¯¯ü®¯®¯¯ °±ù²±±²±±²²û³²³²³³´õ³´´µµ´´µµ´µµ®ý¯®¯¯þ°¯¯°ü±°°±±þ²±±²³þ²³³þ²³³´÷³´µµ´´µ´µµ®ú­®®¯®¯¯®¯°þ¯°°û±°±°±±²±ý²±²²þ³²²³ý´³´´úµ´µµ´®®¯þ°¯¯°þ±°°ü±°°±±²³²³ü´³³´´òµ´­®®­®­®®¯¯®¯¯°ü±°°±±²³û²³³´³³´µý­®­­®¯ý°¯°°±ü²±±²²ù³²²³³²³³´­®­®¯þ®¯¯ü°¯¯°°±þ°±±þ²±±²ú³²³³²³³ú´³³´³´´­ ®¯þ°¯¯°ý±°±±²³ø²³³´³´³´´­®þ­®®¯°¯°±°ý±°±±ý²±²²ý³²³³ü´³³´´þ¬­­®¯õ°¯°¯°¯°±°°±±²ü³²²³³ø´³´³­­¬­­ ®¯ù®¯°°¯¯°°ü±°°±±²±²ú³²²³²³³ö´³¬¬­¬¬­¬­­®ü¯®®¯¯°þ¯°°ý±°±±²þ±²²³þ²³³þ´¬¬û­¬­¬­­þ®­­®¯û®¯¯®¯¯þ°¯¯°û±°±°±±ö²±²²±²²³²³³¬þ­¬¬­ü®­­®®¯þ®¯¯°þ¯°°±þ²±±²û³²³³¬¬­ü¬­¬­­ù®­­®­­®®ú¯®®¯®¯¯ü°¯¯°°ý±°±±þ°±±ü²±±²²³¬ú­¬¬­¬­­®þ¯®®¯ °ý±°±±þ²±±²ø³²³««¬«¬¬ú­¬­¬¬­­®¯®¯°þ¯°°ü±°°±±þ²±±²ø³²««¬¬«¬¬þ­¬¬­®ü¯®®¯ ¯°û±°±°±±ý²±²²«¬­þ¬­­®ú¯®¯¯®¯¯ý°¯°°û±°±°±±ý²±²²«¬ý­¬­­û®­®­®®¯°ù¯°±±°°±±þ²±±²«þ¬««ý¬«¬¬­®¯ô®¯¯®¯¯°¯¯°¯°°ý±°±±²ý«ª««¬­þ¬­­®þ­®®¯ý°¯°°þ±°°±²ªû«ª«ª««¬­®þ­®®ý¯®¯¯ý°¯°°þ¯°°±ü²±²ªªô«ª««ª«¬«¬««¬¬ú­¬­¬¬­­®ý¯®¯¯û°¯°¯°°ý±°±±°±þ²ªª«þ¬«« ¬­ý®­®®÷¯®®¯®®¯®¯¯°þ¯°°±°±ªú«ª««ª««¬«¬­ý®­®®¯®¯ °±ü°±©ªª«ª«þ¬««¬­þ¬­­ ®¯þ®¯¯°±°ü±ª©ªªü«ªª««û¬«¬«¬¬­®ý¯®¯¯°þ¯°°±ûª©ª©ªªþ«ªª«¬õ­¬¬®­­®­®­®®þ¯®®¯ý°¯°°ü±°±©©ýª©ªªü«ªª««ú¬««¬«¬¬­ó¬­¬­­®­­®­®­®®¯þ®¯¯°©ªû©ªª©ªª «ý¬«¬¬­¬ý­®­­ý®­®®¯°ü¯°¯°°©ªþ©ªªý«ª«« ¬ü­¬¬­­ý®­® ®¯°û¯©©¨©©ýª©ªªú«ª««ª««¬ò«¬¬­­¬¬­¬­­®­®®þ­®®¯õ°¯¯°°©¨©¨¨©©ªþ©ªªý«ª««ù¬««¬¬«¬¬­þ¬­­þ¬­­ý®­®® ¯î°¯°©¨©¨¨©©ªª©ª©ª©ªªý«ª««¬þ­¬¬­®þ­®®¯ü®¯®¯¯õ°¯¯°¨¨©¨©¨©©ª«þª««¬ú«¬¬­¬­­®þ­®®¯þ®¯¯°þ§¨¨ý©¨©©ýª©ªªý«ª««¬þ­¬¬­þ®­­®¯®¯ý¨§¨¨÷©¨©¨©©ª©ªªü«ªª««û¬«¬«¬¬ú­¬¬­¬­­®þ¯®®ü¯®¯¨¨©ûª©ª©ªªú«ª««ª«« ¬­ý®­®®¯ø®¯¯§¨¨§¨¨©þ¨©©ª«¬þ«¬¬þ«¬¬ý­¬­­®þ­®®ú¯®¨§§¨¨©þ¨©©ªû«ª«ª««¬«¬­þ¬­­®þ­®®§õ¨§¨¨§¨©©¨¨©©ýª©ªª«þª«« ¬­ü®­­®®§¨þ§¨¨©þ¨©©üª©©ªª «ý¬«¬¬­®¦§ü¨§§¨¨©þ¨©©ªþ©ªªý«ª««¬þ­¬¬ ­®§ü¦§¨§§¨þ§¨¨ý©¨©©ªü©ª©ªªú«ª««ª««¬ü«¬«¬¬­þ¬­­ø®­®­®­¦§§¨þ©¨¨©þª©©ªþ©ªªþ«ªª«¬þ«¬¬û­¬­¬­­þ®­­þ®¦¦§þ¨§§ ¨©ªþ©ªª«ý¬«¬¬­þ¬­­ú®¦§¦¦§§ü¨§§¨¨©þ¨©©ûª©ª©ªªþ«ªªü«ªª««ý¬«¬¬ý­¬­­¦§þ¦§§¨þ§¨¨ý©¨©©ª©ªü«ªª««ý¬«¬¬­þ¥¦¦ú§¦§¦¦§§ú¨§¨§§¨¨©ýª©ªª «¬­¬þ­¦¦û§¦§¦§§ü¨©¨©©þ¨©©ýª©ªªü«ªª««¬­þýþúýþýýþýýýþýþþüýþýþþüýþýþþþÿþþûÿþþÿþþÿýþý þýþûýþýýþþþýþþþÿþþþÿþþûÿþþÿþþüÿþÿþþõýþþýþýþýþýþþõýþþýþýýþþýþ þþÿþþþÿþþþÿþþþÿþþþÿþþýþþýýþþýýþüýþýþþþýþþþýþþþýþþùÿþþÿþþýýþúýþýýþýýþûýþþýþþýþþÿþþÿýþþýýþþýþþýüþýþýýñþýýþýþþýþþýþþýþþþÿþþûÿþþÿýýþýþþýýþýþýùþýþýþýþþþýþ þûÿþþÿþþüÿþÿýýþýþýüþýýþþþýþþþýþþþÿþþþÿþþüÿþþýýþþýýþþýýøþýýþþýþýýýþýþþþýþ þýþÿýþþýýøþýýþýþýþþïýþýþýþýþþýþþýýþýþþþýþþþÿþþýþþýýþþýýþý÷þýþýþýþýþþþýþþþýþþúÿþÿþþý ýþýýþýþþûýþýýþþþýþþýþþýýþþýýøþýýþýýþýýþûýþýýþþýþûýþþýþþþýþþýþþýýòþýýþýþýþþýýþýþþþýþþþýþþþýþþýþþý ýøþýþþýþýþþþýþþþýþþýûþýýþý ýýþýþþþýþþüýþýþþýþþýýûþýýþýýþýúþýþýþýýþýþýþþýþþþüý ýþþýýþþýýþþýýþýúþýþþýþþûýþýýþþýþþýýîþýþýþþýýþýþýþýýþýþþüýþýþ þý÷þýþþýýþþýýþ÷ýþþýýþþýþþý þü ýþþýýûþýýþýýþþýýþòýþþýþþýþýýþýýþ þýþüý ýþþýýþþýýþþýýþüýþýþþúýþýþýþþùýþýþþýþþýþüý ýþþýýþþýýüþýýþþùýþþýþýþþýüþýýþþúýþþýýþþýöþýþýþýþýþýýþüýþýþþýþþüýýþüýýþüýýþþý ýüþýýþþýþýýþýþþüýþýþþýþýüýþüýýþýþýþýþûýþþýþþýýüýýûüýýüý ýþþýýþþýýþþýýþýýþýýûþýþþýýþýýüýüüúýüýýüýýþý÷þýþþýþýýþþúýþþýþýýûþýýüýýþþýýþþýý÷þýþýþþýþýýþñýþþýþýüüýüýýüüý ýþþý ýþþýýüþýþýýþùýþýþþýþþýþþýýûüýýüýýüýýüýýþüý ýûþýýþýýþòýþýýþýþþýþýþýþþýýüýýþüý ýþþýýþþýýþýþýþýþþýýüüýüýýüýþüý ýþþý ýþýþþýþþþýüüýü ýûþýþþýýíþýþýýþýýþþýþýþþýþýþþýóüýüýýüýýüýýüýýüýþýþþýýúþýýþýþþýþóýþþýýüüýýüüýüüý÷üýýüüýýüý ýùþýþýýþýýþýüþýþýýþþýýýþüýýùüýüýýüýýûüýüüý ýþüýýùþýþýýþýýþþýþþýýþýýþüýýüüýüýýôüýüýüýýüýýüýýþüýþýþþýòþýþýüüýýüýýüýüüýüýüüýüýýþþýýùþýýþýþýýþýþüüýüüýýóüýýüüýüüýýüüýýþüý ýüþýþýýþýøþýþýþýýüüýýüýýõüýüýüýüýýüýýþüýýûþýýþýýþýýþýýêüýýüýüüýüýýüüýüýüüýýüýýþüýý÷þýþýýþýýþþýøüýüüýüüýýþüýýüúýüýüüýýùüýüýýüý ýþþýýûþýþýþþþýüüýþüýýüúýüýýüýýüüýüý ýþþýýüþýýüüëýüüýüüýüýüüýýüýýüüýüýýþüýýûþýýþýýþüýüþýüüýþüýýüøýüýýüüýüü ýþþýýúþýþýþýýýüýüüýõüýüýýüýüýüýýüýüúýüýýüýýúþýýþýüüûýüüýüüýüôýüýýüüýüüýüýýþüýýþþýýúüýüüýüüñýüýýüýýüüýüýýüýýüüýüüýýþüýýþþýýüþýüüýüýüýýüýýùüýýüýüýýüýþüý ýúþýþþýü üýüþýüüýþüý ýþüýýüýüýûüýüýüüýüüýüýýü ýüýþüý ýþþýýüìýüýüýýüýüýüýüüýüýüýüüýýüýýúüýüýüýýüüýýüüüýüýüüþýüüþýüüþýüüüýüüýýþüýýúüýýüüý ýþþýýü÷ýüüýýüüýüüþýüüýòüýüýýüüýýüýýüýýþüý ýþþü üþýüüýøüýüýüüýüüþýüüýüüýüýýþüýý üþýüüþýüüúýüýüýüüýüüýüýýþüýýûüýýüýýüýýüýý üý üüýüüýýýüýüüýüýüýþüý ýúüûüüûüüúýüüýýü üýüüýüýýüýüýþüýýþüýý üþýüüüýüýüüþýüüýùüýüýüüýýüýýüý ýüüýýü üþýüüþýüüþýüüýýüýýþüýýûüýýüýýþüýýüýûûüüûüüüýüýüüþýüüòýüýüüýüüýüýýüýýþüýýüûýüüýüüýûüýüüýýüþýüüýüüýüýýþüýýýüûüüýüùýüüýüýüüýþüýýüùýüýýüüýýüüýüýýÿµ¶þµ¶¶ý·¶··þ¸··¸¹¸¹¸¹ì¸¹¹¸¸¹¸¸¹¸¹¸¹¸¹¸¹¹¸¹¹µþ¶µµ¶·¸þ¹¸¸¹¸¹þ¸¹¹¸¹û¸¹¹¸¹¹þ´µµù¶µµ¶¶µ¶¶·ü¸··¸¸þ·¸¸þ¹¸¸þ¹¸¸ ¹þ¸¹¹´µþ´µµ¶÷µ¶¶·¶¶·¶··ú¸··¸·¸¸þ¹¸¸¹þ¸¹¹¸¹ï¸¹¹¸¹¹¸¹¸¸¹¸´´µ´µµ¶þµ¶¶·þ¶··ý¸·¸¸þ¹¸¸þ¹¸¸õ¹¸¸¹¸¹¸¸¹¹¸¸¹þ¸´´µþ´µµú¶µ¶µµ¶¶þ·¶¶·þ¸··ý¸·¸¸ø¹¸¹¹¸¹¹¸¸ú¹¸¸¹¸¹¹þ¸´´µù¶µ¶µ¶¶··þ¶··þ¸··¸ü¹¸¹¸¸ø¹¸¹¸¹¸¸¹¹þ¸¹¹þ¸´´ù³´´µ´´µµ¶µ¶·þ¶··ý¸·¸¸ü¹¸¸¹¹ü¸¹¸¹¹ù¸¹¸¸¹¹¸¸û³´´³´´µû¶µ¶µ¶¶õ·¶·¶¶¸·¸¸·¸¸¹¸¹¸ì¹¸¹¹³³´³³´³´´µ´µ´µ´µµû¶µ¶µ¶¶ý·¶··û¸·¸·¸¸¹ø¸¹¹¸¹¸¸¹¹ú¸¹¸¹³´´þ³´´µþ´µµ¶þµ¶¶ý·¶··ý¸·¸¸ü¹¸¸¹¹¸û¹¸¹¹¸¸¹÷²³³´³³´³´´µ¶ý·¶··¸·¸ú¹¸¸¹¹¸¸¹¸ü¹¸¸³³ü´³³´´ùµ´µ´µ´µµ¶µ¶· ¸õ¹¸¸¹¸¹¸¹¹¸¹¹³´þ³´´µ¶·ú¶··¸·¸¸¹þ¸¹¹ü¸¹¸²²³´þ³´´þµ´´µ ¶·ó¸·¸··¸¸¹¸¸¹¸¹¹ö¸¹¸¸¹¸¹²³²²³´õ³´³´´µ´µ´´µµ¶µ¶·ü¶·¶··ü¸··¸¸þ¹¸¸¹û¸¹¸¸²²ý³²³³´ùµ´´µµ´µµý¶µ¶¶ý·¶··¸ó¹¸¹¹¸¹¹¸¹¹¸¹²²³þ²³³´þ³´´ýµ´µµ ¶·¸ø¹¸¸¹¹¸¸¹¹±ý²±²²³´úµ´´µ´µµü¶µµ¶¶û·¶·¶··ý¸·¸¸þ·¸¸¹þ¸¹¹±²ú³²³³²³³ü´³³´´µû¶µ¶µ¶¶ú·¶·¶¶··ý¸·¸¸î¹¸¹¹±±²±±²±²³²³²²³³÷´³´´³³´´µµù´µ´µµ¶µµ¶ùµ¶¶·¶¶··ú¸··¸·¸¸ú¹¸¸¹¸±±ý²±²²ý³²³³´þ³´´ýµ´µµ¶·¶ý·¶··ú¸·¸¸·¸¸û¹¸¸°±±²±²ý³²³³´µú¶µ¶¶µ¶¶·õ¸··¸·¸¸¹¹°±±ý²±²²³þ²³³´ó³´´µ´´µµ´µµ¶µµ¶·þ¶··¸ò°±±°°±±²²±²²±²²³ú´³³´³´´üµ´´µµý¶µ¶¶·¸þ·¸¸û±°±°±±²ü³²²³³ý´³´´ µ¶·þ¶··ý¸·¸¸°ù±°±±°°±±ü²±±²²³´÷³´´µ´´µ´µµ¶þµ¶¶·ü¸·¸°°ý±°±±²±²ý³²³³ý´³´´úµ´µµ´µµ¶þ·¶¶·þ¸°°±²±ú²±±²²³³²³ü´³³´´µ´µý¶µ¶¶ü·¶¶··°±þ°±±þ²±±²ý³²³³´þ³´´úµ´´µ´µµ¶üµ¶µ¶¶·¯ý°¯°°±ü°±°±±²±²ý³²³³ ´µþ´µµü¶µµ¶¶·¯ý°¯°°ú±°°±°±±²þ±²²³²³´û³´´³´´µþ´µµ¶·ý¶·¯¯ü°¯¯°°±þ°±±²³´³´µþ´µµù¶µ¶¶µµ¶¶·þ®¯¯ý°¯°°ø±°°±°±°±±²þ±²²þ³²²³´µþ´µµý¶µ¶¶¯ü°¯¯°°±ú²±±²±²²³²³´ü³´³´´µþ´µµ¶µ¶®¯û°¯°¯°°ú±°±±°±±ý²±²²³ý´³´´µ¶®ú¯®¯¯®¯¯°±²þ±²²þ³²²³þ´³³´µý¶µ¶¶®¯þ®¯¯°±þ°±±ý²±²²û³²³²³³ý´³´´µþ´µµ¶þµ®®¯þ®¯¯°±ú°±±²±²²ý³²³³´þ³´´µü¶µ­®®ü¯®®¯¯° ±²ú±²²³²³³þ²³³ô´³´³´´µµ´µ´µµü¶­­®®ý¯®¯¯õ°¯¯°°¯°±°°±±²ü³²²³³ú´³³´³´´÷µ´µµ­­®­®®¯ü°¯°¯¯°±õ²±²±²±²²³²³³þ´³³´µ­®ý¯®¯¯ü°¯¯°°ù±°°±°°±±ý²±²²³´³´ûµ´µµ­­ý®­®®¯ý°¯°°ü±°±°°±²þ±²²³þ²³³´µ´­ý®­®®¯þ®¯¯°þ¯°°±°ý±°±±²þ³²²³þ´³³´ý­¬­­®ü­®­®®ý¯®¯¯þ®¯¯°ú±°°±°±±ý²±²²ý³²³³´þ³´´­®þ­®®û¯®¯®¯¯°±°±ú²±²²±²²³þ²³³´þ³´´¬­þ®­­®¯°±þ°±±ý²±²²³÷´³³´³´¬­¬¬­þ®­­®ü¯®®¯¯°û±°±°±±²ý³²³³û´³³´¬¬­ú®­®®­®®¯ú°¯°¯¯°°þ±°°±û²±²±²²ú³²³²²³³ü´³´¬¬­ü®­­®®ü¯®®¯¯°ø±°±±°±²±±ú²±±²³²²³ü´¬«¬¬­ü¬­¬­­®¯þ®¯¯°±þ°±±ý²±²²ó±²²³²³²²³³´«¬¬­þ¬­­ü®­­®®¯ °±þ°±±ú²±²²±²²ý³²³³«¬­ ®ý¯®¯¯°þ¯°°±û²±²±²²ý³²««¬«¬ú­¬­¬¬­­®ü¯®®¯¯ü°¯¯°°ý±°±±þ²±±²ú³²²³³««¬ý­¬­­ý®­®®¯ý°¯°°±²³ü²«ª««¬ý­¬­­®¯ø°¯°¯°°¯°°±ú²±²±±²² «¬ý­¬­­®¯°ý±°±±þ°±±²«þª««¬­þ¬­­®ý¯®¯¯°þ¯°°±þ°±±²±²ý«ª««þª««ý¬«¬¬­®ö¯®®¯®¯®¯°¯¯ý°¯°°ý±°±±²ª«ù¬«¬¬««¬¬û­¬­¬­­®ý¯®¯¯û°¯°¯°°ü±°°±±ú²±²²©ªªû«ª«ª««ø¬««¬¬««¬¬­ù¬­­®­­®®ú¯®¯¯°¯¯°±õ°±°±±²±±ª©ªª«þ¬««¬­þ¬­­ü®­­®®¯ý°¯°°±þ°±±©ýª©ªªý«ª««¬þ«¬¬þ­¬¬­®¯°±¸ú·¸¹¸¸¹¹ûº¹º¹ººþ»ºº»þ¼» »þ¼»»¼»þ¼»»¼û·¸··¸¸¹þ¸¹¹ºú¹º¹º¹ºº»º»¼»þ¼»»¼ý»¼»»ù¼»¼·¸·¸¸ü¹¸¸¹¹ýº¹ººý»º»»þ¼»»þ¼»»¼»þ¼»»·þ¸··¸ù¹¸¸¹¹¸¹¹ºü»ºº»»þ¼»»ù¼»»··¸··¸ý¹¸¹¹þº¹¹º»þº» »þ¼»»ü¼»¼»»¼»¶·¸þ·¸¸¹ü¸¹¹ºº¹ºû»º»º»»þ¼»»þ¼»»þ¼» »¶·ù¸·¸·¸·¸¸¹ýº¹ºº»º»þ¼»»û¶··¶··¸ü·¸¹¸¸¹úº¹¹º¹ºº»þº» »þ¼»»¼»ù·¶¶·¶¶··þ¸··¸¹üº¹¹ºº»þº»»¶·¶·ý¸·¸¸¹þº¹¹ºý»º» »þ¼»»û¼¶¶·¶¶ý·¶··ý¸·¸¸¹ºþ¹ºº»þº» »þ¼»»¶·¶·ý¸·¸¸ý¹¸¹¹ýº¹ººö»ºº»»º»»¼»»þ¼»»¶ü·¶¶··ý¸·¸¸ü¹¸¸¹ ¹º»º»þ¼»»þ¼»»µ¶ý·¶··¸ù·¸·¸··¸¸ ¹ýº¹ºº»þ¶µµ¶·¸·¸¹üº¹¹ººþ»ººý»º» »ü¼»»µµý¶µ¶¶õ·¶··¸·¸·¸·¸¸ý¹¸¹¹º»º»÷¼»¼»»¼»»µµ¶µ¶·ý¸·¸¸ü·¸¹¸¸¹üº¹¹ººý»º»»þ¼»»µ¶øµ¶µ¶¶·¶··þ¶··ý¸·¸¸ú¹¸¹¹¸¹¹ûº¹º¹ºº »ý¼»´´µý¶µ¶¶·¶·¸þ·¸¸¹ùº¹¹ºº¹ººý»º»»û¼µ´´µµú¶µ¶¶µ¶¶·þ¶··ü¸··¸¸¹ù¸¹¹º¹¹ººû¹ºº»ºº»ø¼´µ´´µ´µµ¶ ·¸þ¹¸¸ý¹¸¹¹ ºý»º»»´µ¶·¶·ù¸·¸·¸·¸¸ý¹¸¹¹º¹º»þ³´´µý¶µ¶¶þ·¶¶·ý¸·¸¸ ¹öº¹º¹ºº»ºº»»´ýµ´µµþ¶µµ¶üµ¶¶··þ¶··¸¹þº¹¹º»þº»»´úµ´´µ´µµþ¶µµ¶ø·¶¶··¶¶··¸¹¸¹ºþ¹ººþ»ºº»ú³´³´³´´ýµ´µµ¶ù·¶¶·¶¶··¸¹þ¸¹¹ºþ»ºº³ý´³´´ýµ´µµ¶û·¶·¶··ú¸·¸··¸¸ù¹¸¸¹¹¸¹¹ºü»³´³³´µþ´µµü¶µµ¶¶ü·¶¶··ú¸··¸·¸¸ü¹¸¸¹¹þ¸¹¹üº¹¹ºº³´þµ´´µ¶·¶·¸·¸¹þ¸¹¹ü¸¹¹ººø¹º¹ºº²²³³ý´³´´üµ´µ´´ûµ¶µµ¶¶õµ¶¶·¶·¶¶·¶··¸¹ú¸¹¹º¹ººý¹º³³´þ³´´µ¶·û¸·¸·¸¸ý¹¸¹¹ºù¹³²²³²³³ü´³³´´µú´µµ¶µ¶¶·¶·¸·¸¹º²ü³²²³³þ´³³´µø¶µµ¶µ¶µ¶¶·¶·¸¹ùº¹º²²³²²³û´³´³´´üµ´´µµ¶üµ¶µ¶¶þ·¶¶·ý¸·¸¸ö¹¸¹¸¹¹¸¹¹²²³þ²³³ ´µü¶µµ¶¶ù·¶··¸·¸¸ü·¸·¸¸ý¹¸¹¹ü±²±²²³´³´µ¶õµ¶¶·¶·¶¶·¶··¸·¸ü¹¸¸¹¹þ±²²ú³²³²²³³ý´³´´ýµ´µµ¶ý·¶··¸·¸±ý²±²²ý³²³³´üµ´´µµ¶þ·¶¶·ý¸·¸¸±²þ³²²³ ´ýµ´µµý¶µ¶¶ü·¶¶··ü¸··¸¸þ¹±±ü²±±²²ü³²²³³ý´³´´µ¶ü·¶¶··¸·¸±ý²±²²ý³²³³ý´³´´µþ´µµ¶þµ¶¶ù·¶¶··¶··÷¸·¸··¸°°±±ý²±²²ý³²³³ü²³²³³ý´³´´µù¶µµ¶µµ¶¶ú·¶·¶¶··¸±²ü±²±²²ú³²²³²³³ù´³³´´³´´µþ´µµ¶·¸·þ°±±þ°±±²³þ´³³´û³´´µ´´µü¶µµ¶¶þµ¶¶·þ¸°°ý±°±±þ²±±²³²³ü´³³´´µþ´µµý¶µ¶¶ý·¶··°ý±°±±ú²±²±±²²û³²³²³³þ´³³´µþ´µµ¶·°ü±°°±±ü²±±²²ú³²³³²³³ ´ýµ´µµþ¶µµ¶ý·¶··ý°¯°°±û°±±°±±²ø±²²³²³²³³ü´³³´´úµ´µµ´µµ¶þµ¶¶ú·¶¯°¯°°û±°±±°°±²þ±²²ý³²³³ý´³´´ µý¶µ¶¶ø·¯¯°¯°¯°°±þ°±±õ²±±²²±²²³³²²³þ²³³´µþ´µµû¶µ¶µ¶¶ý¯°¯¯°ý±°±±ý²±²²ü³²²³³þ´³³´ýµ´µµü¶µµ¶¶¯°¯°ü±°°±±ý²±²²³ù²³²³³´³³ý´³´´µþ´µµú¶µ¶¶µ¶¶¯°ü±°°±±ù²±²²³²³³´µ¶ûµ¶¶µ¯¯ý°¯°°ü±°°±±²ü³²²³³ú´³´´³´´µü´µ´µµ¶¯þ®¯¯þ°¯¯ý°¯°°±þ²±±²³þ´³³´ µ¶®¯ò°¯¯°°¯°°±°±±°±± ²³ ´µ®¯þ®¯¯°þ¯°°±þ²±±²ø±³²²³²²³³÷´³´´³³´³´´ýµ´µµö¶­®®¯®®¯®¯¯ú°¯¯°¯°°ü±°°±±ý²±²²³þ²³³´³´üµ´´µµ®ý¯®¯¯°þ¯°°±ü²±±²²þ³²²³÷´³´´³´´³´´µú´µµ­­®®ü¯®®¯¯°¯°±÷°±°±±²±±²²û³²³²³³þ´³³´üµ´´­­®ý¯®¯¯°±ý²±²²³ ´®­®ý¯®¯¯ú®¯¯°¯°°±þ°±±ý²±²²³´³´­ó®­®­®­­®®¯¯®¯¯°þ¯°°±°±²ø±²±²²³²³³²³´³´÷¬­­®­®®­®®û¯®¯®¯¯°ø¯°°±°±°±±²û±²²±²²³ü´³³´´þÿùþÿþþÿÿþþýÿþÿÿþ)ÿóþÿÿþÿþþÿÿþÿþÿÿþþÿ'ÿþþÿÿþôÿþÿÿþþÿþÿÿþÿÿþþÿÿþþÿÿþþÿÿþýÿþÿÿþþÿÿþÿþÿûþÿÿþÿ ÿøþÿþÿþÿþÿÿþ÷ÿþÿÿþÿÿþÿ ÿþþÿÿýþÿþþÿþÿüþÿþÿ.ÿþÿþÿúþÿÿþþÿÿþÿþþÿÿþþÿÿþÿþþÿþþ÷ÿþÿþÿÿþþÿÿûþÿÿþÿÿþÿþÿþÿüþÿþÿ%ÿüþÿÿþþþÿþþÿòþÿþÿþÿÿþÿÿþÿþÿÿûþÿþþÿÿþþÿþþþÿþþøÿþÿþÿÿþÿÿöþÿþÿþþÿÿþÿÿþþÿÿþýÿþÿÿüþÿÿþþÿþþÿÿþÿùþÿþÿþþÿÿþþÿÿþøÿþþÿþþÿþþýÿþÿÿþþÿÿþÿþþÿÿþþÿþþÿþÿþþÿþþÿþþÿÿúþÿþÿþÿÿþþÿÿþþÿ ÿþøÿþþÿþÿþÿÿþþÿþþøÿþÿÿþÿÿþþ ÿþþÿÿþþÿþþÿþÿþþÿÿþþÿÿ÷þÿþþÿÿþþÿÿûþÿÿþÿÿþþÿ ÿþúÿþÿþÿþþéÿþÿþþÿÿþþÿþÿÿþþÿþþÿþÿþÿÿüþÿþÿÿþþÿ ÿþþÿþþÿþÿþûÿþÿþÿÿþþÿÿüþÿþÿÿþÿ þûÿþþÿþþûÿþÿþÿÿþÿþþÿÿþþÿÿüþÿþÿ ÿþþÿþþúÿþÿÿþÿ ÿþÿýþÿþþÿþýÿþÿÿþþÿÿýþýþþþÿþþÿþþÿÿüþÿþÿ ÿþþÿÿþøÿþÿþÿþþÿÿýþÿþþÿþþÿÿþþÿþþøÿþþÿþþÿþþõÿþÿÿþÿþÿþþÿÿúþÿÿþþÿÿþþÿÿ þþÿþþþÿþþþÿþþÿþöÿþÿÿþÿþÿþÿÿþüÿþþÿ ÿþþýþþûÿþþÿþþÿëþÿþþÿþþÿþþÿÿþÿÿþÿÿþþÿÿ÷þÿÿþÿÿþþÿÿþþÿÿýþýþþùÿþÿþþÿþþûÿþþÿþþ÷ÿþÿÿþÿÿþÿÿþþÿÿþþÿÿþþÿÿþþýþ þÿþþÿþþÿþ÷ÿþþÿþþÿþÿÿùþÿÿþÿþÿÿþþÿÿùþÿþÿýýþþþÿþþûÿþÿþÿÿøþÿÿþÿÿþÿÿþþÿÿþþýþþúÿþÿþÿþþòÿþÿþþÿþÿþþÿÿþÿÿýþÿþþÿþýþþýþþþÿþþþÿþþéÿþÿþÿþÿþÿþÿþÿÿþÿÿþÿÿþÿþþý þþÿþþúÿþþÿÿþþÿìþÿÿþþÿþÿþþÿÿþÿþÿÿþþÿÿþþýþ þþýþþõÿþþÿþþÿþþÿþþÿþýÿþÿÿþþÿÿûþÿÿþÿÿþþýþþþýþ þüÿþÿþþüÿþÿþþùÿþÿþÿþÿÿøþÿÿþÿþþÿÿþþÿÿøýþþýþþýþþþýþþþýþþþÿþþøÿþþÿþÿþÿÿôþÿÿþÿÿþÿÿþþÿÿþýÿþÿÿþýþþýþþþýþþþÿþþùÿþÿþþÿþþÿüþÿþÿÿþþÿÿþÿýùþýþþýýþþûýþþýþþþÿþþúÿþÿÿþÿÿþùÿþþÿÿýþþúýþþýþýýüþýýþþþýþþÿþþÿþþÿþÿýþÿþþýùþýþýþýþþüýþýþþþÿþþþÿþ þüÿþþÿÿüþýþýýþüýþýþþþýþþý þþÿþþíÿþÿþþÿþÿÿþþÿÿþÿÿþÿþþýþþýýþýþýýþýþþþýþþÿûþÿÿþÿÿüýþýþþýþýþûýþýýþ þþÿþ þþÿþþíÿþÿþþÿÿþýýþþýþýýþýþþüýþýþ þþýþ þþÿþþþÿþþüÿþþÿÿ÷þÿþÿýþþýþþüýþýþþüýþýþþþýþþüýþýþ þþÿþþþÿþþÿþÿþýöþýþýþþýþýþþûýþýýþþýüþýýþþþÿþþûÿþþÿþþþÿþþ÷ýþþýýþýýþþýþýþþýþþþÿþþÿþýûþýýþýýþýþþýþþüýþýþþþÿþþþÿþþûÿþÿÿþþúÿþþÿþýýþþýýþþýþþýþùýþýþþýþþþÿþþöÿþÿþÿþþýýþþþýþþýøþýþþýýþýýþþýþþþýþþùÿþÿþÿþýýþþýþþöýþýþþýþþýþþýþûýþýýþþ ýþüýþþýý÷þýþþýþþýþþûýþýýþþýÿþýý÷þýþýþýýþýýþ÷ýþþýýþþýþþýþþýþþþÿþþþÿþþøÿþþýýþþýýùþýþýþýþþþýþþýþøýþýýþþýþþþýþ þþÿþþýþþýýþþýþþýùþýýþþýþþûýþþýþþþÿþþþÿýýþþýýþþýýýþýþþýþûýþþýþþüýþýþþþýþþýþþýýþþýýúþýýþýþþýýþýþþûýþþýþþþÿýýþþýýþýþþýþþýýþýýúþýþýýþþþÿýýþþýýþþýýóþýýþýýþþýþþýþþúýþþýýþþýþüýþýþþýøþýýþþýþýýþþýþþüýþýþ þýþþýýþþýýþýþþýýüþýþýýþþýýöþýþýþþýþýþ þýÿþý ýùþýýþýþýýþýþý÷þýýþýþýýþþý þýþþýýþþýýþþýýùþýýþýþýýýþýþþýþýþûýþþýþ þý÷þýþýþýýþýýþýùþýþþýýþþþýþþþýþþ ýþþýý÷þýýþýþýýþþýþýóþýýþýþþýþþýýþ þýþþýýùþýþýýþýýþýýþýýþüýþýþþþýþþÿû¸¹¹¸¹¹¸ü¹¸¸¹¹þ¸-ù¹¸¸¹¸¸¹¹ù¸¹¹¸¹¹-¸¹þ¸¹¹÷¸¹¸¸¹¸¸¹-þ¸¹¹ü¸¹¸¹¹ø¸¹¸¸¹¸¹,¸¹þ¸¹¹¸þ¹¸¸ü¹¸¸,ý¹¸¹¹¸¹¸-þ¹¸¸¹¸û¹¸¹¸¹¹-í¸¹¹¸¹¸¹¹¸¹¹¸¸¹¹¸¹¹,¹¸¹¸¹-þ¹¸¸¹¸¹þ¸,¸¹¸ú¹¸¸¹¹¸¸-¹ü¸¹¸¹¹¸¹¸þ¹,ý¸¹¸¸ù¹¸¹¸¹¸¹¹¸¹-¹ü¸¹¸¹¹¸û¹¸¹¹,¸¹¸¹¸¹ü¸¹¸,¸ü¹¸¹¸¸¹ú¸¹¹¸¸,û¹¸¹¸¹¹¸þ¹,¹¸¹þ¸¹¹¸þ¹,þ¹¸¸¹ý¸¹¸¸¹¸ü¹¸¸,¹¸ò¹¸¸¹¸¹¹¸¹¸¹¸¸,ý¸¹¸¸ü¹¸¸¹¹þ¸,þ¹¸¸þ¹¸¸¹ø¸¹¸¹¸¸¹,ý¸¹¸¸¹¸¹¸-ý¸¹¸¸¹¸¹ú¸¹¸¹¹,¸ý¹¸¹¹ø¸¹¸¸¹¸¹,𸹹¸¹¹¸¹¹¸¹¸¸¹¹¸¸-¸ý¹¸¹¹¸û¹¸¸¹¸¸þ¹,þ·¸¸¹ý¸¹¸¸ý¹¸,ù·¸··¸¹¸¸¹û¸¹¹¸¹¹-·¸þ¹¸¸¹þ¸,·¸ù¹¸¹¹¸¹,·¸ü¹¸¸¹¹-þ¶··ý¸·¸¸¹¸-·ú¸·¸··¸¸¹-¶·þ¸··¸þ¹¸¸-¶·þ¶··þ¸··¸-¶·¸-¶·ù¸·¸·¸¸,¶ü·¶¶··ü¸·¸, ¶·¸-µ¶·¶·þ¸,µ¶ý·¶··-µ¶þµ¶¶·-µþ¶µµ¶·-´µ¶þ·¶¶-´µù´µµ¶¶µ¶¶-´µü¶µµ¶¶-´µ¶µ¶-´ýµ´µµú¶µµ¶¶,ý´³´´ûµ´µ´µµý¶µ¶¶-³´µ´µþ¶,³´ýµ´µµ-³´µ-³ô´³³´´³´´µµ´µµ-³ý´³´´µû´µ´µ,ù³²²³´³´´³´µ´þµ,ü³²²³³û´³´³´´µ-²ý³´³³´þµ,²³þ²³³ý´³´´-þ±²² ³þ´,²ø±²³²²³²³³´ý³´,û²±²±²²ü³²²³³þ´³³-ü±²±²²ý³²³³þ´,±²³þ²³³-»ý¼»-».»ü¼»¼» ».»þ¼»»-»-þ¼»»þ¼»»ù¼»»¼»»,»þ¼» »þ¼, »û¼»»¼»»-»ú¼»»¼¼»»-»û¼»»¼»»þ¼»»-ý»¼»»þ¼»»þ¼»»-»ü¼»¼»»ü¼»»,»þ¼»»þ¼»»ü¼»¼,ü¼»¼» »-þ¼»»-»þ¼»»þ¼»»-»ö¼»»¼»¼»»¼»»-»¼»-¼»þ¼» »-»þ¼»»¼»þ¼, »ü¼»¼»»ý¼»,»õ¼»¼»»¼»¼»¼»»-»þ¼» »-þº» »þ¼»»-»þ¼»»þ¼»»-ý»º»»þ¼»»ú¼»¼¼»,ü»ºº»»ü¼»¼»»þ¼,ºý»º» »ü¼»»,º»ú¼»¼»»,ºþ»ºº»þ¼»»-ºú»º»ºº»»û¼»»¼,¹ùº¹ºº»º»»ý¼»,ýº¹º º»-ø¹º¹º¹º¹ººû»º»º»»-¹ýº¹ºº»ûº»»¼,¹þº¹¹ºù»ºº»º»,¹º¹º»þº,ý¹¸¹¹ºþ¹ººþ»,þ¸¹¹þ¸¹¹ýº¹ººþ»,ú¸¹¹¸¸¹¹üº¹¹ºº-¸ý¹¸¹¹º-¸¹ùº¹ºº¹º,¸¹ºý¹º,ü·¸·¸¸ý¹¸¹¹ýº¹,û·¸¸·¸¸û¹¸¹¸¹¹ýº¹,·ü¸··¸¸ú¹¸¹¸¸¹¹-·¸þ·¸¸¹þ¸¹¹-þ¶··ü¸··¸¸ý¹¸¹¹-·÷¸··¸·¸··¸¸û¹¸¹¸,þ¶··¸þ·¸¸ý¹¸,¶·¸ü·¸·¸¸-¶ý·¶··¸-¶û·¶·¶··ý¸·¸¸-¶·þ¶··ú¸·¸·¸,¶ú·¶·¶¶··¸-þµ¶¶ü·¶¶··þ¸,ü¶µµ¶¶þ·¶¶·-õµ¶µ¶¶µµ¶¶·¶¶·-µþ¶µµ¶·-þ´µµ¶þµ¶¶ù·¶·¶··,µû¶µ¶µ¶¶ý·¶,üµ´´µµú¶µµ¶µ¶¶ý·¶,û´µµ´µµü¶µ¶µµ¶-ü´µµ´´µû¶µ¶¶,ÿ.ÿ.ÿ.ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿþþÿ ÿ-þÿ-ÿ-ÿ-ÿ-ýÿþÿÿ-ÿþþÿÿ-ÿþ ÿ-þÿþÿ-ÿþþÿ ÿ- ÿþþÿÿ-õþÿþÿÿþÿþÿþÿÿûþÿþÿ,ýÿþÿÿüþÿþÿÿ-ýÿþÿÿûþÿþþÿÿ-÷þÿþþÿÿþþÿÿûþÿþÿ,þ ÿþþ,þÿþþõÿþÿþÿþÿÿþþÿÿ-üÿþþÿÿúþÿþÿþÿÿýþÿ,þþÿÿþÿþþÿÿþ-þÿþÿ-÷þÿþÿÿþÿÿþþÿþþÿÿ-þÿùþÿÿþÿÿþþ-þÿþþÿÿüþÿþÿÿþþ,þþÿÿþÿþÿþ-þüÿþþÿÿþúÿþþÿÿ,þýÿþÿÿþÿþ-þûÿþÿÿþþüÿþþ,þþÿþþüÿþÿþþýÿþ,þþÿÿüþÿþÿÿþýÿþÿÿ-þþÿþþúÿþÿþÿþþÿ-þúÿþÿÿþÿÿþþ,þôÿþþÿþþÿþÿþþ,þüÿþÿþþýÿþ, þþÿþþÿýþÿ,þüÿþþÿÿþþÿ, þþÿþþ-þþÿþþþÿþþÿþ- þþÿþþÿ-ÿþq-ÿþ­-ÿþä-ÿþ,ÿþI,ÿþq,ÿþ”,ÿþ²,ÿþË,ÿþß,ÿþî,ÿþø,ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-€€€€+þpqqþpqqrýsr*püqppqqrþs*pùqpqqppqqr+pqýrqrr+ûpopoppqõpqqrrqqrqr*opüopqppqþrqq+opûoppqppq+oüpooppqýrq*þnoopúqpqppqqþr*opþoppqþp*oþnooýpoppqpþq*ýonooûpopoppqþp*noþnooýpopp+nonoþpoop+nøononnonooýpopp+þmnnýonoopýop*únmnmmnnýonooüpop*mnöononoopop*mnýonooüpoo*lmnûononoo+þlmmýnmnno+mþlmmnümnmnnüono*lmþnmmnþmnno+lþmllmnþmnn+lþmllmn+ýlkllýmlmmnþmnn+þkllýmlmmn+kýlkllmþlmmþnmm+kölkklmllmlmmn+ýklkklmþn*kþlkkýlkllýmlmm+ýkjkklþkllm+kýlkllm+kjkýlkllkl+jkjkûlklkllþmll+jòkjkjkklkkllkkll+jkþjkkúlkklkll+ijkúlkkll*þjiijýkjkkûlkll*ijkþl*iûjijijjk+ühiijjþijjk+ijijûkjkjkk+hiþjiijk+hijþijj+ùhiihihiijûijjkjj+hijij+ghiþhiij+ýhghhýihiij+þghhüihhiiûjiij*üghghhiûjiij*gûhghghhij+ghþghhüihhii+gþhggúhgghihhi+gþfgghiühii*úfgfgfggýhghh+fghüihi*fgþfggýhghhþi*fügffggh+f gh+ýfeffgh+eýfgffýgfggýhg*e fg+e÷feffeffgffýgfgg+ýwxwwxyþxyy+øxwxwxwwxxýyxyy+wöxwxxyyxyxyy+wxyýxy*vwþxwwxûyxyy*vøwvwxwxxwwxúyxxyx*ûvwwvwwxþwxxþy*úwvvwvwwxþy*ûuwvwvvûwvwwxx+vwvwx+vwx+uvwþvww+uvûwvwvww+uývuvvþwvvw+uvüuvuvvwüvww*þtuuvw+tuvw+ýutuuþvuuvwþv*tuvýwv*týutuuûvuvuvvþw*tuþtuuvüuvuvv+tüuttuuvýuv*þsttúuttutuuv+sýtsttüuttuuv+stþsttuþtuuþv*øststststtöuttutuuvu*sütssttúuttutuu+ststûutuu*ürsrssötsttststuttýut*þrssþrssýtstt+rýsrssütsstt+rüsrrssütsstt+rsþrssütsstt+rþsrrsûtsst*rþqrrstþs*ûrqrqrrsørsstsst*qrqrþsrrsýts*qürqqrrþsrrsþt*qûrqrqrrsrs+þpqqrqrs+ýqpqqrqrúsrrss*üpqpqqürqqrrýsr*püqppqqrqrþs*üpqpqqýrqrr+pqþpqqrúqrqqr*ýpoppqþpqqþr*üopoppqûrqrr*üopoppqþpqqþrqq+opûqpqpqq+opúqppqpqq+opüqppqq+opþoppq+opþoppùqppqpq*nýonoopþq*nopûoppoppþq*noþpoopþq*þmnnop+þmnnûononoop+m÷nmnnononooþp*mnøonononnoo+m nøonnoopo*mnþmnnüonnoo+múnmnnmnno+þlmmnþonno+õ+õþôõ õ+õô õ+ôõþôõõþôõõýöõ*úôõôõôõ õ+ôõô õ+ôõôõüôõôõõ+õôõþôõõúôõôõôõõ+üõôôõõôõþôõõ+ôõûôõõôõõ+þõôôõøôõõôõõôõõýôõ*üôõôõõþôõõ+ùôõõôõôõõûôõõôõõ+ôõûôõõôõõþôõõþô*ôýõôõõôõþô*ôùõôôõôõôôýõôõõýôõ*ôõôüõôôõõôõ+ôõôòõôõôõõôõõôõôõ*õùôõôõôôõõôõþô*ôþõôôöõôôõõôõõôõõþô*ôþõôôõøôõõôõôõ*ôþõôôüõôôõõþôõõþô*ôõôõôþõ*ôõýôõôôõüôõô*ôõôôõôõõôôõõôô*ýôõôôþõôôôõôõôôõõôôõõ*ôõôõüôõôõõôüõôõ*ôîõôôõôôõôôõôôõõôõô*ôþõôôþõôôõô+ôþõôôþõôôþõôôõþô*ûôõôõôôõôõ+ôõôõôþõ*ôúõôõôõ*ô+ôþõô ôýõô*ôþõ*ôþõôôþõ* ôþõôô+ô+þóôôþõ*ýôóôôþóôôþõôô+ôþóôôþóô ô+ô+þóôô+ôþóô ô+þóôôóôþóôô+þôóóúôóôôóô ô+ôó ô+ôóôþóôôþóôô+ôþóô ô+þóôôþóôôþóôô+ýóôóóýôóôôóôýóô*óøôóóôóôóôôùóôóôôó*óýôóôôþóôôþóôô+÷óôóóôóôóôôþóôôóô+þóôôûóôóóôôþóôôþó*óôþóôôóô+óþôóóþôóóôüóôô*üôóôóóóôóóôóôôóôóôô*÷óôóôóóôôóóöôóóôôóôóô*þôóóûôóôóôôúóôóôô*ôóþôóóýôóôô+ûóôóóôô óôþó*ìôóôóôôóóôôóôóóôóôóóô+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿsýtst tuývuvvûwvwvwwxyþxyyz{sýtsttuvwüvwvwwxüwxwxxýyxyyzyzûrssrssütssttýutuuvwvwxyþxyyzrstuötuuvvuuvuvvýwvwwxüyxxyy÷zyyzrrsrsstùuttuutuuúvuuvuvvþwvvwxyöxyzyyzyzqrrstuúvuuvuvvwþvwwüxwwxxþyxxyþxyyrúsrrssttþsttüututtuývuvvwxüyxxyyûzyqqrrýsrsstþuttuývuvvwýxwxxþyxxùyqqrqqrrüsrrsstýutuuvùuvwwvvwwxyýxyqqýrqrrstuvùwvvwwvwwxþwxxûyxyxqqýrqrrsûtststtuývuvvûwvwvwwùxwxwxwxxqþrqqrsþrssütssttuývuvvþuvvwþxwwxyqþpqqrqrsútsttsttýutuuvýwvwwýxwxxýqpqqþrqqürqqrrsrýsrss tuvwvüwxwxxqþpqqþpqqûrqrqrrüsrrssýtsttuvþuvvýwvwwüxwxppqúpqqrrqqrýsrsstúststtuuþtuuvþwvvwxwpüqppqqrþsrrsþtsstuþtuuývuvvwxpýqpqqþrqqr stúutuutuuúvuuvuvvwþvwwþoppqûpqppqqýrqrrýsrssûtststtuþtuuvûwvwvwwopûoppqppqýrqrrsûrsstsstýutuuývuvvýwvwwopþoppþqppqrsþtsstuvþuvvúwvvwvoopþoppüqppqqûrqrqrrùsrsststtüuttuuûvuvuvvopqþpqqúrqrrqrrýsrsstýutuuvn÷onoopopoppüqppqqürqqrrsrsýtsttýutuuývuvvþnooþpoopþqppqrsþtsstýutuuývuvvünonoopqþrqqrstüuttuuvþuvvnoûpopoppûqpqpqqûrqrqrrüsrrssütssttuvunoýpoppqpqþpqqrûsrsrssûtststtuþtuuýnmnnýonoopqpqrüqrqrrsþtssýtsttuümnmnnöonnonnoopoopþoppýqpqqýrqrrsütssttuþtuuþmnnúonnonoopýqpqqürqqrrsþrsstþuttùutumnmnnûononooúpoopoppûqpqpqqürqqrrýsrssütssttôutuummnmnmmnnopþoppüqppqqrüqrqrrüsrrssütssttmnoúpoopoppqrsûtststtýulmmn opüqppqqýrqrrsrsþtsstþlmmnþmnnopqýrqrrýsrsstùlmlmllmmnómnnonoonoopoppqürqqrrósrsrsststtssllmýnmnnoþnooýpoppýqpq qrþsrrsötstkllmllmmýnmnnüonnoopopþqppqýrqrrsþrssl mnopopqþpqqúrqqrrssrõstsskklklmllmnmnþonnoýpoppýqpqqürqqrrýsrssklýmlmmûlmmnmmnøonoononooþpoopýqpqqrsýrskklmþnmmnýonoopüqppqqrþqrrûsrsrkklûmlmlmmnoþnooûpopoppýqpqqrûsrkjkklmnmnopüopoppqùpqqrqqrrþjkklýmlmmünmmnnúonoonooûpopoppqúrqqrqrrúkjkkjkklmünmmnnoüpooppqürqqrrjýkjkklmþlmmnoþnooûpopoppüqpqppqrjûkjkjkklmùlmnmnmnnýonooþnoopqþpqqûrqqrjjklklmnûmnnonnopþoppqþrjjûkjkjkklümllmmþnmmnûononoopþoppqûrjiijjkþjkklþkllömllmmnnmmnnoþnoopqþpqqjiýjijj÷kjkkjkklkklýmlmmþnmmnoþnoopüopqppqüpqjiijùkjjkjjkklkl mnûononooûpopoppqijþijjýkjkkýlkllúmlmmlmmnonopûqhihiijükjjkklþkllýmlmmnþmnnoþpoopþqiiýjijj klmnmønmnononooüpooppúoppihiijkþlkklûmlmlmm÷nmnnoonnoopþopphijiújijjkjjýkjkklýmlmm÷nmnnmmnnoopýophhýihiiòjijiijjkkjkkjkklmþlmmûnmnmnnûononooüpoohhiûjijijjkûlklkllmnúononnoopþghhüihhiij klýmlmmúnmnnmnnýonooýpohhijijklûkllmllmnþmnnýonooghiþhiiýjijjúkjklkllþkllþmllmünmmnnoýzyzzþ{zz{ü|{{||}þ|}}ý~}~~ü~~þ€€ú€€yzzúyzz{z{{ü|{{||ü}||}}ý~}~~ý€€€ø€zyzzyzzþ{zz{ý|{||}~}~ü~~€þ€€yzþyzz{z{|{|}|}ú~}}~}~~þ~~ø€€€€€yüzyyzzü{zz{{ü|{{||ý}|}}ø~}~}~}}~~ý~€yýzyzz{z{|þ{||}þ|}}~õ~~~€€€þxyyzþyzz{|þ{||ý}|}}ù~}}~}}~~ü~~ø€€yxyyzþyzz{|þ}||}ý~}~~û~~þ€ü€xxyyþxyyzú{z{{z{{|}|ý}|}}~þ}~~þ~~ü~~xýyxyy z{ú|{{|{||þ}||}~ú~~~xüyxxyyzû{z{z{{þ|{{|ü}||}}~þ}~~ü~~þwxxþyxxýyxyyzþyzz{zý{z{{|õ{||}||}|}|}}~ùwxwxxyxxûyxyxyyzý{z{{þ|{{|þ{||}ü|}|}}ü~}}~~wxyxyûzyzyzzü{zz{{|}þ|}}þ~}}~þ~~þwwxyùzyyzyyzzý{z{{þz{{þ|{{|}þ|}}ú~}~~}~~ù~~wwxxwxyz{üz{z{{|þ{||ú}|}}|}}ý~}~~ý~wwûxwxwxx yz {ý|{||}þ|}}ü~}}~~þvwwûxwxwxxyýzyzzyþz{{þz{{|ý}|}}û~}~~wwxwxøyxxyxyxyy z{þ|{{|ú}||}|}}ø~}}vvwvwwýxwxxüyxxyyzý{z{{ý|{||ü}||}}ù~}vvwvwwüxwwxxyzyzü{z{zz{|þ{||}þ|}}ý~}vvwþvwwþxwwxûyxyxyyzþyzzý{z{{ý|{||õ}||}|}||}}vvüwvvwwxwýxwxxüyxxyyzþyzzô{z{z{{|{|{{||ý}|}}uvýwvwwúxwxxwxxyxyzþyzzò{zz{{z{{|{||{||}|}û|vuuvvûwvwvwwýxwxxyxyýzyzzû{z{z{{þ|{{|þ}||þvuuvwxüyxyxx yz{üz{z{{ü|{{||ù}uuvvuvvwvwúxwxwwxxyþxyyzþyzz{ý|{||þ}uuvýwvwwxüwxwxxþyxxyz{ý|{||uvüuvuvvwþxwwxûyxyxyyzý{z{{|{|þtuuvuvüwvvwwxýyxyyzyz{ý|{|| uvwþxwwxýyxyyþzyyz{þz{{| uvþuvvwxþwxxúyxyyxyyzþyzz{þz{{ú|ttutuuývuvvþwvvwxþwxx yz{þz{{tuvýwvwwþxwwýxwxxyþxyyüzyyzz{þsttu vüwvvwwxüyxxyyýzyzz{ýtsttuvýwvwwþvwwýxwxxyþzyyz{ùz{zztsttuvuvwxþwxxyþxyyzýstsstúututtuuvúwvvwvwwýxwxxyxyzù{zsststt uývuvvúwvwvvwwýxwxxyýzyzzþ{ssõtssttsttutuuývuvvw xyzyzþ{sstüuttuuvþuvvwvwûxwxwxxúyxxyxyy÷zyyzzrsrssýtstt uþvuuvøwvvwvwvwwüxwwxxyûzyzyzzsþrsstýutuuvúwvvwvwwxyþxyyûzyzzssürsrssütssttüuttuuývuvvwþvwwxþwxxyözyrsrssrrssýtsttúutuutuuövuuvvuvvwvvwþxwwxyrsrstýutuuývuvvúuvvwwvvwøxwwxwxwxxýyxyyþzrrüsrrssýtsttþuttuþvuuvwúvwwxxwwxþyxxùyxyxqqrrþsrrýsrsstýutuuþvuu vwxyýxyrrþqrrýsrssûtststtuûvuvuvvwþvwwûxwxwxxyqrûsrsrsstsûtstuttýutuuvuvwþvwwxþwxxqþrqqrsþrsstuvþwvvwxþwxxþyqqýrqr rsûtststtutuvwþvwwxþpqqýrqrrüsrrsstuøtuutuuvuuvþuvvýwvwwxýwxqqþpqqrþqrrsürsrssýtsttuøvuvuvuuvvwxþwqqpýqrqqýrqrrþsrrsýtsttþuttuvwøvwvwwxwxxpýqpqqýrqrrstutuüvuuvvwvwþxppýqpqqþrqqrsþrssütssttutuûvuvuvvwýxwppúqppqpqqýrqrrúsrrsrsstuütutuuvþuvvýwvwwþoppýqpqqrs t uvwþvwwýpoppûqpqpqqrþsrrsýtsttöutuvuuvvuvvwopùqppqqpqqrûsrsrsstþsttþuttýutuuvþuvvüwvwoopqþpqqrþqrrúsrssrsstþsttúuttutuuþvuuûvuvwvvopþoppþqppq rsþtsstuþtuuvþuvvoúpoppoppqþpqqrqrýsrsstþsttuütutuuývuvvýõöõ õöûõöõöõõýöõööûõööõööõýöõöö÷õõöõõööõõöõõööõöõöóõöõõöõööõööõööþ÷ööü÷ööõõþöõ õþöõõöþõööõöõöù÷ööõööõõüöõöõõöúõööõõöö÷õöõöõööõööþ÷ööþ÷õõöõöõýöõööþõööûõööõööüõöõö öþ÷ööõþöõõþöõõöõõöõöõöõööõöõõùöõõööõö öþõööõöõùöõöõöõööõöõýöõööþõööþõööü÷ööõ õþöõõùöõõöõöõõþöõõúöõöõõööúõööõõö öõþöõõþöõ õ÷öõõööõöõööþõööõöõûöõõöõõúöõõööõõõöõööõöõööõööþõööþ÷õõþöõõöõþöõõôöõööõõööõööõõýöõööúõööõõöö õøöõõöõööõõôöõöõöõõöõööõõöõöþõööüôõôõõþöõõèöõõöõöõõööõööõööõõööõöõööóõöõõööõöõööõööõþöõõööõöõõöõõöõõöõþöõõùöõöõöõööþõöö õþöõõúöõöõöõõøöõöõõöõööüõöõö öõûöõõöõõöõöøõööõõööõõöþõööüõööõõþôõ õøöõõööõöõõöõöüõööõõöõýöõööõþôõõþöõõùöõöõõöõõýöõööîõöõöõõööõõööõöõööõõþôõõþôõ õüöõöõõþöõõùöõöõõöõõþöõõöþõööþõööþôõõôõþôõõþöõõþöõõöõöõþöõõúöõööõööõôûõôõôõõøöõöõõööõõüöõöõõöõöõþôõõþôõõöõöõöüõöõööõõöõöõööõõöõööõþôõõûôõõôõõùöõõöõõööüõöõööõüôõôõõþôõõüöõöõõèöõöõöõööõööõöõõöõöõöõõôõõôõüôõôõõöõöõüöõõööõöõöõôõúôõôõôõõþöõõþöõõõöõöõööõöõöõõûôõôôõõþôõõþôõõþöõõö÷õöõöõööõööõöõôõþôõõôõøöõööõöõööõôýõôõõþôõõþôõõþôõ õþöõõþöõõöõööõöõõöõôôõõûôõôõôôõôõþôõõþöõõþöõõúöõõööõõüöõõööõôõõôõôôõôõõôôõõþôõõôõöõöõöõöôõôüõôôõõþôõõöõûöõööõõúöõöõõôôõôôõôõõôôõôôõôõõþôõ õûöõõöõõþöõõøöõõöõöõööúôõôõôõõýôõôôòõôôõõôôõõôôõôõõþöõõüöõöõõþöõõúöõôõõôôþõôôûõôõõôôþõôôýõôõõþôõõöõöøõööõõôõôôõüôõôõõôýõôõõôõüôõôõõþöõõøôõôôõôõôôõþôõõþôõõôõþôõõöõöüõööõõúôõôôõôôùõôõôõõôôõøôõõôõõôõõþôõ õþöõõûöõõöõõôþõôôþõôôõõôõõôôõôõõôõõþôõõüôõôõõþôõõþöõõþöõõôõôôõôõõôôõôõõôõõôõôüõôõôôþõôôõþôõõôõþôõõþôõõþôõ õöõýöõô ôõøôõôôõôôõõýôõôôûõôõôõõþôõ õöõôøõôõôõôõôôõôõûôõôôõõøôõõôõõôõ õþöõõôþõô ôüõôõôôüõôôõõþôõõùôõôõõôõõþôõõþöõõôõôõôõôûõôõôõõôõüôõôõõþöôôþõôôõôþõôôíõôõõôôõôõôõõôõôôõôõõùôõôõõôõõþöôôõôõõôôõõôôõôôõõ÷ôõôõõôõôõõûôõôôõõ ôõôùõôõõôõôô÷õôõôôõõôõõôýõôõõ ôðõôõôõôôõôôõõôôõôôõôõøôõôôõõôõõôûõôõôõõôûõôõôõõôóõôôõõôôõôõôôõõôõûôõõôõõ ôýõôõõôõôùõôõôõõôôøõôôõõôõôôýõôõõôþóô ôþõôôõþôõõôýõôõõôýõôõõôõþôõõ ôþõôôûõôôõôôõôþõôôõûôõôõôôõþôõõþóô ôüõôõôôûõôõõôôõóôõôõôõõôõõôõôôõþôõõôþõôôùõôôõôõôôõþôõõôõôõöôõõôõõôõôõõýôóôôþõôôõûôõôôõõôûõôõõôôõþôõõôþóôôüóôóô ôþõôôúõôõôõôôýõôõõôòõôôõõôõõôõôõõôôþõôôûõôôõôôþõôôþõôôõþôõõýôõôôõþóôôþóôôþõôôþõôôúõôõôõôôöõôõôõôõôôõõüôõôõõóôþõôôþõôôõôýõôõõôõôõûôõôóô ôþóô ôüõôõôôõôõôõýôõôôõûóôôóôôþóôôþóôôõòôõôôõõôõõôõôôõõôôõôõõôôõôõôóôôþóôôõôþõôôõôõôõüôõõôôþóôôþõôôûõôôõôôõôõôõþôõõÿûz{{z{{|þ{||þ}||} ~ü€€€ý€‚üƒ{z{{|}ú~}~~}~~ú~~€ý€‚û‚z{zz{|þ{||}þ|}}~ý~€û‚‚‚zzû{z{z{{û|{|{||þ}||}~~ý€€€ý€ü‚‚zzý{z{{| }~û~€€ú€€ý‚yzz{z{ùz{{||{||}~ü~~ü€€€yz{þ|{{|}þ|}}~þ}~~û~~€þ€€÷€€€yyzü{zz{{|þ{||}ù~}~~}}~~€yz{ý|{||ý}|}}~û~~ú€€€€üyyzzþyzzü{zz{{û|{||}}~ü}~~þ~ü€€€yzyz{|þ}||}ý~}~~ú~~€xüyxxyy z{| }~÷~~~€€xyzþyzz{ú|{|{{||ô}|}}~}~}~~}~~ý~ú€€€€€þxyyxyüzyyzzþ{zz{ø|{{|{|}||}~û}~~~~€xyûxyyxyyzü{zz{{ü|{{||ü}||}}~þ~~ø€€wwxxyzþyzzü{zz{{|ý}|}}ú~}~}}~~ü~~ý€wxxyúzyzyyzz{õ|{|{||}|}|}}~þ}~~ü~~~wxyüxyxyyüzyyzz{z{|þ}||}~þ}~~÷~xxwxwxxyxýyxyyzþ{zz{|ü{||}}þ|}}~ö~~~~wwxxwùxyyxyxyyzý{z{{ý|{||}~þ}~~þvwwxþyxxyýzyzzý{z{{ý|{||}~}~ú~~vwwxûwxxwxxyxyûzyzyzz{|ü{|{||}þ~}}ý~}~~üwvvwwôxwwxwxxyxyxyyüzyyzz{þz{{þz{{|þ{||}þ|}}~výwvwwxyxyzü{zz{{|þ{||}ý~}~~výwvwwxýyxyyz{þ|{{|ý}|}}ý~}vvüwvvww xyzþyzzü{zz{{û|{|{||}þ|}}~vüwvvwwýxwxxyüxyxyyz{ý|{||ý}|}}üvuuvvýwvwwýxwxxýyxyyz{þz{{|}þ|}}ü~uuvvüwvvwwxþwxxúyxxyxyyýzyzzý{z{{|÷}||}||}}uuývuvvwvwxþwxxyzyzý{z{{ý|{||}ü|}}uuvþuvvwýxwxxyýzyzzþyzz{z{|þ}uuvþwvvýwvwwxyüzyyzzü{zz{{|û}|}tuuývuvvwþvwwxþwxxyþxyyzüyzyzz{|ý}tuuüvuuvvúwvwwvwwxúyxxyxyyzý{z{{ö|{|{||}ttuuvþuvvûwvwvwwxyzyz{|{|tuûvuvuvvwþvwwxþyxxyþzyyzý{z{{þ|ttýutuuvwýxwxxyýzyzz{ûz{{|{{tuývuvvýwvwwxþwxxýyxyyýzyzz{z{üststtýutuuvþuvvþwvvwúxwwxwxxùyxxyyxyyz{z{stúutuutuuvùwvvwvvwwxþwxxyxyzþyzzþ{zz{ústststtûututuuvþuvvwüxwwxxyþxyyzyz{úz{{stsstýutuuþtuuvøuvvwvvwvvwòxwxwxwxxyyxyxyyzþyzzü{zzssütssttuþtuuvwvwùxwxxwwxxþyxxyzùyzz{{zssþtsstuûvuvuvvwxþwxxþyxxyûzyzyzzsþrsstýutuuvûwvwvwwýxwxxyzürsrssütstsstuþvuuvüwvvwwþxwwxüyxxyyzrýsrsstþstt uvwþvwwýxwxxüyxxyyzrsþrssütssttýutuuv wxyxyþzyyrsürsrsstuövuvuvvwwvwwýxwxxúyxyxxyyùzrrqrsrrösrsstsststtýutuuúvuuvuvvwýxwxxúwxxyxyyøxyzyrrqrrýsrsstþsttuþtuuvwþvwwýxwxxþwxxyqrsþrsstýutuuüvuuvvûwvwvwwxûwxxyxxyqùrqrqrsrrsýtsttuývuvvwùxwwxwwxxüyqpqqýrqrrôsrrssrsstssttùuttuutuuývuvvwvwþxwwxþwxxûyxqpqqýrqrrsþrsstûstuuttuvwxþwxxüpqpqqrqrþsrrstuþtuuvùuvvwwvwwxýqpqqrþsrrsþtsstýutuuütutuuvþuvvwüvwvwwxýpqppqürqqrrsþtsstúuttutuuývuvvwõxwwxxppqqpq qrstûututuuvuvwxwþoppqþpqqýrqrrýsrsststûututuuvüwvvwwp qrþsrrsýtsttøstututtuu vwýxoppqrqrsþrsstuþtuuvýwvwwûopooppýqpqqùrqrqrqrrsútsttsttuþtuuvówvwwoopooppoppqùrqrrqqrrsürsrssütssttýutuuvþuvvwû‚‚‚‚ýƒ‚ƒƒü„ƒƒ„„…„…†þ…††‡†‡ˆü‡ˆˆþ‚‚ýƒ‚ƒ ƒ„û…„…„……þ†……†‡þ†‡‡ˆ‡üˆ€€‚ýƒ‚ƒƒý„ƒ„„ý…„……†ý‡†‡‡þˆ‡‡þ€‚ƒþ‚ƒƒþ„ƒƒ„ý…„……þ„……ý†…††‡ü†‡†‡‡ù€€€€þ‚‚ýƒ‚ƒƒý„ƒ„„…û†…†…††þ‡††‡úˆ€€€‚û‚‚‚‚ýƒ‚ƒƒø„ƒ„ƒƒ„ƒ„„…ù†…†…††‡‡þ†‡‡€þ€ ‚ýƒ‚ƒƒ„…þ„……†þ‡††‡€þ€‚þ‚‚ƒ‚ƒ„ù…„…„…„……þ†……†‡€€ý€þ‚‚ƒþ‚ƒƒ„ý…„……ø†…†‡‡†‡††ý€€€ý€ ‚ýƒ‚ƒƒþ„ƒƒ„…ù†……††…††ü‡††ý€€€ý€‚þ‚‚þƒ‚‚ƒ„…„…†þ…††ý€€€ù€€€û‚‚‚‚ƒý„ƒ„„ …†þ€ý€€€ý€û‚‚‚‚ýƒ‚ƒƒû„ƒ„ƒ„„…ó†……††…†~€€ý€þ‚ö‚‚‚ƒ‚ƒ‚‚ƒƒþ„ƒƒ„…†ú~~~€€€‚‚ƒþ‚ƒƒ„ƒ„ý…„……÷†…††~~€þ€€€ý‚‚‚üƒ‚ƒ‚‚ƒ„þƒ„„ý…„……~þ€ý€€€ý€þ€‚ƒþ‚ƒƒþ„ƒƒ „…†~þ~~ý~€€ý€‚þ‚‚ƒþ‚ƒƒ„öƒ„„……„……„……ý~}~~õ€€€€€€þ€ó‚‚‚‚‚ƒƒ‚‚ƒƒù„ƒƒ„„ƒ„„ü…„„…… ~ú€€€€€ú€€€þ‚‚úƒ‚ƒƒ‚ƒƒý„ƒ„„…„…}~þ~ú€€€€þ€‚úƒ‚ƒ‚‚ƒƒý„ƒ„„ú…}}~}~~þ~ý€€€‚ú‚‚ƒ‚ƒƒþ‚ƒƒú„ƒ„ƒƒ„„ü}~}~~þ}~~€‚‚øƒ‚ƒ‚ƒƒ‚ƒƒ„ø…„}}~}}~~þ~û€€€€û€€‚þ‚‚ƒý„ƒ„„}ü~}}~~þ}~~þ~ù€€€€ý‚‚‚ƒ„|}ý~}~~ú~~~ý€€€ ‚ýƒ‚ƒƒ„}û~}~}~~þ€€ø€€‚‚ ƒ„|}ý~}~~þ~þ€€ú‚‚‚‚ƒ„|û}|}|}}~€‚þƒ‚‚ƒ|ý}|}}ú~}}~}~~€þ€€ý€‚þ‚‚üƒ‚‚ƒƒþ{||ý}|}}~ý€€€‚þ‚‚ƒ|}þ|}}ú~}~~}~~ý~ù€€€€û€€‚ú‚ƒƒ‚ƒƒ{|ü}||}}þ~}}~ý~ý€€€þ€€ú‚‚‚‚‚ûƒ‚ƒ|{{|þ}||ý}|}}~þ}~~þ~ €ú‚‚‚‚‚þƒ{{û|{|{||}~þ}~~€ú€€€€‚‚{ú|{||{||}ú|}~}}~~û~~ú€€€€€ý€‚{þ|{{|þ}||}~}~ü€€€û€€‚þz{{|þ{||ý}|}}ü~}}~~û~~ü€€€ö€‚‚‚{{z{|ù}||}||}}~þ}~~ €ü€€€‚ûz{zz{{|ý}|}}ý~}~~ù~~~÷€€€€€÷‚{z{{z{z{{ý|{||÷}||}|}}~}}~þ€€ú€€€z{ùz{z{{|{{|û}|}|}}~ø}~~}~~~~ €zü{zz{{|þ}||}ü~}}~~þ~~€ý€ýzyzzø{z{z{{z{{ú|{||{||ú}|}}|}}ý~}~~ ù€€€€€þzzþyzzý{z{{|ý}|}}ú~}~}}~~ü~~€yzüyzz{{z{|þ{||}þ|}}~þ~ý€€€yzþyzz{ý|{||}ú~}}~}~~€yzþ{zz{|þ{||þ}||ý}|}}ý~}~~þ€€ýyxyyzý{z{{|}þ|}}ü~}}~~ù~~~€ø€€yxyxyyz{|}û~}~}~~ý~xyzþyzzý{z{{|ý}|}}þ|}}ü~}}~~xyýzyzzý{z{{ |}ü~}}~~þ}~~xyùzyzyzyzz{üz{z{{|û{||}||}þ|}}ü~}}~~ý~xüyxxyyþzyyz{z{ô|{|{|{||}}|}}ú~}~~}~~ý~x yzü{zz{{|û{|}|} }~ü~~~üxwwxxyxyýzyzz{|ù}|}}||}}~}~ûwxwwxxüyxxyyzyzü{zz{{|}þ|}}~û~~wwxüyxxy yz{û|{|{||ý}|}}ý~}~~wôxwxwxwxxyyxyyzý{z{{þz{{|}~}~wxyxyùzyzyzyzz{úz{|{|{{|ü}||}}ý~}~~û}~wvwwxþwxxyxyzøyz{zz{z{{|ø{|}||}|}}~výwvwwxüwxwxxúyxyyxyyúzyzyyzzü{zz{{ý|{||}õ~}~~vwvwvvwwxyþxyyzyz{ü|{{||ù}|}}||}}ø~}~vwvvwwþxwwxüyxxyyzø{zz{z{z{{|ý}|}}þ~}öó÷ö÷÷ö÷ö÷ö÷÷ö÷÷ö÷ûö÷÷ö÷÷þø÷÷ø÷ö÷öý÷ö÷÷öö÷ö÷ö÷÷ö÷ö÷÷ûö÷öö÷÷öþ÷ööý÷ö÷÷ö÷üö÷ö÷÷üø÷ø÷÷÷ø÷÷öö÷öö÷÷ö÷ðö÷ö÷÷ö÷÷ö÷öö÷÷ö÷÷þø÷÷öþ÷öö÷þö÷÷üö÷ö÷ ÷þö÷÷þö÷ ÷þø÷÷öú÷ö÷öö÷÷ö÷ýö÷öö÷þö÷÷þö÷÷þö÷ ÷þø÷ ÷öö÷ö÷÷öö÷ö÷ööù÷öö÷÷ö÷÷þö÷÷ö÷ø÷þøööû÷ö÷÷öö÷öü÷ö÷öö÷ùö÷÷ö÷÷öö÷ö÷þö÷÷øø÷÷øöö÷ööú÷ö÷ö÷öö÷ö÷þö÷÷þø÷÷öþ÷ööû÷öö÷ööû÷öö÷ööú÷öö÷÷öö÷öþ÷ööû÷öö÷ööþ÷öö÷þö÷÷þö÷÷ ö÷ýö÷ööø÷öö÷÷öö÷÷ûö÷öö÷÷þö÷÷þö÷÷ ö÷ö÷ö÷÷ö÷öö÷ö÷ööý÷ö÷÷þö÷÷þö÷÷öü÷ö÷ööþ÷öö÷ö÷ö÷þö÷÷øö÷ö÷ö÷ö÷ ÷ ö÷öþ÷öö÷þö÷÷þö÷÷ûö÷öö÷÷þö÷ ÷ öü÷öö÷÷ö÷öþ÷öö÷÷ö÷öö÷öö÷öö÷øö÷÷ö÷÷ö÷÷þõöö÷öõ÷ö÷ö÷öö÷÷ö÷÷üö÷ö÷÷üö÷ö÷÷þö÷÷þõöö÷öþ÷öö÷ö÷þö÷÷þö÷÷ûö÷÷ö÷÷þö÷÷öû÷öö÷öö÷ýö÷öö÷þö÷÷ûö÷÷ö÷÷ öþ÷öö÷öþ÷ööþ÷öö÷öþ÷ööþ÷ööý÷ö÷÷þö÷÷üöõõööõöü÷ö÷öö÷öò÷ö÷ö÷÷öö÷ö÷öö÷÷ûö÷öö÷÷þö÷÷öüõöõööõ÷öö÷öö÷÷ö÷ööü÷öö÷÷îö÷ö÷öö÷÷ö÷÷ö÷ö÷ö÷ööþõööü÷ö÷öö÷öþ÷öö÷ö÷þö÷÷öþõööþ÷ööö÷ö÷ö÷öö÷÷ööþ÷öö÷÷ö÷ö÷÷öö÷÷ýöõööøõöõõööõö öü÷ö÷ö öò÷öö÷÷ö÷öö÷ö÷ö÷÷üö÷÷öö÷õöþõööþõööþõööþ÷ö öþ÷ööþ÷öö÷ñö÷÷ö÷÷öö÷ö÷ööõööõûöõöõööþ÷ööþ÷öö÷öü÷öö÷÷öõ"öû÷öö÷ö öø÷öö÷÷ö÷ööý÷õööþõööþõööüõöõöö÷÷ö÷ö÷ö÷öö÷÷öû÷ö÷ö÷÷þõööþõööõöþõööþ÷ö öü÷ö÷ööú÷ö÷ö÷ööý÷õööûõööõööþ÷ööû÷ö÷÷ööþ÷ööü÷ö÷ööý÷ö÷÷ýöõööøõöõööõõööýõöõõöþõööþ÷ööþ÷ööþ÷ööü÷ö÷öö÷öþ÷õõöõöõöûõööõö öþ÷ööþ÷ööþ÷öö÷ö÷ùö÷÷öö÷ööõöøõöõõööõöö÷ýö÷öö÷ö÷øöõöõööõööõöþõööþõööþõöö÷öó÷öö÷õõööõõöõöööõöõööõööõööþõö öþ÷ööþ÷ööþ÷öö õöþõööóõöõööõööõööõö ö÷ö÷þö÷÷ýö÷ööõùöõöõõöõõýöõööþõööüõöõöö÷÷öö÷÷öö÷öö÷öõþöõõûöõõöõõöþõööþõööþõööú÷ö÷öö÷÷öþ÷ööþ÷õõûöõööõõþöõõûöõöõööüõööõõöþõööþ÷ööþ÷ööþ÷ööý÷öõõöõøöõõöõõöõõýöõööþõööþ÷ööþ÷ööû÷ö÷öõõúöõööõööþõööüõööõõýöõö ö÷öú÷ö÷÷öõõôöõöõöõõööõõööõúöõöõõööõöõùöõõööõööüõöõööþõööþõööþõööþ÷ööõþöõ õüöõöõõþöõõøöõööõöõööû÷öö÷õõþöõõúöõöõöõõöýõöõõöûõööõööþõö öþ÷ööþ÷ööõþöõõüöõöõõöõöõýöõööùõöõõöõööõöý÷öõõþöõõþöõõùöõööõõööþõööõ öþõö öõþöõõøöõöõöõöõõöõöüõöõöööõööõööõööõõúöõöõõööþõö öõûöõõöõõöõþöõõüöõõööõöþõööþõööþõööõöþõöö õþöõõþöõõöõöþõööûõööõö öõûöõõöõõþöõõöõöõöþõööõöõûöõõöõõúöõöõöõõþöõõýöõööõöþõööýõôõõùöõööõöõõöþõööýõöõõúöõöõõööþõööüõöõöö õöñõöõööõõöõöõöõöõõöõöþõööþõööýõöõõþôõ õþöõ õöõýöõööõûöõöõö öõöõþöõõööõöõöõõöõööþõööþõööþõööþõööõþôõõüöõöõõþöõõïöõööõõöõöõõööõöõööþõööõûôõõôõõûöõõöõõýöõööõþöõõþöõõöõöþõööûõööõööõþöõõööõöõöõõööõõüöõõööüõöõööõöþõööþõööøõôõõôõôõõþöõõöõöõöýõöõõýöõööþõööõüôõôõõþôõõþöõõþöõõöýõöõõöõþöõõöþõöö õô õúöõöõöõõþöõõöúõöõöõööüõöõööüõööõõþöõõôõþôõ õþöõõþöõõöõööõöõõööõõöö÷õööõõööõööÿƒþ‚ƒƒ„ …†‡ ˆ‰ûЉЉŠŠ‚þƒ‚‚ƒþ„ƒƒ„…þ†……†‡†‡ˆý‰ˆ‰‰õЉ‰Š‚‚ƒƒ‚‚ƒƒü„ƒƒ„„ý…„……†…†ý‡†‡‡ˆ‰üˆ‰ˆ‰‰Š‚ƒþ‚ƒƒû‚ƒƒ„ƒƒ„ü…„„……†þ…†† ‡ˆ‰òˆ‰‰Š‰‰‚‚‚‚ƒ‚ƒƒþ‚ƒƒ„…ü„…„……ü†……††ü‡††‡‡ ˆ‰þŠ‚úƒ‚ƒƒ‚ƒƒ„þƒ„„ú…„……„……†ú…†‡†‡††‡ˆ‡ˆ‰üˆ‰‰÷‚‚‚ƒ‚‚ƒƒ„þƒ„„þ…„„…†û‡†‡†‡‡ýˆ‡ˆˆ‰üˆ‰‰‚þ‚‚ýƒ‚ƒƒû„ƒ„ƒ„„…û†…†…††û‡†‡†‡‡ˆþ‰‚ƒþ„ƒƒ„ …†ü‡††‡‡ˆ‚ûƒ‚ƒ‚ƒƒ„ø…„…„„…„……ü†……††‡þ†‡‡üˆ‡‡ˆˆ€ý‚‚‚þƒ‚‚ƒý„ƒ„„û…„…„……†þ…††‡þ†‡‡ˆþ‡ˆˆþ€þ€‚ýƒ‚ƒƒ„ƒ„…þ„……†ü‡††‡‡þˆ‡‡ˆ€þ€‚þ‚‚ƒ‚ƒý„ƒ„„ü…„„……†þ…††‡þ†‡‡ˆý‡ˆ€€ ‚ôƒ‚ƒ‚ƒ‚ƒƒ„„ƒ„„ý…„……û†…†…††‡ûˆ‡‡€€ü€€û‚‚‚‚ƒ‚üƒ‚‚ƒƒ„øƒ„„…„…„…… †ý‡†‡‡üˆ‡‡€€þ€€þ€‚üƒ‚‚ƒƒ„þƒ„„…ý†…††ú‡†‡††‡‡€ú€‚‚‚üƒ‚‚ƒƒ„…ý†…††‡þ†‡‡€û€€‚þ‚‚ƒþ„ƒƒ„ú…„„…„……†þ…††‡€þ€€ú€€€‚ýƒ‚ƒƒü„ƒƒ„„ö…„„…„……†…††ù€€€€€ü‚‚‚ýƒ‚ƒƒ„…„…ü†……††þ~€ü€€‚þ‚‚ýƒ‚ƒƒü„ƒ„ƒƒ„…ý†…††ú~~~€ü€€ý‚‚‚ƒ„…†û~~~ù€€€€€‚ûƒ‚ƒ‚ƒƒú„ƒƒ„ƒ„„ú…„……„……ý†…††~ü~~€þ€‚ƒú‚ƒ‚ƒ„ƒƒ„ü…„„……†~þ~€ý€‚ýƒ‚ƒƒþ‚ƒƒ„þƒ„„ý…„……†þ}~~ü~~ü€€€þ‚‚þƒ‚‚ƒû„ƒ„ƒ„„ý…„……ü}~}~~ú~~~€€ý‚‚‚üƒ‚‚ƒƒ„þƒ„„…}ý~}~~ý~€û€€€ý€ý‚‚‚ƒþ‚ƒƒõ„ƒ„„ƒƒ„ƒ„„……„…}þ~}}~ý~€þ€€ú€€€‚ƒþ‚ƒƒþ„ƒƒ„þ…„„þ…}}~þ}~~ý~û€€€€ü€€‚úƒ‚‚ƒ‚ƒƒ„ô…„„…}}~}}~}~~ü~~ü€€€þ‚‚ýƒ‚ƒƒþ„ƒƒ„…}~ü~€€þ€‚ƒ„ý…„||}~õ}~~}~~~~€þ€€‚ƒþ‚ƒƒü„ƒƒ„„}|}~þ}~~þ~þ€€‚þƒ‚‚ƒ„|þ}||}þ~}}ý~}~~€þ€€þ‚‚üƒ‚‚ƒƒý„ƒ||ý}|}}~~€þ€€ý€ü‚‚‚üƒ‚‚ƒƒ|û}|}}||}~þ€€ú‚‚‚‚ƒû„ƒƒ„||}~þ~€€ü‚‚‚ƒþ{||ù{||}}|}}~þ~€ý€þ€‚ýƒ‚ƒƒ{|ý}|}}~ý~€ü€€ú‚‚‚‚ƒ{ø|{|}}||}}~þ}~~ý~ý€€€ý€‚‚þƒ{{þ|{{|}þ|}}ý~}~~ú~~~€þ€ý‚‚‚{|{|ú}|}}|}}ú~}~~}~~ù€€€€€ý€‚üz{z{{ü|{{||ý}|}}ü~}}~~ý€€€þ‚‚z{ý|{||ý}|}}ý~}~~þ}~~ú~~€ü€€‚ø‚{z{zz{{ü|{{||ý}|}}~ €ý€û‚‚yzz{|þ{||}ý~}~~ü~~€ þyzz{üz{z{{|}~þ~ý€€€þyzz{|ú}|}}|}}~þ}~~þ~þ€€ýzyzzý{z{{þ|{{|ý}|}}~÷}~}~~~ý€€€yúzyzz{zz{|{|}þ~}}~þ~~þ€€ò€€€yyzzyyzzþ{zz{|þ{||}ü~}}~~€ý€yyzyzý{z{{ý|{||û}|}|}}ý~}~~÷~~€€€€õxyxyyzzyyzzý{z{{|ý}|}}~þ~~€ù€yxyxyyüzyyzz{ |}~ú~~€þ€€þyxxyüzyyzz{zû{|{{||÷{}||}}||}}~þ~€xyzþyzz{zù{z{{||{{|} ~ô€€wxxyxyxxyyzþyzzý{z{{ü|{{||}þ~}}~ø~~€€x yzþyzz{þz{{|þ{||ü}||}}þ~}}~ý~ùwxwxxyxxüyxxyyýzyzzý{z{{ |} ~ý~wxyúzyzyyzzý{z{{|ü}||}}~þ}~~ø~€xwxwwxy÷xyyzyzzyzzõ{zz{z{{|{{||}û~}~}~~wxyýzyzzùyzz{{z{{| }~÷~wwxxwxwxxüyxxyyúzyzzyzz{þz{{õ|{|{|{|}}|}}÷|}}~}~~}~~ˆ‰Šþ‹ŠŠ‹ŒýŒùŽŽŽŽŽýŽˆû‰ˆ‰ˆ‰‰üЉ‰ŠŠù‹ŠŠ‹‹Š‹‹üŒ‹‹ŒŒúŒŒŒýŽŽŽøŽŽŽü‡ˆˆ‰‰þˆ‰‰Šþ‰ŠŠ ‹üŒ‹‹ŒŒŒŽŽõŽˆˆ‡ˆˆ‰ˆ‰‰ Š‹Œþ‹ŒŒúŒŒýŽŽŽþŽŽýŽþ‡ˆˆ‰ˆ‰Š‹ýŒ‹ŒŒþ‹ŒŒŽþŽŽøŽŽ‡‡ˆˆý‰ˆ‰‰Šþ‰ŠŠý‹Š‹‹úŒ‹Œ‹‹ŒŒýŒŽþŽŽ÷‡‡ˆ‡ˆˆ‡ˆˆû‰ˆ‰ˆ‰‰ýЉŠŠ‹ ŒüŒŒŽ‡ýˆ‡ˆˆý‰ˆ‰‰þЉ‰Š‹þŠ‹‹þŒ‹‹ŒúŒŒŒüŽŽŽþ†‡‡ ˆ‰þЉ‰ýЉŠŠý‹Š‹‹ŒûŒŒŽùŽŽŽ‡‡ ˆý‰ˆ‰‰÷Љ‰Š‰ŠŠ‰ŠŠû‹Š‹Š‹‹Œþ‹ŒŒýŒŽþ†‡‡ˆþ‡ˆˆ‰þˆ‰‰þЉ‰Š‹Š‹ŒýŒŽ‡û†‡‡†‡‡ˆü‡ˆ‰ˆˆ‰Šþ‰ŠŠú‹ŠŠ‹Š‹‹ýŒ‹ŒŒýŒõކ‡‡†‡††‡‡ûˆ‡ˆ‡ˆˆú‰ˆˆ‰ˆ‰‰ýЉŠŠ‹Œ‹ŒûŒŒ†‡ü†‡†‡‡ýˆ‡ˆˆø‡ˆˆ‰ˆˆ‰ˆˆ‰ýЉŠŠû‹Š‹Š‹‹þŒ‹‹ŒþŒ…†ý‡†‡‡üˆ‡‡ˆˆ‰ˆ‰õŠ‰ŠŠ‰ŠŠ‹Š‹ŠŠ‹Œ‹ŒþŒŒ…†ý‡†‡‡ˆ‡ˆ‰ˆ‰ûЉЉŠŠý‹Š‹‹ûŒ‹Œ‹ŒŒŒ…†þ…††þ‡††‡üˆ‡‡ˆˆý‰ˆ‰‰Šú‹ŠŠ‹Š‹‹ Œ…û†…†…††‡ ˆü‰ˆˆ‰‰úŠ‰ŠŠ‹ŠŠý‹Š‹‹ŒöŒ……†…†…††‡ˆ‰þˆ‰‰Š‹þŠ‹‹Œ…†‡ˆ‡ýˆ‡ˆˆþ‰ˆˆ‰Šü‹ŠŠ‹‹Œþ‹ŒŒ…þ†……†þ‡††‡ýˆ‡ˆˆ‰üЉ‰ŠŠø‹Š‹‹Š‹Œ‹‹Œ„…û†…†…††‡þ†‡‡ˆþ‰ˆˆ‰Šý‹Š‹‹üŒ‹‹ŒŒ…†û…††‡††‡†‡ýˆ‡ˆˆý‰ˆ‰‰Š‹Š‹Œü„…„……ú†…††…††‡þ†‡‡ˆþ‰ˆˆý‰ˆ‰‰úЉЉ‰ŠŠü‹ŠŠ‹‹„ú…„…„„……ý†…††û‡†‡†‡‡üˆ‡‡ˆˆý‰ˆ‰‰üЉ‰ŠŠ‹Š‹„þ…„„…ù„……†……††‡þˆ‡‡ˆý‰ˆ‰‰ýЉŠŠ‹ý„ƒ„„ý…„……þ†……†û‡†‡†‡‡ûˆ‡ˆ‡ˆˆþ‰ˆˆý‰ˆ‰‰Šþ‹ŠŠü‹„ƒ„„…û„……„……†…ø†‡†‡†‡†‡‡þˆ‡‡ˆþ‰ˆˆ‰ýЉŠŠ‹Šþ‹ƒƒ„ …†ý‡†‡‡þ†‡‡üˆ‡‡ˆˆ‰úЉЉ‰ŠŠ‹þŠƒƒ „…ü†……†† ‡ˆý‰ˆ‰‰þˆ‰‰þЉ‰Šú‹ƒƒ„ƒ„„…ù„…††…†……†þ‡††‡þˆ‡‡ˆ‰þˆ‰‰úЉЉ‰ŠŠƒý„ƒ„„…þ„……†…†‡úˆ‡ˆˆ‡ˆˆü‰ˆˆ‰‰ýЉŠŠ÷ƒ‚ƒƒ„„ƒƒ„„ …†ü‡††‡‡ˆ‰Šƒþ„ƒƒ„ …†ý‡†‡‡ˆþ‡ˆˆû‰ˆ‰ˆ‰‰Šýƒ‚ƒƒû„ƒ„ƒ„„ü…„„……þ†……†þ‡††ý‡†‡‡þˆ‡‡õˆ‡ˆˆ‰‰ˆˆ‰ˆ‰‰Šþ‰‚‚üƒ‚‚ƒƒû„ƒ„ƒ„„û…„…„……†‡þ†‡‡þˆ‡‡ˆþ‡ˆˆû‰ˆ‰ˆ‰‰Š‚ƒþ‚ƒƒú„ƒƒ„ƒ„„…û†…†…††‡û†‡‡†‡‡ˆý‰ˆ‰‰‚ƒü‚ƒ‚ƒƒý„ƒ„„û…„…„……õ†……††‡†‡‡†‡‡ˆþ‡ˆˆþ‰ˆˆ‰‚ƒþ‚ƒƒû„ƒ„ƒ„„ú…„……„……†‡þ†‡‡ˆþ‡ˆˆü‰ˆˆ‰‰‚þ‚‚ƒü‚ƒ‚ƒƒ„ƒý„…„„…ý†…††þ…††ý‡†‡‡úˆ‡ˆˆ‰ˆˆü‰‚‚‚ýƒ‚ƒƒ„þƒ„„ý…„……†þ…††‡þ†‡‡ˆþ‡ˆˆþ‰ˆˆý‚‚‚ƒ„þƒ„„…†þ…††ý‡†‡‡ˆ ‚ƒ„úƒ„ƒ„ƒ„„…†…†‡†‡üˆ‡‡ˆˆ€ø‚‚‚‚‚ƒ„ƒ„ü…„„……þ†……ý†…††‡þ†‡‡ùˆ‡ˆ‡ˆˆü‚‚‚þƒ‚‚ƒ‚ƒ„ƒ„ü…„„……ý†…††÷‡††‡‡†‡ˆ‡‡ùˆ‡‡ˆ€€‚ûƒ‚ƒ‚ƒƒý„ƒ„ „…†þ…†† ‡ùˆ€€€€ ‚ƒþ‚ƒƒ „…†þ…†† ‡úˆ€€‚þ‚‚þƒ‚‚ƒ„ûƒ„„ƒ„„ü…„„……†‡þˆ€€ý€‚ƒ„þƒ„„…þ„……ý†…††‡þ†‡‡þ€€ý€ú‚‚‚‚‚þƒ‚‚ƒ„…þ„……†‡ý†‡€€þ€€ý‚‚‚ƒ„ý…„……þ„……†ø‡†‡†‡€€€û€‚‚þƒ‚‚ƒþ„ƒƒ„…†…†‡þ€€þ€€‚þ‚‚ƒó‚ƒ‚ƒƒ„„ƒƒ„„ƒ„„ù…„…„…„……†û‡†€€þ€€‚ýƒ‚ƒƒø„ƒ„ƒ„ƒƒ„„…÷„…„……†……††÷‡~€€€€þ€€þ€‚ƒþ‚ƒƒü„ƒƒ„„…†þ‡ú€€€€€ý‚‚‚ƒ „…†ú…†~~ú€€€€ú€€ý‚‚‚ƒþ‚ƒƒý„ƒ„„…†þ…††~ý~ý€€€ú€€ý‚‚‚þ‚‚ƒû„ƒ„ƒ„„ý…„……ú†~~ü€€€þ€€ú€€í‚‚‚‚ƒ‚‚ƒƒ‚ƒƒ„„ƒƒ„„ú…„„…†……þ†~~þ€€þ‚‚þƒ‚‚ƒú„ƒƒ„ƒ„„î…„…„…„……†…~~~~~ý€€€ ‚ýƒ‚ƒƒü„ƒƒ„„…~þ~~ü€€€û€€€ü‚‚‚üƒ‚‚ƒƒ„ƒ„þƒ„„ú…„„……~~ü~~ €ü€€‚ýƒ‚ƒƒþ„ƒƒ„÷…„„……~}}~~ý€€€þ€ø€‚‚‚‚ûƒ‚ƒ‚ƒƒú„ƒ„„ƒ„„ý…„…÷ø÷þø÷÷ø÷øþ÷ø øþ÷øøùùøùøùùøøþ÷øøþ÷øøü÷øø÷÷øò÷øø÷øø÷øø÷ø÷÷øøþùøøûùøùùøø÷õø÷ø÷ø÷ø÷ø÷øø÷üø÷ø÷÷ø÷øþùøøüùøùøøù÷ø÷÷øø÷÷ýø÷øø÷ýø÷øø÷øþ÷øøùøùø÷ø÷øø÷ø÷÷øø÷øø÷øþ÷øøþ÷øøþ÷ø øþùø øþù÷÷òø÷øø÷÷ø÷÷øø÷÷øøý÷ø÷÷øþ÷øøûùøøùøø÷þø÷÷ø÷þø÷÷ø÷þø÷÷ûø÷ø÷øøü÷ø÷øøüùøù÷÷þø÷÷üø÷÷øøû÷øø÷øø÷øþ÷øøþ÷ø øþùøøþùøøýùø÷÷óø÷÷øø÷ø÷ø÷øø÷÷þø÷÷ ø÷ øþùøø÷ùø÷÷ø÷ø÷÷öø÷ø÷÷øø÷÷øøþ÷øøû÷øø÷ø øþùøøþù÷÷ûø÷÷ø÷÷þø÷÷ø÷ûø÷øø÷÷úø÷÷øø÷÷ø÷þø÷÷øü÷øø÷÷öø÷øø÷øø÷÷øøþ÷ø øû÷øøùøøýùø÷÷ûø÷÷ø÷÷þø÷÷øû÷ø÷÷øøþ÷øø÷øû÷øø÷ø ø÷þø÷÷þø÷÷ùø÷÷ø÷ø÷÷ø÷ûø÷ø÷øø÷øþ÷øøù÷øø÷ø÷øø÷þø÷ ÷þø÷÷úø÷øø÷øø÷ø÷øþ÷ø ø÷ø÷ùø÷÷ø÷ø÷÷÷ø÷÷ø÷ø÷÷øø÷ø÷ø÷ø÷ýø÷øø÷ùø÷÷ø÷ø÷÷úø÷÷ø÷øøù÷ø÷øø÷ø ø÷þø÷÷üø÷ø÷÷ýø÷øøþ÷øøû÷øø÷øøþ÷ø ø ÷þø÷÷þø÷÷þø÷÷üø÷÷øøþ÷øøþ÷øøø÷øø÷øø÷øø÷øý÷ö÷÷ùø÷÷ø÷÷øø÷ûø÷ø÷øøö÷øø÷ø÷÷øø÷÷ ø÷þø÷÷þø÷÷îø÷øø÷÷ø÷øø÷øø÷øø÷øøü÷øø÷÷üø÷ø÷÷øø÷÷øø÷÷øø÷øþ÷øøü÷ø÷øøþö÷÷þö÷÷þø÷÷ûø÷÷ø÷÷øü÷øø÷÷øû÷ø÷÷øøø÷øø÷÷ø÷øø÷þø÷÷þø÷÷øþ÷øø÷òø÷ø÷÷ø÷øø÷øø÷øøø÷ø÷÷ø÷ö÷÷üø÷ø÷÷ñø÷ø÷÷øø÷ø÷ø÷ø÷øø÷ø÷üø÷÷øø÷þö÷÷þø÷÷ûø÷÷ø÷÷øý÷ø÷÷øþ÷øø÷ýø÷øø÷ø÷øö÷÷ö÷÷ö÷ ÷úø÷ø÷ø÷÷øø÷÷ø÷ø÷øø÷ø÷øþ÷øøþ÷øø÷ûö÷öö÷÷üö÷ö÷ ÷þø÷÷øø÷ø÷ø÷ø÷÷øö÷øø÷÷øø÷÷øø÷þö÷÷þö÷÷þø÷÷þø÷÷üø÷ø÷÷ø÷øþ÷öö÷öý÷ö÷ ÷þø÷÷ø÷ùø÷øø÷ø÷÷ø÷úø÷ø÷ø÷÷øý÷ö÷÷üö÷ö÷÷þø÷÷þø÷÷ø÷þø÷÷øù÷ø÷øøö÷÷þö÷ ÷þö÷÷þø÷÷þø÷÷øþ÷øøþ÷øøþö÷÷öý÷ö÷÷þö÷÷þö÷÷þø÷÷ø÷þø÷÷íø÷ø÷÷øø÷øö÷ö÷÷öö÷ö÷÷úö÷ö÷ö÷÷þö÷÷üø÷ø÷ ÷þø÷÷øñ÷øø÷÷ö÷ö÷÷ö÷÷ö÷÷ö ÷þø÷÷ñø÷øø÷ø÷öö÷ö÷öö÷÷ùö÷ö÷öö÷÷þö÷÷ø÷ñø÷÷ø÷øø÷ø÷ø÷÷ø÷÷úøö÷öö÷÷ö÷ö÷ùö÷÷ö÷ö÷÷þø÷÷þø÷÷øø÷÷øø÷÷øøý÷ø÷÷øø÷öö÷ö÷ööø÷ö÷ö÷÷ö÷÷ûö÷öö÷÷øþ÷øø÷øüö÷ö÷÷üö÷ö÷÷þö÷÷ø÷øø÷ø÷ø÷ø÷÷ö÷ýö÷öö÷üö÷ö÷ ÷þö÷ ÷ùø÷÷ø÷ø÷÷ýø÷øø÷ùø÷ö÷öö÷÷õö÷÷ö÷öö÷öö÷÷öý÷ö÷÷ûö÷÷ö÷÷þø÷÷øý÷ø÷÷ö÷ýö÷ööý÷ö÷÷ö÷þö÷÷þö÷÷øü÷øø÷÷ø÷ö÷ö÷þö÷÷ö÷úø÷ø÷ø÷÷øû÷öö÷ööþ÷öö÷üö÷ö÷÷üö÷ö÷÷þø÷÷øø÷÷ø÷øø÷÷ö÷þö÷÷üö÷ö÷÷úö÷öö÷öö÷þö÷÷ðø÷÷ø÷ø÷öö÷ö÷öö÷öö÷óö÷ö÷ö÷öö÷öö÷öö÷þø÷÷öþ÷ööø÷ö÷ö÷÷ö÷÷üö÷ö÷÷þö÷÷þö÷÷þö÷÷þö÷ ÷óø÷ø÷÷ö÷öö÷ö÷ööû÷öö÷öö÷öö÷÷öö÷ö÷ö÷÷ùö÷÷ö÷ö÷÷þö÷÷þø÷÷ýö÷ööþ÷ööþ÷ööù÷öö÷öö÷÷øö÷öö÷öö÷ ÷þö÷÷þö÷÷þø÷÷þøööþ÷öö÷ö÷ýö÷ööû÷ö÷ö÷÷ûö÷÷ö÷÷ö÷þö÷÷ö÷òö÷ö÷ö÷ö÷öö÷öö÷÷ùö÷ö÷öö÷÷ûö÷÷ö÷÷þö÷÷öù÷ö÷öö÷ööü÷ö÷ööü÷öö÷÷þö÷÷þö÷÷þö÷÷öþ÷ööþ÷ööþ÷ööû÷ö÷÷öö÷úö÷÷öö÷÷ö÷öþ÷ööþ÷öö÷ö÷ö÷öý÷ö÷÷öþ÷öö÷öû÷öö÷öö÷ö÷öþ÷öö÷öþ÷ööþ÷ööú÷ö÷ö÷öö÷ö÷÷ö÷÷öö÷ö÷÷øö÷÷ö÷÷ö÷÷ öý÷ö÷÷öú÷öö÷÷ööú÷ö÷÷ö÷÷þö÷÷þö÷÷þö÷÷öþõööþ÷ööí÷ö÷öö÷öö÷ö÷÷ö÷ö÷÷ö÷÷öý÷ö÷÷ öþ÷ööþ÷ö öþ÷ööû÷ö÷ö÷÷ö÷ö÷þö÷÷öþõööþ÷öö÷öó÷ö÷ö÷÷ö÷ö÷÷ö÷ ÷ö÷öþ÷ööø÷ö÷ö÷öö÷÷öü÷öö÷÷þö÷÷øö÷÷ö÷÷ö÷÷þõööü÷ö÷ööü÷ö÷öö÷þö÷ ÷ö÷üö÷÷ööþõööþ÷ööù÷öö÷öö÷÷ö÷ö÷ö÷þö÷÷öþõööþ÷ööþ÷ööþ÷ööø÷öö÷ö÷ö÷÷ö÷ö÷ÿЋЋŒþ‹ŒŒýŒŽýŽþŽõ‘‘‘‘û’‘’‘ŠŠ‹Š‹Œþ‹ŒŒþŒýŽŽŽþŽüý‘‘‘’þ‰ŠŠú‹Š‹‹Š‹‹þŒ‹‹ŒþŒŒŽüŽŽû‘þ‘‘Šþ‰ŠŠþ‹ŠŠ‹ýŒ‹ŒŒþŒŒŽüŽŽ‘‰Šþ‰ŠŠü‹ŠŠ‹‹üŒ‹‹ŒŒýŒýŽŽŽýŽýý‘‘‘ü‰‰ŠŠþ‰ŠŠý‹Š‹‹ŒýŽŽŽþŽøŽ‘‰üЉ‰ŠŠþ‰ŠŠ‹úŒ‹‹Œ‹ŒŒþŒøŒŽŽŽŽŽþŽŽ‘ü‘ˆ‰‰üЉ‰ŠŠõ‹Š‹‹ŠŠ‹‹Œ‹ŒŒþ‹ŒŒýŒûŽŽŽŽ ‰Š‰Šý‹Š‹‹þŠ‹‹ ŒúŒŽŽŽùŽü‘ˆˆ‰‰Š‹þŒ‹‹ŒþŒŽûŽŽýý‰ˆ‰‰ýЉŠŠø‹ŠŠ‹‹Œ‹Œ ŒúŒŽŽüŽŽüýˆ‰ˆˆ‰úŠ‰ŠŠ‰ŠŠ‹þŠ‹‹þŒ‹‹ŒüŒŒþŽŽüŽŽõˆˆ‰‰ˆˆ‰ ‰÷Š‹Š‹ŠŠ‹Š‹‹ŒüŒŒŽíŽŽŽŽŽŽŽ‡ˆˆû‰ˆ‰ˆ‰‰ýЉŠŠù‰ŠŠ‹‹Š‹‹Œ‹ŒþŒüŽŽŽýŽˆ‡ˆý‰ˆ‰‰Šþ‰ŠŠþ‹ŠŠ‹ŒŒ ŽŽ‡úˆ‡ˆ‡ˆ‰‰þˆ‰‰Š‹Š‹úŒ‹Œ‹‹ŒŒùŒŒŒŒŽþŽŽ‡ˆ‰þˆ‰‰Šþ‰ŠŠý‹Š‹‹þŒ‹‹ŒýŽŽŽûއ‡ýˆ‡ˆˆü‰ˆˆ‰‰Š‹ýŒ‹ŒŒŽ‡ˆü‰ˆˆ‰‰üЉ‰ŠŠ‹þŠ‹‹úŒ‹‹Œ‹ŒŒŽþŽŽ‡þ†‡‡ˆ‰Šþ‰ŠŠ‹Š‹Œü‹Œ‹ŒŒüŽŽŽ‡†‡ýˆ‡ˆˆ‰üˆ‰ˆ‰‰øŠ‰Š‰ŠŠ‹ŠŠ‹ŒþŒŒþŒýŽŽŽ†‡þˆ‡‡ˆý‰ˆ‰‰Š‰Šü‹ŠŠ‹‹ŒüŒŒŽ†‡†‡ˆ‡úˆ‡ˆ‰ˆ‰‰þˆ‰‰ Šý‹Š‹‹ýŒ‹ŒŒþŒŽö…††‡††‡††‡‡ˆþ‡ˆˆý‰ˆ‰‰ýЉŠŠþ‹ŠŠ‹Œþ‹ŒŒþŒþ…†† ‡øˆ‡ˆˆ‰ˆ‰ˆˆ‰Š‰Š‹ýŒ‹ŒŒýŒýކ†þ‡††‡ˆþ‡ˆˆ‰þˆ‰‰üЉ‰ŠŠ‹ýŒ‹ŒŒþŽ……†ý‡†‡‡þ†‡‡ýˆ‡ˆˆû‰ˆ‰ˆ‰‰ùЉ‰ŠŠ‰ŠŠû‹Š‹Œ‹‹ûŒ‹Œ‹ŒŒýŒ…†û‡†‡†‡‡þˆ‡‡ˆ‰üЉ‰ŠŠ‹Œ‹ŒúŒŒ……ü†……††‡†‡öˆ‡ˆ‡ˆˆ‰‰ˆ‰‰Šû‰ŠŠ‹ŠŠ‹üŒ‹‹ŒŒöŒ…„……†……††‡þ†‡‡ˆý‰ˆ‰‰õˆ‰‰Š‰Š‰‰Š‰ŠŠý‹Š‹‹Œ‹Œ…þ„……†‡üˆ‡‡ˆˆ‰ýЉŠŠ‹þŒ‹‹Œþ„…… †‡ýˆ‡ˆˆý‰ˆ‰‰óЉ‰Š‰ŠŠ‹Š‹ŠŠ‹‹Œø„…„„……„……†‡þ†‡‡ˆ‰þЉ‰Šú‹Š‹‹Š‹‹Œþ‹ŒŒ„…ø„†…†…†…††ý‡†‡‡ˆõ‰ˆˆ‰‰Š‰‰Š‰ŠŠú‹ŠŠ‹Š‹‹Œ„…†þ…††ý‡†‡‡üˆ‡‡ˆˆ‰ˆ‰Šû‰ŠŠ‰ŠŠ‹Œü‹Œƒ„„ü…„„……†‡þ†‡‡ˆ‡ˆû‰ˆ‰ˆ‰‰ýЉŠŠ‹„þƒ„„… †‡ˆý‰ˆ‰‰Šù‰ŠŠ‹ŠŠ‹‹„üƒ„ƒ„„…ù„……††…††‡üˆ‡‡ˆˆ‰þˆ‰‰Šþ‰ŠŠü‹ŠŠ‹‹þƒ„„þƒ„„û…„…„……ü†……††‡ýˆ‡ˆˆ‰üˆ‰ˆ‰‰õŠ‰ŠŠ‹ŠŠ‹Š‹ƒƒý„ƒ„„ø…„……„…„……†û‡†‡†‡‡ˆü‰ˆˆ‰‰ýЉŠŠ‹ƒû„ƒ„ƒ„„þ…„„…þ†……† ‡öˆ‡ˆˆ‰‰ˆ‰ˆ‰‰ýЉŠŠþ‚ƒƒ„ƒ„ý…„……†þ…††û‡†‡†‡‡ýˆ‡ˆˆ‰ýЉŠŠ‚ƒý„ƒ„„ý…„……†ü‡††‡‡ˆþ‡ˆˆý‰ˆ‰‰Š‚ƒ„þƒ„„þ…„„…ú†……†…††‡þ†‡‡ˆþ‡ˆˆ‰þˆ‰‰Šî‰Š‰Š‰‚‚ƒ‚ƒƒ‚‚ƒ„„ƒ„„÷ƒ„„…„„…„……ü†……††‡üˆ‡‡ˆˆý‰ˆ‰‰úЉ‰Š‚‚ýƒ‚ƒƒ„ý…„……†û‡†‡†‡‡ýˆ‡ˆˆ‰þЉ‰‚ ƒ„ý…„……ü†……††þ‡††‡ˆ‰þˆ‰‰þ‚‚ƒ„…÷„……†…†……††‡þ†‡‡ýˆ‡ˆˆþ‡ˆˆ‰üˆ‰‰‚þ‚‚ƒþ‚ƒƒ„ý…„……ý†…††ù‡††‡‡†‡‡þˆ‡‡ˆý‰ˆ‰‰‚þ‚‚ƒ„ƒ„…†…†ý‡†‡‡ûˆ‡ˆ‡ˆˆý‰ˆ‰‰ý‚‚‚ƒ„õƒ„ƒ„„…„……„……†ù…††…†‡††‡ˆþ‰‚ýƒ‚ƒƒ„ö…„…††…†……††ý‡†‡‡üˆ‡‡ˆˆû€€‚ ƒ„… †‡ˆ‡ýˆ‡ˆˆþ€‚þƒ‚‚ƒ„…þ„……†ú‡†‡‡†‡‡ˆþ‡ˆˆ€ü‚‚‚þƒ‚‚ƒý„ƒ„„…ý†…††ù‡†‡†‡†‡‡ˆû‡ˆ€ý‚‚‚ƒþ„ƒƒ„…ù„……†……††ù‡†‡†‡†‡‡ˆþ‡€€‚þ‚‚ƒü‚ƒƒ„„…†…†þ‡††ý‡†‡‡þˆ€€ý€ý‚‚‚üƒ‚‚ƒƒ„õƒ„…„„…„„……† †‡ûˆ€€€ ‚ƒ„þƒ„„…ý†…††þ‡††‡ý€þ€€ù€‚‚‚þƒ‚‚ƒþ‚ƒƒü„ƒƒ„„…ý†…††õ‡†‡††‡‡€€€ü€€ý‚‚‚úƒ‚ƒ‚‚ƒƒ„…þ„……†‡ü€€€ý€ü‚‚‚ƒü„ƒƒ„„ý…„……þ„……ü†……††ü‡††ý€€€õ‚‚‚‚ƒ‚ƒ‚ƒƒý„ƒ„„ý…„……†û€€€€‚þ‚‚ƒþ‚ƒƒü„ƒƒ„„…û„…†…††þ…††‘ ’“ý”“””ü•””••ú–•–••––ýû‘‘‘‘’“”þ“””•–•–ý—ý‘þ‘‘ü’‘‘’’“’“ý”“””ü•””••–þ‘þ‘‘ ’“”þ“””ý•”••ø–•––•––ü‘þ‘‘þ’‘‘’ö‘’“’“’““’““”ý•”••–ýý‘‘‘’þ‘’’ý“’““þ’““þ”““”ô•”••”••–•–•––ýŽýþ‘ ‘’“”þ“””ý•”••–ò‘‘‘‘’’‘‘’‘’’þ“’’“ö’““”“”“”“””•þŽþŽ ‘’þ‘’’“”“ý”“””•ú–ŽŽŽþú‘‘‘‘’þ‘’’“”•ŽýŽþ‘þ‘‘ú’‘‘’‘’’“ú’“’“’““û”“”“””ï•”••”••ŽŽŽŽŽŽþýý‘‘‘þ‘‘ý’‘’’“û’““’““ ”û•ŽŽŽþŽþü‘‘‘þ’‘‘’ù“’’““’““þ”““”ö•””•ŽŽŽŽüŽŽþý‘‘‘’þ‘’’“þ’““ô”““””“””•”• Ž ‘’þ‘’’“ú”“””“””ŽŽþŽþýü‘‘‘ú’‘’’‘’’“þ’““û”“”“””þŒýŽŽŽþŽûú‘‘‘‘‘ý’‘’’“þ’““”ýŒýŽŽŽýŽ ‘ý’‘’’ý“’““ü”“”““ü”ŒŒŽþû‘‘‘‘ý’‘’’“ø’“””““”ŒŒýŽŽŽþŽþþ‘‘’‘’“ù’“”““”ŒŒùŽŽŽŽõŽŽ‘ý’‘’’“ý”“ŒŒüŒŒýŽŽŽüŽŽú‘‘‘‘‘ý’‘’’ý“’““ýŒ‹ŒŒýŒýŽŽŽüŽŽ ü‘‘‘’õ‘’‘’’“’’“’““ýŒ‹ŒŒþŒ ŽüŽŽúú‘‘‘‘’“‹ŒýŒŽþŽþ‘‘’ý“’‹‹ŒþŒ ŽýŽú‘þ‘‘’‹ŒüŒŒŽüŽŽø‘‘‘‘û’‘’‘’’‹úŒ‹‹Œ‹ŒŒ ŽþŽŽüŽŽþý‘ü’‘‘’’þŠ‹‹Œ‹ŒþŽŽþŽþ‘ý’‘’’Šý‹Š‹‹ ŒŽýŽŽŽûú‘‘‘‘’þŠ‹‹Œþ‹ŒŒüŽŽŽŽ‘û’‘’Š‹‹ûŒ‹Œ‹ŒŒûŒŒþŽŽüŽŽþý‘‘‘ú’‘ŠŠ‹ŠŠ‹Œ‹ŒþŒŒøŽŽŽŽŽùŽü‘‘‘Šü‹ŠŠ‹‹ŒýŽŽŽüŽŽ ‘Šú‹Š‹‹Š‹‹üŒ‹‹ŒŒüŒŒŽþŽŽþŽ‘ýЉŠŠ‹þŠ‹‹ŒþŒŽþŽó‘‘‘ŠŠ‰‰ŠŠü‹ŠŠ‹‹ûŒ‹Œ‹ŒŒúŒŒŒûŽŽŽŽ ý‘‰ŠŠ‰÷ЉЋ‹Š‹Š‹‹Œû‹ŒŒŒŒüŽŽŽ ù‘‘‰‰Š‹þŠ‹‹úŒ‹‹Œ‹ŒŒþŒŒýŽŽŽýŽü‰òŠ‰Š‰Š‰ŠŠ‹ŠŠ‹Š‹‹øŒ‹ŒŒ‹ŒŒþŒøŽŽŽŽŽŽþŽŽûˆ‰ˆ‰ŠŠ‰Š‹ ŒþŒŒŽþŽŽþŽý‰ˆ‰‰þЉ‰Šú‹Š‹‹Š‹‹ŒùŒŒŒŒŽøŽŽŽû‰ˆˆ‰‰ùЉЉЉŠŠü‹ŠŠ‹‹üŒ‹‹ŒŒúŒŒŒŽüŽŽŽðŽŽˆˆ‰‰ˆ‰‰øŠ‰Š‰ŠŠ‰ŠŠ‹ýŒ‹ŒŒùŒŒŒŽüŽŽŽýŽýˆˆ‰ˆ‰Šþ‰ŠŠý‹Š‹‹þŒ‹‹ŒýŽŽŽþŽˆþ‰ˆˆý‰ˆ‰‰Šü‰Š‰ŠŠú‹Š‹ŠŠ‹‹ýŒ‹ŒŒþŽŽþŽŽþ‡ˆˆ‰Š‹ýŒ‹ŒŒþŒŽüŽŽû‡ˆ‡‡ˆˆþ‰ˆˆö‰ˆ‰‰Š‰‰Š‰ŠŠý‹Š‹‹Œþ‹ŒŒþŒŒûŽŽŽŽú‡ˆ‡‡ˆˆ‰ˆ‰ûЉЉŠŠü‹ŠŠ‹‹ŒüŒŒŽþŽŽ‡ˆú‰ˆ‰‰ˆ‰‰üЉ‰ŠŠ ‹ŒþŒýŽŽŽ‡ýˆ‡ˆˆ‰þˆ‰‰úŠ‰ŠŠ‰ŠŠ‹úЋЋ‹ŒŒü‹Œ‹ŒŒŽþŽŽ‡ýˆ‡ˆˆý‰ˆ‰‰ýЉŠŠ‹Š‹Œþ‹ŒŒûŒŒýŽŽŽ‡ˆû‰ˆ‰ˆ‰‰óŠ‰ŠŠ‰Š‹ŠŠ‹ŠŠ‹‹Œþ‹ŒŒûŒŒŽü†‡†‡‡ˆý‰ˆ‰‰Šþ‰ŠŠ‹þŒ‹‹Œ÷‹ŒŒŒŒŒŽü††‡‡ˆû‰ˆ‰ˆ‰‰Šþ‰ŠŠü‹ŠŠ‹‹øŒ‹ŒŒ‹ŒŒŒ†‡þˆ‡‡ˆ‰þˆ‰ ‰Š‹Œþ‹ŒŒþŒŒþŒþކ†‡ûˆ‡ˆ‡ˆˆ‰Šþ‰ŠŠ‹þŠ‹‹ýŒ‹ŒŒ†þ‡††‡þˆ‡‡ˆ‰þˆ‰‰Šþ‰ŠŠ‹Š‹ûŒ‹Œ‹ŒŒþ…††ù‡†‡†‡†‡‡ˆ‡ˆù‰ˆˆ‰ˆˆ‰‰Šý‹Š‹‹þŠ‹‹ Œý…††û‡†‡†‡‡ýˆ‡ˆˆþ‰ˆˆ‰üЉ‰ŠŠø‹ŠŠ‹‹ŠŠ‹‹Œ‹öŒ‹ŒŒŒ†……†þ‡††‡ˆþ‡ˆˆ‰Šû‰Š‰‰ŠŠ‹þŠ‹‹úŒ‹ŒŒ‹ŒŒýŒ……†þ…††‡þ†‡‡ˆ‰ˆý‰ˆ‰‰üЉ‰ŠŠ‹ýŒ‹ŒŒ…ý†…††‡üˆ‡ˆ‡‡ˆ‰þЉ‰Š‹þŠ‹‹þŒ‹‹Œ…ü†……††þ…††‡úˆ‡‡ˆ‡ˆˆõ‰ˆ‰ˆ‰ˆ‰Š‰‰ŠŠý‹Š‹‹ýŒ‹ŒŒùöøùùøùùøùøùùúøùøùøùùþøùùüúùúùùüúùùúúýùúøøøùøøùøùøùùþøùùþøùùþøùùûúùùúùùüúùúùùúùôúùúøøùùøøùøùùþøùùþøùùøùþúùùøþùøøùýøùøøùþøùùþøùùþøùùþúùùþúùùú÷ùúùùúøùøùùíøùøøùøùøùøùøùøùøùøùùþøù ùûúùúúùùüúùúùùûúùøùøøùüøùùøøþùøøùø÷ùøùøùùøøù ùþúùùöúùùúùùúúùúúùýøùøøùùøøùùøùùø ùþøùùúùøüùøøùùøùþøùùøøùøøùùøùùþúùùúùøùþøùùúøùùøøùùþøù ùþúùùúúùúùùøø÷ùøøùøùøùøøùüøùøùùøùþøùùþøùùþúùùþúùùúúùùúùøøùúøùøøùøøüùøøùùþøùùüøùøùùþúùùþúùùþúøøùøþùøøþùøøúùøøùùøøùüøùøùùþøùùþúøøùøüùøùøøùøùøùøùþøùùüúùùøøðùøøùøøùøùøøùøùøùùøüùøùøøùõøùùøùùøùùøù ùúùþúøøüùøùøøóùøùùøùøùøùùøùùûøùøøùùøùþøùùùúùúùùúùùøùøùùøùøùùøøùùøùøùøùùûøùùøù ùþøùùþúùùøþùø øùøýùøùù÷øùùøøùøøùùûúøøùøøùùøùøùùøøùøûùøùøùùþøùùùøùùøùøùùþøùù øùùøøùøùøøòùøøùøùùøùøøùøùùþøùùþøùùþøùùøþùø øþùøøùøûùøùøùùøùþøùùûøùùøùùøùûøùøøùùøùöøùøùùøùùøùùøù øùøùýøùøøüùøùøøùþøùùþøùùþøùùþøù ùøûùøøùøøúùøøùùøøùøùøùþøùùøþùø øùüøùùøøûùøùùøøùøù øüùøùøøþùøøþùøøùøþùøøýùøùùøùþøùù÷ø÷÷øø÷ø÷øøóùøøùùøøùùøøùøøùøùøýùøù ùþ÷øøüùøùøøûùøøùøøöùøøùøùøùùøøùøùùøøùùøùùøþ÷øøþùøøþùøøýùøùùþøùùüøùù÷÷ø÷øûùøøùøøòùøùøøùøøùùøùùøøùüøùøùùþ÷øøþùøøùøþùøøþùøøüùøøùùøþùøøþ÷øøù øëùøøùøøùùøùùøøùøùøùùøùùøù÷ø÷øø÷øø÷øøþ÷øøðùøøùùøùøùøøùøùøùùþøùùþøùùûø÷ø÷øøþ÷øøþ÷øøþùøøþùøøýùøùùøùøùøùþøùùø÷ø÷øþùøøúùøøùùøøùøïùøøùøø÷øø÷øø÷øø÷øøþùø øùøùþøùùøýùø÷÷ ø÷üø÷÷ø øüùøùøøûùøùùøøùøùø÷øû÷ø÷÷øøþ÷ø øùøûùøøùøøýùøùùþøùùûøùùøùù÷ûø÷ø÷øøü÷ø÷øøþ÷ø øüùøùøøùøþùøøïùøùøùùøùøùù÷÷øø÷øø÷ýø÷ø"ø÷ùøùøùøùùøøýù÷øø÷øþ÷øøþ÷øøþ÷ø øüùøøùùøùøùùø÷ø÷ø÷øøù÷ø÷÷ø÷øøþ÷øøþùøøôùøùùøùùøùøø÷÷ø÷ø÷øþ÷øøþ÷øøþùøøþùøøùøùöøùøùù÷÷ø÷øø÷þø÷÷ø÷ýø÷øøûùøùùøøùùøùøøùøøøùøùøø÷÷øøô÷øø÷ø÷÷øø÷÷øøþ÷øøþùøøùøùùøùùøøùùøú÷ø÷÷ø÷÷ø÷øþ÷øøû÷øø÷øøþ÷øøþùøøûùøøùøø÷ø÷ø÷þø÷÷øþ÷øøþ÷øøþùøøþ÷øøú÷øø÷ø÷÷ø÷ûø÷ø÷øøþ÷ø øùøþùøøþùøøûùøùø÷÷ýø÷øø÷øþ÷øø÷ø÷÷øø÷øø÷÷øøü÷ø÷øøùø÷ø÷úø÷ø÷ø÷÷øû÷øø÷øø÷øþ÷øøþùøøþùøø÷ø÷ûø÷÷ø÷÷ø÷þø÷÷øû÷øø÷øøþ÷ø øúùøøùùøøù÷þø÷÷ôø÷÷øø÷ø÷ø÷÷øøø÷øø÷øø÷øøþ÷øøþ÷øøþ÷øøþùøøþùøø÷øî÷ø÷÷øø÷÷ø÷÷ø÷÷øø÷øøþ÷øøþ÷øøþ÷øøþùø ø ÷óø÷ø÷ø÷ø÷÷ø÷÷øøü÷ø÷øøûùøøù÷÷þø÷÷øø÷÷ø÷÷ø÷÷ø÷øù÷ø÷ø÷ø÷÷ø÷ø÷øþùøøý÷ø÷÷øý÷ø÷÷ùø÷÷øø÷øø÷øù÷ø÷ø÷÷øø÷øü÷ø÷øøù ÷øý÷ø÷÷ø÷úø÷ø÷÷øøþ÷ø øþ÷øøþ÷ø ø÷ø÷øû÷ø÷ø÷÷þø÷÷ø÷øû÷øø÷øø÷ûø÷÷ø÷÷ýø÷øø÷ø÷øø÷øø÷øø÷ø øþù÷÷íø÷ø÷÷ø÷÷ø÷÷øø÷ø÷÷ø÷÷øþ÷øøü÷øø÷÷øþ÷øøþ÷øø÷ûø÷÷ø÷÷ø÷þø÷÷øü÷ø÷øøü÷ø÷øø÷ø÷ø÷öø÷ø÷øø÷÷ø÷÷øþ÷øøü÷ø÷ø ø ÷ûø÷÷ø÷÷ûø÷øø÷÷öø÷øø÷ø÷÷ø÷÷ øþ÷øø÷þö÷÷þø÷÷åø÷ø÷÷øø÷÷ø÷÷ø÷ø÷÷ø÷ø÷ø÷øø÷øø÷ øþö÷÷ø÷øû÷ø÷ø÷÷ýø÷øøý÷ø÷÷øü÷ø÷øøþ÷øøÿ’“þ’““ ”• –—ù˜——˜˜—˜˜™þ˜™™’“þ’““þ”““”ú•””•”••–þ—––—ù˜—˜˜——˜˜ý™˜™™ü‘’‘’’ü“’’““”þ“””•–—þ–——ý˜—˜˜ý™˜™™ù‘’‘’‘‘’’“”•þ”••ý–•–– —˜™ü˜™™‘‘’“ý”“””•þ–••–ü—––——ý˜—˜˜þ™˜˜‘’‘’“ü’“’““ú”“””“””•–þ•––þ—––—ü˜——˜˜ô™˜‘‘’‘’‘’‘’’“þ’““”ý•”••ù–•–•––——˜—˜ü™‘‘ý’‘’’ “”•þ–••–—˜—ý˜—˜˜‘ü‘‘‘’“þ’““”þ“”” •–þ•––—þ˜——ú˜—˜‘‘’“”þ“””ú•”•””••ù–•–•–•––ù—––——˜——˜û‘‘‘‘’ú‘’’“’“ “”ý•”••û–•–•–– —þ˜ý‘‘‘’þ“’’“”•ë–••–•––—––—––——˜—˜˜‘’“’ú“’““”““”ý•”••–ü—––——ü˜þ‘‘ù’‘’‘’‘’’“þ’““”þ“””•”•–þ•––—ù˜þ‘‘’‘’“”ü“”“””•þ”••û–•–•––—û‘ü‘‘‘ý’‘’’“”“”•ø–•–•––—––ú— ‘’÷“’“’““”“””•”ø–•–••–•––—þŽüý‘‘‘’þ‘’’û“’“’““”ý•”••–ø—Žý‘‘‘’þ‘’’ý“’““û”“”“””ü•””••ý–•––Žú‘‘‘ý’‘’’“”þ“””•ü–••––ýŽŽŽ‘’ù“’“’“’““”ü“”“””•–ŽüŽŽý‘‘ ‘’“ ”•ü–•–ŽŽþŽ‘þ‘‘’þ“’’“ý”“””ý•”••þ–ŽŽýŽþý‘‘‘’û‘’’‘’’“ø”“””•””••ýŽŽŽúŽü‘‘‘’þ‘’’“þ’““”þ“””ý•”••ŽüŽŽŽýŽú ‘ý’‘’’ü“’’““ý”“””•þŽŽüŽŽý‘þ’‘‘’“”þ“””•üŽŽŽýŽúŽ‘‘’“’“ý”“””ü•””ŽþŽŽýŽý‘þ‘‘ý’‘’’ “”•ŒüŽŽŽþý‘‘‘ü’‘‘’’“þ’““ý”“””ŒõŒŽŽŽŽŽŽ ‘þ‘‘’‘’ “”üŒŒŽþŽŽüŽŽü‘‘‘ý’‘’’þ‘’’“þ’““”ŒþŒüŽŽŽþŽýú‘‘‘‘þ’‘‘’ý“’““”ŒûŒŒúŽŽŽŽýŽü‘‘‘û’‘’‘’’“‹ŒýŽŽŽþŽŽúŽü‘‘‘’ý“’““û”‹Œ‹ŒŒŽŽýŽ‘õ’‘’’““’““’““‹ýŒ‹ŒŒŽþŽ ‘’“‹Œþ‹ŒŒýŒŽþŽý‘þ‘‘’“‹úŒ‹ŒŒ‹ŒŒþŒŒŽþŽŽûŽŽû‘þ‘‘ü’‘‘’’ú“’“ŠŠ‹‹ûŒ‹Œ‹ŒŒŽùŽŽŽŽú‘‘‘‘’ü“‹Š‹‹Œ ŽüŽŽþ‘‘û‘’‘’’“Š‹þŠ‹‹Œ ŽýŽþý‘‘‘ù’‘’‘‘’‹‹þŠ‹‹Œþ‹ŒŒüŽŽŽýŽ‘’‘þ’ŠŠ‹ýŒ‹ŒŒ ŽýŽýþû‘‘’‘‘þ’ŠŠý‹Š‹‹ýŒ‹ŒŒŒýŒŽýŽ ‘ýЉŠŠ‹Œþ‹ŒŒùŒŒŒŽþŽüú‘‘‘‘ú’‘’ЉŠŠý‹Š‹‹ýŒ‹ŒŒŽýŽþ‘þ‘‘‰ýЉŠŠ‹üЋЋ‹ýŒ‹ŒŒýŒúŽŽŽŽýŽŽù‘þ‘‘‰üЉ‰ŠŠ‹øŒ‹ŒŒ‹ŒŒþŒýŽŽŽþŽŽù‘‘þ‘‰‰Šý‹Š‹‹Œ÷‹ŒŒŒŒýŽŽŽ‘‰üЉ‰ŠŠô‹ŠŠ‹ŠŠ‹‹Œ‹‹ŒŒýŒŽþŽŽŽþ‰úЉ‰Š‰ŠŠ‹þŠ‹‹ýŒ‹ŒŒýŒŽþŽŽúŽŽŽþ‰þˆ‰‰Š‹Œþ‹ŒŒŒûŽŽŽŽúŽŽŽü‰ˆˆ‰‰ýЉŠŠþ‰ŠŠ‹Œø‹ŒŒŒŒŽþŽùˆ‰ˆ‰ˆˆ‰‰þЉ‰Šú‹Š‹‹Š‹‹ŒýŒŽüŽŽôˆ‡ˆ‰ˆ‰ˆ‰‰ýЉŠŠ‹þŠ‹‹ŒúŽŽŽŽùŽŽŽû‡ˆˆþ‰ˆˆ‰ýЉŠŠ‹þŠ‹‹Œ‹ŒþŒûŽŽŽˆþ‡ˆˆ‰Šü‹ŠŠ‹ ‹ŒþŒŽ÷އˆˆ‡‡ˆˆ‰þˆ‰‰ýЉŠŠý‹Š‹‹ŒúŒŒŒþŽŽþއˆ‰ Š‹þŠ‹‹ýŒ‹ŒŒóŒŽŽŽŽŽŽüŽŽ‡‡ˆü‡ˆ‡ˆˆú‰ˆ‰‰ˆ‰‰ýЉŠŠü‹ŠŠ‹‹ŒþŒŒûŽŽŽŽ‡ýˆ‡ˆˆ‰þˆ‰‰Šø‰Š‰ŠŠ‹Š‹‹ ŒüŒŒŽŽ‡þ†‡‡ýˆ‡ˆˆú‰ˆ‰‰ˆ‰‰Š‰Šü‹ŠŠ‹‹øŒ‹Œ‹ŒŒ‹ŒŒýŒŽ†‡ýˆ‡ˆˆü‰ˆˆ‰‰Š ‹ýŒ‹ŒŒýŒþŽŽø–—–˜˜——˜˜þ™˜˜™þš™™ýš™ššû›š›š››œúœœœžþžž—˜þ—˜˜ý™˜™™üš™™šš›þš››ýœ›œœýœþžžû—–—–——þ˜——˜ý™˜™™úš™šš™šš›š›œ›œüœœúžž—––—˜ý™˜™™šþ™ššú›šš›š››þœ›› œýž––—þ–——ü˜——˜˜þ™˜˜™ šû›š›š››œýœþž––ý—–——ý˜—˜˜ý™˜™™þ˜™™ûš™š™šš›ûœ›œ›œœþž––õ—–——–——˜˜—˜˜ý™˜™™÷˜™™š™™š™ššý›š››ùœ›œ›œ›œœþœ–þ•––ü—––——˜™š›šý›š››üœ››œœúœ•–••–û—–—–——ý˜—˜˜™š™šû›š›š››œþœœù•–•–••––—ö–——˜˜——˜—˜˜ý™˜™™šú™šš›š››üœ››œœõœ–•––•–••––—˜™þ˜™™ š›þš››œ•–—ý˜—˜˜û—™˜™˜˜û™˜™™š š›œþ••–ú—–——–——þ˜——˜™šþ›šš›œû›œ””••–û—–—–——˜ý™˜™™šþ™šš›š›œù”•”•””••–ü—––——ý˜—˜˜™÷š™š™™šš›šš›ûœ››œ””•ý–•––—–—˜þ—˜˜™û˜™™˜™™úš™šš™ššü›šš››þš››öœ””•””••”••ü–••––þ—––—˜þ—˜˜™ýš™ššþ™šš›÷š›š›š››œ””ý•”••÷”•–••–••––—ü˜——˜˜™šþ™šš›ü“”“””ý•”••ý–•––ü—––——˜þ™˜˜™šþ›šš”ö“””••”•””••þ–••–ü—––——þ˜——˜™˜™üš™™ššì›š”““””“””•””••”••–••–—þ–——ý˜—˜˜™ö˜™š™™š™š™šš›“”•”•–—ü–—–——û˜—˜—˜˜ý™˜™™þ˜™™ýš™ššû›šš›““ý”“””û•”•”••–þ•––û—–—–——˜þ—˜˜þ™˜˜ý™˜™™š™šü™šš““” •–—þ–——˜™ýš™šš“ü”““””ö•”••–•–••––ý—–——˜—ý˜—˜˜ú™˜˜™˜™™ýš™ššû™“’’““ý”“””þ•””•–þ•––—ú˜——˜—˜˜ú™˜™™˜™™öš™š™š’’“’““ú”“”““”” •– —˜™š’“÷’““”“””“””•”•ù–•––••––þ—––—ý˜—˜˜™’“ü”““””•þ–••–ú—––—–——ý˜—˜˜þ™˜˜™þ˜™™þ‘’’ë“’’““”“”“””“””•””••”••–þ•––û—–—–——˜™ú˜™™š‘’’“û”“”“””ý•”••–û—–—–——˜þ—˜˜û™’’‘’’þ“’’“ý”“””•”•–þ•––—þ–——˜þ—˜˜™ ’“ý”“” ”•–þ•––—þ–——˜þ—˜˜ú™‘‘’‘’’û“’“’““”•”ý•”••ý–•––þ—––—˜ö™˜‘‘’’‘‘’’“þ’““”þ“””ú•”•””••–•–û—–—–——˜þ™‘‘’‘ü’‘‘’’“þ’““þ”““ù”“””••””•–þ•––ü•–—––—ù˜—˜—˜—˜˜ô‘‘‘’’‘’‘‘’’õ“’“’““’““”““”•þ”• •–ú—––—–——÷˜——˜˜‘‘‘ú’‘’‘‘’’ý“’““ý”“””ý•”••–þ•––ý—–——˜÷‘‘‘‘’‘‘ý’‘’’“û’““’““ý”“””ü•””••û–•–•––ý—–——˜ü‘‘‘’þ‘’’“”þ“””•þ”••–þ•––þ—––ý—–——ú‘‘‘‘ú’‘’’‘’’“ý”“””þ“””•û–•–•––ü—–—––—ý‘‘‘þ’‘‘ý’‘’’“û”“”“””•ý–•––—þ‘ ’“þ”““ý”“””•þ”••þ–••–ù—–ý‘‘‘ú’‘’’‘’’ú“’’“’““”þ“””•–þ•––—‘þ‘‘ú’‘’’‘’’“þ’““”ü•””••û–•–•––ø—þ‘‘’ý“’““õ”“””“””•””••–ù•–•––—û‘‘‘‘ü’‘‘’’“”•þ”••–ý—Žú‘‘‘‘ý’‘’’“þ”““ý”“””•”•–ýŽ‘’ü‘’‘’’“û’”““””ü“”•””•þ”••–Žý ‘’ý“’““þ”““”ý•”••–ù•ŽŽŽŽþü‘‘‘ý’‘’’ý“’““ü”““””•þ–ŽŽþ‘û’‘’‘’’ü“’’““”ü•””••ŽüŽŽúý‘‘‘÷’‘’’‘’’“’’“”þ•””•ŽþŽŽüü‘‘‘’ü‘’‘’’þ“’’“”“”þ•””•ŽþŽŽ ‘’û‘’’‘’’“þ’““”•ŽýŽüý‘‘‘ý’‘’’ô“’“’“’““”“”““”þ•””ŽüŽŽŽúŽú‘‘‘‘ý’‘’’“”þ“””•ýŽŽúŽŽŽþ‘þ‘‘’þ‘’’ü“’’““û”“”“””úŽŽŽŽüŽŽúý‘‘‘’‘’“’“ý”“””þŒŽþŽŽþŽŽý‘‘‘þ’‘‘’“”ý“”úŽŽŽŽŽ  ‘’“þ’““”ý“”ŒŒýŽŽŽûŽŽ‘þ‘‘ù’‘‘’’‘’’“ù”““ŒŒŽüŽŽø‘ý‘‘‘’þ‘’’“ü”ŒŒŒŽþŽŽþŽýü‘‘‘ú’‘’’‘’’“þ’““þ”“úù úüùúùú úþûúúûýúûúúûúûüúùúùùúûùúúùúúþùú ú÷ûúúûûúúûúúûúûûúûúûúúû÷úûùùúùùúùùûúùúùúúùúþùúúþûúúøûúúûúûûúúýûúûûúþùúúøùúùùúúùúúóûúúûúûûúûúûûúúûúúûúùúùùúù úþùúúþùú úüûúûúúþûúúûúúûúúûúúùþúùùûúùúùúúûùúùùúúþûúúþûúúûúûúþûúúþùúúùùúúùúùúúùúûùúùùúúûúûþúûûóúùùúúùúùùúúùúúþùúúþûúúûýúûúúþùúúþùúúûùúúùúúþùúúþùú úþûúúþûúúþûúúùðúùúúùùúùúùúùùúùú úþùú úû úþûúúùöúùùúúùúùùúúýùúùùúþùúúþùúúûýúûúúýûúùùþúùùúþùúúþùúúúùúùúùúúûûúûûúúûüúûûúúùúùþúùùúùúüùúúùùúþùú úþûúúüûúúùùõúùùúùùúùùúùùùúùùúúùúúþùúúþùú úþûúúûñúûúúûúúùúùùúùúùùüúùúùùúùýúùúúþùúúúûúúùúùùúù÷úùùúùúúùúú÷ùúùúùúùùúúüùúùúúùúþûú úùøúùùúùùúùùúùúùúþùúúüùúùúúýûúùùøúùùúùùúùùúùüúùùúúùúúùúúùùúúüùúùúúýûúùùúùõúùùúùùúùùúùùúùýúùúúþùúúùûúûúûúùùþúùùþúùùüúùùúúþùúúþùúúþùúúøûùùúùùúùù÷úùúùúùùúùùúùúþùúúúùúúùùúúþùúúùüúùúùùúýùúùùúùúüùúùúúþùúúùùúùúúùúúþùúúùùúùùúùúùùùúùúúùùúúûùúúùúúùþúùùúùüúùúùùûúùúúùùúúùúúùúúùúùþúùùþúùù÷úùúùúùùúùùúùúùýúùúúüùúùúúþùúúùþúùùþúùùûúùùúùùúþùúúùúùúùúþùúúþøùùþúùùþúùùüúùúùùþúùùûúùúùúúùúþùúúûùúùùúúþùúúùþøù ùúýùúùùþúùùþúùùþúùùúûùúúùúúþùúúùþøù ùþúùùþúùùþúùùþúùùúùúûùúúùú úþùúúþøù ùþúùùúùýúùúúüùúùúúþùúúùþøùùüúùúùùþúùùþúùùëúùúúùúúùùúúùùúùúùúúùúúùúùþøùùþøùùúüùúùúúýùúùùúùöúùùúúùúúùúúþøùùþøùùïúùúùùúúùúùùúùùúúùùúùûúùúùúúùøøùøùùøøùùþúùùúùúöùúúùúùùúùúúüùúúùùüøùøù ùþúùùþúùùþúùùõúùúúùúùúúùúúøùúùúùúúùùûøùùøùùþúùùúþùúúùúûùúùúùùýúùúúþùúúöùúùùøùùøùøøùþøùùøúùúùùúúùùþúùùöúùùúúùúùùúúþùúúùùøùøøùøùùüøùøùùþøù ùúùûúùùúùù÷úùùúùùúúùùýúùúúùýúøùùþøùùø ùþúùùùúùúúùùúúùúùûúùùúùùúø!ùúùúùþúùùúúùúúùùøøùøùøøùøùøùùøù ùþúùùûúùùúùùúùýúùúúþùúúøùúúøøùøùùüøùøùùþøùùþøùùþúù ùþúùùþúùùúùú÷ùúùùøùùøùùþøùùþøù ùþúùùúùþúùùýúùúúùùøùùøøùùùøùøùùøùùùúùúùùúùùúúùùúùúúùøùøùüøùøùùø ùüúùúùùúùúùúöùøùøøùøùøùùüøùøùùþøùùþøùùþøùùþúùùúùúùøþùøøùùøùùøøùùøùþøùùø ùþúùùþúùùúùüøùùøøùøùøúùøùùøùùúùúýùúùùúøùúùøøùùøøùþøùùþøùùøùùøùøùøøùùþúùùþúùùüúùùúúø÷ùøùùøøùøùùøùýøùøøùøùþúùùþúùùþúùùýøùøøùøüùøøùùûøùùøùùþøùùøùþøù ùûúùùúùùúûùøøùøøþùøøùùøùùøøùøøüùøøùùøùþúùùúøðùøøùøùøùøøùøùùøùùöøùùøùøùùøùùþøùùûúùùúùùøúùøùøùøøùøùøùøùþúùùúýùúøøùøùøþùøøùüøùøùùþøùùþøù ùþúùùýøùøøúùøøùùøøþùøøûùøùøùùøùþøùùûúùùúùùøþùøøùùøùøøùùøøùøýùøù ùþøùù øþùøøùüøùøùùøúùøùùøùùþøù ùþúùùøþùøøþùøøùøýùøùùøùûøùùøùùûøùùøùùþúøøûùøøùøøùùøùùøøùøøúùøøùùøøùøøùøøùùøùùþøù ù øþùøøùøþùøøùøùøúùøùùøùùþøù ùøþùøøþùøøòùøøùøøùùøøùøøùùø ùøþùøøþùøøëùøøùùøùøùøøùøøùùøøùøùùþøùùþøùùþøù ù øúùøùøùøøüùøøùùýøùøøùþøùùÿ™šý›š››œ›œœ žŸ ý¡ ¡¡þ ¡¡úš™™š™ššø›š››œ››œœõœžžžžúŸžžŸžŸŸ  ¡üš™™ššù›šš›šš››œ žŸþžŸŸý Ÿ  ¡™üš™™ššý›š››œžžúŸžžŸžŸŸ þ¡  ¡™šü›šš››œýœžûžžžžŸý Ÿ  û¡ ¡˜™™ûš™š™ššý›š››ýœ›œœžŸþžŸŸü ŸŸ  ü¡˜˜™™úš™šš™ššý›š››üœ››œœþœžúžŸžžŸŸ þ˜™ ™šü›šš››ýœ›œœžžŸù Ÿ Ÿ  ˜˜ü™˜˜™™šþ™šš›œþœ÷žžžŸžŸžžŸ úŸ ˜˜™˜˜™šþ™šš›þš››þœ››œžžýŸžŸŸþ ŸŸ˜ü™˜˜™™÷š™š›š›šš››œþ›œœžþžžüŸžŸžžŸ˜ý™˜™™÷š™šš™šš›šš›ýœ›œœýœþžžŸû —˜—˜˜™þ˜™™š™š›š›œþ›œœýœž÷žžžŸŸžŸŸ˜—˜™û˜™™˜™™šú›š››š››þœ››œýœžþžžŸúž——˜—˜˜ ™šþ™šš›þš››ýœ›œœûžžžžŸž—ü˜——˜˜™ø˜™™š™š™šš›þš››œžüžžžûŸž––——ü˜——˜˜™šþ™ššý›š››œöœœœžž—–—˜û™˜™˜™™š›šý›š›› œüœœž—þ–——ý˜—˜˜ó™˜˜™˜™™š™™š™ššü›šš››œœöžžžžž–——þ–——ý˜—˜˜™þš™™š›œþœœýžžžþ––û—–—–——ü˜——˜˜™ûš™š™ššý›š››œþœœýœžþ•––ý—–——˜—˜ ™šü›šš››ýœ›œœûž••––ü—––——˜ý™˜™™ýš™šš›ýœ›œœüœœý–•––þ—––—˜—˜™ýš™ššü›šš››œ›œþ›œœ –ü—––——þ˜——ý˜™˜˜™ýš™ššý›š›› œûœ••–þ•––—˜ü™˜˜™™þš™™šú›š››š››œþ›œœíœœœ””••–••–•––—–——þ–——˜û™˜™˜™™š›úš›š›š››œþ›œœüœ”••þ–••–—û˜—˜—˜˜þ™˜˜™šû›š›š››œþ›œœüœ”••–þ—––—˜þ—˜˜™þ˜™™š›þœ››œþ”••ü–••––û—–—–——ý˜—˜˜ý™˜™™š™šù›šš››š››õœ››œœ”•”•”••ú–•–••––—þ–——˜™šû™šš›ššý›š››œû›œ”•””•þ”••–ý—–——û˜—˜˜™™˜™šþ›šš›ùœ”“””•””•ü–••––ü—––——ö–—˜—˜——˜—˜˜™š›ûœ›”“””ý•”••ý–•––—þ–——˜™üš™™šš›“”•þ”••ü–••––þ—––—ý˜—˜˜ü™˜˜™™š›“”•ü–••–– —˜™ýš™šš›ý𛓓”ú•””•”••– — ˜™üš™™ššø›š›š““”““”•÷”•–•–•–•––û—–—–——ý˜—˜˜™ûš™š™ššú›š››’““ü”““””•þ”••ý–•––—ý˜—˜˜ù™˜˜™˜˜™™ýš™šš›“”þ“””•þ–••–û—–—–——þ˜——˜™þ˜™™šû’“’’““”þ“””•ü–••––û—–—–——ý˜—˜˜ò™˜™˜™š™™šš™šš’’“ü”““””ú•”••”••–ú—–——–——û˜—˜—˜˜™þ˜™™š™üš’“’’“ü”““””ù•””••”••–—þ–——ý˜—˜˜þ—˜˜™þ˜™™šý™‘’’“”þ“””•þ”••õ–•–•––——––——˜ü™˜˜™™ü𙑒’û“’“’““ú”“””“””ý•”••–û—–—–——˜—˜÷—˜™˜˜™™˜™™û’‘’‘’’ü“’’““”•ý–•––—–—˜þ—˜˜™þ˜™™‘ý’‘’’“þ’““”þ“””•þ–••–—˜—˜™˜ü™‘‘’’þ‘’’ý“’““ü”““””•ü”•”••ý–•––—ù˜——˜˜—˜˜™‘ò’‘’’‘‘’’“’“’’““ú”“””•””•ø–•–•––•––û—–—–——û˜—˜—˜˜þ™‘‘þ’‘‘’þ‘’’“’“ü”““””•ý–•– –—˜ü—˜—˜˜û™‘‘‘ý’‘’’“þ’““”•–þ•–– —˜û‘‘‘‘’‘ø’‘’’“’’““ ”•ý–•––ý—–——˜ý—˜‘’ú‘’’‘‘’’ “”•þ–••–—ú˜——˜—ú‘‘‘‘‘’ý“’““”•÷”••”••–•––þ—––—þ˜——û‘‘‘‘’ü“’’““ý”“”” •–þ—––—ü˜ý‘‘‘û‘’’‘‘’ú“’““’““”û•”•”••þ–••ý–•––—˜þú‘‘‘‘‘ý’‘’’ý“’““ý”“””•–ü—––——ü‘ý’‘’’ú“’““’““”þ“””ú•”•””••û–•–•––ú—–—––‘þ‘‘ü’‘‘’’ý“’““”•–þ•––þ‘ü’‘‘’’þ“’’“ ”•–•–—þ–‘÷’‘’‘‘’““’’“õ”““”“””•””••–þ•––þŽþ‘þ‘‘ü’‘‘’’“ý”“””•þ”••–þ•––ûŽŽ‘þ’‘‘’“þ’““þ”““”ý•”••–ü•––ŽŽýŽ‘þ‘‘ý’‘’’ý“’““õ”““””“”••”••ü–••–üžŸžŸŸþžŸŸý Ÿ  þ¡  ý¡ ¡¡ú¢¡¢¡¡¢¢£¤þ£¤¤¥þ¤¥¥þžžŸý Ÿ  þŸ  ú¡ ¡¡ ¡¡¢ý£¢££¤þ£¤¤¥þžžúŸžŸŸ ŸŸ þ¡  ¡ü¢¡¡¢¢£ú¤££¤£¤¤¥þ¤žžŸþžŸŸû Ÿ Ÿ  ô¡ ¡ ¡¡¢¡¡¢¡¢¢þ£¢¢£¤þ£¤¤¥ú¤žžžýŸžŸŸ ¡ò ¡ ¡ ¡¡¢¡¡¢¢¡¢¢ý£¢££ü¤££¤¤¥úžžžžŸžŸ üŸ Ÿ  ¡û ¡¡ ¡¡¢£þ¢££¤û¥¤¥¥ýžžžüŸžžŸŸ þŸ  ¡û¢¡¢¡¢¢£¢£¤£¤ûžžžžýŸžŸŸ þŸ  ¡ø¢¡¡¢¢¡¡¢¢ý£¢££¤ýœžŸú Ÿ  Ÿ  ¡ü¢¡¡¢¢ý£¢££÷¤£¤£¤¤œüžžžŸ Ÿ ¡¢þ¡¢¢ù£¢¢££¢££¤þœüžžžøŸžžŸŸžžŸŸþ ŸŸ ý¡ ¡¡ü¢¡¡¢¢ý£¢££þ¤££œþœžþžžüŸžžŸŸ ¡ ¡ý¢¡¢¢ý£¢££þ¢££ø¤œœœœžþžžýŸžŸŸò Ÿ Ÿ Ÿ  ¡ ¡¡ ¡¡ý¢¡¢¢£þ¢££þ›œœùžžžžžþŸžžŸ ¡þ ¡¡¢ù£¢¢££›œœþœžþžžŸþžŸŸ þ¡  ý¡ ¡¡¢ø£¢£›œœ›œœœžþžž Ÿù Ÿ  ¡¡  ¡ü¢¡¡¢¢ý£¢››œýœžüžžžŸþžŸŸ÷ ŸŸ Ÿ  ¡  ¡ü ¡¡¢¢÷£¢¢£››œ›œœþœœþžžŸ þŸ  ü¡  ¡¡¢ù¡¢¢£¢¢››ýœ›œœþœœþžžŸ ü¡  ¡ ¡¢£›œþ›œœžùŸžŸžŸžŸŸ  ¡þ ¡¡ý¢¡¢¢ï›š››œœ›œ››œ›œœœüžžýžžžŸý Ÿ  ¡ý¢¡¢¢›œ›œüœœœ÷œžžžžŸþžŸŸ ¡ ¡¢ù¡¢šš›š››œù›œ›œœœ žŸ Ÿ ¡ú¢¡¢¡¡šš›ýœ›œœþœþœžþžžýŸžŸŸþžŸŸ ü¡  ¡¡ý¢¡šš›š›ûœ›œ›œœþœœýžžžŸúžŸ  Ÿ  ù¡ ¡¡  ¡¡š›š›üœ››œœþœœüžžžŸþžŸŸý Ÿ  ¡šþ›šš›þš››œþœúžžžžžýŸžŸŸ þŸ  ¡ü ¡ ššþ™ššý›š››œþ›œœúžžžžùŸžžŸžžŸŸ ø¡ ¡¡šš™ššý›š››œ žûŸžŸžŸŸý Ÿ  û¡ ¡ ™™üš™™šš›š›œýœžþžžýŸžŸŸ ý™š™™ýš™ššý›š››œýœžþžžŸú ŸŸ  ™™š™š ›ýœ›œœžþžžŸø ŸŸ  ™˜™™šþ™šš ›œ žŸþžŸŸü ŸŸ  ü˜™˜™™šü›šš››œ›œüœœöžžžžžŸŸžžŸú Ÿ ˜˜™™šü›šš››ýœ›œœýœþžžŸþ ˜˜ü™˜˜™™šþ™šš›ýœ›œœžþžžŸ ˜ý™˜™™šþ™šš›þš››úœ›œœœœž÷žžŸžŸŸžŸŸ˜û™˜™˜™™þš™™ýš™šš›œùœœœžžŸý˜—˜˜™þ˜™™ýš™šš›š›œ›ýœ›œœýœùžžžžùŸžŸžŸŸ˜˜ ™šþ™šš›œ›œ žüŸ˜—˜˜™úš™š™™šš›œþ›œœœøœžžžþ˜——˜ü™˜˜™™üš™™ššý›š››þš››œü›œ›œœüžžžþŸ——˜—˜ü™˜˜™™þš™™š›ûš››œ››œþœžû–——˜——˜™š›œýœžž–—ú˜——˜—˜˜™þ˜™™š›œýœýžžž–—þ–——þ˜——˜™þ˜™™üš™™šš›ýœ›œœýœþ–— —ü˜——˜˜™šþ™ššþ›šš›úš››œ›œœþ›œœþž–– —ü˜——˜˜ù™˜˜™™˜™™š›œ›œœþž––û—–—–——˜ý™˜™™šü™š™šš›þš››œüœœ–ü—––——ý˜—˜˜™þ˜™™š›œþ›œœ–—–—˜þ—˜˜ý™˜™™úš™šš›šš›ýœ›œœœò–•––•––——–——–——ý˜—˜˜ú™˜™™˜™™õš™šš™šš›š›šš›œ• –—þ˜——˜ú™˜™˜˜™™šþ™šš›œýœ••ý–•––þ—––—þ˜——˜ü™˜˜™™þš™™š›þš››üœ››œœ•–•–ý—–——˜þ—˜˜™üš™™ššý›š››þš››œü›œ›œœþ”••û–•–•––þ—––—˜™ýš™šš›š›œþ”••ý–•––—–—ü˜——˜˜™üš™™šš›þš››þœ››þ”••ú–•–••––þ—––—˜—˜ý™˜™™šþ™ššý›š››œü›””••ö–•––•–—––——þ˜——˜ù—˜˜™˜˜™™ûš™š›šš›þœ””•ù–•––••––ü—––——˜þ—˜˜ú™˜™˜˜™™šþ›šš›”ý•”••–•–—–—˜™˜™üš™™ššþ›šš›ý”“””ý•”••–ý—–——˜þ™˜˜™ýš™šš›”•”•ý–•––þ—––—ý˜—˜˜þ—˜˜™ šü›““””•þ”••ý–•––ü—––——˜—ý˜—˜˜™þš™™šü›š›šûüúûúûûþúûûùüûûüûüûûøüûüüûüüûûüûûüûûüüöûüûüüúûúúûûýúûúúýûúûûüûûüûüûüüðûüûüûüüûûüüûûüüûûþúûûúû÷úûúûúûûúûûûüûûüûûüþûüüðûüüûüûûüüûúûûúúûûþúûûú ûûüûûüûûüûüýûüûûüûúüûúúûûþúûûûúûûüûûþüûûûüûûüûûþüûûüøûüûüûûüûûúûþúûûþúûûþüûûþüûûýüûüüûüûüüûúûúúþûúúûúûûúûúúû ûþüûûûüûûüûûüûüûüüûûúúûúûûúûûúûûüùûüûûüüûûüûûüûûüûûúûûúûúûûþúûûüúûúû ûþüû ûüûüüûüúú÷ûúúûúúûúûûúûüúûúûûþúûûþüûûþüû ûþüúúûþúûûúûûúûúûûþúûûþüûûüüûüûûþüûûüúûþúûûúûúûûúûûúûûþúûûþúû ûþüûûþüûûüüûüûúúïûúúûúúûúûûúûúûûúûûúýûúûûþúûûþüûûüûùüûüûüûüüúýûúûûûúûúûúúûúûþúû ûþúûûþüûûøüûüûüûüûûûüûûúûûúûþúûûûúûûúûûþüû ûöüûüûûúûúúûûþúûûúñûúûúûúûûúûúúûúûûûúûûúûûþúûûþüûûúûúýûúûûúûûúûûúûûú ûþüûû÷üûûúúûúûúúûûúûûúúüûúúûûþúûûüúûúû ûþüûûþüûûþüúúùûúûúûûúúûúûúûöúûúûûúûûúû ûþüûûþüûûþüûûýúûúúûúûúþûúúûûúûúûûûúûúúûûþúû ûþüûûþüúúþûúúïûúúûûúûûúúûûúûúûúúûþüû ûúþûúúùûúûúûúûûþúûûþüûûýúûúúþûúúûþúûûýúûúúùûúúûûúûûúûúøûúûûúúûúúûúûòúûûúûúúûúúûûúûûúûúþûúúûúúûûúúûûúûüúûúûûþúûûþúûûúûûúúûúúûüúûúûûúûüúûúûûúúûúûúûûúûþúû ûúþûúúûûúúûúúûþúûûúûþúûûþúûû úþûúúûòúûúûûúúûúûúûûúúùûúúûûúûûþúûûþúû ûúüûúûúúûûúûûúúüûúûúúýûúûûöúûûúûûúûûú úüûúûúúþûúúþûúúüûúúûûúûþúûûûúûúúûûúþùú úþûúúþûúúûúýûúûûþúûûúúûúûúûûþúûû úþûúúøûúúûúûûú úûúûþúûû úþûú úøûúûúúûûúúûþúûûþúûûþúûûúþùúúþûúúþûúúþûúúûúûúûþúûûþúûûþúûû÷úûûúùúúùúúþùúúþûúúþûúúþûú úûûúûúûûöúûúûûúûúúûû÷úûúúûúúùúúþûú úûúüûúúûûúûýúûúúþûúúûûúúûúúûúûúþûúúûüúûûúúûþùúúþùúúûúþûúúþûúúûúüûúúûûúúûûúûúúüùúùúúûúúûúúûúúùûúúûúûúúûõúûûúúùùúúùúúþùúúþûúúüûúûúúþûúúûúûúýûúûûþúùùúþùúúþùúúþùúúûûúûûúúûûúûúûûúûúûýúûúúþùúú÷ûúûúúûúûúúüûúûúúûþúûû÷úûúùùúùùúúþùú úþùú úþûúúùûúûûúûúúþûúúüûúûúúûùþúùùúþùúúúûúûúûúúûúûúûüúûûúúùúúùúúùúúûùúúùúúüûúûúúûúûõúûûúûúûûúûùùúûùúúùú-úûúûùúüùúùúúûùúúùúúûýúûúúûúûûúûúûûúôùúùúùùúúùúúùùýúùúúùúþùú úþûúúüûúûúúûúûùúûúúùúùùúùúùúüùúùú úþûúúþûúúþûúúèûúúûûùúùúùúúùúúùúúùùúùùúúþùú úþûú úþûúúûúùýúùú úûùúùùúú÷ûúûúûúûûúúþûúúùúùùúùúùúùùúþùúúþûúúûúûúþûúúùùúùúùùúùùúùúþùúúþùúúþùúúþûúúöûúûúúùúùùúúñùúùùúúùúùúùúùùúúûùúúùúúþùú úòûúûúúûúúûûúûúùùþúùùúùúùúùúþùú úþûúúýûúùùõúùúùúùúùúúùùúùùúùúùùúúþûúúþûúúýùúùùúúùúùúùùúùýúùúúùúþùú úþûúúþûúúóûùùúùúúùùúùùúúùþúùùõúùúúùùúùùúùùúþûúúüùúúùùõúùúùúùúùúùúúùùúùùúúùúúùýúùúúþûúú÷ùúúùúùùúùùøúùúùúùùúúùúùúþùúúþùúúþûúúùþúùùûúùúùúúþùúúþùúúùúþùú úþùú úûùúùúùúüùúùúúþùúúùúûùúúùúú ùþúùùúøùúùùúúùúúúùúùúùúúþùúúþùúúþùúúùùúùúùùúùùþúùùûúùùúùùúûùúùùú úþùúúÿ¡þ¢¡¡¢£þ¢££ý¤£¤¤¥ü¦¥¥¦¦ú§¦¦§¦§§¨þ§¨¨õ©¨©¨©©¡¡¢¡¢¢û£¢£¢££ý¤£¤¤ú¥¤¤¥¤¥¥¦ú§¦§¦¦§§¨û©¨©©¡¡¢þ¡¢¢£¤þ£¤¤ý¥¤¥¥¦þ¥¦¦§ý¨§¨¨©ý¨©¡¡¢ú¡¢¡¢¢££¤þ£¤¤¥¦ü§¦¦§§¨þ§¨¨©¡¢û¡¢¢£¢¢£ù¤££¤¤£¤¤¥¤¥¦ §ü¨§§¨¨þ ¡ ¡¢ù£¢¢££¤££¤¥ù¦¥¦¥¦¥¦¦§þ¦§§¨ ¡¢þ¡¢¢£ù¤£¤£¤£¤¤¥¦þ¥¦¦§÷¨§¨§§¨§§  ¡¢ü¡¢¡¢¢£þ¢££¤þ£¤¤¥¦§ü¦§¦§§ú¨  ¡¡  ¡þ¢¡¡¢£þ¢££ý¤£¤¤ü¥¤¤¥¥¦û§¦§¦§§¨ ü¡  ¡¡¢þ£¢¢ý£¢££ú¤£¤££¤¤ü¥¤¤¥¥¦§ ô¡  ¡¡ ¡¡¢¡¡¢¢£þ¢££ü¤££¤¤þ¥¤¤¥þ¦¥¥¦§÷¦§§Ÿ  ŸŸ  ¡¢£¢£ ¤¥ü¦¥¥¦¦ø§¦§¦¦§§  þ¡  ¡ý¢¡¢¢£ú¢££¤£¤¤¥¦¥¦§Ÿ ¡þ ¡¡¢þ¡¢¢£ú¤££¤¥¤¤¥þ¤¥¥ô¦¥¦¥¥¦¦§§¦§ŸŸù ŸŸ ¡ ¡¡þ ¡¡¢ £¤¥þ¤¥¥¦þ¥¦¦ý§žŸŸ ¡õ ¡ ¡¡¢¡¢¢¡¢¢ü£¢¢££ý¤£¤¤¥þ¤¥¥ý¦¥¦¦Ÿþ ŸŸ ¡û¢¡¢¡¢¢£þ¤££¤ú¥¤¤¥¤¥¥¦¥¦žýŸžŸŸ þŸ  ¡þ¢¡¡¢ü£¢¢££¤ù¥¤¥¤¥¤¥¥ý¦¥¦¦žŸý Ÿ  þ¡  ¡¢û£¢£¢££ý¤£¤¤¥¦žýŸžŸŸ þŸ  ¡¢£¤þ£¤¤¥ý¦žžŸù Ÿ Ÿ Ÿ  ¡þ ¡¡¢£÷¢££¤£¤££¤¤þ¥¤¤¥þ¦žžŸú Ÿ ŸŸ  ¡¢þ¡¢¢£þ¢££¤ý¥¤¥¥žþžžúŸžžŸžŸŸý Ÿ  ¡ö ¡¡ ¡¡¢¢¡¢¢£¤ü£¤£¤¤¥žŸþžŸŸ÷ Ÿ Ÿ  ¡ ¡¡¢ø£¢¢££¢¤££¤¥žüŸžžŸŸ ¡ø¢¡¢¢£¢¢££¤þ£¤¤¥ýœžûŸžŸžŸŸ ý¡ ¡¡ú¢¡¡¢¢¡¡¢ý£¢££ü¤££¤¤ý¥¤žüŸžžŸŸý Ÿ  ¡¢ü£¢¢££¤üœœžþžžŸ ¡ ý¡ ¡¡ ¢£ú¤£¤¤£¤¤þœþœûžžžžûŸžŸžŸŸ Ÿ ý¡ ¡¡¢þ¡¢¢£þ¢££ù¤££¤¤œýžžžþŸžžŸþžŸŸý Ÿ  ù¡ ¡¡¢¢¡¡¢£ú¤£¤£¤œœþœœžþžžŸþ ŸŸ õ¡ ¡ ¡  ¡¡¢¡¡¢û£¢£¢££ý¤›œœüžžž Ÿ ¡þ ¡¡¢þ£¢¢£œýœýžžžùŸžžŸŸžŸŸ  ¡¢þ¡¢¢£ü›œ›œœôœœžžžžžŸú Ÿ  Ÿ  ¡¢¡ý¢¡¢¢£›œüœœžþžžüŸžžŸŸ þŸ  û¡ ¡ ¡¡¢û£¢££›› œžŸú ŸŸ Ÿ  ý¡ ¡¡ý¢¡¢¢£ü¢£¢››üœ››œœýžžžýŸžŸŸ  ¡ø¢¡¢¢££¢››œœüžžžŸûžŸŸžŸŸý Ÿ  ¡ü ¡ ¡¡¢ø¡¢¡¢¢£¢› ›œ žŸ þŸ  ú¡ ¡  ¡¡ý¢¡¢¢š›ýœ›œœþ›œœúœœžýŸžŸŸþ ŸŸ ¡÷¢¡¢¢››š›šš› œúžžžžýŸžŸŸ ú¡  ¡ ¡¡ü¢¡™šš›þš››ýœ›œœúœœœûžžžž Ÿ ü¡  ¡¡þ¢šš›þš››œþ›œœýœžøžžŸŸžžŸŸ ù¡  ¡¡ ¡¡ý¢¡šš›þš››þœ››œýœþžžŸ ý¡ ¡¡þ™ššü›šš››œúœœœžžýŸžŸŸý Ÿ  ý¡ ¡¡™šø™š›šš›š››œ žŸþžŸŸ Ÿ ¡ö ¡™™š™š™™šš›œ󜜜žžžžžŸú Ÿ  Ÿ  ¡™š›šû›œœ›œœüœœøžžžžžžŸ ý¡˜™™óš™™š™šš››š›š››ýœ›œœþœœýžžžýŸžŸŸý Ÿ  þ˜™™ýš™šš›œýœùžžžžžŸþžŸŸý Ÿ  ü˜™˜™™š›š›œþ›œœ÷œžžžžùŸžžŸžžŸŸú Ÿ ™˜™™š™š›þš››œüœœœþžžŸ ˜™þš™™šý›š››œ ž Ÿþ—˜˜™þ˜™™ýš™ššõ›š››š››œ››œœžþžžŸþžŸŸü ——˜˜þ™˜˜™üš™™šš›þš››œøžžžžžžûŸžŸžŸŸý˜—˜˜ý™˜™™þš™™šü›šš››œüœœžŸõžŸžžŸ ——˜—˜˜ý™˜™™ûš™š™ššý›š››úœ›œœœœžþžžŸ—û˜—˜—˜˜™šý›š››þš››ûœ›œ›œœþžžþŸ——˜ù—˜˜™˜˜™™ýš™ššý›š››œþ›œœþžýžžžýŸž——ý˜—˜˜÷—˜˜™˜™™˜™™ýš™šš›ýœ›œœùœœœžýŸž––—˜ú—˜˜™˜™™šó™šš™šš›š››šš››ùœ››œœ›œœžþžžü—––——˜—˜ý™˜™™ýš™šš›þš››œ›œýžžžøžž–——–——û˜—˜—˜˜ý™˜™™šû›š›š››ýœ›œœýœþœž–ú—––—–——˜™˜™ š›œýœžþ¥¦¦§þ¦§§¨©ýª©ªªú«ª««ª««û¬«¬«¬¬­ý¬¦¥¥¦§ý¨§¨¨©¨©ªú«ªª«ª««¬þ«¬¬ý­¬¥¥¦ø§¦¦§¦§¦§§¨þ§¨¨ü©¨¨©©ýª©ªª«û¬«¬«¬¬¥ý¦¥¦¦ü§¦§¦¦§þ¨§§ý¨§¨¨©ûª©ª©ªª«þª««ý¬«¬¬¥ý¦¥¦¦§¦§¨þ§¨¨©ª©ªü«ªª««¬ý«¬¥¥þ¤¥¥ü¦¥¥¦¦§ú¦§¦§¦§§ü¨§§¨¨þ©¨¨©úª©©ª©ªªú«ªª«ª««¬ö¤¥¤¥¤¥¥¦¦¥¥¦§¦§¨ó§¨¨§¨¨©¨¨©©¨©©ýª©ªª«¬ý¤¥¤¤¥¦§þ¦§§¨þ§¨¨ý©¨©©ª«þª««¤ü¥¤¤¥¥ü¦¥¥¦¦ý§¦§§¨ý©¨©©ýª©ªªý«ª««þ¬¤¤ù¥¤¤¥¥¤¥¥¦ü§¦¦§§ü¨§§¨¨û©¨©¨©©ªû©ªª«ªª«¤ö£¤¤¥¤¤¥¤¤¥¥¦÷§¦§§¦¦§¨§§¨§¨©þ¨©© ªû«ª««¤¤ù¥¤¤¥¥¤¥¥ý¦¥¦¦ý§¦§§¨þ§¨¨ú©¨©©¨©©ª«ûª«¤£¤¤ý¥¤¥¥ú¦¥¦¥¥¦¦ý§¦§§¨ö§¨§¨§§¨¨©¨¨©ªþ©ªªú¤££¤£¤¤þ¥¤¤¥þ¦¥¥¦§þ¦§§¨§¨þ©¨¨©üª©©ªªü«ªª££þ¤££¤þ¥¤¤ý¥¤¥¥¦ñ§¦¦§§¦§¨§¨§¨¨§¨¨ý©¨©©ªþ©ªª£¤£¤¥þ¦¥¥¦§÷¦§¦§¨§¨§¨¨þ©¨¨©ªþ©ªª£þ¢££ý¤£¤¤¥ø¤¥¥¤¥¥¦¥¥¦ý§¦§§¨ù§¨¨©¨¨©©ª©ûª££¢££¤þ£¤¤¥ ¦ý§¦§§¨þ§¨¨©þª¢¢£þ¤££¤þ£¤¤ý¥¤¥¥ ¦ù§¦§§¦¨§§ô¨§¨§¨©¨¨©©¨©©ª¢£ü¢£¢££¤þ£¤¤ý¥¤¥¥þ¦¥¥¦§¦§ý¨§¨¨©þ¨©©¢þ£¢¢õ£¢££¤¤£¤££¤¤û¥¤¥¤¥¥þ¦¥¥¦§¦§¨§¨©ü¨©¨©©¢þ£¢¢£¤ü¥¤¤¥¥¦þ¥¦¦§¦§¨÷©¨©©¨©©¡¢¢ü£¢¢££þ¤££¤ü¥¤¤¥ ¥¦§ü¨§§¨¨©ü¡¢¡¢¢ü£¢¢££ú¤££¤£¤¤ ¥ý¦¥¦¦§¦ý§¨§§¨©þ¨¡¡¢£¢£ý¤£¤¤û¥¤¥¤¥¥¦§þ¦§§þ¨§§¨û©¨¨©¡¡¢þ¡¢¢ý£¢££¤þ£¤¤¥¤¥¦ü§¦¦§§ü¨§§¨¨©¡¢¡ø¢¡¢¢£¢¢££¤ü£¤£¤¤ù¥¤¤¥¥¤¥¥¦§¦§¨û§¨¨©¡¡¢þ£¢¢£¤þ£¤¤ü¥¤¤¥¥ý¦¥¦¦§ü¦§¦§§¨ ¡¢ý£¢££ý¤£¤¤ü¥¤¥¤¤¥¦¥¦ý§¦§§¨ ¡û¢¡¢¡¢¢ú£¢£¢¢££¤ ¥ý¦¥¦¦§¦§¨ ¡¢¡¢þ¡¢¢£þ¢££¤þ£¤¤¥þ¤¥¥ý¦¥¦¦§¦ó§¦¦§§¨§¨¨  ¡  ¡¢ü¡¢£¢¢ý£¢££ ¤¥ü¦¥¥¦¦§ù¨  ¡  ¡ ¡¢£¤¥ù¦¥¥¦¦¥¦¦§þ¦§§ ¡¢£¢£¤ü£¤£¤¤¥ú¦¥¦¦¥¦¦§ý Ÿ  ¡ ý¡ ¡¡ü¢¡¡¢¢ý£¢££ ¤ý¥¤¥¥þ¦¥¥¦þ§¦¦ú§Ÿ ŸŸ  û¡ ¡¢¡¡¢£þ¢££ý¤£¤¤¥¤¥þ¤¥¥ ¦ö§ŸŸ  Ÿ  ¡  ¡¢£¢£ý¤£¤¤¥¦§Ÿü ŸŸ  ù¡ ¡ ¡ ¡¡ú¢¡¡¢¡¢¢£ý¢£¤¤£¤¥¤õ¥¤¥¦¥¥¦¦¥¥¦¦Ÿü ŸŸ  ý¡ ¡¡ó¢¡¢¢¡¢¢£¢¢£¢££¤ ¥¦Ÿ üŸ Ÿ  ¡ö¢¡¡¢¢¡¢¢£¢¢£ø¢££¤¤££¤¤ ¥¦ýŸžŸŸ ý¡ ¡¡¢þ¡¢¢ú£¢¢£¢££þ¤££¤þ¥¤¤¥¦û¥¦ŸžŸŸ üŸ Ÿ  ¡¢þ¡¢¢ü£¢¢££ý¤£¤¤¥û¦¥¥ŸžžŸ ý¡ ¡¡ú¢¡¢¡¡¢¢ü£¢¢££û¤£¤£¤¤û¥¤¥¤¥¥ýžŸžžŸü ŸŸ  û¡ ¡ ¡¡¢þ¡¢¢£ù¢££¤¤£¤¤¥þ¤¥¥þ¦žžŸüžŸžŸŸþ ŸŸý Ÿ  ú¡  ¡ ¡¡ú¢¡¢¢¡¢¢£¤ý¥¤¥¥þžžýŸžŸŸ  ¡þ ¡¡¢þ¡¢¢£þ¢££¤ý¥¤¥¥üžžžþŸžžŸ  ¡ý¢¡¢¢£¤þ£¤¤ú¥žžžžŸùžŸŸ  Ÿ  ¡þ ¡¡ò¢¡¡¢¡¢¢£¢£¢£¢££¤÷¥¤¤¥žžžžŸüžŸžŸŸ þ¡  ¡ü¢¡¡¢¢£¤û£¤¤£¤¤ýžžžŸžŸþ ŸŸ ý¡ ¡¡¢£þ¢££þ¤££¤žþžž Ÿ ¡ü¢¡¡¢¢ý£¢££û¤£¤£¤¤þœüžžžþžžŸþžŸŸõ Ÿ  Ÿ  ¡¡ ¡¡¢ú£¢£¢¢££¤ýœžŸžŸú Ÿ  Ÿ  ¡ ¡ü¢¡¡¢¢¡î¢£¢¢£¢££¢£¤££¤£¤œžŸüžŸžŸŸý Ÿ  ¡þ ¡¡ú¢¡¢¢¡¢¢ú£¢£¢£¤¤þ£œœœøžžžžžŸžŸþ ŸŸ ¡¢ú¡¢¢£¢££ý¤£œœþœžþŸžžŸ ¡þ ¡¡ú¢¡¡¢¡¢¢£þ¢££œþœøžžžžžžŸú Ÿ ŸŸ  ü¡  ¡¡þ¢¡¡¢ý£¢££þ›œœýœžþžžŸ þŸ  ¡ ¡¢ý£¢££›œ žŸ þŸ  ¡þ ¡¡¢¡ý¢¡¢¢ú£¢›œ›œœýœþžžŸþžŸŸý Ÿ  ù¡ ¡¡  ¡¡þ¢¡¡¢›ûœ›œ›œœûœœœ žŸþžŸŸ þŸ  ý¡ ¡¡ý¢¡¢¢ü£¢¢››ýœ›œœýœžþžžüŸžžŸŸý Ÿ  ý¡ ¡¡þ ¡¡¢þ¡¢¢›œþœüžžžŸþžŸŸý Ÿ  ü¡  ¡¡¢þš››ýœ›œœþœžþžžŸ Ÿ ü¡  ¡¡ü¢¡¡¢¢üüûüûü üþýüüþýüüúýüüýýüüýüüýüüýýúüûüûûüüþûüüþýüüýüþýüüýþüýýûüýüüýýüýþüýýüþûüüýüþýüüýüþýüüýýüýýûüýüüýýüüûûüüþûü üþýüüýü÷ýüýüýýüýüüýüýüúýüýüüýý üþûü üþýü üýüýúüýýüýüüýüý÷üýüüýýüüûûýüûüüþûüüþûü üþýüüýøüýüýüýüýýøüýüýüüýüüþýüüýýüûûüþûüüþýüüþýüüýýüýýþüýýüüýýüüýýüûûýüûüüþûüüþûüüþýüüøýüýüýüýüüüýüüýýþüûûõüûüûûüûüüûüüþýüüøýüüýüüýüüýüøýüüýüýüýý÷üýûüüûüûüüþûüüþûüüüýüüýýüþýüüýýüýûûüùûüûüûûüüþûü üúýüýüýüüýüúýüüýýüüýüþýüüûûüûûüüþûüüþûüüüûüûüüþýüüýüýüùýüûüüûüüüûüûüüûüûûüüûüüýüþýüüýüûüøûüûûüûûüüþûüüþûüüþûüüþýüüþýüüûýüýüýýüüýûüüûüüûüûüüþûüüüûüûüüþûüüýüþýü üýüýüøûüüûûüûüüûýüûü üþûüüþýüüüýüýüüñýüýüüûûüûûüûûüûûûüûüûüüûüþûüüþûüüþýüüþýüüöýüýüýýüüýûûüûþüûûüûüûûüûûüüþûü üüýüýüüþýüüøýüüûûüüûûüûüþûüüûüþûüüþýüüû÷üûüüûûüûüüûüþûüüýüúûüûûüûûüûþüûûüþûüüþûü üþýüüþýüüþýüüûúüûüûüûûüûüþûüüþûüüüûüûüüþûüüþýüüûýüýûüüýûüûûûüûûüûûüûüûüûüþûüüþûüüýûüû ûùüûûüüûüüþûüüþûüüþûüüþûüüþýû ûüúûüûûüûûüþûüüþûüüþýüüûþüûûôüûüüûûüûüûüûûùüûüüûûüüþûüüþûüüúûüûûüû ûñüûüüûûüûüûüûûüûûüýþüûûüûïüûüüûûüüûüûüûüûüûûüûýüûü üþûü üûýüýüû ûþüûûóüûüûüüûûüüûüûûüþûüüûþüûûüûûüûüûûøüûüûüüûüü ûþüûûñüûüüûüûûüûüûûüûûüüûûüüüûüûüüþûüüûþúûûþüûûüûüüûüûüüûùüûüüûüûûüúûüûüûüüþûü üûüýûüûûøüûûüüûûüüþûüüûûüûûüüþúû ûûüûûüûûüûþüûûüûûüüûüüüûüûüüþûüü ûþüûûþüûûýüûüüüûüüûûüõûüûüûüûüüûüüüûüüûûþüûûþüû ûü÷ûüûûüüûûüüûüþûüüûüþûúúûüüûüûûüûúüûüûüûûþüûûüþûüüþûüüûþüûûûüûûüûûüüûüûûöüûüûüûüüûüüþûüüûøúûúúûûúû ûüûûüûüûûüþûüüûüûüüûûüüûüûûüüúûûüúûúûûüúûüüûüûûüúûüüûûüüîûüüûüûüûûüüûûüûûúûûþüûûþüû ûüûüûûüûûüûûüøûüûüûüüûûúûþúûûþúûûüûþüûûöüûûüûüûüüûûüüûûüüüûüûüüþûüüýûúûûüúûúûûþüûûþüûûþüûûùüûûüûûüüüûüûüüûúûûüûüüûûüüûüûûóüûüûûüüûüüûûüüýûüûûüúûúûûüúûúû ûþüûûþüûûüüûüûûùüûüüûûüüþûüüûûúûûúûûú ûþüûûúüûüûüûûüüûüûüüýûüûûüúûúûüúûúûûþúûûüýûüûûüûüüûüûûùüûüüûüûûþúûûúúûúûúûûûúûûúûûûüûûüûûüýûüûûúùûúûúûúûûþúû ûþüû ûüûüþûüüîûüüûüûûüüûüûúúûûúûûúúûúûúûûþüûûþüûûïüûûüûüûüûüûüûüûüûûúþûúúûúûþúûûþúûûþüûûüûüûþüûûùüûüüûüûûþúûûúýûúûûþüûûüûþüûûüùûúûûúúûûúûþúûûúûûúûúû ûþüûûüûûüûûüûûüûýúûúúûþúûûþúûûþúûûþúû ûþüûûûüûûüûûòüûüûûüüûûúúûûúúûüúûúûûþúûûþúûûþüûûþüûûúüûüûüûûüüûûúúûöúûúûúûúûúûûùúûûúûúûûþúû ûøüûûüüûüûûþüûûûüúûûúúýûúûûþúûûüúûúû ûþúû ûüûúþûúúþûúúûúûþúûûúûüüûûúúûúúûúûûúûûüúûúûûüúûúûûüû úûýúûúúûþúûûþúûûþúûûúüûûüüúúþûúú÷ûúúûúûúúûûúûüúûúû ûüûü ûúþûúúûúûóúûûúûúûúúûúúûûþúûûþüúúûúüûúûúúûþúûûþúûûüúûúûûúûýüûúúþûúúþûúúûú÷ûúûúûúûúûûúûÿþ©ªª©ª«øª«ª«¬«¬««¬­®þ¯®®¯ù°¯¯°°¯°°±û°©©ª©©ªü©ª«ªª«¬ü«¬¬­­¬­û®­®­®®ü¯®®¯¯°ú±°°±±©©ª©ª«þ¬««¬ù­¬¬­­¬­­ý®­®®ì¯®¯¯®®¯¯°¯°°¯¯°°±°±©©úª©ª©©ªªý«ª««¬þ«¬¬­û®­®­®®¯ú®¯¯°¯°°þ±¨¨©þª©©ªû«ª«ª««ý¬«¬¬ò­¬¬­­¬­­®­®®­®®¯þ®¯¯°¨©ýª©ªªû«ª«ª««ý¬«¬¬­®¯°¨ý©¨©©ýª©ªªú«ªª«ª««¬­ü¬­¬­­ü®­­®®û¯®¯®¯¯ü°¯¯¨¨ý©¨©©ªý«ª«« ¬­ý®­®®ý¯®¯¯þ°¯¯ý¨§¨¨©þ¨©©ªú«ª«ªª««ü¬««¬¬­®­®¯þ®¯¯¨þ§¨¨©ýª©ªªý«ª««þ¬««ö¬«¬¬­¬­¬¬­­®þ¯®®¯ù°¯§¨¨§¨¨©þª©© ª«¬þ«¬ ¬­ü®­­®®¯§¨þ©¨¨©ªþ©ªªü«ªª««¬þ«¬¬ý­¬­­®¯ù®§§¨§§¨¨þ©¨¨©ªþ©ªª «¬ý­¬­­®­ú®­®¯¯®®§û¨§¨§¨¨ý©¨©©ªü«ªª««¬«¬­þ¬­­®÷­®®­®¯®¯¦¦ý§¨§§¨©þ¨©©ª«ôª««ª««¬«¬««¬¬­ø®­®­®®¯¦¦§¨ø©¨©¨©©¨©©ªþ©ªª«üª«ª««ý¬«¬¬­õ®­®­®®­®¦¦§§ý¨§¨¨ý©¨©©ýª©ªªý«ª««ý¬«¬¬ý­¬­­û®­®®¦¦õ§¦§§¨§§¨¨§¨¨©þ¨©©ªû«ª«ª««þ¬««¬ú­¬­¬¬­­®­¦û§¦§¦§§ý¨§¨¨ý©¨©©øª©ª©ªª«ªª«¬þ«¬¬ý­¬­­÷®­¥¥¦¦§¦§§þ¦§§¨þ§¨¨ý©¨©©ýª©ªª« ¬­ú®­¦¦¥¦¦§¨þ§¨¨©ªü©ª©ªªú«ª««ª««¬þ­¬¬ý­¬­­ý¦¥¦¦ü§¦¦§§¨ý©¨©©üª©©ªª«þª««¬­¥¦ü§¦¦§§¨§¨©þ¨©©ªü©ªª««¬þ«¬¬­¬ó­¥¦¥¦¦¥¥¦¦§§¦¦§¨û§¨¨©¨¨ý©¨©©ýª©ªªý«ª««¬þ«¬¬ú­¬¬­­¥¥¦ü§¦¦§§ý¨§¨¨©üª©©ªªû«ª«ª««¬ü­¬¬¥¥ý¦¥¦¦ú§¦§§¦§§ý¨§¨¨©þ¨©©ª«þª««ý¬«¬¬¥þ¤¥¥¦þ¥¦¦ü§¦¦§§¨þ©¨¨©úª©©ª©ªªý«ª««ý¬«¬¬û«¬¥¤¥¥¦þ¥¦¦§¨©¨© ª«þ¬««¬¤û¥¤¥¤¥¥¦§¦§ù¨§¨§¨§¨¨ý©¨©©ýª©ªªû«ª«ª««ö¬««¬¤¤¥¤¤¥¥ý¦¥¦¦þ¥¦¦§þ¦§§÷¨§¨¨§¨¨©¨¨©ª©ªþ«ªª«ü¬«£¤¤ý¥¤¥¥ý¦¥¦¦§þ¦§§ ¨©ªþ«ªª«þ£¤¤þ¥¤¤¥¦¥ý¦¥¦¦§û¦§§¦§§¨©ü¨©¨©©ªþ©ªª«£ú¤£¤¤¥¤¤¥¦ü¥¦¦§§þ¦§§¨ô©¨©©¨¨©ª©ª©ªª«ª«¤þ£¤¤¥ù¦¥¦¥¦¥¦¦§¦§¨©þ¨©©úª©ª©©ªªó«ªª««££¤££¤£¤¤û¥¤¥¤¥¥¦þ¥¦¦§þ¦§§¨§¨þ©¨¨©úª©ªª©ªª«þ¢££ü¤££¤¤¥ý¦¥¦¦ù§¦§§¦¦§§ú¨§§¨§¨¨ý©¨©©ýª©ªªõ«ª«££¢££¤£¤¤ ¥¦§ù¦§§¨¨§¨¨ù§©¨¨©¨©©ªþ©ªªþ«££ù¤£¤£¤£¤¤¥¦¥¦§¦§÷¦¨§§¨§¨§¨¨ý©¨©©÷ª©©ª©ªª¢££þ¢££¤¥¦þ¥¦¦§ú¨§§¨§¨¨©ùª©ªª¢¢££þ¢££ý¤£¤¤¥ý¦¥¦¦ §¨©ª¢ý£¢££þ¤££û¤£¥¤¥¥þ¤¥¥¦§¦§þ¨§§ý¨§¨¨©þ¨©©ª©ü¡¢¡¢¢£¤ü¥¤¤¥¥ ¦§þ¦§§ü¨§§¨¨©þ¨©©úª¡¢¢¡¢¢ý£¢££¤ø£¤¤££¤¤¥¥þ¤¥¥ú¦¥¦¦¥¦¦§þ¦§§þ¨§§¨ý©¨©©¢ú¡¢¢¡£¢¢ü£¢¢££ý¤£¤¤¥¦ü¥¦¥¦¦ý§¦§§ü¨§§¨¨©þ¨©©¡ý¢¡¢¢£ü¤££¤¤¥û¦¥¦¥¦¦§ý¨§¨¨©¡¢£¢£¤¥¦§þ¦§§ù¨§¨¨§§¨¨©ý¨ ¡¡¢þ¡¢¢£¤þ¥¤¤¥¦§þ¨§§¨þ©¡¡¢£¢£¤þ£¤¤¥þ¤¥¥ý¦¥¦¦§þ¦§§þ¨§§¨ ¡¢þ¡¢¢ü£¢¢££þ¤££¤ü¥¤¤¥¥¦§¦§þ¨§§¨ü ¡ ¡¡¢£¢£¤þ£¤¤¥ü¦¥¥¦¦ü§¦§¦¦§ø¨§¨§¨¨§  ¡¢û¡¢££¢¢£¤ü£¤¤¥¥þ¤¥¥¦ý§¦§§û¨§¨§  ¡ý¢¡¢¢£ö¢££¤¤£¤££¤¤¥¦¥¦þ§¦¦ý§¦§§þ¨  ý¡ ¡¡ô¢¡¢¡¢¢£¢¢£¢££ü¤££¤¤þ¥¤¤ý¥¤¥¥¦§þŸ  ý¡ ¡¡ý¢¡¢¢£¢£þ¤££ý¤£¤¤¥¦¥¦ü§¦¦§§Ÿ ¡þ¢¡¡¢£¢£þ¤££¤¥þ¤¥¥þ¦¥¥¦§úŸ  ŸŸ  ü¡  ¡¡ü¢¡¡¢¢ý£¢££ ¤ý¥¤¥¥þ¦¥¥¦þ§¦¦þ§ŸŸý Ÿ  û¡ ¡ ¡¡¢ý£¢££þ¤££¤ý¥¤¥¥¦þ¥¦¦ù§¦¦§¦§ŸŸú Ÿ  Ÿ  õ¡ ¡ ¡ ¡¢¡¡¢¢ý£¢££ý¤£¤¤¥þ¤¥¥û¦¥¦¥¦¦þ§ŸŸþ ŸŸ ¡û¢¡¢¡¢¢ü£¢¢££ ¤¥ú¦¥¥¦¥¦¦žýŸžŸŸ ¡¢þ¡¢¢ý£¢££¤¥þ¤¥¥þ¦¥¥¦žüŸžžŸŸ ¡¢þ£¢¢£¤ü¥¤¤¥¥÷¦¥¦¦žžŸžŸŸþžŸŸ ÷¡ ¡ ¡¢¢¡¢¢£¢£ù¤£¤£¤£¤¤¥þ¦¥¥þ¦žžýŸžŸŸþ ŸŸ ¡ü ¡ ¡¡¢þ¡¢¢£þ¢££¤þ£¤¤ü¥¤¤¥¥¦ûžžŸžžŸú Ÿ ŸŸ  ¡¢þ¡¢¢£¤£¤¥¤ý¥¦¥¥ý­¬­­ý®­®®þ¯®®ü¯®®¯¯°û±°±°±±þ²±±ò²±±²³³²²³²³³´³³ú´³´´¬­­®þ­®®¯ý°¯°°±þ°±±ü²±±²²³÷²³³´³´³¬­­ú®­®®­®®þ¯®®¯ü°¯¯°°ü±°°±± ²³´ú³¬­­¬­ ­®ý¯®¯¯°þ¯°°ü±°°±±þ²±±²þ±²²³ý´³¬¬­¬­ø®­­®®­­®®ý¯®¯¯ü°¯¯°°±²³ü²³´¬¬ü­¬¬­­ý®­®®þ¯®®¯°þ¯°°±ú²±±²±²²ý³²³³«¬ý­¬­­ü®­­®®¯þ°¯¯°þ±°°±þ²±±ý²±²²ø³²³³«¬«¬¬­ý®­®®û¯®¯®¯¯°ý±°±±þ°±±²³þ²««ý¬«¬¬­þ¬­­þ®­­õ®­®®¯®®¯¯®¯¯°þ¯°°±ý²±²²³û«¬¬«¬¬­þ¬­­® ¯°ý±°±±ý²±²²þ³««ý¬«¬¬­ý®­®®¯þ®¯¯°þ±°°±ý²±²²«ô¬««¬¬«¬­¬­¬­­®þ­®®¯þ®¯¯þ°¯¯°ú±°°±°±±²û±²±²««þ¬««¬­¬­û®­®­®®¯û®¯¯®¯¯ °±²þ±²²«þª««¬ý­¬­­þ¬­­þ®­­®þ¯®®¯°þ¯°°ü±°°±±²þ±ªª«÷¬««¬«¬¬«¬¬ú­¬­­¬­­®¯®¯þ®¯¯°¯°û±°±°±±þ²ªª«¬ù­¬¬­¬¬­­ø®­®­­®­®®ý¯®¯¯ü°¯¯°°±ý²±ªª«þª««¬­®þ­®®¯þ®¯¯û°¯°¯°°ü±°°±±þ©ªªý«ª««¬­þ¬­­û®­®­®®ø¯®®¯®¯®¯¯°ú¯°¯°°±±þ©ªª«¬«¬­ ®¯ú°¯°°¯°°ý±°±±ýª©ªªû«ª«ª««¬þ«¬¬­¬­ý®­®®û¯®¯®¯¯°þ±°°©ªþ©ªª«ª«¬þ«¬¬÷­¬¬­¬­­®­­®þ­®®¯ý°¯°°©üª©©ªªý«ª««¬þ­¬¬­ü®­­®®¯ù°¯¯°¯¯°°þ±©©ª«ý¬«¬¬­û®­®­®®¯ý°¯°°©ýª©ªª«¬«¬ü­¬¬­­ü®­­®®¯°¯°ý©¨©©ªþ©ªªú«ªª«ª««¬«¬ ­®ý¯®¯¯°¯©þ¨©©ª«ª«ý¬«¬¬­û¬­­¬­­û®­®­®®¯ü®¯®¯¯°û¨©¨¨©©üª©©ªªü«ªª««ý¬«¬¬­ý®­®®¯þ®¯¯þ¨©©¨©ª«üª«ª««ý¬«¬¬­þ¬­­û®­®­®®¯þ®¯¯þ°¨¨þ©¨¨© ª«¬«ý¬«¬¬­ü®­­®®¯ò®¯¯¨§¨©¨©¨©©¨©© ª«ý¬«¬¬­þ¬­­ý®­®®þ¯®®¯ý¨§¨¨©¨©ýª©ªªý«ª««¬­¬­®­®¯û®¨¨§¨¨ ©ýª©ªªþ«ªªý«¬««ý¬«¬¬ý­¬­­ý®­®®¯ü®§§¨¨þ©¨¨©ûª©ª©ªª«þª« «¬ý­¬­­ü®­­®®§¨§¨©ªþ©ªªú«ª««ª««¬ý­¬­ ­®þ¯§§þ¨§§¨©þ¨©©ýª©ªªý«ª««¬­þ¬­­ú®­­®­®®§ý¨§¨¨©üª©©ªªþ«ªª«ü¬««¬¬­ü®­­®®¦§ü¨§¨§§¨ú©¨©©¨©© ª«¬þ«¬¬ü­¬¬­­þ®­­þ¦§§ú¨§§¨§¨¨ú©¨©¨¨©©ªþ«ªª«þ¬««¬­ý®­¦¦§þ¨§§¨ú©¨¨©¨©©ªþ©ªªþ«ªª«ý¬«¬¬­¦ú§¦¦§¦§§¨ü©¨¨©©þª©©ªþ«ªªý«ª««¬û­¬­¬­­¦ü§¦¦§§ý¨§¨¨ø©¨¨©©¨¨©©üª©©ªª«þª««¬û«¬­¬­­þ¥¦¦§þ¦§§¨©ª©ªü«ªª««ý¬«¬¬­þ¥¦¦ý¥§¦¦§û¨§¨§¨¨©ýª©ªª«þª«« ¬­ò¬¥¦¥¦¥¦§§¦§¦¦§§¨ü©¨¨©©ûª©ª©ªª«þ¬««¬ü­¬­¥¥ý¦¥¦¦§¦§ ¨©÷ª©©ªª©©ª««ûª«ªª««¬ö¥¦¥¥¦¥¦¥¥¦¦þ§¦¦§¨ý©¨©©þª©©ªô«ªª«ªª««¬¬«¬¬¥¦þ¥¦¦ù§¦¦§¦¦§§¨þ§¨¨ ©ªý«ª««¬þ¤¥¥þ¦¥¥¦ §¨û©¨©¨©©ªþ©ªª«¬þ«¥¥¦ü§¦¦§§ú¨§¨§§¨¨©þ¨©©ªþ©ªªý«ª««¬ü«¬¬¤¤¥ý¦¥¦¦ú§¦§¦¦§§¨ø©¨¨©¨©¨©©ýª©ªªü«ªª««¤ ¥ý¦¥¦¦ú§¦§¦¦§§ü¨§§¨¨ü©¨¨©©þª©©ªþ«ªª«¤¥þ¤¥¥ï¦¥¥¦¥¦¥¦¦§¦§¦§§¦§§¨þ§¨¨ü©¨¨©©ªþ©ªªý«ª««¤ü¥¤¤¥¥ó¦¥¦¦¥¦¦§¦§¦¦§§ ¨©ª«þ£¤¤ ¥¦§þ¦§§¨§¨©ª«¤þ£¤¤ù¥¤¤¥¥¤¥¥¦ù§¦§§¦¦§§ý¨§¨¨û§¨¨©¨¨©ª©ªý«ª««þ£¤¤¥þ¤¥¥¦þ¥¦¦ú§¦§¦¦§§ý¨§¨¨ý©¨©©ª«ª£ü¤££¤¤¥ý¦¥¦¦û§¦§¦§§¨§¨©ªþ©ªªý«ª££ý¤£¤¤ ¥ý¦¥¦¦§þ¦§§¨þ§¨¨©ùª©©ª©©ªª£ù¤££¤££¤¤ü¥¤¤¥¥ò¦¥¥¦¥¦¥¦¦§¦§¦§§ý¨§¨¨ý©¨©©ªþ©ªªþ¢££ý¤£¤¤¥û¤¥¥¤¥¥þ¦¥¥¦ú§¦§¦¦§§¨þ§¨¨ö©¨©¨©¨©©ª©©üª©£¢¢£¤ù£¤¤¥¤¤¥¥þ¤¥¥ý¦¥¦¦þ§¦¦§þ¨§§¨û©¨©¨©©ûª©¢¢££þ¢££¤þ£¤¤¥þ¤¥¥þ¦¥¥¦§þ¦§§¨ü©¨¨©©ûª©ªª¢¢£þ¢££þ¤££¤þ£¤¤¥þ¤¥¥ ¦§¨©þ¨©©¢ £¤ý¥¤¥¥¦û¥¦¦§¦¦§ù¨§¨¨§§¨¨©þ¨©©ýþþýýþþýýþòýþþýýþýþþýýþýþþýýþýþþýüüýüýýþþý ý÷þýþýþýþþýýþûýþþýþþþýþ þþüýýöþýþýþýþýþýýþþýýþþýþþ÷ýþþýýþþýþþúýþþýüýýüýþýþþýýþþýýþýþþýþþþýþþýýüýýþüýýþüý ýþþýýþþýýõþýýþýþýýþþýýúþýþþýþþþýþþþýþþúýüýüüýýþüýýûþýþþýýþýþþýþþþýüüýûüýüüýýþüý ýöþýþýþýþþýþþýþþýýþùýþþýýþýýöüýýüýýüýüý ýþþýýþþýýóþýþýýþýýþþýýþ þøüýýüýüýüüýþüýýòþýþýýþýþýþýþýþþýþüýþþýýüüýýüüýýüýýþüýþýþþýüþýýþþýûþýýüýýþüýýþüýýþþýýþýýþýýþþýýþýþøýþþüýüýüüýüüýýüü ýóþýþþýýþýþýýþýýûþýýþýýùþýþþýýüüýìüýýüýüýýüüýýüýýüýýüý ýþþýýþôýþþýýþþýýüýüüýýüýýþüýýþüýýüþýþý ýýþýþþòýþþýüýüýüýýüüýýþüýýþüýýþüýýýþýþþýöþýþþýþýýþýýöüýýüüýýüüýýþüýýùüýüýýüýýþþýýþêýþýþýýþþýýþþýüýýüýüýüýýüýýüýýúüýýüüýýþüýýþþýýúþýþýþýýúþýþýþýýúþýþýýüüýýüýýþüýýüýúüýýüüýýþüýýüþýþýýþôýþýþýþýýþþýüüýþüýýüýüüýüýýþþý ýñþýþýþþýþþýþþýýüüýûüýüüýýúüýýüüýýþþýýþþýýþþýýùþüýüýýüüýøüýüýýüüýýüýþýþýþüýüõýüýüüýüýüüýýþüýýþüýýþüýýþþýýþýüûýüýüýýüýýüýýüñýüýüýüýüýýüýýüýýþýþþýýûþüýýüüýüúýüýýüýýþüýýþüýýþüýýþý üñýüýüýüýýüýýüýüýýûüýýüýýþüýýþüýýþþýþþþýüüýüûýüüýüüýýüýýüüýüýýýüýüüýþþýýþþýýüøýüýüüýýüüýûüýüüýýóüýýüýüýüüýýüýýüüýýüüýüþýüüüýüýüüýüýùüýýüüýüüýüþýüüüýüýüüý÷üýüýüýýüýýþüýýüýüüýüýüüûýüüýüüýþüýýþüýýþþýýþþüüùýüýüüýüüýüýüøýüüýüýüýýþüýýþþýýüßýüüýüýýüýýüüýüüýýüýýüýüüýýüýýüýüý ýþüýýýþýüüþýüüùýüüýüýüüþýüüýýüý ýüýþüýýþüý ý üûýüüýüüþýüüýüýüýþüýýùüýýüýüýýü ýüøýüýüýüýüüýüýýüýýüýüþýüüðýüüýýüýüüýýüýýüýýûüýýüýýüýüüýüýüüýüýüýóüýüýüýüýüüýüýýüüýüýýüüýüýüüþýüüýìüýüýýüüýüýýüüýüýýüýüüýþüýýüþýüüþýüüõýüýýüüýüýüýýúüýýüüýýûúüûüüûüüþýüüýüþýüüýüúýüýüýüüýûüýýüýýþüýýûüüûûüüûýüüýüüýüýüþýüüôýüýýüüýüýüüý ýûüý üýüýýüýýùüýýüýýüüýüþûüüþûü üýýüýýüþýüü÷ýüüýüýüüýýüýþüýýüþûüüý üþýüüýüüýüüýýýüýüüýüüýýüüþûüüõýüüýüüýüýýüü÷ýüýýüýüüýýüûüþûüüþûü üþýüüýñüýüüýüýüüýüýüüýýùüýüýýüýýþûüüüûüûüüôýüüýüýýüýüüýýüøýüýüüýüýýûüýýüýýøüýüûüüûüüüûüûüüüýüýüüþýüü÷ýüýýüýýüýýüüýüýýûüþûüüþûüüùýüüýüýüüýýüýýüøýüüýýüýüüøýüûûüüûüüûüüûüûüüþýüüþýüüýüýü÷ýüýýûüüûüüúûüûüûü üýþüýýüýûöüûûüüûüûüûûùüûûüûûüüþýüüúýüýüýüüûýüýýüüûýüûûüüûüûüþûüüþýüüýüóýüýüüýüüýýüûüüûýüûüüùûüüûüûüüþûüüýüðýüýýüýüüýûûüüûüûûûüûüûüüþûü üùýüýüüýü üýüýûûüüûüü÷ûüûüûüüûüüýüþýüü÷ýüüýüýüüûûüøûüüûüüûüüýûüûûüüýüýüüûýüüýüüýúüýûüûüüûüüûüûüüüûüûüüþýüüþýüüþýüüýüûüøûüüûüûûüüøûüüûüûûüüþýüüóýüýüüýüüýýüýûûüýûüûûýüûüüüûüûüüüûüûüüûýüüýüüýüûýûûüûûüûûüüûüüûüþûüüþýü üýýüýûûüûüýûüûûýüûüüþûüüþûüüøýüüýüüýüüýûüûûþüûûþüûûüþûüüôûüûüûüüûüüûüüýýüýýûíüûûüûüûüûüûûüûüûüûüüùûüüûüûüüûýüûü üûýüüýüüþýüÿ±ü²±±²²³-±ù²±²±²±²²³-þ°±±²±²ý³²,°±ý²±²²ý³²,°ü±°°±±ý²±²²-°±þ°±±û²±²±²²-°ý±°±±ü²±±²²-¯°±þ°±±þ²±±-û°¯°¯°°±²-¯°±þ°±±-°ø¯°°¯°°±°°±-þ®¯¯°ü±°°±±-¯þ®¯¯°û±°±±,û®¯¯®¯¯û°¯°¯°°þ±,®¯ý°¯°°þ±,ý¯®¯¯ý°¯°°-®ý¯®¯¯°-þ­®®ø¯®¯®¯¯°¯¯ü°¯°,þ­®®¯® ¯-­®þ¯®®¯û°¯°¯,û­®®­®®¯-­®¯-­®þ­®®¯-­®ô­®­®¯®®¯®¯¯,­®¯-õ¬­¬­­¬­­®­®®ý¯®,¬­ý®­®®-ý¬­¬¬­®-¬­®þ­®®-¬­ú®­­®®,þ«¬¬þ«¬¬ý­¬­­ý®­,«¬ö­¬­¬­­®­®,ø¬«¬««¬«¬¬­ü¬­¬­­-«ý¬«¬¬­¬­-«ý¬«¬¬þ«¬¬­-ü«ªª««¬­þ¬,þª««¬ú«¬­¬­,öª«ª««ª««¬««¬-ü«ªª««þª««ú¬«¬¬«¬¬-ª«þª««û¬«¬«¬¬-þ©ªªý«ª««þ¬««þ¬,ü©ª©ªª«þª««û¬«¬¬,üª©©ªª«ª«¬þ«,©þª©©ª«-©ªþ©ªª«-þ¨©©ªþ©ªªü«ª«,ý©¨©©ûª©ª©ªªù«ªª«ª«,û¨©¨¨©©ªü«ªª,¨ý©¨©©úª©ª©©ªªþ«,¨þ©¨¨©ª©ª-¨ù©¨©¨©¨©©ª-¨©þª,þ§¨¨ü©¨¨©©ýª©,󨧨¨§¨¨©¨¨©¨©©þª,§¨ý©¨©©-§ò¨§§¨§¨§¨©¨©¨¨©©-§ý¨§¨¨©ý¨©,ý§¦§§ü¨§§¨¨©-¦§ý¨§¨¨ü©¨¨,ú¦§§¦¦§§û¨§¨§¨¨-¦§ý¨§¨¨-¦ý§¦§§ø¨§¨¨§¨¨,¦§¦ù§¦§¨§§¨¨-¥¦§þ¦§§ü¨§§,´µþ´µµ¶þµ¶¶þµ,þ³´´ýµ´µµû¶µ¶µ,´µþ¶,þ³´´þ³´´µþ´µµ-ú³´´³³´´µþ´µµ-³´þ³´´ýµ´µµ-³´þµ´´µ-³´þµ´´-²³ü´³³´´ûµ´µµ,û²³³²³³´-þ²³³þ´³³ú´³´´µ,ý²³²²³þ´³³´ý³´,²³þ²³³û´³´´,²³û´³´´,²³ü²³²³³þ´,±²ú³²²³²³³ý´³,±²þ±²²³þ²³³-±²ý³²³³-±û²±²±²²ü³²²³³-±ý²±²²³²þ³,þ°±±ü²±±²²-þ°±±þ²±±²-ü°±°±±ý²±²²þ³,°±²-°±ü²±±²²-°ú±°°±°±±ü²±±,󰯯°°±°°±±°°±±þ²,¯°õ±°±±°±±²±±,¯ý°¯°°±-¯ý°¯°°û±°±±,¯þ°¯¯°±°±- ¯°±þ°,®¯þ°¯¯°þ±,ü¯®®¯¯°þ¯°°-ú®¯®¯®¯¯ý°¯°°-®ü¯®®¯¯°þ¯°°-®¯°¯-®û¯®¯®¯¯û°¯¯°,þ­®®ü¯®®¯¯ý°¯,­®ü¯®®¯¯-­ ®ü¯®®¯¯-­®¯®¯-þ¬­­ý®­®®¯-ý­¬­­ü®­­®®-­þ¬­­®ü¯®®,ú­¬­­¬­­ý®­®®þ¯,¬ý­¬­­ú®­®®­®®-¬ý­¬­­®-þ«¬¬ù­¬¬­­¬­­®-«¬­þ¬­­ý®­,¬ö­¬­¬­­®­­,¬ö«¬«¬­¬­¬¬­­ý®­,«¬ü­¬¬­­-«¬ý­¬­­þ¬,«ü¬««¬ ¬-ùª««ª«¬««¬­-ª«¬­þ¬,ªü«ªª««þ¬««¬-ªý«ª««þ¬««¬-ª«ª«¬-þ©ªªý«ª««ú¬««¬«,©ªý«ª««ý¬«,©ýª©ªª«þ¬,©ªø«ª««ª«¬,þþÿþþûÿþÿþ,þýþþ-þýþþ-þýþ þýÿþ, þûÿþþÿ,þþýþþþýþþ-þýþþ-þþýþ þ-ùýþýýþýþ þ-úþýþþýþ þ-þþýýýþýþ þ-þýþþýþþ-þûýþþýþþ-ýþþýþþýþ-÷ýþýýþýþýþþùýþþýþþ,ýýþýþ þ-ûýþýþýýþþýýþ-øþýþýþýýþþûýþþýþþ-öýþýýþþýýþýýþûýþýþ,þýþþýþýûþýýþ,ýþýþýþþý,þöýþþýþýýþýþþý-ûýþýþýýýþýþþþýþþ-ýùþýýþþýþþ-þþýýûþýþþýýüþýþ,þþýýþüýþýþþûýþþý,ýïþýþþýþýþþýýþýþýþ,ýýþýýþýþþýýþ-ýøþýþýþýþýýþþý,ýøþýþþýþþýýýþý,ýþþýýôþýýþþýþýýþþ,ýþþýýþþýýþýþ-ýþþýýþûýþýý,ýüþýþýýþýýþý, ýýþýþþ-ýþþýýþýþþý, ýûþýþý,ýþþýýþþ, ýþúýþýýþ, ýûþýþþ,ý-ýþüý ý-ýýþý,ýüýþþýý-ýþþ,þüý ýþüýý-ûüýýüýýûüýýüýý- ýþüýý-üý-ýøüýüýýüüýý- ý÷üýýüýýüý,ýüýüýüýü-ýüüýüýýþüýýþü,þüýýúüýüýüýýüþý,üýüüýýûüýýüýýþüýý-üýüýüüýþüýý-üüýüýýþüýýýüý,õüýýüýüüýüüýý-üýüüýýüüý-÷ýüýüýüýýüüüýüýüü-ýüýþüýýüüýý,üüýüüýýõüýüýýüüýýü,üüýüýüüüýüüýýüþý,ûüýüüýýüý-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-€€€€+ýedeefgfþg*ûdeedeeüfeeffgýfg*ûdeedeeófeeffeffggfg*deüdeeffþeff+def+deúdeeffeef+ûdcdcddeþdeef+þcddüeddeefþe*þcddùcdcdedeefþe*cúdcdccddüeddee+cdþcddþedde+bcþdccdeýde*þbccdþcddúedede*bûcbcbccdcde+bcþbccýdcddýed*þabbýcbccdþcdd+bcdûcdcd*bcd+aýbabbücbbccýdc*aýbabbcýdc*abþabbücbbccd+abþabbücbbcc+þ`aabþabbûcbcc*aöbabbabcbbcc+`abþabb+üa``aaü`abaab+`abýcb*`þa``ýa`aabab+_`ýa`aaba+_`ab+ü`__``þa``aþb*_`þ_``aü`a`aaþb*_þ`__`aþ`aa+_`þ_``þa``þa*_þ^__ `+_^_`þ_``+^_þ^__ý`_``þa*^_`a+þ]^^_`+^þ_^^_ø`_`_`_`*]^_þ^__`+^þ]^^_þ`__+]^þ]^^_+]ý^]^^þ_^^_+ý]\]]ý^]^^ü_^^__+]þ\]]^]^_+]\]ú^]^^]^^+û]\]\]]^_+\ü]\\]]þ^]]^+\]\]ù^]]^^_*\ü]\\]]^+[\û]\]\]]^+û[\[[\\]û\]]\]]ý^]*[\ý]\]]þ^*[û\[\[\\]\]þ^*[ýZ[\\þ]\\]+Z[\þ[\\ü]\]*ó[ZZ[Z[[\[\[[\\ý]\*Z[\ü]\\*þYZZø[Z[\\[[\\+Z[\û[\[\*Z÷[ZZ[Z[[\[[\þ[*þZYYýZ[ZZ[øZ\[[\[[*YZý[Z[[+þlmmnþmnnoþn*lmûnmnmnnüonn*þlmmlmnmnþo*þkllümllmmþnmmn+lmþlmmønmnnmnn*klýmlmmýnmnn+ýlkllümllmmþn*þkllþkllmþn*kýlkllümllmm+þjkklm+ýkjkklümllmm+jkþlkklm+kþjkkþlkklm+jýkjkkülkkll+jþkjjkýlkll+jkølkllkll*ýjijjkýlkll+þijjkl+ûjijijjýkjkkl+iüjiijjkþjkkýlk*iþjiijýkjkk+ijijkjþk*hiüjiijjk+ühihiijþijjk+h ijükjk*h ijþijjþk*hüihhiijiýjijj+h ij+ghýihiiýjijj+g÷hghhiihhiiüjij*ghûihihiiþjii+ghþghhýihiiýji*g hi+g hi+fghþghhi+gþfggþhgghi+ûgfgfggühgghhþi*ùfgffgfggh+fgh+fõgfgffgghgghh+þeffgþfggýhghh+üefeffgýhghh+þeffþeffgh+eýfeffgþfgg+eþfeefügffgg+üeddeefg+efefgf+efef+deùfeefeeffþg*deþdeeýfeffþg*dedûefeeff+dûededeeûfeef*dþcddeþdeef+dcdef+dcdûededee+úcddccdde+cdûcddcdde+cdþcddýed*þbccdþcddeþd*bcýdcddþe*cbcýdcdd+bcþbccþdccdþe*þabbc÷bcdccddcdd+b÷cbccbcddccd+óûôóôôóóýôóôôýóô*óôóøôóóôôóô*óûôóôó*óþôóóúôóôóóôôþó*óûôóóôóóþôóóþô*óþôóóô+óþôóóûôóóô* óþôóóþô*óþôó óôó+óøôóôóôóôóó+ óþôóóýôó*óþôóóþôóó+óôþó*óþòóóþôóó+þòóóýôó*óþòó óþôóó+þòóóôþó*óþòó ó+øóòóóòóòó ó+ó+ýóòóóòó+þòóóò ó+ûóòóòóóþòó ó+þòóóøòóòòóóòóó+óòóþòóó+óûòóòòó óýòó*ýóòóóüòóòóóòó+üòóóòòóûòóóòóó+òóòóüòóòóó+þóòòþóòòóòùóòóòóó*òõóòóòóòóòóóòòüóòó*óòúóòóòòóó+üòóóòòüóòòóóüòóòóó+òóûòóòòóóûòóòò*òüóòóòòóþòóó+òóðòóòóòòóóòóòóóòò*óòøóòóòóòòóóòýóò*ýóòóóþòóóòùóòóóòó*ûóòòóòòóòóüòóó*òóòóòúóòòóó* òóøòóòòóóò*òüóòòóóüòóóòò+òþóòòóòýóò*òûóòóóòòó÷òóòóòòóó*òþóòòüóòóòò+ òóýòóòò+ýòóò òþóòò+òþóòòúóòóòóòò+ òþóòò+òþóòòþóòò+òþñòòþóòòó+ýòñòòþóòòüóòó*òüóòò*òýóò*þñòò+þñòò+ñò+òúñòòññò ò+ñòþñò ò+þñòòüñòñò ò+òþñòò+ûòñòñòòþñòò+òþñòòþñòò+òþñòòþñò ò+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿgþhgghùihhiijiijúkjjkjkklþkllmnmnþmnnoghüghghhijkújklkkllmþnmmnýofgg hiýjijjükjjkklklýmlmmnúofgffgghiüjiijjùijjkjjkklþkllýmlmmnúoffgfggýhgh hiüjiijjûkjkjkklþkllmlmýnmnnfýgfgghúihhihiiýjijjkþjkkûlklkllmlømlmmnnmnnfgþhggýhghhiõjiijiijkjkjjkýlkllûmlmlmmünmmffgþfggýhghhijþijjkúlkllkllmlmfýgfgghøghihiihiiójiijijjkjkjjkklùmlmlmlmmefgühgghhúihhihiijüijjkkjkýlkllmþeffúeffgfgghþghhiþhiijþijjklþkllmlümlmeefþeffýgfggýhghhüihihhûijijiijýkjkklükllmmeþfee fgýhghhiühihiijijkûlklkllúmlmmdeeýfeffýgfggþfgghijûkjkjkklþkllþdeeýfeffghþghhþihhýihiiýjijjkþjkklkleüfeeffghþghhüihhiijþijjkþjkklüeddeeùfeeffeffgþfggýhghhýihiiþhiiýjijjúkjkjjkkùlklkllddýedeefghiþhiiújijiijjkùlkklkkddefgþfggýhghhiþhiij kdefûeffeffghgýhghhüihhiijùijijjkjjkýlkddþcddeþdeeýfeffgfghüghghhýihiiýjijjkøjkjkkdcdd efghijijøkjkjjkkccdeýfeffûeffgffgùhgghhghhýihiijkcdþcdd efúgffgfgghþghhûihihiijkcdüeddeefüefeffgúhgghghhúihiihiijijükcbccdþcddefgüfgfgghiûhihhiiýjijjþkbbýcbccdüeddee fghghüihhiiþjiijbcbcúdccdcddefgúhghhghhiújiijjbbcýdcddefþeffügffgghýihiiûjijjbbcþdccdüeddeeüfeeffgúhgghghhüihhiiþjbbcþbccdcdýedeefþeffgþfggýhghhúihiihiiþabbúcbccbccdcdýedeeüfeeffgþhgghiabþabbcþbccýdcddýedeefùgffggfgghþghhiabûabbcbbcdeüfeeffýgfgghiababëcbcbccbcdcdccddcdeedeefþeffþgffgþfggühgghhüia`aabcüdccddefgfghýi`aaübaabbþabbcþbccdcdûededee fghþi``abcúdcddcddeýfeffgóhgghggh`a`a`aaübaabbcýdcddþcddeþfeeüfeeffýgfggh`abþcbbøcbccdccdd efýgfggh`þa``a÷babbabbcbbcdeþdeeüdfeffgþfgg`þ_``aýbabbcdòededeedeefefeff g_`þa``aýbabbûcbcbccýdcddüeddeeýfeffgþfggýh_``þ_``üa``aaúbabbabbücbbccdþcddeúfefeeffûgfgfggü`__``þ_``abýcbccþbccüdccddedeûfefeffg_`þa``abcüdccddeþdeeüfeeffüg_^__`ýa`aabúababbc cdýedeeýfeffg_`þ_``ýa`aaýbabbcùbccdccd defþg__þ^__þ`__`þ_``aþ`aaýbabböcbcbbccdcddeúfefef^^_`abýcbccýdcddþeddef^û_^_^__`ýa`aa býcbccýdcddefþe^^ý_^__ý`_``ûa`a`aaýbabbcdeüdedeeþf^^_þ^__`þ_``abýcbccýdcd deþf]]^ý_^__ý`_``abþabbcdcdýedeeûf]]^]]^ü_^^__`þ_``ýa`aab cýdcdde]^]^_ý^_``ü_`_``ýa`aaýbabbcþbcc de]^_û`_`_``aûbababbcýdcddeþd]]ú^]^^]^^_`ýa`aababøcbbccbbccýdcddüedd]]ü\^]^^þ]^^_ü^_^__`øa``a`aabbabýcbccdþ\]]ý^]^^_þ^__`a`ababýcbccûdcdd]]\]ü^]]^^ö_^_^__`__``ûa`a`aabcbcd\] ^_`ü_`_``abcüdcd\\ý]\]]þ^]]^_þ^__ú`__`_``úa`a``aabûabaabbcýdc\\ý]\]]^_^_`ü_`_``ýa`aa bcþnooþpoopqþpqqþrqq rstúuttutuuvoþnooüpooppýqpqqrþsrrstþsttuþvuunoþnoopopüqppqqýrqrrýsrsststþuttuùvnnonnooûpopoppúqpqppqqýrqrrûsrsrssýtsttutunopqpqýrqrrýsrssùtsttssttýutuuývmnnopþoppqrstþsttuþtuunoþnoopþoppqürqqrrsýtsttutûunmmnnúonoonoopøqpqpqqpqqrýsrssøtstsststtüuttmmnýonooüpooppqþpqqúrqqrqrrsþrsststþummünmmnnoþnoo pqþpqqrsrstþummnüonnooûpopoppqûrqrqrrúsrssrssþtsstmýnmnnopqþpqqrûsrsrsstùstsstlmmnüonnoopqþpqq rsütstllmþnmmnopopýqpqqýrqrrsþrssötsttmlmmlmmnüonnooûpoopoopqþrqqrþsrrsûtsstllmûnmnmnnþonnopopüqppqqrüsrrssýtsllùmllmmlmmúnmnnmnnüonnooønooppooppqþpqqûrqrqrrüsrrsslmnþmnnoþnoopùqppqqpqqûrqrqrrùsrsslkllmülmmnnþmnnonoýpoppqrqrûsrsskklúmlmlmllømnmmnnmnnüonnoopþopp qrþqrrklþkllýmlmmýnmnnýonoop÷qpqppqqpqqrþsrròlkllklkllmlmmllmnonoýpoppqrklùkllklmllmnúononnoopöoppqppqppqqrþjkkýlkllmõnmmnmnnonnooüpooppþoqqpùqppqqrqqrklþkllümllmmýnmnnüonnooýpoppþqppüqppqqrýkjkklþkllmýnmnnþonnoþpoopqpqþpqqrjkþjkkýlkllmnþmnnoúpoppoppqþpqqúrqjkjkkýlkllýmlm mýnmnnýonooûpopoppqjúkjkjjkklklümllmmnüonnooùnooppoppqþpqqþijjþkjjklklmlûmnmmnnþmnnþonnoûpopoppqüpqqjjkþjkkölklmllmmlmmûnmnmnnoþnooþpoopûqjjijjklümllmmýnmnnonopþoppüqiijj klþkllmýnmnnoþnooûpopoppþqiiýjijjúkjkkjkkúlkllkll mnúononnoopopùoppqhijjijkþjkkùlkkllkllúmllmlmm nopiújijjijjýkjkkþjkklþkllúmlmmlmmnýonoopéoppiihiijijijjiijjkkjjkkýlkllýmlmmþnmmnýonoo÷popoopihiiújijiijjklmnþmnnoþnoopûoihhiiújijjijjkþjkklmþnmmnohiþhiiüjiijjþijjókjkjjkklklkkllþmllmýnmnnøonooppghhiþjiijkújkjkjkkýlkllýmlmmünmmnnøonnoonohhiþhiijkþjkkþlkklmþlmmnþonnüogghhýihiiýjijjkþjkklm noghiûhiihiiýjijjkjùkjkklkllýmlmmûnmnmnnùonghhghhijþijj kýlkllmþlmmýnmnnoghijükjjkklýmlmmýnmnngþhgghiûjijijjükjjkkþjkkýlkllýmlmmnþmnnýgfggþhgghþihhijijkþjkklümllmmönmnmnnfgfggúhghhghh ijùkjjkkjkklmùnmgfgfggýhghhýihiiújiijijjkþjkklkýlkllmðnmffgfggfgghghghhýihiiþhiiüjiijjkýlkllmþlmmýnmffgþfgghüghihh ijkþlkklþkllmþeffýgfggþhgghiújiijijj÷kjjkklklkklmþlmmfûgfgfggúhgghihhiûjijijjýkjkkþlkklûmleeffgõhgghghhiihiijijkþjkkýlkllmûlffeffghghihiýjij jkýlkllmefýgfggúhghgghhýihiiûjijijjþkjjkùlkkllkllýdfeefúgffgfgghþghhiþjiijþkjjklþdeefügffgghiþhiiýjijjükjjkkýlkllþdeeúfefeeffgühgghhúihiihiiôjiijjiijjkjkkþlkkúlededee fghiþjiiýjijjkjk÷lkllkdedeeýfeff gýhghhihiûjijijjýkjkk÷lklddeddeeüfefeefghiþhiijkùlddeddeeûfefeffgúhghghgghüihhiiüjiijjkþjkkôþóôôþóôôþóôôþóôôüõôõôôþõôôþõôôõôþõôôõ÷ôóôóóôôóôôûóôôóôôþõô ôõýôõôôõôõóôóôóôþóôôùõôõôõõôôõôõýôóôôóôóýôóôôþõôôþõôôøõôõôôõõôôõýôõôôûóôóóôôó÷ôóôóôôóóôôþóôôþõôôûõôõõôôþõôôþõôôõþôóóøôóóôôóóôôüóôóôôþóôôøõôõôõôõôôûõôôõôôþõôôþõôôóôþóôôþóô ôþóôôþõôôþõôôþõôôüõôôóóôþóôôüóôóôôþóôôþóô ôþõô ôüõôôõõõôõõôõõôóôôóóþôóóôóúôóôôóôôþóô ôþõôôûõôõõôôåõôóóôóóôóôôóôóóôôóôôóôôóôóô ôþóôôñõôóôóóôôóóôóóôóóôþóôôûóôóóôôþóôôþõôôþõôôóþôóóûôóôóôôúóôóôôóóôþóô ôùõôõôôõôô÷õôôóôóôôóó÷ôóôóôôóôóóôóôþóôôûóôôóôôþõôôõýôõôôõóôóôóôóôóôóóôîóôôóôóôôóóôôóóôôóôôþóô ôþõôôùõôôóóôóóôóôûóôóôóóýôóôôóúôóôôóôôþóôôþóôôþõôôþõôôüóôôóóþôóóôóôõóôóôóôóóôóôôüóôóôôüõôõôôóþôóóôúóôóôóôôóóôóóôóôôóôôóôôýõôóóôóôóôóøôóôóóôóôôþóôôóôþóô ôüõôôóóüôóôóóôóúôóóôóôôþóôôóôþõôô óôóôóôóôóôóöôóóôóôôóôóóþôóóýôóôôúóôóôóô ôóýôóôôþõôôóþôóóôóüôóôóóôþóôôþóôôþóôôþóôôþóôôóþôóóüôóôó óôóöôóôôóôôóôóóôþóôô óüôóôóóôóûôóôóôôóýôóôôüóôóôôþóô ôýóòóóðôóóôóôôóóôôóóôôóóùôóóôóôóóôóôþóôôþóôôóþòó óùôóóôóóôôóôýóôóóûôóôôóóýôóôôþóôôóþôóóôýóôóóöôóôóôóóôóôôþóôôþóôôþóôôóþòóóþôó óüôóôóóýôóôôóôýóôóóôþóôôþóôôýóòóóþôóóþôóóûôóôóôôþóôôüóôóôôþóôôþóôôóôüóôôóóùôóôóôôóóôþóôôþóôôýóòóóúôóôóôóóôóûôóôóôôûóôôóôôþóôôõóôóôôóôóôòóóòóôóúôóôôóôôþóôôüóôóôôþóôô óþòó óûôóóôóóôüóôóôôóôöóôóôóôóôóôôóþòóóþòóóôóôóýôóôôüóôóôôóôòóþòóóþòóóþôóóýôóôôóùôóóôóôóó÷ôóóôóóôóôôóôýóòóóþòóóòóþôóó÷ôóôóóôóóôôöóôóôôóôôóôôòóþòóóþòóóþòóóþòó óûôóóôóóþôóóýôóôôìóôóôôóóôóôôóòóóòóóòóóûôóóôóóôúóôóôóôôõóôóóôôóôóôó óþòó óþôóóþôóóôöóôóóôóóôôóóôüóòòóóüòóòóóþòóóþôóóþôóóýôóôôóúôóôôóôôóùòóóòóòóóþòóóþôóóüôóôóóôþóôôóòýóòó óþòóóþôóóôóþôóóôóôóúôòòóòóóþòóóòóüòóòóóôóþôóóþôóóôóòôóóòòóóòóóòóòóóûòóóòóóòóüôóôóóþôóóòôóóôóôôóóòóóòóóûòóóòóóþòóóþôóóôõóôóôóôóóôôóóòòóóòóòòóóòóòòóóþôóóþôó óôóþòóóòóóòóòóòòóóòóòóóùòóóòóòóóýôóôôóûôóôóòòõóòòóòòóòóòóó÷òóóòóóòòóóþòóóôóôóôóûòóòòóóòþóòòóþòóóþòóóþòó óüôóôóóþôóóùôóóòóóòòûóòóóòòñóòòóòóóòóóòóóòóóüòóòóóþôóóþôóóòûóòóóòòóúòóòóòóóüòóòóóûôóóôóóþôóóþôòòóþòóó÷òóòóòóòóòòóþòóóûòóóòóóõôóóôóóòòóóòòúóòòóóòòóþòóóòóòóþòó óþôóóþôóóòüóòòóóþòóóòóþòóóùòóòòóóòòóòóúôóòòóòòùóòòóòóòòýóòóóþòóóþòóóþòóóüôóôóóþôóóòþóòòþóòòþóòòýóòóóòóþòóóþòó óþôóóüòóóòòóýòóòòóýòóòòõóòòóóòóòóòóóþòóóùôòòóòóòòüóòóòòóòóþòóóþòóóþòóóþòóóþôóóþôòòùóòòóòóòòóòóòüóòòóó÷òóòòóóòòóóþòóó òþóòòôóòóóòòóòóòòóóüòóòóóþòó óúôóòòóòòóüòóóòòûóòòóòòûóòóòóóøòóóòóóòó ó òõóòóòòóòòóóòòóøòóòòóóòóóûòóóòóóþôóóòùóòóòòóòòóòêóòóòòóòòóòòóóòòóòòóòòóóýôóòòóòöóòòóóòóóòóóüòóòóóÿoýpoppqþpqqrsôrssrststststtýutuuvþuvvýwnoopqpqürqqrrùsrrsrrssûtststtuþtuuvþwoopþoppûqpqpqqürqqrrsýtsttuþtuuvúwnnonooüpooppqrsþtsstutýutuuvoþnoopûoppoppýqpqqýrqrrýsrssütssttúutuutuuþvuunopüqppqqýrqrrþqrrsùtsttssttýutuuvunoþnooþnooüpooppýqpqqýrqrrsùrsrststtuývmnnþonnoýpoppqþrqqörqrrsrrsrsstsýtsttuúvnnmmnnýonooðpooppopqppqqpqrqqrþqrrýsrssýtsttumýnmnnôonnoononoopoopqpqürqqrrþsrrstuütuummnoûpopoppqþpqqrþqrrstþsttýutuumnþmnnopqýrqrrþqrrýsrsstúutuulmmünmmnnùonnoonooýpoppqýrqrrsýtsttùutmlmlmmünmmnnonüonnooþpooøpoppqppqqýrqrrsþrssütssttmþlmmünmmnnoþnooùpopopoppýqpqqþrqqrýsrsstlmúnmmnmnnýonooúpoppoppqþpqqýrqrrýsrsstýlmllýmlmmýnmnnýonoopopqpqrsúrsststtlmnoýpoppýqpqqrüqrqrrstþsllýmlmmnþmnnùonnoonooúpoppoppýqpqqýrqrrýsrssþtllþmllmýnmnnýonooüpooppqüpqpqqr÷srsstklkllmþlmmnmnopþoppüqppqqrùsrsrsskklùmlmmnmnnþonnopþqppýqpqqrsklþkllmnûmnmmnnýonooüpooppúqppqpqqrþqrrsklùmlmlmlmmýnmnnopúqpqppqqrjkúlkklkllümllmmþnmmnoþnoopúopqppqqüpqqrr÷qrrqrrjjkk lmünmmnnþmnnýonoopopüqppqqýrqrrjükjjkklýmlmmnoþnoopqþpqqrjükjjkkülkkllmþlmmnþmnnoüpooppqþpqqýrqrrjþkjjýkjkklmlümnnmmnùmnnonnooýpoppóqpqppqpqrqqijjkýlkllúmllmlmmnþmnnoþnooüpooppqüijijjklömlmmlmnmmnnýonoopþoppüqppqqijkþlkkl mnüonnooüpooppqijþijjýkjkkúlkklkllmlmnümnmnnop÷oppqppqqiiþjiijkjúkllkkllùkllmmlmmùnmnmnmnnopopûqpphiiþjiij klýmlmmn opþoppijkülkkllúkllmlmmýnmnnüonnoopophiýjijjklüklkllümllmmýnmnnoìpoppophhihiihiijijijjklùkllmmlmmþnmmnonoúpoophiiþhiiùjiijjijjýkjkklmþlmmünmmnnonohijúkjkkjkklþmllömlmmnnmnmnnohûghihiijþijjûkjkjkkl münmmnnýonooõphhghghiihiiøhiijijijjþkjjýkjkklþkllmýnmnnoghþghhýihiiújijiijjkþlkklmnoúnoogghhghi jkýlkllklmünmmnnogþhgghiüjiijjklþkllmþlmmnýofgg hýihiijkjýkjkkýlkllmnofghýihiiýjijjúkjjkjkklýmlmmnþmnngþfggýhghhijþijjküjklkklmýnmnnfgþfgghghihiùjiijjijjkjk lmúnmnmnffghghijþijj kløklmllmlmmnfgþfgghghþihhijijkþjkklþkllmlmnýfeffýgfgghüghghhøihiijiijjkýlkllýmlmmünmeffþeffýgfggúhghgghhüihihhijkjk lmeýfeffügffggýhghh ijúijijjk kýlkllmûfefeffýgfggöhghghghhihhiþjiijkþlkklme fýgfggh ijýkjkkølklkklkllömedeefefeffg÷hghghhiihhijþijjýkjkkülkkllefþgffgýhghhþghhijþijjþkjjklûdeddeeýfeffgúhghgghhiújiijijjýkjkklúededdeefúgfgghgghiíjijjijjkjjkkjkkllklldeþfeefghiöhiihiijjijjýkjkkülkcddeüdedeeöfeeffggffgghghiþhiijijk deñfeeffeffgfgfgfggûhghghhiþhiijkûcddcddeýfeffúgffgfgg hiújiijijjþkjjkvúwvwwvwwxyþxyyúzyyzyzz{ü|{{||}vwþvwwxüyxxyyûzyzyzz{ü|{{||}uvýwvwwxüyxxyyzþyzz{þz{{þ|{{|}û|}|}vvûwvwvww xýyxyyúzyyzyzzü{zz{{|þ{||ý}|}}uývuvvwüvwvwwxþwxx yýzyzzù{z{z{z{{|ü{|{||}uvþuvvúwvvwvwwxyþxyyzý{z{{|u výwvwwxþwxxúyxxyxyyzý{z{{þ|{{|uývuvvýwvwwxwxyþxyyýzyzz{|ø{|{||ttuuüvuuvvwxúyxyyxyyûzyzyzzû{z{z{{÷|{{||tutuuvwþvwwýxwxxwxyzþyzz{þz{{|þuttuþvuuvþwvvýwvwwúxwxxwxxõyxxyyxxyyzyyýzyzzý{z{{|øtuttuutuuûvuvuvvwxwýxwxxúyxyyxyyþzyyz{tûututuuûvuvuvvwýxwxxýyxyyüzyyzz{týutuuúvuuvuvvwþxwwxyþxyyýzyzz{þsttýutuuþvuuvwxþwxxúyxyxxyyþxyyzþ{zzý{sttüuttuuvuvwþvwwþxwwxýyxyyþxyyzþyzz{stþuttuþvuuvwûxwxwxxõyxyyxyyzyyzzþyzzsýtsttuütutuuvwxûwxwwxxyþxy yûz{zzsstþsttýutuuûvuvuvvwxwxûyxyxyyüzyyzzþrssýtsttýutuuvþwvvüwvvwwx yzüyrrss tuvþuvvýwvwwüxwwxxýyxyyzürsrssûtststtuvüuvvwwþvww xyýzyrrûsrsrsstu vwxyxyrstuütuvuuývuvvwþvwwþxwwxøwxxyxyxyyrsþrssútstssttõutuuttutuuvv÷wvwvwwvwxxþwxxñyxyxyxyyqrqrrsrrsýtsttu výwvwwöxwwxxwxxyxxyýrqrrsütssttþuttuûvuvuvvwïxwwxxwxxyxxyxrrqrrstúuttutuuùvuuvvuvvwúvwxwwxxüyxqrrþqrrstûstssttýutuuvwþvwwxûyqqrqqrsrstuþtuuøvuvvuvwvvýwvww xqrüsrsrrstþsttuþtuuvýwvwwýxwxxqþrqqrsþrsstuþtuuvþuvvýwvwwxpqrûsrsrsstþsttuv wxqpqürqqrrsþrsstuþtuuvþuvvwûpqppqqürqqrrûsrsrssùtstststtýutuu vwôxpqppqpqpqqrrþqrrsþrsstþsttuvþuvvwùvwvwwxppqûpqqrqqýrqrrsþrssütssttýutuuþvuuvwúvwwooppqrøqrrqrrsrrsýtsttuþvuuvøwvwvvwwppqpqürqqrrýsrsstöstututtutuuüvuuvvþwvvþwp pqúrqrrqrrsþrsstþsttuvøwvooppoppûqpqpqqûrqrqrrúsrsrrsstýutuuvþwooþpooùpoppqpqqrüsrrssütssttýutuuþvuuvoûpopoppqpqr stuþtuuývuvvoúpoppoppqþrqqrüsrrssütssttüuttuuvnopqüpqpqqrþqrrsýtsttuþtuuünonooüpooppüopqppqürqqrrúsrrsrsstþsttuùvonnonooüpooppqþrqqrúsrsrrsststûututuu÷vnonnonnoopþoppqþpqqýrqrrstuütutuunûononooïpopoppqqppqqpqqrqqr sýtsttþuttumnúonoonoopýqpqqýrqrrstþstt÷utuumnnmnnòonoonooppoppoppqýrqrrsþrsstþsttuþnmmnoønoopoopoopqþpqqrqrsþrsststþummnýonooýpoppqüpqpqqrûqrqqrrsütstsstýulmmnüonnoopùqpqpqpqqrqrsürsrsstûsttlmmnþmnnonûonooppopþqppqórqrqrrsrsrsrsst mnopqþpqqrùsrsrsrssùtststmllmýnmnnüononnopopûqpqpqqürqrqqrþsrrsøtssttllmmþlmmnþmnnoþnooüpooppqpqýrqrrsørsststsllmnþmnnoýnonnoøpopoopqppqýrqrrýsrsslmnmnýonoopûoppqppqürqqrrslûmlmlmmnþmnnopüopoppqpqþrqqrýsrsslükllmmôlmmlmmnnmnmnnoþnooûnoopoopqþpqqrõsrsrsrklkkllùmlmnnmnnopþqppqrösrrsrklkkll mno÷poopoppqppqrþôõõþôõõùöõöõööõõöõö÷õöõööõööõõþôõõþôõ õþöõõüöõöõõöþõööõôõþôõõþôõõþôõõöõöõöõöõïöõöõõööõõôõôõõôôõ õþôõõþöõõþöõõöõöõüöõöõõööõöõöõôõôõõþôõõôõöõöõöõöøõööõöõöõõôõüôõõôôõüöõöõõöõöýõöõõöôõùôõôõôôõõüôõôõõýöõööøõöõõööõööõýöõööúõöõõôõõþôõõûôõõôõõþôõõûöõõöõõùöõõöõõööõûôõõôõõúôõõôôõõüöõöõõüöõöõõöýõöôôõôõôùõôôõôôõõûöõõöõõïöõööõöõöôôõõôõôôõõýôõôôõýôõôôýõôõõþöõõö÷õööõöõõöõõôþõôôõôüõôôõõôõþöõõöõôöõõööôôõõôôõõùôõõôôõôôõþôõõüôõôõ õöüõööõõúöõöôõôôõûôõôôõõþôõõþôõõþôõõüôõôõõþöõõüöõöõõþöõõõôõôôõôõõôôõõôõôþõôôõüôõôõ õþöõõûöõööõõúöõöõõôôþõôôõôõô õþôõõþôõõüöõöõõöõôþõôô÷õôôõôôõôõõôôõôõõôõôõôõôõõþöõõþöõõöýõöôôþõôôúõôõôõôôõôúõôõôõôôõôõþöõõöõöôõôõúôõôõôõõþôõõ÷ôõõôôõõôõ õöõôþõôôþõôôïõôõôôõôõôõôõôõôôõõþôõõþôõõþöõõñöõöõööôõôõõôõõôôñõôôõôõôõõôôõõôõõôþõôôõüôõôõ õþöõõôüõôõôôõôþõôôýõôõõüôõôõõþôõõüôõôõõôþõô ôùõôõôôõôôûõôõôõõýôõôôõþôõõüôõôõõôõôøõôõôôõôõõôõôõþôõõþôõõþöõõôþõôôþõôôõôõùôõôôõôõõüôõôõ õþôõõôþõôôþõôôùõôõôôõôôõúôõôõôõõüôõôõõûôõõôõ õôþõôôþõôôþõôôøõôõôõôõôôýõôõõûôõôôõõþôõõ ôõôûõôôõôôõôþõôôýõôõõôõþôõõþôõ õôþõôôúõôõôõôôõôõôõôúõôõõôõõüôõõôôþõôôþõôôõ ôõ÷ôõôôõôõôõõòôõõôõôõôôõôõôõõ ôþõôôþõô ôýõôõõôõóôõôõõôõôõôõôõõôþõôôþõôôýõôõõôõóôõõôôõôõôõõôõõûôõõôõõôþóô ôþõôôþõôôüõôôõõôþõôôüõôôõõþôõõþôõõþôõõôýõôõõôõôüõôôõõûôõõôõõôõýôõôôþóôôüõôõôôõüôõôõõôõûôõõôõõüôõôõõûôõõóôôüóôóôôõôþõôôõôõôýõôõõüôõóôôþóôôõõôõôôõôõôõôôüõôôõõûôõôõôôõöôõôõôôõôóôôùóôóôóóôôùõôôõôõôôõôõùôõõôõõôôþóôôóôüõôõôôñõôôõôôõôôõôôõõôôõûôõôóôôõóôôóóôôóôóô ôþõôôõôõ÷ôõõôõõôôõõùôóóôôóôôþóôôøõôôõôôõôôõôöõôõôôõôõôõõñôõóôóôôóôôóóôóôôþóôôþóô ôõôþõôôõôôõôõõôõôõôôõõóôóýôóôôþõôôûõôôõôôýõôõõûôõôôõõþôóóôóôóôüóôóôôþõôôöõôõõôõôõõôôöõôôõõôôõõôôþóôôþóôôüóôóôôþóôôøõôôõôôõôôúõôõôôõõüôõõôôóôóôþóôôóôüõôôõõôúõôôõôõõôóøôóôóóôóôôüóôôóóôþõôôõôõôõûôõôóôôþóôôúóôôóóôôþóôôþõôôùõôôõôôõõôùõôõõôóôôóôóýôóôôþóôôó ôþõôôþõôôôõôôõõôôõôóôóóýôóôôúóôôóóôôþóôôþóôôóôüõôõôôõôýõôóóþôóóôøóôôóóôóôôóýôóôôþóôôþõôôþõôôþõôôóúôóôóóôôóôþóôôüóôóôôó ôüõôôõõôõýôõôôüóôôóóôóýôóôôõóôóôôóôóôóôôûóôôóôôøõôôõôõõôôþõóóüôóóôôñóôóôóóôôóóôóôóôôþõôôþõô ôóôôóôôóóôóóôóôôöóôôóóôôóóôôùõôôõôõôôóôüóôóôôóôýóôóóôüóôóôôþóô ôþõôôõôúõôóôôóóüôóôóóôþóôôóôüóôóôôþõôô÷õôõôôõôôóóþôóóüôóóôôþóôôûóôôóôôþóôôþõôôóôõóôôóôóóôóóôôúóôôóóôôûõôõõôôýóôóóôóúôóóôôóóùôóôôóóôôþóôôþóôôýóôóóþôóóôýóôóóúôóôôóôôóôþóôôþõóóõôóôóóôôóôóôôóôþóôôõóôóóôôóôôóô ôùõôõôôõóóüôóôóóúôóóôóôôóôúóôôóóôôþóôôþóôôþõôôóþôóóþôó óõôóôôóôôóôóôôþóôôþõôôþõôÿwùxwwxwwxxúyxyyxyyzïyzyzz{{z{{zz{{|{||}þ|}}ý~}~~wüvwwxxüwxwxxyz{þz{{ü|{{||ü}||}}~vüwvvwwxyúzyyzyzz{ü|{{||}~þ}~~óvwvvwwvwxxwwxx yz{|þ{||þ}||}~vwþvwwùxwwxxwxxyzyzþ{zz{|}þ|}}výwvwwxyxyýzyzzú{z{{z{{|þ{||þ}||}vwþvwwýxwxxüyxxyyzþyzzý{z{{ |}~uvøuvvwwvvwwýxwxxøyxyyxyxyyz{þz{{ |}ý|}uuvüwvvwwxþwxxyþxyyýzyzzü{zz{{|}uúvuuvuvvwþvww xýyxyyûzyzyzzü{zz{{|þ}||uvüwvvwwxþwxxûyxyyxxyzô{z{{z{{|{|{||þ}uuývuvvþwvvýwvwwxþwxxyþxyyýzyzz{þz{{ü|{{||ù}||tutuuùvuuvvuvvwxwxþwxxyz{|ò{|{||ttuutuuvuuvùwvvwvvwwûxwxwxxyúzyzzyzz{ó|{||{||ttuttuuývuvvwþvwwxûwxwwxxyþzyyzû{z{z{{ó|{{||ttututtuuvúwvwvvwwýxwxxüyxxyyýzyzz{|{þsttuútuuvuvv÷wvwwxwwxwwxýyxyyzþyzz{ý|{ttutuývuvvþwvvwüxwwxxýyxyyýzyzz{ûz{{sttuvwþvwwüxwwxxyxyz{þz{{ûsttsttuývuvvýwvwwxyþzyyz{õz{{sststtsttüuttuuþvuuvþwvvýwvwwýxwxxüyxxyyzþyzz{sþtsstþutt uvýwvwwþxwwxyüzyyzzþ{ssýtsttuìtuutuuvvuuvvuvwvwwvwwýxwxxyzþyzzþrssýtsttutuvþuvvwxyþxyyzþyzzþrsstutýutuuvþwvvwþxwwxyþzyyzørssrrsrsstíststtuututtuuvuvvuvvwûxwxwxxþyxxyýzyzzrþsrrstüuttuuúvuvvuvvúwvvwvwwûxwxwxxyzþyrrsrstûututuuüvuuvvwvwxþwxxúyxyyxyyüzrqrrýsrsstþsttûututuuvþuvvwüxwwxxyþxyyqrsþrsstþsttúutuutuuvüuvuvvýwvwwûvxwwxxþyxxyqrþqrrüsrrssútsttsttýutuuvüwvvwwxþyxxyqrþqrrsþrsstuvþuvv÷wvvwvwwxwwýxwxxüyxxqqrþqrrýsrsstüututtuvýwvwwxþwxxqürqqrrsürsrsstýutuuývuvvwxþwxxpýqpqqrõqrqrrssrsrsstþsttùuttuutuuvýwvwwxpqrstþsttþuttuúvuuvuvvwþvwwxüpqpqqþpqqrsýtsttuþtuuúvuvvuvvûwvwvwwxûopqpqqúrqrrqrrýsrss tuývuvvwþvwwxþoppüqppqqýrqrrstuþtuuüvuuvvýwvwwxýpoppqýrqrrstþuttuvþuvvwvwýxwoopqrsôrsststststtuutuüvuuvvwoýpoppqrsrsýtsttýutuu÷vuvuvwvwvvþwooüpooppöqppqpqqrqrrþqrrsrsýtsttýutuuûvuvuvvwþvoopopqþpqqýrqrrýsrssýtsttuþtuuvuvûwvonoopþoppýqpqqýrqrrs÷rststtsstt uvoüpooppýqpqqúrqrqqrrsûrssrss tüuttuuvþuvvüonnooúpopooppýqpqqûrqrqrrsørsrssttsstutuþtuuüvuuvvþonnopþoppýqpqqrsôrsrsstsstssttuþvuuþvnnûononoopopqþpqqýrqrrþsrrýsrssýtsttuötuuvuvuvmnnopþoppqýrqrrýsrssýtsttuþtuuývmnnoýpoppüqppqqrýsrssýtsttþuttuývnmmnûononoopþoppýqpqqrqrststuútuummn noüpooppüqppqqr stþuttumnþmnnoýpoppqýrqrrsþrssþtsstutmnþmnnoýpoppüqppqqrúsrssrsstùsttuutmmýnmnnûononoopþoppýqpqqýrqrrýsrssütssttúutmmlmmýnmnnýonoopöoppqppqqpqqrýsrssþtsstúlmlmlmmýnmnnüonnoopqpqúrqrrqrrstýstllmýnmnnýonoopûqpqpqqýrqrrsþrssøtsstllmllmnmnþonnoðpopopooppqqpqqpqqúrqrrqrrsýtsllþmllmúnmnnmnnûononooýpoppqrþqrrsörststtllkllûmlmlmmýnmnnýonoopüqppqqørqrqrrqrrsþrssþlkklmýnmnnûononoopýqpqqrûqrrsrrslþkllmnoþnoopqþpqqrþqrrs}ý~}~~ü~~ý€€€þ€‚ ƒ„þƒ„„ù~}}~~}~~þ~~ý~ý€€€ü‚‚‚þƒ‚‚ƒ„þ|}}û~}~}~~ €‚ƒþ‚ƒƒ„ƒ„}ý~}~~~€þ€€‚þ‚‚ ƒ„|}~þ~û€€€€ý€‚þ‚‚ƒù„ƒƒ„ƒ„||ù}|}}~}~~þ}~~ü~~ý€€€ý€‚úƒ‚ƒƒ‚ƒƒþ„||}þ|}}ü~}}~~þ~€þ€€ ‚ƒ„|ý}|}}÷~}}~~}~~þ~€ø€€€€‚þ‚‚ùƒ‚‚ƒ‚‚ƒƒ|}þ|}}ø~}~}~~~~ý€€€û€€‚þƒ‚‚ƒ|ú}|}}|}}~ý~ €ü€€‚þ‚‚ƒ‚þƒ||}þ|}}~þ}~~~€þ€€þ€‚þ‚‚ƒù‚ƒƒ||{||þ}||}ø~}~}~}}~~ý~€þ€€ü‚‚‚õƒ‚ƒ‚{{|{|{||}þ|}}~}~ý~€þ€€‚‚{ü|{{||}|}ù~}}~~}~~þ~ý€€€€þ‚ý‚‚‚{þ|{{ý|{||}ý~}~~ù~~~÷€€€€€þ€ý‚‚‚z{|ù{||}||}}ý~}~~€€ý€ý‚‚‚ý{z{{|ü}||}}ý~}~~ý~þ~û€€€ €ù‚‚‚zz{{ü|{{||}ü~}}~~þ~ý€€€‚z {|þ}||}~ù~~~€þ€€þ‚zzü{zz{{ |}~þ}~~€€z{üz{z{{|þ{||ý}|}}þ~}}~ü~~€þ€€ú€€ûyzz{zz{þz{{|þ{||}|}ý~}~~þ~~ú€€€€ýzyzzü{zz{{ü|{{|| }ü~}}~~ €þ€€ýyzz{úz{{||{{ý|{||ý}|}}þ|}}~ü~~þ€€yýzyzzþ{zzý{z{{ |}~þ~€þ€€yüzyyzz{þz{{ |}þ~}}ý~}~~þ~~÷~€€€€yzþyzz{|ö}||}|}~}}~~û~~û€€€€÷xyxyzzyyzzþ{zz{|}ý~}~~ù~~€€þ€€óxyxyyzzyyzyyzzý{z{{|û{||{||}þ|}}~þ}~~û€€xxy z{ù|{{||{||}û~}~}~~ü~~xyzþyzz{ý|{||þ}||}þ~}}~ý~~ý€xxyzþyzz{þz{{|û{||}||}þ~}}~ú~~~þ€xxyxyþzyyzý{z{{û|{|{||}~þ}~~ýxwxxyþxyyüzyyzzý{z{{ý|{||ý}|}}÷~}~~}~~~~þwxxúyxyyxyyýzyzzü{zz{{|{|ô}|}|}|}}~~}~~ø~wwxwwxx yýzyzzþ{zz{|{| }~þ~~wxþwxxýyxyyþzyyýzyzz{þz{{|ù{||}}|}}ý~}~~þwwýxwxxúyxyyxyyzyzùyzz{zz{{þz{{|ü{|{||}~þ}~~wxýyxyyzô{z{zz{{|{{|{{|}þ|}}~û}~~vwwxþwxxyöxyxyyzzyyzzý{z{{ý|{| |}~þ}~~vwúxwxxwxxøyxyyxyxyyzü{zz{{ü|{{|| }üvwvwwxýyxyyz{þz{{ý|{||}~ó}~vvwvvwwvwxwwxûyxyxyyzþyzzý{z{{ |}þ|}}vwõxwxxwxxyxxyyþzyyz{üz{z{{ |}þ~vvwxûyxyxyyùzyzzyyzz{þz{{ý|{||}uvwþxwwxyzþyzzó{zz{z{{|{{|{||ü}uuvvüwvvwwüxwwxxüyxxyyþzyyzþ{zz{ú|{||{||üvuuvvýuvwwvwýxwxxüyxxyyz{ý|{||þ}||uvuvýwvww xyzþyzz{z{|uvþuvvþwvvõwvvwwxwxwwxxyzþyzzý{z{{ø|{||{||uuvúwvwwvwwýxwxxyýzyzzý{z{{û|{|{||uþvuuvýwvwwxwxüyxxyyzþyzzü{zz{{ú|{|ttuuvþuvvûwvwvwwýxwxxúwxyxxyyz{üz{z{{û|{{uttu vwýxwxxçyxyxyxxyzzyyzzyyz{z{zz{z{{þ|ttuþtuuüvuuvvùwvwvwvwwýxwxx yzþyzzý{z{{þ|ttuv wxüyxyxxyýzyzzý{z{{zü{tsttutuývuvvþwvvwûxwxwxxy zø{z{{ttsttu vwûxwxwxxy zþ{sstýutuuvþuvvýwvwwûxwxwxxýyxyyþzyyz{stuûvuuvuuvûwvwvwwxwxýyxyyz{stþsttýutuuþvuuvýwvwwþxwwýxwxxyþxyyüzyyzzý{zssþtsstýutuuývuvvwüxwwxxýyxyyúzyyzyzzsûtststtýutuuvþuvvwþvwwüxwwxxyòxyyzyzyzyzsrrssýtsttüuttuuývuvvúwvvwvwwxþwxxýyxyyzyöû÷öö÷öö÷ö÷öþ÷ööü÷ö÷öö÷þö÷÷öþõööþõööþ÷ööû÷öö÷ö ö÷ýö÷öö÷öõöþõööþõööþ÷öö÷ öþ÷öö÷ö÷ö÷õöõöþ÷öö÷ùö÷ö÷ö÷öö÷ö÷úö÷ö÷÷öö÷üö÷÷ööø÷ööõööõööþõööû÷öö÷öö÷ö÷üö÷ö÷÷öý÷ö÷÷ûöõöõööþõööþõö öþ÷ööþ÷ööþ÷ööú÷ö÷÷ö÷÷õö÷÷öö÷÷öö÷ööþõööþõööþõööþõö ö÷öý÷ö÷÷ ö÷ûöõöõööõöûõöõõöö÷öú÷ö÷öö÷÷öú÷öö÷÷ööõ÷ö÷õõööõõöõõöõöõ öþ÷ö ö÷üö÷÷öö÷úö÷÷ö÷ööþõööõöþõööþ÷ööü÷ö÷ööì÷ö÷öö÷÷ö÷öö÷ö÷ööõööõõöþõööþõööþõööüõöõö öû÷öö÷öö÷ùö÷÷ö÷÷ööú÷õööõööõýöõööõöü÷ö÷öö÷öú÷öõõöõõüöõõööùõöõööõööþõö ö÷÷öö÷÷ö÷÷öö÷öõöøõöõööõõööþõö öþõööû÷öö÷öö÷ö÷ö÷öõöõöüõöõööõöî÷öö÷öö÷÷ö÷öö÷öõööõõûöõöõööþõööüõöõö öþ÷ööþ÷öö÷öþ÷ööõöõöþõööþõö öþ÷ööì÷öö÷öõõööõöõöõöõõööõõùöõööõõööüõöõööþõööö÷ö÷öö÷÷ö÷õõþöõõöõöþõööþõööþõöö÷öþ÷ööþ÷õõöõðöõööõöõöõõöõööõööõöþ÷ööú÷öö÷÷õõö õþöõõûöõöõööõøöõöõõöõö öþ÷ööö÷ö÷öö÷õõöõõôöõööõöõõööõööõööõõöõõööõööþõö öþ÷ööü÷ööõõþöõ õýöõööþõööþõö öþõö öý÷ö÷÷öõøöõõöõööõõüöõõööøõööõöõöõõöûõööõööõçöõõööõöõöõöõööõöõöõöõõöõööûõöõõööþõööþ÷ööõöõûöõõöõõööõöõöõõöõööûõöõõööþõö öõöõöùõöõõöõööûõööõööøõööõõööõõö÷õöõüöõõööõöõ öþõö öõöõþöõõùöõõööõööõöõöùõööõöõö öõöõüöõöõõüöõöõõöüõöõö öúõöõöõö ö õöõþöõõüöõöõõ öõö õøöõööõõöõõýöõööùõöõöõõööõöüõöõööþõööþôõõþöõõö÷õöõöõöõöõõôöõööõöõöõöõööüõöõööõüöõöõõöõöùõöõööõööþõööþõööõþôõ õúöõöõöõõüöõõööûõööõööüõöõööþõööþõööýõôõ õþöõõüöõõööõöõöõûöõõöõõþöõõöõöþõööþõööýõôõõþöõõþöõ õüöõõööõ öüõôôõ õþöõ õúöõöõöõõöõüöõõööõöüõööõõþôõ õöõþöõõûöõõöõõüöõöõõþöõõûöõõöõõö õþôõõþöõõîöõöõööõõööõõöõõöõööþõööþõööõûôõõôõõüöõöõõöõûöõööõõüöõõööüõöõöö õôõþöõõøöõöõõöõööûõöõõööõöõöýõôõõüôõôõõþôõõüöõõööïõöõööõöõõöõõöõöõööþõööúõööõôõõûôõõôõõøöõõöõõöõõþöõõþöõõöõöúõöõööôôõöôõõôôõôõôõ õþöõõúöõõöõööýõöõõöõýöõööôùõôôõõôõõþôõõþôõ õþöõ õúöõõööõõþöõõôöõõööõöõõôôõõþôõõþôõõþôõ õþöõõþöõõúöõöõõööõõööõõöõööõôôõþôõõþôõõþôõõþöõõþöõõþöõõþöõõöýõöôôüõôôõõôõþöõõûöõööõõúöõõöõööþôõõôõúôõõôôõõúöõõööõõöõöûõöõôõõôõþôõõþôõõþôõõþôõõþöõõþöõõöõôõôôõôõôõôõõþôõõùôõôõõôõõþôõ õþöõõöõööõööôõõôõôõõþôõõûôõõôõõ÷öõõöõöõöõõöõôþõôô÷õôõõôõõôõõþôõõôõþôõ õþöõõöõööõööõöõööôôõóôõõôõôôõõôõõôôõþôõõþôõõûöõõöõõêöõöõöõôõôôõõôõôôõõôõôõõüôõõôô õüôõôõ õûöõõöõõñöõöõöõôôõôõõôôõõõôõõôõôõôõôõ õþôõ õö õôõõôôõôôõõôôõõþôõõôõþôõõöõþöõõôöõôõôõõôôõõôôóõôõôõôõõôôõõôôúõôôõõôôõöþõôôüõôõôôûõôôõôôúõôôõôõõôõþôõõúöõõööôôûõôôõôôõô÷õôõõôõõôõõûöõõöõõöôõûôõôôõõôõùôõôôõôõõþôõõôõúöõõôõôôþõôôõôûõôõõôôõôüõôôõõþôõõþôõõþöõõÿþ~€ý€€€€ý‚‚‚ýƒ‚ƒƒ„…þ„……ò†…†…†…††~~~þ€€þ€‚üƒ‚‚ƒƒý„ƒ„„ý…„……†ý…†~~ü~~þ€ý€€€ý€‚þ‚‚ƒ„ý…„……ú†……††~~ý~ü€€€ý€ý‚‚‚üƒ‚‚ƒƒü„ƒƒ„„…þ„……†ö~}~~~~€ ‚úƒ‚‚ƒ‚ƒƒ„þƒ„„…û†…†}~~þ~û€€€€ü€€‚ƒù„ƒƒ„„ƒ„„ý…„……ý†}~~ü€€€û€€‚ýƒ‚ƒƒ„û…„…„……}õ~}~}~~~~ý€€€ü€€ò‚‚‚‚ƒ‚‚ƒƒ‚ƒƒý„ƒ„„…þ„}}~þ~~ö~€€€€€û€€÷‚‚‚‚ƒƒ‚‚ƒ„…}ý~}~~ý~€ù€€€€ý‚‚‚ƒ‚ƒý„ƒ„„ú…„…}|}}ý~}~~ú~~ú€€€€€ý‚‚‚ƒ‚ƒú„ƒ„„ƒ„„þ…||}~þ}~~ý~€‚þ‚‚ýƒ‚ƒƒ„ƒ„|}þ|}}~þ~ý€€€ý€ï‚‚‚ƒ‚‚ƒƒ‚‚ƒƒ„„|ú}|}}|}}ý~}~~ø~~~€€þ€€ý‚‚‚ýƒ‚ƒƒù„ƒƒ„ƒ„||}~}~þ~€þ€€þ€þ‚‚ƒþ‚ƒƒý„{||}þ|}}ý~}~ ~€€ü€€‚ƒý„ƒ||ù}||}}|}}~ú}~~~ü€€€‚ƒ‚ƒý|{||}ü~}}~~û~~ô€€€€€€€‚þ‚‚ýƒ‚ƒƒþ|{{|þ{||ý}|}}ù~}}~~}~~þ~~€‚ýƒ‚ƒƒ{÷|{{||{|}||}ú~}~~}~~û€€€û€‚‚þƒ‚‚ûƒ‚{z{{ý|{||}û~}~}~~ú~~~€þ€€ý‚‚‚üƒ‚ƒ{{|þ{||}þ|}}þ~}}~ù€€€€€þ€‚üz{z{{|þ{||}þ|}} ~ý~€û€€‚þ‚‚z{÷z{{|{||{||}~}~ü€€€ý€þ‚û‚‚‚zzý{z{{ü|{{||}~þ~~ú€€€€€ü‚‚zz{ |}þ~}}~ü~~ý€€€ý€þ‚zz{þz{{ |}ý~}~~þ~ú€€€€ü€€ú‚zyzz{ý|{||}þ|}}ý~}~~ø~€€€€û€€€€üyzyzzü{zz{{þ|{{|û}|}|}}ü~}}~~€øzyzyzzyzzû{z{z{{ø|{||}||}}ù~}}~~}~~þ~€þ€€øyzyzzyyzzþ{zz{ý|{||ü}||}}ú~}}~}~~ú~€€€ý€yyz{õz{{|{{||{{||}~ý~€þ€€ôyyxyzyyzzyzz{üz{z{{|{|û}|}|}}~ û€€€þxyyzû{z{z{{|þ{||}ý~}~~ü~~€x yz{ú|{|{{||ú}|}||}}ý~}~~ù~~~ù€€€€xxyþzyyzùyzz{zz{{|þ{||ý}|}}~þ~~ý~û€xxyxxyúzyyzyzzú{z{zz{{ú|{{|{||}ü~}~}}÷~~~~~xúyxyxzyyz{|ú{||}|}}ü~}}~~þ~þwxxýyxyyzyz{þ|{{|û}|}|}}~þ~ûwxxwxxyþxyyþzyyzû{z{z{{þ|{{|}~}~ý~éwxwwxwxxyxxyyxxyyzyzyyzz{þz{{ý|{||}þ|}}ü~}}~~ú~wxxwxýyxyy÷zyyzyzzyzz{|{|ü}||}}ý~}~~þvwwýxwxxüyxxyyüzyyzzü{zz{{ý|{||}þ|}}ü~}}~~þvwwxyþxyyzú{z{{z{{|þ{||ý}|}}ö~}~~}~~vwwxüyxxyyûzyzyzzþ{zz{|þ{||}|}û~}~}~~wvwxyúzyzyyzz{þz{{û|{|{||ü}||}}~}~þvwwûvwwvwwýxwxxûyxyxyyýzyzzý{z{{ |}ý~}~~vþwvvüwvvwwýxwxxúyxyyxyyz{ý|{||ü}||}}~þ}vvûwvwvwwýxwxxýyxyyüzyyzz{î|{|{||}}|}|}}~}~uvvwþvwwýxwxxyzü{zz{{ú|{{|{||ý}|}}üuvuvvwþvwwxwxúyxyxxyyþzyyz{þz{{ð|{||{{|}||}}|}}uuvüwvvwwxýwxyyüzyyzz{|û{||{||û}|}|uuvüwvvwwýxwxxyþxyyzþ{zzý{|{{|û}|}|uuüvuuvvýwvwwxüyxxyyøzyzzyzz{{|}uvþuvvýwvwwþvwwùxwwxwwxxyzý{z{{ý|{||ü}ttuuvýwvwwxþyxxyúxyyzyzzúyz{zz{{|þ{||tuþtuuvûwvwvwwþxwwxýyxyyz{þ|{{tuvþuvvwxûwxxwxxýyxyyz{þz{{|{ü|stuuývuvvýwvw wxyþxyyzú{zz{z{{|þsttuþtuuvwxýyxyyzþyzzý{z{{ týutuuv wxüwxyxxöyxxyyzyzyzzý{z{{ýstsstuþtuuvwxþwxxöyxxyyzyzyzzý{z{{sütssttuûvuvuvvúwvwvvwwþxwwxyþxyyz{stuþtuuvuvýwvwwxýyxyyzþ{zzþ„……†þ…††ý‡†‡‡ˆ‡ˆ‰ûˆ‰ˆˆ‰‰Š‹üŒ‹‹ŒŒ …†÷‡†‡†‡†‡‡ˆˆ‡ˆ‰Š‹Œù‹…„„…„……†þ…††‡þ†‡‡ˆý‰ˆ‰‰Šõ‹Š‹‹Š‹‹Œ‹Œ„„…þ„……†‡û†‡‡†‡‡ˆü‰ˆˆ‰‰Šþ‰ŠŠü‹ŠŠ‹‹þŒ„„…þ„……ü†……††‡þˆ‡‡ˆþ‰ˆˆ‰Šü‰Š‰ŠŠ‹„…þ„……þ†……†‡þ†‡‡ˆþ‡ˆˆ‰ðЉ‰Š‰ŠŠ‹ŠŠ‹‹Š‹‹„„ú…„……„……þ†……†‡ˆ‰Š‹Šþ‹„„ü…„„……†þ…††‡ ˆ‰ûЉЉŠŠû‹„„ƒ„ „…û†…†…††û‡†‡†‡‡ˆ‰øˆ‰ˆˆ‰‰Š‰‰Šþ‰ŠŠ„ùƒ„ƒ„„ƒ„„ú…„……„……ú†……†…††‡ˆþ‡ˆ ˆ‰þЉ‰Šƒ„ú…„„…„……†ù‡††‡‡†‡‡ˆ‰ˆý‰ˆ‰‰Š‰Šþ‚ƒƒú„ƒ„„ƒ„„ù…„„……„……þ†……†þ…††ý‡†‡‡ˆþ‡ˆˆ ‰Šýƒ‚ƒƒ„ý…„……û†…†…††ý‡†‡‡þ†‡‡ˆþ‡ˆˆ‰ôЉ‰Š‰Š‚‚ƒ‚‚ƒƒ„…ú†…†……††‡þ†‡‡ˆü‡ˆ‡ˆˆ‰þˆ‰‰Š‰ýŠƒ‚‚ƒ„…„…ü†……††‡þ†‡‡üˆ‡‡ˆˆ‰ˆ‰Š‚ƒþ‚ƒƒ„þƒ„„…„…†‡ñˆ‡ˆ‡ˆ‡ˆˆ‰ˆ‰‰ˆˆ‰‰‚þƒ‚‚ƒü„ƒƒ„„…þ„……†…†‡þ†‡‡ˆ‰‚þ‚‚ƒþ„ƒƒ„ƒ„…ú†…††…††û‡†‡†‡‡þˆ‡‡ýˆ‡ˆˆ‰ý‚‚‚ƒþ‚ƒƒù„ƒƒ„ƒƒ„„û…„…„……ý†…††ü‡††‡‡ˆ‡ˆ‰û‚‚‚‚ýƒ‚ƒƒ „þ…„„…ý†…††þ‡††‡ðˆ‡ˆ‡ˆ‰ˆˆ‰‰‚‚‚ƒý„ƒ„„…†÷…††‡††‡†‡‡þˆ‡‡ˆþ‡ˆˆ‚þ‚‚ýƒ‚ƒƒ„þƒ„„…÷„……†…††…††‡þ†‡‡ˆ‚þ‚‚üƒ‚‚ƒƒý„ƒ„„ü…„„……†ó‡†‡†‡†‡‡ˆ‡ˆ‡ˆˆ€‚þ‚‚þƒ‚‚ƒþ‚ƒƒ„üƒ„ƒ„„…†þ…††ù‡††‡‡†‡‡ýˆ‡ˆˆ€ ‚ƒþ‚ƒƒ„…„ý…„……†ý‡†‡‡ˆú‡ˆ€€‚þ‚‚ƒþ‚ƒƒû„ƒ„ƒ„„ý…„……ý†…††‡þ†‡‡þˆ€€þ€€‚þ‚‚ýƒ‚ƒƒý„ƒ„„ý…„……þ„……ý†…††ú‡†‡‡†‡‡€û€€ý‚‚‚ùƒ‚ƒƒ‚‚ƒƒý„ƒ„„…þ„……†÷‡†‡†‡†‡‡€€ý€‚þ‚‚ýƒ‚ƒ ƒ„þƒ„„…ý†…††ý‡†‡‡ý€€€þ€‚ƒ‚ƒ„ …†þ…††‡ô€€€€€€€‚ö‚‚ƒ‚‚ƒ‚‚ƒƒ„ú…„……„……†û‡†‡‡õ€€€€€€€‚üƒ‚‚ƒƒ„þƒ„„ý…„……þ†……†ø€€€€€þ€‚þ‚‚ƒ„þƒ„„ý…„……†ý‡†þ€ý€€€û€‚‚þ‚‚ûƒ‚ƒ‚ƒƒ„þƒ„„…þ„……†û€€€€‚þ‚‚ûƒ‚ƒ‚ƒƒ„…ü†……††€ü€€€ ‚ûƒ‚ƒ‚ƒƒý„ƒ„„ü…„„……ü†……††ü~~€ú€€€þ‚‚ýƒ‚ƒƒ„þƒ„„ý…„……†~ý~þ€€þ€ü‚‚‚þ‚‚ƒþ‚ƒƒ„þƒ„„…þ„……ý~~~ö€€€€€ ý‚‚‚ýƒ‚ƒƒü„ƒƒ„ „…~þ~€þ€€‚þ‚‚ƒø„ƒƒ„ƒ„ƒ„„…ü„……~~þ~~€€‚þ‚‚ƒ„ƒ„…„…þ}~~ü~~€þ€€ú€€€‚þ‚‚ ƒ„õ…„……„„}~}}~~ü€€€ù€€€ý‚‚‚ýƒ‚ƒƒü„ƒƒ„„…„~þ}~~ü~~€þ€€þ€€ü‚‚‚ƒ‚ýƒ‚ƒƒ„ƒ„ú…„„}}~~ü~~€þ€€ú€‚‚þ‚‚úƒ‚ƒƒ‚ƒƒ„ƒ„û|~}}~~þ}~~€þ€€ý€ú‚‚‚‚‚ýƒ‚ƒƒý„ƒ„„}~þ}~~ú~~õ€€€€€€‚þ‚‚ýƒ‚ƒƒþ„ƒƒ„þ|}}~þ~ý€€€ú€€€ý‚‚‚ùƒ‚ƒ‚ƒ‚ƒƒ„}ú|}||~}}~ý~€ý€‚üƒ‚‚ƒƒþ‚ƒƒú„||}|}}~û~~ü€€€ý€ü‚‚‚þ‚‚ ƒ|}ý~}~~}~ü~~€€ù‚‚‚‚‚ƒþ„||}þ~}}ü~}}~~ú~~û€€€€ü€€‚þ‚‚ƒ|}ú|}}||}}~þ}~~~ý€€€û€€‚øƒ‚ƒƒ‚‚ƒ{{|õ}||}}|}}~}~~€€ý€ý‚‚‚ýƒ‚ƒƒý‚{||}ø~}~}~~}~~ü~~þ€€‚ùƒ‚‚ƒ{{||þ{||}ü|}|}}~þ~~þ€€û€€û‚‚‚‚þƒ‚‚{ |}~þ}~~ü~~ú€€€€ù€€€ý‚‚‚{ý|{||}|}þ~}}~ €þ€€þ‚‚{ü|{{||}þ|}}~ü}~}~~€þ€€ù€‚‚û‚zz{{|ý}|}}þ~}}~ö€€€€€€€z{ú|{{|{||ü}||}}þ~}}~~€þ€€þ€€÷‚{zz{zz{{|ý}|}} ~€þ€‚óz{z{zz{z{{|{{|û}|}|}}ú~}}~}~~ý€€€zú{zz{z{{|þ{||}þ|}}ý~}~~ €þ€€þ€€ý€÷þö÷÷üø÷ø÷÷þø÷÷ø÷øþ÷øøþ÷øøú÷øø÷÷øøú÷øø÷ø÷÷üø÷ø÷÷þø÷÷øú÷øø÷÷øøý÷ø÷÷øû÷øø÷øø÷þö÷÷ø÷üø÷ø÷÷øþ÷øøþ÷øøù÷ø÷øø÷øø÷ûø÷ø÷øø÷þö÷÷ðø÷ø÷÷øø÷ø÷ø÷ø÷ø÷÷ùø÷÷øø÷øøû÷øøö÷÷ûö÷÷ö÷÷þø÷ ÷üø÷ø÷÷üø÷÷øøü÷ø÷øøþ÷ööû÷ö÷ö÷÷þö÷ ÷þø÷÷ø÷ýø÷øøú÷ø÷ø÷øøü÷øø÷÷øü÷öö÷÷þö÷÷úø÷÷øø÷÷ýø÷øø÷øö÷ø÷÷ø÷ö÷ö÷÷ö÷ö÷þö÷÷þø÷÷øô÷ø÷÷øø÷÷ø÷ø÷÷ûø÷øøöö÷þö÷÷ö÷ø÷üø÷ø÷÷øó÷ø÷ø÷÷ø÷÷ø÷ø÷÷øþ÷øø÷þö÷÷þö÷÷ö÷üö÷ö÷÷þø÷÷þø÷÷ø÷øþ÷øøöþ÷öö÷ö÷ûö÷÷ö÷ ÷úø÷ø÷ø÷÷úø÷÷øø÷÷úø÷ø÷÷øø÷öø÷ø÷ø÷÷øö÷÷þö÷÷ûö÷öö÷÷þö÷÷þö÷÷ûø÷÷ø÷÷ûø÷÷ø÷÷ø÷ýø÷øø÷úø÷ö÷÷öö÷ö÷þö÷÷âø÷øø÷÷øø÷ø÷øø÷÷ø÷÷ø÷÷ø÷øø÷ø÷ö÷÷öü÷öö÷÷þö÷÷þø÷÷þø÷÷þø÷÷ûø÷øø÷÷ø÷ùö÷ö÷öö÷÷ö÷öý÷ö÷ ÷þø÷÷ýø÷øø÷ûø÷ø÷øøö÷øø÷ø÷øøö÷÷þö÷÷þö÷÷þö÷÷þö÷÷þö÷÷þö÷÷ø ÷ûø÷ø÷øøý÷ø÷÷öú÷öö÷ö÷÷öý÷ö÷÷þø÷÷ø÷þø÷÷ø÷ûø÷÷ö÷÷öþ÷ööü÷öö÷÷þö÷ ÷þø÷÷øû÷ø÷ø÷÷ø÷öþ÷ööý÷ö÷÷üö÷ö÷÷öý÷ö÷÷þø÷÷ôø÷÷ø÷ø÷÷ø÷÷öö÷þö÷÷ýö÷öö÷þö÷÷ø÷ø÷üøö÷öö÷úö÷ö÷÷öö÷ùö÷÷ö÷ö÷÷ö÷ø÷ø÷ ö÷ýö÷ööó÷öö÷÷ö÷÷ö÷öö÷ ÷þø÷ ÷þø÷÷ûøö÷ö÷÷ö÷ýö÷öö÷þö÷÷ûö÷÷ö÷÷þö÷÷þö÷ ÷þø÷÷ø÷öø÷÷ö÷öö÷÷öö÷ö÷üö÷ö÷÷þö÷÷ø÷úø÷öö÷öö÷ûö÷ö÷öö÷þö÷÷ûö÷÷ö÷÷ö÷ø÷ýø÷øø öþ÷ööý÷ö÷÷üö÷ö÷÷þö÷÷þø÷÷öþ÷öö÷þö÷÷ö÷þö÷÷þö÷ ÷þö÷ ÷úø÷öö÷ööô÷ö÷öö÷÷öö÷÷öö÷þö÷÷þö÷÷þö÷÷üø÷ø÷÷öþ÷ööý÷ö÷÷ûö÷öö÷÷ö÷ö÷øø÷÷ø÷ø÷ööþ÷öö÷ö÷ö÷ýö÷öö÷þö÷÷ö÷øö÷÷ö÷÷ö÷÷þö÷÷þø÷÷üø÷øööþ÷ööó÷öö÷ö÷ö÷÷ö÷÷ööù÷öö÷ö÷öö÷þö÷÷öþ÷ööû÷öö÷ööù÷öö÷ö÷öö÷ö÷þö÷÷þö÷ ÷þø÷÷öþ÷öö÷öü÷ö÷ööþ÷ööù÷ö÷öö÷öö÷÷öö÷öö÷ö÷÷þö÷ ÷ öü÷ö÷ööü÷ö÷ööþ÷öö÷üö÷ö÷÷ö÷þö÷ ÷öü÷öö÷÷üö÷÷ööþ÷öö÷þö÷÷öù÷öö÷öö÷÷þö÷÷ öþ÷ööþ÷öö÷öõ÷öö÷ö÷ö÷÷ö÷÷üö÷ö÷ ÷þõööþ÷ööþ÷öö÷öü÷öö÷÷üö÷ö÷÷úö÷÷öö÷÷üö÷ö÷÷þö÷÷þõööþõööþ÷ö ö÷õö÷÷öö÷ö÷÷ö÷÷ûö÷÷ö÷÷ûö÷÷ö÷÷ öô÷ö÷öö÷÷ö÷ö÷ööô÷öö÷÷ö÷ö÷ö÷öö÷þö÷÷þö÷÷þö÷÷öû÷öö÷ööú÷öö÷÷ööû÷ö÷ö÷÷ö÷ö ÷ö÷ö÷öü÷öö÷÷ö÷ýö÷ööþ÷öö÷öþ÷ööü÷ö÷ööþ÷öö÷üö÷÷öö÷þö÷÷ö÷öõ ö÷öû÷ö÷÷ööþ÷ööþ÷öö÷ö÷ýöõö öþõööþ÷ööþ÷öö÷öý÷ö÷ ÷þö÷÷öþõööþ÷ööþ÷öö÷öü÷ö÷öö÷þö÷÷üö÷ö÷÷öõöþõöö÷öü÷öö÷÷úö÷öö÷ööü÷ö÷ööú÷ö÷öõööþõööø÷ö÷öö÷÷ööü÷ö÷ööú÷öö÷ö÷÷öþ÷ööüõöõööþõö öþ÷ööþ÷ööû÷ö÷÷ööü÷öö÷÷ûö÷÷ö÷÷þö÷÷öö÷õõööõööõõûöõöõöö÷ öú÷ö÷öö÷÷öþ÷öö÷üöõõööõöûõöõõööþõööù÷ö÷öö÷ööø÷ö÷÷ö÷ö÷÷÷ö÷ö÷ö÷ööõõ öõöö÷ö÷÷ö÷ö÷÷ööþ÷ööþõööõ öþõööþ÷ööþ÷ööü÷öö÷÷ýö÷ööþ÷ööùõöõõöõööõýöõööþõööþ÷ööú÷ö÷ö÷öö÷ûö÷÷ö÷÷ö÷ööõöõööõõöõõýöõööûõööõööþ÷öö÷ö÷þö÷÷õ÷öõöõööõõööõöþõööü÷ö÷ööþ÷ööõ÷ö÷õõöõõööõõöþõööõöþ÷öö÷üö÷÷ööû÷ö÷÷ööþõööõöþõööúõöõöõööþõööö÷öö÷ö÷÷öö÷÷ùöõõöõõööõöüõöõö öþõööþ÷öö÷öø÷ö÷öõõöõõööõöõõöõõöõööþõöö÷öû÷ö÷÷ööþ÷ööõôöõöõöõõööõõööùõööõöõööüõöõööþõööû÷öö÷ööþ÷ööþ÷ööþ÷õõþöõõúöõõöõööõöþõööýõöõõ öþ÷öö÷üö÷÷ööõùöõõöõöõõöòõöõõöõõööõööõööþõööü÷ö÷ööý÷öõõúöõõööõõüöõõööõüöõõööõýöõöö÷öþ÷ööõþöõõöõöõöõöþõöö÷õöõõööõõöö÷ÿ† ‡ˆ‰ùˆ‰‰Š‰Š‰‰Šþ‹ŠŠ‹Œþ‹ŒŒþŒŽù††‡††‡‡ˆþ‡ˆˆ ‰Šü‹ŠŠ‹‹Œýކ†ü‡††‡‡ýˆ‡ˆˆ‰þˆ‰‰ýЉŠŠü‹ŠŠ‹‹Œþ‹ŒŒûŽŽ…†† ‡ˆþ‡ˆˆý‰ˆ‰‰üЉЉ‰Šø‹Š‹Š‹Š‹ŒŒüŒŒŽû††…††‡öˆ‡ˆ‡‡ˆˆ‰‰ˆˆ‰Š ‹ýŒ‹ŒŒûŒŒ…ý†…††û‡†‡†‡‡ˆ‰Šü‹ŠŠ‹‹ýŒ‹ŒŒýŒ…ú†…††…††ý‡†‡‡ˆý‰ˆ‰‰þЉ‰Šþ‹ŠŠ‹Œþ‹ŒŒþŒ……†‡ˆü‰ˆˆ‰‰ýЉŠŠø‹Š‹Š‹‹Œ‹‹ýŒ‹ŒŒ÷„……††…†…††‡†‡ˆ‡ˆ‰Š‰Šü‹ŠŠ‹‹Œþ‹ŒŒþ„„…† ‡ˆþ‰ˆˆ‰Š‹þŠ‹‹Œ„ …†‡þ†‡‡ˆþ‡ˆˆ‰üˆ‰ˆ‰‰Šþ‰ŠŠ‹þŠ‹‹Œ„ü…„„……ý†…††ú‡†‡††‡‡ˆ‡ˆ‰Šþ‰ŠŠ‹þŠ‹‹Œþ‹ŒŒ„…þ„……†þ‡††‡óˆ‡ˆˆ‡ˆˆ‰ˆˆ‰ˆ‰‰ýЉŠŠý‹Š‹‹Œ„…ý†…††ù‡††‡‡†‡‡üˆ‡‡ˆˆü‰ˆˆ‰‰üЉ‰ŠŠþ‹ŠŠ‹ýŒƒ„„ý…„……û†…†…††‡ü†‡†‡‡ˆý‰ˆ‰‰üЉ‰ŠŠ‹ƒ„ý…„……†‡þ†‡‡ˆ‰ˆ‰Šþ‰ŠŠ‹ƒ„…þ„……†ý‡†‡‡ˆý‰ˆ‰‰üЉ‰ŠŠ‹ýƒ„ƒƒ„…þ„……†þ…††ü‡††‡‡üˆ‡‡ˆˆü‰ˆˆ‰‰úЉ‰Š‰ŠŠ‹Šƒ„…ù„……†…†……†‡†‡ˆþ‡ˆˆ÷‰ˆˆ‰‰ŠŠ‰ŠŠƒ„üƒ„ƒ„„ý…„……† ‡ˆ‰ýЉŠŠü‚ƒ‚ƒƒý„ƒ„„…û„……„……þ†……†ý‡†‡‡ýˆ‡ˆˆý‰ˆ‰‰ûЉЉŠŠúƒ‚‚ƒ‚ƒƒ„þ…„„…þ„……†þ…††ü‡††‡‡ýˆ‡ˆˆø‡ˆˆ‰ˆ‰ˆ‰‰üЉ‰ŠŠþ‚ƒƒ÷‚ƒƒ„ƒ„ƒƒ„„ü…„„……†ý‡†‡‡ˆþ‡ˆˆý‰ˆ‰‰Š‚üƒ‚‚ƒƒþ„ƒƒ„ü…„„……ý†…††‡ù†‡‡ˆ‡‡ˆˆ‰þˆ‰‰Š‰‚ƒ‚ƒ„…„÷…„…†…†……††‡ˆ‰øˆ‰Š‰‰Š‚‚ƒ„ƒö„ƒ„„…„„…„……†þ…††‡†ý‡†‡‡ýˆ‡ˆˆ‰ ‚ùƒ‚ƒƒ„ƒ„„…þ†……†þ‡††ý‡†‡‡üˆ‡‡ˆˆý‰ˆ‰‰ûˆ‰‰Š‚ƒþ„ƒƒ„þ…„„…ý†…††‡üˆ‡ˆ‡‡ˆ‰‚ý‚‚‚ûƒ‚ƒ‚ƒƒ„û…„…„……†þ‡††‡ûˆ‡ˆ‡ˆˆ‰þˆ‚ýƒ‚ƒƒ„þƒ„„ú…„…„„……†‡ü†‡†‡‡ýˆ‡ˆˆú‰ˆ‰ˆˆ‚ƒ‚ƒ„þƒ„„…†…ý†‡††‡üˆ‡‡ˆˆý‰ˆ‚ýƒ‚ƒƒþ‚ƒƒ „…†ü‡††‡‡ýˆ‡ˆˆý‰€€‚ýƒ‚ƒƒ„þƒ„„…†…†‡ýˆ‡ˆˆû€€ú‚‚‚‚ƒû‚ƒƒ„ƒƒ„…þ„……†‡†‡þˆ‡‡ôˆ‡‡€€€€ý‚‚‚øƒ‚ƒ‚ƒƒ‚ƒƒ„…ý†…††‡ˆþ‡€€€þ‚‚ûƒ‚ƒ‚ƒƒû„ƒ„ƒ„„ú…„…„„……û†…†…††þ‡††‡€ü€€‚þ‚‚ƒü„ƒƒ„„ú…„……„……†‡þ†‡‡ €‚ƒû‚ƒƒ‚ƒƒ„…„…û†…†…††ý‡†‡‡ý€€€û€€ü‚‚‚ûƒ‚ƒ‚ƒƒ„ü…„„……†‡ý†‡ý€€€þ€€ý€ü‚‚‚ýƒ‚ƒƒþ„ƒƒ„þ…„„…þ†……†þ‡††þ‡û€€€€ý€û‚‚‚‚ƒþ‚ƒƒ„þƒ„„ …ý†…††‡€þ€€û€€‚þ‚‚ƒþ„ƒƒ„û…„…„……ý†…††ú‡††‡~þ€€þ€€þ‚‚ƒ‚ýƒ‚ƒƒ„…þ„……ý†…††~ý~€ý‚‚‚ýƒ‚ƒƒý„ƒ„„…ü†……††ù…††~~ý€€€þ€€ý‚‚‚úƒ‚ƒ‚‚ƒƒ„÷…„…„„…††……†ý~~~ý€€€ü€€ý‚‚ ‚ƒ„þƒ„„…†þ…~~û~~ý€€€ú€€€‚ýƒ‚ƒƒ„þƒ„„ö…„……††……}~~ý~û€€€€ú€€€ý‚‚‚ƒ‚üƒ‚„ƒƒ „…~€þ€ú‚‚‚‚‚ƒþ‚ƒƒý„ƒ„„ý…„……ù†}}~~}~~€þ€‚‚ýƒ‚ƒƒ„üƒ„ƒ„„…û}~}}~~ý~ý€€€þ€€‚ƒ‚ƒ„…}~û~~~€þ€€ý€‚ýƒ‚ƒƒü„ƒƒ„„…þ|}}ý~}~~þ~~ý~€ý€‚üƒ‚‚ƒƒ„õƒ„ƒ„ƒ„…„…|}}~þ~ý€€€û€€ý‚‚‚ƒ‚ƒ„û…}}|}}ý~}~~þ~€þ€€þ€€ý€‚‚ƒ„üƒ„„||} ~þ€€þ€‚ƒû„ƒƒ„|| }~ý~ü€€€û€€‚ýƒ‚ƒƒþ„ƒƒ|}þ|}}~þ~€þ€€û€€ü‚‚‚üƒ‚‚ƒƒü„|{||}~û}~~}~~ü~~ý€€€ù€€€€ý‚‚‚þ‚‚ƒþ‚ƒƒý|{||ý}|}}ý~}~~ú~~€ý€‚ü‚‚‚ƒû{||{||}~}~ü€€€þ€‚ƒ{ü|{{||}þ|}}þ~}}~ü~~€þ€€ý€‚öƒ‚{{|{||{||}ý~}~~þ~ý€€€ý‚‚‚ƒ{|ü}||}}~ý~ü€€€þ€‚ü‚ƒ‚‚ŒýŒŽüŽŽþý‘‘‘’“ü’“’““ŒþŒ ŽýŽ ý‘‘‘ü’‘‘’’ú‘’““’““’ýŒ‹ŒŒþŒŽýŽŽŽûŽŽù ‘’þ“’’ý‹Œ‹‹ŒýŒŽŽõ‘‘‘’‘’’‘’’÷“’“‹‹ŒŒ‹ŒŒþŒŒýŒýŽŽŽúŽŽŽú‘þ‘‘ý’‘’’þ‘’’‹Œû‹ŒŒ‹ŒŒüŒŒŽŽüŽŽþ‘‘þ’‘‘ü’“’‹‹ýŒ‹ŒŒŽûŽŽŽŽýŽý‘’‹ŒýŒŽüŽŽþý‘‘‘’‘‹ŒýŒ ŽýŽþýü‘‘‘’Š‹üŒ‹‹ŒŒýŒõŽŽŽŽŽŽý‘ö‘‘‘’‘‘’ŠŠý‹Š‹‹ŒûŒŒýŽŽŽüŽŽ ‘Š‹þŠ‹‹üŒ‹Œ‹‹ŒýŽŽŽýŽþ‘þ‘‘Š‹Œ‹ŒŒûŽŽŽŽþ‘Š‹ŒýŽŽŽ ‘ý‘ŠŠ‹ûŒ‹Œ‹ŒŒüŒŒûŽŽŽŽýø‘‘‰Š‰ŠŠú‹Š‹‹Š‹‹ýŒ‹ŒŒùŒŒŒŽüŽŽŽþŽüþ‘‰‰Šþ‹ŠŠ‹ýŒ‹ŒŒüŒŒýŽŽŽù‰Š‰‰Š‰ŠŠþ‹ŠŠ‹Œ‹ŒñŒŒŽŽŽŽŽþŽùþˆ‰‰Šþ‰ŠŠ ‹ŒþŒýŽŽŽüŽŽ‰üЉ‰ŠŠ‹Š‹Œ‹ŒþŒŒþŽŽùŽŽŽøˆ‰‰ûЉЉŠŠ‹ýŒ‹ŒŒúŒŒ ŽþŽˆ‰þЉ‰Š‹þŠ‹‹þŒ‹‹ŒýŒüŽŽŽúˆˆ‰ˆ‰‰þЉ‰Šý‹Š‹‹Œ‹ŒüŒŒýŽŽŽ ˆþ‰ˆˆ‰Š‰Š‹Œþ‹ŒŒýŽŽŽþŽþ‡ˆˆ‰ñЉ‰ŠŠ‰‰ŠŠ‹Š‹‹Š‹‹ŒŽþŽŽˆ‰þˆ‰‰Šû‹Š‹Š‹‹úŒ‹ŒŒ‹ŒŒýŒŽŽýŽû‡ˆˆ‡ˆˆý‰ˆ‰‰Šþ‰ŠŠú‹Š‹ŠŠ‹‹Œþ‹ŒŒŽøŽŽŽ‡ˆˆý‰ˆ‰‰üЉ‰ŠŠ‹÷ŠŒ‹‹Œ‹Œ‹ŒŒöŒŽŽŽŽ‡ˆ‰Š‹þŠ‹‹ûŒ‹Œ‹ŒŒùŒŒŒŽúŽŽŽ‡‡úˆ‡ˆˆ‡ˆˆ‰ˆ‰Š‹þŠ‹‹ŒýŒýŽŽŽ‡þˆ‡‡ˆý‰ˆ‰‰Šþ‰ŠŠ‹þŠ‹‹öŒ‹Œ‹ŒŒŒŒúŒŽŽŽý†‡‡ˆ‡ˆþ‰ˆˆ‰ýЉŠŠ‹þŠ‹‹Œ‹ŒýŒþŽŽ‡ˆþ‡ˆˆ‰÷ˆ‰ˆ‰ˆ‰‰Š‰‰Š‹Œþ‹ŒŒýŒõŽŽ‡††‡‡†‡‡ˆþ‡ˆˆ‰Šþ‰ŠŠ‹Œ‹ŒýŒþކ†ý‡†‡‡þˆ‡‡ˆ‰ûˆ‰‰ˆ‰‰Šý‹Š‹‹þŒ‹‹Œ†‡ýˆ‡ˆˆ‰ýЉŠŠþ‹ŠŠ‹Œþ‹ŒŒ†ú‡†‡‡†‡‡ˆþ‡ˆˆ‰þˆ‰‰ýЉŠŠ‹üЋЋ‹ýŒ‹ŒŒ÷Œ……†…††‡þ†‡‡ˆ‰þˆ‰‰üЉ‰ŠŠþ‰ŠŠý‹Š‹‹ýŒ‹ŒŒý…††‡ˆü‰ˆˆ‰‰üЉ‰ŠŠ‹ôŠ‹‹Š‹‹Œ‹‹Œ‹ŒŒþ……†ý‡†‡‡óˆ‡‡ˆˆ‰ˆˆ‰ˆ‰ˆ‰‰Š‹ŒöŒ……††…†…††‡þ†‡‡ˆý‰ˆ‰‰ýЉŠŠ‹Šø‹Œ‹‹ŒŒ‹ŒŒ…†þ…††û‡†‡†‡‡ ˆ‰þˆ‰‰Šþ‰ŠŠ‹ýŒ‹ŒŒ…†þ…††ü‡††‡‡ýˆ‡ˆˆ ‰Š‹þŠ‹‹üŒ‹‹ŒŒü‹Œ„……û†…†…††‡†‡ˆþ‡ˆ ˆ‰Š‹þŠ‹‹Œ„…†‡ˆþ‡ˆˆ‰Šû‹ŠŠ‹ŠŠ‹„ü…„„……ý†…††þ‡††‡ˆ‡ˆú‰ˆ‰ˆˆ‰‰ûЉЉŠŠ‹þŠ‹‹„…ù„…„……†……†ø…††‡†‡†‡‡ˆ‡ˆ‰ˆ‰Š‰Šý‹Š‹‹„…„…†þ…††‡ù†‡†‡‡ˆ‡‡ˆ‰ˆ‰Šþ‰ŠŠõ‹ŠŠ‹‹Š‹‹„ƒ„„…þ„……ý†…††ü‡††‡‡úˆ‡ˆˆ‡ˆˆ‰þˆ‰‰üЉ‰ŠŠ‹ü„ƒƒ„„…†…†‡ˆþ‡ˆˆú‰ˆ‰ˆˆ‰‰üЉ‰ŠŠý‹Š„ „…ú†……†…††‡þ†‡‡öˆ‡‡ˆ‡ˆˆ‡‰ˆˆ‰ Šú‹Šƒ„ƒ„„ý…„……þ„……†þ‡††‡ˆý‰ˆ‰‰Šƒ„þƒ„„…ü„…†……†ú‡†‡‡†‡‡ýˆ‡ˆ ˆ‰Šü‰Š‰ŠŠƒ„…†ý‡†‡‡þ†‡‡ûˆ‡ˆ‡ˆˆü‰ˆˆ‰ ‰Šýƒ‚ƒƒþ„ƒƒ„…þ„……†‡þ†‡‡úˆ‡ˆˆ‡ˆˆ‰þˆ‰‰üŠ‰Šƒƒù„ƒƒ„„ƒ„„…†ü‡††‡‡ˆþ‡ˆˆ‰Šý‰Š‚‚ƒú„ƒ„ƒƒ„„ …û†…†…††ý‡†‡‡ˆ‡ˆ÷‰ˆˆ‰ˆˆ‰Š‰‰ùŠ‚‚ƒ‚‚ƒƒ„ƒ„…ü†……††þ‡††‡úˆ‡‡ˆ‡ˆˆý‰ˆ‰‰üЉ‰‚‚ƒý„ƒ„„þƒ„„ý…„……†‡ýˆ‡ˆˆ‰þ‚‚ƒü„ƒƒ„„…÷†…†…†…†‡††ý‡†‡‡ýˆ‡ˆˆü‰ˆˆ‰‰øˆ‰‚‚‚ƒ‚‚ûƒ‚ƒ‚ƒƒ„…þ„……õ†…††…†‡‡††‡‡ˆ‡ˆ‰ý‚‚‚ ƒý„ƒ„„…÷†…††…††…††‡úˆ‡ˆ‡‡ˆˆù‰ˆˆ‚‚‚ýƒ‚ƒƒþ„ƒƒ„úƒ„„……„„…†‡ˆþ‡ˆˆý‚ö‚‚ƒ‚‚ƒ‚‚ƒƒ„ƒ„ò…„„…„…„…†……†…††‡ˆøþùøøþùøøùøùþøùùûøùøøùùþøùù÷øùùøøùùøùùþøùù øùøþùøøùùøøùøøùùøüùøøùùúøùùøøùùþøùùûøùùøùùýø÷ø øþùøøþùøøùøüùøùøøùøùùøùøùøùùþøùùø÷ øûùøøùøøúùøøùùøøùøùþøùùõøùùøøùùøùøùùøþùøøþùøøùøùøùþøùù øþ÷ø øþùøøøùøùøùøùøøùøúùøùøøùùþøùùöøùøø÷ø÷ø÷ø øþùøøúùøùøøùùøôùøùùøùùøùùøùùþøùùþøùùøþ÷øøþ÷øøþùøøùøôùøùùøøùùøùùøøùûøù÷÷øøûùøøùøøþùøøùüøùùøøüùøøùùøþùø øùùøùùøøùùøøùùøøùùøøþùøøùþ÷øøþ÷øøøùøøùøøùøøûùøøùøøùùøùùøùøøùøþ÷ø øþ÷ø øñùøùøøùùøùøùøøùøøýùøùùýøùøøû÷øø÷øøû÷øø÷øøþùøøþùøøùøùøùþøùùøù÷ø÷ø÷÷øøþ÷øøüùøùøøûùøøùøøùøýùøùùøöùøøùùø÷ø÷øøþ÷øøþ÷øøþ÷ø øþùøøúùøøùùøø÷ùøøùøøùùøøùøüùøø÷÷üø÷÷øøþ÷øøþ÷øøþ÷øøüùøùøøüùøùøøùòøùøùøùøøùù÷ø÷øøü÷ø÷øø÷øþ÷ø øþùø øüùøùøøøùøùøùùøùùøü÷ø÷ø øû÷øø÷ø øùøþùøøþùøøùýøùøøþ÷øøü÷ø÷øøþ÷øøüùøùøøþùøøùøùüø÷ø÷÷øû÷ø÷÷øøü÷ø÷øøþ÷øøþùøøþùøøþùøø÷õø÷÷øø÷øø÷÷øøû÷øø÷øøþ÷ø øþùøøþùøøòùøøùùøùøùøøùùøøù÷ø÷ø÷÷øø÷øþ÷øøúùøøùùøøùøùý÷ø÷÷øø÷ø÷øø÷øøþ÷øøü÷ø÷øøþùøøùûøùøø÷÷øí÷ø÷ø÷øø÷÷øø÷ø÷øø÷÷øøùþøùùøýùø÷÷ýø÷øø÷ø÷ø÷øüùøùøø÷ðø÷÷øø÷ø÷ø÷øø÷ø÷øø÷ýø÷øøþùøøùø÷ôø÷ø÷ø÷ø÷ø÷÷øøü÷ø÷øø÷øþ÷øøþùøøùùøøùøùøø÷ø÷ýø÷øøü÷ø÷øøý÷ø÷÷ýø÷øøüùøøùùøùý÷ø÷÷üø÷ø÷÷øù÷ø÷÷øø÷÷øþ÷øø÷ýø÷øøþ÷øøþ÷ø øûùøøùøø÷øû÷øø÷øø÷ýø÷øøþ÷øø÷ûø÷ø÷øøû÷ø÷ø÷÷þø÷÷øù÷ø÷÷ø÷øø÷ø÷ýø÷øø÷øü÷ø÷øøþùøøù÷úø÷ø÷ø÷÷ùø÷ø÷ø÷øøû÷ø÷÷øøþ÷øø ÷þø÷÷ø÷øø÷ø÷øø÷øøþ÷øø÷øþùøø÷þø÷÷þø÷÷ø÷üø÷÷øøü÷ø÷øøþ÷øø÷þø÷÷þø÷÷øû÷ø÷ø÷÷øü÷ø÷øø÷þø÷÷ø÷þø÷÷úø÷ø÷ø÷÷ûø÷÷ø÷÷÷ø÷ø÷÷øø÷øøþ÷øøþùøø÷þø÷÷üø÷ø÷÷úø÷÷ø÷øøý÷ø÷÷øø÷øø÷ø÷øøþ÷øøþ÷øø÷þø÷÷þø÷÷þø÷÷óø÷÷ø÷ø÷ø÷ø÷÷øø÷øü÷ø÷ø ø÷þø÷÷ø÷þø÷÷ïø÷øø÷øø÷÷øø÷÷ø÷÷øø÷þø÷÷þø÷÷øû÷ø÷÷øøù÷ø÷øø÷øø÷þö÷ ÷þø÷÷þø÷÷þø÷÷üø÷ø÷÷ýø÷ø øþ÷øø÷ø÷þø÷÷òø÷ø÷ø÷÷øø÷øø÷øø÷ýø÷øø÷ø÷ø ÷þø÷÷ùø÷ø÷øø÷÷ø÷þø÷÷øø÷øø÷øø÷øøþ÷øø÷þø÷÷õø÷ø÷÷ø÷ø÷÷øøþ÷øøþ÷øøþ÷øø÷þø÷÷þø÷÷øü÷øø÷÷÷ø÷÷ø÷øø÷øø÷ûø÷ø÷øøú÷ø÷÷ö÷ ÷üø÷ø÷÷ûø÷øø÷÷úø÷ø÷ø÷÷üø÷÷øøþ÷øøö÷ø÷øøö÷÷ö÷÷þö÷÷þø÷÷ø÷úø÷ø÷ø÷÷üø÷ø÷÷óø÷ø÷øø÷øø÷ø÷øø÷ûø÷ø÷öö÷ûö÷÷ö÷÷üø÷ø÷÷üø÷ø÷÷ûø÷÷ø÷÷ùø÷ø÷ø÷øø÷øþ÷øøþö÷÷þö÷÷þø÷÷þø÷÷øþ÷øøý÷ø÷÷õø÷ø÷÷øø÷öö÷÷þø÷÷þø÷÷ø÷øþ÷øøü÷ø÷øøþö÷÷úö÷ö÷ö÷÷þö÷÷þø÷÷ø÷øû÷ø÷÷øø÷ùø÷ø÷ø÷øøô÷ø÷öö÷÷öö÷ö÷÷ö÷üø÷ø÷÷øú÷ø÷÷ø÷÷ýø÷øø÷÷ø÷÷øø÷÷ö÷÷þö÷÷þö÷÷þö÷ ÷þø÷÷ø÷øø÷ø÷÷øø÷÷þø÷÷ôø÷ø÷öö÷öö÷ö÷ ÷þö÷÷þø÷÷üø÷÷øø÷þø÷÷øü÷ø÷øø÷ûø÷÷ö÷ ÷þö÷÷ýø÷øøú÷ø÷÷ø÷÷ùö÷ö÷÷ö÷÷ö÷þø÷÷üø÷÷øø÷øú÷øø÷÷øø÷öö÷÷öö÷÷öö÷÷úö÷÷öö÷ ÷þø÷÷þø÷÷÷ø÷÷øø÷÷ø÷÷õø÷ø÷ø÷ö÷öö÷÷úö÷÷öö÷÷þö÷÷ûö÷÷ö÷÷þö÷÷þø÷÷ø÷ø÷ýøö÷÷öõ÷öö÷ö÷÷ö÷ö÷÷þö÷÷þø÷÷÷ø÷÷øø÷øø÷÷úøö÷ö÷öö÷ûö÷÷ö÷÷þö÷÷þö÷ ÷þø÷÷þø÷÷üø÷ø÷÷ýø÷öö÷þö÷÷þö÷÷üö÷ö÷÷þö÷÷þø÷÷þø÷÷ø÷ôø÷÷øø÷ø÷ö÷÷öö÷üö÷÷öö÷ûö÷÷ö÷÷ùø÷÷ø÷ø÷÷ø÷ö÷öý÷ö÷÷ö÷ø÷ýøö÷÷ö÷ö÷öû÷ö÷ö÷÷þö÷÷þö÷÷úø÷ø÷ø÷ÿŽŽ÷‘‘‘‘’‘’ý“’““ý”“””•þ”••ú–•–•–ŽŽüŽŽ‘ø’‘‘’’““’’“û”“”“””•–þŽŽýŽý‘ý’‘’’“ ”•÷ŽŽŽŽŽŽýŽýü‘‘‘’þ‘’’“”þ“””û•”•”••þŽŽþ‘û’‘’‘’’ý“’““ü”““””ý•”••ŽþŽŽûŽý‘‘‘û’‘’‘’’“”þ“””•ŽþŽþŽþ‘þ‘‘’ü“’’““”þ“””ýŽŽŽþŽŽü‘ý’‘’’þ‘’’ý“’““”ú•ŒŒŽþŽŽ ‘’“õ’““’“”“””“””ûŒŒúŽŽŽŽýŽþø‘‘‘’‘‘’’ü“’’““ù”“””ŒŒŒûŽŽŽûŽŽþþ‘‘’þ‘’’“þ’““”ŒûŽŽŽŽþŽ‘’ý“’““ü”““ŒŒýŒûŽŽŽŽýŽû‘û‘‘‘þ’‘‘’“þ’““ý”“ŒŒþŒýŽŽŽýŽ‘þ‘‘ ’ü“’’““ü”‹‹ŒŒþŒŽüŽŽ‘þ‘‘ú’‘’’‘’’“ø”‹‹Œ‹Œ‹ŒŒŽŽþŽŽý‘‘‘ú’‘’’‘’’“‹ŒüŒŒŒŽüŽŽý‘‘‘ü’‘‘’’ú“’’““‹‹ýŒ‹ŒŒüŽŽŽŽý ‘ý’‘’’ù‘’’“’“‹‹úŒ‹Œ‹‹ŒŒýŒŽþŽþü‘‘‘ü’‘‘’’ù“’’ЋЋ‹ûŒ‹Œ‹ŒŒŒŽþŽ‘’ú‹Š‹‹Š‹‹Œþ‹ŒŒýŒŽúŽŽ‘‘’þ‘’’Š‹üŒ‹‹ŒŒ ŽýŽý‘‘‘þ’‘‘þ’ŠŠ‹ûŒ‹Œ‹ŒŒþŒŒýŒŽŽüŽ ‘û’‘‘’ŠŠ‹ýŒ‹ŒŒþŒýŽŽŽþŽŽüŽŽý‘‘’þ‰ŠŠ‹ŒŒŽýŽú‘‘‘ý’‘ŠŠ‹Œ‹ŒûŽŽŽŽþ‘þ‘‘‰ýЉŠŠ‹ŒþŒŽþŽŽþŽþ‘þ‘‘‰Š‹þŠ‹‹Œþ‹ŒŒ ŽúŽŽŽ‘þ‘‰‰ýЉŠŠû‹Š‹Š‹‹üŒ‹‹ŒŒýŒþŽýŽŽŽú‘ü‘ˆ‰‰ýЉŠŠý‹Š‹‹Œ‹ŒüŒŽŽþŽŽûŽŽüý‘ˆ‰‰Šþ‰ŠŠû‹Š‹Š‹‹ŒŽþŽŽþމˆ‰Š‰Š‹ôŠ‹‹ŒŒ‹‹Œ‹ŒŒþŒþŽŽýŽû‰ˆü‰ˆˆ‰‰Šû‹Š‹Š‹‹Œþ‹ŒŒýŒŽþŽŽýŽýˆˆ ‰Šù‹Š‹Š‹Š‹‹ŒþŒŒýŒŽôŽŽŽˆˆ‰úЉЉ‰ŠŠ‹ŒþŒüŽŽŽüŽŽùˆˆ‡ˆˆ‰Šü‹ŠŠ‹‹ýŒ‹ŒŒúŒŒŒ Žüˆ‡‡ˆˆ‰þˆ‰‰Šþ‰ŠŠ‹þŠ‹‹ ŒýŒŽüŽŽú‡‡ˆ‡ˆˆý‰ˆ‰‰Š‹Œ‹ŒþŒŽþŽŽ‡ýˆ‡ˆˆ‰óˆ‰‰ˆ‰‰Š‰Š‰Š‰ŠŠú‹ŠŠ‹Š‹‹Œ‹ŒþŒ÷ŽŽŽŽŽŽ‡ˆþ‡ˆˆ‰Šý‹Š‹‹Œþ‹ŒŒ ýŽŽŽý‡†‡‡ˆ‡ˆ‰þˆ‰‰Šú‹Š‹‹Š‹‹Œ‹ŒñŒŽŽŽŽŽŽ‡‡ˆþ‡ˆˆ‰þˆ‰‰üЉ‰ŠŠ‹þŠ‹‹ŒŽŽýކ†‡ˆ ‰Šú‹ŠŠ‹Š‹‹üŒ‹‹ŒŒýŒôŽŽŽŽ‡†‡†‡‡üˆ‡‡ˆˆý‰ˆ‰‰Šý‹Š‹‹ûŒ‹Œ‹ŒŒŽ†‡ˆû‰ˆ‰ˆ‰‰Š‹þŠ‹‹ŒýŒþކ†ý‡†‡‡ˆ‰þˆ‰‰þЉ‰Š‹Š‹Œþ‹ŒŒûŒŒüކ…††ý‡†‡‡ˆþ‡ˆˆ‰þˆ‰‰üЉЉ‰Šþ‹ŠŠü‹ŠŠ‹‹ýŒ‹ŒŒüŒŒ†þ…††‡ ˆ‰Šþ‰ŠŠ‹Œ‹øŒ‹ŒŒŒŒú…†…†…††‡þ†‡‡þˆ‡‡ˆ‰üЉ‰ŠŠü‹ŠŠ‹‹þŒ‹‹ŒûŒ……†‡ˆþ‡ˆˆú‰ˆ‰ˆˆ‰‰Šþ‰ŠŠý‹Š‹‹úŒ‹Œ‹‹ŒŒúŒŒ……ý†…††û‡†‡†‡‡ˆý‰ˆ‰‰ûЉЉŠŠ‹Œþ‹ŒŒ…ü†……††‡þ†‡‡ýˆ‡ˆˆó‰ˆ‰‰ˆ‰Š‰Š‰Š‰ŠŠ‹þŠ‹‹Œ…þ†……ý†…††ý‡†‡‡ýˆ‡ˆˆý‰ˆ‰‰ Š‹þŠ‹‹þŒ‹‹Œú…„…„„……ü†……††÷‡†‡†‡‡ˆˆ‡‡ˆü‰ˆˆ‰‰Šþ‹ŠŠ‹Œþ‹ŒŒ„û…„…„……ý†…††ý‡†‡ ‡ˆü‰ˆˆ‰‰ýЉŠŠü‹ŠŠ‹‹Œ„…†‡üˆ‡‡ˆˆü‰ˆˆ‰‰ýЉŠŠ‹üЋЋ‹Œø„ƒ„…„…„……†þ…††ý‡†‡‡öˆ‡‡ˆˆ‡ˆˆ‰ˆˆ‰Šý‹Š‹‹Œü‹ƒƒ„„ü…„„……†‡þ†‡‡úˆ‡‡ˆ‡ˆˆ‰ýЉŠŠý‹Š‹‹üƒ„ƒ„„…†‡ø†‡†‡‡ˆˆ‡‡ˆþ‰ˆˆ‰ýЉŠŠý‹Š‹‹ƒ„þ…„„…ü†……††û‡†‡†‡‡ýˆ‡ˆˆ‰ïŠ‰ŠŠ‰ŠŠ‹‹ŠŠ‹‹Šƒƒ„„þƒ„„þ…„„… †‡ ˆ‰þˆ‰‰þЉ‰Šû‹Š‹‹ƒƒ„ù…„„……„……ü†……††ú‡††‡†‡‡üˆ‡‡ˆˆý‰ˆ‰‰Šþ‹ƒƒ„ƒ„ù…„„…„„……†þ…††ý‡†‡‡ˆý‰ˆ‰‰Šó‹Š‚ƒƒ‚ƒƒ„„ƒƒ„„ú…„…„„……†þ…†† ‡ˆþ‡ˆˆ‰ˆ‰Š“ý”“””•ý–•––ý—–——þ˜——˜ú™˜˜™˜™™þš™™šö™š›šš““”“””þ“””•û–•–•––—˜ ™š“”þ•””ý•”••–—þ–——˜ý™˜™™šþ’““”“”ý•”••ý–•––—þ–——˜þ—˜˜ý™˜™™ù˜™šš™™ššü’“’““ú”“”““””ú•”•””••–þ•––ü—––——þ˜——˜™˜™šú™“’“’““ý”“””þ•””•ý–•––—ý˜—˜˜þ—˜˜ý™˜™™þš’’ “”ü•””••þ–••–—˜þ—˜˜™’ “”ü•””••–þ•––ú—––—–——˜™’ú“’““’““”û“””“””•”•–ü•–•––ú—––—–——˜™’ü“’’““”ú•”••”••–ý—–——þ˜——˜ô—˜˜™™˜˜™™‘‘’’“”þ“””•ü”•”••–þ—––—˜ü—˜—˜˜ù™˜‘‘’‘’’“÷’““”“”““””û•”•”••ò–•–•–•–—––—––——ý˜—˜˜ü™˜˜‘‘’þ‘’’ü“’’““ü”““” ”ý•”••–ù—–——––——˜þ—˜˜‘’ý“’““ý”“””•ú–•––•––ý—–——˜þ—˜˜þ‘‘’“û’““”““ö”“”“””•””••û–•–•––—˜‘’ü‘’‘’’“ý”“””•þ–••–ú—––—–——˜þ‘‘ý‘’’þ‘’’“þ’““ú”““”“””•û–•–•––—þ–——ú˜—˜‘‘’‘ö’“’“’“’“’““þ”““”ú•”•””••ý–•–– —þ‘‘ù‘‘’‘‘’’ü‘’“’’ “” •ý–•––ý—–——ý‘‘‘’þ‘’’“þ”““”•–þ•––—þ–——ý‘‘‘ú’‘’’‘’’“ü’“’““”ý•”••ó–••–•––——–—–——þ‘þ‘‘ü’‘‘’’þ“’’“”÷•””•””•”––•–÷—–—–—‘þ’‘‘’“’“”“”•þ”••ý–•––û—–——ü‘‘‘þ’‘‘’“”ú•””•”••–•–ý—–þý‘‘‘ù’‘’‘’“’’“”ý•”••–þ•––þ‘þ‘‘û’‘’‘’’“þ’““ ”•û”••–••–ü•––þû‘‘‘‘’ü‘’‘’’“þ’““ú”“””“””•þ”••–ýŽüú‘‘‘‘‘ü’‘‘’’û“’“’““ù”“””““””þ•””•–ö•–ŽŽýý‘‘‘’þ‘’’ý“’““”þ•””•ŽýŽûû‘‘‘‘’“”ü•””••–ŽþŽŽ ‘’ù‘’’‘’“’’“û”“”“””ý•”••Žûý‘‘‘ ’“þ’““ü”““””•þŽŽýý‘‘‘’ü‘’‘’’ý“’““ý”“””•ýŽŽŽþŽþ‘þ‘‘ ’“’“”õ•””••”ŽŽŽü‘û‘‘‘’þ‘’’ú“’““’““ý”“””þŽùŽŽŽŽþŽ‘‘ý’‘’ ’“”û•”ŽúŽŽŽŽŽï‘‘‘‘‘’‘‘’’‘‘’’““’“”þ“””ú•ŒŽŽŽý‘þ‘‘’ý“’““ý”“””þŽŽûŽŽŽŽú‘‘’þ‘’’“”ŒŽüŽŽüû‘‘‘‘ý’‘’’ü“’’““”ý“”ŒŒüŽŽ Žýø‘‘‘‘‘ý’‘’’ý“’““ŒŽþŽŽúŽŽý‘þ‘‘’“þ’““ŒúŽŽŽŽŽýŽý‘‘‘’þ‘’’ý“’““ŒýŒþŽŽûŽŽý‘‘‘ý’‘’’ù‘’’“’’““ú’““Œ‹ŒŒýŒŽú‘‘ø’‘‘’‘’‘’’“’þ“ŒŒþŒøŽŽŽŽŽýŽüþ‘‘þ‘‘ý’‘’’“ü’“Œ‹‹ŒþŒ Žúü‘‘‘’‘’ý“’‹‹üŒ‹‹ŒŒøŒŒŒŽüŽŽ‘‘’ù“’’‹ŒŒ‹‹üŒ‹‹ŒŒúŒŒŒŽþŽŽþŽŽúý‘‘‘ú’‘’’‘’’ý“’‹‹Œ÷‹ŒŒŒŽ ‘þ‘‘ý’‘’’‹ýŒ‹ŒŒþŒþŽýŽŽŽþŽ þ‘‘’Š‹ ŒúŽŽŽŽþŽŽþ‘þ’‘‘ù’ŠŠ‹ŠŠ‹‹üŒ‹‹ŒŒŽüŽŽý‘þ‘‘Šþ‹ŠŠ‹ýŒ‹ŒŒüŽŽŽüŽŽý‘û‘‘‘’Š‹þŠ‹‹ŒüŒŒøŽŽŽŽŽŽþ‘Š‹þŠ‹‹ŒŒŽþŽŽþŽý‘Šø‹Š‹Š‹‹Š‹‹ûŒ‹ŒŒøŽŽŽŽŽŽûŽŽþû‘ЉŠŠü‹ŠŠ‹‹Œ‹Œ ýŽŽŽû‘‰ýЉŠŠ‹þŠ‹‹ŒýŒúŒŽŽŽôŽŽ‘‰Šü‰Š‰ŠŠ‹þŒ‹‹ŒþŒŒýŒ ŽþŽŽ‰Šþ‹ŠŠ‹ùŒ‹‹ŒŒ‹ŒŒŽþŽŽû‰Š‹þŠ‹‹Œ‹ŒüŒŒüŽŽŽýˆ‰‰Šþ‰ŠŠ‹Œü‹Œ‹ŒŒüŒŒŽþŽŽûŽŽŽŽˆý‰ˆ‰‰ûЉЉŠŠü‹ŠŠ‹‹ŒŒŽùŽŽŽþùþúùùúùúùúùùúùùúùúúþùúúþùúúþùú úùþúù ùöúùúùùúúùúùùùúùùúùúùùúúùúùúùúúþùúúýûúù ùúùüúùúùùúùþúùùúùúþùú úýùøù ùøúùùúùúúùùúûùúùùúúüùúùúúþùúúùúýùúùùþúùùúùùúùùúúùúúþùúúùúþùúúùûúùùúùùøúùùúùùúùùìúùùúùùúúùúúùúùùúúùùúúþùúúùþøù ùýúùúú ùûúùùúùùúþùúúþùúúüùúúù ùþúùùüúùúùùùúùúùùúùùõúùùúùúúùúùúúøùúúùúúùúú ùþøùùúùþúùùúúùùúùúúùúþùúúùüúùúùùøúùúúùúùúúùùúùúúùúúþùúúþùúúùþøùùúùúýùúùùúüùúúùùúþùúúúùúùúùúúûùøùøùùþøùùþúùùýúùúúùýúùúúù÷úùúùúùúùúúüùúøùùþøùùþøùùþúùùþúùùúúùúùúùùúøùúúùúúùúúþùúúýùúùùþúùùúýùúùùøúùúùúùúùùúùúùúùøùþøùùûøùùøùùþúù ùúùüúùúùùúùúîùúùúùúúøøùùøùùøùøùùþøùùúþùúúùüúùùúúõùúùúúùùúúùøøùøùüøùøùùúùüúùúù ùùúùùúùùúúþøùùøúùøùùøùùþøùùþúùùùúùùúùúùùôúùúùùúúùúúùúúùûøùøøùù÷øùøùøùùøùùþúùùúùûúùúùúúþùúúüùúøùùøùøøùùøùùøù ùþúùùþúùùúõùúùùúúùùúùúúùüúùøùùúøùùøøùùüøùøùùþúùùþúùùúúùúùúùúúùúúùøùøùùþøùùüøùøùùþøù ùþúùùþúùùûúùùúùùþúùùúùøùþøùùþøùùøùþúù ùúùúùúùøýùøùùûøùùøùùþøùùú ùûúùúùúúüùúùøøùþøùùþøùùþøùù÷øùøùùøùøùùõúùùúùúùùúúùùüøùùøøùþøùùüøùøù ùþøùùþúùùþúùùþúùùþúøøðùøùùøùùøùùøøùùøùùþøùùúøùùøøùùþúùùúùîúøøùøùøùùøøùøùøøùøøýùøùùøùúúùúùúùùúùýúùøøùøùøùýøùøø ùþøù ùþúùùþúùùúôùúúùúùùøøùùøøøùøùøøùøùùøøùùøøùøùùþøùùüúùúùùøüùøùøøïùøøùùøøùøùùøùùøøùùþøùùþøùùþúùùúúùúùúùùøüùøøùùüøùùøøýùøùùøùþøùùþúùùþúùùøþùøøùøøùùøøùøùùüøùøùùø ùþúùùúýøùøøùýøùøøþùøøùþøùùøùþøùùþøù ùþúùùûúøøùøøùõøùùøùùøøùøùùûøùùøùùûøùùøùùúýùúùùøüùøùø øùøþùøøóùøøùøùùøùùøøùùø ùþúùùøùøôùøùùøøùøùùøùùøúùøùùøùùþøù ùùúùùúùùø øùöøùùøøùøùøùùþøùùøûùøùøùùþøù ùüúùùøøþùøøùøþùøøüùøøùùûøùùøùùþøùùøùøûùøøùøøùìøùùøùøøùùøùøùøùøùøøùùþøù ùþúøøþùøøþùøøûùøùøùùþøùùøþùøøùþøùùþøùùøþùøøøùøùùøùøùùøùøýùøù ùþøùùþ÷ø øýùøùùûøùøùøøüùøùøøùþøùùøùþøùùþøùùýø÷ø øúùøøùùøøùøþùøøüùøøùùûøùùøùùûøùøøùù øþùø øùøùðøùøùùøùøùøøùùøøùùûøùùøùùþøùù øþùøøýùøùùøûùøøùøøùùøùøøùùøø ùþøùùþøùùýø÷ø øúùøùøùøøþùøøþùøøùþøùùþøùùþøùùþøùùøù÷øüùøùøøþùøøýùøùùøùüøùùøø ùøû÷øø÷ø øþùøøùþøùùøùøùøùþøùùøþ÷øøùøùøþùøøýùøùùûøùùøùùþøùùüø÷÷øøþ÷øøþùøøþùøøùøýùøùùüøùøùùùøùùøø÷øøþ÷øøùüøùøùùöøùøùùøùøøùùøùýøùøøþ÷øøû÷øø÷øøùøôùøøùùøùøøùøùùøùúøùøù÷øøþ÷øø÷øþ÷øøùøþùøøù÷øùøùøùøøùùøþ÷øøü÷ø÷øøþùø øþùøøøùøùùøùøùùúøùø÷÷øøþ÷øøüùøùøøþùøøùüøùùøøùùøùùøø÷øøþ÷øø÷øþ÷øøþ÷øøþùøøùþøùùøþùøøùøúùøùø÷øø÷øþ÷øø÷ øþùøøüùøøùùøûùøø÷øø÷óø÷øø÷÷øø÷øø÷ø øüùøùøøþùøøþùøøûùøùùøøðùø÷ø÷ø÷÷øø÷÷øø÷øø÷øþ÷øøþùøøùüøùøùùøô÷ø÷÷ø÷ø÷øø÷øøþùøøþùøøþùøøþùøøòùøùøùùøù÷ø÷÷ø÷÷øþ÷øøþ÷øøþ÷øøþ÷ø øþùøøùøùøùü÷ø÷øøù÷ø÷øø÷øøü÷øø÷÷øþ÷ø øúùøùøùøøüùøùøøûùøøùøøüù÷ø÷÷þø÷÷øü÷ø÷øøþ÷øøþ÷ø øøùøøùøùùøø÷ùøùøùøøùøøÿ–—˜™š›þš››œœ•û–•–—––—˜ù—˜˜™˜˜™™øš™š™šš›šš›þœ››œû•––•––—þ–——˜—˜þ™˜˜™ýš™šš›œþ›œœù›œœœû•––•––—˜ù™˜˜™™˜™™ûš™š™ššý›š››œýœþ•––•–ý—–——˜þ—˜˜û™˜™˜™™š›œþ›œœ•ý–•––—–—˜ú™˜™™˜™™ýš™šš›ùš››œ››œœþ••þ–••–ü—––——˜™þ˜™™š›š›ûœ›œ›œœþ”••–•–þ—––—˜û—˜˜—˜˜ý™˜™™ýš™šš›ùœ››œœ›œœû”••”••þ–••–ý—–——˜™ýš™šš›þš››œû›•””••–ú—–——–——˜þ—˜˜™þ˜™™š›þš››ûœ›œœ”” •–—þ˜——ò˜—˜˜™™˜˜™™˜™™ššû›š›š››ûœ›”“””•û–•–•––—þ–——˜ü—˜™˜˜ý™˜™™šþ™šš›ý”“””•ü–••––—þ–——˜ö—˜—˜™˜˜™˜™™š›þš››“”ü•””••–û—–—–——˜ü™˜˜™™õš™™šš›š››š››“ý”“””•û–•–•––ý—–——˜þ™˜˜™ 𛓔•þ”••ü–••––ý—–——˜ü™˜˜™™š›“”“”•ü–••––—ô˜—˜˜—˜˜™˜™™˜˜™ýš™ššû›šš’““”þ“””•–—ú˜—˜˜—˜˜™šú™šš›’““þ”““ý”“””ù•”•”••––•–ü—––——ý˜—˜˜™øš™š™šš™ššþ’““”•ú”••–•––ø•––—–—–——ý˜—˜˜ü™˜˜™™ôš™šš™š“’“’’““”ú“””•”••ú–••–•––þ—––—˜ý™˜™™š÷™’’“’’“’““ú”“””“””•–—þ–——˜þ—˜˜ ™û’‘’’““þ’““”•”•–ý—–——˜þ—˜˜û™˜™˜™™þš’’ý“’““þ’““”“”ü•””••ø–••––••––—ü˜——˜˜™ûš’’‘’’“þ’““ü”““””•ý–•––—ý˜—˜˜™˜™ú’‘‘’‘’’“”•ø”•–•–••––ù—–—˜——˜˜ù™˜™™˜™‘‘’“”“”ý•”••ü–••––û—–—–——˜þ—˜˜™‘’“ü’““””ü“”“””ý•”••ý–•–– —˜þ‘‘’þ‘’’“”•þ”••ü–••––—˜ú™˜˜‘‘’ö“’’““’““”““ý”“””ý•”••–þ•––—ý˜—˜˜‘ú’‘’’‘’’ü“’’““”•–ý—–——ü˜——˜˜û—˜‘‘þ’‘‘ý’‘’’ “ý”“”” •ý–•––ý—–——ý˜—ü‘‘‘’ý“’““”•ñ–•–•–•––——–——–——˜‘û’‘’‘’’“þ’““”•þ”••ü–••––—‘‘’þ“’’“û”“”“””ü“”•””•þ–••–ó—––——–——˜ü‘‘‘ý’‘’’“ú”““”“””ü•””••ü–••––ü—––——ù‘þ’‘‘’þ“’’“”•ü–••––ø—––——–‘þ‘‘þ’‘‘’þ“’’“”þ“””•þ”••–—þ–þ‘þ‘‘’û‘’‘‘’’“”û“””“””ý•”••–•–—ü‘‘‘ø’‘’‘‘’‘’’“ ”•–û—Ž‘‘’ù“’’““’””þ“””ý•”••–þŽýú‘‘‘ü’‘’‘‘’ “”ü•””••ý–•––ŽýŽý‘‘‘’þ‘’’“”þ“””ý•”••ú–••––ŽŽþŽúú‘‘‘’‘‘ü’‘‘’’“”ú•”••”••ý–ŽŽúŽþ‘’ú‘’’““’’“û”“”“””•þ”••ö–ŽŽŽŽŽõ‘‘‘‘‘ý’‘’’ “”ý•”••þŽŽøŽŽŽ‘’ý“’““”þ“””ý•”••úŽŽŽŽŽþŽŽ÷‘‘‘‘’‘‘’ “”ü•””••üŽŽŽûŽŽýù‘‘’‘‘’ú“’““’““ý”“””ü•”•ŽþŽŽûþ‘‘ù’‘’’‘‘’’ý“’““”“þ”••ü”ŒŽüŽŽý‘‘’ù‘’‘’’“’’“þ”““”þ“””þŒŽüŽŽþŽþü‘‘‘ý’‘’’“þ”““”üŒŒýŽŽŽúŽ ‘ý’‘’’“’“þ”““ú”ŒŒŒýŽŽŽŽ‘‘‘‘‘‘’ü‘’‘’’“þ”““”ŒúŒŒŒŽþŽý‘û’‘’‘’’“û”“””ŒŒýŒýŽŽŽŽ‘û‘‘‘‘ý’‘’’“þ’““”ŒýŒŽý‘‘ ’“Œþ‹ŒŒþŒŒöŒŒŽŽŽŽþŽû‘þ’‘‘ý’‘’’þ“’’“‹ŒþŒûŽŽŽŽùŽŽŽŽþú‘‘‘‘’þ‘’’“’‹ŒŽþŽŽü‘‘‘ü’‘‘’’“þ’‹‹üŒ‹‹ŒŒüŒŒüŽŽŽüŽŽû‘’þ‘’’û“’“Š‹‹üŒ‹‹ŒŒþŒŒôŽŽŽŽŽŽŽþ‘ý’‘’’þ‘’’Š‹ŒþŒŒŽþŽŽýŽû‘ü’‘‘’’Šý‹Š‹‹ŒüŒŒýŽŽŽþŽŽ‘’þš››þœ››œžøžŸžžŸžŸŸþ ŸŸ ¡ü¢¡›šš›ûœ›œ›œœœ žýŸžŸŸý Ÿ  ¡ ¡¢š›œüœœùžžžžŸú Ÿ  Ÿ   ¡š›š›úœ››œ›œœýžžžýŸžŸŸú ŸŸ Ÿ  û¡ ¡ ¡¡þ¢šš›þš››œœþž žŸû Ÿ Ÿ  ¡ü ¡™ššý›š››ýœ›œœûžžžžúŸžŸŸžŸŸû Ÿ Ÿ  ¡šþ™šš›þš››ýœ›œœþœžýŸžŸŸ ý¡š™™šú›šš›š››úœ››œ›œœýœžúŸžžŸžŸŸý Ÿ  ý¡ ™™ýš™šš›úœ›œ››œœþœœõžžžžŸŸžŸŸþžŸŸý Ÿ  ™šû™šš™ššý›š››ýœ›œœùœœœžüŸžžŸŸ ™óš™š™™š››š›šš››œ›œúœœžŸ üŸ  ™™ š›ýœ›œœüœœžûžžžžŸ ÷Ÿ  Ÿ˜™˜˜™™šû›š›š››øœ›œ›œœœœüœœžþŸžžýŸžŸŸø Ÿ ™˜™˜™™úš™šš™ššý›š››ýœ›œœúœœœþžžþŸžžŸ ýŸ˜™™ú˜™š™™š š›ùœ››œœ›œœýœþžžýŸžŸŸþ ˜˜ý™˜™™šý›š››úœ›œ››œœüœœüžžžùŸžŸžŸžŸŸ˜ù™˜˜™™˜™™ùš™™šš™ššý›š››œþ›œœýœžþžžŸ ˜™šþ™ššþ›šš›üœ››œœýœýžžžûŸ˜——˜˜™þ˜™™š ›œý›œœ ž—˜™ó˜™˜™™šš™™šš™ššý›š››ýœ›œœþœžüŸžŸ——˜ü™˜˜™™š™š›šý›œ››œþœžþžž—˜™þ˜™™šû›šš›šš›üœ››œœûœœœüžžžþ–——˜þ—˜˜™š™š ›œùœœœœž—˜û—˜˜—˜˜ì™˜™™˜™™š™™š™™šš›š›š››œþ›œœõœœžžžþ–——˜þ—˜˜þ™˜˜™øš™š™™š™ššý›š››üœ››œœþ›œœþœúž––—–——þ˜——ö˜™™˜™™˜™˜™™šý›š››œþ›œœýœþž–– —˜™þ˜™™úš™™š™šš÷›š››š››š››œþœœýœöž––——–—––——˜û™˜™˜™™š™š›þœ››œ–ü—––——ý˜—˜˜™ø˜™˜˜™™š™™ýš™šš›þš››úœ›œœ›œœýœ––û—–—–——˜™þš™™š›œýœ–—û–—––——˜ú™˜˜™˜™™šþ›šš›ýœ›œœï••––•–•–—––——––——˜™þ˜™™š›úœ›œœ›œœú•–••––—þ–——˜þ—˜˜™ü˜™˜™™šþ™š š›ýœ›œœ•–û—–—–—— ˜™ýš™šš›šý›š››œü”•”••ý–•––—ø˜—˜—˜˜—˜˜ü™˜˜™™üš™™ššü›šš››üš››œœ›þœ••þ”••–ü—––——˜þ—˜˜™þ˜™™ûš™š™ššü›šš››øœ›œ”••”••–ú•–•–•––ò—––——–——˜——˜—˜˜™þ˜™™š›þš››”•–ý—–——÷–—˜—˜˜——˜˜þ™˜˜™ š›”•ü–••––—þ˜——ý˜—˜˜ø™˜™˜™˜˜™™šþ™ššý›š››”ú•””•”••ý–•– –—˜ü™˜˜™™üš™™šš›š›”þ•””•–þ—––ý—–——ü˜——˜˜þ™˜˜ý™˜™™š›š›”ü“””••þ”••–þ•––—˜™šþ™šš÷›šš››“”“””þ•””•ý–•––ý—–——˜þ—˜˜þ™˜˜™úš™š™™ššû›“”“””þ“””•þ”••–—þ–——ý˜—˜˜™ûš™š™ššý›’““”þ“””•”•–þ•––—û˜—˜—˜˜þ™˜˜™ýš™šš“þ”““”•–•–ü—––——û˜—˜—˜˜™þ˜™™ýš™šš’“”•ú”•–••––õ—–—––—––—˜——˜™þ˜™™ûš™šš’’“”þ“””•þ”••þ–••–þ•––ý—–——þ˜——˜ü™˜˜™™öš™™š™’““’““ý”“””û•”•”••–—û–˜˜—˜˜ý™˜™™÷š™™š’’“’““”þ•””•–þ•––—˜þ—˜˜õ™˜˜™™˜™™š™’’“”•”•–þ•––—þ–——ø˜—˜˜—˜™˜˜™’“’“”þ•””ø•”••–••––—ý˜—˜˜™’þ‘’’“ý”“””ó•”••”•”•–•–•––ñ—–—–—–——˜—˜˜——˜˜þ™˜˜ü‘’‘’’÷“’““”“”“””ü“””••þ”••–—ü˜——˜˜ø™˜‘‘’’‘’’“’“”ý•”••–û•–——––—ü˜——˜˜û™˜‘‘’’þ‘’’“û’““”““”•”•–þ•––—þ–——ý˜—˜˜þ‘‘’þ‘’’ü“’’““þ”““”•þ”••þ–••–—þ˜——˜‘’þ‘’’ü“’’““þ”““”þ“””•”• –ý—–——ü˜——˜˜ý‘‘‘’ý“’““’“”þ•””ý•”••ñ–•–••––——––—––——˜þ—‘ú’‘’’“’’“ü”““””•û”••”••ü–••––ü—––——ø˜——‘‘‘‘’“ü”““””ü•””••–•–ý—–——ú‘‘‘‘’“’û“”““””ü•””••þ–••–—û˜‘‘û’‘’‘’’“ú”““”“””•–þ•––ø—–—–——û‘‘‘‘ý’‘’’û“’“’““”“”ý•”• •–û—–—–——ú÷ûúúûúúûúûûúûüúûûúúûþúûûùúûûúûúûûúûþúûûúûþúûûúûúúûúûúûûûüûûüûûúþûúúûúûïúûûúûúûûúûûúûúûúûûþúûûúþûúúüûúûúúûúüûúúûûûúûûúûûüúûúûûþüûûúþûúúúûúúûûúúïûúûúûûúúûûúûûúûúûûþúû ûúþûúúþûúúûþúûûúûúûüúûúûûþúûûþüúúüûúûúúùûúûúûúûûúýûúû ûþúûûúþùú úöûúúûúûúúûúúùûúûûúúûûþúûûüúûúû ûúûúúûúûúûúúûúûþúûûþúûûú÷ûúúûúûúúûûøúûûúûúúûûúûþúûû úüûúûúúþûúúûüúûûúúûúûþúûûûúûûúûûúøûúûúúûûúúûúúûúûûúûûþúûûúúùúúùúúüûúûú úüûúûúúûþúûûýúûúúþùúúù úþûúú÷ûúúûúûûúûûúûúûþúûûûúûûúûûúûùúúùú úþûúúþûúúûúüûúúûûùúûúûûúûûþúûûüùúùúúþùúúþûúúûúûúúûúúûúúûúûõúûûúúûûúúùúúþùúúùûúûúúûúúûúûúöûúûúùùúúùúúþùúúþûúúûúþûúúûûúúûúúûúýûúûûþúûûþúûûúùúùúþûúúþûúúûíúûúúûúûûúúûûúúûûúûúúüùúùúúù úþûúúôûúûúûûúúûûúûûúûüúûúûûüúùùúúþùúúþùúúþùúúþûúúþûúúýûúûûúûüúûúûûýúûúúþùúúþùúúþùú úûûúûúûûúúûúûûúúýûúûûüúûúûûþúùùüúùúùùúþùúúûùúúùú úþûúúûúûøúûûúûúûùùúùýúùúúûùúúùúúþùú úþûúúû÷úûúûûúúûúúþùúúþùúúùúþùú úûúþûúúûóúûúûúûûúûùùúùùýúùúúùúúùúúùùú úûûúúûúúüûúûúúû÷úûúùúùúùúúþùúúùúûùúúùúúþùúúþûúúûûúúûúúúûúúûûúúûùúùúþùúúþùúúúûúúûûúúþûúúüûùúùùúüùúúùùúùýúùúúûúûúûóúùúùúùùúùùúùúúüùúùúúùúþùúúøûúúûúúûúúþûúúñûúûúúûúûùúùùúùúúüùúùúúûùúúùúúøùúúùúúùú úþûúúþûúúþûúúùûúûúùúùùúþùúúþùúúþùúúúùúúùùúúþùú úûúøûúúûúúûúúùîúùúùúúùúùúúùúùùúùúúûúþûúúûúûðúùùúúùúúùùúúùúúùùúþùúúþùúúþùúúþûúúùþúùùüúùùúúûùúùùúúõùúùúúùùúúùú úþûúúþûúúíûúûúùùúùùúùùúúùùúùúúù úûùúúùú úüûúûúúþûúúùúùúùýúùúú÷ùúúùúùúùúúþûúúúûùúùúùùþúùùýúùúúùúüùúùúúþûúúùúþùúúù÷úùúùúùúùúúúùúùúúùùýúùúúþùú úþûúúûùþúùùòúùùúùúúùúùùúúùùõúùúúùúùùúùúúþùúúùúùþúùùúùüúùúùùýúùúúüùúùúúûúùþúùùþúùùþúùùþúùù úùúúùùúùúú ùúþùúúúùúúùúùùúûùúúùúúþùúúþùúúþûù ùüúùúùùþúùùþúùùúûùúùùúúùüúùùúúüùúúùùøúùúúùùúùùúùúùùúúùúùúúùüúùùú úüùúùúúýûúùùúúùúùúùùúùúúùúúùúúûùúùùúúþùúúþùúúùúùûúùùúùùþúùùúýùúùùýúùúúùúùüúùúùùþúùù÷úùùúúùùúùùþúùùþúùù úüùúùúú ùþúùùïúùùúùùúúùúùúùúùúùùùúùùúúùúúùûúùùúùùúù÷úùúùúùúùúúùùúùúúùùúúþùúúùþøù ùþúùùþúùùúúùùúùúúþùúúùúþùúúþùúúùþøùùþúùùþúùùüúùùúúùúúùúúùúúõùúúùùúùúùúùùûøùùøùùþúùùõúùùúúùúùúùúúþùúúûùúúùúúûùúúùúúûùúúøùùþøùùþøù ùþúùùúùþúùùþúùùúþùúúþùúúþùúúûøùùøùùþøù ùþúùùúùùúùùúúùúúóùúúùúùúúùúúøùùúøùùøøùùþúù ùúùòúùúùúúùúùúùúúùùúùþøùùþøùùüøùøùùþúùùúùúùýúùúúùú÷ùúùúúùùøùùþøùùùøùùøùøùùúýùúùùúùúùúùöúùúúùúùúùøøùø ùþøùùþúùùþúùùûúùúúùùýúùúúûùúùùúúûùúùùøøùþøùùúùþúùùúýùúùùúùøüùøøùùøùúùþúùùúùúùúøùøùþøùùþøùùþúùù÷úùúùúùúùúúùøúùúùùúúùùøüùøøùùøùþøùùûúùùúùùúûùúúùúúõùúùúùúùúùùúúõùøøùøùùøùøùùøùø ùþúù ùûúùúùúúùüúùùúúÿþžžùŸžŸžŸžŸŸý Ÿ  ú¡ ¡¡ ¡¡¢ü£¢¢££¤¥¤¥žŸüžŸžŸŸû Ÿ Ÿ  ¡¢þ¡¢¢ú£¢¢£¢££¤û¥¤¥¤¥¥žúŸžŸŸžŸŸ ý¡ ¡¡ü¢¡¡¢¢ó£¢££¢££¤££¤£¤¤ý¥¤¥¥žüžŸžŸŸþžŸŸ Ÿ ¡ü ¡ ¡¡þ¢¡¡¢£ü¤££¤¤žüŸžžŸŸ ¡þ ¡¡ý¢¡¢¢þ£¢¢£ý¤£¤¤¥öœžžžžžýŸžŸŸý Ÿ  ü¡  ¡¡ý¢¡¢¢ £ý¤£¤¤ü¥œüžžžŸý Ÿ  ü¡  ¡¡ý¢¡¢¢þ£¢¢ù£¢£¤££¤¤þœþœžŸžŸý Ÿ  ü¡  ¡¡ ¢ý£¢££ø¤££¤£¤¤œœþœžþžž Ÿý Ÿ  ü¡  ¡¡ù¢¡¡¢¡¡¢¢£¢£¤œžŸý Ÿ  ü¡  ¡¡¢¡¢£¢£¤œüœœýžžžýŸžŸŸþ ŸŸ ü¡  ¡¡þ¢¡¡¢ý£¢££ø¤›œ››œœþœžýžžžýŸžŸŸ þŸ  ú¡ ¡¡ ¡¡¢£œþ›œœüœœòžžžžŸŸžŸžŸŸû Ÿ Ÿ  ¡þ¢¡¡¢ø£¢£¢¢££››ýœ›œœüœœýžžžýŸžŸŸ þŸ  ý¡ ¡¡¢þ£¢¢£›œýžžžþžžüŸžžŸŸü ŸŸ  ú¡ ¡¡ ¡¡¢£›œþ›œœþœœüžžžúŸžŸžžŸŸ üŸ Ÿ  ¡¢þ£››œžŸžŸü ŸŸ  ý¡ ¡¡¢þ¡¢¢›þš››œûœœžþžž Ÿ ü¡  ¡¡ø¢¡¢¢¡¢›šš›þœ››ýœ›œœûœœžþžžþŸžžŸó Ÿ  Ÿ ¡  ¡  ¡¡¢šý›š››úœ›œœ›œœýœžŸ  ¡õ¢¡¢¢šš›š›š››œþ›œœþœœýžžžùžžŸžŸžžŸý Ÿ  ¡¢¡ýš™ššþ›šš›ýœ›œœúœœüžžžŸþ ŸŸ þ¡  ¡¢™šþ›šš›þš››œžžŸó Ÿ ŸŸ  ¡  ¡ ¡¡™šþ›šš›œþœœûžžžžŸú ŸŸ Ÿ  ý¡ ¡¡™šþ›šš›üœ››œœþœžýŸžŸŸý Ÿ  þŸ  þ¡™™š›þœ››œþžžŸü ŸŸ  þŸ  ¡™šþ™ššþ›šš›þœ››œžžŸþžŸŸ û¡ ˜˜™™š›ýœ›œœýœúžžžžýŸžŸŸý Ÿ  ˜ý™˜™™öš™šš›š›šš››þœ››œþœýžžžŸó Ÿ Ÿ Ÿ ˜™˜™˜™™üš™™ššû›š›š››úœ›œ››œœúœœœþžžŸý Ÿ  ü˜™˜™™þš™™š›ýœ›œœüžžžŸüžŸ ŸŸ ø—˜™˜™™˜™™üš™™šš›þœ››öœ›œœœœœüžžžŸý Ÿ˜˜þ™˜˜™ýš™ššý›š››œùœœœžŸúžŸŸžŸ  ý˜—˜˜þ™˜˜™š›þš››œ›œýœžùžžŸžžŸŸ ˜™š™š›þš››œ›ùœœœœžþŸžžŸ—˜ý™˜™™šü›šš››œþ›œœžþžžýŸžŸŸ—˜™˜™š›þš››üœ››œœüœœžþžž—ý˜—˜˜™û˜™™˜™™šü™š™šš›œžþ–——˜û™˜™˜™™š™š›ýœ›œœýœžüžžžþ–——þ˜——˜™úš™šš™šš›ýœ›œœñ›œœœœœœžžžþ–——˜ü™˜˜™™þ˜™™÷š™š™šš›š››ýœ›œœöœœœžž–—þ–——˜ý™˜™ ™š ›œüœœþœž–ü—–—––—˜ú™˜™˜˜™™š™šý›š› ›œúœœœýž––—˜ý™˜™™üš™™šš›œþ›œœþœ–þ•––ý—–——˜þ—˜˜ú™˜˜™˜™™úš™šš›šš›œýœþ•––þ•––—û˜—˜—˜˜™û˜™˜™ššþ™šš›üš›š››œ›ýœ›œœúœœ••–—ø–—˜——˜—˜˜™š›þš››œûœœ••–—ý˜—˜˜™úš™šš™ššü›šš››þœ››œ•–û—–—–——ý˜—˜˜™ýš™ššü›šš››œ•–—þ–——˜þ—˜˜™ýš™šš›ûš››š››œþ”••–•–þ—––ý—–——˜þ—˜˜ý™˜™™üš™™šš›þš››øœ››œ›œœ””• –—ý˜—˜˜™šþ™ššý›š››þš››ýœ›œœ”•þ”••þ–••ý–•––ü—––——ý˜—˜˜™š›œ”ì•””••””••–•–•––•—––— —˜ý™˜™™šþ™šš›þœ””ý•”••ý–•––ú—–——–——˜ý™˜™™ýš™šš™š›þš››“”þ•””•þ–••–þ—––—˜ý™˜™™ùš™™šš™šš›û“””“””ü•””••–þ•––—˜þ—˜˜™ùš™™šš™ššþ›šš›”“”•–ù—––—––—— ˜ý™˜™™ûš™š™šš›“”ö“”•”•”••”••–þ•––ý—–——ý˜—˜˜û™˜™˜™™šû›š››““þ”““ý”“””ü•””••–þ—––—ø–—˜—˜˜—˜˜™˜™šþ™šš“”ý•”••–—˜—˜™ûš™š™ššü›’’““”“”•ú–•–••––—ú˜——˜—˜˜™˜™šü’“’““ý”“””ý•”••ú–•––•––—ü–—˜——˜ý™˜™™š’ü“’’““ü”““””•þ”••ú–•––—––—˜þ—˜˜ú™˜˜™š™™š¢ý£¢££ý¤£¤¤þ£¤¤¥¦þ¥¦¦ú§¦§¦¦§§ú¨§¨¨§¨¨©ý¢¡¢¢ý£¢££ú¤£¤££¤¤ ¥¦§û¨§¨§¨¨©¡¢ý£¢££ ¤ý¥¤¥¥ü¦¥¥¦¦§þ¦§§ ¨ý¢¡¢¢£¤ü¥¤¤¥¥ù¦¥¦¥¦¥¦¦§¨þ©¡¡¢ý£¢££¢£¤þ£¤¤ü¥¤¤¥¥¦¥¦§ý¨§¨¨¡¢ù£¢££¢¢££¤þ£¤¤ý¥¤¥¥ú¦¥¦¦¥¦¦ü§¦§¦¦§û¨§¨§¨¨¡¢þ¡¢¢þ£¢¢£¤þ£¤¤ú¥¤¤¥¤¥¥ô¦¥¦¦¥¦§¦§§¦§§¨§þ¨¡¡¢þ¡¢¢£ý¤£¤¤þ£¤¤¥ ¦ý§¦§§ú¨§¨§¡  ¡¢þ£¢¢£ý¤£¤¤ý¥¤¥¥þ¤¥¥ý¦¥¦¦ý§¦§§ú¨§§¡ ¡¡¢ £¤£¤û¥¤¥¤¥¥þ¦¥¥¦§ü¨§§  ¡ ¡÷¢¡¢¢¡¡¢¢££þ¢££ý¤£¤¤þ¥¤¤¥þ¤¥¥ý¦¥¦¦§¦§û¨  ¡  ¡þ ¡¡¢£ü¢£¢££û¤£¤£¤¤þ¥¤¤¥þ¦¥¥¦§þ¦§§ ü¡  ¡¡ý¢¡¢¢þ¡¢¢£¤÷¥¤¥¥¤¥¥¦¥¥¦§þŸ  û¡ ¡ ¡¡ú¢¡¢¢¡¢¢ö£¢£¢££¤£¤££¤¥þ¤¥¥¦õ§¦§§¦§Ÿ ŸŸ  ¡þ ¡¡ù¢¡¡¢¡¡¢¢£¤þ£¤¤¥ý¦¥¦¦§Ÿ Ÿ ¡þ ¡¡ ¢£¤þ£¤¤û¥¤¥¤¥¥¦û§¦ŸŸ  þŸ  ¡þ ¡¡¢£¢£¤¥ý¦¥¦¦ýŸžŸŸ ú¡  ¡ ¡¡¢þ¡¢¢ü£¢¢££ü¤££¤¤¥þ¦¥¥ö¦¥¦¦ŸžŸŸ ŸŸ ¡ý¢¡¢ ¢£¤£ý¤£¤¤þ¥¤¤¥¦ú¥¦¦ŸžŸŸ Ÿ ¡þ ¡¡ý¢¡¢¢£þ¢££ ¤¥ø¦¥¦¥¥¦žŸŸþžŸŸû Ÿ Ÿ  ¡ ¢£¤þ£¤¤ý¥¤¥¥¦žüŸžžŸŸ þ¡  ¡ü¢¡¡¢¢£þ¢££¤þ£¤¤¥žŸ ¡þ ¡¡¢þ¡¢¢ú£¢££¢££¤¥ý¦žž Ÿ ù¡  ¡  ¡¡¢þ¡¢¢£ý¢£¢¢£¤¥ž÷žžŸžŸžžŸŸû Ÿ Ÿ  ¡û ¡¡ ¡¡¢ü¡¢¡¢¢£ ¤û¥žžž Ÿ þŸ  ¡÷¢¡¡¢¢¡¢¢££¢£¤ü¥¤¥žžþžžþŸžžýŸžŸŸ ÷¡ ¡ ¡¡ ¡¢¢ü¡¢¡¢¢ £¤¥žŸøžŸžžŸŸ ŸŸ ù¡ ¡ ¡ ¡¡¢ù£¢¢££¢££ü¤££¤¤þ¥ žýŸžŸŸù ŸŸ ŸŸ  ¡ü ¡ ¡¡¢û£¢£¢££÷¤££¤£¤¤¥ýžžžŸ Ÿ ¡ü ¡ ¡¡û¢¡¢¡¢¢£þ¢££¤žþžžûŸžŸžŸŸú ŸŸ Ÿ  ¡¢þ¡¢¢ý£¢££ø¤£¤£œœùžžžžžýŸžŸŸû Ÿ Ÿ   ¡¢ £þ¤œœžŸ ¡þ ¡¡¢þ¡¢¢ý£¢££÷¤œœœýžžžþŸžžŸ ¡þ ¡¡¢û£¢£¢££œþžüžžžŸû Ÿ Ÿ  ¡þ ¡¡ú¢¡¢¡¡¢¢£¢£ùœ›œœœžûžžžŸþžŸŸ Ÿ Ÿ ü¡  ¡¡ý¢¡¢¢þ¡¢¢ù£¢£¢££œœüœœœýžžž Ÿ ü¡  ¡¡ ô¡¢¡¢¡¢¢¡¢¢£¢¢£þ›œœžžŸþžŸŸþ ŸŸ ý¡ ¡¡ü¢¡¡¢¢ù£¢£›œœ››ûœœüžžžõžžŸŸžžŸŸžŸŸ þŸ  ý¡ ¡¡ý¢¡¢¢ý£¢››œüœœžŸþžŸŸ ¡¢¡¢£›œžþžžûŸžŸžŸŸü ŸŸ   ¡¢›œþœœþœžüŸžžŸŸ Ÿ ý¡ ¡ ¡¢þš››œþ›œœþœžžþŸžžŸ  ¡ü ¡ ¡¡ù¢¡¡¢šš››þœ››üœ››œœûžžžžŸþžŸŸ  ý¡ ¡¡¢ý¡¢šš›œþ›œœþœûžžžžŸžŸý Ÿ  ¡ûš›šš››ýœ›œœþœžýŸžŸŸü ŸŸ  û¡  ¡  ¡ý¢¡šš›ýœ›œœþœœúžžžžžŸû Ÿ Ÿ  ý¡ ¡¡šý›š››ýœ›œœûœœýžžžŸ Ÿý Ÿ  ü¡  ¡¡þ™ššü›šš››œ›œ žþžž Ÿ ü¡  ¡¡ü™š™ššý›š››þœ››ýœ›œœüžžžþžžþŸžžŸ  ü¡™™šš›œþ›œœýœžþžžüŸžžŸŸ þŸ  ™üš™™ššû›š›š››ýœ›œœòœœžžžžžûŸžŸžŸŸû Ÿ Ÿ  ™ýš™šš™ûš›šš› ›œžþžž Ÿþ ŸŸ ™þš™™šþ™šš›þš››ýœ›œœžþžžŸü ŸŸ  ý™˜™™ûš™š™ššü›šš››œüœžžþžžŸþžŸŸø Ÿ  ™™˜™™š›þš››üœ››œœýœžüŸžžŸŸþ ŸŸð ˜™™˜˜™˜™™š™™š™šš›ýœ›œœþœœžŸûžŸžžŸŸ˜ú™˜˜™˜™™ýš™šš›š›úœ›œœ›œœœûžžžžýŸžŸŸ˜™þ˜™™üš™š™™šý›š››œþ›œœüœœüžžžúŸžžŸžŸŸ˜þ™˜˜ý™˜™™ýš™šš›ûœ›œ›œœžþžžŸûžŸ˜—˜˜ü™˜˜™™ø˜™™š™š™šš›îš››œ››œœ›œœœœœüžžžŸ—ý˜—˜˜ü™˜˜™™šþ™šš›üœ››œœžþžžŸ—˜ý™˜™™šþ™ššý›š››œþ›œœûžžžžùŸ——˜——˜˜÷™˜™˜™˜™™šš›úœ›œœ›œœ žøûüûüûûüûûþüûûüüûüûû÷üûüûüûüûüüþûüüûûüüûüüþýüüþýüüûùüûüûüüûûüþûüüûüþýüüûúüûüûüûûûüûüûüüûûüüûüüûüûüþýüüûþüû ûþüûûýüûüüû üûûüüûüüþýüüûþüûûúüûüûüûûüþûüüûûüûüûüüþûüüûüþýüüøýûûüûûüûûþüûûúüûûüûüüûýüûüüûüúûüüûûüüþûüüúýüýûüûûûüûûüûûþüûûüþûüüûüüûüüûûüûüûüûíüûûüüûüûüüûûüüûüüûü ü ûþüûûþüûûüùûüûüûüûûüþûüüûüûùüûüûûüûûüþûüüüûüûüüûüþúû ûüüûüûüüûþüûûøüûüüûüûüüûüüûûü ü ûþüûûþüûûþüûûþüûû÷üûûüûûüûüüþûüüþûü üûþüûûõüûûüûüüûüüûûüüûüûûûüûüüûûýüûü üþúûûþúûûûüûûüûûöüûûüûüüûüûûüþûü üþûüüûøüûüüûûüûûüûüþûüüþûüüûûüüûüüûþüûûþüûûþüûûüûûüûûüüûüüûüûüüüûüûüüùúûûúûúûûüþûüüûüþûüüûýüûüüþûüüüûüúûûþüûûþüûûüüûüûûîüûüûüüûüüûüüûüûüûüüûûüûüûûüúûúûûþúûûþüûûøüûüûûüüûûþüûûþüûûüþûüüõûüúúûûúûûúûûüûþüûûüþûüüþûüüùûüûüüûüüûþúûûþúûûþúûûüüûüûû÷üûûüûüûüûûüòûüüûüûûüüûûüüûûþúûûþúûûþüûûüûüûüüûûüüûûúûûúûûþúûûþúûûþüûûûüûûüûûøüûüûüüûüüýûüûûüúûúûûþúûûþúû ûþüûûøüûûüûüüûûþüûûþüûûüûþúûûúýûúûûþúûûþüûû÷üûûüûûüüûûûüûüûüüûûüûúûûþúû!ûüúûüûüüûûüûüûûúûúûûüúûúûûþúûûþúûûÜüûüûûüüûûüûüûüûûüûûüûúúûúúûúûûúúûúúûûþüûûüûþüûûêüûûüüûûüûüûûüûûüüûûúûúúúûúûúúûûþúûûþúûûþüûûüûüõûüüúûúûúûúûûúûûúûûúûûþúûûúüûûüüûûüúõûúûúûúûúûúûûþúûûþúûûþüûûöüûüûüûüûüûûþüûûúúûûúûúúûûúûúûúúýûúûûþúûûþüûûüûþüûûüûþüûûùúûúúûûúúúûúûûúûûú÷ûúûûúûûúûûüüûüûûûüûüüûûü÷ûúúûûúûúûûõúûúúûúúûûúûûþúûûþüûûøüûûüûûüûûüúûúúûúûûúûûþúûûþüûûõüûüüûüûûüûúúûúûøúûûúûúúû ûûúûûúûûþüûûüûüûúüûûúûúúûýúûúúýûúûûþúûûþúû ûþüûûþüûûôüûüûüûüúûúúûûûúûúûúúûúûþúûûú ûþüûûüüûüûûýüûúúþûúúþûúúþûúúûúýûúûûûúûûúûûþüûûýüûúúúûúúûûúúþûúúýûúûûúûüúûúûûþüûûúûúûúûúû÷úûúûûúûúûûþüûûúþûúúûôúûûúúûûúûûúûûþúûûúûþúûûþüûûûüûüûúúûúñûúûúûúúûúûûúûúûûþúûûùúûûúûúûûþüúúþûúúþûúúûüúûûúúýûúûûúûþúûûúüûúúûúúþûúú÷ûúúûúúûúûûúúûûúûúúûþúûûþúûûýúûúúþûúúþûúúþûúúûúûúûþúûûúûþúû ûúþûúúûûúûûúú÷ûúûúúûúúûûúûüüûûúúþûúúûúúûúûúûúúûüúûúûûôúûûúûúûúûûúû û úûèúûúûúúûûúúûúûúûúúûûúûûúûûúûûúûûúûû úüûúûúúôûúûûúúûûúûúûûýúûúúøûúûûúûúûûþúû ûúûýúûúúüûúúûûþúûûþúûûúúûûúûúú ûúþùúúþûú úûúþûúúûúûôúûûúúûúûúûúûûûùúúùúúüûúûúúþûúúþûúúõûúûúúûûúûúûûú ûþúûûúûûúúûúúûúýûúûûúûþúûûþùúúþùúúþûúúþûúúþûúúýûúûûúûúûüúûúûûúþûúúûúôûúûúûúûúûúúûûþúûûýúûúúþùúúþûúúýûúûûúýûúûûúûúûþúûûúúûûúùúúþùúúûýúûúúûúõûúûûúúûúûúûû÷úûûúûûúúûûúþùúúùýúùú úüûúûúúûúûûúúûúúöûúûúûúûûúû ûþùúúûùúúùú úþûú úûýúûúúû÷úûúûúúûúûûþúûûýúùúúþùúúþùú úþûúúüûúûúúþûúúþûúú ûýúùúúöùúúùúùúúùúúþûúúüûúûúúûþúûûúûöúûûúûúúûúûûõúùúùúùúùúùúúþùúúùûúúûúûúúüûúúûûúùûúûûúúûûüúûûúúùúþùúúþùúúþûúúûúþûúúûýúûúú÷ûúûúúûûúûÿû¥¦¥¥¦¦§¨-¥þ¦¥¥¦§þ¦§§-¥¦§û¦§¦§,þ¤¥¥¦§¦þ§,¥¦ü¥¦¥¦¦§-¥¤¥ù¦¥¥¦¦¥¦¦-þ¤¥¥þ¤¥¥ü¦¥¥¦¦-¤¥û¦¥¦¥¦¦-¤¥¤¥ù¦¥¦¦¥¦,þ£¤¤¥þ¤¥¥ú¦¥¥¦¦, ¤¥ý¦¥,£¤þ£¤¤ü¥¤¤¥¥þ¦,£ý¤£¤¤ü¥¤¤¥¥-£þ¤££¤ü¥¤¤¥¥-þ¢££ý¤£¤¤¥-ý£¢££ú¤£¤££¤¤û¥¤¥¤,£¢£ý¤£¤¤-¢ý£¢££¤þ£¤¤-¢£ý¤£¤¤-¢ü£¢¢££ü¤£¤,¢£þ¢££¤-ô¡¢¢¡¢¢£¢¢£¢££þ¤,û¡¢¢¡¢¢£¢û£¤£¤,ü¢¡¡¢¢þ£¢¢£-¡¢þ¡¢¢£-¡¢þ¡¢¢û£¢££,¡ ¢£-ü ¡ ¡¡¢ý£¢, ¡þ ¡¡¢- ý¡ ¡¡¢þ£, ¡ ¡ü¢¡¡¢¢- ¡¢ü¡¢¢,ú ŸŸ  ¡¡ ¡û¢¡¢¡,Ÿ Ÿ ¡þ ¡¡-Ÿý Ÿ  û¡ ¡ ¡¡-Ÿ ¡ü ¡¡,Ÿ ÷Ÿ  ¡ ¡ ¡,ýŸžŸŸ û¡ ¡¡,žŸ ÷Ÿ Ÿ ¡  ¡,žŸ þŸ  -žŸžŸ þŸ  -žŸü ŸŸ  -þžžýŸžŸŸú Ÿ  Ÿ,žýŸžŸŸ -žüŸžžŸŸ -žþžžþŸžžŸþ ,žžýŸžŸŸ-þžžýŸžŸŸ-œüœžžüžŸžž-þœùžžžžžþŸ,ûœœž-ûœœœœüžžžþŸ,œúžžž,›œúœœ-þ›œœýœžüž,ûœ›œ›œœûœœþž,û›œ››œœúœœœ-›ýœ›œœ-›ýœ›œœ-›þš››ýœ›œœþœœ-þš››þš››œþ›œœ-šý›š››ûœ›œ›œœþ,šþ›šš›œ›œ-šý›š››ýœ›œœ-©ª«þª««-©úª©ªª©ªªþ«ªª-©ýª©ªªþ«,©þ¨©©þª©©ª-¨ý©¨©©ª-¨ü©¨¨©©ªþ©ªª-¨©þ¨©©ªý©ª,¨ý©¨©©ª-¨ø©¨©¨©©¨©©ýª©,¨ü©¨¨©©-ý¨§¨¨ü©¨¨©©-§ý¨§¨¨ý©¨©©-§ ¨©-þ¦§§ý¨§¨¨ý©¨,þ¦§§¨þ§¨¨©-¦§ý¨§¨¨-ú¦§¦§¦§§¨©-¦§ú¦§§¨§¨¨§¨-¦ü§¦¦§§û¨§¨¨,þ¥¦¦§ü¦§¦§§¨-¦§õ¦§¦§§¨§§¨¨,¥¦§þ¦§§þ¨,¦¥¦ü§¦¦§§-ù¥¦¥¥¦¥¦¦§þ¦§§-¥¦§-¥ú¦¥¦¦¥¦¦þ§¦¦§-¥¦ý§¦,¥¤ü¥¦¥¦¦-ý¥¤¥¥¦¥¦þ§,¤¥þ¦¥¥ü¦¥¦,¤ü¥¤¤¥¥¦ü¥¦¦,¤ù¥¤¤¥¥¦¥¥-¤û¥¤¥¤¥¥-þ£¤¤ú¥¤¥¥¤¥¥-£ý¤£¤¤ü¥¤¤¥¥-£ü¤££¤¤¥¤¥-£¤ý¥¤¥¥-£þ¤££¤¥-£þ¤££¤-£þ¢££¤þ¥,¢ý£¢££¤£¤-¢ü£¢¢££¤ü£¤¤,¢£÷¢£¢££¤££¤¤-þ¡¢¢ý£¢££ú¤££¤£,ü¡¢¡¢¢ý£¢££¤þ£,¡ý¢¡¢¢£þ¢££-¡¢þ¡¢¢£ü¢£¤,ü¡¢¡¢¢£þ¢££-¡¢¡¢ø£¢££¢££,¡ù¢¡¡¢¢¡¢¢þ£, ¡¢þ¡¢¢ü£¢¢, ÷¡ ¡¡¢¢¡¡¢¢- ¡ý¢¡¢¢-ý ¡  ¡ý¢¡¢¢- ü¡  ¡¡¢-ý Ÿ  ¡ ¡- ¡þ¢,Ÿ ö¡  ¡ ¡¡¢¡,þ ŸŸ ¡ü ¡ ¡¡-Ÿú Ÿ ŸŸ  ¡-Ÿü ŸŸ  ¡ü ¡¡,Ÿþ ŸŸ û¡  ¡,ýžŸžžŸ üŸ Ÿ  þ¡,žýŸžŸŸ þŸ  -üýõüýüýýüýýüý,ýðüýüýüýüýüüýüýüü,úýüýüýüüýùüýüýýü,ü÷ýüýüýýüýüüþý,ýüýüüýüüýüü,üýüý-üùýüýüüýüü-üþýüüþýüüþý, ü÷ýüüýüüýü,üþýüüýüý-üýýü,üþýüüûýüüýüüüýüý,ü-üùýüýüüýüü- üýü-üýýü,ü-üþûüüþýüü- üþýüü-þûüüþûü ü-ûüûüüýüü,üûûüûûüüþûüü-üûüþûüü-þûü üûûüûüü,ûûüüûüüþûüüüûüü,û÷üûûüûüüûüü-üûüûüüþûüüþûüü-üûúüûüüûüü-þûüüþûüüûûüûûüü-üþûüüþûüüùûüüûüû,üûüûüüøûüüûüüûüü-ûüûüûüüûüûûüüûüü-úûüûüûüüþûüü-þüûûüûüúûüûüû,üûüûùüûüüûû,ùûüûûüüûûüûüþû,÷üûûüüûûüûûúüûüûü,ûüýûüûûýüûüü-ûûüüûüüùûüüûüûüüû-ûüüûûüüûþü,ûüûüûýüû,ûüüûûüüû-û÷üûûüüûûüûûüüûû,ûüüûüûûþüûû-ûüûüùûüüûûü,ûþüûûüüûüûûüû-þüûûþüûûüûü- ûùüûüüûü,ûþüûûþüûûþüûûüþû, ûþüûû-ûûüûûüûûþüûûüüûû,ûþüûûþüûûü-ûþüûûþüûû-ýûúûûýüûüüûýüû, ûþüûû- ûþüûûýüû,ûþúûûüüûû, ûþüûû-þúû ûýüû,þûúúüûúúû û-ûþúû û-ûüúûúû û-úúûúûúûûþúûûüúûû,÷ûúúûûúûúûû-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-€€€€+YZ[Z[+YýZYZZ[þZ[[+YýZYZZþYZZ[þZ[[+YZ[+úYXYYXYYZYZü[Z[*üXYXYYûXYYZYYZý[Z*XYZþ[*þWXXýYXYYZ+XYýZYZZþY*üXWWXXYüZYY*WXYþXYY+ýWXWWýXWXXYüZYY*þVWWXWôXYXXYYXYXYY*WýXWXXûYXYY*öVWWVWWXXWXXýYXYY+VWýXWXXþY*VW÷VWWXWWXWXX+VWX+VýWVWWøVXWXXWWXX+VùWVVWWVWWýXWXX+VþUVVýWVWWûXWXX*üVUUVVøWVVWVWXWW+UVW+þTUUVþUVVWýXW*UVWüVWW*ýUTUUüVUUVVùWVWVWV*þTUUVUVWV+þTUUþTUUþVUUVüWVV*TUþTUUVúUVVWV*ùSTTUTTUUþVUUûVUVV*TýUTUUøVUUVVUV*TþSTTUþVUUþV*ûSTTSTTþUTTUüVUV*STùUTTUUTUUþV*STþSTTýUTUU+þRSSTõSTTSTTUTUTUU+þRSSûTSTSTTUþT*RSûTSTSTTþU*RýSRSSþTSST+RSþRSST+ýRQRRSþRSST+þQRRýSRSSTST+RýSRSSýTS*þQRRSøRSSTSST*QúRQQRQRRSþRSSþT*QRQRþSRRSþT*QýRQRRýSRSS+ýQPQQþRQQRþS*PýQPQQRSþR*PûQPQPQQRSR+PüQPPQQúRQQRQRRþS*þOPPúQPQQPQQR+üOPOPPüQPPQQR+ùOPPOPPQQþPQQR+OPQüPRQRR+OúPOPPOPPQþR*OPþQPPQþR*NOPþOPPQPQ+NýONOOPþOPPþQ*OþNOOPþOPPQ+þONNOýPOPPþOPP+NOþNOOüPOOPP+NOûPOPP*þMNNýONOOþPOOP+ûabaabbcýdc*bþabb cþd*abþabbcþbcc+aýbabbcþbcc+aübaabb÷cbcbccbc*þ`aabûcbcc*aþbaaýbabb+ abþc*`aöbabaabbcc*`a`ab+`úa`a``aab+`þ_``abaþb*`þa``aþb*_`ab+_ü`__``a+÷^__`_``_``aþ`aa+ _`aþ`*_`þ_``üa`a*þ^__`_`úa`aa`*û^__^__`_`þa*^_þ^__ú`_``_``+^ù_^^__`__ý`_``+^ý_^__`ü_``*þ]^^_ø`__`_``*^þ]^^ý_^__þ^__ü`__*]^_^ø_^__`__*]û^]^]^^û_^_^__+]^û]^^]^^_þ^__+\]÷^]]^^]^_^^_+]ü^]]^^ú_^^__*ý]\]]^]û^]^^__þ^*û\]\\]]^ü_^^*\ý]\]]^þ]^^þ_*\ý]\]]ö^]]^^]^]^*\þ]\\]ø^]^]]^^*þ[\\ü]\\]]^+[\ú]\]\\]]^+[\]þ\]]+[ü\[[\\]+[ü\[[\\ü]\\]]+ý[Z[[\þ[\\ú]\]\\]]+üZ[Z[[\ü]\\]]+úZ[[ZZ[[ý\[\\ü]\\*ù[ZZ[[Z[[þ\[[\+Zü[ZZ[[ú\[\[[\\+ùZYZZ[Z[[þ\[[\+Zú[Z[[Z[[û\[[\*YZ[ü\[[\\+YZý[Z[[þZ[[þ\*ZYýZYZZü[ZZ[[+YþZYYZ[þZ[[+Y Z[+ýYXYYúZYYZYZZû[Z[Z*YúXYYZYZZþ[*ûYXYXYYZüYZYZZý[Z*XýYXYYúZYZZYZZþ[*X YZ+XYZüYZZ*XþYXXüYXXYYZ+XþYXXYþZYY+WXYþXYY+WúXWWXWXXYþXYYþZ*WýXWXXY+WýXWXXY+óñòñòññòòñòòñòòþñòò+ñýòñòò+þñòòüñòòññò+þòññòþñòòüñòò*òüñòñòòýñò*úñòòñòññòñò+ñúòñòññòòþñòò+õòñòñòòñòòñòòüñòñòò+ûñòòñòòñòþñòò+þñòòïñòñòññòññòñòòñòò*ñúòñòññòòýñò*þñòòñòñòñýòñ*ñøòññòñòòññòñ+ñûòññòññüòññòòûñòññ*þòññòõñòòññòñòññ*ýñòññýòñòò+ñòñòñýòñ* ñþòññûòñòò*ñþòññòüñòñ*ñþòññòñòþñ*ýñòññþòññò+ñþòññûòñòòññ+ñòñûòñòò* ñòñûòñòñ*ñþòññúòññòñ*ñþòññþòññò+ñþòññ+ñ+ýñðññòûñòñòññ+ñþòññ+ñþðñ ñò+þðññþðñ ñýòñ*ñøðññðññðññþòññ+ñþðññûðññðññ+þðññþðññþðññ+üðñðññþðñ ñ+ñþðñ ñ+ñþðññþðññ+ýñðññþðññùðñðñðñ* ñðñ+ðñþðññüðñðññ+ñþðññüðñðññ+ñðùñððñððññ+ôðññððñððññðññþð*ðþñððñúðññððññ+ñþðññþðññúðñððñ*ûðññðññôðñðñðñððñðñ*ðñðþñððõñðññðñðñðñ*ðñüðññððñûðñðñ*úñðñðñððñþðññûðñðñ*ðñðñ÷ðñðñðñðñ*ðòñðññðñðññðñðñ*þñððñõðñðññððññð*ðñýðñððýñðññþð*ðñðñðþñððýñð*ðñýðñððñûðñðñ*úðñððñððúñððññððüñðñ*ðþñððöñðñðñðññðññ+ýðñððûñðññððþñððýñð*ðþñððñðøñððñððñ* ðþñððñýðñ*þñððûñðñðññðúñððññ* ðýñðññðüñðð* ðúñðñðñðð+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿþ[\\þ]\\ý]\]]ý^]^^ü_^^__þ`__ý`_``üa``aaúbabbabbc[ý\[\\]\]÷^]]^]]^^__^_ò`_``_``a``a``aaýbabbüc[[\\þ[\\]þ\]]ú^]^^]^^_`abücbc[[\þ[\\]ü^]]^^_þ^__`ùa`a`a`aa bþc[[\[\]þ\]]^]^÷_^__^__`__`ùa``aa`aabýcb[[\[\]ü\]\]]û^]^]^^_þ`__`aþ`aaýbabbZõ[Z[[\[\\[[\\û]\]\]]^ü_^^__`þ_``ûa`a`aaböabac[ZZ[Z[[\þ[\\ü]\\]]ý^]^^_þ^__ü`__``þa``aûbaabZZ[þ\[[\ý]\]]^]^þ_^^_`þ_``abþaZZ[\]þ\]]ü^]]^^ý_^__ `aûbabYZZ[\þ[\\ü]\\]]^þ]^^ _`ýa`aaþ`aaþYZZ[\þ[\\ú]\]]\]]^ü_^^__ú`_``_``aþ`aaúZYZZYZZ[\ü]\\]]^_þ^__`a`YöZYZZYZZ[Z[[þZ[[\þ]\\ ]^_þ`__ý`_``öa`aaYYZYYZZü[ZZ[[û\[\[\\]þ\]]^û_^_^__`þ_``aYýZYZZþYZZ[ûZ[[\[[\]^ý_^__`þ_``ýaXYYZ[þZ[[\þ[\\]^û_^_^__`þ_``þXYYýZYZZ[þZ[[\þ]\\]^ý_^__þ`__`XYZ[Z[\]þ\]]^_`øXYXYXYXYYþZYYZ[ð\[\[\\]\\]]\]]^]]^þ]^^_`þ_XXýYXYYZ[\]ù^]]^^]^^ý_^__ü`_`XXYýZYZZû[Z[Z[[ý\[\\]ý^]^^_þWXXYZþYZZø[Z[[Z[\[[\ü]\\]]^_^_XþWXXYþXYYZ[Z[ý\[\\]þ\]]^þ]^^ý_^__WýXWXXYüXYYZZþYZZ[Z[\]^þ]^^_ù^_WXWWXXþWXXYXYZ[þZ[[ü\[[\\ü]\\]]ý^]^^_þ^WWXYþZYYZý[Z[[þ\[[\]\] ^VWýXWXXYýZYZZ[\ñ[\[\\]]\\]]\^]^^þVWWXþWXXYûZYZYZZ[\]þ\]]^VWXþWXXùYXXYXXYYZö[Z[[\[\\[\\]ý^]^^V÷WVWVVWWXWWXYøXYXYZYYZZ[þZ[[\]ý\]^^VWþXWWýXWXXYüZYYZZý[Z[[\þ[\\]þUVVWþVWWüXWWXXYZü[ZZ[[\þ]\\]÷UVVUVVWVWWýXWXXYýZYZZþ[ZZ[þ\[[\]\]úUVUVUVVWþVWWXþYXXYZþYZZ[Z[\]\UVWüVWVWWXþWXXY Z[\þ[\\]ý\]UUýVUVVþWVVWóXWWXWXXYXYYXYYZü[ZZ[[\ý]\UUVWVWXYþXYYZ[ý\[\\ýUTUUûVUVUVVþWVVWüXWWXXþYXXøYXYYZZYZZ[ô\[[\\[\]\TTUUýVUV VWXýYXYYüZYYZZ[ý\[\\TUüVUUVVWVWõXWXWXYXXYXYYúZYZZYZZ[ý\[\\TüUTTUUüVUUVVûWVWVWWXüYXXYY Z[ú\[\[STTýUTUUúVUUVUVVWýXWXXYýZYZZ[øZ[\[[\STTUýVUVVüWVVWWþXWWXYüZYYZZ[þ\SSôTSTUTUTUTUVUUVùWVWVWVWWXýYXYYZYZ[STUþTUUýVUVVWXþWXXýYXYYýZYZZý[Z[[üZ[[SSTýUTUUüVUUVVWXþWXXYüZYYZZû[ZZ[SSýTSTTUþTUUVþUVVýWVWWýXWXXYüXYXYYýZYZZ[STüUTTUUVþWVVWXþWXXýYXYYþXYYýZYZZü[RRSSTUýVUVVúWVWWVWWùXWXWXWXXYúZYZZYZZSûRSSTSSTüUTTUUVþUVVþWVVWüXWWXXYþXYYZüRSRSSTüSTSTTUûVUVUVVúWVWWVWWXüYXXYYýZYZZRSTUTUüVUUVVýWVWWXYþZYYRüSRRSSTüUTTUUýVUVVøWVWVVWVWWXüYXXYYRSþRSSýTSTTýUTUUþTUUVUVWüXWWXXYüZRQRRúSRSSRSSüTSSTTUVWþVWWXþWXXþYXXYúRQQRQRRSþRSSTùUTTUUTUUVWþVWWXþWXXøYXYXYXYQQRüSRRSSTüSTSTTúUTUTTUUýVUVVýWVWWXþWXXúYXXYYQQûRQRQRRýSRSSTþSTTýUTUUûVUVUVVóWVWWVWWXWWXWXXþYQQRSTþSTTUþTUUVWVWþXWWXYQRþQRR÷SRSSRSSTSSTöUTTUUVUVUVVWXþWXXúYQPQPQQRSTþSTTUTUVøWVWWVWVWWXûPQPPQQýRQRRýSRSST÷STTUTTUTUUýVUVVWþVWWüXWXPPüQPPQQRQïRQRRSRRSSRRSSTTSTTUTUüVUUVVWþXW÷dcddededeeüfeeffgüfgfgghþghhýihiiújijiijjþkjjkdûededeefþeffügffgghghiþhiijþijjükjkccdedeúfeefeffþgffýgfgghgýhghhûihihiijijökjcdccddcddeþdeeófeffgfgffggfggóhghhghihhihhiijþkccýdcddeþdeefþeffgþfgghþghhiþhiijiýjijjc düeddeefþeffþgffghþghhiûjijijjýcbccþdccdýedeeþdeeüfeeffügffggøhghgghghhýihii÷jijjijbbccýdcddýedeeýfeffgfghþghhijúijjcbccdüeddeefeòfeffggfgffgghgghiûhiihiijýicbbcdefþeffúgfggfgg hýihiijbûcbcbccüdccddùeddeedeeýfeffügffgghüihhiibùcbbccbccdþeddefefýgfggúfgghghhügihiiýbabbücbbccdcdúeddedeefgýhghhüihhiiýbabbcübcbccýdcddôededeefeffeffgüfgfggýhghhþghhüihiaabcûbccbccýdcddýedeefþeffgüfghggýhghhiûhiaabbúcbccbccdücddeede÷defeffeeffgüfgghhüghghh÷ihabaababbcbcþdccdøeddeedfeefgúhgghghhiþ`aaýbabbcübcdccdýedeeýfeffügffggûhghhaa bcýdcddüeddeefþeffghþ`aabþcbbcýdcddýedeefþeffgþfggù`a``a`aaýbabbýcbccüdcdccdeûfefeffýgfggþfggöhghh``a``aabcþbccdcýdcddýedeefýgfggûh`aa``ýa`aaübaabbýcbccdýedeeûfefeffþgffgýh_``a`abûcbcbccdeüdedeefþeffg`aþ`aaübcbccþbccýdcddúeddedeefüefeffýgfgg`þ_``aþ`aabþabbcþbc cdefgð_``_``a`aa`a`a`aaýbabbþcbbcüdccddúededdeefg_ `ýa`aaübaabbcïbccddccdccddeeddeef_`ýa`aaþ`aaþbaabûcbcbccdùeddeedeef_ý`_``aþ`aabüababbcbcdþcddeøfeffeff__`aþbaabþabbcd ef^_ú`_`__``ýa`aaübaabbýcbccdefý_^__ý`_``ýa`aaûbababbcþdccdeüdedeef^û_^_^__`þa``ababþabbcdcdúedeedee^_`þa``abúcbccbccûdcdcddýedeeû]^^_^^_ `ýa`aabþabbcþbccdþcddþedde]^_ü`__``aþ`aaübaabbcüdccddøedded]]^^_ý`_``ûa`a`aabýcbcc dýe]^^ü_^^__`_`þa``abcþdccdúede]]^^]^_`þ_``öa`aa`abaabbþabbcúdcdccddþe]]^ù_^_^_^__`abþabbcbcþbccþdccd]^û_^_^__þ`__ý`_``üa``aa÷baababbcbbc÷dcdcdcdd]]^þ]^^ú_^^_^__`ûa``a``abüababbùcbbccbccdýc\]]^û_^_^__ô`_`_``a`a``aaýbabbýcbccùdc\\]\]]^þ]^^ü_^^__ý`_``ùa`ababaaõbabbcbcbcbccd\]ý^]^^ü]^]^^þ_^^_`ýa`aaýbabbcbøcbccddc\\]^þ]^^_`þ_``ýa`aabýcbccþ[\\ú]\\]\]]^]^þ_^^_þ`__`a`abcbûcbc[\\]ú^]]^]^^_û^__`__`þ_``ýa`aabþabbcûbcc[\\]þ\]]ý^]^^_ù^__^__``þ_``ýa`aaþ`aab÷cbbcc\[[\\þ]\\]û^]^]^^ý_^__`ab÷ababccbb[[\þ[\\]ø^]^]^^]^^_þ^__ `üa``aabc[ü\[[\\ ]^þ]^^_ý`_``aübaabb[\]^þ]^^ú_^__`__`aü`abaab[þZ[[ú\[\[[\\]þ\]]ø^]^^]^^__û^__^__`_`a÷baabab[Z[[ý\[\\÷]\]]\]]\]]^þ]^^ú_^__^__ý`_``aþ`aaþbZZý[Z[[ù\[\[\\]]^]^ü_^^__ý`_``üa``aa÷`aababZZ[[ü\[[\\ü]\\]]^ý_^__û`_`_``þa``aZ[Z[ý\[\\ý]\]]ö^]^]^^_^_^^_`ùa`a`aaZZû[Z[Z[[\]þ\]]ý^]^^ý_^__ú`_``_``ýa`aaZý[Z[[þZ[[\]ú\]\]\]] ^_ý`_``÷a`a`aYZYZZú[Z[[Z[[\þ[\\ñ]\]]^]^]^^]^^_^^_þ^__þ`__`øa`YZZYYZZþ[ZZ[\ù]\]\]\]]ý^]^^ú_^^_^__`þaYYZú[ZZ[Z[[þ\[[\ý]\]]þ^]]ý^]^^ú_^__^__`òþóòòüóòóòòóòóûòóòòóóþòóóþòóóòþóòòíóòóòóòóòòóòòóòòóóòóóòóþòó óòþóò òóúòóòóóòòóüòóòóóþòóóýòñò òþóòòþóòòóòóýòóòòýóòóóþòóóýòñò òþóòòóòóòóùòóòóóòóóòóûòóóòóóòñ òþóòò÷óòòóòóòóòòûóòòóòòóüòóòóóòóòþñòòþóòòûóòóóòòóòóüòóòóóñòþñòòþóòòóòúóòóóòóóòûóòóóòòöóòóóòòóòñòòþñòòüñòñòòüóòóòòóòýóòóóýòóòòþóòòóòóûòñòñòòþñòòþóòòûóòóòóóòüóòóòòýóòóóòùóòñòòñòòûñòòñòòüóòóòòùóòòóòóòòþóòòóüòóòóóþòóóüòóòóóòûñòòñòòúóòòóóòòüóòóòòûóòòóòòóüòóòóóòõóòòóóòñòòñòòþñòòþñòòþñòòþóòòþóòòùóòòóòòóóòóúòóóòòóóòúñòòññòòþñòòþóòòùóòóòòóòòóøòóòóòòóòòýóòóóúñòòñòññòüñòñòòñ òþóòòþóòòüóòóòòóúòóòóóòòóüòóòññòüñòñòòþñòòþñòòó òþóòòóòþñòòþñòòûñòòñò òüóòóòòþóòòóòöóòóòñòòñòññòþñòòþñòòúóòóòóòòóòóþñòòùñòññòñòòþñòòþñòòþóòòþóòòóòóöòóòòññòòñò òûñòòñòòþñòòûóòòóòòóòóòóòñúòññòñòòþñòòþñò òþóòòþóòòøóòóòóòóòòùóòóóòñòòþñòòþñòòþñòòþóòò÷óòóòóòóóòòñûòññòññòþñò òñ òóòóýòóòòüóòóòòñ÷òññòñòññòò÷ñòñòññòñòòþñò òûóòòóò òõóòòóññòòñòññòþñò òþñò òóòþóòòþóòòó÷òñòñòòññòòòñòñòñòòñòñòññòòñòþñò òþóòòþóòòþóññõòññòòññòòñòòñòñòþñòòþñòòþñòòôóòòóòóòóòòóòòýóòññþòññò÷ñòñòòñòñòò÷ñòòñòñòñòòüóòóòòñþòññòñòñòùñòñòòñòòþñòòþñò òþóòòúóòóòòññùòññòñòññûòññòññûòññòññýòñòòþóòòùóòññòòññòñúòñòòñòòñûòññòññòñòþñòòúóññòòññýòñòòñþòññüòññòòùñòñòññòòþñòòüóòòñ ñôòññòññòòñòòññòñùòñòòññò òþñòòóþòóóúòóòñòññþòññúòññòòññûòñòñòòñòûóòóòññòñûòñòòññòñòñþòññòþñòòþñò òñþòññûòñòòññ÷òñòòñòññò òñò ñøòññòññòññòþñòòñôòñòñòñòñòññòòüóòòññþòññþòññòúñòñòòññòþñòòñòûñòòñò ò ñÜòññòññòñòññòñòòñòòñòòññòòñòòññòñòññòòþñò òþðñ ñöòññòññòñòññòñòþñòòñòöñòñòòñòòñòòñõòñòññòòñòòññýòñòòþñòòþñòòþñòòñþòññòòñòññòñòññòññòòøñòòññòñòòþñòòñòþðñ ñþòññþòññþòññúòññòñòòþñòòñòñüòññòòþñòòþðñ ñþòññõòññòñòòñòñòòñòñòûñòòñòòþñòòñþòññûòññòññòôñòñòñòñòòñòññòþñòòñüðñðñ ñþòññûòññòññýòñò òþñòòþñòòüñòòññûðññðññþòññúòññòñòòüñòòññ òùñòòññðññþðñ ñüòñòññþòññòùñòñòòñòòüñòñòòþñòòñþðñ ñþðññþòññòûñòññòòñýòñòòþñòòñþðññþòññþòññþòññòîñòññòñòñòññòññòòñòòñùðññðñðññþòññþòññüòñòññþòññòñòñòþñòòýñðñ ñþðñ ñþòññþòññîòñòòñòññòòññòòñòòññþðññþðññþðññþòññòñþòññöòññòòññòñòòñýòñððñüðñðññüðñðññþòññþòññøòñòòññòññòôñòòñòñòñòððññþðññþðññúòñòòñòòýñòññò÷ñòñððññðññðñþðññþòññýòñòòñùòñòñòòññòòññòññðññðññðññþðññþðñ ñøòññòññòññòúñòññòññòþñòòñðýñðññüðñðññþðññþðñ ñþòññòñ÷òñòññòòñòòøñòññòñòððûñðññððýñðññþðññúòñòñòññøòññòòñòññððñðñðñððñðññðññðññþòññòñþòññòñðúñðññðññþðññþðññþðññþðñ ñûòññòññòñòõñòòððñððñðññþðñ ñþòññûòññòññþòññüòðñððýñðññðýñðññþðññð ñþòññòòññòñòñòññððñððüñððññõðññðññððñðññðñüðñðñ ñòñòñýòñòÿùcdccdcdde fgýhghhiþhiijþijjkøcddccdcddýedeeþfeefþeffýgfgghþghhûihihiijúkjjkkccýdcddeþdeeüfeeffgþfggûhghghhiþhiiýjijjýkjccdþeddefýgfgghiþhiijcúdcdccddþeddýedeefûgfgfgghghiþhiiöjiijjkbcbccdþcdde fýgfggþhgghiüjiijjúbcbcbccþdccdeùfeeffeffügffggûhghghhüihhiiýjijjbcþbccýdcddüeddeeýfeffgfghýihiiûjijibbcûbccbcc defþeffþgffghüghghhýihiiüjijbbcbcdcýdcddeûfefeffýgfgghýihiiabcbcýdcddþcddþeddeýfeffúgfggfggîhghhihihhihijabaabbúcbbcbcc defþeffýgfggühgghh÷ihhiihhiaabüabbccþbccdeüdedeefeúfgfgfgghi÷hiabaababbcþbccd efýgfgg haûbababbcøbccbcdcddcdefýgfggühgghhþiaabcûdcdcddeþdeefefghþghhaþ`aaýbabbþcbbc defþeffúgfggfggýhghhaþ`aaöbaabbabbcbbýcbccdeþdeefgþhggh`úa``a`aabþabbýcbccýdcddúcdeddeeþfeefþgffg`aþbaabcýdcddcdeþdeefügffgghý`_``aþ`aaôbabbabcbbcbccdücdcddüeddeefþeffgþ_``aþbaabcbcþbccdeüfeeffgfg`þ_``úa`aa`aabþabbcdeüdedeeýfeffùgfggfg__`úa``a`aabþcbbücbbccdþcddüeddeefþgffþg__ü`__``aö`aabaabaabbcbcde÷fefeeffgffþ^__ `÷a`abaababbücbbccdcdeýfeff_þ^__`þa``aûbababbúcbccbccýdcddeþdeefý_^__þ`__`þa``abcüdccddþeddüeddeeøfeffeef^^ý_^__ú`_`__``a`abþabbcþbccdüeddeeêfeeff^^__^_^__``_`_`_``ýa`aabcbýcbccdþcddeüfeeff^_ý`_``aýbabbûcbcbccdþcddeô]^]^^_^_^_^__ý`_``üa``aaù`aabbabbýcbccýdcddeüfe]^^ù_^_^_`__`ýa`aaþbaabùcbbcbbccdeüdedee]ý^]^^_þ^__ý`_``ýa`aaþbaab cüdccdde]^þ]^^_þ^__ `abaýbabb cdeú\^^]]^^ü_^^__ü`__``a býcbccýdcddüedd]]ø^]^]^]]^^_^_`þ_``abcübcbccýdcddü\]\]]^]^_þ`__`þ_``aúbabaabbcþbccdûe\]\]]^þ]^^ú_^__^__ú`_`__``ýa`aabcýdcddþ\]]þ\]]ú^]^^]^^_`øa`aa`a`aabþabbcd\]þ\]]ý^]^^_ `aûbababbcþdccþ[\\]^_`þ_``üa``aabûcbcbccýd[\\ý]\]]^_þ^__ü`__``aþ`aaúbabbabbcþbccýd[\\ý]\]]^þ]^^_`üa``aabþabbûcbcbcc[õ\[\\]\\]\\]]^]^_`ûa`a`aaýbabbc[\û]\]\]]þ^]]^þ]^^ü_^^__`_`a`÷a`aabbaabbþcbb[þ\[[\ü]\\]]ù^]]^^]^^_ü`_`__`ababc[ý\[\\ú]\]]\]]þ^]]^_þ^__`aübabaabücbZ[[\ú[\]\\]]^þ]^^ú_^__^__`a`ababZ[\]þ^]]ý^]^^_ô`__`__``a``aaúbaabbZZ[üZ[[\\]û\]]\]] ^_ö`__``_`a`aaýbabbZþ[ZZ[\þ[\\û[\\]\\]ü^]]^^ü_^^__ `ýa`aabZý[Z[[ý\[\\þ]\\]ý^]^^ý_^__ú`_`__``aZþ[ZZ[ý\[\\þ[\\û]\]\]]ø^]^^_^^__ü^_`__`aYZ[üZ[Z[[ü\[[\\]^ø]^^__^^__`aû`a``aaùYZZYZYZZý[Z[[ý\[\\]\ý]\]]ü^]]^^_û^__`__`üa``aaûYZYYZZ[þ\[[\]þ\]]þ^]]^_^_`_`ýa`YYZü[ZZ[[\ú]\]\\]]^ü_^^__`þa``þXYYþZYYZ[\ý]\]]ü^]]^^ü_^^__û`_`_``ýYXYYùZYZYZYZZ[\[\þ]\\]û^]^]^^ _`ýYXYYZþYZZ[Z[\]þ\]]ø^]^]^]]^^_`ûXYXXYYýZYZZý[Z[[ü\[[\\ý]\]]ù^]^]^]^^þ_^^_þ^__`ü_``XXYZþYZZ[ \]^û_^_^__ü`_`XXýYXYYZ[ùZ[\[\[\\ø]\]\]]^]]^ú_^^_^__üklkllmþlmmýnmnnûmnnonnopqþrqqrkþlkklmlmþnmmnùonnoonoopqüpqpqqrþqrrklþkllýmlmmünmmnnonoýpoppýqpqqþrqqþjkklmþlmmnoûnonnoo pqýrqrrþqkkþjkkülkkllmúlmnmmnnýonooþnooýpoppqpqûrqrjkkþjkkúlkllkllm noüpooppúqppqpqqrjýkjkköjkklkkllkllýmlmmnþmnnúonoonooþpoopýqpqqpqjkûjkklkklümllmmnüonnoopþoppqüijijjk lûmlmlmmnmnoþnoopþqppqýpijjkýlkllþkllmþlmmùnmnnmmnnoþnooþpoopqijúkjjkjkkþlkkýlkll mnûononoopqùijjijijjkûlklkllýmlmmþnmmnoûnoppoopþqiiýjijjýkjkkúlkllkllûmlmlmmünmmnnoþnooûpopoppýqhiijküjkjkkýlkllýmlmmúnmnnmnnýonooþpoopýihiijijýkjkkþjkklmþlmmünmmnnoúpophhiiûjijijjkýlkllmlmnýonoophijijkúlklkkllûmlmlmmûnmnmnnûononooþphhiüjiijjýkjkklùklmmllmmþnmmnohijükjjkkülkkllmlmnoùhghhihiijþkjjklþkllûmlmlmmnþmnnþmnnoghiþhiiýjijjklþkllmnþmnnoüngghhúihiihiiýjijj k÷lkllmlmlmmúnmmnmnnoþghhþghhiþhiijijþkjjkýlkllýmlmmýnmnnûghgghhijijklklømllmmllmmnmnüogghhþghhûihihiijijýkjkklûmlmlmmnþmnngühgghhiýjijj kýlkllmnþmnnþfgghþghhûihihiijijklúmlmmlmmnûmfgfggùhghghghhýihiiújijjijjþkjjùkjkllkllmòlmmnnmnmnggffgghøihihhihiiòjiijijjkjjkjjkklþkllûmlmlmmnúmffgfgghiüjiijjkýlkllþmllmýnmffýgfgghghþihhijûijiijjkþjkk lýmlmmfghþghhùihiihhiiýjijjýkjkkùlkkllkllmþlmmüfeeffghþihhýihiiýjijjükjjkkülkkllmþeffgûfggfgghghiýjijjúkjkjjkklømllmefeffýgfgghýihiiþhiiýjijjkýlkllýefee÷feffggffggühgghhiþhiijküjkjk külmmeeôfeefeffgffgffgýhghh ijýkjkkúlkllkllõedeefefefeffgþfggýhghhijýkjkkýlkll÷dedefefeffgûhghghhþihhijkþjkklþdeeúfefeeff÷gfggfgghggýhghhþihhiüjiijjýkjkklúdededeefþgffýgfgghþghhiûjijijjkþjkkdefgþfgghiþhiijkdeþdeeüfeeffgþfgghûghhghhiþhiiüjiijjúkjkkjkkdüeddeeúfeefeff gh iýjijjùkjkjkcddeúfeefeffgøhgghhgghhiþhiiýjijjkþcddûededeeýfeffgüfgfgghúihihhiijijøkjkcdccddýedeefghûihihiiýjijjcdüeddeefgþfgg hiþhiijþijjcþdccdefeýfeffgýhghhýghi ijcdþcddeýfeffúgfgffgghgþhiih ij cdýedeeùfeefeeffùgfgfgfgg hiújijbbccdeüfeeffýgfggýhghhijbcþbccdþcddeûfefeff gýhghhiþjiibücbbcc düeddeeýfeffgüfgfggühgghhýihiiþhiibúcbccbccdþcddûededeeûfefeffgþfggýhghhihi÷ababbcbbccþdccdeþdeeúfeefeffügffgghøghihiihiiýbabbþcbbcdþcddeúdedefeefgþfggühgghhiabcúdcddcddýedeeüfefeefýgfggýhghhùihihaabbþabb cdöeddeffefeffgþhggha býcbccüdccddeüfeeffghabücbbccýdcddefþeff ghþ`aaþbaabûcbcbccûdcdcddeýfeffúgffgfggh`ða`aababaababbcbccþbccüdccddûededeeýfeffgfýgfggühgh``aübaabbýcbccùdccddcdd efþeffgühggh óþôóó÷ôóôóôôóóôôûóôôóôôóôþõóóúôóôóôóóôóôóôóôþóô ôóþôóóþôóóþôóó÷ôóôôóóôôóóþôóóýôóôôóôþóôôóþôóóþôóóôóøôóôôóóôóóôþóôôþóôôó ôóþôóóôýóôóóôòóôóôóôóôóôóôóôôóô óþôóóþôóóôóöôóóôóóôóóôôûóôóóôôþóô ô óþôóóûôóóôóóôóúôóóôóôôþóôôüóôóôôþóôôóüôóôóóþôóóôóôóôþóô ôþóôôþóôô óþôóóùôóôôóôó óüôóôóóôøóôôóôôóôôóòóþôóóôóôóúôóôôóôôúóôôóóôôúóôóôôóóþòóóþôóóüôóôóóüôóôóóþôóóôóôþòóóþòóóþòóóõôóóôóôôóóôóóôóôóôóôõóôóóòòóòóòó óþôóóþôó óþôóóóôóóôóóôóôóôóôôþóôôóþòóóþòóóôöóôóóôóóôóôôóô÷óôóôóôôóôôóòýóòóóôüóôôóóôóüôóóôôóòýóòóóôóôóþôóóüôóóôôûóôóóôôùóôòòóòóóüòóòó óþôóóôýóôóóþôóóôõóôôóôóôóòòó óòóþòó óôóüôóôóóþôóóþôóóôôóôôóóôóôóóòòóûòóóòóóõôóóôóóôóóôóóôüóôôóóôýóôóóòóûòóòòóóþòóóþòóóþòóóüôóôóóôóòôóôóôôóòòóòóòóóòóüôóôó óôóþôóóôòóò÷óòóóòóóòóóüôóôóóôèóôóôóôóòóòóòóòóóòòóòóóòóóûòóóòóóûôóóôóóþôóóôóúôóóôóôôýóòóóþòóóøòóóòóóòóóüòóòóóò óøôóóôóôôó óüôóóòòóûòóóòóóþòóóþòóóþôóóñôóôôóôóóôóóôóóôôúóòóòóòòüóòòóóúòóóòòóóþòóóôóþôóóüôóôóóòóóòòóóòóóòóóòóóüòóòó óþôó óþôóóþôóóòóòóþòóóòóþòó óô óôóòóòôóòóóòóòóòóòóóúòóòóòóóþôóóüôóôóóòóòóòóþòóóþòóóþòóóþòóóôóòóòþóòòóòùóòòóòòóóüòóòóóûôóôóòòóýòóòòûóòóòóóòóþòóóôóòúóòóóòóóòýóòóóòóþòóóüòóòóóþôóóýôóòòýóòóóöòóòóòòóòòóóûòóóòóóôóòþóòòûóòóóòòóöòóòóóòóòòóóòóþôóóòþóòòóýòóòòøóòòóòóòóóòóøòóòòóóòóóýôóòòûóòòóòòóòóòóúòóóòóòòóþòóóòóýòóòòóòòóòóóòóóòóòóóòòøóòóòóóòóóþòóóýòóòòüóòóòòóëòóóòóòòóóòóòóòóóòóóòóóþòóóþòóóòùóòóòòóòòùóòóóòóòòýóòóóþòóóöòóòóóòóòòóó òþóòòóòóûòóóòóóòóüòóòóóòóòýóòóóòóþòóóûòóóòóóòùóòóòòóòòçóòóóòóóòóóòóòòóòòóòóóòóòóóþòóó òûóòòóòòþóòòïóòòóòòóóòóòòóòóòóóòþóòòýóòóóòóòóõòóóòóóòóóòóóòýóòóóüòóòóó òþóòòóòóòóûòóóòóóýòóòòóòûóòóòóóòüóòóòòóùòóóòóòóóòóþòóóòþñò òþóòòþóòòþóòòóòóþòóóùòóòóóòóóýòñòòñòóòþóòòõóòóóòóòóóòóóþòóóþñòòþñò òùóòóòóóòòþóòòþóòòøóòòóòóòóóûòóòòóóòüñòñòòþóòòóòóòýóòóóúòóóòòóóþòóóòþñòòüñòñòòøóòòóóòóòòó÷òóóòòóóòóóòóüòóóòòþñòòþñò òüóòóòòþóòòóóòòóòòóòóóòòóóüòóòóóòóñ!òþóòòóòýóòóóþòóóòþñòòþñòòþóòòûóòòóòòóòóýòóòòûñòññòòþñòòþñòòûóòòóòòóùòóòòóóòòóòóòóýòñòòñöòñòññòñòñò òþóòòþóòòþóòòóòýóòóóòñòþñòòñòþóòòóòóòòóòññòòññòñòñòòþñòòþóòòóòþóòòóòóòòóòóòóññòñòòñòòñòüñòñò òþóòòóòóòóòúóññòñòòþñòòþñòòþñòòþñòòþóòòûóòòóòò÷óòóóòóñòññüòññòòþñò òþñòòûóòóóòòóòýóòññ÷òñòòññòñòòñ òûñòòñò òûóòóóòòùóòóóòòóóòþóòòñòüñòñòòñòþñòòüñòñòòþóòòóòüóòòóóÿôklklkklklmlmmþlmmünmmnnoüpooppqrsklmþlmmýnmnnýonooýpoppqüpqrqqrsþjkkþlkklmnoýpoppþqppqrkþjkkýlkllómlmlmmlmmnmmnnýonooýpoppþoppqüpqrqqõrqqrrsjkjjkklþmllmþnmmnoúpopooppqñpqpqrqqrqqrrjjkkl mnonopqþpqqrjkþjkkûlklkllümllmmýnmnnþonnopq÷pqqrqqrrjjükjjkkúlklkkllmnmnþmnnüonnooùpoppopqqpqrûqijijjkülkkllmlmûnmnmnnøonoonopooýpoppóqpqpqqpqqijijjükjjkkülkkllþmllmnopþoppqijüijijjýkjkklmólmmnmmnmnmmonnüonnooúpoppqppq÷ijiijijijjkùlklklkllmþlmmnûononoopopûqppqiijükjkjj÷kllklklkllmþlmmýnmnnoýpoppøoppqpqhiijijökjkjkkjklkklmùnmnmnmnnýonoopþoppqýihiiûjijijjkülkkllýmlmmnoüpooppühihiijkjkýlkllþmllûmlmlmmnþmnnopophijõkjkjjkjkklkklümllmmnþmnnýonoopûohhihhijükjjkkýlkllümllmmnýonoohijijükjjkkýlkllúmlmmlmmnþmnnonoghiüjiijjkülkkllmönmnmnnoonooûghhghhi÷hijjijiijjûkjkjkkõlkkllkllmlmm noúghghghhýihiiüjiijjýkjkkýlkllmûlmmlmmýnmnnogýhghhihijkþlkklümllmmnþmnnoþfggùhghghghhiújiijijjkþjkk lümllmmnþmnnþogg høihiihiij jûkjkjkklþkllümllmmnùonnggfgghøihihiihiijùijjkjkjjklþkllmþlmmýnmnnüfgfggýhghhiþhiijkjkúlkklkllmlmýnmnnúfgfgfgghghihijþijjþkjjklklmlmnfûgfgfgghiþhiiüjiijjükjjkkülkkllmlmnþeffþgffghiþhiiýjijjýkjkkúlkklkllmlmûnmeeffügffggúhghhghhijijkýjlkklþmllmünmeffg hiýjijjükjjkkülkkllmþlmmýfeffgùfhghgghhijýikjjúkjkklkklmefügffgghihijùijjkkjkklklýmleeüfeeffýgfggúhghhihhijüijijjkýlkllmþdeefþeffgfgýfghhüghghhýihiiýjijjkülkkllefþeffgfgõhghghihhihiijþkjjúkjkklkklþdeeùfeeffeffògfggfgghhghhghhýihiijýkjkkülkklldefýgfgghüghhiihiüjiijjklkdúedeedeeþfeef ghýihiijkldeüfeeffþgffghgûhihihhijûijkkjjkücdcddüeddeefþeffghijijýkjkkýdcddüeddeedefefýgfggýhghhýihiijþijjkcdeþdeefûgfgfgghgh ijkjkcdefþeffghþihhijkújccdcddýedeefþeffgùhghghghhiýjijjýkjccdùedededeefûgfgfggýhghhiþhiiþjiijücbbccdþcddeþdeeýfeffýgfggh iüjiijjùbcbbcbccdþcddûededeeúfefeeffgýfhgghýihiiøjijijjibbýcbccdcdeþdeefgúhghhghhóihihiijjiijjbbücbbccüdccddeþdeefþeffúgfgghgghiþhiijbcþbccdþcddeþdeefþeffýgfggöhghghhihhiiýjibbücbbccdþcddefþeffgüfgfgghihiþjbbcþbccdeüfefeefúgfggfgghýihiiýbabbúcbccbccdcdüeddeefýgfggýhghhiabcd efþeffýgfggühgghhþiaabûabbcbbýcbccdeþdeeþfeeýfeffýgfgghiþ`aab÷abbcbccbccdþeddýedeeüfeeffgôhgghhghhi``aabýcbcc÷dccdcddeddýedeeýfeffgfghþghhü`a`aaþbaabýcbccdþcddüeddeeûfefeffgþfggþhgghaþ`aab cûdcdcddeýfeffþgffghýgh``aýbabbúcbbcbccûdcdcdde fgþh``þa``abýcbccdúcddedeeýfeffògfgfghggh_`__``öa`aabaababbücbbccdþcddeþfeefgh stúuttutuuvþuvvýwvwwûxwxwxxþyxxyøzrrssrrssûtststtuütutuuüvuuvvüwvvwwxüwxyxxyrsûtststtuþtuuúvuvvuvvùwvwvwvwwxúyxyxxyyrüsrrssýtsttúuttutuuóvuvuvuvvwwvvww xyþqrrøsrsrsrrsstþsttuövuvvuvwvvwwýxwxxùyxyyxyrrþqrrüsrrssýtsttýutuuúvuvvuvvwvwxûwxwwxxûyxyxqqrësrsrrsststststtuttutuuývuvvwvwxüwxwxxýyxqqýrqrrsütssttüuttuuývuvv wxýqrqqrýsrssþrsstþsttuvþuvvüwvvwwþvwwþxwwxqrqrûsrsrssûtststtutuvuvûwvwvwwxúwxxqpqqrþqrrüsrrsstþsttöuttutuutuvvþuvvwõxwwxxqpqqpqqýrqrrstþsttutuvówvwvwwxwxxwwppqrþqrrüsrrsstûututuuüvuuvvwøxpqppqpqqûrqrqrrüsrrssýtsttuþtuuüvuuvvûwvwvwwpýqpqqrþqrrùsrsrsrsstst÷uttuuvuuv vwpýqpqqþpqqrþqrrýsrssýtsttýutuuþvuuvùwvvwwvwwpqpq rsütssttþuttuøvuuvuvuvv÷wvwwvppoppýqpqqürqqrrstþsttu vøwvoppooppýqpqqøpqrqqrqrrüsrrsstûututuuývuvvüwvvooýpoppýqpqqrsýtsttüututtuvþnoopqþpqqþpqq rsþrsstuþtuuvüwooppóoppoppqpqpqpqqrþqrrýsrsststýutuuvûuvvnooýpoppþqppqýrqrrsþrsstþsttûututuu÷vuvuvvonooþpoopþqppqþpqqrýsrsstýutuuþvuuùvnnonnoopqþpqqrþqrrsþtsstuûnonnoopþoppqrqrûsrsrsstùutututuunoþnooòpoopoppqpqpqpqqrþqrrsütsstt÷utuutuuvnnopþqppqýrqrrstþuttuýnmnn÷onnoopooppþqppqþpqqrstüstuttþmnnüononnoüpooppþqppqürqqrrþsrrüsrrsstùututmmnn opqrýsrss tmnþmnnoúpoppoppýqpqqürqrqqrstþsttm noþnoopþoppqúrqqrqrrþsrrsýtsttmnmnþonnoýpoppqpqþpqqûrqrqrrþsrrsýtstt mn opþoppýqpqqrsrsøtsslmmlmmûnmnmnnonoøpoopopoppqrþqrrýsrssútslmlmmnoþnoopopqþpqqrúsrsrrssþtsslm÷nmmnnonnoopþoppüqppq qrslümllmmûnmnmnnüonnoopþoppqrûqrrqrrúsrsrrsslúmlmllmmþnmmnüonnoopþoppýqpqqrsürssllùmlmlmlmmønmmnnmmnno÷poopoppoppüqppqqrqrüskkll mýnmnnýonoopúqpqqpqqòrqqrrqqrrsrrskkúlkllmllümllmmnüonnooþnooýpoppqýrqrrklmûlmmlmmnþonno pq÷rqrrqqrqrrklmþlmmnþmnnoùpoppooppqürqqrrjkúlkllkllmûlmmlmmnùonnoonoopþopp qrklþkllm n opýqpqqþpqqrþjkkýlkllúmllmlmmünmmnnopþoppýqpqqþpqqjýkjkklþkllmnýonooúpoppoppþqppqjükjjkklýmlmmnoþnoopqüpqpqqûjijkjjklþkllmnmýnmnnþonnoýpoppqjýkjkkùlkllkkllm÷lmmnmmnmnnúonnonoopqjkþjkkþlkklmþlmmnonoýpoppþoppüqpjiiújijjkjjklýmlmm nüonnoop÷oppqpqppiiýjijjkýlkllümllmmønmmnmnmnnopüqpqiiýjijjþkjjk lmùlmmnmmnnþonnopüopoppijkjkýlkllmnmnýonoopüopoppýihiijýkjkkülkkllûmlmlmmünmmnnþmnnoýpopphijküjkjkklkl mnþmnnþonnop iýjijjükjjkkþlkklúmlmmlmmûnmnmnnoûnonnoohiþjiiüjiijjùkjjkklkklmülmlmmünmmnnonopýhihhiøhiijijijjøkjkkjkjkklmlmþnmmnúonoophhþihhiújijjijjúkjkkjkkþlkklmýnmnnöonoonnooghhiþhiiþjiijklkýlkllmønmnnmnonnýonoo ôõìôõôôõôõôôõõôõôõõôôõôôõôþõôôûõôôõôôõôõôõúôõôõôõõûôõõôõ õýöõôôþõôôþõôôþõôôúõôõõôõõôþõôôõþôõõþôõõþôõõþöõõôûõôôõôôþõôôõõôõôõõôôõõôôõùôõôõõôõõô õôüõôõôôþõôôõûôõôõôôùõôôõôõôô÷õôôõôõõôõõþôõõþôõõôùõôõôõõôôüõôõôôþõôôõùôõôõõôõõøôõõôõõôõõþôõõôõôþõôôþõôôýõôõõüôõôõõþôõõþôõ õôøõôõôôõõôôúõôôõôõõúôõôõôõõôõùôõõôôóôôþõôôõôõûôõõôõõûôõõôõõûôõõôõõüôõôõõôüõôõôôõôøõôõôôõôõõôõüôõõôôøõôõôõôõôôõúôõôõôõõôõùôõôôõôõõþôõõôøõôôõôõõôôõôþõôôýõôõõþôõõþôõõôõôõôõôôõôõôõõôôõôõõôþóô ôþõôôþõôôõòôõôôõôõõôôõõôõõûôõõôõõ÷ôõõôõôóóôôþóôôþóô ôþõôôþõôôúõôõôôõõ÷ôõõôõõôôõõôõþôõõôþóôôõôðõôõôôõôôõôõôõõôõõøôõõôôóóôôþóô ôþõôôúõôõôõôôõôúõôõôõôôõþôõõôþóôôüóôôóóôõôýõôõõôõüôõõôôõôõôýóôóóôþõôôþõôôûõôôõôôõôõþôõõôþóôôþóôôõôüõôõôôýõôõõóôõõôôõõôõõôôõõùóôôóôóôôþóôôþõô ôûõôôõôôþõôôõóôûóôóóôôþóôôþóôôùõôõôôõôôûõôôõôôõôõôõôþóôôóôþóô ôþõôôþõôôõôûõôõôõõüôõõóóôùóôôóôóôôþóôôþóôôþõôôþõôôõñôõõôõôõóôóóôóóôôóôþóôôó ôþõôôþõôôøõôõõôôõôôõþôõõôþóôôóôþóôôþóôôüóôóôôþõôôõüôõôõõüôõóôôøóôóôôóóôôùóôóôôóôôþóôôþõôôôõôôõõôôõôõôóóýôóôôþóôôþóôôþóôôó ôõôõûôõõôõõôþõôôóôûóôóóôôþóôôóôþóôôþóôôþõôôþõôôõôõýôóôôóþôóóûôóôóôôóôóôþóôôóôþõôôõûôõôõôôþóôôûóôôóôôþóôôúóôóôóô ôþõôôíõôôõõôõôôõôôõõôôõôóóôûóôóóôôöóôôóôóôôóôôþóô ôþõôôþõôôõôóýôóôôóþôóóüôóóôôþóôôþóôôþõôôþõôôûóôóôóóôóôóüôóôóóôþóôôþóôôþõôô÷õôôõõóôôóóøôóôôóôóôôóùôóóôóóôôûóôôóôôþõôôóüôóóôôóôþóôôüóôóôôûóôôóôôþõôôþõôôïõóóôóóôóóôôóóôôóôôúóôóôóôôþóôôùóôóôôóôôüõôõôôõýóôóóòôóôóôóôóôôóôóôôóôþóôôþõôôóôúóôôóóôôóòôóôóóôóóôôóôóôôþóôôþõôôþõôôóþôóóôþóôôùóôóôóôóóþôóóýôóôôûóôóóôôóôöõôôóóôóóôóóôóôóüôóôóóøôóôôóôóôôúóôôóóôôóþôóóôóôóúôóôóôóóôöóôôóóôóôóôôþóôôþõôôóöôóôóóôóôôóóøôóôôóóôóóûôóôóôôóüôóóôôþóôôþóôôóþôóóþôóóôõóôôóôóóôóôóóôóôóôó ôýõôó óùôóôóóôóóôóüôóóôôóôþóôôüóôóôôþóô ôóþôóóüôóôóóüôóóôôõóôóóôóôôóóôôûóôôóôôþóôôóþôóóþôóóýôóôôýóôóóôüóôóôôþóôôþóô ô óþôóóþôóóôóôüóôóôô÷óôóóôôóóôôþóôôóüôóôóóôóôóûôóôóôôóôóôþóôôóþôóóôóôöóôóôóóôôóôôóóôóôôóôôóôóôôóóþòóóþôó ó÷ôóôóóôóôóóôþóôôóýôóôôýóôóóþòó óôóüôóôóóøôóôôóôóôôóôüóôóôôòóôóþôóóùôóôóôóôôóôóþôóóþôó óôþóôôþóôôþóôôúóôóòòóóþôóóôóôöóôóôôóôóóôôüóôôóóôþóôôûóôòòóóùòóóòóòóóôôóóôóôóôôóóôôøóôóóôóóôôþóôôóûòóóòóóüòóòó óúôóóôôóóûôóóôóóôóïôóôóóôôóóôòóòóóòóóòóþòóóôýóôóóþôóóôóôþóôôþóôôòóþòóóþòóóôóôóôóôóòóùòóòóòòóóþòó óþôóó÷ôóôóôóóôóóýôóôôóûôóôóôôþòóóþòóóûòóóòóóþòóóôóþôóóþôóóôýóôóóôýòóòòóòóþòóóþôóóùôóôóôóôôþóòòóûòóóòóóûòóóòó óþôóóùôóóôôóôôóôòóòûóòóòóóþòóóòóùôóôôóôóóôøóôóôóôóôôÿþrssútsttsttutuvþuvvwþvwwxþyxxyøxyzyzzyzzörsrsstststtuûvuvuvvüwvvwwúxwxwwxxýyxyyzûrssrsstþstt uvwþxwwüxwwxxüyxxyyzþyzzûrsrrssýtsttuþtuuvüwvvwwxyýzyzzþsrr stþuttuþvuuývuvvwxüyxxyyüzyyzzrsþtsstutuûvuvuvvwþvwwxþwxxyþxyyþzyyrøqrrssrrssþtsstýutuuvþuvvwþvwwýxwxxýyxyyqrsþrsstþsttuvwxþwxxyüqrqrrstûutuuttuvýwvwwýxwxxyüxyyqqrsýtsttþuttuvwõvwvwwxwwxwxxyüxyyqqrsùtssttsttüuttuuvøuvwvwvvwwxþwxxyqrsþtssþtsstuvûuvuuvvwþxwwxûyxypqqùrqrrqqrrsýtsttúutuutuuûvuvuvvýwvwwxøyxxqqppqqrþqrrs÷rsrsstssttuvüuvuvvwxwxüpqpqqrsýtsttuvuvwþvwwxýwxppýqpqqrósrssrsstsststtutuvþuvvwxpqrqrsúrssttsstuývuvvûwvwvwwxýpoppqrþqrrsþtsstuþvuuvwòxwopoppqppqppqqröqrrqrrsrrsstþsttutuùvuuvvuvvýwvwwúoppooppýqpqqrsþrsstýutuuývuvvwývwooýpoppüqppqqrûsrsrsstuþtuuvuvýwvwwopq rsûtsttuutuvwopþoppqýrqrrstúuttutuuvüonnoopþoppþqppqrþsrrststþuttuývuvvopýqpqqürqqrrstþsttuþtuuvþuvvnoþpoop÷opqppqppqqrstúuttutuuývuvvnôonoonoppopoppqpqýrqrrsýtstt÷sttututtuuvnþonnopqþpqqröqrrsrrsrrssýtsttýutuuvýuvnnoùpoopooppúqppqpqqrqrsrýsrsstuþtuuþmnnþonnopüopoppúqppqpqqrs t÷ututuummnnúonoonoopopþqppýqpqqrþqrrsþrssütssttþsttum nýonooúpoppoppqþpqqúrqqrqrrs÷rsstsststtutumnþonnûonooppúqppqpqqrsþtsstutýulmmnþonnopþoppþqppqrþsrrýsrsstùsttuutmmnüonnooüpoopp qrsþrsstþullmnýonoopþoppúqpqqpqqrýsrsstlmnûononoopúqppqpqqrüsrrsstýstllmnþmnnýono opýqpqqþrqqrsûtstsllmünmmnnõonoonnonooppqþpqqûrqrqrrýsrssýlkll mnoþnooüpooppqrþqrrýsrssýtkllmnmnoüpooppqþpqqrþqrrýsrssþtllþkllmýnmnnúonnonoopüqppqqrþqrrsklýmlmmnþmnnüonnooýpoppüqppqqrñqrsrsrrsrklklkllümllmmnoþnoopþoppqýpqrrqrsýrskkülkkllmýnmnnoþnoopüqppqqrþskkülkkll mnoünopooýpoppûqpqpqqrûsrkjkkúlkklkllmþlmmùnmmnnmnnoûpopoppùqpqpqrqqrjkþjkklûkllkllmlmnoþnoopqrqrjýkjkklþkllmnþmnnþonnopþqppqýrqjjkþjkkülkkllümllmmünmmnnonopøopopqqpqqùrqrrjijjýkjkklm÷lmmlmmnmnnýonoopüoppqqpqýrijjklkýlkllümllmmþnmmnoýpoppqpýqpqqþijjkþjkklýmlmmünmmnnopqiüjiijjkülkkllômlmmllmlmnnmmnýonoopýqpqqijûijjkjjkûjkklkklþmllmùnmmnnmnnoþnoopþoppiüjiijjkýlkllmþlmmünmmnnýonoopõoppqpqqiihiijþijjkülkkllmýnmnnþonnoýpoppüqphiijþijjþkjjûkjkkllþkllümllmmýnmnnþonnoþpoopþihhijøkjjkkjjkklûkllkllmþlmm nopo÷phhiihihiij÷ijkkjjkjkkölkklkllmmllmnümnmnnýonooõpoopphihihiiýjijjókjjkjkjlklkkllúmlmllmmnýonoopoþphhiþjiiýjijjýkjkklklýmlmmnmnýonooýpghhýihii jýkjkklmnýonooghijýkjk klmþnmmýnonnoyzú{z{{z{{ý|{||ý}|}}ý~}~~þ}~~û~~€ü€€zyz{z{|{|ü}||}}ý~}~~ý~ú€€€€€üzyzz{ù|{{|{{||}~ý~ý€€€ù€yyzz{üz{z{{ü|{{||û}|}|}}û~}~}~~~€ú€yyzyyz{þz{{| }ý~}~~ý~ý€€€yzùyzz{{z{{ø|{||}||} }~€þ€€yúzyzzyzzý{z{{ü|{{||}þ~}}ý~}~~~€þxyyýzyzzû{z{z{{ý|{||}ù|}|}}~}}~þ}~~ü~~€úyxyxxyyz{üz{z{{|ý}|}}ý~}~~~þ€xyþxyyzþyzzû{z{z{{þ|{{|ü}||}}~ü}~}~~~ý€xxyzùyzzyz{zzý{z{{ù|{|{|{||}ý~}~~÷~~€xxüyxxyyýzyzzü{zz{{ü|{{||ý}|}}~þ}~~x yzü{zz{{ý|{||}~}~õ~~wxwxwxxüyxxyyzöyzz{zz{{z{{|þ}||}~þ}~~wxüyxyxxyzõ{zz{z{||{|{{|}þ|}}~þ}~~þwwxþyxxýyxyyzü{zz{{|þ{||ý}|}}ú~}}~}~~wxwxþwxxyøzyzyyzyzz{üz{|{{ù|{||}|} }ý~}~~wüxwwxxyþxyyz{þz{{|}|}þ|}}~ûwvwvwwxþyxxyýzyzz{z{|{ý|{||}~}üwvvwwýxwxxþyxxùyxyyzyzzû{z{z{{|þ{||}þ|}}ý~}vvýwvwwüxwwxxyzû{z{z{{|þ{||ú}||}|}}ú~vvwvwwüxwwxxþyxxyzûyzzyzzû{z{z{{ý|{||þ}||}vüwvvwwxwxyþxyyúzyyzyzzü{zz{{ü|{{||þ}||ý}|}}vwþvwwxþwxxþyxxyþxyy z{|}þ|}}þuvvwþxwwxýyxyyzý{z{{ù|{{||{||÷}||}}uvuvv÷wvvwvwvvwwýxwxxyþxyyzþyzz{|ù}||}|uvvþuvvýwvwwúxwwxwxxy÷xyyzzyzyzzü{zz{{|{|}þ|uuvýwvwwûxwxwxxyzyzü{zz{{û|{|{||uvþuvvùwvwvwvwwýxwxxûyxyxyyzþyzzü{zz{{|ü{|{||tuvþuvvúwvwwvwwúxwxwwxxúyxyyxyyzyz {û|tutuuvýwvwwxþwxxyzüyzyzz{÷|{||{uttuuþvuuvwþvwwxúyxyyxyyz{ôz{zz{{|{|{|ttuvþuvvwüxwwxxûyxyxyyzþyzzý{z{{tþuttuúvuvuuvvûwvwvwwöxwwxxwxxyxxyzþyzzý{z{{tuøtuutuuvuuvþuvvøwvwvwwxwwýxwxxyxyîzyyzzyzz{{zz{z{z{ttuþtuuvþwvvwxùyxyxyxyyzþyzzý{z{{ütssttu vwxüyxxyyøxyzyyzyzzþ{ttþsttýutu uv wxyxyzû{z{zssütssttuþtuuvþwvvýwvwwüxwwxxûyxyxyyzþyzzsýtsttuúvuuvuvvwþvwwüxwwxxýyxyyzüyzyzzsýtsttuútuvvuvvûuvwwvvwxþyxxyýzyzzstutýutuuvûwvwvwwxøyxyyxxyzzürsrss÷tsttstuuttuývuvvûwvwvwwüxwwxxyþxyyzürsrssütssttûututuuövuvuvuvvwvvwxúwxwxxyyüxyxyyôzyyzrssrsrrsstutuývuvvùwvvwvvwwxùwxwxyxyyrsþrssþtsst u vwxýyxyyüxyyrrþsrrstutuvüuvuvvüwvvwwõxwxwxyxyyxyyrsrsýtsttutuvwvwýxwxxyúxyyqqrrùsrrsrrsstüststtþuttuþvuuvûwvwvwwüxwwxxþwxxyüqrqrrüsrrssùtssttsttýutuuvwþvwwüxwwxxyqrþsrrststýutuuývuvvwvwxöyqqrqrrqqrrýsrssýtsttýutuu÷vuvvuvwvwwþvwwxwxqrþqrrûsrsrsstþsttuþtuuývuvvwxýwxqqrúsrrsrsstþsttôuttutuuvvuuvvwþvwwýxwxxpqrsþrssütssttýutuuþtuuvwv wûqpqpqqþrqqrstöuttuutuuvuuvwûxwppqqþpqqrsürsrssûtststtýutuuývuvvýwvwwûoppqppqýrqrrýsrsst uøvuvvwvvwwþxppýqpqqýrqrrsûtststtuþtuuvûwvwvwwpüqppqqrþqrrýsrsstüststtýutuuvøwvwwvwwppþoppýqpq qrüsrrssýtsttuüvuvuuvwñvppoopopqpqpqpqqrþqrrþsrrsýtsttþstt uvþuvvüwvvoopüqppqqrúsrsrrssþtssýtsttuûvuvuvvopopýqpqqþpqqrúsrssrsstþsttþuttuvõþöõõöõúöõõöõööþõööõöþ÷ööõùöõõöõöõõùöõöõõöõõöõöþõööþõööûõööõö öû÷öö÷ööõöþõööõööõõöõõööõööõöùõööõöõööù÷öö÷ööõõþöõõüöõöõõúöõöõõööúõöõõöõõöþõööþ÷öö÷öúõöõööõõïöõõööõõööõöõõööõööõöõöõþöõõöüõööõõöþõööýõöõõúöõööõööþõööþõööõöõöõöüõööõõþöõõöýõöõõöõüöõöõõþöõõþöõõöùõöõöõöõõþöõõýöõööûõööõööþõö öõöõûöõõöõõüöõõööþõööùõöõõöõööûõööõööþõö öõþöõõùöõõöõõööõöõö÷õöõõööõöõõýöõööþõööþõööõðöõõöõööõöõõöõööõõöþõööþõööõþöõ õþöõõöõöüõööõõöüõöõööûõööõö ö õþöõõþöõõþöõõöþõööþõööõöþõööþõööýõôõõþöõõøöõõöõööõõöõöõööõöõõöõööõööüôõôõ õþöõõøöõõöõõöõõöúõöõöõööøõööõööõööõõööõööõöõöõõþôõõûöõõöõõþöõõöúõöõöõööþõööõþôõõþöõõöýõöõõüöõöõõöõöüõöõööõôõûöõõöõõööõööõööõöõööõö÷õööõôõõôõõþöõõööõöõõöõööõõöþõööüõöõööôõøôõõôôõôõ õööõõöõõöõöõõýöõööõöõöõöþõööõþôõõþöõõöõöýõöõõýöõööõöúõôõõôõõþôõõöõþöõõñöõöõõöõõööõööõööòõööõöôõôõôôõôõõþôõõïöõööõöõõöõöõõöõöõõöúõöõööõõôýõôõ õþôõ õþöõõþöõõöýõöõõöüõööõõöøõôõôõôõôôýõôõõþöõõþöõõ÷öõõöõööõööþõööõüöõõööôõùôõôõôôõõúôõôõôõõûöõõöõõþöõõöþõööõöþõööõþôõõô$õþöõõþöõõúöõöõõööõôõôøõôõôõõôõ õþöõõþöõõþöõõûöõõöõõþöõõòôõôõôõôôõôôõôõõûôõõôõ õþöõõüöõöõõúöõõöõôôõþôõõûôõõôõõûôõõôõõþôõõþöõõöõþöõõþöõõ÷öõööôõôõôôøõôõõôõôõõþöõõöýõöõõüöõöõõöõôõôõüôõôõõùôõõôõôõõþöõõöýõöõõûöõôôõõýôõôôõôïõôôõôõôôõõôõôõõôõ õöõþöõõûöõõöõõôõõôôõôõôõõôõõþôõõþôõõþôõõþöõõöôþõôôõôõôõþôõõþôõõúôõôõôõõøöõõööõöõõöôõôõýôõôôõûôõõôõõþôõ õþöõõþöõõþöõõöýõöôôõñôõôõôõõôôõôõõôõõþöõõöùõöõõööõõûöôôõôôøõôõôõõôõõûôõôôõ õþôõ õþöõ õôýõôõõôþõôôõöôõõôõôõõôõõùôõõôõôõõþôõõóöõôôõõôôõôôõôôþõôôõþôõõþôõõüôõôõõþöõõôüõôõôôþõôôõôõûôõôôõõûôõõôõõþôõõõöõöõõöõõôõôôûõôôõôôöõôõõôõõôôõõöôõõôõõôõôõõöýôõôôõôûõôôõôôõöôõôõôõõôõôôõþôõõþôõ õùöõõöõõôôþõôôþõôôñõôõõôõõôõôôõôôõõûôõõôõõöûõöõõô ôõôõýôõôô õþôõõþôõ õýöõôôõôõô õôõþôõõþöõõôþõôôþõôôùõôõôôõôôõôþõôôõþôõõôõþôõõþöõõôîõôôõõôõôõõôõôôõôõôô õþôõõôûõôôõôôõôõüôõôõõþôõõþôõ õôþõôôúõôõôôõõôôõôôõõôõôõôõõþôõõþôõõ ôøõôôõôõõôôõþôõõùôõõôõôõõôõþôõõþôõõôþõôôþõô ôõûôõõôõõþôõõôõþôõõþôõõþôõõ ôþõôôöõôôõôôõõôõ õþôõõôõþôõõôþóô ôôõôõôôõôõôõôõõô õüôõôõõôûóôôóô ôþõôôüõôõôôþõôôýõôõõüôõõôôõüôõôõõüóôóôôþóôôþõôôþõôôüõôõôôõùôõõôôõôôýõôõõûôõõôõõôóôùõôõôôõôôûõôôõôôõúôõõôôõõþôõõôûóôôóô ôõôþõôôõõôõôôõõôõôõôôõôõôóôõôõôûõôõôõõøôõõôõôóôôóôóôôõôõôõõôõõôõôôõþôõõôþõôôõôõôþóôôþóô ô÷õôõôõôôõôôúõôõôôõõôúõôõõôõõýôóôôþóôôþõôôþõôôõôøõôõôôõôõõôþóôôþóô ôþõô ôþõôôõôõôýõôõõúôõôõõôôþóôôøóôóóôôóôôõôþõôôõôúõôôõõôÿ{|þ{||}ý~}~~þ~€û€€€€‚þ‚‚þz{{÷z{|{{|{{||ú}|}}|}}~}~€þ€€€û‚‚‚‚z{|þ{||}þ|}}ý~}~~þ~~ý~€€û€€‚‚z{z{|ú}|}||}} ~€þ€€þ€ý‚‚‚z {|ý}|}}~þ~€û€€ý‚yzz {þ|{{|ü}||}}~ù~~~~€þ€€ý€ü‚zyzzþ{zz{|{|}ú~}~~}~~ú~€€û€€ý‚yzzý{z{{û|{|{||}þ~}}ý~}~~þ~ù€€€€€yýzyzz{ú|{{|{||ü}||}}ý~}~~û~~ö€€€€€yûzyzyzz{| }~þ}~~ü~~ý€€€yzþyzz{û|{|{||ý}|}}ü~}}~~þ~~ý€€€û€xyyûzyzyzz{þz{{|þ}||}ú~}}~}~~€€xyûzyzyzzý{z{{ú|{||{||ý}|}}ý~}~~þ~€ú€€yxxyüzyzyyz{þz{{|þ{||û}|}|}}~ú~~~ý€€€xúyxyyxyyzü{zz{{ü|{{||}ü~}}~~þ~xýyxyyzþyzzþ{zz{|þ{||ý}|}}ý~}~~xþyxxyzþ{zz{ý|{||}|}~~ý€wxxüyxyxxyüzyyzz{ý|{||ü}||}}~}~xþwxxýyxyyüzyyzz{þz{{|þ{||}þ~}}~þ~~xwýxwxxüyxyxxyûzyzyzzü{zz{{|ý}|}}ý~}~~wûxwxwxxúyxyyxyyz{|ý}|}}ù~}}~}}~~ü~wvwwxyþxyyüzyyzzþ{zz{ý|{||}ô~}~}~~wwvwwxþyxxyz{þz{{|ý}|}}þ~}}~üvvww xyz{|ü{|{||}~û}~}~vvwúxwxxwxxyzü{zz{{ý|{||}þ|}}~vúwvvwvwwýxwxxþyxxyzþyzzô{z{zz{|{|{{||û}|}|}}~ö}~vvwvvwvwwýxwxxþyxxýyxyyzyzû{z{z{{|{|}þ|}}~vwûvwwvwwxyûzyzyzzú{z{{z{{|û}|}|}}ü~uuvvûwvwvwwýxwxxyxyúzyzzyzzú{z{{z{{ø|{||}}|}}ò~uuvuvuvvwwvvwwüxwwxxýyxyyzyz{þz{{|}uvúwvwvvwwxwxýyxyyúzyyzyzzû{z{z{{ý|{||ù}||}}|uuvüwvvwwxþwxxüyxxyyzþ{zzý{z{{|þ}uuvwþxwwxýyxyyz{z{|{|ý}|ttuüvuuvvüwvvwwýxwxxyýzyzzý{z{{ù|{{|{{||tuývuvvûwvwvwwüxwwxxyúzyyzyzz{ùz{{||{||týutuuývuvvþuvvwþxwwxýyxyyzüyzz{{z{|{þ|ttuþtuuývuvvôwvwwxwxwwxwxxyþxyyzþyzzú{z{zz{{ý|{||tüuttuuvwûxwxwxxyzyz{þz{{ú|{|tsttuþtuuþvuuvwx÷wxxyxyyxyyüzyyzz{û|{ssttuvwþvwwýxwxxyz{þsttþsttüuttuuùvuuvvuvvýwvwwýxwxxyþxyyzþ{zz{stþsttúuttutuuüvuuvv÷wvwwvwwxwwxy zù{sstssttuþtuuüvuuvvþwvvýwvwwxûyxyxyyözyyzz{z{{ssýtstt uvwþvwwýxwxx yzrstþsttûututuuvþuvvýwvwwxúyxyxxyyýzyzzsþrsststùuttuttuuvwvwxyxyzþyzzrsùtstststtuvuvwôxwxwxxyxyxxyyzñrsrsrsrrsstststtûututuuývuvvwövwwxwwxxwxxyzrûsrsrssøtsttsttuuþtuuvwxþwxxyþxyyýzyrrsþrssütssttuþtuuývuvvûwvwvwwxwxyûzrqqrrsþtsstýsuttüuttuu vwxy rstutuvþuvvwýxwxxyqrøqrqrssrssùrsstssttùuttuttuuüvuuvvýwvwwxþwxxþyxxýyxqqþrqqrsþrsstüststtüuttuuvuvùwvvwwvwwxþyxxqrstþuttuvüuvuvvüwvvwwxüyxxqqrûsrsrssûtststtuþtuuvwxþwxxúypqqpqqürqqrrþsrrstýsuttu v÷wvwxwwxwxxûqpqpqqþrqqrüsrrsstþuttuvüwvvwwxþwxxpqrsþrsstýutuuývuvvwvwxwùxwooppqqøpqqrrqqrrþsrrstuþtuuvwþvwwxopûqpqpqqrqrýsrsststûututuuvùwvvwvvwwopqrûsrsrssýtsttúututtuuvuvýwvwwopüqppqqrýsrsstúututtuuúvuuvuvvwýopoopqþpqqþrqqrstuþtuuvþuvvwþvwü‚‚‚þ‚‚ƒ‚ýƒ‚ƒƒù„ƒƒ„„ƒ„„…„…†‡ûˆ‡ˆ‡ˆˆú‚‚‚‚‚ƒ„ý…„……ý†…††‡ˆü‡ˆˆø‚‚‚‚‚‚ƒü„ƒƒ„„þƒ„„û…„…„……ý†…††ý‡†‡‡ˆ€‚ýƒ‚ƒƒ„þƒ„„…ü„…„……†…†‡ˆ€ý€þ‚õ‚‚‚ƒ‚‚ƒƒ‚ƒƒ„þ…„„…†þ‡††‡€ý€‚þ‚‚ƒþ‚ƒƒý„ƒ„„ù…„„……„……†ü‡††‡‡ýˆ‡€€‚ýƒ‚ƒƒ„þƒ„„û…„…„……†…†‡€ô€€‚‚‚‚þƒ‚‚ƒû„ƒ„ƒ„„…†þ…††ö‡†‡††‡€€€ø€€‚‚ùƒ‚‚ƒƒ‚ƒƒû„ƒ„ƒ„„ý…„……þ†……†þ…††‡€þ€€þ€ü‚‚‚þƒ‚‚ƒ„…þ„……†þ…††‡€þ€€þ‚‚ƒü‚ƒ‚ƒƒü„ƒƒ„„û…„…„……†þ…††‡€þ€€ ‚ýƒ‚ƒƒ„þƒ„„þ…„„ö…„…†……†……††ý€€ü‚‚‚ƒþ‚ƒƒ„…û†…†…††€ü€€€€þ‚‚ƒ„…†ý~ü€€€û‚‚‚‚ƒþ„ƒƒ„ü…„„……þ†……†þ~~€þ€€‚ƒü‚ƒ‚ƒƒþ„ƒƒ„…þ„……†~ü~~ü€€€‚ƒþ‚ƒƒ„þƒ„„…„ø…„„……†…~~€€þ€û‚‚‚‚ýƒ‚ƒƒþ„ƒƒ„ý…„……~ü€€€û€€€‚þ‚‚ƒþ‚ƒƒþ„ƒƒ„û…„…„……~þ€ý€€€û€€ý‚‚‚ýƒ‚ƒƒ„þƒ„„…þ„~~ý~€ü€€€‚ƒþ‚ƒƒü„ƒƒ„„ü…„„……ú„}~}}~~ý~ü€€€ü€€ù‚‚‚‚‚ƒ„ƒ„ý…„~~þ}~~ý€€€€ú‚‚‚‚‚ƒú„ƒ„„ƒ„„}û~}~}~~ý~ý€€€÷€‚‚‚‚ƒü„ƒƒ„„}þ~}}~ú€€€€€ü‚‚‚ýƒ‚ƒƒþ‚ƒƒ„}ü|}}~~}~ý~€þ€ú‚‚‚‚ƒþ‚ƒƒ„þ|}}ý~}~~û~~û€€€€þ€ý‚‚‚üƒ‚‚ƒƒù„ƒ„ƒ||} }~þ~~€ ‚ýƒ‚ƒƒþ‚ƒƒü|}|}}~}~ü~~ú€€€€ý€‚þ‚‚þƒ‚‚ƒ|}þ|}}~ø~~€ý€€€‚þ‚‚ýƒ‚ƒƒþ„||}~ý~ü€€€þ€€÷€‚‚‚‚ûƒ‚ƒ‚ƒƒ|}|}~þ}~~ý~ý€€€ý€‚þ‚‚ƒ‚ƒô{|{||}|}}||}}~ü}~}~~ú~~~û€€€€‚ƒû‚ƒ‚{||}þ|}}~þ~û€€€€ü€€ü‚‚‚ûƒ|{{||ü}||}}ý~}~~ú€€€€þ€€þ€þ‚‚{|þ}||}ý~}~~þ~~ý~€þ‚‚{ü|{{| |ú}|}}~}}ý~}~~~ü€€ €‚{|þ{||}û~}~}~~ý~ý€€€ü€€‚ü‚z{{|ü{|{||þ}||ý}|}}~û~~€þ€€þ€ü‚‚{{þz{{þ|{{|ù}||}||}}ü~}}~~ý~ü€€€€z{þz{{|þ{||}~€€û€€€þ‚zz{þz{{û|{|{||ý}|}}ý~}~~þ~€û€€zü{zz{{|{|ü}||}}ý~}~~ ý€€€ú€zyzz{üz{z{{|ý}|} }~þ~~€þ€€ý€úyzyzyzzô{z{{||{|{|{||}~~ü€€€ü€yzzþyzz{úz{{|{||}|}~þ}~~û~~þ€€ø€yyzzyzz{zû{z{{||÷}||}|}}~}}~ý~ý€€€yþzyyzý{z{{|}|}û~}~}~~ý~þ€€yþzyyýzyzz{ó|{{|{|{||}||}}ý~}~~ü~~ý€€€þxyyýzyzz{|þ{||}þ|}}þ~}}~þ~€ý€yyþxyyþzyyzþ{zz{|ú{|{|}||}ü~}}~~ø€€xyyxyyüzyyzzù{zz{zz{{|}þ|}}~þ~ú€€xxyyxyüzyyzzü{z{zz{ |}~ý~xyzþyzzý{z{{|}|}~xüyxxyyþzyyzý{z{{|{|}~ú~~xxüyxxyyzù{zz{{z{{|ü{|{||þ}||}~}ý~}~~wýxwxxûyxyxyyzþyzzú{z{zz{{|{ú|}}||}}~ü}~~~üwxwxxýyxyyzþyzzþ{zz{ú|{||{|| }~þ}~~ü~~wwxwxyþxyyzú{zz{z{{|ü}||}}ý~}~~þwwýxwxxyzø{zz{z{{||{|ü}||}}~þ}~~wxúyxyyxyyz {|ü{|}||}ý~}~~þvwwüxwwxxyþxyyzý{z{{ |ý}|}}ú~}}~~vvûwvwwxxþwxxyþxyyzyýzyzz{ø|{{|{|{||ý}|}}~vwxþwxxyxyüzyyzzý{z{{|þ{|| }ûö÷ö÷ööó÷öö÷ö÷÷ö÷ö÷ö÷÷ûö÷÷ö÷÷øø÷÷ø÷÷ø÷÷öø÷ö÷÷öö÷öö÷öø÷ö÷÷ö÷ö÷÷þö÷÷þø÷÷öý÷ö÷÷ýö÷ööü÷öö÷÷þö÷÷ö÷÷ö÷÷ö÷÷ö÷ ÷üø÷ø÷÷îö÷öö÷öö÷ö÷ö÷öö÷÷ö÷÷ö÷þö÷ ÷þö÷÷þø÷÷öþ÷ööí÷öö÷ö÷÷ö÷ö÷÷ö÷ö÷÷ö÷÷úö÷÷öö÷÷þö÷÷ùø÷ø÷ø÷öö÷øö÷öö÷÷ö÷÷ö÷þö÷÷þö÷÷þö÷÷öù÷öö÷ö÷ööü÷öö÷÷þö÷÷öû÷ö÷ö÷÷ûö÷÷ö÷ ÷öø÷÷ø÷÷ö÷÷ööþ÷ööþ÷öö÷ö÷þö÷÷þö÷÷ùö÷÷ö÷ö÷÷öþ÷ööú÷öö÷÷ööþ÷öö÷ùö÷ö÷÷ö÷÷þö÷÷üö÷ö÷÷þö÷ ÷ö÷ùö÷÷ö÷÷öö÷þö÷÷öý÷ö÷÷þö÷÷öþ÷ööþ÷ööù÷ö÷ö÷ö÷÷ûö÷ö÷öö ÷ûö÷÷ö÷ ÷ýö÷ööþ÷öö÷þö÷÷ öþ÷öö÷ö÷ö÷þö÷÷ûö÷÷ö÷÷ öþ÷ööû÷ö÷÷ööü÷öö÷÷þö÷÷ûö÷öö÷ ÷ öþ÷ööñ÷ö÷÷öö÷öö÷ö÷ö÷öö÷ö÷þö÷÷þö÷÷öþ÷öö÷ öò÷öö÷ö÷ö÷÷ö÷÷ö÷÷üö÷ö÷÷ûö÷ö÷öö÷þö÷÷öþõö ö÷öü÷öö÷÷ö÷ö÷ûö÷÷ö÷÷þö÷÷þö÷÷ö÷öùõöõöö÷ööþ÷ööü÷ö÷öö÷ö÷öî÷ö÷÷ö÷öö÷öö÷ö÷ö÷ö÷÷ öþ÷ööþ÷ööþ÷ööþ÷ööþ÷öö÷ýö÷öö÷þö÷÷þö÷÷öþõö ö÷ öþ÷öö÷ùö÷öö÷ö÷÷ö÷þö÷÷þõööþ÷ööü÷ö÷ööö÷ö÷öö÷÷ö÷öö÷öû÷ö÷ö÷÷þõööþõöö÷õö÷÷ö÷ö÷öö÷ööö÷ö÷ö÷ö÷öö÷÷þö÷÷ûö÷ö÷ööþõööþõööþ÷öö÷ö÷ùö÷öö÷÷öö÷ôö÷÷öö÷÷ööõõööþõööû÷öö÷öö÷þö÷÷ùö÷÷ö÷ö÷÷þõööþõööþõö ö÷÷öö÷ö÷ö÷öö÷üö÷ö÷÷úö÷÷öö÷÷þö÷÷öõöþ÷ööø÷ö÷ö÷÷ö÷÷ö÷üö÷÷ööý÷ö÷÷öýõöõõöþõöö÷öþ÷ööø÷ö÷ö÷ö÷öö÷÷ö÷õöõöõõööõýöõööüõöõööþ÷ööþ÷ööø÷ö÷ö÷ö÷öö÷ö÷þö÷÷ôöõõööõööõöõööþõö öþ÷ööú÷ö÷÷ö÷÷ûö÷÷ö÷÷ö÷þõööõöõýöõööþõööþõööþ÷ööü÷ö÷öö÷ö÷ö÷ö÷üöõõööþõööõýöõöö÷îö÷÷öö÷÷öö÷÷öö÷÷ö÷öö÷þöõõöõöþõööõöõýöõö öþ÷ööü÷ö÷ööþ÷öö÷þõöööõöõöõõöõõö öþõööþ÷öö÷öü÷öö÷÷öþ÷öö÷þöõõöùõöõöõõööþõööþõö öû÷öö÷ööþ÷öö÷þö÷÷ùö÷÷õõöõõöüõöõööúõööõõöö÷öþ÷öö÷öü÷ö÷ööý÷õööüõöõööùõöõöõõööþõööþõööý÷ö÷÷öþ÷ööþ÷ööõöþõööúõöõöõööõöþõö ö÷ öú÷ö÷ö÷ööü÷ööõõöþõööõöþõööõöþõööþ÷ööü÷ö÷ööú÷ö÷ööõõöõ÷öõööõööõööõöõöþõööþõööþ÷ööü÷öö÷÷ûö÷ööõõöþõööõøöõööõöõööþõööû÷öö÷ööû÷öö÷ööúõööõöõõöüõööõõüöõõööüõöõööþõööþ÷ööû÷öö÷õõýöõööýõöõõöõýöõööùõöõöõöõõöþõööû÷ö÷÷ööõþöõõþöõõöõþöõõöúõööõõööþ÷ööô÷ööõöõõöõõöõõüöõõööûõöõõööõöþõööþõöö÷öõþöõõööõõöõõöõõööõõöõõöõõöõõööþõööþõööý÷öõõüöõöõõýöõöööõöõõööõõöõõýöõööþõö öþ÷ööþ÷ööü÷õöõõôöõõöõöõöõööõõþöõõöþõööþõööþ÷õõþöõõòöõõööõöõõöõöõööõöõöõöþ÷ööõþöõõþöõõüöõöõõùöõõöõõööþõööþõöö÷þöõõöõþöõõöýõöõõýöõööúõööõõööþõööþõööþõööý÷öõõþöõõþöõ õöòõöõõöõõöõöõöõööþõö öþõööõþöõõøöõõööõõööøõööõöõöõõûöõöõö öþ÷ööõöýõöõõöõþöõõöõïöõõöõööõöõöõöõöõö öõþöõõûöõõöõõøöõõööõöõõýöõööþõööþõööþõööþõööþôõ õöõôöõõöõöõöõõöõõöõûöõöõööõþôõ õþöõõîöõõöõõööõõöõöõööõööõöþõööõþöõõýöõööúõöõöõööõùöõöõöõööõö õúöõõööõõûöõöõööøõööõööõööüõôôõ õöõöõþöõõöýõöõõöõöþõööõþôõ õþöõõþöõõùöõõöõöõõöúõöõöõööúõööõõööõûôõõôõ õþöõ õþöõõöõúöõööõööþõööûôõõôõ õüöõöõõöõ÷öõõöõõööõõöõûöõöõööþõööõþôõõþôõ õþöõõüöõöõõöùõööõõöõõöõöõüöõôõõþôõõüôõôõõþöõõþöõõìöõööõööõõööõõööõööõööÿƒþ‚ƒƒ„…þ„……†þ…††‡†‡üˆ‡‡ˆˆ‰þЉ‰Šú‚ƒ‚ƒ‚ƒƒú„ƒ„„ƒ„„…þ„……þ†……ý†…††ý‡†‡‡ˆû‰ˆ‰ˆ‰‰Š‚ýƒ‚ƒƒ„þ…„„…ý†…††‡þ†‡‡ˆþ‡ˆˆû‰ˆ‰ˆ‰‰Šý‰Š‚‚ƒû„ƒ„ƒ„„ý…„……†þ…††‡ü†‡†‡‡ˆ‰Š‚ýƒ‚ƒƒý„ƒ„„ý…„……ý†…††‡ˆ‡ýˆ‡ˆˆþ‰ˆˆ‰‚ƒý„ƒ„„ý…„……†þ…††ü‡††‡‡üˆ‡ˆ‡‡ˆý‰ˆ‰‰ý‚‚‚ƒ„þƒ„„…þ„……ù†……††…††ø‡†‡‡†‡ˆ‡‡ˆþ‰ˆˆ‰‚ýƒ‚ƒƒ„ …†‡õˆ‡‡ˆˆ‰ˆ‰‰ˆü‚‚‚ûƒ‚ƒ‚ƒƒ„þƒ„„ …ý†…††‡þ†‡‡úˆ‡ˆˆ‡ˆˆý‰€‚ü‚ƒ‚‚ƒü„ƒƒ„„…„…†þ…††ü‡††‡‡ˆþ‡ˆˆý‰ˆ‚ƒþ„ƒƒ„ù…„„…„„……†…†‡ˆ€‚ƒþ‚ƒƒ„…„…ý†…††‡þˆ‡‡ˆþ€€ý‚‚‚ƒú„ƒ„„ƒ„„…†þ…††þ‡††‡øˆ‡ˆ‡‡ˆˆ€€þ€‚‚ƒü‚ƒ„ƒƒ„ý…„……†þ…††‡†‡ˆü‡ˆ‡€€ý€‚úƒ‚ƒ‚‚ƒƒú„ƒƒ„ƒ„„…†…†‡þ†‡‡ˆü‡€€û‚‚‚‚ýƒ‚ƒƒ„ýƒ…„„ö…„…„……†……††þ‡††‡ý€€€€‚þ‚‚ƒþ‚ƒƒù„ƒ„„…„……ý†…††‡†ý‡†‡‡þ€€‚úƒ‚ƒƒ‚ƒƒþ„ƒƒ„ü…„„……þ„……†þ…††‡û€€€€ú€€€‚þ‚‚üƒ‚‚ƒƒù„ƒ„„ƒƒ„„ü…„„……ý†…††ú‡††‡‡ý€€€ý‚‚‚ƒ„…„…†~€ó€€€€‚‚‚‚ùƒ‚‚ƒƒ‚ƒƒ„ôƒ„„…„„…„……„……†þ…††þ~ý€€€ú€€ý‚‚‚ƒ„þ…„„…†÷~~~€€€þ€‚üƒ‚‚ƒƒü„ƒƒ„„…†þ~€ø€€€€ý‚‚‚ ƒ„ý…„……ú†……††~~€ý€‚þ‚‚þƒ‚‚ƒ„üƒ„ƒ„„ü…„„……þ}~~ý€€€€‚þ‚‚üƒ‚‚ƒƒþ„ƒƒ÷„ƒ„„……„„……ý†}~~€û€€‚ûƒ‚ƒ‚ƒƒý„ƒ„„…ü†…}~~ü~~€þ€€þ‚ý‚‚‚þƒ‚‚ƒ„…}ü~}}~~€ú€€‚þ‚‚ƒþ‚ƒƒ„ý…„……}û~}~}~~þ~ý€€€€‚þ‚‚ûƒ‚ƒ‚ƒƒ„…þ„}}~û}~~~~þ~ý€€€€‚÷ƒ‚ƒƒ‚ƒ‚ƒ„„üƒ„ƒ„„…ý}|}}þ~}}~ú~~~€÷€€€€‚þ‚‚ƒý„ƒ„„þ…}}ù~}~}~}~~ý~€ý€‚ƒ„…þ|}}ü~}}~~ü~~ý€€€ý€ý‚‚‚ýƒ‚ƒƒ„ƒ„ü}||}}~þ€€ú€€€ý‚‚‚þƒ‚‚ƒú„ƒƒ„„||ý}|}}~ô}~}}~~~~ €ü‚‚‚ýƒ‚ƒƒ|}~}û~~~û€€€€õ€‚‚‚‚‚ƒƒ‚ƒý„ƒ||ü}||}}~÷~~€€€€þ€€ù€€‚‚ƒ{|ý}|}}ø~}~~}~~~ú€€€€þ€‚üƒ‚‚ƒƒ{ |}ü~}}~~€þ€€ü€€ý‚‚‚ûƒ‚ƒ‚{{|}~ý~€ ‚üƒ‚ƒ{{ü|{{||}~þ}~~þ~~ý€€€þ€ú‚‚‚‚ƒþz{{|}~}~€€ý€ü‚‚‚öƒz{z{{|{{||}þ|}}ý~}~~þ~ý€€€‚zý{z{{ý|{||}þ|}}~û~~€þ€ô‚‚‚‚zz{{z{{|þ{||ú}||}|}}~þ}~~þ~€þ€€ý€‚þzz{|}|}~ü~~ €û‚‚zz{z{ý|{||û}|}|}}ý~}~~€ú€€€þ€zý{z{{î|{||{{||}}|}}|}}~}}ý~}~~€þ€ûyzyyzz{z{ |}~þ}~~ý~ý€€€yzû{z{z{{ý|{||ô}|}|}}~}~~}~~ö€€€€€yz {|}þ|}}ý~}~~þ~~€yzþyzz{ý|{||}þ|}}~þ~ý€€€þxyyzü{zz{{|þ{||ü}||}}ú~}~}}~~€þ€€üyxyyzõ{z{z{{z{{|{{ú|}|}|}}~ü~~€þ€€üyxyyzúyzyzyzz{û|{|{||ý}|}}þ~}}~~€úxyxyxyyúzyzzyzz{þz{{|}þ|}}û~}~}~~ü€€€xyzý{z{{|þ{||}ü~}}~~€xþyxxyzþyzz{|û}|}|}}û~}~}~~ü€xxýyxyyzûyzzyzz{ý|{||}~xyýzyzzþyzzþ{zz{|þ}||}~ü~~þwxxþwxxyüxyzyyz{þz{{|}û|}}~}}÷~}~~~~wxýyxyyzþyzzý{z{{úz{{||{{|}ü~}}~~ü~~~wxyxyzý{z{{|þ{||û}|}|}}û~}~}~~ü‰ˆˆ‰‰ýЉŠŠþ‹ŠŠ‹þŠ‹‹Œþ‹ŒŒòŒŒŽŽŽŽŽŽˆó‰ˆˆ‰‰ˆ‰Š‰‰Š‰ŠŠú‹Š‹ŠŠ‹‹Œ‹ŒùŒŒŒŽþŽŽˆü‰ˆˆ‰‰üЉ‰ŠŠ‹÷Œ‹Œ‹Œ‹ŒŒþŒŽýŽˆý‰ˆ‰‰Šü‹ŠŠ‹‹ýŒ‹ŒŒüŒŒŽŽýŽˆþ‡ˆˆú‰ˆ‰‰ˆ‰‰ýЉŠŠú‹Š‹ŠŠ‹‹ŒýŽŽŽ÷އˆˆ‡ˆˆ‰÷Š‰ŠŠ‰ŠŠ‰ŠŠý‹Š‹‹ŒþŽŽúއˆˆ‡ˆˆü‰ˆˆ‰‰Š‰Šü‹ŠŠ‹ ‹öŒ‹ŒŒŒŒýŽŽŽ‡ûˆ‡ˆ‡ˆˆû‰ˆ‰ˆ‰‰Š‹Œþ‹ŒŒýŒŽ‡ùˆ‡‡ˆˆ‡ˆˆõ‰ˆˆ‰‰ŠŠ‰Š‰ŠŠý‹Š‹‹þŠ‹‹ýŒ‹ŒŒüŒŒüŽŽŽþ‡‡ˆý‰ˆ‰ ‰Šû‹Š‹Š‹‹ŒþŒŽúއ‡†‡‡úˆ‡ˆˆ‡ˆˆý‰ˆ‰‰Šþ‰ŠŠ‹ýŒ‹ŒŒôŽŽ††‡‡†‡‡úˆ‡‡ˆ‡ˆˆþ‰ˆˆ‰ýЉŠŠ‹þŠ‹‹úŒ‹‹Œ‹ŒŒýŒ÷ŽŽ‡†‡†‡‡ˆþ‡ˆˆö‡ˆˆ‰ˆˆ‰ˆˆ‰‰ýЉŠŠý‹Š‹‹Œ‹ŒþŒŒ†‡þ†‡‡úˆ‡ˆˆ‡ˆˆ‰ûЉЉŠŠ‹Šý‹Š‹‹ŒŒ†ý‡†‡‡ö†‡‡ˆˆ‡‡ˆ‡ˆˆú‰ˆˆ‰ˆ‰‰ýЉŠŠ‹þŒ‹‹Œø‹ŒŒŒŒ†ü‡††‡‡ˆþ‡ˆˆø‰ˆ‰ˆ‰‰Š‰‰Š‹Š‹ ŒøŒ…†…††‡ˆþ‡ˆˆ‰þˆ‰‰ýЉŠŠü‹ŠŠ‹‹üŒ‹‹ŒŒþ‹ŒŒúŒ…††þ…††‡þ†‡‡ˆþ‡ˆˆ‰üˆ‰ˆ‰‰ ЋЋýŒ‹ŒŒû…†…††‡ýˆ‡ˆˆú‰ˆ‰‰ˆ‰‰þЉ‰Šý‹Š‹‹þŒ‹‹ŒüŒ……††þ…††ú‡†‡‡†‡‡ˆü‡ˆ‡ˆˆ‰ýЉŠŠ‹þŠ‹ ‹Œþ……†‡ýˆ‡ˆˆý‰ˆ‰‰Š‹þŒ‹‹Œ…ý†…††‡÷†‡†‡‡ˆ‡‡ˆˆú‡ˆ‰ˆ‰ˆˆ‰Š‹Š‹Œú‹ŒŒ…„……ý†…††ý‡†‡‡ûˆ‡‡ˆ‡‡ýˆ‰ˆˆ‰ýЉРŠ‹Œ„…þ„……ý†…††þ‡††ý‡†‡‡ˆ‰ Šú‹Š‹ŠŠ‹‹þŒ„„ü…„„……†…†‡ü†‡†‡‡ˆ‰Šú‹ŠŠ‹Š‹‹Œ„þ…„„ý…„……þ†……ø†‡‡††‡†‡‡ˆþ‰ˆˆ‰ýЉŠŠþ‰ŠŠ‹÷ƒ„„…„……„……†ý‡†‡‡ýˆ‡ˆˆ‰ýЉŠŠ‹ƒ„…þ„……ú†…††…††‡†‡ˆþ‰ˆˆ‰üЉЉ‰Šø‹Š‹ŠŠ„ƒ„„þ…„„…ø„……††……††‡ûˆ‡ˆ‡ˆˆü‰ˆˆ‰ ‰Š‹Šú‹ƒƒ„ƒ„„…†þ…††ü‡††‡‡ˆû‰ˆ‰ˆ‰‰ýЉŠŠƒ„ƒ„ü…„„……ý†…††‡ˆþ‡ˆˆý‰ˆ‰‰Šû‰Š‰‰ŠŠƒ„ƒ„…†þ…††‡†‡ˆþ‡ˆˆý‰ˆ‰‰Š‰Šƒ„…ø„…†…†……††þ‡††‡ˆü‰ˆˆ‰‰öЉЉ‰ŠŠ‚‚ƒƒ„…þ„……ý†…††ü‡††‡‡þˆ‡‡ˆ‰ˆ‰ðЉЉ‰Šƒƒ‚ƒƒ„ƒ„ƒ„„…û„……„……†ü…†…††û‡†‡†‡‡ýˆ‡ˆˆý‰ˆ‰‰úŠ‰ŠŠƒ‚‚ýƒ‚ƒƒ„û…„…„……ü†……††û‡†‡†‡‡üˆ‡‡ˆˆ ‰‚ƒü„ƒƒ„„ú…„…„„……†þ…††ý‡†‡‡ˆ‰ûˆ‰‰ˆ‰‰‚ƒ „…†ü…†…††‡þ†‡‡ˆþ‡ˆˆú‰ˆˆ‰ˆ‰‰‚ƒ„þ…„„ü…„„……†þ…†† ‡ˆþ‡ˆˆ‰‚ƒþ‚ƒƒ„þƒ„„ý…„……†ü‡††‡‡þ†‡‡ˆþ‡ˆˆ‰øˆ‰‚‚‚‚ƒû„ƒ„ƒ„„ý…„……†þ…††‡þ†‡‡úˆ‡‡ˆ‡ˆˆø‰ˆ‰ˆ‰‚‚‚üƒ‚‚ƒƒü„ƒƒ„„û…„…„……†‡þ†‡‡ˆþ‡ˆˆû‰‚‚‚ƒ‚ýƒ‚ƒƒ„ƒ„ú…„…„„……† ‡ˆ‡ˆø€‚‚‚‚üƒ‚‚ƒƒ„þƒ„„…ý†…††ü‡††‡‡ˆþ‡ˆˆ‡ˆü‚‚‚ýƒ‚ƒƒù‚ƒƒ„ƒƒ„„…ù„……††…††û‡†‡†‡‡üˆ‡‡ˆˆ‚ù‚‚‚‚‚ƒ„þƒ„„…þ†……†‡ü†‡†‡‡üˆ€þ‚‚þƒ‚‚ƒü„ƒƒ„„ý…„…… †‡øˆ‡‡ˆˆ€€þ€ý‚‚‚üƒ‚‚ƒƒ„þƒ„„…†‡þ†‡‡€ý€ý‚‚‚ƒþ‚ƒƒ„þƒ„„ý…„……„…ü†……††û‡†‡†‡‡öˆ‡ˆ€€€€ý‚‚‚ýƒ‚ƒƒ„ùƒ„„…„„……þ„……þ†……†‡†‡ø€€€€‚þ‚‚ýƒ‚ƒƒü„ƒƒ„„û…„…„……ý†…††û‡†‡‡€€ú€€€ü‚‚‚ƒü„ƒƒ„„þ…„„…þ„……ú†……†…††û‡†‡€€þ€€ú‚‚‚‚ýƒ‚ƒ ƒ„ü…„„……ü†……††ü‡†€ €ú‚‚‚‚ûƒ‚ƒ‚ƒƒ„…þ„……þ†……†þ‡††€ü€€‚ü‚‚‚ýƒ‚ƒƒþ„ƒƒ÷„ƒƒ„„…„„……þ„……ý†…††û…†‡†ü€€€û‚‚‚‚ƒþ‚ƒƒ„…þ„……ü†……††ý€€€€‚þ‚‚ýƒ‚ƒƒ„þƒ„„…ü„…„……ý†…††€€þ€€ý‚‚‚ƒ÷‚ƒƒ„„ƒ„ƒ„„ú…„……„……ø†……†~~€€ý€ý‚‚‚ƒþ‚ƒƒý„ƒ„ „…~ý~€þ€€þ€ ‚ƒþ‚ƒƒ„ü…„„……†~õ~~€€€€õ€€‚‚‚‚ƒû„ƒ„ƒ„„…~þ~~€þ€€‚þ‚‚ƒþ‚ƒƒ„þ…„„…þ}~~þ~ù€€€€€ø€€‚‚ƒý„ƒ„„ý…„……~ý~ý€€€ù€€€‚ƒü‚ƒƒ„„þƒ„„ü…„„……þø÷÷ûø÷øø÷÷þø÷÷øù÷øø÷ø÷øøþ÷øøùùøøùøùøøôùøøùøùøø÷øø÷÷üø÷÷øø÷ýø÷øøþ÷øøþ÷øøþùøøþùøøþùøøòùøùùøø÷÷øø÷ø÷øøþ÷øøû÷ø÷÷øøþ÷øøþùøøùø÷÷ø÷ø÷÷øø÷øøþ÷øøþ÷øøþ÷ø øþùøøûùøøùøøýùø÷÷ø÷ø÷øþ÷øøþ÷øøþ÷øøþù÷÷üø÷÷øøü÷øø÷÷öø÷ø÷÷øø÷÷øøû÷øø÷øøùùøùøøùøø÷ø÷øø÷øø÷ø÷÷øøü÷ø÷øøùýøùøøúù÷ø÷÷øøý÷ø÷÷þø÷÷üø÷÷øø÷øþ÷øøùøù÷þø÷÷ø÷þø÷÷øú÷ø÷÷ø÷÷øûùøøùøøùùøøùùø÷÷ðø÷÷ø÷÷ø÷÷øø÷øø÷øø÷úø÷ø÷÷øøûùøøùøø ÷õø÷÷øø÷÷ø÷ø÷÷ø÷øü÷ø÷ø øþ÷ø øúùøøùø÷÷þø÷÷úø÷ø÷ø÷÷þø÷÷ôø÷÷øø÷ø÷÷ø÷øøþ÷øøþ÷øøþùøø÷þø÷÷ø÷ø÷ýø÷øøü÷ø÷øøþ÷øøþ÷øøûùøøùøø÷þø÷÷úø÷øø÷øøó÷ø÷ø÷ø÷÷øø÷ø÷÷ø÷þø÷÷þø÷÷üø÷÷øø÷þø÷÷ýø÷øøþ÷øøþ÷øø÷üø÷ø÷÷üø÷ø÷÷øù÷øø÷÷ø÷÷øü÷ø÷øøü÷ø÷øøþ÷øø÷ôø÷÷ø÷÷ø÷ø÷ø÷÷ýø÷øøï÷ø÷÷ø÷øø÷øø÷÷øø÷ø øþù÷ ÷ýø÷øøý÷ø÷÷ø÷ø÷ûø÷ø÷øøþ÷øø÷ ø÷þø÷÷öø÷ø÷÷ø÷øø÷÷ùø÷øø÷÷øøþ÷øøú÷ø÷ø÷øøþ÷øø ÷þø÷ ÷þø÷÷ø÷øô÷øø÷÷ø÷øø÷÷øø÷ø÷øý÷ø÷÷þø÷÷ûø÷ø÷øøö÷ø÷÷øø÷ø÷øøþ÷øø÷þø÷÷þø÷÷üø÷÷øøù÷øø÷øø÷÷ùø÷÷ø÷÷øøþ÷øøþö÷÷üö÷ö÷÷þø÷ ÷ø÷øì÷øø÷÷ø÷÷ø÷÷øø÷øø÷ø÷øøþö÷÷þö÷ ÷ôø÷ø÷øø÷ø÷÷ø÷÷ùø÷÷ø÷÷øø÷ýø÷øø÷øö÷þø÷÷òø÷ø÷ø÷ø÷øø÷øø÷÷ùø÷ø÷ø÷øø÷øþ÷øøý÷ø÷÷þö÷ ÷þø÷÷þø÷÷ø÷óø÷÷ø÷ø÷ø÷÷øø÷÷þø÷÷ýø÷øøü÷öö÷÷þö÷÷þø÷÷õø÷ø÷÷ø÷ø÷ø÷÷þø÷÷ýø÷øøý÷ø÷÷ýø÷øø÷ûø÷÷ø÷ ÷ùø÷÷øø÷øø÷ýø÷øøü÷ø÷øøó÷øø÷ø÷÷ö÷÷öö÷÷þø÷÷ø÷ùø÷ø÷ø÷øø÷üö÷ö÷÷þö÷÷øü÷ø÷øøø÷ø÷÷ø÷÷øøþ÷øøý÷ö÷÷þö÷÷ûö÷öö÷÷þø÷÷òø÷÷øø÷ø÷ø÷øø÷øø÷÷ø÷÷ö÷ö÷ö÷÷ö÷þö÷÷ûø÷÷ø÷÷üø÷ø÷÷þø÷÷ùø÷ø÷÷ø÷÷ùö÷÷ö÷ö÷÷þö÷÷ôø÷ø÷ø÷ø÷÷ø÷øøþ÷øøü÷ø÷ööý÷ö÷÷úö÷÷öö÷÷þö÷÷üø÷ø÷÷üø÷÷øø÷øþ÷øø÷üø÷÷ööü÷ö÷öö÷þö÷÷þö÷ ÷ø÷þø÷÷ø÷ø÷øý÷ø÷÷úøöö÷÷ööú÷ö÷÷ö÷÷þö÷÷þö÷÷üø÷ø÷÷øþ÷øøþö÷÷ö ÷þö÷÷ûö÷öö÷ ÷úø÷÷øø÷÷üø÷ø÷÷ø÷ýø÷ööö÷öö÷ö÷ö÷ö÷÷ö÷þö÷÷þø÷÷ø÷÷ø÷÷ø÷øö÷ööü÷ö÷öö÷þø÷÷þø÷÷øþ÷øøù÷ö÷÷ö÷öö÷þö÷÷ûö÷÷ö÷÷ö÷þö÷÷ýø÷øøý÷ø÷÷ö÷öþ÷ööü÷ö÷öö÷ö ÷þø÷ ÷þø÷÷þø÷÷öû÷ö÷ö÷÷ûö÷÷ö÷÷þö÷÷þø÷÷øø÷ø÷ø÷ø÷÷ûø÷ø÷öö÷ôö÷ö÷öö÷ö÷öö÷÷þö÷÷ö ÷þø÷÷þø÷÷ø÷úø÷ö÷ö÷÷ö÷ö÷þö÷÷þö÷÷üö÷ö÷÷ø÷öþ÷öö÷öþ÷öö ÷þö÷÷þø÷÷øû÷ø÷÷öö÷öü÷ö÷öö÷þö÷÷þö÷÷ö÷þö÷ ÷üø÷ø÷÷öþ÷öö÷ýö÷ööý÷ö÷÷þö÷÷öö÷ö÷öö÷÷ö÷÷þö÷ ÷ø÷öù÷ö÷öö÷öö÷þö÷÷ûö÷öö÷÷þö÷÷ö÷üö÷ö÷ ÷ø÷þøööõ÷ö÷öö÷ö÷öö÷÷ö÷üö÷÷ööý÷ö÷÷ö÷öþ÷öö÷ùö÷öö÷÷ööû÷ö÷ö÷÷þö÷÷þö÷ ÷þø÷÷üøö÷ööø÷öö÷ö÷÷ööþ÷öö÷ö÷÷ö÷ö÷÷öö÷÷öö÷ö÷÷ö÷÷ö÷÷þø÷÷ùø÷öö÷÷öö÷öû÷ö÷÷ööü÷öö÷÷öþ÷ööü÷öö÷÷þø÷÷ öô÷öö÷ö÷ö÷÷öö÷÷ö÷öø÷ö÷öö÷ö÷÷öý÷ö÷ ÷ýø÷ö öü÷ö÷ööý÷ö÷÷þö÷÷þö÷÷ö÷ö÷þøööþ÷ööü÷öö÷÷ö÷öý÷ö÷÷÷ö÷öö÷ö÷ö÷÷þö÷ ÷ ö÷öþ÷öö÷öü÷ö÷öö÷þö÷÷þö÷÷ûö÷÷ö÷÷öþ÷ööþ÷ööþ÷ööþ÷öö÷ùö÷÷ö÷ö÷÷þö÷ ÷ö÷ùö÷ö÷÷ö÷÷þö÷÷öö÷÷ö÷÷ö÷ö÷÷öþ÷ö öû÷öö÷öö÷öü÷öö÷÷þö÷÷þö÷÷üö÷÷ö öþ÷öö÷ö÷öô÷ö÷÷ö÷ö÷ö÷÷öö ÷ö÷ö÷ öø÷öö÷÷ö÷ööû÷ö÷ö÷÷÷ö÷÷ö÷öö÷ööþõö öû÷öö÷ööï÷öö÷ö÷öö÷ö÷öö÷öö÷÷üö÷ö÷ ÷öû÷ö÷÷öö÷ýö÷ööý÷ö÷÷üö÷ö÷ ÷öþõööþõööþ÷ööþ÷öö÷þö÷÷þö÷÷þö÷ÿŠ‹Œþ‹ŒŒýŒŽüŽŽý‘ø’‘‘’‘‘’ŠŠ‹þŠ‹‹ýŒ‹Œ ŒŽþŽŽû‘‘‘‘’ý‘‰ŠŠ‹ŒþŒŽþŽŽø‘‘ý’‰ŠŠý‹Š‹‹ýŒ‹ŒŒùŒŒŒŒýŽŽŽüŽŽû‘‘‘‘û’‘‰‰ŠŠý‹Š‹‹ŒýŒŽþŽŽýŽý‘ý‘‰ŠŠþ‰ŠŠ‹þŠ‹‹Œþ‹ŒŒþŽŽýŽú‘‰þЉ‰Š‹þŠ‹‹üŒ‹‹ŒŒþŽŽþ‘û‘‘ˆ‰‰Š‹Š‹øŒ‹Œ‹ŒŒ‹ŒŒ Žý‘‰üЉ‰ŠŠ‹þŠ‹‹Œü‹Œ‹ŒŒþŒŽþŽþú‘‰‰ˆˆ‰‰Š‹ŒþŒŽŽüˆý‰ˆ‰‰Šþ‰ŠŠþ‹ŠŠû‹Œ‹‹ŒŒþŒùŽŽŽŽþŽˆ‰ûЉЉŠŠ‹ûŒ‹Œ‹ŒŒŽþŽŽþþˆˆ‰Šþ‰ŠŠ‹þŠ‹‹ûŒ‹Œ‹ŒŒýŒþŽŽýŽþŽˆø‰ˆˆ‰ˆ‰ˆ‰‰Šþ‰ŠŠ‹ŒþŒŒüŽŽŽþˆˆ‰úˆ‰Š‰‰ŠŠ‹Œþ‹ŒŒüŒŽ Žþ‡‡ˆ‰ Šý‹Š‹‹ŒýŒþŽŽøŽŽŽ‡‡ˆý‰ˆ‰‰Š‹Œþ‹ŒŒþŒŒŽýއˆü‡ˆ‡ˆˆ‰Šü‹ŠŠ‹‹ŒüŒŒüŽŽŽ‡ˆþ‡ˆˆþ‰ˆˆ‰üЉ‰ŠŠ‹úŒ‹‹Œ‹ŒŒüŽŽŽüއ†‡‡ˆþ‰ˆˆ‰Š‰Šý‹Š‹‹ýŒ‹ŒŒŽþŽŽúއ††‡‡ˆ‡ˆü‰ˆˆ‰‰Š‰Š ‹úŒ‹ŒŒ‹ŒŒþŒŽ‡þˆ‡‡ˆ‰þˆ‰‰ýЉŠŠý‹Š‹‹üŒ‹‹ŒŒôŽŽŽŽ‡†‡††‡‡ ˆ‰Šû‹Š‹Š‹‹Œýކ†‡þ†‡‡ˆþ‡ˆˆ‰ˆø‰Š‰‰ŠŠ‰ŠŠý‹Š‹‹ýŒ‹ŒŒúŽŽ†…††‡üˆ‡‡ˆˆù‰ˆ‰ˆ‰ˆ‰‰üЉ‰ŠŠ‹ùŠ‹‹Œ‹‹ŒŒ ü†……††ö‡†‡†‡ˆ‡‡ˆ‡‡ˆü‰ˆˆ‰‰ Š‹ŒþŒŒö…††……††‡†‡‡ø†‡ˆ‡‡ˆ‡ˆˆú‰ˆ‰‰ˆ‰‰Šþ‹ŠŠ‹ýŒ‹ŒŒýŒ…†‡ˆþ‡ˆˆ‰Š‹þŠ‹‹þŒ‹‹ŒùŒŒŒ……† ‡ˆø‰ˆˆ‰‰ˆˆ‰‰ýЉŠŠ‹þŠ‹‹ýŒ‹ŒŒþŒŒ…ý†…††‡ˆþ‡ˆˆü‰ˆˆ‰‰ùŠ‰ŠŠ‰‰ŠŠ‹ûŒ‹Œ‹ŒŒý…„……†‡û†‡‡†‡‡ýˆ‡ˆˆú‰ˆ‰‰ˆ‰‰þЉ‰Šø‹ŠŠ‹Š‹Š‹‹þŒ‹‹Œþ„……†‡ü†‡†‡‡ýˆ‡ˆˆ‰Šþ‰ŠŠü‹ŠŠ‹‹þŒ‹‹Œ„õ…„„……††…†…††ý‡†‡‡ˆù‡ˆ‡ˆˆ‰ˆˆ‰þˆ‰‰Šþ‰ŠŠ‹Œþ…„„…ý†…††‡ù†‡ˆ‡ˆ‡ˆˆü‰ˆˆ‰‰Šý‹Š‹‹Œ„ý…„……þ„……û†…†…††ý‡†‡‡ˆý‰ˆ‰‰öЉ‰Š‹Š‹ŠŠ‹‹Œþƒ„„…ü†……††‡õˆ‡‡ˆ‰ˆˆ‰ˆˆ‰‰Šü‰Š‰ŠŠ‹üŒ‹‹„„…þ„……þ„……†‡ýˆ‡ˆˆþ‰ˆˆ‰ýЉŠŠ‹þŠ‹‹üƒ„ƒ„„…ü†……††‡ù†‡ˆ‡ˆ‡ˆˆý‰ˆ‰‰þЉ‰Šú‰Š‹ŠŠ‹‹ƒ „…†þ…††‡þ†‡‡ýˆ‡ˆˆþ‰ˆˆü‰Š‰ŠŠû‰ŠŠ‹ŠŠ‹ƒý„ƒ„„þ…„„…†þ‡††‡üˆ‡‡ˆˆ‰ˆ‰Šþ‰ŠŠ‹ýŠ‹ƒƒý„ƒ„„…†þ…††‡þ†‡‡ûˆ‡ˆ‡ˆˆý‰ˆ‰‰úЉ‰Š‰ŠŠý‹Šƒƒ„üƒ„„……þ„……†ü‡††‡‡ˆ‰øˆ‰Š‰‰Š‰ŠŠü‹‚‚ƒƒý„ƒ„„…þ„……ü†……††ú‡†‡‡†‡‡ˆü‡ˆ‡ˆˆø‰ˆˆ‰ˆ‰Š‰‰Šü‚ƒ‚ƒƒ„þƒ„„û…„…„……†ü‡††‡‡ˆ ‰Š‚ƒû„ƒ„ƒ„„…þ„……†‡†‡úˆ‡‡ˆ‡ˆˆ‰ýЉŠŠ‚ƒ„þƒ„„÷…„……„……†……†ñ…††‡†‡‡††‡ˆ‡ˆ‡ˆˆ‰ûЉ‰Š‚‚þƒ‚‚ýƒ‚ƒƒý„ƒ„„ý…„……ý†…††‡üˆ‡‡ˆˆý‰ˆ‰‰ûЉ‚‚‚ƒý„ƒ„„…†‡þ†‡‡üˆ‡‡ˆˆû‰ˆ‰ˆ‰‰‚‚úƒ‚ƒ‚‚ƒƒ÷„ƒƒ„ƒ„„…„„…û„……†……†‡ˆ÷‡ˆ‰ˆ‰ˆ‰ˆ‰‰‚þƒ‚‚ƒú„ƒƒ„ƒ„„…û„……†……†ü‡††‡‡ˆþ‡ˆˆü‡ˆˆ‰‰ý‚‚‚üƒ‚‚ƒƒý„ƒ„„ü…„„……þ†……ý†…††‡üˆ‡‡ˆˆþ‰ˆˆþ‰‚ƒþ‚ƒƒ„ý…„……ü†……††ý‡†‡‡ö†‡ˆˆ‡‡ˆˆ‡ˆˆû‰ˆ€‚ýƒ‚ƒƒ„þƒ„„þ…„„…ý†…††…†ý‡†‡‡ˆ‡ˆ‰‚ƒþ‚ƒƒ„þƒ„„…†‡þ†‡‡ýˆ‡ˆˆ€ù‚‚‚‚ƒû„ƒƒ„ƒƒ„ú…„……„……†‡ùˆ‡ˆˆ‡ˆ€€‚‚ƒý„ƒ„„…†…†ü‡††‡‡üˆ‡‡ˆˆý€€€ý€‚þ‚‚ýƒ‚ƒƒ„ …†‡ýˆ‡€€þ‚‚þƒ‚‚ ƒ„ú…„„…„……þ†……†þ‡††‡þˆ‡‡€þ€€þ€‚þ‚‚þƒ‚‚ƒú„ƒ„ƒƒ„„…þ„……û†…†…††ý‡†‡‡€þ€‚úƒ‚‚ƒ‚ƒƒü„ƒƒ„„…þ„……ý†…††ý‡†‡‡€ü€€‚ýƒ‚ƒƒù‚ƒƒ„„ƒ„„…þ„……†‡ý†‡€ü€€‚þ‚‚ýƒ‚ƒƒý„ƒ„„û…„…„……†þ…††ú‡††‡~ü€€€þ€ý‚‚‚ƒú„ƒ„ƒƒ„„ü…„„…… †þ~þ€€ý€þ‚‚÷‚‚ƒ‚‚ƒ‚ƒƒ„þ…„„…†ü‘’“þ’““ü”““””ü“””••þ”••þ–••–þ—––÷—–—ý‘‘‘÷‘‘’‘’‘‘’’“’“ý”“””þ“””•þ”••ü–••––‘’ý“’““”•ý–•––þ—ýý‘‘‘’þ‘’’ú“’““’““ý”“””•þ”••ü–••––ý—–þý‘‘‘ý’‘’’“þ’““ú”““”“””•ú–••–•––‘’þ‘’’“þ’““ù”““””“””•þ”••–ûŽŽŽýü‘‘‘ü’‘‘’’ü“’’““ý”“””•þ”••ú”•–••––þŽüý‘‘‘ý’‘’’ú“’’“’““þ”““ý”“””•–ŽþŽüü‘‘‘ö’‘’‘’‘’’“’’“”“”ü•””••ü–ŽŽø‘‘’ø‘’‘’’“’““”“”•þ”••þŽŽûŽú‘‘‘’“þ’““”ú•””••ŽŽúŽŽŽþü‘‘‘ý’‘’’“ø”“”““”“””•üŽŽŽúŽŽü‘þ‘‘’þ“’’“”þ“””•ý”ŽŽüŽŽ ‘ý’‘’’ü“’’““”ý•ŽýŽŽŽŽ‘þ‘‘þ’‘‘’“’“”ïŽŽŽŽŽŽŽŽŽŽ‘ ’“”þ•øŽŽŽŽŽþŽþ‘ ’“”ŽŽ  ‘’ý“’““”ûŒŒŽýŽüŽüù‘‘‘‘ò’‘’‘‘’’““’““’““”ü“ŒýŽŽŽüŽŽþ‘ý‘‘‘’“÷”“ŒŒŒŽú‘‘‘‘ý’‘’’þ‘’’þ“’’“ŒŒýŽŽŽþŽŽþ‘’þ‘’’“Œ ŽŽý‘ü‘‘‘ü’‘‘’’õ“’’““’““Œ‹ŒŒ ýŽŽŽþŽ‘‘ý’‘’’“ù’“’“Œ‹ŒŒýŒŽþŽŽýŽ ý‘‘‘’ü‘’‘’’û“’Œ‹ŒŒþ‹ŒŒ ŽùŽŽŽü‘ý‘‘‘ý’‘’’ù“’‹‹Œ‹ŒŒüŒŒŽûŽŽ ‘’‹ŒŒþŒ Žý‘þ‘‘ý’‘’’‹ŒþŒŽþŽú ‘û’‘’’‹‹úŒ‹ŒŒ‹ŒŒùŒŒŒøŽŽŽŽŽŽ ú‘‘‘‘÷’‘‘’’‹‹Š‹‹Œþ‹ŒŒûŒŒþŽŽýŽýý‘‘‘’ý‹Š‹‹ŒýŒýŽŽŽýŽý‘‘ü’‘’ŠŠ‹öŠ‹‹Œ‹Œ‹Œ‹ŒŒŒýŽŽŽýú‘‘‘‘þ’ŠŠ‹þŠ‹‹üŒ‹‹ŒŒŽþŽŽûŽŽþ‘Š‹ûŒ‹Œ‹ŒŒýŒüŒŽŽþŽŽü‘‘‘ý‘ŠŠ‹úŠ‹‹ŠŠ‹‹ûŒ‹Œ‹ŒŒúŒŽýŽŽŽ ù‘‘‘þ‰ŠŠ‹Š‹üŒ‹‹ŒŒþŒûŽŽŽŽ û‘‘‰ŠŠý‹Š‹‹þŠ‹‹øŒ‹Œ‹ŒŒŒŒŽþŽŽýþü‘‰‰Š Š‹ŒþŒýŽŽŽþŽŽþ‘‰‰ýЉŠŠý‹Š‹‹Œþ‹ŒŒþŒýŽŽŽþŽŽýˆ‰ýЉŠŠ‹þŠ‹‹Œ‹ŒýŒŽýŽýþˆ‰‰Š‹þŠ‹‹ŒŽûŽŽŽŽþŽŽüˆ‰ˆ‰‰Š ‹ýŒ‹ŒŒþŒŽŽíŽŽˆˆ‰ˆˆ‰‰üЉ‰ŠŠù‹ŠŠ‹ŠŠ‹‹þŒ‹‹ŒþŒŒúŽŽŽŽúŽŽˆý‰ˆ‰‰Šý‹Š‹‹ùŒ‹Œ‹Œ‹ŒŒŽþŽýˆˆö‰ˆ‰ˆ‰Š‰Š‰ŠŠù‹ŠŠ‹ŠŠ‹‹ýŒ‹ŒŒ‹ŒüŒŒþŽýŽŽŽˆþ‰ˆˆ‰Šü‹ŠŠ‹ ‹ŒüŒŒŽ÷ŽŽŽ‡‡ˆˆü‰ˆˆ‰‰÷Š‰ŠŠ‰‰Š‰ŠŠ‹Œ‹ŒŽùŽŽŽˆ ˆ‰ûЉЉŠŠ‹þŒ‹‹öŒ‹Œ‹ŒŒŒŒ÷ŽŽŽŽŽŽŽþˆˆ‰þˆ‰‰ùЉЉЉŠŠ ‹ŒúŒŒŒŽŽ‡ýˆ‡ˆˆ‰Š‹þŠ‹‹Œþ‹ŒŒúŒŒŒŽþŽŽþ†‡‡ ˆý‰ˆ‰‰Šý‹Š‹‹þŠ‹‹ýŒ‹ŒŒýŒþŽŽ‡üˆ‡‡ˆˆ‰ûЉЉŠŠù‹Š‹ŠŒŒ‹‹þŒ‹‹ŒþŒøŽŽŽ†‡†‡‡ýˆ‡ˆˆ‰ˆ‰Šø‰Š‰ŠŠ‹Š‹‹ŒûŒŒøŽŽŽ‡†‡‡þ†‡‡ýˆ‡ˆˆ‰þЉ‰ûЉЉŠŠü‹ŠŠ‹‹Œþ‹ŒŒ ù†‡†‡‡†‡‡ˆþ‡ˆˆ‰üˆ‰ˆ‰‰ Š‹÷Œ‹Œ‹‹ŒŒ‹ŒŒ†‡ýˆ‡ˆˆ‰ýЉŠŠþ‹ŠŠ‹ŒþŒ†‡þˆ‡‡ˆú‰ˆ‰ˆˆ‰‰Šý‹Š‹‹úŒ‹ŒŒ‹ŒŒøŒŒ……††ý‡†‡‡þ†‡‡ýˆ‡ˆˆþ‰ˆˆ‰Šö‰ŠŠ‹‹Š‹‹Š‹‹Œ‹ýŒ‹ŒŒþŒý†…†† ‡ˆþ‡ˆˆý‰ˆ‰‰üЉЉ‰Š‹þŠ‹‹ Œù……†……††ý‡†‡‡ˆ‰þЉ‰Š‹Œý…††ý‡†‡‡øˆ‡ˆˆ‡ˆˆ‰‰þˆ‰‰üЉ‰ŠŠ‹þŠ‹‹ýŒ‹ŒŒ÷……†…††…††ý‡†‡‡ˆü‰ˆˆ‰‰Šþ‹ŠŠ‹Œ‹Œ… †ý‡†‡‡ˆý‰ˆ‰‰úŠ‰ŠŠ‰ŠŠ‹ýŒ‹ŒŒøïùøùøùøøùùøùøøùùøùùúùúùýøùøøüùøøùùþøùùûøùùøùùúùúùòúùúúøøùøùùøùøùùúøùùøøùùûøùùøù ùûúùúúùù÷úùúùúùùúùùúûùøùøùùþøùùþøùùþøùùøýùøùùþøùùùúùùúùúùùþúùùüúùøùùøõùøùùøøùøùøùùúøùøùøù ùûúùùúùùúùúúùúùùøøùþøùùþøùùøøùùøùùøù ùþúùùûúùùúù ùøùøþùøøýùøùùøùþøùùþøùùþúùùúùúüùøùøøùüøùøùùüøùøùùþøùùþøù ùþøùùúùúúøùùøùøøùüøùøùùøøùøøùøøù ùþúùùþúùùúúùùúúùùøùøþùøøùøùüøùøùùþøùùþúùùñúùúúùùúøøùøùøøùùøùþøùùúøùøùøùùøùþúùùøþùøøïùøùøùùøøùøùøøùøøù ùþøùùþúùùþúøø÷ùøùøøùøùøøùþøùùôøùùøøùøøùùøùùøùøúùúúùùúøøþùøøýùøùùøùûøùùøùùüøùùøøùþøù ùþúùùøþùøøùðøùøøùøøùøùùøùøøùùûøùùøùùþøùùûøùùøù ùòúùùúøùøùùøøùùøøùøùïøùøùùøøùùøøùùøùøù ùþøùùøþùøøûùøøùøøúùøøùøùùþøùùúøùøùøùùøùøùúù øùøþùøøúùøùøøùùþøùùþøùùþøùùþøùùøþùøøüùøøùùþøùùøùøûùøùøùùþøù ùøðùøùøùøøùøøùøùøùøøùõøùùøùøøùùøùùüøùøùùøþùøøùøùøùøýùøùùüøùøùùýúùøøþùøøþùøøþùøøüùøøùùþøùùþøùùþøùùøøùøùøùøùùøþùøøûùøøùøøþùøøùûøùùøùùþøù ùþøùù øþùø øùøùùøùùøùøùùþøùùøùúøùøø÷øøúùøøùùøøþùøøúùøùùøùùøùøùþøùùøþ÷øøþùøøþùøøúùøøùùøøùöøùøùùøøùùøøøùøùøùùøùùøþ÷ø øúùøøùùøøþùøøüùøùøøýùøùùþøùùüøùøùùþøùùöøùøøù÷øø÷øøþ÷ø øùøþùøøþùøøûùøøùøøþùøøýùøùùûøùùøùùøþ÷øøü÷ø÷øøùøùùøùøùùøøýùøùùûøùùøùùûøùøùøøþ÷ø øþùøøýùøùùøùøùþøùùø÷øþ÷øøþùøøùøýùøùùüøùøùùüøùùøøþ÷øøþ÷ø øùóøùøùùøùùøùøøùùþøùùþøùùøùúøùøùùøøþ÷øøþ÷ø øþùøøùþøùùøùøùøùþøùùú÷ø÷ø÷øøþ÷øøþ÷øøùûøùøøùùõøùøøùùøùùøùùýøùøøþ÷ø øþ÷øøþ÷øø÷ùøøùøøùùøøüùøøùùøúùø÷÷ø÷÷øøùøøùøøùøøùûøùøøùùþøùùøöùøùøøùùøø÷÷øþ÷øøþ÷øøþ÷ø øûùøøùøøùøýùøùùýøùøøþùøøþ÷øøþ÷øøþùøøùüøùùøøùùøøùùøùùøú÷ø÷ø÷øøû÷øø÷øøþ÷øøúùøøùùøøùûøùøøùùûø÷ø÷øøþ÷øøþ÷ø øþùø øýùøùùøùøõ÷ø÷øø÷÷øø÷øøþ÷øøþ÷ø øþùøøùùøùùøùøøøùøøùøùùøø÷÷ø÷øø÷ø÷øøþ÷øøþ÷ø øþùøøþùøøýùøùùúøùøøùøøþ÷øøþ÷øøû÷øø÷øøü÷ø÷øøùøùîøùùøùø÷÷ø÷ø÷÷ø÷÷ø÷÷øþ÷øøþ÷øøûùøøùøøþùøøòù÷øø÷ø÷øø÷ø÷÷øøü÷ø÷øøû÷øø÷øøùøüùøù÷÷úø÷øø÷øø÷ø÷ø÷øþùøøûùøøùøø÷ûø÷÷ø÷÷ø÷øþ÷ø øú÷ø÷ø÷ø øþùøøþùøøüùøø÷÷øø÷ø÷øø÷÷ø ø÷øþ÷øøþùøøþùøøùþø÷÷÷ø÷øø÷øø÷øø÷öø÷øø÷÷øø÷øøùøþù÷÷ø÷øþ÷øø÷øü÷ø÷øøü÷ø÷øøþ÷ø øüùøùøø÷ø÷ûø÷øø÷÷úø÷÷ø÷øøþ÷øøü÷ø÷øøú÷ø÷ø÷øøþùøøúùøøùùøø÷þø÷÷ø÷øû÷ø÷÷øø÷øþ÷øøü÷ø÷øøþùøøþùøøþùøø÷þø÷÷øø÷ø÷ø÷ø÷÷úø÷øø÷øø÷øù÷ø÷÷ø÷øøþùøø÷óø÷÷ø÷øø÷øø÷ø÷÷øþ÷ø ø÷øþ÷ø ø÷þø÷÷þø÷÷øþ÷øøû÷ø÷ø÷÷øù÷ø÷÷ø÷øøü÷ø÷øøý÷ø÷÷þø÷÷þø÷÷ø÷ø÷øþ÷øøþ÷øøüùøø÷÷þø÷ ÷ø÷÷ø÷ø÷ø÷÷øø÷ýø÷øøþ÷øøþ÷øøþùøø÷ôø÷÷øø÷ø÷÷øø÷÷öø÷÷øø÷ø÷÷øøþ÷øø÷üø÷ø÷÷þø÷÷úø÷÷øø÷÷ø÷ø÷ø÷ øþù÷÷þø÷÷þø÷÷þø÷÷øó÷ø÷øø÷ø÷÷øø÷øø÷øû÷øø÷ø ø÷ùø÷÷ø÷ø÷÷øþ÷øø÷øþ÷øøø÷ø÷ø÷ø÷ø ø÷ø÷øü÷ø÷øø÷ùø÷ø÷ø÷øø÷øû÷øø÷øø ÷ø÷ø÷þø÷÷úø÷ø÷ø÷÷þø÷÷ø÷þø÷÷øþ÷øø÷ø÷þø÷÷þø÷÷öø÷ø÷÷øø÷÷øøþ÷øøÿ’“ý”“””•ú–••–•––—ý˜—˜˜™’ý“’““”û“””“””•þ”••–—ú˜——˜—˜˜ý™˜™™ýš™’’“ø’““”“”“””•þ”••–—–—ý˜—˜˜ü™˜˜™™‘ú’‘’’“’’ý“’““ý”“””ü•””••þ–••–—ü˜——˜˜ý™˜™™ ’“û”“”“””ü•””••ý–•––ý—–——˜ø™˜˜™™˜™‘‘’ú“’’“’““”þ“””•–—þ–——˜û™˜˜™‘‘’þ‘’’“”“” •–ý—–——˜ü™˜˜‘‘’ “ø”“””•””••–ú•–•––— —˜þ‘‘’‘’ü“’’““ý”“””ú•”••”••–ý—–——˜þ—˜˜‘þ’‘‘’þ‘’’û“’“’““”•ý–•––—û˜—˜—˜˜‘‘’“”þ“””ý•”••–û—–—–——ú˜——˜—ô‘‘‘‘‘’‘‘’’“ú”“”““””ú•””•”••–þ•––û—–—–——û˜——˜‘‘û’‘’‘’’“ü”““””ý•”••ý–•––—û–——˜——ö‘‘‘‘’ü‘’“’’“ý”“””•þ”••õ–•–——–——––——ý‘’þ‘’’“’“ý”“””•þ”••–—û‘‘‘‘’þ“’’“þ’““”“”ú•”••”••–—ý–—‘‘ü’‘‘’’“þ’““”û“””“”” •–þ—––û—–Žýü‘‘‘ü’‘‘’’þ“’’“ý”“””•ü–••––þŽþ‘þ‘‘’“û”“”“””ü•””••–þ•––ûŽŽõ‘‘‘‘‘’‘‘’ú“’““’““ò”“””““•””••””••–ü•–•––Ž ù‘‘‘’‘’ ’“”•þ”••–ŽþŽþ‘ü’‘‘’’ø“’’“’“’““û”“”“””ý•”••þ–ŽŽþü‘‘‘’“þ”““” •–ŽüŽŽþŽ‘’þ‘’’ý“’““”þ“””•ü–•ŽûŽŽŽŽù‘’þ‘’’“ü”““””ý•”••ý–ŽŽþŽŽþü‘‘‘’“þ’““”þ“””ü•””••úŽŽŽŽŽýŽü‘ü‘‘‘ý’‘’’“þ’““û”“”“””ü•””••ùŽŽŽŽŽ‘’ý“’““ý”“””ý•ŒŽþŽŽþŽú‘þ‘‘’“û’““’““ý”“””õ•ŒŽŽŽŽ‘ü‘‘‘ ’“ò’““”“”“”“”••ŒýŽŽŽýŽþ÷‘‘‘‘’‘’’þ‘’’ “”ŒýŽŽŽúŽŽŽ ‘’“þ’““ý”“””ŒúŒŽŽŽüŽŽý‘‘’‘’ü“’’““”þ“ŒŒúŒŒýŽŽŽüŽŽú‘‘’þ‘’’“þ’““ù”““””‹ŒŒŽýŽþŽ‘þ‘‘ý’‘’’“󔌌‹ŒŒŒŒŽþŽŽþŽü‘ý’‘’’û“’“’““û”‹Œ‹ŒŒüŒŒŽûŽŽüú‘‘‘‘’þ‘’’“‹ŒŒŽ‘í’‘’’‘’’“’““’“‹Œ‹Œ‹ŒŒŽŽý‘ý’‘’’“’튋‹Œ‹Œ‹Œ‹ŒŒŒŒŒŽûŽŽŽý‘ý’‘’’“‹ŒýŒŽþŽŽü‘ó’‘‘’’‘’“’’ŠŠ‹‹ŒüŒŒŽüŽŽ‘û’‘’‘’’Šý‹Š‹‹ýŒ‹ŒŒúŒŒŒõŽŽŽŽŽûþ‘‘þ‘‘’‘û’‘‹Š‹ ‹ŒþŒŽŽü‘’‘Š‹ŒþŒŽŽþ‘û’‘ЉŠŠ‹þŠ‹‹ýŒ‹ŒŒüŒŒýŽŽŽŽý‘‘‘’Šý‹Š‹‹ŒŽüŽŽý‘‰Šý‹Š‹‹ŒûŒŒüŽŽŽýŽï‘‘‘‘‘‘‰Š Šý‹Š‹‹Œû‹Œ‹‹ŒŒýŒŽþŽþ‘‰Šþ‰ŠŠü‹ŠŠ‹‹ŒŒŽþŽŽüŽŽŽþû‘‘‰‰üЉ‰ŠŠ‹ýŒ‹ŒŒøŽŽŽŽŽþ‘‰Šþ‰ŠŠþ‹ŠŠ‹Œû‹Œ‹‹ŒŒþŒŽøŽŽŽŽþù‘ˆˆ‰þЉ‰Š‹üŠ‹‹ŒŒþŒŒŽüŽŽýˆý‰ˆ‰‰Šþ‰ŠŠ‹ôŒ‹‹Œ‹ŒŒŒŒŽþþˆˆ‰Š‰Š‹Œü‹ŒŒ öŽŽŽŽŽˆ‰Š‹Š‹úŒ‹Œ‹‹ŒŒýŽŽŽý‡ˆˆú‰ˆˆ‰ˆ‰‰ýЉŠŠþ‹ŠŠ‹ŒŽþŽŽýŽý‡ˆˆý‰ˆ‰‰ýЉŠŠ‹Š‹ýŒ‹ŒŒûŒŒýŽŽŽüŽŽøˆ‡ˆˆ‡ˆˆ‰‰þˆ‰‰Š ‹ŒŽþŽŽøŽŽŽ‡‡ˆø‰ˆ‰‰ˆ‰‰ŠŠ‰Š‹ýŒ‹ŒŒþŒŒýŒŽýއ‡ˆù‰ˆ‰ˆ‰ˆ‰‰ûЉЉŠŠ‹þŠ‹‹ýŒ‹ŒŒýŒýŽŽŽ‡ûˆ‡ˆ‡ˆˆ‰þЉ‰Š‹Œü‹Œ‹ŒŒüŽŽŽ‡ˆü‡ˆ‡ˆˆú‰ˆˆ‰ˆ‰‰ýЉŠŠý‹Š‹‹ýŒ‹ŒŒŽûŽŽ†‡‡ˆþ‡ˆˆ‰ Šú‹Š‹‹Œ‹‹ŒûŒŒŽ—˜ù—˜˜™˜˜™™üš™™šš›œþœœûžžžž—˜þ—˜˜þ™˜˜™šû›š›š››œþ›œœ žþ——ý˜—˜˜™š™ýš™šš›þœ››ýœ›œœþœžú—–——–——˜—˜™˜™úš™š™™ššö›šš››œœ››œœòœœžž—–—–——þ˜——˜ ™šþ™šš›š›ýœ›œœ–ú—–——–——ô˜——˜˜™˜˜™˜˜™™šþ™šš›þš››œþ›œœýœ–ü—––——˜þ—˜˜ù™˜™˜™˜™™šþ™šš›üš›š››üœ›œ››œüœœý–•––—˜þ—˜˜þ™˜˜™ûš™š™ššú›š››š››þœ››œøœ––•––—þ–——˜—˜™þ˜™™šú›š››š››œ›œþ›œœü••––ý—–——˜ý™˜™™úš™šš™ššþ›ššý›š››üœ››œœ•–—ú˜——˜—˜˜™ýš™ššú™š›šš››þš››œüœœ••–—þ–——˜þ—˜˜™þš™™š÷›š›šš››œ››œþ”••þ–••ý–•––—þ–——˜þ—˜˜™ü˜™˜™™ýš™šš›þš››œü›œœ••ù–•––•–— —˜þ—˜˜™šþ™ššú›š››œ››üœ••””•ö–•––•–—––——˜ý™˜™™šþ™ššú›šš›š››øœ››••””••ú–••–•––ý—–——˜—ý˜—˜˜þ™˜˜ý™˜™™š™š›üš›š››”•–ü•–•––ü—––——ý˜—˜˜ú™˜™™˜™™ýš™šš›”•þ”••ú–•–••––ü—––——ü˜——˜˜™þ˜™™šþ™šš›š›þ“”” •–—ý˜—˜˜þ™˜˜™üš™š™™š›”ý•”••–ý—–——û˜—˜—˜˜™þ˜™™šî›š›š››””“”“””••””••þ–••–ý—–——ü˜——˜˜™þ˜™™üš™™šš›“”•û”–••––þ•––—–ý—–——˜ü—˜—˜˜™üš™™šš›“”õ“”““””•”•”••–•–ú—–——–——ú˜—˜——˜˜ý™˜™™ š“”ý•”••ý–•––—þ–——ý˜—˜˜™þ˜™™šþ™ššþ’““”•ý–•––û—–—–——˜û™˜™˜™™þš™™šþ’““”ú“””•”••þ”••ú–•–••––—þ˜——˜ý™˜™™šû™šš’““ü”““””ü•””••–þ•––ü—––——˜ü—˜—˜˜ý™˜™™úš™š’“’’“ý”“””þ“””ý•”••ü–•–••–—þ–——ú˜——˜—˜˜™þš’’“”“”ô•””•”••–•–•––þ•––—ú˜—˜˜—˜˜ü™˜˜™™þš’’ “”ý•”••û–•–•––ü—––——ù˜—˜—˜—˜˜™’ý“’““”ø•”••”•–••–þ•––ù—––—––——˜ú™˜˜™™’’“ý”“””ý•”•• – —˜™ý’‘’’“’“”•”•ü–••––ú—–—––——þ˜——˜ø™˜˜™™‘’‘‘’ý“’““”þ“””ý•”••–þ•––—þ˜——˜ø™˜™‘‘’‘’’ü“’“’’“ü”““””ý•”••û–•–•––—þ–——þ˜——˜þ—˜˜‘’þ‘’’“”ñ•”••”••––•–•–•––þ—––—÷˜——˜—˜˜‘‘’þ‘’’“þ’““þ”““”•ú–•––•––—ù˜—˜——˜‘‘þ‘‘’÷“’“’“’“”““ü”““””•ü–••––ý—–——˜‘ú’‘‘’‘’’ú“’“’’““”ù•””••”••ý–•––ý—–——˜õ—˜˜‘‘‘‘‘’ú“’““’““ü”““””ý•”••þ–••–ú—–—––——ý‘‘‘’þ‘’’“ý”“””•ü”•”••–þ•––þ—––—‘’û“’“’““ö”““””“”•”••þ”••ü–••––—þ–——þ‘þ‘‘ú’‘’’‘’’û“’“’““ü”““””•û–•–•––— ‘’ú“’““’““ý”“””ü•””••–þ•––—þ‘þ‘‘’þ“’’“”•þ”••–þ•––ý—–‘’ü‘’‘’’“”ù“”“””“””ü•””••ý–•––û—‘‘ù‘‘’‘‘’’û“’“’““”•”•–ýþ‘‘’“’ý“”““ý”“””•þ”••–þŽþ‘‘’“þ’““þ”““”ý•”••–û•–•–þŽþ‘‘’þ‘’’ý“’““”“” •–üŽŽþ‘’‘’ü“’’““ø”“”“””•””•ù–ŽŽŽŽ‘þ’‘‘’“þ’““”•ý–•ŽŽþŽ‘þ‘‘’ú“’““’““ý”“””•þŽŽý‘þ‘‘ú’‘‘’‘’’“þ”““”• Žýý‘‘‘ ’“”þ“””•Žþü‘‘‘’ “ý”“””ü•””ŽþŽŽüŽŽö‘‘‘‘‘‘’‘ú’“’“’““þ”““”þ•””ýŽŽŽùŽŽŽüü‘‘‘ ’“ü”““””•úŽŽŽŽþ‘þ’‘‘ý’‘’’“þ”““”ŽþŽŽüŽŽþý‘‘‘ý’‘’’þ“’’“þ”““”þŒŽþŽŽþŽþù‘‘‘‘’ “”þŒúŽŽŽŽŽþŽþý‘‘‘þ’‘‘’ü“’’“ “ú”ŒŒŽüŽŽ‘þ‘‘ø’‘’’“’“’’ó“’““”“”ŒŒŒýŽŽŽŽö‘‘‘‘’‘’’“’“”øúùùúùúùúúüùúùúúþùú úûúúûúúûúúþûúúøûúûúúûûúúûþúûûúùúùúüùúùúúþûúúûúøûúûúûûúûûúþùúúþùúúýùúùùúþùúúþùúúùûúúûúûúúþûúúûûúûúûûûúûúúùùýúùúúüùúùúúüùúùúúþûúúüûúûúúûúýùúùùúþùúúþùúúûùúùùúúþùúúþûúúöûúúûúûûúûúúüûúûúúù÷úùùúùúùùúúùúþùúúþùúúþûúúþûúúûýúûúúþùúúøùúùùúúùúúùûúùúùúúþûúúðûúúûúúûûúúûûúûûúúùúùýúùúúùúûùúúùúúþùúúþùúúþûúúûûúûúûúúûìúûûúúûûúùúùùúùùúùúùúúþùúúþùúúøûúúûúúûúú÷ûúûúùùúùúúùúþùúúþùúúþùúúþùúúþûúúûûúûúûûúûþúùùþúùùþúùùùúùùúúùúúþùúúþùúúþûúúûúùùúùùúùúúûùúùùúúþùúúþûúúüûúúûûùúùùúùùúúùûúùúùúúûùúúùúúþùúúþùú úþûúú÷ûúûúúûûúùùúùúþùúúùúù#ú ùúúùùúùúú÷ùúùúùúùùúúþùúúþùúúþùúúüûúûúúþûúúùûúûûùùúúùüúùúùùúûùúúùúúýùúùùúùùúùúúùú úþûúúùûúùùúùùúùúùúùýúùúúþùúúþùúúþûúúùþúùùöúùúùúùúúùúúüùúùúúþùúúþùúúþùú úùþúùùûúùùúùùòúùúúùùúúùùúúùúúþùúúþùúúûùúúùú úþûúúùþúùùúúùúùúùù÷úùúúùùúùúúþùúúþùú úüûúúùùþúùùúýùúùùøúùùúùúùúúþùúúþùúúúùúúùùúúþûúú ùüúùúùùúüùúúùùúùúùýúùúúþùú úþûùùþúùùúùþúùùúòùúùùúúùúùùúúùúúþùúúùúüùúúùùþúùùþúù ùúþùúúùùúùúúùúúüùúùúúùûúùùúùùúùþúùùýúùúúþùúúþùú úùú÷ùúùùúúùùúúþùúúùúþùú úùþøùùþúùù÷úùúúùùúúùùúùúþùúúþùúúþùúúùþúùùþúùùúþùúúùüúùúùùúúùúúùúúùþúùùúýùúùùþúùùúùüúùùúúüùúùúúþùúúüøùøùùþúùùþúùùôúùùúùùúùúùùúúùúþùúúùþøùùþúùùþúù ùùúùúùúùúúûùúùùúúùöúùùúúùùúúùùþøùùþøùùúùøúùùúúùúùùøúùúùúùùúúùúùúùþøùùþøùù÷úùùúúùúùúúùùúúùúùúúùúþùúúýùøùùúùýúùúúùøúùúùùúúùùùúùúúùùúú$ùùúùùúùùúúùúúùúúùúúùþøùùþúùùúùúúùúúùúúúùúúùùúúùøüùøøùùþøùùþúùùúýùúùù÷úùùúùùúùúúùüúùúùùüøùøùùþøùùþøùùúù÷úùùúúùùúùùüúùùúúûùúùùøøýùøùùøøùùøùùøù ùúúùúúùúúùüúùúùùüúùúùùúüùúøùùþøù ùþøù ùþúùùúùýúùúúþùúúùùúùùúúùùøùøùþøùùúùüúùúùùúùúùôúùúùúúùøùøùøøùòøùùøùùøùùøùùøùùþúùùþúùùúùïúùùúùúùùøøùøùøùøùùþøùùûúùùúùùûúùùúùùüúùùúúùøüùøøùùüøùøùùþøùùþúùùùúùúùúùúúùþøùùüøùøùùþøùùûøùùøùùþøù ùþúùùúûùúùúùùúùøùþøùùøùúùþúùùùúùúùúúùùøþùøøùøùûøùùøùùþøùùüúùúùùúûùúùúùùøîùøøùøùùøùøøùùøøùøùùþøùùøúùùúùúúùùüúùùøøùøûùøùøùùûøùøøùùþúùùþúùùúùøùøþùøøùõøùøùøùøùùøùùþøùùþøùùþúùùþúùùþúùùúûøùøùøøùùøùøùùøùùøýùøùùþúùùþúùùþúøøþùøøýùøùùþøùùøýùøùùþúùùúþùúúùøùøýùøùùøùùøùùøøùùþúùùøýùøùùþøùùúøùùøøùùøùøùøùúýùúùùøþùøøùøôùøùùøøùøùùøù ùþúù ùôøùùøùøøùùøùøøüùøùøøúùøøùøùùüøùøùùþøùùþúùùþúøøüùøøùùþøùùþøùùüøùøùùþúùùøûùøøùøøúùøøùùøøþùøøùøþùøøýùøùùøùþøù ùüúùùø øþùøøûùøøùøø÷ùøùùøøùøùùþøùùüøùøùùþøùùþúùùþúøøüùøùøøùøûùøùøùùøýùøùùøùøùþøùùþúùùøùóøùøùùøøùùøùùøøúùøùøøùùûøùùøùùþøù ùøþùøøùúøùøøùøøùøùþøùùøùûøùùøù ù øúùøøùùøøùøþùøøùøùþøùùøþùøøþùøøöùøøùøøùøøùùøùøùþøùùþøù ùÿšý›š››œ-š›š›œþ›,þ™ššü›šš››ýœ›,™š›-™ýš™šš›š›-ù˜™™š™™šš›-˜™šþ›,þ˜™™ýš™ššþ›,ü˜™˜™™ýš™šš-˜™þ˜™™š-˜ú™˜™™˜™™ýš™šš-˜ú™˜˜™˜™™šý™š,˜™þ˜™™š-ú—˜—˜—˜˜ý™˜™™-—÷˜—˜—˜˜™˜™™û˜™™š,—ý˜—˜˜ý™˜™™-—˜™-—þ–——˜û™˜™™,þ–——˜™þ˜,–þ—––—˜þ™,– —˜ü—˜˜,–ü—––——÷˜——˜˜—˜—,þ•––û—–—–——ü˜——˜˜-ü•–•––—þ–——˜-•ý–•––—þ–——þ˜,þ•––þ•––—ý˜—,þ”••–ø•––—–——––—-•–þ•––ü—–—,•ô–•–••––—–——,”•ô–••––•––——–,”•þ”••–-”•ü–••––-”ü•””••ú–••––,”ý•”••–þ•,“”ý•”••þ–,þ”““”ü•””••ý–•,“ý”“””ý•”••-“”ø•”••”••,“ý”“””•-“”•ü”••,“þ’““ú”““”“””-ù“’’“’’““”-’“ý”“””-’“ú”“””“,’“”ý“”,’“þ’““ü”““,ý’‘’’“ü’“’““ý”“,‘’þ‘’’ý“’““-‘ ’“-‘ ’“-ý‘‘‘û’‘’‘’’“-ý‘‘‘’-þ‘‘ú’‘’’‘’’-‘ý’‘’’-þ‘‘ü’‘‘’’-ú‘‘‘‘þ’,û‘‘‘‘þ’,‘-‘-ý‘‘‘-ü‘þ‘‘-üŽŽþþ‘þ‘,þŽý-Ž‘þ,žùŸžŸŸžžŸŸ þŸ  -žŸý Ÿ  -žûŸžŸžŸŸ -žúŸžŸžžŸŸ -þžžüŸžžŸŸû Ÿ Ÿ,üžžžýŸžŸŸ-üžžžŸ-ýžžžŸ-þœúžžžžŸ- ž-œöœžžžžž-žþžž-üœœþœüžžž-œýœž-þ›œœþœýžžž-œþ›œœýž,›œþœþž,ù›œ›œœ›œœýœ-þ›œœþ›œœþœœ-›þœ››œüœ,›úš›œ››œœüœœ,þš››ùœ››œœ›œœüœ,›œþ›œœþ,šý›š››ûœ›œ›œœ-šý›š››üœ››œœ-šþ›šš›úœ››œœ,þ™šš›þš››œ-™ýš™šš›þš››þœ,úš™š™™šš›üœ››,™šû™š›š››þš››-™š›úš›š››,÷˜™š™™šš™ššý›š››-þ˜™™ùš™™šš™ššû›šš›,™þ˜™™úš™šš™šš-ý™˜™™šý™š™™šý›š,ø˜™˜˜™™˜™™ýš™šš-˜™šû™š™™,˜ý™˜™™ýš™šš-ý˜—˜˜ü™˜˜™™ûš™š™,þ—˜˜ý™˜™™š™-ü˜——˜˜ ™-—˜™-—ý˜—˜˜þ™˜˜™-—˜ü™˜™,—˜™þ˜,þ–——ý˜—˜˜þ™,ú—––—–——˜û—˜˜™,–—˜-– —˜-–ú—–——–——ý˜—˜˜-þ•––ý—–——˜—þ˜,û•––•––ý—–——þ–——þ˜,–þ•––—-•ü–••––—ü–——,•–þ•––ù—–—––—,•–þ•––û—–——,”•ý–•––—-”•–ý—–,ü”•”••û–•–•––-ú”•”•”••–û•–••––-þ“””û•”•”••ý–•––-þ“””ý•”••û–•––,”ý•”••–-“ý”“””ý•”••-úûú û-ûûúûûúûû-ýûúûûûúûûúûûþúûû-ûûúûûúûûþú,ûüúûúûûøúûûúúûû,úþûúúûúûúû-úûúûþúûûýúû,þúûûüúûúûûüúûû,úüûúûúúûþú,úúûúûúûúú÷ûúúûúúûû,ûúûûúûûüúûúûûú-òûúûûúûúûúûûúúûû-úûúúûúûûúûûúúûúú-ûýúûúúûúûþú,þúûûúûûúûúûûúþû,ýúûúúûýúûúúúûúúûû,ûúûúúûûúûþúûû-úþûúúþûúúûþú,üúûûúú÷ûúûúûúúûúú-úóûúûúúûúúûúûú,ûúûúûúúüûúûúúþû,þûúúôûúûúûúûûúúûúú-ýúûúúûúýûú, úûûúûú,úýûú,úûüúûûúúþû,úþûúúþû, úøûúúûûúú,ú-úýûú,þùú úýûú, úþûúúþû, úûûúúû,úüûúú,þùúúþùúúþûúú-ýúùúúþùúú-úþùú ú-ùúûùúúùúú-úþùúú-üùúùú ú-úþùúúúùúúùùúú-ûùúúùúúþùúú-úûùúùùúúþùúúþù,ùýúùúúþùúúýùú,üùúùúúùúþùúú-ôùúùúùúùùúúùúúþùúú-úùúþùúú-ýúùúúüùúùúú-øúùùúúùùú ú-õùúùùúúùúúùúúúùúùúú,úùúõùúùúúùúúùú,úùúýùúùùúúùúùù,üúùúùùúùú-ùúýùúùùúþùúú-üúùúùùúùúûùúùù,ùúþùúúùýúù, ùúúùùúù,ùúùúùþú,ùùúùùúúùùüúùúùùýúù,ùúùþúùùýúùúú-ùùúùùúùúùùú-þúùùþúùùúüùúù,ùöúùùúùúùúùúúþù, ùþúùù-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-€€€€+úMNMNMNNOþNOOúPOPOO*NMNýONOOüPOP*MNþMNNOþNOOþP*MNþMNNOþP*þLMMNO+ûLMLLMMNþMNNþONN+þLMMýLNMMýNMNNO+LMùNMMNNMNNþO*L MN+LùMLLMMLMMN+LþKLLýMLMMNþMNNþM*LüMLLMMúNMMNN*KLMN+KLMþLMMýNM*KLþKLLýMLMM+KþLKKøLKMLLMLMM+ýKJKKLþKLLþM*KþJKKýLKLLM+JýKJKKüLKKLL+üJKJKKþJKKþLKKL+JûKJKJKKþLKKL+þIJJ KúLKKLL*IJKþJKKüLKK*þJIIJûKJKJKK+IJþKJJøKJJKKLL*IþJIIJüKJJKK+IJK+IJûKJKK*IûHIIHIIJüKJK*HIøJIIJIJIJJ+HúIHIHHIIúJIIJIJJ+HýIHIIJþIJJ+þGHHIþJIIJ+GHIJ+ùGHGHHGHHIJ+GHþGHHIþJ*GHþGHHIHI+ýGFGGûHGHIHHþIHHþI*GýHGHHIþH*þFGGüHGGHH+FGHüIHH*FGþFGGýHGHH+FýGFGGHþGHH+÷FEFEGFGFGGHGþH* FGüHGH*öFEEFFEFFGFFG+EFGýFHGG+EFýGFGG+ýEDEEFþEFFG+ýEDEEúFEEFEFFGFþG*ûDEDDEEýFEFFýGF*DEùFEEFFEFFýGF*DýEDEEFþEFF+þCDDEþDEEþFEEF+úDCCDDEEF+CDýEDEEFþE*DüCDCDD E+CþDCCDúEDDEDEE+CþDCCDEþF*CûDCDCDDýEDEE+BCöDCDCDDEDDEE+øCBBCBCCDDCDûEDDE*ñBCBCCBCCDDCDDCDDþE*ýBCBBCD+þVWWþXWWùXWXXYXYY+WXüYXY*VýWVWWþXWWXüYXX*VýWVWWXûWXXWXX+öUVVWVVWWVWW÷XWXWXWXX*VW÷VWVWVWWXWWX+VWVWýXW*üUVUVVWVWþX*ûUVVUVVûWVWVWW+þUVVWþVWW+UVûUVVUVVW+þTUUýVUVVW+ýUTUUVþUVVW+TUVþUVV+TUVþW*TUþTUUúVUVVUVV+TúUTTUTUUøVUVVUVV*ýTSTTòUTUTTUVUUVVUV*TýUTUUúVUVUU*þSTTþSTTUüVUV*úSTSTSTTýUTUUTUýVU*STúUTUUTUU+SûTSTSTTüUTTUU+þRSSüTSSTTýUT*SþTSSTýUTUU+ýRSRRSTùSTSTTSTT+RSûTSTSTT+RûSRSRSST+RüSRRSSüTSSTT+þQRRüSRRSSüTST*RùSRSSRRSSTþS*QRúSRSRRSSüTSS*QRýSRSS+QRüSRRSS+QýRQRRSþRSS+üPQPQQRüSRR*ýQPQQR÷QRRSRRSS*ûPQPPQQRüSRR*ýPQPPQýRQRR+PQPQR+PQPQRùQRQQRR*PýQPQQþRQQ+üOPOPPûQPQPQQþRQQþR*þOPPþOPPQþR*OPûQPQPQQþR*OPQúPQPQR*OüPOPOOPúQPPQPQQ+ýONOO PþQ*ONOüPOOPPQ+NýONOOüPOOPPQ+NüONNOOP+NOüPOOPP+NúONONNOOPüOPP*NüONONNýONOOP+MNOüPOO*MýNMNNüONNOOýPO*MNüONNOO+ôLMMNMMNMNNONNùONONOO*þLMMNMNúONNONOO+MNOýNO*MþLMMNþO*úMLMMLMMüNMMNNþO*ýLMLLüMLLMMýNMNNþO*LþMLLýMLMMN+ðþñððúñðñðð* ðþñððþñ*ýðïðð+ðñð+ ðþñððýñð*úðïðïïð ð+ðþñðð+ðþïððïð+ûðïððïï ð+ðûïððïð ðþñ*ûïððïðð+þðïïðþïðð+ ðþïððýïð*þïððüïðïððýïð*ûðïðïððïýðïðð+ïýðïððþïððûïððï*ðþïððþïðð+ïðïð+ïðïðüïðð*ïþðïïðïð+ýïðïïùðïðïïðïïúðïðïï*ïðïïððïïðïððïðïððïð*úðïïððïïðþïððþïððþï*þïððïþðïïðüïðïðð+ûïðïïððþïððïýðïðð+úðïïðïððýïðïïð+õðïððïððïððïïþðïïð+ïþðïïóðïðïðïïðïðïð*þðïïúðïðïðïïðùïðïðïð*þðïïþðïïüðïïððýïð* ïùðïðïððïï+ïðïþðïïûðïïð*ïþðïïüðïðïïþðïïþð*ïþðïïüðïïðð+ïþðïïüðïðïïþð*ïþðïïðï+ïùðïïðïðïïüðïðïï+ïþðïïþðïïðþï*ïþðïïþðïï+ ïûðïïðïï+ýïîï ïðï+ïþîïïþðïïþðïï+ïþîïï+ï+îï+ïþîïïþðïï+ïþîï ï+þîïïþîï ï+ùîïîïîîï ï+ïîïþîïï+ïüîïïîîïþîïï+ïþîïïþîïï+ïýîïîîïþîïï+÷îïïîïïîîïïþîïïýîï*ïþîïïîïýîï*ûîïîîïïþîï ï+îïîþïîîïþîïïýîï*îïúîïîïïîîýïîïï+ïîïïîïîïïîîïïîïîïîï*ïþîïïøîïïîîïîïïþî*ïî÷ïîïîïïîïîîïþî*þïîîïüîïîïïùîïïîïî*ïîïîïýîï*îúïîîïïîîüïîîïï+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿúOPPQPQQýRQRRýSRSSTþSTTUVþUVVüWVVWWýXOPPýQPQQüRQQRRýSRSSýTSTTýUTUUVþUVVþWVVWýXWPPþOPPQýRQRRýSRSSTöSTTUTTUUTUUVþUVVWþVWWýOPOOPûQPQPQQRþQRRúSRSSRSSTSTýUTUUýVUVVWþPOOPúQPPQPQQýRQRRSýTSTTüUTTUUüVUUVVüWVWOOýPOPPþQPPQùRQQRRQRRüSRRSSTþSTTUþVUUVþWVVùNOOPPOPPQúRQQRQRRSþRSSúTSSTSTTýUTUUVùWVVWONOOûPOPOPPQþPQQþRQQR STUþTUUýVUVVNOúPOOPOPPQýRQRRSþRSSúTSSTSTTùUTUTUTUUV÷UVVNONONOOPQþPQQûRQRQRRSTSTUVþUNNOþNOOPûQPQPQQúRQQRQRRSûTSTSTTUøVUUVUUMNN OPQûPQPPQQRSRSTúUTUUVUUþVNNONOPQPQRùQRRSRRSSýTSTTUTUýVMNNOþNOOüPOOPPýQPQQRþQRRüSRRSSTþUTTUûVMNMNNúONOONOOPüQPPQQüRQQRRýSRSSTüSTSTTUüNMMNN OPQRþQRRSRSüTSSTTþSTTõUTUTTMMNMMNNOþNOOüPOOPPQPQRSRSTûSTSSTTUMúNMNMMNNõONONOPOPPOPPQýRQRRþQRRûSRSRSSTòMLMMNMNMNMNMNOOþNOOPûQPPQPPQüRQQRRSþRSSüTSSTTüULLMMNüONNOOPþOPPQüRQQRRýSRSSTLýMLMMýNMNN OPûQPQQRRþQRRSýTSTTLMN OýPOPPüQPPQQRQRSüTSKLLMüLMLMMNüONNOOýPOPPþOPPýQPQQRýSRSSúTSSTKLLMýNMNNOPüQPPQQRþQRRSþRSSþKLLMLMNþMNNýONOOPOPQüPQPQQRþQRRûSRSRSSûLKLKLLMþLMMþNMMNþONNOPýQPQQûRQRQRRSýRSKKLúMLMMLMMüNMMNNOýPOPPQþPQQRûSRRSKKüLKKLLûMLMLMMNMýNMNNüONNOOüPOOPPýQPQQRSKLþKLLMüNMMNN OPQþPQQRþQRRKLþKLL MNüONNOOüPOOPPüQPPQQRúKJJKJKKýLKLLMþLMMNüONNOOýPOPPQRQýRJKKüLKKLLMNüMNMNNüONNOO PQRúQRQRRJJýKJKKLþKLLM÷LMMNMNMMNNOþPOOýPOPPýQPQQRJKLþKLLþMLLûMLMLMMûNMNMNNOPûQPQPQQýRQJJýKJKKLþMLLMúNMNMMNNOþNOOüPOOPPQPQJKúJKKJJKKLKLþMLLMN OýPOPPýQPQQüRJIJJþKJJK LMüNMMNNýONOOþPOOPùQPQQPQIIJþIJJýKJKKLúMLLMLMMüNMMNNùONOONNOOPüQPQIIýJIJJýKJKKýLKLLûMLMLMMóNMNMNMNNONONOOPüOPOPPþQIIJKùLKKLLKLLúMLMLLMMýNMNNOþNOOýPOPPþQIIýJIJJüKJJKKýLKLLMþLMMþNMMNONOPOPIHøIJIIJIIJJüKJJKK÷LKKLKLLKLLýMLMMNüONNOOPOPHIýJIJJôKJKJKKLLKLKLLM÷LMMNNMNMNNýONOOPHþIHHIJüKJJKKLúMLMLLMMýNMNNüONNOOPüOPOHHüIHHIIJþKJJýKJKKþLKKLM÷LMLMMNMMNNúONNONOOþPHHIüJIIJJKúJKLKKLLýMLMMNOPHIþHIIJþIJJüKJJKKLKLýMLMMýNMNNúONOONOOýHGHHýIHIIJýKJKKLMþLMMNOüNOOGGHIüJIIJJúIJJKJKKùJKKLKKLLýMLMMNùONNOONGG HIþJIIJýKJKKýLKLLMþLMMüNMMNNOþNGGüHGGHHIüHIIJJIJKLüMLLMMNFGHýIHIIJKþJKKLùMLMLLMNNþMNNOGHýIHIIJKþJKKúLKLLKLLMþLMMNûFGGFGGûHGHGHHIúJIIJIJJüKJJKKýLKLLýMLMMNFGýHGHHýIHIIJK LýMLMMNþMFFýGFGGóHGGHGHHIIHIHIIýJIJJýKJKKLMLMNþEFFýGFGGôHGHGHIHHIHHIIJIJûKJKJKKLýMLMMüEFEFFGúHGHHGHHýIHIIJIJûKJKJKKLüMLLMMFEFGñHGHHGHGHHIHIIHIIþJIIJKþJKKûLKLKLLýMLMMýLMEEFGHýIHIIJýKJKKýLKLLMEöFEFFGFFGFGGüHGGHHþIHHIþJIIýJIJJKLþKLLþMEEFüGFFGGûHGHGHHIJýKJKKLþDEEüFEFEEFýGFGGüHGGHHIHIýJIJJKJýKLKKýLKLLüEDDEEüFEEFFþGFFGHýIHIIJüKJJKKùLKLLKKLLYZü[ZZ[[\þ[\\]þ\]]^_û^_^^__`þXYYZþYZZ[þ\[[\ü]\\]]^þ]^^_þ^__ú`__``YYZü[ZZ[[\þ[\\þ]\\ý]\]]ú^]]^]^^ý_^__`YþZYYZ[\ü[\]\\]ù^]^]^]^^_þ`__þ`XXýYXYYZþYZZ[þZ[[þ\[[\[\]þ\]]ú^]]^]^^ý_^__XYûXYYXYYZþ[ZZ[\ú]\]]\]]^]^_þ`XXYüZYYZZù[Z[Z[Z[[þ\[[\]þ\]]^þ]^^_^_ýXWXXYZ[þZ[[\þ[\\ý]\]]ü\]^]]^þ]^^_ù^_XXWWXXúYXYYXYYZ[ù\[\[\[\\]þ^]]ý^]^^þ_^^_WXþYXXYþZYYZû[Z[Z[[\þ[\\ý]\]]÷\]^]]^]]^^WXûYXYXYYZþYZZü[ZZ[[\þ[\\]þ\]]ú^]]^]^^_WýXWXXûYXYXYYûZYZYZZ[þ\[[\ü[\]\\]^WüXWWXX YýZYZZþ[ZZ[\ü[\]\\]^þ]^^VWþXWWXýYXYYZþYZZý[Z[[\]þ^]]ü^WVWWýXWXXþWXXYXYýZYZZù[Z[Z[Z[[õ\[\\[\\]\\]]^ú]VWVVWWXûWXXWXXYZ [ý\[\\þ]\\ú]\]]^]]üVWVWWXWXYþXYYýZYZZô[ZZ[[ZZ[\[[\\]þ\]]VWþVWWüXWWXXüYXXYYZþYZZû[Z[Z[[\]VWþXWWXþWXXYþXYYZþYZZû[Z[Z[[\þ[\\]\]VþWVVWXüWXWXXYXY Z[\ú]\]UUVVüWVVW WXYþXYYþXYYZý[Z[[\]UüVUUVVWþVWWþVWWXþWXXYúZYYZYZZ[þ\[[ý\[\\]UüVUUVVüWVVWWXüWXWXXYþXYYZþ[ZZ[\UýVUVVýWVWWXþWXXYXYZþYZZ[ý\[\\þ[\\ UVWþVWWXYýZYZZù[Z[[ZZ[[\ù[\\TUTUUVþWVVWûXWXWXXY Z[\TUûVUVUVVüWVVWWûXWXWXXüYXXYYZYZý[Z[[þZ[[\ûTUUTUUVþWVVWXYZþ[ZZ[\TüUTTUUýVUVVWúVWWXXWWýXWXXYZþYZZ[Z[TU VWVWXYþXYYýZYZZ[TUTUüVUUVVüWVVWWXYüZYYZZù[ZZ[[STTýUTUUûVUVUVVúWVWVVWWýXWXXýYXYYZú[Z[STSSTUûVUVUVVWüVWVWWòXWXWWXWXYXXYXYYZûYZZYZZü[ZZSSTýUTUUVUVWúXWWXWXXYþXYYZü[ZZSSTüSTTUUþTUUüVUUVVþWVVWXYþXYYZûYZYYZZSùTSTSTSTTUþTUUVWúXWXWWXXýYXY YZý[RSSTþSTTýUTUUVüUVUVVWþVWWþXWWXùYXXYYXYYZýSRSSTUñVUVUVVWVVWVWWVWWXYXýYXYYZSùRSSTTSTTUTUVþUVVWXüYXXYYZùRSRRSRSSTSTûUTUTUUVþWVVWüXWWXXYRSþRSSTSýTUTTUVúWVVWVWW XYüZYZRRýSRSSTU÷TUUTUUVUV VWýXWXXYþXYYþZRRþSRRSTþSTTUüVUUVVþWVVWXþWXXY RSTþSTTüUTTUUVUVüWVVWWXþYXXYüQRQRRSúTSTTSTTUþTUUùVUUVUUVVýWVWWýXWXXþYQQRýSRSSýTSTTúUTTUTUUVWþVWWþXWWXQüRQQRRýSRSSüTSSTT UýVUVVWþVWWúXWXXWXXüYXPQQRSþRSSTüUTTUUVûUVVUVVWþXWWûXWXXQQRþQRRüSRRSSûTSTSTTUVUVWþVWWûXWWPQQüRQQRRýSRSSTþSTTøUTUTUUTUUVUVñWVVWVWWXXWXXPPQQýRQRRQRSþRSSTSTúUTUTTUUýVUVVúWVWVVWWXPýQPQQþRQQûRSRRSSþTSSùTSTTUTUUýVUV VWøPQPPQQPQQüRQQRRSTöSTTUTTUUTUUVøUVUVWVWVVWPQþRQQRþQRRSRSTþSTTüUTTUUVüWVVWWPQRúSRSSRSSýTSTTUVUVWýPOPPûQPQPQQRQRSùRSRSRSTTûSTTUTTUVþUVVWþOPPýQPQQúRQQRQRRüSRRSSTSTýUTUUVWOPQüPQPQQRSüTSSTTùUTUTUUV VOýPOPPQRûQRQQRRSþTSSTûUTUTUUþVUUV÷WONOPOPOPPùQPQPQPQQüRQQRRSTSTUüVUUVVýONOOPþOPPýQPQQûRQRQRRSTUýVUVVþNOOýPOPPýQPQQþRQQøRQRRSSRSS TýUTUUVûNONNOOPþOPPQûRQRQRRýSRSSTUþTUUVùNOONONOOþPOOPûQPQPQQRQRSúRSSTSTTûUTTUTTU÷ðññððñððññùðñðññðññðýñðññþðñ ñþòñ ñòûñòñðññðñððññðññðñðñðñðñðññþòññþòññòýðñððüñððññýðñððúñðñððññúðñðñðññòñðþñððñðîñððñððñðññððññðñðññþðññþòññþòññðþñððñðûñðñðññýðñððñþðññòñðúñðñðñððþñððñüðñðññþðñ#ñðþñððýñðññðûñðññððñþðññþðññþðñ ñþòññýòðññðþñððþñððñüðñðññðòñðññððññðññððñ ñþòññðþñððñðþñððñúðñðñðññðûñðññððñð ñ÷òñððññðñððþñððøñððñððñððñðñùðññðñðññ ðñûðññðññûðññðññùðñðññðññþðññþòð ðñýðñððñþðññùðñðñððññûðññðññþðññþðññþòððñðüñððññðýñðññûðñððññüðñðññ ðñðñôðñðñðññðñðñððñðñþðññûðññðñ ñðñðñðþñððñðñðñþðññþðññþðññðñðþñðððñðñððññðññðñðñðññûðññðññðþïððñðüñððññðñþðññðñþðññþðññûðññïððþñððþñððþñððñöðññðñðññðññþðññûïððïððñôðñððñðñðñðñððúñðñððññøðññðññðññðñþïððûïððïððòñððñðñðññðñððññþðññüðñðññðþñððñðñþðññéðññðñðñððñððñðñððññðñïððþïð ðþñððûñðñðññðñîðñðñðññðññðñðññððññýðïððøïðïïððïð ðþñð ðñ÷ðññððññðññþðññüðïïððïðûñððñððñ÷ðñððñðññððýñðññüðññððþïð ðþñððþñððûñððñððñýðñððñðñüðñðññðþñððüïðïððþïððþñð ðñðúñððñðññðñûðñðñððñðûïððïððûïððïððþñððþñððüñðñðð ñøðñïïððïððþïððñýðñððþñððñîðññððññïððïðïððïïððþïððï ðþñððüñðñð ðñðñýðïððþïððüïðïððúïððïïððñðýñðññðþñððñïúðïðïïððþïððûñðññððñðñðñøðïðïðïðïïðüïðïððþïð ðþñð ðþñððòñððñððññðïððïððúïðïðïððþïð ðþñð ðþñððõñððñðññððñððïýðïððïðïðþïð ðþñð ðñðúñðññðññûïðïïððøïððïïðïððïðõïððïððïððïððþñððñðýñïððóïððïððïðïðïðïïýðïððþñððñðùñððññðïïðïûðïðïððïðûïððïððúñðñðñðððñðñðñïðïðïïððïïððï ðûïððïððþïððþñððñðúñðñðñððüïððïïðúïððïïððï÷ðïïðïððïððþñððþñððþñððïüðïïððïýðïððûïððïððûïððïððíñðññððññðññðññïïððïïðïõðïððïïðïðïððûïððïððþïð ðþñððþñððýïðï ïðïðþïððûïððïððþïððþïððñððñðïðïïðïðïïððïððïüðïðïïðûïðïïððþïððþïððþñððþñððïùðïðïïðïïðïðþïððþïððñûðñðñððïðïþðïïûðïðïððüïðïððþïððïðþñððþñïïðïüðïïððïôðïððïððïðïïððúïðïðïððûïððïð ðüñððïïüðïðïïþðïïðýïðïïðþïððþïððñøðïðïïððïïðýïðïïðýïðïïõðïððïððïðïððþñððïþðïïðïüðïðïïðûïððïððþïððúïððïïð ðñþðï ïðöïðïïðïðïðïïýðïððïð ïþðïïððïððïðïïðïððïðïðïïðïð ïþðïïýðïððïð÷ïðïðïðïïððûïðïïððþïððþïð ðïþðïïþðïïðïðöïðïððïððïððþïððïðþïððþïð ðïþðïïûðïïðïïúðïïððïïðþïððïðþïððþïððïþðïïþðïïùðïðïðïððïýðïððþïððïþîïïðïðþïððþïððüïðïððþïððþïððïþðïïþðïïðøïððïððïððþïððþîïïþðïïð÷ïððïïððïððïðþïððþïððïðïþðïïòðïððïððïïððïïððüïððïïðïðïþîï ïðïðþïððûïððïððþïðð÷ïððïððïîïïþðïïþðïïþðïïðüïðïððøïððïîïîïïþðïïûðïïðïïðïðõïðïðïððïðïððûïðîîïïûðïïðïïûðïïðïïðïðþïððïðøïðïîïîîïïþîïïùðïïððïððþïððþïððÿþWXXYZ[þZ[[û\[\[\\ý]\]]þ\]]ý^]^^þ_^^_ýXWXXYZû[Z[Z[[\[\ý]\]]ý^]^^ý_^__WXùWXXYXXYYZþ[ZZ[ý\[\\ý]\]]û^]^]^^_û^__XWWXYüXYXYYüZYYZZ[\þ[\\û]\]\]]û^]^]^^ü_^_WW XYZ[\]^]^û_^__WW XYZ[\[\ý]\]]ý^]^^ý_^WWýXWXXýYXYYZþ[ZZ[\þ[\\]þ\]]^WþVWWýXWXXýYXYYýZYZZ[þ\[[ý\[\\]þ\]]^ý]^VVýWVWWüXWWXXþWXXYZþYZZü[ZZ[[\[\]þ\]]^VøWVVWWXXWWXùYXXYYXYYZYZ[\û]\]\]]ý^]VVWXüYXXYYþZYYZý[Z[[ý\[\\û]\]\]]^ VWýXWXXþYXXYZ[þZ[[ý\[\\]\ù^]]UVUVVWVWþVWWþXWWXYZý[Z[[\þ]\\ý]\]]U VWXYXYýZYZZ[þ\[[\õ]\]]\]]UVUVVþUVVWXþYXXYZþYZZ[þZ[[ú\[\[[\\]þ\UUVûUVVWVVWùXWXWXWXXYZþYZZù[Z[\[\[[\]ý\]UUVWüVWVWWþXWWXYþXYYZþYZZý[Z[[ú\[\\[\\÷]TUUTVUUVVþWVVWöXWXWXXYXXYYýZYZZ[þ\[[\UýVUVVWþVWWýXWXXûYXYXYYZöYZ[Z[Z[[Z[[ü\[[\\ùTUTTUTUUVüWVVWWXYüXYXYYýZYZZý[Z[[ú\[\TUTTUVþUVVWXþYXXYüZYYZZ[þ\[[T UVüWVVWWXYüXYXYYZ[\þ[TTUúVUVVUVVWüXWWXXýYXYYüZYYZZü[ZZ[[û\TTSTTþUTTUVWVWýXWXXýYXYYZý[Z[[STüUTTUUüVUUVV WXþWXXYüZYYZZú[Z[[TSSþTSSTUþTUUVûWVWVWWXWýXYXXYZ[SþTSSTþUTTUüVUUVVüWVVWWXþWXXYþXYYþZYYZû[ZZ[SSüTSSTTúUTUTTUUVþUVVûWVWVWWþXWWýXWXXYXYZSúTSTTSTTýUTUUVþUVVWýXWXXþYXXYúZYZYYZZþRSSTUVUVþWVVWýXWXXYþXYYZSRSTûUTUTUUýVUVVüWVVWWXYXYZYþZRRýSRSSûTSTSTT UV WX YýZQRRüSRRSSTþSTTUþTUUVWüXWWXXYXYüZRQRRýSRSSTüSTSTTUþTUUVWXþWXXùYXXYYXYYüZRQRRýSRSSýTSTTûUTUTUUúVUUVUVVWVóWXXWXWXXYXYXYYQRS TUýVUVVWûXWXWXXûYXXYQQRýSRSSTUüTUUVVþUVVWþVWWXüYXYQQRþQRRýSRSSTUVUVýWVWWûXWXWXXYQRþQRRýSRSSTþSTT UVWúXWXXWXXþPQQýRQRRþSRRSTUþTUUVüUVVW WXýYPQQRùQRRSSRSSüTSSTTUþTUUVþUVVWVWXùWXPQQPQQüRQQRRüSRRSSþTSSTüUTUTTUýVUVVWþVWWùXWXXWXPPøQPPQQRQRRþQRRúSRRSRSSTþSTTUVýWVWWûXWWXPPýQPQQüRQQRRSüTSTSSTUTùUTUVVUVVWþXPPüQPPQQþRQQRSþRSSTüUTTUUýVUVVýWVWWýXOPPQþRQQRûSRSRSSúTSSTSTTùUTTUUTUUVþUVVôWVWWVWWOPOOPPþQPPøQPQQRRQRRSþRSSúTSTTSTTU VWOúPOOPOPPQPQüRQQRRSüRSRSSTüUTTUUúVUVVUVVWýVWOOPQRþSRRSTþSTTýUTUUúVUUVUVVüWVNOOP÷OPOPPQQPQQþPQQRSTþSTTýUTUUVWþVOOPOPQRþQRRSýRSRRS TUùVUVUVUVVûWNONOOòPOOPPOPPQPQPPQQþRQQRSþRSSTþSTTUûVUVUVVNOPQþPQQRùSRSRSRSSTþSTTUþTUUüVUVNNOùPOPOPQPPQúRQRRQRRSþRSSTUVNúONNONOOúPOPPOPPQRþQRRSýTSTTUöTUUVVUUNMNNýONOOþPOOPüQPPQQRýSRSSýTSTTUTUMNOüPOOPPüQPPQQRQRSúTSTSSTTUùVMNMNMNNOýPOPPQüRQQRRSTUTUMýNMNN OPýQPQQþPQQRSþRSSþTSSTúUTTUUMMNüONNOOýPOPPþQPPýQRQQRýSRSSýTSTTUþLMMNúONONNOOPþOPPQýRQRRSþRSSTþSTTýULMMþNMMýNMNNOþPOOPüQPPQQRSTøUTMLMMLMMýNMNNúONOONOOýPOPPQüRQQRRSþRSSTMúLMMNNMMNúONNONOOPQRSþTSSTý`a``abþcbbýcbccdþeddýedeeýfeffþgffgþh``abúcbcbbccdþeddýedeefgþfgg`ýa`aabþabböcbcddcddcddõededdeefeeffýgfggþ_``ýa`a abcþbccdcýdcddüeddeeýfeffgfgþ_``ýa`aaþ`aaübaabbcûdcdcddûededeefþeffùgf__`_``ýa`aaþbaabýcbccdcdþeddeüfeeffý_`__`aþ`aabþabbcüdccddeûdeedeefùeffgff__`_`ùa``aa`aaýbabbcýdcddcdþeddefþeff_û`_`_``úa`aa`aabüababbcüdccddùededefeef_ý`_``ýa`aabcûbccbccdücdcddþeddeúfef_^__`üa`a``abúcbcbbccdþcddüeddeefû^__^__þ`__`ýa`aaýbabbþabbcûbccbccýdcddeüdedeeýfe^^_ü`__``ù_``a``aa`ababýcbccdúeddedee^_ý`_``úa`a``aabúabbcbccþbccûdcdcdde^ù_^^__^__ü`__``aþ`aaübaabbýcbccdüeddeeþ]^^ý_^__`_ü`__``ýa`aabþabbþcbbcdcüdccddeþ]^^ý_^__ý`_``ùa``a``aabþabbûcbcbcc dýe^]]^_þ`__`a`aúbaababbñcbcbbccdcdccdcdd]^ü_^^__þ`__`ýa`aabûabbabbcdcýdcddûe]]^]]^ü_^^__ý`_``aþbaabcþbccd]^]^_^_ú`_`__``ýa`aaûbababbcdúcdd]\]]^ý_^__`üa``aaýbabbücbbccdcüd\\]]^þ]^^ý_^__þ^__ý`_``ýa`aabcübcbcc]ü^]]^^_þ^__`þ_``aþ`aaýbabbcþdcc\ý]\]]ü^]]^^ý_^__`þ_``úa``a`aabýcbcc\û]\]\]]ù^]]^^]^^ü_^^__`þa``aþbaabc\]\]ô^]^]^^__^_^__ý`_``þ_``aþ`aabþabbcúbcc\[\\]÷^]]^^_^_^^_ý`_``a`ýa`aaùbabababbc\[\ú]\\]\]]ü^]]^^û_^_^__ù`__``_``aübaabbòabbcbbcb[[\\[\\ý]\]]þ\]]^]^_^_`ùa``aa`aabýcb[[ü\[[\\]ü^]]^^_ø^__`_`_``abþabb[\þ]\\]ü^]]^^_`ýa`aabþZ[[ý\[\\ú]\\]\]]û^]^]^^ü_^^__`_`þa`` aøbabZ[[Z[[\ü]\\]]^]^ý_^__ù`_`_`_``abþaZZ[ü\[[\\]þ^]]^ý_^__þ^__ý`_``aübaaZZ[þZ[[\]þ\]]^÷]^_^_^_^__`ùa`aa``aaZ[ñ\[\\[[\\]]\]]\]]^þ]^^_ `ýa`aaZþ[ZZ[ý\[\\ý]\]]ü^]]^^û_^^_^^_`úa``a`aaþYZZý[Z[[þZ[[\[\ý]\]]ú^]]^]^^_`þ_``÷a``a`aZYZZ[þZ[[\þ[\\û]\]\]]^ü]^]^^û_^_^__ü`__``a`üYZYZZò[Z[Z[Z[Z[[\\[\\þ]\\ý]\]] ^_ `YZ[ýZ[ZZ[ý\[\\ü]\\]]ü^]]^^_ú^__^^__`þ_``aYZ [\ý]\]] ^_`þ_``þXYYZ[Z[\þ[\\þ]\\] ^_ý`_``óaYYXYYZZYZZYZZý[Z[[\þ[\\þ[\\]\]ú^]^^]^^ü_^^__÷`_`_`YXXYYZ[ \]ü^]]^^û_^_^__õ`__``_XXYXYYZYZ[\ö]\\]]\\]^]]^þ_^^ý_^__ø`_`YXYXYYûZYZYZZ[þZ[[\[\þ]\\]^þ]^^_ý`_XXYþXYYZ[þ\[[\þ]\\]ü^]]^^ö]^^_^^__^__XYþXYYZþYZZ[ü\[[\\ ]^ü_^^__ýXWXXYþXYYýZYZZý[Z[[\]û^]^]^^_ü^_WXXüYXXYYþZYYZò[ZZ[[\[\\[\\[\\ý]\]]ý^]^^ý_^__WXùYXYXYXYYþZYYZ[üZ[\[[\]þ\]]^_þWXXYþXYYþZYYZ[ú\[[\[\\]^WXûWXWXYYüXYXYYZ[þZ[[\þ[\\ ]^WXþWXXYZþYZZ[Z[ \]þ\]]ý^]^^VWûXWXWXXYZ[þ\[[\þ]\\]ú^]^^]^^ýWVWWýXWXXýYXYYýZYZZþYZZú[Z[[Z[[\ü[\[\\ü]\\]]^VWúVWWXWXXþYXXYZ[\þ[\\]þ\]]û^]^VWWøVWVWXWWXXýYXYYþZYYZþ[ZZ[\[\ü]\\]]VýWVWWXWXYXYüZYYZZ[þZ[[ý\[\\ý]\]]VWýXWXXþYXXYZü[ZZ[[ú\[\[[\\]UVþWVVýWVWWXþWXXYZYZý[Z[[þZ[[ú\[\\[\\]ú\]VVUVVWþVWWXWXøYXYYXYXYYZþ[ZZ[þ\[[\]þòññòûñòññòòþñòòþóòòüóòóòòóòýóòóóòþñòòñòñòþñòòüñòñòòþóòòüóòóòòóúòóóòòññðòññòññòñòññòòññòòüñòñòòþñòòþóòòþóòòöóòóòòóòóòóóþòññòþñòòñòñòòñòññòñòòñòòñòòþñòòþóò òþóòòñòöñòòñòññòòññòòññòññòñòòñòñò òþñòòþóòòûóòòóòòþóòòñþòññòñùòññòòñòòñòþñòòþñòòþñòò÷óòñòòñòòññõòñòñòñòññòññùòñòñòñòòþóòòþóòòñþòññðòñòòñòòññòòññòñòòþñòòþñòòüóòóòòûóòòóòòþóññòñüòññòòþñòòñòúñòòññòòþñò òüóòóòòùñòññòòññúòñòññòòúñòñòòññòñòþñòòûóòòóòòûóññòññòñûòññòññ÷òññòñòñòññòþñòòóþòññøòñòñòñòññòñýòñòòñòþñòòþñòòñòñþòññûòñòòññòþñò òþñò òþóòòñøòññòññòññòñòñòþñòòþñòòñþòññþòññûòññòññüòññòòñ òüñòñòòþñòòþñòòñòüñòòññòðñòòññòñòòññòñòñò òþñòòñþòññüòñòññòþñòòüñòñòòúñòòñòññòþñò òñüòñòññþòññþòññýòñòòñòþñòòþñòòþñòòñþòñ ñòñòñòñùòñòòññòòþñòòñ÷òñòññòñòññýòñòòñþòññòûñòññò òñüòñòññôòñòññòòñòñòññòþñòòúñòñòñòòüñòñòòþðññþðñ ñþòññýòñòòñþòññòþñòòþñòòýñòññþðñ ñùòññòñòññòñøòññòñòòññòþñòòùñòññððññþðññþòññòüñòòññýòñòòþñòòõñòòñòññòòñòòñûðññðñ ñöòññòñòññòññüòñòññòúñòòññòòüñòñòòñþðññþðñ ñþòññôòññòòññòñòòññúòññòñòòùñòòñòòññþòññöòñòòññòòñòòþñòòûñòòñòòüñòòññþðññòóñòñòñòññòòñòññòñðýñðññþðñ ñþòññþòññòñòñëòñòñòòññòòñòñòñòòñòòññûðñððññüðñðñ ñþòññøòññòñòòññò÷ñòñòòñòñòòñòþñððýñðññûðññðññþðññþòññòñòýñòññýòñòòüñòòññòñð ñþòññòñþòññòñöòñòñòòñòòññþòññþðññþðññüðñðññþðññþòññþòññò÷ñòññòññòññþòññõòñòòððññðñððùñðññððññþðññýòñòòñòþñòòõñòñòñòðñððññþðññðñþðññþòññòññòòññòññòñòñòñððñðñüðñðññþðññòñòñþòññðñ÷ðñððñðñðññð ñþòñ ñþòññòñòðþñðð ñþðññðñþðñ ñùòññòñòññþòññüòñòññøòñòòððñððúñðññðññðñòóñòññòòññòñòòññðñþðññþðññòñþòññþòññýðñððþñððñðýñðññðñþòññúòññòòññúòððñðññðñðûñðññððýñðññüðñðñ ñþòññùòññòñòññúòññòðññôðñððñðñðññðññþðññðñûòññòññþòññüòññð ðñðñðñðñþòññüòñòññøòñòñòðñððþñððñöðñðñðññððññùðñðññðñ ñòñþòññýòñððñðûñððñððñþðññòñûòññòññðñýðñððûñðñðññðýñðññþðññþðññòñúòññðñððñþðññðñðúñððñðññûðñððññþòññüòñòññðþñððõñðñððñðñððññúðñðñðññþðññûðññðñ ñûòññòññðþñððûñðñðññþðññðöñððñðñðñðñ ñþðññþòññüòññððþñð ðùñððñðñððñþðññþòññðñðñðñþðññðüñððññþðññþðññýòñð ðñðþñððñðòñððññðññðññððññþðññðþñððüñððññðøñðññðññðð÷ñðñðññððññðþñððþñððüñðñððñðüñððññþðñ ñðûñððñððøñðñðñððññüðñðññûðñððññþðñ ñðñýðñððñðñðúñðññðññþðññþðññþïððûñððñððúñðññðññüðñðññþðññ ðñøðñðñðññððûñðññððñðñúðññðñððñðñðùñðñððñððñðñð ñþðññþðññðñðûñðññððñüðñðññþðññðþñððñýðñððôñðññððñðñððññþðññðþïððûñððñððûñððñððñð÷ñðññðññðññüðñðñ ñ ðþïððþñððñöðññððññððññþðñÿþ_` `aýbabbcþbccýdcd deýfeffgþfgg_ý`_``aübaabbýcbccýbcddþcddþeddýedeefþeffg_ü`__``üa``aaýbabbcübcbccdþcddeüdefeefûgfgg__ý`_``aýbabbùcbbccbccdþcddýedeefþefføgffg__^__`_`ýa`aaübaabbþcbbcdþcddeþdeef_ `aúbabaabbýcbccúdccdcddefefýg^__û`_`_``abcbýcbccþdccdefeüfef^^_`aþ`aabüabbccýdcddefef^_`þ_``aùbaabaabbýcbccüdccddefþe^^_ø^_^__`_``þa``abýcbccûdcdcddeþdeeûf^^]^^_þ^__ý`_``üa``aabþcbbcdücdcddýedeeþ]^^ü_^^__`ù_`_`_`aaþ`aabùcbcbcbccýdcddþedde^ö]^^]^^_^^__`_`ûa`a`aaúbabaabbücbbccûdcdcddöedeedee]^]]^_þ^__`þ_``abcdþeddþe]]^_ `ùa`aabbaabcþdccýdcddeû]\]^]]^þ]^^û_^_^__ý`_``aýbabbþabbócbbccddccddcdd\ý]\]]^þ]^^_`aýbabbc÷dcdcdde\]]ý\]^ ^ý_^__`ü_`_``ûa`a`aabýcbccdþcdd\]ý^]^^ý_^__ú`_``_``ababcbc÷dcd\\]]\]]þ\]]^_þ^__`aûbababbcþbccdý\[\\ü]\\]]^þ]^^ý_^__`a`abûcbcbccûd\\[\\ü]\\]]^ú_^__^__ `abþabbcþbcc[\þ[\\]ý^]^^ü_^^__þ`__`üa``aabaùbcbbcbccù[\\[\[\\]ù\]]^]]^ ^_ý`_``ýa`aaúbaababböcbcbcc[\[\\]þ\]]ü^]]^^_û`_`_``ýa`aababc[\þ[\\]þ^]]^ú_^__`__`ýa`aabücZZ[[ý\[\\ü]\]\\] ^_ `aýbabb[\]^_ `aþ`aaþbaabZ[\þ[\\]þ\]]^þ]^^_^_ü`__``aöbaabbZ[ZZ[[\ý]\]]÷^]]^^_^^__þ^__û`_`_``abZ[\ý]\]]^_`û_``_``ûa`a`aaZ[Z[\þ[\\ý]\]]^ü_^^__þ`__`a`aZ[Z[ý\[\\]^]^þ_^^_þ`__`úa`aa`aabYZú[Z[[Z[[\þ[\\ý]\]]^þ]^^ü_^^__ü`__``aþZYYZ[Z[\þ[\\]þ\]]^ý_^__ý`_``aö`aYYZZYZYZZ [\ù]\\]\\]]^_^_`þ_``ýa`YYZ[þZ[[\ý]\]]ý^]^^_þ^__ý`_``YþXYYZý[Z[[\]^ý_^__`þ_``þXYYýZYZZý[Z[[ý\[\\]\]ü^]]^^_^_ý`_``ûXYYXYYüZYYZZ[þZ[[ý\[\\ü]\\]]^]^ _`XYZþYZZ[þZ[[\ý]\]]^þ]^^_`þ_XXYXYúZYYZYZZ[û\[\[\\ý]\]]ý^]^^_`þWXXþYXXYúZYYZYZZ[þZ[[ý\[\\]ü\]\]]^þ]^^_þ^__ü`_`XXYZùY[ZZ[Z[[\ú]\\]\]]þ^]]^_þ^__`þWXXYþXYYýZYZZþYZZ[ú\[\\[\\þ]\\ý]\]]^þ]^^_WXþWXXYþZYYZ[\þ[\\]þ\]]ý^]^^_ù^_WWXWXXûYXYYZZüYZYZZ[þ\[[ý\]\\]^_WüXWWXXøYXYXYYXYYZ[Z[ý\[\\ü]\\]]ý^]^^þ_^^WXüWXWXXúYXXYXYYZû[Z[Z[[\[\]û^]^]^^ü_VVWWXYXYZø[Z[Z[ZZ[[\[\ý]\]]ü\]^]]^VWþXWWXYXýYXYYýZYZZü[ZZ[[\]þ\]]^VýWVWWýXWXXúYXYXXYYZYZü[ZZ[[÷\[\[[\]]\\]^VþWVVWýXWXXýYXYYþZYYZ[Z[\þ[\\]\]^þUVVüWVVWWúXWXWWXXYXYþZYYZ[ü\[[\\]þ^VVWþVWWùXWXWXWXXYúZYYZYZZ[\]\ý]\]]VUVWúXWXXWXXYþZYYZþ[ZZ[\]VþUVVüWVVWWXüYXXYYýZYZZü[ZZ[[\þ[\\ý]\]]UýVUVVøWVWVVWVWWXþWXXYXYõZYZZYZZ[ZZ[[\[\]UVûWVWVWWXþWXXYýZYZZý[Z[[\ù]\\]]TUUûVWWVWWüXWWXXþYXXYûZYZYZZ[þZ[[\[\ý]TUUVþUVVýWVWWüXWWXXYòZYZYYZZ[Z[Z[Z[[\TUüVUUVVWþVWWXþWXXþYXXYúZYZZYZZ[ü\[[\\TUöTUUVUVVUUVVWþVWWýXWXXYZ[\TýUTUUVUVWþVWWXYþXYYZþYZZ[Z[\[ghúihihhiiüjiijjúkjkkjkkl÷mllmllmlmmûnmnmnnoýghgghúihhihiijúkjjkjkk lmûnmmnmmnogûhghghhiühihiijkjkùlkklkkllmýnmnngýhghhiýjijjkþjkklþkllmþlmmngühgghhýihiiýjijjùkjkjkjkklþkllümllmmnmngýhghhøghihiihiiùjijjiijjúkjjkjkklmþlmmngüfgfgghijþkjjkülkkllþkllmónmmnngffgfgfggýhghhûihihiijþijjkjklþmllmýnmffügffgghþghhiþhiijükjjkklklømllmmnmffýgfggúhghhghhiùjiijjijjûkjkjkkýlkllmfgþfggþhgghúihiihiiýjijjkþjkkþlkkülkkllýmlmmþeffúgfggfgghüihihhijkþjkkýlkllmfþeffügffggühgghhýihiihiújiijijjkjklþkllmùleeffeffþgffghiþhiiûjijijj klþmlleýfeffýgfgghþghhýihiijýkjkkùlkkllklleúfeffeffg÷hghghhihiiþhii jkýlkll÷edefefeeffghþihhiøhijjijijjúkjkkjkklklþdeefefýgfg ghijþijjükjjkkldeýfeffgþfgghiühihiiýjijjkjkýlkddeûfefeffghghúihihhiijùkjkjkjkklûeddeddeýfeff÷effgfgffgghýihiiújijiijjýkjkkþlddeüdefeeûfefeffg hýihiiöjiijjijjkjjýkjkkdýedeeþfeefgþfgg hýihii jkþjddýedeeýfeffgþhgghijijkcdúeddedeefûgfgfggh iýjijjkcdýedeefefúgfggfgghýihiiþhiiújijjijjýcdccdüeddee fýgfggþhgghþihhijc dýedeefþeffghüghghhiþhiijüijjccýdcddýedeeýfeffügffgg hýihiijýibccüdccddeþdeefüefeffógfggfghghhgghhþihhiöjiijjbcbbccýdcddeþfeefþgffghûghhihhiþjiibcdþcdd efýgfggùhgghhghhihibþcbbcýdcddþcddþeddefgþfggùfhgghghhüihhiiþjbbücbbccüdccddùcddeddeeôfeffeffggffggþhgghiþabbcdûcddcddeþdeeþfeefþgffgûhghghhibcþbccdþcddýedeeüfeeffgþfgghþihhùibabaabbcþbccýdcddefüefeffýgfggüfgghhþghhþihhabþcbbúcdcdcddeþfeeýfeff ghþiaaóbaabbabcbbcbccýdcddýedeeôfeefefeffgfgghaübaabbýcbccüdccddýedeeýfeffgþfgghghþ`aabþabbcbc defþeffgþfgghûgha`aabcbcþdccdüeddeefgfgh`ýa`aabab cdýedeeþfeeýfeffýgfggúhgh`a``abýcbccdúedeedeefügffgg`aþbaabócbbccbcbccdcddefgþfgg`aþ`aabþcbbýcbccþdccdeöfefefeeffggþfggþ_``þa`` abþabbcdüeddeeùfeffeeffgý`_``÷a``aa`a`aaýbabbcdþcddedeýfeffþg``þ_``þa``abcþbccdeýfeffú`__`_``üa``aabcdþcddeþdeeùfeefeeff_`þa``abþabbcdüeddeeúfeefeff_û`_`_``ýa`aaýbabbþcbbcødcdcdccddüeddeefîefeeff_^^__`__``_``aýbab bcødcdccdcddeüdefeefþ_^^_`_`abþabbücbbccdþcddþeddef^_û`_`_``úa``a`aaýbabbücbbccdþedde^ý_^__`þ_``ýa`aabúcbbcbccdcdeþf^^_û`_`_``abþabbcþdccdùededee^^_^_þ`__`ú_``a`aaùbaabbabbûcbcbccúdccdcddeýde^^ù_^^__^__ú`__`_``ûa`a`aaøbababbabbýcbccýdcddøeded^^]^^ú_^_^^__`abúabababbcþbccòdcddcddeddede]]ý^]^^_þ^__ü`__``aþbaabcþbccþdccdþedd]^þ]^^_`û_``a`` abcúdcdccdd]ü^]]^^_`_`þa``aböabbabbcbbccþdccd]ý^]^^_þ^__ `aþ`aaýbabbcþbccþdccdüóòòóóøòóòòóóòóóþòóóþòó óþôóóþôó óþôóóúôóóôôóóòþóòòóò óþòó óþôóóþôóóôóôüóôôóóòüóòòó óòóþòóóþôóóþôóóùôóòòóòóóþòóóüòóòóóøòóóòóóòóóôóô óùôóôôóóòòýóòóóüòóóòòýóòóóþòóóûòóóòóóþòó óôóøôóóôóôôòòóþòóóüòóòóóþòó óüòóòóóüôóóôôóöôóòóóòóòóòòóîòóóòóóòòóóòóòóóòòóóþòó óøôóôóóôôóóþôóóüòóóòòóòþóòòýóòóóôòóòòóóòòóóòóóúôóóôôóóþôóóüòóòóóøòóòóòòóòòóòóþòóóùôóóôóóòòþóòòóøòóòòóòòóóþòó óþôóóúôóôôòóóòóòþóòòþóòò óþòóóþòó óþôóóþôóóþôóóòóòüóòóòòýóòóóþòóóòþóòòóôôóóòóóòòóóòóóòóôòóóòóóòòóòòóóþòóóþòóóþôóó÷ôóóòòóòóòòóýòóòòóóòóòòóòóòóóòòóóþòóóþôóóûôóóôòòæóòóòòóóòòóòòóòóòòóóòóóòóóòòóûòóóòóóþòó óûôóôôóóýòóòòøóòóóòòóòòþóòò÷óòóóòòóòóóýòóòòìóòòóòóòòóóòóòòóòòóòóóþòóóþòóóþòóóòúóòòóóòòõóòóóòóòóóòóóþòóóúòóòóòóóþòó óòûóòòóòòøóòòóóòóòòýóòóóþòóóòóýôóòòóòóòæóòóóòóòóòòóòóóòòóóòòóóòóòó ó òüóòóòòóüòóóòòþóòòúóòóòòóóüòóòóóüòóòó ó òþóòòþóòòèóòóóòòóóòòóòóòóòóòóòóóòóóþòó óòþóòòúóòóóòóóòõóòòóóòóóòòóóþòóóþòóóþñòòþóòòþóòòþóòòóúòóòóòóóòóþòóóòþñòòúóòóòòóóëòóòòóóòòóòòóóòóóòóóòóóòóöòóóòñòñòñò òþóòòûóòóòóóûòóóòóóþòóóþòóóûòóòòóóùòóòóòñòòþñòòþóòòþóò òóòóþòóóþòóóòóòþóòòóòóþòóóòöóòóòóòòóòóóûòóòòóóþòóóýòóòòþóòòûóòòóòòüóòòóóþòóóðòóóòóóòóòóòóóòñòòþñòòþñòòþóòòþóòòóþòóóòüóòòóóòþñòòþñòòþñòòþóòòùóòòóòóòòõóòòóòòóòóóòòóþòóó òøñòòñòòñòòýóòóóòóöòóóòòóóòòóóòþñòòûóòòóòò÷óòòóóòòóòòýóòóóõòóóòóóòóòóò òþñòòùóòòóòóòòúóòòóóòòóõòóòñòòñòññòòþñò òþóòòóòóöòóóòóóòóóòòó÷òóóòóóòñòòúñòòññòòþñòòþñòòþóò òüóòòóóòþóòòýóòóóýòóññþòññòþñòòþñò òóòûóòóóòòþóòòóòóòýñòññûòñòñòòþñòòþóòòþóòòóòóùòóòòóòóóòóýñòññòüñòñòòûñòòñòòóòûóòòóòòóòóòóòñòñòþñòòûñòòñòòøóòóòóòòóóçòóòññòññòòñòññòòñòòññòòñòòþñò òóúòóòòóòòþóòòóøòñòòñòñòòñòþñòòþñòòõóòóóòóòòóóòòøóòòñòòñòòþñòòþñòòþñòòþóòòøóòòóòòóòòñ òúñòñòñòòùñòñòòñòòûóòòóòòóòóòñöòñòòñòñòñòòþñòò÷ñòòñòñòñòòóòúóòòóòññôòñòñòñòòñòòññòþñòòþñòòñòúóòóòóòòóòûóòòóòòüóññòòñüòñòññýòñòòþñòòþñòòþóòòóòýóòññòñþòññòþñòòñòþóòòïóòóóòòññòòñòññòñòòüñòñòòñòüñòñòòþóòòñþòññþòññòþñòòõñòññòòñòòñòòþóòòûóòóòññûòñòòññþòññòøñòñòòññòòþñòòùñòñòòñòòþñòòþóòòóòñüòññòòñþòññòñòñýòñòòñòþñòòþóòòñþòññ÷òñòñòñòòññþòññòøñòòñòòñòòþñòòýóòññòúñòññòññýòñòòûñòññòòþñòòþóòòýóòñ ñúòñòññòòñ÷òññòñòòñòòñòþñòòñ òþóòòñ÷òññòññòòññþòññöòñòòññòññòòñòñòþñòò ñþòññòûñòññòòñýòñòòñòüñòñòòþñòòñòþóòòñüòñòñ ñòñòüñòòññòþñòòþñò òþóñ ñþòññðòññòñòññòñòñòññòòñòøñòñòñòñòòþñòòþóññòñòñýòñòòþñòòþñòòõñòñòñòòñòñòò ñþòññòûñòñòññòúñòñòòññòþñòòþñòòñþðññûòññòññúòññòòññòñûòñòòññ òþñòò ñþòññøòññòòñòññöòñòññòñòñòòþñòòþñòòþñòòñþòñ ñòñòñðòñòññòòñòñòñòññòòÿhiþhi ijkþlkkølkllmllmmünmmnnoþngghijýkjkkúlkllkllm ngþhgghþihhiþhiij÷kjkjkllkllmþlmmýnmnnúonnffggýhghhþihhiýjijjkþlkklþmllümllmmünmmnnúonoffggþhggýhghhüihhiijkülkkllmþnmmnghghiüjiijjükjjkkýlkllùmllmmlmmngþfggþhgghi jk lmnþeffgþfggõhghhgghhihii÷jiijijjkjjklmúlmlmnmmfügffggúhgghghhiýjijjükjjkkýlkllúmlmmlmmüneeffúgfgffgghiþhiiüjiijjúkjkkjkklýmlmmþeffûefgfgghghiúhiijijjýkjkkýlkllmefgühgghh ijþkjjkýlkllûmleeffefghijijkûlklkllþmeeýfeffògfggffgghghgghhùihihihiijýkjkkýlkllmlýedeefügffggüfgghhijkþjkkýlklldefùefggffgghþghhiühihiijkþjkklûdeedeeüfeeffôgfgfgghgghghhýihii jükjjkkløkllddedeeûfefeffýgfggýhghh÷ihihiijijjþijjkülkklldüeddeefgþhggýhghhýihiijôkjkjkkllkklddeþdeefefgühgghhúihiihiiýjijjýkjkklþcddeüdedeefgýhghhiþhiijþijjkûcdccddüeddeeýfeffgþfggýhghhiþhiiüjiijjýkjkkûcddcddüeddeefùgffggfggýhghhijkjþkccdedùefeffeffgýhghhþihhiüjiijjcdcdøededdedeeýfeffügffgghýihiijûkjjbccþdccdeþdeefefýgfgg÷hgghghhihhiùjijkkbccûdcdcddeùfeffeeffügffgghghýihiiûjijijjýcbccdeûdeddeefýgfggýhghhiþhiijþijjbcûdcdcddûededeef ghijbcúdccdcddýedeefþeffghûihihiijûabbcbbcüdccddýedeefþeffgþfgghghiýjibbþabbcdúcddedeefghþihhýihiiþabbcdücddeeþdeeýfeffg hiüababbcüdccddeþdeefgfýgfgghþghhýihiiabþabb cdýedeefþeffghþghhüih`aaûbababbücbbccýdcddefûgfgfggýhghhûihh`aabüababbþcbbcýdcddeúfeffeffýgfggôhgghhgihha`aabùabbcbbccþbcc defþeffgýhghhü`a`aabþabbýcbccd e fgýhghh`ab cdýedeefügffggh`þa``aýbabbcþbccdýedeefeýfeffgþfgghüghg``aþbaabcdþcddeýfeffgþfgg_`aübaabbcþbccþdccdúededdeefgûfhg_``ýa`aabþabbþcbbcdücdcddeþdeefþeffg`_`þ_``abücbbccdþcddþeddeþfeefgý_`__ý`_``ýa`aabþabbücbbccüdccddýedeeýfeffgþ^__ü`__``aübaabbôcbcbccdccdcddýedeefgfþ^__ü`__``aþ`aabþabbcþbccýdcddefûeffg__þ^__`þ_``úa``a`aa bcdöededdeeffeeføg^^_^_^__`abcþbccüdccddþedde÷feeff^^_^^ù_^__`_``ú_`a``aaýbabbñcbbccbbccdccdcddüeddeeþdeef^û_^_^__`üa``aabcýdcddýedeef^_` abûcbcbccþdccýdcddeþdeefþe^^_þ^__`þ_``÷a`aabbaabbcbcdþcddeþdee]^_û`_`_``aýbabbcdþcddþedde^þ]^^_`þ_``ýa`aabþabböcbbcbcbccddícddcddededde]]^]^]^^ù_^^_^^__ý`_``abþabbcûdcdcddûedee]]^_`öa``aabababbcþbccýdcddþedd]þ^]]^_ý`_`` abcýdcddþ\]]^þ]^^_`aþ`aaýbabbýcbccûdcdcddù\]\]]\]]ý^]^^_û`_`_``üa``aaúbaababbûcbcbccûdcdcdd\]\]^ _`aþ`aabýcbccd\û]\]\]]^þ]^^_þ^__`_`aø`ababaabbþcbbcdþc\\û]\]\]]õ^]^^_^__^^__þ`__`ùa``aa`aabcýdcdoþpoop qrsþrssútsttsttuþtuuvuvoüpooppqúrqqrqrrsþrssûtststtuþtuuvonoüpopoopýqpqqþrqqýrqrrýsrsstîuttuuttuuvvuuvonnooþnooûpopoppqpqýrqrrsrsýtsttutuvþunnoþnoop qrþqrrsútsststtýutuunüonnoopóqpqqpqqrqrrqrrsürsrssùtssttsttýutuunýonooþnoopþoppþqppqþrqqrúsrsrrss tünmmnnopþoppþqppqþrqqrüsrrsstõutuutnnmnmnnýonooþpoopþqppqürqqrrsþrsstutmnüonnooüpooppqþpqqþrqqrösrssrssttsst÷unmmnnmmnnþonnoûpopoppqrþqrrüsrrssütssttmnþonnopþoppqürqqrrsþrssütssttmnýonoopüopoppqýrqrrúsrrsrssütssttmþlmmûnmnmnnüonnooþpoopþoppýqpqqrstûslmlmmünmmnnþonnopqþpqqýrqrrstúmllmlmmünmmnnüonnoopþoppýqpqqôrqrqrqrrssrsstþsllümllmmýnmnnùonnoonoopþoppûqpqpqqýrqrrüqrrssþrssl m noýpoppqþpqqrþsrrsýrsllýmlmmnþmnnýonooýpoppüoppqqöpqqrqqrqqrrsrslùmlmlmlmmnmnonoþpoop÷opqqppqpqqürqqrrsrùskllkkll÷mlmllmlnmmýnmnnoþnooüpooppòqpqpqpqqrqqrqrrúsrlkkllmþnmmnþonnopqþpqqýrqrrþskkþlkklmþlmmnþmnnonopþoppqópqqpqrqrqrrqrrklüklkllmþlmmúnmnnmnnoþnooûpopoppôqpqpqqrqqrqrrkýlkll mnüonnoopûoppqppqúrqrqqkkýlkllþmllmþlmmnoþnooüpooppùqppqqpqqürqrkkþjkkúlkklkllþmllmnümnmnnúonoonooüpooppüqppqqrj kýlkllûmlmlmmúnmmnmnnýonooýpoppþqppqjúkjkjjkkl÷klmlmlmlmmþnmmnúonoonoopþqppqjýkjkklmlmnmnoùpoppooppþqppqjükjjkkýlkllümllmmnúonnonooýpoppýqpqqijýkjkklýmlmmþlmmýnmnnüonnoopøqpqqijijjklökllmllmmlmmýnmnnopþoppûqpiijjkþjkklklmnþmnnýonooònopopoppoppqqiijükjjkkþlkklmölmmnmnnmmnnüonnooúpopooppiþjii jkýlkllmünmmnnonoüpooppþhiiýjijjk÷jkjkkllkllmlmnýonoopýihiijþijjkþjkklþkllýmlmmnmnøonnoonnppûhiihiiüjiijjkþjkklümllmmnonýonooýphiiújijiijjükjjkklþkllmþlmmünmmnnohýihiiüjijiijükjjkkülkkllmýnmnnýonoohiühihiijþijjükjjkkýlkllýmlmmýnmnnmnþonnûonoghhiþhiijùijkjjkjjklýmlmmnoþghhþihhijùkjjkkjkkülkkllmülmlmmnþmnnûonghgghúihiihiiüjiijjklklmùlmmnmnmmnöonnhgghhghhiþhiijþijjýkjkk lmþlmmnmnghþihhijþijjkülkkllümlmllmnümnoggýhghhihýihiijþijjkúlkklkllmùnmnnffggühgghhiþhii jýkjkklýmlmmnfgýhghhýihiiûjijijjþkjjklømlmllmlmmþnffgùhghhgghhýihiiújijjijjkþjkklþmllmnùfgfgffgghúihhihiiýjijjkülkkllmfügffggùfgghhghhýihiijùijijjkjjküjkkllümllmmýfeffýgfgghþghhýihi iýjijjklümllmmfþeffgühgghhõihihihiijijjükjjkkúlkllkllmefûgfgfgghùihihihiiþjiijúkjkkjkklmüefeffýgfgghþghhiûjijijjkýlkll÷meefeefeffgþfgghþghhüihhiijþijjklkýlklleýfeffgþhggýhghhijiûjijijjklefþeffgþhgghýihiiþjiijøkjjkjkjkkþlkklýedeeüfeeffûgfgfggþhgghüihihhijþijjükjjkklükleddefügffgghþihhijþijjùkjjklkllûdeddeeýfeffþgffgýhghhûihihiijþijjkd efefýgfggühgghhiþhiiýjijjkþjkklóôþóôôýóôóóôþóôôþõôôþõôôýõôõõôüõôôõõþóôôþóôôúóôóôóô ôþõôôþõôôþõôôõþôõõýôõóóôóôþóôôþóôôþõôôäõôôõõôõôôõôõôôõôõôõôõôôõôôõôôüóôóôôþóôôþóôôõýôõôôþõôôõôõôóôóôóýôóôôüõôõôôõôùõôôõõôóóýôóôôþóôôþóôôþóôôþóô ôþõôôõôõôýõôõõýôóôôüóôóôôóýôóôôóôõ ôüõôôõõôóýôóôôþóôôóôþóôôûõôôõôôõõôôõôõôóôôóóûôóôóôôýóôóóøôóôóôôóôôþóôôüõôõôôõôþõóóôôóôôóôôóóôóóôôþóôôóôûõôõõôôõôûõôõôóóúôóóôôóóôóôóýôóôôúõôõõôõõôýóôóóôüóôôóóøôóôóóôóôôüóôóôôûõôôõóóïôóôóóôôóóôóôôóóôóóôþõôôþõôôõôóþôóó÷ôóôóôôóôóóôóôùóôôóôóôôþóôôõýôõôôâõóóôóóôôóóôóôóôóôôóóôóôóôóôóóôôþõôôüõôõôôó÷ôóóôóóôôóóýôóôôùóôóóôóôôüóôóôôþõôôúõôôóôóóöôóóôóóôóôóóûôóôóôôóôûóôôóôôþõôôþõóóôóþôóóøôóóôóóôóóôóôþóôôþõôôóþôóóþôóóúôóôóóôôüóôóôôùóôôóôóôôüõôõóó÷ôóóôóóôóôôýóôóóþôóóüôóóôôþóôôþóôôóþôóóôóûôóôôóóôüóôôóóôúóôôóóôôþóôôóýôóô ôóûôóóôóóþôóóúôóôóôóóüôóôóóôùóôóôôóôôþõóóôóôþóôôñóôôóôôóôôóóôôóô ôþõóóûôóóôóóþôóóþôóóúôóóôôóóôöóôôóôôóôóô ôóúôóóôôó óôó÷ôóóôóóôóôôþóô ô óôüóôôóóôóüôóóôôþóôôøóôôóôôóôôóøôóôóôóôóóôþóôôþóô ôóþôóóþôó óýôóôôüóôóôôþóôôþóô ô óüôóôóóôøóôóôóóôóóþôóóôóôüóôóôôóôóþòóóûôóóôóóþôóóøôóôóôóóôôóôûóôôóô ôóþòóóþòóóûôóóôóóþôóóôøóôóóôôóôôó÷ôóóôóôóóôô óò óöôóóôôóôóóôôúóôôóóôôùóôóôôóôôþóôôýóòóóþòó óôóþôóóôóøôóóôôóôóóüôóóôôûòóóòóóþòó óôóþôóóôóüôóóôôüóôôóóùôóóôôóôôöóôóòóòóóòóóþôóóôôóôóóôóóôóóôóóôóýôóôôþóôôûóòóòóóòóþôóóþôóóþôóóûôóôóôôûóôôóôôûóòóòóóüòóòóóþòó óüôóóôôóôþóôôóôóôóôþóôôüòóòóóþòóóþòó óþôóóûôóôóôôóþôóóôüóôóôôóôùóòòóóòóóþòóóüôóôóóôóôóôóôóøòóóòóóòóóþòóóþôóóþôóóôõóôôóôóôôóôóóüôóóôôûóôóóòòóþòóóþôóóôóôûóôóóôôúóôóóòóóþòóóüòóòóóþòóóþôóóüôóóôôóôøóôóóòóóòò óþòó óþôóóþôóóüôóôóóþôóóôóõòóòóòóóòóóòòóþòó óþôóóøôóóôóóôóóþôóóúôóóòóòòþóòòóûòóóòóóþòóóþòó óþôóóþôóóôóþôóóôøóôôòòóòóóòóþòóóþòó óþôóóùôóóôôóôôóþôóóòôóôóòóòòóòòóóòòóþòóóþòó óûôóóôóóôóúôóóôôóóùôóôóôóòòóøòóòòóòòóóþòóóûòóóòó óþôóóôóþôóóýôóòòóøòóòóòóòóóüòóóòòúóòóóòóóþòóóüôóôóóôþóôôþóòòóúòóóòóòòýóòóóüòóòóóþòó óþôóóüôóôóóöôóóòóòóóòóóòóúòóóòòóóüòóòóóûòóóòó óþôóóùôóôôóôòòýóòóóúòóòóòóóûòóóòóóþòóóþôóóôüóôóòòóûòóòóòòóþòóóþòóóòóòóûôóóôóóòüóòóòòûóòóóòòþóòòþóòò óò óûôóóôóóüòóòóóòóòóþòóóþòóóþòóóûòóóòóóþôóóòþóòòþóòòóþòóóòóüòóóòòóþôóóòóòóòûóòóòóóüòóòóóþòóóòóòóþòóóòóòóòóòýóòóóòóþòóóþòó óþôóóþôóóòüóòóòòóòóòþóòòóòóþòóóþòó óòóøòóòòóòóòòüóòòóóòóòóòþóòò óôó òüóòóòòóòùóòòóóòóóòóòóüòóòóóþòóóòó òùóòóòòóòòýóòóóûòóóòóóòûóòòóòòóòþóòòóûòóóòóóþòóóòóþòóóüòóòóóþòóóòþóòòóøòóòóóòóòòüóòòóóþòóóþòóóÿopþqppqrþqrrûsrsrsstuüvuuvvwvþnoopýqpqqürqqrrþsrrýsrssütssttuývuvvopüopoppqþpqqrþqrrsrsýtsttýutuuúvuuvuvvüwnonnøopooppoppûqpqpqqrsýtsttùsttuttuuvøuvvnnonoopqrüqrqrrûsrsrssütstsstõuttutuuvuuvvnþonnoüpooppýqpqqrþqrrýsrssøtstsststtutuûvuvunnoünonooýpoppùqppqppqqúrqrrqrrûsrsrssütssttúututtuuüvuvnnþonnopopýqpqqýrqrrüsrrssþtsstýutuutuûvummnnûononoopýqpqqýrqrrüsrrsstuþtuumnöonnonooppoopýqpqqrþqrrsúrsststtuþnmmnöonnonnoopoopúqpqqpqqrþqrrsþtsstuøtmnmnnmnnúonoonoopûoppopp÷qppqqpqrqqrþsrrsþtsstúutumlmmnopýqpq qrsþrsstumnþmnnonop qrþsrrsütssttøstuttmlmmnüonnoopýqpq qrsütssttmþlmm nýonoopþoppýqpqqürqqrrsþrssútsstmllýmlmmünmmnnoþnoopqrþsrrsþtsslmûnmnmnnoýpoppqpqürqqrrþsrrslúmlmmlmmþnmmnoþnoopþqpp qrýsrssþtllmnmn opqpqrskl÷kllmmlmlmmnopopýqpqqrýsrssúklklkllþmllmnþmnnúonnonoopþqppqýrqrrsklmlmnoþnoopqþpqqýrqrrsþrkkúlkklkllmünmmnnopýqpqqùrqqrrqrrýsjkklþkllümllmmnoþnooýpoppqþpqqrqrùskjkkjkklmþlmmýnmnnopqþpqqrjklklýmlmmúnmnmmnno pqürqqrrûjkjjkklþkllúmllmlmmnýonoopþoppöoppqqpqppqq÷rqqrijkkjjkõlkllklmmllmmnþmnnýonoopþoppqijøkjjkkllkklümllmmnmnonopopqjþkjjýkjkklklmýnmnnoþnoopûqpqpqqûijjijjkølkklklkllmþlmmünmnoonoýpoppýqpqqjijklüklkllmlmýnmnnoýpoppýqpqqijkþjkk lmnûononooüpooppqþhiijköjkklklklkllýmlmmýnmnnoünonoophijükjjkklüklkllmþlmmþnmmnoþnoopþqiijijýkjkkülkkllmnþmnnoüpoopphýihiiújiijijjkjkþlkkýlkllmýnmnnopþoppûhihhiijýkjkk lmønmmnmnmnnophiühihiijþijjklklmþlmmnmn oýhghhiújijjijjókjjkkjjkklkkllmnûmnnmnnýonooghijôijijjkkjkkjkklþkllmnþmnnüonnooûghhghhiþhiijþijjükjjkklmnoghþihhijþijjkjklmlmnõonnoogghgghhijükjjkklmnþmnnùonnogfggýhghhiþhiiþhiijijklþkllýmlmmnþoggûhghghhihij÷ijjkkjkjkklüklkllmþlmmnõoffgfgghhghhihijþijjkþjkklþkllúmlmllmmnmnþgffghüihhiijkþjkklþkllmònmnmnmmnffggfggühgghhýihiiýjijjýkjkk÷lkllmlmlmmþnmmþnffgþfgghþghhþihhi jklmnfùgfgfgfggühgghhiýjijjúkjjkjkkùlkllklm mfýgfgghghýihiijþijjýkjkklmlmefügffgghþghhûihihiijþijjûkjkjkklümllmmeúfeffeffýgfgghþghh÷ihihiijijjúkjkkjkklümllmmûefeeffýgfggýhghhüihhiijýkjkklmþleefügffggúhghhghhijþijjkúlkklkllmefgþfggýhghhiþhiiýjijjýkjkklþdeefügffggýhghhiýjij jklklþeddef ghiühihiiýjijjúkjjkjkkldeûfefeffgþfgghýihiijþijjkldefþeffghýihiijükjjkkþlkkþcddeýfeffþeffügffgg hýihiiùjiijjijjøkjjkklkddýedeefþeffghiþhiiþjiijkvþwvvwþxwwxyxyüzyyzzù{zz{zz{{|ý}|}}ø~}uvwvvwwvwüxwwxxyzû{z{z{{ü|{{||þ}||}ý~uvvûwvwvwwüxwwxxýyxyyúxyyzyzz{|þ{||}vúwvwvvwwúxwxxwxx yzþyzzü{zz{{|}uvwvwüxwwxxyzù{zz{{z{{ý|{||úuvvuuvv wûxwxwxxyûzyzyzzý{z{{þz{{|þ}uuvþuvvüwvvwwxøyxyxxyxyyýzyzzý{z{{þ|{{|þ}uuþvuuvýwvwwþxwwxyþxyyzý{z{{ü|{{||uþvuuvúwvwwvwwxþwxxyzþ{zz{|þtuu výwvwwüxwwxxýyxyyzùyzyzzyzz{þz{{ø|{{|{ttuuúvuuvuvvwvwxyúzyzzyzzø{z{{z{z{{ü|ttuuútvuvuvvüwvvwwxþwxxyxýyxyyz{ú|tuttuuùtuuvvuvvw÷vwwxwxwwxxyýzyzzý{z{{ý|{ttuþtuuþvuuvúwvwwvwwxþwxxyzþyzzú{zz{z{{ýtsttþuttýutuuüvuuvvýwvwwxyþxyyz÷{zz{{zzsttüuttuuývuvvþwvvwþxwwxyþxyyûzyzyzzý{sttþsttuüvuuv vwxýyxyyzûyzzyzzýtsttþsttuþtuuvwxüwxwxxýyxyyþzyyzsütssttýutuuþtuuvþuvvûwvwvwwüxwwxxyþxyyýzyzzþyzzsütssttüuttuuþvuuvüwvvwwýxwxxyýzyzzsýtsttutuývuvvwüvwvwwxyxyþzyyùzysrsrssýtsttuþtuuvþuvvwýxwxxyùzyyrsrsstúuttutuuývuvvwvwýxwxxûyxyxyyþzrrüsrrssýtsttûututuuývuvvwþvwwxþwxxyþxyyýzyrrýsrssütssttuþtuuvüwvvww xyýzqrrósrsrrsststtsttýutuuvuvüwvvwwxy rstuþtuuüvuuvvwùxwwxxwxxyxüyqqrrúsrsrrssütssttuþvuuývuvv wxüyqqrrþqrr stuõvuuvuvvwvvwwýxwxxþrqqrúsrssrsstýutuuþvuuývuvvwvwþxwwýxwxxûyqqrqqrþsrrsütssttôututuuvuvvuvvþwvvwþxwwxþpqqúrqrrqrrþsrrýsrss tuûvuvuvvýwvwwþxwwúxwxqpqq rõsrsststststtýutuuùvuvuvuvvwxýpqppqýrqrrüsrrsstüststtuvûwvwvww÷xwxxpqppqqrûqrrqrrsþtssýtsttuþvuuvþuvvýwvwwpýqpqqûrqrqrrstþsttóututuuvuvuvuvvøwvvwwvvwwþoppûqpqpqqrþsrrýsrssþtsst uvwþvwwpþqppqrþqrrstsütssttþuttuývuvvýwvwwpýqpqqrþqrrüsrrsstþsttuþtuuvwvwûpopopp qýrqrrþsrrsütssttüuttuuüvuuvvúwvwvvoopqrþqrrþsrrsýtsttutuvþwoo pqrûqrqqrrsütssttüuttuu÷tuuvuuvuvvýopooüpooppqþrqqrýsrsstuþtuuvoýpoppþqppqrþqrrsþrssþtsstuvuvopùqpqpqpqqþrqqrstþsttuütutuuøvuuoonnooûpopoppþqppqpùqrqrqqrrüsrrssûtststtutuúonnonoopopqþpqqürqqrrýsrsstþsttþsttuþtuunoünonoopþoppqrþqrròsrsrsrststtssttþuttuývunnoþnoopþoppqþpqqrþsrrsütssttunoþnoopqpqrýsrssþrssütssttøutuutuunnúmnnonoopþoppqþpqqrqrststöuttuutmnmnnüonno opþqppqrst÷utuumnmnmmýnonn opýqpqqrùqrsrsrssútsttsttûmnnmnnoüpooppqýrqrr stþummnmnonopüqppqq rststþlmmnoþnooûpopoppüqppqqrsþrsstýslmmnmnøonnononoopopýqpqqørqqrrqrssrsûtsttm mnoþnoopýqpqqrqr súlmlmlmmünmmnnùonnonnooûpopoppqþpqqìrqrrqrrsrsrssrsstslmmûlmllmmnoþnoopýqpqqúrqqrqrrûsrsrsslmþnmmnýonoo pqrsl mýnmnnûononooþnoo pqþrqqrøsrrsrlkllýmlmm n o pqýrqrrüqrsrrùslkklkllýmlmmþnmmnýonoopopqþpqqürqqrrþsrr õþôõ õþöõ õööõöõööõöõõööõööõööõööõöõôôøõôôõôõôõõûöõõöõõöýõöõõúöõõöõööõþöõõôýõôõõþöõõöõþöõõúöõöõõööûõöôôõõþôõõþôõõøöõööõööõõüöõõöö÷õööõöõöôõõüôõôõõþôõõþôõ õþöõõýöõööþõööõüöõõööõöôùõôõôõôõõôõþôõ õþöõõôöõõöõööõöõõööõýöõööúõôõôôõõúôõõôôõõþôõõþôõ õöýõöõõüöõöõõöõýöõööûõööõôôõýôõôôõþôõõþôõõþôõõþöõõþöõõúöõööõööõúôõôõôõõüôõõôôýõôõõþôõõöõþöõõýöõööõööõõôõõôõõôôõþôõõþôõ õþöõõóöõõöõõöõõöõõööþõööôõþôõõþôõõôõþôõ õþöõ õöüõööõõìöõõöôôõõôõôõõôõõôõôõõôõûôõõôõõøöõõöõõöõõööõöõöõööõôôõôõüôõõôôõþôõõþöõõóöõõööõõöõõööõõôùõôõôõôõõôýõôõõþôõõþöõõùöõõöõöõõöõïôõõôõôôõôõôôõôõôõõôõùôõôõõôõõþöõõþöõõþöõõôýõôõõôýõôõõ÷ôõôôõôõôõõþôõõþôõõúöõõööõõüôõõôôõôþõôôøõôõõôõõôôõùöõõöõöõõôþõôôõüôõõôôüõôôõõûôõõôõõùôõôõõôõõþöõõøöõõöõôõôôùõôôõôõôôýõôõõô õþôõõþôõõþöõõôüõôõôôüõôõôôöõôõõôõõôôõõþôõ õþôõ õþöõõ ôõûôõôôõõôýõôõõþôõõöõôüõôõôôîõôôõôôõôõôôõôôõõôõõùôõôõõôõõþôõõþôõõöüõöõô ôõþôõõôüõôôõõùôõôôõôõ õþôõõ÷öõõööõööôôþõôôôõôôõôôõôõõôõõþôõõôõôõþôõõþôõõþöõõþöô ôõûôõôôõõôøõôõôôõôõõôýõôõõôõôöõôôõõôõôôõõþôõõúôõôõôõõôþõôôõûôõôõôôþõôôõôõþôõõþôõõ ôþõôôãõôôõõôõôõôôõõôõõôõôôõôôõôôõôõ õþöôôþõôôþõôôþõôôõûôõôôõõôôõôõõôõôõõôõõþôõõôõþóôôþõô ôþõôôüõôôõõþôõõþôõõôõôõþôõõôþõôôõôôõôõõôõôôõôõõþôõõôõþôõõôþóôôþõôô÷õôõôõôõõôôõþôõõýôõôôõôõôþóôôþóô ôûõôôõôôûõôõõôôõôýõôõõþôõõþôõõþôõõôõôþõôôõöôõôõõôôõôõõöôõôõôõõôôõõþôõõöôóôôóôóôóôôúõôôõõôôõôñõôôõôõõôõôõôõôõõôõþóôôþõôôõôþõôôõøôõôõôõôõõüôõôõõóýôóôôõôùõôôõõôõõôõ÷ôõõôõõôôõõôþóôôþóôôþõô ôíõôõôôõôõõôõôôõôôõôõõúôõôôõôôúóôóôóôôûõôôõôôúõôôõõôôõôõüôõôõõþôõõúôóôôóôôüõôõôôþõôôýõôõõôõôüõôõôôüóôóôôþóôôþõôôþõôôûõôôõôôþõôôùõôôõõôõõûôóôóôôóôþõôôúõôôõõôôþõôôõôþõôôþóôôþóôôþóô ôþõôôõýôõôôþõôôüõôõôôõúôóóôóôôþóôôóôþóô ôþõôôûõôôõôôûõôõõôôõ÷ôõõôôóôóôôûóôôóôôùóôôóôóôôüõôõôôóõôôõôõõôõôõõôôõþóôôùóôóôóóôôüóôóôôþõôôõõôôõôõôôõõôôõôûóôôóôô÷óôôóóôóóôôüóôóô ôþõôôþõôôúõôôõôõõôûõôõõôôùóôôóôóôôó ôþóôôõ ôþõôôõôõôóöôóôóôóôôóôô÷óôôóôôóóôôþóôôõôûõôôõôôüõôõôôóýôóôôüóôóôôùóôóôôóôôþóôôþõôôõûôõôõôôóüôóóô ôóôþõôôõôþóôôúóôóóôóóôüóôóôôûóôóóô ôþõôôòõôôõôõôôõôõôõôôþóôôóôþóôôóôþóôôþóôôþõôôõôóþôóóõôóôóôôóôôóôôüóôóôôþóô ôüõôõôôþõôôîõôõôôóóôóôóôôóóôôóóûôóôôóóôóôûõôôõôôóúôóóôóôôøóôóóôóóôôþóôôþõôôùõôôõôõôôóüôóôóóõôóôóôóóôôóôôöóôôóôóôôóôôþóôôþõôôþõôôþõóóüôóôóóôóôóôüóôóôôþóôôþóôôþóôôþõôôþõôôþõôôóýôóôôóôóúôóôôóôôúóôôóóôôüõôõóóüôóôóó÷ôóóôóóôóôôþóôôûóôóóôôþóôôþóôôþõôôûóôóôóóôùóôóóôôóóôóûôóôóôôóýôóôôþóô ôþõôôóûôóóôóóþôóóþôóóùôóôôóóôôóôþóôôóûôóôôóóûôóóôóóúôóóôôóóùôóóôóóôôþóôôõôóôóùôóôôóôóóöôóôóóôóôôóóôóôóôõÿwþxwwýxwxxýyxyyþzyyzý{z{{|ø}|}}~}}~~þvwwýxwxxyþxyyýzyzzþyzzý{z{{|þ{||ù}||}}|}}ü~}}~~ýwvwwúxwwxwxxyzþ{zz{þ|{{|ú}||}|}}ý~}~~vwxúyxxyxyyzüyz{zz{ùz{{||{||ú}|}}|}}ý~}~~vþwvvwxúwxyyxyyzü{zz{{ý|{||}~ý}~vvwþxwwxúyxyxxyyõzyzyyzz{zz{ {|}~výwvwwýxwxxúyxxyxyy z{ý|{||}þ|}}ô~vvuuvvwvwvwwxyþxyyzþyzzú{z{zz{{|þ}||}þuvvþuvvwxyùxyyzzyzzü{zz{{ý|{||}ù|}uvvuvvüwvvwwúxwxwwxxyþxyyzþyzz{ú|{|{{||}ý|}uuüvuuvvwxþwxxyþxyyýzyzzý{z{{|þ}uuývuvvþuvvwúvwwxwxxþwxxyúzyzyyzzù{zz{{z{{|{|tøutuuvuvuuvýwvwwxyþxyyzþ{zz{ö|{|{||}utuuþvuuvüwvvwwxüyxxyy zý{z{{|þ{||tu÷vuuvvuvwvvwýxwxxyþxyyõzyzzyz{{zz{{ý|{ttüuttuuþvuuvüwvvwwýxwxxüyxxyyþzyyz{üz{z{{|tuvwþvwwxþwxxýyxyyz{ü|{|ttuvþuvvüwvvwwýxwxxýyxyyzþyzzû{z{z{{ùststtutt uvwvwxöyxyxxyxzzyyz{stuývuvvõwvvwvwwxwxwwxyþxyyþzyyz{ûz{z{ssùtssttuttùutuvuuvvöuvvwwvwwvwwxþwxxúyxyxxyyüzyyzzû{z{{sstýutuuvwþvwwúxwwxwxx yzþrsstutuvþuvvþwvvwøxwwxxyxyyøxyyzzyyzzý{zsstûsttsttuþtuuvwþvwwþxwwxþyxxyzþyzzrstþuttýutuuývuvvýwvwwýxwxxöyxyyzyzzyzzrûsrsrssýtsttuvòwvwvwwvwxwxxwxxyøzyzzrrsrrsütssttýutuuvþuvvwùvwwxwwxxûyxyxyyzûqrrsrrstûututuuúvuuvuvvýwvwwúxwwxwxxýyxyyørqrsrsrsstuþtuu vwxyrþqrrþsrrststøutuuvvuvvöwvvwwxwxwxxyxyrþqrrsþrss tuvþuvvwþvwwxyqrûqrrsrrúsrsstsstýutuuvüwvwvvwþxwwx÷yxyxyqqrqqýrqrrstþsttuûvuvuvvwxyqýrqrrùsrrssrss tuøvuuvuvwvvýwvwwýxwxxyüxqpqqrþqrrsþrssütssttúututtuuvuvþwvvwxpqrstuvuvúwvvwvwwýxwxxõwxxqppqpqpqqrsþrsstþsttuþtuu vwþxwwpùqppqqpqqrüsrrsstþsttþuttuývuvvýwvwwþxppýqpqqrýsrsstþsttûututuuývuvvwüvwvwwxpqrýsrssûtststtutu÷vuvuuvvwvvwõpoppopqqppqqrþsrrstùutututuuúvuvuvwwvwúvwwpoppqrþqrrûsrsrssþtsstuøtuvuuvuvvþwvvwopqüpqqrrôqrqrrsrsrsrsstýutuuþtuuþvuuvw÷nooppopoppúqpqqpqqýrqrrþsrrsýtstt uvþwoopüqppq qrsrstþsttuþtuuþvuuvýwvooýpoppqpqúrqrrqrrýsrsstþsttu÷tuuvuvvuvvopqþpqqürqqrrsûtststtýutuuvýonooþnoopþoppqpqrýsrsstutuövuuvvnoonooýpop pqrs tuúvuvuvnnüonnoopþoppüqppqqýrqrrþqrrûsrsrsstýutuuñvuumnmnnonnoonoopopqrþqrrsþrsststuünmmnnoþnoopëqpqqpqqrqrqrrqrrssrrsstùutututuuýmnmmnopþqppqúrqqrqrrsûrsrrsststutýutmmnûononooûpopoppqrþqrrsúrsrssttstutmnoþnoopqpqþrqqûrqrrssþrsststumúnmnmmnnoþnooûpopoppqþpqqrüqrrs stýmlmmnoþnoopoýpoppüqppqqrþqrrstþsttmþlmmúnmnnmnnoþnooýpoppqþpqqrüsrrss÷tsttssttllûmlmlmmønmmnmnnoopopqþrqqrsúrsststtþsllmýnmnnoüpooppqþpqqürqqrrsþrssùtssttkllmûnmnmnnþonnoúpoopoppqþpqqürqqrrsþrssütskllúmlmllmmnmnùonnoonooýpoppqþpqqrqrüsrrssþtllþkllmünmmnnoþpoopqørqqrqrqrrsþrssþkllýmlmmnþmnnoùpooppoppýqpqqrs}~ü~~€þ€‚ûƒ‚ƒ‚ƒƒý„ƒ„„û…„}}~~ø}~~~~ý€€€ý‚‚‚ƒþ‚ƒƒý„ƒ„„ý…„}}ý~}~~þ~~ú€€€€û€€þ‚‚ƒý„ƒ„„÷|}}~}}~}~~þ~~€ý€þ€‚úƒ‚‚ƒ‚ƒƒ„}þ|}}ö~}~}~}~~þ~€þ€€þ€‚þ‚‚ƒó„ƒƒ„„}|}|}}~}}~ €ý€‚þ‚‚ƒþ‚ƒƒþ„ƒƒ„ú}|}}|}}ý~}~ ~ü€€€þ€û‚‚‚‚ƒû‚ƒƒ‚ƒƒ„ùƒ||}}|}}ý~}~~þ~~ý€€€þ€ù‚‚‚‚‚ƒ|ý}|}}ý~}~~þ~~ü~~€ ‚ýƒ‚ƒƒ|ý}|}}~þ}~~þ~ü€€€þ€€ý€‚‚ƒ‚‚ƒƒ{{||}|}||}}~þ}~~ý€€€‚‚úƒ‚ƒƒ‚{{|}þ|}}~}~ü~~€ý€‚ƒ{|}ö~}}~~}~ý€€€ý€‚þ‚‚ü|{{||þ}||ù}~}~~}~~€þ€€ý€þ‚‚{÷|{||{||}|| }~ü~~€€ù€€€ü‚‚‚zú{|{{|{{|}þ|}}ü~}}~~ ý€€€ý€þ‚÷‚‚‚{{z{{|þ}||}~ù~~~ü€€€€ý€‚z{ý|{| |}~þ}~~~ý€€€€ó€‚‚‚‚zz{{|{|}ú~}~~}~~ €þ€€ñ€€‚‚‚zz{{z{{ö|{||{|}||}} ~€ü€€þ‚zz{|þ{||ü}|}||}ü~}}~~~€€ü‚yyzz{þz{{ý|{||}û~}~}~~ü~~þ€€ö€€€yyzz{|ý}|}}þ~}}~ý~€þ€€û€yyzý{z{{z{û|{|{||}ö|}|}}~~}}~~þ~€þ€€yýzyzzý{z{{û|{|{||þ}||}~ù~~~€yýzyzz{þz{{|þ}||}ù~}}~~}~~ý~ý€€€yzû{z{z{{þ|{{|ú}||}|}}û~}~}~~ü~~€ýyxyyzþyzz{|}þ|}}~÷~€€€€€yûzyzyzzù{zz{zz{{ü|{{||}þ|}}~þ}~~ý~~~€ü€€yyûzyzyzz{þz{{|{|}þ|}} ~€ùyxxyxxyyýzyzz{|þ{||þ}||}ü~}}~~ø~€€xxyþxyyzþyzzü{zz{{ü|{{||þ}||}~x yözyzyzz{zz{{û|{|{||þ}||}~}ý~}~~xúyxxyxyyýzyzz{ý|{||}|}~þ~~öwxwwxyxyyxxyþzyyz{ûz{{|{{ý|{||ý}|}}~ü}~~wxyz {|}ù~}}~}}~~ù~~wxxyxyþxyy z{ù|{{||{||}ú~}~~}~~wþxwwxýyxyyzý{z{{ù|{{||{|| }~wxþwxxyþxyyýzyzz{üz{z{{ú|{||{||}ú|}}~}~~þwwüxwwxxüyxxyyzý{z{{|{|û}|}|}}~û}~~vwwüxwwxxyûxyyxyyýzyzzþ{zz{|{|}÷~}~wvvwvwwxyþxyyzþyzz{üz{z{{û|{|{||û}|}|}}~ø}vwwvwvwwýxwxxúyxxyxyyzý{z{{|û}|}|}}ø~vwvwvvwwxüyxxyyþzyyûzyzyzz{ü|{{||þ{||ý}|}}vüwvwvvwxþwxxyxyûzyzyzz {|þ}||}ývuvvþwvvwýxwxxûyxyxyyz{üz{|{{ø|{{|}|}||}vwþvwwxþwxxûyxyxyyózyzzyzz{z{zz{{ú|{{|{||}uývuvvwùxwxwxwxxúyxxyxyyzý{z{{ü|{{||ù}|vuvuvvýwvwwýxwxxýyxyyþzyyzû{z{z{{ú|{||{||ü}||uuvwüxwwxxyþxyyzü{zz{{ü|{|{{|þtuuvuvõwvwvwxwxxwxxþyxxýyxyyþzyyz{|{|þtuuvûuvvuvvþwvvýwvwwýxwxxòyxyyxyyzyzyzyzz{|ü{ttuuþvuuvüwvvwwxwxþyxxýyxyyüzyyzzí{z{z{z{{||{|{uttutuuývuvvþwvvwxwxþyxxyûzyzyzzý{z{{ù|ttuttuuþvuuvwþvwwxýyxyyþzyyz{þz{{|ûtuttuuþtuuývuvvýwvwwxýyxyyzþyzzý{z{{tuúvuuvuvvwxwx yzú{z{{z{{tuývuvvþwvvýwvwwxüyxxyyýzyzzý{z{{þsttùututuuvvüuvuvvwþvwwþxwwxyxyzõ{z{zzstststtuþvuuvýwvwwýxwxxýyxyyúzyzyyzz÷{zzsstssttûututuuývuvvýwvwwxýyxyyzþyzzþ{ssütssttýutuuvþuvvüwvvwwxüwxwxxýyxyyzstþsttuþtuuvüwvvww xûyxyxyyùzyyzzrssútstssttûututuuüvuuvvwþvwwüxwwxxyþzyyzöþõöö÷þö÷÷öù÷ö÷ö÷ö÷÷ö÷þö÷÷ûö÷öö÷÷öùõöõööõööü÷ö÷öö÷þö÷÷ö÷þö÷÷øö÷ö÷÷öõööõöù÷öö÷ö÷öö÷øö÷÷ö÷÷ö÷÷ö÷úö÷ööõööþ÷ööþ÷ööþ÷ööù÷ö÷ö÷ö÷÷ö÷üöõõööùõööõöõö öü÷ö÷ö öþ÷öö÷þö÷÷þö÷÷þö÷÷øö÷ö÷öõõööþõööþõööû÷öö÷ööõ÷öö÷÷öö÷ö÷ööõ÷ö÷öö÷ö÷öö÷÷ýö÷ööúõööõöõõùöõõööõööù÷ö÷öö÷ööþ÷ööü÷ö÷ööþ÷öö÷ôö÷÷õöõõööõõööúõööõõö öþ÷ööü÷ö÷ööû÷ö÷ö÷÷þö÷÷þöõõüöõöõõûöõöõööþ÷ööþ÷ööù÷öö÷öö÷÷ö÷ýö÷ööõöþõööþõööþõööû÷öö÷ööù÷öö÷ö÷öö÷öø÷ö÷÷õööõõûöõöõööþõö öþ÷ööþ÷ööþ÷ööþ÷öö÷ö÷þöõõöþõööþõööþõöö÷öý÷ö÷÷ö÷þö÷÷öö÷ööõööõõööøõööõööõööþ÷öö÷ö÷öõýöõööõööõööõöõööõööþõöö÷öû÷öö÷õõöõöõõöõööõöõööõö öþ÷ö öû÷öö÷ööû÷ö÷öõõöþõööõöþõööúõöõõöõõöþõööþ÷ööø÷ö÷ö÷öö÷÷õöõööõõööõõööõöþ÷ööü÷ö÷ööþ÷ööþ÷ööù÷öõõöõööõùöõöõöõööüõöõööõöþõööþõöö÷öï÷öö÷ö÷÷õöõööõõöõööûõööõööõöûõööõööþ÷öö÷öþ÷öö÷÷ö÷ööõõöõõþöõõûöõöõö öüõöõööþõö öü÷ö÷öö÷þö÷÷õûöõõöõõýöõööõöù÷ö÷÷ö÷ööõöõôöõõöõööõööõööøõööõööõööþ÷ööü÷ö÷ööõúöõöõöõõöõöûõööõööþõööþõööþ÷ööú÷öö÷÷ööþ÷õõöõöúõööõõööõöþõööþõö öþ÷ööõöùõöõõööõõöõþöõõöõöþõööûõööõööþõö öõþöõõöýõöõõûöõöõööþõööõöþõööþõö ö õúöõõööõõöõöûõööõööþõööõþöõõþöõõöõôöõöõõööõõöõööüõöõööþõööõþöõõþöõõüöõöõõöùõöõõöõööõýöõööþõööõþöõõþöõõýöõööõöõöõöõöõö õþöõõùöõõöõöõõöþõööùõöõöõõööõöþõööþõöö õúöõöõöõõþöõõþöõõõöõööõöõööõööõûöõöõööþõööõþöõõþöõõúöõööõööõýöõööõöôõööõööõöõöõööþõööõþöõõöüõööõõøöõööõööõõöþõööþõööýõöõõþôõõþöõ õüöõõööûõöõöõõ öþõööõþöõõüöõõööüõöõööþõööþõööõýöõööõþôõ õöõüöõõööõöþõööõüöõõööþõööõþôõõþöõõþöõõöõ öþõööþôõõûöõõöõõüöõõööõúöõööõööûõööõööþõööõþöõ õðöõöõõöõöõöõõööõööõöþõööõôõþôõõþöõõýöõööõúöõöõõööüõööõõöþõööþôõ õþôõ õöõþöõõ÷öõööõöõöõõùöõõöõõööõüôõôõõüöõöõõöþõööóõööõõöõööõöõööõùôõôõõôõõöýõöõõöõüöõöõõöýõöõõöõûöõöõööóõöõõôõõôõôõôõõüôõôõõüöõöõõüöõöõõüöõöõõöõùöõõöõõööõôõþôõõþôõõüöõöõõöõöþõööõõöõõôõõôõôôõõþöõõöõûöõöõööõöôïõôõõôõõôõôõõôõõôõ õþöõõþöõõöþõööõþöõõôõôõþôõ õþöõõ÷öõõöõõööõõöõ÷öõõöõõööõõùôõõôõôõõþôõõöõþöõõüöõöõõöôõööõöõôôõôõôôõôõþôõõþöõõûöõööõõöüõööôôõôõþôõõôõôýõôõ õüöõöõõöõùöõõööõööõôûõôõôõõôýõôõõþôõõûöõõöõõüöõöõõôöõööõöõôôõôõõýôõôôõþöõ õþöõõöîõöôõõôõôõôõõôôõõôõõüôõôõõöýõöõõöõäöõöõöõöôõôôõôôõôôõôõõôõôõõôõõþôõõþöõõþöõõûöôôõôôþõôôûõôôõôôõüôõôõ õþöõõþöõõþöõõüöõöôôþõôôûõôõõôôõþôõ õþöõõøöõöõöõöõõôùõôôõôôõõûôõôôõõþôõõþöõõþöõõþöõõôþõôôõúôõõôôõõøôõôôõõôõõþôõõþôõ õöõþöõõúôõôôõôôûõôôõôôõüôõôõõôõþôõõõöõöõôôõôôõôôþõôôõþôõõ÷ôõôôõôõôõõþôõõûöõõöõõúöôõôõôôþõôôþõôôõüôõôõõôõüôõôõ õþöõõûöõôõôôþõôôõöôõõôôõôõôõõôõôõþôõõþôõõþöõõöÿ~ú€€€€€‚üƒ‚‚ƒƒ„ý…„……†ý~€þ€€€ü‚‚‚ƒ÷„ƒƒ„ƒ„„…„„…†~ý€€€ú€€€ý‚‚‚ƒþ‚ƒƒ„þƒ„„þ…„„…†û…†……~~ü~€€þ€€ý‚‚‚ýƒ‚ƒƒ„þƒ„„ý…„……†þ}~~þ~ü€€€€ü‚‚‚ƒþ‚ƒƒ „…ù„……†…}~~þ€€ü€€ý‚‚‚üƒ‚‚ƒƒ„ƒö„ƒ„……„„…„……û~}~}~~ü~~€€‚üƒ‚‚ƒƒò„ƒ„ƒ„ƒ„„……„…„……þ}~~þ~€ ý‚‚‚ƒþ‚ƒƒý„ƒ„„ü…„„…… ~€þ€€ý€‚ö‚‚‚‚ƒ‚‚ƒƒý„ƒ„„…}ü~}}~~þ~€‚þ‚‚ýƒ‚ƒƒ„ü…„…}}~þ~ý€€€ú‚‚‚‚‚ýƒ‚ƒƒ„þƒ„„}~û~~ø€€€€€€‚‚ƒþ‚ƒƒ„þƒ„„|}~ù}~~~ú€€€€€ü€€ ‚ƒ„øƒ„„||}|}}~€þ€€þ€€ü‚‚‚ƒ„|}þ|}}ý~}~~ô~~€€€€þ€€ý€‚üƒ‚‚ƒƒ„þ{||}þ|}}ø~}~}~~~€þ€€þ€€û‚‚‚‚þƒ‚‚ƒü„ƒƒ||ý}|}}~þ~~ý€€€ú€€‚þ‚‚üƒ‚‚ƒƒ|þ{|| }~~þ€ý€€€õ€€‚‚‚‚ƒù‚ƒƒ|{{||ý{}||}ú~}~~}~~ €ø€‚‚‚‚‚ûƒ‚ƒƒ{{ý|{|| }~þ~€ý€ý‚‚‚ƒ{|þ{||}|þ}||}û~}~}~~ý€€€ý€‚ûƒ‚ƒƒ{{|û{||}||}ü~}}~~ý~€þ€€ý‚‚‚ùƒ‚z{{z{{|ú}|}}|}} ~ý€€€‚úƒz{{z{{|{|}þ|}}~~þ€€ý€ü‚‚‚zý{z{{ú|{{|{||}ü~}}~~€ý€ù‚‚‚‚zz{ú|{{|{||û}|}|}}~€€ý€‚yz{þz{{ý|{||ü}||}}ý~}~~€ý‚yzz{þz{{|}ü~}}~~ý~ú€€€€ý€ü‚yyzz{þz{{|þ}||}ü~}}~~ý€€€ó€€yzzyyzz{z{|þ{||}þ|}}ü~}}~~ý~€þ€€yz{÷z{z{{|{{||ú}|}|}||}~þ}~~ý~€þ€€ù€yyzyyz{|þ{||}ü~}}~~ü~~ý€€€ý€yyzþyzz {|þ{||}~ý~€þ€€xy z{|þ{||ú}|}}|}}~þ~÷€€€yxxyyz{þz{{ü|{{||ü}||}}û~}~}~~ü€€€xyxyûzyzyzzú{zz{z{{|ü}||}}ù~}~~~ý€€€xyzþyzz{|þ{||}þ|}}ü~}}~~ù~~~þ€xxyüxyxyyûzyzyzz{þ|{{|ý}|}}~ú~~~ý€xxýyxyyýzyzz{|}ü~}}~~þ€xxþwxxúyxyyxyyzûyzzyzz{|}~þ}~~þwxxþwxxüyxxyyzþyzz{|þ{||û}|}|}}ý~}~~wüxwwxxöyxxyyzyzyzzü{zz{{øz{|{{|{||ü}||}}~wýxwxxyýzyzz{ü|{{||}ü|}~}}~û~wwýxwxxyþxyyzý{z{{|}þ|}}~þvwwxþwxxýyxyyþzyyz{z{|{|}|}~þ}~~ûvwwvwwûxwxwxxúyxyyxyyzú{zz{z{{þ|{{|ý}|}}~vwxþwxxyûzyzyzz{þz{{|þ}||}~}ý~}vvûwvwvwwxþwxxyúzyzyyzz{þz{{ü|{{||}|}ý~uvvýwvwwýxwxxyýzyzz{þz{{ü|{{||û}|}|}}þuvvøwvwvwvvwwýxwxxþyxxyþzyyz{þz{{ |ý}|}}uvüwvvwwxþwxxyzþyzz{|þ{||}uvýwvwwûxwxwxxýyxyyzyýzyzzþ{zz{|þ{||ý}|}}uývuvvýwvwwxüwxwxxyzþ{zz{þz{{|}ý|}uuúvuvuuvvwvwxþwxxþyxxyùzyzyzyzz{úz{||{||þ}||uûtuvuvvýuvwwvwxþwxxýyxyyzþyzz{þz{{ü|{{||þtuuvùuvvwvvwwxýyxyyzü{zz{{ý|{||útututuuüvuuvvwýxwxxyýxzyyzøyz{z{zz{{ü|{{||tuúvuuvuvvüwvvwwýxwxxöyxxyyzyzyzzü{zz{{ø|{||{||ttüuttuuúvuvuuvvwxýyxyyzüyzyzz{|û{|{sttuüvuuvvwþvwwüxwwxxýyxyyüzyyzzü{zz{{û|ttstt uvwþvwwýxwxxüyxxyyzþyzzö{zz{z{{|sttuþvuuvwvwxyúzyzyyzz{stýutuuvþuvvýwvwwýxwxxyz{s týutuuûvuvuvvwþvwwûxwxwxxûyxyxyyzý{z{…ü†……††ú‡††‡†‡‡üˆ‡‡ˆˆû‰ˆ‰ˆ‰‰ýЉŠŠ‹þŠ‹‹üŒ‹‹ŒŒþ„……ö„……†……††…††‡þ†‡‡øˆ‡‡ˆˆ‰ˆ‰‰ýЉŠŠ‹ùŒ‹„„…„……†þ…††þ‡††‡üˆ‡‡ˆˆù‰ˆˆ‰‰ˆ‰‰ýЉŠŠý‹Š‹‹„…þ„……û†…†…††ú‡†‡‡†‡‡ ˆ‰÷ˆ‰‰Š‰ŠŠ‰ŠŠ‹„ý…„……†…†ü‡††‡‡ˆ‡ˆ‰ýЉŠŠþ‹ŠŠ‹÷Œ„„…„……„……ý†…††‡ýˆ‡ˆˆ‰þˆ‰‰þЉ‰Š‹„…†þ…††‡þ†‡‡ˆþ‡ˆˆþ‰ˆˆ‰úЉ‰Š‰ŠŠ‹„þƒ„„…þ„……†‡†‡ˆý‰ˆ‰‰Šþ‰ŠŠý„ƒ„„þƒ„„…þ„……ü†……††‡þˆ‡‡ˆþ‡ˆˆú‰ˆ‰‰ˆ‰‰üЉ‰ŠŠü‹Šƒ„ „ù…„…†……††‡þ†‡‡ûˆ‡ˆ‡ˆˆ‰úŠ‰ŠŠ‰ŠŠ‹ýƒ„ƒƒ„ …†ø‡†‡††‡‡ˆˆþ‡ˆˆ‰ˆ‰Šþ‚ƒƒý„ƒ„„ú…„„…„……ü†……††‡ˆ‰ùˆ‰‰Š‰‰ŠŠƒ„þƒ„„ý…„……þ„……ú†…††…††û‡†‡†‡‡üˆ‡‡ˆˆü‡‰‰ˆˆ‰Šƒþ‚ƒƒý„ƒ„„ý…„……†‡†‡ˆý‰ˆ‰‰ùŠƒ‚ƒƒ‚ƒƒý„ƒ„„…þ„……ý†…††‡þ†‡‡ýˆ‡ˆˆü‰ˆ‰ˆˆ‰Š‚ûƒ‚ƒ‚ƒƒû„ƒ„ƒ„„…þ„……†þ…††ü‡††‡‡ˆ‡ˆ‰‚ƒ„…ù„……„……††þ…††ý‡†‡‡ýˆ‡ˆˆ‰þˆ‰‰‚ƒþ‚ƒƒý„ƒ„„…ü†……††ý‡†‡‡üˆ‡‡ˆˆ‰ˆü‰‚‚‚ƒú„ƒƒ„ƒ„„þ…„„…†û‡†‡†‡‡úˆ‡‡ˆ‡ˆˆø‰ˆ‰‰‚‚‚ýƒ‚ƒƒ„þƒ„„ü…„„……†þ…††ý‡†‡‡þ†‡‡þˆ‡‡ˆ‰úˆ‰‚‚‚ýƒ‚ƒƒ„þ…„„…ú†…††…††‡þ†‡‡ˆü‰‚‚ƒþ‚ƒƒù„ƒ„ƒ„ƒ„„ý…„……ú†……†…††‡þ†‡‡üˆ‡‡ˆˆý‰ˆ‚þƒ‚‚ƒ„…û„……„……†þ…††‡ýˆ‡ˆˆ ‚ƒþ‚ƒƒ„ƒ„ý…„……ý†…††ý‡†‡‡þˆ‡‡ˆþ€‚þ‚‚ü‚ƒ‚‚ƒú„ƒ„„ƒ„„…þ„……†þ…††‡†‡ˆü‡€€ø‚‚‚‚‚‚ƒü„ƒ„ƒƒ„ü…„„……†þ…††þ‡††‡÷ˆ€€€€‚û‚‚ƒ‚‚ƒú„ƒ„ƒƒ„„ú…„……„…… †‡€ü€€ù‚‚‚‚‚ýƒ‚ƒƒ„öƒ„ƒƒ„„…„„……ø„…†…†……††‡þ†‡‡þˆ€€þ€‚þƒ‚‚ƒþ„ƒƒ„…ø†……††‡‡††‡€ý€ ‚ƒ÷‚ƒƒ„ƒ„„ƒ„„ù…„……„„……†þ…††‡€þ€€ü€€ú‚‚‚‚ƒ„…þ„……†…†‡†€þ€€ ý‚‚‚ýƒ‚ƒƒ„…†…ý†…††ü‡€€ü€€ý‚‚‚ƒú„ƒƒ„ƒ„„þ…„„…ý†…††þ‡††€þ€ ‚üƒ‚‚ƒƒþ„ƒƒ„÷…„…„„……†……†ü€€€ü€‚‚þ‚‚ûƒ‚ƒ‚ƒƒý„ƒ„„…ú†…††…††þ€€ü‚‚‚ýƒ‚ƒƒü„ƒƒ„„…ü„…„……ù†…††~€ü€€ø‚‚‚‚‚‚ƒú„ƒ„„ƒ„„…þ„……†~€ü€€€‚ƒþ‚ƒƒü„ƒƒ„ „…þ†~~€ý€‚þ‚‚ƒ„üƒ„ƒ„„þ…„„…†~ü~~þ€€þ€€‚‚ ƒ„…þ„……~û~~ú€€€€€ þ‚‚ƒþ‚ƒƒ„ûƒ„„ƒ„„þ…„„…~ý~€€ú€€ü‚‚‚þƒ‚‚ƒ„…ù„……„}}~~ø€€€€€þ€‚ƒ‚ƒ„üƒ„ƒ„„…ù~}}~~}~~ü~~€€þ€ ‚ƒý„ƒ„„þƒ„„þ~}}ý~}~~€þ€€ý€ü‚‚‚ýƒ‚ƒƒ„…þ„}}ü~}}~~€ú€€‚þƒ‚‚ƒ„}þ~}}~ü€€€þ€€‚þ‚‚ƒ„ýƒ„}}~ø~~~~ý€€€‚úƒ‚‚ƒ‚ƒƒø„ƒ„ƒ„„|}}ø~}~}}~}~~ü~~û€€€€ý€û‚‚‚‚þƒ‚‚ƒõ„ƒ„„ƒ}|}}|}}~}~ü~~ý€€€ø€€€€ ‚ƒ„|ý}|}}ü~}}~~€ü€€‚ƒü„ƒƒ||}ü~}}~~€þ€€‚þ‚‚ýƒ‚ƒƒú{||}|}}ý~}~~ö~~~€€€÷€€€€€ü‚‚‚ýƒ‚ƒƒý|{||}|}~þ~ú€€€€þ€û‚‚‚‚ƒþ{||ý}|}}~þ}~~ý~ü€€€þ€€‚ýƒ‚ƒƒ{|þ}||} ~þ~€‚úƒ‚‚{{||þ}||}þ|}}þ~}}~þ~~ €ý‚‚‚þƒ{{|ù}||}}|}}~ý~€þ€€ü€€‚{ü|{{||þ}||}~ý~ü€€€û€€ý‚‚‚ù‚z{{z{{|þ}||}ý~}~~ý~~ü€€€þ€‚þz{{|þ{||ý}|}}ü~}}~~ü~~€þ€‚ý‚zz{|û}|}|}}~û}~~~~€ü€€ü‚zz{ý|{||}ø|}}|}}~}}~ ü€€€€z{øz{{z{{|{{|ý}|}}ü~}}~~ü~~ù€€€€€÷þö÷÷þø÷÷öø÷øø÷øø÷÷øøþ÷øøþ÷øø÷øþ÷øø÷ö÷ø÷ø÷øý÷ø÷÷ø÷øþ÷øøø÷ø÷øø÷ø÷÷þö÷÷þö÷÷þø÷÷ø÷óø÷÷øø÷øø÷÷ø÷øøþ÷øøö÷ø÷÷ø÷÷öö÷ ÷þø÷÷úø÷÷øø÷÷ø÷úø÷ø÷÷øø÷øþ÷øø ÷þö÷÷þø÷ ÷ø÷úø÷ø÷÷øø÷ø÷ûö÷÷ö÷÷þö÷÷þö÷÷þø÷÷ûø÷÷ø÷÷øø÷÷ø÷øø÷÷þø÷÷ýø÷øøù÷ø÷ø÷ö÷÷þö÷÷þø÷÷ø÷ø÷üø÷÷øø÷ ø÷þø÷÷ûø÷÷ø÷÷ùø÷ø÷÷ø÷÷ø÷ø÷ôö÷ö÷÷ö÷÷ö÷ö÷ ÷þø÷÷ø÷þø÷÷þø÷÷þø÷÷øò÷ø÷ø÷ø÷øø÷ø÷ø÷÷þö÷÷þö÷÷øò÷øø÷÷ø÷ø÷÷ø÷÷øø÷ø÷üø÷ö÷÷þö÷÷þö÷÷óø÷÷ø÷÷øø÷øø÷øøü÷øø÷÷øø÷øø÷÷øø÷÷þö÷÷þö÷÷þö÷÷ûö÷÷ö÷÷ùø÷ø÷øø÷÷øø÷øø÷ø÷ø÷÷úö÷÷ö÷öö÷þö÷÷þö÷÷þö÷÷þø÷÷üø÷ø÷÷ø÷øþ÷øø÷ö÷ûö÷÷ö÷ ÷ûø÷÷ø÷÷þø÷÷þø÷÷øé÷ø÷÷ø÷÷øø÷÷ø÷÷ø÷ö÷÷ö÷ö÷÷ö÷ö÷þö÷÷ø÷ø÷üö÷÷ööó÷öö÷÷ö÷÷ö÷÷ö÷÷þø÷÷øû÷ø÷ø÷÷þø÷÷þøöö÷ö÷þö÷÷þö÷÷öø÷÷ø÷÷ø÷ø÷÷þø÷÷öø÷ö÷÷ö÷ö÷÷ö÷úö÷÷öö÷÷ø÷ö÷þö÷÷ö÷üö÷ö÷÷þö÷÷þø÷ ÷ø÷øý÷ø÷÷úö÷öö÷öö÷ûö÷÷ö÷÷þö÷÷þø÷÷øý÷ø÷÷ø÷öþ÷ööý÷ö÷÷ö÷÷ö÷÷öö÷ö÷ ÷þö÷÷þö÷÷þø÷÷ùø÷ø÷÷ø÷÷þø÷÷ùö÷öö÷÷öö÷÷ö÷ö÷÷ö÷ö÷÷þö÷÷þö÷÷þø÷÷øöþ÷ööú÷ö÷öö÷÷ö÷üö÷ö÷÷ö÷þö÷ ÷þø÷÷ùø÷øø÷øöö÷÷ö÷÷öö÷ö÷öö÷ö÷úö÷÷öö÷÷üö÷ö÷÷þø÷ ÷ùö÷ö÷ö÷öö÷ö÷öý÷ö÷÷ö÷þø÷÷þø÷÷öø÷øöö÷öö÷ööû÷ö÷÷ööõ÷öö÷ö÷öö÷ö÷÷ö÷üø÷ø÷÷þø÷÷ýö÷öö÷öó÷öö÷ö÷÷öö÷÷ö÷÷þö÷÷þø÷÷ùø÷÷øø÷ööþ÷ööû÷ö÷ö÷÷þö÷÷ùö÷ö÷öö÷÷üö÷ö÷÷ûø÷÷ø÷÷öþ÷ööü÷ö÷ööü÷öö÷÷ùö÷öö÷÷öö ÷ø÷öþ÷öö÷ö÷ö÷ö÷ö÷üö÷ö÷÷ö÷þö÷÷þö÷ ÷øþ÷ö öþ÷öö÷÷ö÷÷öö÷ö÷"÷øþ÷ööþ÷ö öþ÷ööü÷öö÷÷ö÷ö÷þö÷÷ öþ÷öö÷ö÷öø÷ö÷ö÷öö÷÷þö÷÷þö÷÷ö÷öü÷öö÷÷ö÷þö÷ ÷þö÷÷öþ÷ööò÷öö÷ö÷öö÷ö÷ö÷ööþ÷ööû÷ö÷ö÷÷ûö÷÷ö÷ ÷þõööú÷ö÷ö÷öö÷ö÷ö÷öû÷ö÷ö÷÷üö÷ö÷÷ö÷ öþ÷ööü÷öö÷÷öþ÷ööø÷ö÷ö÷÷ö÷÷öû÷ö÷ö÷÷üö÷ö÷ ÷ö÷öú÷ö÷ö÷ööý÷ö÷÷öù÷öö÷÷ö÷ ÷ûöõöõö öþ÷ööþ÷ööõ÷ö÷÷öö÷ö÷ö÷÷ö÷üö÷ö÷÷þö÷÷öþ÷öö÷öú÷ö÷ö÷ööþ÷ööû÷ö÷ö÷÷ö÷ö÷ö÷öú÷öö÷÷ö öý÷ö÷÷øö÷ö÷ö÷ö÷÷þö÷÷öþõöö÷öø÷öö÷÷ö÷ööý÷ö÷÷ö÷þö÷÷öþõööþ÷ööþ÷öö÷þö÷÷öûõööõööþ÷ö öü÷ö÷öö÷ùö÷÷ö÷ö÷÷þö÷÷ýö÷ööþ÷öö÷öò÷ö÷ö÷÷öö÷ö÷÷ö÷÷þö÷÷ýöõööûõööõööþ÷öö÷÷ö÷ö÷öö÷öö ÷ûö÷ö÷ööþõööú÷ö÷ö÷ööú÷ö÷ö÷ööú÷ö÷öö÷÷ö÷öþ÷ööþõöö÷ö÷õö÷ö÷öö÷ö÷÷öö÷öõöúõööõõööþõööþ÷öö÷ûö÷ö÷öö÷ö÷÷ö÷ö÷ö÷ö÷÷öûõöõõööþõööü÷ö÷ööý÷ö÷÷ö÷üö÷÷öö÷öö÷ö÷÷õõöõööøõöõõööõööþõööþ÷öö÷ö÷÷ö÷ööõööõöööõöõöõöõöõööþ÷öö÷öþ÷ööü÷öö÷÷öüõööõõöõüöõõööü÷ö÷ööþ÷öö÷øö÷÷ö÷öö÷÷þõööõþöõõ öó÷öö÷öö÷ö÷öö÷öö÷ööõöõõöõööõööþõööþ÷ööþ÷ööý÷ö÷÷ýö÷ööþ÷ööý÷öõõüöõõööþõööþõö öþ÷ööñ÷öö÷öö÷÷öö÷öö÷ööý÷öõõþöõõöûõööõööõöþõööû÷ö÷ö÷÷öô÷öö÷ö÷öö÷÷öõõõöõõöõõööõõööõøöõöõõöõööþõööþ÷ööü÷ö÷ööý÷ö÷÷öõöõöþõööþõööý÷ö÷÷ûö÷÷öõõöûõööõööþõööüõöõööþõööþõööþ÷ööþ÷ööü÷öö÷÷ûöõööõõûöõööõõöûõööõööþ÷ö öþ÷ööþ÷ööù÷ööõöõöö÷õöõöõõööõõöþõö ö÷÷öö÷÷ö÷÷õõöõþöõõöõýöõööûõööõööô÷öö÷ö÷ööõööõõööõõööõöõõööõüöõõööþõö öþ÷öö÷öÿý†‡††‡úˆ‡‡ˆ‡ˆˆý‰ˆ‰‰ Š‹ûŒ‹Œ‹ŒŒýŒõŽŽŽ†‡†‡‡†‡‡ˆþ‰ˆˆ‰úŠ‰ŠŠ‰ŠŠ‹ýŒ‹ŒŒýŒùŽŽŽ††‡ˆü‰ˆˆ‰‰þˆ‰‰ýЉŠŠý‹Š‹‹ýŒ‹ŒŒü‹ŒŒŒùŽŽŽ†…††ú‡††‡†‡‡ˆ‰úЉЉ‰ŠŠü‹Š‹ŠŠ‹Œù‹ŒŒ‹ŒüŽŽ††‡ˆ÷‡ˆ‡ˆˆ‰ˆˆ‰‰ýЉŠŠý‹Š‹‹þŒ‹‹ýŒ‹ŒŒýŒûކ…††ý‡†‡‡ˆü‰ˆˆ‰‰Š‰Šþ‹ŠŠ‹ýŒ‹ŒŒþ…††û…††‡††‡ˆ‰üЉ‰ŠŠþ‰ŠŠþ‹ŠŠ‹ýŒ‹ŒŒþŒ…†þ‡††‡þˆ‡‡ýˆ‡ˆˆ‰üˆ‰ˆ‰‰üЉ‰ŠŠ‹Š‹Œ‹ŒþŒ……†þ…††ü‡††‡‡ûˆ‡ˆ‡ˆˆý‰ˆ‰‰Šü‹ŠŠ‹‹þŒ‹‹Œ…ý†…††‡þ†‡‡ˆú‰ˆ‰‰ˆ‰‰Š‹þŠ‹‹Œþ‹ŒŒþ„……†ú‡†‡‡†‡‡ýˆ‡ˆˆ‰Š‰Šü‹ŠŠ‹‹Œ‹Œ„…þ„……†…ý†…††ú‡†‡‡†‡‡ˆý‰ˆ‰‰þЉ‰Šý‹Š‹‹þŒ‹‹Œú…„„…„……ý†…††ô‡†‡†‡‡ˆ‡‡ˆ‡ˆˆ‰ˆ‰ûЉЉŠŠþ‹ŠŠö‹Š‹ŒŒ‹Œ‹‹„„…û„……†……ý†…††‡ˆý‰ˆ‰‰ýЉŠŠ‹Œþ‹„„…þ„……û†…†…††‡†‡üˆ‡‡ˆˆ‰þˆ‰‰Šü‰Š‹ŠŠ‹Œý„ƒ„„…ú†……†…†† ‡ˆò‰ˆˆ‰‰ˆ‰‰Š‰‰Š‰ŠŠ‹„þƒ„„ý…„……ü†……†† ‡ˆ‰þˆ‰‰ùŠ‰ŠŠ‰‰ŠŠý‹Š‹‹ƒý„ƒ„„þ…„„…û†…†…††‡ýˆ‡ˆˆü‰ˆˆ‰‰ýЉŠŠý‹Šƒƒ„þƒ„„…†þ…††‡ ˆ‰Šù‹Š‹ŠŠ‹ƒƒí„ƒ„„ƒ„ƒ„„……„……„…†…††þ…††ý‡†‡‡ýˆ‡ˆˆú‰ˆ‰‰ˆ‰‰ýЉŠŠþ‚ƒƒû„ƒ„ƒ„„…ü†……††ý‡†‡‡ˆý‰ˆ‰‰Šú‹Šƒƒ‚ƒƒü„ƒƒ„„…†ý‡†‡‡ˆ‰þˆ‰‰Šƒþ‚ƒƒü„ƒƒ„„ý…„……þ„……†ø…††‡‡††‡‡ˆü‰ˆˆ‰‰ýЉŠŠ‚ƒþ‚ƒƒý„ƒ„„…þ†……†ü‡†‡††‡ˆþ‡ˆˆý‰ˆ‰‰úˆ‰Š‰‰ŠŠ‚ƒþ‚ƒƒ÷„ƒ„„ƒ„„…„„ý…„……þ†……†‡ˆþ‰ˆˆ‰Š‚øƒ‚ƒ‚ƒƒ„ƒƒý„ƒ„„ý…„……†þ…††þ‡††‡ˆø‡ˆ‡ˆ‰ˆ‰ˆˆ‰üŠ‚‚‚ƒø‚ƒƒ„„ƒƒ„„þ…„„…†‡þ†‡‡ˆ‰ˆö‰ˆ‰‰‚‚‚‚‚ûƒ‚ƒ‚ƒƒ„…†þ…††‡üˆ‡‡ˆˆ‰‚þ‚‚ƒþ‚ƒƒõ„ƒ„ƒ„…„……„……ý†…††ú…†‡††‡‡ˆþ‡ˆˆù‰ˆ‰ˆ‰‰‚ƒþ‚ƒƒþ„ƒƒý„ƒ„„ý…„……†þ…††‡þˆ‡‡ˆû‰ˆˆ‰‚‚ƒþ„ƒƒý„ƒ„„ý…„……ý†…††ñ‡††‡‡††‡ˆ‡‡ˆ‡‡ˆˆû‰ˆ‰ˆ‚üƒ‚‚ƒƒý„ƒ„„û…„…„……ý†…†† ‡ˆ‰þ€‚ ƒý„ƒ„„þ…„„…†‡ûˆ‡ˆ‡ˆˆù€€€€ý‚‚‚ƒþ‚ƒƒ„ý…„……ý†…††‡ˆü€€‚‚ýƒ‚ƒƒý„ƒ„„…ü„…„……†þ…††þ‡††‡÷ˆ‡ˆˆ€€ü‚‚‚ƒ„…†þ…††‡†‡ˆþ€€ý€‚þ‚‚þ‚‚ƒ„…„…†þ…††û‡†‡†‡‡ˆ€þ€€ü‚‚‚ƒþ‚ƒƒý„ƒ„„û…„…„……†þ‡††‡ýˆ‡€ý‚‚‚ø‚‚ƒ‚ƒ‚ƒƒý„ƒ„„ƒ„…†…†ú‡†‡‡†‡‡€‚þ‚‚ýƒ‚ƒƒö„ƒ„„…„……„……ý†…††÷‡†‡‡€€€ý€‚þ‚‚úƒ‚ƒƒ‚ƒƒ„þƒ„„…þ„……†þ‡††þ‡û€€€€ü€€ý‚‚‚ƒ‚ýƒ„ƒƒý„ƒ„„…ù†…†…†…††€ý€÷‚‚‚‚ƒ‚ƒƒõ„ƒƒ„ƒƒ„„…„……þ„……†î…††…†‡‡~~€€€€ú€€€‚þ‚‚üƒ‚‚ƒƒü„ƒƒ„„û…„…„……ü†……††ù…††~~€þ€€‚ƒ„þ…„„…†~ù€€€€€€ü‚‚‚ƒ„þƒ„„ø…„„……†…††…~€€ý€‚ýƒ‚ƒƒ„…†ú…††~}~~ý~€þ€€þ€€ú€€‚ƒþ‚ƒƒ„úƒ„„…„……ù„……†……~~þ~~€û‚‚‚‚ƒþ‚ƒƒý„ƒ„„…„…û†~~}~~þ~~€ü€€€ü€€‚ýƒ‚ƒƒü‚ƒ„ƒƒ„û…„…„……ý}~}}~ô~~~~€€€ ‚úƒ‚ƒƒ‚ƒƒü„ƒƒ„„…}~þ}~~ý~ý€€€€ý‚‚‚ýƒ‚ƒƒý„ƒ„„…|}~û~~~~û€€€€‚þ‚‚ƒþ‚ƒƒý„ƒ„„þƒ„„þ|}}ý~}~~ü~~ü€€€ý€ü‚‚‚ƒþ‚ƒƒ„þ…}}û~}~}~~ú~~~€‚þ‚‚ƒ„|}ý~}~~ý~€‚ƒþ„ƒƒ„þ}||}ý~}~~þ}~~þ~ü€€€þ€ý‚‚‚ýƒ‚ƒƒ„ûƒ„ƒƒ||þ}||}ù~}~~~ü€€€€‚‚þƒ‚‚ƒ„|ü}||}} ~ý~ø€€€€ý‚‚‚ƒþ‚ƒƒ„{|ý}|}}ý~}~~þ€õ€€€€€€‚ýƒ‚ƒƒý„{||û}|}|}} ~ €ü€€‚ûƒ‚ƒ‚ƒƒ{ý|{||ý}|}}ø~}~}}~}~~ô~~€€€€€û‚‚‚‚ýƒ‚ƒƒù{|{|{{||þ}||}ý~}~~ø~~€€þ€ü‚‚‚ƒý‚ƒ{{|}þ|}}~þ~€þ€€‚Œ ŽŽý‘ú’‘’‘‘’’ý“’““ŒûŒŒŽŽŽŽüú‘‘‘‘‘ý’‘’’ü“’’““ýŒ‹ŒŒúŒŒŒŽüŽŽþý‘‘‘’ý“’““ŒþŽŽþŽŽ‘‘’ù“’“ŒŒ‹ŒŒþŒŒöŒŒŽŽŽŽþŽú‘‘‘‘’õ“’’“‹Œ‹‹Œ‹ŒŒŽùŽŽŽþü‘‘‘’ú“’‹‹Œ‹‹ŒŽþŽŽý‘‘‘’‘’þŠ‹‹ŒüŒŒþŽŽþŽþýý‘‘‘’û‘’’Š‹‹Œü‹Œ‹ŒŒüŽŽŽþŽ ‘’þŠ‹‹ŒþŒŽþŽŽ þ‘‘’Šü‹ŠŠ‹‹ŒöŒŽŽŽŽŽûŽŽþ‘þ’ŠŠ‹þŒ‹‹ŒŒúŒŒŽŽúŽŽŽú‘þ‘‘Šý‹Š‹‹þŒ‹‹Œú‹ŒŒŒüŽŽŽûŽŽþ‘‰Š‹þŠ‹‹Œþ‹ŒŒŽþŽŽûŽŽûü‘‘‘Šþ‰ŠŠ‹Œ Žú‘‘‘‰‰Šü‹ŠŠ‹‹ýŒ‹ŒŒýŒŽ ‘‰Š‹þŠ‹‹ŒýŒŽþŽþ‘‰ýЉŠŠ‹ûŠ‹‹Œ‹‹ŒüŒŒŽýŽ ‰ Š‹ýŒ‹ŒŒûŒŒýŽŽŽüŽŽþþ‘‰‰ùЉЉЉŠŠ‹ŒûŒŒúŽŽŽŽüŽŽþŽú‰ˆ‰‰Š‹þŠ‹‹Œþ‹ŒŒŽþŽŽüŽŽû‰‰Šþ‰ŠŠ‹ŒþŒŒŽöŽŽŽŽŽûˆˆ‰‰þˆ‰‰Šý‹Š‹‹þŠ‹‹Œþ‹ŒŒýŒúŽŽŽŽˆü‰ˆˆ‰‰ùЉ‰ŠŠ‰ŠŠý‹Š‹‹öŒ‹‹ŒŒ‹ŒŒŒŒýŽŽ Žþ‡ˆˆ‰ýЉŠŠú‹Š‹‹Š‹‹ŒúŒŒŒŽþŽŽˆù‰ˆˆ‰ˆˆ‰‰þЉ‰Šö‹ŠŠ‹Š‹‹Œ‹ŒŒþŒúŽŽŽŽŽøŽŽŽ‡‡ˆþ‰ˆˆ‰Š‰Šþ‹ŠŠ‹ýŒ‹ŒŒŽýއˆˆý‰ˆ‰‰Šþ‰ŠŠ‹þŠ‹‹ŒŽ÷ŽŽˆ‡ˆˆ‡ˆˆú‰ˆ‰‰ˆ‰‰ýЉŠŠ‹þŠ‹‹Œ‹ŒŽŽ‡ˆþ‡ˆˆ‰Š‹þŠ‹‹ûŒ‹Œ‹ŒŒŽ÷†‡‡ˆ‡ˆˆ‡ˆˆ‰Šú‹Š‹‹Š‹‹ŒŽþŽŽ‡ˆ‰ˆ‰ûЉЉŠŠú‹Š‹ŠŠ‹‹ýŒ‹ŒŒöŒŒŒŒŽ‡þ†‡‡ûˆ‡ˆ‡ˆˆ‰ýЉŠŠ‹üЋЋ‹úŒ‹ŒŒ‹ŒŒŒ÷ŽŽ††‡†‡‡ ˆø‰ˆˆ‰‰ŠŠ‰‰Š‹þŠ‹‹Œ†ý‡†‡‡ýˆ‡ˆˆü‰ˆˆ‰‰Šü‹ŠŠ‹‹Œýކ†ý‡†‡‡ˆù‰ˆˆ‰ˆˆ‰‰Š‹þŠ‹‹úŒ‹‹Œ‹ŒŒýŒ†‡ýˆ‡ˆˆ‰Š‰Š‹þŠ‹‹ûŒ‹Œ‹ŒŒþŒŒ†þ…††ý‡†‡‡þˆ‡‡ˆþ‡ˆˆù‰ˆˆ‰‰ˆ‰‰üЉ‰ŠŠ‹Œþ‹ŒŒúŒ…††‡†‡üˆ‡‡ˆˆþ‰ˆˆ‰Š‰Šò‹Š‹Š‹‹ŒŒ‹Œ‹Œ‹ŒŒû…††…††‡þ†‡‡üˆ‡‡ˆˆû‰ˆ‰ˆ‰‰üЉ‰ŠŠù‹ŠŠ‹‹Š‹‹ Œ†…† ‡ýˆ‡ˆˆý‰ˆ‰‰øŠ‰ŠŠ‹ŠŠ‹‹Œþ‹ŒŒ…ý†…††ú‡†‡‡†‡‡úˆ‡ˆˆ‡ˆˆ‰þˆ‰‰øŠ‰ŠŠ‰ŠŠ‹‹Š‹Œþ……ü†……††‡†‡ýˆ‡ˆˆ‰úЉЉ‰ŠŠý‹Š‹‹Œû‹Œ…„……ý†…††ý‡†‡‡ˆ‡ˆ‰þЉ‰Šü‹ŠŠ‹‹ùŠ‹‹ŒŒ‹ŒŒû…„…„……ý†…††‡þ†‡‡ˆþ‡ˆˆ‰þЉ‰Š‹Š‹Œ„…„…þ†……†þ‡††ü‡††‡‡üˆ‡‡ˆˆ‰ýЉŠŠú‹ŠŠ‹Š‹‹Œ„ü…„„……†‡†‡ˆþ‡ˆˆ‰þЉ‰Šý‹Š‹‹øŒ‹„„……„……†û…††‡††‡óˆ‡ˆ‡ˆˆ‡‡ˆ‰‰ˆ‰‰Šþ‰ŠŠý‹Š‹‹„û…„…„……ü†……††þ‡††‡úˆ‡‡ˆ‡ˆˆü‰ˆˆ‰‰üЉ‰ŠŠ‹Š‹ý„ƒ„„…þ„……ü†……††þ‡††ý‡†‡‡üˆ‡‡ˆˆþ‡ˆˆ‰ûЉЉŠŠ‹þƒ„„…ú†……†…††÷‡†‡†‡†‡‡ˆ ˆ‰Š‰Šþƒ„„…þ„……†þ…††‡þ†‡‡úˆ‡ˆˆ‡ˆˆ‰Šü‰Š‰ŠŠþ‹ƒƒ„…†‡þ†‡‡ˆþ‡ˆˆ‰þˆ‰‰Šý‹Šƒƒ„…þ„……† ‡ˆ‰þЉ‰Šƒð„ƒƒ„ƒ„„ƒ„…„…„…„……ü†……††‡þ†‡‡üˆ‡‡ˆˆ‰þˆ‰‰üЉ‰ŠŠý‰‚ƒƒþ„ƒƒ÷„ƒ„……„…„……þ†……†‡þ†‡‡ ˆý‰ˆ‰‰Šý‰Š‰‰ýƒ‚ƒƒü„ƒƒ„„ý…„……ü†……††‡ˆþ‰ˆˆ‰ùŠ‰Šƒƒ‚ƒƒ„ú…„„…„……þ†……ý†…††þ‡††ý‡†‡‡ùˆ‡ˆˆ‡‡ˆˆ‰þˆ‰‰ùˆ‰Š‰Š‰‚‚ƒý„ƒ„„…þ„……ý†…††ü‡††‡‡ûˆ‡ˆ‡ˆˆ‰‚ùƒ‚‚ƒƒ‚ƒƒý„ƒ„„ýƒ…„„…ú†……†…††þ‡††‡÷†‡‡ˆ‡ˆ‡‡ˆˆø‰ˆ‰‰ˆ‰‚‚ƒþ‚ƒƒú„ƒ„„ƒ„„ý…„……†þ‡††ý‡†‡‡ýˆ‡ˆˆ‰þ‚‚ƒþ„ƒƒ„ý…„……†þ…††ü‡†‡††‡ˆõ‰ˆ‰ˆ‚‚‚‚‚ƒþ‚ƒƒý„ƒ„„ý…„……†þ…†† ‡ýˆ‡ˆˆ‰üˆ‚‚ýƒ‚ƒƒþ‚ƒƒú„ƒƒ„ƒ„„þ…„„… † ‡ˆ‰øþ÷øøþùøøþùøøùøùøùøùþøùùüøùøùùøùøùüøùøùùýøùøøùüøùøùùøùøùøûùøùøùùüøùøù ùþøùù øþùøøþùøøùøþùøøùøüùøùøøýùøùùûøùùøùùøûùøøùøøýùøùùþøùùýøùøøùüøùøùùýøùøøûùøøùøøøùøøùøøùøøþùøøýùøùùþøùùþ÷øøþùø øþùøøùøüùøùøøùþøùùóø÷øø÷øø÷÷øø÷øøùýøùøøøùøùøùùøùùøûùøùùøøù÷øþ÷ø øþùøøúùøùøùøøýùøùùøùøùþøùù÷÷øø÷÷ø÷÷øøþ÷øøþùøøþùø øùùøøùøøùùõøùøøùøøùøøùù øþ÷øøþùøøòùøùøøùøøùùøøùøøöùøùøùøùøøùùü÷ø÷øøþ÷øøþ÷øøþ÷øøûùøøùøøþùøøùüøùøùùøøùøùø÷÷øøþ÷øøùøùûøùùøùùøùóøùøùùøùù÷øø÷øøû÷øø÷øøþ÷øøúùøùøùøøþùøøùøùøùøù÷ýø÷øøþùøøþùøøùùøùøøùøøûùøù÷øøþ÷øø÷øø÷øø÷øø÷ø øùøúùøøùùøøûùøøùøøóùøùùøùøù÷ø÷÷øøþ÷øøþ÷øøþ÷øøþùøøûùøøùøøùøùøñùøùøù÷÷øø÷÷øø÷øøþ÷øøþùøøþùøøþùøøùùøùøùùøø÷ øþ÷øøþùøøþùøøùêøùøùøùøø÷ø÷÷øø÷÷ø÷øø÷øøþùøøþùøøùõøùùøù÷÷ø÷÷øøø÷øø÷øø÷øøþ÷ø øüùøùøøþùøøùøüùøù÷÷øü÷øø÷÷úø÷÷ø÷øøþ÷øøýùøùùùøùùøùùøøþ÷øøþ÷ø ø÷ûø÷ø÷øøþ÷øøûùøøùøøùøþùøøù÷ø÷÷ø÷ø÷ø÷÷ø÷ýø÷øøþ÷øøþ÷øøúùøùøùøøùøøùøøùøùùøø÷þø÷÷ø÷ø÷÷ø÷ø÷÷øø÷øøþ÷ø øûùøùùøøùùøùøùøù÷÷øþ÷øøø÷ø÷÷øø÷øøþ÷øøü÷ø÷øøþ÷ø øþùøøô÷øø÷÷ø÷ø÷øø÷÷ø÷øþ÷ø øþùøøùøþùøøþùøø÷þø÷÷úø÷÷ø÷ø øû÷øø÷øøþùøøûùøøùøø÷úø÷÷øø÷÷ø÷ùø÷ø÷ø÷øøþ÷øøþùøøüùøùø ø÷úø÷÷ø÷øø÷þø÷÷øü÷øø÷÷øü÷ø÷øøþ÷øøþùø ø÷ø÷þø÷÷ûø÷øø÷÷õø÷÷ø÷÷øø÷÷øøþ÷øø÷þø÷÷÷ø÷÷øø÷÷ø÷÷ø÷øû÷øø÷øø÷øþ÷øøøùøùøøùù÷÷þø÷÷ø÷ø÷ýø÷øøú÷ø÷ø÷øøþ÷ø øþùøøûù÷÷ø÷÷þø÷÷üø÷ø÷÷øý÷ø÷÷þø÷÷ø÷ø÷þø÷÷úø÷÷ø÷øø÷úø÷ø÷÷øøþ÷ø ø ÷ø÷þø÷÷øü÷ø÷øøþ÷øøý÷ø÷÷ýø÷øøþ÷øø÷þø÷ ÷üø÷÷øø÷þø÷÷ýø÷øø÷øù÷ø÷øø÷ø ø ÷ø ÷þø÷÷üø÷÷øøþ÷øø÷ûø÷÷ø÷÷ø÷þø÷÷ø÷ýø÷øø÷øü÷ø÷øøþ÷ø ø÷þö÷÷ûø÷øø÷÷øø÷ø÷ø÷ø÷÷ø÷øý÷ø÷÷ø÷øû÷øø÷øø÷ø ÷þø÷÷ø÷ø÷ø÷ûø÷ø÷øøû÷øø÷ø ø÷üø÷ø÷÷óø÷øø÷ø÷ø÷øø÷øøø÷øø÷÷ø÷øøþ÷øø÷þø÷÷øý÷ø÷÷úø÷÷øø÷÷øü÷øø÷÷ øüö÷ö÷÷þø÷÷üø÷ø÷÷öø÷ø÷ø÷øø÷øøþ÷øøü÷øø÷÷øû÷øø÷øøûö÷÷ö÷÷þø÷÷þø÷÷ø÷þø÷÷þø÷÷øø÷øø÷÷ø÷øøþ÷øø÷þö÷ ÷þø÷÷üø÷ø÷÷ùø÷ø÷øø÷÷þø÷÷ûø÷øø÷÷ ø÷üö÷ö÷÷üø÷ø÷÷þø÷÷ø÷ûø÷ø÷øøþ÷øøö÷þö÷÷ýø÷øø÷úø÷÷øø÷÷øþ÷øø÷øü÷öö÷÷üø÷ø÷÷ûø÷÷ø÷÷øþ÷øø÷ýø÷øø÷ùø÷ö÷÷ö÷÷þö÷÷þö÷ ÷üø÷ø÷÷üø÷ø÷÷üø÷ø÷÷øþ÷øø÷ýø÷øøþ÷ööý÷ö÷÷þø÷÷ûø÷÷ø÷÷øí÷øø÷ø÷÷ø÷øø÷ø÷÷ø÷ø÷÷öø÷ö÷ö÷öö÷÷þø÷÷þø÷÷öø÷÷ø÷ø÷ø÷øøþ÷øø÷þö÷÷ûö÷÷ö÷÷ö÷þø÷÷øï÷ø÷ø÷ø÷÷ø÷÷øö÷öö÷÷úö÷÷öö÷÷þö÷ ÷þø÷÷þø÷÷ø÷úø÷÷øø÷÷øþ÷øø÷þö÷÷÷ö÷ö÷ö÷÷ö÷÷þø÷ ÷üø÷ø÷÷ø÷þø÷÷øú÷öö÷ö÷÷þö÷÷þö÷ ÷þø÷÷úø÷÷øø÷÷ø÷ùø÷ö÷öö÷÷ùö÷öö÷ö÷÷þö÷ ÷ø÷ø÷ûø÷ø÷øøý÷ø÷÷ûö÷öö÷÷ùö÷ö÷öö÷÷þö÷÷þø÷÷ûø÷÷ø÷÷ø÷üø÷÷øø÷ýøö÷÷þö÷÷öý÷ö÷÷üö÷ö÷÷þø÷÷ø÷øü÷øø÷÷þøöö÷öö÷öö÷ö÷÷ö÷÷þö÷÷þö÷÷üø÷ø÷÷ùø÷ø÷ø÷øøý÷ö÷÷öú÷ö÷öö÷÷üö÷ö÷÷þø÷÷ûø÷øø÷÷øù÷ø÷÷ö÷ööþ÷öö÷öù÷ö÷ö÷ö÷÷ø÷ø÷öþ÷ööþ÷öö÷ûö÷öö÷÷ö÷þö÷÷ø÷øø÷÷ø÷÷ø÷÷ö÷öþ÷ööý÷ö÷÷þö÷÷þö÷ ÷þø÷÷øý÷ø÷÷üø÷÷øøÿŽþŽŽù,Ž þ,ŽŽþ-þŽŽŽþ,ýŽŽŽùŽŽŽ-üŽŽŽüŽŽ-ýŽŽŽýŽ-þŽŽüŽ,ŒûŽŽŽŽûŽŽ,þŒŒŽýŽ,úŒŒŒýŽŽŽüŽŽ,ýŒŒŒúŽŽŽŽ-ŒŽ-þ‹ŒŒøŒŒŽŽþ,Œþ‹ŒŒûŒŒûŽŽ,‹ŒþŒŒ-þŒ‹‹ŒþŒŒþŽ,‹ýŒ‹ŒŒú‹ŒŒ-þŠ‹‹Œþ‹ŒŒýŒ-ý‹Š‹‹Œú‹ŒŒŒ-ý‹Š‹‹ýŒ‹ŒŒ-‹þŠ‹‹Œþ‹ŒŒþ,Š‹Œþ‹ŒŒ-òŠ‹ŠŠ‹‹Š‹Š‹‹ŒŒ‹‹Œ-ùŠ‰ŠŠ‹Š‹‹úŒ‹‹ŒŒ,‰Šú‹Š‹‹Š‹‹-ýЉŠŠü‹ŠŠ‹‹üŒ‹‹,‰Š‹þŒ,‰Šþ‰ŠŠ‹-‰úЉЉ‰ŠŠû‹Š‹‹,þˆ‰‰ûЉЉŠŠ‹-ˆ‰ýЉŠŠ-þˆ‰‰öˆ‰‰Š‰‰ŠŠ‰ŠŠ-ˆ‰Š-ˆ‰þˆ‰‰ýЉŠŠ-ˆþ‰ˆˆ‰Šþ‰,ü‡ˆ‡ˆˆ‰þˆ‰‰Šþ‰,ˆö‡ˆˆ‰‰ˆˆ‰ˆ‰‰þŠ,‡ˆþ‡ˆˆ‰ûˆ‰‰Š,‡ˆþ‡ˆˆ‰-‡ˆþ‡ˆˆü‰ˆˆ‰‰-‡ùˆ‡‡ˆˆ‡ˆˆü‰ˆˆ,þ†‡‡ˆþ‡ˆˆ-† ‡úˆ‡ˆˆ‰,†ý‡†‡‡ýˆ‡ˆˆý‰ˆ,†ü‡††‡‡ˆ-†ý‡†‡‡ýˆ‡ˆˆ-…†ý‡†‡‡-ú†…†……††ý‡†‡‡ýˆ‡,…ú†…††‡††‡þˆ,…ý†…††‡-þ„……†þ…††‡-ü…„„……ý†…††‡-…þ„……†þ‡††-„ü…„„……ý†…††þ‡,„ý…„……†-þƒ„„…†ü…††,„ü…„„……ý†…††þ…,ûƒ„„ƒ„„ü…„„……û†……†,üƒ„ƒ„„ý…„……-ñƒ„ƒ„„ƒƒ„„…„…„„……-ƒ„…þ„……-ƒù„ƒ„ƒ„ƒ„„ý…„……-þ‚ƒƒ„û…„……,ù“”“””“””•-“”þ•””•ý”•,“ý”“””•-’“ü”““””•þ”, “”ú•”•””,“ú”“””“””þ•,û’““’““”-’ý“’““ø”“”““””,’“’“”þ“””-þ‘’’ý“’““”ý“”,þ‘’’“þ’““þ”,ú‘’‘’‘’’“þ’““ý”“,‘ü’‘‘’’“þ’““-‘’“ü’“’““-‘ü’‘‘’’“þ’““-‘ö’‘‘’‘’‘’’““-‘’“-û‘‘‘’ö‘’‘’‘’’““,þ‘‘’þ‘’’-‘þ‘‘’-ù‘‘‘‘û’‘’’,‘ú’‘’‘’,þù‘‘‘‘‘-ù‘‘‘‘‘-üü‘‘‘-ü‘‘‘-þþ‘þ‘,þŽ‘-ŽýŽ þ‘,üŽŽþ‘,ŽüŽŽü,øŽŽŽŽ-ŽüŽŽþ,þŽŽþ-ŽþŽŽúŽŽŽ-ŽøŽŽŽŽþ,üŽŽŽþŽ-ýŽýŽŽŽ-ŽþŽ Ž-ŽþŽ,øŒŽŽŽŽŽ-þŒþŒŽþŽŽ-þŒŒþŒýŽŽŽ-ŒüŽŽŽ-þ‹ŒŒüŒŒüŽŽ,ŒüŒŒúŽŽŽ,‹Œ -‹Œü‹ŒŒûŒŽ,úŒ‹Œ‹‹ŒŒŒ-þŠ‹‹ŒûŒŒ-ý‹Š‹‹ýŒ‹ŒŒûŒŒ,ý‹Š‹‹Œþ,ûŠ‹ŠŠ‹‹Œ‹Œ-Š ‹Œþ‹ŒŒ-Šû‹Š‹Š‹‹ýŒ‹ŒŒ-Šý‹Š‹‹ûŒ‹Œ‹,þ‰ŠŠû‹Š‹Š‹‹Œ-Šþ‰ŠŠ‹þŒ,‰Š‹þŒ,þ‰ŠŠü‰ŠŠ‹‹þŠ‹‹-‰úŠ‰ŠŠ‰ŠŠý‹Š‹‹-‰ýЉŠŠþ‰ŠŠ‹-‰Šþ‰ŠŠ‹-ˆ‰Šþ‰ŠŠü‹Š‹, ùüúùúùù-ùüúùù,ùúþù,ùþú,ù-ù-ùüúùù,ù-üùøøùùøùüúùù,ùþøù ùýúù,ùûøùùøùù-ù-ùøøùøùøùøùù-÷øùùøøùùøùù-þøùùþøù ùýøù,ùøýùøùùþø,ýùøùùüøùøùù-øùþøùù-øýùøù ùüøùù,ùøùþøùùýøù,ùøüùøøùùþøùùþø,øùþøùùøù-þùøøýùøùùúøùùøøùù-ø ùþø,ùùøùùøùøøüùøøùùø- øùþøùùþø,þøùùõøùùøùùøùøùøø-ýøùøøúùøùùøùù-ø÷ùøùøøùùøùùýøù,þùøøùþøùùø-þùøøþùøøøùøùøùùø,üøùøùùøüùøøùù-øùøüùøøùù-øùøùýøù,øþùøøþùøøûùøùø,øùøþùøøüùøø,øþùøøüùøøùù-øóùøùøøùøøùøùù,øþùøøþùøøûùøøù,øûùøøùøøùùøùøùø,øþùøøþùøø-øþùø ø-øþùøøùýøùøø- øþùøøùþø,øýùø,ø-ø-øþ÷ø ø-ø-üø÷÷ø ø-ýø÷øøþ÷øø-ø÷ ø-øù÷øø÷ø÷øø-øþ÷øøþ÷øø-üø÷÷øøþ÷øøü÷øø,þø÷÷ø÷øû÷ø÷ø,ü÷ø÷ø ø-÷ø÷ø÷þø,þ÷øøþ÷øøú÷ø÷ø÷øø-ø÷ø÷ø÷ø÷øøû÷ø÷÷øø-ý÷ø÷÷þø÷÷ýø÷øøü÷øø,üø÷ø÷÷úø÷øø÷øø-ø÷ø÷þø,þ÷øøø÷øø÷ø÷÷øøþ÷øø-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-€€€€+BCDþCDD+BCD+ABCBCüDCD*ABýCBCCþD*ABþABBCD+ABûCBCBCC+AüBAABBþABBC+ýA@AA BýCB*ýA@AABúCBBCB*û@AA@AAýBABBC+@ûA@A@AABþC*@Aü@A@AAýBABB+@ AB+ú@??@?@@ AþB*?ý@?@@ýA@AAþB*?þ@??@úA@A@@AA+?@ü?@?@@ûA@A@AA+ö?>?@??@??@@A+?û@?@?@@Aý@A*ü?>>??þ@??@üA@@*>?@þA*>?õ@?@??@@A@A*>?þ>??@ú?@?@A*þ=>>ü?>>??û@?@?@@+>þ=>>?þ>??û@?@?*=>ý?>??þ@*=>ý?>??+=ü>==>>?þ>??+þ<==>=ý>=>>?+þ<==>=>ú?>>??*<=þ<==>û?>?>*<=>þ=>>þ?*þ<==þ<==ý>=>>?+<ý=<==ù>=>=>>*<=>ü=>>*;<ú=<<=<==ú>=>==*ý;<;;< =+;ý<;<<=þ>*;ü<;;<<=+;<=ü<==*þ:;;û<;<;<<=ü<==*;ü<;;<<=+ý;:;;þ:;;ý<;<<þ=*:ü;::;;ý<;<<þ=*:ý;:;;<;<+:û;:;:;;ø<;<;;<<*û9::9::;:;ü<;;*9:;þ:;;þ<*9û:9:9::þ;::;þ<*9:9:û;:;:;;+þ899þ:99:;+89:;þ:*ý9899:ü;:;*ö89899899:99÷:9::;;::*89ü:99::+8ü98899:+þ788ö98989899:99û:9::*ü78788ý9899ý:9::þ9*ý87889þ:*ú7887788þ9889ü:9:*78789þ899þ:*78ø798898899+7þ677 89+þ6778ý989+LýMLMMN+üKLKLLMþLMMüNMN*ûKLLKLLýMLMMüNMN*þKLLüMLLMM+KLüMLLMM+KùLKKLLKLLøMLLMLMM*KþJKKýLKLL÷MLMLLMML*ýKJKK L+þJKKþJKKLKLþM*þKJJKLþKLLþM*JûKJKJKKL+JþKJJKL+þIJJýKJKKüLKL*IJþKJJKLKþL*IJþKJJKþL*IýJIJJüKJJKK+øIJIIJIIJJKþL*IJþKJJK+þHIIþJIIJþIJJûKJKJ*üIHHIIJKüJKK*üIHHIIJþIJJüKJJ*HIõJIJJIIJJKJ*úGHIHHIIJ+ôGHHIHIIHIIHIIJ+üGHGHHIHIûJIJI*GHIüJII*üGHGHHIJ+øHGHGHHGHHIþJ*GHýIHII+GýHGHHûIHII*ýGFGGHGHIþH*üFGFGGHIH+FGúHGGHGHH+ýFGFFGH+FGFGýFHGGH+FýGFG GH+FþEFFGFGH+ýFEFFýGFGG+ûEFEEFFGýHG*EFüEFEFFýGFGG+EüFEEFFüGFFGG+ýEDEEþFEEFG+E FüGFG*üDEDEEFGýFG*DúEDEEFEEF+DEýFEFF+DúEDEEDEEûFEFEFF+DþEDDùEFFEFEFF+þCDDøEDEDDEDEEFýEF*CDEüFEE*þCDDüCDCDDE+CúDCCDCDDEþF*CDúEDEDDEE+CþBCCDúEDEDE*þBCCþDCCDüEDD*BCûDCDCDDEýDE*CBCüDCCDDþE*BCDþCDD+ýBABBCýDCDD+BýCBCCýDCDDþC* BCúDCDCD*ABüCBBCCD+þABBþABBC+û@ABBAABC+ýîïîîýïîïïþîïïîï+ùïîîïîïîîùïîîïîîïïþî*úîïîîïîîùïîîïîîïïî+îþïîîïûîïîîïï+üîïïîîûïîïîïïîïþî*ýîïîîïîïîþï*þïîîïîïîúïîïîï*îñïîîïîïïîîïïîîïîî+îïîýïîïïüîïî* îöïîïîîïîïî*ïî+îþïîîþïîîûïîïî*îþïîîúïîïîïîî+îþïîî+îüïîï* îýïîïïî+îþíîîþïîîýïî* îþïîîïþî*úîíîîíî î+îþï*üîííîî+îþíî î+íîþíî îþï*îþíî î+îþíîîþíîî+÷îíîííîîíî î+üîííîîþíîîþíîî+ýîíîîøíîîíîîíîî+þîííýîíîîüíîíîî+úîíîîíîîíî+îüíîíîî+ýíîííî+þîíí îí+îûíîííîîíî+úíîíîíîîûíîíîííî+íûîíîíîîíîþí*þíîîíýîíîîþíîîüíîî*íòîíîíîîíîííîîíîî+þíîîúíîîíîííûîíîî*ýíîííõîíîíîîíîíî*ýíîíí÷îííîîíîíîîýíî*üíîîííþîííîíýîí*þîííòîííîîíîîíîííî*þîíí÷îíîíîííîííýîí*îýíîííüîííîîýíî*þîí íîùíîíîíî*öíîíîíîíîíîîíüîíîíí+íîýíîííþîííüîíí*íþîííùîíîîíí*íûîííîííîýíîííþî* íîíîýíî* íûîííîíí+ íöîííîîííîí*íþîííþî* íþîííýîí*íþîííüîíí*í+ íúîííîîíí+ íþîíí+þìíí+í+íþìííþìíí+íþìí íüîíí*íþìííþìíí+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿþDE EFGþFGGHýIHIIûJIJIJJKþJKKLôKLKLLDDEEDDEEøFEFFGFFGGýHGHHIùHIIJJIJJýKJKKýLKDDúEDEEDEEFþEFFGýHGHHþIHHIJKDþEDDùEDDEEFEEFGýHGHHüGHHIIþHIIýJIJJKþCDDûEDEDEEýFEFFþGFFGýHGHHIJþIJJüKJKJJKCDýEDEEýFEFFGùFGGHHGHHùGHHIHIHHIüJIIJJýKJKKûCDDCDDEýFEFFGûFGGFGGHGHIüJIIJJüKJKCCDþCDDEFGõHGHHGHHIIHIIJþIJJKþJCCDþCDDEýFEFFòGFGGFGGHHGHGGHHIöHIHIJIJJIJJûKJKBCCûDCDCDDEþDEEúFEFGGFFGHGHIþHIIJûKCBBCCýDCDDýEDEEFEFGFGúHGHHGHHIñJIIJJIJJBCCBCBCCDøEDEEFEEFFGHþGHHýIHIIJûBCCBCCDþCDDEþDEEFþEFFüGFFGGþHGGýHGHHýIHIIûJIIJBBCþBCCýDCDDþCDDEFEFøGFFGHHGHHIûHIIJIIAüBCBCCDEDýEDEEFGþFGG HIJBCþBCCDþCDDýEDEEýFEFFüGFFGGþHGGýHGHHöIHHIIHIIABBüABBCCöBCCBCCDCCDDüEDDEEFGþFGGúHGHHGHHIABþABBCDýEDEEüFEEFFøGFGFGFFGGHûIHIIAABCùBCCDCDCCDüEDDEEFEFýGFGGüHGGHHùI@ABAABBüCBBCCDþEDDEüFEEFFýGFGGHûIAA@AABABCDýEDEEýFEFFGþFGGýHGHHü@A@AABCûBCBBCCDýEDEEüFEEFFGþFGGHùGH@A@@AABCDûEDEDEEFGýHGHH@Aþ@AA÷BAABACCBCCüDCCDDýEDEEFüGFFGGþHGG@þA@@ABAùBCBCCBCCúDCDDCDDóEDDEEFEFEFEEFFGûHGH?@@üA@@AAþBAABýCBCCþDCCDEþDEEôFEEFFGFFGFFGGýHG@@üA@@AAùBAABAABBCB CDEýFEFFGþFGGþ?@@AþBAAùBCBCBBCCýDCDDEþDEEFþEFFþGFFG?@AýBABBýCBCCúBCCDCDDþCDDEFG?@Aþ@AABýCBC CDEþDEEFúGFFG>??ý@?@@úA@AA@AAüBAABBóCBCCBCDCDCDCDDEûDEEDEEFþEFFG?@þ?@@ABþABBýCBCCþDCCDùEDDEEDEEFþEFF?>?@ýA@AABþABBûCBCBCCDþCDDEþFEEFûEF>?>>?@AýBABBCýDCDDýEDEEFþEFF>ý?>??ô@?@@?@A@@A@AABABùCBBCCBCCýDCDDEFöEFE>>?>?>??ý@?@@úA@AABAABøCBCBCCBCCDþEDDEFþ=>>?þ>??ú@?@@A@@ABCüBCBCCDûEDEDEEûFE>=>>?þ>??@þ?@@ýA@AAõ@ABABABABCBBüCBBCCDþCDDEú=>>==>>þ?>>?ý@?@@AúBABBABBCDüCDCDDüEDDEE=>þ=>>ü?>>??ü@??@@ýA@AABCþBCCüDCCDDþEDDE=ü>==>>ý?>??@þ?@@Aþ@AABþCBBCDEDþE==>þ=>>?þ>??@ABCþBCCýDCDDüE=<==>þ=>>?>ú?@?@?@@üA@@AABüABABBCþBCCûDCDCDD=þ<==>þ=>>û?>?>??@þ?@@ABþABBýCBCCDû<==<== >?ü@?@??@ýA@AAüBAABBCþBCCD<û=<=<==ý>=>>ý?>??@ûA@A@AAýBABBûCBCBCCDöC<<=<<==<==>ø?>??>??@@þ?@@Aþ@AABCûDCCD<<ý=<==þ>==>ú=>>?>??ý@?@@ûA@A@AAþBAABC<=þ<==ü>==>>?þ>??ý@?@@A@AþBAABCþBCCû;<;;<<û=<=<==þ>==>?@?@Aþ@AABCþ;<<ü=<<==þ>==>?@?@AýBABBôCBCBBCC;<<;<<ý=<==ý>=>>ü?>>??ú@?@@?@@AþBAABþABBþ:;;<ú;<<=<==>þ?>>?û@?@?@@þA@@A B;<=ü>==>>ý?>??ý@?@@AýBABBùCBB;;:;;<ý=<==>? @ABò:;;:;:;<;<;<;<<=þ<==>þ=>>þ?>>?@þ?@@ABüA:;::;<=ü>==>>?ü@??@@þ?@@AûBABB::û;:;:;;ú<;<;;<<=þ<==û>=>=>>û?>?>??û@?@?@@Aþ@AAýBA:: ;<ú=<<=<==ú>=>>=>>?ü@??@@Aþ@AABý:9::ý;:;;<ú=<=<<==> ?@AüB9:99:;þ:;;þ<;;<=ö<=<=>==>=>>?ù@??@??@@A9ý:9::ý;:;;<ü=<<==>=> ?@þA99:;þ:;;<û=<=<==ý>=>>?þ>??ý@?@@þA99:ü;::;;ø<;<<=<<==>þ?>>ý?>??ý@?@@üA@A@NOþNOOPþOPPúQPQQPQQRþQRRýSRSSTUTUüTUUNNOúPOPPOPPýQPQ QRS TUNONúONOOPOO PQüRQQRRüSRRSSTûSTUTUUNùMONONNOOüPOOPPúQPPQPQQýRQRRþSRRSúTSSTSTTúUMMNMNNøONNOONNOOýPOPPýQPQQýRQRRöSRRSRSRSSTTþSTT÷UNMMNNMMNN OýPQPPýQPQQRþQRRSûTSTSTTþUMMNþMNNOPþOPPþQPP QRSýTSTTþLMMNþMNNýONOOPþQPPQþRQQRSRSøTSSTTMLMMNþMNNüONNOOüPOOPPýQPQQR STþLMMýNMNNùONNONNOOüPOOPP QRSûTSSTLLMúNMMNMNNýONOOýPOPPþQPPQRþQRRýSRSSýTSLLMüLMLMM NOþPOOPúQPQQPQQüRQQRRþSRRSLúMLLMLMMûNMNMNNýONOOPþOPPþQPPQRøQRQRQRSRRSüRSSLLüMLLMMNþONNOPOPøQPQPPQPQQ RSLþMLLMNþMNNOþNOOüPOOPPQþPQQýRQRRúSRRSSKKLýMLMMNOþPOOPQRþQRRüSRLKKLýMLMMþNMMNOþNOO PQRùSLKKLKLLMNþMNNOþPOOPýQPQQþRQQR÷SRJKKLKKLLMNþMNNO PQüRQQRRKLúMLLMLMMúNMNNMNNOþNOOPQRùQRRQRJKKLþKLLýMLMMNôONONONOOPOOPPýQPQQRþJKKþJKKýLKLLMLMüNMMNNOüNONOOúPOOPOPPQþPQQRQþRJJKLKLMþLMMúNMMNMNNOPþOPPQJKþLKKLMüLMLMMNOþNOOýPOPPQþPQQJKþJKKûLKLKLLûMLMLMMýNMNNONOPOPýQPQQJþIJJKþJKKLýMLMMLMNþONNOþPOOýPOPPQJKLMLMNüMNMNNOûPOPOPPQýPQIIJKþJKKþLKKLMúLMMNMNNþMNNýONOOPþOPPQüPIIJJKJKLMþLMMN÷ONNONNOOPPþOPPþQPPIýJIJJKþJKKúLKKLKLLMþLMMNþMNNýONOOýPOPPI JKþLKKLüMLLMMüNMMNNüMNNOOþNOOùPOPOPPIIJþKJJKLKLMþNMMýNMNNýONOOPûOIHHIIýJIJJKLMúNMMNMNNþONNOPøOPHHIHHIIJüKJJKKþLKKLûMLMLMMNþMNNýONOOPHýIHIIJIJúKJJKJKKøLKLKLLKLLMþLMMNûONONOOþNOOþPHHûIHIHIIJKJKýLKLLMûLMLLMMýNMNNONOþGHHIûJIJIJJ KLþMLLüMLLMMNúONOONOOþGHHIøJIIJIJIJJKþJKKûLKLKLLMþLMMúNMNMMNNONûOGHGHHýIHIIJüIJIJJKþLKKLýMLMMýNMNNOúGHGHGHHúIHHIHIIýJIJJúKJKJJKKúLKKLKLLMþLMMNMNôONNHHGHGHHGHHýIHIIJKþJKKüLKKLLþKLLMþLMMNG HIJþIJJKóJKJKKLKKLKLKLLMþLMMýLMNNGHI÷HIIJIIJIJJûKJKJKKúLKLKKLLMNGþFGGHúIHIHHII JKLþKLLMüNMNMMNGþFGGHþGHHüIHHIIJþIJJKüJKKLLKLûMLMLMMNúMNMGFGGHýIHIIýJIJJ KLþKLLýMLMMúNMMFFGGüHGGHHIJKýLKLLMþLMM÷NFFGFFGFGGýHGHHI JKLMF GHúIHIHHIIýJIJJKLþKLLMûLMMEFFGüFGFGGHIHõIHIIJIIJIIJJýKJKKþJKKLMLMûEFFEFFGHþGHHIûHIIJIIJ KLýMEFFþEFFGHüGHGHHIþHIIýJIJJKüLKKLLýMLEEFýGFGGHþGHHýIHIIJùIJJKKJK KLEFGûFGFFGGHýIHI IJKJKûLKLLKKLEýFEFFþEFFGúFGGFFGGüHGGHHIJKþJKKLþDEEFEýFGFFGHIHIþJIIJþIJJýKJKKLEþDEE FG HIþHIIJþKJJKûLEDDEEFúGFGGFGGHIHIüJIIJJüKJJKKDþEDDEùFEFEFEFFGFGHIüHIHIIJüKJJKKýLKDDüEDDEEFþEFFGHüGHGHHýIHIIûJIJIJJýKJKKþCDDEFEüFEEFFGþHGGýHGHHýIHIIþHIIJóIJJKKJKKJKCCDDúEDEDDEE FúGFGHGHHýIHIIþJIIJKøJKKCCDCDDýEDEEFûEFFEFFýGFGGHIJüIJIJJûKCDCDDþEDDEFþEFFüGFFGGHGHùIHIIHHIIýJIJJïþîïïþîïïüîïîïïüðïðï ïðûïðïïðð÷ïððïïððïððûïîïîïïþîïïþîï ïþðïïþðïïùðïðïïðïïùðïððïïððûïðïîïïîïþîïïþðïïüðïïððïðïðþïððþïððîïúîïïîîïïþðïïüðïðï ïðïüðïïððýïîïïþðïï÷ðïïððïðïððïûðïðïððþïððüïîîïïúîïîïîïïþîïïþðï ïþðïïðûïððïððîïþîïïûîïïîïïþîï ïþðïï÷ðïðïïðïðïïúðïïðïððïýîïîîïöîïïîïîîïîïïþðïïøðïððïððïïðýïîïïîïîïîïðýïðïïþðïïþðïïðïóîïîïïîïîïîïîïïüîïîïïüîïîï ïþðï ïðïþðïïøðïðïîîïîîúïîïîîïïþîïïþîï ïþðïïðúïðïïðïïþðïïúîïïîîïïþîïïîïî ïþðïïþðïïþðïïøðïðïðïïîîïîøïîîïîïîïïþîïïîïþðïïþðïïþðïïòîïîïîïîïîîïîîïïûîïïîïïþîïïþîïïþðïïðúïððïïîîïþîïïüîïîïïþîïïîïîïþðïïþðïïððïïîïîïïîîïîîïïîîüïîîïïþîïïþðïïþðïïþðïïýîïîîïîïüîïîïïøîïïîïïîï ïøðïïðïïðïïðîüïîïîî÷ïîïîîïïîïïþîïïþîïïþðïïóðïððïîïîîïïîïïîïîïþîïïîùïîîïîîïïþîïïþðï ïóîïîîïïîïïîîïîîïîýïîïïþîïïþîïïûîïîïîîþïîîðïîïïîîïîïîïîïïîïïþîï ïþðïï÷ðïððïîîïîîøïîïîïîïîîïîýïîïïîïüîïîï ïþðïïþðîîúïîîïïîîïýîïîîýïîïïûîïïîïïîïþîïïþîïï îüïîîïïîúïîïïîïïüîïîïïîþïîîïîþïîîþïîîïüîïïîîúïîïïîïïüîïîï ïîþïîîþïîîïîïþîïïîïþîïïþîïïþîï ï îïîûïîïîïïîïîþïîîüïîîïïþîï ïîþïîîûïîîïîîïîöïîïïîïïîîïïþîïïþîïï îþïîîþïîîïîþïîîúïîïîïîîïîïîïîïîüïîïîîïîüïîîïïüîïîï ïþîïïîþïîîþïîîïîïîïûîïîîïïþîïïúîíîîíî îþïîîïîïþîïïöîïîïïîïïîïïþîïïîïúîïïîïîîüïîïîîïþîïïî ïîüíîíîîþïîîþïîîïî÷ïîîïïîïîïïüîïîïïþîïïúíîîííîîþíîîþïîîòïîïîîïîïîîïîîïïî÷ïîîïîîïîïïûîïîîïïîþíîî÷ïîïîïîîïîîüïîîïïîïîúïîîïîïïûîïííîîþïîîüïîîïïüîïïîîïþîïïîûíîîíîîíîþïîîþïîîþïîîøïîïïîïîïïþîïïûîïííîîþïîî÷ïîîïïîîïîîþïîîýïîïïûîïîîïïýîïîîþíîîþíîîþïîîúïîïîîïïýîïîîþïîîïþîïïøíîííîîíîîíîþíîîûïîïîïïøîïïîïïîïïõîïïîïîïîïïîîúíîíîíîîþíîîþïîîþïîîþïîîþïîîòïîïîïîïïîîïïîïïýîïîîíîþíîîûíîîíî îþïîîïéîïîîïîïïîïïîïïîïîïîïîîííîþíîîþïîîûïîîïîîþïîîïþîïïîíîþíîîöïîïîïîïîïî îïüîïïîîíúîííîíîîûíîîíîîþïîîþïîîïîïîþíîîøíîíîîííîîþíîîúïîîïïîîïîýïîïïîïíîíöîíîíîííîíîîíîûíîîíî îþïîîïûîïîïîîïþîííñîíîíîîíîíîîíîíîîþïîîïîùïîîïïîïïîùïîíîííîîíþîííîþíîî÷ïîïîîïîïîîïîñïîïïîïííîííîîíîîíîþíîîþíîîþïîîïîïîþïîîûíîíîííîúíîîííîîþíîîíîûíîîíîîþïîîïýîïîîõïîîííîîíîîííþîííúîíîííîîþíîîþíî îþïîîþïîîþïîîüïîïîîýíîííîýíîííüîííîîúíîíîíîîþíî îïþîïïóîïîïîîïïîííîííîíîúíîíîíîîúíîîííîîþïîîñïîïïííîíîííîíîííúîíîííîîíúîíîîíî îþïîîïûîïîïîîîïíîíîííîííîîííîííîîüíîîííõîíîîíîíîîíî îþïîîüïîïîîíþîííñîíîííîíîííîíîîííúîíîîíîîþíîîþíîîþïî îøïííîíîîííîôíîííîíîíîíîííüîííîîñíîíîííîîíîíîîíî îïîíþîííîþíîîíîþíîîþíî îþïîîíþîííþîíí÷îííîîííîííîûïîïîííþîííþîííîíîþíîîþíî îüíîíîîþïîîûíîíîííýîíîî÷íîîííîííî îúíîíîíîîþíî îýïîííüîíîííýîíîîíîþíîîøíîîíîîíîîÿLMNýONOOýPOPPQRSþRSSTLMNMNýONOOPþOPPýQPQQRQRSþRSSúTSTSKLLþMLLMNMNOþNOOPþOPPQPQ RýSRSSþKLLMþLMMþLMMNOüPOPOOPýQPQQRýSRSSøKLLKLLMLLøMLLMMNMNNüONONNOPþOPPQýRQRRþQRRSKLþKLLMùNMNMNMNNOþNOOùPOOPPOPPQýRQRRýSRSSKþLKK÷LKLMLMLLMMNMNüONNOOûPOPOPPQýRQRRSþJKKýLKLLüMLLMMNOþNOOPúQPQQPQQýRQRRJKüLKKLLýMLMMúNMMNMNNüONNOOüPOOPPüQPPQQRJKLþKLLýMLMMNõONOONOOPPOPPþQPPQRþKJJKLýMLMMüNMMNNOPúQPQPPQQRJýKJKKLþKLLþMLLMþLMMýNMNNýONOOùPOPOPOPPýQPQQþRQQþRJJKLþKLLMNýONOOPQþPQQùRJIJJKJJýKJKKLKLMùNMMNNMNNýONOOúPOOPOPPQþIJJüKJJKKýLKLLM÷NMMNNONNOONO PýQPQQIJKþJKKLMLMüNMMNNOþNOOþNOOýPOPPýQPQQIJþKJJýKJKKLMþNMMNOþNOOþPOOýPOPPQIJþIJJKûLKLKLLMüNMMNNOPþOPPQýPQIIJKûJKKJKKLýMLMMúNMNNONNýONOOüPOOPPIýJIJJþIJJüKJJKKLùKLMMLLMMùNMMNMNOOþNOOPúOPQPHIIýJIJJúKJKKJKKLûKLLMLLMNOúPOPPOPPþIHHIýJIJJKþJKKLþKLLþMLLMùNMMNNMNNOþPOOüPOPHHýIHIIüJIIJJKþJKKýLKLLMNþMNNúONOONOOHIHIþJIIJKþJKKýLKLL MNúONONNOOùPOGGHHIIüHIHIIJùKJJKKJKKLýMLMMNûMNMMNNüONNOOýPGHHûIHIHII JKùLKKLKKLLüMLLMMNMNOþNOOGHüIHHIIJýKJKKúLKLKKLLMLMþNMMNôONNOOGHGHGGHHIþHIIõJIJJKJJKKJKKüLKKLLüMLLMMNûONOOGGHIþJIIJKþJKKýLKLLMLMýNMNNþOGGHüGHGHH IJüKJJKKùLKLKLKLL MNüOGFGGHGHüIHHIIJIJKLþKLLMþLMMýNMNNýOFGGüHGGHHýIHIIýJIJJKúLKLKKLLùMLLMMLMMNFýGFGGHGHIJIJKþJKKýLKLLùMLLMMLMMýNMNNFGHýIHIIJüIJIJJúKJKKJKKLþMLLMõNMNMNFFGFGFFGHGHþIHHIJþIJJýKJKKýLKLLMLMþNMMFGûHGHGHHüIHHIIýJIJJKJKLýMLMMFþEFFþGFFGýHGHHIJIJKøJKKLLKKLLýMLMMþEFFþEFFýGFGGHIúJIJJIJJKJKLþKLLMùLMMLEEFFGFGHýIHIIJKþJKKþLKKLMýLMEEFýGFGGóHGHHGHGHIHIHIIúJIJIIJJKþJKKüLKKLLEþFEEFGþFGGýHGHHþGHHýIHIIJþIJJýKJKKL÷KLLKMLLME EFüGFFGG HIJþIJJKþJKKLþKLLDEFEFýGFGGHýIHII JýKJKKLþDEEþDEEFþEFFGFýGFGGýHGHHIùJIJJKJKKùLKLKLLDDEþDEEFûGFGFGGHþGHHýIHIIJþIJJKþJKKùLKKLKCDDEFEFGþFGGþHGGHIJþIJJüKJJKKýDCDDEDE FGHþIHHIJþIJJþKJJKúLKKDCDDýEDEEüFEEFFüGFFGGüHGGHHIJIJüKJJKKCDüEDDEEýFEFFúGFGFFGGHþIHHIJüIJIJJKüJKCDDCDüEDDEEFGþFGGýHGHHýIHIIJüIJIJJþKJJCDþCDDüEDDEEFGúHGHHGHHýIHIIJKþBCCDþCDDþEDDEúFEEFEFFüGFFGGHþGHHIüHIHIIJúKJCCBCCDEþFEEFGHþGHH IJýKJCCþBCCDþEDDEýFEFFGþFGGüHGGHHIþHIIþJIIJüCBBCCúDCDCCDDEþDEEýFEFFGþFGGôHGHGGHIHIHHIIúJIBCBCCDEþDEEüFEEFFûGFGHGGHýIHIIJBýCBCCýDCDDEDEFüEFEFFGûFGGFGGüHGGHHüIHHIIýBABBýCBCCDCúDCDDEDDýEDEEFþEFFüGFFGGHøGHGHHIHIIþHIIJBûABCBCCþBCCDýEDEEþDEEýFEFFþGFFGHúIHIIHIIABüCBBCCúDCDDEDDüEDDEEýFEFFGHIûHIAABBùCBBCCBCCDEûDEDDEEFýGFGGHGHIABûABBCBBCüDCCDDýEDEEFýGFGGHþIHHABþABBýCBCCþBCCDùEDDEEDEEFþEFFúGFGFFGGHþ@AABüABCBBCDþCDDûEDEDEEúFEEFEFFGüHGGHHþIHVþUVVWüXWWXXYZ[þZ[[û\[\[\\]UVWþVWWûXWXWXXùYXYXYYZZYZþ[ZZý[Z[[\þ[\\UVþUVVWþVWWüXWWXXYZYZü[ZZ[[ú\[\\[\\UV WXYþXYYúZYZZYZZû[Z[Z[[û\[\[\\ýUTUUVúWVVWVWWøXWXWXXWXXYýZYZZ[øZ[Z[\[[\\ûUTUTUUþVUUVûWVWVWWüXWWXXùYXXYYXYYZú[Z[ZZ[[þTUUþTUUVWþVWWXWXYþXYY Z[TUþTUUýVUVVýWVWWXþWXXYûZYZYZZý[Z[[TUþTUUVWVWýXWXXYþZYYZý[Z[[TUþTUUVUVùWVVWVVWWXúYXXYXYY Z[ýZ[SSTUTUVWþVWWýXWXXýYXYYþZYYZ[ýZ[TTþSTTýUTUUVòUVWWVVWWVWWXWXXþYXXYZû[Z[[SSTþSTTýUTUUVýWVWWþXWWXYüXYXYYúZYZZYZZSûTSTSTTúUTTUTUUùVUUVVUVVWX YZþ[SSúTSTTSTTUTUVýWVW WXýYXYYZYZSùTSTTSSTTUþTUUýVUVVöWVWXWWXXWXXYîZYZYZYSRSRSSTSSTSTTýUTUUVWXWXúYXYYXYYZüYRRSSTSýTSTTþUTTUþVUUöVUVVWVWWVWWXYøZYRRSSRSS TUVUVWXWúXYYXXYYRSöRSRRSSTTSTTUTUVôUVVWVVWWVWVWWüXWXWWXýYXYYþZRRSTúUTUTTUU VWXWXùYXYXYXYYRúSRRSRSS TýUTUUVüUVUVVWþXWWXYóXYXRQQRRSRSRSSüTSSTTþUTTU VWþXWWXYþQRRSTSTUþTUUþVUUVWþVWWXûYXXYQQRþSRRSúTSTSSTTUVWþVWWþXWWXúWXXYYQQRQRýSRSSüRSSTTþSTTýUTUUVóWVWVWWXWWXWWXXQýRQRRSüTSSTTüUTTU UVüWVVWWýXWXXQþRQQRSTUTUþTUUVûWVWVWWöXWXWXXPQPQQýRQRRSþRSSTþSTTùUTTUUTUUVþWVVWXQðRQRRQRRQRRSRSSRSSüTSSTTþSTTöUTUTUTUUVUUVWþVWWXýWQPPùQPQQRRQQýRQRRýSRSSþTSSTUVþWVVW÷XPPQPQQPQQRSþRSSýTSTTúUTTUTUUýVUV VWþXPPQõPQPPQRQRQQRR SýTSTTUýVUVVþUVVþWVVWþOPPøQPPQPQPQQüRQQRRSþTSSTUþVUUVWýVOPPQþRQQRüSRRSSøTSTSTTSTTúUTUUTUUúVUVUUVVþWOOüPOOPPýQPQQñRQRRQRQRRSRSSRSSýTSTTUüVUUVVøWVVWWOOPPþOPPýQPQQüRQQRRSýTSTTøUTUUTUTUUVþUVVWþVOOþPOOPýQPQQýRQRRSRýSRSSýTSTTUVOüPOOPPûQPQPQQýRQRRSûTSTSTTUþTUUVOPýQPQQüRQQRRSþRSSýTSTTUöVUVUVVOONOOýPOPPQRQRSTUþVUUüNONOOPþOPP QRþQRRüSRRSSTþSTTüUTTUUùVUONONOOþPOOPýQPQQRþQRRSþTSSTUùTUTUUVNNOþNOOüPOOPPQþPQQýRQRRSøTSSTTSSTTUNO PüQPPQQRQRýSRSSûTSTSTTUNýONOOüPOOPPQúPQPQPQQRQRSüRSRSSTúUTTNMNNOPþOPPQRþQRRüSRRS SýTSTTúNMNMMNNýONOOPüQPPQQ RSTSTþSTTûMNNMNN OPþQPPQúRQQRQRRüSRRSSTMNüONNOOýPOPP÷QPPQPQQPQQûRQRQRRþSRRSTþSTTMýNMNNOPþOPPþQPPQRSþRSSTþLMMýNMNNùONOONNOOýPOPPýQPQQ RSûTSLLMMNþMNNOþNOOþPOOPüQPPQQRSTLMNýONOOPQþPQQRúSRSSRSSúTSTSLMMýNMNNOþNOOPôOPQPPQPPQQRQQRüSRRSSðTSLLMLLMLMMLMMNMMNþONNýONOOPQRþQRRüSRRSSLMþLMMþNMMNOøPOOPPOOPPQ RýSRSSKýLKLLMþLMMNONOûPOPOPPüQPPQQRúSRRSKLLMþLMMúNMNNMNNúONONNOOýPOPPQRøQRRSSRSLLþKLLMþLMMNüONNOOþPOOýPOPPQüRQQRRSKLþMLLMNMNøONOOPPOPPþOPPQúRQQRQRRKûLKLKLLMüLMLMMNþONNOPþOPPýQPQQýRQRRJKLþKLLMúNMNMMNNýONOOPOPQýRQRRüQRRKKþLKKLþMLLM NOþNOOüPOOPPQûPQQPQQûRQQRQïýðïððþïð ðûñððñððñðþñððøñððñðñðññþðññöðññðñððññððúñððññððüñðñððúñðñððññþðññüðñðññûðññðññðþïððùñðññðñððñðññðñðññððññðñððñððñùðïððïïððþïððþïð ðþñððþñððñûðñðñððñðþïð#ðþñðð÷ñðññððñðññðþñððïðüïðïððþñððåñððññðñðññððññððñðñðññïðïïððþïððþïððñøðññððññððñûðññðññðþñððïðþïð ðþñððñðñýðñððýñðññúðñððïððûïððïððþïððþñððøñððññðñððýñðññúðñðñðññúðññðïððïñðïïððïððïðïððïððüñðñððþñððñðùïðïððïððþïððþïððüñðñððþñððüñðïððïðþïððþïð ðþñð ðöñððñðñðññððñðïðþïððøïððïððïððüïðïð ðþñððþñððôñððññððñðññððòïððïððïððïððïð ðûïððïððþñððñðñððñðñðññðïïððïïðïððþïððøïððïððïð ðúñððññððúñððññððñðñðúñðñððïïðïðøïððïïðïððûñððñððñðþñïïöðïïðïïðïïððþïððþïððþïððþïððþñð ðüñððññøïðïððïðïïðïüðïïððþïððþïððþïððüñððññôðñððïïððïððïïðþïððúïððïïððþïððþïððþñððúñððññïïóðïðïïðïïððïïððþïððïðûïððïððþñððþñððïþðïïðïýðïððûïððïð ðþïððþñððïðôïðïððïðïðïïððüïðïððþïððþïððþïðð÷ñððññððñððïðúïðïïðïïðïðþïððþïððûñððñïïþðïïøðïðïïððïïðýïðïïðùïððïðïððñüðñðïïðýïðïïðïüðïïððïðïðüïðïððýïðïïðïýðïððïõðïïððïïðïïððþïððþïð ðùñðññððïïþðïïðïð÷ïðïððïðïððúïððïðïïýðïððïþðïïþðïïðïýðïððïüðïïððïýðïððþñï ïüðïïððïðïðïóðïïðïðïðïððïððüïðïððþñððïþðïïüðïïððþïððýïðïïðþïðð÷ïðïðïððïððþïð ð ïþðïï÷ðïððïðïïððïðöïððïðïððïððïþðïïøðïðïððïððïðþïððþïð ðïþðïïþðïïþðïïðïõðïðïïðïððïððóïðïïðïððïððïððýïîïïþðïïüðïðïïðøïðïïððïððõïðïïððïïðïððþïððïþðïïþðïïþðïïþðïïôðïïðïïððïðïððþïð ðþîï ïûðïïðïïøðïððïððïïþðïïðöïððïðïðïðïïðþïððîûïîïîïïþðïï÷ðïïðïðïðïïþðïïðïþðïïðïðþïððùïððïïîïïðïðï÷ðïðïïðïðïï÷ðïðïïððïððþïððýïîïïþðïïöðïïðïððïïððúïðïððïïûðïððïïðþïððïþîïïþðïïðïþðïïõðïðïððïðïïððïðïþðïïðýïðïïûðïððïïúðïðïïððïðýïðïïþîïïþðïïúðïðïðïïðþïððþïððúïððïïððïîïþîï ïþðïïðùïðïïðïððïþðïï÷ðïððïðïïððîúïîîïîïïþîï ïþðïïðôïððïðïðïðïðïïþðïïðþïððþîïïúîïîïïîîïþðïïðïðïðïðïðïþðïïðîïúîïîïîïïþîïïþðïïþðïïðíïðïððïððïîîïîïîîïîïïþðïïðïýðïððþïðððïîïîïîïîïîîïîïîïïþîï ïþðïïüðïðïïðïþðïïðýïðîî ïüîïîïïûðïððïïþðïï÷ðïðïïðïïððïûîïïîïïîïîïþîïïþîïïþðïïôðïïðïððïðïîïïîýïîïïþîïïüðïðïïþðïïþðïïöðïïðïðïîîïïîùïîïïîîïïþîï ïþðï ïðþïððþïððïîïûîïïîïïüîïîïïîïþîï ïþðïïðúïððïïððøïððïïîîïïýîïîîïîïüîïîïïþîïïð ïûðïððïïîïîïîïûîïïîïïþðïïðïþðïïîþïîîþïîîïúîïïîîïïþîïïþîï ïüðïïððïðþïîîïîöïîïîïïîïîïïîýïîïïþîïïþðïïþðïï÷îïïîïïîïîîïîøïîïïîïîïïþîïïðïþðïïîüïîïîîþïîîýïîïïî÷ïîîïîïïîïïúðïðïðïïüðïðîîûïîïîïïîïîïþîïïþîï ïðïþðïïîïîïüîïîïïüîïîïïþîïïî ïôðïððïðïððïðîîûïîîïîîïîûïîîïîîûïîïîïïîïî ïþðï ïýîïîîïóîïîîïîîïîïïîïïþîïïüîïîï ïúðïïðïîî÷ïîîïîïîîïïîþïîîûïîîïîîïûîïïîïïþîïïþðïÿTUûVUVUVVWXùWXXWXXY YZ[û\[SSTTüUTTUUúVUVVUVVW XYZ[þZ[[\TüSTTUUTýUTUUûVUVUVVüWVVWWýXWXXYþXYYZ[TSTUVüUVUVVüWVVWWþXWWXúYXXYXYYZö[ZZ[Z[SSTSSTúUTTUTUUýVUVVWXYþZYYZý[ZSSýTSTTUVþUVVWþVWWóXWXWXXYYXXYXYYZþYZZú[RSRTSSTUôVUVUUVVWWVVWWXWXYüZYYZZü[Z[SSþTSSTUV WXýYXYYøZYZYYZYZZüSRRSSþTSS TUüVUUVVWXüWXWXXYþZYYZøRSSRSSRSSúTSTTSTTûUTUTUU VýWVWWXYZýYZRRSýTSTTUþTUUþVUUV WýXWXXþYXXYZR STýUTUUüVUUVVWXþWXXüYXXYYRSúTSSTSTTUþTUUýVUVVWýXWXXYýZYRRûSRSRSSTþSTTUTùUTUTUUVVþUVVûWVWVWWýXWXXYóQRRQQRRSRRSRSSTSTUþTUUVûWVWVWWøXWXWXXWXXYQRþSRRýSRSSþTSSTUüTUTUUøVUVUVVWVVWýXWXXùYXXYYXQQRþQRRSüRSRSSTSTþUTTUVþUVVWøXWXWXXWXXYýXPQQRùQRRSSRSSTSTüUTUTTUüVUUVVWþVWWýXWXXQRSþTSSTUTUþVUUVWXþWXXüQPPQQüRQQRRSþRSSóTSSTSTTUTUTTUUVýWVWWïXWXXPQPPQPQQRQRQRRSþRSSýTSTTUþTUUûVUVUVVWúXWWXWPPýQPQQRùSRSSRRSSTüUTTUUVúWVWWVWWPøQPPQPQPQQüRQQRR SõTSTUTUTUUTUUVWVW PQúRQRRQRRúSRRSRSSýTSTTUùTUVVUUVVýWVWWþOPPQþPQQRúSRRSRSSTSTUVþUVVWöVWWOPPOPOPPûQPQPQQRþQRRSTþSTTþUTTUýVUVVWOPþOPPQþRQQRûSRSRSSTþSTTûUTUTUUüVUUVVOñPOPPOPPQPQPPQPQQþRQQRýSRSSTUVþUVVOPþOPPQýRQRRSýTST TUVýWNOOPþOPPQþPQQRþQRRýSRSSùTSTSTUTTUùTUUVUUVVúONOONOO PQRüSRRSSTþSTTUVNýONOOýPOPPQRSRS÷TSTSSTTUTTUþVUUVNOPöOPPQPPQQPQQüRQQRRýSRSS TýUTUUVNOüPOOPPQýRQRRþSRRûSRSRSS TUûVUUMNNOþNOOPùOPPQPPQQRûQRRQRRûSRSRSSýTSTTþUTTUNþONNOPþQPPQRüSRRSSTSTUûMNMMNNþONNOPþOPPQþPQQýRQRRSRSüTSSTTûUTUUMMýNMNNûONONOOþPOOPQþPQQRSRýSRSSTSTûUTUUMMþNMMNõONOONNOOPOP PQþRQQýRQRRSýTSTTMNüMNMNNOPüQPPQQRþQRRþSRRSüTSTSSTUýMLMMNþMNNOPQRþQRRSTþLMMNONOýPOPPõQPPQQRQRRQRRSþRSSTSTLüMLLMMþNMMNýONOOùNOOPPOPPùQPPQQPQQûRQRQRR SþTLLýMLMMNONOýPOPPQþPQQþRQQRSòTSTTLKLLMLMLLMMýNMNNOþPOOPûQPQPQQRQRþSRRSüTLKLLþMLLýMLMMNOþNOOýPOPPQþPQQRþQRRSKL MNOPþOPPQýRQRRSþRSSûKLLKLLþMLLMNûMNOONNOúPOOPOPPQýRQRRSùKLKLLKLLMûNMNMNNýONOOPýQPQQýRQRRúSRRSSKKúLKKLKLLMþLMMûNMNMNNùONNOONOOPúQPQQPQQýRQRRSþRKKùLKKLKKLLMNüMNMNNOýPOPPüQPPQQüRQQRRJKüLKLKKLýMLMMNþONNOûPOPOPPûQPQPQQþRQQRúKJJKJKKLþKLLýMLMMNþMNNOþNOOýPQPPQRQRJKþJKKLúMLMMLMMýNMNNOPQþPQQöRQQRRJJKJKKLMûNMNMNNO PQþRJJKJKLùKLKLLMLLMNþMNNOþNOO PQýRQJJKJKLþKLLMþLMMýNMNNýONOOþNOOýPOPPQûJIJIJJüKJJKKýLKLLMûNMNMNNONOPúQPPQPQQþJIIJýKJKKLúKLLMLMMþNMMNOúPOPQPQQúJIIJIJJúKJJKJKKLþMLLMNþMNNýONOOüPOOPPQPIJIJKûJKJJKKýLKLLúMLLMLMMN OPýQHIIJþIJJýKJKKýLKLLúMLLMLMMüNMNMMNúONONNOOPóOPQPQQIHIHIIJJýKJKKLõKLKLLMLMLLMMýNMNNüONNOOPþOPPûQHIHIIJIJKJKýLKLLMþLMMýNMNNüONNOOP]^þ]^^ù_^__^^__`ûa`a`aaûbababbùcbbccbccdþ]\\]þ^]]^ù_^^_^^__ü`_`__÷`a`a``a`aaûbababbcdû\]\\]]û^]^]^^ý_^__`úa``a`aaúbabbabbýcbccþd\\ü]\\]]^þ]^^ý_^__ý`_`` aýbabbc\ú]\\]\]]ý^]^^þ_^^_÷`_`__``_``aþ`aaûbababbcbcþ[\\û]\]\]]^ü_^^__`_`þ_``aþ`aaübaabbücbbccþ[\\ü]\\]]^_ø`_``_`_``aýbabbcý\[\\ü]\\]]^ú_^_^^__`úa`aa`aaþbaabúc[\\[\\]^ö]^^_^^_^^__þ`__`þ_``úa`a``aaúbaababb[ü\[[\\]þ\]]^þ]^^_þ`__`þ_``ýa`aabþabbþZ[[ \]þ^]]ú^]^^]^^_þ`__`üa``aaübaabb[þ\[[ø\[\[\\]\\]ý^]^^_^_`_`ýa`aaûbaabaaZ[ú\[[\[\\ý]\]]ý^]^^_þ^__`úa``a`aaýbabbüZ[Z[ [\]^ý_^__`þ_``aü`a`aabþaZZ[\ü]\\]]þ\]]^ü_^^__`ýa`aaýbaZZ [\ú]\]]\]]ý^]^^ò_^__^__`_`_`_``aþ`aaZ[ý\[\\]ø\]]^^]]^^ý_^__`aZú[ZZ[Z[[ý\[\\ý]\]]^]^_ý`_``øa``aaYYZZþ[ZZú[Z[[\[[\ý]\]]û^]^]^^_^_ü`__``aYZú[Z[ZZ[[ý\[\\ý]\]]^þ]^^ý_^__û`_`_``ùa`YYZYZZý[Z[[Z[\]\]ù^]]^^]^^_`aYóZYYZYZZ[Z[ZZ[[ý\[\\ý]\]]^]^þ]^^_`öYXYYZYYZYZZ[þZ[[û\[\[\\þ]\\]^]^ _ý`_``þXYYZYZ[\þ[\\]þ\]]^_þ^__þ`__þ`XXYùZYZYZYZZ[ý\[\\]þ\]]ú^]^]]^^_þ^__`úXYXYXYY Z[þZ[[\ù[\\]\\]]\]^_þ^__ú`XYYXYYûZYZYZZ[\û[\\[\\]\]þ^]]ý^]^^ý_^__þ^__ö`XXYXYYXXYYZþYZZü[ZZ[[\ü[\[\\ý]\]]ý^]^^þ]^^_XùYXXYXXYYZ[\[ý\[\\]þ^]]^÷_^__^_XWXXYþXYYüZYYZZý[Z[[\þ[\\þ]\\]ø\]]^^]]^^_^_XóYXYXYYZZYZZYZZø[ZZ[[\[\\]û\]]\]]ý^]^^_úXWWXWXXúYXXYXYYZ[þ\[[\þ[\\ü]\\]]^þ]^^_WùXWXXYYXXYüZYYZZ÷YZZ[ZZ[Z[[ý\[\\]þ\]]^þ]^^þ_WWýXWXXüYXXYYúZYYZYZZý[Z[[ú\[\\[\\]^WýXWXXýYXYYZþYZZ[÷Z[\[[\\[\\þ]\\]^]^VWüXWWXXþWXXYZü[ZZ[[þZ[[\û]\]\]]^ø]^VVWWVWWýXWXXûYXYXYYZ[öZ[[\[[\\[\\]þ\]]^VWýXWXX YýZYZZú[ZZ[Z[[\ü[\[\\û]\]\]]^þ]VVWXYøXYYXYYZYYZû[Z[Z[[û\[\[\\ü]\\]]û^VVWVVWXYúXYXYZYYZ[Z[ù\[[\\[\\ú]\]]\]]VWXYXYûZYZYZZú[ZZ[Z[[\]VWüVWVWWX YZþ[ZZ[ü\[[\\÷]\\]]VVUVVúWVVWVWWXWX YZú[Z[ZZ[[\þ[\\û]\\]UUVWXWXþYXXYùZYZYZYZZû[Z[Z[[\þ[\\ù]\UUVUVVþWVVW XYüZYYZZý[Z[[û\[\[\\UûVUVUVVWVWýXWXXüYXXYYùZYZYZYZZý[Z[[þ\[[\TUVUVúUVVWWVVþWXXWXýYXYYúZYYZYZZ[þZ[[\ý[TUUúVUUVUVV÷WVWVVWWVWWXþWXXýYXYYZ[þZ[[þ\[[û\TUTUUVúUVUVVWWüVWVWWXþWXXYXYüZYYZZþ[ZZ[ú\[\TTUUVþUVVWVýWVWWXY Z[ù\TUUTTUUüVUUVVúWVVWVWWûXWXWXXýYXYYùZYYZZYZZ[þZ[[þSTTUôTUVUVUVUVVWVVWòXWXXWWXXYXYYXYYZö[Z[[Z[[TSTTýUTUUúVUVVUVVþWVVWþXWWXýYXYYZ[ûZ[[STTUVþWVVWXþWXXYüXYXYYýZYZZ[üSTSTTüUTTUUüVUUVVWþVWWúXWXXWXXYXYùZYZYZYZZù[SSTTSTT UVWþVWWXûWXWWXXýYXYYùZYYZZYZZø[TSSTSSTTúUTUTTUUVWVWõXWXWXXWXXYXXYüZYZYYZSTýUTUUVþUVVùWVVWVVWWXöYXXYXYYZYZZSøTSSTSTTU UVýWVWWýXWXXúYXYXXYYZYSRSûTSTSTTýUTUUVùWVWWVVWWýXWXXYþXYYþZYYRSýTSTTüUTTUUüVUVUUVWùVWXXWXWWýXYXXYøZYYZRSRSSüTSSTTUþVUUVþWVVWXþWXXYþZRRüSRRSSüTSSTTþUTTUúVUUVUVVWüVWVWWXüYXXYYRûSRSRSSýTSTTôUTUUTUUVUVUVV WýXWXXYñþðññþòññûòñòñòòûñòññòòñòþñò òýñðñ ñþòññøòñòòññòññûòñòòññðòññòòññòñòñòññòññòñþðññûòññòññòñòñ÷òññòòñòñòòñþðññòñòûñòññòòñò÷ñòññòñòñòòþñòòñüðñðñ ñüòñòññþòññúòññòòññþòññûòñòñòòýñòññòñþðññþðññþòññòñòñòñýòñòòðñòòñòòññòñðñðñðñ ñûòññòññûòññòññùòññòñòññþòññòñþòññòøñòñððñðññüðñðñ ñúòññòòññõòñòññòññòñòòñ÷òññòòññðññúòññòòññþòññöòñòòññòòñòòñýòðññþðññðñòñóòñòòññòòñòòñòòþñòòùñòñðñðññþðññþòññþòññüòñòññòñüòññòòýñòññþðññðñùðñðññðññþðññþòññþòññòêñòññòñòñòñòñòòñòññòñðññðñð ñþòññþòññþòññûòññòññúòñòññòòûñòððññýðñððñþðññþðññþòññüòñòññòñîòñòòññòòññòñððññðññþðññþðññüòññòòñüòññòòüñòòððñþðññðñüðñðññþòññòñþòññòúñððñðññðñðüñððññüðñðññþòññòüñòòññòñúòñðññððñðñþðññð ñþðñ ñþòñññòññòñòññòññòòñððùñðññðñððñúðñðñðññþðññþòññôòññòñòñòððñððøñðñðññðññðñþðññõòñòñòñòññòññòþñððüñðñððüñððññúðñðñðññðñüòñòññòñðùñðñðñðññþðññþðññþðñ ñúòñððñððüñðñððþñððñðýñðññþòññüòñòññðüñðñððþñððñþðññüðñðññþòññþòññüòññððþñððñðüñððññðñþðññüðññððñþòññðþñððüñðñððþñððñþðññþòñ ñþòññúðñðñðññüðññððñðñþðññûðññðññð ñþòññðñðþñððñúðñððñððýñðññþðññõòññððññððñððñýðñððùñðñðñðñ ñþðññúòññòñð ðñþðññùðññðññðð ñþðññþòññþòððûñððñððøñðñðñðñððñüðññððñüðñðññðöñðññðñððñððñûðññðññýðñððþñððñüðñðññþòññðþñððùñðññðñððûñðñðññþðññðñðñþðñ ñðñøðñðñðññððþñððþñððûñðññððñþðññþðññ ðþñððñðñðñþðññþðññþðññðüñðñððûñððñððñðýñðññüðñðñ ñðñ ðþñððýñðññðùñðñðññððþñððúñðññðññþðññð ñ ðûñððñððúñðñðñððñðñðñùðññðñðññþðññ ðþñððþñððúñðñððññðñôðñðññðñðññðññðþñððþñððüñðñððþñððñûðññðññþðñ ñüïðïððþïððþñððüñðñððñðýñðññýðñððñþðññûðññðññðþïð ðúñððñðññððñðñðñððñðññðñðñððüñððññþðññþïððþñððþñððìñððñððñððññððñðñðñðññþïððøñðñðñðñððõñððñððññðñððñûðñððññûðññðññðþïððþïððþïððñðþñððþñððþñððþñððüñðñððñúðñðñðññüðññððüïðïððïðùñðñððñððöñððñðñððñððöñðñððñðñðññðñðþïððþïððþñððñþðññýðñððñðýñðññøðïðïðïïððûïððïððûïððïð ðùñððñðñððïñðñðñððññððññðñðññþïððþïððûïððïððþïð ðþñððøñððññðñððñðñùðñððñðññüðñïððüïðïððþïððõñðñðñððñðñððóñðñððññððñðñïïðþïððþïððþïð ðñðñùðñððñðññðñõðññðñïïððïð ðüïðïððïñððññððññðñððññðññðúñïðïïððïðþïððþñððþñððûñððñððñð÷ñðññðïðïððþïððúïððïïððþñððñðñðöñïðïððïððïïýðïððúïðïðïððñðñúðññððññûðñðñðð÷ïðïððïðïððþïððñðñóðñðñððñððññðïïþðïïûðïðïððïðþïð ðþñððúñððññððþñððïðüïðïððûïðïïððþïððþïð ðþñððññððñðññððñððïïððïðïýðïððþïððïúðïððïððñðýñðññðïðïðïðþïððüïðïð ðþñððûñððñðð÷ñððñðïïðïïüðïðïïøðïðïððïððþñððùñðñðññððüñðñïïùðïðïïðïïð÷ïððïððïïððþïððþïð ðüñðñððþñïïõðïððïðïððïððïðþïððþïððþñððþñððýñðïïúðïðïïððïùðïððïïððþïððþñððÿ\]þ\]]^ú_^^_^__ü`__``aýbabbücbbccúd\[\[\\]þ\]]^ø]^]^_^_^^_þ`__`aþ`aabcøbcc\[\[\\]^]^_ü`__``aþ`aaúbabaabbcþ\[[ü\[[\\ý]\]]ý^]^^ü_^^__`_`ûa`a`aabúcbbcc[[\ý]\]]ý^]^^_þ^__þ`__`a`a býcb[[ú\[\[[\\û]\]\]]^û_^_^__`aúbaababbþZ[[\þ[\\]^þ]^^û_^_^__`aþ`aaýbabbZ[ûZ[[\[[\]þ\]]ý^]^^ _`üa``aabüabbZZ[\[\]þ\]] ^_þ`__`üa``aabøabZZ[ZZ[[þZ[[\þ[\\ü]\\]]þ^]]^û_^_^__`aþbaaþYZZý[Z[[\þ[\\]÷^]]^^]^]^^ý_^__ü`__``ýa`aaYZþ[ZZ[û\[\[\\]^ý_^__ü`__``aþ`aaûbYZYZZý[Z[[\þ[\\û]\]\]]^_^_ú`_``_``aþ`aaûZYZYZZ [ý\[\\ü]\\]]ü^]]^^_`ùa`aaYZYYZþ[ZZ[ý\[\\ ]^þ_^^_ý`_``üa``YYýZYZZý[Z[[ü\[[\\]ü^]]^^_þ^__`þ_``þa``ýYXYYüZYYZZ[\þ]\\]ü^]]^^_ý`_``ña`aYYXYXYYZYZYZZ[\þ]\\]ü^]]^^_ð^__`_`_`_``XYXXYYZþYZZ[þZ[[\þ[\\]^]^ø_^_^__^__`ü_``XXýYXYYZý[Z[[ø\[\[\]]\\]ý^]^^ý_^__þ`__þ`XXYZYZ[þZ[[\[\]þ^]]^_ü`_WXXYþXYYZþYZZ[\ý]\]]ö^]^^]^_^^__ú`_`_WXXYýZYZZý[Z[[\]ü^]]^^_þ`XXþWXXYüZYYZZþ[ZZ[\ü[\[\\]^_WXþYXXYýZYZZ[\ú[\\]\]]^ü_^^__WýXWXXY÷ZYYZYZYYZZú[Z[ZZ[[ý\[\\]^ü_^^WWXþYXXYZ[\ø]\\]\]^]]^_^WXùYXXYXXYYûZYZYZZý[Z[[\]^þ]^^ý_^WWþVWWXþWXXþYXXYýZYZZ[Z[ý\[\\]ü\]\]]^üVWVWWýXWXXYZYZ[û\[\[\\ü]\\]]^ûVWVVWWýXWXXYZ[üZ[Z[[ý\[\\]ý^]^^ý]^VVWùXWWXWWXXYZ [\ ]VWþVWWþVWWXYüXYXYYýZYZZû[Z[Z[[\[\]þ\]]ú^]UVUVVWXWXýYXYYZYZû[Z[Z[[ú\[\\[\\]þUV VWXYXYZü[ZZ[[ý\[\\ü]\\]]üUVUVVWXYþXYYZý[Z[[\þ]\\]UVüUVUVVýWVWWýXWXXüYXXYYúZYZYYZZ [\ý]\UUVüWVVWW XYüZYYZZ[ü\[[\\ù[\\]\]UUV÷UVWVWWVVWWXYXY Z[ùZ[\[\[\\øTUUTUUVUUýVUVVüWVVWWüXWWXXýYXYYýZYZZü[ZZ[[ú\[[\[\\þTUUýVUVVWþVWWXüWXWXXYZþYZZ[ûZ[ZZ[[ý\[\\þTU UöVUVVWWVWVWWþXWWXûYXYXYYZ÷[Z[Z[Z[[\\ý[\TTUýVUVVúWVWWVWWXüYXXYYZ[þZ[[þ\TTýUTUUVûUVWVWWþVWW XYZûYZZ[ZZ[\TUüVUVUUVWþXWWXûYXXZYYýZYZZú[Z[[Z[[STUVýWVWWXWXüYXXYYZý[Z[[STUþTUUVW XYþXYYøZYZYYZZ[[ýZ[SSTþUTTúUTUUVUUVþUVVúWVVWWXXþWXXYýZYZZý[Z[[STþSTTUþTUUVüUVUVVýWVWWýXWXXYûZYZYZZþ[ZZý[RSSùTSSTTSTTüUTTUUVùWVVWVVWWýXWXXýYXYYZþRSSTþSTTUûVUVUVVWþVWWýXWXXY÷XYYXYYZYZZ÷YZZSRRSRSSTýUTUUüVUVUUVýWVWWþXWWXYXYýZYZZRSüTSSTTýUTUUVþWVVWXWXYýZYZZRSRSúTSTSSTTýUTUUVþUVVüWVVWWúXWWXWXXYXYüZYYRRSTþSTTýUTUUýVUVVûWVWVWWþXWWXýYXYYZQRýSRSSýTSTTýUTUUýVUVVWXþWXXúYXYYXYYQRSRSüTSSTTUüVUUVVWXýYXYYúRQRQQRRôSRRSSRSSTSSTTüUTTUUùVUUVVUVVWýXWXXYûRQQRQQRýSRSSøRSTSSTSTTùUTUTUTUUúVUUVUVVúWVWWVWW XýYXQQRþQRRSþRSSýTSTTýUTUUVþUVVWVWýXWXXPQRþQRRùSRRSSRSSüTSSTTùUTTUUTUUVýWVWWXþWXXPQþRQQýRQRRSTûUTUTUUVWþVWWXPýQPQQúRQRRQRRýSRSSýTSTTýUTUUVûWVWVWWXPýQPQQRøQRRSRSRSSýTSTTýUTUUùVUUVVUVVWüXWWXXdeýfeffgþfgghiþhii÷hiijijiijjþkjjkýjkddúeddedeeýfeffgþfgghúihiihiijõkjjkjkddccddþeddeýfeffþgffgh÷ghghhihhiiùjijijijjkújccdcdd eüfeeffýgfggøhgghghghhýihiijijþkccdýedeeûfefeffgþfggúhghhghhýihiijúijkjkccõdcdcdeddedeeþfeefghþghhûihhihhiþjiijijcdþcddefþeffgþfgghýihiiýjijjükcbccdedeüdeeffþeffgþfgghþghhiþhiijibcdþcddeþdeefþeff ghþihhiûjbcbccýdcddýedeefefghþghhiühijiibcüdccddûededeefþeffþgffghþghhiþhiijbcdeþdeefûeffgffýgfgghþghhihibcþbccdefûgfgfggühgghhýihiiýbabbcþbccýdcddþcddefghþihhiabcþbccdþcddefùeffgffgghihûabaabbýcbccüdccddýedeefýgfggùhgghhghhüihhaaýbabbúcbcbbccýdcddýedeefþeffýgfgghghþiaabcýdcddýedeeþfeefgöhghhghha`aaúbabbabbûcbcbccýdcddýedeeþdeefþeffgþfggúhgghhaaübaabbcüdccddeýfeffþgffghþa``ýabaababúcbccbccdïcddeddeedeeffefeffgôhgghhg``aa`aabüababbõcbbccddcdcdd efgþfggþ`aaþ`aabýcbccýdcddeödefeeffeeffgýhg``þa``abþabbcþbccýdcddefþeffþgffgþ_``ùa``a``aabcdücdcddeþdeefüefeffgþ_``ýa`aabþcbbcþbccüdccddeúfeefeffgúfgf`_``þa``aûbababbücbbccdcdüeddeeýfeffþgffþ`__ý`_``abþabbûcbcbccþdccdeùfeffeeff÷gfg`__`_``aþbaabcþbccdþcddöeddedeeffeeýfeffúg__`_``aþ`aaûbababbcþdccýdcddeþdeeüfeeff_`þ_``aþ`aababcübcbccdþcddýedeefþeffþ^__ý`_` `aýbabbcþbccdeþdeefüef_^^_`û_``a``aýbabbcûdcdcddýedeeúfefee^^_ý`_``þ_``aûbababbcüdccddþeddýefee^_^_` abþabbcþbccýdcddeódefe^^__^^_^__þ`__`aþbaaýbabbcdcdûededee^_`þ_``þa``ababþcbbcþdccde^ý_^__þ^__þ`__ý`_``aþ`aabüababbcdþcddúededd]]ý^]^^ý_^__þ^__`ùa``aa`aaýbab búcbccdccýdcddøedee]]^]]^ú_^_^^__ý`_``a`aübabaabúcbcbbccùdccddcdd]û^]^]^^_`_` abcþbccdþcdd]^û]^^_^^_þ^__ú`__`_``aþ`aaýbabbýcbccúdccdcdd]^þ]^^_`aþ`aa bcdû\]]\]]^ý_^__`þ_``aþ`aaýbabbþcbbcúd]\]\]]^ú_^_^^__`þa``abaùbabbcbccýdc\\ý]\]]ú^]^]]^^ý_^__û`__`__`úa`aa`aabýcbcc\]þ\]]ü^]]^^_þ^__ý`_``a`abþabbýcbcc\]þ\]]^_ü`__``aþ`aabþabbcþbccý\[\\ý]\]]÷\]]^]^]]^^õ_^_^^_^__`__`aýbabbýcbccý\[\\÷]\]]^]^]^^_ý`_``aþbaabùcbcb[[\\û]\]\]]ü^]]^^_þ^__ü`__``aþ`aaübaabbûcbcc[[\ý]\]]þ\]]^_ú`_``_``aýbabbcý[\[[ý\[\\ø]\\]\]\]]ý^]^^_`þ_``abab[\þ[\\]þ\]]ü^]]^^þ_^^_ö`__`_`_`_``ýa`aab[þ\[[\þ]\\ü]\\]]^]^_`øa``a`a`aab[øZ[[\\[[\\]þ\]]^þ]^^_`_ý`_``úa`aa`aaýbaZZü[ZZ[[ý\[\\ý]\]]ø^]]^]^]^^_þ^__`_`aü`a`aaùbaZ[[Z[[øZ[\[\[[\\]þ\]]ù^]^]^]^^ü_^^__ `aZ[Zý[Z[[\[\]ý^]^^_ü`__``aþYZZ[Z[\]þ\]]^þ]^^ý_^__ý`_``ýa`aaYZ[\þ[\\]ü^]]^^_ý`_``ýaYZZ[\þ[\\]ú\]]^]^^ú_^^_^__ü`__``aYZþYZZý[Z[[û\[\[\\õ]\]]^]]^]]^^_ý`_``aþ`YYZþYZZ[Z[\ý]\]]^þ]^^_`ü_`_``þa` òþóòòþóòòþóòòóôòóòóòóóòóóòóóþòóóþòóóþòóó òþóòòúóòóòóòòûóòòóòòóþòóóòóòóþòóó òóòüóòóòòþóòòýóòóóòóüòóòóóùòóòòóòó óòùóòòóòóòòûóòóóòòþóòòóò óýòóò òþóòòóòóüòóóòòþóòòûóòóòó óþòóóòøóòòóòòóò òóòþóòòûóòóòóóþòóóýòñòòþóòòóòóùòóòóòòóóýòñòòóóòòóòòóòóòóóòòóþòóóòóûñòòñòòóòþóòòóòþóòòþóòòúóòòóòóóþñòòûóòòóòòóòôóòóòòóóòòóòóóòþñòòþóòòþóòòóóòóòóòòóòóòòóóþòóóòñýòñòòó÷òóóòóòòóòòüóòóòòóýñòññòþñòòüóòóòòóòóòúóòóòóòòóýòóòòóüòññòòþñòòûóòòóòòþóòòúóòòóóòòóòùóòòóóòóóòóñòññòñòñòñòñòòóò÷óòóòòóóòóóþòóóòùóòòññòññòøñòòñòññòòþóòòüóòóòòóòóýòñòò÷ñòòññòòñòòþóòòóþòóóýòóòòóòñïòñòñòòñòòñòññòòñòòþóòòþóòòóôòóóòóòóòòóòññòøñòñòñòñòòûñòòñò òþóòòóòóòóòóýòóññùòñòòññòòþñòòüñòñòòñ òþóòòóûòóòòóóòòóóññòññòñòòñòòþñòòþñòòúñòòññò òþóòòüóòóòòþóòòñóòòóóñòññòñòññòòýñòññòþñòòüóòóòòóòóñòññòñòññòñòòññò òóýòóòòóûòóòòññòþñòòúñòòñòññòñ òþóòòþóò òþóòòñòûñòòñòòþñòòùñòòñòñòòóóòòóòñòñòòñòññòûñòññòòñòîóòóòòóòóòóòòóòòñòññüòñòññòýñòññòûñòòñòòþñò òüóòóòòüóòóòòñþòññúòñòòñòòöñòñòòññòòññòñòóòóòñþòññòñòñýòñòòñòúóòòóòóóñò ñòñóòññòñòòññòññò òüñòñò ò÷óòòóòóòòññþòññüòñòññòñýòñòò÷ñòòñòñòñòòþñòòþñòòûñòòóòòþóòòóòúóòññòññþòññòñýòñòòþñòò÷ñòñòññòñòòþñòòþñòòóòñò ñ÷òñòòñòññòòþñòòþñòòüóòóññþòññòýñòññòñòóñòññòòñòñòòñòòþóòòñþòññþòññåòñòñòòñòñòñòñòñòñòòññòññòñòòñ÷òññòñòñòññòñòñòñòñþòññòþñòòþñòòñéòñòññòññòñòòñòòñòñòòññòòùñòñòòñòòüóòòñ ñþòññòøñòñòòññòòñòþñòòûñòòñò òýóòñ ñþòññòþñòòüñòñòòñùòñòññòññüòñòññüòñòññòûñòòñòòñòñþòññüòñòññòñòþñòòýñòññþòññòñòýñòññ÷òñòòññòñòòñòñíòññòñòñòñòññòñòòññòòñýòñòòþñòòñòñòñòñòñòûñòòñòòñþòññòñþòññòñ òûñòòñòò ñþðñ ñüòñòññòöñòñòòñòññòòûñòòñòòñþðññþòññùòñòòñòññýòñòòþñòòñþðññòñóòñòòñòñòñòòñòòñòñòþñòòýñòññðñþòññüòññòòúñòñòñòòþñòòûñòñòññþòññþòññöòñòòñòòñòññòñòøñòñòòñòññþðññðñüòñòññþòññõòññòòññòññòòýñòññòùñððñððññòñþòññþòññòñòüñòñòòñûðññðññþòññòñòñòúñòñòòññòôñðññðññðñððñ ñþðññüòñòññþòññòúñòñòñòòñýòñòòøñòñðññðññðýñðññûðññðñ ñûòññòññþòññòñòûñòñòññüðñðññþðññþðññþòññòñòùñòòñòòññþðññðñþðññþòññòñòûñòòñòòñúðññððññþðñ ñþðññþòññþòññòôñòñòññòññòðññüðñðññüðñðññûðññðññþòññùòñòññòññöòñòñòñðñðññðøñððñðñðññþðññþðññþòññûòñòòññúòññòñòòðñøðñððñððññþðññþòññþòññùòñòññòññòüñòðññðñúðñðñðññõòññòññòòñòñññòñòññòññðñðñðñððüñððññðøñððñðñðññþðñ ñþòññòýñòññ÷òðñððñððññðñðñúòññòòññùòñòññòñÿûcdccdde fýgfggühgghhýihiiþjiijköjkkccddccddedefgþfgghþghhiþhiiüjiijjþkjjþkccdefþeffghiùhiijjijjkcdþcddeþdeefgþfggõhghhihhihhiijûkjcbccdþcddýedeefefügffggýhghhýihiiühijiijýcbccüdccddüeddeefýgfggþfgghöihijiijjijjúcbbcbccþdccde fghûihihiiøjijjcbbccýdcddþeddýedeeýfeffghþghhýihiijþibbcþbccdýedeefgfghþghhýihiiüjbabb cdeüfeeffýgfgghüihhiiýjibbþabbücbbccd÷ededeefef fghþghhüihhiiùjaabaabb÷cbccbcdcddþeddeþdee fýghgghiþhiiaýbabbcûbccdccýdcddýedeefþgffýgfggýhghhiúhiihiaabcþbccüdccddüeddeeýfeffghüghghhûihi`aabab cdøededeefeeýfeffgûhghghhýih``abýcbccþdccýdcddüeddeeøfeffggfggühgghhaþ`aaýbabbücbbccdcdüeddeeüfefeefýgfggühgghhýia``aýbabbcdþcddûededeefûgfgfggþhggh` abcýdcddúededdeeüfeeffgþhggþh``üa``aabûcbcbccdþcddûededeefúgfggfggþh``a`aübaabbücbbccýdcddüeddeeûfefeffýgfgg`aübaabbýcbccdüeddeefýgfgg_`þ_``aþ`aababcýdcddefefþgffgø_`_`_`_``a`abûcbcbccýdcddýedeeþdeefþgffgþf__û`_`_``óa`aa`aababbabbcþdccýdcddûededeeýfeffgþ^__`üa``aaþbaabþabbcdþcddýedeef^_`ù_``a``aabücbbccþbcc deüfeeffû^__^__`þ_``üa``aaübaabbcþdccdüeddeeþfeef^_þ^__`ü_``aa`aübaabbcþdccdýedeeùfeffef^^_þ`__`ý_`aa`aùbaabaabbcbcdþcddüeddeeþf^^ _`þ_``aýbabbcûdcdcddýedeef^þ_^^_ý`_``aübaabbücbbccýdcddeû]^^]^^ý_^__÷`_``_``a``aùbaabbabbýcbccþdccýdcdde]ý^]^^_ü`__``ýa`aaúbaababbcbcdeüdedee]^ô_^^_^__``__``aúbabbabbcdûedde]]^þ]^^ü_^^__ú`_``_``a`ababcdþcdde]^ü_^^__`aþ`aabþabbcýdcddûede\]] ^_û`_`_``üa``aaýbabbücbbccûdcdcddþe\\]ó^]^]^^]^_^_^__`ü_``aaþbaaýbabbcd÷cdcdd\]\]]^_`þa``abcdcd\]^ú_^^_^__ú`__`_``aúbaababbýcbccüdccdd\]^þ]^^ù_^__^^__`üa``aabüababb÷cbccdccd\\]^ý_^__`þ_`` abücbbccýd[\\]þ\]]^þ]^^ü_^^__`aþ`aabc[\þ[\\]ü^]]^^_`þ_`` aûbcbbccübcc[[ü\[[\\]û^]^]^^_þ^__`aùbabababbcýbc[[ý\[\\]^þ]^^_`aübaabbýcb[[ý\[\\ü]\\]]^_þ^__`þ_``aþ`aabþabbc[\û[\\[\\]þ\]]ú^]]^]^^ _`úa``a`aababúcbb[Z[[\] ^ö_^__`_``_``ýa`aabZ[ \ý]\]]ü^]]^^_þ^__`þ_``ûa`a`aaþbaab[Z[ý\[\\]^û]^^_^^ý_^__ü`__``ýa`aaûbabYZZ[Z[ \]û^]^]^^ý_^__ý`_``þa``aþbZZú[Z[[\[[\þ[\\]ü\]\]]ý^]^^ü_^^__`þ_``aúbabZYZZý[Z[[\ü]\\]]^_þ^__ú`__`_``ýa`aaýZYZZý[Z[[þZ[[\ü[\[\\ý]\]]ú^]^]]^^ _ý`_``õa`a`aaYZZYZZ[þZ[[ü\[[\\ý]\]]õ^]^^_^^__^__`aYýZYZZ[þZ[[ö\[\\]\]]\]]^ý_^__`þ_``aYýZYZZ[ý\[\\þ[\\]þ\]]^_þ^__û`_`_``YûZYZ[ZZ[þ\[[\ý]\]]þ\]]ü^]]^^ _`þaXXYüZYYZZû[Z[Z[[ý\[\\ý]\]]þ^]]^_ý`_``XýYXYYZú[Z[[Z[[\þ[\\]þ\]]ð^]^]^^_^^_^__`_``XYüZYZYYZý[Z[[ü\[[\\ý]\]]û^]^]^^_þ^__û`_`_XXýYXYYþZYYZ[\]þ\]]þ^]]^_`éklklklkllmllmmlmmnmmnmnnþonnopþqppqþrqqrýsrkkýlkllþmllýmlmmnopþoppýqpqqýrqrrûqrrskkûlklkllùmlmlmlmmnþmnnûononoopýqpqqrklþkllmùnmmnmmnnoùnoopopoopq÷rqrqqrkjkklümllmmþnmmýnmnnûononoopýqpqqrúqrrjjkklýmlmmnmnoþnooúpoppqppqrqùjkjjkjkkülkkllýmlmmþnmmnmnûononooüpooppqjúkjkjjkkúlkllkllmnmnýonooýpoppqpqürjijjk lmûnmnmnn÷onoonoopoopûqppqppqjýkjkklklüklmllmnþonnoþpooýpoppqýpijjkjklþkllmnoþnoo pqij÷ijjkjkjjkkülkkllmþlmmýnmnnoþnooþpoopqþijjijkjkþlkklþmllmnoþnooþnooýpoppþoppijüijijjúkjkkjkkýlkllmûnmnmnnûononooüpooppýihiiújijjijjýkjkkølklkklkllümllmmþnmmn opoþhiijþijjkýlkllmþlmmnþmnnüonnooþpoohiüjiijjükjjkkþlkkýlkllmúnmnnmnnýonoohi÷jijijijijjkþjkkþlkklmþlmmúnmnnmnnoøpophihhiiýjijjùkjkkjjkklþkllýmlmmnoþnooýpohhüihhiijþijjkülkkllümllmmùnmnmnmnnoúnoohghhiüjiijjúkjkkjkklûmlmlmmúnmnnmnnùonoohghhijþijjükjjkklmýnmnnoünhghhiþhiijþijjküjklkklmûlmmnmmnüogghhiþhiijijk÷lkllkllmllmnúonngghhiýjijjûijjkjjkþjkklmþlmmnghþghh iýjijjkþlkkýlkllmúlmlmlmmýnmnnghôghhghhihhihiijþijjýkjkkl mønmmnggfgghùihihiijjþijjkûjkklkklmønmnmnffgghþghhýihi ijþijjküjkjkklýmlm mûfgffgghþihhijkúlkllkllmþlmmfghýihiijijkþjkklöklmlmllmlmmføgfgffgfgghùghhihhiijþijjýkjkklmûlmmefføgfgffgghhþghhýihiiûjijijjùkjkjkjkkülkkll÷mlmmeffeffügffgghþghhþihhiüjiijjýkjkkýlkllþkllmûeffeffügffggþhgghûihihiijúkjjkjkkülkkllûmleef fgýhghhþihhijüijijjkþjkkþlkklýmleeûfeffg ghiþjiijúkjkkjkklþmeeýfeffúgfggfgghþghhüihhiiþjiijkýlklleùfeefeeffgüfgfgghüghghhùihiihhiiýjijjýkjkklefefþeffýgfggþhgghüihhiijkûlklle efgþhgghúihhihiijkülddeeþdeeþfeefþgffghiþhiijüijijjùkjjkkjkkýldeeþdeefþeffgühgghhûihihiijkjkþlddþeddøedeefeeffghþghhiþhiijûkjkkjjkdeúfeffeffúgffgfgghþghhýihiiüjiijjýkjkkýdcddeýfeffgþfgghþghhiþhiijkcdýedeefþeffûeffgffgýhghhihiþjiijkýjkddþcddþeddefþeffgþfgghghiþhiijc deþfeefghghýihiiøjijijjijjcýdcddücdde efýgfgg hiüjiijjcýdcddþcddefþeffghghiþhiiþjiiýcbccþdccdùeddeddeefþeffgýhghhùihihiijjùijjcbbccúdcddcddefòeffeffgffggffggõhghghhiihhiiöjibbccbcbccüdccddefghþghhùihihihiibcdþcddýedeefgfghgýhghhijbcþbccdþcddeýfeffghþghhiúhihiabbcýdcddeüdedeeúfeffeffghþghhiòhiiaabbabbcbbccdýcdccdedefþeffgþfggh÷ghghhihhiiþbaabýcbccüdccddefþeffýgfggýhghhþihhüababbcdþcddüeddeeýfeff÷gffgfgghgghþghha bcdþcddeûdeddeefþgffghþghhþ`aaþbaabcþdccdþcddefþeffúgffgfggþhggýhgaaýbabbcødccddccddeþdeefüefeffügffggýhghhû`aa`aabþabbücbbccdþcddeþdeeþfeeýfeffýgfggühgghóþôóóôüóôôóóôþóôô÷óôôóôôóóôôþóô ôýóôóóüôóôó óôôóôóóôóôóôóóôôóô óþôóóñôóôóóôóôôóóôóôóóôûóôóóôôþóô ôóþôó óôüóôóôôþóôôþóô ô óþôóó÷ôóóôóóôôóóôóðôóôóôôóôóôôóôôóô ôóþôóóþôóóôóôùóôóóôóôôóôþóôôþóôôóþôóóôøóôóôóôôóóôþóôôûóôôóôôþóôôóô óôóôóóôôóóôôóóôóóô ôýóòóóþôóóôóüôóôóóüôóóôôüóôóôôþóôôýóòóóþòóóþôóóþôóóþôóóûôóôôóóôóôóôûóôôóôôþóôôóúòóòóòóóþôóóöôóóôôóôóóôôúóôôóóôôóúòóóòòóóõôóóôóóôóôôóóôóýôóôôóôúóôôóòóóþòóóôóþôóóûôóóôóóôôóôóôóôóóôóôôþóôôóòóþòóóôóþôóóûôóôóôôóôúóôóôóôôüóòòóóþòóóôùóôóóôôóóôóûôóôóôôóþôòòúóòóóòóóþòóóôóôóúôóóôôóóùôóóôôóôôþóôôýóòóóþòóóþòó óýôóôôóîôóóôóôôóôóóôóóôóôóóõôóóôôóóôôòóóþòóóþòóóô÷óôôóóôóôóóòôóóôóôôóóôôóòóóòóþòóóôóýôóôôóýôóôôöóôôòóóòóóòòóþòóóôøóôóóôóóôôóûôóóôóóòýóòóóûòóóòóóþòóóôôóóôóóôóóôôóóþôóóòôóóôóóôóòòóòóòòóùòóòóòòóóþòóóþôóóþôóóöôóôóóôóóôóóôóôóþòóóòóûòóóòóóþôóóùôóôóôôóóöôóôóòòóòóòòóþòóóòóûòóóòó óôóþôóóôóòóòþóòòóòóþòó óþôóóþôóóþôóóùôóóôóôóóôýóòóóòýóòóóòóûòóòòóóþòóóþòóóþôóóùôóóôôóôôòóòóóòòóòóóòòóòòýóòóóòóóôóôóôóôóôóôôóóþôóóòúóòòóòóóòóûòóóòóóþòóóôõóôóóôôóôôóòòýóòóóòóþòóóüòóòóóþòóóþôóóþôóóôþóòòðóòóóòóòòóòòóóòóòòóüòóòóóþòóóôóôýóôóóóôóòòóòòóóòóòóóòóüòóòóóþôóóþôóóøôóôóóôóòòóòûóòóóòòüóòòóóþòóóôóôòóòóòóþòóóûòóóòóóôýóôóóúòóòòóòòøóòòóóòòóóòóûòóòòóóþòóóþòóóþòó óþôóóþôòòùóòóòóòóóýòóòòóòóüòóòóóþòóóýòóòòûóòóóòòþóòòóòóòýóòóóøòóòòóóòó óþôóóýôóòòþóòòþóòòóòóóòóòóòòóóòóòóó òûóòóòóóùòóóòóòóóþòóóþòóóþôóóýôóòòüóòòóóòùóòóòòóòòóòóóòóòóòóóòóòòóóþòó óýôóò òó òþóòòóøòóòòóóòóóòýóòóóþôóó òþóòòóüòóòóóôòóòóóòóóòóòóóþòó óüôóôòòüóòóò òùóòòóóòóóúòóòóòóóþòóóúòóòóòó óòþóòòüóòóòòþóòòøóòóòòóòóóþòóóùòóóòóòó óþñòòúóòòóóòòóüòóòóóò óûòóóñò òóòþóòòóüòóòóóóòóóòóóòòóòóòóóòóþòóóþòóóòþñòòþñòòóòóòóòóþòóóþòóó òþóòòöóòóóòóòòóòòóüòóòóóòóòóþòóóòþóòòúóòóòòóóòóöòóòóòóóòóòòòóòóóòóóòóòòññòòþóòòþóòòüóòòóóþòóóòúóòóóòóóþòóóòóòþóòòüóòóòòúóòòóóòòóýòóòòýóòóóòóòóòûñòòñòòþñòòûóòòóòòþóòòóòþóòòüóòòóóòóüòóòóóþòóóòñòþñòòþóòòþóòòóòüóòóòòýóòóóòóþòóóòñòþñòòûóòòóò òóóòòóòòóóòóòòó óòüóòñòòþñòòûóòòóòòþóòòóþòóóüòóóòòþñòòñòþñòòüóòóòòþóòòúóòòóóòòøóòóòóòòóó÷òñòññòññòòñòûóòóòóóüòóóòò÷óòóóòóòòóóþñòòñòþñòòþóòòóóòòóòòóòòóòóòòïóòóóòóóññòñòñòòñòòñòþñò òûóòòóòòþóòòøóòóòóòóòòüóòóòòñòûñòññòòþñò òþóòòþóòòþóòò÷óòòóòóòóòòóúòóòóóòòûñòññòòñòþñòòüóòóòòóóòóóòòóòóòóóòòóñüòñòññòþóòòþóòòþóòòþóòòúóòóòòóóûòóòòññòþñòòüñòñòòþóòòûóòóòóóòñõòñòòñòñòòñòòþñòòþñòòùóòòóòóòòþóòòüóòóòòøóòóòòñòññùòñòòñòññüòññòòþñòòüñòñò òóòþóòòöóòóóòóòóòóóÿk lmnmønonnoonooýpoppq rskýlkllmþlmmónmnnmnnononnooþpoopûqpqpqqrûsrsjkklýmlmm n opqrqrsþjkklþmllmnoþnooýpoppýqpqqúrqqrqrrþsjjkülkkllûmlmlmmýnmnnømnnononooýpoppüqppqqúrqrrqrrjklmünmmnnoùpopopoppýqpqqrjükjjkkûlklkllmõlmmlmmnmnmnnöonnonnoopoopúqpqqpqqrjùkjjkjjkklþkllýmlmmýnmnnþonnopqþpqqúrqrjijjkýlkllümllmmnoþnoopqpqúrqqiijjkjklþkllmþlmmnþmnn÷ononnoopooýpoppqþpqqýjijjþkjjklümlmllmnùmnnoonooôpopooppqqppqqiýjijjýkjkkýlkllmþnmmnopopúqpqqpiijþijjûkjkjkkýlkllmølmmnmnmnnýonoopþoppþqiiýjijjkl÷klkllmllmmnþmnnýonooýpoppûqpqhiijþijjkjklýmlmmþnmmnýonooøpopoopoppühihiijükjjkklmþlmmnþmnnýonooüpoopphiüjiijjküjkjkklþkllmþlmmûnmnnoonophûihihiijþijjkùjkklkkllýmlmmýnmnnúonoonoophýihiiùjiijjijjýkjkkýlkllmnþmnnýono oþghhijþijjùkjjkkjkkýlkllmûlmnmnnþonnoúpoghghhiþhiiýjijjýkjkkþlkklümllmmþnmmnoûghhghhiùhiijjijjýkjkkþjkkl mnüonnooghiûjijijjýkjkklúmlmllmmþnmmnogùhgghgghhijñkjkkjkklkklklkllmþnmmnüonfggühgghhùihihijiijkýlkllmünmmnnoþfgghþghhiùhiijiijjükjkjjkùlkkllkllümllmmünmmnnýonggûhghghhiþhiiújijjijjúkjjkkllmúnmnnmnnfghghiþhii jkýlkllþmllmnfgþfggýhghhþihhýihiiýjkjjkýlkllümllmmnfg hiôjijijjkjjkjkkülkkllýmlmmnþeffgøhgghghghhiþhiiþjiijkýlkllýmlmmfþgffghþghhiþjiijkþjkklmefgýhghh ijþijjýkjkklþmllmeøfefeffgffögfgghghgghhiþhiiýjijjkþjkkölklkllmmlmmeýfeffúgfggfgghiþhii jkýlkllómlmedeefeefeffghüihhiijþijjküjkjkkýlkllêmllddeefeffefeffgffgfggühgghhihijöijjkkjkkjkkýlkllûededeeþfeefghþgh hiüjiijjkþjkklþdeefþgffýgfggúhgghghhiûjijijjýkjkkõlkkllddeddeefgþhgghûihihiiþjiijklýklddefþeffgúhghhghhüihhiiüjiijjkjkúlklkcddýedeefûgfgfgghiýjijjkülklddeýfeffgþfgghiüjiijjkûcddcddýedeeüfeeffgýhghhýihiiújijjijjküjkkccdüeddeefþeffýgfggþfggþhgghýihiijþijjkcdefþeffgþhgghþihh÷ijijiijijjkýjkccdýedeefefýgfggþhgghiþhiijþkccdcdeþdeeýfeffgùfghhgghhiúhiijjiiýjijjþbccúdcdccddeþdeeûfefeffògfgffgghghghghhijþijjcþbccýdcddúeddedeefþgffgúhghhghhûihihii÷jiijjbbcbbcdücdcddeýfeffgþfgghûihihiiþabbýcbccdþcddeþdeeýfeffgþfgg hiýbabbcþbccýdcddedefûeffeffgþfgghiþjbbcþbccdúededdeeüfeeffgûhghghhiùabbababbcýdcddefþeffgfghghiûhihiaaþbaabücbbccdeþdeeõfeffeffgffgghiabûcbcbccdefgþfgghihaûbabcbb cdeýfeffýgfggühgghhihabùcbcbcbccýdcddýedeefþeff ghþ`aaübaabbþabbcþdccdöeddeddedeffûeffeffgþfggóhghghh`a`aa`aaûbababbûcbcbccdýedeefþeffgþfggh÷ghh``aa`aaùbaabaabbcdúcdeddeeýfeffügffggühgh``ùa`aa``aaübaabb cdüeddeeúfeffeffûgfgfggh`þ_``aü`a`aabcdþcddeüfeeffügffggrûsrssttþuttuúvuvuuvvúwvwvvwwxýyxyyþxyyùzrrssrsstþsttuþtuuvúwvwwvwwxýyxyyzrýsrssýtsttuþtuuvúwvwvvwwxyþxyyrýsrssþrssútsttstt uv wxyr stüuttuuývuvvwþvwwxüwxwxxyrùqrrssrsstþsttuïvuuvvuvuvwvwvwwvwwýxwxxüyxyxxþyqqrstsútututuuvþuvvwúvwxwwxxûyrqqrrýsrssùtstststtüuttuuývuvv wxqrþqrrùsrsrsrssütssttuþtuuvwxþwxxýypqqrûqrrsrrstþsttþuttuvþuvvwþvwwxqr stþuttuþvuuvüwvvwwxqûrqrqrrþsrrstuvþuvvwþvwwxûqpqpqqrsþrsstþsttuvþuvvøwvwwvwvwwxýqpqqrþqrrþqrrýsrssýtsttuþtuuvþuvvüwvvwwpûqpqpqqrþqrrsýtsttutuývuvvwvwxþoppýqpqqrstuüvuuvvwþoppqýrqrrstuûtuuvuuvwývwppþoppýqpqqýrqrrýsrsstüuttuuúvuvuuvvwùvwwppoppqúrqrrqrrststüuttuuv÷wvwwpopoppýqpqqûrqrqrrþsrrýsrsstuütutuuvþuvvúwoopoppýqpqqrqörqqrrsrsrsstýutuuvþnoopþoppqþpqqýrqrrsýtsttuütutuuvþuvvþnooþpoopqrqrùsrrssrssþtsstýutuuvþnooþpoopqüpqrqqrþqrr stþsttýutuu÷vuvvnnonoopopqþrqqrþqrrstþstt uvnoúpoppoppq÷pqqrqqrqrrsýtsttüuttuuvnýonoopqrüqrqrrsþtsstüuttuunóonnonnonooppoopøqppqpqpqqrþqrrþsrrsýtsttuþmnnoúpoppopp qýrqrrsþrsstuümnmnnýonooúpopooppqýrqrrsrsûtststtþuttuümnmnnoþnooþnooýpoppqþpqq÷rqrqrqrqrrýsrsstúutmnmnnúononnooüpooppùqppqqpqqrüsrrssýtsttýutmmnþmnnoþnooýpoppqþpqqýrqrrsütssttþummnþonnopýqpqqýrqrrüsrrsststþlmmnùmnnonnoo pqúrqrrqrrsþtsstmýnmnnûononooüpooppþoppûqpqpqqûrqrqrrþsrrsútllmlmmnmýnmnnoþpooýpoppýqpqqþpqqýrqrrsþtll mnonopqþpqqrqrsýtsllþmllmnøonnonopooýpoppýqpqqýrqrrüsrrssklýmlmmýlnmmnþonno pqøpqqrqrqrrsürssll mnümnmnnoþnooûpopoppqrq rþkllþmllmýnmnnþmnnýonooýpoppýqpqqúrqrqqrrüsrsllmlm÷nmmnmmnmnnýonooýpoppþoppýqpqqþrqqýrqrrklþkll mþnmmnúonoonoopøqppqpqpqqrkýlkllþmllýmlmmnmnùonononoopqþpqqúrqqrqrrkülkkl lmønmnmmnmnnoþnoopþoppqürqqrrþjkklúmllmlmmýnmnnýonoopùqppqppqqrùqrrjkjkklþmllmúnmnnmnnûononoopqrôqjjkkjkkllkllklmþlmmúnmnnmnnopþoppqöpqpqqrrqrjjýkjkklûkllmllýmlmmnþmnnoñnoopooppooppqpqqþrjjkþlkk lmôlmnmnnmnmnnoopþoppýqpqqûpqqijjþkjj÷kjkklklkllmþnmmnoþnooþpoopþoppqûpqjijjkþjkklmþlmmnþmnnoþnooùpoppooppqüpqij jklþmllmnþonnopqijþijjkjkýlkllþkllmþlmmnþmnnýonoopüqiij jükjjkklúmlmllmmünmmnnoýpoppþqiijþijjklklmölmmnnmnmmnnoünopooýpoppþhiijûkjkjkklklþmllmnmnoþnooõpoopooihihiijþijjkýlkllklùmllmmlmmnùmnnoonooûnoopoophijþijjkýlkllýmlmmùlmmnmmnnýonooûpopihhijkþjkklþkllmýnmnnonoýpohhúihhihiiýjijjýkjkkûlklkllömllmllmmnmmýnmnnoh÷ihiihiijiijýkjkkþlkklómlmmnmnnmnnmnnþonnüopghhiþhiijþijjkjklþkllýmlmmnýonooýôõôôùõôõôõõôôõþôõõòôõôôõôõõôõôõôõõöõýôõôôùõôôõôôõõôýõôõõþôõõüôõôõ õþöõõþöôôõþôõõùôõôõõôõõþôõõüôõôõõ ôþõôôþõôôüõôôõõþôõõôúõôôõôõõþöõõôþõôôþõôôõôþõôôõþôõõôõþôõõþôõõüöõõô ôöõôõõôõôôõôôùõôôõôôõõôõûôõõôõ õ ôþõôôþõôôõôþõôôøõôõõôôõôôùõôôõôôõõþôõõýôóôôûõôôõôôøõôõõôôõôôôõôõôôõõôõôôõõôõôþõôôõýôõôôþõôôõôõþôõõüôõôõõúôõôõôõõôõûôõôôõõýôõôôüõôõôôõþôõõôõôõôõôùõôôõõôõõôõþôõõþôõõýôóôôþõôôõôýõôõõþôõõôõþôõ õýôóôôûõôôõôôùõôõôôõôôõþôõõþôõõôõûôõõóôôþóôôþõôôõôòõôôõôõõôõôôõõôôõþôõõþôõõýôõôôþõôôþõôôõôþõôôýõôõõûôõõôõ õüóôóôôþõôôþõôôõúôõôõôõõûôõõôõõøôõôõôôóôôõôþõôô÷õôõôõõôõôôõôõ÷ôõõôõõôõôôþóôôþóôôõôüõôõôôõôúõôõôõôôõôõñôõôõôõóóôôóôôóôôó ôõôôõôõõôôõôõôõôôõþôõõôõóôõôóôôóóôóôóôôûóôóóô ôüõôõôôøõôõôôõõôôõôõõôôõõôõôôõôôþóôôóôþóô ôþõôôõôþõôôûõôõõôôõôõûóôóóôôþóôôóôþóô ôõýôõôôúõôõõôõõôõùôóóôôóô ôþóô ôþõôôõôþõôôõþôõõúôõôõõôôúóôóôóôôþóôôþõôôþõôôõýôõôôýõôõõóôóôóýôóôôþóôôþõôôúõôôõõôôõôõùôõôôõôóóôóôþóôôþóôôþóôôõõôôõôôõôôõôôõíôóóôôóóôôóôôóôóôóóôôûóôôóôôþõôôþõôôûõôôõôôõôõôôóôôóôóóôôóóôôþóôôþóô ôþõôôþõôôîõôõõôõôôõõôôõôóôôóóôûóôôóôôþóôôùõôôõôôõõýôõôôóóôóôôóôóôôóóôôóýôóôôþóôô÷õôõõôõôõôôûóôóóôôó ôüóôóôôõôüõôõôôþõôôýóôóóôóôþóô ôþóôôúõôõôõôôõôûõôôóôôóôûóôóôóóôþóô ôþóôôüõôõôôõôþõôôóôýóôóóúôóôóóôôþóôôþóôôþõôôüõôõôôóþôóóóôóóôóóôôóôôóôôûóôôóôôúõôõôõôôþõôôùõóóôóôóóþôóóîôóôóóôóóôôóôóôóôóôôüóôóôôõôøõôôõôôõôôóþôóóôóôþóôôþóôôþóôôþóôôþóôôþóôôûõôôõôôþõóóôôóôôóóôôóôôóóýôóôôóôó ôúõôôõõôôóþôóóôóüôóóôôøóôóôôóóôôþóôôþóôôþõôô óûôóóôóóüôóóôôþóôôþóôôóôþóôôûõôõôó óþôóóûôóôôóóôóôþóôôþóôôþõóóþôóóûôóóôóóûôóôôóóôóüôóóôôþóô ôó ôóþôóóôóôôóôóóôôóôóóôôùóôôóôóôôþóôôóþôóóôóøôóóôóóôóóôóõôóóôóôóôóóô ôþõôôóþôóóúôóóôóôôöóôôóôôóóôóóôóþôóóôöóôóôóôôóóôôþõôô óþôóóôûóôôóôôöóôóóôóóôóôôþòóóüôóôóóüôóôóóôóôþóôôõóôóôôóóôôóôôóôóýôóôôøóôôóôóóôôþóôôþóôôóþòóóòôóôóôóóôóóôóôóóýôóôôóôþóôôþóôôýóòóóüôóóôôóôóôüóôóô ôóþôóóþôóóþôóóúôóóôóôôûóôóóôôþóôôóþôóóûôóôôóóþôóóúôóóôóôôøóôóôôóóôôþóôôüóôòóóþòóóûôóóôóóôþóôôóôþóôôóüòóòóóôýóôóóôûóôóôóó÷ôóôóôôóôóóþôóóôþóôôóþòó óþôóóôñóôôóôóôóóôóôóóôôûóôóóôôóôþòóóþòó óþôóóþôóóôóôóôóôþóôôóþòóóþòóóþôóóôôóôóóôóóôôóôôþóôôóöôòòóóòóóòóóûôóóôóóôóùôóôôóóôôóôúóôôóôóóöôóòóòòóóòóóþòóóþôóóûôóóôóóôóôûóôôóôôóüòóòóóøòóóòóóòóóüôóôóó÷ôóóôôóóôóóôóôþóôôúóòòóòóóþòóóþòóóøôóôóôóóôôóôóóôóôóóôóôôóóôô÷óòóòòóòòóóþòóóþôóóþôóóûôóóôóóôóôúóôóôóôôøóòóòóóòóóþòóóþôóóþôóóôüóôôóóôþóôôó÷ôóòóòóóòóóþòóóþòóóþòóóþòóóþôóóüôóóôôóôÿstuúvuuvuvvúwvwvvwwxþwxxüyxxyyz{ýzrsststýutuuøtuvuuvuvvwþvwwxwxøyxyxyxxyyzþ{rrsütssttuùvuvvuwvvýwvwwxüwxwxxüyxxyyúzyyzyzzûrssrsst uývuvv wxûyxyxyyz÷yzzrssrrsstýutuuùvuvuvuvvwûxwxwxxüyxxyyúzyzyyrrstuûtuutuuývuvvwüxwwxxyüzyyrrstuùtuuvvuvvþuvvwüxwwxxþyxxyüzyqrrsütssttuüvuuvvwýxwxxyýzyrrsýtsttuvûwvwvwwúxwxxwxxóyxyxxyyqrqrqrrsþrsststýutuuütuvuuvwvw xyþxqqûrqrqrrýsrsstþsttùuttuutuuvuvwüvwwxxûyxxyqqýrqrrüsrrsstþsttuþtuuývuvv wxþyxxqrqrsþrssþtsstuþtuuývuvvýwvwwxþwxxýqpqqürqqrrsürsrssütssttôuttuvvuuvuuvvûwvwvwwx÷wxyyppqpqqürqqrrýsrssütssttýutuuvþwvvýwvwwýxwxxþpqqpqrsýtsttuþtuuývuvvwûxwxxppþqppqrþqrrsrstþuttuývuvvüwvvwwxþwppqûpqqpqqrsþrsstþsttüuttuuv wpüqppqqrsrsûtststt uvuvwþvwwýxwppüqpqppqrýsrs sýtsttu vûwvwvwwopqrûqrrqrrstùstututuuývuvvþwvvwûoppoppqþpqqrþqrrsþrsstüststtýutuuvüuvvwwoüpooppqpq rsýtsttùutututuuývuvvwþnoopþoppqrsþrsstutuvoúnoopoppýqpqqürqrqqrösrssrsrstsstþsttuþtuuvüuvvooþnooþpoopqürqqrrsþtsstuþtuuþvuuvûononooúpoppoppqþpqqúrqrrqrrþsrrstþsttýutuuvüuvunnoþnoopøqppqpqqrrsûrssrsstþuttuûvuvvnnþonnoþnoo pqrsrsýtsttýutuuüvnmnnoþnooýpoppúqpqqpqqürqqrrüsrrsstüststtuþmnnýonoopqýrqrrsþtsstumþnmmno÷nopopopoppüqppqqþrqqrstuûtumnmmnoþnoopþoppûqpqpqqýrqrrsþrsstumnþmnnoýpoppqûrqrqrrýsrsstüutummnmnoûnoopoop qrsrststuütllmmnoþnoopopqürqqrrsrsýtsttlmýnmnnopþoppûqpqpqqrsþrsstülmlmmýnmnnoþnoopûoppqppqrqrùsrsrsrsstústtlmllýmlmmûnmnmnnüonnooúpoppoppqüpqqrrþqrrsôrsrstssttlkllmnþmnnýonoopþoppüqpqppqúrqrrqrrsþtkkúlmlmlmmünmmnnoþnooùpopopoppqúpqrrqrrösrsrsrttskklùmlmlmlmmýnmnnonopqûpqqrqqrsklmnümnnooønooppooppqþrqqrøsrrssrskklmþlmmnümnmnnýonoopopýqpqqýrqrrûsrsskklúklmllmmúnmnmmnnoþnooüpooppqýrqrrsrþjkklþkllmnýonoopùqppqqpqqrklümlmllmúnmnnmnnýonooüpooppúqppqpqqrþjkkþjkkýlkllmúnmnnmnnoþnooúpoopoppqrûkjkjkklmþlmmönmmnmmnnonnopþoppqrjkþjkk÷lkllklmlmmünmmnnüonnoo pqrüijjkkþjkklþkllþmllmþnmmýnmnnòonnoonoopoppoppþqppqrjýkjkklmnþmnno pqüijijjklþkllmþlmmýnmnnoýpoppþqppqiüjiijjõkjjkklkklkllmþlmmnüonnoopþoppüqppqqijkjkýlkllmþlmmýnmnnþonnopøopoppqpqqiùjijijijjýkjkkûlklkllýmlmmùnmmnmmnnoþpoopþoppýqhiijþkjjkýlkllmþlmmnoþnooþpoopýihii jklýmlmmnþmnnopýqphhýihiijþijjklmünmmnnoýpopphiþjiijýkjkkúlklkkllmnþmnnopûopoohhihiüjiijjkølkkllmlmmþnmmnophijkúlkllkllmúlmlmnmmnüonnooþghhýihiiþhiijþkjjkýlkllûmlmlmmnþmnnoýhghhijþijj klýmlmmúnmmnmnnýonoozý{z{{ý|{||ù}||}}~}}ý~}~~ü~~€þ€€þyzz{ö|{||{||}|}}~û~~~ý€€€ù€€€yzzý{z{{ú|{||{||ü}||}}ý~}~~þ~ý€€€ý€yzzýy{zzý{z{{|ú}|}}|}}~}~ý~€û€yzzþyzzù{z{z{z{{|}ó~}}~}~~~~ý€€€þyyùzyyzzyzz{þz{{|}ü|}|}}ý~}~~ò~~~€€€€€ùxyxzyzyyz{þz{{þ|{{|}þ~}}~þ~€û€yxyyzüyzyzz{þz{{|þ{||û}|}|}}þ~}}~€û€yxyyþzyyýzyzz{|þ{||ù}||}}|}}õ~}}~~}~~~þ€yyþxyyzyz{|þ{||ý}|}}þ~}}û~}~}~~ý~þ€xxyþxyyzþyzz{|}~þ~þ€xxýyxyyûzyzyzz{þz{{|û}|}|}}~þ~üwxwxxyzþyzzû{z{z{{ý|{||ù}||}||}}~þ}~~þ~~ûwxxwxxýyxyyz{þz{{ü|{{||}þ~}}~ø~~xwwxxyþxyyúzyzzyzzý{z{{ý|{||}ý~}~~wxûwxwxyyüxyxyyz{þz{{|þ{||ü}||}}ý~}~~þwwûxwxwxxyzþyzz{þz{{|ü{|{||þ}||}þ~}}~wxýyxyyýzyzz{ü|{{||þ}||}ý~}~~wûxwxwxxyzú{zz{z{{ü|{|{{|û}|}|}}~vwýxwxxýyxyyzyz{þz{{|þ{|| }û~vwvwwxyþxyyzü{zz{{ý|{||ü}||}}vwþvwwùxwwxxwxxýyxyyzþyzzý{z{{|þ}||}þ~vvwüxwwxxyûzyzyzz{þz{{|þ{||}þuvvwvwxwxyzü{zz{{û|{|{||ú}|}}|}}uvwþvww xüyxxyyúzyzz{zz{ý|{||}þuvvwvwxýyxyyúzyyzz{{üz{z{{|}ûuvuuvvþwvvýwvwwxþwxxyzþyzz{ûz{{|{{ý|{||ûuvvuvvüwvvwwxy÷zyzzyzzyzz{ü|{{||uvþuvvwývwxxþwxxyþxyyzþ{zz{ý|{||uvuvúwvvwvwwxþwxxyzüyzyzz{|þtuuvúwvwwvwwxþwxxyýzyzzþyzzü{zz{{ý|{||uùvuuvvuvvwxyýzyzzþyzz{þ|{{|týutuuþvuuvûwvwvwwýxwxxúyxyyxyyúzyzzyzzú{z{zz{{|tuvýwvwwýxwxx yýzyzzý{z{{tuþtuuvþuvvwúxwwxwxxyzyz{þz{{týutuuývuv vwüxwwxxyxyzþyzz{tùsttuutuuþtuuvþwvvwxþwxxyþxyyþzyyzþ{zz{üststtøututtutuuvuývuvvwþvwwxþwxxùyxyyxxyyzù{z{{z{sstuvûuvvuvvüwvvwwûxwxwxxúyxxyxyyzþyzzö{ssttsststtýutuuývuvvúwvwwvwwxþwxxýyxy yzsûtststtùuttuttuuúvuvuuvvwþvwwüxwwxxüyxxyyzstþsttýutuuüvuuvvýwvwwxüwxwxxýyxyyzýsrsstst uvúwvvwvwwúxwxwwxxöyxxyyxyyzyyûzyrrssþtsstu vwxþwxxyzyþsrrsýtsttuvw÷vwwxwxxwxxyúzyyrrssþrssûtststtýutuuvwþvwwxþwxxyþxyyùqrssrrss tuývuvvwþvwwxþwxxüyxxyyrýsrssýtsttþuttuýtvuuüvuuvvwþvwwúxwxxwxxyüxyyrrýsrsstþsttùutututuuûvuvuvvýwvwwxùyxyyqqrrsrstüuttuuþtuuvwxþwxxûyxxyqqýrqrrsrsþtss÷tsttututuuývuvvwùxwwxwwxxýyxqqrýsrssýtsttuþtuuvþuvvüwvvwwöxwwxxyxxpqqrsþrs sùtstuttuuûvuvuvvwþvwwýxwxxýypqqýrqr rsûtststtuþtuuvwüxwwxxqrüqrqrrsþrsstþsttûututuuývuvvwýxwxxqþpqqrþqrrþsrrsütstsstþuttuþtuuvþuvvöwvwvvwvwwxxüpqpqqrüsrrsstþsttuþtuuþvuuvwþvwwùxppqqpqqrþqrrsúrsrsrsststuþtuuüvuuvvwþxppüqppqqrþsrrsþtsstutuûvuvuvvwvþwppqrstýutuuvþuvvwvwþoppqþpqqþpqqýrqrrsürsrssýtsttuvuvüwvwoopúqpqqpqqrqrsrsþrsstuvþuvvwúvoopoppúqpqqpqqürqqrrstþsttþuttuvþwoopþoppýqpqqýrqrrsþrsstþsttúututtuuvþuvvûõöõöõõöþõööõöûõööõööþõö öûõööõööþ÷ööý÷öõõûöõõöõõöñõööõöõööõööõöõööþ÷ööõþöõõúöõõööõõöûõöõöõõööõööõõöõöõööþ÷öö õöõöþõööõõöõõöõöõöõöö÷úöõöõöõõöõþöõõöòõöõõööõõööõöõööú÷ö÷ööõõþöõõüöõõööþõööüõöõööþõööþõööþõööõþöõõùöõöõöõööõöþõööþõööýõöõõöõþöõõöõöøõöõõööõööõ÷öõööõõööõõ öý÷öõ õþöõõþöõõüöõõööþõööþõö öþõööõöõþöõõöõüöõõööùõööõöõö ö õúöõõööõõöõùöõööõõööíõöõõöõöõööõöõöõööõööþõöö õùöõöõööõõöõúöõööõööúõöõöõööþõööþõööõöõþöõõöþõööøõöõõööõööþõööþõööõþöõõûöõõöõõþöõõöõöþõööõþöõõòöõõöõõöõöõõöõöö÷õööõõööõööþõööûõöõõööõþôõõûöõõöõõþöõõö õþöõõùöõöõöõööõöõþôõõþöõõþöõõûöõõöõõöõöþõööùõööõöõööþõööõþôõ õþöõõüöõöõõþöõõöõöþõööõþôõõþôõõþöõõüöõõööþõööûõööõööõöõøöõöõööõööþôõõþöõõþöõõþöõõöõøöõöõöõõööõþöõõþôõõþôõõþöõõüöõöõõüöõöõõöõýöõööøõöõöõöõööýõôõõúôõôõôõ õþöõõøöõöõöõöõõþöõõöûõööõööñõööõöõôõôõõôõôõ õþöõõöõüöõöõõûöõõöõõöûõööõööüõöõööôõôõþôõõþôõ õùöõõöõöõõöõþöõõýöõööõúôõõôôõõþôõõÑöõõööõööõõöõöõõöõõööõööõöõöõööõôõôõõôôõõôôõõôôõõþôõ õöýõöõõþöõõöùõöõööõööþõööóôõôõõôõôõõôôõõôõþöõõööõõöõöõöõööõõöõööõôõõôõõôõþôõõþôõõþöõõñöõöõõööõööõööôõõýôõôôõûôõõôõõôõþôõõþöõõþöõ õùöõõööõööüõöõööôõôõþôõõþôõõþôõõöõöþõööõôõñôõôôõôõôõõôõõôõõþöõõûöõõöõõöþõôôõþôõõôõùôõôõôôõ õþöõõüöõöõõöôõô õôõôõþôõ õûöõõöõõþöõõöõýöõööþõôôõôõôýõôõõþôõõüôõôõõþôõ õöþõööõúöõõöõôôõúôõôõôõõþôõõþôõõþôõõþöõõüöõöõõôúõôõôôõõôõþôõõþôõõþöõõþöõõþöõõôüõôôõõüôõõôôýõôõõûôõõôõõþôõõøöõõööõöõõýöõööôõôõüôõôõõþôõõþôõõþôõõþôõõþöõõýöõôôõöôõôõôôõôõôôýõôõõþôõõþôõõöõþöõõúöõõöõôôöõôõõôõôõôõõþôõõõôõõôõõôõõôõõþôõõûöõõöõõöôõôúõôôõôõõôõôýõôõõþôõ õöõøöõõööõôõõýôõôôþõôôõûôõõôõõ÷ôõõôõõôôõõþöõ õôþõôôþõôôøõôõôôõôõõôõþôõõúôõôõôõ õþöõõôþõôôþõôôûõôôõôô õþôõõôõôõôõüôõôõõôôõôõôôõôõõôõõûôõôôõ õüöõöõõôõüôõõôôøõôôõôõôõõôõþöõõ ôþõôôõõôõôõôõõôõôôýõôõõô õþôõõ ôõðôõõôõõôôõôõôôõõôô õþôõõþôõ õôþõôôüõôõôôþõôôõþôõõõôõôõôõôõôôõõûôõôôõõôþõôôüõôõôô÷õôôõõôôõôôõþôõõûôõôôõõþöôôþõôôþõôôþõôôùõôõõôôõõôýõôõõþôõõ ôþõôôûõôôõôôõôþõôôúõôôõôõõþôõõþóôôþõôôþõôôýõôõõýôõôôþõôôõþôõõôõôýõôõõüôõôõõ ôüõôõôôþõôôüõôõôôõôõñôõõôôõôôõõôõõôõõôïõôôõõôõôôõôôõôõõôôõþôõõôõýôóôôüóôóôôþõôôõôõôþõôôþõôôõøôõôôõôõôôõôõúôóôóóô ôþõôôõþôõõþôõõôôõôõôõôõôõôõõüôõôõõóôþõôôõôüõôõôôûõôõôõõþôõõþóôôþóô ôõõôõôôõôõôõôôþõôôõôýõôõõþôõõýôõôôþóô ôûõôôõôôþõôôõõôõõôôõõôõõôôõùôõôõõôõõôóôþõôôõôþõôôþõôôþõôôúõôôõôõõôõúôõôôóôôþóôôþóôôþóôôþõôôíõôôõôõôôõõôõôôõõôôõõõôõôõõôõõôôõõøôõôóôôóôôüõôõôôõõôôõôôõôõõôôõôõþôõõôüóôóôôõôþõôôðõôõôôõõôôõõôõõôõõÿ{ý|{||ý}|}}ý~}~~ý€€€ú€‚‚‚óz{zz{{|{{||{||ý}|}}~~ü€€€þ€€ý‚‚‚z{þz{{þ|{{|ü}||}}ý~}~~ú€€€€€ô‚‚‚‚zz{zz{{|ü{|{||ö}|}|}}~}}~~ü~~€ú€€€÷‚‚‚yz{{þz{{ü|{{||}ý~}~~ü~~€û€€€þ‚z{ý|{||ý}|}}~}~þ~€þ€€þ€zû{z{z{{þ|{{|}~ý~€yz {|þ{||}û|}}~}}~ú~~~ý€€€üyzyzzý{z{{|û}|}|}}~ý~~€÷€yyzzyyzzû{z{z{{ý|{||}ý~}~~ù~~~~€ý€yyz{þz{{ü|{{||ü}||}}ý~}~~þ~€þxyyz{üz{|{{|}þ|}}~þ}~~þ~€ý€€€xyózyzyyzz{zz{z{{|{ô|{|}||}||}|}}û~}~}~~€÷€€xxyyxyyýzyzz{ý|{||þ{||ý}|}}ü~}}~~þ~~þ€€ýxyxxyz{þz{{|þ{||}ù|}||}}~~þ}~~û~~€xyxyz {|ó}|}|}|}}~~}}~~þ~þ€xyýzyzz{ý|{||}ú|}}~}~~~ö€xxwxyxyxyyþzyyzý{z{{|þ{||ý}|}}þ~}}~û~~üxwwxxýyxyyzþyzz{|þ{||}|}ú~}}~}~~wxwxþyxx÷yxyzyzyyzz{ |}~þ}~~wxüyxxyyüzyzyyz{þz{{þ|{{|û}|}|}}~}~þ~~wxyxyþxyyz{þz{{ú|{||{||}~þ}~~þwwùxwxwxwxxüyxxyyzý{z{{|û}|}|}}ú~}}~}~~ûwvvwwxyùxyyzzyzzû{z{z{{ù|{{||}||}ö|}~}~}~}}~~výwvwwýxwxxþyxxyz{þz{{|þ}||}÷~}}~~}~~vvýwvwwûxwxwxxyþxyyzüyzyzz{üz{z{{ |}ý~}vvýwvwwüxwwxxyýzyzzþ{zz{ý|{||ý}|}}ú~}~uuvvýwvwwþxwwxýyxyyz{|ü{|{||ü}||}}ývuvvýwvwwýxwxxùyxyyxxyyzþyzz{þz{{|}þuvvwþvwwxwxúyxyxxyyzþyzzý{z{{ý|{||}üvuuvvwxþyxxyüzyzyyz{|þ}uuvûwvwvwwxùwxxyyxyyz{z{ý|{||í}|}uuvuvuvvuvwwvwvwwþxwwxüyxxyyzþyzz{|}uüvuuvvwxwxýyxyyúzyzzyzzý{z{{|þ{||tuvþwvvýwvwwxþwxxyüzyyzz{þ|{{|tuþtuuvuvüwvvwwxyöxyxyzyzzyzz{þ|{{|ütutuuvþuvvwxþwxxþwxxyþzyyz{|ü{||ttýutuuþtuuývuvvüwvvwwûxwxwxx yýzyzz{þz{{þ|{{tuüvuuvvwûvwwxwwxyøzyzyz{z{{|ýtsttuvùuvvwvwvvwûxwxwxxýyxyyúzyyzyzz{þz{{ü|ssttuüvuuvvùwvwvwvwwxýyxyyzþ{zz{sõtsttuttuutuuúvuvvuvvþwvvwúxwxxwxxýyxyyýzyzzþ{zzstuþtuuþvuuývuvvwþxwwxýyxyyýzyzzû{rstsstuvüwvvwwxýyxyyz{ýsrsstüststtuùtuuvuuvvwþvwwôxwxxwwxxyxxyyzyzû{zrrssýtsttüuttuuùvuvvuuvvwxyþxyyúzyyzyzzsúrsststtøstuututuuüvuuvv w xyþzyyzrsrsýtsttuüvuuvvûwvwvwwxüyxxyyøzyyzzyzrrîsrrsrsststtsttuttuuþvuuvûwvwvwwýxwxxyxyzrsþrssýtsttüuttuuývuvvwþvwwxwxyxyzûyrrqrrýsrssütssttûututuuývuvvýwvwwxþwxxýyxyyþqrrýsrsstýutuuvþuvvwüxwwxxyüzqqrrýsrssútsststtüuttuuüvuuvvúwvwwvwwýxwxxyúqrqrqrrsrstþsttuþtuuvþuvvýwvww xyûpqqrqqrsýtsttúutuutuuúvuuvuvvwýxwxxýqpqqýrqrrsþrss tuúvuvvuvvüwvvwwýxwxxqpqrstþsttüuttuuvúuvwvvwwþxwwxþwxxpõqppqqrqqrqrrýsrssütssttuvùuvvwwvwwþxwwxþpqqþpqqúrqrrqrrsþrssþtsstuþtuuvþuvvýwvwwxüwxxppqrüqrqrrstþsttuvwýxwpp÷qppqqrqrqqrýsrssûtststtýutuuþvuuvþwvvwxpqrsrsôtsttsttututuuûvuvuvvwþoppþoppqþpqqrþqrrsþrsstþuttuvûuvvwvvwopùqppqppqqúrqrqqrrýsrssütssttûututuuvþuvvwô‚‚‚ƒ‚‚ƒ‚‚ƒƒ„…þ„……†‡þ†‡‡ˆþ‡ˆˆþ‚‚ƒþ‚ƒƒý„ƒ„„ …ý†…††ü‡††‡‡ýˆ‡ˆˆþ‰‚ƒü‚ƒ‚ƒƒ„…„…†þ…††þ‡††‡üˆ‡‡ˆˆþ€‚þ‚‚üƒ‚‚ƒƒû„ƒ„ƒ„„ú…„„…„……†ü‡††‡‡ˆþ€‚‚ýƒ‚ƒƒû„ƒ„„ƒƒ„ú…„„…„……ü†……††ý‡†‡‡€‚ùƒ‚ƒƒ‚‚ƒƒ„ƒ„…†þ…†† ‡þˆ€€ ‚ýƒ‚ƒƒþ„ƒƒ„þ…„„…ù†……††…††‡þ†‡‡€ý‚‚‚ƒþ‚ƒƒ„þƒ„„ü…„„……†…†û‡†‡†‡‡þ€€ý€û‚‚‚‚üƒ‚‚ƒƒ „…ü†…†……ý†…††‡ü†‡€€ý€ý‚‚‚ûƒ‚ƒ‚ƒƒ„…ý†…††ú‡†‡‡€€ü€€‚ƒû‚ƒƒ‚ƒƒ„…†‡ø†€€€€þ€€þ‚‚þ‚‚üƒ‚‚ƒƒ„þƒ„„…þ†……†þ…††ý‡†€ý€‚ƒþ‚ƒƒù„ƒ„…„…„„…ý†…††û…†‡†ý€€€ú€€€‚þ‚‚ ƒý„ƒ„„…†ý~ý€€€þ€€ ‚ƒý„ƒ„„…ü„…„……†ü…††~~ú€€€€€ý€‚þƒ‚‚ƒ„…þ†……þ†€þ€€€‚ƒþ‚ƒƒý„ƒ„„ü…„„……þ†……~ý~ €ü‚‚‚üƒ‚ƒ‚‚ƒý„ƒ„„…þ†~~ü€€€‚þ‚‚ƒþ‚ƒƒ„ƒ„ú…„……„……~ý€€€ ‚ƒø‚ƒ„ƒ„„ƒ„„…þ„……~þ}~~û€€€€þ‚‚ƒ„üƒ„ƒ„„…}~ù}~~~~€€ ‚þ‚‚ƒþ„ƒƒ„ø…„„……}}~~þ~~€þ€€û€€ü‚‚‚ùƒ‚ƒ‚ƒ‚ƒƒ„ƒ„ü~}}~~û~~~€ü€€ú‚‚‚‚ýƒ‚ƒƒù„ƒƒ„ƒƒ„„þ…}}~ù~~~ü€€€ñ€€€€‚‚‚‚‚ýƒ‚ƒƒø„ƒ„„ƒ„„}}ü~}}~~ü~~ý€€€þ‚‚ ƒ„}ý~}~~ü~~ü~€€ü€€‚ƒþ‚ƒƒù„ƒ„„||}}ý~}~~ý~€ö€€€€‚ø‚‚ƒƒ‚‚ƒƒ„õƒ„||}|}|}~}}ý~}~ ~€þ€€û€€‚þ‚‚ƒ‚ƒ„|ý}|}}ú~}~~}~~ý~€þ€€ú‚‚‚‚‚ƒþ‚ƒƒ|}þ|}}~ €ö€€€€‚þƒ‚‚ƒ|}ü|}|}}~þ}~~ü~~ü€€€€ý‚‚‚þƒ‚‚ƒý|{||ý}|}}~ü}~}~~ü€€€ù€‚‚‚ö‚‚ƒ‚ƒ‚ƒƒ{{|þ}||}~}~€þ€€‚þ‚‚õƒ‚ƒ‚|{{||{||ý}|}}ü~}~}}~ú~~ý€€€þ€€ý€‚{|þ}||}~ý~€þ€‚ƒþ‚{{|}ø~}~}}~}~~€þ€€û€€‚{|þ{||}þ|}}~}~ý€€€ý€ú‚‚‚z{{|{|}þ|}}~ù~~~ú€€€€‚þz{{õz{||{|{{|{|| }ü~}}~~ü~~€þ€‚ü{zz{{ü|{{||û}|}|}}~}~ü~~€þ€€z{þz{{|ý}|}}þ~}}ý~}~~û~~~€€ý€z{|ü{|{||ü}|}||}~þ~ý€€€zý{z{{|þ{||}þ|}}~~ý€€€ù€€zzü{zz{{ý|{||{|}ý~}~~ù~~~ý€€€þ€yyzý{z{ {|}|}þ~}}~ý~€þyzz{z{þ|{{|ý}|}} ~€õ€€€yzyyzz{þz{{|þ{||}ü|}|}}ý~}~~þ~ü€€€yzþyzz{þz{{þ|{{ý|{||ý}|}}ü~}}~~þ~~ý~ø€€€€€yyz{|þ{||ý}|}}~ú~~€ýyxyyzþ{zz{ý|{||þ}||}ü~}}~~€üxyxyyzù{z{z{z{{ý|{| |}~þ}~~ý~ü€xx yz{ôz{z{{||{{|{||û}|}|}}û~}~}~~þ~ü€xxüyxxyyúzyzzyzzü{zz{{ü|{{||þ{|| }ý~}~~ý~xyþxyyüzyyzzý{z{{|ý}|}}þ|}}~x÷wxyxyyxxyyz{z{ü|{{||þ}||}ý~}~~þ~wxyzyz{ |}~þ}~~ý~x xyøzyzyzzyzzý{z{{þ|{{|}û~}~}~~üwwxxyxyzþ{zz{|ý}|}}ü~}}~~wxyxyzþ{zzý{z{{ý|{||}þ|}}~þ}~~wxþwxxþyxxyzüyzyzz{ý|{||}þ|}}~þvwwýxwxxyþxyyz {ý|{||}þ|}}ü~vvwwùxwwxxwxxyzyz{þz{{ý|{||}|}ö~}}~}}wvvwwxùwxwxyxyyzyzý{z{{û|{|{||ü}||}}~üö÷÷ööþ÷öö÷öü÷öö÷÷üö÷ö÷÷ö÷þö÷÷þö÷÷ø÷÷ø÷÷ø÷øø÷÷ðø÷÷øø÷÷öö÷÷ö÷ö÷öö÷þö÷÷þö÷÷þø÷÷ýø÷øøý÷ø÷÷öþ÷öö÷öþ÷öö ÷ö÷þö÷÷þø÷÷þø÷÷öø÷÷øø÷÷öö÷÷ýö÷ööú÷öö÷ö÷÷ö÷üö÷ö÷÷þö÷ ÷þø÷÷ø÷öþ÷öö÷ýö÷ööü÷öö÷÷þö÷÷üö÷ö÷÷þö÷÷÷ø÷öö÷öö÷ööþ÷ööþ÷ööô÷öö÷÷öö÷öö÷öö÷þö÷÷ö÷ö÷úö÷ö÷÷öö÷ö÷üö÷ö÷÷þö÷÷þö÷ ÷öø÷÷øø÷öö÷öö÷ö÷üö÷÷öö ÷þö÷÷þö÷÷þø÷÷öþ÷ööþ÷ööý÷ö÷÷ö÷ýö÷öö÷þö÷÷þö÷÷ýö÷ööü÷ö÷öö÷öõ÷öö÷ö÷öö÷ö÷÷þö÷ ÷þö÷÷þö÷÷þøööû÷öö÷öö÷öû÷öö÷ööý÷ö÷÷úö÷ö÷ö÷÷þö÷÷ö ÷ö÷öþ÷öö÷ö÷÷ö÷ö÷÷ö÷ö÷÷þö÷÷ öþ÷ööó÷öö÷öö÷÷ö÷÷ö÷÷þö÷÷þö÷÷ö÷þö÷÷þö÷ ÷öþ÷ööû÷öö÷ööþ÷öö÷ûö÷öö÷÷þö÷÷ö÷þö÷÷öù÷ö÷ö÷÷ööû÷ö÷ö÷÷þö÷ ÷þö÷ ÷öþ÷ööþ÷ööý÷ö÷÷÷ö÷ö÷ö÷ö÷ööý÷ö÷÷ùö÷ö÷÷ö÷÷ûö÷÷ö÷÷ öü÷ö÷ööû÷ö÷÷öö÷ö÷ö÷þö÷÷ö÷þö÷÷öþõö öþ÷ö ö÷ö÷þö÷÷þö÷÷ýö÷öö÷úö÷öö÷öö÷õö÷÷ö÷÷ö÷÷ö÷÷üö÷÷ööþõöö÷ö÷ö÷ö÷ö÷þö÷÷öü÷öö÷÷öþ÷öö÷þö÷÷þö÷÷ýöõööþõöö÷ö÷÷ö÷ö÷ö÷÷öö÷ùö÷ö÷öö÷÷þö÷÷öõýöõö öþ÷ööþ÷öö÷ö÷ö÷öþ÷öö÷üõöõö öþ÷ööþ÷öö÷öþ÷öö÷ùö÷öö÷ö÷÷ö÷÷ö÷ööõööõööþõööþ÷öö÷üö÷ö÷÷þö÷÷þö÷÷þö÷÷üö÷÷ööúõööõõööþõööþõö öþ÷ööþ÷öö÷þö÷÷þö÷÷öö÷öö÷÷ö÷ö÷÷ýöõööþ÷ööþ÷ööþ÷ööþ÷öö÷öü÷öö÷÷öø÷ööõõöõööüõöõööù÷öö÷öö÷÷öú÷öö÷ö÷÷ö÷ùö÷÷ööõööþõö öþõööþ÷öö÷ýö÷ööü÷öö÷÷öû÷öõöõõöþ÷ööþ÷ööý÷ö÷÷ö÷ö÷öþ÷ööùõöõööõööþõööý÷ö÷÷öþ÷öö÷ö÷öõôöõöõööõöõööõõö÷ö÷òö÷÷ö÷÷öö÷÷ö÷÷ööõõööõööõöõöõõúöõööõööþõö öø÷öö÷öö÷ööü÷öö÷÷ïö÷öö÷ö÷ö÷õöõöõööõõýöõööþõööþõöö÷ö÷ûö÷ö÷ööü÷öö÷÷öòõöõõöõöõöõöõöõõöüõöõö öþ÷ö öò÷ö÷ö÷öö÷öö÷ö÷ööõöúõöõõöõõöþõööüõöõöö÷ûö÷ö÷ööþ÷ööþ÷ööúõöõõöõõöõöõöþõööþõöö÷÷öö÷ö÷öö÷÷ùõöõöõõööõöõõöõööõõööõööþ÷ööþ÷ööè÷ö÷öö÷÷ö÷÷ööõööõööõöõööõõöõûöõöõööþõöö÷ýö÷ööö÷ö÷ö÷õõööõõöõöþõööþõööûõööõööü÷ö÷ööö÷ö÷ö÷ö÷ööõõöúõöõöõööþõööþõööþõööû÷ö÷ö÷÷öþ÷õõþöõõöüõööõõöþõööõöþõö öþ÷ööþ÷ööþ÷õõúöõöõöõõöõöþõööùõöõõöõööõöþ÷ööþ÷ööõüöõöõõöýõöõõ÷öõööõõöõööþõööþõööþ÷ööþ÷ööû÷öö÷õõþöõõøöõöõöõöõõþöõõùöõööõõööþõööþ÷ööü÷ö÷õõþöõõöõöúõöõöõööþõööþõööú÷õõööõõþöõõöõüöõöõõöüõööõõ öþõööþ÷ööü÷õöõõþöõõþöõõóöõõöõööõõöõöõõöþõööõýöõööþ÷ööü÷ööõõþöõõýöõööõöõ öõöþõööþõööõþöõõöõþöõõúöõöõõööõùöõööõõööþõööþõööõþöõõôöõöõööõõöõöõõýöõööþõööþõö öõôöõöõöõöõõööõõþöõõöõöûõöõõööõöõþöõõöõüöõöõõöõöþõööõ ö õüöõöõõþöõõþöõõöûõööõööüõöõööþõööõþöõõùöõõöõõööõöõýöõööõöþõöö õöýõöõõúöõööõööõúöõööõööüõööõõöõûöõõöõõþöõõöþõööþõö öõô õþöõõûöõööõõöõôöõööõööõõöõö öõþôõ õþöõõöýõöõõøöõööõõöõõöþõööõþöõõþöõõüöõõööõüöõõööûõööõööõþôõõþôõõöõþöõõúöõöõöõõöþõööüõöõö öõþôõõþöõõþöõõúöõõööõõöõöøõöõõöõõööõöõþôõõþöõõþöõõöþõööûõööõööõúôõõôôõõøöõõöõõöõõûöõöõööþõööõöÿ‚ƒý„ƒ„„ý…„,‚ƒü‚ƒƒ„„-‚ƒù‚ƒƒ„ƒƒ„„-‚ƒ„-þ‚‚ƒü‚ƒƒ„„ýƒ„,ö‚‚‚‚ƒƒ‚ƒƒ-þ‚‚ýƒ‚ƒƒ-û‚‚‚‚ýƒ‚ƒƒ-þ‚‚ƒ-‚üƒ‚‚ƒƒ-þ€‚þ‚‚üƒ‚ƒ,ü‚‚‚üƒ‚‚,€ý€‚ú‚ƒ‚ƒ,€þ€ü‚‚‚-€‚ü‚‚,€þ€‚þ,€ -ü€€€þ€þ‚,€ü€€‚-þ€ý€€€þ‚,€ü€€€€ý€,ú€€€€þ€€þ,ü€€ý€€€-ú~~ø€€€€,ü~~þ€€-~þ~ý€€€-þ}~~þ~€þ,ý~}~~û€€,}ý~}~~ý~û€€,}~þ~-}û~}~}~~û~,}þ~}}ý~}~~-ü|}|}}~ø}~~~,|}~þ}~~ý~,ú}|}}|}}~}~þ,|}~-|}þ|}}~-|ú}|}}|}}~ý}~,þ{||ú}|}||}}þ~,þ{||}ý~},þ{||þ{||}-{|ý}|}}-þz{{|û}||},{ |þ},þz{{ö|{|{}||}},úz{{zz{{ü|{{||ü}||,þ{zzú{z{{|{{ý|{||-ýz{zz{þz{{ý|{||-þyzz{|{-zû{z{z{{|-y÷zyyzz{zz{{|-üyzyzz{z{þ|,yýzyzzü{zz{{-yz÷{zz{zz{{,yzþyzzù{z{z{z, yzþ{,ûxyyxyyzþ{,þyxxyzüyzyzz-xþyxxyýzyzz-x yzþy, xýyxyyz-wxyþzyy-wxyþxyyýzy,wxþwxxy-‰þˆ‰‰þЉ‰Š-ùˆ‰ˆˆ‰ˆ‰‰Š‰ýŠ‹,ˆ‰þˆ‰‰Šü‰ŠŠ,þ‡ˆˆý‰ˆ‰‰ùŠ‰ŠŠ‰Š,þ‡ˆˆþ‰ˆˆ‰ûˆ‰‰Š‰‰-ˆý‰ˆ‰‰þŠ,‡ˆþ‡ˆˆ‰-ûˆ‡ˆ‡ˆˆ‰þˆ‰‰þŠ,‡þˆ‡‡ˆ‰-þ†‡‡ˆü‡ˆ‡ˆˆ‰-‡ˆþ‰,ý‡†‡‡ˆþ‡ˆˆþ‰,†‡þ†‡‡ýˆ‡ˆˆ-† ‡ˆ-†û‡†‡†‡‡÷ˆ‡ˆ‡‡ˆ‡ˆ,†ö‡†‡‡ˆ‡‡ˆˆ,…†þ‡††‡úˆ‡‡ˆˆ,†ý‡†‡‡-†þ…††‡-þ…††þ…††ú‡†‡‡†‡‡-…ü†……††û‡†‡‡,…ý†…† †-ü„…„……†‡- …†ü‡††,…þ„……†-„…†…†-„ü…„„……†þ…,„ù…„„…„„……ý†…,üƒ„ƒ„„ý…„……û†…††,üƒ„ƒ„„…†-탄ƒ„ƒ„„……„…„…„……†…,ùƒ„ƒ„„ƒ„„ú…„…„…,ƒ„þƒ„„…ü„……,þ‚ƒƒû„ƒ„ƒ„„ü…„…,ƒ„ƒ„þ…,üƒ‚‚ƒƒ„þƒ„„ü…„„,‚ƒþ„ƒƒ„-‚üƒ‚‚ƒƒ„-‚ûƒ‚ƒ‚ƒƒ„-þ‚‚ýƒ‚ƒƒ„-ý‚‚‚ýƒ‚ƒƒþ‚ƒƒ-ý‚‚‚þ‚‚øƒ‚‚ƒƒ„ƒ,ü‚‚‚üƒ‚‚ƒƒ-ù‚‚‚‚‚ƒü‚ƒƒ,ü‚‚‚þ‚‚ƒü‚ƒƒ,ý€‚‚þ‚‚þƒ‚‚-û€€€ü‚‚‚ƒ-€‚þ‚‚-€ý€ú‚‚‚‚‚þƒ,€ü€€ý‚‚‚-ý€€€þ€‚ý‚,€þ€€þ€-þ€€-€ü€€-€þ€€-€û€€ü€,€û€€€€þ,þ~€þ€€-ü~~€-~€ý€,~ú~€€€-~ü~~û€€€,~€ý€,þ}~~ü~~þ€-÷ýø÷øøþ÷øøý÷ø,÷üø÷÷øø÷üø÷÷øø-ú÷øø÷ø÷÷ûø÷ø÷øø-÷øø÷ø÷øø÷øø÷-÷øø÷øø÷÷øø÷÷ûø÷÷ø,÷ø÷ø÷ýø÷,÷õø÷øø÷ø÷÷øø÷÷-ø÷ø÷øþ÷,þø÷÷þø÷÷ø÷þø, ÷þø÷÷þø,÷þø÷÷þø÷÷-÷þø÷÷üø÷÷,ý÷ø÷ ÷ýø÷,÷þø÷÷üø÷÷,÷þø÷ ÷-÷- ÷úø÷ø÷ø,÷ùø÷÷ø÷ø÷÷-÷- ÷þø÷÷- ÷þø÷÷þø, ÷úø÷ø÷÷,÷þø,÷þö÷ ÷-÷þö÷÷þö÷÷-÷þö÷ ÷-ûö÷÷ö÷ ÷-÷-÷þö÷÷þö÷÷þö÷÷-÷-ý÷ö÷÷ùö÷÷ö÷÷,ýö÷öö÷þö÷÷þö÷÷-þö÷÷þö÷÷þö÷÷-÷ö÷þö÷÷-ý÷ö÷÷ö÷üö÷ö,þö÷÷ö÷þö÷÷ýö÷,÷öö÷ö÷÷öö÷÷öö÷-öø÷ö÷ö÷÷ö÷÷ö-÷öý÷ö÷÷þö÷÷ýö÷,ýö÷öö÷ùö÷÷ö÷ö,öù÷öö÷öö÷÷üö÷÷,ö÷ö÷úö÷ö÷ö,ö÷÷ö÷ö÷÷öö÷÷þö,÷ö÷÷öö÷÷ö÷÷öý÷ö÷÷-û÷öö÷ööô÷ö÷÷ö÷ö÷÷ö÷,þ÷ööû÷ö÷ö÷÷ùö÷÷ö÷÷,öþ÷ööþ÷öö÷-öþ÷ööø÷öö÷÷ö÷, öù÷öö÷öö,÷öþ÷öö÷üö÷÷,ýö÷ööû÷öö÷öö÷-öü÷ö÷ööþ÷ööü÷ö÷,öþ÷öö- ö÷÷ö÷öö÷öö,ö÷ö÷ö-öý÷ö,ö-öþ÷öö-öü÷ö÷,ö-öþõööþ÷öö-öþõö ö-þõööþõö ö-ö-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-€€€€+67ý878898+6ý7677ý8788þ9*û56676678þ788+þ566ø766767677ù878778*þ566ú7667677û8788*ü565667þ677þ8*5ý6566ù76677677þ8*56ú5656766ü76677+5ú65655667+þ4556ý7677+5þ4556û7676*4û545455ü65566ü766*4þ544÷5455656566+4ý5455ý6566+4ý54556ú56556*þ34456+345þ4556+ù343433445ü656*345þ6*3ü234334þ544ý5455+ 345+23ø43434434454+23ú4344344+23ü43344+2ý3233ý4344+ý2122ý3233ü434*ï122123223233244344+ý21223ý43*1ý21223þ4*12þ122÷32322343*ú101121123+012þ1223ü233*1û212122û3223*0ý1011þ2112+0ý1011ý2122+0ý1011û212122+ý0/001ø012112122,ý0/00 12,ý0/001ø0112122+ý/0//0ú1011011,/þ0//0ø1001121,ú/00//00þ100ý1011-/þ0//01-/01ý01-./0þ/00þ1-./0ú/0010-./0/0ý10.ô././././/0/00//./00./0.ý/.//1÷././/././/þ00þ/../ü.//1./.ú/././1ý/.//.ý/.2./4./û./..4þ/..5.÷/./../..5.7ú./../..8.9.:.+þ@AAùBAABBCBBC+ABþABBþCBBýCB*@AùBABABABBýCB*ú@A@A@AABþABBþC*@AþBAABC+@ABþABB+@ûA@A@AAþBAAB+ý@?@@þA@@AúBAABA*?@üA@@AABþA*ü@??@@Aþ@AABýAB*?@þ?@@AB+?@ýA@AA+?@þ?@@ûA@AA*þ>??@þ?@@ùA@AA@A*ú?>>?>?? @þA*>?ø@?@??@A@@+>ý?>??@þ?@@+>?þ>??@+>û?>?>??@+>ü?>>??ü@?@*ò=>=>=>>??>??>??ý@?*þ>==>?>?þ@*=>þ=>>ý?>??+=þ>==>þ=>>?ü>??*=û>=>=>>û?>??*ú=<=<<==ú>=>>=>>?+ý=<== >þ?*<=þ<==>+<ý=<==ý>=>>+þ;<<ý=<==ü>==>>+;<=þ<==ú>==>>*þ;<<=þ<==û>=>=*;ý<;<<=>+ü<;;<<=<=+;ü<;;<<=+;<ý=<==+ü:;:;;ý<;<<ü=<=+þ:;;<þ;<<ú=<=<=+:;ú<;<<;<<û=<<=+:û;:;;<<þ;<<,;û:;;:;;<ý=<,:ü;::;;ù<;;<;<,:;þ:;;<-ö:9:;:;:;:;;þ<-ý:9::ý;:;;<þ;-:û;:;:;;.:9:;/9ý:9::ý;:;;/ú:99:9::ü;:;/ :ü;:;/9ü:99::1ü9::99:þ;09:þ9::29þ:99ù:9:9::1ò:9::99:9::99:2þ:99ú:99::3ô:9::99:99::4:9þ:99þ:4û9:9:99þ:5ö:9:9:99::698:9:9ù9:9:999ý9:99+þìííûìííìíí+íüìíìííþìíí+íþìííøìííìííìííüìíí*íþìííþìííþìíí+ìíûìííìííýìí*þìííì í+þíììôíìííìíìíìíìíí+üíììííìúíìíììííüìíí*íþìííìíþìíí+öíìííììíìíììíþìíí+ìíþìííüìíí*ìüíìíììíìí+øíììííììííìíìþí*þíììþíììøíììííììíí+ìíúìíìíìíí+÷ìíìíìíìíììíþìííüìíì*ìüíììííýìíììûíìíí*ìþíììíøìíìííìí*ìíì÷íììíìííì*ìþíììøíìíìíìíììí+ûíììíì ìþí*þíììöíìíììííìí*ûíìííììí÷ìíììííìì*ýìíììþíì ìþí*ìíìýíìíí+ìþíììùíììííì*ìí+ìüíìíììúíììíí* ìùíììíìí*ìþíììþí*ìþíììþíìì+ìûíìíì*ýìëììþí*ìúíììíì* ìþíìì+ìþëì ìþí*þëìì,ìþëììþëìì,þëììþëì ì,ëìþëììþëìì,ìýëìëëìþëìì-ýìëììëì-ìþëìì-ìëþìëëì.ùëììëìëììþëìì.ë ìúëììëë-öëìëìëìëìëìì/ûëìëëììþëìì/ëýìëììþëìì0ìëìþëìì0ðìëëììëìëìëëììëì0ëìëìëþì0ìþëìì2ëìëìûëììë1ýìëììúëìëìë2ìúëìëìëììþë3ôëììëëìëëìëì4ëìüëìëìì5þëììþëìì6ìë7ìëþì7øìëëììëë8üëìëìì:ëþìë+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+ÿ+þøÿÿ+þîÿÿ+þßÿÿ+þËÿÿ+þ²ÿÿ+þ”ÿÿ+þqÿÿ+þIÿÿ+þÿÿ,þäÿÿ,þ­ÿÿ,þqÿÿ,þ0ÿÿ-þßÿÿ-þ”ÿÿ-þDÿÿ.þßÿÿ.þ…ÿÿ.þ&ÿÿ/þ­ÿ ÿ/þDÿ ÿ0þ¼ÿ ÿ0þIÿ ÿ1þ²ÿ ÿ1þ5ÿ ÿ2þÿ ÿ2ýßÿ ÿ3þSÿ ÿ4þ”ÿÿ5þËÿÿ5ý0øÿÿ6þXÿÿ7þvÿÿ8þŠÿÿ9þ”ÿÿ:þ”ÿÿ9þ899:9:õ;:;:;;<;<;<<=>þ=>>?þ>??ü@??@@ýA899ü:99::ü;::;;ú<;<<;<<=þ<==>?@þ899ú:99:9::ý;:;;û<;<;<<ý=<==>ý?>??÷@??@?@@9889ý:9::û;:;:;;<þ;<<=þ>==>ø?>>??@@??þ@889þ899:9:þ;::ý;:;;<=ý>=>>?þ>??8ú9899899:;þ:;;þ<;;<=þ>==ú>=>>?>>?ü877889:þ9::õ;::;:;;<;;<<ý=<==>ú?>??>??8þ7889þ:99:ð;::;;<;;<<;;<<=<<ý=<==ý>=>>ø?>??>??77ý87889ü:99::þ;::;<;<=þ<==>þ=>>?>ø7877877889ú:99:9::ø;::;;:;<<ù;<;<<=<<=>þ=>>?7 89þ:99:;<þ;<<ü=<<==ü>==>>þ6778ü98899:ý;:;;ü<;;<<=ü<=<==ü>==>>ü676778ý9899þ899:þ9::;<þ;<<û=<=<==>=>þ677þ6778789ü:9:99:;:;<þ;<<ý=<==ú>==>>66ú76776778ú9899899:û;:;:;;<þ=<<=ú>=>=>66þ76678û989899û:9:9::õ;:;;<;;<;;<<=û<==>==þ>66þ7667ù87788788ý9899:ý;:;;ý<;<<=ü>==66ý76778þ988ý9899:þ9::;û:;<<;;<ý=<==ü565667þ6778þ7889þ899:û;:;:;;<ý=<==5ü65566û76767789:ý;:;;<;<ý=<==5ý6566ý7677 89ý:9::;þ:;;ý<;<<õ=545565665667û8787889ý:9::þ;::ý;:;;<û=<<=556ú76676778õ788988989899ú:9::;::ý;:;;<ú;<=<455þ455ý65667þ6778789þ899:9:;þ:;;ý<;<<ü45455ü65566û7676778þ788ú9898899ý:9::ú;:;::;;<ý;<44 56þ766789:û9::9::ý;:;;<þ;445ý6566ú56676778þ788þ9889:ý;:;;ý<;445þ4556þ566ý7677þ877ù89889899þ:99:;û:;;:;;345þ455 67þ67789þ899ú:9:99::;þ:;;û3433445456þ56678þ788þ9889þ899þ:99:;ý:;33ü433445ù65566766ü76677ý87889þ:99:õ;::;;3343344ú5455455ú65655667÷6787787788ü98899:ù;:;;:;3343å455454554556556566776767667789þ899:9:þ9::3ý43445þ45567þ677ü87788þ7889:3þ233û434344ü54455ü65566ý76778ú7889899ý:9::þ233þ2334þ344ú54454556þ566û767677ý87889þ899:2þ3223 45ý65667þ677ý87889:ü9223 345þ455þ6556þ5667þ87789:2û32332234545 67ý8788û9898992þ3223ý4344545ü65566þ566ü766778ý98991234í344345445545455665667878þ98891û2121223þ233þ43345ý65667ú8788788ù98989122þ322345û4554556ý7677ý8788ü98911þ2112 34ý545567ý8788ü910112þ1223þ233ý43445þ455ú6566566ú76676778ü01011 2ý32334567801ý21223þ2334 5ù65656677ü67788þ78801ü21122þ32234þ34456û5655667þ6778þ7001ý2122ú323323345þ455656 701þ2112ý32334ý5455û656566ó76676778770/001ý21223ù434433445þ455ý65667/ý0/00ý101123þ233ý4344ø54454556656ù76778/00ú1001011ü21122þ32234345ü45455676ü767//012þ1223þ233ù434343445ý6566ý7677/þ0//ý0/001þ01123û43434456þ5667ö/..//00//0010121÷2123223233ü433445ý656656ü76.//01ù01101122þ122ý3233ý4344ü54455þ4556ý7.//0/01þ011ô2122122323233þ43345þ4556ü566../ý0/00þ/00û101011ü21122ý32334ü3445 5ý6/.././þ0//0ü10011ý2122 345ý65..þ/../ 0ý1011ú2121122ý32334ý5455ü6./../þ.//ý0/001ü010112þ122ý323345þ455.û/../../þ.//0ý1011û2121223þ2334õ54455./../..þ/../ý0/00ý1011ü21122343454CDýEDEEýFEFFGöFGFGHGHGGHHIHIJûBCDCDDúCDCDDEEüFEEFFGýHGHHþIHHIýJIJJCDEDEFþEFF GHúIHIHHIIüJIIJJýIJCCþBCCDEFþEFFGüFGGHHþGHH IJCþBCCúDCDCCDDûEDEDEEýFEFFýGFGGúHGGHGHHIHùIHIIJIJJBóCBCCBCDCCDCCDDýEDEEûFEFEFFýGFGGúHGGHGHHþIHHIBýCBCCþBCCýDCDDEûDEEFEEFGHþIHHIBCDûCDDCDDEþDEEýFEFFýGFGGüHGGHHýIHIIBùCBCCBBCCüDCCDDýEDEEþDEEFûGFGFGGúHGGHGHHþIHHIþABBýCBCCøDCDCDDCDDEþDEEFþEFFGHþGHHIýHABBúCBCCBCCDEûDEDDEEþFEEFGþFGGHúIHIAABBþABBCBCýDCDDþEDDEFþEFFþGFFGüHGGHHþIAABùABBCBBCCüDCCDDñCDDEDEDEEDEEFFEEFüGFGFFGûHGHGHHþ@AABýCBCCùBCCDCCDDEýFEFFGûFGGFGGþHGGHAýBABBûCBBCBBCDCDEFõGFGGFGHGHGHHA BýCBCCDûEDEDEEúFEFFEFFGúHGGH@AAôBAABABCBBCBCCýDCDDEFøEFEFFGFGGHþG@@ýA@AAüBAABBýCBCCþDCCDEþDFFþEFFGFGúHGG@@AA@A BCDþCDDýEDEEþFEEüFEEFFýGFGGý@?@@ABþABBüCBBCCDCDýEDEEFEFGþFGG@þ?@@Aþ@AAýBABBCDEDEýFEFFöGFGFFGG@?@@ýA@AABüCBBCCDþCDDûEDEDEEFþEFFøGFF?@@?@@ ABüCBBCCþDCCDýEDEEýFEFFGù@??@@?@@AþBAAB CDúEDDEDEEýFEFFþG??@üA@@AABýCBCCDþCDDúEDDEDEEýFEFF?@þA@@ ABýCBCCDEDEùFEFF>>??ý@?@@ùA@@AA@AA÷BAABBCBBCCþDCCDEþDEEFý?>??ú@?@??@@üA@@AABúCBBCBCCDEüDEEFF>?ü@??@@úA@A@@AABCþBCCýDCDDýEDEEùFE>>?>??@Aþ@AABABCþBCCúDCDDCDDEþF>>ü?>>??ý@?@@Aþ@AABþABBýCBCCüDCCDDþEDDE>?@þA@@AüBAABBCþBCCDþCDDEüDEE>>?@ýA@AA BCþDCCDþCDDøEDE==>=>> ?ý@?@@þA@@AþBAABúCBCBBCCýDCDDþCDDü>==>>?þ>??þ>??@Aþ@AAøBABABBABBCþBCCDCD=ý>=>>?@ùA@A@AABBAýBABBCD=>=>?þ>??û>??@??@ùA@@A@ABBAýBABBýCBCCDþCDDþ<==>?@?@üA@A@@ABþABBCþBC CD=õ<=>>=>==>=>>?þ>??@ýA@AABõABBABBCBCBCCóDCD=<==<==>=>>þ=>>?þ>??þ@??ý@?@@üA@@AAûBABABBCþDCC<ý=<==ý>=>>?þ>??ý@?@@ABúABABABBCþBCCD<=þ<==>þ=>>?þ>??þ@??@üA@@AABûCBCBCCøD<=<=<<= =>þ?>>?ú@?@??@@þA@@ýA@AABCþD<<=þ<==ü>==>>ü?>>??@?@üA@@AAþBAABCþ;<<þ=<<=>ö=>?>>?>?>??@þ?@@öA@A@AABAABBC<þ;<<ý=<==ü>==>>þ=>>û?>?>??ú@?@@?@@AûBABABBCü;<;<<ý=<==>þ=>>?þ>??@AûBABABBøCBC;<;;<<ù=<<==<== >?@Aþ@AAþBAABýCB;;ý<;<<ô=<<=<<==>==>>þ=>>?þ>?? @ABAB;ü<;;<<ý=<== >ý?>??@ ABý;:;;<ý=<==þ<==>þ?>>?@þ?@@ABúABBAB::ý;:;;ú<;<;;<<ý=<==>û=>>=>>?þ>??@A@ABùAB:;::;;ù<;<;<;<< =>?@þ?@@ûA@A@AA:ü;::;;ù<;<;<;<<=þ<==ý>=>>?þ>??@A:;ú<;;<;<<þ=<<ý=<==>=>ù?>>??>??@ýA@AA9:;þ:;;ý<;< <=ý>=>>ü?>>??þ@??ý@?@@öA@A@AA::9::ý;:;;<=<=þ<==ý>=>>?ú>??>>??ý@?@@þ?@@ûA@AA99:;<;<=þ<==>?@þ?@@ûA:99::ù9::;::;;ý<;<<þ=<<=ú<==>=>>?þ>??@þ?@@üA9:99:ü;::;; <ø=<==>==>>?þ@??@9:þ9::ý;:;;þ:;;ü<;;<<ú=<==<==û>=>=>>ú?>>?>??@þ?@@ý9:99:;þ:;;<ü=<<==>?@?@9ü:99: :;þ<;;<ý=<==> ?þ@99:þ9::þ9::;<ü;<;<< =>?þ>??@ íùîíîííîííîøíîîííîíîîûíîîíîîþíîîíîí÷îíîíîíîîííþîííýîíîîþíîîíîíûîíîíîîíîùíîíîííîîþíîîíýîíîîþíîî íþîííîíîíîôíîîííîîíîííîîþìííîûíîííîîíîûíîîíîîþíîîíþîííîïíîîííîíîîíîîíîííîîþíîîþíîîýíîííúîííîîííùîíîíîîííõîíîíîíîíîíîîüíîíîîíøîííîíîîííîþíîîíîíîþíîîþíîîíþîííîíúîíîîíîîíüîííî îíþîííòîííîííîîíîíîíîîùíîíîîíîîøíîíîîííîîøíìíìííìííûîííîííþîííþîííùîííîîíîîþíîîþíîîíþìííþìííþìííþîííñîíîííîíîíîíîîíîîíýîíîîýíìííüìíìí íþîííîíþîííîþíîîíîþíîîíìíþìííþîííþîííîíîûíîíîííîþíîîûíîííîîúíìííìííþìííþîíí÷îíîîííîíîîþíî îþìííþìííþìííîýíîííîþíîîíýîíîîíþìííþìííþìííþîííþîííüîíîííîþíîîíýîíîîíîíþìííþìííþìííûîííîííîþíîîíþîííúîíîîíîîõìíììíìíìíìííþìííþìííîöíîííîíîíîííùîííîîíîîûíîííîîüíììííùìííìíìííþìííþîííüîíîííúîííîíîîíîþíììíìûíìíìííþîííîíöîííîîííîíîîìíìýíìííìíþìííþîííîþíîîíîþíîîûíìíìííìíþìí íþìí íþîííþîííþîííîüíîîííøìííìííìííþìííìíþìííþîííúîíîííîîúíîíìíììíìþíììíìíþîííúîíîíîííþîííîøíîîììííììúíìíììííþìííþìííþìí íþîííúîíîíîííîúíîíîîííìíìíìûíìíìííþìííìíþîííþîííîöíîîíìíììíììüíìíìì÷íììííìíìííþìííþìí íþîííîíüîííììüíììííìíìíìíþìííþîííîþíîîíìøíìíììíìííìíìíþìííþîííîûíîîìííìíûìíììííìíìýíìí íûîííîííþîííìüíìíììíúìííììííìíüìíìííüìíìííþîííüîííììíýìíììíìûíìíìííøìííìííìííûîííîííýìíììþíììúíìíììííüìíìííúìííìíììíþìííþîííþîííýîíììíìíýìíììíûìíììííì÷íìííìííìííüîííììûíìííììíìíûìííìí íüîíîì ìíöìííìííìíìííìýíìí íìþíììíìíì÷íììíìííìí íþìííþîííìþíììûíìíìííþìííìýíìííöìíìííìííìí íþîííìþíììùíìíììíììþíììúíìííìííìíþîììüíìíììþíììùíììíìíììüíììííìíþìí íþìí í ìûíììíììíìþíììíìíþìííþìííìýíìííìíüìíìííìûíìíìííþìí íìþíì ìíìõíìíìíìíìíìííûìííìííì íìþíììíìòíìíììíìíììíìíììíþìííþìííþëììûíìííììíþìííõìííìííìíììí íìþëììþíì ìíìíìýíìííìíöìíìíììííìííìþëììíìþíììþíììíìüíììííøìííìííìííüëìëììþëììíìúíììííììöíìíìíìííìííþìííìüëìëììþëììþíììíýìíììúíìííìííûìíììííþìííþìííýìëììþëììþëììúíìíììííìíøìíììíììííûìíììííìøëììëììëììþíììíýìíììüíìíììíþìííþìííþìííìùëìëìëëììüíìíììíìøíìíììíìííþìííüìíìííìëìþëì ìíýìíììíìíìíìíìëìüíìíììíìúíìíìíììùíìíìíìííûìíìëììþëììíìøíìíìíìíìì÷íìííìíììííóìííìëëìëëììëììüëìëììþíììþíììíìíììíììíììíìíììíìííììëììëìûëìëëììþíììíìíìþíììíöìííìíììëëììëìþëììþëì ìíìøíìíìíìíììíìäíìíìíììíìëììëììëìëìëììëëììëììíìûíìíìííììíììíììííììëììëëìëëììùëìëììëììþíììíúìíìíìííìíëüìëëììëìþëìì÷íìíìíìííììþíììííììííìíìëìëììëìëìëììûëììëììþëì ìþíììþíììíìüíìíììëìûëììëììþëììûíìííììõíìíìíìíìííìÿ@AýBABBýCBCCDþCDDEFöEFGGFFGGFGGHþGHHþ@AAþ@AABþABBCýDCDDEþFEEFþGFFGúHGGHH@@ûA@A@AAþBAABCDþCDDEFGþFGGH@üA@@AAúBABBABBúCBCCBCCDEFûEFFGFFGôFGHHGH@?@AA@@ABþABBCüDCCDDúEDEEDEEFþEFFGFGHýG?@@A@AüBAABBøABBCCBBCCDýEDEEýFEFFG?@ýA@AA÷BAABBCBBCCDûEDEDEEFþEFFþEFFGûFG?@??@úA@AA@AABCüBCDCCDEüDEDEEFGFùG?@?@?@@ýA@AABþABBýCBCCþDCCDEúFEFEEFFüGFG?? @ABABýCBCCüDCCDDEDEFEFûGFG>??@þ?@@ýA@AAüBAABBýCBCCDþCDDEüDEDEEüFEEFFü?>>??ü@??@@Aþ@AAýBABBúCBBCBCCýDCDDEùFEFFEEFF?@û?@??@@AýBABBCýDCDDþEDDEF>ü?>>??@ýA@AABCDCDüEDDEEûFEEF>>ý?>??@AöBAABBCBCBCCýDCDDEüFEF>>?ý@?@@þ?@@üA@@AABøABBCBCBCCDûEDEDEE>þ=>> ?@þA@@A BüCBBCCüDCCDDEþDEEþF>>?û@?@?@@Aþ@AABþABBCDþEDDEü=>=>>ý?>??þ>??ü@??@@ýA@AABCþBCC÷DCCDDCDEDDþE==>ý?>??ý@?@@AýBABBòCBCCBCCDCCDDCDDûEDE<==>ü?>>??û@?@?@@Aþ@AAýBABBýCBCCþDCCDþ<==ú>=>>=>>?þ>??ú@?@@?@@A@AþBAABþABB CD<ý=<==û>=>=>>ü?>>??ù@??@??@@Aþ@AABCþBCCD<ý=<==>þ=>>ý?>??@þ?@@A@AüBAABBýCBCCýDCDDý<=<<=ü>==>>?þ>??@ü?@?@@Aþ@AABþCBBCþDCCD<=þ<==>þ=>>?ý@?@@AB CüD<;<<=ù<==>==>>ü?>>??û@?@?@@ûA@A@AAýBABBýCBCCDü;<;<<û=<=<==>ü?>>??@?@ ABCüBCBCC<ý=<==>=>?>?@þA@@ïA@A@AABAABBABBCBCC;ú<;<<;<<ü=<<==>=>þ?>>?þ@??õ@??@@A@@A@AAüBAABBC;þ<;;<ü=<<==ú>==>=>>ý?>??@þA@@AýBABBûCBCC;;ú<;<<;<<=>þ=>>ó?>>?>??@?@@?@@Aþ@AABþABBúCBC::;;<ü;<;<<ü=<<==>þ=>>?û>??>??ü@??@@ûA@A@AAóBABABBCB;:;:;;ý<;<<þ=<<=>ö=>=>>?>?>??@AB÷ABB::;;:;;<þ;<<ò=<<=<<==>>=>=>>þ?>>?@Aþ@AAþBAAB:;:; <=>ü?>>??@ûA@A@AAüBAA::ü;::;;ü<;;<<þ=<<=ý>=>>ú?>>?>??û@?@?@@AþB::;þ<;;<ü=<<==ý>=>>?ý@?@@ûA@A@AA:ø9::;;::;;<=þ<==û>=>=>>û?>?>??@ýA@AAý:9::ü;::;;ý<;<<þ=<<= >?@þ?@@Aü@A@AA:÷9:99::;:;;ò:;;<;;<;<;<<=<<=ú>=>>=>>?þ>??ý@?@@ú?@@A@AA9û:9:9::ý;:;;<=>þ=>>ú?>?>>??ü@??@@þA99ù:99:99::û;:;:;;ý<;<<=<=ü>==>>?@þA99:þ9::;ý<;<<=û>=>=>>?ü@??@@ûA99899þ:99ý:9::ý;:;;<þ;<<=>ý?>??ü@??@@8ý9899:9:;<;<ü=<=<<=>?þ>??ý@?@@ý8988ú9899:99:û;:;:;;ý<;<<=<ý=<==ý>=>>ú?>>?>??@ý?7889 :;<þ;<<ý=<==þ>==>ý?>??ú@??@788 9:ý;:;;<=<=>?>?78ü98899ü:9:99:ú;:;::;;<þ;<<=>þ=>>?7ý87889þ899ý:9::;:;ü<;;<<û=<=<==>=>?þ>??78þ7889þ:99:ü;::;;ý<;<<ü=<=<<=ü>=>==>?þ>??78ü98899ü:99::ý;:;;ý<;<<ú=<==<==þ>==ü>?>??7û878788ý9899ù:9::9;::;<=ü>==>>ý?>77û878788ü98899:þ9::ý;:;;<ü;<;<<=þ<==>78ü98899:þ9::;ý<;<<þ=<<=ý>=>>û=>>7667þ8778þ9889ý:9:: ;ý<;<<=ý>=>>67ü87788ø789899899:ý;:;; <=>=6ù767676778789þ899ü:99::;þ:;;ý<;<<=þ<==þ566767þ6778ý9899:þ9::ü;::;;<=þ<==ý>5667ý8788û989988ü9::99:;:;ü<;;<<ý=<==5ü655667þ67789þ899ü:99::;<ö;<;<<=<=<==567þ6778þ788ý9899û:9:9::;ú<;;<;<<=56þ566 7ü87788õ9889899::9::;<=þJKKþLKKLúMLLMLMM NOþPOOPþOPP QþRJJKLúMLMMLMMýNMNNOúPOPOOPP QJKþJKKþLKKLúMLMMLMMýNMNNþONNOPQþPQQJýKJKKLMþLMMþLNNMNýONOOúPOOPOPPýQPQQøJIJJKJJKKúLKKLKLLýMLMMNMNüONNOOûPOPOPPQþPQQJþIJJúKJKJJKKLMNýONOOýPOPPûQIJIJJþKJJ÷KJJKKLLKLLúKLLMLMMýNMNNþONNOüPOOPPýQPIIJýKJKKLþMLLMüNMMNNüONNOOýPOPPIúJIJJIJJùKJKKJJKKLûKLLMLLMýNMNNOþNOOùPOOPOOPPIþJII JKLK÷LMLLMMLLMMNþMNNøONONNONOOðPOOPPIHIIJIJIJIJJKþJKKúLKLLKLLüMLLMMNþMNNONûONOOPPûOPPHIIúJIIJIJJKLûMLMLMMNüMNMNNOþNOOPýOPHHIJIJýKJKKLMLýMLMMNþMNNOþNOOþPHHI JKþJKKþLKKLMþLMMNOþPHHüIHHIIüJIIJJüKJJKKLMøNMNNMNMNNOþGHHIJýKJKKýLKLLMLMýNMNNþONNOHIHIüJIIJJK÷JKKJKKLLKKLMþLMMNMNONOHùGHHIHIHHIûJIJIJJþKJJKLþMLLMüNMMNNúONOGGHHýIHIIýJIJJþKJJKüLKKLLýMLMMNüONNGGHIJþIJJýKJKKüJKLKKLýMLMMûNMNMNNþOGGýHGHHþIHHøIHIIJJIJ JKLþKLLüMLLMMýNMNNGýHGHHIüHIHIIýJIJJýKJKKLþKLLþMLLýMLMMþNMMNþMGGþHGGHýIHIIþHIIùJIIJJIJJüKJJKKLMþLMMøNMMNNGFGGþHGGûHGHGHHIýJIJJKþJKKüLKKLLMþNMMFGHüIHHIIýJIJJK÷JKLKKLKKLLMþLMMøNMMFFGFGGHþGHHIýJIJJKþJKKüLKKLLMúLMMNMFFGHúGHHIHIIþHIIüJIIJJKJKLýMLMMþNFFGþFGGHüGHGHHøIHIHIIJII JKýLKLLMþLMMüFEEFFGHþGHHIþHIIüJIIJJúKJKKJKKýLKLLþMLLýMEFFþEFFGüHGGHHúIHIIHIIJIJûKJKJKKüLKKLLMþLEEûFEFEFFGøFGGHHGGHH IõJIJJKJKJKJKKLþKLLúMEEFFEEFýGFGGýHGHHýIHIIJþIJJþKJJKLEFGýHGHHþIHHIýJIJJýKJKK÷LKLLKKLLEEFúGFFGFGGHþGHHùIHIHIJIIJKüJKJKKLûKLLDEEFýGFGGúHGGHGHHýIHIIJ KLþDEEFGøFGHGGHGHHþIHHIüHIIJ JKûLKKLDDýEDEEFGýHGHHýIHIIøHIJIJJIJJüKJJKKþLKKDýEDEEþFEEFýGFGGøHGHGHHGHHIþJIIJKþJKKDEDEFEFúGFGGFGGHúIHHIHIIýJIJJKþJKKøDCDDEEDEEþDEEFüEFEFFGþFGGþHGGýHGHHIJûKJKJKKþCDDýEDEEüFEEFFGHIþJIIJK DEûFEFEFFüGFFGGHûGHHGHHIþHIIûJIJIJJKCDþCDDE÷FEFFEFEEFFýGFGGýHGHHúIHIIHIIýJIJJþKCCDEþDEEFGHþGHHIHIöJIJJIIJJKCCýDCDDþEDDEþDEEýFEFFGûFGGFGGHþGHHùIHHIHHII÷JIIJJIJJCCõDCDDCCDEDDEEþDEEFþEFFùGFGGFFGGüHGGHHþIHHIþHIIJþBCCþDCCDEþFEEFGHþGHHøIHIIHIIJJûBCBBCCDþCDDEûDEEDEEýFEFFþGFFüGFFGGHþGHHIJýIJBBCüDCCDDúEDDEDEEFGFýGFGGüHGGHHIõJBBCCBBCBCDDCDEþFEEF GýHGHHúIHIHHIIBCüDCCDDþEDDEFûEFFEFFþGFFGýHGHHIBüABBCCDþCDDýEDEEýFEFFGþFGGHùGHGHHGHHùIHHIIABBþCBBCùDCDDCCDDýEDEEFGùFGGHGGHHIABþABB CDEýFEFFGFGHøIHHABAABBCDCDEüDEDEEüFEEFFGûHGHGHHIABþABBCþBCCýDCDDüEDDEEüFEFEEFGüFGHGGHAýBABBüCBBCCDýEDEEýFEFFGFýGFGGHABþABB CDEFþEFFýGFG G@ýA@AABþABBCþBCCúDCDDCDDýEDEEFGHGùA@A@A@AAýBABBCDþCDDEþDEEFþEFF Gü@A@AABþABBCBC÷DCDCDEDDEEüFEEFFþGFFGýHG@@üA@@AABþABBýCBCCDþCDDüEDEDDEýFEFFüGFFGG@þA@@ýA@AAûBABABBþCBBCDýEDEEþDEEøFGFFGGFGG@ùA@@AA@AABüCBBCCýDCD DEýFEFFýGFGG îþïîîùïîïîïîïïýîïîî ïûîïïîïïîþïîîþïîîûïîîïîîþïîîïþîïïþðïïîþïîîùïîîïîïîîüïîîïïþîïïþîïïþîï ïîþïîîþïîîþïîîþïîîûïîïîïïüîïîïïüðïïîîþïî îûïîîïîîüïîïîîïþîïïþîïï îþïîîïúîïïîïîîûïîïïîîûïîïïîîïþîïïþîïïîïîïîïîïöîïïîïïîïîïïþíîîýïîïïîúïîïïîïïîýïîïïûîïïîï ïþîïïîþïîîïîïíîïïîïîîïïîïïîïïîïîïïîþíîîïîïîúïîïïîïïîïúîïîïîïïþîïïîþíîîþïî îïýîïîîïþîïïüîïîïïîýïîïïîùïîïïîïîîïîþïîîïþîïïþîï ïîíîõïîïïîïïîîïîîïïîïîîïïîîïïîïîïïîïïîüíîíîîúïîïîïîî÷ïîïîîïîîïïîïîïîøïîïîïïîïïîþíîîþíî îúïîïîïîîïîþïîîôïîîïïîîïîïîïïüîïíîîþíîîþïîîúïîïïîïïýîïîîùïîîïïîïïîïúíîîííîîþíîîûïîîïîîûïîîïîîüïîîïïîñïîïîïïîîïïîíîîííîþíî îïýîïîîüïîïîîïîïîïùîïîïîîïïîøíîîíîîíîîþíîîþíî îþïîîüïîïîîïî÷ïîïîïîïîïïþîïïýîíîîþíî îþïîîþïîîþïîîïîïîïîíüîííîîïüîïïîîþïîîïýîïîîïúîïïîîïïîöïîííîíîííîîüíîíîîþïîîþïîîýïîïïîýïîïïîíîþíîîïîöïîïîîïïîïîîïþîïïþíîîíîûíîííîîéïîïîïîïïîîïîîïîïîïïîîïîîòïîîïïíîîíîíîíîîïîïùîïïîîïîîïîíîûíîîíîîþïîîüïîîïïîøïîîïîîïîîþïîîíîþíî îþíî îïîïýîïîîüïîîïïùíîíîîíîîíúîíîîíîîþíî îïîüïîïîîþïîîíùîíîîííîîíîþíîîíîþïî îñïîïîîïîîïîïîîíîîúíîííîííüîííîîþíîîýïîïïóîííîîíîíîîííîîûíîîíîîþíîîþíîîþïîîþïî îþïîîûïííîííþîííîûíîííîîíýîíîîþíîîïîþïîîïýíîííîíîõíîíîîííîííî îïýîïîîíþîííîþíîîüíîíî îþíîîïúîïïîïîîýïîííþîííþîííîíýîíîîúíîíîíîîþíîîïîòïîîïîîïïîîïíîííîíþîííþîííîþíî îþíîîïîíîíîþíîîõíîîííîîíîíîîüíîíîîþíîîýïîííîíüîíîííîíîþíîîþíîîþïîîüïíîííþîííîþíîîþíîîþíîîùíîîíîíîîþíî îüïîïîîíþîííùîíîííîííûîííîííîíîüíîíîîþíîîüïîîííþîííþîííîíûîíîíîîþíîîíîþíîîûïîîïííþîííîúíîííîííîíîùíîíîîíîîþíî îúïîîïïííøîíîííîîííþîííýîíîîíîíîþïííîíîíîþíîîíîíýîíîîþíîîüíîíîîýïîííùîíîíîîííîíöîíîííîíîíîîíýîíîîþíîîûíîîíîîíþîííþîííîíûîíîíîîøíîíîíîíîîþíî îíúîííîîííüîíîííîíîíýîíîîþíî î íþîííìîíîííîíîîíîíîîíîîííîîþíîîóíîíîîííîîíîíîîýíìí íþîííîíîíûîííîííîíîíöîíîíîíîíîííûîíîíîîöíîííîíîîíîîüíîîííîíþîííîíþîííýîíîîþíîîíîþíî îýíìííþîííîíîþíîîíîþíîîþíîîþìííþîííöîííîííîíîííîüíîíî îþíîîûíìíìí íüîíîííîíîúíîííîííîöíîííîíîîíîîþìííðîííîííîíîííîííîííîúíîíîíîîíîíìýíìííûìííìííüîíîííþîííóîíîíîíîíîîííîîþíîîíì íþîííõîíîîíîíîîíîîíîýìíììüíììííüìíìí íþîííþîííîíîíî÷íîííîíîíîîíüìíìííþîííþîííîýíîííîíüîííîîíìùíìííììííþìí íþîííîíöîíîíîîíîíîîíîþíîîþíîîìþíììíûìííìííüîíîííøîííîíîîííîõíîîííîîííìííùìíìííìííþìí íöîíîîííîíîííþîííúîíîíîííýîíîîðíìííìíìííìííìíìííîí îìíþìííþìííþìííþìí íéîííîííîííîíîîííîíîíîííîîþíîîÿHüIHHIIýJIJJýKJKKüLKKLLüMLLMMNOþNOOPHIüHIIJJþIJJüKJJKKþLKKLýMLMMýNMNNONOúPOOPPHHIùHIIJIIJJûKJKJKKLMþNMMNOþNOOPGHIJþKJJ KLMûNMNMNNOþGHHIþHIIûJIJIJJúKJKKJKKLüMLLMMNOþNOOGýHGHHøIHHIHIHIIJ KLMúNMNNMNNüONONNGüHGGHHIùJIIJJIJJýKJKKLMþLMMüLMNMMNOøNOGGHGGHHúIHIIHIIJþIJJKLKLüMLLMMúNMMNMNNýONGGüHGGHHýIHIIýJIJJþKJJKLýMLMMNþMNNGHþGHHIþHIIõJIJIJJKJKJKKýLKLLûMLMLMMNFGHIþHIIJKþJKKLûKLLKLLMNþMNNþFGGþHGGHüIHHIIøHIIJJIIJJýKJKKLþMLLMüNMNFFGýHGHHIþHIIJIJKþJKKýLKLLMüLMLMMüNMNFFGþFGGHòIHIIHIIJIJIJIJJK LMFþEFFG HIýJIJJKüLKKLLýMLMMFGþFGGýHGHHIüHIIJJKüJKJKKLþKLLMýEFEEFG HIüJIIJJþKJJKýLKLLûMLMMEEýFEFFúGFFGFGGHGHüIHHIIþJIIJKJKýLKLLòMLLMMEEFEFEFEFFýGFGGýHGHHIþHIIýJIJJKùLKLKLKLLEFüGFFGGþHGGHIþHIIûJIJIJJKJKLýEDEEFþEFFGHüIHHIIJþKJJýKJKKòLKKLLKLMLDDEDEEFüEFEFFGþFGGHIþHIIüJIIJJKþJKKýLKLLýDEDDýEFEEFþGFFGHþGHHüIHHIIJþIJJüKJJKKúLKKLLDDEFõEFEFGFGFGFGGýHGHHIýJIJJKLDýEDE EFþGFFGüHGGHHýIHIIüJIIJJKLýKCDDEüFEEFFüGFFGGHüGHGHHýIHIIüJIIJJKþCDDEúFEFFEFFGHüIHHIIüJIIJJKüDCCDDþEDDEFýGFGGýHGHHýIHIIýJIJJûKJKKCCDEþFEEFýGFGGüHGGHHIþJIIJKCDüEDDEEFýGFGGHöIHHIHIIJIJJþKJJCDþEDDEùFEFFEEFFGHþIHHIJIJüKCBCC DEýFEFFGúFGFGFGGH IJBCDEFGþFGGHüGHGHHIHIJBCDþEDD EFûGFGFGGüHGGHHüIHHII÷JIJJBCCBCCDüCDCDDEþFEEFüGFFGGüHGGHHþIHHIþHIIþABBCüDCCDDüEDDEEòFEFEEFFGFFGFFGGþHGGýHGHHIýJIBBýCBCCDþCDDEûFEEFEEFGøFGGHGHGHHûIHIHIIþABBøCBCBBCBCCýDCDDúEDDEDEEýFEFFýGFGGHþGHHIúHIIBBAABCúDCDDCDDúEDEDDEE FGHIAýBABBCþBCCüDCCDDúEDEEDEEFGHGHIABöCBCCBBCCDCCDEüFEEFFüGFFGGHGHABABCþBCCþDCCDúEDDEDEEFýGFGGHþGHHA@ABþABBýCBCCýDCDDEüFEEFFýGFGGýHGHHû@AA@AA BCýDCDDýEDEEöFEFGFFGFFGGH@Aþ@AABABCõDCDDCDDEDDEEþFEEF GH@Aü@A@AABþABBCüDCCDDEDEFúGFFGFGGúH@?@@AAþ@AAüBAABBúCBCCBCCýDCDDEþFEEFGûHGHH@@þA@@ýABAABCþBCCùDCCDCCDDüEDDEEùFEEFEEFFGùFGGHG?@@ABþCBBýCBCCûDCDCDDøEDEDEEDEEFûGFGFGGý@?@@AýBABBCDüEDDEEýFEFFGïFG??@?@??@@A@AA@AAýBABBCýDCDDEûFEFEFFþGFF?þ@??@Aþ@AABþABBýCBCCúDCCDCDDýEDEEFýGF??ü@??@@þA@@AþBAABþCBBCDþCDDýEDEEFüG>>??@ûA@A@AAüBAABBCúDCCDCDDEFþEFFú>?>?>??@þ?@@Aú@AABABB CDEþDEEF>?û@?@?@@ABþABBöCBBCCDDCCDDýEDEEFûE>>?>>?@þ?@@üA@@AAüBAABBýCBCCDûCDEDEEþFEE>ý?>??@ýA@AABþABBCüBCDCCDùEDEDEEFF>?>?@ýA@AAþBAAýBABBCþBCCüDCCDDúEDEDDEEñ=>>=>>?>?>>??@??@üA@A@@ABþABBþCBBCöDCDCDCDDEDDE=>ý?>??ü@??@@þA@@ABýCBCCDþEDDEøD=>=>==>>?@þ?@@üA@@AABýCBCCDE÷=>=>=>>=>>?ü>?>??@ú?@@A@AAýBAB BCûDCDCDD=þ>==>ü?>>??õ@?@@A@@AA@AA BCúDCCDCDDþEDQRúSRSSRSSTüUTTUUVþWVVWþVWWXþWXXYXYRùQRRSRRSSýTSTTUTUýVUVVüWVVWWX÷YXYYQQRQRRSRSúTSTTSTTýUTUUýVUVVWûVWWXWWXYQüRQQRRýSRSSTUûVUVUVVWúXWXWWXXþYQQRSûRSRRSSýTSTTUTüVUVUUVþWVVWþXWWX÷YQQRQRRQRRüSRRSSTþSTTUTUVUVWûXWXWXXQùRQRQRQRRSRSüTSSTTúUTUUVUUüVUUVVùWVVWWVWWXûWQQPQQüRQQRRSþRSSüTSSTTUýVUVVþUVVWüXWXPPQRþQRRSóTSTTSTUTTUTTUUþVUUVúWVWWVWWXþQPPQRþQRRùSRRSRRSSTUþVUUVþUVVøWVWVWWVWWPQþPQQRýSRSSTþSTTúUTTUUTTùUVVUVUVVýWVWWýXWPPùQPQPQPQQ RSTþSTTüUTTUUVUVùWVWWOOPPýQPQQýRQRRþQRRýSRSSTþSTTúUTTUTUUVþUVVûWVVWPPQRþQRR SûTSTSTTþUTTUüVUUVVùWVWPOOPPýQPQQRþQRRSRSüTSSTTýUTUUöVUVUVVWVWOOþPOOP QRýSRSSþTSSTýUTUUüVUUVVOPûOPPOPPQRQRûSRSRSSTúUTUUTUUûVUVUVVOûPOPOPPQùPQQRQQRRùSRSSRRSSTùUTUTUTUUV OPQPQ RSTSTýUTUUþTUUþVUUýONOOýPOPP QRþSRRSùTSSTTSTTþUTTUVþONN÷ONOPOPPOPP QRþQRRSýTSTTýUTUUùVNNONNOOüPOOPPQRúQRRQQRRSþRSSTUþTUUNOþNOOPQþPQQRSTþSTTýUTUUýNMNNOþNOOPOPüQPPQQýRQRRýSRSSþRSSTüUTTUUNùMNNONNOO PQþRQQRûSRSRSS TUþMNNOýPOPPQöPQRQRQQRQRRþSRRSTùUTUNMNMMNüONNOOûPOPOPPúQPPQPQQRþQRRúSRSSRSSþTSSTüUTUMMNOþNOOPûOPPOPPQþPQQRþQRRSüRSRSSTMþNMMNþMNNOûPOPOPPýQPQQúRQRRQRRSTüSTSTTöLMMNMMNNMNNOûPOPOPPýQPQQRþQRRSùTSTSSTMMýNMNNONOüPOOPPýQPQQýRQRRSùRSSTSSTTLMNOþNOOûPOPOPPQþRQQRþQRRSTøSMLLMLLMMNþMNNOþNOOPQýRQRRSþTLLñMLMLMMNMNNMNNMNNýONOOþPOOýPOPP QRSRýSRSSLøMLMLLMLMMNOþNOOþPOOPøQPQPQQRQQRûSRSRSSLûMLMLMMþNMMýNMNNOüNONOOýPOPPýQPQ QRþSRRüSRSLLMLMNþMNNóONONOONOOPPOPPþQPPQûRQRQRRSúRSKLKLLMüNMMNNOþNOOPýQPQQñRQRQQRRSRSRLLKLLMNþMNNþONNOýPOPPQüRQRQQùRQSRSRKKLMýNMNN÷ONNONOONOOPQPQüPQRQQRKLKLþKLLMûLMLLMMNOþNOOþPOOPýQPQQRKýLKLLúMLMMLMMùNMMNNMNNOPþOPPQöRQQRRJJKJKKLMNþMNNOþPOOPýQPQQüRQRKKJKþLKKLýMLMMüNMMNNûONONOOPQþPQQRJKJKLMLMNONOPOPQûRQQRJJøKJJKJKKLLþKLLMþLMMúNMNNMNNOPüQPQPPQöIJKJKKJKJKKLýMLMMNþMNNOþPOOPQþPQQJýKJKKøLKLLKLLMMýNMNNOþNOOûPOPOPPýQPQQIJKþJKK LMüNMMNNOþNOOPþOPPQúPIJJIJJ KLþMLLMNMNýONOOPþOPPöQPIIJIJIIJJýKJKKLûMLMLMMNOþNOOýPOPPQIûJIJIJJûKJKJKKLMLMûNMNMNNOüNOOPPþOPPþHIIüJIIJJûKJKJKKLMLMNûMNMMNNùONOONNOOPIþJIIJýKJKKJKýLKLLïMLMLMLMLMMNMNMNMNNýONOOûPOPPHHýIHIIJþIJJùKJKJKKLLþKLLüMLLMMýNMNNOþNOOPHýIHIIJ KLMþLMMNþMNNOþNOOýPOHHýIHIIýJIJJúKJJKJKKüLKKLLýMLMMüNMMNNOþPHHIþHIIúJIJJIJJKþJKKøJKKLLKKLLýMLMMNþMN NýONOOþGHHýIHIIøJIJIJJIJJüKJJKKúLKKLKLLMýNMNNüONNOOþGHHIûHIIHIIüJIIJ JKøLKLKKLKLLM N HIûJIJIJJKJKþLKKLýMLMMúNMNNMNNOþHGGHIýJIJJKLüMLLMMýNMNNOþNGGûHGHGHHIüJIIJJKþJKKþLKKL MNûMNNOGGHGH÷IHIIHIIJIIýJIJJúKJJKJKKLüMLLMMþLMMNþïððýïðïïðûïðïïððïðþñððþñððõïððïïððïïðïïúðïïðïððþïððüïðïððûïððïððþñððøñððñïïðïïðýïðïïðïðîïðïððïðïïðïðïðïðïððïþðïïðïðüïðïððôïðïððïïðïðïððþïððúñðïïðïïðïñðïïðïðïðïïðïïðïïðöïððïððïðïððþïððïþðïïüðïïððòïðïðïðïððïðïïððûïððïððþïð ðþñðð ïþðïï÷ðïððïïðïðð÷ïðïðïððïððþïðð ïðïþðïïðøïðïððïïððõïðïïðïððïïððïðïþðïïþðïïüðïðïïùðïïðïïððþïð ðþïð ðïþðïïþðïïûðïðïððïðûïððïð ð ïüðïðïïðïþðïïðþïððïðüïðïððõïðïððïïððïððïþðïï÷ðïïðïïððïïþðïïðïðûïððïððþïð ð ïþðïïðïðïõðïðïðïïððïððþïððúïððïïððýïîïïùðïðïðïððþïððþïððüïðïððöïððïððïðïððþïððïùðïïðïðïïþðïïõðïïðïïðïðïððûïðïïððïþðïïûðïðïððïýðïððþïððûïððïððþïððïþîïïþðïïýðïððïðïðïðüïðïððýïîïïûîïîîïïúðïððïððïúðïððïððïðþïððúïîïîîïïþîï ïüðïðïïòðïððïïðïðïððïððïþðïïðýïîïïþðïïðïþðïïðôïððïïððïïðïððþïððïî ïðïòðïïððïïððïðïïððüïðïððùïððïðïððî÷ïîîïïîïîïïþðïïðïóðïïðïððïððïïððïýðïððüîïîïïîï÷ðïïðïïððïïýðïððïüðïïððïðýïðïïîïþîï ïþðïïðûïðïïððöïððïïððïïððúïðïðïððõïððïîïïîïîïïîïûðïïðïïðïðþïððîïûîïîîïïþîï ïþðïïþðïïðüïðïððïðõïðïððîïïîïîîýïîïïüîïîïïðïøðïðïïððïïüîïîïï÷îïîïîïïîï ïðïðïððïðïðïðïððïðïïðïïþîïïûîïîïîîïþîï ïþðïïþðïïüðïðïïðüïððïïðõïðîîïîïîïîïïþîïïõðïïðïðïðïðïïþðïïþðïïîüïîîïïþîïïþîïïþîï ïûðïïðïïüðïðïïðõïðïððïïîïïîîïîïþîïïþîïïþðïïðúïððïïððñîïîïîïîîïïîîïîï ïþîïïþðïïúðïïððïïðïîóïîïïîîïïîîïîïïþîïïþîïïðþïððûïððîïïîïøîïïîîïîï ïþðïïøðïððïïðîîüïîîïïîïîïîïþîïïûîïïîïïþðïïþðïïðïýðïîîøïîîïîïïîîïûîïïîïïüîïîï ïðïîïîþïîîþïîîïùîïîïïîïïüðïðïïðúïððïïîîþïîîþïîîûïîïîïïþîïïþîïïþðïïþðïïþðïïîþïîîùïîïïîîïïîïüîïîïïþîïïþðïïùðîïîîïîîïîïîùïîïîïïîîïþîïïþîïïüðïïîîýïîïïîûïîîïîîüïîîïïîïøîïïîïïîïïøðïðïïðïî îïîþïîîïýîïîîúïîïîïîîïþîïïþîïïþðïïþðîîïîüïîïîîïîïîïûîïïîïïýðïîîþïîîûïîîïîîþïîî÷ïîïïîîïîïïþîïïþîïïûðïïðïïîïîïîïîýïîïïîïüîïîï ïþîïïðîûïîîïîîùïîïîîïîîïîïþîïïîïþîïïîïýîïîîûïîîïîîþïîîöïîïîïîïîîïïûîïïîïïîþïîîïîïîþïîîþïîîþïîîïýîïîîïîïî ïîþïî îïúîïîîïîîïýîïîîïþîïïîþïîîþïîîöïîîïîïïîîïïþîïïî ïîïîüïîïîîúïîïîîïïþîïïþîïïþîï ï îï îûïîïïîîüïîîïïþîïïþîï ï îüïîïîîþïîîøïîîïïîïîîúïîïïîïïþîïïûîïîîïïùîïíîîíî îþïîîúïîîïïî îïîþïîîïþîïïþîïïîþíîîþïîîýïîïïîïîïþîï ïîþíîîþíîîïõîïîïîîïîîïîîùïîïîïîïïüîïîïïîþíîîþíîîïîþïîîøïîïîïïîïïîýïîïïîüíîíîîþïîîïîïýîïîîüïîîïïûîïïîïïîüíîíîîþíî îþïîîïõîïîîïïîîïïîîýïîïïøîïîîïïîïïýîíîîþïîîþïîîøïîïîïîïîîïýîïîîþïîîüïîîïïûîïîïîîþíîîþíî îþïî îþïîîþïîî ïî÷ïîíîîíîíîîþïîî÷ïîïîïïîîïïðîïïîïîïîïïîîïîîïïþíîîùíîííîíîîüíîíîîþïîîïîûïîîïîîüïîîïïúîïïîîïïîÿPQùPQQRQQRRSRSúTSSTSTTUýVUVVûWVWVWWXPýQPQQRþQRRýSRSSþTSSTýUTUUýVUVVWþVWWXþOPPQþPQQRSþRSSùTSSTSSTTUVþWVVWOPQüRQQRRüSRRSSýTSTTSTýUTUUûTUUVUUVúWVWWPOOPýQPQQRSýTSTTUVúUVVUUVVúWVWWPOOPQþPQQRSýTSTTþUTTUüVUUVVùWVWWVWOOüPOOPPúQPPQPQQRSþRSSTSTUVüWONOOþPOOPQüRQQRRýSRSSýTSTTUTUVþUVVþONNOþPOOPûQPQPQQ RSTþSTTUþTUUVN OPQPQýRQRRSTýUTUUVýUVNNýONOOPþQPPýQPQQRSþRSSûTSTSTTUþTUUûVUVVNNýONOOPQRþQRRSúTSTTSTTUVNýONOOúPOOPOPPQýRQRRSTþUTTUþMNNüONNOOPþOPPQRûSRSRSSýTSTTUøNMNMNNONNOPOPQþPQQûRQRQRRSTUøTUUNNMMNNOPýQPQQ RSTUMNùONNOONOOPQþPQQRþQRRûSRSRSSTþSTTýULMMNþONNOúPOPPOPPüQPPQQüRQQRRöSRSSTSTTSTTûUTMLMMNþMNNýONOOPþOPPýQPQQRSTüUTUMMúNMNNMNNýONOOýPOP PQRýSRSSüTSSTTüMLLMMúNMNNMNNOPüQPPQQýRQRRüSRRSSýTSTTL MýNMNNOýPOPPùQPPQQPQQ RSõTSTSTLLMLLMMýNMNNþONNOPQõRQRQRRQRRSRRSLMNMùNONOONOOûPOPOPPQþPQQ RSýLKLLýMLMMþNMMNýONOOPþOPPQûRQRQRRýSRSSKLMùNMNNMMNNOPOýPOPP QRSRSþKLLþKLLMNþMNNOþNOOPQúPQQRQR RSKýLKLLýMLMMýNMNNúONOONOOýPOPPýQPQQýRQRRýSRSSKúLKLKKLLMùNMNNMMNN÷ONONONOOPPþOPPúQPQPPQQRúSRRSJKKLþKLLMûNMNMNNúONOONOOúPOPPOPPûQPQPQQýRQRRýSJKKLþMLLýMLMMNúONONNOOüPOOPPôQPQQPQRQQRQRRûKJKJKKþLKKLýMLMMNùONNONNOOPQýRQRRJKþLKKýLKLLýMLMMýNMNNúONNONOOPþOPPüQPPQQRóQRRJJKJKJKKJKKýLKLLýMLMMþNMMNOþNOOýPOPPQRþIJJKLþMLLMýNMNNONOPQþRJJKLþKLLMüNMMNNOþNOOúPOPPOPPúQPQQPQQýJIJJýKJKKúLKLLKLLMþLMMýNMNNOPOPQPQIJúKJKJJKKóLKLKLLMLLMMLMMNONOPüOPOPPýQPQQI JK L÷MLMMNMNMNNOþNOOPþQPPþQIIJþIJJýKJKKýLKLLýMLMMNûONONOOüPOOPPIüJIIJJúKJKJJKKúLKKLKLLMNþMNNOøPOPOPOOPPIþJIIJüKJJKK LMNþMNNOþNOOýPOPPýQHIIüJIIJJûKJKJKKLþKLLMþLMMüNMMNNúONONNOO÷POOPOOPIHHIJúKJKJJKKLýMLM MNOþNOOPHIýJIJJþIJJKLþKLLMþLMMNüONNOOþPHHIþHIIJKLüMLLMMNþMNNüONNOOýPGHHIJKLþKLLMNüONNOOüPHGHHýIHIIJþIJJýKJKKLüMLLMMþNMMûNMNONNOHþGHHýIHIIJúKJKKJKKûLKLKLLþMLLMNMNOGýHGHHûIHIHIIJýKJKKLþKLLûMLMLMMNOGþHGGHýIHIIJüIJIJJüKJJKK LMNGüHGGHHöIHHIHIHIIJJþIJJKþJKKLþMLLMýNMNNôONFFGFHGGHGHHýIHIIJþIJJøKJJKKJLKKLüMLLMMöNMNNMNNOGFFG÷HGGHHGHHIIHIJIJKüLKLKKLýMLMMNþMNNFGýHGHHýIHIIJþIJJKþJKK LMNøMFFGFGFGGHþGHHúIHIIHIIýJIJJüKJJKKøLKLLKLLMMLMýNEFF GHIþHIIùJIJJKJKKþLKKýLKLLûMLMLMMûNEFEFFGýHGHHþIHHIúJIIJIJJKýLKLLMþLMMþEFFõGFGFFGGHGGHHIþHIIJþIJJþKLLKLüMLLMMøNEFEEFEFFúGFGFFGGHþIHHýIHIIýJIJJKþJKKþLKKLýMLMMEýFEFFGþFGGHþGHHIûHIJIJJþIJJúKJJKJKKüLKKLLùMLMLLDEEýFEFFGýHGHHúIHIIHIIþJIIJKLþKLLüMLDEEýFEFFþGFFGHþGHHþIHHIJðKJKJKKJKKLKKLLKLLEþDEEFþGFFýGFGGùHGHGHIHHIJIJKûLKLKLLYóZYZZYZYZZ[[Z[[\[ö\[\\]\]\\]] ^_þ`__`YþZYYZ [\]\]^_ú`__`_`` YZý[Z[[þ\[[\]\]ý^]^^_`_X YZý[Z[[ü\[[\\ü]\\]]þ\]]^]^_`ûXYXXYYúZYYZYZZ[\ü[\[\\]þ\]]^ú_^^_^__`_XYþXYYúZYZYYZZú[Z[ZZ[[\]\]þ^]]^_XYøZYYZYZZ[ [\ý]\]]^þ]^^_XüYXXYYýZYZZý[Z[[\ý]\]]^÷_^__^__WXXYþXYYúZYYZYZZø[ZZ[Z[Z[[\þ[\\]^]ò^]]^_^^_^__WWXXýYXYYZ[þZ[[û\[\[\\]þ\]]þ^]]^_úXWWXWXXYþXYYZ[þZ[[ü\[[\\]þ\]]^]^ù_^^_WWXXYþXYYúZYZYYZZ[ü\[[\\]\]ú\]]^]^^þ]^^WýXWXXþWXXþYXXY Zý[Z[[ù\[[\\[\\]^þ]^^ý_VWWXþWXXYþXYYZ[þ\[[\ý]\]]^þ]^^WX YüZYYZZ[\]ü\]\]]ö^]^^]]WVVWWýXWXXþWXXYýZYZZý[Z[[ý\[\\ù]\\]\\]]^ûWVWVWWýXWXXþYXXYýZYZZý[Z[[\[ý\[\\þ]\\]VWþVWWþXWWXYZYZ[þZ[ [\]VWýXWXXYüXYXYYZý[Z[[\]\]ýVUVVýWVWWXWXúYXYXXYYúZYZZYZZ[þZ[[\]ø\]]\]UUVVùWVVWVVWWXþWXXYþXYYýZYZZý[Z[[\þ[\\ý]\]]VùUVVWVVWWXþWXXþYXXYþZYYZ[þ\[[\]UVöUVVWVWVWVWWXYZ [\UVþUVVWXüYXXYYõZYYZZY[ZZ[ZZ[\[\UýVUVVþUVVWXYþXYYZü[ZZ[[ý\[\\[þ\UUýVUVVWüVWWXXWXúYXXYXYYZþYZZ[Z[ü\UTUUüVUUVVþUVVWXûWXXWXXYüZYYZZý[Z[[ø\[\[[\\TTUVWûXWXWXXYþXYYZ[î\[[\\TTUTTUUTUUVUVVWñXWXWWXWXXYXXYXYYüZYYZZ[óZ[[\[\TUUTUTUUþVUUýVUVVüWVVWWþXWWXYZ[TýUTUUúVUUVUVVýWVWWVWXúWXWXWXXYZþYZZþ[ZZû[Z[[TTýUTUUVýWVWWXûWXXWXXýYXYYüZYYZZú[ZZ[STTýUTUUVþUVVüWVVWWûXWXWXXýYXYYýZYZZû[ZZSTTUþTUUþVUUVWþVWWùXWXWXWXXüYXXYYZ[SýTSTTUVùUVUVVWVVWýXWXXúYXYYXYYZYZý[ZSST÷UTTUTUUTUUVWXûWXXWXX YZSTSTúUTUTTUUýVUVVWþXWWXYþZYYýZYZZþRSSýTSTTýUTUUV WXþYXXYúZYZZRSSøRTSSTSSTTþUTTýUTUUVüWVVWWùXWXWXWXXYZûYSRRSSTSTUþTUUVWùXWWXWWXXüYXXYYûZYYZRRSþRSSýTSTTýUTUUûVUVUVV÷WVVWWVWWX XYþXYYöZRSSRRSSRSS TUVûUVVUVVWþXWWýXWXXüYXXYYþZRR STUTUýVUVVWXþWXXúYXYYXYYRýSRSSþTSSýTSTTU÷TUUVUUVUVVûWVWVWWXýYXYYRþQRRüSRRSSúTSTTSTTUþTUUòVUVVUUVVWVWVVWWXYXRQRøSRRSRSRSSýTSTTUþVUUýVUVVþWVVWXþWXXþYQQRûSRSRSSþRSSTST UVøWVWVWVVWWüXWWXXþYQQRþSRRSTüSTTUUþTUUVWXþPQQúRQRRQRRSþRSSTþSTTUýVUVVúWVWVVWWXþPQQýRQRRüSRRSS TU VýWVWWùXWXXPPQQûRQRQRRSþTSSTUüTUTUUVúWVVWVWWüPQPQQRþQRRõSRRSRSSTSSTTUTUVûUVVWVVWþXPPQýRQRRüSRRSSTýUTU UúVUVVWVVWúVWWXWPPQRþQRRýSRSSþTSSTUûVUVUVVþUVVWPQþPQQRQRüSRRSSTSTøSTTUUTTUUVWþVWWOP QRSRSýTSTTúUTTUTUUVUVWVüWVOPPQþPQQRüSRRSSTSTUVWüOPOPPýQPQQüRQQRRSýTSTTUþTUUüVUUVVýWVOOPùQPQPQPQQRþSRRSTþUTTUVþWOOPùQPPQQPQQýRQRRþQRRöSRSRSSTSSTTUVOüPOOPPQRüSRRSSTSTUûVUVVOOýPOPPQRþQRRS TUVNýONOOPQRþQRRýSRSSþRSSTUþTUU÷VUUNONONOOýPOPPüQPPQQüRQRQQRýSRSSüTSSTTûUTUTUUðññððñðñðñðññðñðññðñþðñ ñþòññòþñððñðþñððñòðñððñðññðññððññþðññþòññòñþðññ÷ðñðñðññðññðñþðññþðññøòñòñòòñððññðñððñðñðññðñðññüðñðññþðññþðññþòññòñþòññðýñðññðñðôñððñðñððñððññûðñððññûòññòññýòñððùñðññððññðñùðñððñðññþðññþòññýðñððþñððýñðññðþñððñûðññðññþðññþðññþðññþòññðñðñúðñðñðññðñðñþðññþðññ ðþñððúñðññðññúðññððññðýñðññð ñþòññ ðñýðñððñðñþðññûðññðññþðñ ñõòññòñòññðñð ðþñððñðñþðññúðñðñðññþðññüòññððññððñðññðññðñððññðñþðññðûñðñðññþòññ ðñüðññððñðòñðññððññðñðñðññüðñðññþðññùòññòðïð ðþñððñðìñðññðñðññððññðñðññðññþðññûðñððññ ðüñðñððñìðñððññðñðññððñðññððññüðñðññþðññðñðñðñðñþðññüðñðññþðññýðñððþñððþñððöñðñðñðñððññþðññûðññðññþðññýðïððñðþñððøñðñðñðñððñðúñððñðññþðññðñðòñðñððñððñðñððññðñðñþïððþïððþïð ðþñððþñððýñðññþðññ÷ðñðñðñððññþðññðþïððþñððûñðññððñðñðñþðññüðñðññðþïððþïð ð÷ñðññððññððþñððþñððþñððñþðññþðññðþñððþñððþñððöñððñðññðñððñüðñðññþðññýðïððñðþñððþñððñþðññøðñððññðññüðññïïðûïððïð ðþñððþñððñ÷ðñððññððññþðññðþïððþñððþñðð÷ñððñðññðññþðññüðñðññðüïðïð ðþïððüñðñððïñðñððñððñðñðñððñððñþðññðþïððïðøñððñðññððñðþñððñðñúïðïðïððüïðïððþïððüñðñððþñððüñðñððñüðñðññðùñðñðïïððþïððþñððüñðñððýñðññøðññðñðñððþïððüïðïððþïððþñððþñððþñððùñðññðñððþïððïðþïððþïððñðþñððñàðñððññðñðñððñðññðïððïðïðïððïððïððþïððþñððþñððñüðññððþñððýñðññøðïðïïðïððïýðïððûïððïððþñððøñððñððñððöñððñðñðññïïðþïððïýðïððþïððþñððûñððñððúñðñïðïïðõïðïïððïðïðïïðüïðïððþïððñðþñððñðúñððñðïïüðïðïïðýïðïïýðïððùïðïððïððñþðññðïðïðøïððïððïððþïððþïð ðþñððþñððýïðïïýðïððïðïðþïð ðþñððþñððñðïóðïïðïïðïïðïïððþïððþïð ðþñððþñððþñððïøðïðïðïðïïúðïððïððïðüïðïððþïððñïðïþðïïðþïððþïððþñððþñððúñðñððïïðïðúïðïðïð ðþïð ðþïð ðþñððûïðïðïïþðïïþðïïûðïïðïïðþïððþïð ðþñððüñðñððþñððïùðïïðïïððïûðïðïððïðþïððïðþñððûñððñïïðïüðïðïïðöïðïððïïðïððûïððïððúïðïïðïïðïûðïðïððïðþïððþñïïùðïïðïðïïüðïðïïëðïïðïðïðïðïðïððïïððïððþïððþñððïûðïïðïïþðïïðïýðïððüïðïð ðþïððþñðð ïþðïïüðïðïïþðïïðïõðïðïððïððïððþïððïþðïïðïðüïðïððïðïðþïð ðïþðïïüðïðïïðúïðïïðïïðüïðïððþïð ðüïðïðð ïúðïðïðïïúðïïððïïðûïðïïð ðþïð ðïûðïïðïïðþïððùïððïðïððþïððïðïþðïïðïúðïïðïððùïðïïðïððïðïýðïððïþðïïðþïððïðþïððïþîïïþðïïþðïïðïýðïððûïðïðïïûðïðïððîïðþïððïðûïðïïððöïðïðïïðïïððüïðïððïþîï ïþðïïúðïðïðïïðøïððïðïïð ðþïððïüðïðïïûðïðïððïúðïïððïïðúïððïïððïðïþîïïúðïïððïïðïðïýðïððüïðïððïùîïïîïîïïüðïðïïþðïïþðïïððïððïðïðïïððïððïððïþîï ïþðï ïþðïïýðïððôïððïðïïððïïððûïðïðïïîïþðïïðïð÷ïðïðïïðïððï ðÿþWXXYýZYZZý[Z[[ú\[\[[\\û]\]\]]^ü]^]^^_ø^__`_WWXXüYXXYYZû[Z[Z[[÷\[[\\]\\]]þ\]]ý^]^^ý_^__ú`_XXWXXþYXXYZYZ[þZ[[\ö[\\[\\]]\]]ý^]^^ú_^^__WWýXWXX YZú[Z[ZZ[[ý\[\\ý]\]]ý^]^^ü_^^__WXþYXXùYXYYZYZZ[þ\[[ü\]]\\]^_WXYZþYZZú[ZZ[Z[[\ñ]\]\]\]]^^]]^]^^þ_WWûXWXWXXYýZYZZ[þZ[[ü\[[\\]ù\]]^]^]]^û_WWVWWûXWXWXXýYXY YZ[Z[û\[\[\\ ]^þVW WûXWXXYYþXYYZþYZZü[ZZ[[\þ[\\þ]\\]ù^]^]^^VVWøVWXWXWWXXüYXXYYýZYZZ[þZ[[ú\[[\[\\]\]õ^]^^VVWVWVWWXWX YZû[Z[Z[[ý\[\\ø]\\]\]\]]^ý]UVVWúXWXWWXXYZYZý[Z[[þ\[[\ú]\]]\]]ü^]UVVýWVWWXøWXXYYXXYYüZYYZZþ[ZZ[\û[\\]\\ø]\]]^]UVVûWVWVWWüXWWXXYýZYZZ[þZ[[þ\[[\ù]\]\]]UUVWüVWVWWXüYXXYYþZYYZ[\û[\\[\\ý]\UUýVUVVýWVWWXWXþYXXYýZYZZ[ý\[\\]UVWüVWWXXWXóYXYXYYZYYZYYZZú[Z[[\[[\]UVþUVVWXýYXYYZ[üZ[Z[[ý\[\\ú]TUUTUUýVUVVýWVWWýXWXX YZ[þ\[[\þ]UUûVUVUVVþWVVWöVWXXWXXWWXXYþZYYZ[ø\[[\[\\TTUýVUVVýWVWWXúYXXYXYYZþ[ZZ[\TUþTUUýVUVVWþVWWûXWXWXXYþXYYZþYZZü[ZZ[[û\[\STTýUTUUVWþVWWXYZý[Z[[TõUTTUUVVUVUVV WXýYXYYýZYZZý[Z[[TýUTUUVþUVVWúXWXXWXXYZ[STùSTTUTTUUýVUVVûWVWVWWXYXYüZYYZZ[ûZ[[TSSTþSTTüUTTUUVþUVVüWVVWWXþWXXYZöYZZ[ZZ[Z[SSTýUTUUûVUVUVVWúVWWXWXXYZü[Z[SSýTSTTUþTUUVøWVWWXWWXXüWXYXXYZøYZZ[[RRSSTüUTTUUýVUVVýWVWWXWXYXYZRSTþSTTùUTUUTTUUVýWVWWXþWXXýYXYYùZYZZYZRRSøRSTSTSSTTUýVUVV WXYZYRSRSýTSTTUþTUUVWúXWXXWXXYþZRRüSRRSSTþSTTUþTUUVUVýWVWWôXWWXXWXXYYXYYýZYRRSýTSTTUþTUUVýWVWWýXWXXýYXYYþZQQRSüRSSTTUþVUUVùWVWWVVWWýXWXXYþQRRSþRSSTUVUVýWVWWýXWXXYQþRQQRSþRSSTùSTTUTTUUüVUUVVWXþYXXQýRQRRüSRRSSþRSSýTSTTUVWVWXþWXXûYPQPQQûRQRQRRS÷RSSTSSTSTTUüVUUVVWýXWXXýQPQQRñSRSSRSSRSSTSTSTTUýVUVVWXþWXXPQRýSRSSûTSTSTTUþTUUûVUVUVVýWVWWXþWXXùPQPQPPQQRùSRSRSRSSTSTUüTUTUUüVUUVVûWVWVWWXþWPPýQPQQýRQRRSýTSTTúUTUUTUUVþUVVWþVWWPùQPQPQRQQRþSRRSTõSTTSTTUTUTUUýVUVVWX PQýRQRRSRSùTSSTSSTTUüTUTUUüVUUVVWOPQR÷QRRSRSRRSSûTSTSTTýUTUUVWOPþOPPýQPQQRþQRRýSRSSTýUTUUVWùOPOOPOPPQR STUVûUVVUVVWOPýQPQQýRQRRûSRSRSSTûUTUTUUVUVýWVOOPþOPP QRþSRRôSRSSTSSTTSSTTUýVUVV÷WVVNNOONOOPþOPPüQPPQQûRQRQRRúSRSSRSSTST UVNOPQþPQQRúSRSSRSSüTSSTTUVþNOOþNOOýPOPPQþPQQRþQRRSýTSTTýUTUUVNüONNOOýPOPPQRþSRRSTUþTUUVþUNNüONNOOPýQPQQýPQRRýSRSSýTSTT÷UTUUTUUTUUþMNNOüPOOPPýQPQQRSþRSSûTSTSTTUM NOPQüPQPQQRSþTSSTúUTUTTUUûNMNMNNOþPOOPQPQûRQRQRRýSRSSTþSTTUM NOPþOPPQþPQQ RST÷STTUTTUUMMNMNüONNOOPüOPOPPüQPPQQùRQRQRQRRSTûSTTSTTüUTTMMNþMNNOþPOOPQûPQRRQQRSþRSSTûLMLLMMûNMNMNNOüPOOPP QRSûTSTSTTLMýNMNNOüPOOPPQþPQQüRQQRRSTþSTTþ`aaþ`aabþcbbýcbccýdcddþeddefþeffgþ`aaþ`aabþabbcþdccýdcddeþdeeýfeffýgfggýhg``üa``aabøcbccbcbccdþcdd eýfeffþgffg`úa``a`aaýbabbúcbccbccýdcddedeûfefeffgþfgg`øa`a`aa`aabýcbccýdcddedýedeefgþfggþ_``ýa`aaýbabbýcbccdcýdeddeùfeeffeffg_÷`__`a`a`aaúbabbabbûcbcbcc d efþg__ý`_``ýa`aabþabbýcbccdþcddüeddeeøfeefefeff_ `aøbabbababbcþdccdefþeff_`û_``_``ýa`aaûbababbcdeþdeeùfeff^^__þ`__`abþabbcþbccdeþdeefýe^__û`_`_``a`abþabbücbbccübcdccdeûfeff^^ü_^^__`_`üa``aaúbaababbcþbccdücdcddef^_^_`ýa`aa bûcbccddcdeþdee^ý_^__`üa``aabücbbccýdcdde^ù]^^_^^__ý`_``þa``abaýbabbcþbccúdcddcddôedeedee]^^]^^_`aþbaabcüdccddeþ]^^_þ^__`_`þ_``aù`aabaabbýcbccþdccdeþ]^ ^ý_^__`aþ`aa÷babaababccbc dþe]]^þ]^^_÷^__`__`_``ýa`aaþ`aabúcbccbccdþcdd]^þ]^^ý_^__`a bcþbccüdccddþ\]]ø^]]^^]]^^ý_^__þ`__`aú`a`a`aaþbaabcdýcd\\]^ü]^]^^ý_^__`þ_``aþ`aa bcdõ]\]]\]]^]]^^þ_^^_ý`_``aúbabbabbûcbcbccþd\\ý]\]]^_`_ø`a`aa``aabücbbcc\þ]\\]^]^ý_^__`þ_``þa``ûa`abaaübaabbcbc\ý]\]]ù^]^]^]^^_^_ý`_``a`ýa`aaúbaababbýcbccþ[\\]ü^]]^^ý_^__`þ_``aü`a`aaübaabbcübcc\\ü]\\]]^þ]^^_ý`_``üa``aaýbabbþcbbøc\\[\[[\\þ]\\]ü^]]^^ü_^^__ú`_``_``üa``aab÷cbbc[[\[\\]þ\]] ^_ù`__``_``aýbabbc[\þ[\\û]\]\]]ý^]^^_ó^_^_^__`_``_``üa``aaýbabbþc[[û\[\[\\ü]\\]]ü^]]^^ú_^_^^__û`_`_``aýbabbþZ[[\]\]ú^]]^]^^þ_^^_`abøabb[[ZZ[[ý\[\\ö]\\]\]]^]^^ø]^^__^^__`þ_``abþaZZ[ýZ\[[\ý]\]] ^_`aþbaa[üZ[Z[[\]þ\]]^ _`û_`a`aaùbaaZZ[ZZ[\ý]\]]ý^]^^ý_^__ú`_``_``aþ`aaZü[ZZ[[\ü[\[\\]û^]^]^^_þ^__`ða`aa`a`ZYYZZ[ZZ[[þ\[[\ý]\]]^þ]^^ü_^^__`a` Zý[Z[[\]\]ü^]]^^_^_ú`__`_``ùa`aZZYZZý[Z[[ü\[[\\ý]\]]ý^]^^_`aý`YZZYZ[Z[\ý]\]]^þ]^^û_^_^__`_`üa``YYZ[\þ[\\ú]\\]\]]^]^þ_^^_`YZþYZZ[\ú]\\]\]]þ^]] ^ô_^_`__`__``YYùZYYZZYZZý[Z[[ý\[\\]^þ]^^þ_^^_ö`__``YXYXYYZþYZZ[þZ[[û\[\[\\ú]\\]\]]ý^]^^ý_^__`ùXYXYYXYYZYZ[Z[\þ[\\û]\]\]]ú^]]^]^^ü_^^__÷`XXYXXYXYYüZYYZZ [ý\[\\ý]\]]^þ]^^ü_^^__XYýZYZZ[ý\[\\þ]\\ý]\]]^ü]^]^^_þ^__ýXWXXYþXYYZùYZZ[[Z[[ú\[[\[\\ù]\]\]\]]^û]^^]^^ý_^__XþYXXYþXYYýZYZZþYZZ[þZ[[þ\[[\]ú^]^]]^^_ûWXWWXXúYXYYXYYýZYZZ[þZ[[þ\[[\ý]\]]þ^]]^î_^^_WWXXWXWXXYXYXYYýZYZZ[\]ú^]]^]^^ý_^WWXúYXYXXYYýZYZZ÷[ZZ[[Z[[\\þ[\\]þ\]]^WXþWXXYýZYZZü[ZZ[[\þ[\\ù]\]]\\]]^þ_WWXWXYXYýZYZZü[ZZ[[\þ[\\]þ\]]û^]^]^^üWVVWWXüYXXYYZþYZZü[Z[ZZ[û\[\[\\]^ù]^^WWVWWüXWWXXYüXYXYYýZYZZó[Z[[ZZ[\[[\[\\]þ\]]ý^]VVWþXWWXYþZYYZ[\ý[\[[\]þ\]]ý^]VVWüXWXWWX YZû[Z[Z[[ý\[\\]þUVVýWVWWüXWWXXþWXXYXYZþYZZû[Z[Z[[ü\[[\\]ú\]\]]VVWþVWWXYX YýZYZZ[÷Z[[\[\[[\\]ú\]UVUVVWþVWWúXWWXWXXøYXXYXYXYYýZYZZý[Z[[\þ]\ìòñòòñòòñòññòòññòòññòòþñòòþñòòóòóþòóóñûòñòòññòþñòòþñòòúñòñòñòòþñò òüóòóòòóòýóòññöòññòññòññòòüñòòññòþñòòþñòòóòþóòòûóòóóòòøñòññòòñòòþñòòûñòòñòòóòþóòòóýñòññþòññúòñòòñòòþñòòñòüñòñòòþóòòøóòòóóòòññüòñòññòþñòòñòùñòòñòñò òûóòòóòòþóòòùóòññòòñ ñøòñòñòòñòòþñò òþñòòüñòñòòñòúñòñòñòòþñòòþñòòûñòòñòòñøòññòññòññþòññûòñòñòòñòþóòòñòñþòññ÷òñòññòòñòòñòöñòòñòñòòñòòþóòòûóòñòññýòñòòñþòññò÷ñòñòòñòñòòûñòòñòòúóññòòññòñýòñòòñòõñòññòñòòññò òûñòòñò òûóòóòñññòñòñòñòñòòññòñòòþñòòþñòòóúñòññòññòñòñòñò÷ñòòñòòññòòþñòòþñòòñþòññúòñòññòòñúòñòñòññòñò ñþòññøòññòññòññüòññòòþñòòñýòñòòûñòòñò òñøòñòòñòñòòñýòñòòñòùñòòñòñòòþñò ò ñþòññüòñòññòòñòñòññòñòñòòññòñòþñòòýñðñ ñøòñòòññòññüòññòòñòþñòòñòþñòòñùòñòñòòññòñüòñòññôòñòòñòòñòòñòòþñòòþñòòýñðññûòññòññòòññòñòññòñòññòòûñòòñòòñþðññíòññòòñòñòñòñòññòññòòöñòñòòñòññòòþñòòñüòñòññøòññòññòññòñòñòþñòòþñòòüñððññþðññþòññþòññòøñòñòñòòññþòññòûñòòñòòþñòò ñþðññþòññþòññòñüòñòññòøñòñòñòñòòþðññð ñþòññòýñòññûòññòññ÷òñòññòññòòñòñòþñòòñþòññùòñòññòññùòñòñòñòòþñòòñþòññþðññþðñ ñüòñòññþòññòñýòñòòûñòñòññòñþðññþðñ ñþòññüòññòòýñòññúòññòòññòþñòòñþðññþðññòñòýñòññûòññòññòñòúñòññðññþðññúòñòñòññþòññòûñòòñòòüñòñòòñüðñðññøðññððñðññþðññòñûòññòññíòñòññòòñòñðñðññðñðññþðñ ñþòññòûñòòñòòñüòñòññûòñòñòòüñòðññþðñ ñþðññþòññüòñòññþòññøòññòññòññüòñòññòðñþðññðñðñþðñ ñþòññüòñòññøòñòòñòñòòþñððýñðññðñðñüòñòññòñþòññþòññòñüòñðññðüñðñððñüðññððñþòññþòññòþñòòùðñððñðññþðññþòññòñòüñòñòòýñòððýñðññðïñðñðññððññðñðññðññüòñòññûòñòòññöòññòòññðñððñþðññþðññþòññòñùòñðññðññðñðúñððññððñþðññþòññùòñòññòññðûñððñððöñððñðññððññþðññþðññþòñ ñòûñòñòññüòññððþñððñðñþðñ ñþðñññòññòññòððñððññððñþðññðñþðññþòññüòñòññðñðñüðñðññþðññùðññðñðññüðñðñ ñþòññüòñòññýòðññöðñðñðñðñðññðýñðññðýñðññòñûòñðñððëñððññðñðñðñðññððñðñðññûðññðññúòñòññððþñððþñððñýðñððñþðññðñþðññòñðûñððñððùñððññðññüðñðññðñþðñ ñòñþòññýðñððôñðññððñðññðññþðññðöñðñðñððñðññþðñ ñþòññþòññðñýðñððñðñþðññùðñðññðññûòññòð ðùñðñðññðð÷ñðññððñðññúðñðñðññþðññþðñ ñýòñððþñððþñððñðþñððñûðññðññüðñðññüðñðñ ñüòññð ðþñððöñððñðñððñðð ñþðññðóñððñðñðñðññðññþðññþðñ ñðñôðññðñððñððñððñðñðñþðññþòððûñðññððþñððþñððñðþñððñüðñðñ ñðñðþñððñðüñðñððñûðññðññýðñððñøðññðñòñððþïððþñð ðþñððúñðññðñññðñðñðñðññðññððññüðñðññ ðþñððþñððñðúñððñðññðñþðññðüñðñððñðïñðññðñðñððññðñððññüðññððúñðññðññðüñððññýðñððôñððñððññðñðññðñøðññðññðññðþïððüñðñððúñððñðññþðññðñðñþðññðñþðññ ðþñððñýðñðð÷ñððñðñððññðñöðñðññðññðñÿ_`a`aþbaabúcbcbbccdücdcddefefg_û`_`_``aþ`aaübaabbcýdcd defg_`a`abaýbabbcdøcdedeedeefgüfgf__` abýcbc cdeýfeffùgfgfg^__ý`_``úa`aa`aaýbabbücbbccdþcddüeddeefgý_^__û`_`_``aþbaabcþbccdcdef_`ü_`_``a`aübaabbþcbbcdøcddeeddeefúeff^_^^_ý`_``þa``ababcûdcdcddeûdefeff^ý_^__ú`__`_``þa``abýcbccdþcddüeddeeýfeff^_^_ú`__`_``aþ`aabücbbccùdccddcddýedeeýfe^^ú_^__`__`ú_``a`aabûcbcbccüdccddeüf]]^^_þ^__÷`_``_`a`aaúbabaabbcdcdýedee^]^_û`_`_``ýa`aabcþbccdþeddeý]^]]^_`_`a`abcübcbccdeýde]]^ù_^^__^__`_û`a``aaóbabbabbccbcbccde]^þ]^^ý_^__`üa``aaübaabbcbcüdccdde\]^þ]^^_þ`__`abýcbccüdccdd\]^ý_^__`÷_``_a`a`aaûbababbücbbccdöcdd]]\\]\]]^_ý`_``þa``aûbababbùcbccbbccýdcdd\]^]^ _`üa`a``ababþcbbcûdcdd\\ü]\\]]û^]^]^^_ý`_``aýbabbcd\ü]\\]]ý^]^^ü]^^__`_`abcþbccù[\[\\]\\]ü^]]^^þ_^^_ú`__`_``a`abcþbccø[\\[\\]\\]^_^_`þa``ýa`aaübaabbcübcbcc[ý\[\\þ]\\]û^]^]^^ü_^^__`aûbababbcýbc[[\û]\]\]]^ý_^__þ`__`ýa`aaübaabbcþb[[\þ[\\ý]\] ]^_ý`_``þ_``þa``aõbabbabcbbZ[[ý\[\\ý]\]]^þ]^^þ_^^_`ýa`aabþabbþZ[[\þ[\\û]\]\]]^ü_^^__`û_``_``ûa`a`aabùcZZ[[Z[[\]^þ]^^þ_^^_` abZ[þZ[[\ý]\]]þ^]]^ _`ýa`aaþbZZ[øZ[[\\[[\\þ]\\]ý^]^^_ý`_``üa``aaýZYZZõ[Z[ZZ[[\[[\\]þ\]]ý^]^^_þ^__ý`_``aù`abbaYZZ[þZ[[ü\[[\\]ý^]^^ú_^_^^__`þ_``a`aüZYYZZ[Z[\ù[\\]\\]]^_û`_`_``aýZYZ Z[ \]þ\]]ü^]]^^þ_^^ý_^__`ù_``aa`aaYZþYZZý[Z[[\þ[\\ü]\\]]ø^]]^^]]^^_`ûa``aYYZ[þZ[[û\[\[\\û]\]\]]ü^]]^^_û`_`_``üa`aYYüZYYZZý[Z[[ü\[[\\þ]\\]ò^]^^]^^_^^_^^__ `ûXYYXYYüZYYZZ[þZ[[ý\[\\]^þ_^^ý_^__`YþXYY÷ZYZYZZ[Z[[þ\[[ý\[\\ý]\]]^_ý`_``X YZ[ù\[[\[[\\]\]õ^]^]^^_^^_^^_`þWXXýYXYYZþYZZ[Z[\]ý^]^^_þ^__XýYXYYZý[Z[[ù\[[\\[\\ý]\] ]^_þ^__XþWXXYZ[\ü[\[\\]^þ]^^_WüXWWXXýYXYYþXYYZ[ý\[\\ý]\]]^ü_^^__ýWXWWXýYXYYøZYZYZZ[ZZ[ý\[\\]ú^]]^]^^_WþXWWXýYXYYZ[Zý[Z[[ý\[\\]ü\]]^^_þ^WWýXWXXüYXXYYZþYZZ[Z[ \]ü^]]^^þ_^^WúXWXXWXXYXYZý[Z[[\û]\]\]]ü^]]^^WõVWVWXWWXWWXXýYXYYþXYYZú[Z[[Z[[\[\]þ\]]^þVW WXYýZYZZ[ý\[\\þ]\\]^þ]VVýWVWWýXWXXYþXYYZ[û\[\[\\û]\]\]]ú^]]^^VVWþVWWûXWXWXX YZý[Z[[ý\[\\ò]\\]\]]\]]^^]VVWVWXYZ[þZ[[\þ[\\ú]\]]\]]þUVVWþVWWXY÷XYXYYZZYZZü[ZZ[[\þ[\\þ]\\]UVþWVVWX÷WXXYXYYXYYZû[Z[Z[[û\[\[\\õ]\\]\]UUVUVVüWVVWWüXWWXXøYXYYXYZYYZû[Z[Z[[\ò]\\]]\UVVUVUUVVWXþWXXYþXYYýZYZZù[ZZ[ZZ[[ú\[[\[\\]UýVUVVWVWþXWWýXWXXYXYZþ[ZZ[ý\[\\ý]\UUVõWVWVWXWXXWXXYþXYYùZYYZYYZZý[Z[[\TUVþUVVøWVWVWWVWWýXWXXYýZYZZ[úZ[Z[[\\[\UT÷UTUUVVUUVVWXüWXWXXYüZYYZZý[Z[[\TýUTUUVýWVWWþVWWXWXYûZYZYZZ[þZ[[þ\[[þ\[þghhiþhiijþijjkþjkkþlkklmþlmm nohþghhihiþjiijþijjþkjjýkjkkýlkllmþlmm noghþghhþihh ijkjk÷lkllkklkllýmlm mûnonngghiühihiijþkjjklþkllúmllmlmmnúmnnongghþghhihiýjijjúkjkkjkklöklklkllmlmmngþhggøhghihiihhiüjiijjökjjkjkjkkllþkllúmllmlmmònmngfgfgghghghhihiýjijjýkjkklþkllmþlmmnømgffggfggýhghhýihiijþijjklþkllümllmmnýgfggþfggýhghhüihhiiþjiijklmþnffgýhghhþghhúihhihiijþijjkþjkkülkkllýmlmmýnmffþgffgúhghgghh÷ihiihiijiijþkjjkþlkklûmlmlmmþeffgfýgfgghýihiiþjiijþijjkùlkllkkllmfþeffgúhghhghhüihhiiùjiijjijjkþjkkülkkllömlleefefeffghþghhijþijjýkjkküjkkllþkllefþgffghûghhihhijùkjjkklkkýlkllþmeeüfeeff g hiùjijijijjkûlklklleüfeeffgþfgghghþihhiþhiijþkjjkþjkkülkklløeddeefeffþeffgfgühgghhûihihiijþijjúkjjkjkklýedeeüfeeffýgfggþfggùhghhgghhóihhihiijiijijjkûlklleeþdeefþgffgýhghhýihiijijþkjjkülkldd efþgffghþghhiýjijjkþlddeüfeeffgþfgghýihiiújijiijjþkjjkdefügffgghþghhýihiijõkjkjkkjkdcddúedeedee fg÷fghgghhghhiýjijjõkjkjjkccdcddýedeeüfeeffúgffgfgg h ijkjdþcddeþdeefgýhghhiýhij jýcdccdùcdeeddeefþeffþgffgh÷ihihhiijiijöcdcdccdccddeþdeefþeffgþfggþhgghiþhiijcdcdeþfeefúgffgfggühgghhiþhiiþjiijýijccýdcddeûfefeffgúhgghghhiþhiij÷icbbcbcdccdüeddeefefýgfggýhghhýihiiûjbcbccdúeddedeeýfeffýgfggþhgghþihhijþibbcþbccödccdccddeddeþdeeýfeffügffgghúghhihiiþhiiþjbbúcbbcbccùdccddcddüeddeefþeffûgfgfgghþghhiþabbcbcþdccdüeddeeûfefeffgüfgfggúhghgghhiþabbcýdcddeþdeefþgffügffgghþghhýihiib cüdccddüeddeeþdeefûgfgfgghûihiab bcþbccdcdýedeeýfeffghiabýcbccþdccdeúfefeeffûgfgfgghaúbabaabbûcbcbccdcdedefþeffgûhghghhabøabbccbbccdùedeeddeefg÷fggfgghghhüghhaaþ`aaúbabbabbc deûfefeffþgffýghgghaúbaababbcþbccþdccdeõdeedeffefeffügffggþhggþh``úa`aabaabûcbcbccûdcdcddedef gú`a``a``aôbaabbccbccbcc deþdeeýfeffgüfgfggþh``üa``aaúbaababbýcbccódcddedeedeedeefúgfgffggþ_``üa``aaþbaabþcbbcdcdúedeedeeüfeeffügfg` `abþabbþcbbcþdccýdcddýedeeýfeffgü`__``abüababbýcbccdþcddeøfefeffeffþg__` abþabbcdþcddefþefføgff_`_`__`úa``a`aa bcdef_ý`_``þ_``aþ`aaübaabbcýdcddeþfeeûfeff__ù`__``_``ûa`a`aabcbcþdccýdcddýedeeþdeefþeffý_^__ú`_`__``úa``a`aabþcbbc dþeddeûfeef^^_ú`_``_``a`abýcbccdýedeeýfe^^ _`þa``aûbababbcdeþdeeýf_^^_ý`_``þ_`` a bücbbccdcde^ü_^^__ü`__``abüababbcþbccdýedee^ú_^^_^__ `aýbabbþabbþcbbc døeddee^]^^þ_^^_ý`_``ö_``a``aa`aabcþbccýdcdde]ü^]]^^ú_^__^__ü`__`` abôcbbccbbccdcdd÷cddededd]]ý^]^^_þ^__ý`_``aþ`aaûbababbcdþcdd÷ed]]^]^]^^þ_^^ú_^__`__`ü_``aa`abþabbþcbbcdücdd]]þ^]]^û_^_^__`_`aþ`aababcbcdýòóòòóþòóóúòóóòòóóøôóóôóóôóóþôóóôúóôóòóòòóþòóóþòóóþòóóþòóóþôóóüôóôóóôûóôóôòòóûòóóòóóùòóòóòòóóþòóóþôóóüôóôóóùôóôóôóôôüòóóòòóýòóòòóýòóòòóþòó óþôóóþôóóüôóóôôûóôóóôôþóòòþóòòóòóþòóóþôóóþôóóþôóóþôóóýôóòòðóòóòòóòòóóòòóòòóóôôóóôôóôóôóôóóþôóóþòóóòóýòóòòúóòòóóòòùóòóóòòó óüôóôóóôóþôóóþôóóòúóòóóòóóòúóòòóóòòóúòóóòòóóøôóóôóóôóóòøóòòóòòóòòúóòóóòóóûòóòòóóþòóóþôóóûôóôôóóòüóòóòòóòýóòóóûòóóòóóüòóòóóþòó óôóþôóóôôòóòóòòóòóòóóòóòýóòóóùòóòòóòó óþôóóþôóóùôóôóôôòòþóòòó÷òóóòóóòòóóþòóóþòóóþòó óþôóóþôóóþôóóòþóòòóýòóòòùóòòóóòóóüòóòóóþòó óôóôòüóòòóóêòóóòóóòóòòóòòóóòòóòóòóóþòóóüòóòóóûôóôôóóþôóóòþóòòóòòóòòóóòòóòòóóòòþóòòóþòóóþôóóüôóóòòþóòòóòýóòóóòóòóûòóóòóóþòó óþôóóòþóòòûóòòóòòöóòóòòóòóòóóòóûòóòóòòóþòóóþôóóòþóò òóòóòýóòóóòóþòóóþôò òüóòóòòóôòóòóóòóòóóòóóþòóóþòóóòùóòóóòóòòùóòóòòóòòóò óþòó ó òðóòòóòóòòóóòòóòòóóýòóòòóò÷óòòóòóóòóóýôóò òóúòóóòóòòûóòòóòòüóòòóóþòóóþòóóòþóòòóòþóòòóòóûòóóòó óúòóóòñòòþóòòôóòóóòòóóòóóòòñóòóóòóòóóòóóòòóóòóñòþóòòóòýóòóóþòóóòóüòóòóóùòóòòóóòòþóòòþóòòóüòóòó óýòñòòþñò òþóòòûóòòóòòþóòòóúòóóòòóóòóþòóóüñòñòòþñòòþóòòþóòòóüòóòóóüòóòóóùòóòóóòóóüòóóòòþñòòþóòòþóòòþóòòóüòóòóóòóüòóòóóò÷óòòóòóóòóóòþóòò óòóòþñò òþóòòóòþóòòýóòóóòýóòóóòóòþñòòþñò òþóòòóúòóòóóòòöóòóòòóóòòóóüòóòóóþñòòþñòòþóòòóòñóòòóóòóòóòóòóòóóþòóóòþñòòþñòòúóòóòóòòýóòóóòüóòòóóòüñòñòòþóò òóòùóòòóóòóóþòóóûòóòñòòþñòòþñòòþñòòüóòóòòõóòóóòóóòòóòò÷óòòóòóòòóóýòñòòñòñõòñòñòòñòññòòþóò òêóòóòóòóóòóòóóòóóòòóòóòòýñòññòñòþñòòþñòòþóò òóòóúòóòóòóóòóþòññþòññòþñòòþñòòñòþóòòþóòòóòùóòóòòóòòñòñýòñòòñòõóòóóòòóóòóòòóñòóóòñòñòòññòññòòñòþñòòþóòòóòûóòòóòòíóòññòñòñòñòññòñòòñòòñ òþóòòûóòóóòòó÷òóñòñòòñòòýñòññòñýòñò òþóòòüóòòóóòüóòóòòóòñòþñòòñòñòóýòóòòóòþóòòûñòññòòþñòòúñòñòñòòúñòòññòòþñòòþóòòóóòóóòóòòóóòóòññùòñòñòòññòùñòòñòñòòüóòóòòþóòòñøòñòñòñòññþòññòóñòòñòññòòñòñò òþóòòþóòòöóòñòññòñòññòñòþñòòüñòñòò÷óòóòòóóòóóòñíòññòññòòñòññòñòñòñòòúñòòñòññòþñòòþóòòýñòññàòñòññòòññòòñòñòòñòñòñòññòñòòñòñòòúóòòóóòòñþòññöòñòññòòñòññþòññòüñòòññòñòûñòòóòòñòýñòñ ñòùñòòñòñòòþñò òûóòòóòòúóòòóòññþòññûòññòññòþñòòþñòòñòüóòóòòþóòò ñúòññòòññòþñòòúñòñòñòòþñòòþñòòñúòññòñòòýñòññòûñòññòòñøòññòñòñòòþñòòñþòññþòññþòññòñòñòþñòòóþòññþòññòýñòññýòñòòûñòòñòòüñòñò òþóòòñ÷òññòñòññòòñùòññòòñòòþñòòñòþóòòñòñüòñòññûòñòñòòñùòññòññòòþñòòþñòò ñþòññòþñòòûñòòñòòñøòñòòñòñòòþñòòþñòòþðññþòññòýñòññòøñòññòòñò òþñòòñþòññþòññòñòûñòòñòòñòñøòñòññòñòòþñòòþñòòþñòòñþòññóòñòñòòñòòñòñòòþñòòþñòòþñò òñþòññòñöòñòòñòññòññòñýòñòòüñòñòòÿgýhghhi÷jijkjjkjkkûlklkllýmlmmýnmnnoünooggh ijøkjkkjkjkklþmllmünmmnnùonnonogghþihhiújijjijjkýlkllûmlmlmmýnmnnþfgghghüihhiijþijjkþjkkùlklklkllm nþfgghþghhijþijjùkjjkkjkklklûmlmlmmnþmnnþgffg hýihiijkúlkklkllýmlmmþnmmnfgþfgghþghhüihhiiüjiijjkûjkkjkkýlkllmnfgþfgghýihiiýjijjkûlklkllýmlmmþlmmnfýgfg ghýihiiýjijjklmýneffôgffgfgghghghhiýjijjükjjkkúlkklkllmfúgffgfgghihijþkjjkþlkklmlmeýfeffügffgghüihhiiùjiijjijj klþkll÷mllmmefeffgþfggøhghghhihhiþjiijûkjkjkklklmýlmeefügffggýhghhþihhùijjijijjþkjjkülkkllþklleûfefeffgþhggh ijijúkjkkjkklþmllþdeeûfefeffgfghiþhiiújijjijjükjjkkþlkkleþdeeþfeefügffggýhghhûihihiiüjiijjkþjkkülkklldeöfeffefeffggfûgffhgghiþhii jkõjkkllklkllddeþdeefúgffgfggþhgghij kldþeddefþeffþgffgóhgghhghhihihiiþjiiûjijjkkûjkkjkkýlcddúededdeef ghüghhiiühihiijýkjkkûldccdd eýfeffghijkcdeþdeeüfeeffûgfgfgghþghhúihihhii jkûdcdcddeþdeefghiüjiijjûkjkkccýdcddýedeeýfeffgfögfgghghgghhihiùjiijjijjkcdþcddeþdeeüfeefføgfggfgghhþghhiüjiijjþkbbcdeþdeefefgþfggýhghhþihhiüjiijjþbccdþcdde fghýihiijõijjijcbbcbccþdccdedefþeffghghýihiijbcôdccddedededeeýfeffgøhghiihhiiûjiijbbcdücdcdd eýfeffúgfggfggühgghhiüjiibbcdcdeðfefefeeffggfgffgghúihhihiiþbaabúcbbcbccúdcddcddefþeffgüfgfggúhghhghhúihhihiiaýbabbc dýedeefþgffgühghgghiûababaabùcbcbcbccúdcdccddüeddeefefýgfgghþihhabýcbccüdccddýedee fgühgghhihabúcbccbccdýedeeüfeeffýgfggýhghhýihaaübaabbcdýedeefýgfggýhghhiýa`aa bøcbccddcddefefþgffgýhghh`ýa`aabócbccbccddcdcddýedeeüfeeffýgfggþhgghý`a``abúababcbbcdþcddefefýgfgghüghh``a`ababýcbccýdcddüeddeeüfeeffôgffggfghghh``aþ`aaúbaababb cdeøfeffefgffghü_`_``þa``ýa`aabþabbcbcódcdcdcdedeedeeýfeffgùfgg``_``aü`a`aabþabbùcbbccbccdefþeffgýfg__ý`_``aþ`aaübaabbûcbcbccdýedeeýfeffþeffþgff_ú`__`_``üa``aabcøbcdccdcddüeddee f_`ýa`aabþabbcdûcdccddeþdeefþg__ú`_`__``aþ`aabþcbbcýdcddûededeefþ^__ü`__``aübaabbcþbccüdccddþcddeþdeefþeff^_þ^__ü`__``aû`a``aaøbabbccbccýdcddeþdeeúfeeff^^_`_`aþ`aababþabbýcbccûdcdcdd e^û_^_^__`þ_``aþ`aaúbabbabbcdøcddcddedde÷deefef^]^^ _ý`_``ûa`a`aabýcbccþdccdùceddedeeþf^^_^_ ` abýcbccdþedde^]^ý_^__`a`aùbaabbabbûcbcbccúdcddcddûedee]]ø^]^^_^^__ø`_``_`_``aþ`aaübaabbúcbbcbccdþcddþeddøe]^]^]]^^_þ^__û`_`_``ýa`aabþcbbýcbccdþcddýed]]ú^]^]]^^û_^_^__`úa``a`aaýbabbûcbcbccdüed\]]^þ]^^ý_^__ü`__``õa`a`ababaabbýcbccdþcddþ\]]þ\]]^]^ú_^_^^__`ýa`aaýbabbcdþcdd]\]þ^]]^_ù`__``_``aþ`aaþbaabýcbccôdcdd\\]\]]\]]^ü]^]^^ü_^^__`ûa`a`aaýbabbùabbcbbccúdcddc\\]^_`aþ`aababcýdcdoúpopooppqþpqqýrqrrþqrrsrsütssttuþtuuvnoýpoppýqpqqürqqrrúsrrsrssûtststtûututuuvoüpooppýqpqq rsýtsttuvunopüqppqqrþqrrsrstûututuun opqúrqrrqrrsýtsttùutuuttuuývunnýonoopúqppqpqqúrqrqqrrüsrrsstþsttþuttuþvnnoþnooýpoppøqpqpqppqqýrqrrsþrssütssttýutuuütuummnopþqppqrúsrssrsstþuttuþmnnüonnooýpoppúqpqppqqrþqrrsútstssttu nýonoopúqppqpqqúrqrrqrrsýtsttøutummnmnnýonooüpooppûqpqpqqrûqrrqrrsþrssütssttmnþmnnýonooýpoppqüpqpqqþrqqrúsrsrrssýtsttmnùmnmnnonnýonoopopüqppqqrþqrrúsrsrrsstýmlmmûnmnmnnüonnoopopqrþqrrsrsûtststt mnoþnooþpoopqrqrstlmlmnmnoþnooþpoop qrsrsþtllmnþmnnùonoonnooüpooppüqppqqrýqrssþrssýtkllm÷lmmnmmnmnnopþoppqþpqqrqrsþrsslmþlmmnþmnnûononooépopoppoppqppqppqrrqrrqrrýsrssúrsskkllmnmnùonoonnooýpoppqrqrsúrsslkllmnümnmnnøonnononoopþoppúqppqpqqürqqrr÷srsklklkllmülmlmmþnmmnýonoopþoppüqppqqürqqrrýsrkkýlkllmþnmmnüononnopþqppqrúsklklkklmlýmlmmnúononnoopþoppýqpqqrüqrrkkùlklklkllýmlmmúlmmnmnnþonnoüpooppúqpqppqqýrqrrýkjkkþlkkölmlmlmlmlmmnúonnonooýpoppqþpqqúrqrrqjjklümllmm÷nmmnmnnmnnoþnooüpooppqrqjýkjkkûlklkllmnýmnoonoûpopoppqþpqqþrjjkþjkklmûnmnmnnonoþpoopñqpqpqqrrjjkjkjkkýlkllmûlmmlmmnþmnnoþnoop÷qppqqrjijjkþjkkþlkklümllmmýnmnnopýqpqqijkûlklkllýmlmmnonoýpoppýqpqqújijjijjklmþlmmnþmnnúonoonooþpoopþqiiýjijjükjjkklþkllmúnmmnmnnüonnoo piõjijijjkjkjkklklùmllmmlmmnoýpoppijþijjklþkllûmlmlmmûnmnmnnoýpoppüoppiijkþjkkýlkll mýnmnnoünonoo÷poopophhiiýjijjkjkýlkllmþlmmúnmmnmnnüonnooõpopoppiihhiijþijjükjjkklümllmmònmnnmnnmnnonnooþphhiýjijjýkjkklþkllmþlmmýnmnnûononooýphiiþhiiüjiijjýkjkklþkllûmlmlmmünmmnnonoþghhi jükjjkkýlkllmþlmmnþmnnohiþhiijkþlkkûlkllmmülmlmmýnmnnøonnongghhýihiijkþjkk lýmlmmýnmnnþonnúoghhghhiþhiijijþkjjýkjkkûlklkllümllmmnümnmnnoúhghgghhiñjijiijjijkjkjjkkýlkllômlmlmmnmnmmnnoghiþhiiüjiijjkjklþkllmþnmmnþfgghiþhiijijkjkýlkllúmlmllmmünmmnngþhgghüihhiijþijjýkjkklmlmýnmnnþfggúhghgghhûihihiiýjijjýkjkkýlkllmlmþlmmnûfggfggýhghhiûhiihiiújijiijjkþjkklýmlmm÷nfgffgffggûhghghhijükjjkkúlkklkllýmlmmünmnffgýhghh iýjijjûkjkjkklûkllkllmfgüfgfgghþghhþihhiûjijijjýkjkklømlmmffeffgühgghhþihhiüjiijjkþjkklþkllõmlmlmmeefeffýgfggûhghghhihiýjijj klkl÷mllmeffeffýgfgghihiýjijjýkjkkýlkllþmeefgühgghhýihiiújijjijjýkjkklþkllþmeefügffgghþihhiýjijjkleûfefeffgfgýhghhüihhiijþijjûkjkjkklþkllþdeefþeffgþfgghúihiihiijþijjkþjkkl efýgfgghþghhûihihiiüjiijjýkjkkølkkllddeeúfeefeffgþfggûhghghhihiüjiijjkþjkklþkddeþfeefg hiûjijijjûkjkjkklúôóóôóôôþóôôþõôôúõôôõõô ôýõôõõþôõõþôóóþôóóýôóôôóôõôõôòõôõõôõôôõôôõõôôþóô ôþóôôþóô ôõþôõõôõôõôõøôóôóôóóôôþóôôþóôôþõôôõôõôùõôõôõôõõþóôôûóôôóôôþóôôóôþóô ôõôûõôôõôôüõôõôôîõôóôóôóôóóôôóôóôóôôüóôóôôøõôõôõôõôôõôþóôôþóôôþóôôóôþóôôþõôôüõôõôôüõôõôôýóôóóýôóôôóüôóóôôþóôôþóôôþõôôþõôôþõôôúõôôõôõõïóôóóôóóôóóôôóóôóôôóôþõôôþõôôüõôõôôõþôóóôþóôôùóôóôôóôôóôöóôôóôóôôóô ôþõôôþõôôôõôõóôóôóôóóôôþóôôùóôóôóóôôþóô ôþõô ô÷õôõóôôóôóóôóöôóôôóóôôóôôþóôôüóôóôôûõôôõôôþõôôúõôõôôóóñôóôôóóôóôôóóôóôôùóôóôôóôôþóôôôõôõôõôõóôóôóóôüóôóôôþóôôþóôôþóôôóôþõôôþõôôþõôôóþôóóôóúôóóôóôôóôþóôôþóôôøóôóôóóôóóþôóóôõóôôóôôóôôóôôóýôóôôôõôõõôõóóôóôóóûôóóôóóûôóôóôôûóôôóôôþóôôõôüõôóôôýóôóó÷ôóóôóôôóôôùóôóóôóôôûóôóóôôóøôóôóóôóôôóùôóóôôóôôõóôôóóôóôôóôôþóôôþóô ôûõôõôóóþôóóþôóóôúóôóôóôôóôüóôóôôþóôô óþôóóôóñôóôóôôóôóôôóôóôôþõóóþôóóúôóóôôóóúôóôóôóóôóôüóôóô ô óüôóôóóôóôþóôôþóôôþóôôó÷ôóóôóôóóôôþóô ô óþôóóøôóóôóóôóóþôóóôóôöóôóóôóóôóôôóüôóóôôýóôóóþôóóôóôþóôôþóôô óþôóóôóôóôóôóúôóôóóôôþóô ô óóôóóôóôóóôóôôóóùôóóôôóôôüóôôóóúôóóôóôôüóôóôôóôóöôóôóôóôôóôôóôùóôôóôóôôþóô ôóþòóóþôóóûôóóôóóôóúôóóôóôôüóôóôôþóôôüóôòó óþôóóýôóôôóôüóôóôôþóôôóûôóôôóóþôóóþôóóûôóôóôôþóôôó ôóûòóóòóóôóûôóóôóóôóôóýôóôôþóôôþòóóþòó óþôóóþôóóôóþôóóôþóôô÷óôôóôóôòóóôôóóôóôôóôóóôôòóôóóôóôóôóôôóôôóþòóóýôóôôõóôóóôóôôóôóóôþóôôóüôóòóóüôóóôô óôþóôôóþôóóôþóôôóòóûôóóôóóôóôóôþòóóþòóóþòóóþòó óþôóóþôóóôóôþóôôþóôôóòóûòóòòóóþòóóþôóóúôóôôóôôûóôóóôôûóôôòóóûòóóòóóþòóóþòóóóôóóôóôôóôóôôóóùôóôóôôóóþòóóþòóóþòóóþôóóðôóóôôóóôóôóôóôóôôóôþòóóòóûòóòòóóþòóóþôóóþôóóôóþôóóôóòóøòóóòóóòó óôóýôóôôóþôóóýôóôôòýóòóóòóòýóòóóþòó óþôóóüôóôóóüôóôóóôýóôóóòòóòóóòòóòóóòòóóòóþòóóþôóóþôóóôýóôóóþôóóùôóóôòóòòöóòóóòóóòòóóþòóóþòóóôóôóôòþóòòþóòò óûòóóòó óôóôóóôóóôóôôóóôôòóóòþóòòóþòó óûòóóòóóþòó óþôóóúôóôóóôôòóòóþòóóþòóóþòóóüòóòóóþôó óþôóóôóþòóóüòóóòòóþòóóùòóóòóòóóþòóóþôóóôóôòùóòóóòóòòþóòò÷óòòóóòóòóóþòóóòôóòòóóòòóòòóòòóþòóóþòóóþòó óüôóôóóôóòþóòòúóòóòòóóòóþòóóûòóóòóóýòóòòóùòóòóóòóóñòóòóóòòóóòóóòòóóýôóòòóýòóòòóóòòóóòóóòóòòóóòóôòóòóþòóóþòóóþòóóþôóóòóòöóòòóóòóòòóóòóòóþòóóþôóóòóýòóòòþóòòóòóòóòóþôóóòóòóòóò÷óòóóòóòòóó òõóòóòòóòòóòóóýòóòòóýòóòòóüòóòóóþôòòþóòòøóòóòòóóòòóöòóòóóòóóòóóõòóòóóòóóòòóóòþóòòþóòòþóòòõóòòóòòóòóòóóòóþòóóþòóóþôóóòóòþóòòóþòóóòýóòóóòóþòó óýôóò òþóòòþóòòóòóòóþòóóþòó óÿoüpooppqrûsrsrssýtsttüuttuu vwþnoopqþpqqùrqrqrqrrsþrssùtsstssttuþtuuvwþvoopqrsþrsstýutuuúvuvuuvvûwvnnoopþqppqrýsrsstúututtuuvnýonoopþoppüqppqqþpqqþrqqrýsrsstuvnþonnoüpooppqþpqqrþqrrsrsütssttýutuunúonoopoopqõrqqrrsrssrssýtsttuvmnüonnooþpoopúqpqqpqqþrqqrþqrrüsrrssþtsstúuttutuuüvumnnoþnooýpoppþqppqþpqqýrqrrsútsttsttþuttýutuuþmnnýonoopopqürqqrr stòuttuutuunmnmmnnoúnonooppqþpqqrþqrrstþsttuýmnmmnopqýrqrrsýtsttuúlmnmmnnûononoopûqpqrqqrsrstúuttmlmmýnmnnþonnopþqppq÷rqrqrrssrrsõtssttuummlmmnþmnnoþnooöpoppqpqppqqrsýtsttøutllmllmmnýonoopýqpqqrþqrrstlþmllmýnmnnopýqpqqrêsrrsrsrsstststsllmlmlmmúnmnnmnnonopþoppýqpqqrqùrqrsrrssýtsttlmþlmmnoþnooûpopoppqþrqqrýsrssütssllýmlmmýnmnnoúpoppoppöqppqpqrqqrrýsrsslþkllmnþmnnþonnop qrôsrrsrrssklkllmlmnømnnoonnooüpooppüopqppqýrqrrøsrsrrsskklmlýmlmmnþonnoýpoppüqppqqrþqrrskülkkllmþlmmnþmnnoúpoppoppýqpqqrüsrskkülkkllmølnmmnnmnnoünopoop qrþqrrýsrkklþkllmþnmmn oýpoppþqppqrþqrrjkülkkllýmlmmýnmnnoünonoopúqpqqpqqrjkýlkllùmllmmlmmnþmnnoúpoppoppqûrqqrjjükjjkkýlkll÷mllmmlmmnnþmnnþonnoþnooýpoppýqpqqürqrjjýkjkkúlklkkllúmlmllmm noúpoopoppqúrqriijjûkjkjkkúlkklkllmülmnmmnoüpooppþqppqýjijjýkjkkýlkllmûnmnmnnýonoopýqpqqiýjijjükjjkklklmülmlmmnþmnnoþpoopqijþijjklûmlmlmmnoüpooppqpþqiijk÷jkjkllkkllümllmmýnmnnüononnopûqpqhiijþijjýkjkkülkkllýmlm mnoûpopoppüihhiiþjiijýkjkklýmlmmýnmn nopþhiiùjiijiijjókjkjkklkklkkllmnmnþonno÷noopoopoppþihhýihiijijklþkllmnonophøihiijiijj÷ijjkjjkjkkúlkklkllýmlmmônmmnmnnoonnooüpophhþihhijþijjýkjkkülkkllmnþmnnonoüpoohhijþijjýkjkkl÷mlmnmmnmnnûononooûpohghhiõjijijijjkjkklmünmmnnoþnooühgghhiûhijijjþkjjkülkkllümllmmünmmnnoûghgghhijijükjjkkýlkllmþlmmnmnþonnoghýihiiüjiijjklklmýnmnnþogghþihhijkjkþlkklmnüonngghýihiiýjijjkþjkklýmlmmþnmmnfghþihhýihiiýjijjklýmlmmnmngþfg ghiújijiijjükjjkk lmënmmnmnnffggfggfgghhghhýihiijþkjjk lmúnmnmnffghþghhiüjiijjklümllmmüfeeffgühgghhûihihiiüjiijjþkjjkýlkllûmlmlmmefügffgghüihhii jkþjkkýlkllþmllmeýfeffúgfgghgghþihhijijýkjkkülkkllûmlmmeef gýhghhiýjijjþkjjkýlkllmúlmdeeffûgfgfgghghþihhiújiijijjkúlklkkllümlmeefgühgghhiþhiiûjijijjklefþeffgúhghgghhijklkldöedeefeefeffgýhghhiüjiij jkldeýfeffýgfgghüihhiijþijj kþlddýedeefgþfggûhghghhüihhiiýjijjþijjýkjkklþkddõedeefefefeffõgfgghhgghghhiþhiiújijiijjûkjkjkkýdcddefþeffýgfggühgghhiùjijijijjkvüwvvwwxþwxx yz{þz{{|}þ|}}øvwvvwwvwwx÷yxxyxyxxyyzþyzzý{z{{ü|{{||}þ|}}výwvwwþvwwúxwxxwxx y z{|{|}þ|}}ývuvvwýxwxxyûxyxxyyzù{z{{zz{{|}þ|}}uvûwvwwvvwxûyxyxyyzþyzzû{z{z{{|þ{||}ý|uvvýwvwwþxwwxýyxyyýzyzz{ý|{||ö}|}uuvvuuvvýwvwwxwxüyxxyyzþyzzù{z{z{z{{ú|{||{||þ}uuvwvwûxwxxwwxyxyùzyyzzyzz{ý|{||uvwþvwwx yz{þz{{ý|{||þtuuvüuvuvvwúxwxxwxxüyxxyyzü{zz{{|ýutuuvþuvv wxyþxyyùzyzyzyzzþ{zz{û|{{|ttýutuuûvuvuvvüwvvwwxwýxwxxyýzyzz{û|{||ttýutuuývuvvüwvvwwýxwxxyûxyxxyyüzyyzzü{zz{{túuttutuuvûwvwvwwþxwwxøyxyxyyzyyzü{zz{{þstt uvwþvwwxþwxx yzö{z{z{z{tsttúutuutuuvýwvwwxwxúyxyyxyyzþyzzü{zz{{ýtsttuvþuvvýwvwwúxwxwwxxyþxyyüzyyzzù{zz{zsttøstutuutuuv÷uvwvvwwvwwúxwwxwxxyûxyyxyyýzyzzþsttþuttuývuvvþuvvýwvwwxyûxyyxyyýzyzzþ{sstsûtsttuuvþuvvwþvwwxþwxxýyxy yúzyz{rsstþsttuþtuu v÷wvwvwwxwxxýyxyyüxyxyyzüysrsstþsttuûtuutuuývuvvwxþwxx yzþsrrùstsststtýutuuüvuuvvúwvwwvwwxýyxyy÷zyyrssrrsstþuttýutuuûvuvuvvþwvvwýxwxxýyxyyúzrsrrssütssttûututuuvþuvvwxúyxxyxyyrúsrrsrsstuþtuuüvuuvvýwvww÷xwwxwwxyxxýyxyyrsþrss tuvwþvwwüxwwxxýyxyyqrþsrrsþtsstúuttutuuþtuuvþwvvýwvwwýxwxxþwxxûyxqqrrsùtssttsttutuývuvvwûvwvvwwúxwxxwxxyrqrþsrrstutuúvuuvuvvwxüwxwxxqýrqrrüsrrssútsststtýutuuúvuuvuvvwvwxþyqqrsøtsstststtuvþuvvýwvwwxþwxxqrþqrrsþtsstøutuutuuvvýwvw wxýqpqqýrqrrsütssttuþtuuùvuvvuuvvüwvvwwüxwxppq rýsrssþtsstuþtuuvþuvvþwvvwpqrþqrrsþrssýtsttuvúwvvwvwwþxppýqpqqrüsrrssütssttüstuttuüvuuvvüwvvwwpqpqrsútstssttuûtuttuuvüuvuvvwvþwppøqpqqpqqrr sûtststtuüvuuvvwúvwvooppòqppqpqqrqqrqqrrùsrssrrss tuvþuvvwûvwpoppqpøqpqqrqqrrsþrsstþsttýutuuvöwvwvvoppoppûqpqpqqúrqqrqrrsürsrsststuþtuuvoúpoopoppýqpqqúrqrqqrrsrstþsttuvþuvvopþoppùqpqqppqqûrqrqrrþsrrstþsttýutu uvoûpopoppüqppqqýrqrrsþrsstüuttuu÷vuuvvonnoopüqppqqýrqrrstutuvþno oýpoppýqpqqýrqrrüsrrsstüuttuunüonnoopþoppüqppqqrsûtststtþuttuþvnnoûnonoppüopoppýqpqqþrqqrsþtssýtsttunono pqþpqqrqrsûrssrssþtsstuýnmnnopýqpqqûrqrqrrþsrrsþtssýtstt÷uttuunmmnnoünonooýpoppýqpqqþpqq rsýtsttùututmmnnüonnoopqýrqrrsrsûtststtuùtnmnmmnnúononnooüpoopp÷qppqqpqqrrþqrrstþstt÷umnmmnmmnnoüpooppþoppýqpqqþrqqrýsrssïtsttsttmlmnnmmnmnnoþnoo pqþpqqrùsrrssrsstþlmmnþmnnüonnooüpooppûqpqpqqrúsrssrsstþlmmnþmnnýonoopûqpqpqqþrqqrýsrssútmlmlmmùnmmnnonnoýpoppqûpqqpqqrqrslmùlmlmnmnnþonnoþpooýpopp qrúsrssrsslmnoþnooþnooûpopoppqþpqqrüsrrssûlklmllýmlmmnùonnonnoopþqppqýrqrrslþkllmülmlmmúnmmnmnnoþnooýpoppqþpqqrþqrrslklþmllmnopopqþrqqørqrrssrssüôõôõõôõþöõõöüõööõõöýõöõõþöõõöúõööõôõõþôõõûöõõöõõþöõõöõöûõööõööõöøôõõôôõôõõþôõõþöõõöõ÷öõõööõööõõöüôõôõõöúõöõõöõõûöõööõõìöõõöõööõööõõööõöõôõôôõúôõõôôõõþôõõþöõõöõüöõöõõýöõööõüöõõööôõþôõõþöõõööõööõööõôõõôõüôõôõõôõþöõõöõöêõööõôôõôôõôõôõôôõõôõôõõûöõõöõõþöõõöõøöõöõõôôõõûôõõôõõþôõõþôõ õþöõõöõþöõõþöõõþöõõôöõõööõôôõõôõõýôõôôõþöõõþöõõþöõõöõôüõôôõõôõþôõõþôõõüöõöõõûöõöõööõöøõöõõôôõôôõûôõôõôôõþôõõùöõõöõöõõþöõ õôûõôôõôôõüôõôõõþôõõþôõõþöõõñöõöõôôõôôõõôõõôôõôõþôõõþôõõöõöùõööõôõôôþõôôõþôõõüôõôõõþôõõôõöõúöõõöõôôýõôõõôõüôõôõ õþôõõöýõöõõôôõõôõôôõôôõôôþõôôõôõôõôõþôõ õþöõõöýõöôôýõôõõôõþôõõþôõõüôõôõõôõþôõõþöõõüöõöõõö÷ôõôôõôõõôôíõôõôõôôõôôõôõõôôõôõõüôõôõ õûöõõöõõþöõõýôõôôþõôôþõôôõôøõôôõôõôõõûôõõôõõôõúöõõôôõõô÷õôôõôõôôõõôõþôõ õþöôôþõôôñõôôõôôõôõôõõôõôôõô õþôõõþôõ õöûõôôõôôðõôôõôôõôõôõôõõôõõþôõõûôõõôõõýôõôôõôùõôõôôõôôýõôõõþôõõôõþôõõþöõõôþõôôõôõýôõôôùõôôõõôõõúôõõôôõõô õôþõôôþõôôúõôõôôõõûôõôôõõôõôüõôôõ õþöõõôõôðõôõôõõôôõôôõôôõôôõôõþôõõûôõõôõõôüõôõôôõþôõõüôõõôôõôõõôõõôõõôõôõ õ ôóõôõôôõõôõôõõôôúõôõõôõõôûõôõôõõôõüôõôõõôþõôôûõôõõôôûõôôõôôùõôõôõôõõôùõôôõôôõ õþôõõûôóôóôôúõôõôõôôõôûõôõõôôõôøõôôõõôôõõüôõôõõôþóôôõôüõôõôôõôõôýõôõõþôõõôõôþõôôþõôôþõôôõþôõõþôõõüôõôõõþóôôùõôõôõõôôþõôôþõôôûõôõôõõôýõôõõûôõõôõõþóôôþóôôþõôôõôûõôõõôôõøôõõôôõôõõýôõôôûõôõôõõþôõõýôõóóôþóôôþõôôõôþõôôüõôôõ õôþõôôõôõüôõõôôþõôôõôõþôõõþôõõôþõôôþóôôûõôôõô ôûõôõõôôõýôõôôþóôôþóô ôþõô ôþõôôûõôõõôôýõôõõôõôõüôõóôôöóôóôôóóôóôôþõôô÷õôôõôõôôõõôýõôõõô÷õôõôôóôóôôþóô ôüõôõôôõôõùôõõôõõôôõûôóôóôôúóôóôóôôþóô ôõôþõôôõôúõôõôõôôõúôõôõõôôóôþõôô÷õôõôõôõõôôõöôõôôõõôõôõõôþóôôóôþóôôþóôôþõôôüõôôõõôþõôôþóôôþóôôóôøõôôõôõõôôýõôõõôúõôôõõôôóøôóôóôôóôôþõôôüõôõôôùõôõôõõôôõüôõõôôþóôôóôûóôôóôôóôþóô ôþõôôõôöõôôõôôõôôõõýôõôôóôóýôóôôþóôôþõôôþõôôõôøõôõõôôóôôøóôóóôôóôôþóô ôþóôôôõôõôõôôõôôõôôõôøõôôõôôóôôóôþóôôþóôôþóôôþõôôþõôôþõôôýõôõõñôõôõóôôóôôóóôôóóôóô÷õôõõôõôõôôõôóüôóóôôóôþóôôùóôóôôóô ôþõôôüõôõôôõôðõôõôóôóóôóóôôóôóóôþóôôþóôôþóôôûõôôõôôþõôôþõôôóôóôóôóôþõôôüõôõôôóþôóóôýóôóóúôóôôóôôóôþóôôûõôôõôôúõôôõõóóòôóóôóôóôóôóôôóóüôóóô ôþóôôþõôôÞõôóóôóôóôôóôôóóôôóôóôóôóóôôóóôôóóôôõôóüôóôóóôüóôóôôõóôôóóôóóôóôôþóôôõôúõôôóôóóüôóôóóõôóôóôôóôóóôôóýôóôôþóôôþõôôûõôõôó óþôóóôþóôôóýôóôôþóôôýõôóóþôóóúôóóôôóóôóôþóôôó ôþóô ôüõôôó óôñóôóôóôóóôóôôóóôôþóôôúõôõôõó óþôóóüôóôóóôûóôóóôôóôþóôôóôóôóöôóôôóôôóôóó ôþóô ôÿwüxwwxxyüxyy,wýxwxxy-üwvvwwûxwxwxxüyxy,þvwwvwxüyxy,vüwvvwwýxwxx-vwþvwwx-ùuvvwvvwwýxwxx-uvûwvwvwwþx,vþwvvwx-uvw-uvþuvvwþvww-uúvuvvuvvùwvwvvw,uøvuvuvvuvvüwvv, uvþuvv-uþtuuývuvvúuvvwv,tõutuutuvvuuvv-tüuttuu÷vuuvvuvv,tuôtutuuvuvuvv,týutuuv-þtsstuývu,þsttþsttüuttuuþv,sýtsttýutuu-stþsttu-stüutu,þrssþtsstüutt,srst-ûrssrssötsststtut,rst-rûsrsrsst-ûqrrqrrýsrsst-ýrqrrsýts,qrüqrrssûrstt,qrþqrrsýrs,qrüsrrss-qýrqrrüsrrss-ýqpqqrþqrrþs,pqýrqrr-ûqpqpqqr.pqpqürqqrr.pqrüqrr-pq.poûpqqpqqýrq.popq/opþoppq/þnoopþq/oþnoopýqp/üonnoopþopp0þonnop1nýonoo1nýonoo2nop2þmnnýon2nûonoo2mnýon3ùmnmnnmnn4mþnmmn5mþlmmþn5þlmm7úlmlmlmm7þlmmülmm7lmþl8külml9þkll;kþl;þ}~~~-}~-}þ~}}~-}~þ}~~~þ,}ü~}}~~ü~,|}~-í|}|}|}}~}}~}}~~~~,}þ|}}þ|}}~-|}þ|}}þ~}}~-|}þ|}}þ~}}þ~,ý|{||ü}||}}~þ},|þ}||}~þ},|þ{||}-ý{|{{|}-ö{|{||{{||}}ü|}|}}-{|{|}-þz{{|{û|}||}}-z{û|{|{||}-{þz{{ù|{||{{||þ},û{z{z{{|þ},zý{z{{û|{||,zú{z{zz{{þ|{{þ|,zþ{zzý{z{{|-ýzyzzý{z{{ü|{{,ýzyzzü{zz{{ý|{,yz{ý|{,yýzyzzü{zz{{-yzþyzz{-yþzyyúzyzzyzzþ{,yøxyyzyzyzz{-úxyxyxyyýzyzz-ûxyxxyyz-xyüzyyzz-xyþxyyþzyy-þwxxyþxyyûzyyz,wxüyxxyyþz,üwxwxxùyxyxyxyy-ûxwxwxxüyxxyy.wxy.vwûxwxxyyþx-þvww x.ýwvww÷xwwxwwxwxx/þwvvwx/vwøxwwxwxx.vwþvwwx0vwþvww0vþwvvw0ûvuvuvvüwvvww1úvuuvuvvúwvvww0üuvuvvwv2uvþuvvþw1uüvuuvv3þtuuv3ütutuuv4uþtuuþvuu4øtuttuutuu5tüututt6tþutt7þstt7st8ùsttstt8s:sþt:ürsr;ýöõöö-öþõö ö-öüõöõö ö-öþõö ö-ýõöõõüöõõööþõöö-öûõööõöö-öõþöõõöþõöö-þõööøõööõööõöö-þõööþõö öýõö,ýöõööüõöõöö-úöõöõöõõöõö-öõöõõöõööõöõöö,õöõüöõõööþõöö-öûõöõõööõö-þõööõüöõöõõûöõõö,õþöõõöþõöö-õöõöüõöö,öõùöõõöõõ,ýõöõõöõþöõõö-õöõúöõõöõööõ-õýöõööýõöõõöüõöõ,õüöõöõõúöõöõöõõ-øõöõöõõöõõýöõööõ-õöõþöõõöõþö,õöõö-õþöõõõöõöõõöõõöõ,ýõöõõöõ-õþöõõþöõõ- õöõýöõ,õöõúöõöõõ,ýõöõõþöõõöõ-õüöõöõõøöõõöõõö,þôõõöõýöõ, õþöõõ-õþöõõþöõõ-ùõôõôõôõ õ-õþôõõþöõõ-õ.þôõõþôõõ.õ.öõôõõôôõõôõõ.õ/õþôõõüôõõ.õüôõôõõ/ôõþôõõ0þôõõöôõõôõõôõõ/ôõôõýôõ/ôõôôõôõõôõôôõõ1ôõûôõõôõõýôõ0ôüõôôõõôõ2õôõôûõôôõ1õôúõôõôô2óõôôõôõôôõõôõ2ôõôõõôõõôôõô3þõôôõô4ýôõôôõüôõô4üõôõôôþõ5ô7ôüõôõ6ôúõôôõõ7ô9ô:ôõ;üõôô;ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿ-ÿþø,ÿþî,ÿþß,ÿþË,ÿþ²,ÿþ”,ÿþq,ÿþI,ÿþ,ÿþä-ÿþ­-ÿþq-ÿþ0-ÿþß.ÿþ”.ÿþD. ÿþß/ ÿþ…/ ÿþ&/ ÿþ­0 ÿþD0 ÿþ¼1 ÿþI1 ÿþ²2 ÿþ52 ÿþ3ÿýß3ÿþS4ÿþ”5ÿþË6ÿýø06ÿþX7ÿþv8ÿþŠ9ÿþ”:ÿþ”;€€€€;.ý/.;ü/..<ý./=þ.ÿ;9<9=9>þ:ÿ;ìë<üìëë<ë>þëÿ;þŠÿÿ<üvÿÿ<ýXø=þ0ÿ.þ/../ü0//001þ011ý21223ú43343445.þ/..ü/..//ü0//00ü10011212ü3232234þ344ý54..ö/.././././/01ü01011ý21223þ233ý4344ü5./../.þ/../þ.//ý0/001ú2122122 3ý4344þ. .ñ/.//..//0//00/00ý10112323ú2343344.þ/..þ/..û/././/0þ/001ü21122ý3233ü434 .þ/..ý/.//ü0//00þ10012þ122ù32232233þ/..þ/..ú/.//.//û0/0/00ú10110112þ122õ3233223343.þ/..þ/..ý/.//./þ0//0ú10100112û323233.ù/.././../þ0//0ü10011ý2122ø133233233 ó.//../..//./../û0/0/001ü211223þ2 ý./..þ/..ý/.//0ø/0/001011ù01122122þ3ü.//. ./þ.//ý0/001012þ122ý./../þ.//þ.//0þ/001þ011ý2122 €þ9::9:9:þ;::;<þ;<<=õ>==>>=>?>>??þ>??þ@99þ:99þ:99û:9:9::ý;:;;ú<;<;;<<ý=<==>ú=>==>??þ>??÷9:99:99:99:9:þ9::;<þ;<<=ü<==>>þ=>>?þ>??÷9::9::9:99þ:99: ;ý<;<<=ü>==>>÷?>>??>?99þ:99:9ý:9::ù9:;:;;::;ü<;;<<=þ<==>þ=>>þ?>>ø?:9::9 9:þ9::þ;::ý;:;;<=>?:9ò:9:9::9:9:9:9::ü;::;;<þ;<<ý=<==ü>==>>9û:99:99þ:99:;þ:;;<ú=<=<<==ý>=>>þ?÷:9:9::9:99:;þ:;;û<;<;<<þ=<<=þ>==>ú9:9::99þ:99ù:9:9:9::;þ<;;<=ø>==>=>> 9û:99:99þ:99þ:99:þ;::;ý<;<<ý=<==û>==> ý9:99þ:99:þ9::ø;:;;<;;<<÷=<<=<==>==û:9::99:ù;::;;:;;<=þ<==ý9:99ú:9:99::;þ:;;<þ;<<þ=<<= €øìëëììëëììëìþëììþëììþëììþíììíìíìðíìíìëëìëììëìëëìëëüìëëììëìíýìíììíìþëììöëììëìëëìëììþëììûëììëì ìþíììþíììùíìíìííëëìúëìëìëììûëìëëììþëììóíììíììíììíëììëìëìëüìëìëëýìëììþíììûíìííìì÷ìëëììëëìëëìþëììüëìëììëììüëìëììþëììüëìëììëìë ìþíì ìùíìíìííìëìëìþëììöëìëëììëìëììþíììþíììþíëìöëììëìëìëëììëüìëìëëìþëììþíìëìñëììëììëìëìëììëììþëì ìþëììþí íëìëììëìëëììëìëììëëììþëììþëìì ìëùìëëììëììëìëìþëììüëìëììþíììýíìûëìëìëëúìëìëëììþëì ìþëì ìëúìëìëìëëøìëììëìëììþí ÀÿþËÿ=ÿý”ÿ<ÿýSßÿ:ÿýÿ9ÿý5²ÿ7ÿýI¼ÿ5ÿýD­ÿ3ÿ ü&…ßÿ0ÿ üD”ßÿ-ÿû0q­äÿ)ÿöIq”²Ëßîøÿ ÿ €5ú65655667ý87889:;ý<;<<ø;<=<<4455ü65566ú7676677þ8778ý9899þ899:þ9:: ;ý<;<<ý=455ý6566ö56767677677ý8788ý9899:þ;::;<û454455ý6566ü766778þ788ü98899:ý;:;;<4 56ý7677ü87788ý9899:;ü<;<445ù45565566ý7677ý8788ú9889899:ü9:9::ý;:;;ý<;44ù54454455ý6566789þ899:ý;:;;ý4344ý5455ý6566ú7677677ú8778788ü989889:;:;3ý43445ò6565566766776778989:þ9::ý;:;;3456û565566ý7677ú87787889:þ9::;34÷34554544556ü76677ý87889þ:99:;÷:;;323343345ù65566566ý7677ú87887889:;ý3233û434344ø545445655678ý9899:þ233ü43344ý5455÷6556676677ö87788788988 9: €þ?@@úA@A@@AABüABABBüCBBCCDüCDCDDEDEþFEEýFEFFGúF?@??@@þA@@ABþABBýCBCCúDCDCCDDôEDEEFEFEFFEFF?ý@?@@ ABýCBCCDEFEFþG??ý@?@@Aþ@AABþABBûCBCBCCDþCDDEþDEEüFEFEEFþ>??@?ö@AA@A@@A@AABCüDCCDDEüDEDEEFþEFF?@þ?@@úA@A@@AAüBAABBþCBBýCBCCùDCCDDCDDEúDEEFEFFúEF>?>??@þ?@@ýA@AABúCBBCBCCýDCDDEþDEEøFEEFF>>??ü>?@??@ùA@@AA@AAþBAABýCBCCüDCCDDEþDEEýFE>>?þ@??@Aþ@AABþABBüCBBCCDþCDDE÷F>>?>??>??@þA@@Aþ@AABCþDCCDõEDEDEDEE>=>>þ?>>?ý@?@@þA@@A BûCBCBCCûDCDCDDúEDEDDEE> ?@Aþ@AAýBABBCþBCCûDCDCDDEüDED>>õ?>??>??@??@@ABúCBBCBCCDüCEEDDòE==>=>==>>?>>?? @ ABüCBBCCDCD €ìíìíúìííììííþìí íîíùîííîíîííýîíîîþíîîöíîìíììíììííìíþìííûìííìííþìí íþîííþîííîíøîíîííîíîîíüìííììíõìííììíìííìííþìííþîííþîííûîííîííûîíìíììþíììíìíûìííìííùîíîîíîííî÷íìíìíìíìííýìíììíþìííþîííþîííþîííøîííîîìíììíì íûìííìííûîííîíí÷îíîîííììííìíóìíìíìííììííìííþìí íüîííîîíüîíîí íìíøìíììííìííþìííþîíí÷îíîííîííîîìüíììííþìííìýíìííüìííììíþìííýîíììíìíðìíìííììííììíìíìííûìííìííþîí íîùíîìíìíììíúìííìíììíþìííûìííìííþìííûîííîííìüíìíììþíììíìùíìííììííþìííþìííîíþîííýìíììüíìíììõíììíìíìíìíììíþìííþìííþìííþìííöîííîíììíìííìíôìííìííìíìííììíüìííììíüîíí €ÿ €ý=<==>ü?>>??@þ?@@AB CDøED<==<<==ú>==>=>>?þ@??@ABþABBýCBCCýDCDD<ü=<<==>?ö>?>??@@??@@ýA@AABøCBBCCBBCCúDCCDD<<=þ<==>ý?>??ü@??@@A@ABþABBþCBBýCBCCþ;<<ý=<==ô>==>=>==?>>??ý@?@@ýA@AABýCBCCDýC;<<ý=<==ü>==>>ý?>??û@?@?@@ýA@AAýBABBCBCýDC<<þ;<<ý=<==>=>?@ýA@AABþABBC;<=þ<==>?ü@??@@Aþ@AAýBABBC;û<;<;<<=>?ú@??@?@@ýA@AABAýBCBB;ý<;<<=õ>==>=>??>>??þ@??@ýA@AABüABABB;<;<ú=<=<<==þ>==>?>?@?ý@?@@ýA@AABCüB::;;ú<;;<;<<=>þ=>>ý?>??@ü?@?@@AýBABB÷CB;:;;:;<<þ;<<=þ<==ý>=>>?û@?@?@@Aú@ABAABBû:;::;;ü<;;<<ü=<<==ý>=>>?@Aþ@AAýBA G HüIHHIIJöKJJKJKJKLKKLMþNMMNþFGGúHGGHGHHúIHIIHIIüJIIJJKLöKLLMLLMLLMMNøMNNMFGFGGýHGHHIþHII JKþLKKýLKLLýMLMMNüFGFGGHöGHGHIHIHHIIüJIIJJKüJKJKKLMLýMNMMøFGGFGGFGGþHGGHIùHIHIIHIIùJIIJJKJJKLMþLMMFüGFFGGùHGHGHGHHûIHIHIIøJIIJIJIJJKùLKLLKKLLýMLMMýNEFFGFGHþGHHIþHIIJýKJKKLþKLLMEFùGFFGGFGGHúIHIIHIIýJIJJKúLKLKKLLMLþMEEFýGFGGHþGHHIþHIIýJIJJKJKLMEFüGFGFFýGFGGHþGHHIþHIIýJIJJ KLEFýGFGGHþGHHIHIJþIJJýKJKKLEF GöHGHGHIIHHIIýJIJJKþJKKLþDEEùFEFFEEFFGþFGGHIHIûJIJIJJKJüKJJKKúLKKLLEEýFEFF GHIJþIJJKûLKKL þíîîíüîííîîþíîîþïî îïýîïîîüïîïîîï îüíîíîîþíî îïîïýîïîîïûîïïîïïýîïîîüíîíîîíîþíîîïîþïîîúïîîïîïïúîïîííîîíýîíîîþïîîûïîïïîîïîïîïüîííî îþíîîüíîíîîþíîîúïîîïïîîýïîïïîðïîïîîïîïîîïíîíîííîíîí îþïîîþïîîþïîîüïîïîîðïîïîïíîîííîííîíîîí îþíî îþïîîþïîîúïîîïïîîþïííþîííùîíîîííîîüíîíî îþíîîþïîîòïîîïîîïîííîíîííîþíîîüíîíîîþíîîþïîîïîþïîîþïîîïþîííîíøîííîíîíîîøíîîííîíîîþíîîþïîîþïîîúïîïîïîîïþîííôîííîîíîíîîíîîþíîîþíîîþíîîþïîîûïîîïîîíîí÷îíîííîîíîîþíîîþïîîþïîîøïîíîííîííôîííîîíîíîííîîþíî îíýîíîîþïîîîïîïîïïíîíîííîííîíîîøíîîíîííîîþïîîïîüïîî €ÿ €DEýFEFFGûFGGFGGHþGHHI÷JIJIIJJKJJKþJKKLDEDEýFEFFüGFFGGHþGHHIJþIJJûKJKJKKùLDEEDDEEFþEFFGüHGGHHIþHIIJýKJKKLDþEDDEFGúHGHHGHHIJþIJJKúLKKDCDDEF GHüIHHIIJþIJJKJKýDCDDEFýGFGGúHGHGGHHýIHIIüJIIJJK÷JKLDCCDCDDEþDEEFýGFGGHþGHHýIHIIJþIJJKþCDDþCDDEýFEFFýGFGGHüIHHIIJKþJCCDEûFEFEFF GHýIHIIûJIIJIIJKýJBCCDCDEFôEFEFFGFGFGFGGüHGGHHûIHIHIIJKûJBCBCCDþCDDEFûGFGFGGHþGHHþIHHIJýKBCCýDCDD EFûGFGFGGHIþHIIïJIIJIJBBCBCCBCCDCCDüEDDEEüFEEFFGþFGGýHGHHIþHIIúJIJIIBBCBCýDCDDCDùEDDEDFEEFüGFFGG HIJ €NýONOOþPOOPýQPQQRûSRSRSSúTSTTSTTûUTUTUUNONOPþOPPQõPQQRQQRQRQRRýSRSSýTSTTüUTTUUþMNNýONOOüPOOPPQþPQQýRQRRQùSRRSSRSSTþUTTUNþONNøONOOPOOPPüQPPQQúRQQRQRRüSRRSSýTSTTUûTNNMN NOüPOOPPQúRQRRQRRýSRSSþTSSTùUTUNNMNNüONNOOPQPQýRQRRSúTSTSSTTMüNMMNNüONNOOýPOPPþOPPQöPQRRQQRRQRRýSRSSþRSSøTSTTUTLMMN OPþOPPüQPPQQRûSRSRSSýTSTTMNMNùONNOONOOPüQPPQQñRQRRQRQRRSRRSRSSTûSTMLMMNüMNMNNþONNOýPOPPQþPQQþPQQRüSRRSSøTSSLLMLMMþNMMýNMNNOþNOOPýQPQQ RSþRSSTþLMMþLMMþNMMNOüPOOPPýQPQQþRQQRüSRRSSþTLLüMLLMMýNMNN OýPOPPQRüSRRSSþTLL MNüONNOOþPOOýPOPPQûRQRQRRS €ûïîïïîîïþîïïúðïïððïïðïûðïðïððïýðïððïîïþîïïðïþðïïüðïðïïûðïððïïûðïðïððîïõîïîîïïîïïîï ïþðïïþðïïðþïððöïððïðïðïïðð÷ïîïïîïïîïïþîïïî ïþðïïþðïïþðïïüðïðïïðïüðïïððïúîïïîîïïþîï"ïúðïïðïððüïðïîîïþîïïîýïîïïûîïïîïïþðïïüðïïððòïðïîïïîïîïïîîïïîïþðïïðïðïðþïððîïýîïîîïþîï ïþîïïðþïððûïðîîïïþîïïþîïïþðïïþðïïþðïïðüïðïððîïîïîïïîïïîïîïîïïîïïþðïïøðïïðïððïïðôïðïîïïîîïîïîîïîýïîïïþîïïþîïïþðï ïöðïðïïðïïðïïîñïîïîîïïîïïîîïîï ïþîï ïüðïðïïðõïððïðïððïîïïþîïïîïøîïïîîïîïïþîïïûîïïîï ïþðïïõðïððïïðïïðïïîüïîîïïîïþîïïþîïïþðïïùðïððïðïï €€ÿ €LMþLMMýNMNNùONONONOO PQRþQRRSüRSRSSöTSTSLLMLLM MNOöNONOPOPOOPPýQPQQøRQRQRQQRRSTLMþLMMNþMNNýONOOPQúPQQRQRRSþTLLùMLMLMLMMýNMNNOüPOOPPüQPQPPQRQRSLþKLLúMLMMLMM NýONOOPOPQúRQRRQRRSûKLKKLLMõLMMNMMNMNMNNONOüPOOPPýQPQQýRQRRúSRSRSKKüLKKLLýMLMMNþMNNûONONOOPQüRQQRRSýKJKKLýMLMMüNMMNNONOPOP QýRQRRüSRRKK LMNþMNNøONOONONOOPúQPQPPQQýRQRRJKóLKLLKLMMLMLLMMüNMMNNOýPOPPQPüQPPQQýRQRRüSKJKKþLKKLMþLMMNüONNOOPþOPPQRþQRRJüKJJKKLþMLLýMLMMúNMNMMNNýONOOþNOOPþQPPQRJüKJJKKûLKLKLLMùNMMNMMNNýONOOPúOPQPPQQýRQJJúKJJKJKKLüMLLMM NOýPOPPQPQýRQ üUVUVVþWVVWXWXYþXYYZý[Z[[þZ[[ý\[\\ü]\\UUVþUVVWþVWWXðWXXYXYXYXYYZYZYZZû[Z[Z[[\UVWþVWWXûYXYYXXYýZYZZý[Z[[ù\[[\\[\\þTUUVøWVWWVWXWWýXWXXüYXXYYZ[\U VýWVWWùXWXXWWXXYþXYYZþYZZý[Z[[\þ[UUýVUVVüWVVWWûXWXWXXþYXXYúZYZYYZZ[Z[\ý[TUUþVUUV÷WVWVVWWXWWýXWXXYþXYYZYZ[þZ[[\ýTUTTUVUV WýXWXXöYXXYYXZYYZZý[Z[[ø\[[TTUTUUVUVýWVWWúXWXXWXXûYXYXYY Z[TüUTTUUVûWVWVWWXøWXXYXYXYYZý[Z[[T UVWúXWXWWXXûYXYXYYþZYYýZYZZ[Zý[STTúUTTUTUUVWVWXúYXYYXYYüZYYZZ÷[ZZ[[TSSTTUVüWVVWWXþWXXYZý[ZSSôTSTTSTUTUTTUUüVUUVVúWVVWVWWûXWXWXXþYXXYZ €ðïðþñððåñðñððñððñðñððñððñððññðñðññððñ ðþïððñúðññðñððúñðññðññþðññøðñððïðïððïúðïððïððüñððññøðñððñððñ ñüðñðññðþïððþïððüñðñððñðûñððñððñ÷ðññððññðññøðññðññïððüïðïððþïððüñðñððñúðññððññðõñðññðïðïðïððþïððñðñð ñïðþñððüñðñððþñððýñðññðñðüïðïððþïððüïðïððþïððñ ðëñðñðñððñððñððñðñððññððïðþïððûïðïïð ðþñððóñðñðñððñððññððüñððññïþðïïúðïðïïððþïððùñðñðññððüñðñððüñððññúðñïððïïðþïððþïððþïððþïððþñð ðóñðñðññðñðñððññðûñðïïððúïððïïððþïððþïð ðüñðñððþñð ðýñðññïþðïïðþïððûïððïððñýðñððöñððññðñððññïðúïððïðïïüðïïððþïððñðøñðñððññ €ÿ €TUþTUUüVUUVVûWVWVWWöXWXWXYXYXYYþZYYZ[\[TõUTUUTUUVVUVVýWVWWXüYXXYYúZYZYYZZü[ZZ[[ú\STTSTTUVUýVUVVWôVWWXWXXWWXXYYXYýZYZZ[úZ[Z[\TTUTUVWVWXôWXXYYXYXYYZYYZî[Z[[TTSTSSTTUTUUTUUüVUUVVWþXWWXúYXYXXYYûZYZYZZþSTTþSTTUüVUUVVûWVWVWWòXWXXWXWXXYXYXYYúZYYZYZZ[üZ[RSSþTSSøTSTTUTTUUûVUVUVVýWVWW XYZ[SúRSSTSTTþSTTUVWVWûXWXWXXYþXYYZøSRSSRSST TýUTUUVüWVVWWûXWXWXXüYXXYYúXYYZYZZûRSSRSSTþSTTU VýWVWWýXWXXýYXYYýZYZZR STUVUVýWVWWüXWWXXYXYZùQRRSSRSSTþSTTþUTTUýVUVVýWVWWXþWXXYûZYZYRRüSRRSSTUTUVýWVWWXþYXXYùQRQRRSRRSþRSSTýUTUUûVUVUVVWûVWWXWWXY €]ü^]]^^ü_^^__`þ_``ùa``a``aaýbabb÷cbccbccbccdþ]\\]ý^]^^û_^_^__ý`_``úa`aa`aabúabababbcdþc]]ú^]^]]^^þ_^^ _`a`aþbaabcd÷cd]]\\]\]]ý^]^^ü_^^__ý`_``aþ`aab÷abbcbcbbccþd\\]ü\]\]]^]ý^]^^_û^_^^__`ýa`aaýbabbþcbbcø\[]\]\\]]ý^]^^ý_^__ü`__` `abýcbcc\ú]\]\\]]^þ]^^_þ^__`þ_``ýa`aaýbabbþabbc\þ[\\þ]\\] ^_`ýa`aaûbababbcýbc\\þ[\\]\]^]^ý_^__ý`_``a`aübaabbcb[ý\[\\]ý^]^^_`÷_`_``a``aaýbabbýcb[[\þ[\\]þ\]]ü^]]^^ü_^^__`aþ`aaþbaab[ú\[[\[\\ü]\\]]^û]^]]^^_û`_`_``ýa`aaöbabbabb[Z[[\þ[\\]þ\]] ^_ú`_`__``abûZ[[Z[[ý\[\\]þ\]]ý^]^^ú_^__^__`þ_``øa``a`aabba € ñüòñòññüòññòò÷ñòññòñòòññòúñòòññòò÷ñòòñòòððññþðññò ñòûñòñòññòñòþñòòþñòòñþðñ ñþòññþòññþòññüòñòññöòñòòññòñòññòþñòòñþòññùòññòñòññòþñòòñýòñòòþñòòþðññòñþòññúòñòññòòñøòñòñòòñòòñþðññðñþðñ ñòñûòññòññ÷òññòòñòòññòþñòòñþðññþòññïòñòòñòòñòòñòòñòñòòûñòññòòþñòòñðñòñòñúòññòñòòññòññòòñòòðñðñðññþðññþòññò ñòñòûñòñòññþðññþðññþðññüòñòññþòññò÷ñòññòòññòòþñòòþñòòñðñþðññòñõòññòññòòñòññòþñòòðñôðññððññððñðññþðññûòññòññùòñòñòòññòþðññð÷ñðññðññðññþòñ ñþòññøòñòòñòòññòðñúðññððññþòññþòññþòññ÷òñòñòññòññþò €ÿ €þ[\\]þ\]]^_^_`ababcþbccý\[\\]^_þ^__ú`_``_``ýa`aabýcbccþ[\\û]\]\]]û^]^]^^_ü`__``üa``aabýcbccü[\[\\]þ\]]^ý_^__` abücbc[[\þ]\\]û^]^]^^ý_^__`a`ýa`aab[\ü]\\]]þ^]]^_ý`_``þa``aübaabbþc[[\þ]\\]ý^]^^ú]^_^^__ü`__``abþabbþc[[ú\[\[[\\ü]\\]]^û_^_^__`_`a`aþbaab[ûZ[[Z[[ü\[[\\ù]\\]]\]]ý^]^^_þ^__ü`__``ýa`aaýbabbþ[ZZ[û\[\[\\]\]ý^]^^ý_^__`ýa`aaþ`aaübabZZ[þZ[[û\[\[\\]^ _`aþ`aabaZ[\[\]þ\]]þ^]]^þ_^^ý_^__`_`aþYZZþ[ZZ[ý\[\\]^_ü^_^__`ù_``a``aaübZYZZ[ý\[\\]ö\]\]]^]^]^^_^_ï`__``_``a``aa`aa deþdeefgþfgghþghhi jkþjkkþcddüeddeeýfeffûgfgfggùhgghhghhiþhiijüijijjøkjjkkdcddüeddeeýfeffügffggýhghh ijûkjjkccdøededeefeefügffggúhghhghhiþhiijkcdþcddýedeeþdeeýfeffgfgühgghhihiújijiijjøkjccddcddedeýfeff ghýihiiji÷jkjccdccddücddeeþfeefþgffûghgghhûihihiiþjiijþbccdüeddeeýdeffefýgfgghþghhihýihiijijùbccbcdccûdcddeedefýgfgghýihiiùjijjcbccdcdeüdedeeýfeffýgfgghþghhñihhihiihijijiibbýcbccødccdcdcdd efgþhgghþihhiþhiibcüdccddefþeffgfgþhggýhghhibýcbccýdcddþeddefügffggþfgghghüihhiiþjbbcübcbccdþcddeýfeffþeffgþfgghüghghhøihhiihi  òþóòòùóòòóòóòòóøòóóòóóòóóòóüòóòó ó òþóòòóòóòõóòóóòòóóòòóóòóýòñòòóòóòóòõóòóóòóóòóòóóòýóòóóúòóòóóòòþóòòûóòòóòòûóòóóòòóûòóóòóóòþóòòþóò òþóòòþóòòóîòóòóóòóóòóóòóóòóòóóòþñò òþóòòþóòòþóòòöóòóòòóóòòóóòüóòòóóñòóóòóóòóòòñòòñò òþóòòûóòóóòòüóòòóóüòóòóóþòóóüòóòóóñòþóò òóò÷óòóòóóòòóóòþñòòþóòòüóòóòòóþòóóþòóóòýóòóóòñòûóòòóòòóòóýòóòòóýòñòòüñòñò òþóòòþóòòûóòóóòòóòóøòóòòñòñòòõóòòóòóóòòóòòùóòóòòóòòùóòòóòòóóòûñòòñòòþñòòþñòòþñòòþóò òóòóòûóòóóòòêóòòóòòóòññòññòññòòñòñòòþóòòó òóòüóòòóóüòóó €ÿ €dþcdd efýgfggýhghhñihhihiijjijijijjýkjkkcdüeddeefôgffggfgghgghhiüjiijjþkjjþkccdüeddeeýfeffúgfggfgghüihhiijkcûdcdcddeüfeeffgþfgg hiýjijjþccýdcddþeddeûfefeffgþfgghihijijþbccûdcdcddýedeeüfeeffgûhghhiiühihiijþbccdcýdcddedefþeffgüfgfgghiþhiiþjûcbcbccþdccdeûfefeffýgfggþhgghýihiibcþbccdþeddeþfeefgýhghhþibþcbbcdedeüfeeffgþhggh þabbcdcdeþdeefþeffügffggh bþabbýcbccýdcddùeddeddeeþfeefgþabbþabbcdþcddüeddeeýfeffýgfþabbýcbccüdccddeþdeefþe –klmþlmmúnmmnmnnýonooþnoopqûrqrqrrüsrrkklþkllmnþmnnùonnoonoopüqppqqrùqrrsrrkk lmnoýnonnoýpoppýqpqqürqqrrýkjkkúlkllkllmùlmnnmmnnýono opqpqúrqqjkkýlkllýmlmmnoþnoopþoppúqpqqpqqürqqþjkklþkllýmlmmnþmnnoþnooüpooppýqpqqjûkjkjkklþmllmþlmmnmnþonno púqppqpükjjkklþmllmþnmmnýonoopüopoppýqpþijj klmünmmnnûmnnonnoýpoppjúkjjkjkklüklkllýmlmmnmnoþnoop jküjkjkkølklkllmllmýnmnnüonnooþp ýjijjükjjkkýlkllmnþmnnùononooûijiijjkþjkkülkkllýmlmmnþoiýjijjûkjkjkkþlkklýmlmmþn –óþôóóøôóôóôóôóóôþóôôúóôôóóôôõþôóóþôóóýôóôôóðôóôóóôôóôôóôóôóôôþóôôþóô ôóùôóóôóôóóúôóóôôóóþôóóôûóôôóôôþóôôþóôôþõóóþôóóþôóóúôóóôôóóðôóóôôóóôóóôóôôóôôüóôôóó ôþóóôóþôóóôüóôóôôöóôóôóóôôóôôüóôôóþôóóôóôóôóôþóôôóôôóóôôóóôóôôóóôóôüóôóôôó ôóþòóóþôóóþôóóôñóôóôóôôóôôóôôóôôþóôôóôóôóôóôúóôóôóôôóôóþôóóþôóóôóüôóóôôüóôóôôùóôôóôó óþòóóþôóóþôóóôüóôóôô óþòóóüôóôóóþôóóøôóôóôóóóþôóóôøóôóôôóôóóôóþôòóþòóóþòóóþôóóþôóóôóüôóó –¾ÿýøXÿ;ÿüË0ÿ:ÿþ”9ÿýßS8ÿý6ÿý²54ÿý¼I2ÿý­D /ÿüß…& ,ÿüß”D(ÿûä­q0ÿöøîß˲”qI –ýkl<þk¾r=þs¾ô=þô¾ýÿŠ<þv¾€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ääää‹‹ÅÅbb11White Backgoundÿ     8 ìú í ú^ új úv ú‚ ïÎ ïÞ ïî ïþ ð ð ð. ð> ðN ð^ ðn ð~ ðŽ ðž ð® ð¾ ðÎ ðÞ ðî ðþ ñ ñ ñ. ñ> ñN ñ^ ñn ñ~ ñŽ ñž ñ® ñ¾ ñÎ ñÞ ñî ñþ ò ò ò. ò> òN ò^ òn ò~ òŽ òž ò® ò¾ òÎ òÞ òî òþ ó ó ó. ó> óN ó^ ón ó~ óŽ óž ó® ó¾ óÎ óÞ óî óþ ô ô ô. ô> ôN ô^ ôn ô~ ôŽ ôž ô® ô¾ ôÎ ôÞ ôî ôþ õ õ õ. õ> õN õ^ õn õ~ õŽ õž õ® õ¾ õÎ õÞ õî õþ ö ö ö. ö> öN ö^ ön ö~ öŽ öž ö® ö¾ öÎ öÞ öî öþ ÷ ÷ ÷. ÷> ÷N ÷^ ÷n ÷~ ÷Ž ÷ž ÷® ÷¾ ÷Î ÷Þ ÷î ÷þ ø ø ø. ø> øN ø^ øn ø~ øŽ øž ø® ø¾ øÎ øÞ øî øþ ù ù ù. ù> ùN ù^ ùn ù~ ùŽ ùž ù® ù¾ ùÎ ùÞ ùî ùþ ú ú ú. ú> úNÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿ€ÿäÿäÿäÿäÿ‹‹ÅÅbb11¾ Backgroundÿ      ûA¾ ûe ÿ ÿ% ÿ1 ÿ=¾ ü ü ü- ü= üM ü] üm ü} ü ü ü­ ü½ üÍ üÝ üí üý ý ý ý- ý= ýM ý] ým ý} ý ý ý­ ýÉ ýå þ þ þ9 þU þq þ þ© þÅ þá þýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿ€ÿ€ÿ€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€ ÿ€ ÿ€ ÿ€€xÿÜxÿÜxÿÜT‹_Å/b1 pyclustering-0.10.1.2/docs/page/000077500000000000000000000000001375753423500163435ustar00rootroot00000000000000pyclustering-0.10.1.2/docs/page/cpp_pyclustering_intro.md000077500000000000000000000117401375753423500235000ustar00rootroot00000000000000C++ PyClustering Library {#mainpage} ======================== [TOC] # Introduction C++ pyclustering is an open source library for data mining that is written in C++. The general aim of the project is to provide C++ developers an ability to use cluster analysis algorithms and other tools including bio-inspired algorithms that are based on oscillatory neural networks. Most of the algorithms and models are presented by parallel implementations that help to maximize the performance. One of the client of C++ pyclustering is Python pyclustering library that uses the library in order to reach the maximum performance by using C++ advantages. The library is written in pure C++14 without any other third-party dependencies and it can be built for various platforms. The only requirement for a compiler is to support C++14. The quality of the library is ensured by more than 3500+ unit and integration tests including memory leakage checks and static analyzers. The C++ pyclustering library is distributed as a source code and can be easily built using makefile or MS Visual Studio. The library can be built as a dynamic library or as a static library. # Functionality of the Library There are two general namespaces where functionality focuses: - `pyclustering::clst` - cluster analysis. - `pyclustering::nnet` - oscillatory neural networks. Following general algorithms are implemented in clustering namespace `pyclustering::clst`: - Agglomerative (pyclustering::clst::agglomerative); - BSAS (pyclustering::clst::bsas); - CLIQUE (pyclustering::clst::clique); - CURE (pyclustering::clst::cure); - DBSCAN (pyclustering::clst::dbscan); - Fuzzy C-Means (pyclustering::clst::fcm); - G-Means (pyclustering::clst::gmeans); - HSyncNet (bio-inspired algorithm pyclustering::clst::hsyncnet); - K-Means (pyclustering::clst::kmeans); - K-Means++ (pyclustering::clst::kmeans_plus_plus); - K-Medians (pyclustering::clst::kmedians); - K-Medoids (pyclustering::clst::kmedoids); - MBSAS (pyclustering::clst::mbsas); - OPTICS (pyclustering::clst::optics); - ROCK (pyclustering::clst::rock); - Silhouette (pyclustering::clst::silhouette, pyclustering::clst::silhouette_ksearch); - SOM-SC (pyclustering::clst::somsc); - SyncNet (bio-inspired algorithm pyclustering::clst::syncnet); - TTSAS (pyclustering::clst::ttsas); - X-Means (pyclustering::clst::xmeans); Following general oscillatory network models are implemented in `pyclustering::nnet`: - Oscillatory network based on Hodgkin-Huxley model (pyclustering::nnet::hhn_network); - LEGION: Local Excitatory Global Inhibitory Oscillatory Network (pyclustering::nnet::legion_network); - PCNN: Pulse-Coupled Neural Network (pyclustering::nnet::pcnn); - SOM: Self-Organized Map (pyclustering::nnet::som); - Sync: Oscillatory Network based on Kuramoto model (pyclustering::nnet::sync_network); - SyncPR: Oscillatory Network based on Kuramoto model for pattern recognition (pyclustering::nnet::syncpr); # Linux – How to Build the Library 1. Download Release source files from: https://github.com/annoviko/pyclustering/releases 2. Extract the archive. 3. Navigate to `pyclustering/ccore`: ```bash $ cd pyclustering/ccore ``` 4. Execute one of the following command in order to build the library: * `make ccore_64bit` - to build shared library. * `make ccore_64bit_statis` - to build static library. * `make` - to print all available targets. # MacOS – How to Build the Library 1. Download Release source files from: https://github.com/annoviko/pyclustering/releases 2. Extract the archive. 3. Navigate to `pyclustering/ccore`: ```bash $ cd pyclustering/ccore ``` 4. Execute one of the following command in order to build the library: * `make ccore_64bit` - to build shared library. * `make ccore_64bit_statis` - to build static library. * `make` - to print all available targets. # Windows – How to Build the Library 1. Download Release source files from: https://github.com/annoviko/pyclustering/releases 2. Extract the archive. 3. Navigate to `pyclustering/ccore`. 4. Open `ccore.sln` solution using Visual Studio. 5. Build `ccore` project using one of the following configuration: * `Release` - to build dynamic library. * `Release Static Library` - to build static library. # Cite the Library If you are using pyclustering library in a scientific paper, please, cite the library: Novikov, A., 2019. PyClustering: Data Mining Library. Journal of Open Source Software, 4(36), p.1230. Available at: http://dx.doi.org/10.21105/joss.01230. BibTeX entry: ``` @article{Novikov2019, doi = {10.21105/joss.01230}, url = {https://doi.org/10.21105/joss.01230}, year = 2019, month = {apr}, publisher = {The Open Journal}, volume = {4}, number = {36}, pages = {1230}, author = {Andrei Novikov}, title = {{PyClustering}: Data Mining Library}, journal = {Journal of Open Source Software} } ``` pyclustering-0.10.1.2/paper/000077500000000000000000000000001375753423500156065ustar00rootroot00000000000000pyclustering-0.10.1.2/paper/paper.bib000077500000000000000000000511571375753423500174070ustar00rootroot00000000000000@book{Oliphant2006, author = {Oliphant, Travis}, year = {2006}, month = {01}, title = {Guide to NumPy} } @article{Hunter2007, author = {Hunter, J. D.}, title = {Matplotlib: A 2D graphics environment}, journal = {Computing In Science \& Engineering}, volume = {9}, number = {3}, pages = {90--95}, abstract = {Matplotlib is a 2D graphics package used for Python for application development, interactive scripting, and publication-quality image generation across user interfaces and operating systems.}, publisher = {IEEE COMPUTER SOC}, doi = {10.1109/MCSE.2007.55}, year = 2007 } @misc{SciPy, author = {Eric Jones and Travis Oliphant and Pearu Peterson and others}, title = {{SciPy}: Open source scientific tools for {Python}}, year = {2019}, url = "http://www.scipy.org/" } @article{Nethercote2007, author = {Nethercote, Nicholas and Seward, Julian}, title = {Valgrind: A Framework for Heavyweight Dynamic Binary Instrumentation}, journal = {SIGPLAN Not.}, issue_date = {June 2007}, volume = {42}, number = {6}, month = jun, year = {2007}, issn = {0362-1340}, pages = {89--100}, numpages = {12}, url = {http://doi.acm.org/10.1145/1273442.1250746}, doi = {10.1145/1273442.1250746}, acmid = {1250746}, publisher = {ACM}, address = {New York, NY, USA}, keywords = {Memcheck, Valgrind, dynamic binary analysis, dynamic binary instrumentation, shadow values}, } @book{book_algorithms_for_clustering_data, author = {Jain, Anil K. and Dubes, Richard C.}, title = {Algorithms for Clustering Data}, year = {1988}, isbn = {0-13-022278-X}, publisher = {Prentice-Hall, Inc.}, address = {Upper Saddle River, NJ, USA}, } @inproceedings{inproceedings_bang_1, author = "Schikuta, Erich and Erhart, Martin", editor = "Amin, Adnan and Dori, Dov and Pudil, Pavel and Freeman, Herbert", title = "BANG-Clustering: A novel grid-clustering algorithm for huge data sets", booktitle = "Advances in Pattern Recognition", year = "1998", publisher = "Springer Berlin Heidelberg", address = "Berlin, Heidelberg", pages = "867--874", isbn = "978-3-540-68526-5", doi = "10.1007/BFb0033313" } @article{article_birch_1, author = {Zhang, Tian and Ramakrishnan, Raghu and Livny, Miron}, title = {BIRCH: An Efficient Data Clustering Method for Very Large Databases}, journal = {SIGMOD Rec.}, issue_date = {June 1996}, volume = {25}, number = {2}, month = jun, year = {1996}, issn = {0163-5808}, pages = {103--114}, numpages = {12}, url = {http://doi.acm.org/10.1145/235968.233324}, doi = {10.1145/235968.233324}, acmid = {233324}, publisher = {ACM}, address = {New York, NY, USA}, } @book{book_pattern_recognition_2009, Title = {Pattern Recognition, fourth edition}, Annote = {SIGNATUR = 2011-10411}, Author = {Sergios Theodoridis and Konstantinos Koutroumbas}, Keywords = {PATTERN RECOGNITION}, Publisher = {Elsevier}, Year = {2009}, Aquired = {2011}, Place = {Favoritenstrasse 9/4th Floor/1863} } @article{article_clarans_1, author = {Ng, Raymond and Han, Jiawei}, year = {2002}, month = {10}, pages = {1003- 1016}, title = {CLARANS: A method for clustering objects for spatial data mining}, volume = {14}, journal = {Knowledge and Data Engineering, IEEE Transactions on}, doi = {10.1109/TKDE.2002.1033770} } @article{article_clique_1, author = "Agrawal, Rakeshand Gehrke, Johannes and Gunopulos, Dimitrios and Raghavan, Prabhakar", title = "Automatic Subspace Clustering of High Dimensional Data", journal = "Data Mining and Knowledge Discovery", year = "2005", month = "Jul", day = "01", volume = "11", number = "1", pages = "5--33", issn = "1573-756X", doi = "10.1007/s10618-005-1396-1", url = "https://doi.org/10.1007/s10618-005-1396-1" } @article{article_cure_1, author = {Guha, Sudipto and Rastogi, Rajeev and Shim, Kyuseok}, title = {CURE: An Efficient Clustering Algorithm for Large Databases}, journal = {SIGMOD Rec.}, issue_date = {June 1998}, volume = {27}, number = {2}, month = jun, year = {1998}, issn = {0163-5808}, pages = {73--84}, numpages = {12}, url = {http://doi.acm.org/10.1145/276305.276312}, doi = {10.1145/276305.276312}, acmid = {276312}, publisher = {ACM}, address = {New York, NY, USA}, } @inproceedings{inproceedings_dbscan_1, author = {Ester, Martin and Kriegel, Hans-Peter and Sander, Jorg and Xu, Xiaowei}, title = {A Density-based Algorithm for Discovering Clusters a Density-based Algorithm for Discovering Clusters in Large Spatial Databases with Noise}, booktitle = {Proceedings of the Second International Conference on Knowledge Discovery and Data Mining}, series = {KDD'96}, year = {1996}, location = {Portland, Oregon}, pages = {226--231}, numpages = {6}, url = {http://dl.acm.org/citation.cfm?id=3001460.3001507}, acmid = {3001507}, publisher = {AAAI Press}, } @article{article_cluster_elbow_1, author = "Thorndike, Robert L.", title = "Who belongs in the family?", journal = "Psychometrika", year = "1953", month = "Dec", day = "01", volume = "18", number = "4", pages = "267--276", issn = "1860-0980", doi = "10.1007/BF02289263", url = "https://doi.org/10.1007/BF02289263" } @article{article_ema_1, author = {Gupta, Maya R. and Chen, Yihua}, title = {Theory and Use of the EM Algorithm}, journal = {Found. Trends Signal Process.}, issue_date = {March 2011}, volume = {4}, number = {3}, month = mar, year = {2011}, issn = {1932-8346}, pages = {223--296}, numpages = {74}, url = {http://dx.doi.org/10.1561/2000000034}, doi = {10.1561/2000000034}, acmid = {1969853}, publisher = {Now Publishers Inc.}, address = {Hanover, MA, USA}, } @article{article_ga_2, title = "A genetic algorithm approach to cluster analysis", journal = "Computers & Mathematics with Applications", volume = "37", number = "7", pages = "99 - 108", year = "1999", issn = "0898-1221", doi = "https://doi.org/10.1016/S0898-1221(99)00090-5", url = "http://www.sciencedirect.com/science/article/pii/S0898122199000905", author = "M.C. Cowgill and R.J. Harvey and L.T. Watson", keywords = "Cluster analysis, Data clustering, Genetic algorithm, Global optimization, Variance-ratio maximization" } @article{artcile_hsyncnet_1, author = {J. Shao and X. He and C. Böhm and Q. Yang and C. Plant}, journal = {IEEE Transactions on Knowledge and Data Engineering}, title = {Synchronization-Inspired Partitioning and Hierarchical Clustering}, year = {2013}, volume = {25}, number = {4}, pages = {893-905}, doi = {10.1109/TKDE.2012.32}, ISSN = {1041-4347}, month = {April}, } @inproceedings{inproceedings_kmeans_1, author = {J. Macqueen}, title = {Some methods for classification and analysis of multivariate observations}, booktitle = {In 5-th Berkeley Symposium on Mathematical Statistics and Probability}, year = {1967}, pages = {281--297} } @inproceedings{article_kmeans_plus_plus_1, author = {David Arthur and Sergei Vassilvitskii}, title = {K-means++: the advantages of careful seeding}, booktitle = {In Proceedings of the 18th Annual ACM-SIAM Symposium on Discrete Algorithms}, year = {2007} } @article{article_optics_1, author = {Ankerst, Mihael and Breunig, Markus M. and Kriegel, Hans-Peter and Sander, Jorg}, title = {OPTICS: Ordering Points to Identify the Clustering Structure}, journal = {SIGMOD Rec.}, issue_date = {June 1999}, volume = {28}, number = {2}, month = jun, year = {1999}, issn = {0163-5808}, pages = {49--60}, numpages = {12}, url = {http://doi.acm.org/10.1145/304181.304187}, doi = {10.1145/304181.304187}, acmid = {304187}, publisher = {ACM}, address = {New York, NY, USA}, keywords = {cluster analysis, database mining, visualization}, } @inproceedings{inproceedings_rock_1, author = {S. {Guha} and R. {Rastogi} and K. {Shim}}, title = {ROCK: A Robust Clustering Algorithm for Categorical Attributes}, booktitle = {Proceedings of the 15th International Conference on Data Engineering}, series = {ICDE '99}, year = {1999}, isbn = {0-7695-0071-4}, pages = {512-521}, url = {http://dl.acm.org/citation.cfm?id=846218.847264}, acmid = {847264}, publisher = {IEEE Computer Society}, address = {Washington, DC, USA}, doi = {10.1109/ICDE.1999.754967}, issn = {1063-6382}, } @article{article_cluster_silhouette_1, author = {Rousseeuw, Peter}, title = {Silhouettes: A Graphical Aid to the Interpretation and Validation of Cluster Analysis}, journal = {J. Comput. Appl. Math.}, issue_date = {November 1987}, volume = {20}, number = {1}, month = Nov, year = {1987}, issn = {0377-0427}, pages = {53--65}, numpages = {13}, url = {http://dx.doi.org/10.1016/0377-0427(87)90125-7}, doi = {10.1016/0377-0427(87)90125-7}, publisher = {Elsevier Science Publishers B. V.}, } @article{article_syncnet_1, author = {Novikov, A. V. and Benderskaya, E. N.}, title = {Oscillatory Neural Networks Based on the Kuramoto Model for Cluster Analysis}, journal = {Pattern Recognit. Image Anal.}, issue_date = {September 2014}, volume = {24}, number = {3}, month = sep, year = {2014}, issn = {1054-6618}, pages = {365--371}, numpages = {7}, url = {http://dx.doi.org/10.1134/S1054661814030146}, doi = {10.1134/S1054661814030146}, acmid = {2670644}, publisher = {Springer-Verlag New York, Inc.}, address = {Secaucus, NJ, USA}, } @inproceedings{article_nnet_som_1, author = {T. Kohonen}, journal = {Proceedings of the IEEE}, title = {The self-organizing map}, year = {1990}, volume = {78}, number = {9}, pages = {1464-1480}, doi = {10.1109/5.58325}, issn = {0018-9219}, month = {Sep}, } @inproceedings{article_syncsom_1, author = {Novikov, A. V. and Benderskaya, E. N.}, title = {SYNC-SOM Double-layer Oscillatory Network for Cluster Analysis}, booktitle = {Proceedings of the 3rd International Conference on Pattern Recognition Applications and Methods}, series = {ICPRAM 2014}, year = {2014}, isbn = {978-989-758-018-5}, location = {ESEO, Angers, Loire Valley, France}, pages = {305--309}, numpages = {5}, url = {http://dx.doi.org/10.5220/0004906703050309}, doi = {10.5220/0004906703050309}, acmid = {2971006}, publisher = {SCITEPRESS - Science and Technology Publications, Lda}, address = {Portugal}, keywords = {Cluster analysis, Kuramoto model, oscillatory network, self-organized feature map}, } @inproceedings{article_xmeans_1, author = {Pelleg, Dan and Moore, Andrew W.}, title = {X-means: Extending K-means with Efficient Estimation of the Number of Clusters}, booktitle = {Proceedings of the Seventeenth International Conference on Machine Learning}, series = {ICML '00}, year = {2000}, isbn = {1-55860-707-2}, pages = {727--734}, numpages = {8}, url = {http://dl.acm.org/citation.cfm?id=645529.657808}, acmid = {657808}, publisher = {Morgan Kaufmann Publishers Inc.}, address = {San Francisco, CA, USA}, } @article{article_nnet_cnn_1, author = "Benderskaya, E. N. and Zhukova, S. V.", title = "Large-dimension image clustering by means of fragmentary synchronization in chaotic systems", journal = "Pattern Recognition and Image Analysis", year = "2009", month = "Jun", day = "01", volume = "19", number = "2", pages = "306--314", issn = "1555-6212", doi = "10.1134/S1054661809020151", url = "https://doi.org/10.1134/S1054661809020151" } @book{book_chemical_oscillatorions_waves, author = {Kuramoto, Yoshiki}, isbn = {978-0-486-42881-9}, keywords = {oscillations reaction-diffusion networks turbulence waves synchronization}, note = {originally published: Springer Berlin, New York, Heidelberg, 1984}, publisher = {Dover Publications}, series = {Chemistry Series}, title = {Chemical oscillations, waves, and turbulence}, year = 2003 } @article{article_nnet_hnn_1, title = "Selective attention model with spiking elements", journal = "Neural Networks", volume = "22", number = "7", pages = "890 - 900", year = "2009", issn = "0893-6080", doi = "https://doi.org/10.1016/j.neunet.2009.02.002", author = "David Chik and Roman Borisyuk and Yakov Kazanovich", keywords = "Hodgkin–Huxley neurons, Synchronization, Attention model, Sequential selection" } @article{article_nnet_hysteresis_1, author = {Jin'no, Kenya and Taguchi, Hiroshi and Yamamoto, Takao and Hirose, Haruo}, year = {2003}, month = {01}, pages = {737-740}, title = {Dynamical Hysteresis Neural Networks for Graph Coloring Problem}, doi = {10.1109/ISCAS.2003.1206418} } @article{article_legion_1, author = {Wang, DeLiang and Terman, David}, title = {Image Segmentation Based on Oscillatory Correlation}, journal = {Neural Comput.}, issue_date = {May 15, 1997}, volume = {9}, number = {4}, month = may, year = {1997}, issn = {0899-7667}, pages = {805--836}, numpages = {32}, url = {http://dx.doi.org/10.1162/neco.1997.9.4.805}, doi = {10.1162/neco.1997.9.4.805}, publisher = {MIT Press}, address = {Cambridge, MA, USA}, } @book{book_image_processing_using_pcnn, author = {Lindblad, Thomas and Kinser, Jason M.}, title = {Image Processing using Pulse-Coupled Neural Networks}, year = {2013}, isbn = {978-3-642-36877-6}, doi = {10.1007/978-3-642-36877-6}, edition = {3rd}, publisher = {Springer-Verlag}, address = {Berlin, Heidelberg}, } @article{article_nnet_sync_1, title = "Synchronization in complex networks", author = "Alex Arenas and Albert Diaz-Guilera and Jurgen Kurths and Yamir Moreno and Changsong Zhou", year = "2008", month = "12", doi = "10.1016/j.physrep.2008.09.002", volume = "469", pages = "93--153", journal = "Physics Reports", issn = "0370-1573", publisher = "Elsevier", number = "3", } @article{article_nnet_syncpr_1, author = {R. Follmann and E. E. N. Macau and E. Rosa and J. R. C. Piqueira}, journal = {IEEE Transactions on Neural Networks and Learning Systems}, title = {Phase Oscillatory Network and Visual Pattern Recognition}, year = {2015}, volume = {26}, number = {7}, pages = {1539-1544}, doi = {10.1109/TNNLS.2014.2345572}, issn = {2162-237X}, month = {July}, } @inproceedings{inproceedings_nnet_syncsegm_1, author = {Novikov, Andrei and Benderskaya, Elena}, title = {Oscillatory Network Based on Kuramoto Model for Image Segmentation}, booktitle = {Proceedings of the 13th International Conference on Parallel Computing Technologies - Volume 9251}, year = {2015}, isbn = {978-3-319-21908-0}, pages = {210--221}, numpages = {12}, url = {http://dx.doi.org/10.1007/978-3-319-21909-7_20}, doi = {10.1007/978-3-319-21909-7_20}, acmid = {2958474}, publisher = {Springer-Verlag New York, Inc.}, address = {New York, NY, USA}, keywords = {Image segmentation, Kuramoto model, Oscillatory network, Phase oscillator, Synchronization}, } @article{article_gcolor_dsatur_1, author = {Brelaz, Daniel}, title = {New Methods to Color the Vertices of a Graph}, journal = {Commun. ACM}, issue_date = {April 1979}, volume = {22}, number = {4}, month = apr, year = {1979}, issn = {0001-0782}, pages = {251--256}, numpages = {6}, doi = {10.1145/359094.359101}, acmid = {359101}, publisher = {ACM}, address = {New York, NY, USA}, } @article{article_gcolor_sync_1, title = "Clustering dynamics of nonlinear oscillator network: Application to graph coloring problem", journal = "Physica D: Nonlinear Phenomena", volume = "240", number = "24", pages = "1972 - 1978", year = "2011", issn = "0167-2789", doi = "https://doi.org/10.1016/j.physd.2011.09.010", author = "Jianshe Wu and Licheng Jiao and Rui Li and Weisheng Chen", keywords = "Clustering, Graph coloring, Phase oscillator, Complement graph, Kuramoto model" } @book{book_the_design_and_analysis, author = {Samet, Hanan}, title = {The Design and Analysis of Spatial Data Structures}, year = {1990}, isbn = {0-201-50255-0}, publisher = {Addison-Wesley Longman Publishing Co., Inc.}, doi = {https://doi.org/10.1016/0098-3004(91)90117-V}, address = {Boston, MA, USA}, } pyclustering-0.10.1.2/paper/paper.md000077500000000000000000000321771375753423500172540ustar00rootroot00000000000000--- title: 'PyClustering: Data Mining Library' tags: - pyclustering - data mining - clustering - cluster analysis - oscillatory network - machine learning - engineering - python - C++ authors: - name: Andrei V. Novikov orcid: 0000-0002-9666-9141 affiliation: "1" affiliations: - name: Independent Researcher index: 1 date: 22 January 2019 bibliography: paper.bib --- # Introduction A variety of scientific and industrial sectors continue to experience exponential growth in their data volumes, and so automatic categorization techniques have become standard tools for dataset exploration. Automatic categorization techniques -- typically referred to as clustering -- help expose the structure of a dataset. For example, the generated clusters might each correspond to a customer group with reasonably similar needs and behavior. Because the resulting clusters are often used as building blocks for higher-level -- often custom -- predictive models, researchers have continually tweaked and invented new clustering techniques. PyClustering is an open source data mining library written in Python and C++ that provides a wide range of clustering algorithms and methods, including bio-inspired oscillatory networks. PyClustering is mostly focused on cluster analysis to make it more accessible and understandable for users. # Summary The PyClustering library is a Python and C++ data mining library focused on cluster analysis. By default, the C++ part of the library is used for processing in order to achieve maximum performance. This is especially relevant for algorithms that are based on oscillatory networks, whose dynamics are governed by a system of differential equations. If support for a C++ compiler is not detected, PyClustering falls back to pure Python implementations of all kernels. In order to increase the performance of the Python implementations, PyClustering makes use of the NumPy (Oliphant, 2006) library for its array manipulations. PyClustering provides optimized, parallel C++14 clustering implementations; on most platforms, threading is provided by std::thread, though the Parallel Patterns Library is used for Windows. Due to the standardization of these threading libraries, PyClustering is simple to integrate into pre-existing projects. The core Python dependencies of PyClustering are NumPy and SciPy (Jones, Oliphant, Peterson, et al., 2019), and MatPlotLib (Hunter, 2007) and Pillow are required for visualization support. The visualization functionality includes 2D and 3D plots of the cluster embeddings, image segments, and, in the case of oscillatory networks, graphs of the synchronization processes. The PyClustering library is available on PyPi and from a github repository. Since the first release on PyPi in 2014, it has been downloaded more than 141.000 times. The quality of the library is supported by static and dynamic analyzers, such as cppcheck, scan-build, and valgrind [@Nethercote2007]. More than 93% code coverage is provided by more than 2200 unit and integration tests. Each commit to the repository triggers building, analysis, and testing on CI services such as travis-ci or appveyor. PyClustering provides fully-documented code for each library version, including examples, math and algorithms description, and installation instructions. # Clustering Algorithms Algorithms and methods are located in the Python module `pyclustering.cluster` and in the C++ namespace `ccore::clst`. +---------------------------------------------------------+--------------+--------------+ | Algorithm | Python | C++ | +=========================================================+==============+==============+ | Agglomerative [@book_algorithms_for_clustering_data] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | BANG [@inproceedings_bang_1] | $\checkmark$ | | +---------------------------------------------------------+--------------+--------------+ | BIRCH [@article_birch_1] | $\checkmark$ | | +---------------------------------------------------------+--------------+--------------+ | BSAS [@book_pattern_recognition_2009] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | CLARANS [@article_clarans_1] | $\checkmark$ | | +---------------------------------------------------------+--------------+--------------+ | CLIQUE [@article_clique_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | CURE [@article_cure_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | DBSCAN [@inproceedings_dbscan_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | Elbow [@article_cluster_elbow_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | EMA [@article_ema_1] | $\checkmark$ | | +---------------------------------------------------------+--------------+--------------+ | GA - Genetic Algorithm [@article_ga_2] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | HSyncNet [@artcile_hsyncnet_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | K-Means [@inproceedings_kmeans_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | K-Means++ [@article_kmeans_plus_plus_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | K-Medians [@book_algorithms_for_clustering_data] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | K-Medoids [@book_algorithms_for_clustering_data] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | MBSAS [@book_pattern_recognition_2009] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | OPTICS [@article_optics_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | ROCK [@inproceedings_rock_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | Silhouette [@article_cluster_silhouette_1] | $\checkmark$ | | +---------------------------------------------------------+--------------+--------------+ | SOM-SC [@article_nnet_som_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | SyncNet [@article_syncnet_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | Sync-SOM [@article_syncsom_1] | $\checkmark$ | | +---------------------------------------------------------+--------------+--------------+ | TTSAS [@book_pattern_recognition_2009] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ | X-Means [@article_xmeans_1] | $\checkmark$ | $\checkmark$ | +---------------------------------------------------------+--------------+--------------+ # Oscillatory Networks and Neural Networks Networks are located in the Python module `pyclustering.nnet` and in the C++ namespace `ccore::nnet`. +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | Model | Python | C++ | +=======================================================================================================================+==============+==============+ | CNN - Chaotic Neural Network [@article_nnet_cnn_1] | $\checkmark$ | | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | fSync - Oscillatory network based on Landau-Stuart equation and Kuramoto model [@book_chemical_oscillatorions_waves] | $\checkmark$ | | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | HHN - Oscillatory network based on Hodgkin-Huxley model [@article_nnet_hnn_1] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | Hysteresis Oscillatory Network [@article_nnet_hysteresis_1] | $\checkmark$ | | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | LEGION - Local Excitatory Global Inhibitory Oscillatory Network [@article_legion_1] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | PCNN - Pulse-Coupled Neural Network [@book_image_processing_using_pcnn] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | SOM - Self-Organized Map [@article_nnet_som_1] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | Sync - Oscillatory network based on Kuramoto model [@article_nnet_sync_1] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | SyncPR - Oscillatory network for pattern recognition [@article_nnet_syncpr_1] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ | SyncSegm - Oscillatory network for image segmentation [@inproceedings_nnet_syncsegm_1] | $\checkmark$ | $\checkmark$ | +-----------------------------------------------------------------------------------------------------------------------+--------------+--------------+ # Graph Coloring Algorithms Algorithms are located in the Python module `pyclustering.gcolor`. +----------------------------------------------+--------------+-----+ | Algorithm | Python | C++ | +==============================================+==============+=====+ | DSatur [@article_gcolor_dsatur_1] | $\checkmark$ | | +----------------------------------------------+--------------+-----+ | Hysteresis [@article_nnet_hysteresis_1] | $\checkmark$ | | +----------------------------------------------+--------------+-----+ | GColorSync [@article_gcolor_sync_1] | $\checkmark$ | | +----------------------------------------------+--------------+-----+ # Containers Containers are located in the Python module `pyclustering.container` and in the C++ namespace `ccore::container`. +------------------------------------------+--------------+--------------+ | Container | Python | C++ | +==========================================+==============+==============+ | KD Tree [@book_the_design_and_analysis] | $\checkmark$ | $\checkmark$ | +------------------------------------------+--------------+--------------+ | CF Tree [@article_birch_1] | $\checkmark$ | | +------------------------------------------+--------------+--------------+ # References pyclustering-0.10.1.2/pyclustering/000077500000000000000000000000001375753423500172275ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/__init__.py000077500000000000000000000257071375753423500213560ustar00rootroot00000000000000"""! @brief PyClustering module that consists of general modules related to clustering, graph coloring, containers, oscillatory networks. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause @mainpage PyClustering library @section intro_sec Introduction PyClustering is an open source data mining library written in Python and C++ that provides a wide range of clustering algorithms and methods, including bio-inspired oscillatory networks. PyClustering is mostly focused on cluster analysis to make it more accessible and understandable for users. The library is distributed under the 3-Clause BSD License and provides a comprehensive interface that makes it easy to use in every project. By default, the C++ part of the library is used for processing in order to achieve maximum performance. This is especially relevant for algorithms that are based on oscillatory networks, whose dynamics are governed by a system of differential equations. If support for a C++ compiler is not detected, PyClustering falls back to pure Python implementations of all kernels. PyClustering consists of five general modules. Cluster analysis algorithms and methods (module pyclustering.cluster): - Agglomerative (pyclustering.cluster.agglomerative); - BANG (pyclustering.cluster.bang); - BIRCH (pyclustering.cluster.birch); - BSAS (pyclustering.cluster.bsas); - CLARANS (pyclustering.cluster.clarans); - CLIQUE (pyclustering.cluster.clique); - CURE (pyclustering.cluster.cure); - DBSCAN (pyclustering.cluster.dbscan); - Elbow (pyclustering.cluster.elbow); - EMA (pyclustering.cluster.ema); - Fuzzy C-Means (pyclustering.cluster.fcm); - GA (genetic algorithm pyclustering.cluster.ga); - G-Means (pyclustering.cluster.gmeans); - HSyncNet (bio-inspired algorithm pyclustering.cluster.hsyncnet); - K-Means (pyclustering.cluster.kmeans); - K-Means++ (pyclustering.cluster.center_initializer); - K-Medians (pyclustering.cluster.kmedians); - K-Medoids (PAM) (pyclustering.cluster.kmedoids); - MBSAS (pyclustering.cluster.mbsas); - OPTICS (pyclustering.cluster.optics); - ROCK (pyclustering.cluster.rock); - Silhouette (pyclustering.cluster.silhouette); - SOM-SC (pyclustering.cluster.somsc); - SyncNet (bio-inspired algorithm pyclustering.cluster.syncnet); - SyncSOM (bio-inspired algorithm pyclustering.cluster.syncsom); - TTSAS (pyclustering.cluster.ttsas); - X-Means (pyclustering.cluster.xmeans); Oscillatory and neural network models (module pyclustering.nnet): - Oscillatory network based on Hodgkin-Huxley model (pyclustering.nnet.hhn); - fSync: Oscillatory Network based on Landau-Stuart equation and Kuramoto model (pyclustering.nnet.fsync); - Hysteresis Oscillatory Network (pyclustering.nnet.hysteresis); - LEGION: Local Excitatory Global Inhibitory Oscillatory Network (pyclustering.nnet.legion); - PCNN: Pulse-Coupled Neural Network (pyclustering.nnet.pcnn); - SOM: Self-Organized Map (pyclustering.nnet.som); - Sync: Oscillatory Network based on Kuramoto model (pyclustering.nnet.sync); - SyncPR: Oscillatory Network based on Kuramoto model for pattern recognition (pyclustering.nnet.syncpr); - SyncSegm: Oscillatory Network based on Kuramoto model for image segmentation (pyclustering.nnet.syncsegm); Graph coloring algorithms (module pyclustering.gcolor): - DSATUR (pyclustering.gcolor.dsatur); - Hysteresis Oscillatory Network for graph coloring (pyclustering.gcolor.hysteresis); - Sync: Oscillatory Network based on Kuramoto model for graph coloring (pyclustering.gcolor.sync); Containers (module pyclustering.container): - CF-Tree (pyclustering.container.cftree); - KD-Tree (pyclustering.container.kdtree); Utils (pyclustering.utils) that can be used for analysis, visualization, etc. @section section_install Installation The simplest way to install pyclustering library is to use `pip`: @code{.sh} pip3 install pyclustering @endcode The library can be built and installed manually. pyclustering's python code delegates computations to pyclustering C++ code that is represented by C++ pyclustering library: `pyclustering.dll` in case of Windows and `libpyclustering.so` in case of Linux and MacOS. There are three general ways to build C++ pyclustering: 1. @ref subsection_build_makefile 2. @ref subsection_build_cmake 3. @ref subsection_build_msvc @subsection subsection_build_makefile Build PyClustering Using Makefile 1. Clone pyclustering library from the official repository: @code{.sh} mkdir pyclustering cd pyclustering git clone https://github.com/annoviko/pyclustering.git . @endcode 2. The Makefile is located in `ccore` folder. Navigate to that folder: @code{.sh} cd ccore @endcode 3. The Makefile uses GCC to build pyclustering library. Make sure that your GCC compiler supports C++14. Build pyclustering library for corresponding platform: @code{.sh} make ccore_64bit # build the library for 64-bit operating system. # make ccore_32bit # build the library for 32-bit operating system. @endcode 4. Install pyclustering library: @code{.sh} cd ../ # Return back to pyclustering's root folder when setup.py is located. python3 setup.py install @endcode @subsection subsection_build_cmake Build PyClustering Using CMake 1. Clone pyclustering library from the official repository: @code{.sh} mkdir pyclustering cd pyclustering git clone https://github.com/annoviko/pyclustering.git . @endcode 2. Navigate to C++ pyclustering sources and create build folder: @code{.sh} cd ccore mkdir build @endcode 3. Generate makefiles using CMake: @code{.sh} cmake .. @endcode 4. Build pyclustering library using generated makefile (it automatically detects platform): @code{.sh} make pyclustering @endcode 5. Install pyclustering library: @code{.sh} cd ../ # Return back to pyclustering's root folder when setup.py is located. python3 setup.py install @endcode @subsection subsection_build_msvc Build pyclustering using MSVC 1. Clone pyclustering library from the official repository: @code{.sh} mkdir pyclustering cd pyclustering git clone https://github.com/annoviko/pyclustering.git . @endcode 2. Navigate to `pyclustering/ccore`. 3. Open MSVC project `ccore.sln`. 4. Choose the following `Release` configuration and corresponding platform (`x64` or `x86`). 5. Build `pyclustering-shared` project. @image html pyclustering_build_msvc.png @section section_cite Cite the Library If you are using pyclustering library in a scientific paper, please, cite the library: Novikov, A., 2019. PyClustering: Data Mining Library. Journal of Open Source Software, 4(36), p.1230. Available at: http://dx.doi.org/10.21105/joss.01230. BibTeX entry: @code @article{Novikov2019, doi = {10.21105/joss.01230}, url = {https://doi.org/10.21105/joss.01230}, year = 2019, month = {apr}, publisher = {The Open Journal}, volume = {4}, number = {36}, pages = {1230}, author = {Andrei Novikov}, title = {{PyClustering}: Data Mining Library}, journal = {Journal of Open Source Software} } @endcode @section example_sec Examples This section contains few examples in order to demonstrate the interface of the library. The documentation contains examples for every algorithm/method/model/etc. More examples of a functionality can be found on a corresponding page of the function in this documentation. The library provides intuitive and friendly interface. Here is an example how to perform cluster analysis using BIRCH algorithm: @code{.py} from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.birch import birch from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Load data for cluster analysis - 'Lsun' sample. sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Create BIRCH algorithm to allocate three clusters. birch_instance = birch(sample, 3) # Run cluster analysis. birch_instance.process() # Get allocated clusters. clusters = birch_instance.get_clusters() # Visualize obtained clusters. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode Here is an how to perform cluster analysis using well-known K-Means algorithm: @code{.py} from pyclustering.cluster.kmeans import kmeans, kmeans_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis. sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Prepare initial centers using K-Means++ method. initial_centers = kmeans_plusplus_initializer(sample, 2).initialize() # Create instance of K-Means algorithm with prepared centers. kmeans_instance = kmeans(sample, initial_centers) # Run cluster analysis and obtain results. kmeans_instance.process() clusters = kmeans_instance.get_clusters() final_centers = kmeans_instance.get_centers() # Visualize obtained results kmeans_visualizer.show_clusters(sample, clusters, final_centers) @endcode An example cluster analysis (that is performed by DBSCAN algorithm) for FCPS samples and visualization of results: @image html fcps_cluster_analysis.png An example of Hodgkin-Huxley oscillatory network simulation with 6 oscillators. The first two oscillators have the same stimulus, as well as the third and fourth oscillators and the last two. Thus three synchronous ensembles are expected after simulation. @code{.py} from pyclustering.nnet.hhn import hhn_network, hhn_parameters from pyclustering.nnet.dynamic_visualizer import dynamic_visualizer # Change period of time when high strength value of synaptic connection exists from CN2 to PN. params = hhn_parameters() params.deltah = 400 # Create Hodgkin-Huxley oscillatory network with stimulus. net = hhn_network(6, [0, 0, 25, 25, 47, 47], params) # Simulate network. (t, dyn_peripheral, dyn_central) = net.simulate(2400, 600) # Visualize network's output (membrane potential of peripheral and central neurons). amount_canvases = 6 + 2 # 6 peripheral oscillator + 2 central elements visualizer = dynamic_visualizer(amount_canvases, x_title="Time", y_title="V", y_labels=False) visualizer.append_dynamics(t, dyn_peripheral, 0, True) visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True) visualizer.show() @endcode """ import pathlib ## The current version of pyclustering library. __version__ = '0.10.1.2' ## The current root directory of pyclustering library. __PYCLUSTERING_ROOT_DIRECTORY__ = str(pathlib.Path(__file__).parent) pyclustering-0.10.1.2/pyclustering/cluster/000077500000000000000000000000001375753423500207105ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/cluster/__init__.py000077500000000000000000000740131375753423500230310ustar00rootroot00000000000000"""! @brief pyclustering module for cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import itertools import math import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec from pyclustering.utils.color import color as color_list class canvas_cluster_descr: """! @brief Description of cluster for representation on canvas. """ def __init__(self, cluster, data, marker, markersize, color): """! @brief Constructor of cluster representation on the canvas. @param[in] cluster (list): Single cluster that consists of objects or indexes from data. @param[in] data (list): Objects that should be displayed, can be None if clusters consist of objects instead of indexes. @param[in] marker (string): Type of marker that is used for drawing objects. @param[in] markersize (uint): Size of marker that is used for drawing objects. @param[in] color (string): Color of the marker that is used for drawing objects. """ ## Cluster that may consist of objects or indexes of objects from data. self.cluster = cluster ## Data where objects are stored. It can be None if clusters consist of objects instead of indexes. self.data = data ## Marker that is used for drawing objects. self.marker = marker ## Size of marker that is used for drawing objects. self.markersize = markersize ## Color that is used for coloring marker. self.color = color ## Attribures of the clusters - additional collections of data points that are regarded to the cluster. self.attributes = [] class cluster_visualizer_multidim: """! @brief Visualizer for cluster in multi-dimensional data. @details This cluster visualizer is useful for clusters in data whose dimension is greater than 3. The multidimensional visualizer helps to overcome 'cluster_visualizer' shortcoming - ability to display clusters in 1D, 2D or 3D dimensional data space. Example of clustering results visualization where 'Iris' is used: @code from pyclustering.utils import read_sample from pyclustering.samples.definitions import FAMOUS_SAMPLES from pyclustering.cluster import cluster_visualizer_multidim # load 4D data sample 'Iris' sample_4d = read_sample(FAMOUS_SAMPLES.SAMPLE_IRIS) # initialize 3 initial centers using K-Means++ algorithm centers = kmeans_plusplus_initializer(sample_4d, 3).initialize() # performs cluster analysis using X-Means xmeans_instance = xmeans(sample_4d, centers) xmeans_instance.process() clusters = xmeans_instance.get_clusters() # visualize obtained clusters in multi-dimensional space visualizer = cluster_visualizer_multidim() visualizer.append_clusters(clusters, sample_4d) visualizer.show(max_row_size=3) @endcode Visualized clustering results of 'Iris' data (multi-dimensional data): @image html xmeans_clustering_famous_iris.png "Fig. 1. X-Means clustering results (data 'Iris')." Sometimes no need to display results in all dimensions. Parameter 'filter' can be used to display only interesting coordinate pairs. Here is an example of visualization of pair coordinates (x0, x1) and (x0, x2) for previous clustering results: @code visualizer = cluster_visualizer_multidim() visualizer.append_clusters(clusters, sample_4d) visualizer.show(pair_filter=[[0, 1], [0, 2]]) @endcode Visualized results of specified coordinate pairs: @image html xmeans_clustering_famous_iris_filtered.png "Fig. 2. X-Means clustering results (x0, x1) and (x0, x2) (data 'Iris')." """ def __init__(self): """! @brief Constructs cluster visualizer for multidimensional data. @details The visualizer is suitable more data whose dimension is bigger than 3. """ self.__clusters = [] self.__figure = None self.__grid_spec = None def append_cluster(self, cluster, data = None, marker = '.', markersize = None, color = None): """! @brief Appends cluster for visualization. @param[in] cluster (list): cluster that may consist of indexes of objects from the data or object itself. @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data. @param[in] marker (string): Marker that is used for displaying objects from cluster on the canvas. @param[in] markersize (uint): Size of marker. @param[in] color (string): Color of marker. @return Returns index of cluster descriptor on the canvas. """ if len(cluster) == 0: raise ValueError("Empty cluster is provided.") markersize = markersize or 5 if color is None: index_color = len(self.__clusters) % len(color_list.TITLES) color = color_list.TITLES[index_color] cluster_descriptor = canvas_cluster_descr(cluster, data, marker, markersize, color) self.__clusters.append(cluster_descriptor) def append_clusters(self, clusters, data=None, marker='.', markersize=None): """! @brief Appends list of cluster for visualization. @param[in] clusters (list): List of clusters where each cluster may consist of indexes of objects from the data or object itself. @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data. @param[in] marker (string): Marker that is used for displaying objects from clusters on the canvas. @param[in] markersize (uint): Size of marker. """ for cluster in clusters: self.append_cluster(cluster, data, marker, markersize) def save(self, filename, **kwargs): """! @brief Saves figure to the specified file. @param[in] filename (string): File where the visualized clusters should be stored. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'visible_axis' 'visible_labels', 'visible_grid', 'row_size', 'show'). Keyword Args:
- visible_axis (bool): Defines visibility of axes on each canvas, if True - axes are visible. By default axis of each canvas are not displayed. - visible_labels (bool): Defines visibility of labels on each canvas, if True - labels is displayed. By default labels of each canvas are displayed. - visible_grid (bool): Defines visibility of grid on each canvas, if True - grid is displayed. By default grid of each canvas is displayed. - max_row_size (uint): Maximum number of canvases on one row. """ if len(filename) == 0: raise ValueError("Impossible to save visualization to file: empty file path is specified.") self.show(None, visible_axis=kwargs.get('visible_axis', False), visible_labels=kwargs.get('visible_labels', True), visible_grid=kwargs.get('visible_grid', True), max_row_size=kwargs.get('max_row_size', 4)) plt.savefig(filename) def show(self, pair_filter=None, **kwargs): """! @brief Shows clusters (visualize) in multi-dimensional space. @param[in] pair_filter (list): List of coordinate pairs that should be displayed. This argument is used as a filter. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'visible_axis' 'visible_labels', 'visible_grid', 'row_size', 'show'). Keyword Args:
- visible_axis (bool): Defines visibility of axes on each canvas, if True - axes are visible. By default axis of each canvas are not displayed. - visible_labels (bool): Defines visibility of labels on each canvas, if True - labels is displayed. By default labels of each canvas are displayed. - visible_grid (bool): Defines visibility of grid on each canvas, if True - grid is displayed. By default grid of each canvas is displayed. - max_row_size (uint): Maximum number of canvases on one row. By default the maximum value is 4. - show (bool): If True - then displays visualized clusters. By default is `True`. """ if not len(self.__clusters) > 0: raise ValueError("There is no non-empty clusters for visualization.") cluster_data = self.__clusters[0].data or self.__clusters[0].cluster dimension = len(cluster_data[0]) acceptable_pairs = pair_filter or [] pairs = [] amount_axis = 1 axis_storage = [] if dimension > 1: pairs = self.__create_pairs(dimension, acceptable_pairs) amount_axis = len(pairs) self.__figure = plt.figure() self.__grid_spec = self.__create_grid_spec(amount_axis, kwargs.get('max_row_size', 4)) for index in range(amount_axis): ax = self.__create_canvas(dimension, pairs, index, **kwargs) axis_storage.append(ax) for cluster_descr in self.__clusters: self.__draw_canvas_cluster(axis_storage, cluster_descr, pairs) if kwargs.get('show', True): plt.show() def __create_grid_spec(self, amount_axis, max_row_size): """! @brief Create grid specification for figure to place canvases. @param[in] amount_axis (uint): Amount of canvases that should be organized by the created grid specification. @param[in] max_row_size (max_row_size): Maximum number of canvases on one row. @return (gridspec.GridSpec) Grid specification to place canvases on figure. """ row_size = amount_axis if row_size > max_row_size: row_size = max_row_size col_size = math.ceil(amount_axis / row_size) return gridspec.GridSpec(col_size, row_size) def __create_pairs(self, dimension, acceptable_pairs): """! @brief Create coordinate pairs that should be displayed. @param[in] dimension (uint): Data-space dimension. @param[in] acceptable_pairs (list): List of coordinate pairs that should be displayed. @return (list) List of coordinate pairs that should be displayed. """ if len(acceptable_pairs) > 0: return acceptable_pairs return list(itertools.combinations(range(dimension), 2)) def __create_canvas(self, dimension, pairs, position, **kwargs): """! @brief Create new canvas with user defined parameters to display cluster or chunk of cluster on it. @param[in] dimension (uint): Data-space dimension. @param[in] pairs (list): Pair of coordinates that will be displayed on the canvas. If empty than label will not be displayed on the canvas. @param[in] position (uint): Index position of canvas on a grid. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'visible_axis' 'visible_labels', 'visible_grid'). Keyword Args:
- visible_axis (bool): Defines visibility of axes on each canvas, if True - axes are visible. By default axis are not displayed. - visible_labels (bool): Defines visibility of labels on each canvas, if True - labels is displayed. By default labels are displayed. - visible_grid (bool): Defines visibility of grid on each canvas, if True - grid is displayed. By default grid is displayed. @return (matplotlib.Axis) Canvas to display cluster of chuck of cluster. """ visible_grid = kwargs.get('visible_grid', True) visible_labels = kwargs.get('visible_labels', True) visible_axis = kwargs.get('visible_axis', False) ax = self.__figure.add_subplot(self.__grid_spec[position]) if dimension > 1: if visible_labels: ax.set_xlabel("x%d" % pairs[position][0]) ax.set_ylabel("x%d" % pairs[position][1]) else: ax.set_ylim(-0.5, 0.5) ax.set_yticklabels([]) if visible_grid: ax.grid(True) if not visible_axis: ax.set_yticklabels([]) ax.set_xticklabels([]) return ax def __draw_canvas_cluster(self, axis_storage, cluster_descr, pairs): """! @brief Draw clusters. @param[in] axis_storage (list): List of matplotlib axis where cluster dimensional chunks are displayed. @param[in] cluster_descr (canvas_cluster_descr): Canvas cluster descriptor that should be displayed. @param[in] pairs (list): List of coordinates that should be displayed. """ for index_axis in range(len(axis_storage)): for item in cluster_descr.cluster: if len(pairs) > 0: self.__draw_cluster_item_multi_dimension(axis_storage[index_axis], pairs[index_axis], item, cluster_descr) else: self.__draw_cluster_item_one_dimension(axis_storage[index_axis], item, cluster_descr) def __draw_cluster_item_multi_dimension(self, ax, pair, item, cluster_descr): """! @brief Draw cluster chunk defined by pair coordinates in data space with dimension greater than 1. @param[in] ax (axis): Matplotlib axis that is used to display chunk of cluster point. @param[in] pair (list): Coordinate of the point that should be displayed. @param[in] item (list): Data point or index of data point. @param[in] cluster_descr (canvas_cluster_descr): Cluster description whose point is visualized. """ index_dimension1 = pair[0] index_dimension2 = pair[1] if cluster_descr.data is None: ax.plot(item[index_dimension1], item[index_dimension2], color=cluster_descr.color, marker=cluster_descr.marker, markersize=cluster_descr.markersize) else: ax.plot(cluster_descr.data[item][index_dimension1], cluster_descr.data[item][index_dimension2], color=cluster_descr.color, marker=cluster_descr.marker, markersize=cluster_descr.markersize) def __draw_cluster_item_one_dimension(self, ax, item, cluster_descr): """! @brief Draw cluster point in one dimensional data space.. @param[in] ax (axis): Matplotlib axis that is used to display chunk of cluster point. @param[in] item (list): Data point or index of data point. @param[in] cluster_descr (canvas_cluster_descr): Cluster description whose point is visualized. """ if cluster_descr.data is None: ax.plot(item[0], 0.0, color=cluster_descr.color, marker=cluster_descr.marker, markersize=cluster_descr.markersize) else: ax.plot(cluster_descr.data[item][0], 0.0, color=cluster_descr.color, marker=cluster_descr.marker, markersize=cluster_descr.markersize) class cluster_visualizer: """! @brief Common visualizer of clusters on 1D, 2D or 3D surface. @details Use 'cluster_visualizer_multidim' visualizer in case of data dimension is greater than 3. @see cluster_visualizer_multidim """ def __init__(self, number_canvases=1, size_row=1, titles=None): """! @brief Constructor of cluster visualizer. @param[in] number_canvases (uint): Number of canvases that is used for visualization. @param[in] size_row (uint): Amount of canvases that can be placed in one row. @param[in] titles (list): List of canvas's titles. Example: @code # load 2D data sample sample_2d = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); # load 3D data sample sample_3d = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA); # extract clusters from the first sample using DBSCAN algorithm dbscan_instance = dbscan(sample_2d, 0.4, 2, False); dbscan_instance.process(); clusters_sample_2d = dbscan_instance.get_clusters(); # extract clusters from the second sample using DBSCAN algorithm dbscan_instance = dbscan(sample_3d, 1, 3, True); dbscan_instance.process(); clusters_sample_3d = dbscan_instance.get_clusters(); # create plot with two canvases where each row contains 2 canvases. size = 2; row_size = 2; visualizer = cluster_visualizer(size, row_size); # place clustering result of sample_2d to the first canvas visualizer.append_clusters(clusters_sample_2d, sample_2d, 0, markersize = 5); # place clustering result of sample_3d to the second canvas visualizer.append_clusters(clusters_sample_3d, sample_3d, 1, markersize = 30); # show plot visualizer.show(); @endcode """ self.__number_canvases = number_canvases self.__size_row = size_row self.__canvas_clusters = [ [] for _ in range(number_canvases) ] self.__canvas_dimensions = [ None for _ in range(number_canvases) ] self.__canvas_titles = [ None for _ in range(number_canvases) ] if titles is not None: self.__canvas_titles = titles self.__default_2d_marker_size = 5 self.__default_3d_marker_size = 30 def append_cluster(self, cluster, data=None, canvas=0, marker='.', markersize=None, color=None): """! @brief Appends cluster to canvas for drawing. @param[in] cluster (list): cluster that may consist of indexes of objects from the data or object itself. @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data. @param[in] canvas (uint): Number of canvas that should be used for displaying cluster. @param[in] marker (string): Marker that is used for displaying objects from cluster on the canvas. @param[in] markersize (uint): Size of marker. @param[in] color (string): Color of marker. @return Returns index of cluster descriptor on the canvas. """ if len(cluster) == 0: return if canvas > self.__number_canvases or canvas < 0: raise ValueError("Canvas index '%d' is out of range [0; %d]." % self.__number_canvases or canvas) if color is None: index_color = len(self.__canvas_clusters[canvas]) % len(color_list.TITLES) color = color_list.TITLES[index_color] added_canvas_descriptor = canvas_cluster_descr(cluster, data, marker, markersize, color) self.__canvas_clusters[canvas].append(added_canvas_descriptor) if data is None: dimension = len(cluster[0]) if self.__canvas_dimensions[canvas] is None: self.__canvas_dimensions[canvas] = dimension elif self.__canvas_dimensions[canvas] != dimension: raise ValueError("Only clusters with the same dimension of objects can be displayed on canvas.") else: dimension = len(data[0]) if self.__canvas_dimensions[canvas] is None: self.__canvas_dimensions[canvas] = dimension elif self.__canvas_dimensions[canvas] != dimension: raise ValueError("Only clusters with the same dimension of objects can be displayed on canvas.") if (dimension < 1) or (dimension > 3): raise ValueError("Only objects with size dimension 1 (1D plot), 2 (2D plot) or 3 (3D plot) " "can be displayed. For multi-dimensional data use 'cluster_visualizer_multidim'.") if markersize is None: if (dimension == 1) or (dimension == 2): added_canvas_descriptor.markersize = self.__default_2d_marker_size elif dimension == 3: added_canvas_descriptor.markersize = self.__default_3d_marker_size return len(self.__canvas_clusters[canvas]) - 1 def append_cluster_attribute(self, index_canvas, index_cluster, data, marker = None, markersize = None): """! @brief Append cluster attribure for cluster on specific canvas. @details Attribute it is data that is visualized for specific cluster using its color, marker and markersize if last two is not specified. @param[in] index_canvas (uint): Index canvas where cluster is located. @param[in] index_cluster (uint): Index cluster whose attribute should be added. @param[in] data (list): List of points (data) that represents attribute. @param[in] marker (string): Marker that is used for displaying objects from cluster on the canvas. @param[in] markersize (uint): Size of marker. """ cluster_descr = self.__canvas_clusters[index_canvas][index_cluster] attribute_marker = marker if attribute_marker is None: attribute_marker = cluster_descr.marker attribure_markersize = markersize if attribure_markersize is None: attribure_markersize = cluster_descr.markersize attribute_color = cluster_descr.color added_attribute_cluster_descriptor = canvas_cluster_descr(data, None, attribute_marker, attribure_markersize, attribute_color) self.__canvas_clusters[index_canvas][index_cluster].attributes.append(added_attribute_cluster_descriptor) def append_clusters(self, clusters, data=None, canvas=0, marker='.', markersize=None): """! @brief Appends list of cluster to canvas for drawing. @param[in] clusters (list): List of clusters where each cluster may consist of indexes of objects from the data or object itself. @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data. @param[in] canvas (uint): Number of canvas that should be used for displaying clusters. @param[in] marker (string): Marker that is used for displaying objects from clusters on the canvas. @param[in] markersize (uint): Size of marker. """ for cluster in clusters: self.append_cluster(cluster, data, canvas, marker, markersize) def set_canvas_title(self, text, canvas = 0): """! @brief Set title for specified canvas. @param[in] text (string): Title for the canvas. @param[in] canvas (uint): Index of the canvas where title should be displayed. """ if canvas > self.__number_canvases: raise ValueError("Canvas with index '%d' does not exists (total amount of canvases: '%d')." % canvas, self.__number_canvases) self.__canvas_titles[canvas] = text def get_cluster_color(self, index_cluster, index_canvas): """! @brief Returns cluster color on specified canvas. """ return self.__canvas_clusters[index_canvas][index_cluster].color def save(self, filename, **kwargs): """! @brief Saves figure to the specified file. @param[in] filename (string): File where the visualized clusters should be stored. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'invisible_axis', 'visible_grid'). Keyword Args:
- invisible_axis (bool): Defines visibility of axes on each canvas, if `True` - axes are invisible. By default axis are invisible. - visible_grid (bool): Defines visibility of grid on each canvas, if `True` - grid is displayed. By default grid of each canvas is displayed. There is an example how to save visualized clusters to the PNG file without showing them on a screen: @code from pyclustering.cluster import cluster_visualizer data = [[1.1], [1.7], [3.7], [5.3], [2.5], [-1.5], [-0.9], [6.3], [6.5], [8.1]] clusters = [[0, 1, 2, 4, 5, 6], [3, 7, 8, 9]] visualizer = cluster_visualizer() visualizer.append_clusters(clusters, data) visualizer.save("1-dimensional-clustering.png") @endcode """ if len(filename) == 0: raise ValueError("Impossible to save visualization to file: empty file path is specified.") invisible_axis = kwargs.get('invisible_axis', True) visible_grid = kwargs.get('visible_grid', True) self.show(None, invisible_axis, visible_grid, False) plt.savefig(filename) def show(self, figure=None, invisible_axis=True, visible_grid=True, display=True, shift=None): """! @brief Shows clusters (visualize). @param[in] figure (fig): Defines requirement to use specified figure, if None - new figure is created for drawing clusters. @param[in] invisible_axis (bool): Defines visibility of axes on each canvas, if True - axes are invisible. @param[in] visible_grid (bool): Defines visibility of grid on each canvas, if True - grid is displayed. @param[in] display (bool): Defines requirement to display clusters on a stage, if True - clusters are displayed, if False - plt.show() should be called by user." @param[in] shift (uint): Force canvas shift value - defines canvas index from which custers should be visualized. @return (fig) Figure where clusters are shown. """ canvas_shift = shift if canvas_shift is None: if figure is not None: canvas_shift = len(figure.get_axes()) else: canvas_shift = 0 if figure is not None: cluster_figure = figure else: cluster_figure = plt.figure() maximum_cols = self.__size_row maximum_rows = math.ceil( (self.__number_canvases + canvas_shift) / maximum_cols) grid_spec = gridspec.GridSpec(maximum_rows, maximum_cols) for index_canvas in range(len(self.__canvas_clusters)): canvas_data = self.__canvas_clusters[index_canvas] if len(canvas_data) == 0: continue dimension = self.__canvas_dimensions[index_canvas] #ax = axes[real_index]; if (dimension == 1) or (dimension == 2): ax = cluster_figure.add_subplot(grid_spec[index_canvas + canvas_shift]) else: ax = cluster_figure.add_subplot(grid_spec[index_canvas + canvas_shift], projection='3d') if len(canvas_data) == 0: plt.setp(ax, visible=False) for cluster_descr in canvas_data: self.__draw_canvas_cluster(ax, dimension, cluster_descr) for attribute_descr in cluster_descr.attributes: self.__draw_canvas_cluster(ax, dimension, attribute_descr) if invisible_axis is True: ax.xaxis.set_ticklabels([]) ax.yaxis.set_ticklabels([]) if dimension == 3: ax.zaxis.set_ticklabels([]) if self.__canvas_titles[index_canvas] is not None: ax.set_title(self.__canvas_titles[index_canvas]) ax.grid(visible_grid) if display is True: plt.show() return cluster_figure def __draw_canvas_cluster(self, ax, dimension, cluster_descr): """! @brief Draw canvas cluster descriptor. @param[in] ax (Axis): Axis of the canvas where canvas cluster descriptor should be displayed. @param[in] dimension (uint): Canvas dimension. @param[in] cluster_descr (canvas_cluster_descr): Canvas cluster descriptor that should be displayed. @return (fig) Figure where clusters are shown. """ cluster = cluster_descr.cluster data = cluster_descr.data marker = cluster_descr.marker markersize = cluster_descr.markersize color = cluster_descr.color for item in cluster: if dimension == 1: if data is None: ax.plot(item[0], 0.0, color = color, marker = marker, markersize = markersize) else: ax.plot(data[item][0], 0.0, color = color, marker = marker, markersize = markersize) elif dimension == 2: if data is None: ax.plot(item[0], item[1], color = color, marker = marker, markersize = markersize) else: ax.plot(data[item][0], data[item][1], color = color, marker = marker, markersize = markersize) elif dimension == 3: if data is None: ax.scatter(item[0], item[1], item[2], c = color, marker = marker, s = markersize) else: ax.scatter(data[item][0], data[item][1], data[item][2], c = color, marker = marker, s = markersize)pyclustering-0.10.1.2/pyclustering/cluster/agglomerative.py000077500000000000000000000334441375753423500241230ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: agglomerative algorithm. @details Implementation based on paper @cite book::algorithms_for_clustering_data. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from enum import IntEnum from pyclustering.cluster.encoder import type_encoding from pyclustering.utils import euclidean_distance_square from pyclustering.core.wrapper import ccore_library import pyclustering.core.agglomerative_wrapper as wrapper class type_link(IntEnum): """! @brief Enumerator of types of link between clusters. """ ## Distance between the two nearest objects in clusters is considered as a link, so-called SLINK method (the single-link clustering method). SINGLE_LINK = 0 ## Distance between the farthest objects in clusters is considered as a link, so-called CLINK method (the complete-link clustering method). COMPLETE_LINK = 1 ## Average distance between objects in clusters is considered as a link. AVERAGE_LINK = 2 ## Distance between centers of clusters is considered as a link. CENTROID_LINK = 3 class agglomerative: """! @brief Class represents agglomerative algorithm for cluster analysis. @details Agglomerative algorithm considers each data point (object) as a separate cluster at the beginning and step by step finds the best pair of clusters for merge until required amount of clusters is obtained. Example of agglomerative algorithm where centroid link is used: @code from pyclustering.cluster.agglomerative import agglomerative, type_link from pyclustering.cluster import cluster_visualizer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Sample for cluster analysis (represented by list) sample = read_sample(FCPS_SAMPLES.SAMPLE_TARGET) # Create object that uses python code only agglomerative_instance = agglomerative(sample, 6, type_link.SINGLE_LINK, ccore=True) # Cluster analysis agglomerative_instance.process() # Obtain results of clustering clusters = agglomerative_instance.get_clusters() # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode There is example of clustering 'LSUN' sample: @code from pyclustering.cluster.agglomerative import agglomerative, type_link from pyclustering.cluster import cluster_visualizer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # sample Lsun for cluster analysis lsun_sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # create instance of the algorithm that will use ccore library (the last argument) agglomerative_instance = agglomerative(lsun_sample, 3, type_link.SINGLE_LINK, True) # start processing agglomerative_instance.process() # get result and visualize it lsun_clusters = agglomerative_instance.get_clusters() visualizer = cluster_visualizer() visualizer.append_clusters(lsun_clusters, lsun_sample) visualizer.show() @endcode Example of agglomerative clustering using different links: @image html agglomerative_lsun_clustering_single_link.png """ def __init__(self, data, number_clusters, link = None, ccore = True): """! @brief Constructor of agglomerative hierarchical algorithm. @param[in] data (list): Input data that is presented as a list of points (objects), each point should be represented by list, for example [[0.1, 0.2], [0.4, 0.5], [1.3, 0.9]]. @param[in] number_clusters (uint): Number of clusters that should be allocated. @param[in] link (type_link): Link type that is used for calculation similarity between objects and clusters, if it is not specified centroid link will be used by default. @param[in] ccore (bool): Defines should be CCORE (C++ pyclustering library) used instead of Python code or not (by default it is 'False'). """ self.__pointer_data = data self.__number_clusters = number_clusters self.__similarity = link self.__verify_arguments() if self.__similarity is None: self.__similarity = type_link.CENTROID_LINK self.__clusters = [] self.__ccore = ccore if self.__ccore: self.__ccore = ccore_library.workable() if self.__similarity == type_link.CENTROID_LINK: self.__centers = self.__pointer_data.copy() # used in case of usage of centroid links def process(self): """! @brief Performs cluster analysis in line with rules of agglomerative algorithm and similarity. @return (agglomerative) Returns itself (Agglomerative instance). @see get_clusters() """ if self.__ccore is True: self.__clusters = wrapper.agglomerative_algorithm(self.__pointer_data, self.__number_clusters, self.__similarity) else: self.__clusters = [[index] for index in range(0, len(self.__pointer_data))] current_number_clusters = len(self.__clusters) while current_number_clusters > self.__number_clusters: self.__merge_similar_clusters() current_number_clusters = len(self.__clusters) return self def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @remark Results of clustering can be obtained using corresponding gets methods. @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data. @see process() """ return self.__clusters def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __merge_similar_clusters(self): """! @brief Merges the most similar clusters in line with link type. """ if self.__similarity == type_link.AVERAGE_LINK: self.__merge_by_average_link() elif self.__similarity == type_link.CENTROID_LINK: self.__merge_by_centroid_link() elif self.__similarity == type_link.COMPLETE_LINK: self.__merge_by_complete_link() elif self.__similarity == type_link.SINGLE_LINK: self.__merge_by_signle_link() else: raise NameError('Not supported similarity is used') def __merge_by_average_link(self): """! @brief Merges the most similar clusters in line with average link type. """ minimum_average_distance = float('Inf') for index_cluster1 in range(0, len(self.__clusters)): for index_cluster2 in range(index_cluster1 + 1, len(self.__clusters)): # Find farthest objects candidate_average_distance = 0.0 for index_object1 in self.__clusters[index_cluster1]: for index_object2 in self.__clusters[index_cluster2]: candidate_average_distance += euclidean_distance_square(self.__pointer_data[index_object1], self.__pointer_data[index_object2]) candidate_average_distance /= (len(self.__clusters[index_cluster1]) + len(self.__clusters[index_cluster2])) if candidate_average_distance < minimum_average_distance: minimum_average_distance = candidate_average_distance indexes = [index_cluster1, index_cluster2] self.__clusters[indexes[0]] += self.__clusters[indexes[1]] self.__clusters.pop(indexes[1]) # remove merged cluster. def __merge_by_centroid_link(self): """! @brief Merges the most similar clusters in line with centroid link type. """ minimum_centroid_distance = float('Inf') indexes = None for index1 in range(0, len(self.__centers)): for index2 in range(index1 + 1, len(self.__centers)): distance = euclidean_distance_square(self.__centers[index1], self.__centers[index2]) if distance < minimum_centroid_distance: minimum_centroid_distance = distance indexes = [index1, index2] self.__clusters[indexes[0]] += self.__clusters[indexes[1]] self.__centers[indexes[0]] = self.__calculate_center(self.__clusters[indexes[0]]) self.__clusters.pop(indexes[1]) # remove merged cluster. self.__centers.pop(indexes[1]) # remove merged center. def __merge_by_complete_link(self): """! @brief Merges the most similar clusters in line with complete link type. """ minimum_complete_distance = float('Inf') indexes = None for index_cluster1 in range(0, len(self.__clusters)): for index_cluster2 in range(index_cluster1 + 1, len(self.__clusters)): candidate_maximum_distance = self.__calculate_farthest_distance(index_cluster1, index_cluster2) if candidate_maximum_distance < minimum_complete_distance: minimum_complete_distance = candidate_maximum_distance indexes = [index_cluster1, index_cluster2] self.__clusters[indexes[0]] += self.__clusters[indexes[1]] self.__clusters.pop(indexes[1]) # remove merged cluster. def __calculate_farthest_distance(self, index_cluster1, index_cluster2): """! @brief Finds two farthest objects in two specified clusters in terms and returns distance between them. @param[in] (uint) Index of the first cluster. @param[in] (uint) Index of the second cluster. @return The farthest euclidean distance between two clusters. """ candidate_maximum_distance = 0.0 for index_object1 in self.__clusters[index_cluster1]: for index_object2 in self.__clusters[index_cluster2]: distance = euclidean_distance_square(self.__pointer_data[index_object1], self.__pointer_data[index_object2]) if distance > candidate_maximum_distance: candidate_maximum_distance = distance return candidate_maximum_distance def __merge_by_signle_link(self): """! @brief Merges the most similar clusters in line with single link type. """ minimum_single_distance = float('Inf') indexes = None for index_cluster1 in range(0, len(self.__clusters)): for index_cluster2 in range(index_cluster1 + 1, len(self.__clusters)): candidate_minimum_distance = self.__calculate_nearest_distance(index_cluster1, index_cluster2) if candidate_minimum_distance < minimum_single_distance: minimum_single_distance = candidate_minimum_distance indexes = [index_cluster1, index_cluster2] self.__clusters[indexes[0]] += self.__clusters[indexes[1]] self.__clusters.pop(indexes[1]) # remove merged cluster. def __calculate_nearest_distance(self, index_cluster1, index_cluster2): """! @brief Finds two nearest objects in two specified clusters and returns distance between them. @param[in] (uint) Index of the first cluster. @param[in] (uint) Index of the second cluster. @return The nearest euclidean distance between two clusters. """ candidate_minimum_distance = float('Inf') for index_object1 in self.__clusters[index_cluster1]: for index_object2 in self.__clusters[index_cluster2]: distance = euclidean_distance_square(self.__pointer_data[index_object1], self.__pointer_data[index_object2]) if distance < candidate_minimum_distance: candidate_minimum_distance = distance return candidate_minimum_distance def __calculate_center(self, cluster): """! @brief Calculates new center. @return (list) New value of the center of the specified cluster. """ dimension = len(self.__pointer_data[cluster[0]]) center = [0] * dimension for index_point in cluster: for index_dimension in range(0, dimension): center[index_dimension] += self.__pointer_data[index_point][index_dimension] for index_dimension in range(0, dimension): center[index_dimension] /= len(cluster) return center def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if self.__number_clusters <= 0: raise ValueError("Amount of cluster (current value: '%d') for allocation should be greater than 0." % self.__number_clusters) pyclustering-0.10.1.2/pyclustering/cluster/bang.py000077500000000000000000001267041375753423500222060ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: BANG. @details Implementation based on paper @cite inproceedings::bang::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import itertools import warnings import matplotlib import matplotlib.gridspec as gridspec import matplotlib.pyplot as plt import matplotlib.patches as patches import matplotlib.animation as animation from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.encoder import type_encoding from pyclustering.utils import data_corners from pyclustering.utils.color import color as color_list class bang_visualizer: """! @brief Visualizer of BANG algorithm's results. @details BANG visualizer provides visualization services that are specific for BANG algorithm. """ __maximum_density_alpha = 0.6 @staticmethod def show_blocks(directory): """! @brief Show BANG-blocks (leafs only) in data space. @details BANG-blocks represents grid that was used for clustering process. @param[in] directory (bang_directory): Directory that was created by BANG algorithm during clustering process. """ dimension = len(directory.get_data()[0]) amount_canvases = 1 if dimension > 1: amount_canvases = int(dimension * (dimension - 1) / 2) figure = plt.figure() grid_spec = gridspec.GridSpec(1, amount_canvases) pairs = list(itertools.combinations(range(dimension), 2)) if len(pairs) == 0: pairs = [(0, 0)] for index in range(amount_canvases): ax = figure.add_subplot(grid_spec[index]) bang_visualizer.__draw_blocks(ax, directory.get_leafs(), pairs[index]) bang_visualizer.__draw_two_dimension_data(ax, directory.get_data(), pairs[index]) plt.show() @staticmethod def show_dendrogram(dendrogram): """! @brief Display dendrogram of BANG-blocks. @param[in] dendrogram (list): List representation of dendrogram of BANG-blocks. @see bang.get_dendrogram() """ plt.figure() axis = plt.subplot(1, 1, 1) current_position = 0 for index_cluster in range(len(dendrogram)): densities = [ block.get_density() for block in dendrogram[index_cluster] ] xrange = range(current_position, current_position + len(densities)) axis.bar(xrange, densities, 1.0, linewidth=0.0, color=color_list.get_color(index_cluster)) current_position += len(densities) axis.set_ylabel("density") axis.set_xlabel("block") axis.xaxis.set_ticklabels([]) plt.xlim([-0.5, current_position - 0.5]) plt.show() @staticmethod def show_clusters(data, clusters, noise=None): """! @brief Display BANG clustering results. @param[in] data (list): Dataset that was used for clustering. @param[in] clusters (array_like): Clusters that were allocated by the algorithm. @param[in] noise (array_like): Noise that were allocated by the algorithm. """ visualizer = cluster_visualizer() visualizer.append_clusters(clusters, data) visualizer.append_cluster(noise or [], data, marker='x') visualizer.show() @staticmethod def __draw_two_dimension_data(ax, data, pair): """! @brief Display data in two-dimensional canvas. @param[in] ax (Axis): Canvas where data should be displayed. @param[in] data (list): Data points that should be displayed. @param[in] pair (tuple): Pair of dimension indexes. """ ax.set_xlabel("x%d" % pair[0]) ax.set_ylabel("x%d" % pair[1]) for point in data: if len(data[0]) > 1: ax.plot(point[pair[0]], point[pair[1]], color='red', marker='.') else: ax.plot(point[pair[0]], 0, color='red', marker='.') ax.yaxis.set_ticklabels([]) @staticmethod def __draw_blocks(ax, blocks, pair): """! @brief Display BANG-blocks on specified figure. @param[in] ax (Axis): Axis where bang-blocks should be displayed. @param[in] blocks (list): List of blocks that should be displyed. @param[in] pair (tuple): Pair of coordinate index that should be displayed. """ ax.grid(False) density_scale = blocks[-1].get_density() for block in blocks: bang_visualizer.__draw_block(ax, pair, block, density_scale) @staticmethod def __draw_block(ax, pair, block, density_scale): """! @brief Display BANG-block on the specified ax. @param[in] ax (Axis): Axis where block should be displayed. @param[in] pair (tuple): Pair of coordinate index that should be displayed. @param[in] block (bang_block): BANG-block that should be displayed. @param[in] density_scale (double): Max density to display density of the block by appropriate tone. """ max_corner, min_corner = bang_visualizer.__get_rectangle_description(block, pair) belong_cluster = block.get_cluster() is not None if density_scale != 0.0: density_scale = bang_visualizer.__maximum_density_alpha * block.get_density() / density_scale face_color = matplotlib.colors.to_rgba('blue', alpha=density_scale) edge_color = matplotlib.colors.to_rgba('black', alpha=1.0) rect = patches.Rectangle(min_corner, max_corner[0] - min_corner[0], max_corner[1] - min_corner[1], fill=belong_cluster, facecolor=face_color, edgecolor=edge_color, linewidth=0.5) ax.add_patch(rect) @staticmethod def __get_rectangle_description(block, pair): """! @brief Create rectangle description for block in specific dimension. @param[in] pair (tuple): Pair of coordinate index that should be displayed. @param[in] block (bang_block): BANG-block that should be displayed @return (tuple) Pair of corners that describes rectangle. """ max_corner, min_corner = block.get_spatial_block().get_corners() max_corner = [max_corner[pair[0]], max_corner[pair[1]]] min_corner = [min_corner[pair[0]], min_corner[pair[1]]] if pair == (0, 0): max_corner[1], min_corner[1] = 1.0, -1.0 return max_corner, min_corner class bang_animator: """! @brief Provides service for creating 2-D animation using BANG clustering results. @details The animator does not support visualization of clustering process where non 2-dimensional was used. Code example of animation of BANG clustering process: @code from pyclustering.cluster.bang import bang, bang_animator from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Read data two dimensional data. data = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Create instance of BANG algorithm. bang_instance = bang(data, 9) bang_instance.process() # Obtain clustering results. clusters = bang_instance.get_clusters() noise = bang_instance.get_noise() directory = bang_instance.get_directory() # Create BANG animation using class 'bang_animator': animator = bang_animator(directory, clusters) animator.animate() @endcode """ def __init__(self, directory, clusters): """! @brief Creates BANG animator instance. @param[in] directory (bang_directory): BANG directory that was formed during BANG clustering process. @param[in] clusters (list): Allocated clusters during BANG clustering process. """ self.__directory = directory self.__clusters = clusters self.__noise = [] self.__current_block = 0 self.__current_level = 0 self.__level_blocks = directory.get_level(0) self.__figure = plt.figure() self.__ax = self.__figure.add_subplot(1, 1, 1) self.__special_frame = 0 self.__validate_arguments() def __validate_arguments(self): """! @brief Check correctness of input arguments and throw exception if incorrect is found. """ if len(self.__directory.get_data()[0]) != 2: raise ValueError("Impossible to animate BANG clustering process for non 2D data.") def __increment_block(self): """! @brief Increment BANG block safely by updating block index, level and level block. """ self.__current_block += 1 if self.__current_block >= len(self.__level_blocks): self.__current_block = 0 self.__current_level += 1 if self.__current_level < self.__directory.get_height(): self.__level_blocks = self.__directory.get_level(self.__current_level) def __draw_block(self, block, block_alpha=0.0): """! @brief Display single BANG block on axis. @param[in] block (bang_block): BANG block that should be displayed. @param[in] block_alpha (double): Transparency level - value of alpha. """ max_corner, min_corner = block.get_spatial_block().get_corners() face_color = matplotlib.colors.to_rgba('blue', alpha=block_alpha) edge_color = matplotlib.colors.to_rgba('black', alpha=1.0) rect = patches.Rectangle(min_corner, max_corner[0] - min_corner[0], max_corner[1] - min_corner[1], fill=True, facecolor=face_color, edgecolor=edge_color, linewidth=0.5) self.__ax.add_patch(rect) def __draw_leaf_density(self): """! @brief Display densities by filling blocks by appropriate colors. """ leafs = self.__directory.get_leafs() density_scale = leafs[-1].get_density() if density_scale == 0.0: density_scale = 1.0 for block in leafs: alpha = 0.8 * block.get_density() / density_scale self.__draw_block(block, alpha) def __draw_clusters(self): """! @brief Display clusters and outliers using different colors. """ data = self.__directory.get_data() for index_cluster in range(len(self.__clusters)): color = color_list.get_color(index_cluster) self.__draw_cluster(data, self.__clusters[index_cluster], color, '.') self.__draw_cluster(self.__directory.get_data(), self.__noise, 'gray', 'x') def __draw_cluster(self, data, cluster, color, marker): """! @brief Draw 2-D single cluster on axis using specified color and marker. """ for item in cluster: self.__ax.plot(data[item][0], data[item][1], color=color, marker=marker) def animate(self, animation_velocity=75, movie_fps=25, movie_filename=None): """! @brief Animates clustering process that is performed by BANG algorithm. @param[in] animation_velocity (uint): Interval between frames in milliseconds (for run-time animation only). @param[in] movie_fps (uint): Defines frames per second (for rendering movie only). @param[in] movie_filename (string): If it is specified then animation will be stored to file that is specified in this parameter. """ def init_frame(): self.__figure.clf() self.__ax = self.__figure.add_subplot(1, 1, 1) self.__figure.suptitle("BANG algorithm", fontsize=18, fontweight='bold') for point in self.__directory.get_data(): self.__ax.plot(point[0], point[1], color='red', marker='.') return frame_generation(0) def frame_generation(index_iteration): if self.__current_level < self.__directory.get_height(): block = self.__level_blocks[self.__current_block] self.__draw_block(block) self.__increment_block() else: if self.__special_frame == 0: self.__draw_leaf_density() elif self.__special_frame == 15: self.__draw_clusters() elif self.__special_frame == 30: self.__figure.clf() self.__ax = self.__figure.add_subplot(1, 1, 1) self.__figure.suptitle("BANG algorithm", fontsize=18, fontweight='bold') self.__draw_clusters() self.__special_frame += 1 iterations = len(self.__directory) + 60 # print("Total number of iterations: %d" % iterations) cluster_animation = animation.FuncAnimation(self.__figure, frame_generation, iterations, interval=animation_velocity, init_func=init_frame, repeat_delay=5000) if movie_filename is not None: cluster_animation.save(movie_filename, writer = 'ffmpeg', fps = movie_fps, bitrate = 3500) else: plt.show() class bang_directory: """! @brief BANG directory stores BANG-blocks that represents grid in data space. @details The directory build BANG-blocks in binary tree manner. Leafs of the tree stored separately to provide a direct access to the leafs that should be analysed. Leafs cache data-points. """ def __init__(self, data, levels, **kwargs): """! @brief Create BANG directory - basically tree structure with direct access to leafs. @param[in] data (list): Input data that is clustered. @param[in] levels (uint): Height of the tree of blocks. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'observe'). Keyword Args:
- observe (bool): If 'True' then blocks on each level are stored. - density_threshold (double): The lowest level of density when contained data in bang-block is considered as a noise and there is no need to split it till the last level. Be aware that this parameter is used with 'amount_threshold' parameter. - amount_threshold (uint): Amount of points in the block when it contained data in bang-block is considered as a noise and there is no need to split it till the last level. """ self.__data = data self.__levels = levels self.__density_threshold = kwargs.get('density_threshold', 0.0) self.__amount_density = kwargs.get('amount_threshold', 0) self.__leafs = [] self.__root = None self.__level_blocks = [] self.__size = 0 self.__observe = kwargs.get('observe', True) self.__create_directory() def __len__(self): """! @brief Returns amount of blocks that is stored in the directory @return (uint) Amount of blocks in the BANG directory. """ return self.__size def get_data(self): """! @brief Return data that is stored in the directory. @return (list) List of points that represents stored data. """ return self.__data def get_leafs(self): """! @brief Return leafs - the smallest blocks. @details Some leafs can be bigger than others because splitting is not performed for blocks whose density is less than threshold. @return (list) List of blocks that are leafs of BANG directory. """ return self.__leafs def get_level(self, level): """! @brief Returns BANG blocks on the specific level. @param[in] level (uint): Level of tree where BANG blocks are located. @return (list) List of BANG blocks on the specific level. """ return self.__level_blocks[level] def get_height(self): """! @brief Returns height of BANG tree where blocks are stored. @return (uint) Height of BANG tree. """ return len(self.__level_blocks) def __create_directory(self): """! @brief Create BANG directory as a tree with separate storage for leafs. """ min_corner, max_corner = data_corners(self.__data) data_block = spatial_block(max_corner, min_corner) cache_require = (self.__levels == 1) self.__root = bang_block(self.__data, 0, 0, data_block, cache_require) if cache_require: self.__leafs.append(self.__root) self.__store_level_blocks([self.__root]) else: self.__build_directory_levels() def __store_level_blocks(self, level_blocks): """! @brief Store level blocks if observing is enabled. @param[in] level_blocks (list): Created blocks on a new level. """ self.__size += len(level_blocks) if self.__observe is True: self.__level_blocks.append(level_blocks) def __build_directory_levels(self): """! @brief Build levels of direction if amount of level is greater than one. """ previous_level_blocks = [ self.__root ] for level in range(1, self.__levels): previous_level_blocks = self.__build_level(previous_level_blocks, level) self.__store_level_blocks(previous_level_blocks) self.__leafs = sorted(self.__leafs, key=lambda block: block.get_density()) def __build_level(self, previous_level_blocks, level): """! @brief Build new level of directory. @param[in] previous_level_blocks (list): BANG-blocks on the previous level. @param[in] level (uint): Level number that should be built. @return (list) New block on the specified level. """ current_level_blocks = [] split_dimension = level % len(self.__data[0]) cache_require = (level == self.__levels - 1) for block in previous_level_blocks: self.__split_block(block, split_dimension, cache_require, current_level_blocks) if cache_require: self.__leafs += current_level_blocks return current_level_blocks def __split_block(self, block, split_dimension, cache_require, current_level_blocks): """! @brief Split specific block in specified dimension. @details Split is not performed for block whose density is lower than threshold value, such blocks are putted to leafs. @param[in] block (bang_block): BANG-block that should be split. @param[in] split_dimension (uint): Dimension at which splitting should be performed. @param[in] cache_require (bool): Defines when points in cache should be stored during density calculation. @param[in|out] current_level_blocks (list): Block storage at the current level where new blocks should be added. """ if block.get_density() <= self.__density_threshold or len(block) <= self.__amount_density: self.__leafs.append(block) else: left, right = block.split(split_dimension, cache_require) current_level_blocks.append(left) current_level_blocks.append(right) class spatial_block: """! @brief Geometrical description of BANG block in data space. @details Provides services related to spatial functionality and used by bang_block @see bang_block """ def __init__(self, max_corner, min_corner): """! @brief Creates spatial block in data space. @param[in] max_corner (array_like): Maximum corner coordinates of the block. @param[in] min_corner (array_like): Minimal corner coordinates of the block. """ self.__max_corner = max_corner self.__min_corner = min_corner self.__volume = self.__calculate_volume() def __str__(self): """! @brief Returns string block description. @return String representation of the block. """ return "(max: %s; min: %s)" % (self.__max_corner, self.__min_corner) def __contains__(self, point): """! @brief Point is considered as contained if it lies in block (belong to it). @return (bool) True if point is in block, otherwise False. """ for i in range(len(point)): if point[i] < self.__min_corner[i] or point[i] > self.__max_corner[i]: return False return True def get_corners(self): """! @brief Return spatial description of current block. @return (tuple) Pair of maximum and minimum corners (max_corner, min_corner). """ return self.__max_corner, self.__min_corner def get_volume(self): """! @brief Returns volume of current block. @details Volume block has uncommon mining here: for 1D is length of a line, for 2D is square of rectangle, for 3D is volume of 3D figure, and for ND is volume of ND figure. @return (double) Volume of current block. """ return self.__volume def split(self, dimension): """! @brief Split current block into two spatial blocks in specified dimension. @param[in] dimension (uint): Dimension where current block should be split. @return (tuple) Pair of new split blocks from current block. """ first_max_corner = self.__max_corner[:] second_min_corner = self.__min_corner[:] split_border = (self.__max_corner[dimension] + self.__min_corner[dimension]) / 2.0 first_max_corner[dimension] = split_border second_min_corner[dimension] = split_border return spatial_block(first_max_corner, self.__min_corner), spatial_block(self.__max_corner, second_min_corner) def is_neighbor(self, block): """! @brief Performs calculation to identify whether specified block is neighbor of current block. @details It also considers diagonal blocks as neighbors. @param[in] block (spatial_block): Another block that is check whether it is neighbor. @return (bool) True is blocks are neighbors, False otherwise. """ if block is not self: block_max_corner, _ = block.get_corners() dimension = len(block_max_corner) neighborhood_score = self.__calculate_neighborhood(block_max_corner) if neighborhood_score == dimension: return True return False def __calculate_neighborhood(self, block_max_corner): """! @brief Calculates neighborhood score that defined whether blocks are neighbors. @param[in] block_max_corner (list): Maximum coordinates of other block. @return (uint) Neighborhood score. """ dimension = len(block_max_corner) length_edges = [self.__max_corner[i] - self.__min_corner[i] for i in range(dimension)] neighborhood_score = 0 for i in range(dimension): diff = abs(block_max_corner[i] - self.__max_corner[i]) if diff <= length_edges[i] + length_edges[i] * 0.0001: neighborhood_score += 1 return neighborhood_score def __calculate_volume(self): """! @brief Calculates volume of current spatial block. @details If empty dimension is detected (where all points has the same value) then such dimension is ignored during calculation of volume. @return (double) Volume of current spatial block. """ volume = 0.0 for i in range(0, len(self.__max_corner)): side_length = self.__max_corner[i] - self.__min_corner[i] if side_length != 0.0: if volume == 0.0: volume = side_length else: volume *= side_length return volume class bang_block: """! @brief BANG-block that represent spatial region in data space. """ def __init__(self, data, region, level, space_block, cache_points=False): """! @brief Create BANG-block. @param[in] data (list): List of points that are processed. @param[in] region (uint): Region number - unique value on a level. @param[in] level (uint): Level number where block is created. @param[in] space_block (spatial_block): Spatial block description in data space. @param[in] cache_points (bool): if True then points are stored in memory (used for leaf blocks). """ self.__data = data self.__region_number = region self.__level = level self.__spatial_block = space_block self.__cache_points = cache_points self.__cluster = None self.__points = None self.__amount_points = self.__get_amount_points() self.__density = self.__calculate_density(self.__amount_points) def __str__(self): """! @brief Returns string representation of BANG-block using region number and level where block is located. """ return "(" + str(self.__region_number) + ", " + str(self.__level) + ")" def __len__(self): """! @brief Returns block size defined by amount of points that are contained by this block. """ return self.__amount_points def get_region(self): """! @brief Returns region number of BANG-block. @details Region number is unique on among region numbers on a directory level. Pair of region number and level is unique for all directory. @return (uint) Region number. """ return self.__region_number def get_density(self): """! @brief Returns density of the BANG-block. @return (double) BANG-block density. """ return self.__density def get_cluster(self): """! @brief Return index of cluster to which the BANG-block belongs to. @details Index of cluster may have None value if the block was not assigned to any cluster. @return (uint) Index of cluster or None if the block does not belong to any cluster. """ return self.__cluster def get_spatial_block(self): """! @brief Return spatial block - BANG-block description in data space. @return (spatial_block) Spatial block of the BANG-block. """ return self.__spatial_block def get_points(self): """! @brief Return points that covers by the BANG-block. @return (list) List of point indexes that are covered by the block. """ if self.__points is None: self.__cache_covered_data() return self.__points def set_cluster(self, index): """! @brief Assign cluster to the BANG-block by index. @param[in] index (uint): Index cluster that is assigned to BANG-block. """ self.__cluster = index def is_neighbor(self, block): """! @brief Performs calculation to check whether specified block is neighbor to the current. @param[in] block (bang_block): Other BANG-block that should be checked for neighborhood. @return (bool) True if blocks are neighbors, False if blocks are not neighbors. """ return self.get_spatial_block().is_neighbor(block.get_spatial_block()) def split(self, split_dimension, cache_points): """! @brief Split BANG-block into two new blocks in specified dimension. @param[in] split_dimension (uint): Dimension where block should be split. @param[in] cache_points (bool): If True then covered points are cached. Used for leaf blocks. @return (tuple) Pair of BANG-block that were formed from the current. """ left_region_number = self.__region_number right_region_number = self.__region_number + 2 ** self.__level first_spatial_block, second_spatial_block = self.__spatial_block.split(split_dimension) left = bang_block(self.__data, left_region_number, self.__level + 1, first_spatial_block, cache_points) right = bang_block(self.__data, right_region_number, self.__level + 1, second_spatial_block, cache_points) return left, right def __calculate_density(self, amount_points): """! @brief Calculates BANG-block density. @param[in] amount_points (uint): Amount of points in block. @return (double) BANG-block density. """ volume = self.__spatial_block.get_volume() if volume != 0.0: return amount_points / volume return 0.0 def __get_amount_points(self): """! @brief Count covered points by the BANG-block and if cache is enable then covered points are stored. @return (uint) Amount of covered points. """ amount = 0 for index in range(len(self.__data)): if self.__data[index] in self.__spatial_block: self.__cache_point(index) amount += 1 return amount def __cache_covered_data(self): """! @brief Cache covered data. """ self.__cache_points = True self.__points = [] for index_point in range(len(self.__data)): if self.__data[index_point] in self.__spatial_block: self.__cache_point(index_point) def __cache_point(self, index): """! @brief Store index points. @param[in] index (uint): Index point that should be stored. """ if self.__cache_points: if self.__points is None: self.__points = [] self.__points.append(index) class bang: """! @brief Class implements BANG grid based clustering algorithm. @details BANG clustering algorithms uses a multidimensional grid structure to organize the value space surrounding the pattern values. The patterns are grouped into blocks and clustered with respect to the blocks by a topological neighbor search algorithm @cite inproceedings::bang::1. Code example of BANG usage: @code from pyclustering.cluster.bang import bang, bang_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Read data three dimensional data. data = read_sample(FCPS_SAMPLES.SAMPLE_CHAINLINK) # Prepare algorithm's parameters. levels = 11 # Create instance of BANG algorithm. bang_instance = bang(data, levels) bang_instance.process() # Obtain clustering results. clusters = bang_instance.get_clusters() noise = bang_instance.get_noise() directory = bang_instance.get_directory() dendrogram = bang_instance.get_dendrogram() # Visualize BANG clustering results. bang_visualizer.show_blocks(directory) bang_visualizer.show_dendrogram(dendrogram) bang_visualizer.show_clusters(data, clusters, noise) @endcode There is visualization of BANG-clustering of three-dimensional data 'chainlink'. BANG-blocks that were formed during processing are shown on following figure. The darkest color means highest density, blocks that does not cover points are transparent: @image html bang_blocks_chainlink.png "Fig. 1. BANG-blocks that cover input data." Here is obtained dendrogram that can be used for further analysis to improve clustering results: @image html bang_dendrogram_chainlink.png "Fig. 2. BANG dendrogram where the X-axis contains BANG-blocks, the Y-axis contains density." BANG clustering result of 'chainlink' data: @image html bang_clustering_chainlink.png "Fig. 3. BANG clustering result. Data: 'chainlink'." """ def __init__(self, data, levels, ccore=False, **kwargs): """! @brief Create BANG clustering algorithm. @param[in] data (list): Input data (list of points) that should be clustered. @param[in] levels (uint): Amount of levels in tree that is used for splitting (how many times block should be split). For example, if amount of levels is two then surface will be divided into two blocks and each obtained block will be divided into blocks also. @param[in] ccore (bool): Reserved positional argument - not used yet. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'observe'). Keyword Args:
- density_threshold (double): If block density is smaller than this value then contained data by this block is considered as a noise and its points as outliers. Block density is defined by amount of points in block divided by block volume: amount_block_points/block_volume. By default it is 0.0 - means than only empty blocks are considered as noise. Be aware that this parameter is used with parameter 'amount_threshold' - the maximum threshold is considered during processing. - amount_threshold (uint): Amount of points in the block when it contained data in bang-block is considered as a noise and there is no need to split it till the last level. Be aware that this parameter is used with parameter 'density_threshold' - the maximum threshold is considered during processing. """ self.__data = data self.__levels = levels self.__directory = None self.__clusters = [] self.__noise = [] self.__cluster_blocks = [] self.__dendrogram = [] self.__density_threshold = kwargs.get('density_threshold', 0.0) self.__amount_threshold = kwargs.get('amount_threshold', 0) self.__ccore = ccore self.__validate_arguments() def process(self): """! @brief Performs clustering process in line with rules of BANG clustering algorithm. @return (bang) Returns itself (BANG instance). @see get_clusters() @see get_noise() @see get_directory() @see get_dendrogram() """ self.__directory = bang_directory(self.__data, self.__levels, density_threshold=self.__density_threshold, amount_threshold=self.__amount_threshold) self.__allocate_clusters() return self def get_clusters(self): """! @brief Returns allocated clusters. @remark Allocated clusters are returned only after data processing (method process()). Otherwise empty list is returned. @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_noise() """ return self.__clusters def get_noise(self): """! @brief Returns allocated noise. @remark Allocated noise is returned only after data processing (method process()). Otherwise empty list is returned. @return (list) List of indexes that are marked as a noise. @see process() @see get_clusters() """ return self.__noise def get_directory(self): """! @brief Returns grid directory that describes grid of the processed data. @remark Grid directory is returned only after data processing (method process()). Otherwise None value is returned. @return (bang_directory) BANG directory that describes grid of process data. @see process() """ return self.__directory def get_dendrogram(self): """! @brief Returns dendrogram of clusters. @details Dendrogram is created in following way: the density indices of all regions are calculated and sorted in decreasing order for each cluster during clustering process. @remark Dendrogram is returned only after data processing (method process()). Otherwise empty list is returned. """ return self.__dendrogram def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __validate_arguments(self): """! @brief Check input arguments of BANG algorithm and if one of them is not correct then appropriate exception is thrown. """ if len(self.__data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data)) if self.__levels < 1: raise ValueError("Height of the tree should be greater than 0 (current value: '%d')." % self.__levels) if self.__density_threshold < 0.0: raise ValueError("Density threshold should be greater or equal to 0 (current value: '%d')." % self.__density_threshold) if self.__amount_threshold < 0: raise ValueError("Amount of points threshold should be greater than 0 (current value: '%d')" % self.__amount_threshold) def __allocate_clusters(self): """! @brief Performs cluster allocation using leafs of tree in BANG directory (the smallest cells). """ leaf_blocks = self.__directory.get_leafs() unhandled_block_indexes = set([i for i in range(len(leaf_blocks)) if leaf_blocks[i].get_density() > self.__density_threshold]) current_block = self.__find_block_center(leaf_blocks, unhandled_block_indexes) cluster_index = 0 while current_block is not None: if current_block.get_density() <= self.__density_threshold or len(current_block) <= self.__amount_threshold: break self.__expand_cluster_block(current_block, cluster_index, leaf_blocks, unhandled_block_indexes) current_block = self.__find_block_center(leaf_blocks, unhandled_block_indexes) cluster_index += 1 self.__store_clustering_results(cluster_index, leaf_blocks) def __expand_cluster_block(self, block, cluster_index, leaf_blocks, unhandled_block_indexes): """! @brief Expand cluster from specific block that is considered as a central block. @param[in] block (bang_block): Block that is considered as a central block for cluster. @param[in] cluster_index (uint): Index of cluster that is assigned to blocks that forms new cluster. @param[in] leaf_blocks (list): Leaf BANG-blocks that are considered during cluster formation. @param[in] unhandled_block_indexes (set): Set of candidates (BANG block indexes) to become a cluster member. The parameter helps to reduce traversing among BANG-block providing only restricted set of block that should be considered. """ block.set_cluster(cluster_index) self.__update_cluster_dendrogram(cluster_index, [block]) neighbors = self.__find_block_neighbors(block, leaf_blocks, unhandled_block_indexes) self.__update_cluster_dendrogram(cluster_index, neighbors) for neighbor in neighbors: neighbor.set_cluster(cluster_index) neighbor_neighbors = self.__find_block_neighbors(neighbor, leaf_blocks, unhandled_block_indexes) self.__update_cluster_dendrogram(cluster_index, neighbor_neighbors) neighbors += neighbor_neighbors def __store_clustering_results(self, amount_clusters, leaf_blocks): """! @brief Stores clustering results in a convenient way. @param[in] amount_clusters (uint): Amount of cluster that was allocated during processing. @param[in] leaf_blocks (list): Leaf BANG-blocks (the smallest cells). """ self.__clusters = [[] for _ in range(amount_clusters)] for block in leaf_blocks: index = block.get_cluster() if index is not None: self.__clusters[index] += block.get_points() else: self.__noise += block.get_points() self.__clusters = [ list(set(cluster)) for cluster in self.__clusters ] self.__noise = list(set(self.__noise)) def __find_block_center(self, level_blocks, unhandled_block_indexes): """! @brief Search block that is cluster center for new cluster. @return (bang_block) Central block for new cluster, if cluster is not found then None value is returned. """ for i in reversed(range(len(level_blocks))): if level_blocks[i].get_density() <= self.__density_threshold: return None if level_blocks[i].get_cluster() is None: unhandled_block_indexes.remove(i) return level_blocks[i] return None def __find_block_neighbors(self, block, level_blocks, unhandled_block_indexes): """! @brief Search block neighbors that are parts of new clusters (density is greater than threshold and that are not cluster members yet), other neighbors are ignored. @param[in] block (bang_block): BANG-block for which neighbors should be found (which can be part of cluster). @param[in] level_blocks (list): BANG-blocks on specific level. @param[in] unhandled_block_indexes (set): Blocks that have not been processed yet. @return (list) Block neighbors that can become part of cluster. """ neighbors = [] handled_block_indexes = [] for unhandled_index in unhandled_block_indexes: if block.is_neighbor(level_blocks[unhandled_index]): handled_block_indexes.append(unhandled_index) neighbors.append(level_blocks[unhandled_index]) # Maximum number of neighbors is eight if len(neighbors) == 8: break for handled_index in handled_block_indexes: unhandled_block_indexes.remove(handled_index) return neighbors def __update_cluster_dendrogram(self, index_cluster, blocks): """! @brief Append clustered blocks to dendrogram. @param[in] index_cluster (uint): Cluster index that was assigned to blocks. @param[in] blocks (list): Blocks that were clustered. """ if len(self.__dendrogram) <= index_cluster: self.__dendrogram.append([]) blocks = sorted(blocks, key=lambda block: block.get_density(), reverse=True) self.__dendrogram[index_cluster] += blocks pyclustering-0.10.1.2/pyclustering/cluster/birch.py000077500000000000000000000267341375753423500223700ustar00rootroot00000000000000"""! @brief BIRCH (Balanced Iterative Reducing and Clustering using Hierarchies) cluster analysis algorithm. @details Implementation based on paper @cite article::birch::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from pyclustering.cluster.agglomerative import agglomerative, type_link from pyclustering.cluster.encoder import cluster_encoder, type_encoding from pyclustering.container.cftree import cftree, measurement_type class birch: """! @brief Class represents the clustering algorithm BIRCH (Balanced Iterative Reducing and Clustering using Hierarchies). @details BIRCH is suitable for large databases. The algorithm incrementally and dynamically clusters incoming multi-dimensional metric data points using the concepts of Clustering Feature and CF tree. A Clustering Feature is a triple summarizing the information that is maintained about a cluster. The Clustering Feature vector is defined as a triple: \f[CF=\left ( N, \overrightarrow{LS}, SS \right )\f] Example how to extract clusters from 'OldFaithful' sample using BIRCH algorithm: @code from pyclustering.cluster.birch import birch from pyclustering.cluster import cluster_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FAMOUS_SAMPLES # Sample for cluster analysis (represented by list) sample = read_sample(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL) # Create BIRCH algorithm birch_instance = birch(sample, 2, diameter=3.0) # Cluster analysis birch_instance.process() # Obtain results of clustering clusters = birch_instance.get_clusters() # Visualize allocated clusters visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode Here is the clustering result produced by BIRCH algorithm: @image html birch_clustering_old_faithful.png "Fig. 1. BIRCH clustering - sample 'OldFaithful'." Methods 'get_cf_entries' and 'get_cf_clusters' can be used to obtain information how does an input data is encoded. Here is an example how the encoding information can be extracted and visualized: @code from pyclustering.cluster.birch import birch from pyclustering.cluster import cluster_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Sample 'Lsun' for cluster analysis (represented by list of points) sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Create BIRCH algorithm birch_instance = birch(sample, 3, diameter=0.5) # Cluster analysis birch_instance.process() # Obtain results of clustering clusters = birch_instance.get_clusters() # Obtain information how does the 'Lsun' sample is encoded in the CF-tree. cf_entries = birch_instance.get_cf_entries() cf_clusters = birch_instance.get_cf_cluster() cf_centroids = [entry.get_centroid() for entry in cf_entries] # Visualize allocated clusters visualizer = cluster_visualizer(2, 2, titles=["Encoded data by CF-entries", "Data clusters"]) visualizer.append_clusters(cf_clusters, cf_centroids, canvas=0) visualizer.append_clusters(clusters, sample, canvas=1) visualizer.show() @endcode Here is the clustering result produced by BIRCH algorithm: @image html birch_cf_encoding_lsun.png "Fig. 2. CF-tree encoding and BIRCH clustering of 'Lsun' sample." """ def __init__(self, data, number_clusters, branching_factor=50, max_node_entries=200, diameter=0.5, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE, entry_size_limit=500, diameter_multiplier=1.5, ccore=True): """! @brief Constructor of clustering algorithm BIRCH. @param[in] data (list): An input data represented as a list of points (objects) where each point is be represented by list of coordinates. @param[in] number_clusters (uint): Amount of clusters that should be allocated. @param[in] branching_factor (uint): Maximum number of successor that might be contained by each non-leaf node in CF-Tree. @param[in] max_node_entries (uint): Maximum number of entries that might be contained by each leaf node in CF-Tree. @param[in] diameter (double): CF-entry diameter that used for CF-Tree construction, it might be increase if 'entry_size_limit' is exceeded. @param[in] type_measurement (measurement_type): Type measurement used for calculation distance metrics. @param[in] entry_size_limit (uint): Maximum number of entries that can be stored in CF-Tree, if it is exceeded during creation then the 'diameter' is increased and CF-Tree is rebuilt. @param[in] diameter_multiplier (double): Multiplier that is used for increasing diameter when 'entry_size_limit' is exceeded. @param[in] ccore (bool): If True than C++ part of the library is used for processing. """ self.__pointer_data = data self.__number_clusters = number_clusters self.__measurement_type = type_measurement self.__entry_size_limit = entry_size_limit self.__diameter_multiplier = diameter_multiplier self.__ccore = ccore self.__verify_arguments() self.__features = None self.__tree = cftree(branching_factor, max_node_entries, diameter, type_measurement) self.__clusters = [] self.__cf_clusters = [] def process(self): """! @brief Performs cluster analysis in line with rules of BIRCH algorithm. @return (birch) Returns itself (BIRCH instance). @see get_clusters() """ self.__insert_data() self.__extract_features() cf_data = [feature.get_centroid() for feature in self.__features] algorithm = agglomerative(cf_data, self.__number_clusters, type_link.SINGLE_LINK).process() self.__cf_clusters = algorithm.get_clusters() cf_labels = cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, self.__cf_clusters, cf_data).\ set_encoding(type_encoding.CLUSTER_INDEX_LABELING).get_clusters() self.__clusters = [[] for _ in range(len(self.__cf_clusters))] for index_point in range(len(self.__pointer_data)): index_cf_entry = numpy.argmin(numpy.sum(numpy.square( numpy.subtract(cf_data, self.__pointer_data[index_point])), axis=1)) index_cluster = cf_labels[index_cf_entry] self.__clusters[index_cluster].append(index_point) return self def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster is represented by a list of indexes where each index corresponds to a point in an input dataset. @return (list) List of allocated clusters. @see process() """ return self.__clusters def get_cf_entries(self): """! @brief Returns CF-entries that encodes an input dataset. @return (list) CF-entries that encodes an input dataset. @see get_cf_cluster """ return self.__features def get_cf_cluster(self): """! @brief Returns list of allocated CF-entry clusters where each cluster is represented by indexes (each index corresponds to CF-entry). @return (list) List of allocated CF-entry clusters. @see get_cf_entries """ return self.__cf_clusters def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if self.__number_clusters <= 0: raise ValueError("Amount of cluster (current value: '%d') for allocation should be greater than 0." % self.__number_clusters) if self.__entry_size_limit <= 0: raise ValueError("Limit entry size (current value: '%d') should be greater than 0." % self.__entry_size_limit) def __extract_features(self): """! @brief Extracts features from CF-tree cluster. """ self.__features = [] if len(self.__tree.leafes) == 1: # parameters are too general, copy all entries for entry in self.__tree.leafes[0].entries: self.__features.append(entry) else: # copy all leaf clustering features for leaf_node in self.__tree.leafes: self.__features += leaf_node.entries def __insert_data(self): """! @brief Inserts input data to the tree. @remark If number of maximum number of entries is exceeded than diameter is increased and tree is rebuilt. """ for index_point in range(0, len(self.__pointer_data)): point = self.__pointer_data[index_point] self.__tree.insert_point(point) if self.__tree.amount_entries > self.__entry_size_limit: self.__tree = self.__rebuild_tree(index_point) def __rebuild_tree(self, index_point): """! @brief Rebuilt tree in case of maxumum number of entries is exceeded. @param[in] index_point (uint): Index of point that is used as end point of re-building. @return (cftree) Rebuilt tree with encoded points till specified point from input data space. """ rebuild_result = False increased_diameter = self.__tree.threshold * self.__diameter_multiplier tree = None while rebuild_result is False: # increase diameter and rebuild tree if increased_diameter == 0.0: increased_diameter = 1.0 # build tree with update parameters tree = cftree(self.__tree.branch_factor, self.__tree.max_entries, increased_diameter, self.__tree.type_measurement) for index_point in range(0, index_point + 1): point = self.__pointer_data[index_point] tree.insert_point(point) if tree.amount_entries > self.__entry_size_limit: increased_diameter *= self.__diameter_multiplier continue # Re-build is successful. rebuild_result = True return tree pyclustering-0.10.1.2/pyclustering/cluster/bsas.py000077500000000000000000000220211375753423500222120ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: BSAS (Basic Sequential Algorithmic Scheme). @details Implementation based on paper @cite book::pattern_recognition::2009. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import ccore_library from pyclustering.core.bsas_wrapper import bsas as bsas_wrapper from pyclustering.core.metric_wrapper import metric_wrapper from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.encoder import type_encoding from pyclustering.utils.metric import type_metric, distance_metric class bsas_visualizer: """! @brief Visualizer of BSAS algorithm's results. @details BSAS visualizer provides visualization services that are specific for BSAS algorithm. """ @staticmethod def show_clusters(sample, clusters, representatives, **kwargs): """! @brief Display BSAS clustering results. @param[in] sample (list): Dataset that was used for clustering. @param[in] clusters (array_like): Clusters that were allocated by the algorithm. @param[in] representatives (array_like): Allocated representatives correspond to clusters. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'figure', 'display', 'offset'). Keyword Args:
- figure (figure): If 'None' then new is figure is created, otherwise specified figure is used for visualization. - display (bool): If 'True' then figure will be shown by the method, otherwise it should be shown manually using matplotlib function 'plt.show()'. - offset (uint): Specify axes index on the figure where results should be drawn (only if argument 'figure' is specified). @return (figure) Figure where clusters were drawn. """ figure = kwargs.get('figure', None) display = kwargs.get('display', True) offset = kwargs.get('offset', 0) visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample, canvas=offset) for cluster_index in range(len(clusters)): visualizer.append_cluster_attribute(offset, cluster_index, [representatives[cluster_index]], '*', 10) return visualizer.show(figure=figure, display=display) class bsas: """! @brief Class represents BSAS clustering algorithm - basic sequential algorithmic scheme. @details Algorithm has two mandatory parameters: maximum allowable number of clusters and threshold of dissimilarity or in other words maximum distance between points. Distance metric also can be specified using 'metric' parameters, by default 'Manhattan' distance is used. BSAS using following rule for updating cluster representative: \f[ \vec{m}_{C_{k}}^{new}=\frac{ \left ( n_{C_{k}^{new}} - 1 \right )\vec{m}_{C_{k}}^{old} + \vec{x} }{n_{C_{k}^{new}}} \f] Clustering results of this algorithm depends on objects order in input data. Example: @code from pyclustering.cluster.bsas import bsas, bsas_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read data sample from 'Simple02.data'. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) # Prepare algorithm's parameters. max_clusters = 3 threshold = 1.0 # Create instance of BSAS algorithm. bsas_instance = bsas(sample, max_clusters, threshold) bsas_instance.process() # Get clustering results. clusters = bsas_instance.get_clusters() representatives = bsas_instance.get_representatives() # Display results. bsas_visualizer.show_clusters(sample, clusters, representatives) @endcode @see pyclustering.cluster.mbsas, pyclustering.cluster.ttsas """ def __init__(self, data, maximum_clusters, threshold, ccore=True, **kwargs): """! @brief Creates classical BSAS algorithm. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] maximum_clusters: Maximum allowable number of clusters that can be allocated during processing. @param[in] threshold: Threshold of dissimilarity (maximum distance) between points. @param[in] ccore (bool): If True than CCORE (C++ part of the library) will be used for solving. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric'). Keyword Args:
- metric (distance_metric): Metric that is used for distance calculation between two points. """ self._data = data self._amount = maximum_clusters self._threshold = threshold self._metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN)) self._ccore = ccore and self._metric.get_type() != type_metric.USER_DEFINED self._clusters = [] self._representatives = [] if self._ccore is True: self._ccore = ccore_library.workable() self._verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of BSAS algorithm. @return (bsas) Returns itself (BSAS instance). @remark Results of clustering can be obtained using corresponding get methods. @see get_clusters() @see get_representatives() """ if self._ccore is True: self.__process_by_ccore() else: self.__prcess_by_python() return self def __process_by_ccore(self): ccore_metric = metric_wrapper.create_instance(self._metric) self._clusters, self._representatives = bsas_wrapper(self._data, self._amount, self._threshold, ccore_metric.get_pointer()) def __prcess_by_python(self): self._clusters.append([0]) self._representatives.append(self._data[0]) for i in range(1, len(self._data)): point = self._data[i] index_cluster, distance = self._find_nearest_cluster(point) if (distance > self._threshold) and (len(self._clusters) < self._amount): self._representatives.append(point) self._clusters.append([i]) else: self._clusters[index_cluster].append(i) self._update_representative(index_cluster, point) def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_representatives() """ return self._clusters def get_representatives(self): """! @brief Returns list of representatives of allocated clusters. @see process() @see get_clusters() """ return self._representatives def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def _find_nearest_cluster(self, point): """! @brief Find nearest cluster to the specified point. @param[in] point (list): Point from dataset. @return (uint, double) Index of nearest cluster and distance to it. """ index_cluster = -1 nearest_distance = float('inf') for index in range(len(self._representatives)): distance = self._metric(point, self._representatives[index]) if distance < nearest_distance: index_cluster = index nearest_distance = distance return index_cluster, nearest_distance def _update_representative(self, index_cluster, point): """! @brief Update cluster representative in line with new cluster size and added point to it. @param[in] index_cluster (uint): Index of cluster whose representative should be updated. @param[in] point (list): Point that was added to cluster. """ length = len(self._clusters[index_cluster]) rep = self._representatives[index_cluster] for dimension in range(len(rep)): rep[dimension] = ( (length - 1) * rep[dimension] + point[dimension] ) / length def _verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self._data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self._data)) if self._amount <= 0: raise ValueError("Amount of cluster (current value: '%d') for allocation should be greater than 0." % self._amount) if self._threshold < 0: raise ValueError("Threshold of dissimilarity (current value: '%d') between points should be greater or " "equal to 0." % self._threshold)pyclustering-0.10.1.2/pyclustering/cluster/center_initializer.py000077500000000000000000000330061375753423500251520ustar00rootroot00000000000000"""! @brief Collection of center initializers for algorithm that uses initial centers, for example, for K-Means or X-Means. @details Implementation based on paper @cite article::kmeans++::1. @authors Andrei Novikov, Aleksey Kukushkin (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause @see pyclustering.cluster.kmeans @see puclustering.cluster.xmeans """ import numpy import random import warnings class random_center_initializer: """! @brief Random center initializer is for generation specified amount of random of centers for specified data. """ def __init__(self, data, amount_centers, **kwargs): """! @brief Creates instance of random center initializer. @param[in] data (list): List of points where each point is represented by list of coordinates. @param[in] amount_centers (unit): Amount of centers that should be initialized. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'random_state'). Keyword Args:
- random_state (int): Seed for random state (by default is `None`, current system time is used). """ self.__data = data self.__amount = amount_centers self.__available_indexes = set(list(range(len(self.__data)))) random.seed(kwargs.get('random_state', None)) if self.__amount <= 0: raise ValueError("Amount of cluster centers should be at least 1.") if self.__amount > len(self.__data): raise ValueError("Amount of cluster centers '%d' should be less than data size." % self.__amount) def initialize(self, **kwargs): """! @brief Generates random centers in line with input parameters. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'return_index'). Keyword Args:
- return_index (bool): If True then returns indexes of points from input data instead of points itself. @return (list) List of initialized initial centers. If argument 'return_index' is False then returns list of points. If argument 'return_index' is True then returns list of indexes. """ return_index = kwargs.get('return_index', False) if self.__amount == len(self.__data): if return_index: return list(range(len(self.__data))) return self.__data[:] return [self.__create_center(return_index) for _ in range(self.__amount)] def __create_center(self, return_index): """! @brief Generates and returns random center. @param[in] return_index (bool): If True then returns index of point from input data instead of point itself. """ random_index_point = random.randint(0, len(self.__data)) if random_index_point not in self.__available_indexes: random_index_point = self.__available_indexes.pop() else: self.__available_indexes.remove(random_index_point) if return_index: return random_index_point return self.__data[random_index_point] class kmeans_plusplus_initializer: """! @brief K-Means++ is an algorithm for choosing the initial centers for algorithms like K-Means or X-Means. @details K-Means++ algorithm guarantees an approximation ratio O(log k). Clustering results are depends on initial centers in case of K-Means algorithm and even in case of X-Means. This method is used to find out optimal initial centers. Algorithm can be divided into three steps. The first center is chosen from input data randomly with uniform distribution at the first step. At the second, probability to being center is calculated for each point: \f[p_{i}=\frac{D(x_{i})}{\sum_{j=0}^{N}D(x_{j})}\f] where \f$D(x_{i})\f$ is a distance from point \f$i\f$ to the closest center. Using this probabilities next center is chosen. The last step is repeated until required amount of centers is initialized. Pyclustering implementation of the algorithm provides feature to consider several candidates on the second step, for example: @code amount_centers = 4; amount_candidates = 3; initializer = kmeans_plusplus_initializer(sample, amount_centers, amount_candidates); @endcode If the farthest points should be used as centers then special constant 'FARTHEST_CENTER_CANDIDATE' should be used for that purpose, for example: @code amount_centers = 4; amount_candidates = kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE; initializer = kmeans_plusplus_initializer(sample, amount_centers, amount_candidates); @endcode There is an example of initial centers that were calculated by the K-Means++ method: @image html kmeans_plusplus_initializer_results.png Code example where initial centers are prepared for K-Means algorithm: @code from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster import cluster_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read data 'SampleSimple3' from Simple Sample collection. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Calculate initial centers using K-Means++ method. centers = kmeans_plusplus_initializer(sample, 4, kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE).initialize() # Display initial centers. visualizer = cluster_visualizer() visualizer.append_cluster(sample) visualizer.append_cluster(centers, marker='*', markersize=10) visualizer.show() # Perform cluster analysis using K-Means algorithm with initial centers. kmeans_instance = kmeans(sample, centers) # Run clustering process and obtain result. kmeans_instance.process() clusters = kmeans_instance.get_clusters() @endcode """ ## Constant denotes that only points with highest probabilities should be considered as centers. FARTHEST_CENTER_CANDIDATE = "farthest" def __init__(self, data, amount_centers, amount_candidates=None, **kwargs): """! @brief Creates K-Means++ center initializer instance. @param[in] data (array_like): List of points where each point is represented by list of coordinates. @param[in] amount_centers (uint): Amount of centers that should be initialized. @param[in] amount_candidates (uint): Amount of candidates that is considered as a center, if the farthest points (with the highest probability) should be considered as centers then special constant should be used 'FARTHEST_CENTER_CANDIDATE'. By default the amount of candidates is 3. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'random_state'). Keyword Args:
- random_state (int): Seed for random state (by default is `None`, current system time is used). @see FARTHEST_CENTER_CANDIDATE """ self.__data = numpy.array(data) self.__amount = amount_centers self.__free_indexes = set(range(len(self.__data))) if amount_candidates is None: self.__candidates = 3 if self.__candidates > len(self.__data): self.__candidates = len(self.__data) else: self.__candidates = amount_candidates self.__check_parameters() random.seed(kwargs.get('random_state', None)) def __check_parameters(self): """! @brief Checks input parameters of the algorithm and if something wrong then corresponding exception is thrown. """ if (self.__amount <= 0) or (self.__amount > len(self.__data)): raise ValueError("Amount of cluster centers '" + str(self.__amount) + "' should be at least 1 and " "should be less or equal to amount of points in data.") if self.__candidates != kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE: if (self.__candidates <= 0) or (self.__candidates > len(self.__data)): raise ValueError("Amount of center candidates '" + str(self.__candidates) + "' should be at least 1 " "and should be less or equal to amount of points in data.") if len(self.__data) == 0: raise ValueError("Data is empty.") def __calculate_shortest_distances(self, data, centers): """! @brief Calculates distance from each data point to nearest center. @param[in] data (numpy.array): Array of points for that initialization is performed. @param[in] centers (numpy.array): Array of indexes that represents centers. @return (numpy.array) List of distances to closest center for each data point. """ dataset_differences = numpy.zeros((len(centers), len(data))) for index_center in range(len(centers)): center = data[centers[index_center]] dataset_differences[index_center] = numpy.sum(numpy.square(data - center), axis=1).T with warnings.catch_warnings(): numpy.warnings.filterwarnings('ignore', r'All-NaN (slice|axis) encountered') shortest_distances = numpy.nanmin(dataset_differences, axis=0) return shortest_distances def __get_next_center(self, centers): """! @brief Calculates the next center for the data. @param[in] centers (array_like): Current initialized centers represented by indexes. @return (array_like) Next initialized center.
(uint) Index of next initialized center if return_index is True. """ distances = self.__calculate_shortest_distances(self.__data, centers) if self.__candidates == kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE: for index_point in centers: distances[index_point] = numpy.nan center_index = numpy.nanargmax(distances) else: probabilities = self.__calculate_probabilities(distances) center_index = self.__get_probable_center(distances, probabilities) return center_index def __get_initial_center(self, return_index): """! @brief Choose randomly first center. @param[in] return_index (bool): If True then return center's index instead of point. @return (array_like) First center.
(uint) Index of first center. """ index_center = random.randint(0, len(self.__data) - 1) if return_index: return index_center return self.__data[index_center] def __calculate_probabilities(self, distances): """! @brief Calculates cumulative probabilities of being center of each point. @param[in] distances (array_like): Distances from each point to closest center. @return (array_like) Cumulative probabilities of being center of each point. """ total_distance = numpy.sum(distances) if total_distance != 0.0: probabilities = distances / total_distance return numpy.cumsum(probabilities) else: return numpy.zeros(len(distances)) def __get_probable_center(self, distances, probabilities): """! @brief Calculates the next probable center considering amount candidates. @param[in] distances (array_like): Distances from each point to closest center. @param[in] probabilities (array_like): Cumulative probabilities of being center of each point. @return (uint) Index point that is next initialized center. """ index_best_candidate = 0 for i in range(self.__candidates): candidate_probability = random.random() index_candidate = -1 for index_object in range(len(probabilities)): if candidate_probability < probabilities[index_object]: index_candidate = index_object break if index_candidate == -1: index_best_candidate = next(iter(self.__free_indexes)) elif distances[index_best_candidate] < distances[index_candidate]: index_best_candidate = index_candidate return index_best_candidate def initialize(self, **kwargs): """! @brief Calculates initial centers using K-Means++ method. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'return_index'). Keyword Args:
- return_index (bool): If True then returns indexes of points from input data instead of points itself. @return (list) List of initialized initial centers. If argument 'return_index' is False then returns list of points. If argument 'return_index' is True then returns list of indexes. """ return_index = kwargs.get('return_index', False) index_point = self.__get_initial_center(True) centers = [index_point] self.__free_indexes.remove(index_point) # For each next center for _ in range(1, self.__amount): index_point = self.__get_next_center(centers) centers.append(index_point) self.__free_indexes.remove(index_point) if not return_index: centers = [self.__data[index] for index in centers] return centers pyclustering-0.10.1.2/pyclustering/cluster/clarans.py000077500000000000000000000271131375753423500227140ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: CLARANS. @details Implementation based on paper @cite article::clarans::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random from pyclustering.cluster.encoder import type_encoding from pyclustering.utils import euclidean_distance_square class clarans: """! @brief Class represents clustering algorithm CLARANS (a method for clustering objects for spatial data mining). """ def __init__(self, data, number_clusters, numlocal, maxneighbor): """! @brief Constructor of clustering algorithm CLARANS. @details The higher the value of maxneighbor, the closer is CLARANS to K-Medoids, and the longer is each search of a local minima. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] number_clusters (uint): Amount of clusters that should be allocated. @param[in] numlocal (uint): The number of local minima obtained (amount of iterations for solving the problem). @param[in] maxneighbor (uint): The maximum number of neighbors examined. """ self.__pointer_data = data self.__numlocal = numlocal self.__maxneighbor = maxneighbor self.__number_clusters = number_clusters self.__clusters = [] self.__current = [] self.__belong = [] self.__optimal_medoids = [] self.__optimal_estimation = float('inf') self.__verify_arguments() def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if self.__number_clusters <= 0: raise ValueError("Amount of cluster (current value: '%d') for allocation should be greater than 0." % self.__number_clusters) if self.__numlocal < 0: raise ValueError("Local minima (current value: '%d') should be greater or equal to 0." % self.__numlocal) if self.__maxneighbor < 0: raise ValueError("Maximum number of neighbors (current value: '%d') should be greater or " "equal to 0." % self.__maxneighbor) def process(self): """! @brief Performs cluster analysis in line with rules of CLARANS algorithm. @return (clarans) Returns itself (CLARANS instance). @see get_clusters() @see get_medoids() """ random.seed() for _ in range(0, self.__numlocal): # set (current) random medoids self.__current = random.sample(range(0, len(self.__pointer_data)), self.__number_clusters) # update clusters in line with random allocated medoids self.__update_clusters(self.__current) # optimize configuration self.__optimize_configuration() # obtain cost of current cluster configuration and compare it with the best obtained estimation = self.__calculate_estimation() if estimation < self.__optimal_estimation: self.__optimal_medoids = self.__current[:] self.__optimal_estimation = estimation self.__update_clusters(self.__optimal_medoids) return self def get_clusters(self): """! @brief Returns allocated clusters by the algorithm. @remark Allocated clusters can be returned only after data processing (use method process()), otherwise empty list is returned. @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_medoids() """ return self.__clusters def get_medoids(self): """! @brief Returns list of medoids of allocated clusters. @see process() @see get_clusters() """ return self.__optimal_medoids def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __update_clusters(self, medoids): """! @brief Forms cluster in line with specified medoids by calculation distance from each point to medoids. """ self.__belong = [0] * len(self.__pointer_data) self.__clusters = [[] for i in range(len(medoids))] for index_point in range(len(self.__pointer_data)): index_optim = -1 dist_optim = 0.0 for index in range(len(medoids)): dist = euclidean_distance_square(self.__pointer_data[index_point], self.__pointer_data[medoids[index]]) if (dist < dist_optim) or (index == 0): index_optim = index dist_optim = dist self.__clusters[index_optim].append(index_point) self.__belong[index_point] = index_optim # If cluster is not able to capture object it should be removed self.__clusters = [cluster for cluster in self.__clusters if len(cluster) > 0] def __optimize_configuration(self): """! @brief Finds quasi-optimal medoids and updates in line with them clusters in line with algorithm's rules. """ index_neighbor = 0 while (index_neighbor < self.__maxneighbor): # get random current medoid that is to be replaced current_medoid_index = self.__current[random.randint(0, self.__number_clusters - 1)] current_medoid_cluster_index = self.__belong[current_medoid_index] # get new candidate to be medoid candidate_medoid_index = random.randint(0, len(self.__pointer_data) - 1) while candidate_medoid_index in self.__current: candidate_medoid_index = random.randint(0, len(self.__pointer_data) - 1) candidate_cost = 0.0 for point_index in range(0, len(self.__pointer_data)): if point_index not in self.__current: # get non-medoid point and its medoid point_cluster_index = self.__belong[point_index] point_medoid_index = self.__current[point_cluster_index] # get other medoid that is nearest to the point (except current and candidate) other_medoid_index = self.__find_another_nearest_medoid(point_index, current_medoid_index) other_medoid_cluster_index = self.__belong[other_medoid_index] # for optimization calculate all required distances # from the point to current medoid distance_current = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[current_medoid_index]) # from the point to candidate median distance_candidate = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[candidate_medoid_index]) # from the point to nearest (own) medoid distance_nearest = float('inf') if ( (point_medoid_index != candidate_medoid_index) and (point_medoid_index != current_medoid_cluster_index) ): distance_nearest = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[point_medoid_index]) # apply rules for cost calculation if (point_cluster_index == current_medoid_cluster_index): # case 1: if (distance_candidate >= distance_nearest): candidate_cost += distance_nearest - distance_current # case 2: else: candidate_cost += distance_candidate - distance_current elif (point_cluster_index == other_medoid_cluster_index): # case 3 ('nearest medoid' is the representative object of that cluster and object is more similar to 'nearest' than to 'candidate'): if (distance_candidate > distance_nearest): pass; # case 4: else: candidate_cost += distance_candidate - distance_nearest if (candidate_cost < 0): # set candidate that has won self.__current[current_medoid_cluster_index] = candidate_medoid_index # recalculate clusters self.__update_clusters(self.__current) # reset iterations and starts investigation from the begining index_neighbor = 0 else: index_neighbor += 1 def __find_another_nearest_medoid(self, point_index, current_medoid_index): """! @brief Finds the another nearest medoid for the specified point that is differ from the specified medoid. @param[in] point_index: index of point in dataspace for that searching of medoid in current list of medoids is perfomed. @param[in] current_medoid_index: index of medoid that shouldn't be considered as a nearest. @return (uint) index of the another nearest medoid for the point. """ other_medoid_index = -1 other_distance_nearest = float('inf') for index_medoid in self.__current: if (index_medoid != current_medoid_index): other_distance_candidate = euclidean_distance_square(self.__pointer_data[point_index], self.__pointer_data[current_medoid_index]) if other_distance_candidate < other_distance_nearest: other_distance_nearest = other_distance_candidate other_medoid_index = index_medoid return other_medoid_index def __calculate_estimation(self): """! @brief Calculates estimation (cost) of the current clusters. The lower the estimation, the more optimally configuration of clusters. @return (double) estimation of current clusters. """ estimation = 0.0 for index_cluster in range(0, len(self.__clusters)): cluster = self.__clusters[index_cluster] index_medoid = self.__current[index_cluster] for index_point in cluster: estimation += euclidean_distance_square(self.__pointer_data[index_point], self.__pointer_data[index_medoid]) return estimation pyclustering-0.10.1.2/pyclustering/cluster/clique.py000077500000000000000000000654031375753423500225570ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: CLIQUE @details Implementation based on paper @cite article::clique::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import itertools from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.encoder import type_encoding from pyclustering.core.wrapper import ccore_library import pyclustering.core.clique_wrapper as wrapper import matplotlib import matplotlib.gridspec as gridspec import matplotlib.pyplot as plt import matplotlib.patches as patches class clique_visualizer: """! @brief Visualizer of CLIQUE algorithm's results. @details CLIQUE visualizer provides visualization services that are specific for CLIQUE algorithm, for example, to display grid and its density. """ __maximum_density_alpha = 0.6 @staticmethod def show_grid(cells, data): """! @brief Show CLIQUE blocks as a grid in data space. @details Each block contains points and according to this density is displayed. CLIQUE grid helps to visualize grid that was used for clustering process. @param[in] cells (list): List of cells that is produced by CLIQUE algorithm. @param[in] data (array_like): Input data that was used for clustering process. """ dimension = cells[0].dimensions amount_canvases = 1 if dimension > 1: amount_canvases = int(dimension * (dimension - 1) / 2) figure = plt.figure() grid_spec = gridspec.GridSpec(1, amount_canvases) pairs = list(itertools.combinations(range(dimension), 2)) if len(pairs) == 0: pairs = [(0, 0)] for index in range(amount_canvases): ax = figure.add_subplot(grid_spec[index]) clique_visualizer.__draw_cells(ax, cells, pairs[index]) clique_visualizer.__draw_two_dimension_data(ax, data, pairs[index]) plt.show() @staticmethod def show_clusters(data, clusters, noise=None): """! @brief Display CLIQUE clustering results. @param[in] data (list): Data that was used for clustering. @param[in] clusters (array_like): Clusters that were allocated by the algorithm. @param[in] noise (array_like): Noise that were allocated by the algorithm. """ visualizer = cluster_visualizer() visualizer.append_clusters(clusters, data) visualizer.append_cluster(noise or [], data, marker='x') visualizer.show() @staticmethod def __draw_two_dimension_data(ax, data, pair): """! @brief Display data in two-dimensional canvas. @param[in] ax (Axis): Canvas where data should be displayed. @param[in] data (list): Data points that should be displayed. @param[in] pair (tuple): Pair of dimension indexes. """ ax.set_xlabel("x%d" % pair[0]) ax.set_ylabel("x%d" % pair[1]) for point in data: if len(data[0]) > 1: ax.plot(point[pair[0]], point[pair[1]], color='red', marker='.') else: ax.plot(point[pair[0]], 0, color='red', marker='.') ax.yaxis.set_ticklabels([]) @staticmethod def __draw_cells(ax, cells, pair): ax.grid(False) density_scale = max(len(cell.points) for cell in cells) for cell in cells: clique_visualizer.__draw_cell(ax, pair, cell, density_scale) @staticmethod def __draw_cell(ax, pair, cell, density_scale): max_corner, min_corner = clique_visualizer.__get_rectangle_description(cell, pair) belong_cluster = (len(cell.points) > 0) if density_scale != 0.0: density_scale = clique_visualizer.__maximum_density_alpha * len(cell.points) / density_scale face_color = matplotlib.colors.to_rgba('blue', alpha=density_scale) edge_color = matplotlib.colors.to_rgba('black', alpha=1.0) rect = patches.Rectangle(min_corner, max_corner[0] - min_corner[0], max_corner[1] - min_corner[1], fill=belong_cluster, facecolor=face_color, edgecolor=edge_color, linewidth=0.5) ax.add_patch(rect) #ax.annotate(str(cell.logical_location), (min_corner[0], min_corner[1]), fontsize=6, ha='center', va='center') @staticmethod def __get_rectangle_description(cell, pair): max_corner, min_corner = cell.spatial_location.get_corners() max_corner = [max_corner[pair[0]], max_corner[pair[1]]] min_corner = [min_corner[pair[0]], min_corner[pair[1]]] if pair == (0, 0): max_corner[1], min_corner[1] = 1.0, -1.0 return max_corner, min_corner class spatial_block: """! @brief Geometrical description of CLIQUE block in data space. @details Provides services related to spatial functionality. @see bang_block """ def __init__(self, max_corner, min_corner): """! @brief Creates spatial block in data space. @param[in] max_corner (array_like): Maximum corner coordinates of the block. @param[in] min_corner (array_like): Minimal corner coordinates of the block. """ self.__max_corner = max_corner self.__min_corner = min_corner def __str__(self): """! @brief Returns string block description. @return String representation of the block. """ return "(max: %s; min: %s)" % (self.__max_corner, self.__min_corner) def __contains__(self, point): """! @brief Point is considered as contained if it lies in block (belong to it). @return (bool) True if point is in block, otherwise False. """ for i in range(len(point)): if point[i] < self.__min_corner[i] or point[i] > self.__max_corner[i]: return False return True def get_corners(self): """! @brief Return spatial description of current block. @return (tuple) Pair of maximum and minimum corners (max_corner, min_corner). """ return self.__max_corner, self.__min_corner class clique_block: """! @brief CLIQUE block contains information about its logical location in grid, spatial location in data space and points that are covered by the block. """ def __init__(self, logical_location=None, spatial_location=None, points=None, visited=False): """! @brief Initializes CLIQUE block. @param[in] logical_location (list): Logical location of the block in CLIQUE grid. @param[in] spatial_location (spatial_block): Spatial location in data space. @param[in] points (array_like): Points that belong to this block (can be obtained by method 'capture_points', this parameter is used by CLIQUE in case of processing by C++ implementation when clustering result are passed back to Python code. @param[in] visited (bool): Marks if block is visited during clustering process. """ self.__logical_location = logical_location or [] self.__spatial_location = spatial_location self.__points = points or [] self.__visited = visited def __str__(self): """! @brief Returns string representation of the block using its logical location in CLIQUE grid. """ return str(self.__logical_location) def __repr__(self): """! @brief Returns string representation of the block using its logical location in CLIQUE grid. """ return str(self.__logical_location) @property def logical_location(self): """! @brief Logical location is represented by coordinates in CLIQUE grid, for example, in case of 2x2 grid blocks may have following coordinates: [0, 0], [0, 1], [1, 0], [1, 1]. @return (list) Logical location of the block in CLIQUE grid. """ return self.__logical_location @logical_location.setter def logical_location(self, location): """! @brief Assign logical location to CLIQUE block. @param[in] location (list): New logical location of the block in CLIQUE grid. """ self.__logical_location = location @property def spatial_location(self): """! @brief Spatial location is represented by real data space coordinates. @return (spatial_block) Spatial block that describes location in data space. """ return self.__spatial_location @spatial_location.setter def spatial_location(self, location): """! @brief Assign spatial location to CLIQUE block. @param[in] location (spatial_block): New spatial location of the block. """ self.__spatial_location = location @property def dimensions(self): """! @brief Amount of dimensions where CLIQUE block is located. @return (uint) Amount of dimensions where CLIQUE block is located. """ return len(self.__logical_location) @property def points(self): """! @brief Points that belong to the CLIQUE block. @details Points are represented by indexes that correspond to points in input data space. @return (array_like) Points that belong to the CLIQUE block. @see capture_points """ return self.__points @property def visited(self): """! @brief Defines whether block is visited during cluster analysis. @details If cluster analysis has not been performed then value will False. @return (bool) True if block has been visited during processing, False otherwise. """ return self.__visited @visited.setter def visited(self, visited): """! @brief Marks or unmarks block as a visited. @details This setter is used by CLIQUE algorithm. @param[in] visited (bool): New visited state for the CLIQUE block. """ self.__visited = visited def capture_points(self, data, point_availability): """! @brief Finds points that belong to this block using availability map to reduce computational complexity by checking whether the point belongs to the block. @details Algorithm complexity of this method is O(n). @param[in] data (array_like): Data where points are represented as coordinates. @param[in] point_availability (array_like): Contains boolean values that denote whether point is already belong to another CLIQUE block. """ for index_point in range(len(data)): if (point_availability[index_point] is True) and (data[index_point] in self.__spatial_location): self.__points.append(index_point) point_availability[index_point] = False def get_location_neighbors(self, edge): """! @brief Forms list of logical location of each neighbor for this particular CLIQUE block. @param[in] edge (uint): Amount of intervals in each dimension that is used for clustering process. @return (list) Logical location of each neighbor for this particular CLIQUE block. """ neighbors = [] for index_dimension in range(len(self.__logical_location)): if self.__logical_location[index_dimension] + 1 < edge: position = self.__logical_location[:] position[index_dimension] += 1 neighbors.append(position) if self.__logical_location[index_dimension] - 1 >= 0: position = self.__logical_location[:] position[index_dimension] -= 1 neighbors.append(position) return neighbors class coordinate_iterator: """! @brief Coordinate iterator is used to generate logical location description for each CLIQUE block. @details This class is used by CLIQUE algorithm for clustering process. """ def __init__(self, dimension, intervals): """! @brief Initializes coordinate iterator for CLIQUE algorithm. @param[in] dimension (uint): Amount of dimensions in input data space. @param[in] intervals (uint): Amount of intervals in each dimension. """ self.__intervals = intervals self.__dimension = dimension self.__coordiate = [0] * dimension def get_coordinate(self): """! @brief Returns current block coordinate. """ return self.__coordiate def increment(self): """! @brief Forms logical location for next block. """ for index_dimension in range(self.__dimension): if self.__coordiate[index_dimension] + 1 < self.__intervals: self.__coordiate[index_dimension] += 1 return else: self.__coordiate[index_dimension] = 0 self.__coordiate = None class clique: """! @brief Class implements CLIQUE grid based clustering algorithm. @details CLIQUE automatically finds subspaces with high-density clusters. It produces identical results irrespective of the order in which the input records are presented and it does not presume any canonical distribution for input data @cite article::clique::1. Here is an example where data in two-dimensional space is clustered using CLIQUE algorithm: @code from pyclustering.cluster.clique import clique, clique_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # read two-dimensional input data 'Target' data = read_sample(FCPS_SAMPLES.SAMPLE_TARGET) # create CLIQUE algorithm for processing intervals = 10 # defines amount of cells in grid in each dimension threshold = 0 # lets consider each point as non-outlier clique_instance = clique(data, intervals, threshold) # start clustering process and obtain results clique_instance.process() clusters = clique_instance.get_clusters() # allocated clusters noise = clique_instance.get_noise() # points that are considered as outliers (in this example should be empty) cells = clique_instance.get_cells() # CLIQUE blocks that forms grid print("Amount of clusters:", len(clusters)) # visualize clustering results clique_visualizer.show_grid(cells, data) # show grid that has been formed by the algorithm clique_visualizer.show_clusters(data, clusters, noise) # show clustering results @endcode In this example 6 clusters are allocated including four small cluster where each such small cluster consists of three points. There are visualized clustering results - grid that has been formed by CLIQUE algorithm with density and clusters itself: @image html clique_clustering_target.png "Fig. 1. CLIQUE clustering results (grid and clusters itself)." Sometimes such small clusters should be considered as outliers taking into account fact that two clusters in the central are relatively huge. To treat them as a noise threshold value should be increased: @code intervals = 10 threshold = 3 # block that contains 3 or less points is considered as a outlier as well as its points clique_instance = clique(data, intervals, threshold) @endcode Two clusters are allocated, but in this case some points in cluster-"circle" are also considered as outliers, because CLIQUE operates with blocks, not with points: @image html clique_clustering_with_noise.png "Fig. 2. Noise allocation by CLIQUE." """ def __init__(self, data, amount_intervals, density_threshold, **kwargs): """! @brief Create CLIQUE clustering algorithm. @param[in] data (list): Input data (list of points) that should be clustered. @param[in] amount_intervals (uint): Amount of intervals in each dimension that defines amount of CLIQUE blocks as \f[N_{blocks} = intervals^{dimensions}\f]. @param[in] density_threshold (uint): Minimum number of points that should contain CLIQUE block to consider its points as non-outliers. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'ccore'). Keyword Args:
- ccore (bool): By default is True. If True then C++ implementation is used for cluster analysis, otherwise Python implementation is used. """ self.__data = data self.__amount_intervals = amount_intervals self.__density_threshold = density_threshold self.__ccore = kwargs.get('ccore', True) if self.__ccore: self.__ccore = ccore_library.workable() self.__clusters = [] self.__noise = [] self.__cells = [] self.__cells_map = {} self.__validate_arguments() def process(self): """! @brief Performs clustering process in line with rules of CLIQUE clustering algorithm. @return (clique) Returns itself (CLIQUE instance). @see get_clusters() @see get_noise() @see get_cells() """ if self.__ccore: self.__process_by_ccore() else: self.__process_by_python() return self def get_clusters(self): """! @brief Returns allocated clusters. @remark Allocated clusters are returned only after data processing (method process()). Otherwise empty list is returned. @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_noise() """ return self.__clusters def get_noise(self): """! @brief Returns allocated noise. @remark Allocated noise is returned only after data processing (method process()). Otherwise empty list is returned. @return (list) List of indexes that are marked as a noise. @see process() @see get_clusters() """ return self.__noise def get_cells(self): """! @brief Returns CLIQUE blocks that are formed during clustering process. @details CLIQUE blocks can be used for visualization purposes. Each CLIQUE block contain its logical location in grid, spatial location in data space and points that belong to block. @return (list) List of CLIQUE blocks. """ return self.__cells def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __process_by_ccore(self): """! @brief Performs cluster analysis using C++ implementation of CLIQUE algorithm that is used by default if user's target platform is supported. """ result = wrapper.clique(self.__data, self.__amount_intervals, self.__density_threshold) (self.__clusters, self.__noise, block_logical_locations, max_corners, min_corners, block_points) = result amount_cells = len(block_logical_locations) for i in range(amount_cells): self.__cells.append(clique_block(block_logical_locations[i], spatial_block(max_corners[i], min_corners[i]), block_points[i], True)) def __process_by_python(self): """! @brief Performs cluster analysis using Python implementation of CLIQUE algorithm. """ self.__create_grid() self.__allocate_clusters() self.__cells_map.clear() def __validate_arguments(self): """! @brief Check input arguments of CLIQUE algorithm and if one of them is not correct then appropriate exception is thrown. """ if len(self.__data) == 0: raise ValueError("Empty input data. Data should contain at least one point.") if self.__amount_intervals <= 0: raise ValueError("Incorrect amount of intervals '%d'. Amount of intervals value should be greater than 0." % self.__amount_intervals) if self.__density_threshold < 0: raise ValueError("Incorrect density threshold '%f'. Density threshold should not be negative." % self.__density_threshold) def __allocate_clusters(self): """! @brief Performs cluster analysis using formed CLIQUE blocks. """ for cell in self.__cells: if cell.visited is False: self.__expand_cluster(cell) def __expand_cluster(self, cell): """! @brief Tries to expand cluster from specified cell. @details During expanding points are marked as noise or append to new cluster. @param[in] cell (clique_block): CLIQUE block from that cluster should be expanded. """ cell.visited = True if len(cell.points) <= self.__density_threshold: if len(cell.points) > 0: self.__noise.extend(cell.points) return cluster = cell.points[:] neighbors = self.__get_neighbors(cell) for neighbor in neighbors: if len(neighbor.points) > self.__density_threshold: cluster.extend(neighbor.points) neighbors += self.__get_neighbors(neighbor) elif len(neighbor.points) > 0: self.__noise.extend(neighbor.points) self.__clusters.append(cluster) def __get_neighbors(self, cell): """! @brief Returns neighbors for specified CLIQUE block as clique_block objects. @return (list) Neighbors as clique_block objects. """ neighbors = [] location_neighbors = cell.get_location_neighbors(self.__amount_intervals) for i in range(len(location_neighbors)): key = self.__location_to_key(location_neighbors[i]) candidate_neighbor = self.__cell_map[key] if not candidate_neighbor.visited: candidate_neighbor.visited = True neighbors.append(candidate_neighbor) return neighbors def __create_grid(self): """! @brief Creates CLIQUE grid that consists of CLIQUE blocks for clustering process. """ data_sizes, min_corner, max_corner = self.__get_data_size_derscription() dimension = len(self.__data[0]) cell_sizes = [dimension_length / self.__amount_intervals for dimension_length in data_sizes] self.__cells = [clique_block() for _ in range(pow(self.__amount_intervals, dimension))] iterator = coordinate_iterator(dimension, self.__amount_intervals) point_availability = [True] * len(self.__data) self.__cell_map = {} for index_cell in range(len(self.__cells)): logical_location = iterator.get_coordinate() iterator.increment() self.__cells[index_cell].logical_location = logical_location[:] cur_max_corner, cur_min_corner = self.__get_spatial_location(logical_location, min_corner, max_corner, cell_sizes) self.__cells[index_cell].spatial_location = spatial_block(cur_max_corner, cur_min_corner) self.__cells[index_cell].capture_points(self.__data, point_availability) self.__cell_map[self.__location_to_key(logical_location)] = self.__cells[index_cell] def __location_to_key(self, location): """! @brief Forms key using logical location of a CLIQUE block. @return (string) Key for CLIQUE block map. """ return ''.join(str(e) + '.' for e in location) def __get_spatial_location(self, logical_location, min_corner, max_corner, cell_sizes): """! @brief Calculates spatial location for CLIQUE block with logical coordinates defined by logical_location. @param[in] logical_location (list): Logical location of CLIQUE block for that spatial location should be calculated. @param[in] min_corner (list): Minimum corner of an input data. @param[in] max_corner (list): Maximum corner of an input data. @param[in] cell_sizes (list): Size of CLIQUE block in each dimension. @return (list, list): Maximum and minimum corners for the specified CLIQUE block. """ cur_min_corner = min_corner[:] cur_max_corner = min_corner[:] dimension = len(self.__data[0]) for index_dimension in range(dimension): cur_min_corner[index_dimension] += cell_sizes[index_dimension] * logical_location[index_dimension] if logical_location[index_dimension] == self.__amount_intervals - 1: cur_max_corner[index_dimension] = max_corner[index_dimension] else: cur_max_corner[index_dimension] = cur_min_corner[index_dimension] + cell_sizes[index_dimension] return cur_max_corner, cur_min_corner def __get_data_size_derscription(self): """! @brief Calculates input data description that is required to create CLIQUE grid. @return (list, list, list): Data size in each dimension, minimum and maximum corners. """ min_corner = self.__data[0][:] max_corner = self.__data[0][:] dimension = len(self.__data[0]) for index_point in range(1, len(self.__data)): for index_dimension in range(dimension): coordinate = self.__data[index_point][index_dimension] if coordinate > max_corner[index_dimension]: max_corner[index_dimension] = coordinate if coordinate < min_corner[index_dimension]: min_corner[index_dimension] = coordinate data_sizes = [0.0] * dimension for index_dimension in range(dimension): data_sizes[index_dimension] = max_corner[index_dimension] - min_corner[index_dimension] return data_sizes, min_corner, max_corner pyclustering-0.10.1.2/pyclustering/cluster/cure.py000077500000000000000000000475671375753423500222460ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: CURE @details Implementation based on paper @cite article::cure::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from pyclustering.cluster.encoder import type_encoding from pyclustering.utils import euclidean_distance_square from pyclustering.container.kdtree import kdtree from pyclustering.core.wrapper import ccore_library import pyclustering.core.cure_wrapper as wrapper class cure_cluster: """! @brief Represents data cluster in CURE term. @details CURE cluster is described by points of cluster, representation points of the cluster and by the cluster center. """ def __init__(self, point, index): """! @brief Constructor of CURE cluster. @param[in] point (list): Point represented by list of coordinates. @param[in] index (uint): Index point in dataset. """ ## List of points that make up cluster. self.points = [ ] ## Point indexes in dataset. self.indexes = -1 ## Mean of points that make up cluster. self.mean = None ## List of points that represents clusters. self.rep = [ ] if point is not None: self.points = [ point ] self.indexes = [ index ] self.mean = point self.rep = [ point ] ## Pointer to the closest cluster. self.closest = None ## Distance to the closest cluster. self.distance = float('inf') # calculation of distance is really complexity operation (even square distance), so let's store distance to closest cluster. def __repr__(self): """! @brief Displays distance to closest cluster and points that are contained by current cluster. """ return "%s, %s" % (self.distance, self.points) class cure: """! @brief Class represents clustering algorithm CURE with KD-tree optimization. @details CCORE option can be used to use the pyclustering core - C/C++ shared library for processing that significantly increases performance. Here is an example how to perform cluster analysis of sample 'Lsun': @code from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.cure import cure; from pyclustering.utils import read_sample; from pyclustering.samples.definitions import FCPS_SAMPLES; # Input data in following format [ [0.1, 0.5], [0.3, 0.1], ... ]. input_data = read_sample(FCPS_SAMPLES.SAMPLE_LSUN); # Allocate three clusters. cure_instance = cure(input_data, 3); cure_instance.process(); clusters = cure_instance.get_clusters(); # Visualize allocated clusters. visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, input_data); visualizer.show(); @endcode """ def __init__(self, data, number_cluster, number_represent_points = 5, compression = 0.5, ccore = True): """! @brief Constructor of clustering algorithm CURE. @param[in] data (array_like): Input data that should be processed. @param[in] number_cluster (uint): Number of clusters that should be allocated. @param[in] number_represent_points (uint): Number of representative points for each cluster. @param[in] compression (double): Coefficient defines level of shrinking of representation points toward the mean of the new created cluster after merging on each step. Usually it destributed from 0 to 1. @param[in] ccore (bool): If True then CCORE (C++ solution) will be used for solving. """ self.__pointer_data = self.__prepare_data_points(data) self.__clusters = None self.__representors = None self.__means = None self.__number_cluster = number_cluster self.__number_represent_points = number_represent_points self.__compression = compression self.__ccore = ccore if self.__ccore: self.__ccore = ccore_library.workable() self.__validate_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of CURE algorithm. @return (cure) Returns itself (CURE instance). @see get_clusters() """ if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library). """ cure_data_pointer = wrapper.cure_algorithm(self.__pointer_data, self.__number_cluster, self.__number_represent_points, self.__compression) self.__clusters = wrapper.cure_get_clusters(cure_data_pointer) self.__representors = wrapper.cure_get_representors(cure_data_pointer) self.__means = wrapper.cure_get_means(cure_data_pointer) wrapper.cure_data_destroy(cure_data_pointer) def __process_by_python(self): """! @brief Performs cluster analysis using python code. """ self.__create_queue() # queue self.__create_kdtree() # create k-d tree while len(self.__queue) > self.__number_cluster: cluster1 = self.__queue[0] # cluster that has nearest neighbor. cluster2 = cluster1.closest # closest cluster. self.__queue.remove(cluster1) self.__queue.remove(cluster2) self.__delete_represented_points(cluster1) self.__delete_represented_points(cluster2) merged_cluster = self.__merge_clusters(cluster1, cluster2) self.__insert_represented_points(merged_cluster) # Pointers to clusters that should be relocated is stored here. cluster_relocation_requests = [] # Check for the last cluster if len(self.__queue) > 0: merged_cluster.closest = self.__queue[0] # arbitrary cluster from queue merged_cluster.distance = self.__cluster_distance(merged_cluster, merged_cluster.closest) for item in self.__queue: distance = self.__cluster_distance(merged_cluster, item) # Check if distance between new cluster and current is the best than now. if distance < merged_cluster.distance: merged_cluster.closest = item merged_cluster.distance = distance # Check if current cluster has removed neighbor. if (item.closest is cluster1) or (item.closest is cluster2): # If previous distance was less then distance to new cluster then nearest cluster should # be found in the tree. if item.distance < distance: (item.closest, item.distance) = self.__closest_cluster(item, distance) # TODO: investigation is required. There is assumption that itself and merged cluster # should be always in list of neighbors in line with specified radius. But merged cluster # may not be in list due to error calculation, therefore it should be added manually. if item.closest is None: item.closest = merged_cluster item.distance = distance else: item.closest = merged_cluster item.distance = distance cluster_relocation_requests.append(item) # New cluster and updated clusters should relocated in queue self.__insert_cluster(merged_cluster) for item in cluster_relocation_requests: self.__relocate_cluster(item) # Change cluster representation self.__clusters = [cure_cluster_unit.indexes for cure_cluster_unit in self.__queue] self.__representors = [cure_cluster_unit.rep for cure_cluster_unit in self.__queue] self.__means = [cure_cluster_unit.mean for cure_cluster_unit in self.__queue] def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @return (list) List of allocated clusters. @see process() @see get_representors() @see get_means() """ return self.__clusters def get_representors(self): """! @brief Returns list of point-representors of each cluster. @details Cluster index should be used for navigation between lists of point-representors. @return (list) List of point-representors of each cluster. @see get_clusters() @see get_means() """ return self.__representors def get_means(self): """! @brief Returns list of mean values of each cluster. @details Cluster index should be used for navigation between mean values. @return (list) List of mean values of each cluster. @see get_clusters() @see get_representors() """ return self.__means def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __prepare_data_points(self, sample): """! @brief Prepare data points for clustering. @details In case of numpy.array there are a lot of overloaded basic operators, such as __contains__, __eq__. @return (list) Returns sample in list format. """ if isinstance(sample, numpy.ndarray): return sample.tolist() return sample def __validate_arguments(self): """! @brief Check input arguments of BANG algorithm and if one of them is not correct then appropriate exception is thrown. """ if len(self.__pointer_data) == 0: raise ValueError("Empty input data. Data should contain at least one point.") if self.__number_cluster <= 0: raise ValueError("Incorrect amount of clusters '%d'. Amount of cluster should be greater than 0." % self.__number_cluster) if self.__compression < 0: raise ValueError("Incorrect compression level '%f'. Compression should not be negative." % self.__compression) if self.__number_represent_points <= 0: raise ValueError("Incorrect amount of representatives '%d'. Amount of representatives should be greater than 0." % self.__number_cluster) def __insert_cluster(self, cluster): """! @brief Insert cluster to the list (sorted queue) in line with sequence order (distance). @param[in] cluster (cure_cluster): Cluster that should be inserted. """ for index in range(len(self.__queue)): if cluster.distance < self.__queue[index].distance: self.__queue.insert(index, cluster) return self.__queue.append(cluster) def __relocate_cluster(self, cluster): """! @brief Relocate cluster in list in line with distance order. @param[in] cluster (cure_cluster): Cluster that should be relocated in line with order. """ self.__queue.remove(cluster) self.__insert_cluster(cluster) def __closest_cluster(self, cluster, distance): """! @brief Find closest cluster to the specified cluster in line with distance. @param[in] cluster (cure_cluster): Cluster for which nearest cluster should be found. @param[in] distance (double): Closest distance to the previous cluster. @return (tuple) Pair (nearest CURE cluster, nearest distance) if the nearest cluster has been found, otherwise None is returned. """ nearest_cluster = None nearest_distance = float('inf') real_euclidean_distance = distance ** 0.5 for point in cluster.rep: # Nearest nodes should be returned (at least it will return itself). nearest_nodes = self.__tree.find_nearest_dist_nodes(point, real_euclidean_distance) for (candidate_distance, kdtree_node) in nearest_nodes: if (candidate_distance < nearest_distance) and (kdtree_node is not None) and (kdtree_node.payload is not cluster): nearest_distance = candidate_distance nearest_cluster = kdtree_node.payload return (nearest_cluster, nearest_distance) def __insert_represented_points(self, cluster): """! @brief Insert representation points to the k-d tree. @param[in] cluster (cure_cluster): Cluster whose representation points should be inserted. """ for point in cluster.rep: self.__tree.insert(point, cluster) def __delete_represented_points(self, cluster): """! @brief Remove representation points of clusters from the k-d tree @param[in] cluster (cure_cluster): Cluster whose representation points should be removed. """ for point in cluster.rep: self.__tree.remove(point, payload=cluster) def __merge_clusters(self, cluster1, cluster2): """! @brief Merges two clusters and returns new merged cluster. Representation points and mean points are calculated for the new cluster. @param[in] cluster1 (cure_cluster): Cluster that should be merged. @param[in] cluster2 (cure_cluster): Cluster that should be merged. @return (cure_cluster) New merged CURE cluster. """ merged_cluster = cure_cluster(None, None) merged_cluster.points = cluster1.points + cluster2.points merged_cluster.indexes = cluster1.indexes + cluster2.indexes # merged_cluster.mean = ( len(cluster1.points) * cluster1.mean + len(cluster2.points) * cluster2.mean ) / ( len(cluster1.points) + len(cluster2.points) ); dimension = len(cluster1.mean) merged_cluster.mean = [0] * dimension if merged_cluster.points[1:] == merged_cluster.points[:-1]: merged_cluster.mean = merged_cluster.points[0] else: for index in range(dimension): merged_cluster.mean[index] = ( len(cluster1.points) * cluster1.mean[index] + len(cluster2.points) * cluster2.mean[index] ) / ( len(cluster1.points) + len(cluster2.points) ); temporary = list() for index in range(self.__number_represent_points): maximal_distance = 0 maximal_point = None for point in merged_cluster.points: minimal_distance = 0 if index == 0: minimal_distance = euclidean_distance_square(point, merged_cluster.mean) #minimal_distance = euclidean_distance_sqrt(point, merged_cluster.mean); else: minimal_distance = min([euclidean_distance_square(point, p) for p in temporary]) #minimal_distance = cluster_distance(cure_cluster(point), cure_cluster(temporary[0])); if minimal_distance >= maximal_distance: maximal_distance = minimal_distance maximal_point = point if maximal_point not in temporary: temporary.append(maximal_point) for point in temporary: representative_point = [0] * dimension for index in range(dimension): representative_point[index] = point[index] + self.__compression * (merged_cluster.mean[index] - point[index]) merged_cluster.rep.append(representative_point) return merged_cluster def __create_queue(self): """! @brief Create queue of sorted clusters by distance between them, where first cluster has the nearest neighbor. At the first iteration each cluster contains only one point. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @return (list) Create queue of sorted clusters by distance between them. """ self.__queue = [cure_cluster(self.__pointer_data[index_point], index_point) for index_point in range(len(self.__pointer_data))] # set closest clusters for i in range(0, len(self.__queue)): minimal_distance = float('inf') closest_index_cluster = -1 for k in range(0, len(self.__queue)): if i != k: dist = self.__cluster_distance(self.__queue[i], self.__queue[k]) if dist < minimal_distance: minimal_distance = dist closest_index_cluster = k self.__queue[i].closest = self.__queue[closest_index_cluster] self.__queue[i].distance = minimal_distance # sort clusters self.__queue.sort(key=lambda x: x.distance, reverse = False) def __create_kdtree(self): """! @brief Create k-d tree in line with created clusters. At the first iteration contains all points from the input data set. @return (kdtree) k-d tree that consist of representative points of CURE clusters. """ representatives, payloads = [], [] for current_cluster in self.__queue: for representative_point in current_cluster.rep: representatives.append(representative_point) payloads.append(current_cluster) # initialize it using constructor to have balanced tree at the beginning to ensure the highest performance # when we have the biggest amount of nodes in the tree. self.__tree = kdtree(representatives, payloads) def __cluster_distance(self, cluster1, cluster2): """! @brief Calculate minimal distance between clusters using representative points. @param[in] cluster1 (cure_cluster): The first cluster. @param[in] cluster2 (cure_cluster): The second cluster. @return (double) Euclidean distance between two clusters that is defined by minimum distance between representation points of two clusters. """ distance = float('inf') for i in range(0, len(cluster1.rep)): for k in range(0, len(cluster2.rep)): dist = euclidean_distance_square(cluster1.rep[i], cluster2.rep[k]) # Fast mode if dist < distance: distance = dist return distance pyclustering-0.10.1.2/pyclustering/cluster/dbscan.py000077500000000000000000000250471375753423500225270ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: DBSCAN. @details Implementation based on paper @cite inproceedings::dbscan::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.container.kdtree import kdtree_balanced from pyclustering.cluster.encoder import type_encoding from pyclustering.core.wrapper import ccore_library import pyclustering.core.dbscan_wrapper as wrapper class dbscan: """! @brief Class represents clustering algorithm DBSCAN. @details This DBSCAN algorithm is KD-tree optimized. By default C/C++ pyclustering library is used for processing that significantly increases performance. Clustering example where DBSCAN algorithm is used to process `Chainlink` data from `FCPS` collection: @code from pyclustering.cluster.dbscan import dbscan from pyclustering.cluster import cluster_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Sample for cluster analysis. sample = read_sample(FCPS_SAMPLES.SAMPLE_CHAINLINK) # Create DBSCAN algorithm. dbscan_instance = dbscan(sample, 0.7, 3) # Start processing by DBSCAN. dbscan_instance.process() # Obtain results of clustering. clusters = dbscan_instance.get_clusters() noise = dbscan_instance.get_noise() # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(noise, sample, marker='x') visualizer.show() @endcode """ def __init__(self, data, eps, neighbors, ccore=True, **kwargs): """! @brief Constructor of clustering algorithm DBSCAN. @param[in] data (list): Input data that is presented as list of points or distance matrix (defined by parameter 'data_type', by default data is considered as a list of points). @param[in] eps (double): Connectivity radius between points, points may be connected if distance between them less then the radius. @param[in] neighbors (uint): minimum number of shared neighbors that is required for establish links between points. @param[in] ccore (bool): if True than DLL CCORE (C++ solution) will be used for solving the problem. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'data_type'). Keyword Args:
- data_type (string): Data type of input sample 'data' that is processed by the algorithm ('points', 'distance_matrix'). """ self.__pointer_data = data self.__kdtree = None self.__eps = eps self.__sqrt_eps = eps * eps self.__neighbors = neighbors self.__visited = None self.__belong = None self.__data_type = kwargs.get('data_type', 'points') self.__clusters = [] self.__noise = [] self.__neighbor_searcher = None self.__initialize_ccore_state(ccore) self.__verify_arguments() def __getstate__(self): """! @brief Returns current state of the algorithm. @details It does not return internal temporal variables that are not visible for a user. @return (tuple) Current state of the algorithm. """ return (self.__pointer_data, self.__eps, self.__sqrt_eps, self.__neighbors, self.__visited, self.__belong, self.__data_type, self.__clusters, self.__noise, self.__ccore) def __setstate__(self, state): """! @brief Set current state of the algorithm. @details Set state method checks if C++ pyclustering is available for the current platform, as a result `ccore` state might be different if state is moved between platforms. """ self.__pointer_data, self.__eps, self.__sqrt_eps, self.__neighbors, self.__visited, self.__belong, \ self.__data_type, self.__clusters, self.__noise, self.__ccore = state self.__initialize_ccore_state(True) def process(self): """! @brief Performs cluster analysis in line with rules of DBSCAN algorithm. @return (dbscan) Returns itself (DBSCAN instance). @see get_clusters() @see get_noise() """ if self.__ccore is True: (self.__clusters, self.__noise) = wrapper.dbscan(self.__pointer_data, self.__eps, self.__neighbors, self.__data_type) else: if self.__data_type == 'points': self.__kdtree = kdtree_balanced(self.__pointer_data, range(len(self.__pointer_data))) self.__visited = [False] * len(self.__pointer_data) self.__belong = [False] * len(self.__pointer_data) self.__neighbor_searcher = self.__create_neighbor_searcher(self.__data_type) for i in range(0, len(self.__pointer_data)): if self.__visited[i] is False: cluster = self.__expand_cluster(i) if cluster is not None: self.__clusters.append(cluster) for i in range(0, len(self.__pointer_data)): if self.__belong[i] is False: self.__noise.append(i) return self def get_clusters(self): """! @brief Returns allocated clusters. @remark Allocated clusters can be returned only after data processing (use method process()). Otherwise empty list is returned. @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_noise() """ return self.__clusters def get_noise(self): """! @brief Returns allocated noise. @remark Allocated noise can be returned only after data processing (use method process() before). Otherwise empty list is returned. @return (list) List of indexes that are marked as a noise. @see process() @see get_clusters() """ return self.__noise def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if self.__eps < 0: raise ValueError("Connectivity radius (current value: '%d') should be greater or equal to 0." % self.__eps) def __create_neighbor_searcher(self, data_type): """! @brief Returns neighbor searcher in line with data type. @param[in] data_type (string): Data type (points or distance matrix). """ if data_type == 'points': return self.__neighbor_indexes_points elif data_type == 'distance_matrix': return self.__neighbor_indexes_distance_matrix else: raise TypeError("Unknown type of data is specified '%s'" % data_type) def __expand_cluster(self, index_point): """! @brief Expands cluster from specified point in the input data space. @param[in] index_point (list): Index of a point from the data. @return (list) Return tuple of list of indexes that belong to the same cluster and list of points that are marked as noise: (cluster, noise), or None if nothing has been expanded. """ cluster = None self.__visited[index_point] = True neighbors = self.__neighbor_searcher(index_point) if len(neighbors) >= self.__neighbors: cluster = [index_point] self.__belong[index_point] = True for i in neighbors: if self.__visited[i] is False: self.__visited[i] = True next_neighbors = self.__neighbor_searcher(i) if len(next_neighbors) >= self.__neighbors: neighbors += [k for k in next_neighbors if ( (k in neighbors) == False) and k != index_point] if self.__belong[i] is False: cluster.append(i) self.__belong[i] = True return cluster def __neighbor_indexes_points(self, index_point): """! @brief Return neighbors of the specified object in case of sequence of points. @param[in] index_point (uint): Index point whose neighbors are should be found. @return (list) List of indexes of neighbors in line the connectivity radius. """ kdnodes = self.__kdtree.find_nearest_dist_nodes(self.__pointer_data[index_point], self.__eps) return [node_tuple[1].payload for node_tuple in kdnodes if node_tuple[1].payload != index_point] def __neighbor_indexes_distance_matrix(self, index_point): """! @brief Return neighbors of the specified object in case of distance matrix. @param[in] index_point (uint): Index point whose neighbors are should be found. @return (list) List of indexes of neighbors in line the connectivity radius. """ distances = self.__pointer_data[index_point] return [index_neighbor for index_neighbor in range(len(distances)) if ((distances[index_neighbor] <= self.__eps) and (index_neighbor != index_point))] def __initialize_ccore_state(self, ccore): """! @brief Initializes C++ pyclustering state. @details Check if it is requested and if it is available for the current platform. These information is used to set status of C++ pyclustering library. @param[in] ccore (bool): """ self.__ccore = ccore if self.__ccore: self.__ccore = ccore_library.workable() pyclustering-0.10.1.2/pyclustering/cluster/elbow.py000077500000000000000000000230711375753423500224000ustar00rootroot00000000000000"""! @brief Elbow method to determine the optimal number of clusters for k-means clustering. @details Implementation based on paper @cite article::cluster::elbow::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer, random_center_initializer from pyclustering.core.wrapper import ccore_library import pyclustering.core.elbow_wrapper as wrapper class elbow: """! @brief Class represents Elbow method that is used to find out appropriate amount of clusters in a dataset. @details The elbow is a heuristic method of interpretation and validation of consistency within cluster analysis designed to help find the appropriate number of clusters in a dataset.Elbow method performs clustering using K-Means algorithm for each K and estimate clustering results using sum of square erros. By default K-Means++ algorithm is used to calculate initial centers that are used by K-Means algorithm. The Elbow is determined by max distance from each point (x, y) to segment from kmin-point (x0, y0) to kmax-point (x1, y1), where 'x' is K (amount of clusters), and 'y' is within-cluster error. Following expression is used to calculate Elbow length: \f[Elbow_{k} = \frac{\left ( y_{0} - y_{1} \right )x_{k} + \left ( x_{1} - x_{0} \right )y_{k} + \left ( x_{0}y_{1} - x_{1}y_{0} \right )}{\sqrt{\left ( x_{1} - x_{0} \right )^{2} + \left ( y_{1} - y_{0} \right )^{2}}}\f] Usage example of Elbow method for cluster analysis: @code from pyclustering.cluster.kmeans import kmeans, kmeans_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.elbow import elbow from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # read sample 'Simple3' from file (sample contains four clusters) sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # create instance of Elbow method using K value from 1 to 10. kmin, kmax = 1, 10 elbow_instance = elbow(sample, kmin, kmax) # process input data and obtain results of analysis elbow_instance.process() amount_clusters = elbow_instance.get_amount() # most probable amount of clusters wce = elbow_instance.get_wce() # total within-cluster errors for each K # perform cluster analysis using K-Means algorithm centers = kmeans_plusplus_initializer(sample, amount_clusters, amount_candidates=kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE).initialize() kmeans_instance = kmeans(sample, centers) kmeans_instance.process() # obtain clustering results and visualize them clusters = kmeans_instance.get_clusters() centers = kmeans_instance.get_centers() kmeans_visualizer.show_clusters(sample, clusters, centers) @endcode By default Elbow uses K-Means++ initializer to calculate initial centers for K-Means algorithm, it can be changed using argument 'initializer': @code # perform analysis using Elbow method with random center initializer for K-Means algorithm inside of the method. kmin, kmax = 1, 10 elbow_instance = elbow(sample, kmin, kmax, initializer=random_center_initializer) elbow_instance.process() @endcode @image html elbow_example_simple_03.png "Elbows analysis with further K-Means clustering." """ def __init__(self, data, kmin, kmax, **kwargs): """! @brief Construct Elbow method. @param[in] data (array_like): Input data that is presented as array of points (objects), each point should be represented by array_like data structure. @param[in] kmin (int): Minimum amount of clusters that should be considered. @param[in] kmax (int): Maximum amount of clusters that should be considered. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `ccore`, `initializer`, `random_state`, `kstep`). Keyword Args:
- ccore (bool): If `True` then C++ implementation of pyclustering library is used (by default `True`). - initializer (callable): Center initializer that is used by K-Means algorithm (by default K-Means++). - random_state (int): Seed for random state (by default is `None`, current system time is used). - kstep (int): Search step in the interval [kmin, kmax] (by default is `1`). """ self.__initializer = kwargs.get('initializer', kmeans_plusplus_initializer) self.__random_state = kwargs.get('random_state', None) self.__kstep = kwargs.get('kstep', 1) self.__ccore = kwargs.get('ccore', True) or \ isinstance(self.__initializer, kmeans_plusplus_initializer) or \ isinstance(self.__initializer, random_center_initializer) if self.__ccore: self.__ccore = ccore_library.workable() self.__data = data self.__kmin = kmin self.__kmax = kmax self.__wce = [] self.__elbows = [] self.__kvalue = -1 self.__verify_arguments() def process(self): """! @brief Performs analysis to find out appropriate amount of clusters. @return (elbow) Returns itself (Elbow instance). @return """ if self.__ccore: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs processing using C++ implementation. """ if isinstance(self.__initializer, kmeans_plusplus_initializer): initializer = wrapper.elbow_center_initializer.KMEANS_PLUS_PLUS else: initializer = wrapper.elbow_center_initializer.RANDOM result = wrapper.elbow(self.__data, self.__kmin, self.__kmax, self.__kstep, initializer, self.__random_state) self.__kvalue = result[0] self.__wce = result[1] def __process_by_python(self): """! @brief Performs processing using python implementation. """ for amount in range(self.__kmin, self.__kmax + 1, self.__kstep): centers = self.__initializer(self.__data, amount, random_state=self.__random_state).initialize() instance = kmeans(self.__data, centers, ccore=False) instance.process() self.__wce.append(instance.get_total_wce()) self.__calculate_elbows() self.__find_optimal_kvalue() def get_amount(self): """! @brief Returns appropriate amount of clusters. """ return self.__kvalue def get_wce(self): """! @brief Returns list of total within cluster errors for each K-value, for example, in case of `kstep = 1`: (kmin, kmin + 1, ..., kmax). """ return self.__wce def __calculate_elbows(self): """! @brief Calculates potential elbows. @details Elbow is calculated as a distance from each point (x, y) to segment from kmin-point (x0, y0) to kmax-point (x1, y1). """ x0, y0 = 0.0, self.__wce[0] x1, y1 = float(len(self.__wce)), self.__wce[-1] for index_elbow in range(1, len(self.__wce) - 1): x, y = float(index_elbow), self.__wce[index_elbow] segment = abs((y0 - y1) * x + (x1 - x0) * y + (x0 * y1 - x1 * y0)) norm = math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2) distance = segment / norm self.__elbows.append(distance) def __find_optimal_kvalue(self): """! @brief Finds elbow and returns corresponding K-value. """ optimal_elbow_value = max(self.__elbows) self.__kvalue = (self.__elbows.index(optimal_elbow_value) + 1) * self.__kstep + self.__kmin def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data)) if self.__kmin < 1: raise ValueError("K min value (current value '%d') should be greater or equal to 1." % self.__kmin) if self.__kstep < 1: raise ValueError("K step value (current value '%d') should be greater or equal to 1." % self.__kstep) if self.__kmax - self.__kmin + 1 < 3: raise ValueError("Amount of K (" + str(self.__kmax - self.__kmin) + ") is too small for analysis. " "It is require to have at least three K to build elbow.") steps_to_process = math.floor((self.__kmax - self.__kmin) / self.__kstep) + 1 if steps_to_process < 3: raise ValueError("The search step is too high '%d' for analysis (amount of K for analysis is '%d'). " "It is require to have at least three K to build elbow." % (self.__kstep, steps_to_process)) if len(self.__data) < self.__kmax: raise ValueError("K max value '%d' is greater than amount of points in data '%d'." % (self.__kmax, len(self.__data))) pyclustering-0.10.1.2/pyclustering/cluster/ema.py000077500000000000000000000673471375753423500220500ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: Expectation-Maximization Algorithm for Gaussian Mixture Model. @details Implementation based on paper @cite article::ema::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import random from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.kmeans import kmeans from pyclustering.utils import pi, calculate_ellipse_description, euclidean_distance_square from enum import IntEnum import matplotlib.pyplot as plt import matplotlib.animation as animation from matplotlib import patches def gaussian(data, mean, covariance): """! @brief Calculates gaussian for dataset using specified mean (mathematical expectation) and variance or covariance in case multi-dimensional data. @param[in] data (list): Data that is used for gaussian calculation. @param[in] mean (float|numpy.array): Mathematical expectation used for calculation. @param[in] covariance (float|numpy.array): Variance or covariance matrix for calculation. @return (list) Value of gaussian function for each point in dataset. """ dimension = float(len(data[0])) if dimension != 1.0: inv_variance = numpy.linalg.pinv(covariance) else: inv_variance = 1.0 / covariance divider = (pi * 2.0) ** (dimension / 2.0) * numpy.sqrt(numpy.linalg.norm(covariance)) if divider != 0.0: right_const = 1.0 / divider else: right_const = float('inf') result = [] for point in data: mean_delta = point - mean point_gaussian = right_const * numpy.exp( -0.5 * mean_delta.dot(inv_variance).dot(numpy.transpose(mean_delta)) ) result.append(point_gaussian) return result class ema_init_type(IntEnum): """! @brief Enumeration of initialization types for Expectation-Maximization algorithm. """ ## Means are randomly taken from input dataset and variance or covariance is calculated based on ## spherical data that belongs to the chosen means. RANDOM_INITIALIZATION = 0 ## Two step initialization. The first is calculation of initial centers using K-Means++ method. ## The second is K-Means clustering using obtained centers in the first step. Obtained clusters ## and its centers are used for calculation of variance (covariance in case of multi-dimensional) ## data. KMEANS_INITIALIZATION = 1 class ema_initializer(): """! @brief Provides services for preparing initial means and covariances for Expectation-Maximization algorithm. @details Initialization strategy is defined by enumerator 'ema_init_type': random initialization and kmeans with kmeans++ initialization. Here an example of initialization using kmeans strategy: @code from pyclustering.utils import read_sample from pyclustering.samples.definitions import FAMOUS_SAMPLES from pyclustering.cluster.ema import ema_initializer sample = read_sample(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL) amount_clusters = 2 initial_means, initial_covariance = ema_initializer(sample, amount_clusters).initialize() print(initial_means) print(initial_covariance) @endcode """ __MAX_GENERATION_ATTEMPTS = 10 def __init__(self, sample, amount): """! @brief Constructs EM initializer. @param[in] sample (list): Data that will be used by the EM algorithm. @param[in] amount (uint): Amount of clusters that should be allocated by the EM algorithm. """ self.__sample = sample self.__amount = amount def initialize(self, init_type = ema_init_type.KMEANS_INITIALIZATION): """! @brief Calculates initial parameters for EM algorithm: means and covariances using specified strategy. @param[in] init_type (ema_init_type): Strategy for initialization. @return (float|list, float|numpy.array) Initial means and variance (covariance matrix in case multi-dimensional data). """ if init_type == ema_init_type.KMEANS_INITIALIZATION: return self.__initialize_kmeans() elif init_type == ema_init_type.RANDOM_INITIALIZATION: return self.__initialize_random() raise NameError("Unknown type of EM algorithm initialization is specified.") def __calculate_initial_clusters(self, centers): """! @brief Calculate Euclidean distance to each point from the each cluster. @brief Nearest points are captured by according clusters and as a result clusters are updated. @return (list) updated clusters as list of clusters. Each cluster contains indexes of objects from data. """ clusters = [[] for _ in range(len(centers))] for index_point in range(len(self.__sample)): index_optim, dist_optim = -1, 0.0 for index in range(len(centers)): dist = euclidean_distance_square(self.__sample[index_point], centers[index]) if (dist < dist_optim) or (index == 0): index_optim, dist_optim = index, dist clusters[index_optim].append(index_point) return clusters def __calculate_initial_covariances(self, initial_clusters): covariances = [] for initial_cluster in initial_clusters: if len(initial_cluster) > 1: cluster_sample = [self.__sample[index_point] for index_point in initial_cluster] covariances.append(numpy.cov(cluster_sample, rowvar=False)) else: dimension = len(self.__sample[0]) covariances.append(numpy.zeros((dimension, dimension)) + random.random() / 10.0) return covariances def __initialize_random(self): initial_means = [] for _ in range(self.__amount): mean = self.__sample[ random.randint(0, len(self.__sample)) - 1 ] attempts = 0 while (mean in initial_means) and (attempts < ema_initializer.__MAX_GENERATION_ATTEMPTS): mean = self.__sample[ random.randint(0, len(self.__sample)) - 1 ] attempts += 1 if attempts == ema_initializer.__MAX_GENERATION_ATTEMPTS: mean = [ value + (random.random() - 0.5) * value * 0.2 for value in mean ] initial_means.append(mean) initial_clusters = self.__calculate_initial_clusters(initial_means) initial_covariance = self.__calculate_initial_covariances(initial_clusters) return initial_means, initial_covariance def __initialize_kmeans(self): initial_centers = kmeans_plusplus_initializer(self.__sample, self.__amount).initialize() kmeans_instance = kmeans(self.__sample, initial_centers, ccore = True) kmeans_instance.process() means = kmeans_instance.get_centers() covariances = [] initial_clusters = kmeans_instance.get_clusters() for initial_cluster in initial_clusters: if len(initial_cluster) > 1: cluster_sample = [ self.__sample[index_point] for index_point in initial_cluster ] covariances.append(numpy.cov(cluster_sample, rowvar=False)) else: dimension = len(self.__sample[0]) covariances.append(numpy.zeros((dimension, dimension)) + random.random() / 10.0) return means, covariances class ema_observer: """! @brief Observer of EM algorithm for collecting algorithm state on each step. @details It can be used to obtain whole picture about clustering process of EM algorithm. Allocated clusters, means and covariances are stored in observer on each step. Here an example of usage: @code from pyclustering.cluster.ema import ema, ema_observer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read data from text file. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Create EM observer. observer = ema_observer() # Create EM algorithm to allocated four clusters and pass observer to it. ema_instance = ema(sample, 4, observer=observer) # Run clustering process. ema_instance.process() # Print amount of steps that were done by the algorithm. print("EMA steps:", observer.get_iterations()) # Print evolution of means and covariances. print("Means evolution:", observer.get_evolution_means()) print("Covariances evolution:", observer.get_evolution_covariances()) # Print evolution of clusters. print("Clusters evolution:", observer.get_evolution_clusters()) # Print final clusters. print("Allocated clusters:", observer.get_evolution_clusters()[-1]) @endcode """ def __init__(self): """! @brief Initializes EM observer. """ self.__means_evolution = [] self.__covariances_evolution = [] self.__clusters_evolution = [] def __len__(self): """! @return (uint) Amount of iterations that were done by the EM algorithm. """ return len(self.__means_evolution) def get_iterations(self): """! @return (uint) Amount of iterations that were done by the EM algorithm. """ return len(self.__means_evolution) def get_evolution_means(self): """! @return (list) Mean of each cluster on each step of clustering. """ return self.__means_evolution def get_evolution_covariances(self): """! @return (list) Covariance matrix (or variance in case of one-dimensional data) of each cluster on each step of clustering. """ return self.__covariances_evolution def get_evolution_clusters(self): """! @return (list) Allocated clusters on each step of clustering. """ return self.__clusters_evolution def notify(self, means, covariances, clusters): """! @brief This method is used by the algorithm to notify observer about changes where the algorithm should provide new values: means, covariances and allocated clusters. @param[in] means (list): Mean of each cluster on currect step. @param[in] covariances (list): Covariances of each cluster on current step. @param[in] clusters (list): Allocated cluster on current step. """ self.__means_evolution.append(means) self.__covariances_evolution.append(covariances) self.__clusters_evolution.append(clusters) class ema_visualizer: """! @brief Visualizer of EM algorithm's results. @details Provides services for visualization of particular features of the algorithm, for example, in case of two-dimensional dataset it shows covariance ellipses. """ @staticmethod def show_clusters(clusters, sample, covariances, means, figure = None, display = True): """! @brief Draws clusters and in case of two-dimensional dataset draws their ellipses. @param[in] clusters (list): Clusters that were allocated by the algorithm. @param[in] sample (list): Dataset that were used for clustering. @param[in] covariances (list): Covariances of the clusters. @param[in] means (list): Means of the clusters. @param[in] figure (figure): If 'None' then new is figure is creater, otherwise specified figure is used for visualization. @param[in] display (bool): If 'True' then figure will be shown by the method, otherwise it should be shown manually using matplotlib function 'plt.show()'. @return (figure) Figure where clusters were drawn. """ visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) if figure is None: figure = visualizer.show(display = False) else: visualizer.show(figure = figure, display = False) if len(sample[0]) == 2: ema_visualizer.__draw_ellipses(figure, visualizer, clusters, covariances, means) if display is True: plt.show() return figure @staticmethod def animate_cluster_allocation(data, observer, animation_velocity = 75, movie_fps = 1, save_movie = None): """! @brief Animates clustering process that is performed by EM algorithm. @param[in] data (list): Dataset that is used for clustering. @param[in] observer (ema_observer): EM observer that was used for collection information about clustering process. @param[in] animation_velocity (uint): Interval between frames in milliseconds (for run-time animation only). @param[in] movie_fps (uint): Defines frames per second (for rendering movie only). @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure() def init_frame(): return frame_generation(0) def frame_generation(index_iteration): figure.clf() figure.suptitle("EM algorithm (iteration: " + str(index_iteration) +")", fontsize = 18, fontweight = 'bold') clusters = observer.get_evolution_clusters()[index_iteration] covariances = observer.get_evolution_covariances()[index_iteration] means = observer.get_evolution_means()[index_iteration] ema_visualizer.show_clusters(clusters, data, covariances, means, figure, False) figure.subplots_adjust(top = 0.85) return [ figure.gca() ] iterations = len(observer) cluster_animation = animation.FuncAnimation(figure, frame_generation, iterations, interval = animation_velocity, init_func = init_frame, repeat_delay = 5000) if save_movie is not None: cluster_animation.save(save_movie, writer = 'ffmpeg', fps = movie_fps, bitrate = 1500) else: plt.show() @staticmethod def __draw_ellipses(figure, visualizer, clusters, covariances, means): ax = figure.get_axes()[0] for index in range(len(clusters)): angle, width, height = calculate_ellipse_description(covariances[index]) color = visualizer.get_cluster_color(index, 0) ema_visualizer.__draw_ellipse(ax, means[index][0], means[index][1], angle, width, height, color) @staticmethod def __draw_ellipse(ax, x, y, angle, width, height, color): if (width > 0.0) and (height > 0.0): ax.plot(x, y, color=color, marker='x', markersize=6) ellipse = patches.Ellipse((x, y), width, height, alpha=0.2, angle=-angle, linewidth=2, fill=True, zorder=2, color=color) ax.add_patch(ellipse) class ema: """! @brief Expectation-Maximization clustering algorithm for Gaussian Mixture Model (GMM). @details The algorithm provides only clustering services (unsupervised learning). Here an example of data clustering process: @code from pyclustering.cluster.ema import ema, ema_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Read data from text file. sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Create EM algorithm to allocated four clusters. ema_instance = ema(sample, 3) # Run clustering process. ema_instance.process() # Get clustering results. clusters = ema_instance.get_clusters() covariances = ema_instance.get_covariances() means = ema_instance.get_centers() # Visualize obtained clustering results. ema_visualizer.show_clusters(clusters, sample, covariances, means) @endcode Here is clustering results of the Expectation-Maximization clustering algorithm where popular sample 'OldFaithful' was used. Initial random means and covariances were used in the example. The first step is presented on the left side of the figure and final result (the last step) is on the right side: @image html ema_old_faithful_clustering.png @see ema_visualizer @see ema_observer """ def __init__(self, data, amount_clusters, means=None, variances=None, observer=None, tolerance=0.00001, iterations=100): """! @brief Initializes Expectation-Maximization algorithm for cluster analysis. @param[in] data (list): Dataset that should be analysed and where each point (object) is represented by the list of coordinates. @param[in] amount_clusters (uint): Amount of clusters that should be allocated. @param[in] means (list): Initial means of clusters (amount of means should be equal to amount of clusters for allocation). If this parameter is 'None' then K-Means algorithm with K-Means++ method will be used for initialization by default. @param[in] variances (list): Initial cluster variances (or covariances in case of multi-dimensional data). Amount of covariances should be equal to amount of clusters that should be allocated. If this parameter is 'None' then K-Means algorithm with K-Means++ method will be used for initialization by default. @param[in] observer (ema_observer): Observer for gathering information about clustering process. @param[in] tolerance (float): Defines stop condition of the algorithm (when difference between current and previous log-likelihood estimation is less then 'tolerance' then clustering is over). @param[in] iterations (uint): Additional stop condition parameter that defines maximum number of steps that can be performed by the algorithm during clustering process. """ self.__data = numpy.array(data) self.__amount_clusters = amount_clusters self.__tolerance = tolerance self.__iterations = iterations self.__observer = observer self.__means = means self.__variances = variances self.__verify_arguments() if (means is None) or (variances is None): self.__means, self.__variances = ema_initializer(data, amount_clusters).initialize(ema_init_type.KMEANS_INITIALIZATION) if len(self.__means) != amount_clusters: self.__amount_clusters = len(self.__means) self.__rc = [ [0.0] * len(self.__data) for _ in range(amount_clusters) ] self.__pic = [1.0] * amount_clusters self.__clusters = [] self.__gaussians = [ [] for _ in range(amount_clusters) ] self.__stop = False def process(self): """! @brief Run clustering process of the algorithm. @return (ema) Returns itself (EMA instance). """ previous_likelihood = -200000 current_likelihood = -100000 current_iteration = 0 while(self.__stop is False) and (abs(previous_likelihood - current_likelihood) > self.__tolerance) and (current_iteration < self.__iterations): self.__expectation_step() self.__maximization_step() current_iteration += 1 self.__extract_clusters() self.__notify() previous_likelihood = current_likelihood current_likelihood = self.__log_likelihood() self.__stop = self.__get_stop_condition() self.__normalize_probabilities() return self def get_clusters(self): """! @return (list) Allocated clusters where each cluster is represented by list of indexes of points from dataset, for example, two cluster may have following representation [[0, 1, 4], [2, 3, 5, 6]]. """ return self.__clusters def get_centers(self): """! @return (list) Corresponding centers (means) of clusters. """ return self.__means def get_covariances(self): """! @return (list) Corresponding variances (or covariances in case of multi-dimensional data) of clusters. """ return self.__variances def get_probabilities(self): """! @brief Returns 2-dimensional list with belong probability of each object from data to cluster correspondingly, where that first index is for cluster and the second is for point. @code # Get belong probablities probabilities = ema_instance.get_probabilities(); # Show porbability of the fifth element in the first and in the second cluster index_point = 5; print("Probability in the first cluster:", probabilities[0][index_point]); print("Probability in the first cluster:", probabilities[1][index_point]); @endcode @return (list) 2-dimensional list with belong probability of each object from data to cluster. """ return self.__rc def __erase_empty_clusters(self): clusters, means, variances, pic, gaussians, rc = [], [], [], [], [], [] for index_cluster in range(len(self.__clusters)): if len(self.__clusters[index_cluster]) > 0: clusters.append(self.__clusters[index_cluster]) means.append(self.__means[index_cluster]) variances.append(self.__variances[index_cluster]) pic.append(self.__pic[index_cluster]) gaussians.append(self.__gaussians[index_cluster]) rc.append(self.__rc[index_cluster]) if len(self.__clusters) != len(clusters): self.__clusters, self.__means, self.__variances, self.__pic = clusters, means, variances, pic self.__gaussians, self.__rc = gaussians, rc self.__amount_clusters = len(self.__clusters) def __notify(self): if self.__observer is not None: self.__observer.notify(self.__means, self.__variances, self.__clusters) def __extract_clusters(self): self.__clusters = [[] for _ in range(self.__amount_clusters)] for index_point in range(len(self.__data)): candidates = [] for index_cluster in range(self.__amount_clusters): candidates.append((index_cluster, self.__rc[index_cluster][index_point])) index_winner = max(candidates, key=lambda candidate: candidate[1])[0] self.__clusters[index_winner].append(index_point) self.__erase_empty_clusters() def __log_likelihood(self): likelihood = 0.0 for index_point in range(len(self.__data)): particle = 0.0 for index_cluster in range(self.__amount_clusters): particle += self.__pic[index_cluster] * self.__gaussians[index_cluster][index_point] if particle > 0.0: likelihood += numpy.log(particle) return likelihood def __probabilities(self, index_cluster, index_point): divider = 0.0 for i in range(self.__amount_clusters): divider += self.__pic[i] * self.__gaussians[i][index_point] if (divider != 0.0) and (divider != float('inf')): return self.__pic[index_cluster] * self.__gaussians[index_cluster][index_point] / divider return 1.0 def __expectation_step(self): self.__gaussians = [ [] for _ in range(self.__amount_clusters) ] for index in range(self.__amount_clusters): self.__gaussians[index] = gaussian(self.__data, self.__means[index], self.__variances[index]) self.__rc = [ [0.0] * len(self.__data) for _ in range(self.__amount_clusters) ] for index_cluster in range(self.__amount_clusters): for index_point in range(len(self.__data)): self.__rc[index_cluster][index_point] = self.__probabilities(index_cluster, index_point) def __maximization_step(self): self.__pic = [] self.__means = [] self.__variances = [] amount_impossible_clusters = 0 for index_cluster in range(self.__amount_clusters): mc = numpy.sum(self.__rc[index_cluster]) if mc == 0.0: amount_impossible_clusters += 1 continue self.__pic.append( mc / len(self.__data) ) self.__means.append( self.__update_mean(self.__rc[index_cluster], mc) ) self.__variances.append( self.__update_covariance(self.__means[-1], self.__rc[index_cluster], mc) ) self.__amount_clusters -= amount_impossible_clusters def __get_stop_condition(self): for covariance in self.__variances: if numpy.linalg.norm(covariance) == 0.0: return True return False def __update_covariance(self, means, rc, mc): covariance = 0.0 for index_point in range(len(self.__data)): deviation = numpy.array([self.__data[index_point] - means]) covariance += rc[index_point] * deviation.T.dot(deviation) covariance = covariance / mc return covariance def __update_mean(self, rc, mc): mean = 0.0 for index_point in range(len(self.__data)): mean += rc[index_point] * self.__data[index_point] mean = mean / mc return mean def __normalize_probabilities(self): for index_point in range(len(self.__data)): probability = 0.0 for index_cluster in range(len(self.__clusters)): probability += self.__rc[index_cluster][index_point] if abs(probability - 1.0) > 0.000001: self.__normalize_probability(index_point, probability) def __normalize_probability(self, index_point, probability): if probability == 0.0: return normalization = 1.0 / probability for index_cluster in range(len(self.__clusters)): self.__rc[index_cluster][index_point] *= normalization def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data)) if self.__amount_clusters < 1: raise ValueError("Amount of clusters (current value '%d') should be greater or equal to 1." % self.__amount_clusters) pyclustering-0.10.1.2/pyclustering/cluster/encoder.py000077500000000000000000000227161375753423500227140ustar00rootroot00000000000000"""! @brief Module for representing clustering results. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math from enum import IntEnum class type_encoding(IntEnum): """! @brief Enumeration of encoding types (index labeling, index list separation, object list separation). """ ## Results are represented by list of indexes and belonging to the cluster is defined by cluster index and element's position corresponds to object's position in input data, for example [0, 0, 1, 1, 1, 0]. CLUSTER_INDEX_LABELING = 0 ## Results are represented by list of lists, where each list consists of object indexes from input data, for example [ [0, 1, 2], [3, 4, 5], [6, 7] ]. CLUSTER_INDEX_LIST_SEPARATION = 1 ## Results are represented by list of lists, where each list consists of objects from input data, for example [ [obj1, obj2], [obj3, obj4, obj5], [obj6, obj7] ]. CLUSTER_OBJECT_LIST_SEPARATION = 2 class cluster_encoder: """! @brief Provides service to change clustering result representation. @details There are three general types of representation: 1. Index List Separation that is defined by `CLUSTER_INDEX_LIST_SEPARATION`, for example `[[0, 1, 2], [3, 4], [5, 6, 7]`. 2. Index Labeling that is defined by `CLUSTER_INDEX_LABELING`, for example `[0, 0, 0, 1, 1, 2, 2, 2]`. 3. Object List Separation that is defined by `CLUSTER_OBJECT_LIST_SEPARATION`, for example `[[obj1, obj2, obj3], [obj4, obj5], [obj5, obj6, obj7]`. There is an example how to covert default Index List Separation to other types: @code from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.cluster.encoder import type_encoding, cluster_encoder from pyclustering.cluster.kmeans import kmeans # load list of points for cluster analysis sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) # create instance of K-Means algorithm kmeans_instance = kmeans(sample, [[3.0, 5.1], [6.5, 8.6]]) # run cluster analysis and obtain results kmeans_instance.process() clusters = kmeans_instance.get_clusters() print("Index List Separation:", clusters) # by default k-means returns representation CLUSTER_INDEX_LIST_SEPARATION type_repr = kmeans_instance.get_cluster_encoding() encoder = cluster_encoder(type_repr, clusters, sample) # change representation from index list to label list encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) print("Index Labeling:", encoder.get_clusters()) # change representation from label to object list encoder.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) print("Object List Separation:", encoder.get_clusters()) @endcode Output of the code above is following: @code Index List Separation: [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] Index Labeling: [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] Object List Separation: [[[3.522979, 5.487981], [3.768699, 5.364477], [3.423602, 5.4199], [3.803905, 5.389491], [3.93669, 5.663041]], [[6.968136, 7.755556], [6.750795, 7.269541], [6.593196, 7.850364], [6.978178, 7.60985], [6.554487, 7.498119]]] @endcode If there is no index or object in clusters that exists in an input data then it is going to be marked as `NaN` in case of Index Labeling. Here is an example: @code from pyclustering.cluster.encoder import type_encoding, cluster_encoder # An input data. sample = [[1.0, 1.2], [1.2, 2.3], [114.3, 54.1], [2.2, 1.4], [5.3, 1.3]] # Clusters do not contains object with index 2 ([114.3, 54.1]) because it is outline. clusters = [[0, 1], [3, 4]] encoder = cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, clusters, sample) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) print("Index Labeling:", encoder.get_clusters()) @endcode Here is an output of the code above. Pay attention to `NaN` value for the object with index 2 `[114.3, 54.1]`. @code Index Labeling: [0, 0, nan, 1, 1] @endcode """ def __init__(self, encoding, clusters, data): """! @brief Constructor of clustering result representor. @param[in] encoding (type_encoding): Type of clusters representation (Index List, Object List or Labels). @param[in] clusters (list): Clusters that were allocated from an input data. @param[in] data (list): Data that was used for cluster analysis. @see type_encoding """ self.__type_representation = encoding self.__clusters = clusters self.__data = data @property def get_encoding(self): """! @brief Returns current cluster representation. """ return self.__type_representation def get_clusters(self): """! @brief Returns clusters that are represented in line with type that is defined by `get_encoding()`. @see get_encoding() """ return self.__clusters def get_data(self): """! @brief Returns data that was used for cluster analysis. """ return self.__data def set_encoding(self, encoding): """! @brief Change clusters encoding to specified type (Index List, Object List, Labeling). @param[in] encoding (type_encoding): New type of clusters representation. @return (cluster_encoder) Return itself. """ if encoding == self.__type_representation: return self if self.__type_representation == type_encoding.CLUSTER_INDEX_LABELING: if encoding == type_encoding.CLUSTER_INDEX_LIST_SEPARATION: self.__clusters = self.__convert_label_to_index() else: self.__clusters = self.__convert_label_to_object() elif self.__type_representation == type_encoding.CLUSTER_INDEX_LIST_SEPARATION: if encoding == type_encoding.CLUSTER_INDEX_LABELING: self.__clusters = self.__convert_index_to_label() else: self.__clusters = self.__convert_index_to_object() else: if encoding == type_encoding.CLUSTER_INDEX_LABELING: self.__clusters = self.__convert_object_to_label() else: self.__clusters = self.__convert_object_to_index() self.__type_representation = encoding return self def __convert_index_to_label(self): clusters = [float('NaN')] * len(self.__data) index_cluster = 0 for cluster in self.__clusters: for index_object in cluster: clusters[index_object] = index_cluster index_cluster += 1 return clusters def __convert_index_to_object(self): clusters = [ [] for _ in range(len(self.__clusters)) ] for index_cluster in range(len(self.__clusters)): for index_object in self.__clusters[index_cluster]: data_object = self.__data[index_object] clusters[index_cluster].append(data_object) return clusters def __convert_object_to_label(self): positions = dict() clusters = [float('NaN')] * len(self.__data) index_cluster = 0 for cluster in self.__clusters: for data_object in cluster: hashable_data_object = str(data_object) if hashable_data_object in positions: index_object = self.__data.index(data_object, positions[hashable_data_object] + 1) else: index_object = self.__data.index(data_object) clusters[index_object] = index_cluster positions[hashable_data_object] = index_object index_cluster += 1 return clusters def __convert_object_to_index(self): positions = dict() clusters = [[] for _ in range(len(self.__clusters))] for index_cluster in range(len(self.__clusters)): for data_object in self.__clusters[index_cluster]: hashable_data_object = str(data_object) if hashable_data_object in positions: index_object = self.__data.index(data_object, positions[hashable_data_object] + 1) else: index_object = self.__data.index(data_object) clusters[index_cluster].append(index_object) positions[hashable_data_object] = index_object return clusters def __convert_label_to_index(self): clusters = [[] for _ in range(max(self.__clusters) + 1)] for index_object in range(len(self.__data)): index_cluster = self.__clusters[index_object] if not math.isnan(index_cluster): clusters[index_cluster].append(index_object) return clusters def __convert_label_to_object(self): clusters = [[] for _ in range(max(self.__clusters) + 1)] for index_object in range(len(self.__data)): index_cluster = self.__clusters[index_object] if not math.isnan(index_cluster): clusters[index_cluster].append(self.__data[index_object]) return clusters pyclustering-0.10.1.2/pyclustering/cluster/examples/000077500000000000000000000000001375753423500225265ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/cluster/examples/__init__.py000077500000000000000000000002701375753423500246410ustar00rootroot00000000000000"""! @brief Collection of examples devoted to clustering algorithms and methods. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/pyclustering/cluster/examples/agglomerative_examples.py000077500000000000000000000154711375753423500276370ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of agglomerative algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.agglomerative import agglomerative, type_link from pyclustering.utils import read_sample from pyclustering.utils import timedcall from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_clustering(number_clusters, path, links): sample = read_sample(path) clusters_centroid_link = None clusters_single_link = None clusters_complete_link = None clusters_average_link = None visualizer = cluster_visualizer(len(links), len(links)); index_canvas = 0; if (type_link.CENTROID_LINK in links): agglomerative_centroid_link = agglomerative(sample, number_clusters, type_link.CENTROID_LINK, True); (ticks, result) = timedcall(agglomerative_centroid_link.process); clusters_centroid_link = agglomerative_centroid_link.get_clusters(); visualizer.append_clusters(clusters_centroid_link, sample, index_canvas); visualizer.set_canvas_title('Link: Centroid', index_canvas); index_canvas += 1; print("Sample: ", path, "Link: Centroid", "\tExecution time: ", ticks, "\n"); if (type_link.SINGLE_LINK in links): agglomerative_simple_link = agglomerative(sample, number_clusters, type_link.SINGLE_LINK); (ticks, result) = timedcall(agglomerative_simple_link.process); clusters_single_link = agglomerative_simple_link.get_clusters(); visualizer.append_clusters(clusters_single_link, sample, index_canvas); visualizer.set_canvas_title('Link: Single', index_canvas); index_canvas += 1; print("Sample: ", path, "Link: Single", "\tExecution time: ", ticks, "\n"); if (type_link.COMPLETE_LINK in links): agglomerative_complete_link = agglomerative(sample, number_clusters, type_link.COMPLETE_LINK); (ticks, result) = timedcall(agglomerative_complete_link.process); clusters_complete_link = agglomerative_complete_link.get_clusters(); visualizer.append_clusters(clusters_complete_link, sample, index_canvas); visualizer.set_canvas_title('Link: Complete', index_canvas); index_canvas += 1; print("Sample: ", path, "Link: Complete", "\tExecution time: ", ticks, "\n"); if (type_link.AVERAGE_LINK in links): agglomerative_average_link = agglomerative(sample, number_clusters, type_link.AVERAGE_LINK); (ticks, result) = timedcall(agglomerative_average_link.process); clusters_average_link = agglomerative_average_link.get_clusters(); visualizer.append_clusters(clusters_average_link, sample, index_canvas); visualizer.set_canvas_title('Link: Average', index_canvas); index_canvas += 1; print("Sample: ", path, "Link: Average", "\tExecution time: ", ticks, "\n"); visualizer.show(); def cluster_sample1(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_sample2(): template_clustering(3, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_sample3(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_sample4(): template_clustering(5, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_sample5(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_elongate(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_ELONGATE, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_lsun(): template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, [type_link.CENTROID_LINK, type_link.SINGLE_LINK, type_link.AVERAGE_LINK, type_link.COMPLETE_LINK]); def cluster_target(): template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET, [ type_link.CENTROID_LINK ]); def cluster_two_diamonds(): template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [ type_link.CENTROID_LINK ]); def cluster_wing_nut(): template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT, [type_link.CENTROID_LINK ]); def cluster_chainlink(): template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK, [ type_link.CENTROID_LINK ]); def cluster_hepta(): template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA, [ type_link.CENTROID_LINK ]); def cluster_tetra(): template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA, [ type_link.CENTROID_LINK ]); def cluster_engy_time(): template_clustering(2, FCPS_SAMPLES.SAMPLE_ENGY_TIME, [ type_link.CENTROID_LINK ]); def experiment_execution_time(ccore = False): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [type_link.SINGLE_LINK]); template_clustering(3, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [type_link.SINGLE_LINK]); template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [type_link.SINGLE_LINK]); template_clustering(5, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [type_link.SINGLE_LINK]); template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [type_link.SINGLE_LINK]); template_clustering(2, SIMPLE_SAMPLES.SAMPLE_ELONGATE, [type_link.SINGLE_LINK]); template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, [type_link.SINGLE_LINK]); template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET, [type_link.SINGLE_LINK]); template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [type_link.SINGLE_LINK]); template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT, [type_link.SINGLE_LINK]); template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK, [type_link.SINGLE_LINK]); template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA, [type_link.SINGLE_LINK]); template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA, [type_link.SINGLE_LINK]); template_clustering(2, FCPS_SAMPLES.SAMPLE_ATOM, [type_link.SINGLE_LINK]); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_sample4(); cluster_sample5(); cluster_elongate(); cluster_lsun(); cluster_target(); cluster_two_diamonds(); cluster_wing_nut(); cluster_chainlink(); cluster_hepta(); cluster_tetra(); cluster_engy_time(); experiment_execution_time(False); # Python codepyclustering-0.10.1.2/pyclustering/cluster/examples/bang_example.py000077500000000000000000000060421375753423500255270ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of BANG algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import os from pyclustering.cluster.bang import bang, bang_visualizer, bang_animator from pyclustering.utils import draw_image_mask_segments, read_sample, read_image from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_clustering(data_path, levels, **kwargs): print("Sample: '%s'." % os.path.basename(data_path)) density_threshold = kwargs.get("density_threshold", 0.0) amount_threshold = kwargs.get("amount_threshold", 0) data = read_sample(data_path) bang_instance = bang(data, levels, density_threshold=density_threshold, amount_threshold=amount_threshold) bang_instance.process() clusters = bang_instance.get_clusters() noise = bang_instance.get_noise() directory = bang_instance.get_directory() dendrogram = bang_instance.get_dendrogram() bang_visualizer.show_blocks(directory) bang_visualizer.show_dendrogram(dendrogram) bang_visualizer.show_clusters(data, clusters, noise) if len(data[0]) == 2: animator = bang_animator(directory, clusters) animator.animate() # movie_filename = os.path.basename(data_path) + ".mp4" # animator.animate(movie_filename=movie_filename) def template_segmentation(source, levels, threshold): data = read_image(source) bang_instance = bang(data, levels, threshold) bang_instance.process() clusters = bang_instance.get_clusters() draw_image_mask_segments(source, clusters) def cluster_simple_sample(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, density_threshold=2.5) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 8) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 8) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 7) template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 7) def cluster_fcps(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 9) template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 11) template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 11) template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 10) template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 10) template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 11) template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 13) template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 11) cluster_simple_sample() cluster_fcps() pyclustering-0.10.1.2/pyclustering/cluster/examples/birch_examples.py000077500000000000000000000130061375753423500260700ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of BIRCH algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.birch import birch from pyclustering.container.cftree import measurement_type from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_clustering(number_clusters, path, branching_factor=50, max_node_entries=100, initial_diameter=0.5, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE, entry_size_limit=200, diameter_multiplier=1.5, show_result=True): print("Sample: ", path) sample = read_sample(path) birch_instance = birch(sample, number_clusters, branching_factor, max_node_entries, initial_diameter, type_measurement, entry_size_limit, diameter_multiplier) birch_instance.process() clusters = birch_instance.get_clusters() if show_result is True: visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() return sample, clusters def cluster_sample1(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 5, 0.1, measurement_type.CENTROID_EUCLIDEAN_DISTANCE, 2) # only two entries available def cluster_sample2(): template_clustering(3, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): template_clustering(5, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_sample7(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE7) def cluster_sample8(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE8) def cluster_elongate(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN) def cluster_lsun_rebuilt(): template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, entry_size_limit=20, diameter_multiplier=1.5) def cluster_target(): template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET) def cluster_two_diamonds(): template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_wing_nut(): template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_chainlink(): template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_hepta(): template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_tetra(): template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA) def cluster_engy_time(): template_clustering(2, FCPS_SAMPLES.SAMPLE_ENGY_TIME) def experiment_execution_time(ccore=False): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) template_clustering(3, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) template_clustering(5, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) template_clustering(2, SIMPLE_SAMPLES.SAMPLE_ELONGATE) template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN) template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET) template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT) template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK) template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA) template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA) template_clustering(2, FCPS_SAMPLES.SAMPLE_ATOM) def display_fcps_clustering_results(): (lsun, lsun_clusters) = template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, show_result=False) (target, target_clusters) = template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET, show_result=False) (two_diamonds, two_diamonds_clusters) = template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, show_result=False) (wing_nut, wing_nut_clusters) = template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT, show_result=False) (chainlink, chainlink_clusters) = template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK, show_result=False) (hepta, hepta_clusters) = template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA, show_result=False) (tetra, tetra_clusters) = template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA, show_result=False) (atom, atom_clusters) = template_clustering(2, FCPS_SAMPLES.SAMPLE_ATOM, show_result=False) visualizer = cluster_visualizer(8, 4) visualizer.append_clusters(lsun_clusters, lsun, 0) visualizer.append_clusters(target_clusters, target, 1) visualizer.append_clusters(two_diamonds_clusters, two_diamonds, 2) visualizer.append_clusters(wing_nut_clusters, wing_nut, 3) visualizer.append_clusters(chainlink_clusters, chainlink, 4) visualizer.append_clusters(hepta_clusters, hepta, 5) visualizer.append_clusters(tetra_clusters, tetra, 6) visualizer.append_clusters(atom_clusters, atom, 7) visualizer.show() cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample7() cluster_sample8() cluster_elongate() cluster_lsun() cluster_lsun_rebuilt() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_engy_time() experiment_execution_time(True) # C++ code + Python env. display_fcps_clustering_results() pyclustering-0.10.1.2/pyclustering/cluster/examples/bsas_examples.py000077500000000000000000000034541375753423500257370ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of BSAS algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.bsas import bsas, bsas_visualizer; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.utils import read_sample; from pyclustering.utils.metric import distance_metric, type_metric; def template_clustering(path, amount, threshold, **kwargs): metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)); ccore = kwargs.get('ccore', False); draw = kwargs.get('draw', True); sample = read_sample(path); print("Sample: ", path); bsas_instance = bsas(sample, amount, threshold, ccore=ccore, metric=metric); bsas_instance.process(); clusters = bsas_instance.get_clusters(); representatives = bsas_instance.get_representatives(); if draw is True: bsas_visualizer.show_clusters(sample, clusters, representatives); def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0); def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1.0); def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 1.0); def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, 1.0); def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, 1.0); def cluster_sample6(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 2, 1.0); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, 1.0); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_sample4(); cluster_sample5(); cluster_sample6(); cluster_elongate();pyclustering-0.10.1.2/pyclustering/cluster/examples/center_initializer_examples.py000077500000000000000000000065271375753423500306760ustar00rootroot00000000000000"""! @brief Examples of center initializer API. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer def template_kmeans_plusplus_initializer(path, amount, draw=True): sample = read_sample(path) centers = kmeans_plusplus_initializer(sample, amount, 1).initialize() if draw is True: visualizer = cluster_visualizer() visualizer.append_cluster(sample) visualizer.append_cluster(centers, marker='*', markersize=10) visualizer.show() return sample, centers def kmeans_plusplus_initializer_sample_simple_01(): template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2) def kmeans_plusplus_initializer_sample_simple_02(): template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3) def kmeans_plusplus_initializer_sample_simple_03(): template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4) def kmeans_plusplus_initializer_sample_simple_04(): template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5) def kmeans_plusplus_initializer_sample_simple_05(): template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4) def kmeans_plusplus_initializer_collection(): (sample1, centers1) = template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, False) (sample2, centers2) = template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, False) (sample3, centers3) = template_kmeans_plusplus_initializer(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, False) (sample4, centers4) = template_kmeans_plusplus_initializer(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, False) visualizer = cluster_visualizer(4, 2) visualizer.append_cluster(sample1, canvas=0) visualizer.append_cluster(centers1, canvas=0, marker='*', markersize=10) visualizer.append_cluster(sample2, canvas=1) visualizer.append_cluster(centers2, canvas=1, marker='*', markersize=10) visualizer.append_cluster(sample3, canvas=2) visualizer.append_cluster(centers3, canvas=2, marker='*', markersize=10) visualizer.append_cluster(sample4, canvas=3) visualizer.append_cluster(centers4, canvas=3, marker='*', markersize=10) visualizer.show() def kmeans_plusplus_initializer_fcps_lsun(): template_kmeans_plusplus_initializer(FCPS_SAMPLES.SAMPLE_LSUN, 3) def kmeans_plusplus_initializer_fcps_two_diamonds(): template_kmeans_plusplus_initializer(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2) # kmeans_plusplus_initializer_sample_simple_01() # kmeans_plusplus_initializer_sample_simple_02() kmeans_plusplus_initializer_sample_simple_03() kmeans_plusplus_initializer_sample_simple_03() kmeans_plusplus_initializer_sample_simple_03() kmeans_plusplus_initializer_sample_simple_03() kmeans_plusplus_initializer_sample_simple_03() kmeans_plusplus_initializer_sample_simple_03() # kmeans_plusplus_initializer_sample_simple_04() # kmeans_plusplus_initializer_sample_simple_05() # # kmeans_plusplus_initializer_collection() # # kmeans_plusplus_initializer_fcps_lsun() # kmeans_plusplus_initializer_fcps_two_diamonds() pyclustering-0.10.1.2/pyclustering/cluster/examples/clarans_examples.py000077500000000000000000000054201375753423500264250ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of CLARANS algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.clarans import clarans; from pyclustering.utils import read_sample; from pyclustering.utils import draw_clusters; from pyclustering.utils import timedcall; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; def template_clustering(number_clusters, path, iterations, maxneighbors): sample = read_sample(path); clarans_instance = clarans(sample, number_clusters, iterations, maxneighbors); (ticks, result) = timedcall(clarans_instance.process); print("Sample: ", path, "\t\tExecution time: ", ticks, "\n"); clusters = clarans_instance.get_clusters(); draw_clusters(sample, clusters); def cluster_sample1(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 3); def cluster_sample2(): template_clustering(3, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 10, 3); def cluster_sample3(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 10, 3); def cluster_sample4(): template_clustering(5, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 10, 4); def cluster_sample5(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 10, 5); def cluster_sample6(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 10, 3); def cluster_sample7(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 10, 3); def cluster_sample8(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 15, 5); def cluster_elongate(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, 2); def cluster_lsun(): template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, 2, 2); def cluster_target(): template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET, 2, 2); def cluster_two_diamonds(): # tooo long template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, 2); def cluster_wing_nut(): # too long template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT, 2, 2); def cluster_chainlink(): # too long template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK, 2, 2); def cluster_hepta(): template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA, 2, 2); def cluster_tetra(): template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA, 2, 2); def cluster_engy_time(): # too long template_clustering(2, FCPS_SAMPLES.SAMPLE_ENGY_TIME, 2, 2); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_sample4(); cluster_sample5(); cluster_sample6(); cluster_sample7(); cluster_sample8(); cluster_elongate(); cluster_lsun(); cluster_target(); cluster_two_diamonds(); # too long cluster_wing_nut(); # too long cluster_chainlink(); # too long cluster_hepta(); cluster_tetra(); cluster_engy_time(); # too longpyclustering-0.10.1.2/pyclustering/cluster/examples/clique_example.py000077500000000000000000000050551375753423500261050ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of CLIQUE algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import os from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.clique import clique, clique_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_clustering(data_path, intervals, density_threshold, **kwargs): print("Sample: '%s'." % os.path.basename(data_path)) data = read_sample(data_path) clique_instance = clique(data, intervals, density_threshold) clique_instance.process() clusters = clique_instance.get_clusters() noise = clique_instance.get_noise() cells = clique_instance.get_cells() print([len(cluster) for cluster in clusters]) clique_visualizer.show_grid(cells, data) visualizer = cluster_visualizer() visualizer.append_clusters(clusters, data) visualizer.append_cluster(noise, data, marker='x') visualizer.show() def cluster_simple_sample(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 10, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 5, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 5, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 15, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 7, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 7, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 5, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 7, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 2, 0) template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 7, 0) def cluster_fcps(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 15, 0) template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 15, 0) template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 15, 0) template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 10, 0) template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 9, 0) template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 10, 0) template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 10, 0) template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 10, 0) cluster_simple_sample() cluster_fcps() pyclustering-0.10.1.2/pyclustering/cluster/examples/cure_examples.py000077500000000000000000000106761375753423500257510ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of CURE algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils import read_sample from pyclustering.utils import timedcall from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.cure import cure def template_clustering(number_clusters, path, number_represent_points=5, compression=0.5, draw=True, ccore_flag=True): sample = read_sample(path) cure_instance = cure(sample, number_clusters, number_represent_points, compression, ccore_flag) (ticks, _) = timedcall(cure_instance.process) clusters = cure_instance.get_clusters() representors = cure_instance.get_representors() means = cure_instance.get_means() print("Sample: ", path, "\t\tExecution time: ", ticks, "\n") #print([len(cluster) for cluster in clusters]) if draw is True: visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) for cluster_index in range(len(clusters)): visualizer.append_cluster_attribute(0, cluster_index, representors[cluster_index], '*', 10) visualizer.append_cluster_attribute(0, cluster_index, [ means[cluster_index] ], 'o') visualizer.show() def cluster_sample1(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): template_clustering(3, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): template_clustering(5, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): template_clustering(4, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_sample6(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_SIMPLE6) def cluster_elongate(): template_clustering(2, SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, 5, 0.3) def cluster_target(): template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET, 10, 0.3) def cluster_two_diamonds(): template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 5, 0.3) def cluster_wing_nut(ccore_flag=True): template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT, 4, 0.3, ccore_flag=ccore_flag) def cluster_chainlink(): template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK, 30, 0.2) def cluster_hepta(): template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_tetra(): template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA) def cluster_engy_time(): template_clustering(2, FCPS_SAMPLES.SAMPLE_ENGY_TIME, 50, 0.5) def cluster_golf_ball(): template_clustering(1, FCPS_SAMPLES.SAMPLE_GOLF_BALL) def cluster_atom(): "Impossible to obtain parameters that satisfy us, it seems to me that compression = 0.2 is key parameter here, because results of clustering doesn't depend on number of represented points, except 0." "Thus the best parameters is following: number of points for representation: [5, 400]; compression: [0.2, 0.204]" "Results of clustering is not so dramatically, but clusters are not allocated properly" template_clustering(2, FCPS_SAMPLES.SAMPLE_ATOM, 20, 0.2) def experiment_execution_time(draw, ccore): template_clustering(3, FCPS_SAMPLES.SAMPLE_LSUN, 5, 0.3, draw, ccore) template_clustering(6, FCPS_SAMPLES.SAMPLE_TARGET, 10, 0.3, draw, ccore) template_clustering(2, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 5, 0.3, draw, ccore) template_clustering(2, FCPS_SAMPLES.SAMPLE_WING_NUT, 1, 1, draw, ccore) template_clustering(2, FCPS_SAMPLES.SAMPLE_CHAINLINK, 5, 0.5, draw, ccore) template_clustering(4, FCPS_SAMPLES.SAMPLE_TETRA, 5, 0.5, draw, ccore) template_clustering(7, FCPS_SAMPLES.SAMPLE_HEPTA, 5, 0.5, draw, ccore) template_clustering(2, FCPS_SAMPLES.SAMPLE_ATOM, 20, 0.2) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample6() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_atom() cluster_engy_time() cluster_golf_ball() experiment_execution_time(True, False) experiment_execution_time(True, True) pyclustering-0.10.1.2/pyclustering/cluster/examples/dbscan_examples.py000077500000000000000000000211741375753423500262400ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of DBSCAN algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.dbscan import dbscan from pyclustering.utils import read_sample from pyclustering.utils import timedcall from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_clustering(radius, neighb, path, invisible_axes = False, ccore = True, show = True): sample = read_sample(path) dbscan_instance = dbscan(sample, radius, neighb, ccore) (ticks, _) = timedcall(dbscan_instance.process) clusters = dbscan_instance.get_clusters() noise = dbscan_instance.get_noise() print([len(cluster) for cluster in clusters]) if show: visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(noise, sample, marker = 'x') visualizer.show() print("Sample: ", path, "\t\tExecution time: ", ticks, "\n") return sample, clusters, noise def cluster_sample1(): template_clustering(0.4, 2, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): template_clustering(1, 2, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): template_clustering(0.7, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): template_clustering(0.7, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): template_clustering(0.7, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_sample7(): template_clustering(1.0, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE7) def cluster_sample8(): template_clustering(1.0, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE8) def cluster_elongate(): template_clustering(0.5, 3, SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_LSUN) def cluster_target(): template_clustering(0.5, 2, FCPS_SAMPLES.SAMPLE_TARGET) def cluster_two_diamonds(): "It's hard to choose properly parameters, but it's OK" template_clustering(0.15, 7, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_wing_nut(): "It's hard to choose properly parameters, but it's OK" template_clustering(0.25, 2, FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_chainlink(): template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_hepta(): template_clustering(1, 3, FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_golf_ball(): "Toooooooooooo looooong" template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_GOLF_BALL) def cluster_atom(): template_clustering(15, 3, FCPS_SAMPLES.SAMPLE_ATOM) def cluster_tetra(): template_clustering(0.4, 3, FCPS_SAMPLES.SAMPLE_TETRA) def cluster_engy_time(): template_clustering(0.2, 20, FCPS_SAMPLES.SAMPLE_ENGY_TIME) def experiment_execution_time(ccore = False): "Performance measurement" template_clustering(0.5, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, False, ccore) template_clustering(1, 2, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, False, ccore) template_clustering(0.7, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, False, ccore) template_clustering(0.7, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, False, ccore) template_clustering(0.7, 3, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, False, ccore) template_clustering(0.5, 3, SIMPLE_SAMPLES.SAMPLE_ELONGATE, False, ccore) template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_LSUN, False, ccore) template_clustering(0.5, 2, FCPS_SAMPLES.SAMPLE_TARGET, False, ccore) template_clustering(0.15, 7, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, ccore) template_clustering(0.25, 2, FCPS_SAMPLES.SAMPLE_WING_NUT, False, ccore) template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_CHAINLINK, False, ccore) template_clustering(1, 3, FCPS_SAMPLES.SAMPLE_HEPTA, False, ccore) template_clustering(0.4, 3, FCPS_SAMPLES.SAMPLE_TETRA, False, ccore) template_clustering(15, 3, FCPS_SAMPLES.SAMPLE_ATOM, False, ccore) def display_fcps_clustering_results(): (lsun, lsun_clusters, _) = template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_LSUN, False, True, False) (target, target_clusters, _) = template_clustering(0.5, 2, FCPS_SAMPLES.SAMPLE_TARGET, False, True, False) (two_diamonds, two_diamonds_clusters, _) = template_clustering(0.15, 7, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (wing_nut, wing_nut_clusters, _) = template_clustering(0.25, 2, FCPS_SAMPLES.SAMPLE_WING_NUT, False, True, False) (chainlink, chainlink_clusters, _) = template_clustering(0.5, 3, FCPS_SAMPLES.SAMPLE_CHAINLINK, False, True, False) (hepta, hepta_clusters, _) = template_clustering(1, 3, FCPS_SAMPLES.SAMPLE_HEPTA, False, True, False) (tetra, tetra_clusters, _) = template_clustering(0.4, 3, FCPS_SAMPLES.SAMPLE_TETRA, False, True, False) (atom, atom_clusters, _) = template_clustering(15, 3, FCPS_SAMPLES.SAMPLE_ATOM, False, True, False) visualizer = cluster_visualizer(8, 4) visualizer.append_clusters(lsun_clusters, lsun, 0) visualizer.append_clusters(target_clusters, target, 1) visualizer.append_clusters(two_diamonds_clusters, two_diamonds, 2) visualizer.append_clusters(wing_nut_clusters, wing_nut, 3) visualizer.append_clusters(chainlink_clusters, chainlink, 4) visualizer.append_clusters(hepta_clusters, hepta, 5) visualizer.append_clusters(tetra_clusters, tetra, 6) visualizer.append_clusters(atom_clusters, atom, 7) visualizer.show() def display_fcps_dependence_clustering_results(): (two_diamonds, two_diamonds_clusters_1, _) = template_clustering(0.15, 4, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_2, _) = template_clustering(0.15, 5, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_3, _) = template_clustering(0.15, 6, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_4, _) = template_clustering(0.15, 7, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_5, _) = template_clustering(0.10, 6, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_6, _) = template_clustering(0.12, 6, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_7, _) = template_clustering(0.15, 6, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) (two_diamonds, two_diamonds_clusters_8, _) = template_clustering(0.17, 6, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, False, True, False) visualizer = cluster_visualizer(8, 4) visualizer.append_clusters(two_diamonds_clusters_1, two_diamonds, 0) visualizer.append_clusters(two_diamonds_clusters_2, two_diamonds, 1) visualizer.append_clusters(two_diamonds_clusters_3, two_diamonds, 2) visualizer.append_clusters(two_diamonds_clusters_4, two_diamonds, 3) visualizer.append_clusters(two_diamonds_clusters_5, two_diamonds, 4) visualizer.append_clusters(two_diamonds_clusters_6, two_diamonds, 5) visualizer.append_clusters(two_diamonds_clusters_7, two_diamonds, 6) visualizer.append_clusters(two_diamonds_clusters_8, two_diamonds, 7) visualizer.show() def clustering_random_points(amount, ccore): sample = [ [ random.random(), random.random() ] for _ in range(amount) ] dbscan_instance = dbscan(sample, 0.05, 20, ccore) (ticks, _) = timedcall(dbscan_instance.process) print("Execution time ("+ str(amount) +" 2D-points):", ticks) def performance_measure_random_points(ccore): clustering_random_points(1000, ccore) clustering_random_points(2000, ccore) clustering_random_points(3000, ccore) clustering_random_points(4000, ccore) clustering_random_points(5000, ccore) clustering_random_points(10000, ccore) clustering_random_points(20000, ccore) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample7() cluster_sample8() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_golf_ball() # it is commented due to long time of processing - it's working absolutely correct! cluster_atom() cluster_tetra() cluster_engy_time() experiment_execution_time(False) # Python code experiment_execution_time(True) # C++ code + Python env. display_fcps_clustering_results() display_fcps_dependence_clustering_results() performance_measure_random_points(False) performance_measure_random_points(True)pyclustering-0.10.1.2/pyclustering/cluster/examples/dbscan_segmentation.py000077500000000000000000000143021375753423500271120ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of DBSCAN algorithm in image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from math import floor; from PIL import Image; from pyclustering.utils import draw_image_mask_segments, draw_image_color_segments, read_image; from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES, IMAGE_MAP_SAMPLES, IMAGE_REAL_SAMPLES; from pyclustering.cluster.dbscan import dbscan; def template_segmentation_image(source, color_radius, color_neighbors, object_radius, object_neighbors, noise_size): data = read_image(source); dbscan_instance = dbscan(data, color_radius, color_neighbors, True); print("Segmentation: '", source, "', Dimensions:", len(data[0])); dbscan_instance.process(); clusters = dbscan_instance.get_clusters(); real_clusters = [cluster for cluster in clusters if len(cluster) > noise_size]; print("Draw allocated color segments (back mask representation)..."); draw_image_mask_segments(source, real_clusters); print("Draw allocated color segments (color segment representation)..."); draw_image_color_segments(source, real_clusters); if (object_radius is None): return; # continue analysis pointer_image = Image.open(source); image_size = pointer_image.size; object_colored_clusters = []; for cluster in clusters: coordinates = []; for index in cluster: y = int(floor(index / image_size[0])); x = index - y * image_size[0]; coordinates.append([x, y]); # perform clustering analysis of the colored objects if (len(coordinates) < noise_size): continue; dbscan_instance = dbscan(coordinates, object_radius, object_neighbors, True); dbscan_instance.process(); object_clusters = dbscan_instance.get_clusters(); # decode it real_description_clusters = []; for object_cluster in object_clusters: real_description = []; for index_object in object_cluster: real_description.append(cluster[index_object]); real_description_clusters.append(real_description); if (len(real_description) > noise_size): object_colored_clusters.append(real_description); print("Draw allocated object segments (back mask representation)..."); draw_image_mask_segments(source, object_colored_clusters); print("Draw allocated object segments (color segment representation)..."); draw_image_color_segments(source, object_colored_clusters); def segmentation_image_simple1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, 128, 4, None, None, 10); def segmentation_image_simple2(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE02, 128, 4, None, None, 10); def segmentation_image_simple3(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE03, 128, 4, None, None, 10); def segmentation_image_simple4(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE04, 128, 4, None, None, 10); def segmentation_image_simple5(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE05, 128, 4, 4, 10, 4); def segmentation_image_simple6(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE06, 128, 4, 4, 10, 4); def segmentation_image_simple7(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE07, 128, 5, 4, 10, 4); def segmentation_image_simple8(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE08, 128, 5, 4, 10, 4); def segmentation_image_simple9(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE09, 128, 4, 4, 10, 4); def segmentation_image_simple10(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE10, 128, 5, 4, 10, 4); def segmentation_image_simple11(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE11, 64, 10, 4, 10, 4); def segmentation_image_beach(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BEACH, 128, 4, None, None, 10); def segmentation_image_building(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BUILDING, 16, 10, 10, 10, 10); def segmentation_image_fruits_small(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_FRUITS_SMALL, 15, 10, 2, 4, 20); def segmentation_image_white_sea(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_WHITE_SEA, 8, 16, None, None, 30); def segmentation_image_white_sea_small(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_WHITE_SEA_SMALL, 8, 16, None, None, 10); def segmentation_image_nile(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_NILE, 5, 11, None, None, 30); def segmentation_image_nile_small(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_NILE_SMALL, 5, 11, 10, 5, 10); def segmentation_image_map_buildings(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_BUILDINGS, 8, 10, None, None, 5); def segmentation_image_flower_field(): template_segmentation_image(IMAGE_REAL_SAMPLES.IMAGE_FIELD_FLOWER, 8, 8, None, None, 5); def segmentation_image_tree_field(): template_segmentation_image(IMAGE_REAL_SAMPLES.IMAGE_FIELD_TREE, 11, 4, None, None, 5); segmentation_image_simple1(); segmentation_image_simple2(); segmentation_image_simple3(); segmentation_image_simple4(); segmentation_image_simple5(); segmentation_image_simple6(); segmentation_image_simple7(); segmentation_image_simple8(); segmentation_image_simple9(); segmentation_image_simple10(); segmentation_image_simple11(); segmentation_image_beach(); segmentation_image_building(); segmentation_image_fruits_small(); segmentation_image_white_sea(); segmentation_image_white_sea_small(); segmentation_image_nile(); segmentation_image_nile_small(); segmentation_image_map_buildings(); segmentation_image_flower_field(); segmentation_image_tree_field();pyclustering-0.10.1.2/pyclustering/cluster/examples/elbow_examples.py000077500000000000000000000065151375753423500261200ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Elbow method. @authors Andrey Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import matplotlib.pyplot as plt from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer, random_center_initializer from pyclustering.cluster.elbow import elbow from pyclustering.cluster.kmeans import kmeans, kmeans_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES def elbow_analysis(sample_file_path, kmin, kmax, **kwargs): initializer = kwargs.get('initializer', kmeans_plusplus_initializer) sample = read_sample(sample_file_path) elbow_instance = elbow(sample, kmin, kmax, initializer=initializer) elbow_instance.process() amount_clusters = elbow_instance.get_amount() wce = elbow_instance.get_wce() centers = kmeans_plusplus_initializer(sample, amount_clusters).initialize() kmeans_instance = kmeans(sample, centers) kmeans_instance.process() clusters = kmeans_instance.get_clusters() centers = kmeans_instance.get_centers() print("Sample '%s': Obtained amount of clusters: '%d'." % (sample_file_path, amount_clusters)) figure = plt.figure(1) ax = figure.add_subplot(111) ax.plot(range(kmin, kmax), wce, color='b', marker='.') ax.plot(amount_clusters, wce[amount_clusters - kmin], color='r', marker='.', markersize=10) ax.annotate("Elbow", (amount_clusters + 0.1, wce[amount_clusters - kmin] + 5)) ax.grid(True) plt.ylabel("WCE") plt.xlabel("K") plt.show() kmeans_visualizer.show_clusters(sample, clusters, centers) def sample_simple_01(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10) elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, initializer=random_center_initializer) def sample_simple_02(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 10) elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 10, initializer=random_center_initializer) def sample_simple_03(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 10) def sample_simple_04(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 10) def sample_simple_05(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 10) def sample_simple_06(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 1, 10) def sample_simple_07(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 1, 10) def sample_simple_08(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 1, 10) def sample_simple_09(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, 10) def sample_simple_10(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 1, 10) def sample_simple_11(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, 10) def sample_simple_12(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 10) def sample_simple_13(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 1, 10) def sample_simple_14(): elbow_analysis(SIMPLE_SAMPLES.SAMPLE_SIMPLE14, 1, 10) sample_simple_01() sample_simple_02() sample_simple_03() sample_simple_04() sample_simple_05() sample_simple_06() sample_simple_07() sample_simple_08() sample_simple_09() sample_simple_10() sample_simple_11() sample_simple_12() sample_simple_13() sample_simple_14()pyclustering-0.10.1.2/pyclustering/cluster/examples/ema_examples.py000077500000000000000000000153571375753423500255560ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of expectation maximization algorithm. @authors Andrey Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.ema import ema, ema_initializer, ema_observer, ema_visualizer, ema_init_type; from pyclustering.utils import read_sample; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES, FAMOUS_SAMPLES; def template_clustering(sample_file_path, amount_clusters, initializer, show_animation = False): sample = read_sample(sample_file_path); observer = None; if (show_animation is True): observer = ema_observer(); initial_means, initial_covariance = ema_initializer(sample, amount_clusters).initialize(initializer); ema_instance = ema(sample, amount_clusters, initial_means, initial_covariance, observer=observer); ema_instance.process(); clusters = ema_instance.get_clusters(); covariances = ema_instance.get_covariances(); means = ema_instance.get_centers(); cluster_length = [ len(cluster) for cluster in clusters ]; print("Data '" + sample_file_path + "'"); print("Clusters: " + str(len(clusters)) + ", Length:" + str(cluster_length)); if (observer is True): ema_visualizer.show_clusters(observer.get_evolution_clusters()[0], sample, observer.get_evolution_covariances()[0], observer.get_evolution_means()[0]); ema_visualizer.show_clusters(clusters, sample, covariances, means); if (show_animation is True): ema_visualizer.animate_cluster_allocation(sample, observer); #ema_visualizer.animate_cluster_allocation(sample, observer, movie_fps=2, save_movie="ema_target.mp4"); def cluster_sample01_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample01_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, ema_init_type.KMEANS_INITIALIZATION); def cluster_sample02_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample02_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, ema_init_type.KMEANS_INITIALIZATION); def cluster_sample03_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample03_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, ema_init_type.KMEANS_INITIALIZATION); def cluster_sample04_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample04_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, ema_init_type.KMEANS_INITIALIZATION); def cluster_sample05_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample05_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, ema_init_type.KMEANS_INITIALIZATION); def cluster_sample08_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 4, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample08_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 4, ema_init_type.KMEANS_INITIALIZATION); def cluster_sample11_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, ema_init_type.RANDOM_INITIALIZATION); def cluster_sample11_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, ema_init_type.KMEANS_INITIALIZATION); def cluster_elongate_init_random(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, ema_init_type.RANDOM_INITIALIZATION); def cluster_elongate_init_kmeans(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, ema_init_type.KMEANS_INITIALIZATION); def cluster_lsun_init_random(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 3, ema_init_type.RANDOM_INITIALIZATION); def cluster_lsun_init_kmeans(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 3, ema_init_type.KMEANS_INITIALIZATION); def cluster_target_init_random(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 6, ema_init_type.RANDOM_INITIALIZATION); def cluster_target_init_kmeans(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 6, ema_init_type.KMEANS_INITIALIZATION); def cluster_two_diamonds_init_random(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, ema_init_type.RANDOM_INITIALIZATION); def cluster_two_diamonds_init_kmeans(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, ema_init_type.KMEANS_INITIALIZATION); def cluster_wing_nut_init_random(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 2, ema_init_type.RANDOM_INITIALIZATION); def cluster_wing_nut_init_kmeans(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 2, ema_init_type.KMEANS_INITIALIZATION); def cluster_engy_time_init_kmeans(): template_clustering(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 2, ema_init_type.KMEANS_INITIALIZATION, False); def cluster_engy_time_init_random(): template_clustering(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 2, ema_init_type.RANDOM_INITIALIZATION, False); def cluster_old_faithful_init_kmeans(): template_clustering(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL, 2, ema_init_type.KMEANS_INITIALIZATION, True); def cluster_old_faithful_init_random(): template_clustering(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL, 2, ema_init_type.RANDOM_INITIALIZATION, True); def cluster_lsun_more_gaussians(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 6, ema_init_type.KMEANS_INITIALIZATION); def cluster_target_more_gaussians(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 12, ema_init_type.KMEANS_INITIALIZATION); cluster_sample01_init_random(); cluster_sample01_init_kmeans(); cluster_sample02_init_random(); cluster_sample02_init_kmeans(); cluster_sample03_init_random(); cluster_sample03_init_kmeans(); cluster_sample04_init_random(); cluster_sample04_init_kmeans(); cluster_sample05_init_random(); cluster_sample05_init_kmeans(); cluster_sample08_init_random(); cluster_sample08_init_kmeans(); cluster_sample11_init_random(); cluster_sample11_init_kmeans(); cluster_elongate_init_random(); cluster_elongate_init_kmeans(); cluster_lsun_init_random(); cluster_lsun_init_kmeans(); cluster_target_init_random(); cluster_target_init_kmeans(); cluster_two_diamonds_init_random(); cluster_two_diamonds_init_kmeans(); cluster_wing_nut_init_random(); cluster_wing_nut_init_kmeans(); cluster_old_faithful_init_kmeans(); cluster_old_faithful_init_random(); cluster_engy_time_init_kmeans(); cluster_engy_time_init_random(); cluster_lsun_more_gaussians(); cluster_target_more_gaussians();pyclustering-0.10.1.2/pyclustering/cluster/examples/fcm_examples.py000077500000000000000000000106701375753423500255520ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Fuzzy C-Means algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES, FAMOUS_SAMPLES from pyclustering.cluster import cluster_visualizer_multidim from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.fcm import fcm from pyclustering.utils import read_sample from pyclustering.utils import timedcall def template_clustering(start_centers, path): sample = read_sample(path) fcm_instance = fcm(sample, start_centers) fcm_instance.process() clusters = fcm_instance.get_clusters() centers = fcm_instance.get_centers() membership = fcm_instance.get_membership() visualizer = cluster_visualizer_multidim() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(centers, marker='*', markersize=10) visualizer.show() def cluster_sample1(): start_centers = [[4.7, 5.9], [5.7, 6.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): start_centers = [[3.5, 4.8], [6.9, 7], [7.5, 0.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): start_centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): start_centers = [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): start_centers = [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_sample6(): start_centers = [[2.0, 6.0], [8.5, 4.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE6) def cluster_sample7(): start_centers = [[-3.0], [2.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE7) def cluster_sample8(): start_centers = [[-4.0], [3.1], [6.1], [12.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE8) def cluster_elongate(): "Not so applicable for this sample" start_centers = [[1.0, 4.5], [3.1, 2.7]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): "Not so applicable for this sample" start_centers = [[1.0, 3.5], [2.0, 0.5], [3.0, 3.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_LSUN) def cluster_target(): "Not so applicable for this sample" start_centers = [[0.2, 0.2], [0.0, -2.0], [3.0, -3.0], [3.0, 3.0], [-3.0, 3.0], [-3.0, -3.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TARGET) def cluster_two_diamonds(): start_centers = [[0.8, 0.2], [3.0, 0.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_wing_nut(): "Almost good!" start_centers = [[-1.5, 1.5], [1.5, 1.5]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_chainlink(): start_centers = [[1.1, -1.7, 1.1], [-1.4, 2.5, -1.2]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_hepta(): start_centers = [[0.0, 0.0, 0.0], [3.0, 0.0, 0.0], [-2.0, 0.0, 0.0], [0.0, 3.0, 0.0], [0.0, -3.0, 0.0], [0.0, 0.0, 2.5], [0.0, 0.0, -2.5]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_tetra(): start_centers = [[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TETRA) def cluster_engy_time(): start_centers = [[0.5, 0.5], [2.3, 2.9]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_ENGY_TIME) def cluster_iris(): start_centers = kmeans_plusplus_initializer(read_sample(FAMOUS_SAMPLES.SAMPLE_IRIS), 4).initialize() template_clustering(start_centers, FAMOUS_SAMPLES.SAMPLE_IRIS) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample6() cluster_sample7() cluster_sample8() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_engy_time() cluster_iris()pyclustering-0.10.1.2/pyclustering/cluster/examples/ga_examples.py000077500000000000000000000141031375753423500253670ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of genetic algorithm for cluster analysis. @authors Aleksey Kukushkin (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.cluster.ga import genetic_algorithm, ga_observer, ga_visualizer from pyclustering.utils import read_sample import time def template_clustering(path, count_clusters, chromosome_count, population_count, count_mutation_gens, coeff_mutation_count=0.25, select_coeff=1.0, fps=15, animation=False): sample = read_sample(path) algo_instance = genetic_algorithm(data=sample, count_clusters=count_clusters, chromosome_count=chromosome_count, population_count=population_count, count_mutation_gens=count_mutation_gens, coeff_mutation_count=coeff_mutation_count, select_coeff=select_coeff, observer=ga_observer(True, True, True)) start_time = time.time() algo_instance.process() print("Sample: ", path, "\t\tExecution time: ", time.time() - start_time, "\n") observer = algo_instance.get_observer() ga_visualizer.show_clusters(sample, observer) if (animation is True): ga_visualizer.animate_cluster_allocation(sample, observer, movie_fps=fps, save_movie="clustering_animation.mp4") # ga_visualizer.animate_cluster_allocation(sample, observer); def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, count_clusters=2, chromosome_count=20, population_count=20, count_mutation_gens=2) def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, count_clusters=3, chromosome_count=40, population_count=120, count_mutation_gens=2) def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, count_clusters=4, chromosome_count=100, population_count=200, count_mutation_gens=2, coeff_mutation_count=0.8, select_coeff=0.3) def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, count_clusters=5, chromosome_count=100, population_count=200, count_mutation_gens=1) def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, count_clusters=4, chromosome_count=40, population_count=140, count_mutation_gens=1) def cluster_sample6(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, count_clusters=2, chromosome_count=20, population_count=100, count_mutation_gens=1) def cluster_sample7(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, count_clusters=2, chromosome_count=20, population_count=30, count_mutation_gens=1) def cluster_sample11(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, count_clusters=2, chromosome_count=20, population_count=30, count_mutation_gens=2) def cluster_sample8(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, count_clusters=4, chromosome_count=50, population_count=200, count_mutation_gens=2, coeff_mutation_count=0.15, select_coeff=1.0) def animation_cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, count_clusters=2, chromosome_count=10, population_count=50, count_mutation_gens=2, select_coeff=0.02, fps=5, animation=True) def animation_cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, count_clusters=3, chromosome_count=30, population_count=150, count_mutation_gens=2, select_coeff=0.02, fps=8, animation=True) def animation_cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, count_clusters=4, chromosome_count=100, population_count=150, count_mutation_gens=2, coeff_mutation_count=0.8, select_coeff=0.3, fps=5, animation=True) def animation_cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, count_clusters=5, chromosome_count=50, population_count=500, count_mutation_gens=2, select_coeff=0.1, fps=15, animation=True) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample6() cluster_sample7() cluster_sample11() animation_cluster_sample1() animation_cluster_sample2() animation_cluster_sample3() animation_cluster_sample4() pyclustering-0.10.1.2/pyclustering/cluster/examples/general_examples.py000077500000000000000000000146421375753423500264250ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of clustering algorithms from cluster module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from random import random, randint from math import floor import matplotlib.pyplot as plt from pyclustering.nnet import initial_type from pyclustering.cluster.agglomerative import agglomerative from pyclustering.cluster.birch import birch from pyclustering.cluster.clarans import clarans from pyclustering.cluster.cure import cure from pyclustering.cluster.dbscan import dbscan from pyclustering.cluster.hsyncnet import hsyncnet from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.kmedians import kmedians from pyclustering.cluster.kmedoids import kmedoids from pyclustering.cluster.optics import optics from pyclustering.cluster.rock import rock from pyclustering.cluster.syncnet import syncnet from pyclustering.cluster.syncsom import syncsom from pyclustering.cluster.xmeans import xmeans from pyclustering.utils import timedcall CLUSTER_SIZES = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50] NUMBER_CLUSTERS = 4 CURRENT_CLUSTER_SIZE = None REPEAT_MEASURE = 15 def simple_gaussian_data_clustering(cluster_sizes): algorithms_times = { 'agglomerative': [], 'birch': [], 'clarans': [], 'cure': [], 'dbscan': [], 'hsyncnet': [], 'kmeans': [], 'kmedians': [], 'kmedoids': [], 'optics': [], 'rock': [], 'syncnet': [], 'syncsom': [], 'xmeans': [], } algorithms_proc = { 'agglomerative': process_agglomerative, 'birch': process_birch, 'clarans': process_clarans, 'cure': process_cure, 'dbscan': process_dbscan, 'hsyncnet': process_hsyncnet, 'kmeans': process_kmeans, 'kmedians': process_kmedians, 'kmedoids': process_kmedoids, 'optics': process_optics, 'rock': process_rock, 'syncnet': process_syncnet, 'syncsom': process_syncsom, 'xmeans': process_xmeans, } datasizes = [] for cluster_size in cluster_sizes: print("processing clusters with size:", cluster_size) global CURRENT_CLUSTER_SIZE CURRENT_CLUSTER_SIZE = cluster_size # generate data sets dataset = [] for mean in range(0, NUMBER_CLUSTERS, 1): dataset += [ [random() + (mean * 5), random() + (mean * 5)] for _ in range(cluster_size) ] datasizes.append(len(dataset)) # process data and fix time of execution for key in algorithms_proc: summary_result = 0 print("processing clusters with size:", cluster_size, "by", key) for _ in range(REPEAT_MEASURE): summary_result += algorithms_proc[key](dataset) algorithms_times[key].append( summary_result / REPEAT_MEASURE ) print(datasizes) for key in algorithms_times: print(key, ":", algorithms_times[key]) plt.plot(datasizes, algorithms_times[key], label = key, linestyle = '-') plt.show() def process_agglomerative(sample): instance = agglomerative(sample, NUMBER_CLUSTERS) (ticks, _) = timedcall(instance.process) return ticks def process_birch(sample): instance = birch(sample, NUMBER_CLUSTERS) (ticks, _) = timedcall(instance.process) return ticks def process_clarans(sample): instance = clarans(sample, NUMBER_CLUSTERS, 10, 3) (ticks, _) = timedcall(instance.process) return ticks def process_cure(sample): instance = cure(sample, NUMBER_CLUSTERS) (ticks, _) = timedcall(instance.process) return ticks def process_dbscan(sample): instance = dbscan(sample, 1.0, 2) (ticks, _) = timedcall(instance.process) return ticks def process_hsyncnet(sample): instance = hsyncnet(sample, CURRENT_CLUSTER_SIZE, initial_type.EQUIPARTITION, CURRENT_CLUSTER_SIZE) (ticks, _) = timedcall(instance.process, 0.998) return ticks def process_kmeans(sample): instance = kmeans(sample, [ [random() + (multiplier * 5), random() + (multiplier + 5)] for multiplier in range(NUMBER_CLUSTERS) ]) (ticks, _) = timedcall(instance.process) return ticks def process_kmedians(sample): instance = kmedians(sample, [ [random() + (multiplier * 5), random() + (multiplier + 5)] for multiplier in range(NUMBER_CLUSTERS) ]) (ticks, _) = timedcall(instance.process) return ticks def process_kmedoids(sample): instance = kmedoids(sample, [ CURRENT_CLUSTER_SIZE * multiplier for multiplier in range(NUMBER_CLUSTERS) ]) (ticks, _) = timedcall(instance.process) return ticks def process_optics(sample): instance = optics(sample, 1.0, 2) (ticks, _) = timedcall(instance.process) return ticks def process_rock(sample): instance = rock(sample, 1, NUMBER_CLUSTERS, 0.5) (ticks, _) = timedcall(instance.process) return ticks def process_syncnet(sample): instance = syncnet(sample, 3.0, initial_phases = initial_type.EQUIPARTITION) (ticks, _) = timedcall(instance.process) return ticks def process_syncsom(sample): instance = syncsom(sample, 1, NUMBER_CLUSTERS) (ticks, _) = timedcall(instance.process, 0, False, 0.998) return ticks def process_xmeans(sample): instance = xmeans(sample, [ [random() + (multiplier * 5), random() + (multiplier + 5)] for multiplier in range(NUMBER_CLUSTERS) ]) (ticks, _) = timedcall(instance.process) return ticks simple_gaussian_data_clustering(CLUSTER_SIZES)pyclustering-0.10.1.2/pyclustering/cluster/examples/gmeans_examples.py000077500000000000000000000152671375753423500262660ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of G-Means algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.gmeans import gmeans from pyclustering.utils import read_sample def template_clustering(sample_path, k_init=1, ccore=True, **kwargs): sample = read_sample(sample_path) gmeans_instance = gmeans(sample, k_init, ccore, repeat=5).process() clusters = gmeans_instance.get_clusters() centers = gmeans_instance.get_centers() visualize = kwargs.get('visualize', True) if visualize: visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(centers, None, marker='*', markersize=10) visualizer.show() return sample, clusters def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_sample6(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6) def cluster_sample7(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7) def cluster_sample8(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8) def cluster_sample9(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9) def cluster_sample10(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10) def cluster_sample11(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11) def cluster_sample12(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12) def cluster_sample13(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13) def cluster_sample14(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE14) def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN) def cluster_tetra(): template_clustering(FCPS_SAMPLES.SAMPLE_TETRA) def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_wingnut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_atom(): template_clustering(FCPS_SAMPLES.SAMPLE_ATOM) def cluster_engytime(): template_clustering(FCPS_SAMPLES.SAMPLE_ENGY_TIME) def display_simple_clustering_results(): (simple1, simple1_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, visualize=False) (simple2, simple2_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, visualize=False) (simple3, simple3_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, visualize=False) (simple4, simple4_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, visualize=False) (simple5, simple5_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, visualize=False) (simple6, simple6_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, visualize=False) (simple7, simple7_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, visualize=False) (simple8, simple8_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, visualize=False) (simple9, simple9_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, visualize=False) visualizer = cluster_visualizer(9, 3) visualizer.append_clusters(simple1_clusters, simple1, 0, markersize=3) visualizer.append_clusters(simple2_clusters, simple2, 1, markersize=3) visualizer.append_clusters(simple3_clusters, simple3, 2, markersize=3) visualizer.append_clusters(simple4_clusters, simple4, 3, markersize=3) visualizer.append_clusters(simple5_clusters, simple5, 4, markersize=3) visualizer.append_clusters(simple6_clusters, simple6, 5, markersize=6) visualizer.append_clusters(simple7_clusters, simple7, 6, markersize=6) visualizer.append_clusters(simple8_clusters, simple8, 7, markersize=6) visualizer.append_clusters(simple9_clusters, simple9, 8, markersize=6) visualizer.show() def display_fcps_clustering_results(): (simple3, simple3_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, visualize=False) (lsun, lsun_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, visualize=False) (target, target_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, visualize=False) (two_diamonds, two_diamonds_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, visualize=False) (wing_nut, wing_nut_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, visualize=False) (chainlink, chainlink_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, visualize=False) (hepta, hepta_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, visualize=False) (tetra, tetra_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, visualize=False) (atom, atom_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, visualize=False) visualizer = cluster_visualizer(9, 3) visualizer.append_clusters(simple3_clusters, simple3, 0, markersize=3) visualizer.append_clusters(lsun_clusters, lsun, 1, markersize=3) visualizer.append_clusters(target_clusters, target, 2, markersize=3) visualizer.append_clusters(two_diamonds_clusters, two_diamonds, 3, markersize=3) visualizer.append_clusters(wing_nut_clusters, wing_nut, 4, markersize=3) visualizer.append_clusters(chainlink_clusters, chainlink, 5, markersize=6) visualizer.append_clusters(hepta_clusters, hepta, 6, markersize=6) visualizer.append_clusters(tetra_clusters, tetra, 7, markersize=6) visualizer.append_clusters(atom_clusters, atom, 8, markersize=6) visualizer.show() cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample6() cluster_sample7() cluster_sample8() cluster_sample9() cluster_sample10() cluster_sample11() cluster_sample12() cluster_sample13() cluster_sample14() cluster_elongate() cluster_lsun() cluster_tetra() cluster_hepta() cluster_two_diamonds() cluster_chainlink() cluster_wingnut() cluster_atom() cluster_engytime() # display_simple_clustering_results() # display_fcps_clustering_results() pyclustering-0.10.1.2/pyclustering/cluster/examples/hsyncnet_examples.py000077500000000000000000000103051375753423500266330ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Hierarchical Sync (HSyncNet) algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils import read_sample, draw_clusters, timedcall; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; from pyclustering.cluster.hsyncnet import hsyncnet; from pyclustering.nnet.sync import sync_visualizer; from pyclustering.nnet import initial_type, solve_type; def template_clustering(file, number_clusters, arg_order = 0.999, arg_collect_dynamic = True, ccore_flag = False): sample = read_sample(file); network = hsyncnet(sample, number_clusters, initial_neighbors = int(len(sample) * 0.15), osc_initial_phases = initial_type.EQUIPARTITION, ccore = ccore_flag); (ticks, analyser) = timedcall(network.process, arg_order, solve_type.FAST, arg_collect_dynamic); print("Sample: ", file, "\t\tExecution time: ", ticks, "\n"); clusters = analyser.allocate_clusters(); if (arg_collect_dynamic == True): sync_visualizer.show_output_dynamic(analyser); draw_clusters(sample, clusters); def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, ccore_flag = True); def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3); def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4); def cluster_simple4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5); def cluster_simple5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, arg_collect_dynamic = False); def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 3, arg_collect_dynamic = False); def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, arg_collect_dynamic = False); def cluster_tetra(): template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 4, arg_collect_dynamic = False); def cluster_target(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 6, arg_collect_dynamic = False); def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 2, arg_collect_dynamic = False); def cluster_wing_nut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 2, arg_collect_dynamic = False); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, arg_collect_dynamic = False); def experiment_execution_time(show_dyn = False, ccore = False): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 0.999, show_dyn, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 0.999, show_dyn, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 0.999, show_dyn, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, 0.999, show_dyn, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, 0.999, show_dyn, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, 0.999, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 3, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 6, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 2, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 2, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 4, 0.98, show_dyn, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 2, 0.98, show_dyn, ccore); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_simple4(); cluster_elongate(); cluster_lsun(); cluster_hepta(); cluster_tetra(); cluster_target(); cluster_chainlink(); cluster_wing_nut(); cluster_two_diamonds(); experiment_execution_time(False, False); experiment_execution_time(False, True);pyclustering-0.10.1.2/pyclustering/cluster/examples/kmeans_examples.py000077500000000000000000000164661375753423500262740ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of K-Means algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES, FAMOUS_SAMPLES from pyclustering.cluster import cluster_visualizer_multidim from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.kmeans import kmeans, kmeans_observer, kmeans_visualizer from pyclustering.utils import read_sample from pyclustering.utils import timedcall from pyclustering.utils.metric import distance_metric, type_metric def template_clustering(start_centers, path, tolerance = 0.25, ccore = False): sample = read_sample(path) dimension = len(sample[0]) metric = distance_metric(type_metric.MANHATTAN) observer = kmeans_observer() kmeans_instance = kmeans(sample, start_centers, tolerance, ccore, observer=observer, metric=metric) (ticks, _) = timedcall(kmeans_instance.process) clusters = kmeans_instance.get_clusters() centers = kmeans_instance.get_centers() print("Sample: ", path, "\t\tExecution time: ", ticks, "\n") visualizer = cluster_visualizer_multidim() visualizer.append_clusters(clusters, sample) visualizer.show() if dimension > 3: kmeans_visualizer.show_clusters(sample, clusters, centers, start_centers) kmeans_visualizer.animate_cluster_allocation(sample, observer) def cluster_sample1(): start_centers = [[4.7, 5.9], [5.7, 6.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): start_centers = [[3.5, 4.8], [6.9, 7], [7.5, 0.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): start_centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): start_centers = [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): start_centers = [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_sample7(): start_centers = [[-3.0], [2.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE7) def cluster_sample8(): start_centers = [[-4.0], [3.1], [6.1], [12.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE8) def cluster_elongate(): "Not so applicable for this sample" start_centers = [[1.0, 4.5], [3.1, 2.7]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): "Not so applicable for this sample" start_centers = [[1.0, 3.5], [2.0, 0.5], [3.0, 3.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_LSUN) def cluster_target(): "Not so applicable for this sample" start_centers = [[0.2, 0.2], [0.0, -2.0], [3.0, -3.0], [3.0, 3.0], [-3.0, 3.0], [-3.0, -3.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TARGET) def cluster_two_diamonds(): start_centers = [[0.8, 0.2], [3.0, 0.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_wing_nut(): "Almost good!" start_centers = [[-1.5, 1.5], [1.5, 1.5]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_chainlink(): start_centers = [[1.1, -1.7, 1.1], [-1.4, 2.5, -1.2]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_hepta(): start_centers = [[0.0, 0.0, 0.0], [3.0, 0.0, 0.0], [-2.0, 0.0, 0.0], [0.0, 3.0, 0.0], [0.0, -3.0, 0.0], [0.0, 0.0, 2.5], [0.0, 0.0, -2.5]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_tetra(): start_centers = [[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TETRA) def cluster_engy_time(): start_centers = [[0.5, 0.5], [2.3, 2.9]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_ENGY_TIME) def cluster_iris(): start_centers = kmeans_plusplus_initializer(read_sample(FAMOUS_SAMPLES.SAMPLE_IRIS), 4).initialize() template_clustering(start_centers, FAMOUS_SAMPLES.SAMPLE_IRIS) def experiment_execution_time(ccore = False): template_clustering([[3.7, 5.5], [6.7, 7.5]], SIMPLE_SAMPLES.SAMPLE_SIMPLE1, ccore) template_clustering([[3.5, 4.8], [6.9, 7], [7.5, 0.5]], SIMPLE_SAMPLES.SAMPLE_SIMPLE2, ccore) template_clustering([[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], SIMPLE_SAMPLES.SAMPLE_SIMPLE3, ccore) template_clustering([[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], SIMPLE_SAMPLES.SAMPLE_SIMPLE4, ccore) template_clustering([[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], SIMPLE_SAMPLES.SAMPLE_SIMPLE5, ccore) template_clustering([[1.0, 4.5], [3.1, 2.7]], SIMPLE_SAMPLES.SAMPLE_ELONGATE, ccore) template_clustering([[1.0, 3.5], [2.0, 0.5], [3.0, 3.0]], FCPS_SAMPLES.SAMPLE_LSUN, ccore) template_clustering([[0.2, 0.2], [0.0, -2.0], [3.0, -3.0], [3.0, 3.0], [-3.0, 3.0], [-3.0, -3.0]], FCPS_SAMPLES.SAMPLE_TARGET, ccore) template_clustering([[0.8, 0.2], [3.0, 0.0]], FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, ccore) template_clustering([[-1.5, 1.5], [1.5, 1.5]], FCPS_SAMPLES.SAMPLE_WING_NUT, ccore) template_clustering([[1.1, -1.7, 1.1], [-1.4, 2.5, -1.2]], FCPS_SAMPLES.SAMPLE_CHAINLINK, ccore) template_clustering([[0.0, 0.0, 0.0], [3.0, 0.0, 0.0], [-2.0, 0.0, 0.0], [0.0, 3.0, 0.0], [0.0, -3.0, 0.0], [0.0, 0.0, 2.5], [0.0, 0.0, -2.5]], FCPS_SAMPLES.SAMPLE_HEPTA, ccore) template_clustering([[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]], FCPS_SAMPLES.SAMPLE_TETRA, ccore) template_clustering([[-0.5, -0.5, -0.5], [0.5, 0.5, 0.5]], FCPS_SAMPLES.SAMPLE_ATOM, ccore) template_clustering([[0.5, 0.5], [2.3, 2.9]], FCPS_SAMPLES.SAMPLE_ENGY_TIME, ccore) def clustering_random_points(amount_points, amount_centers, ccore): sample = [ [ random.random(), random.random() ] for _ in range(amount_points) ] centers = [ [ random.random(), random.random() ] for _ in range(amount_centers) ] kmeans_instance = kmeans(sample, centers, 0.0001, ccore) (ticks, _) = timedcall(kmeans_instance.process) print("Execution time ("+ str(amount_points) +" 2D-points):", ticks) def performance_measure_random_points(ccore): clustering_random_points(1000, 5, ccore) clustering_random_points(2000, 5, ccore) clustering_random_points(3000, 5, ccore) clustering_random_points(4000, 5, ccore) clustering_random_points(5000, 5, ccore) clustering_random_points(10000, 5, ccore) clustering_random_points(20000, 5, ccore) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample7() cluster_sample8() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_engy_time() cluster_iris() experiment_execution_time(False) # Python code experiment_execution_time(True) # C++ code + Python env. performance_measure_random_points(False)pyclustering-0.10.1.2/pyclustering/cluster/examples/kmeans_segmentation.py000077500000000000000000000062741375753423500271470ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of K-Means algorithm in image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils import draw_image_mask_segments, read_image; from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES, IMAGE_MAP_SAMPLES; from pyclustering.cluster.kmeans import kmeans; from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer; def template_segmentation_image(source, start_centers): data = read_image(source); kmeans_instance = kmeans(data, start_centers); kmeans_instance.process(); clusters = kmeans_instance.get_clusters(); draw_image_mask_segments(source, clusters); def template_segmentation_image_amount_colors(source, amount): data = read_image(source); centers = kmeans_plusplus_initializer(data, amount, kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE).initialize(); kmeans_instance = kmeans(data, centers); kmeans_instance.process(); clusters = kmeans_instance.get_clusters(); draw_image_mask_segments(source, clusters); def segmentation_image_simple1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, [[255, 0, 0], [0, 0, 255], [180, 136, 0], [255, 255, 255]]); def segmentation_image_simple2(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE02, [[255, 0, 0, 128], [0, 0, 255, 128], [180, 136, 0, 128], [255, 255, 255, 128]]); def segmentation_image_simple3(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE03, [[255, 0, 0, 128], [0, 0, 255, 128], [180, 136, 0, 128]]); def segmentation_image_simple4(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE04, [[0, 128, 0, 128], [255, 0, 0, 128]]); def segmentation_image_beach(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BEACH, [[153, 217, 234, 128], [0, 162, 232, 128], [34, 177, 76, 128], [255, 242, 0, 128]]); def segmentation_image_building(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BUILDING, [[93, 104, 111, 128], [130, 179, 211, 128], [176, 142, 105, 128]]); def segmentation_image_fruit(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_FRUITS, [[164, 35, 39, 128], [248, 187, 18, 128], [255, 255, 255, 128]]); def segmentation_image_fruit_small(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_FRUITS_SMALL, [[164, 35, 39, 128], [248, 187, 18, 128], [255, 255, 255, 128]]); def segmentation_image_nil(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_NILE_SMALL, [[54, 64, 39], [193, 171, 134], [26, 71, 128]]); def segmentation_image_map_buildings(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_BUILDINGS, [[134, 179, 166], [73, 95, 74], [75, 84, 80]]); segmentation_image_simple1(); segmentation_image_simple2(); segmentation_image_simple3(); segmentation_image_simple4(); segmentation_image_beach(); segmentation_image_fruit(); segmentation_image_building(); segmentation_image_fruit_small(); segmentation_image_nil(); segmentation_image_map_buildings();pyclustering-0.10.1.2/pyclustering/cluster/examples/kmedians_examples.py000077500000000000000000000071531375753423500266020ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of K-Medians algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.kmedians import kmedians from pyclustering.utils import draw_clusters from pyclustering.utils import read_sample from pyclustering.utils import timedcall def template_clustering(start_medians, path, tolerance = 0.25): sample = read_sample(path) kmedians_instance = kmedians(sample, start_medians, tolerance) (ticks, result) = timedcall(kmedians_instance.process) clusters = kmedians_instance.get_clusters() print("Sample: ", path, "\t\tExecution time: ", ticks, "\n") draw_clusters(sample, clusters) def cluster_sample1(): start_medians = [[3.7, 5.5], [6.7, 7.5]] template_clustering(start_medians, SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): start_medians = [[3.5, 4.8], [6.9, 7], [7.5, 0.5]] template_clustering(start_medians, SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): start_medians = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] template_clustering(start_medians, SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): start_medians = [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]] template_clustering(start_medians, SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): start_medians = [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]] template_clustering(start_medians, SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_elongate(): start_medians = [[1.0, 4.5], [3.1, 2.7]] template_clustering(start_medians, SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): start_medians = [[1.0, 3.5], [2.0, 0.5], [3.0, 3.0]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_LSUN) def cluster_target(): start_medians = [[0.2, 0.2], [0.0, -2.0], [3.0, -3.0], [3.0, 3.0], [-3.0, 3.0], [-3.0, -3.0]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_TARGET) def cluster_two_diamonds(): start_medians = [[0.8, 0.2], [3.0, 0.0]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_wing_nut(): start_medians = [[-1.5, 1.5], [1.5, 1.5]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_chainlink(): start_medians = [[1.1, -1.7, 1.1], [-1.4, 2.5, -1.2]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_hepta(): start_medians = [[0.0, 0.0, 0.0], [3.0, 0.0, 0.0], [-2.0, 0.0, 0.0], [0.0, 3.0, 0.0], [0.0, -3.0, 0.0], [0.0, 0.0, 2.5], [0.0, 0.0, -2.5]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_tetra(): start_medians = [[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_TETRA) def cluster_engy_time(): start_medians = [[0.5, 0.5], [2.3, 2.9]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_ENGY_TIME) def cluster_atom(): start_medians = [[-0.5, -0.5, -0.5], [0.5, 0.5, 0.5]] template_clustering(start_medians, FCPS_SAMPLES.SAMPLE_ATOM) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_atom() cluster_engy_time() pyclustering-0.10.1.2/pyclustering/cluster/examples/kmedoids_examples.py000077500000000000000000000120421375753423500265770ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of K-Medoids algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.kmedoids import kmedoids from pyclustering.utils import read_sample, calculate_distance_matrix from pyclustering.utils import timedcall, distance_metric, type_metric def template_clustering(start_medoids, path, tolerance=0.25, show=True, **kwargs): ccore = kwargs.get('ccore', True) data_type = kwargs.get('data_type', 'points') original_data = read_sample(path) sample = original_data if data_type == 'distance_matrix': sample = calculate_distance_matrix(sample) metric = distance_metric(type_metric.EUCLIDEAN_SQUARE, data=sample) kmedoids_instance = kmedoids(sample, start_medoids, tolerance, metric=metric, ccore=ccore, data_type=data_type) (ticks, result) = timedcall(kmedoids_instance.process) clusters = kmedoids_instance.get_clusters() print(clusters) medoids = kmedoids_instance.get_medoids() print("Sample: ", path, "\t\tExecution time: ", ticks, "\n") if show is True: visualizer = cluster_visualizer(1) visualizer.append_clusters(clusters, original_data, 0) visualizer.append_cluster([original_data[index] for index in start_medoids], marker='*', markersize=15) visualizer.append_cluster(medoids, data=original_data, marker='*', markersize=15) visualizer.show() return original_data, clusters def cluster_sample1(): template_clustering([2, 9], SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def cluster_sample2(): template_clustering([3, 12, 20], SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def cluster_sample3(): template_clustering([4, 12, 25, 37], SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def cluster_sample4(): template_clustering([4, 15, 30, 40, 50], SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def cluster_sample5(): template_clustering([4, 18, 34, 55], SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def cluster_elongate(): template_clustering([8, 56], SIMPLE_SAMPLES.SAMPLE_ELONGATE) def cluster_lsun(): #template_clustering([10, 275, 385], FCPS_SAMPLES.SAMPLE_LSUN) template_clustering([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], FCPS_SAMPLES.SAMPLE_LSUN, data_type='distance_matrix') def cluster_target(): template_clustering([10, 160, 310, 460, 560, 700], FCPS_SAMPLES.SAMPLE_TARGET) def cluster_two_diamonds(): template_clustering([10, 650], FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) def cluster_wing_nut(): template_clustering([19, 823], FCPS_SAMPLES.SAMPLE_WING_NUT) def cluster_chainlink(): template_clustering([30, 900], FCPS_SAMPLES.SAMPLE_CHAINLINK) def cluster_hepta(): template_clustering([0, 35, 86, 93, 125, 171, 194], FCPS_SAMPLES.SAMPLE_HEPTA) def cluster_tetra(): template_clustering([0, 131, 214, 265], FCPS_SAMPLES.SAMPLE_TETRA) def cluster_atom(): template_clustering([0, 650], FCPS_SAMPLES.SAMPLE_ATOM) def cluster_engy_time(): template_clustering([10, 3000], FCPS_SAMPLES.SAMPLE_ENGY_TIME) def display_fcps_clustering_results(): (lsun, lsun_clusters) = template_clustering([10, 275, 385], FCPS_SAMPLES.SAMPLE_LSUN, 0.1, False) (target, target_clusters) = template_clustering([10, 160, 310, 460, 560, 700], FCPS_SAMPLES.SAMPLE_TARGET, 0.1, False) (two_diamonds, two_diamonds_clusters) = template_clustering([10, 650], FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 0.1, False) (wing_nut, wing_nut_clusters) = template_clustering([19, 823], FCPS_SAMPLES.SAMPLE_WING_NUT, 0.1, False) (chainlink, chainlink_clusters) = template_clustering([30, 900], FCPS_SAMPLES.SAMPLE_CHAINLINK, 0.1, False) (hepta, hepta_clusters) = template_clustering([0, 35, 86, 93, 125, 171, 194], FCPS_SAMPLES.SAMPLE_HEPTA, 0.1, False) (tetra, tetra_clusters) = template_clustering([0, 131, 214, 265], FCPS_SAMPLES.SAMPLE_TETRA, 0.1, False) (atom, atom_clusters) = template_clustering([0, 650], FCPS_SAMPLES.SAMPLE_ATOM, 0.1, False) visualizer = cluster_visualizer(8, 4) visualizer.append_clusters(lsun_clusters, lsun, 0) visualizer.append_clusters(target_clusters, target, 1) visualizer.append_clusters(two_diamonds_clusters, two_diamonds, 2) visualizer.append_clusters(wing_nut_clusters, wing_nut, 3) visualizer.append_clusters(chainlink_clusters, chainlink, 4) visualizer.append_clusters(hepta_clusters, hepta, 5) visualizer.append_clusters(tetra_clusters, tetra, 6) visualizer.append_clusters(atom_clusters, atom, 7) visualizer.show() cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_atom() cluster_engy_time() display_fcps_clustering_results() pyclustering-0.10.1.2/pyclustering/cluster/examples/mbsas_examples.py000077500000000000000000000037611375753423500261150ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of MBSAS algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.bsas import bsas_visualizer; from pyclustering.cluster.mbsas import mbsas; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; from pyclustering.utils import read_sample; from pyclustering.utils.metric import distance_metric, type_metric; def template_clustering(path, amount, threshold, **kwargs): metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)); ccore = kwargs.get('ccore', False); draw = kwargs.get('draw', True); sample = read_sample(path); print("Sample: ", path); mbsas_instance = mbsas(sample, amount, threshold, ccore=ccore, metric=metric); mbsas_instance.process(); clusters = mbsas_instance.get_clusters(); representatives = mbsas_instance.get_representatives(); if draw is True: bsas_visualizer.show_clusters(sample, clusters, representatives); def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0); def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1.0); def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 1.0); def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, 1.0); def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, 1.0); def cluster_sample6(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 2, 1.0); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2, 1.0); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2, 1.0); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_sample4(); cluster_sample5(); cluster_sample6(); cluster_elongate(); cluster_two_diamonds();pyclustering-0.10.1.2/pyclustering/cluster/examples/optics_examples.py000077500000000000000000000123731375753423500263100ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of OPTICS algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer from pyclustering.utils import read_sample, timedcall from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_clustering(path_sample, eps, minpts, amount_clusters = None, visualize = True, ccore = False): sample = read_sample(path_sample) optics_instance = optics(sample, eps, minpts, amount_clusters, ccore) (ticks, _) = timedcall(optics_instance.process) print("Sample: ", path_sample, "\t\tExecution time: ", ticks, "\n") if (visualize is True): clusters = optics_instance.get_clusters() noise = optics_instance.get_noise() visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(noise, sample, marker = 'x') visualizer.show() ordering = optics_instance.get_ordering() analyser = ordering_analyser(ordering) ordering_visualizer.show_ordering_diagram(analyser, amount_clusters) def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5, 3) def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3.0, 3) def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3) def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3) def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3) def cluster_sample6(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 1.0, 3) def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 0.5, 3) def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 0.5, 3) def cluster_lsun_radius_calculation(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 1.0, 3, 3) def cluster_target(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 0.5, 2) def cluster_target_radius_calculation(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 10.0, 2, 6) def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 0.15, 7) def cluster_two_diamonds_radius_calculation(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1.0, 7, 2) def cluster_wing_nut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 0.25, 2) def cluster_wing_nut_radius_calculation(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 1.0, 2, 2) def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 0.15, 3) def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3) def cluster_golf_ball(): template_clustering(FCPS_SAMPLES.SAMPLE_GOLF_BALL, 0.5, 3) def cluster_atom(): template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 15, 3) def cluster_tetra(): template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 0.4, 3) def cluster_engy_time(): template_clustering(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 0.2, 20) def experiment_execution_time(ccore): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 1.0, 3, 3, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 10.0, 2, 6, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1.0, 7, 2, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 2.0, 3, 2, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 1.0, 2, 2, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3, None, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 1.0, 3, 4, False, ccore) template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 30, 3, 2, False, ccore) def clustering_random_points(amount, ccore): sample = [ [ random.random(), random.random() ] for _ in range(amount) ] optics_instance = optics(sample, 0.05, 20, None, ccore) (ticks, _) = timedcall(optics_instance.process) print("Execution time ("+ str(amount) +" 2D-points):", ticks) def performance_measure_random_points(ccore): clustering_random_points(1000, ccore) clustering_random_points(2000, ccore) clustering_random_points(3000, ccore) clustering_random_points(4000, ccore) clustering_random_points(5000, ccore) clustering_random_points(10000, ccore) clustering_random_points(20000, ccore) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_sample6() cluster_elongate() cluster_lsun() cluster_lsun_radius_calculation() cluster_target() cluster_target_radius_calculation() cluster_two_diamonds() cluster_two_diamonds_radius_calculation() cluster_wing_nut() cluster_wing_nut_radius_calculation() cluster_chainlink() cluster_hepta() cluster_golf_ball() cluster_atom() cluster_tetra() cluster_engy_time() experiment_execution_time(False) experiment_execution_time(True) performance_measure_random_points(False) performance_measure_random_points(True)pyclustering-0.10.1.2/pyclustering/cluster/examples/rock_examples.py000077500000000000000000000072461375753423500257500ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of ROCK algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.rock import rock; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.samples.definitions import FCPS_SAMPLES; from pyclustering.utils import read_sample; from pyclustering.utils import draw_clusters; from pyclustering.utils import timedcall; def template_clustering(path, radius, cluster_numbers, threshold, draw = True, ccore = True): sample = read_sample(path); rock_instance = rock(sample, radius, cluster_numbers, threshold, ccore); (ticks, result) = timedcall(rock_instance.process); clusters = rock_instance.get_clusters(); print("Sample: ", path, "\t\tExecution time: ", ticks, "\n"); if (draw == True): draw_clusters(sample, clusters); def cluster_simple1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 0.5); def cluster_simple2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 0.5); def cluster_simple3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 0.5); def cluster_simple4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 0.5); def cluster_simple5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 0.5); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 1, 2, 0.5); def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 1, 3, 0.5); def cluster_target(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 1.2, 6, 0.2); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 0.2, 2, 0.2); def cluster_wing_nut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 0.3, 2, 0.2); def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 0.6, 2, 0.2); def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1.2, 7, 0.2); def cluster_tetra(): template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 0.5, 4, 0.2); def experiment_execution_time(ccore): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 0.5, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 0.5, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 0.5, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 0.5, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 1, 2, 0.5, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 1, 3, 0.5, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 1.2, 6, 0.2, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 0.2, 2, 0.2, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 0.3, 2, 0.2, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 0.6, 2, 0.2, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1.2, 7, 0.2, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 0.5, 4, 0.2, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 15, 2, 0.2, True, ccore) cluster_simple1(); cluster_simple2(); cluster_simple3(); cluster_simple4(); cluster_simple5(); cluster_elongate(); cluster_lsun(); cluster_target(); cluster_two_diamonds(); cluster_wing_nut(); cluster_chainlink(); cluster_hepta(); cluster_tetra(); experiment_execution_time(False); # Slow code - python # experiment_execution_time(True); # Fast code - C++ CCOREpyclustering-0.10.1.2/pyclustering/cluster/examples/silhouette_examples.py000077500000000000000000000066321375753423500271750ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Silhouette algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.silhouette import silhouette_ksearch_type, silhouette_ksearch from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.utils import read_sample def find_optimal_amout_clusters(sample_path, kmin, kmax, algorithm): sample = read_sample(sample_path) search_instance = silhouette_ksearch(sample, kmin, kmax, algorithm=algorithm).process() amount = search_instance.get_amount() scores = search_instance.get_scores() print("Sample: '%s', Scores: '%s'" % (sample_path, str(scores))) initial_centers = kmeans_plusplus_initializer(sample, amount).initialize() kmeans_instance = kmeans(sample, initial_centers).process() clusters = kmeans_instance.get_clusters() visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() def sample_simple01(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple02(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple03(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple04(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple05(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple06(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple07(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple08(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple09(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple10(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple11(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple12(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple13(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 2, 10, silhouette_ksearch_type.KMEANS) def sample_simple14(): find_optimal_amout_clusters(SIMPLE_SAMPLES.SAMPLE_SIMPLE14, 2, 10, silhouette_ksearch_type.KMEANS) def sample_hepta(): find_optimal_amout_clusters(FCPS_SAMPLES.SAMPLE_HEPTA, 2, 10, silhouette_ksearch_type.KMEANS) sample_simple01() sample_simple02() sample_simple03() sample_simple04() sample_simple05() sample_simple06() sample_simple07() sample_simple08() sample_simple09() sample_simple10() sample_simple11() sample_simple12() sample_simple13() sample_simple14() sample_hepta()pyclustering-0.10.1.2/pyclustering/cluster/examples/somsc_examples.py000077500000000000000000000046621375753423500261350ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of SOM-SC algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.somsc import somsc; from pyclustering.utils import read_sample; from pyclustering.utils import timedcall; def template_clustering(path, amount_clusters, epouch = 100, ccore = True): sample = read_sample(path); somsc_instance = somsc(sample, amount_clusters, epouch, ccore); (ticks, _) = timedcall(somsc_instance.process); clusters = somsc_instance.get_clusters(); print("Sample: ", path, "\t\tExecution time: ", ticks, "\n"); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample); visualizer.show(); def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2); def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3); def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4); def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5); def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 6); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 2); def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 3); def cluster_target(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 6); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 2); def cluster_wing_nut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 2); def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 2); def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7); def cluster_tetra(): template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 4); def cluster_engy_time(): template_clustering(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 2); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_sample4(); cluster_sample5(); cluster_elongate(); cluster_lsun(); cluster_target(); cluster_two_diamonds(); cluster_wing_nut(); cluster_chainlink(); cluster_hepta(); cluster_tetra(); cluster_engy_time();pyclustering-0.10.1.2/pyclustering/cluster/examples/syncnet_examples.py000077500000000000000000000224101375753423500264630ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Sync algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.syncnet import syncnet, syncnet_visualizer; from pyclustering.nnet.sync import sync_visualizer; from pyclustering.nnet import initial_type, solve_type; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.samples.definitions import FCPS_SAMPLES; from pyclustering.utils import draw_clusters; from pyclustering.utils import read_sample; from pyclustering.utils import timedcall; def template_clustering(file, radius, order, show_dyn = False, show_conn = False, show_clusters = True, ena_conn_weight = False, ccore_flag = True, tolerance = 0.1): sample = read_sample(file) syncnet_instance = syncnet(sample, radius, enable_conn_weight = ena_conn_weight, ccore = ccore_flag) (ticks, analyser) = timedcall(syncnet_instance.process, order, solve_type.FAST, show_dyn) print("Sample: ", file, "\t\tExecution time: ", ticks) if show_dyn == True: sync_visualizer.show_output_dynamic(analyser) sync_visualizer.animate(analyser) sync_visualizer.show_local_order_parameter(analyser, syncnet_instance) #sync_visualizer.animate_output_dynamic(analyser); #sync_visualizer.animate_correlation_matrix(analyser, colormap = 'hsv') if show_conn == True: syncnet_instance.show_network() if show_clusters == True: clusters = analyser.allocate_clusters(tolerance) print("Amount of allocated clusters: ", len(clusters)) draw_clusters(sample, clusters) print("----------------------------\n") return (sample, clusters) def cluster_simple1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, show_dyn = True, show_conn = True); def cluster_simple2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, show_dyn = True, show_conn = True); def cluster_simple3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, show_dyn = True, show_conn = True); def cluster_simple4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0.999, show_dyn = True, show_conn = True); def cluster_simple5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0.999, show_dyn = True, show_conn = True); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 0.5, 0.999, show_dyn = True, show_conn = True); def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 0.45, 0.9995, show_dyn = True, show_conn = True); def cluster_target(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 0.95, 0.99995, show_dyn = False, show_conn = True); def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 0.999, show_dyn = True, show_conn = True); def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 0.8, 0.999, show_dyn = True, show_conn = True); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 0.3, 0.999, show_dyn = False, show_conn = False); def cluster_atom(): template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 25, 0.999, show_dyn = False, show_conn = False); def cluster_wing_nut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 0.28, 0.999, show_dyn = False, show_conn = False); def experiment_execution_time(show_dyn = False, ccore = False): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, show_dyn, False, True, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, show_dyn, False, True, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, show_dyn, False, True, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0.999, show_dyn, False, True, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0.999, show_dyn, False, True, False, ccore); template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 0.5, 0.999, show_dyn, False, True, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 0.45, 0.98, show_dyn, False, False, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 0.4, 0.98, show_dyn, False, False, True, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 0.3, 0.98, show_dyn, False, True, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, 0.28, 0.98, show_dyn, False, True, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, 0.8, 0.98, show_dyn, False, True, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 0.98, show_dyn, False, True, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, 0.3, 0.98, show_dyn, False, True, False, ccore); template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, 25, 0.98, show_dyn, False, True, False, ccore); def cluster_simple1_conn_weight(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 0.999, show_dyn = True, show_conn = True, ena_conn_weight = True); def cluster_simple2_conn_weight(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 0.999, show_dyn = True, show_conn = True, ena_conn_weight = True); def cluster_simple3_conn_weight(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 0.999, show_dyn = True, show_conn = True, ena_conn_weight = True); def cluster_simple4_conn_weight(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 10, 0.999, show_dyn = True, show_conn = True, ena_conn_weight = True); def cluster_simple5_conn_weight(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 10, 0.999, show_dyn = True, show_conn = True, ena_conn_weight = True); def template_animated_clustering(file, radius, order, expected_cluster_amount, title_animation = None): sample = read_sample(file); expected_result_obtained = False; analyser = None; while (expected_result_obtained == False): network = syncnet(sample, radius, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore = True); analyser = network.process(order, solve_type.FAST, True); clusters = analyser.allocate_clusters(0.1); if (len(clusters) == expected_cluster_amount): print("Expected result is obtained - start rendering...") expected_result_obtained = True; visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample); visualizer.show(); else: print("Expected result is NOT obtained - rendering is NOT started ( actual:", len(clusters), ")..."); syncnet_visualizer.animate_cluster_allocation(sample, analyser, tolerance = 0.1, save_movie = "clustering_animation.mp4", title = title_animation); def animation_cluster_allocation_sample_simple3(): template_animated_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1.0, 0.999, 4); def animation_cluster_allocation_sample_simple5(): template_animated_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1.0, 0.999, 4); def animation_cluster_allocation_elongate(): template_animated_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 0.5, 0.999, 2); def animation_cluster_allocation_lsun(): template_animated_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 0.45, 0.999, 3); def animation_cluster_allocation_target(): template_animated_clustering(FCPS_SAMPLES.SAMPLE_TARGET, 0.95, 0.9999, 6); def animation_cluster_allocation_hepta(): template_animated_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 0.995, 7, "Sync clustering\nOscillatory based algorithm"); def display_fcps_clustering_results(): (simple4, simple4_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0.999, show_dyn = False, show_conn = False, ccore_flag = True); (simple_elongate, simple_elongate_clusters) = template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 0.5, 0.999, show_dyn = False, show_conn = False, ccore_flag = True); (lsun, lsun_clusters) = template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, 0.45, 0.9995, show_dyn = False, show_conn = False, ccore_flag = True, tolerance = 0.2); visualizer = cluster_visualizer(1, 3); visualizer.append_clusters(simple4_clusters, simple4, 0); visualizer.append_clusters(simple_elongate_clusters, simple_elongate, 1); visualizer.append_clusters(lsun_clusters, lsun, 2); visualizer.show(); cluster_simple1(); cluster_simple2(); cluster_simple3(); cluster_simple4(); cluster_simple5(); cluster_elongate(); cluster_lsun(); cluster_target(); cluster_hepta(); cluster_chainlink(); cluster_two_diamonds(); cluster_atom(); cluster_wing_nut(); cluster_simple1_conn_weight(); cluster_simple2_conn_weight(); cluster_simple3_conn_weight(); cluster_simple4_conn_weight(); cluster_simple5_conn_weight(); experiment_execution_time(False, False); experiment_execution_time(False, True); animation_cluster_allocation_sample_simple3(); animation_cluster_allocation_sample_simple5(); animation_cluster_allocation_elongate(); animation_cluster_allocation_lsun(); animation_cluster_allocation_target(); animation_cluster_allocation_hepta(); display_fcps_clustering_results();pyclustering-0.10.1.2/pyclustering/cluster/examples/syncsom_examples.py000077500000000000000000000137551375753423500265070ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of SYNC-SOM algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from random import random; from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.syncsom import syncsom; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.samples.definitions import FCPS_SAMPLES; from pyclustering.utils import read_sample, draw_dynamics; from pyclustering.utils import timedcall; def template_clustering(file, map_size, radius, sync_order = 0.999, show_dyn = False, show_layer1 = False, show_layer2 = False, show_clusters = True): # Read sample sample = read_sample(file); # Create network network = syncsom(sample, map_size[0], map_size[1], radius); # Run processing (ticks, (dyn_time, dyn_phase)) = timedcall(network.process, show_dyn, sync_order); print("Sample: ", file, "\t\tExecution time: ", ticks, "\n"); # Show dynamic of the last layer. if (show_dyn == True): draw_dynamics(dyn_time, dyn_phase, x_title = "Time", y_title = "Phase", y_lim = [0, 3.14]); if (show_clusters == True): clusters = network.get_som_clusters(); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, network.som_layer.weights); visualizer.show(); # Show network stuff. if (show_layer1 == True): network.show_som_layer(); if (show_layer2 == True): network.show_sync_layer(); if (show_clusters == True): clusters = network.get_clusters(); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample); visualizer.show(); def cluster_simple1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [4, 4], 1.0, 0.999, True, True, True, True); def cluster_simple1_as_som(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [1, 2], 1.0, 0.999, True, True, True, True); def cluster_simple2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [4, 4], 1.0, 0.999, True, True, True, True); def cluster_simple2_as_som(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [1, 3], 1.0, 0.999, True, True, True, True); def cluster_simple3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [5, 5], 1.0, 0.999, True, True, True, True); def cluster_simple4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [5, 5], 1.0, 0.999, True, True, True); def cluster_simple5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [5, 5], 1.0, 0.999, True, True, True); def cluster_lsun(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, [9, 9], 0.45, 0.999, True, True, True); def cluster_target(): template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, [9, 9], 0.9, 0.999, True, True, True); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [10, 10], 0.15, 0.999, True, True, True); def cluster_wing_nut(): template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, [10, 10], 0.25, 0.999, True, True, True); def cluster_chainlink(): template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, [10, 10], 0.5, 0.999, True, True, True); def cluster_hepta(): template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, [7, 7], 1.0, 0.999, True, True, True); def cluster_tetra(): template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, [7, 7], 0.4, 0.998, True, True, True); def experiment_execution_time(): template_clustering(FCPS_SAMPLES.SAMPLE_LSUN, [4, 4], 0.45, 0.999, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_TARGET, [4, 4], 0.9, 0.998, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_WING_NUT, [4, 4], 0.25, 0.999, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_CHAINLINK, [4, 4], 0.5, 0.998, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_TETRA, [4, 4], 0.4, 0.998, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_HEPTA, [6, 6], 1.0, 0.998, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [4, 4], 0.15, 0.998, False, False, False, False); template_clustering(FCPS_SAMPLES.SAMPLE_ATOM, [4, 4], 15, 0.998, False, False, False, False); def experiment_execution_one_cluster_dependence(layer_first_size, radius, order): print("Experiment: map size =", layer_first_size[0] * layer_first_size[1], "radius =", radius, "order =", order); cluster_sizes = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150]; for cluster_size in cluster_sizes: # generate data sets dataset = []; dataset += [ [random(), random()] for _ in range(cluster_size) ]; general_value = 0.0; amount_attempt = 5; for _ in range(amount_attempt): network = syncsom(dataset, layer_first_size[0], layer_first_size[1], radius); (ticks, (dyn_time, dyn_phase)) = timedcall(network.process, False, order); general_value += ticks; print("Sample: ", cluster_size, "\t\tExecution time: ", general_value / float(amount_attempt)); print("\n"); cluster_simple1(); cluster_simple1_as_som(); cluster_simple2(); cluster_simple2_as_som(); cluster_simple3(); cluster_simple4(); cluster_simple5(); cluster_lsun(); cluster_target(); cluster_two_diamonds(); cluster_chainlink(); cluster_hepta(); cluster_tetra(); experiment_execution_time(); experiment_execution_one_cluster_dependence([5, 5], 0.6, 0.998); experiment_execution_one_cluster_dependence([6, 6], 0.6, 0.998); experiment_execution_one_cluster_dependence([7, 7], 0.6, 0.998); experiment_execution_one_cluster_dependence([8, 8], 0.6, 0.998); experiment_execution_one_cluster_dependence([9, 9], 0.6, 0.998); experiment_execution_one_cluster_dependence([10, 10], 0.6, 0.998);pyclustering-0.10.1.2/pyclustering/cluster/examples/syncsom_segmentation.py000077500000000000000000000036311375753423500273560ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of SYNC-SOM algorithm in image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from PIL import Image; from pyclustering.utils import draw_image_mask_segments, read_image, draw_dynamics; from pyclustering.utils import timedcall; from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES; from pyclustering.cluster.syncsom import syncsom; def template_segmentation_image(source, map_som_size = [5, 5], radius = 128.0, sync_order = 0.998, show_dyn = False, show_som_map = False): data = read_image(source); network = syncsom(data, map_som_size[0], map_som_size[1], 1.0); (ticks, (dyn_time, dyn_phase)) = timedcall(network.process, show_dyn, sync_order); print("Sample: ", source, "\t\tExecution time: ", ticks, "\t\tWinners: ", network.som_layer.get_winner_number(), "\n"); if (show_dyn is True): draw_dynamics(dyn_time, dyn_phase); clusters = network.get_clusters(); draw_image_mask_segments(source, clusters); def segmentation_image_simple1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, show_dyn = True); def segmentation_image_simple2(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE02, show_dyn = True); def segmentation_image_simple3(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE03, show_dyn = True); def segmentation_image_simple4(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE04, show_dyn = True); def segmentation_image_beach(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BEACH, show_dyn = True); segmentation_image_simple1(); segmentation_image_simple2(); segmentation_image_simple3(); segmentation_image_simple4(); segmentation_image_beach();pyclustering-0.10.1.2/pyclustering/cluster/examples/ttsas_examples.py000077500000000000000000000040131375753423500261350ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of TTSAS algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.bsas import bsas_visualizer; from pyclustering.cluster.ttsas import ttsas; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; from pyclustering.utils import read_sample; from pyclustering.utils.metric import distance_metric, type_metric; def template_clustering(path, threshold1, threshold2, **kwargs): metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)); ccore = kwargs.get('ccore', False); draw = kwargs.get('draw', True); sample = read_sample(path); print("Sample: ", path); ttsas_instance = ttsas(sample, threshold1, threshold2, ccore=ccore, metric=metric); ttsas_instance.process(); clusters = ttsas_instance.get_clusters(); representatives = ttsas_instance.get_representatives(); if draw is True: bsas_visualizer.show_clusters(sample, clusters, representatives); def cluster_sample1(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0); def cluster_sample2(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1.0, 2.0); def cluster_sample3(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1.0, 2.0); def cluster_sample4(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1.0, 2.0); def cluster_sample5(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1.0, 2.0); def cluster_sample6(): template_clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 1.0, 2.0); def cluster_elongate(): template_clustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 1.0, 2.0); def cluster_two_diamonds(): template_clustering(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1.0, 2.0); cluster_sample1(); cluster_sample2(); cluster_sample3(); cluster_sample4(); cluster_sample5(); cluster_sample6(); cluster_elongate(); cluster_two_diamonds();pyclustering-0.10.1.2/pyclustering/cluster/examples/xmeans_examples.py000077500000000000000000000322641375753423500263030ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of X-Means algorithm in cluster analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import ntpath import random from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.xmeans import xmeans, splitting_type from pyclustering.utils import read_sample, timedcall def template_clustering(start_centers, path, tolerance=0.025, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore=True): sample = read_sample(path) xmeans_instance = xmeans(sample, start_centers, 20, tolerance, criterion, ccore, repeat=5) (ticks, _) = timedcall(xmeans_instance.process) clusters = xmeans_instance.get_clusters() centers = xmeans_instance.get_centers() criterion_string = "UNKNOWN" if (criterion == splitting_type.BAYESIAN_INFORMATION_CRITERION): criterion_string = "BAYESIAN INFORMATION CRITERION"; elif (criterion == splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH): criterion_string = "MINIMUM NOISELESS DESCRIPTION_LENGTH"; print("Sample: ", ntpath.basename(path), "\nInitial centers: '", (start_centers is not None), "', Execution time: '", ticks, "', Number of clusters:", len(clusters), ",", criterion_string, "\n") visualizer = cluster_visualizer() visualizer.set_canvas_title(criterion_string) visualizer.append_clusters(clusters, sample) visualizer.append_cluster(centers, None, marker = '*') visualizer.show() def cluster_sample1(): "Start with wrong number of clusters." start_centers = [[3.7, 5.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample1_without_initial_centers(): template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample2(): "Start with wrong number of clusters." start_centers = [[3.5, 4.8], [2.6, 2.5]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, criterion=splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, criterion=splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample2_without_initial_centers(): template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, criterion=splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, criterion=splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample3(): "Start with wrong number of clusters." start_centers = [[0.2, 0.1], [4.0, 1.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, criterion=splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, criterion=splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample3_without_initial_centers(): template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, criterion=splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE3, criterion=splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample4(): start_centers = [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample4_without_initial_centers(): template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE4, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample5(): "Start with wrong number of clusters." start_centers = [[0.0, 1.0], [0.0, 0.0]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_sample5_without_initial_centers(): template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(None, SIMPLE_SAMPLES.SAMPLE_SIMPLE5, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_elongate(): "Not so applicable for this sample" start_centers = [[1.0, 4.5], [3.1, 2.7]] template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_ELONGATE, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, SIMPLE_SAMPLES.SAMPLE_ELONGATE, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_lsun(): "Not so applicable for this sample" start_centers = [[1.0, 3.5], [2.0, 0.5], [3.0, 3.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_LSUN, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_LSUN, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_target(): "Not so applicable for this sample" start_centers = [[0.2, 0.2], [0.0, -2.0], [3.0, -3.0], [3.0, 3.0], [-3.0, 3.0], [-3.0, -3.0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TARGET, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TARGET, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_two_diamonds(): "Start with wrong number of clusters." start_centers = [[0.8, 0.2]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_two_diamonds_without_initial_centers(): template_clustering(None, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(None, FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_wing_nut(): start_centers = [[-1.5, 1.5], [1.5, 1.5]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_WING_NUT, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_WING_NUT, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_chainlink(): start_centers = [[1.1, -1.7, 1.1], [-1.4, 2.5, -1.2]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_CHAINLINK, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_CHAINLINK, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_hepta(): "Start with wrong number of clusters." start_centers = [[0.0, 0.0, 0.0], [3.0, 0.0, 0.0], [-2.0, 0.0, 0.0], [0.0, 3.0, 0.0], [0.0, -3.0, 0.0], [0.0, 0.0, 2.5]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_HEPTA, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_HEPTA, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def cluster_tetra(): start_centers = [[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]] template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TETRA, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION) template_clustering(start_centers, FCPS_SAMPLES.SAMPLE_TETRA, criterion = splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH) def template_clustering_performance(start_centers, path, tolerance = 0.025, criterion = splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore = False): sample = read_sample(path) xmeans_instance = xmeans(sample, start_centers, 20, tolerance, criterion, ccore) (ticks, _) = timedcall(xmeans_instance.process) criterion_string = "UNKNOWN" if (criterion == splitting_type.BAYESIAN_INFORMATION_CRITERION): criterion_string = "BAYESIAN INFORMATION CRITERION"; elif (criterion == splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH): criterion_string = "MINIMUM NOISELESS DESCRIPTION_LENGTH"; print("Sample: ", ntpath.basename(path), "', Execution time: '", ticks, "',", criterion_string) def template_clustering_random_points_performance(cluster_length, amount_clusters, ccore_flag): sample = [ [ random.random(), random.random() ] for _ in range(cluster_length) ] for index in range(1, amount_clusters): default_offset = 5 sample += [ [ random.random() + default_offset * index, random.random() + default_offset * index ] for _ in range(cluster_length) ] initial_center = [ [ random.random(), random.random() ], [ random.random(), random.random() ] ] ticks_array = [] amount_measures = 5 for _ in range(amount_measures): xmeans_instance = xmeans(sample, initial_center, 20, 0.25, splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore_flag) (ticks, _) = timedcall(xmeans_instance.process) ticks_array.append(ticks) print("Random sample: (size:" + str(len(sample)) + ") ', Execution time: '", sum(ticks_array) / amount_measures) def experiment_execution_time(ccore_flag = False): template_clustering_performance([[3.7, 5.5]], SIMPLE_SAMPLES.SAMPLE_SIMPLE1, ccore = ccore_flag) template_clustering_performance([[3.5, 4.8], [2.6, 2.5]], SIMPLE_SAMPLES.SAMPLE_SIMPLE2, ccore = ccore_flag) template_clustering_performance([[0.2, 0.1], [4.0, 1.0]], SIMPLE_SAMPLES.SAMPLE_SIMPLE3, ccore = ccore_flag) template_clustering_performance([[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], SIMPLE_SAMPLES.SAMPLE_SIMPLE4, ccore = ccore_flag) template_clustering_performance([[0.0, 1.0], [0.0, 0.0]], SIMPLE_SAMPLES.SAMPLE_SIMPLE5, ccore = ccore_flag) template_clustering_performance([[1.0, 4.5], [3.1, 2.7]], SIMPLE_SAMPLES.SAMPLE_ELONGATE, ccore = ccore_flag) template_clustering_performance([[1.0, 3.5], [2.0, 0.5], [3.0, 3.0]], FCPS_SAMPLES.SAMPLE_LSUN, ccore = ccore_flag) template_clustering_performance([[0.2, 0.2], [0.0, -2.0], [3.0, -3.0], [3.0, 3.0], [-3.0, 3.0], [-3.0, -3.0]], FCPS_SAMPLES.SAMPLE_TARGET, ccore = ccore_flag) template_clustering_performance([[0.8, 0.2]], FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, ccore = ccore_flag) template_clustering_performance([[-1.5, 1.5], [1.5, 1.5]], FCPS_SAMPLES.SAMPLE_WING_NUT, ccore = ccore_flag) template_clustering_performance([[1.1, -1.7, 1.1], [-1.4, 2.5, -1.2]], FCPS_SAMPLES.SAMPLE_CHAINLINK, ccore = ccore_flag) template_clustering_performance([[0.0, 0.0, 0.0], [3.0, 0.0, 0.0], [-2.0, 0.0, 0.0], [0.0, 3.0, 0.0], [0.0, -3.0, 0.0], [0.0, 0.0, 2.5]], FCPS_SAMPLES.SAMPLE_HEPTA, ccore = ccore_flag) template_clustering_performance([[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]], FCPS_SAMPLES.SAMPLE_TETRA, ccore = ccore_flag) template_clustering_performance([[1, 0, 0], [0, 1, 0], [0, -1, 0], [-1, 0, 0]], FCPS_SAMPLES.SAMPLE_ATOM) template_clustering_random_points_performance(1000, 6, ccore_flag) template_clustering_random_points_performance(2000, 6, ccore_flag) template_clustering_random_points_performance(4000, 6, ccore_flag) template_clustering_random_points_performance(6000, 6, ccore_flag) template_clustering_random_points_performance(8000, 6, ccore_flag) template_clustering_random_points_performance(10000, 6, ccore_flag) template_clustering_random_points_performance(15000, 6, ccore_flag) template_clustering_random_points_performance(30000, 6, ccore_flag) template_clustering_random_points_performance(45000, 6, ccore_flag) template_clustering_random_points_performance(100000, 6, ccore_flag) template_clustering_random_points_performance(200000, 6, ccore_flag) template_clustering_random_points_performance(300000, 6, ccore_flag) template_clustering_random_points_performance(1000000, 6, ccore_flag) cluster_sample1() cluster_sample2() cluster_sample3() cluster_sample4() cluster_sample5() cluster_elongate() cluster_lsun() cluster_target() cluster_two_diamonds() cluster_wing_nut() cluster_chainlink() cluster_hepta() cluster_tetra() cluster_sample1_without_initial_centers() cluster_sample2_without_initial_centers() cluster_sample3_without_initial_centers() cluster_sample4_without_initial_centers() cluster_sample5_without_initial_centers() cluster_two_diamonds_without_initial_centers() experiment_execution_time(False) # Python code experiment_execution_time(True) # C++ code + Python env.pyclustering-0.10.1.2/pyclustering/cluster/fcm.py000077500000000000000000000251431375753423500220370ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: Fuzzy C-Means @details Implementation based on paper @cite book::pattern_recognition_with_fuzzy. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import pyclustering.core.fcm_wrapper as wrapper from pyclustering.core.wrapper import ccore_library class fcm: """! @brief Class represents Fuzzy C-means (FCM) clustering algorithm. @details Fuzzy clustering is a form of clustering in which each data point can belong to more than one cluster. Fuzzy C-Means algorithm uses two general formulas for cluster analysis. The first is to updated membership of each point: \f[w_{ij}=\frac{1}{\sum_{k=0}^{c}\left ( \frac{\left \| x_{i}-c_{j} \right \|}{\left \| x_{i}-c_{k} \right \|} \right )^{\frac{2}{m-1}}}\f] The second formula is used to update centers in line with obtained centers: \f[c_{k}=\frac{\sum_{i=0}^{N}w_{k}\left ( x_{i} \right )^{m}x_{i}}{\sum_{i=0}^{N}w_{k}\left ( x_{i} \right )^{m}}\f] Fuzzy C-Means clustering results depend on initial centers. Algorithm K-Means++ can used for center initialization from module 'pyclustering.cluster.center_initializer'. CCORE implementation of the algorithm uses thread pool to parallelize the clustering process. Here is an example how to perform cluster analysis using Fuzzy C-Means algorithm: @code from pyclustering.samples.definitions import FAMOUS_SAMPLES from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.fcm import fcm from pyclustering.utils import read_sample # load list of points for cluster analysis sample = read_sample(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL) # initialize initial_centers = kmeans_plusplus_initializer(sample, 2, kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE).initialize() # create instance of Fuzzy C-Means algorithm fcm_instance = fcm(sample, initial_centers) # run cluster analysis and obtain results fcm_instance.process() clusters = fcm_instance.get_clusters() centers = fcm_instance.get_centers() # visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(centers, marker='*', markersize=10) visualizer.show() @endcode The next example shows how to perform image segmentation using Fuzzy C-Means algorithm: @code from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.fcm import fcm from pyclustering.utils import read_image, draw_image_mask_segments # load list of points for cluster analysis data = read_image("stpetersburg_admiral.jpg") # initialize initial_centers = kmeans_plusplus_initializer(data, 3, kmeans_plusplus_initializer.FARTHEST_CENTER_CANDIDATE).initialize() # create instance of Fuzzy C-Means algorithm fcm_instance = fcm(data, initial_centers) # run cluster analysis and obtain results fcm_instance.process() clusters = fcm_instance.get_clusters() # visualize segmentation results draw_image_mask_segments("stpetersburg_admiral.jpg", clusters) @endcode @image html fcm_segmentation_stpetersburg.png "Image segmentation using Fuzzy C-Means algorithm." """ def __init__(self, data, initial_centers, **kwargs): """! @brief Initialize Fuzzy C-Means algorithm. @param[in] data (array_like): Input data that is presented as array of points (objects), each point should be represented by array_like data structure. @param[in] initial_centers (array_like): Initial coordinates of centers of clusters that are represented by array_like data structure: [center1, center2, ...]. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'tolerance', 'itermax', 'm'). Keyword Args:
- ccore (bool): Defines should be CCORE library (C++ pyclustering library) used instead of Python code or not. - tolerance (float): Stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. - itermax (uint): Maximum number of iterations that is used for clustering process (by default: 200). - m (float): Hyper-parameter that controls how fuzzy the cluster will be. The higher it is, the fuzzier the cluster will be in the end. This parameter should be greater than 1 (by default: 2). """ self.__data = data self.__clusters = [] self.__centers = initial_centers self.__membership = [] self.__tolerance = kwargs.get('tolerance', 0.001) self.__itermax = kwargs.get('itermax', 200) self.__m = kwargs.get('m', 2) self.__degree = 2.0 / (self.__m - 1) self.__ccore = kwargs.get('ccore', True) if self.__ccore is True: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis in line with Fuzzy C-Means algorithm. @return (fcm) Returns itself (Fuzzy C-Means instance). @see get_clusters() @see get_centers() @see get_membership() """ if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def get_clusters(self): """! @brief Returns allocated clusters that consists of points that most likely (in line with membership) belong to these clusters. @remark Allocated clusters can be returned only after data processing (use method process()). Otherwise empty list is returned. @return (list) List of allocated clusters, each cluster contains indexes from input data. @see process() @see get_centers() @see get_membership() """ return self.__clusters def get_centers(self): """! @brief Returns list of centers of allocated clusters. @return (array_like) Cluster centers. @see process() @see get_clusters() @see get_membership() """ return self.__centers def get_membership(self): """! @brief Returns cluster membership (probability) for each point in data. @return (array_like) Membership for each point in format [[Px1(c1), Px1(c2), ...], [Px2(c1), Px2(c2), ...], ...], where [Px1(c1), Px1(c2), ...] membership for point x1. @see process() @see get_clusters() @see get_centers() """ return self.__membership def __process_by_ccore(self): """! @brief Performs cluster analysis using C/C++ implementation. """ result = wrapper.fcm_algorithm(self.__data, self.__centers, self.__m, self.__tolerance, self.__itermax) self.__clusters = result[wrapper.fcm_package_indexer.INDEX_CLUSTERS] self.__centers = result[wrapper.fcm_package_indexer.INDEX_CENTERS] self.__membership = result[wrapper.fcm_package_indexer.INDEX_MEMBERSHIP] def __process_by_python(self): """! @brief Performs cluster analysis using Python implementation. """ self.__data = numpy.array(self.__data) self.__centers = numpy.array(self.__centers) self.__membership = numpy.zeros((len(self.__data), len(self.__centers))) change = float('inf') iteration = 0 while change > self.__tolerance and iteration < self.__itermax: self.__update_membership() centers = self.__calculate_centers() change = self.__calculate_changes(centers) self.__centers = centers iteration += 1 self.__extract_clusters() def __calculate_centers(self): """! @brief Calculate center using membership of each cluster. @return (list) Updated clusters as list of clusters. Each cluster contains indexes of objects from data. @return (numpy.array) Updated centers. """ dimension = self.__data.shape[1] centers = numpy.zeros((len(self.__centers), dimension)) for i in range(len(self.__centers)): # multiplication '@' requires python version 3.5 centers[i] = numpy.divide(self.__membership[:, i] @ self.__data, numpy.sum(self.__membership[:, i])) return centers def __update_membership(self): """! @brief Update membership for each point in line with current cluster centers. """ data_difference = numpy.zeros((len(self.__centers), len(self.__data))) for i in range(len(self.__centers)): data_difference[i] = numpy.sum(numpy.square(self.__data - self.__centers[i]), axis=1) for i in range(len(self.__data)): for j in range(len(self.__centers)): divider = sum([pow(data_difference[j][i] / data_difference[k][i], self.__degree) for k in range(len(self.__centers)) if data_difference[k][i] != 0.0]) if divider != 0.0: self.__membership[i][j] = 1.0 / divider else: self.__membership[i][j] = 1.0 def __calculate_changes(self, updated_centers): """! @brief Calculate changes between centers. @return (float) Maximum change between centers. """ changes = numpy.sum(numpy.square(self.__centers - updated_centers), axis=1).T return numpy.max(changes) def __extract_clusters(self): self.__clusters = [[] for i in range(len(self.__centers))] belongs = numpy.argmax(self.__membership, axis=1) for i in range(len(belongs)): self.__clusters[belongs[i]].append(i) def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data)) if len(self.__centers) == 0: raise ValueError("Initial centers are empty (size: '%d')." % len(self.__centers)) pyclustering-0.10.1.2/pyclustering/cluster/ga.py000077500000000000000000000644251375753423500216670ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: Genetic clustering algorithm (GA). @details Implementation based on papers @cite article::ga::1, @cite article::ga::2. @authors Aleksey Kukushkin, Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import matplotlib.pyplot as plt import matplotlib.animation as animation from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.ga_maths import ga_math class ga_observer: """! @brief Genetic algorithm observer that is used to collect information about clustering process on each iteration. """ def __init__(self, need_global_best=False, need_population_best=False, need_mean_ff=False): """! @brief Constructs genetic algorithm observer to collect specific information. @param[in] need_global_best (bool): If 'True' then the best chromosomes and its fitness function value (global optimum) for each iteration are stored. @param[in] need_population_best (bool): If 'True' then current (on each iteration) best chromosomes and its fitness function value (local optimum) are stored. @param[in] need_mean_ff (bool): If 'True' then average value of fitness function on each iteration is stored. """ # Global best chromosome and fitness function for each population self._global_best_result = {'chromosome': [], 'fitness_function': []} # Best chromosome and fitness function on a population self._best_population_result = {'chromosome': [], 'fitness_function': []} # Mean fitness function on each population self._mean_ff_result = [] # Flags to collect self._need_global_best = need_global_best self._need_population_best = need_population_best self._need_mean_ff = need_mean_ff def __len__(self): """! @brief Returns amount of iterations that genetic algorithm was observed. """ global_length = len(self._global_best_result['chromosome']) local_length = len(self._best_population_result['chromosome']) average_length = len(self._mean_ff_result) return max(global_length, local_length, average_length) def collect_global_best(self, best_chromosome, best_fitness_function): """! @brief Stores the best chromosome and its fitness function's value. @param[in] best_chromosome (list): The best chromosome that were observed. @param[in] best_fitness_function (float): Fitness function value of the best chromosome. """ if not self._need_global_best: return self._global_best_result['chromosome'].append(best_chromosome) self._global_best_result['fitness_function'].append(best_fitness_function) def collect_population_best(self, best_chromosome, best_fitness_function): """! @brief Stores the best chromosome for current specific iteration and its fitness function's value. @param[in] best_chromosome (list): The best chromosome on specific iteration. @param[in] best_fitness_function (float): Fitness function value of the chromosome. """ if not self._need_population_best: return self._best_population_result['chromosome'].append(best_chromosome) self._best_population_result['fitness_function'].append(best_fitness_function) def collect_mean(self, fitness_functions): """! @brief Stores average value of fitness function among chromosomes on specific iteration. @param[in] fitness_functions (float): Average value of fitness functions among chromosomes. """ if not self._need_mean_ff: return self._mean_ff_result.append(numpy.mean(fitness_functions)) def get_global_best(self): """! @return (dict) Returns dictionary with keys 'chromosome' and 'fitness_function' where evolution of the best chromosome and its fitness function's value (evolution of global optimum) are stored in lists. """ return self._global_best_result def get_population_best(self): """! @brief (dict) Returns dictionary with keys 'chromosome' and 'fitness_function' where evolution of the current best chromosome and its fitness function's value (evolution of local optimum) are stored in lists. """ return self._best_population_result def get_mean_fitness_function(self): """! @brief (list) Returns fitness function's values on each iteration. """ return self._mean_ff_result class ga_visualizer: """! @brief Genetic algorithm visualizer is used to show clustering results that are specific for this particular algorithm: clusters, evolution of global and local optimum. @details The visualizer requires 'ga_observer' that collects evolution of clustering process in genetic algorithm. The observer is created by user and passed to genetic algorithm. There is usage example of the visualizer using the observer: @code from pyclustering.cluster.ga import genetic_algorithm, ga_observer, ga_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read data for clustering sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) # Create instance of observer that will collect all information: observer_instance = ga_observer(True, True, True) # Create genetic algorithm where observer will collect information: ga_instance = genetic_algorithm(data=sample, count_clusters=2, chromosome_count=20, population_count=20, count_mutation_gens=1, observer=observer_instance) # Start processing ga_instance.process() # Obtain results clusters = ga_instance.get_clusters() # Print cluster to console print("Amount of clusters: '%d'. Clusters: '%s'" % (len(clusters), clusters)) # Show cluster using observer: ga_visualizer.show_clusters(sample, observer_instance) @endcode @see cluster_visualizer """ @staticmethod def show_evolution(observer, start_iteration=0, stop_iteration=None, ax=None, display=True): """! @brief Displays evolution of fitness function for the best chromosome, for the current best chromosome and average value among all chromosomes. @param[in] observer (ga_observer): Genetic algorithm observer that was used for collecting evolution in the algorithm and where whole required information for visualization is stored. @param[in] start_iteration (uint): Iteration from that evolution should be shown. @param[in] stop_iteration (uint): Iteration after that evolution shouldn't be shown. @param[in] ax (Axes): Canvas where evolution should be displayed. @param[in] display (bool): If 'True' then visualization of the evolution will be shown by the function. This argument should be 'False' if you want to add something else to the canvas and display it later. @return (Axis) Canvas where evolution was shown. """ if (ax is None): _, ax = plt.subplots(1) ax.set_title("Evolution") if stop_iteration is None: stop_iteration = len(observer) line_best, = ax.plot(observer.get_global_best()['fitness_function'][start_iteration:stop_iteration], 'r') line_current, = ax.plot(observer.get_population_best()['fitness_function'][start_iteration:stop_iteration], 'k') line_mean, = ax.plot(observer.get_mean_fitness_function()[start_iteration:stop_iteration], 'c') if start_iteration < (stop_iteration - 1): ax.set_xlim([start_iteration, (stop_iteration - 1)]) ax.set_xlabel("Iteration") ax.set_ylabel("Fitness function") ax.legend([line_best, line_current, line_mean], ["The best pop.", "Cur. best pop.", "Average"], prop={'size': 10}) ax.grid() if display is True: plt.show() return ax @staticmethod def show_clusters(data, observer, marker='.', markersize=None): """! @brief Shows allocated clusters by the genetic algorithm. @param[in] data (list): Input data that was used for clustering process by the algorithm. @param[in] observer (ga_observer): Observer that was used for collection information about clustering process. @param[in] marker (char): Type of marker that should be used for object (point) representation. @param[in] markersize (uint): Size of the marker that is used for object (point) representation. @note If you have clusters instead of observer then 'cluster_visualizer' can be used for visualization purposes. @see cluster_visualizer """ figure = plt.figure() ax1 = figure.add_subplot(121) clusters = ga_math.get_clusters_representation(observer.get_global_best()['chromosome'][-1]) visualizer = cluster_visualizer(1, 2) visualizer.append_clusters(clusters, data, 0, marker, markersize) visualizer.show(figure, display=False) ga_visualizer.show_evolution(observer, 0, None, ax1, True) @staticmethod def animate_cluster_allocation(data, observer, animation_velocity=75, movie_fps=5, save_movie=None): """! @brief Animate clustering process of genetic clustering algorithm. @details This method can be also used for rendering movie of clustering process and 'ffmpeg' is required for that purpuse. @param[in] data (list): Input data that was used for clustering process by the algorithm. @param[in] observer (ga_observer): Observer that was used for collection information about clustering process. Be sure that whole information was collected by the observer. @param[in] animation_velocity (uint): Interval between frames in milliseconds (for run-time animation only). @param[in] movie_fps (uint): Defines frames per second (for rendering movie only). @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure() def init_frame(): return frame_generation(0) def frame_generation(index_iteration): figure.clf() figure.suptitle("Clustering genetic algorithm (iteration: " + str(index_iteration) + ")", fontsize=18, fontweight='bold') visualizer = cluster_visualizer(4, 2, ["The best pop. on step #" + str(index_iteration), "The best population"]) local_minimum_clusters = ga_math.get_clusters_representation(observer.get_population_best()['chromosome'][index_iteration]) visualizer.append_clusters(local_minimum_clusters, data, 0) global_minimum_clusters = ga_math.get_clusters_representation(observer.get_global_best()['chromosome'][index_iteration]) visualizer.append_clusters(global_minimum_clusters, data, 1) ax1 = plt.subplot2grid((2, 2), (1, 0), colspan=2) ga_visualizer.show_evolution(observer, 0, index_iteration + 1, ax1, False) visualizer.show(figure, shift=0, display=False) figure.subplots_adjust(top=0.85) return [figure.gca()] iterations = len(observer) cluster_animation = animation.FuncAnimation(figure, frame_generation, iterations, interval=animation_velocity, init_func=init_frame, repeat_delay=5000) if save_movie is not None: cluster_animation.save(save_movie, writer='ffmpeg', fps=movie_fps, bitrate=1500) else: plt.show() class genetic_algorithm: """! @brief Class represents Genetic clustering algorithm. @details The searching capability of genetic algorithms is exploited in order to search for appropriate cluster centres. Example of clustering using genetic algorithm: @code from pyclustering.cluster.ga import genetic_algorithm, ga_observer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read input data for clustering sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) # Create instance of observer that will collect all information: observer_instance = ga_observer(True, True, True) # Create genetic algorithm for clustering ga_instance = genetic_algorithm(data=sample, count_clusters=4, chromosome_count=100, population_count=200, count_mutation_gens=1) # Start processing ga_instance.process() # Obtain results clusters = ga_instance.get_clusters() # Print cluster to console print("Amount of clusters: '%d'. Clusters: '%s'" % (len(clusters), clusters)) @endcode There is an example of clustering results (fitness function evolution and allocated clusters) that were visualized by 'ga_visualizer': @image html ga_clustering_sample_simple_04.png @see ga_visualizer @see ga_observer """ def __init__(self, data, count_clusters, chromosome_count, population_count, **kwargs): """! @brief Initialize genetic clustering algorithm. @param[in] data (numpy.array|list): Input data for clustering that is represented by two dimensional array where each row is a point, for example, [[0.0, 2.1], [0.1, 2.0], [-0.2, 2.4]]. @param[in] count_clusters (uint): The amount of clusters that should be allocated in the data. @param[in] chromosome_count (uint): The amount of chromosomes in each population. @param[in] population_count (uint): The amount of populations that essentially defines the amount of iterations. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `count_mutation_gens`, `coeff_mutation_count`, `select_coeff`, `crossover_rate`, `observer`, `random_state`). Keyword Args:
- count_mutation_gens (uint): Amount of genes in chromosome that is mutated on each step. - coeff_mutation_count (float): Percent of chromosomes for mutation, distributed in range (0, 1] and thus amount of chromosomes is defined as follows: `chromosome_count` * `coeff_mutation_count` - select_coeff (float): Exponential coefficient for selection procedure that is used as follows: `math.exp(1 + fitness(chromosome) * select_coeff)`. - crossover_rate (float): Crossover rate. - observer (ga_observer): Observer that is used for collecting information of about clustering process on each step. - random_state (int): Seed for random state (by default is `None`, current system time is used). """ # Initialize random numpy.random.seed(kwargs.get('random_state', None)) # Clustering data self._data = numpy.array(data) # Count clusters self._count_clusters = count_clusters # Home many chromosome in population self._chromosome_count = chromosome_count # How many populations self._population_count = population_count # Count mutation genes self._count_mutation_gens = kwargs.get('count_mutation_gens', 2) # Crossover rate self._crossover_rate = kwargs.get('crossover_rate', 1.0) # Count of chromosome for mutation (range [0, 1]) self._coeff_mutation_count = kwargs.get('coeff_mutation_count', 0.25) # Exponential coeff for selection self._select_coeff = kwargs.get('select_coeff', 1.0) # Result of clustering : best chromosome self._result_clustering = {'best_chromosome': [], 'best_fitness_function': 0.0} # Observer self._observer = kwargs.get('observer', ga_observer()) self._verify_arguments() def process(self): """! @brief Perform clustering procedure in line with rule of genetic clustering algorithm. @see get_clusters() """ # Initialize population chromosomes = self._init_population(self._count_clusters, len(self._data), self._chromosome_count) # Initialize the Best solution best_chromosome, best_ff, first_fitness_functions \ = self._get_best_chromosome(chromosomes, self._data, self._count_clusters) # Save best result into observer if self._observer is not None: self._observer.collect_global_best(best_chromosome, best_ff) self._observer.collect_population_best(best_chromosome, best_ff) self._observer.collect_mean(first_fitness_functions) # Next population for _ in range(self._population_count): # Select chromosomes = self._select(chromosomes, self._data, self._count_clusters, self._select_coeff) # Crossover self._crossover(chromosomes) # Mutation self._mutation(chromosomes, self._count_clusters, self._count_mutation_gens, self._coeff_mutation_count) # Update the Best Solution new_best_chromosome, new_best_ff, fitness_functions \ = self._get_best_chromosome(chromosomes, self._data, self._count_clusters) # Get best chromosome if new_best_ff < best_ff: best_ff = new_best_ff best_chromosome = new_best_chromosome # Save best result into observer if self._observer is not None: self._observer.collect_global_best(best_chromosome, best_ff) self._observer.collect_population_best(new_best_chromosome, new_best_ff) self._observer.collect_mean(fitness_functions) # Save result self._result_clustering['best_chromosome'] = best_chromosome self._result_clustering['best_fitness_function'] = best_ff return best_chromosome, best_ff def get_observer(self): """! @brief Returns genetic algorithm observer. """ return self._observer def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects from the data. @return (list) List of allocated clusters. @see process() """ return ga_math.get_clusters_representation(self._result_clustering['best_chromosome'], self._count_clusters) @staticmethod def _select(chromosomes, data, count_clusters, select_coeff): """! @brief Performs selection procedure where new chromosomes are calculated. @param[in] chromosomes (numpy.array): Chromosomes """ # Calc centers centres = ga_math.get_centres(chromosomes, data, count_clusters) # Calc fitness functions fitness = genetic_algorithm._calc_fitness_function(centres, data, chromosomes) fitness = numpy.exp(1.0 + fitness * select_coeff) # Calc probability vector probabilities = ga_math.calc_probability_vector(fitness) # Select P chromosomes with probabilities new_chromosomes = numpy.zeros(chromosomes.shape, dtype=numpy.int) # Selecting for _idx in range(len(chromosomes)): new_chromosomes[_idx] = chromosomes[ga_math.get_uniform(probabilities)] return new_chromosomes @staticmethod def _crossover(chromosomes): """! @brief Crossover procedure. """ # Get pairs to Crossover pairs_to_crossover = numpy.array(range(len(chromosomes))) # Set random pairs numpy.random.shuffle(pairs_to_crossover) # Index offset ( pairs_to_crossover split into 2 parts : [V1, V2, .. | P1, P2, ...] crossover between V<->P) offset_in_pair = int(len(pairs_to_crossover) / 2) # For each pair for _idx in range(offset_in_pair): # Generate random mask for crossover crossover_mask = genetic_algorithm._get_crossover_mask(len(chromosomes[_idx])) # Crossover a pair genetic_algorithm._crossover_a_pair(chromosomes[pairs_to_crossover[_idx]], chromosomes[pairs_to_crossover[_idx + offset_in_pair]], crossover_mask) @staticmethod def _mutation(chromosomes, count_clusters, count_gen_for_mutation, coeff_mutation_count): """! @brief Mutation procedure. """ # Count gens in Chromosome count_gens = len(chromosomes[0]) # Get random chromosomes for mutation random_idx_chromosomes = numpy.array(range(len(chromosomes))) numpy.random.shuffle(random_idx_chromosomes) # for _idx_chromosome in range(int(len(random_idx_chromosomes) * coeff_mutation_count)): # for _ in range(count_gen_for_mutation): # Get random gen gen_num = numpy.random.randint(count_gens) # Set random cluster chromosomes[random_idx_chromosomes[_idx_chromosome]][gen_num] = numpy.random.randint(count_clusters) @staticmethod def _crossover_a_pair(chromosome_1, chromosome_2, mask): """! @brief Crossovers a pair of chromosomes. @param[in] chromosome_1 (numpy.array): The first chromosome for crossover. @param[in] chromosome_2 (numpy.array): The second chromosome for crossover. @param[in] mask (numpy.array): Crossover mask that defines which genes should be swapped. """ for _idx in range(len(chromosome_1)): if mask[_idx] == 1: # Swap values chromosome_1[_idx], chromosome_2[_idx] = chromosome_2[_idx], chromosome_1[_idx] @staticmethod def _get_crossover_mask(mask_length): """! @brief Crossover mask to crossover a pair of chromosomes. @param[in] mask_length (uint): Length of the mask. """ # Initialize mask mask = numpy.zeros(mask_length) # Set a half of array to 1 mask[:int(int(mask_length) / 2)] = 1 # Random shuffle numpy.random.shuffle(mask) return mask @staticmethod def _init_population(count_clusters, count_data, chromosome_count): """! @brief Returns first population as a uniform random choice. @param[in] count_clusters (uint): Amount of clusters that should be allocated. @param[in] count_data (uint): Data size that is used for clustering process. @param[in] chromosome_count (uint):Amount of chromosome that is used for clustering. """ population = numpy.random.randint(count_clusters, size=(chromosome_count, count_data)) return population @staticmethod def _get_best_chromosome(chromosomes, data, count_clusters): """! @brief Returns the current best chromosome. @param[in] chromosomes (list): Chromosomes that are used for searching. @param[in] data (list): Input data that is used for clustering process. @param[in] count_clusters (uint): Amount of clusters that should be allocated. @return (list, float, list) The best chromosome, its fitness function value and fitness function values for all chromosomes. """ # Calc centers centres = ga_math.get_centres(chromosomes, data, count_clusters) # Calc Fitness functions fitness_functions = genetic_algorithm._calc_fitness_function(centres, data, chromosomes) # Index of the best chromosome best_chromosome_idx = fitness_functions.argmin() # Get chromosome with the best fitness function return chromosomes[best_chromosome_idx], fitness_functions[best_chromosome_idx], fitness_functions @staticmethod def _calc_fitness_function(centres, data, chromosomes): """! @brief Calculate fitness function values for chromosomes. @param[in] centres (list): Cluster centers. @param[in] data (list): Input data that is used for clustering process. @param[in] chromosomes (list): Chromosomes whose fitness function's values are calculated. @return (list) Fitness function value for each chromosome correspondingly. """ # Get count of chromosomes and clusters count_chromosome = len(chromosomes) # Initialize fitness function values fitness_function = numpy.zeros(count_chromosome) # Calc fitness function for each chromosome for _idx_chromosome in range(count_chromosome): # Get centers for a selected chromosome centres_data = numpy.zeros(data.shape) # Fill data centres for _idx in range(len(data)): centres_data[_idx] = centres[_idx_chromosome][chromosomes[_idx_chromosome][_idx]] # Get City Block distance for a chromosome fitness_function[_idx_chromosome] += numpy.sum(abs(data - centres_data)) return fitness_function def _verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self._data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self._data)) if self._count_clusters <= 0: raise ValueError("Amount of cluster (current value: '%d') for allocation should be greater than 0." % self._count_clusters) pyclustering-0.10.1.2/pyclustering/cluster/ga_maths.py000077500000000000000000000111301375753423500230440ustar00rootroot00000000000000"""! @brief Genetic algorithm math API. @authors Aleksey Kukushkin (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy as np class ga_math: """ @brief Genetic algorithm math API. """ @staticmethod def calc_count_centers(chromosome): return chromosome[chromosome.argmax()] + 1 @staticmethod def get_clusters_representation(chromosome, count_clusters=None): """ Convert chromosome to cluster representation: chromosome : [0, 1, 1, 0, 2, 3, 3] clusters: [[0, 3], [1, 2], [4], [5, 6]] """ if count_clusters is None: count_clusters = ga_math.calc_count_centers(chromosome) # Initialize empty clusters clusters = [[] for _ in range(count_clusters)] # Fill clusters with index of data for _idx_data in range(len(chromosome)): clusters[chromosome[_idx_data]].append(_idx_data) return clusters @staticmethod def get_centres(chromosomes, data, count_clusters): """! """ centres = ga_math.calc_centers(chromosomes, data, count_clusters) return centres @staticmethod def calc_centers(chromosomes, data, count_clusters=None): """! """ if count_clusters is None: count_clusters = ga_math.calc_count_centers(chromosomes[0]) # Initialize center centers = np.zeros(shape=(len(chromosomes), count_clusters, len(data[0]))) for _idx_chromosome in range(len(chromosomes)): # Get count data in clusters count_data_in_cluster = np.zeros(count_clusters) # Next data point for _idx in range(len(chromosomes[_idx_chromosome])): cluster_num = chromosomes[_idx_chromosome][_idx] centers[_idx_chromosome][cluster_num] += data[_idx] count_data_in_cluster[cluster_num] += 1 for _idx_cluster in range(count_clusters): if count_data_in_cluster[_idx_cluster] != 0: centers[_idx_chromosome][_idx_cluster] /= count_data_in_cluster[_idx_cluster] return centers @staticmethod def calc_probability_vector(fitness): """! """ if len(fitness) == 0: raise AttributeError("Fitness functions are empty.") # Get 1/fitness function inv_fitness = np.zeros(len(fitness)) # for _idx in range(len(inv_fitness)): fitness_value = fitness[_idx] if fitness_value != 0.0: if np.isinf(fitness_value): raise ValueError("Impossible to calculate the probability of getting reproduced. " "Make sure that input data for clustering is normalized between [0, 1].") inv_fitness[_idx] = 1.0 / fitness_value else: inv_fitness[_idx] = 0.0 # Initialize vector prob = np.zeros(len(fitness)) # Initialize first element prob[0] = inv_fitness[0] # Accumulate values in probability vector for _idx in range(1, len(inv_fitness)): prob[_idx] = prob[_idx - 1] + inv_fitness[_idx] # Normalize prob /= prob[-1] ga_math.set_last_value_to_one(prob) return prob @staticmethod def set_last_value_to_one(probabilities): """! @brief Update the last same probabilities to one. @details All values of probability list equals to the last element are set to 1. """ # Start from the last elem back_idx = -1 # All values equal to the last elem should be set to 1 last_val = probabilities[back_idx] # for all elements or if a elem not equal to the last elem for _ in range(-1, -len(probabilities) - 1): if probabilities[back_idx] == last_val: probabilities[back_idx] = 1 else: break @staticmethod def get_uniform(probabilities): """! @brief Returns index in probabilities. @param[in] probabilities (list): List with segments in increasing sequence with val in [0, 1], for example, [0 0.1 0.2 0.3 1.0]. """ # Initialize return value res_idx = None # Get random num in range [0, 1) random_num = np.random.rand() # Find segment with val1 < random_num < val2 for _idx in range(len(probabilities)): if random_num < probabilities[_idx]: res_idx = _idx break return res_idx pyclustering-0.10.1.2/pyclustering/cluster/generator.py000077500000000000000000000066231375753423500232620ustar00rootroot00000000000000"""! @brief Cluster generator. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import collections.abc import random class data_generator: """! @brief Data generator provides services to generate data with clusters with normal distribution. """ def __init__(self, amount_clusters, dimension, cluster_sizes, cluster_centers=None, cluster_width=1.0): """! @brief Constructs data generator for generating data-sets. @param[in] amount_clusters (uint): Amount of clusters that should be generated. @param[in] dimension (uint): Dimension of each generated point. @param[in] cluster_sizes (uint|array_like): Size of each cluster. In case of 'array_like' input clusters with corresponding sizes are generated. @param[in] cluster_centers (array_like): Optional parameter that defines cluster centers (means). @param[in] cluster_width (uint|array_like): Optional parameter that defines cluster width (standard deviation). In case of 'array_like' input each cluster has own standard deviation. """ self.__amount_clusters = amount_clusters self.__dimension = dimension self.__cluster_sizes = cluster_sizes if not isinstance(self.__cluster_sizes, collections.abc.Iterable): self.__cluster_sizes = [self.__cluster_sizes] * amount_clusters self.__cluster_width = cluster_width if not isinstance(self.__cluster_width, collections.abc.Iterable): self.__cluster_width = [self.__cluster_width] * amount_clusters self.__cluster_centers = cluster_centers if self.__cluster_centers is None: self.__cluster_centers = self.__generate_cluster_centers(self.__cluster_width) def generate(self): """! @brief Generates data in line with generator parameters. """ data_points = [] for index_cluster in range(self.__amount_clusters): for _ in range(self.__cluster_sizes[index_cluster]): point = self.__generate_point(index_cluster) data_points.append(point) return data_points def __generate_point(self, index_cluster): """! @brief Generates point in line with parameters of specified cluster. @param[in] index_cluster (uint): Index of cluster whose parameters are used for point generation. @return (list) New generated point in line with normal distribution and cluster parameters. """ return [ random.gauss(self.__cluster_centers[index_cluster][index_dimension], self.__cluster_width[index_cluster] / 2.0) for index_dimension in range(self.__dimension) ] def __generate_cluster_centers(self, width): """! @brief Generates centers (means in statistical term) for clusters. @param[in] width (list): Width of generated clusters. @return (list) Generated centers in line with normal distribution. """ centers = [] default_offset = max(width) * 4.0 for i in range(self.__amount_clusters): center = [ random.gauss(i * default_offset, width[i] / 2.0) for _ in range(self.__dimension) ] centers.append(center) return centers pyclustering-0.10.1.2/pyclustering/cluster/gmeans.py000077500000000000000000000404261375753423500225450ustar00rootroot00000000000000"""! @brief The module contains G-Means algorithm and other related services. @details Implementation based on paper @cite inproceedings::cluster::gmeans::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import scipy.stats from pyclustering.core.gmeans_wrapper import gmeans as gmeans_wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.encoder import type_encoding from pyclustering.cluster.kmeans import kmeans from pyclustering.utils import distance_metric, type_metric class gmeans: """! @brief Class implements G-Means clustering algorithm. @details The G-means algorithm starts with a small number of centers, and grows the number of centers. Each iteration of the G-Means algorithm splits into two those centers whose data appear not to come from a Gaussian distribution. G-means repeatedly makes decisions based on a statistical test for the data assigned to each center. Implementation based on the paper @cite inproceedings::cluster::gmeans::1. @image html gmeans_example_clustering.png "G-Means clustering results on most common data-sets." Example #1. In this example, G-Means starts analysis from single cluster. @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.gmeans import gmeans from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Read sample 'Lsun' from file. sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Create instance of G-Means algorithm. By default the algorithm starts search from a single cluster. gmeans_instance = gmeans(sample).process() # Extract clustering results: clusters and their centers clusters = gmeans_instance.get_clusters() centers = gmeans_instance.get_centers() # Print total sum of metric errors print("Total WCE:", gmeans_instance.get_total_wce()) # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode Example #2. Sometimes G-Means might find local optimum. `repeat` value can be used to increase probability to find global optimum. Argument `repeat` defines how many times K-Means clustering with K-Means++ initialization should be run in order to find optimal clusters. @code # Read sample 'Tetra' from file. sample = read_sample(FCPS_SAMPLES.SAMPLE_TETRA) # Create instance of G-Means algorithm. By default algorithm start search from single cluster. gmeans_instance = gmeans(sample, repeat=10).process() # Extract clustering results: clusters and their centers clusters = gmeans_instance.get_clusters() # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode In case of requirement to have labels instead of default representation of clustering results `CLUSTER_INDEX_LIST_SEPARATION`: @code from pyclustering.cluster.gmeans import gmeans from pyclustering.cluster.encoder import type_encoding, cluster_encoder from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample data = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) gmeans_instance = gmeans(data).process() clusters = gmeans_instance.get_clusters() # Change cluster representation from default to labeling. encoder = cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, clusters, data) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) labels = encoder.get_clusters() print(labels) # Display labels @endcode There is an output of the code above: @code [0, 0, 0, 0, 0, 1, 1, 1, 1, 1] @endcode """ def __init__(self, data, k_init=1, ccore=True, **kwargs): """! @brief Initializes G-Means algorithm. @param[in] data (array_like): Input data that is presented as array of points (objects), each point should be represented by array_like data structure. @param[in] k_init (uint): Initial amount of centers (by default started search from 1). @param[in] ccore (bool): Defines whether CCORE library (C/C++ part of the library) should be used instead of Python code. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `tolerance`, `repeat`, `k_max`, `random_state`). Keyword Args:
- tolerance (double): tolerance (double): Stop condition for each K-Means iteration: if maximum value of change of centers of clusters is less than tolerance than algorithm will stop processing. - repeat (unit): How many times K-Means should be run to improve parameters (by default is 3). With larger 'repeat' values suggesting higher probability of finding global optimum. - k_max (uint): Maximum amount of cluster that might be allocated. The argument is considered as a stop condition. When the maximum amount is reached then algorithm stops processing. By default the maximum amount of clusters is not restricted (`k_max` is -1). - random_state (int): Seed for random state (by default is `None`, current system time is used). """ self.__data = data self.__k_init = k_init self.__clusters = [] self.__centers = [] self.__total_wce = 0.0 self.__ccore = ccore self.__tolerance = kwargs.get('tolerance', 0.001) self.__repeat = kwargs.get('repeat', 3) self.__k_max = kwargs.get('k_max', -1) self.__random_state = kwargs.get('random_state', None) if self.__ccore is True: self.__ccore = ccore_library.workable() self._verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of G-Means algorithm. @return (gmeans) Returns itself (G-Means instance). @see get_clusters() @see get_centers() """ if self.__ccore is True: return self._process_by_ccore() return self._process_by_python() def _process_by_ccore(self): """! @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library). """ self.__clusters, self.__centers, self.__total_wce = gmeans_wrapper(self.__data, self.__k_init, self.__tolerance, self.__repeat, self.__k_max, self.__random_state) return self def _process_by_python(self): """! @brief Performs cluster analysis using Python. """ self.__clusters, self.__centers, _ = self._search_optimal_parameters(self.__data, self.__k_init) while self._run_condition(): current_amount_clusters = len(self.__clusters) self._statistical_optimization() if current_amount_clusters == len(self.__centers): # amount of centers the same - no need to continue. break self._perform_clustering() return self def predict(self, points): """! @brief Calculates the closest cluster to each point. @param[in] points (array_like): Points for which closest clusters are calculated. @return (list) List of closest clusters for each point. Each cluster is denoted by index. Return empty collection if 'process()' method was not called. """ nppoints = numpy.array(points) if len(self.__clusters) == 0: return [] metric = distance_metric(type_metric.EUCLIDEAN_SQUARE, numpy_usage=True) npcenters = numpy.array(self.__centers) differences = numpy.zeros((len(nppoints), len(npcenters))) for index_point in range(len(nppoints)): differences[index_point] = metric(nppoints[index_point], npcenters) return numpy.argmin(differences, axis=1) def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @return (array_like) Allocated clusters. @see process() @see get_centers() """ return self.__clusters def get_centers(self): """! @brief Returns list of centers of allocated clusters. @return (array_like) Allocated centers. @see process() @see get_clusters() """ return self.__centers def get_total_wce(self): """! @brief Returns sum of metric errors that depends on metric that was used for clustering (by default SSE - Sum of Squared Errors). @details Sum of metric errors is calculated using distance between point and its center: \f[error=\sum_{i=0}^{N}distance(x_{i}-center(x_{i}))\f] @see process() @see get_clusters() """ return self.__total_wce def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def _statistical_optimization(self): """! @brief Try to split cluster into two to find optimal amount of clusters. """ centers = [] potential_amount_clusters = len(self.__clusters) for index in range(len(self.__clusters)): new_centers = self._split_and_search_optimal(self.__clusters[index]) if (new_centers is None) or ((self.__k_max != -1) and (potential_amount_clusters >= self.__k_max)): centers.append(self.__centers[index]) else: centers += new_centers potential_amount_clusters += 1 self.__centers = centers def _split_and_search_optimal(self, cluster): """! @brief Split specified cluster into two by performing K-Means clustering and check correctness by Anderson-Darling test. @param[in] cluster (array_like) Cluster that should be analysed and optimized by splitting if it is required. @return (array_like) Two new centers if two new clusters are considered as more suitable. (None) If current cluster is more suitable. """ if len(cluster) == 1: return None points = [self.__data[index_point] for index_point in cluster] new_clusters, new_centers, _ = self._search_optimal_parameters(points, 2) if len(new_centers) > 1: accept_null_hypothesis = self._is_null_hypothesis(points, new_centers) if not accept_null_hypothesis: return new_centers # If null hypothesis is rejected then use two new clusters return None def _is_null_hypothesis(self, data, centers): """! @brief Returns whether H0 hypothesis is accepted using Anderson-Darling test statistic. @param[in] data (array_like): N-dimensional data for statistical test. @param[in] centers (array_like): Two new allocated centers. @return (bool) True is null hypothesis is acceptable. """ v = numpy.subtract(centers[0], centers[1]) points = self._project_data(data, v) estimation, critical, _ = scipy.stats.anderson(points, dist='norm') # the Anderson-Darling test statistic # If the returned statistic is larger than these critical values then for the corresponding significance level, # the null hypothesis that the data come from the chosen distribution can be rejected. return estimation < critical[-1] # False - not a gaussian distribution (reject H0) @staticmethod def _project_data(data, vector): """! @brief Transform input data by project it onto input vector using formula: \f[ x_{i}^{*}=\frac{\left \langle x_{i}, v \right \rangle}{\left \| v \right \|^{2}}. \f] @param[in] data (array_like): Input data that is represented by points. @param[in] vector (array_like): Input vector that is used for projection. @return (array_like) Transformed 1-dimensional data. """ square_norm = numpy.sum(numpy.multiply(vector, vector)) return numpy.divide(numpy.sum(numpy.multiply(data, vector), axis=1), square_norm) def _search_optimal_parameters(self, data, amount): """! @brief Performs cluster analysis for specified data several times to find optimal clustering result in line with WCE. @param[in] data (array_like): Input data that should be clustered. @param[in] amount (unit): Amount of clusters that should be allocated. @return (tuple) Optimal clustering result: (clusters, centers, wce). """ best_wce, best_clusters, best_centers = float('+inf'), [], [] for _ in range(self.__repeat): initial_centers = kmeans_plusplus_initializer(data, amount, random_state=self.__random_state).initialize() solver = kmeans(data, initial_centers, tolerance=self.__tolerance, ccore=False).process() candidate_wce = solver.get_total_wce() if candidate_wce < best_wce: best_wce = candidate_wce best_clusters = solver.get_clusters() best_centers = solver.get_centers() if len(initial_centers) == 1: break # No need to rerun clustering for one initial center. return best_clusters, best_centers, best_wce def _perform_clustering(self): """! @brief Performs cluster analysis using K-Means algorithm using current centers are initial. @param[in] data (array_like): Input data for cluster analysis. """ solver = kmeans(self.__data, self.__centers, tolerance=self.__tolerance, ccore=False).process() self.__clusters = solver.get_clusters() self.__centers = solver.get_centers() self.__total_wce = solver.get_total_wce() def _run_condition(self): """! @brief Defines whether the algorithm should continue processing or should stop. @return `True` if the algorithm should continue processing, otherwise returns `False` """ if (self.__k_max > 0) and (len(self.__clusters) >= self.__k_max): return False return True def _verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data)) if self.__k_init <= 0: raise ValueError("Initial amount of centers should be greater than 0 " "(current value: '%d')." % self.__k_init) if self.__tolerance <= 0.0: raise ValueError("Tolerance should be greater than 0 (current value: '%f')." % self.__tolerance) if self.__repeat <= 0: raise ValueError("Amount of attempt to find optimal parameters should be greater than 0 " "(current value: '%d')." % self.__repeat) if (self.__k_max != -1) and (self.__k_max <= 0): raise ValueError("Maximum amount of cluster that might be allocated should be greater than 0 or -1 if " "the algorithm should be restricted in searching optimal number of clusters.") if (self.__k_max != -1) and (self.__k_max < self.__k_init): raise ValueError("Initial amount of clusters should be less than the maximum amount 'k_max'.") pyclustering-0.10.1.2/pyclustering/cluster/hsyncnet.py000077500000000000000000000171261375753423500231270ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: Hierarchical Sync (HSyncNet) @details Implementation based on paper @cite artcile::hsyncnet::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import pyclustering.core.hsyncnet_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.nnet import initial_type, solve_type from pyclustering.cluster.syncnet import syncnet, syncnet_analyser from pyclustering.utils import average_neighbor_distance class hsyncnet(syncnet): """! @brief Class represents clustering algorithm HSyncNet. HSyncNet is bio-inspired algorithm that is based on oscillatory network that uses modified Kuramoto model. Example: @code from pyclustering.cluster.hsyncnet import hsyncnet from pyclustering.nnet.sync import sync_visualizer from pyclustering.utils import read_sample, draw_clusters from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read list of points for cluster analysis. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) # Create network for allocation of three clusters. network = hsyncnet(sample, 3) # Run cluster analysis and output dynamic of the network. analyser = network.process(0.995, collect_dynamic=True) # Get allocated clusters. clusters = analyser.allocate_clusters(eps=0.1) # Show output dynamic of the network. sync_visualizer.show_output_dynamic(analyser) # Show allocated clusters. draw_clusters(sample, clusters) @endcode """ def __init__(self, source_data, number_clusters, osc_initial_phases=initial_type.RANDOM_GAUSSIAN, initial_neighbors=3, increase_persent=0.15, ccore=True): """! @brief Costructor of the oscillatory network hSyncNet for cluster analysis. @param[in] source_data (list): Input data set defines structure of the network. @param[in] number_clusters (uint): Number of clusters that should be allocated. @param[in] osc_initial_phases (initial_type): Type of initialization of initial values of phases of oscillators. @param[in] initial_neighbors (uint): Defines initial connectivity-radius by average distance to connect specified amount of oscillators (points). @param[in] increase_persent (double): Percent of increasing of radius connectivity on each iteration (input values in range (0.0; 1.0) correspond to (0%; 100%)). @param[in] ccore (bool): If True than DLL CCORE (C++ solution) will be used for solving. """ self.__ccore_network_pointer = None if initial_neighbors >= len(source_data): initial_neighbors = len(source_data) - 1 if (ccore is True) and ccore_library.workable(): self.__ccore_network_pointer = wrapper.hsyncnet_create_network(source_data, number_clusters, osc_initial_phases, initial_neighbors, increase_persent) else: super().__init__(source_data, 0, initial_phases=osc_initial_phases, ccore=False) self.__initial_neighbors = initial_neighbors self.__increase_persent = increase_persent self._number_clusters = number_clusters def __del__(self): """! @brief Destructor of oscillatory network HSyncNet. """ if self.__ccore_network_pointer is not None: wrapper.hsyncnet_destroy_network(self.__ccore_network_pointer) self.__ccore_network_pointer = None def process(self, order=0.998, solution=solve_type.FAST, collect_dynamic=False): """! @brief Performs clustering of input data set in line with input parameters. @param[in] order (double): Level of local synchronization between oscillator that defines end of synchronization process, range [0..1]. @param[in] solution (solve_type) Type of solving differential equation. @param[in] collect_dynamic (bool): If True - returns whole history of process synchronization otherwise - only final state (when process of clustering is over). @return (tuple) Returns dynamic of the network as tuple of lists on each iteration (time, oscillator_phases) that depends on collect_dynamic parameter. @see get_clusters() """ if self.__ccore_network_pointer is not None: analyser = wrapper.hsyncnet_process(self.__ccore_network_pointer, order, solution, collect_dynamic) return syncnet_analyser(None, None, analyser) number_neighbors = self.__initial_neighbors current_number_clusters = float('inf') dyn_phase = [] dyn_time = [] radius = average_neighbor_distance(self._osc_loc, number_neighbors) increase_step = int(len(self._osc_loc) * self.__increase_persent) if increase_step < 1: increase_step = 1 analyser = None while current_number_clusters > self._number_clusters: self._create_connections(radius) analyser = self.simulate_dynamic(order, solution, collect_dynamic) if collect_dynamic: if len(dyn_phase) == 0: self.__store_dynamic(dyn_phase, dyn_time, analyser, True) self.__store_dynamic(dyn_phase, dyn_time, analyser, False) clusters = analyser.allocate_sync_ensembles(0.05) # Get current number of allocated clusters current_number_clusters = len(clusters) # Increase number of neighbors that should be used number_neighbors += increase_step # Update connectivity radius and check if average function can be used anymore radius = self.__calculate_radius(number_neighbors, radius) if not collect_dynamic: self.__store_dynamic(dyn_phase, dyn_time, analyser, False) return syncnet_analyser(dyn_phase, dyn_time, None) def __calculate_radius(self, number_neighbors, radius): """! @brief Calculate new connectivity radius. @param[in] number_neighbors (uint): Average amount of neighbors that should be connected by new radius. @param[in] radius (double): Current connectivity radius. @return New connectivity radius. """ if number_neighbors >= len(self._osc_loc): return radius * self.__increase_persent + radius return average_neighbor_distance(self._osc_loc, number_neighbors) def __store_dynamic(self, dyn_phase, dyn_time, analyser, begin_state): """! @brief Store specified state of Sync network to hSync. @param[in] dyn_phase (list): Output dynamic of hSync where state should be stored. @param[in] dyn_time (list): Time points that correspond to output dynamic where new time point should be stored. @param[in] analyser (syncnet_analyser): Sync analyser where Sync states are stored. @param[in] begin_state (bool): If True the first state of Sync network is stored, otherwise the last state is stored. """ if begin_state is True: dyn_time.append(0) dyn_phase.append(analyser.output[0]) else: dyn_phase.append(analyser.output[len(analyser.output) - 1]) dyn_time.append(len(dyn_time)) pyclustering-0.10.1.2/pyclustering/cluster/kmeans.py000077500000000000000000000564201375753423500225520ustar00rootroot00000000000000"""! @brief The module contains K-Means algorithm and other related services. @details Implementation based on paper @cite inproceedings::kmeans::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import copy import numpy import matplotlib.pyplot as plt import matplotlib.animation as animation import pyclustering.core.kmeans_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.core.metric_wrapper import metric_wrapper from pyclustering.cluster.encoder import type_encoding from pyclustering.cluster import cluster_visualizer from pyclustering.utils.metric import distance_metric, type_metric class kmeans_observer: """! @brief Observer of K-Means algorithm that is used to collect information about clustering process on each iteration of the algorithm. @see kmeans """ def __init__(self): """! @brief Initializer of observer of K-Means algorithm. """ self.__evolution_clusters = [] self.__evolution_centers = [] self.__initial_centers = [] def __len__(self): """! @brief Returns amount of steps that were observer during clustering process in K-Means algorithm. """ return len(self.__evolution_clusters) def notify(self, clusters, centers): """! @brief This method is called by K-Means algorithm to notify about changes. @param[in] clusters (array_like): Allocated clusters by K-Means algorithm. @param[in] centers (array_like): Allocated centers by K-Means algorithm. """ self.__evolution_clusters.append(clusters) self.__evolution_centers.append(centers) def set_evolution_centers(self, evolution_centers): """! @brief Set evolution of changes of centers during clustering process. @param[in] evolution_centers (array_like): Evolution of changes of centers during clustering process. """ self.__evolution_centers = evolution_centers def get_centers(self, iteration): """! @brief Get method to return centers at specific iteration of clustering process. @param[in] iteration (uint): Clustering process iteration at which centers are required. @return (array_like) Centers at specific iteration. """ return self.__evolution_centers[iteration] def set_evolution_clusters(self, evolution_clusters): """! @brief Set evolution of changes of centers during clustering process. @param[in] evolution_clusters (array_like): Evolution of changes of clusters during clustering process. """ self.__evolution_clusters = evolution_clusters def get_clusters(self, iteration): """! @brief Get method to return allocated clusters at specific iteration of clustering process. @param[in] iteration (uint): Clustering process iteration at which clusters are required. @return (array_like) Clusters at specific iteration. """ return self.__evolution_clusters[iteration] class kmeans_visualizer: """! @brief Visualizer of K-Means algorithm's results. @details K-Means visualizer provides visualization services that are specific for K-Means algorithm. """ __default_2d_marker_size = 15 __default_3d_marker_size = 70 @staticmethod def show_clusters(sample, clusters, centers, initial_centers = None, **kwargs): """! @brief Display K-Means clustering results. @param[in] sample (list): Dataset that was used for clustering. @param[in] clusters (array_like): Clusters that were allocated by the algorithm. @param[in] centers (array_like): Centers that were allocated by the algorithm. @param[in] initial_centers (array_like): Initial centers that were used by the algorithm, if 'None' then initial centers are not displyed. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'figure', 'display', 'offset'). Keyword Args:
- figure (figure): If 'None' then new is figure is created, otherwise specified figure is used for visualization. - display (bool): If 'True' then figure will be shown by the method, otherwise it should be shown manually using matplotlib function 'plt.show()'. - offset (uint): Specify axes index on the figure where results should be drawn (only if argument 'figure' is specified). @return (figure) Figure where clusters were drawn. """ visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) offset = kwargs.get('offset', 0) figure = kwargs.get('figure', None) display = kwargs.get('display', True) if figure is None: figure = visualizer.show(display=False) else: visualizer.show(figure=figure, display=False) kmeans_visualizer.__draw_centers(figure, offset, visualizer, centers, initial_centers) kmeans_visualizer.__draw_rays(figure, offset, visualizer, sample, clusters, centers) if display is True: plt.show() return figure @staticmethod def __draw_rays(figure, offset, visualizer, sample, clusters, centers): ax = figure.get_axes()[offset] for index_cluster in range(len(clusters)): color = visualizer.get_cluster_color(index_cluster, 0) kmeans_visualizer.__draw_cluster_rays(ax, color, sample, clusters[index_cluster], centers[index_cluster]) @staticmethod def __draw_cluster_rays(ax, color, sample, cluster, center): dimension = len(sample[0]) for index_point in cluster: point = sample[index_point] if dimension == 1: ax.plot([point[0], center[0]], [0.0, 0.0], '-', color=color, linewidth=0.5) elif dimension == 2: ax.plot([point[0], center[0]], [point[1], center[1]], '-', color=color, linewidth=0.5) elif dimension == 3: ax.plot([point[0], center[0]], [point[1], center[1]], [point[2], center[2]], '-', color=color, linewidth=0.5) @staticmethod def __draw_center(ax, center, color, marker, alpha): dimension = len(center) if dimension == 1: ax.plot(center[0], 0.0, color=color, alpha=alpha, marker=marker, markersize=kmeans_visualizer.__default_2d_marker_size) elif dimension == 2: ax.plot(center[0], center[1], color=color, alpha=alpha, marker=marker, markersize=kmeans_visualizer.__default_2d_marker_size) elif dimension == 3: ax.scatter(center[0], center[1], center[2], c=color, alpha=alpha, marker=marker, s=kmeans_visualizer.__default_3d_marker_size) @staticmethod def __draw_centers(figure, offset, visualizer, centers, initial_centers): ax = figure.get_axes()[offset] for index_center in range(len(centers)): color = visualizer.get_cluster_color(index_center, 0) kmeans_visualizer.__draw_center(ax, centers[index_center], color, '*', 1.0) if initial_centers is not None: kmeans_visualizer.__draw_center(ax, initial_centers[index_center], color, '*', 0.4) @staticmethod def animate_cluster_allocation(data, observer, animation_velocity=500, movie_fps=1, save_movie=None): """! @brief Animates clustering process that is performed by K-Means algorithm. @param[in] data (list): Dataset that is used for clustering. @param[in] observer (kmeans_observer): EM observer that was used for collection information about clustering process. @param[in] animation_velocity (uint): Interval between frames in milliseconds (for run-time animation only). @param[in] movie_fps (uint): Defines frames per second (for rendering movie only). @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure() def init_frame(): return frame_generation(0) def frame_generation(index_iteration): figure.clf() figure.suptitle("K-Means algorithm (iteration: " + str(index_iteration) + ")", fontsize=18, fontweight='bold') clusters = observer.get_clusters(index_iteration) centers = observer.get_centers(index_iteration) kmeans_visualizer.show_clusters(data, clusters, centers, None, figure=figure, display=False) figure.subplots_adjust(top=0.85) return [figure.gca()] iterations = len(observer) cluster_animation = animation.FuncAnimation(figure, frame_generation, iterations, interval=animation_velocity, init_func=init_frame, repeat_delay=5000) if save_movie is not None: cluster_animation.save(save_movie, writer='ffmpeg', fps=movie_fps, bitrate=3000) else: plt.show() class kmeans: """! @brief Class implements K-Means clustering algorithm. @details K-Means clustering aims to partition n observations into k clusters in which each observation belongs to the cluster with the nearest mean, serving as a prototype of the cluster. This results in a partitioning of the data space into Voronoi cells. K-Means clustering results depend on initial centers. Algorithm K-Means++ can used for initialization of initial centers - see module 'pyclustering.cluster.center_initializer'. CCORE implementation (C/C++ part of the library) of the algorithm performs parallel processing to ensure maximum performance. Implementation based on the paper @cite inproceedings::kmeans::1. @image html kmeans_example_clustering.png "Fig. 1. K-Means clustering results. At the left - 'Simple03.data' sample, at the right - 'Lsun.data' sample." Example #1 - Clustering using K-Means++ for center initialization: @code from pyclustering.cluster.kmeans import kmeans, kmeans_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis. sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Prepare initial centers using K-Means++ method. initial_centers = kmeans_plusplus_initializer(sample, 2).initialize() # Create instance of K-Means algorithm with prepared centers. kmeans_instance = kmeans(sample, initial_centers) # Run cluster analysis and obtain results. kmeans_instance.process() clusters = kmeans_instance.get_clusters() final_centers = kmeans_instance.get_centers() # Visualize obtained results kmeans_visualizer.show_clusters(sample, clusters, final_centers) @endcode Example #2 - Clustering using specific distance metric, for example, Manhattan distance: @code # prepare input data and initial centers for cluster analysis using K-Means # create metric that will be used for clustering manhattan_metric = distance_metric(type_metric.MANHATTAN) # create instance of K-Means using specific distance metric: kmeans_instance = kmeans(sample, initial_centers, metric=manhattan_metric) # run cluster analysis and obtain results kmeans_instance.process() clusters = kmeans_instance.get_clusters() @endcode @see center_initializer """ def __init__(self, data, initial_centers, tolerance=0.001, ccore=True, **kwargs): """! @brief Constructor of clustering algorithm K-Means. @details Center initializer can be used for creating initial centers, for example, K-Means++ method. @param[in] data (array_like): Input data that is presented as array of points (objects), each point should be represented by array_like data structure. @param[in] initial_centers (array_like): Initial coordinates of centers of clusters that are represented by array_like data structure: [center1, center2, ...]. @param[in] tolerance (double): Stop condition: if maximum value of change of centers of clusters is less than tolerance then algorithm stops processing. @param[in] ccore (bool): Defines should be CCORE library (C++ pyclustering library) used instead of Python code or not. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'observer', 'metric', 'itermax'). Keyword Args:
- observer (kmeans_observer): Observer of the algorithm to collect information about clustering process on each iteration. - metric (distance_metric): Metric that is used for distance calculation between two points (by default euclidean square distance). - itermax (uint): Maximum number of iterations that is used for clustering process (by default: 200). @see center_initializer """ self.__pointer_data = numpy.array(data) self.__clusters = [] self.__centers = numpy.array(initial_centers) self.__tolerance = tolerance self.__total_wce = 0.0 self.__observer = kwargs.get('observer', None) self.__metric = copy.copy(kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE))) self.__itermax = kwargs.get('itermax', 100) if self.__metric.get_type() != type_metric.USER_DEFINED: self.__metric.enable_numpy_usage() else: self.__metric.disable_numpy_usage() self.__ccore = ccore and self.__metric.get_type() != type_metric.USER_DEFINED if self.__ccore is True: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of K-Means algorithm. @return (kmeans) Returns itself (K-Means instance). @see get_clusters() @see get_centers() """ if len(self.__pointer_data[0]) != len(self.__centers[0]): raise ValueError("Dimension of the input data and dimension of the initial cluster centers must be equal.") if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library). """ ccore_metric = metric_wrapper.create_instance(self.__metric) results = wrapper.kmeans(self.__pointer_data, self.__centers, self.__tolerance, self.__itermax, (self.__observer is not None), ccore_metric.get_pointer()) self.__clusters = results[0] self.__centers = results[1] if self.__observer is not None: self.__observer.set_evolution_clusters(results[2]) self.__observer.set_evolution_centers(results[3]) self.__total_wce = results[4][0] def __process_by_python(self): """! @brief Performs cluster analysis using python code. """ maximum_change = float('inf') iteration = 0 if self.__observer is not None: initial_clusters = self.__update_clusters() self.__observer.notify(initial_clusters, self.__centers.tolist()) while maximum_change > self.__tolerance and iteration < self.__itermax: self.__clusters = self.__update_clusters() updated_centers = self.__update_centers() # changes should be calculated before assignment if self.__observer is not None: self.__observer.notify(self.__clusters, updated_centers.tolist()) maximum_change = self.__calculate_changes(updated_centers) self.__centers = updated_centers # assign center after change calculation iteration += 1 self.__calculate_total_wce() def predict(self, points): """! @brief Calculates the closest cluster to each point. @param[in] points (array_like): Points for which closest clusters are calculated. @return (list) List of closest clusters for each point. Each cluster is denoted by index. Return empty collection if 'process()' method was not called. """ nppoints = numpy.array(points) if len(self.__clusters) == 0: return [] differences = numpy.zeros((len(nppoints), len(self.__centers))) for index_point in range(len(nppoints)): if self.__metric.get_type() != type_metric.USER_DEFINED: differences[index_point] = self.__metric(nppoints[index_point], self.__centers) else: differences[index_point] = [self.__metric(nppoints[index_point], center) for center in self.__centers] return numpy.argmin(differences, axis=1) def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_centers() """ return self.__clusters def get_centers(self): """! @brief Returns list of centers of allocated clusters. @see process() @see get_clusters() """ if isinstance(self.__centers, list): return self.__centers return self.__centers.tolist() def get_total_wce(self): """! @brief Returns sum of metric errors that depends on metric that was used for clustering (by default SSE - Sum of Squared Errors). @details Sum of metric errors is calculated using distance between point and its center: \f[error=\sum_{i=0}^{N}distance(x_{i}-center(x_{i}))\f] @see process() @see get_clusters() """ return self.__total_wce def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __update_clusters(self): """! @brief Calculate distance (in line with specified metric) to each point from the each cluster. Nearest points are captured by according clusters and as a result clusters are updated. @return (list) Updated clusters as list of clusters. Each cluster contains indexes of objects from data. """ clusters = [[] for _ in range(len(self.__centers))] dataset_differences = self.__calculate_dataset_difference(len(clusters)) optimum_indexes = numpy.argmin(dataset_differences, axis=0) for index_point in range(len(optimum_indexes)): index_cluster = optimum_indexes[index_point] clusters[index_cluster].append(index_point) clusters = [cluster for cluster in clusters if len(cluster) > 0] return clusters def __update_centers(self): """! @brief Calculate centers of clusters in line with contained objects. @return (numpy.array) Updated centers. """ dimension = self.__pointer_data.shape[1] centers = numpy.zeros((len(self.__clusters), dimension)) for index in range(len(self.__clusters)): cluster_points = self.__pointer_data[self.__clusters[index], :] centers[index] = cluster_points.mean(axis=0) return numpy.array(centers) def __calculate_total_wce(self): """! @brief Calculate total within cluster errors that is depend on metric that was chosen for K-Means algorithm. """ dataset_differences = self.__calculate_dataset_difference(len(self.__clusters)) self.__total_wce = 0.0 for index_cluster in range(len(self.__clusters)): for index_point in self.__clusters[index_cluster]: self.__total_wce += dataset_differences[index_cluster][index_point] def __calculate_dataset_difference(self, amount_clusters): """! @brief Calculate distance from each point to each cluster center. """ dataset_differences = numpy.zeros((amount_clusters, len(self.__pointer_data))) for index_center in range(amount_clusters): if self.__metric.get_type() != type_metric.USER_DEFINED: dataset_differences[index_center] = self.__metric(self.__pointer_data, self.__centers[index_center]) else: dataset_differences[index_center] = [self.__metric(point, self.__centers[index_center]) for point in self.__pointer_data] return dataset_differences def __calculate_changes(self, updated_centers): """! @brief Calculates changes estimation between previous and current iteration using centers for that purpose. @param[in] updated_centers (array_like): New cluster centers. @return (float) Maximum changes between centers. """ if len(self.__centers) != len(updated_centers): maximum_change = float('inf') else: if self.__metric.get_type() != type_metric.USER_DEFINED: changes = self.__metric(self.__centers, updated_centers) else: changes = [self.__metric(center, updated_center) for center, updated_center in zip(self.__centers, updated_centers)] maximum_change = numpy.max(changes) return maximum_change def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if len(self.__centers) == 0: raise ValueError("Initial centers are empty (size: '%d')." % len(self.__pointer_data)) if self.__tolerance < 0: raise ValueError("Tolerance (current value: '%d') should be greater or equal to 0." % self.__tolerance) if self.__itermax < 0: raise ValueError("Maximum iterations (current value: '%d') should be greater or equal to 0." % self.__tolerance) pyclustering-0.10.1.2/pyclustering/cluster/kmedians.py000077500000000000000000000321601375753423500230620ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: K-Medians @details Implementation based on paper @cite book::algorithms_for_clustering_data. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import numpy from pyclustering.cluster.encoder import type_encoding from pyclustering.utils.metric import distance_metric, type_metric import pyclustering.core.kmedians_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.core.metric_wrapper import metric_wrapper class kmedians: """! @brief Class represents clustering algorithm K-Medians. @details The algorithm is less sensitive to outliers than K-Means. Medians are calculated instead of centroids. Example: @code from pyclustering.cluster.kmedians import kmedians from pyclustering.cluster import cluster_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Load list of points for cluster analysis. sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Create instance of K-Medians algorithm. initial_medians = [[0.0, 0.1], [2.5, 0.7]] kmedians_instance = kmedians(sample, initial_medians) # Run cluster analysis and obtain results. kmedians_instance.process() clusters = kmedians_instance.get_clusters() medians = kmedians_instance.get_medians() # Visualize clustering results. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(initial_medians, marker='*', markersize=10) visualizer.append_cluster(medians, marker='*', markersize=10) visualizer.show() @endcode """ def __init__(self, data, initial_medians, tolerance=0.001, ccore=True, **kwargs): """! @brief Constructor of clustering algorithm K-Medians. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] initial_medians (list): Initial coordinates of medians of clusters that are represented by list: [center1, center2, ...]. @param[in] tolerance (double): Stop condition: if maximum value of change of centers of clusters is less than tolerance than algorithm will stop processing @param[in] ccore (bool): Defines should be CCORE library (C++ pyclustering library) used instead of Python code or not. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric', 'itermax'). Keyword Args:
- metric (distance_metric): Metric that is used for distance calculation between two points. - itermax (uint): Maximum number of iterations for cluster analysis. """ self.__pointer_data = numpy.array(data) self.__clusters = [] self.__medians = numpy.array(initial_medians) self.__tolerance = tolerance self.__total_wce = 0 self.__itermax = kwargs.get('itermax', 100) self.__metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) if self.__metric is None: self.__metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) self.__ccore = ccore and self.__metric.get_type() != type_metric.USER_DEFINED if self.__ccore: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of K-Medians algorithm. @return (kmedians) Returns itself (K-Medians instance). @remark Results of clustering can be obtained using corresponding get methods. @see get_clusters() @see get_medians() """ if self.__ccore is True: ccore_metric = metric_wrapper.create_instance(self.__metric) self.__clusters, self.__medians = wrapper.kmedians(self.__pointer_data, self.__medians, self.__tolerance, self.__itermax, ccore_metric.get_pointer()) else: changes = float('inf') # Check for dimension if len(self.__pointer_data[0]) != len(self.__medians[0]): raise NameError('Dimension of the input data and dimension of the initial medians must be equal.') iterations = 0 while changes > self.__tolerance and iterations < self.__itermax: self.__clusters = self.__update_clusters() updated_centers = self.__update_medians() changes = max([self.__metric(self.__medians[index], updated_centers[index]) for index in range(len(updated_centers))]) self.__medians = updated_centers iterations += 1 self.__calculate_total_wce() return self def predict(self, points): """! @brief Calculates the closest cluster to each point. @param[in] points (array_like): Points for which closest clusters are calculated. @return (list) List of closest clusters for each point. Each cluster is denoted by index. Return empty collection if 'process()' method was not called. An example how to calculate (or predict) the closest cluster to specified points. @code from pyclustering.cluster.kmedians import kmedians from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Initial centers for sample 'Simple3'. initial_medians = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] # Create instance of K-Medians algorithm with prepared centers. kmedians_instance = kmedians(sample, initial_medians) # Run cluster analysis. kmedians_instance.process() # Calculate the closest cluster to following two points. points = [[0.25, 0.2], [2.5, 4.0]] closest_clusters = kmedians_instance.predict(points) print(closest_clusters) @endcode """ if len(self.__clusters) == 0: return [] differences = numpy.zeros((len(points), len(self.__medians))) for index_point in range(len(points)): differences[index_point] = [ self.__metric(points[index_point], center) for center in self.__medians ] return numpy.argmin(differences, axis=1) def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_medians() """ return self.__clusters def get_medians(self): """! @brief Returns list of centers of allocated clusters. @see process() @see get_clusters() """ if isinstance(self.__medians, list): return self.__medians return self.__medians.tolist() def get_total_wce(self): """! @brief Returns sum of metric errors that depends on metric that was used for clustering (by default SSE - Sum of Squared Errors). @details Sum of metric errors is calculated using distance between point and its center: \f[error=\sum_{i=0}^{N}distance(x_{i}-center(x_{i}))\f] @see process() @see get_clusters() """ return self.__total_wce def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __update_clusters(self): """! @brief Calculate Manhattan distance to each point from the each cluster. @details Nearest points are captured by according clusters and as a result clusters are updated. @return (list) updated clusters as list of clusters where each cluster contains indexes of objects from data. """ clusters = [[] for i in range(len(self.__medians))] for index_point in range(len(self.__pointer_data)): index_optim = -1 dist_optim = 0.0 for index in range(len(self.__medians)): dist = self.__metric(self.__pointer_data[index_point], self.__medians[index]) if (dist < dist_optim) or (index == 0): index_optim = index dist_optim = dist clusters[index_optim].append(index_point) # If cluster is not able to capture object it should be removed clusters = [cluster for cluster in clusters if len(cluster) > 0] return clusters def __calculate_total_wce(self): """! @brief Calculate total within cluster errors that is depend on metric that was chosen for K-Medians algorithm. """ dataset_differences = self.__calculate_dataset_difference(len(self.__clusters)) self.__total_wce = 0 for index_cluster in range(len(self.__clusters)): for index_point in self.__clusters[index_cluster]: self.__total_wce += dataset_differences[index_cluster][index_point] def __calculate_dataset_difference(self, amount_clusters): """! @brief Calculate distance from each point to each cluster center. """ self.__metric.enable_numpy_usage() dataset_differences = numpy.zeros((amount_clusters, len(self.__pointer_data))) for index_center in range(amount_clusters): if self.__metric.get_type() != type_metric.USER_DEFINED: dataset_differences[index_center] = self.__metric(self.__pointer_data, self.__medians[index_center]) else: dataset_differences[index_center] = [self.__metric(point, self.__medians[index_center]) for point in self.__pointer_data] self.__metric.disable_numpy_usage() return dataset_differences def __update_medians(self): """! @brief Calculate medians of clusters in line with contained objects. @return (list) list of medians for current number of clusters. """ medians = [[] for i in range(len(self.__clusters))] for index in range(len(self.__clusters)): medians[index] = [0.0 for i in range(len(self.__pointer_data[0]))] length_cluster = len(self.__clusters[index]) for index_dimension in range(len(self.__pointer_data[0])): sorted_cluster = sorted(self.__clusters[index], key=lambda x: self.__pointer_data[x][index_dimension]) relative_index_median = int(math.floor((length_cluster - 1) / 2)) index_median = sorted_cluster[relative_index_median] if (length_cluster % 2) == 0: index_median_second = sorted_cluster[relative_index_median + 1] medians[index][index_dimension] = (self.__pointer_data[index_median][index_dimension] + self.__pointer_data[index_median_second][index_dimension]) / 2.0 else: medians[index][index_dimension] = self.__pointer_data[index_median][index_dimension] return medians def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if not hasattr(self.__pointer_data[0], "__getitem__"): raise TypeError("Input data element does not have attribute '__getitem__'.") if len(self.__medians) == 0: raise ValueError("Initial medians are empty (size: '%d')." % len(self.__medians)) if not hasattr(self.__medians[0], "__getitem__"): raise TypeError("Initial medians element does not have attribute '__getitem__'.") if self.__tolerance < 0: raise ValueError("Tolerance (current value: '%d') should be greater or equal to 0." % self.__tolerance) if self.__itermax < 0: raise ValueError("Maximum iterations (current value: '%d') should be greater or equal to 0." % self.__itermax) pyclustering-0.10.1.2/pyclustering/cluster/kmedoids.py000077500000000000000000000403021375753423500230630ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: K-Medoids. @details Implementation based on paper @cite inproceedings::cluster::kmedoids::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from pyclustering.cluster.encoder import type_encoding from pyclustering.utils import medoid from pyclustering.utils.metric import distance_metric, type_metric import pyclustering.core.kmedoids_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.core.metric_wrapper import metric_wrapper class kmedoids: """! @brief Class represents clustering algorithm K-Medoids (PAM algorithm). @details PAM is a partitioning clustering algorithm that uses the medoids instead of centers like in case of K-Means algorithm. Medoid is an object with the smallest dissimilarity to all others in the cluster. PAM algorithm complexity is \f$O\left ( k\left ( n-k \right )^{2} \right )\f$. There is an example where PAM algorithm is used to cluster 'TwoDiamonds' data: @code from pyclustering.cluster.kmedoids import kmedoids from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster import cluster_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Load list of points for cluster analysis. sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Initialize initial medoids using K-Means++ algorithm initial_medoids = kmeans_plusplus_initializer(sample, 2).initialize(return_index=True) # Create instance of K-Medoids (PAM) algorithm. kmedoids_instance = kmedoids(sample, initial_medoids) # Run cluster analysis and obtain results. kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() medoids = kmedoids_instance.get_medoids() # Print allocated clusters. print("Clusters:", clusters) # Display clustering results. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(initial_medoids, sample, markersize=12, marker='*', color='gray') visualizer.append_cluster(medoids, sample, markersize=14, marker='*', color='black') visualizer.show() @endcode @image html pam_clustering_two_diamonds.png "Fig. 1. K-Medoids (PAM) clustering results 'TwoDiamonds'." Metric for calculation distance between points can be specified by parameter additional 'metric': @code # create Minkowski distance metric with degree equals to '2' metric = distance_metric(type_metric.MINKOWSKI, degree=2) # create K-Medoids algorithm with specific distance metric kmedoids_instance = kmedoids(sample, initial_medoids, metric=metric) # run cluster analysis and obtain results kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() @endcode Distance matrix can be used instead of sequence of points to increase performance and for that purpose parameter 'data_type' should be used: @code # calculate distance matrix for sample sample = read_sample(path_to_sample) matrix = calculate_distance_matrix(sample) # create K-Medoids algorithm for processing distance matrix instead of points kmedoids_instance = kmedoids(matrix, initial_medoids, data_type='distance_matrix') # run cluster analysis and obtain results kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() medoids = kmedoids_instance.get_medoids() @endcode """ def __init__(self, data, initial_index_medoids, tolerance=0.0001, ccore=True, **kwargs): """! @brief Constructor of clustering algorithm K-Medoids. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] initial_index_medoids (list): Indexes of intial medoids (indexes of points in input data). @param[in] tolerance (double): Stop condition: if maximum value of distance change of medoids of clusters is less than tolerance than algorithm will stop processing. @param[in] ccore (bool): If specified than CCORE library (C++ pyclustering library) is used for clustering instead of Python code. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `metric`, `data_type`, `itermax`). Keyword Args:
- metric (distance_metric): Metric that is used for distance calculation between two points. - data_type (string): Data type of input sample `data` that is processed by the algorithm (`points`, `distance_matrix`). - itermax (uint): Maximum number of iteration for cluster analysis. """ self.__pointer_data = data self.__clusters = [] self.__labels = [-1] * len(data) self.__medoid_indexes = initial_index_medoids[:] self.__distance_first_medoid = [float('inf')] * len(data) self.__distance_second_medoid = [float('inf')] * len(data) self.__tolerance = tolerance self.__metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) self.__data_type = kwargs.get('data_type', 'points') self.__itermax = kwargs.get('itermax', 200) self.__distance_calculator = self.__create_distance_calculator() self.__ccore = ccore and self.__metric.get_type() != type_metric.USER_DEFINED if self.__ccore: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of K-Medoids algorithm. @return (kmedoids) Returns itself (K-Medoids instance). @remark Results of clustering can be obtained using corresponding get methods. @see get_clusters() @see get_medoids() """ if self.__ccore is True: ccore_metric = metric_wrapper.create_instance(self.__metric) self.__clusters, self.__medoid_indexes = wrapper.kmedoids(self.__pointer_data, self.__medoid_indexes, self.__tolerance, self.__itermax, ccore_metric.get_pointer(), self.__data_type) else: changes = float('inf') previous_deviation, current_deviation = float('inf'), float('inf') iterations = 0 if self.__itermax > 0: current_deviation = self.__update_clusters() while (changes > self.__tolerance) and (iterations < self.__itermax): swap_cost = self.__swap_medoids() if swap_cost != float('inf'): previous_deviation = current_deviation current_deviation = self.__update_clusters() changes = previous_deviation - current_deviation else: break iterations += 1 self.__erase_empty_clusters() return self def predict(self, points): """! @brief Calculates the closest cluster to each point. @param[in] points (array_like): Points for which closest clusters are calculated. @return (list) List of closest clusters for each point. Each cluster is denoted by index. Return empty collection if 'process()' method was not called. An example how to calculate (or predict) the closest cluster to specified points. @code from pyclustering.cluster.kmedoids import kmedoids from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Initial medoids for sample 'Simple3'. initial_medoids = [4, 12, 25, 37] # Create instance of K-Medoids algorithm with prepared centers. kmedoids_instance = kmedoids(sample, initial_medoids) # Run cluster analysis. kmedoids_instance.process() # Calculate the closest cluster to following two points. points = [[0.35, 0.5], [2.5, 2.0]] closest_clusters = kmedoids_instance.predict(points) print(closest_clusters) @endcode """ if len(self.__clusters) == 0: return [] medoids = [self.__pointer_data[index] for index in self.__medoid_indexes] differences = numpy.zeros((len(points), len(medoids))) for index_point in range(len(points)): differences[index_point] = [self.__metric(points[index_point], center) for center in medoids] return numpy.argmin(differences, axis=1) def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @see process() @see get_medoids() """ return self.__clusters def get_medoids(self): """! @brief Returns list of medoids of allocated clusters represented by indexes from the input data. @see process() @see get_clusters() """ return self.__medoid_indexes def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if len(self.__medoid_indexes) == 0: raise ValueError("Initial medoids are empty (size: '%d')." % len(self.__pointer_data)) if self.__tolerance < 0: raise ValueError("Tolerance (current value: '%d') should be greater or equal to 0." % self.__tolerance) if self.__itermax < 0: raise ValueError("Maximum iterations (current value: '%d') should be greater or equal to 0." % self.__tolerance) def __create_distance_calculator(self): """! @brief Creates distance calculator in line with algorithms parameters. @return (callable) Distance calculator. """ if self.__data_type == 'points': return lambda index1, index2: self.__metric(self.__pointer_data[index1], self.__pointer_data[index2]) elif self.__data_type == 'distance_matrix': if isinstance(self.__pointer_data, numpy.matrix): return lambda index1, index2: self.__pointer_data.item((index1, index2)) return lambda index1, index2: self.__pointer_data[index1][index2] else: raise TypeError("Unknown type of data is specified '%s'" % self.__data_type) def __update_clusters(self): """! @brief Calculate distance to each point from the each cluster. @details Nearest points are captured by according clusters and as a result clusters are updated. @return (double) Total deviation (distance from each point to its closest medoid). """ total_deviation = 0.0 self.__clusters = [[] for i in range(len(self.__medoid_indexes))] for index_point in range(len(self.__pointer_data)): index_optim = -1 dist_optim_first = float('Inf') dist_optim_second = float('Inf') for index in range(len(self.__medoid_indexes)): dist = self.__distance_calculator(index_point, self.__medoid_indexes[index]) if dist < dist_optim_first: dist_optim_second = dist_optim_first index_optim = index dist_optim_first = dist elif dist < dist_optim_second: dist_optim_second = dist total_deviation += dist_optim_first self.__clusters[index_optim].append(index_point) self.__labels[index_point] = index_optim self.__distance_first_medoid[index_point] = dist_optim_first self.__distance_second_medoid[index_point] = dist_optim_second return total_deviation def __swap_medoids(self): """! @brief Swap existed medoid with non-medoid points in order to find the most optimal medoid. @return (double) Cost that is needed to swap two medoids. """ optimal_swap_cost = float('inf') optimal_index_cluster = None optimal_index_medoid = None for index_cluster in range(len(self.__clusters)): for candidate_medoid_index in range(len(self.__pointer_data)): if (candidate_medoid_index in self.__medoid_indexes) or (self.__distance_first_medoid[candidate_medoid_index] == 0.0): continue swap_cost = self.__calculate_swap_cost(candidate_medoid_index, index_cluster) if swap_cost < optimal_swap_cost: optimal_swap_cost = swap_cost optimal_index_cluster = index_cluster optimal_index_medoid = candidate_medoid_index if optimal_index_cluster is not None: self.__medoid_indexes[optimal_index_cluster] = optimal_index_medoid return optimal_swap_cost def __calculate_swap_cost(self, index_candidate, cluster_index): """! @brief Calculates cost to swap `index_candidate` with the current medoid `cluster_index`. @param[in] index_candidate (uint): Index point that is considered as a medoid candidate. @param[in] cluster_index (uint): Index of a cluster where the current medoid is used for calculation. @return (double) Cost that is needed to swap medoids. """ cost = 0.0 for index_point in range(len(self.__pointer_data)): if index_point == index_candidate: continue candidate_distance = self.__distance_calculator(index_point, index_candidate) if self.__labels[index_point] == cluster_index: cost += min(candidate_distance, self.__distance_second_medoid[index_point]) - self.__distance_first_medoid[index_point] elif candidate_distance < self.__distance_first_medoid[index_point]: cost += candidate_distance - self.__distance_first_medoid[index_point] return cost - self.__distance_first_medoid[index_candidate] def __erase_empty_clusters(self): """! @brief Erase empty clusters and their medoids. @details Data might have identical points and a lot of identical points and as a result medoids might correspond to points that are totally identical. """ erase_required = False # Before processing check if there are empty clusters for cluster in self.__clusters: if len(cluster) == 0: erase_required = True break if erase_required is False: return none_empty_clusters = [] none_empty_medoids = [] for index in range(len(self.__clusters)): if len(self.__clusters[index]) == 0: continue none_empty_clusters.append(self.__clusters[index]) none_empty_medoids.append(self.__medoid_indexes[index]) self.__clusters = none_empty_clusters self.__medoid_indexes = none_empty_medoids pyclustering-0.10.1.2/pyclustering/cluster/mbsas.py000077500000000000000000000100521375753423500223700ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: MBSAS (Modified Basic Sequential Algorithmic Scheme). @details Implementation based on paper @cite book::pattern_recognition::2009. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.mbsas_wrapper import mbsas as mbsas_wrapper from pyclustering.core.metric_wrapper import metric_wrapper from pyclustering.cluster.bsas import bsas class mbsas(bsas): """! @brief Class represents MBSAS (Modified Basic Sequential Algorithmic Scheme). @details Interface of MBSAS algorithm is the same as for BSAS. This algorithm performs clustering in two steps. The first - is determination of amount of clusters. The second - is assignment of points that were not marked as a cluster representatives to clusters. Code example of MBSAS usage: @code from pyclustering.cluster.bsas import bsas_visualizer from pyclustering.cluster.mbsas import mbsas from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read data sample from 'Simple02.data'. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) # Prepare algorithm's parameters. max_clusters = 3 threshold = 1.0 # Create instance of MBSAS algorithm. mbsas_instance = mbsas(sample, max_clusters, threshold) mbsas_instance.process() # Get clustering results. clusters = mbsas_instance.get_clusters() representatives = mbsas_instance.get_representatives() # Display results. bsas_visualizer.show_clusters(sample, clusters, representatives) @endcode @see pyclustering.cluster.bsas, pyclustering.cluster.ttsas """ def __init__(self, data, maximum_clusters, threshold, ccore=True, **kwargs): """! @brief Creates MBSAS algorithm. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] maximum_clusters: Maximum allowable number of clusters that can be allocated during processing. @param[in] threshold: Threshold of dissimilarity (maximum distance) between points. @param[in] ccore (bool): If True than DLL CCORE (C++ solution) will be used for solving. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric'). Keyword Args:
- metric (distance_metric): Metric that is used for distance calculation between two points. """ super().__init__(data, maximum_clusters, threshold, ccore, **kwargs) def process(self): """! @brief Performs cluster analysis in line with MBSAS algorithm. @return (mbsas) Returns itself (MBSAS instance). @see get_clusters() @see get_representatives() """ if self._ccore is True: self.__process_by_ccore() else: self.__prcess_by_python() return self def __process_by_ccore(self): ccore_metric = metric_wrapper.create_instance(self._metric) self._clusters, self._representatives = mbsas_wrapper(self._data, self._amount, self._threshold, ccore_metric.get_pointer()) def __prcess_by_python(self): self._clusters.append([0]); self._representatives.append(self._data[0]); skipped_objects = []; for i in range(1, len(self._data)): point = self._data[i]; index_cluster, distance = self._find_nearest_cluster(point); if (distance > self._threshold) and (len(self._clusters) < self._amount): self._representatives.append(point); self._clusters.append([i]); else: skipped_objects.append(i); for i in skipped_objects: point = self._data[i]; index_cluster, _ = self._find_nearest_cluster(point); self._clusters[index_cluster].append(i); self._update_representative(index_cluster, point);pyclustering-0.10.1.2/pyclustering/cluster/optics.py000077500000000000000000000764511375753423500226030ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: OPTICS (Ordering Points To Identify Clustering Structure) @details Implementation based on paper @cite article::optics::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import matplotlib.pyplot as plt from pyclustering.container.kdtree import kdtree_balanced from pyclustering.cluster.encoder import type_encoding from pyclustering.utils.color import color as color_list from pyclustering.core.wrapper import ccore_library import pyclustering.core.optics_wrapper as wrapper class ordering_visualizer: """! @brief Cluster ordering diagram visualizer that represents dataset graphically as density-based clustering structure. @details This OPTICS algorithm is KD-tree optimized. @see ordering_analyser """ @staticmethod def show_ordering_diagram(analyser, amount_clusters = None): """! @brief Display cluster-ordering (reachability-plot) diagram. @param[in] analyser (ordering_analyser): cluster-ordering analyser whose ordering diagram should be displayed. @param[in] amount_clusters (uint): if it is not 'None' then it displays connectivity radius line that can used for allocation of specified amount of clusters and colorize diagram by corresponding cluster colors. Example demonstrates general abilities of 'ordering_visualizer' class: @code # Display cluster-ordering diagram with connectivity radius is used for allocation of three clusters. ordering_visualizer.show_ordering_diagram(analyser, 3); # Display cluster-ordering diagram without radius. ordering_visualizer.show_ordering_diagram(analyser); @endcode """ ordering = analyser.cluster_ordering axis = plt.subplot(111) if amount_clusters is not None: radius, borders = analyser.calculate_connvectivity_radius(amount_clusters) # divide into cluster groups to visualize by colors left_index_border = 0 current_index_border = 0 for index_border in range(len(borders)): right_index_border = borders[index_border] axis.bar(range(left_index_border, right_index_border), ordering[left_index_border:right_index_border], width = 1.0, color = color_list.TITLES[index_border]) left_index_border = right_index_border current_index_border = index_border axis.bar(range(left_index_border, len(ordering)), ordering[left_index_border:len(ordering)], width = 1.0, color = color_list.TITLES[current_index_border + 1]) plt.xlim([0, len(ordering)]) plt.axhline(y = radius, linewidth = 2, color = 'black') plt.text(0, radius + radius * 0.03, " Radius: " + str(round(radius, 4)) + ";\n Clusters: " + str(amount_clusters), color = 'b', fontsize = 10) else: axis.bar(range(0, len(ordering)), ordering[0:len(ordering)], width = 1.0, color = 'black') plt.xlim([0, len(ordering)]) plt.show() class ordering_analyser: """! @brief Analyser of cluster ordering diagram. @details Using cluster-ordering it is able to connectivity radius for allocation of specified amount of clusters and calculate amount of clusters using specified connectivity radius. Cluster-ordering is formed by OPTICS algorithm during cluster analysis. @see optics """ @property def cluster_ordering(self): """! @brief (list) Returns values of dataset cluster ordering. """ return self.__ordering def __init__(self, ordering_diagram): """! @brief Analyser of ordering diagram that is based on reachability-distances. @see calculate_connvectivity_radius """ self.__ordering = ordering_diagram def __len__(self): """! @brief Returns length of clustering-ordering diagram. """ return len(self.__ordering) def calculate_connvectivity_radius(self, amount_clusters, maximum_iterations = 100): """! @brief Calculates connectivity radius of allocation specified amount of clusters using ordering diagram and marks borders of clusters using indexes of values of ordering diagram. @details Parameter 'maximum_iterations' is used to protect from hanging when it is impossible to allocate specified number of clusters. @param[in] amount_clusters (uint): amount of clusters that should be allocated by calculated connectivity radius. @param[in] maximum_iterations (uint): maximum number of iteration for searching connectivity radius to allocated specified amount of clusters (by default it is restricted by 100 iterations). @return (double, list) Value of connectivity radius and borders of clusters like (radius, borders), radius may be 'None' as well as borders may be '[]' if connectivity radius hasn't been found for the specified amount of iterations. """ maximum_distance = max(self.__ordering) upper_distance = maximum_distance lower_distance = 0.0 result = None amount, borders = self.extract_cluster_amount(maximum_distance) if amount <= amount_clusters: for _ in range(maximum_iterations): radius = (lower_distance + upper_distance) / 2.0 amount, borders = self.extract_cluster_amount(radius) if amount == amount_clusters: result = radius break elif amount == 0: break elif amount > amount_clusters: lower_distance = radius elif amount < amount_clusters: upper_distance = radius return result, borders def extract_cluster_amount(self, radius): """! @brief Obtains amount of clustering that can be allocated by using specified radius for ordering diagram and borders between them. @details When growth of reachability-distances is detected than it is considered as a start point of cluster, than pick is detected and after that recession is observed until new growth (that means end of the current cluster and start of a new one) or end of diagram. @param[in] radius (double): connectivity radius that is used for cluster allocation. @return (unit, list) Amount of clusters that can be allocated by the connectivity radius on ordering diagram and borders between them using indexes from ordering diagram (amount_clusters, border_clusters). """ amount_clusters = 1 cluster_start = False cluster_pick = False total_similarity = True previous_cluster_distance = None previous_distance = None cluster_borders = [] for index_ordering in range(len(self.__ordering)): distance = self.__ordering[index_ordering] if distance >= radius: if cluster_start is False: cluster_start = True amount_clusters += 1 if index_ordering != 0: cluster_borders.append(index_ordering) else: if (distance < previous_cluster_distance) and (cluster_pick is False): cluster_pick = True elif (distance > previous_cluster_distance) and (cluster_pick is True): cluster_pick = False amount_clusters += 1 if index_ordering != 0: cluster_borders.append(index_ordering) previous_cluster_distance = distance else: cluster_start = False cluster_pick = False if (previous_distance is not None) and (distance != previous_distance): total_similarity = False previous_distance = distance if (total_similarity is True) and (previous_distance > radius): amount_clusters = 0 return amount_clusters, cluster_borders class optics_descriptor: """! @brief Object description that used by OPTICS algorithm for cluster analysis. """ def __init__(self, index, core_distance = None, reachability_distance = None): """! @brief Constructor of object description in optics terms. @param[in] index (uint): Index of the object in the data set. @param[in] core_distance (double): Core distance that is minimum distance to specified number of neighbors. @param[in] reachability_distance (double): Reachability distance to this object. """ ## Index of object from the input data. self.index_object = index ## Core distance - the smallest distance to reach specified number of neighbors that is not greater then connectivity radius. self.core_distance = core_distance ## Reachability distance - the smallest distance to be reachable by core object. self.reachability_distance = reachability_distance ## True is object has been already traversed. self.processed = False def __repr__(self): """! @brief Returns string representation of the optics descriptor. """ return '(%s, [c: %s, r: %s])' % (self.index_object, self.core_distance, self.reachability_distance) class optics: """! @brief Class represents clustering algorithm OPTICS (Ordering Points To Identify Clustering Structure) with KD-tree optimization (ccore options is supported). @details OPTICS is a density-based algorithm. Purpose of the algorithm is to provide explicit clusters, but create clustering-ordering representation of the input data. Clustering-ordering information contains information about internal structures of data set in terms of density and proper connectivity radius can be obtained for allocation required amount of clusters using this diagram. In case of usage additional input parameter 'amount of clusters' connectivity radius should be bigger than real - because it will be calculated by the algorithms if requested amount of clusters is not allocated. @image html optics_example_clustering.png "Scheme how does OPTICS works. At the beginning only one cluster is allocated, but two is requested. At the second step OPTICS calculates connectivity radius using cluster-ordering and performs final cluster allocation." Clustering example using sample 'Chainlink': @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Read sample for clustering from some file. sample = read_sample(FCPS_SAMPLES.SAMPLE_CHAINLINK) # Run cluster analysis where connectivity radius is bigger than real. radius = 0.5 neighbors = 3 optics_instance = optics(sample, radius, neighbors) # Performs cluster analysis. optics_instance.process() # Obtain results of clustering. clusters = optics_instance.get_clusters() noise = optics_instance.get_noise() ordering = optics_instance.get_ordering() # Visualize clustering results. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() # Display ordering. analyser = ordering_analyser(ordering) ordering_visualizer.show_ordering_diagram(analyser, 2) @endcode Amount of clusters that should be allocated can be also specified. In this case connectivity radius should be greater than real, for example: @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Read sample for clustering from some file sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # Run cluster analysis where connectivity radius is bigger than real radius = 2.0 neighbors = 3 amount_of_clusters = 3 optics_instance = optics(sample, radius, neighbors, amount_of_clusters) # Performs cluster analysis optics_instance.process() # Obtain results of clustering clusters = optics_instance.get_clusters() noise = optics_instance.get_noise() ordering = optics_instance.get_ordering() # Visualize ordering diagram analyser = ordering_analyser(ordering) ordering_visualizer.show_ordering_diagram(analyser, amount_of_clusters) # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode Here is an example where OPTICS extracts outliers from sample 'Tetra': @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.optics import optics from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Read sample for clustering from some file. sample = read_sample(FCPS_SAMPLES.SAMPLE_TETRA) # Run cluster analysis where connectivity radius is bigger than real. radius = 0.4 neighbors = 3 optics_instance = optics(sample, radius, neighbors) # Performs cluster analysis. optics_instance.process() # Obtain results of clustering. clusters = optics_instance.get_clusters() noise = optics_instance.get_noise() # Visualize clustering results (clusters and outliers). visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(noise, sample, marker='x') visualizer.show() @endcode Visualization result of allocated clusters and outliers is presented on the image below: @image html optics_noise_tetra.png "Clusters and outliers extracted by OPTICS algorithm from sample 'Tetra'." """ def __init__(self, sample, eps, minpts, amount_clusters=None, ccore=True, **kwargs): """! @brief Constructor of clustering algorithm OPTICS. @param[in] sample (list): Input data that is presented as a list of points (objects), where each point is represented by list or tuple. @param[in] eps (double): Connectivity radius between points, points may be connected if distance between them less than the radius. @param[in] minpts (uint): Minimum number of shared neighbors that is required for establishing links between points. @param[in] amount_clusters (uint): Optional parameter where amount of clusters that should be allocated is specified. In case of usage 'amount_clusters' connectivity radius can be greater than real, in other words, there is place for mistake in connectivity radius usage. @param[in] ccore (bool): if True than DLL CCORE (C++ solution) will be used for solving the problem. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'data_type'). Keyword Args:
- data_type (string): Data type of input sample 'data' that is processed by the algorithm ('points', 'distance_matrix'). """ self.__sample_pointer = sample # Algorithm parameter - pointer to sample for processing. self.__eps = eps # Algorithm parameter - connectivity radius between object for establish links between object. self.__minpts = minpts # Algorithm parameter - minimum number of neighbors that is required for establish links between object. self.__amount_clusters = amount_clusters self.__ordering = None self.__clusters = None self.__noise = None self.__optics_objects = None self.__data_type = kwargs.get('data_type', 'points') self.__kdtree = None self.__ccore = ccore self.__neighbor_searcher = self.__create_neighbor_searcher(self.__data_type) if self.__ccore: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of OPTICS algorithm. @return (optics) Returns itself (OPTICS instance). @see get_clusters() @see get_noise() @see get_ordering() """ if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library). """ (self.__clusters, self.__noise, self.__ordering, self.__eps, objects_indexes, objects_core_distances, objects_reachability_distances) = \ wrapper.optics(self.__sample_pointer, self.__eps, self.__minpts, self.__amount_clusters, self.__data_type) self.__optics_objects = [] for i in range(len(objects_indexes)): if objects_core_distances[i] < 0.0: objects_core_distances[i] = None if objects_reachability_distances[i] < 0.0: objects_reachability_distances[i] = None optics_object = optics_descriptor(objects_indexes[i], objects_core_distances[i], objects_reachability_distances[i]) optics_object.processed = True self.__optics_objects.append(optics_object) def __process_by_python(self): """! @brief Performs cluster analysis using python code. """ if self.__data_type == 'points': self.__kdtree = kdtree_balanced(self.__sample_pointer, range(len(self.__sample_pointer))) self.__allocate_clusters() if (self.__amount_clusters is not None) and (self.__amount_clusters != len(self.get_clusters())): analyser = ordering_analyser(self.get_ordering()) radius, _ = analyser.calculate_connvectivity_radius(self.__amount_clusters) if radius is not None: self.__eps = radius self.__allocate_clusters() def __initialize(self, sample): """! @brief Initializes internal states and resets clustering results in line with input sample. """ self.__processed = [False] * len(sample) self.__optics_objects = [optics_descriptor(i) for i in range(len(sample))] # List of OPTICS objects that corresponds to objects from input sample. self.__ordered_database = [] # List of OPTICS objects in traverse order. self.__clusters = None # Result of clustering (list of clusters where each cluster contains indexes of objects from input data). self.__noise = None # Result of clustering (noise). def __allocate_clusters(self): """! @brief Performs cluster allocation and builds ordering diagram that is based on reachability-distances. """ self.__initialize(self.__sample_pointer) for optic_object in self.__optics_objects: if optic_object.processed is False: self.__expand_cluster_order(optic_object) self.__extract_clusters() def get_clusters(self): """! @brief Returns list of allocated clusters, where each cluster contains indexes of objects and each cluster is represented by list. @return (list) List of allocated clusters. @see process() @see get_noise() @see get_ordering() @see get_radius() """ return self.__clusters def get_noise(self): """! @brief Returns list of noise that contains indexes of objects that corresponds to input data. @return (list) List of allocated noise objects. @see process() @see get_clusters() @see get_ordering() @see get_radius() """ return self.__noise def get_ordering(self): """! @brief Returns clustering ordering information about the input data set. @details Clustering ordering of data-set contains the information about the internal clustering structure in line with connectivity radius. @return (ordering_analyser) Analyser of clustering ordering. @see process() @see get_clusters() @see get_noise() @see get_radius() @see get_optics_objects() """ if self.__ordering is None: self.__ordering = [] for cluster in self.__clusters: for index_object in cluster: optics_object = self.__optics_objects[index_object] if optics_object.reachability_distance is not None: self.__ordering.append(optics_object.reachability_distance) return self.__ordering def get_optics_objects(self): """! @brief Returns OPTICS objects where each object contains information about index of point from processed data, core distance and reachability distance. @return (list) OPTICS objects. @see get_ordering() @see get_clusters() @see get_noise() @see optics_descriptor """ return self.__optics_objects def get_radius(self): """! @brief Returns connectivity radius that is calculated and used for clustering by the algorithm. @details Connectivity radius may be changed only in case of usage additional parameter of the algorithm - amount of clusters for allocation. @return (double) Connectivity radius. @see get_ordering() @see get_clusters() @see get_noise() @see get_optics_objects() """ return self.__eps def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __create_neighbor_searcher(self, data_type): """! @brief Returns neighbor searcher in line with data type. @param[in] data_type (string): Data type (points or distance matrix). """ if data_type == 'points': return self.__neighbor_indexes_points elif data_type == 'distance_matrix': return self.__neighbor_indexes_distance_matrix else: raise TypeError("Unknown type of data is specified '%s'" % data_type) def __expand_cluster_order(self, optics_object): """! @brief Expand cluster order from not processed optic-object that corresponds to object from input data. Traverse procedure is performed until objects are reachable from core-objects in line with connectivity radius. Order database is updated during expanding. @param[in] optics_object (optics_descriptor): Object that hasn't been processed. """ optics_object.processed = True neighbors_descriptor = self.__neighbor_searcher(optics_object) optics_object.reachability_distance = None self.__ordered_database.append(optics_object) # Check core distance if len(neighbors_descriptor) >= self.__minpts: neighbors_descriptor.sort(key = lambda obj: obj[1]) optics_object.core_distance = neighbors_descriptor[self.__minpts - 1][1] # Continue processing order_seed = list() self.__update_order_seed(optics_object, neighbors_descriptor, order_seed) while len(order_seed) > 0: optic_descriptor = order_seed[0] order_seed.remove(optic_descriptor) neighbors_descriptor = self.__neighbor_searcher(optic_descriptor) optic_descriptor.processed = True self.__ordered_database.append(optic_descriptor) if len(neighbors_descriptor) >= self.__minpts: neighbors_descriptor.sort(key = lambda obj: obj[1]) optic_descriptor.core_distance = neighbors_descriptor[self.__minpts - 1][1] self.__update_order_seed(optic_descriptor, neighbors_descriptor, order_seed) else: optic_descriptor.core_distance = None else: optics_object.core_distance = None def __extract_clusters(self): """! @brief Extract clusters and noise from order database. """ self.__clusters = [] self.__noise = [] current_cluster = self.__noise for optics_object in self.__ordered_database: if (optics_object.reachability_distance is None) or (optics_object.reachability_distance > self.__eps): if (optics_object.core_distance is not None) and (optics_object.core_distance <= self.__eps): self.__clusters.append([ optics_object.index_object ]) current_cluster = self.__clusters[-1] else: self.__noise.append(optics_object.index_object) else: current_cluster.append(optics_object.index_object) def __update_order_seed(self, optic_descriptor, neighbors_descriptors, order_seed): """! @brief Update sorted list of reachable objects (from core-object) that should be processed using neighbors of core-object. @param[in] optic_descriptor (optics_descriptor): Core-object whose neighbors should be analysed. @param[in] neighbors_descriptors (list): List of neighbors of core-object. @param[in|out] order_seed (list): List of sorted object in line with reachable distance. """ for neighbor_descriptor in neighbors_descriptors: index_neighbor = neighbor_descriptor[0] current_reachable_distance = neighbor_descriptor[1] if self.__optics_objects[index_neighbor].processed is not True: reachable_distance = max(current_reachable_distance, optic_descriptor.core_distance) if self.__optics_objects[index_neighbor].reachability_distance is None: self.__optics_objects[index_neighbor].reachability_distance = reachable_distance # insert element in queue O(n) - worst case. index_insertion = len(order_seed) for index_seed in range(0, len(order_seed)): if reachable_distance < order_seed[index_seed].reachability_distance: index_insertion = index_seed break order_seed.insert(index_insertion, self.__optics_objects[index_neighbor]) else: if reachable_distance < self.__optics_objects[index_neighbor].reachability_distance: self.__optics_objects[index_neighbor].reachability_distance = reachable_distance order_seed.sort(key=lambda obj: obj.reachability_distance) def __neighbor_indexes_points(self, optic_object): """! @brief Return neighbors of the specified object in case of sequence of points. @param[in] optic_object (optics_descriptor): Object for which neighbors should be returned in line with connectivity radius. @return (list) List of indexes of neighbors in line the connectivity radius. """ kdnodes = self.__kdtree.find_nearest_dist_nodes(self.__sample_pointer[optic_object.index_object], self.__eps) return [[node_tuple[1].payload, math.sqrt(node_tuple[0])] for node_tuple in kdnodes if node_tuple[1].payload != optic_object.index_object] def __neighbor_indexes_distance_matrix(self, optic_object): """! @brief Return neighbors of the specified object in case of distance matrix. @param[in] optic_object (optics_descriptor): Object for which neighbors should be returned in line with connectivity radius. @return (list) List of indexes of neighbors in line the connectivity radius. """ distances = self.__sample_pointer[optic_object.index_object] return [[index_neighbor, distances[index_neighbor]] for index_neighbor in range(len(distances)) if ((distances[index_neighbor] <= self.__eps) and (index_neighbor != optic_object.index_object))] def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__sample_pointer) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__sample_pointer)) if self.__eps < 0: raise ValueError("Connectivity radius (current value: '%d') should be greater or equal to 0." % self.__eps) if self.__minpts < 0: raise ValueError("Minimum number of neighbors (current value: '%d') should be greater than 0." % self.__minpts) if (self.__amount_clusters is not None) and (self.__amount_clusters <= 0): raise ValueError("Amount of clusters (current value: '%d') should be greater than 0." % self.__amount_clusters) pyclustering-0.10.1.2/pyclustering/cluster/rock.py000077500000000000000000000216501375753423500222270ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: ROCK @details Implementation based on paper @cite inproceedings::rock::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.encoder import type_encoding from pyclustering.utils import euclidean_distance from pyclustering.core.wrapper import ccore_library import pyclustering.core.rock_wrapper as wrapper class rock: """! @brief The class represents clustering algorithm ROCK. Example: @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.rock import rock from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Read sample for clustering from file. sample = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA) # Create instance of ROCK algorithm for cluster analysis. Seven clusters should be allocated. rock_instance = rock(sample, 1.0, 7) # Run cluster analysis. rock_instance.process() # Obtain results of clustering. clusters = rock_instance.get_clusters() # Visualize clustering results. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode """ def __init__(self, data, eps, number_clusters, threshold=0.5, ccore=True): """! @brief Constructor of clustering algorithm ROCK. @param[in] data (list): Input data - list of points where each point is represented by list of coordinates. @param[in] eps (double): Connectivity radius (similarity threshold), points are neighbors if distance between them is less than connectivity radius. @param[in] number_clusters (uint): Defines number of clusters that should be allocated from the input data set. @param[in] threshold (double): Value that defines degree of normalization that influences on choice of clusters for merging during processing. @param[in] ccore (bool): Defines should be CCORE (C++ pyclustering library) used instead of Python code or not. """ self.__pointer_data = data self.__eps = eps self.__number_clusters = number_clusters self.__threshold = threshold self.__clusters = None self.__ccore = ccore if self.__ccore: self.__ccore = ccore_library.workable() self.__verify_arguments() self.__degree_normalization = 1.0 + 2.0 * ((1.0 - threshold) / (1.0 + threshold)) self.__adjacency_matrix = None self.__create_adjacency_matrix() def process(self): """! @brief Performs cluster analysis in line with rules of ROCK algorithm. @return (rock) Returns itself (ROCK instance). @see get_clusters() """ # TODO: (Not related to specification, just idea) First iteration should be investigated. Euclidean distance should be used for clustering between two # points and rock algorithm between clusters because we consider non-categorical samples. But it is required more investigations. if self.__ccore is True: self.__clusters = wrapper.rock(self.__pointer_data, self.__eps, self.__number_clusters, self.__threshold) else: self.__clusters = [[index] for index in range(len(self.__pointer_data))] while len(self.__clusters) > self.__number_clusters: indexes = self.__find_pair_clusters(self.__clusters) if indexes != [-1, -1]: self.__clusters[indexes[0]] += self.__clusters[indexes[1]] self.__clusters.pop(indexes[1]) # remove merged cluster. else: break # totally separated clusters have been allocated return self def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @return (list) List of allocated clusters, each cluster contains indexes of objects in list of data. @see process() """ return self.__clusters def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __find_pair_clusters(self, clusters): """! @brief Returns pair of clusters that are best candidates for merging in line with goodness measure. The pair of clusters for which the above goodness measure is maximum is the best pair of clusters to be merged. @param[in] clusters (list): List of clusters that have been allocated during processing, each cluster is represented by list of indexes of points from the input data set. @return (list) List that contains two indexes of clusters (from list 'clusters') that should be merged on this step. It can be equals to [-1, -1] when no links between clusters. """ maximum_goodness = 0.0 cluster_indexes = [-1, -1] for i in range(0, len(clusters)): for j in range(i + 1, len(clusters)): goodness = self.__calculate_goodness(clusters[i], clusters[j]) if goodness > maximum_goodness: maximum_goodness = goodness cluster_indexes = [i, j] return cluster_indexes def __calculate_links(self, cluster1, cluster2): """! @brief Returns number of link between two clusters. @details Link between objects (points) exists only if distance between them less than connectivity radius. @param[in] cluster1 (list): The first cluster. @param[in] cluster2 (list): The second cluster. @return (uint) Number of links between two clusters. """ number_links = 0 for index1 in cluster1: for index2 in cluster2: number_links += self.__adjacency_matrix[index1][index2] return number_links def __create_adjacency_matrix(self): """! @brief Creates 2D adjacency matrix (list of lists) where each element described existence of link between points (means that points are neighbors). """ size_data = len(self.__pointer_data) self.__adjacency_matrix = [[0 for i in range(size_data)] for j in range(size_data)] for i in range(0, size_data): for j in range(i + 1, size_data): distance = euclidean_distance(self.__pointer_data[i], self.__pointer_data[j]) if (distance <= self.__eps): self.__adjacency_matrix[i][j] = 1 self.__adjacency_matrix[j][i] = 1 def __calculate_goodness(self, cluster1, cluster2): """! @brief Calculates coefficient 'goodness measurement' between two clusters. The coefficient defines level of suitability of clusters for merging. @param[in] cluster1 (list): The first cluster. @param[in] cluster2 (list): The second cluster. @return Goodness measure between two clusters. """ number_links = self.__calculate_links(cluster1, cluster2) devider = (len(cluster1) + len(cluster2)) ** self.__degree_normalization - len(cluster1) ** self.__degree_normalization - len(cluster2) ** self.__degree_normalization return number_links / devider def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if self.__eps < 0: raise ValueError("Connectivity radius (current value: '%d') should be greater or equal to 0." % self.__eps) if self.__threshold < 0 or self.__threshold > 1: raise ValueError("Threshold (current value: '%d') should be in range (0, 1)." % self.__threshold) if (self.__number_clusters is not None) and (self.__number_clusters <= 0): raise ValueError("Amount of clusters (current value: '%d') should be greater than 0." % self.__number_clusters) pyclustering-0.10.1.2/pyclustering/cluster/silhouette.py000077500000000000000000000516301375753423500234570ustar00rootroot00000000000000"""! @brief Silhouette - method of interpretation and validation of consistency. @details Implementation based on paper @cite article::cluster::silhouette::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from enum import IntEnum import numpy from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.kmedians import kmedians from pyclustering.cluster.kmedoids import kmedoids from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.utils.metric import distance_metric, type_metric from pyclustering.core.wrapper import ccore_library from pyclustering.core.metric_wrapper import metric_wrapper import pyclustering.core.silhouette_wrapper as wrapper class silhouette: """! @brief Represents Silhouette method that is used interpretation and validation of consistency. @details The silhouette value is a measure of how similar an object is to its own cluster compared to other clusters. Be aware that silhouette method is applicable for K algorithm family, such as K-Means, K-Medians, K-Medoids, X-Means, etc., not not applicable for DBSCAN, OPTICS, CURE, etc. The Silhouette value is calculated using following formula: \f[s\left ( i \right )=\frac{ b\left ( i \right ) - a\left ( i \right ) }{ max\left \{ a\left ( i \right ), b\left ( i \right ) \right \}}\f] where \f$a\left ( i \right )\f$ - is average distance from object i to objects in its own cluster, \f$b\left ( i \right )\f$ - is average distance from object i to objects in the nearest cluster (the appropriate among other clusters). Here is an example where Silhouette score is calculated for K-Means's clustering result: @code from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.silhouette import silhouette from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample # Read data 'SampleSimple3' from Simple Sample collection. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Prepare initial centers centers = kmeans_plusplus_initializer(sample, 4).initialize() # Perform cluster analysis kmeans_instance = kmeans(sample, centers) kmeans_instance.process() clusters = kmeans_instance.get_clusters() # Calculate Silhouette score score = silhouette(sample, clusters).process().get_score() @endcode Let's perform clustering of the same sample by K-Means algorithm using different `K` values (2, 4, 6 and 8) and estimate clustering results using Silhouette method. @code from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.silhouette import silhouette from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample import matplotlib.pyplot as plt def get_score(sample, amount_clusters): # Prepare initial centers for K-Means algorithm. centers = kmeans_plusplus_initializer(sample, amount_clusters).initialize() # Perform cluster analysis. kmeans_instance = kmeans(sample, centers) kmeans_instance.process() clusters = kmeans_instance.get_clusters() # Calculate Silhouette score. return silhouette(sample, clusters).process().get_score() def draw_score(figure, position, title, score): ax = figure.add_subplot(position) ax.bar(range(0, len(score)), score, width=0.7) ax.set_title(title) ax.set_xlim(0, len(score)) ax.set_xticklabels([]) ax.grid() # Read data 'SampleSimple3' from Simple Sample collection. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Perform cluster analysis and estimation by Silhouette. score_2 = get_score(sample, 2) # K = 2 (amount of clusters). score_4 = get_score(sample, 4) # K = 4 - optimal. score_6 = get_score(sample, 6) # K = 6. score_8 = get_score(sample, 8) # K = 8. # Visualize results. figure = plt.figure() # Visualize each result separately. draw_score(figure, 221, 'K = 2', score_2) draw_score(figure, 222, 'K = 4 (optimal)', score_4) draw_score(figure, 223, 'K = 6', score_6) draw_score(figure, 224, 'K = 8', score_8) # Show a plot with visualized results. plt.show() @endcode There is visualized results that were done by Silhouette method. `K = 4` is the optimal amount of clusters in line with Silhouette method because the score for each point is close to `1.0` and the average score for `K = 4` is biggest value among others `K`. @image html silhouette_score_for_various_K.png "Fig. 1. Silhouette scores for various K." @see kmeans, kmedoids, kmedians, xmeans, elbow """ def __init__(self, data, clusters, **kwargs): """! @brief Initializes Silhouette method for analysis. @param[in] data (array_like): Input data that was used for cluster analysis and that is presented as list of points or distance matrix (defined by parameter 'data_type', by default data is considered as a list of points). @param[in] clusters (list): Clusters that have been obtained after cluster analysis. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric'). Keyword Args:
- metric (distance_metric): Metric that was used for cluster analysis and should be used for Silhouette score calculation (by default Square Euclidean distance). - data_type (string): Data type of input sample 'data' that is processed by the algorithm ('points', 'distance_matrix'). - ccore (bool): If True then CCORE (C++ implementation of pyclustering library) is used (by default True). """ self.__data = data self.__clusters = clusters self.__metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) self.__data_type = kwargs.get('data_type', 'points') if self.__metric.get_type() != type_metric.USER_DEFINED: self.__metric.enable_numpy_usage() else: self.__metric.disable_numpy_usage() self.__score = [0.0] * len(data) self.__ccore = kwargs.get('ccore', True) and self.__metric.get_type() != type_metric.USER_DEFINED if self.__ccore: self.__ccore = ccore_library.workable() if self.__ccore is False: self.__data = numpy.array(data) self.__verify_arguments() def process(self): """! @brief Calculates Silhouette score for each object from input data. @return (silhouette) Instance of the method (self). """ if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs processing using CCORE (C/C++ part of pyclustering library). """ ccore_metric = metric_wrapper.create_instance(self.__metric) self.__score = wrapper.silhoeutte(self.__data, self.__clusters, ccore_metric.get_pointer(), self.__data_type) def __process_by_python(self): """! @brief Performs processing using python code. """ for index_cluster in range(len(self.__clusters)): for index_point in self.__clusters[index_cluster]: self.__score[index_point] = self.__calculate_score(index_point, index_cluster) def get_score(self): """! @brief Returns Silhouette score for each object from input data. @see process """ return self.__score def __calculate_score(self, index_point, index_cluster): """! @brief Calculates Silhouette score for the specific object defined by index_point. @param[in] index_point (uint): Index point from input data for which Silhouette score should be calculated. @param[in] index_cluster (uint): Index cluster to which the point belongs to. @return (float) Silhouette score for the object. """ if self.__data_type == 'points': difference = self.__calculate_dataset_difference(index_point) else: difference = self.__data[index_point] a_score = self.__calculate_within_cluster_score(index_cluster, difference) b_score = self.__caclulate_optimal_neighbor_cluster_score(index_cluster, difference) return (b_score - a_score) / max(a_score, b_score) def __calculate_within_cluster_score(self, index_cluster, difference): """! @brief Calculates 'A' score for the specific object in cluster to which it belongs to. @param[in] index_point (uint): Index point from input data for which 'A' score should be calculated. @param[in] index_cluster (uint): Index cluster to which the point is belong to. @return (float) 'A' score for the object. """ score = self.__calculate_cluster_difference(index_cluster, difference) if len(self.__clusters[index_cluster]) == 1: return float('nan') return score / (len(self.__clusters[index_cluster]) - 1) def __calculate_cluster_score(self, index_cluster, difference): """! @brief Calculates 'B*' score for the specific object for specific cluster. @param[in] index_point (uint): Index point from input data for which 'B*' score should be calculated. @param[in] index_cluster (uint): Index cluster to which the point is belong to. @return (float) 'B*' score for the object for specific cluster. """ score = self.__calculate_cluster_difference(index_cluster, difference) return score / len(self.__clusters[index_cluster]) def __caclulate_optimal_neighbor_cluster_score(self, index_cluster, difference): """! @brief Calculates 'B' score for the specific object for the nearest cluster. @param[in] index_point (uint): Index point from input data for which 'B' score should be calculated. @param[in] index_cluster (uint): Index cluster to which the point is belong to. @return (float) 'B' score for the object. """ optimal_score = float('inf') for index_neighbor_cluster in range(len(self.__clusters)): if index_cluster != index_neighbor_cluster: candidate_score = self.__calculate_cluster_score(index_neighbor_cluster, difference) if candidate_score < optimal_score: optimal_score = candidate_score if optimal_score == float('inf'): optimal_score = -1.0 return optimal_score def __calculate_cluster_difference(self, index_cluster, difference): """! @brief Calculates distance from each object in specified cluster to specified object. @param[in] index_point (uint): Index point for which difference is calculated. @return (list) Distance from specified object to each object from input data in specified cluster. """ cluster_difference = 0.0 for index_point in self.__clusters[index_cluster]: cluster_difference += difference[index_point] return cluster_difference def __calculate_dataset_difference(self, index_point): """! @brief Calculate distance from each object to specified object. @param[in] index_point (uint): Index point for which difference with other points is calculated. @return (list) Distance to each object from input data from the specified. """ if self.__metric.get_type() != type_metric.USER_DEFINED: dataset_differences = self.__metric(self.__data, self.__data[index_point]) else: dataset_differences = [self.__metric(point, self.__data[index_point]) for point in self.__data] return dataset_differences def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data)) if len(self.__clusters) == 0: raise ValueError("Input clusters are empty (size: '%d')." % len(self.__clusters)) class silhouette_ksearch_type(IntEnum): """! @brief Defines algorithms that can be used to find optimal number of cluster using Silhouette method. @see silhouette_ksearch """ ## K-Means algorithm for searching optimal number of clusters. KMEANS = 0 ## K-Medians algorithm for searching optimal number of clusters. KMEDIANS = 1 ## K-Medoids algorithm for searching optimal number of clusters. KMEDOIDS = 2 def get_type(self): """! @brief Returns algorithm type that corresponds to specified enumeration value. @return (type) Algorithm type for cluster analysis. """ if self == silhouette_ksearch_type.KMEANS: return kmeans elif self == silhouette_ksearch_type.KMEDIANS: return kmedians elif self == silhouette_ksearch_type.KMEDOIDS: return kmedoids else: return None class silhouette_ksearch: """! @brief Represent algorithm for searching optimal number of clusters using specified K-algorithm (K-Means, K-Medians, K-Medoids) that is based on Silhouette method. @details This algorithm uses average value of scores for estimation and applicable for clusters that are well separated. Here is an example where clusters are well separated (sample 'Hepta'): @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.silhouette import silhouette_ksearch_type, silhouette_ksearch from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample sample = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA) search_instance = silhouette_ksearch(sample, 2, 10, algorithm=silhouette_ksearch_type.KMEANS).process() amount = search_instance.get_amount() scores = search_instance.get_scores() print("Scores: '%s'" % str(scores)) initial_centers = kmeans_plusplus_initializer(sample, amount).initialize() kmeans_instance = kmeans(sample, initial_centers).process() clusters = kmeans_instance.get_clusters() visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode Obtained Silhouette scores for each K: @code Scores: '{2: 0.418434, 3: 0.450906, 4: 0.534709, 5: 0.689970, 6: 0.588460, 7: 0.882674, 8: 0.804725, 9: 0.780189}' @endcode K = 7 has the bigger average Silhouette score and it means that it is optimal amount of clusters: @image html silhouette_ksearch_hepta.png "Silhouette ksearch's analysis with further K-Means clustering (sample 'Hepta')." @see silhouette_ksearch_type """ def __init__(self, data, kmin, kmax, **kwargs): """! @brief Initialize Silhouette search algorithm to find out optimal amount of clusters. @param[in] data (array_like): Input data that is used for searching optimal amount of clusters. @param[in] kmin (uint): Minimum amount of clusters that might be allocated. Should be equal or greater than `2`. @param[in] kmax (uint): Maximum amount of clusters that might be allocated. Should be equal or less than amount of points in input data. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `algorithm`, `random_state`). Keyword Args:
- algorithm (silhouette_ksearch_type): Defines algorithm that is used for searching optimal number of clusters (by default K-Means). - ccore (bool): If True then CCORE (C++ implementation of pyclustering library) is used (by default True). """ self.__data = data self.__kmin = kmin self.__kmax = kmax self.__algorithm = kwargs.get('algorithm', silhouette_ksearch_type.KMEANS) self.__random_state = kwargs.get('random_state', None) self.__return_index = self.__algorithm == silhouette_ksearch_type.KMEDOIDS self.__amount = -1 self.__score = -1.0 self.__scores = {} self.__verify_arguments() self.__ccore = kwargs.get('ccore', True) if self.__ccore: self.__ccore = ccore_library.workable() def process(self): """! @brief Performs analysis to find optimal amount of clusters. @see get_amount, get_score, get_scores @return (silhouette_search) Itself instance (silhouette_search) """ if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs processing using CCORE (C/C++ part of pyclustering library). """ results = wrapper.silhoeutte_ksearch(self.__data, self.__kmin, self.__kmax, self.__algorithm, self.__random_state) self.__amount = results[0] self.__score = results[1] scores_list = results[2] self.__scores = {} for i in range(len(scores_list)): self.__scores[self.__kmin + i] = scores_list[i] def __process_by_python(self): """! @brief Performs processing using python code. """ self.__scores = {} for k in range(self.__kmin, self.__kmax): clusters = self.__calculate_clusters(k) if len(clusters) != k: self.__scores[k] = float('nan') continue score = silhouette(self.__data, clusters).process().get_score() self.__scores[k] = sum(score) / len(score) if self.__scores[k] > self.__score: self.__score = self.__scores[k] self.__amount = k def get_amount(self): """! @brief Returns optimal amount of clusters that has been found during analysis. @return (uint) Optimal amount of clusters. @see process """ return self.__amount def get_score(self): """! @brief Returns silhouette score that belongs to optimal amount of clusters (k). @return (float) Score that belong to optimal amount of clusters. @see process, get_scores """ return self.__score def get_scores(self): """! @brief Returns silhouette score for each K value (amount of clusters). @return (dict) Silhouette score for each K value, where key is a K value and value is a silhouette score. @see process, get_score """ return self.__scores def __calculate_clusters(self, k): """! @brief Performs cluster analysis using specified K value. @param[in] k (uint): Amount of clusters that should be allocated. @return (array_like) Allocated clusters. """ initial_values = kmeans_plusplus_initializer(self.__data, k, random_state=self.__random_state).initialize(return_index=self.__return_index) algorithm_type = self.__algorithm.get_type() return algorithm_type(self.__data, initial_values).process().get_clusters() def __verify_arguments(self): """! @brief Checks algorithm's arguments and if some of them is incorrect then exception is thrown. """ if self.__kmax > len(self.__data): raise ValueError("K max value '" + str(self.__kmax) + "' is bigger than amount of objects '" + str(len(self.__data)) + "' in input data.") if self.__kmin <= 1: raise ValueError("K min value '" + str(self.__kmin) + "' should be greater than 1 (impossible to provide " "silhouette score for only one cluster).") pyclustering-0.10.1.2/pyclustering/cluster/somsc.py000077500000000000000000000132241375753423500224130ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: SOM-SC (Self-Organized Feature Map for Simple Clustering) @details There is no paper on which implementation is based. Algorithm SOM-SC is adaptation of SOM for cluster analysis in simple way. Basic idea: amount of cluster that should be allocated is defines amount of neurons in the self-organized map. SOM-SC can be considered as neural network implementation of K-Means algorithm. Implementation based on paper @cite article::nnet::som::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import ccore_library from pyclustering.cluster.encoder import type_encoding from pyclustering.nnet.som import som, som_parameters from pyclustering.nnet.som import type_conn class somsc: """! @brief Class represents a simple clustering algorithm based on the self-organized feature map. @details This algorithm uses amount of clusters that should be allocated as a size of SOM map. Captured objects by neurons are considered as clusters. The algorithm is designed to process data with Gaussian distribution that has spherical forms. Example: @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.somsc import somsc from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Create instance of SOM-SC algorithm to allocated two clusters somsc_instance = somsc(sample, 2) # Run cluster analysis and obtain results somsc_instance.process() clusters = somsc_instance.get_clusters() # Visualize clustering results. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode """ def __init__(self, data, amount_clusters, epouch=100, ccore=True, **kwargs): """! @brief Creates SOM-SC (Self Organized Map for Simple Clustering) algorithm for clustering analysis. @param[in] data (list): List of points that are used for processing. @param[in] amount_clusters (uint): Amount of clusters that should be allocated. @param[in] epouch (uint): Number of epochs for training of SOM. @param[in] ccore (bool): If it is True then CCORE implementation will be used for clustering analysis. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `random_state`). Keyword Args:
- random_state (int): Seed for random state (by default is `None`, current system time is used). """ self.__data_pointer = data self.__amount_clusters = amount_clusters self.__epouch = epouch self.__ccore = ccore self.__random_state = kwargs.get('random_state', None) self.__network = None if self.__ccore is True: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis by competition between neurons in self-organized map. @return (somsc) Returns itself (SOM Simple Clustering instance). @see get_clusters() """ params = som_parameters() params.random_state = self.__random_state self.__network = som(1, self.__amount_clusters, type_conn.grid_four, params, self.__ccore) self.__network.train(self.__data_pointer, self.__epouch, True) return self def predict(self, points): """! @brief Calculates the closest cluster to each point. @param[in] points (array_like): Points for which closest clusters are calculated. @return (list) List of closest clusters for each point. Each cluster is denoted by index. Return empty collection if 'process()' method was not called. """ result = [] for point in points: index_cluster = self.__network.simulate(point) result.append(index_cluster) return result def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @see process() """ return self.__network.capture_objects def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__data_pointer) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__data_pointer)) if self.__amount_clusters <= 0: raise ValueError("Amount of clusters (current value: '%d') should be greater than 0." % self.__amount_clusters) if self.__epouch < 0: raise ValueError("Amount of epouch (current value: '%d') should be greater or equal to 0." % self.__epouch) pyclustering-0.10.1.2/pyclustering/cluster/syncnet.py000077500000000000000000000414111375753423500227510ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: Sync @details Implementation based on paper @cite article::syncnet::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import matplotlib.pyplot as plt import matplotlib.animation as animation from pyclustering.cluster.encoder import type_encoding from pyclustering.cluster import cluster_visualizer from pyclustering.core.syncnet_wrapper import syncnet_create_network, syncnet_process, syncnet_destroy_network, syncnet_analyser_destroy from pyclustering.core.sync_wrapper import sync_connectivity_matrix from pyclustering.core.wrapper import ccore_library from pyclustering.nnet.sync import sync_dynamic, sync_network, sync_visualizer from pyclustering.nnet import conn_represent, initial_type, conn_type, solve_type from pyclustering.utils import euclidean_distance class syncnet_analyser(sync_dynamic): """! @brief Performs analysis of output dynamic of the oscillatory network syncnet to extract information about cluster allocation. """ def __init__(self, phase, time, pointer_sync_analyser): """! @brief Constructor of the analyser. @param[in] phase (list): Output dynamic of the oscillatory network, where one iteration consists of all phases of oscillators. @param[in] time (list): Simulation time. @param[in] pointer_sync_analyser (POINTER): Pointer to CCORE analyser, if specified then other arguments can be omitted. """ super().__init__(phase, time, pointer_sync_analyser) def __del__(self): """! @brief Desctructor of the analyser. """ if self._ccore_sync_dynamic_pointer is not None: syncnet_analyser_destroy(self._ccore_sync_dynamic_pointer) self._ccore_sync_dynamic_pointer = None def allocate_clusters(self, eps = 0.01, indexes = None, iteration = None): """! @brief Returns list of clusters in line with state of oscillators (phases). @param[in] eps (double): Tolerance that defines the maximum difference between phases of oscillators that belong to one cluster. @param[in] indexes (list): List of real object indexes and it should be equal to amount of oscillators (in case of 'None' - indexes are in range [0; amount_oscillators]). @param[in] iteration (uint): Iteration of simulation that should be used for allocation. @return (list) List of clusters, for example [ [cluster1], [cluster2], ... ].) """ return self.allocate_sync_ensembles(eps, indexes, iteration) def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION class syncnet_visualizer(sync_visualizer): """! @brief Visualizer of output dynamic of oscillatory network 'syncnet' for cluster analysis. """ @staticmethod def animate_cluster_allocation(dataset, analyser, animation_velocity=75, tolerance=0.1, save_movie=None, title=None): """! @brief Shows animation of output dynamic (output of each oscillator) during simulation on a circle from [0; 2pi]. @param[in] dataset (list): Input data that was used for processing by the network. @param[in] analyser (syncnet_analyser): Output dynamic analyser of the Sync network. @param[in] animation_velocity (uint): Interval between frames in milliseconds. @param[in] tolerance (double): Tolerance level that define maximal difference between phases of oscillators in one cluster. @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. @param[in] title (string): If it is specified then title will be displayed on the animation plot. """ figure = plt.figure() def init_frame(): return frame_generation(0) def frame_generation(index_dynamic): figure.clf() if title is not None: figure.suptitle(title, fontsize = 26, fontweight = 'bold') ax1 = figure.add_subplot(121, projection='polar') clusters = analyser.allocate_clusters(eps = tolerance, iteration = index_dynamic) dynamic = analyser.output[index_dynamic] visualizer = cluster_visualizer(size_row = 2) visualizer.append_clusters(clusters, dataset) artist1, = ax1.plot(dynamic, [1.0] * len(dynamic), marker='o', color='blue', ls='') visualizer.show(figure, display = False) artist2 = figure.gca() return [ artist1, artist2 ] cluster_animation = animation.\ FuncAnimation(figure, frame_generation, len(analyser), interval=animation_velocity, init_func=init_frame, repeat_delay=5000) if save_movie is not None: # plt.rcParams['animation.ffmpeg_path'] = 'D:\\Program Files\\ffmpeg-3.3.1-win64-static\\bin\\ffmpeg.exe'; # ffmpeg_writer = animation.FFMpegWriter(fps = 15); # cluster_animation.save(save_movie, writer = ffmpeg_writer); cluster_animation.save(save_movie, writer='ffmpeg', fps=15, bitrate=1500) else: plt.show() class syncnet(sync_network): """! @brief Class represents clustering algorithm SyncNet. @details SyncNet is bio-inspired algorithm that is based on oscillatory network that uses modified Kuramoto model. Each attribute of a data object is considered as a phase oscillator. Example: @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.syncnet import syncnet, solve_type from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample # Read sample for clustering from some file. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Create oscillatory network with connectivity radius 1.0. network = syncnet(sample, 1.0) # Run cluster analysis and collect output dynamic of the oscillatory network. # Network simulation is performed by Runge Kutta 4. analyser = network.process(0.998, solve_type.RK4) # Show oscillatory network. network.show_network() # Obtain clustering results. clusters = analyser.allocate_clusters() # Visualize clustering results. visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.show() @endcode """ def __init__(self, sample, radius, conn_repr=conn_represent.MATRIX, initial_phases=initial_type.RANDOM_GAUSSIAN, enable_conn_weight=False, ccore=True): """! @brief Contructor of the oscillatory network SYNC for cluster analysis. @param[in] sample (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] radius (double): Connectivity radius between points, points should be connected if distance between them less then the radius. @param[in] conn_repr (conn_represent): Internal representation of connection in the network: matrix or list. Ignored in case of usage of CCORE library. @param[in] initial_phases (initial_type): Type of initialization of initial phases of oscillators (random, uniformly distributed, etc.). @param[in] enable_conn_weight (bool): If True - enable mode when strength between oscillators depends on distance between two oscillators. If False - all connection between oscillators have the same strength that equals to 1 (True). @param[in] ccore (bool): Defines should be CCORE C++ library used instead of Python code or not. """ self._ccore_network_pointer = None self._osc_loc = sample self._num_osc = len(sample) self._verify_arguments() if (ccore is True) and ccore_library.workable(): self._ccore_network_pointer = syncnet_create_network(sample, radius, initial_phases, enable_conn_weight) # Default representation that is returned by CCORE is matrix. self._conn_represent = conn_represent.MATRIX else: super().__init__(len(sample), 1, 0, conn_type.DYNAMIC, conn_repr, initial_phases, False) self._conn_weight = None self._ena_conn_weight = enable_conn_weight # Create connections. if radius is not None: self._create_connections(radius) def __del__(self): """! @brief Destructor of oscillatory network is based on Kuramoto model. """ if self._ccore_network_pointer is not None: syncnet_destroy_network(self._ccore_network_pointer) self._ccore_network_pointer = None def _verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if self._num_osc <= 0: raise ValueError("Input data is empty (size: '%d')." % self._num_osc) def _create_connections(self, radius): """! @brief Create connections between oscillators in line with input radius of connectivity. @param[in] radius (double): Connectivity radius between oscillators. """ if self._ena_conn_weight is True: self._conn_weight = [[0] * self._num_osc for _ in range(0, self._num_osc, 1)] maximum_distance = 0 minimum_distance = float('inf') # Create connections for i in range(0, self._num_osc, 1): for j in range(i + 1, self._num_osc, 1): dist = euclidean_distance(self._osc_loc[i], self._osc_loc[j]) if self._ena_conn_weight is True: self._conn_weight[i][j] = dist self._conn_weight[j][i] = dist if (dist > maximum_distance): maximum_distance = dist if (dist < minimum_distance): minimum_distance = dist if dist <= radius: self.set_connection(i, j) if self._ena_conn_weight is True: multiplier = 1 subtractor = 0 if maximum_distance != minimum_distance: multiplier = (maximum_distance - minimum_distance) subtractor = minimum_distance for i in range(0, self._num_osc, 1): for j in range(i + 1, self._num_osc, 1): value_conn_weight = (self._conn_weight[i][j] - subtractor) / multiplier self._conn_weight[i][j] = value_conn_weight self._conn_weight[j][i] = value_conn_weight def process(self, order = 0.998, solution=solve_type.FAST, collect_dynamic=True): """! @brief Peforms cluster analysis using simulation of the oscillatory network. @param[in] order (double): Order of synchronization that is used as indication for stopping processing. @param[in] solution (solve_type): Specified type of solving diff. equation. @param[in] collect_dynamic (bool): Specified requirement to collect whole dynamic of the network. @return (syncnet_analyser) Returns analyser of results of clustering. """ if self._ccore_network_pointer is not None: pointer_output_dynamic = syncnet_process(self._ccore_network_pointer, order, solution, collect_dynamic) return syncnet_analyser(None, None, pointer_output_dynamic) else: output_sync_dynamic = self.simulate_dynamic(order, solution, collect_dynamic) return syncnet_analyser(output_sync_dynamic.output, output_sync_dynamic.time, None) def _phase_kuramoto(self, teta, t, argv): """! @brief Overrided method for calculation of oscillator phase. @param[in] teta (double): Current value of phase. @param[in] t (double): Time (can be ignored). @param[in] argv (uint): Index of oscillator whose phase represented by argument teta. @return (double) New value of phase of oscillator with index 'argv'. """ index = argv # index of oscillator phase = 0.0 # phase of a specified oscillator that will calculated in line with current env. states. neighbors = self.get_neighbors(index) for k in neighbors: conn_weight = 1.0 if self._ena_conn_weight is True: conn_weight = self._conn_weight[index][k] phase += conn_weight * self._weight * math.sin(self._phases[k] - teta) divider = len(neighbors) if divider == 0: divider = 1.0 return self._freq[index] + (phase / divider) def show_network(self): """! @brief Shows connections in the network. It supports only 2-d and 3-d representation. """ if (self._ccore_network_pointer is not None) and (self._osc_conn is None): self._osc_conn = sync_connectivity_matrix(self._ccore_network_pointer) dimension = len(self._osc_loc[0]) if (dimension != 3) and (dimension != 2): raise NameError('Network that is located in different from 2-d and 3-d dimensions can not be represented'); from matplotlib.font_manager import FontProperties from matplotlib import rcParams rcParams['font.sans-serif'] = ['Arial'] rcParams['font.size'] = 12 fig = plt.figure() axes = None if dimension == 2: axes = fig.add_subplot(111) elif dimension == 3: axes = fig.gca(projection='3d') surface_font = FontProperties() surface_font.set_name('Arial') surface_font.set_size('12') for i in range(0, self._num_osc, 1): if dimension == 2: axes.plot(self._osc_loc[i][0], self._osc_loc[i][1], 'bo') if self._conn_represent == conn_represent.MATRIX: for j in range(i, self._num_osc, 1): # draw connection between two points only one time if self.has_connection(i, j) is True: axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], 'b-', linewidth = 0.5) else: for j in self.get_neighbors(i): if (self.has_connection(i, j) is True) and (i > j): # draw connection between two points only one time axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], 'b-', linewidth = 0.5) elif dimension == 3: axes.scatter(self._osc_loc[i][0], self._osc_loc[i][1], self._osc_loc[i][2], c = 'b', marker = 'o') if self._conn_represent == conn_represent.MATRIX: for j in range(i, self._num_osc, 1): # draw connection between two points only one time if self.has_connection(i, j) is True: axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], [self._osc_loc[i][2], self._osc_loc[j][2]], 'b-', linewidth = 0.5) else: for j in self.get_neighbors(i): if (self.has_connection(i, j) == True) and (i > j): # draw connection between two points only one time axes.plot([self._osc_loc[i][0], self._osc_loc[j][0]], [self._osc_loc[i][1], self._osc_loc[j][1]], [self._osc_loc[i][2], self._osc_loc[j][2]], 'b-', linewidth = 0.5) plt.grid() plt.show()pyclustering-0.10.1.2/pyclustering/cluster/syncsom.py000077500000000000000000000220231375753423500227570ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: SYNC-SOM @details Implementation based on paper @cite article::syncsom::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.encoder import type_encoding from pyclustering.cluster.syncnet import syncnet from pyclustering.nnet.som import som, type_conn from pyclustering.nnet import initial_type from pyclustering.utils import euclidean_distance_square class syncsom: """! @brief Class represents clustering algorithm SYNC-SOM. SYNC-SOM is bio-inspired algorithm that is based on oscillatory network that uses self-organized feature map as the first layer. Example: @code # read sample for clustering sample = read_sample(file); # create oscillatory network for cluster analysis where the first layer has # size 10x10 and connectivity radius for objects 1.0. network = syncsom(sample, 10, 10, 1.0); # simulate network (perform cluster analysis) and collect output dynamic (dyn_time, dyn_phase) = network.process(True, 0.998); # obtain encoded clusters encoded_clusters = network.get_som_clusters(); # obtain real clusters clusters = network.get_clusters(); # show the first layer of the network network.show_som_layer(); # show the second layer of the network network.show_sync_layer(); @endcode """ @property def som_layer(self): """! @brief The first layer of the oscillatory network - self-organized feature map. """ return self._som @property def sync_layer(self): """! @brief The second layer of the oscillatory network based on Kuramoto model. """ return self._sync def __init__(self, data, rows, cols, radius): """! @brief Constructor of the double layer oscillatory network SYNC-SOM. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] rows (uint): Rows of neurons (number of neurons in column) in the input layer (self-organized feature map). @param[in] cols (uint): Columns of neurons (number of neurons in row) in the input later (self-organized feature map). @param[in] radius (double): Connectivity radius between objects that defines connection between oscillators in the second layer. """ self._data = data self._radius = radius * radius self._som = som(rows, cols, conn_type=type_conn.grid_four, ccore=False) # The first (input) later - SOM layer. self._som_osc_table = list() self._sync = None # The second (output) layer - Sync layer. self._struct = None # Structure of connections between oscillators in the second layer - Sync layer. # For convenience self._analyser = None def process(self, collect_dynamic=False, order=0.999): """! @brief Performs simulation of the oscillatory network. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @param[in] order (double): Order of process synchronization that should be considered as end of clustering, destributed 0..1. @return (tuple) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see get_som_clusters() @see get_clusters() """ # train self-organization map. self._som.train(self._data, 100) # prepare to build list. weights = list() self._som_osc_table.clear() # must be cleared, if it's used before. for i in range(self._som.size): if self._som.awards[i] > 0: weights.append(self._som.weights[i]) self._som_osc_table.append(i) # create oscillatory neural network. self._sync = self.__create_sync_layer(weights) self._analyser = self._sync.process(order, collect_dynamic=collect_dynamic) return self._analyser.time, self._analyser.output def __create_sync_layer(self, weights): """! @brief Creates second layer of the network. @param[in] weights (list): List of weights of SOM neurons. @return (syncnet) Second layer of the network. """ sync_layer = syncnet(weights, 0.0, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore=False) for oscillator_index1 in range(0, len(sync_layer)): for oscillator_index2 in range(oscillator_index1 + 1, len(sync_layer)): if self.__has_object_connection(oscillator_index1, oscillator_index2): sync_layer.set_connection(oscillator_index1, oscillator_index2) return sync_layer def __has_object_connection(self, oscillator_index1, oscillator_index2): """! @brief Searches for pair of objects that are encoded by specified neurons and that are connected in line with connectivity radius. @param[in] oscillator_index1 (uint): Index of the first oscillator in the second layer. @param[in] oscillator_index2 (uint): Index of the second oscillator in the second layer. @return (bool) True - if there is pair of connected objects encoded by specified oscillators. """ som_neuron_index1 = self._som_osc_table[oscillator_index1] som_neuron_index2 = self._som_osc_table[oscillator_index2] for index_object1 in self._som.capture_objects[som_neuron_index1]: for index_object2 in self._som.capture_objects[som_neuron_index2]: distance = euclidean_distance_square(self._data[index_object1], self._data[index_object2]) if distance <= self._radius: return True return False def get_som_clusters(self): """! @brief Returns clusters with SOM neurons that encode input features in line with result of synchronization in the second (Sync) layer. @return (list) List of clusters that are represented by lists of indexes of neurons that encode input data. @see process() @see get_clusters() """ sync_clusters = self._analyser.allocate_clusters() # Decode it to indexes of SOM neurons som_clusters = list() for oscillators in sync_clusters: cluster = list() for index_oscillator in oscillators: index_neuron = self._som_osc_table[index_oscillator] cluster.append(index_neuron) som_clusters.append(cluster) return som_clusters def get_clusters(self, eps=0.1): """! @brief Returns clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @param[in] eps (double): Maximum error for allocation of synchronous ensemble oscillators. @return (list) List of grours (lists) of indexes of synchronous oscillators that corresponds to index of objects. @see process() @see get_som_clusters() """ sync_clusters = self._analyser.allocate_clusters(eps) # it isn't indexes of SOM neurons clusters = list() for oscillators in sync_clusters: cluster = list() for index_oscillator in oscillators: index_neuron = self._som_osc_table[index_oscillator] cluster += self._som.capture_objects[index_neuron] clusters.append(cluster) return clusters def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def show_som_layer(self): """! @brief Shows visual representation of the first (SOM) layer. """ self._som.show_network() def show_sync_layer(self): """! @brief Shows visual representation of the second (Sync) layer. """ self._sync.show_network() pyclustering-0.10.1.2/pyclustering/cluster/tests/000077500000000000000000000000001375753423500220525ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/cluster/tests/__init__.py000077500000000000000000000015501375753423500241670ustar00rootroot00000000000000"""! @brief Test runner for integration tests and unit-tests for cluster analysis module @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.integration import clustering_integration_tests from pyclustering.cluster.tests.unit import clustering_unit_tests class clustering_tests(suite_holder): def __init__(self): super().__init__() clustering_integration_tests.fill_suite(self.get_suite()) clustering_unit_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(cluster_suite): clustering_integration_tests.fill_suite(cluster_suite) clustering_unit_tests.fill_suite(cluster_suite) pyclustering-0.10.1.2/pyclustering/cluster/tests/agglomerative_templates.py000077500000000000000000000047571375753423500273500ustar00rootroot00000000000000"""! @brief Test templates for agglomerative clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.agglomerative import agglomerative; from pyclustering.utils import read_sample; from random import random; class AgglomerativeTestTemplates: @staticmethod def templateClusteringResults(path, number_clusters, link, expected_length_clusters, ccore_flag): sample = read_sample(path) agglomerative_instance = agglomerative(sample, number_clusters, link, ccore_flag) agglomerative_instance.process() clusters = agglomerative_instance.get_clusters() assert sum([len(cluster) for cluster in clusters]) == len(sample); assert sum([len(cluster) for cluster in clusters]) == sum(expected_length_clusters); assert sorted([len(cluster) for cluster in clusters]) == expected_length_clusters; @staticmethod def templateClusterAllocationOneDimensionData(link, ccore_flag): input_data = [ [random()] for i in range(10) ] + [ [random() + 3] for i in range(10) ] + [ [random() + 5] for i in range(10) ] + [ [random() + 8] for i in range(10) ] agglomerative_instance = agglomerative(input_data, 4, link, ccore_flag) agglomerative_instance.process() clusters = agglomerative_instance.get_clusters() assert len(clusters) == 4; for cluster in clusters: assert len(cluster) == 10; @staticmethod def templateClusterAllocationTheSameObjects(number_objects, number_clusters, link, ccore_flag): input_data = [ [random()] ] * number_objects agglomerative_instance = agglomerative(input_data, number_clusters, link, ccore_flag) agglomerative_instance.process() clusters = agglomerative_instance.get_clusters() assert len(clusters) == number_clusters; object_mark = [False] * number_objects allocated_number_objects = 0 for cluster in clusters: for index_object in cluster: assert (object_mark[index_object] == False); # one object can be in only one cluster. object_mark[index_object] = True allocated_number_objects += 1 assert (number_objects == allocated_number_objects); # number of allocated objects should be the same. pyclustering-0.10.1.2/pyclustering/cluster/tests/bang_templates.py000077500000000000000000000067311375753423500254230ustar00rootroot00000000000000"""! @brief Test templates for BANG algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.assertion import assertion from pyclustering.cluster.bang import bang, bang_visualizer, bang_animator from pyclustering.utils import read_sample class bang_test_template: @staticmethod def clustering(path, levels, density_threshold, expected_clusters, expected_noise, ccore, **kwargs): sample = read_sample(path) amount_threshold = kwargs.get('amount_threshold', 0) bang_instance = bang(sample, levels, ccore, density_threshold=density_threshold, amount_threshold=amount_threshold) bang_instance.process() clusters = bang_instance.get_clusters() noise = bang_instance.get_noise() directory = bang_instance.get_directory() dendrogram = bang_instance.get_dendrogram() assertion.eq(len(clusters), len(dendrogram)) obtained_length = len(noise) obtained_cluster_length = [] for cluster in clusters: obtained_length += len(cluster) obtained_cluster_length.append(len(cluster)) obtained_cluster_length.sort() assertion.eq(len(sample), obtained_length) assertion.eq(expected_noise, len(noise)) if expected_clusters is not None: assertion.eq(len(expected_clusters), len(clusters)) assertion.eq(expected_clusters, obtained_cluster_length) leafs = directory.get_leafs() covered_points = set() for leaf in leafs: points = leaf.get_points() for index_point in points: covered_points.add(index_point) assertion.eq(len(sample), len(covered_points)) return bang_instance @staticmethod def visualize(path, levels, threshold, ccore, **kwargs): sample = read_sample(path) bang_instance = bang(sample, levels, ccore, density_threshold=threshold) bang_instance.process() directory = bang_instance.get_directory() dendrogram = bang_instance.get_dendrogram() bang_visualizer.show_blocks(directory) bang_visualizer.show_dendrogram(dendrogram) @staticmethod def animate(path, levels, threshold, ccore, **kwargs): sample = read_sample(path) bang_instance = bang(sample, levels, ccore, density_threshold=threshold) bang_instance.process() directory = bang_instance.get_directory() clusters = bang_instance.get_clusters() noise = bang_instance.get_noise() animator = bang_animator(directory, clusters) animator.animate() @staticmethod def exception(type, sample_storage, levels, threshold, ccore): try: sample = sample_storage if isinstance(sample_storage, str): sample = read_sample(sample_storage) bang_instance = bang(sample, levels, ccore, density_threshold=threshold) bang_instance.process() except type: return except Exception as ex: raise AssertionError("Expected: '%s', Actual: '%s'" % (type, type(ex).__name__)) raise AssertionError("Expected: '%s', Actual: 'None'" % type)pyclustering-0.10.1.2/pyclustering/cluster/tests/bsas_templates.py000077500000000000000000000036731375753423500254460ustar00rootroot00000000000000"""! @brief Test templates for BSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.tests.assertion import assertion; from pyclustering.cluster.bsas import bsas, bsas_visualizer; from pyclustering.utils import read_sample; from pyclustering.utils.metric import type_metric, distance_metric; class bsas_test_template: @staticmethod def clustering(path, amount, threshold, expected, ccore, **kwargs): metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN)); sample = read_sample(path); bsas_instance = bsas(sample, amount, threshold, ccore=ccore, metric=metric); bsas_instance.process(); clusters = bsas_instance.get_clusters(); representatives = bsas_instance.get_representatives(); obtained_length = 0; obtained_cluster_length = []; for cluster in clusters: obtained_length += len(cluster); obtained_cluster_length.append(len(cluster)); assertion.eq(len(sample), obtained_length); assertion.eq(len(expected), len(clusters)); assertion.eq(len(expected), len(representatives)); assertion.ge(amount, len(clusters)); dimension = len(sample[0]); for rep in representatives: assertion.eq(dimension, len(rep)); expected.sort(); obtained_cluster_length.sort(); assertion.eq(expected, obtained_cluster_length); @staticmethod def visualizing(path, amount, threshold, ccore): sample = read_sample(path); bsas_instance = bsas(sample, amount, threshold, ccore=ccore); bsas_instance.process(); bsas_visualizer.show_clusters(sample, bsas_instance.get_clusters(), bsas_instance.get_representatives());pyclustering-0.10.1.2/pyclustering/cluster/tests/clique_templates.py000077500000000000000000000053341375753423500257740ustar00rootroot00000000000000"""! @brief Test templates for CLIQUE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.assertion import assertion from pyclustering.cluster.clique import clique, clique_visualizer from pyclustering.utils import read_sample class clique_test_template: @staticmethod def clustering(path, intervals, density_threshold, expected_clusters, expected_noise, ccore_enabled, **kwargs): sample = read_sample(path) dimension = len(sample[0]) clique_instance = clique(sample, intervals, density_threshold, ccore=ccore_enabled) clique_instance.process() clusters = clique_instance.get_clusters() noise = clique_instance.get_noise() cells = clique_instance.get_cells() assertion.eq(len(cells), pow(intervals, dimension)) obtained_length = len(noise) obtained_cluster_length = [] for cluster in clusters: obtained_length += len(cluster) obtained_cluster_length.append(len(cluster)) obtained_cluster_length.sort() assertion.eq(len(sample), obtained_length) assertion.eq(expected_noise, len(noise)) if expected_clusters is not None: assertion.eq(len(expected_clusters), len(clusters)) assertion.eq(expected_clusters, obtained_cluster_length) covered_points = set() for cell in cells: points = cell.points for index_point in points: covered_points.add(index_point) assertion.eq(len(sample), len(covered_points)) return clique_instance @staticmethod def visualize(path, levels, threshold, ccore_enabled, **kwargs): sample = read_sample(path) clique_instance = clique(sample, levels, threshold, ccore=ccore_enabled) clique_instance.process() cells = clique_instance.get_cells() clique_visualizer.show_grid(cells, sample) @staticmethod def exception(type, sample_storage, levels, threshold, ccore_enabled): try: sample = sample_storage if isinstance(sample_storage, str): sample = read_sample(sample_storage) bang_instance = clique(sample, levels, threshold, ccore=ccore_enabled) bang_instance.process() except type: return except Exception as ex: raise AssertionError("Expected: '%s', Actual: '%s'" % (type, type(ex).__name__)) raise AssertionError("Expected: '%s', Actual: 'None'" % type)pyclustering-0.10.1.2/pyclustering/cluster/tests/cure_templates.py000077500000000000000000000071721375753423500254520ustar00rootroot00000000000000"""! @brief Test templates for CURE clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.cluster.cure import cure from pyclustering.cluster.encoder import type_encoding, cluster_encoder from pyclustering.tests.assertion import assertion from random import random class CureTestTemplates: @staticmethod def template_cluster_allocation(input_data, cluster_sizes, number_cluster, number_represent_points = 5, compression = 0.5, ccore_flag = False, **kwargs): if isinstance(input_data, str): sample = read_sample(input_data) else: sample = input_data numpy_usage = kwargs.get('numpy_usage', False) if numpy_usage is True: sample = numpy.array(sample) cure_instance = cure(sample, number_cluster, number_represent_points, compression, ccore = ccore_flag) cure_instance.process() clusters = cure_instance.get_clusters() representors = cure_instance.get_representors() means = cure_instance.get_means() assertion.eq(len(clusters), number_cluster) assertion.eq(len(representors), number_cluster) assertion.eq(len(means), number_cluster) obtained_cluster_sizes = [len(cluster) for cluster in clusters] total_length = sum(obtained_cluster_sizes) assertion.eq(total_length, len(sample)) cluster_sizes.sort() obtained_cluster_sizes.sort() assertion.eq(cluster_sizes, obtained_cluster_sizes) @staticmethod def templateClusterAllocationOneDimensionData(ccore_flag): input_data = [ [random()] for _ in range(10) ] + [ [random() + 3] for _ in range(10) ] + [ [random() + 5] for _ in range(10) ] + [ [random() + 8] for _ in range(10) ] cure_instance = cure(input_data, 4, ccore = ccore_flag) cure_instance.process() clusters = cure_instance.get_clusters() assertion.eq(4, len(clusters)) for cluster in clusters: assertion.eq(10, len(cluster)) @staticmethod def templateEncoderProcedures(ccore_flag): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) cure_instance = cure(sample, 4, 5, 0.5, ccore = ccore_flag) cure_instance.process() clusters = cure_instance.get_clusters() encoding = cure_instance.get_cluster_encoding() encoder = cluster_encoder(encoding, clusters, sample) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) encoder.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assertion.eq(4, len(clusters)) @staticmethod def exception(type, input_data, number_cluster, number_represent_points, compression, ccore_flag): try: if isinstance(input_data, str): sample = read_sample(input_data) else: sample = input_data cure_instance = cure(sample, number_cluster, number_represent_points, compression, ccore=ccore_flag) cure_instance.process() except type: return except Exception as ex: raise AssertionError("Expected: '%s', Actual: '%s'" % (type, type(ex).__name__)) raise AssertionError("Expected: '%s', Actual: 'None'" % type) pyclustering-0.10.1.2/pyclustering/cluster/tests/dbscan_templates.py000077500000000000000000000173531375753423500257500ustar00rootroot00000000000000"""! @brief Test templates for DBSCAN clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import pickle from random import random, shuffle from pyclustering.utils import read_sample, calculate_distance_matrix from pyclustering.cluster.dbscan import dbscan from pyclustering.tests.assertion import assertion from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.samples import answer_reader class DbscanTestTemplates: @staticmethod def templateClusteringResults(path, radius, neighbors, expected_length_clusters, ccore, **kwargs): random_order = kwargs.get('random_order', False) sample = read_sample(path) if random_order: shuffle(sample) dbscan_instance = dbscan(sample, radius, neighbors, ccore) dbscan_instance.process() clusters = dbscan_instance.get_clusters() noise = dbscan_instance.get_noise() assertion.eq(len(sample), sum([len(cluster) for cluster in clusters]) + len(noise)) assertion.eq(sum(expected_length_clusters), sum([len(cluster) for cluster in clusters])) assertion.eq(expected_length_clusters, sorted([len(cluster) for cluster in clusters])) @staticmethod def templateClusteringWithAnswers(sample_path, answer_path, radius, neighbors, ccore, **kwargs): random_order = kwargs.get('random_order', False) repeat = kwargs.get('repeat', 1) for _ in range(repeat): sample = read_sample(sample_path) sample_index_map = [ i for i in range(len(sample)) ] if random_order: shuffle(sample_index_map) sample_shuffled = [ sample[i] for i in sample_index_map ] dbscan_instance = dbscan(sample_shuffled, radius, neighbors, ccore) dbscan_instance.process() clusters = dbscan_instance.get_clusters() noise = dbscan_instance.get_noise() for cluster in clusters: for i in range(len(cluster)): cluster[i] = sample_index_map[cluster[i]] for i in range(len(noise)): noise[i] = sample_index_map[noise[i]] noise = sorted(noise) reader = answer_reader(answer_path) expected_noise = sorted(reader.get_noise()) expected_length_clusters = reader.get_cluster_lengths() assertion.eq(len(sample), sum([len(cluster) for cluster in clusters]) + len(noise)) assertion.eq(sum(expected_length_clusters), sum([len(cluster) for cluster in clusters])) assertion.eq(expected_length_clusters, sorted([len(cluster) for cluster in clusters])) assertion.eq(expected_noise, noise) @staticmethod def templateClusteringResultsRandomize(path, radius, neighbors, expected_length_clusters, ccore): for i in range(10): DbscanTestTemplates.templateClusteringResults(path, radius, neighbors, expected_length_clusters, ccore, random_order=True) @staticmethod def templateLengthProcessData(path_to_file, radius, min_number_neighbors, max_number_neighbors, ccore): DbscanTestTemplates.templateLengthProcessSpecificData('points', path_to_file, radius, min_number_neighbors, max_number_neighbors, ccore) @staticmethod def templateLengthProcessDistanceMatrix(path_to_file, radius, min_number_neighbors, max_number_neighbors, ccore): DbscanTestTemplates.templateLengthProcessSpecificData('points', path_to_file, radius, min_number_neighbors, max_number_neighbors, ccore) @staticmethod def templateLengthProcessSpecificData(data_type, path_to_file, radius, min_number_neighbors, max_number_neighbors, ccore): for _ in range(min_number_neighbors, max_number_neighbors, 1): sample = read_sample(path_to_file) if data_type == 'distance_matrix': input_data = calculate_distance_matrix(sample) elif data_type == 'points': input_data = sample else: raise ValueError("Incorrect data type '%s' is specified" % data_type) dbscan_instance = dbscan(input_data, radius, min_number_neighbors, ccore, data_type=data_type) dbscan_instance.process() clusters = dbscan_instance.get_clusters() noise = dbscan_instance.get_noise() length = len(noise) length += sum([len(cluster) for cluster in clusters]) assertion.eq(len(sample), length) @staticmethod def templateClusterAllocationOneDimensionData(ccore_flag): DbscanTestTemplates.templateClusterAllocationOneDimensionDataSpecificData('points', ccore_flag) @staticmethod def templateClusterAllocationOneDimensionDistanceMatrix(ccore_flag): DbscanTestTemplates.templateClusterAllocationOneDimensionDataSpecificData('distance_matrix', ccore_flag) @staticmethod def templateClusterAllocationOneDimensionDataSpecificData(data_type, ccore_flag): for _ in range(50): sample = [[random()] for _ in range(10)] + [[random() + 3] for _ in range(10)] + [[random() + 6] for _ in range(10)] + [[random() + 9] for _ in range(10)] if data_type == 'distance_matrix': input_data = calculate_distance_matrix(sample) elif data_type == 'points': input_data = sample else: raise ValueError("Incorrect data type '%s' is specified" % data_type) dbscan_instance = dbscan(input_data, 1.0, 2, ccore_flag, data_type=data_type) dbscan_instance.process() clusters = dbscan_instance.get_clusters() assertion.eq(4, len(clusters)) for cluster in clusters: assertion.eq(10, len(cluster)) @staticmethod def templateClusteringDistanceMatrix(path_to_file, radius, neighbors, expected_length_clusters, ccore): sample = read_sample(path_to_file) distance_matrix = calculate_distance_matrix(sample) dbscan_instance = dbscan(distance_matrix, radius, neighbors, ccore, data_type='distance_matrix') dbscan_instance.process() clusters = dbscan_instance.get_clusters() noise = dbscan_instance.get_noise() assertion.eq(len(sample), sum([len(cluster) for cluster in clusters]) + len(noise)) assertion.eq(sum(expected_length_clusters), sum([len(cluster) for cluster in clusters])) assertion.eq(expected_length_clusters, sorted([len(cluster) for cluster in clusters])) @staticmethod def pickle_dump_load(ccore): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) dbscan_instance = dbscan(sample, 0.7, 3, ccore) dbscan_instance.process() expected_clusters = dbscan_instance.get_clusters() expected_noise = dbscan_instance.get_noise() expected_encoding = dbscan_instance.get_cluster_encoding() dbscan_dump_file = open('test_dbscan_file.pkl', 'wb') pickle.dump(dbscan_instance, dbscan_dump_file) dbscan_dump_file.close() dbscan_dump_file = open('test_dbscan_file.pkl', 'rb') dbscan_instance = pickle.load(dbscan_dump_file) dbscan_dump_file.close() assertion.eq(expected_clusters, dbscan_instance.get_clusters()) assertion.eq(expected_noise, dbscan_instance.get_noise()) assertion.eq(expected_encoding, dbscan_instance.get_cluster_encoding()) pyclustering-0.10.1.2/pyclustering/cluster/tests/elbow_template.py000077500000000000000000000055271375753423500254430ustar00rootroot00000000000000"""! @brief Test templates for Elbow clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math from pyclustering.utils import read_sample from pyclustering.cluster.elbow import elbow from pyclustering.tests.assertion import assertion from pyclustering.samples import answer_reader class elbow_test_template: @staticmethod def calculate_elbow(path_to_data, path_to_answer, kmin, kmax, ccore, **kwargs): repeat = 15 # Elbow method randomly chooses initial centers therefore we need to repeat test if it fails. testing_result = False kstep = kwargs.get('kstep', 1) sample = read_sample(path_to_data) expected_clusters_amount = None if path_to_answer is not None: if isinstance(path_to_answer, int): expected_clusters_amount = path_to_answer else: expected_clusters_amount = len(answer_reader(path_to_answer).get_clusters()) additional_info = [] for _ in range(repeat): elbow_instance = elbow(sample, kmin, kmax, ccore=ccore, **kwargs) elbow_instance.process() actual_elbow = elbow_instance.get_amount() actual_wce = elbow_instance.get_wce() assertion.gt(actual_elbow, kmin) assertion.lt(actual_elbow, kmax) assertion.eq(len(actual_wce), math.floor((kmax - kmin) / kstep + 1)) assertion.lt(actual_wce[-1], actual_wce[0] + 0.0000001) if (expected_clusters_amount is not None) and (actual_elbow != expected_clusters_amount): additional_info.append(actual_elbow) continue testing_result = True break message = None if expected_clusters_amount is not None: message = str(expected_clusters_amount) + ": " + str(additional_info) assertion.true(testing_result, message=message) @staticmethod def random_state_fixed(path_to_data, kmin, kmax, ccore, **kwargs): repeat = kwargs.get('repeat', 1) kstep = kwargs.get('kstep', 1) for _ in range(repeat): sample = read_sample(path_to_data) elbow_instance = elbow(sample, kmin, kmax, ccore=ccore, **kwargs).process() elbow_1 = elbow_instance.get_amount() wce_1 = elbow_instance.get_wce() assertion.eq(len(wce_1), (kmax - kmin) / kstep + 1) elbow_instance = elbow(sample, kmin, kmax, ccore=ccore, **kwargs).process() elbow_2 = elbow_instance.get_amount() wce_2 = elbow_instance.get_wce() assertion.eq(len(wce_2), (kmax - kmin) / kstep + 1) assertion.eq(elbow_1, elbow_2) assertion.eq(wce_1, wce_2) pyclustering-0.10.1.2/pyclustering/cluster/tests/fcm_templates.py000077500000000000000000000034031375753423500252520ustar00rootroot00000000000000"""! @brief Test templates for Fuzzy C-Means (FCM) clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.tests.assertion import assertion from pyclustering.cluster.fcm import fcm from pyclustering.utils import read_sample class fcm_test_template: @staticmethod def cluster_allocation(path, initial_centers, m, expected_cluster_length, ccore, **kwargs): itermax = kwargs.get('itermax', 100) tolerance = kwargs.get('tolerance', 0.001) sample = read_sample(path) fcm_instance = fcm(sample, initial_centers, m=m, ccore=ccore, tolerance=tolerance, itermax=itermax) fcm_instance.process() clusters = fcm_instance.get_clusters() centers = fcm_instance.get_centers() membership = fcm_instance.get_membership() if itermax == 0: assertion.eq([], clusters) assertion.eq(initial_centers, centers) assertion.eq([], membership) return for probabilities in membership: total_probability = 0.0 for p in probabilities: total_probability += p assertion.eq_float(1.0, total_probability, 0.0000001) obtained_cluster_sizes = [len(cluster) for cluster in clusters] assertion.eq(len(sample), sum(obtained_cluster_sizes)) assertion.eq(len(clusters), len(centers)) for center in centers: assertion.eq(len(sample[0]), len(center)) if expected_cluster_length is not None: obtained_cluster_sizes.sort() expected_cluster_length.sort() assertion.eq(obtained_cluster_sizes, expected_cluster_length) pyclustering-0.10.1.2/pyclustering/cluster/tests/gmeans_templates.py000077500000000000000000000057011375753423500257620ustar00rootroot00000000000000"""! @brief Test templates for G-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.samples import answer_reader from pyclustering.cluster.gmeans import gmeans from pyclustering.utils import read_sample class gmeans_test_template(unittest.TestCase): def clustering(self, sample_path, answer, amount, ccore, **kwargs): attempts = 10 failures = "" k_max = kwargs.get('k_max', -1) random_state = kwargs.get('random_state', None) data = read_sample(sample_path) if isinstance(answer, str): reader = answer_reader(answer) expected_length_clusters = sorted(reader.get_cluster_lengths()) amount_clusters = len(expected_length_clusters) elif isinstance(answer, int): expected_length_clusters = None amount_clusters = answer else: expected_length_clusters = answer amount_clusters = len(answer) for _ in range(attempts): gmeans_instance = gmeans(data, amount, ccore, k_max=k_max, random_state=random_state).process() clusters = gmeans_instance.get_clusters() centers = gmeans_instance.get_centers() wce = gmeans_instance.get_total_wce() self.assertEqual(amount_clusters, len(centers)) if len(clusters) > 1: self.assertGreater(wce, 0.0) else: self.assertGreaterEqual(wce, 0.0) if len(clusters) != amount_clusters: failures += "1. %d != %d\n" % (len(clusters), amount_clusters) continue unique_indexes = set() for cluster in clusters: for index_point in cluster: unique_indexes.add(index_point) if len(data) != len(unique_indexes): failures += "2. %d != %d\n" % (len(data), len(unique_indexes)) continue if expected_length_clusters is None: return expected_total_length = sum(expected_length_clusters) actual_total_length = sum([len(cluster) for cluster in clusters]) if expected_total_length != actual_total_length: failures += "3. %d != %d\n" % (expected_total_length, actual_total_length) continue actual_length_clusters = sorted([len(cluster) for cluster in clusters]) if expected_length_clusters != actual_length_clusters: failures += "4. %s != %s\n" % (str(expected_length_clusters), str(actual_length_clusters)) continue return self.fail("Expected result is not obtained during %d attempts: %s\n" % (attempts, failures))pyclustering-0.10.1.2/pyclustering/cluster/tests/hsyncnet_templates.py000077500000000000000000000056111375753423500263430ustar00rootroot00000000000000"""! @brief Test templates for hSyncNet clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet import initial_type, solve_type; from pyclustering.utils import read_sample; from pyclustering.cluster.hsyncnet import hsyncnet; class HsyncnetTestTemplates: @staticmethod def templateClustering(path, number_clusters, expected_length_clusters, solver, initial_neighbors, increase_persent, collect_dynamic_flag, ccore_flag): result_testing = False; # If phases crosses each other because of random part of the network then we should try again. for _ in range(0, 6, 1): sample = read_sample(path); network = hsyncnet(sample, number_clusters, initial_type.EQUIPARTITION, initial_neighbors, increase_persent, ccore = ccore_flag); analyser = network.process(order = 0.997, solution = solver, collect_dynamic = collect_dynamic_flag); clusters = analyser.allocate_clusters(0.1); if (sum([len(cluster) for cluster in clusters]) != sum(expected_length_clusters)): continue; if (sorted([len(cluster) for cluster in clusters]) != expected_length_clusters): if (sorted([len(cluster) for cluster in clusters]) != sorted(expected_length_clusters)): continue; # Unit-test is passed result_testing = True; break; assert result_testing; @staticmethod def templateDynamicLength(path, number_clusters, expected_length, initial_neighbors, increase_persent, collect_dynamic_flag, ccore_flag): sample = read_sample(path); network = hsyncnet(sample, number_clusters, initial_type.EQUIPARTITION, initial_neighbors, increase_persent, ccore = ccore_flag); analyser = network.process(order = 0.995, solution = solve_type.FAST, collect_dynamic = collect_dynamic_flag); assert len(analyser) != 0; if (collect_dynamic_flag is True): assert len(analyser) >= 1; if (expected_length is None): assert len(analyser) > 1; else: assert len(analyser) == expected_length; else: assert len(analyser) == 1; @staticmethod def testCoreInterfaceIntInputData(): result_testing = False; for _ in range(10): hsyncnet_instance = hsyncnet([ [1], [2], [3], [20], [21], [22] ], 2, initial_type.EQUIPARTITION, ccore = True); analyser = hsyncnet_instance.process(); if (len(analyser.allocate_clusters(0.1)) == 2): result_testing = True; break; assert result_testing; pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/000077500000000000000000000000001375753423500243755ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/__init__.py000077500000000000000000000123041375753423500265110ustar00rootroot00000000000000"""! @brief Integration-test runner for tests of clustering algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.integration import it_agglomerative as cluster_agglomerative_integration_tests from pyclustering.cluster.tests.integration import it_bsas as cluster_bsas_integration_tests from pyclustering.cluster.tests.integration import it_clique as cluster_clique_integration_tests from pyclustering.cluster.tests.integration import it_cure as cluster_cure_integration_tests from pyclustering.cluster.tests.integration import it_dbscan as cluster_dbscan_integration_tests from pyclustering.cluster.tests.integration import it_elbow as cluster_elbow_integration_tests from pyclustering.cluster.tests.integration import it_fcm as cluster_fcm_integration_tests from pyclustering.cluster.tests.integration import it_gmeans as cluster_gmeans_integration_tests from pyclustering.cluster.tests.integration import it_hsyncnet as cluster_hsyncnet_integration_tests from pyclustering.cluster.tests.integration import it_kmeans as cluster_kmeans_integration_tests from pyclustering.cluster.tests.integration import it_kmedians as cluster_kmedians_integration_tests from pyclustering.cluster.tests.integration import it_kmedoids as cluster_kmedoids_integration_tests from pyclustering.cluster.tests.integration import it_mbsas as cluster_mbsas_integration_tests from pyclustering.cluster.tests.integration import it_optics as cluster_optics_integration_tests from pyclustering.cluster.tests.integration import it_rock as cluster_rock_integration_tests from pyclustering.cluster.tests.integration import it_silhouette as cluster_silhouette_integration_tests from pyclustering.cluster.tests.integration import it_somsc as cluster_somsc_integration_tests from pyclustering.cluster.tests.integration import it_syncnet as cluster_syncnet_integration_tests from pyclustering.cluster.tests.integration import it_ttsas as cluster_ttsas_integration_tests from pyclustering.cluster.tests.integration import it_xmeans as cluster_xmeans_integration_tests class clustering_integration_tests(suite_holder): def __init__(self): super().__init__() self.fill_suite(self.get_suite()) @staticmethod def fill_suite(integration_cluster_suite): integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_agglomerative_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_bsas_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_clique_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_cure_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_dbscan_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_elbow_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_fcm_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_gmeans_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_hsyncnet_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_kmeans_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_kmedians_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_kmedoids_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_mbsas_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_optics_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_rock_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_silhouette_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_somsc_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_syncnet_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_ttsas_integration_tests)) integration_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_xmeans_integration_tests)) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_agglomerative.py000077500000000000000000000176751375753423500303140ustar00rootroot00000000000000"""! @brief Integration-tests for agglomerative algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.cluster.tests.agglomerative_templates import AgglomerativeTestTemplates; from pyclustering.cluster.agglomerative import agglomerative, type_link; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.core.tests import remove_library, corrupt_library; class AgglomerativeIntegrationTest(unittest.TestCase): def testClusteringSampleSimple1LinkAverageByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.AVERAGE_LINK, [5, 5], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.AVERAGE_LINK, [10], True); def testClusteringSampleSimple1LinkCentroidByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.CENTROID_LINK, [5, 5], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.CENTROID_LINK, [10], True); def testClusteringSampleSimple1LinkCompleteByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.COMPLETE_LINK, [5, 5], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.COMPLETE_LINK, [10], True); def testClusteringSampleSimple1LinkSingleByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.SINGLE_LINK, [5, 5], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.SINGLE_LINK, [10], True); def testClusteringSampleSimple2LinkAverageByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.AVERAGE_LINK, [5, 8, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.AVERAGE_LINK, [23], True); def testClusteringSampleSimple2LinkCentroidByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.CENTROID_LINK, [5, 8, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.CENTROID_LINK, [23], True); def testClusteringSampleSimple2LinkCompleteByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.COMPLETE_LINK, [5, 8, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.COMPLETE_LINK, [23], True); def testClusteringSampleSimple2LinkSingleByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.SINGLE_LINK, [5, 8, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.SINGLE_LINK, [23], True); def testClusteringTheSameData1LinkAverageByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.AVERAGE_LINK, [10, 20], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.AVERAGE_LINK, [30], True); def testClusteringTheSameData1LinkCentroidByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.CENTROID_LINK, [10, 20], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.CENTROID_LINK, [30], True); def testClusteringTheSameData1LinkCompleteByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.COMPLETE_LINK, [10, 20], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.COMPLETE_LINK, [30], True); def testClusteringTheSameData1LinkSingleByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.SINGLE_LINK, [10, 20], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.SINGLE_LINK, [30], True); def testClusteringTheSameData2LinkAverageByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.AVERAGE_LINK, [5, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.AVERAGE_LINK, [15], True); def testClusteringTheSameData2LinkCentroidByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.CENTROID_LINK, [5, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.CENTROID_LINK, [15], True); def testClusteringTheSameData2LinkCompleteByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.COMPLETE_LINK, [5, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.COMPLETE_LINK, [15], True); def testClusteringTheSameData2LinkSingleByCore(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.SINGLE_LINK, [5, 10], True); AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.SINGLE_LINK, [15], True); def testClusterAllocationOneDimensionDataLinkAverageByCore(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.AVERAGE_LINK, True); def testClusterAllocationOneDimensionDataLinkCentroidByCore(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.CENTROID_LINK, True); def testClusterAllocationOneDimensionDataLinkCompleteByCore(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.COMPLETE_LINK, True); def testClusterAllocationOneDimensionDataLinkSingleByCore(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.SINGLE_LINK, True); def testTwoClusterAllocationTheSameObjectsLinkAverageByCore(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.AVERAGE_LINK, True); def testTwoClusterAllocationTheSameObjectLinkCentroidByCore(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.CENTROID_LINK, True); def testTwoClusterAllocationTheSameObjectLinkCompleteByCore(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.COMPLETE_LINK, True); def testTwoClusterAllocationTheSameObjectLinkSingleByCore(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.SINGLE_LINK, True); def testCoreInterfaceIntInputData(self): agglomerative_instance = agglomerative([ [1], [2], [3], [20], [21], [22] ], 2, type_link.SINGLE_LINK, True); agglomerative_instance.process(); assert len(agglomerative_instance.get_clusters()) == 2; @remove_library def testProcessingWhenLibraryCoreRemoved(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.AVERAGE_LINK, [5, 5], True); @corrupt_library def testProcessingWhenLibraryCoreCorrupted(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.AVERAGE_LINK, [5, 5], True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_bsas.py000077500000000000000000000114411375753423500263770ustar00rootroot00000000000000"""! @brief Integration-tests for BSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.core.tests import remove_library; from pyclustering.cluster.tests.bsas_templates import bsas_test_template; from pyclustering.utils.metric import type_metric, distance_metric; from pyclustering.samples.definitions import SIMPLE_SAMPLES; class bsas_integration_test(unittest.TestCase): def testClusteringSampleSimple1(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 1.0, [5, 5], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 1.0, [10], True); def testClusteringSampleSimple1Euclidean(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN)); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True, metric=distance_metric(type_metric.EUCLIDEAN)); def testClusteringSampleSimple1EuclideanSquare(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 100.0, [10], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); def testClusteringSampleSimple1Manhattan(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.MANHATTAN)); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True, metric=distance_metric(type_metric.MANHATTAN)); def testClusteringSampleSimple1Chebyshev(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.CHEBYSHEV)); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True, metric=distance_metric(type_metric.CHEBYSHEV)); def testClusteringSampleSimple2(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1.0, [5, 8, 10], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 10.0, [23], True); def testClusteringSampleSimple3(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 1.0, [2, 8, 20, 30], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 2.0, [10, 10, 10, 30], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 10.0, [60], True); def testOneDimentionalPoints1(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1.0, [10, 10], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 10.0, [20], True); def testOneDimentionalPoints2(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 1.0, [10, 20], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 10.0, [30], True); def testThreeDimentionalPoints(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 1.0, [10, 10], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 10.0, [20], True); def testTheSamePoints1(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 1.0, [5, 5, 5], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 30, 1.0, [5, 5, 5], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 10.0, [15], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 1.0, [15], True); def testTheSamePoints2(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 1.0, [10, 20], True); bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 10.0, [30], True); def testVisulizeNoFailure(self): bsas_test_template.visualizing(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, True); bsas_test_template.visualizing(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1.0, True); bsas_test_template.visualizing(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 1.0, True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_clique.py000077500000000000000000000162241375753423500267350ustar00rootroot00000000000000"""! @brief Integration-tests for CLIQUE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.clique import clique from pyclustering.cluster.tests.clique_templates import clique_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.core.tests import remove_library from pyclustering.tests.assertion import assertion class clique_integration_test(unittest.TestCase): def test_clustering_sample_simple_1_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0, [5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 7, 0, [5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 0, [5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 0, [5, 5], 0, True) def test_clustering_sample_simple_1_one_cluster_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0, [10], 0, True) def test_clustering_diagonal_blocks_arent_neoghbors_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 0, [5, 5], 0, True) def test_clustering_sample_simple_1_noise_only_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 1000, [], 10, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 10, [], 10, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 5, [], 10, True) def test_clustering_sample_simple_2_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 7, 0, [5, 8, 10], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 0, [5, 8, 10], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0, [23], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 500, [], 23, True) def test_clustering_sample_simple_3_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 9, 0, [10, 10, 10, 30], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 8, 0, [10, 10, 10, 30], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0, [60], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 6, 500, [], 60, True) def test_clustering_sample_simple_3_one_point_noise_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 9, [59], 1, True) def test_clustering_sample_simple_4_one_cluster_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0, [75], 0, True) def test_clustering_sample_simple_5_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 8, 0, [15, 15, 15, 15], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 7, 0, [15, 15, 15, 15], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 6, 0, [15, 15, 15, 15], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 0, [15, 15, 15, 15], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0, [60], 0, True) def test_clustering_one_dimensional_data1_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4, 0, [10, 10], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 0, [20], 0, True) def test_clustering_one_dimensional_data2_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 15, 0, [15, 20, 30, 80], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 2, 0, [145], 0, True) def test_clustering_one_dimensional_data_3_similar_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 7, 0, [10, 20], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 0, [30], 0, True) def test_clustering_sample_simple_10_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 8, 0, [11, 11, 11], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 7, 0, [11, 11, 11], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 2, 0, [33], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 1, 0, [33], 0, True) def test_clustering_three_dimensional_data1_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 6, 0, [10, 10], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 5, 0, [10, 10], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, 0, [20], 0, True) def test_clustering_similar_points_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 8, 0, [5, 5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 7, 0, [5, 5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, 0, [5, 5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, 0, [15], 0, True) def test_clustering_zero_column_by_core(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 3, 0, [5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 2, 0, [5, 5], 0, True) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 1, 0, [10], 0, True) def test_clustering_fcps_lsun_by_core(self): clique_test_template.clustering(FCPS_SAMPLES.SAMPLE_LSUN, 15, 0, [100, 101, 202], 0, True) def test_clustering_fcps_hepta_by_core(self): clique_test_template.clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 9, 0, [30, 30, 30, 30, 30, 30, 32], 0, True) def test_visualize_no_failure_one_dimensional_by_core(self): clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4, 0, True) clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 7, 0, True) def test_visualize_no_failure_two_dimensional_by_core(self): clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0, True) clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0, True) def test_visualize_no_failure_three_dimensional_by_core(self): clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 3, 0, True) def test_high_dimension_data_failure(self): data = [[0, 1, 2, 1, 3, 4, 5, 1, 2, 3, 3, 1, 3], [0, 1, 0, 1, 3, 8, 5, 5, 3, 3, 3, 0, 0]] clique_instance = clique(data, 15, 0) assertion.exception(RuntimeError, clique_instance.process) @remove_library def test_processing_when_library_core_corrupted(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0, [5, 5], 0, True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_cure.py000077500000000000000000000071601375753423500264100ustar00rootroot00000000000000"""! @brief Integration-tests for CURE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.cluster.cure import cure from pyclustering.cluster.tests.cure_templates import CureTestTemplates from pyclustering.core.tests import remove_library class CureIntegrationTest(unittest.TestCase): def testClusterAllocationSampleSimple1ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, 5, 0.5, True) def testClusterAllocationSampleSimple2ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, 5, 0.5, True) def testClusterAllocationSampleSimple3ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, 5, 0.5, True) def testClusterAllocationSampleSimple4ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [15, 15, 15, 15, 15], 5, 5, 0.5, True) def testClusterAllocationSampleSimple5ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [15, 15, 15, 15], 4, 5, 0.5, True) def testClusterAllocationSampleTwoDiamondsByCore(self): CureTestTemplates.template_cluster_allocation(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [399, 401], 2, 5, 0.3, True) def testClusterAllocationSampleLsunByCore(self): CureTestTemplates.template_cluster_allocation(FCPS_SAMPLES.SAMPLE_LSUN, [100, 101, 202], 3, 5, 0.3, True) def testOneClusterAllocationSampleSimple1ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [10], 1, 5, 0.5, True) def testOneClusterAllocationSampleSimple2ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [23], 1, 5, 0.5, True) def testOneClusterAllocationSampleSimple3ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [60], 1, 5, 0.5, True) def testOneClusterAllocationSampleSimple4ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [75], 1, 5, 0.5, True) def testOneClusterAllocationSampleSimple5ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [60], 1, 5, 0.5, True) def testClusterAllocationTheSameData1ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [10, 20], 2, 5, 0.3, True) def testClusterAllocationTheSameData2ByCore(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [5, 5, 5], 3, 5, 0.3, True) CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [5, 10], 2, 5, 0.3, True) def testClusterAllocationOneDimensionDataByCore(self): CureTestTemplates.templateClusterAllocationOneDimensionData(True) def testEncoderProcedureByCore(self): CureTestTemplates.templateEncoderProcedures(True) def testCoreInterfaceIntInputData(self): cure_instance = cure([ [1], [2], [3], [20], [21], [22] ], 2, ccore = True) cure_instance.process() assert len(cure_instance.get_clusters()) == 2; @remove_library def testProcessingWhenLibraryCoreCorrupted(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, 5, 0.5, True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_dbscan.py000077500000000000000000000147521375753423500267110ustar00rootroot00000000000000"""! @brief Integration-tests for DBSCAN algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.dbscan_templates import DbscanTestTemplates from pyclustering.cluster.dbscan import dbscan from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS from pyclustering.samples.definitions import FCPS_SAMPLES from pyclustering.core.tests import remove_library class DbscanIntegrationTest(unittest.TestCase): def testClusteringByCore(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, [5, 5], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 2, [10], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, [5, 8, 10], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 2, [23], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, [10, 10, 10, 30], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 3, [60], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, [15, 15, 15, 15, 15], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 2, 3, [75], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, [15, 15, 15, 15], True) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 10, 3, [60], True) DbscanTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3, [30, 30, 30, 30, 30, 30, 32], True) DbscanTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_HEPTA, 5, 3, [212], True) def testClusteringDistanceMatrixByCore(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, [5, 5], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 2, [10], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, [5, 8, 10], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 2, [23], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, [10, 10, 10, 30], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 3, [60], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, [15, 15, 15, 15, 15], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 2, 3, [75], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, [15, 15, 15, 15], True) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 10, 3, [60], True) def testClusteringTheSameData1ByCore(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 3, [10, 20], True) def testClusteringTheSameData1DistanceMatrixByCore(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 3, [10, 20], True) def testClusteringTheSameData2ByCore(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, [5, 5, 5], True) def testClusteringTheSameData2DistanceMatrixByCore(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, [5, 5, 5], True) def testClusteringSimple5WithoutNeighborsByCore(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 0, [15, 15, 15, 15], True) def testClusteringSimple5WithoutNeighborsDistanceMatrixByCore(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 0, [15, 15, 15, 15], True) def testLengthProcessedByCore(self): DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.7, 0, 10, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5, 0, 10, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 0.3, 0, 15, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0, 15, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.1, 0, 20, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 0, 20, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.1, 0, 10, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 10, 65, 75, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.1, 0, 10, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.3, 0, 10, True) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.6, 0, 10, True) def testClusterAllocationOneDimensionDataByCore(self): DbscanTestTemplates.templateClusterAllocationOneDimensionData(True) def testClusterAllocationOneDimensionDataDistanceMatrixByCore(self): DbscanTestTemplates.templateClusterAllocationOneDimensionDistanceMatrix(True) def testCoreInterfaceIntInputData(self): dbscan_instance = dbscan([ [1], [2], [3], [20], [21], [22] ], 3, 2, True) dbscan_instance.process() assert len(dbscan_instance.get_clusters()) == 2 def testPermutationSampleSimple14(self): DbscanTestTemplates.templateClusteringWithAnswers(SIMPLE_SAMPLES.SAMPLE_SIMPLE14, SIMPLE_ANSWERS.ANSWER_SIMPLE14, 1.0, 5, False, random_order=True, repeat=20) def test_pickle_dump_load(self): DbscanTestTemplates.pickle_dump_load(True) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, [5, 5], True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_elbow.py000077500000000000000000000107251375753423500265630ustar00rootroot00000000000000"""! @brief Integration-tests for Elbow method. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.center_initializer import random_center_initializer from pyclustering.cluster.tests.elbow_template import elbow_test_template from pyclustering.samples.definitions import FCPS_SAMPLES, SIMPLE_SAMPLES, SIMPLE_ANSWERS class elbow_integration_test(unittest.TestCase): def test_elbow_simple_01(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, 10, True) def test_elbow_simple_01_step_2(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, 1, 10, True, kstep=2) def test_elbow_simple_01_step_3(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 4, 1, 10, True, kstep=3) def test_elbow_simple_01_step_4(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 1, 10, True, kstep=4) def test_elbow_simple_01_random_initializer(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, 10, True, initializer=random_center_initializer) def test_elbow_simple_02(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, 10, True) def test_elbow_simple_02_step_2(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, 10, True, kstep=2) def test_elbow_simple_02_step_3(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, None, 1, 10, True, kstep=3) def test_elbow_simple_02_step_4(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, None, 1, 10, True, kstep=4) def test_elbow_simple_02_random_initializer(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, 10, True, initializer=random_center_initializer) def test_elbow_simple_03(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 1, 10, True) def test_elbow_simple_03_random_initializer(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 1, 10, True, initializer=random_center_initializer) def test_elbow_simple_05(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, 1, 10, True) def test_elbow_simple_06(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, 1, 10, True) def test_elbow_simple_10(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, 1, 10, True) def test_elbow_simple_12(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, 1, 10, True) def test_elbow_one_dimensional_simple_07(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, 1, 10, True) def test_elbow_one_dimensional_simple_09(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, 1, 10, True) def test_elbow_three_dimensional_simple_11(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, 1, 10, True) def test_elbow_hepta(self): elbow_test_template.calculate_elbow(FCPS_SAMPLES.SAMPLE_HEPTA, None, 1, 20, True) def test_elbow_tetra(self): elbow_test_template.calculate_elbow(FCPS_SAMPLES.SAMPLE_TETRA, None, 1, 25, True) def test_elbow_random_state(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, True, random_state=5) def test_elbow_random_state_random_initializer(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, True, random_state=5, initializer=random_center_initializer) def test_elbow_random_state_continuous(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, True, random_state=5, repeat=10)pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_fcm.py000077500000000000000000000126751375753423500262260ustar00rootroot00000000000000"""! @brief Integration-tests for Fuzzy C-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.fcm_templates import fcm_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, FAMOUS_SAMPLES, FCPS_SAMPLES class fcm_integration_tests(unittest.TestCase): def test_cluster_allocation_simple01(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], 2.0, [5, 5], True) def test_cluster_allocation_simple01_one_cluster(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], 2.0, [10], True) def test_cluster_allocation_simple01_centers_are_points1(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.768699, 5.364477], [6.593196, 7.850364]], 2.0, [5, 5], True) def test_cluster_allocation_simple01_centers_are_points2(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.936690, 5.663041], [6.968136, 7.755556]], 2.0, [5, 5], True) def test_cluster_allocation_simple01_wrong_amount(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [4.7, 6.5], [3.4, 6.4]], 2.0, [2, 3, 5], True) def test_cluster_allocation_simple02(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], 2.0, [10, 5, 8], True) def test_cluster_allocation_simple02_wrong_amount(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5], [4.5, 6.2]], 2.0, [4, 5, 6, 8], True) def test_cluster_allocation_simple03(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], 2.0, [10, 10, 10, 30], True) def test_cluster_allocation_simple04(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], 2.0, [15, 15, 15, 15, 15], True) def test_cluster_allocation_simple05(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], 2.0, [15, 15, 15, 15], True) def test_cluster_allocation_simple06(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, [[2.0, 6.0], [8.5, 4.5]], 2.0, [20, 21], True) def test_cluster_allocation_simple07(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[-3.0], [2.0]], 2.0, [10, 10], True) def test_cluster_allocation_simple08(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-4.0], [3.1], [6.1], [12.0]], 2.0, [15, 30, 20, 80], True) def test_cluster_allocation_simple09(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [[4.0], [8.0]], 2.0, [10, 20], True) def test_cluster_allocation_simple10(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, [[0.426, 0.065 ], [5.462, 6.529], [9.539, 11.379]], 2.0, [11, 11, 11], True) def test_cluster_allocation_simple11(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], 2.0, [10, 10], True) def test_cluster_allocation_simple12(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [[1.0, 1.0], [2.5, 2.5], [4.0, 4.0]], 2.0, [5, 5, 5], True) def test_cluster_allocation_simple13(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, [[1.35, 1.21, 0.0], [3.79, 4.21, 0.0]], 2.0, [5, 5], True) def test_cluster_allocation_simple14(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE14, [[5.649, 5.199]], 2.0, [41], True) def test_cluster_allocation_famous_oldfaithful(self): fcm_test_template.cluster_allocation(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL, [[4.0, 70], [1.0, 48]], 2.0, None, True) def test_cluster_allocation_two_diamonds(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.71 -0.51], [0.99 -0.24]], 2.0, [400, 400], True) def test_cluster_allocation_tetra(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_TETRA, [[1.001, -0.083, -0.681], [-0.811, 0.476, -0.759], [-0.956, -1.427, -0.020], [0.225, 0.560, 1.794]], 2.0, [100, 100, 100, 100], True) def test_cluster_allocation_fcps_hepta(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_HEPTA, [[-0.06, 0.02, 0.02], [2.41, 0.49, 0.03], [-2.69, 0.34, 0.29], [0.49, 2.89, 0.78], [-0.60, -2.31, 0.05], [-0.15, 0.77, 3.23], [-0.50, 0.43, -2.60]], 2.0, [30, 30, 30, 30, 30, 30, 32], True) def test_cluster_allocation_fcps_hepta_wrong_amount(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_HEPTA, [[-0.06,0.02, 0.02], [2.41, 0.49, 0.03], [-2.69, 0.34, 0.29], [0.49, 2.89, 0.78], [-0.60, -2.31, 0.05], [-0.50, 0.43, -2.60]], 2.0, [30, 30, 30, 30, 30, 62], True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_gmeans.py000077500000000000000000000122071375753423500267220ustar00rootroot00000000000000"""! @brief Integration-tests for G-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.gmeans_templates import gmeans_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS, FCPS_SAMPLES class gmeans_integration_test(unittest.TestCase): def test_clustering_sample_01(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, True) def test_clustering_sample_01_kmax_correct(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, True, k_max=2) def test_clustering_sample_01_kmax_1(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [10], 1, True, k_max=1) def test_clustering_sample_01_kmax_10(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, True, k_max=10) def test_clustering_sample_02(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, True) def test_clustering_sample_02_kmax_correct(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, True, k_max=3) def test_clustering_sample_02_kmax_1(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [23], 1, True, k_max=1) def test_clustering_sample_02_kmax_2(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [8, 15], 1, True, k_max=2) def test_clustering_sample_03(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 1, True) def test_clustering_sample_03_kmax_1(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [60], 1, True, k_max=1) def test_clustering_sample_05(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, 1, True) def test_clustering_sample_06(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, 1, True) def test_clustering_sample_07(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, 1, True) def test_clustering_sample_08(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, 1, True) def test_clustering_sample_09(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, 1, True) def test_clustering_sample_10(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, 1, True) def test_clustering_sample_11(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, 1, True) def test_clustering_sample_12(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, 1, True) def test_clustering_sample_13(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, 1, True) def test_clustering_hepta_kmax_01(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 1, True, k_max=1, random_state=1) def test_clustering_hepta_kmax_01_rnd_1024(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 1, True, k_max=1, random_state=1024) def test_clustering_hepta_kmax_02(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 2, 1, True, k_max=2, random_state=1) def test_clustering_hepta_kmax_03(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 3, 1, True, k_max=3, random_state=1) def test_clustering_hepta_kmax_04(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 4, 1, True, k_max=4, random_state=1) def test_clustering_hepta_kmax_05(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 5, 1, True, k_max=5, random_state=1) def test_clustering_hepta_kmax_06(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 6, 1, True, k_max=6, random_state=1) def test_clustering_hepta_kmax_07(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, True, k_max=7, random_state=1) def test_clustering_hepta_kmax_08(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, True, k_max=8, random_state=1) def test_clustering_hepta_kmax_09(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, True, k_max=9, random_state=1) def test_clustering_hepta_kmax_10(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, True, k_max=10, random_state=1) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_hsyncnet.py000077500000000000000000000046231375753423500273060ustar00rootroot00000000000000"""! @brief Integration-tests for Hierarchical Sync (HSyncNet) algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.cluster.tests.hsyncnet_templates import HsyncnetTestTemplates; from pyclustering.nnet import solve_type; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.core.tests import remove_library; class HsyncnetIntegrationTest(unittest.TestCase): def testClusteringSampleSimple1WithoutCollectingByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], solve_type.FAST, 5, 0.3, False, True); def testClusteringSampleSimple1ByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], solve_type.FAST, 5, 0.3, True, True); def testClusteringOneAllocationSampleSimple1ByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, [10], solve_type.FAST, 5, 0.3, True, True); def testClusteringSampleSimple2ByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [10, 5, 8], solve_type.FAST, 5, 0.2, True, True); def testClusteringOneAllocationSampleSimple2ByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, [23], solve_type.FAST, 5, 0.2, True, True); def testClusteringOneDimensionDataSampleSimple7ByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, [10, 10], solve_type.FAST, 5, 0.3, True, True); def testClusteringTheSameData1ByCore(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, [5, 5, 5], solve_type.FAST, 5, 0.3, True, True); def testDynamicLengthCollectingByCore(self): HsyncnetTestTemplates.templateDynamicLength(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, None, 5, 0.3, True, True); def testDynamicLengthWithoutCollectingByCore(self): HsyncnetTestTemplates.templateDynamicLength(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, None, 5, 0.3, False, True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], solve_type.FAST, 5, 0.3, False, True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_kmeans.py000077500000000000000000000264001375753423500267260ustar00rootroot00000000000000"""! @brief Integration-tests for K-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import numpy import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.kmeans_templates import KmeansTestTemplates from pyclustering.cluster.kmeans import kmeans from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.core.tests import remove_library from pyclustering.utils import read_sample from pyclustering.utils.metric import distance_metric, type_metric class KmeansIntegrationTest(unittest.TestCase): def testClusterAllocationSampleSimple1ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True) def testClusterOneAllocationSampleSimple1ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[1.0, 2.5]], [10], True) def testClusterAllocationSampleSimple1EuclideanByCore(self): metric = distance_metric(type_metric.EUCLIDEAN) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1EuclideanSquareByCore(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1ManhattanByCore(self): metric = distance_metric(type_metric.MANHATTAN) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1ChebyshevByCore(self): metric = distance_metric(type_metric.CHEBYSHEV) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1Minkowski01ByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1Minkowski02ByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=4) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1UserDefinedByCore(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1UserDefinedNumPyByCore(self): data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) centers = numpy.array([[3.7, 5.5], [6.7, 7.5]]) metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(data, centers, [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1Canberra(self): metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1ChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple2ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], True) def testClusterOneAllocationSampleSimple2ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[0.5, 0.2]], [23], True) def testClusterAllocationSampleSimple2UserDefinedByCore(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], True, metric=metric) def testClusterAllocationSampleSimple2UserDefinedNumPyByCore(self): data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2)) centers = numpy.array([[3.5, 4.8], [6.9, 7], [7.5, 0.5]]) metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(data, centers, [10, 5, 8], True, metric=metric) def testClusterAllocationSampleSimple3ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], True) def testClusterOneAllocationSampleSimple3ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1]], [60], True) def testClusterAllocationSampleSimple4ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], True) def testClusterOneAllocationSampleSimple4ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[2.0, 5.0]], [75], True) def testClusterAllocationSampleSimple5ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], True) def testClusterOneAllocationSampleSimple5ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 0.0]], [60], True) def testClusterAllocationSampleSimple5Canberra(self): metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [30, 30], True, metric=metric) def testClusterAllocationSampleSimple5ChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[3.4, 2.6], [3.4, -3.2], [-3.4, -3.4], [-3.1, 3.3]], [15, 15, 15, 15], True, metric=metric) def testClusterOneDimensionSampleSimple7ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[-3.0], [2.0]], [10, 10], True) def testClusterOneDimensionSampleSimple8ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-4.0], [3.1], [6.1], [12.0]], [15, 30, 20, 80], True) def testWrongNumberOfCentersSimpleSample1ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[2.0, 4.5], [3.3, 6.5], [5.0, 7.8]], None, True) def testWrongNumberOfCentersSimpleSample2ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[1.3, 1.5], [5.2, 8.5], [5.0, 7.8], [11.0, -3.0]], None, True) def testTheSameData1ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [ [4.0], [8.0] ], [10, 20], True) def testTheSameData2ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [ [1.0, 1.0], [2.5, 2.5], [4.0, 4.0] ], [5, 5, 5], True) def testClusterAllocationOneDimensionDataByCore(self): KmeansTestTemplates.templateClusterAllocationOneDimensionData(True) def testEncoderProcedureSampleSimple4ByCore(self): KmeansTestTemplates.templateEncoderProcedures(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], 5, True) def testCoreInterfaceIntInputData(self): kmeans_instance = kmeans([ [1], [2], [3], [20], [21], [22] ], [ [2], [21] ], 0.025, True) kmeans_instance.process() assert len(kmeans_instance.get_clusters()) == 2 def testObserveSampleSimple1ByCore(self): KmeansTestTemplates.templateCollectEvolution(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.5, 5.6], [6.8, 7.4]], [5, 5], True) def testObserveSampleSimple1OneClusterByCore(self): KmeansTestTemplates.templateCollectEvolution(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.3, 5.4]], [10], True) def testObserveSampleSimple2ByCore(self): KmeansTestTemplates.templateCollectEvolution(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.4, 4.9], [6.8, 7.1], [7.6, 0.4]], [10, 5, 8], True) def testItermax0ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [], True, itermax=0) def testItermax1ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, itermax=1) def testItermax10Simple01ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, itermax=10) def testItermax10Simple02ByCore(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], True, itermax=10) def testShowResultsSampleSimple01(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.5, 5.6], [6.8, 7.4]], True) def testShowResultsSampleSimple02(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.4, 4.9], [6.8, 7.1], [7.6, 0.4]], True) def testShowResultsOneDimensionalData(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], True) def testShowResultsThreeDimensionalData(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], True) def testAnimateResultsSampleSimple01(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.5, 5.6], [6.8, 7.4]], True) def testAnimateResultsSampleSimple02(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.4, 4.9], [6.8, 7.1], [7.6, 0.4]], True) def testAnimateResultsOneDimensionalData(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], True) def testAnimateResultsThreeDimensionalData(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], True) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_kmedians.py000077500000000000000000000200701375753423500272400ustar00rootroot00000000000000"""! @brief Integration-tests for K-Medians algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import numpy import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.kmedians_templates import KmediansTestTemplates from pyclustering.cluster.kmedians import kmedians from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.core.tests import remove_library from pyclustering.utils import read_sample from pyclustering.utils.metric import type_metric, distance_metric class KmediansIntegrationTest(unittest.TestCase): def testClusterAllocationSampleSimple1Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True) def testClusterAllocationSampleSimple1EuclideanCore(self): metric = distance_metric(type_metric.EUCLIDEAN) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1EuclideanSquareCore(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1ManhattanCore(self): metric = distance_metric(type_metric.MANHATTAN) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1ChebyshevCore(self): metric = distance_metric(type_metric.CHEBYSHEV) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1MinkowskiCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2.0) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterAllocationSampleSimple1UserDefinedCore(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, metric=metric) def testClusterOneAllocationSampleSimple1Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[1.0, 2.5]], [10], True) def testClusterAllocationSampleSimple2Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], True) def testClusterOneAllocationSampleSimple2Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[0.5, 0.2]], [23], True) def testClusterAllocationSampleSimple3Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], True) def testClusterOneAllocationSampleSimple3Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1]], [60], True) def testClusterAllocationSampleSimple5Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], True) def testClusterOneAllocationSampleSimple5Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 0.0]], [60], True) def testClusterAllocationSample1NumpyArrayUserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) input_data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) initial_centers = numpy.array([[3.7, 5.5], [6.7, 7.5]]) KmediansTestTemplates.templateLengthProcessData(input_data, initial_centers, [5, 5], True, metric=metric) def testClusterAllocationSample2NumpyArrayUserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN_SQUARE)) input_data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2)) initial_centers = numpy.array([[3.5, 4.8], [6.9, 7], [7.5, 0.5]]) KmediansTestTemplates.templateLengthProcessData(input_data, initial_centers, [10, 5, 8], True, metric=metric) def testClusterAllocationSample1WrongInitialNumberCenters1Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[2.8, 9.5], [3.5, 6.6], [1.3, 4.0]], None, True) def testClusterAllocationSample1WrongInitialNumberCenters2Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[2.8, 9.5], [3.5, 6.6], [1.3, 4.0], [1.2, 4.5]], None, True) def testClusterAllocationSample2WrongInitialNumberCentersCore(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5], [7.3, 4.5], [3.1, 5.4]], None, True) def testClusterTheSameData1Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [ [4.1], [7.3] ], [10, 20], True) def testClusterTheSameData2Core(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [ [1.1, 1.0], [3.0, 3.1], [5.0, 4.9] ], [5, 5, 5], True) def testOddSize(self): # Bug issue #428 (https://github.com/annoviko/pyclustering/issues/428) data = [[59.00732, 9.748167], [59.00608, 9.749117], [59.0047, 9.749933]] KmediansTestTemplates.templateLengthProcessData(data, [[59.00732, 9.748167], [59.00608, 9.749117]], None, True, tolerance=10) def testClusterAllocationOneDimensionDataCore(self): KmediansTestTemplates.templateClusterAllocationOneDimensionData(True) def testClusterAllocationTheSameObjectsOneInitialCenterCore(self): KmediansTestTemplates.templateClusterAllocationTheSameObjects(20, 1, True) def testClusterAllocationTheSameObjectsTwoInitialCentersCore(self): KmediansTestTemplates.templateClusterAllocationTheSameObjects(15, 2, True) def testClusterAllocationTheSameObjectsThreeInitialCentersCore(self): KmediansTestTemplates.templateClusterAllocationTheSameObjects(25, 3, True) def testClusterAllocationSampleRoughMediansSimple10ByCore(self): initial_medians = [[0.0772944481804071, 0.05224990900863469], [1.6021689021213712, 1.0347579135245601], [2.3341008076636096, 1.280022869739064]] KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, initial_medians, None, True) def testCoreInterfaceIntInputData(self): kmedians_instance = kmedians([ [1], [2], [3], [20], [21], [22] ], [ [2], [21] ], ccore=True) kmedians_instance.process() assert len(kmedians_instance.get_clusters()) == 2 @remove_library def testProcessingWhenLibraryCoreCorrupted(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True) def testItermax0ByCore(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [], True, itermax=0) def testItermax1ByCore(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, itermax=1) def testItermax10Simple01ByCore(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], True, itermax=10) def testItermax10Simple02ByCore(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], True, itermax=10) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_kmedoids.py000077500000000000000000000374671375753423500272660ustar00rootroot00000000000000"""! @brief Integration-tests for K-Medoids algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.kmedoids_templates import kmedoids_test_template from pyclustering.cluster.kmedoids import kmedoids from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS from pyclustering.utils import read_sample from pyclustering.utils.metric import type_metric, distance_metric from pyclustering.core.tests import remove_library class KmedoidsIntegrationTest(unittest.TestCase): def testClusterAllocationSampleSimple1ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], True) def testClusterAllocationSampleSimple1WrongInitials1ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [1, 2, 3, 4], [2, 2, 3, 3], True) def testClusterAllocationSampleSimple1DistanceMatrixByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], True, data_type='distance_matrix') def testClusterAllocationSampleSimple1EuclideanByCore(self): metric = distance_metric(type_metric.EUCLIDEAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1EuclideanDistanceMatrixByCore(self): metric = distance_metric(type_metric.EUCLIDEAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterAllocationSampleSimple1SquareEuclideanByCore(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1SquareEuclideanDistanceMatrixByCore(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterAllocationSampleSimple1ManhattanByCore(self): metric = distance_metric(type_metric.MANHATTAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1ManhattanDistanceMatrixByCore(self): metric = distance_metric(type_metric.MANHATTAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterAllocationSampleSimple1ChebyshevByCore(self): metric = distance_metric(type_metric.CHEBYSHEV) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1ChebyshevDistanceMatrixByCore(self): metric = distance_metric(type_metric.CHEBYSHEV) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterAllocationSampleSimple1MinkowskiByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2.0) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1MinkowskiDistanceMatrixByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2.0) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterAllocationSampleSimple1GowerByCore(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1GowerDistanceMatrixByCore(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterAllocationSampleSimple1UserDefinedByCore(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True) def testClusterAllocationSampleSimple1UserDefinedDistanceMatrixByCore(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, True, data_type='distance_matrix') def testClusterOneAllocationSampleSimple1ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5], [10], True) def testClusterOneAllocationSampleSimple1DistanceMatrixByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5], [10], True, data_type='distance_matrix') def testClusterAllocationSampleSimple2ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [3, 12, 20], [10, 5, 8], True) def testClusterAllocationSampleSimple2DistanceMatrixByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [3, 12, 20], [10, 5, 8], True, data_type='distance_matrix') def testClusterOneAllocationSampleSimple2ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10], [23], True) def testClusterOneAllocationSampleSimple2DistanceMatrixByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10], [23], True, data_type='distance_matrix') def testClusterAllocationSampleSimple3ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [4, 12, 25, 37], [10, 10, 10, 30], True) def testClusterOneAllocationSampleSimple3ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [30], [60], True) def testClusterAllocationSampleSimple5ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [4, 18, 34, 55], [15, 15, 15, 15], True) def testClusterOneAllocationSampleSimple5ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [35], [60], True) def testClusterTheSameData1ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [2, 20], [10, 20], True) def testClusterTheSameData2ByCore(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [2, 7, 12], [5, 5, 5], True) def testClusterAllocationTheSameObjectsOneInitialMedoidByCore(self): kmedoids_test_template.templateClusterAllocationTheSameObjects(20, 1, True) def testClusterAllocationTheSameObjectsTwoInitialMedoidsByCore(self): kmedoids_test_template.templateClusterAllocationTheSameObjects(15, 2, True) def testClusterAllocationTheSameObjectsThreeInitialMedoidsByCore(self): kmedoids_test_template.templateClusterAllocationTheSameObjects(25, 3, True) def testCoreInterfaceIntInputData(self): kmedoids_instance = kmedoids([[1], [2], [3], [20], [21], [22]], [2, 5], 0.025, True) kmedoids_instance.process() assert len(kmedoids_instance.get_clusters()) == 2 def testAllocatedRequestedClustersSampleSimple04ByCore(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 10, None, True) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 25, None, True) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 40, None, True) def testAllocatedRequestedClustersWithTheSamePointsByCore(self): # Bug issue #366 - Kmedoids returns incorrect number of clusters. sample = [[0.0, 0.0], [0.1, 0.1], [0.0, 0.0], [0.1, 0.2]] kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 3, None, True) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 3, None, True) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 2, None, True) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 1, None, True) def testAllocatedRequestedClustersWithTheSamePoints2(self): sample = [[0.23, 0.2], [-0.1, 0.1], [0.0, 0.9], [0.1, -0.2], [0.8, 0.1], [-0.1, 0.1], [-0.4, -0.2], [0.0, 0.9]] answers = [1, 2, 3, 4, 5, 6, 6, 6] for expected_amount in answers: kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, expected_amount, None, True) def testAllocatedRequestedClustersWithTotallyTheSamePointsByCore(self): # Bug issue #366 - Kmedoids returns incorrect number of clusters. sample = [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 1, None, True) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], True) def testItermax0(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [], True, itermax=0) def testItermax1(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], True, itermax=1) def testItermax10Simple01(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], True, itermax=10) def testItermax10Simple02(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [3, 12, 20], [10, 5, 8], True, itermax=10) def testSimple01AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, True, random_state=1000) def testSimple01AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, True, random_state=1000, data_type='distance_matrix') def testSimple02AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, True, random_state=1000) def testSimple02AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, True, random_state=1000, data_type='distance_matrix') def testSimple03AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, True, random_state=1000) def testSimple03AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, True, random_state=1000, data_type='distance_matrix') def testSimple04AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, True, random_state=1000) def testSimple04AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, True, random_state=1000, data_type='distance_matrix') def testSimple05AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, True, random_state=1000) def testSimple05AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, True, random_state=1000, data_type='distance_matrix') def testSimple06AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, True, random_state=1000) def testSimple06AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, True, random_state=1000, data_type='distance_matrix') def testSimple07AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, True, random_state=1000) def testSimple07AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, True, random_state=1000, data_type='distance_matrix') def testSimple08AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, True, random_state=1000) def testSimple08AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, True, random_state=1000, data_type='distance_matrix') def testSimple09AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, True, random_state=1000) def testSimple09AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, True, random_state=1000, data_type='distance_matrix') def testSimple10AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, True, random_state=1000) def testSimple10AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, True, random_state=1000, data_type='distance_matrix') def testSimple11AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, True, random_state=1000) def testSimple11AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, True, random_state=1000, data_type='distance_matrix') def testSimple12AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, True, random_state=1000) def testSimple12AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, True, random_state=1000, data_type='distance_matrix') def testSimple13AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, True, random_state=1000) def testSimple13AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, True, random_state=1000, data_type='distance_matrix') pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_mbsas.py000077500000000000000000000105741375753423500265620ustar00rootroot00000000000000"""! @brief Integration-tests for MBSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.core.tests import remove_library; from pyclustering.cluster.tests.mbsas_templates import mbsas_test_template; from pyclustering.utils.metric import type_metric, distance_metric; from pyclustering.samples.definitions import SIMPLE_SAMPLES; class mbsas_integration_test(unittest.TestCase): def testClusteringSampleSimple1(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 1.0, [5, 5], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 1.0, [10], True); def testClusteringSampleSimple1Euclidean(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True, metric=distance_metric(type_metric.EUCLIDEAN)); def testClusteringSampleSimple1EuclideanSquare(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 100.0, [10], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); def testClusteringSampleSimple1Manhattan(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.MANHATTAN)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True, metric=distance_metric(type_metric.MANHATTAN)); def testClusteringSampleSimple1Chebyshev(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True, metric=distance_metric(type_metric.CHEBYSHEV)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], True, metric=distance_metric(type_metric.CHEBYSHEV)); def testClusteringSampleSimple2(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1.0, [5, 8, 10], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 10.0, [23], True); def testClusteringSampleSimple3(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 2.0, [10, 10, 10, 30], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 10.0, [60], True); def testOneDimentionalPoints1(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1.0, [10, 10], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 10.0, [20], True); def testOneDimentionalPoints2(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 1.0, [10, 20], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 10.0, [30], True); def testThreeDimentionalPoints(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 1.0, [10, 10], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 10.0, [20], True); def testTheSamePoints1(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 1.0, [5, 5, 5], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 30, 1.0, [5, 5, 5], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 10.0, [15], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 1.0, [15], True); def testTheSamePoints2(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 1.0, [10, 20], True); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 10.0, [30], True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_optics.py000077500000000000000000000133261375753423500267540ustar00rootroot00000000000000"""! @brief Integration-tests for OPTICS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.optics_templates import OpticsTestTemplates from pyclustering.cluster.optics import optics from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.core.tests import remove_library class OpticsIntegrationTest(unittest.TestCase): def testClusteringSampleSimple1ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, None, [5, 5], True) def testClusteringSampleSimple1DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, None, [5, 5], True) def testClusteringSampleSimple2ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, None, [5, 8, 10], True) def testClusteringSampleSimple2DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, None, [5, 8, 10], True) def testClusteringSampleSimple3ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, None, [10, 10, 10, 30], True) def testClusteringSampleSimple3DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, None, [10, 10, 10, 30], True) def testClusteringSampleSimple4ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, None, [15, 15, 15, 15, 15], True) def testClusteringSampleSimple4DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, None, [15, 15, 15, 15, 15], True) def testClusteringSampleSimple5ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, None, [15, 15, 15, 15], True) def testClusteringSampleSimple5DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, None, [15, 15, 15, 15], True) def testClusteringHeptaByCore(self): OpticsTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3, None, [30, 30, 30, 30, 30, 30, 32], True) def testClusteringOneDimensionDataSampleSimple7ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2.0, 2, None, [10, 10], True) def testClusteringOneDimensionDataSampleSimple7DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2.0, 2, None, [10, 10], True) def testClusteringOneDimensionDataSampleSimple9ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3.0, 3, None, [10, 20], True) def testClusteringOneDimensionDataSampleSimple9DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3.0, 3, None, [10, 20], True) def testClusteringThreeDimensionalSimple11ByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2.0, 2, None, [10, 10], True) OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 3.0, 2, None, [10, 10], True) def testClusteringTheSameData2ByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, None, [5, 5, 5], True) def testClusteringTheSameData2DistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, None, [5, 5, 5], True) def testClusteringTheSameData2OneClusterByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 20.0, 2, None, [15], True) def testClusteringTheSameData2OneClusterDistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 20.0, 2, None, [15], True) def testClusteringSampleSimple2RadiusGreaterByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5.0, 2, 3, [5, 8, 10], True) def testClusteringSampleSimple2RadiusGreaterDistanceMatrixByCore(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5.0, 2, 3, [5, 8, 10], True) def testClusteringSampleSimple3RadiusGreaterByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5.0, 3, 4, [10, 10, 10, 30], True) def testClusteringSampleSimple4RadiusGreaterByCore(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 6.0, 3, 5, [15, 15, 15, 15, 15], True) def testClusteringLsunRadiusGreaterByCore(self): OpticsTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_LSUN, 1.0, 3, 3, [99, 100, 202], True) def testCoreInterfaceIntInputData(self): optics_instance = optics([ [1], [2], [3], [20], [21], [22] ], 3, 2, 2, True) optics_instance.process() assert len(optics_instance.get_clusters()) == 2; @remove_library def testProcessingWhenLibraryCoreCorrupted(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, None, [5, 5], True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_rock.py000077500000000000000000000051771375753423500264160ustar00rootroot00000000000000"""! @brief Integration-tests for ROCK algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.cluster.tests.rock_templates import RockTestTemplates; from pyclustering.cluster.rock import rock; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.core.tests import remove_library; class RockIntegrationTest(unittest.TestCase): def testClusterAllocationByCore(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 0.5, [5, 5], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 1, 0.5, [10], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 0.5, [10, 5, 8], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 1, 0.5, [23], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 0.5, [10, 10, 10, 30], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1.7, 4, 0.5, [10, 10, 10, 30], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 0.5, [15, 15, 15, 15, 15], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1.5, 5, 0.5, [15, 15, 15, 15, 15], True); RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 0.5, [15, 15, 15, 15], True); def testClusterAllocationByCoreIncorrectNumberOfClusters(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 4, 0.5, [15, 15, 15, 15, 15], True); def testClusterTheSameData1ByCore(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, 2, 0.5, [10, 20], True); def testClusterTheSameData2ByCore(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 2, 0.5, [5, 5, 5], True); def testClusterAllocationOneDimensionDataByCore(self): RockTestTemplates.templateClusterAllocationOneDimensionData(True); def testCoreInterfaceIntInputData(self): optics_instance = rock([ [1], [2], [3], [20], [21], [22] ], 3, 2, 0.5, True); optics_instance.process(); assert len(optics_instance.get_clusters()) == 2; @remove_library def testProcessingWhenLibraryCoreCorrupted(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 0.5, [5, 5], True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_silhouette.py000077500000000000000000000247201375753423500276400ustar00rootroot00000000000000"""! @brief Integration-tests for Silhouette algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.silhouette import silhouette_ksearch_type from pyclustering.cluster.tests.silhouette_templates import silhouette_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS class silhouette_integration_tests(unittest.TestCase): def test_correct_score_simple01(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, True) def test_correct_score_simple02(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, True) def test_correct_score_simple03(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, True) def test_correct_score_simple04(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, True) def test_correct_score_simple05(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, True) def test_correct_score_simple06(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, True) def test_correct_score_simple07(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, True) def test_correct_score_simple08(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, True) def test_correct_ksearch_simple01(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple01_kmedoids(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEDOIDS, True) def test_correct_ksearch_simple01_kmedians(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEDIANS, True) def test_correct_ksearch_simple02(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple02_kmedoids(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEDOIDS, True) def test_correct_ksearch_simple02_kmedians(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEDIANS, True) def test_correct_ksearch_simple03(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple03_kmedoids(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEDOIDS, True) def test_correct_ksearch_simple03_kmedians(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEDIANS, True) def test_correct_ksearch_simple05(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple06(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple07(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple08(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple09(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple10(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple11(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple12(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_correct_ksearch_simple13(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, 2, 10, silhouette_ksearch_type.KMEANS, True) def test_distance_matrix_sample01(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, True) def test_distance_matrix_sample02(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, True) def test_distance_matrix_sample03(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, True) def test_distance_matrix_sample04(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, True) def test_distance_matrix_sample05(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, True) def test_distance_matrix_sample06(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, True) def test_distance_matrix_sample07(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, True) def test_random_state_1_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 1, True) def test_random_state_2_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 2, True) def test_random_state_4_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 4, True) def test_random_state_8_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 8, True) def test_random_state_16_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 16, True) def test_random_state_128_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 128, True) def test_random_state_1024_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 1024, True) def test_random_state_1_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 1, True) def test_random_state_2_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 2, True) def test_random_state_4_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 4, True) def test_random_state_128_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 128, True) def test_random_state_1024_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 1024, True) def test_random_state_1_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDOIDS, 1, True) def test_random_state_2_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 2, True) def test_random_state_4_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 4, True) def test_random_state_128_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 128, True) def test_random_state_1024_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 1024, True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_somsc.py000077500000000000000000000110631375753423500265730ustar00rootroot00000000000000"""! @brief Integration-tests for SOM-SC algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.somsc_templates import SyncnetTestTemplates from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.core.tests import remove_library class SomscIntegrationTest(unittest.TestCase): def testClusterAllocationSampleSimple1ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], True) def testClusterOneAllocationSampleSimple1ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, [10], True) def testClusterAllocationSampleSimple2ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [10, 5, 8], True) def testClusterOneAllocationSampleSimple2ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, [23], True) def testClusterAllocationSampleSimple3ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [10, 10, 10, 30], True) def testClusterOneAllocationSampleSimple3ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, [60], True) def testClusterAllocationSampleSimple4ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, [15, 15, 15, 15, 15], True) def testClusterOneAllocationSampleSimple4ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, [75], True) def testClusterAllocationSampleSimple5ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, [15, 15, 15, 15], True) def testClusterOneAllocationSampleSimple5ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, [60], True) def testClusterOneDimensionSampleSimple7ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, [10, 10], True) def testClusterOneDimensionSampleSimple8ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 4, None, True) def testWrongNumberOfCentersSimpleSample1ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, None, True) def testWrongNumberOfCentersSimpleSample2ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 4, None, True) def testClusterTheSameData1ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, [10, 20], True) def testClusterTheSameData2ByCore(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, [5, 5, 5], True) def testClusterAllocationOneDimensionDataByCore(self): SyncnetTestTemplates().templateClusterAllocationOneDimensionData(True) def test_predict_one_point_ccore(self): SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[0.3, 0.2]], [0], True) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[4.1, 1.1]], [1], True) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 1.9]], [2], True) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 4.1]], [3], True) def test_predict_two_points_ccore(self): SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[0.3, 0.2], [2.1, 1.9]], [0, 2], True) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 4.1], [2.1, 1.9]], [3, 2], True) def test_predict_four_points_ccore(self): to_predict = [[0.3, 0.2], [4.1, 1.1], [2.1, 1.9], [2.1, 4.1]] SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, to_predict, [0, 1, 2, 3], True) def test_predict_five_points_ccore(self): to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, to_predict, [0, 1, 1, 2, 3], True) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], True) pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_syncnet.py000077500000000000000000000203231375753423500271310ustar00rootroot00000000000000"""! @brief Integration-tests for Sync algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from numpy import pi; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet import initial_type, conn_represent, solve_type; from pyclustering.cluster.tests.syncnet_templates import SyncnetTestTemplates; from pyclustering.cluster.syncnet import syncnet; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.core.tests import remove_library; class SyncnetIntegrationTest(unittest.TestCase): def testClusteringSampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [5, 5], True); def testClusteringSampleSimple2ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [5, 8, 10], True); def testClusteringSampleSimple3ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [10, 10, 10, 30], True); def testClusteringSampleSimple4ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [15, 15, 15, 15, 15], True); def testClusteringSampleSimple5ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [15, 15, 15, 15], True); def testClusteringSampleElongateByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 0.5, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [135, 20], True); def testClusterAllocationHighToleranceSampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, None, [10], True); def testClusterAllocationHighToleranceSampleSimple2ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, None, [23], True); def testClusterAllocationHighToleranceSampleSimple3ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, None, [60], True); def testClusterAllocationHighToleranceSampleSimple4ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, None, [75], True); def testClusterAllocationHighToleranceSampleSimple5ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, None, [60], True); def testClusteringTheSameData1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [10, 20], True); def testClusteringTheSameData2ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5, 5], True); def testClusterAllocationConnWeightSampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, None, [5, 5], True); SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, None, [10], True); def testClusterAllocationConnWeightSampleSimple2ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, None, [5, 8, 10], True); SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 10, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, None, [23], True); def testClusteringWithoutDynamicCollectingSampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [5, 5], True); def testClusteringWithoutDynamicCollectingSampleSimple2ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [5, 8, 10], True); def testClusteringWithoutDynamicCollectingSampleSimple3ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [10, 10, 10, 30], True); def testClusteringRandomInitialSampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [5, 5], True); def testClusteringRandomInitialSampleSimple2ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, None, [5, 8, 10], True); def testClusteringSolverRK4SampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.RK4, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5], True); def testClusteringSolverRKF45SampleSimple1ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.RKF45, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5], True); def testClusteringOneDimensionDataSampleSimple7ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 0.999, solve_type.FAST, initial_type.EQUIPARTITION, True, False, 0.05, conn_represent.MATRIX, [10, 10], True); def testClusteringOneDimensionDataSampleSimple9ByCore(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 0.999, solve_type.FAST, initial_type.EQUIPARTITION, True, False, 0.05, conn_represent.MATRIX, [20, 10], True); def testConnectionApiByCore(self): SyncnetTestTemplates.templateConnectionApi(conn_represent.MATRIX, True); SyncnetTestTemplates.templateConnectionApi(conn_represent.LIST, True); def testShowNetwork2DimensionByCore(self): SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, True); SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2.0, True); def testShowNetwork3DimensionByCore(self): SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1.0, True); def testCoreInterfaceIntInputData(self): result = False; for _ in range(0, 20, 1): syncnet_instance = syncnet([ [1], [2], [3], [20], [21], [22] ], 3, conn_represent.MATRIX, initial_type.EQUIPARTITION, ccore = True); analyser = syncnet_instance.process(0.999, solve_type.FAST); result = (len(analyser.allocate_clusters(0.1)) == 2); if (result is True): break; assert True == result; @remove_library def testProcessingWhenLibraryCoreCorrupted(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, None, [5, 5], True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_ttsas.py000077500000000000000000000076611375753423500266160ustar00rootroot00000000000000"""! @brief Integration-tests for TTSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.core.tests import remove_library; from pyclustering.cluster.tests.ttsas_template import ttsas_test; from pyclustering.utils.metric import type_metric, distance_metric; from pyclustering.samples.definitions import SIMPLE_SAMPLES; class ttsas_integration_tests(unittest.TestCase): def testClusteringSampleSimple1(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], True); def testClusteringSampleSimple1Euclidean(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], True, metric=distance_metric(type_metric.EUCLIDEAN)); def testClusteringSampleSimple1EuclideanSquare(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [5, 5], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 100.0, 200.0, [10], True, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); def testClusteringSampleSimple1Manhattan(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], True, metric=distance_metric(type_metric.MANHATTAN)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], True, metric=distance_metric(type_metric.MANHATTAN)); def testClusteringSampleSimple1Chebyshev(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], True, metric=distance_metric(type_metric.CHEBYSHEV)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], True, metric=distance_metric(type_metric.CHEBYSHEV)); def testClusteringSampleSimple2(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1.0, 2.0, [5, 8, 10], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 10.0, 20.0, [23], True); def testClusteringSampleSimple3(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1.0, 2.0, [10, 10, 10, 30], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 10.0, 20.0, [60], True); def testOneDimentionalPoints1(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 1.0, 2.0, [10, 10], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 10.0, 20.0, [20], True); def testOneDimentionalPoints2(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 2.0, [10, 20], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 10.0, 20.0, [30], True); def testThreeDimentionalPoints(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1.0, 2.0, [10, 10], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 10.0, 20.0, [20], True); def testTheSamePoints1(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 1.5, [5, 5, 5], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 0.001, 0.002, [5, 5, 5], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1000, 2000, [15], True); def testTheSamePoints2(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 2.0, [10, 20], True); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 10.0, 20.0, [30], True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], True); pyclustering-0.10.1.2/pyclustering/cluster/tests/integration/it_xmeans.py000077500000000000000000000641351375753423500267520ustar00rootroot00000000000000"""! @brief Integration-tests for X-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.xmeans_templates import XmeansTestTemplates from pyclustering.cluster.xmeans import xmeans, splitting_type from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.core.tests import remove_library from pyclustering.utils import read_sample from pyclustering.utils.metric import distance_metric, type_metric class XmeansIntegrationTest(unittest.TestCase): def testBicClusterAllocationSampleSimple1ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple1RepeatByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, repeat=2) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, repeat=4) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, repeat=8) def testBicSampleSimple1WithoutInitialCentersByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicSampleSimple1WithoutInitialCentersRepeatByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, repeat=5) def testBicSampleSimple1MaxLessRealByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 1, True) def testBicSampleSimple1MaxLessRealRepeatByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 1, True, repeat=5) def testBicWrongStartClusterAllocationSampleSimple1ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicWrongStartClusterAllocationSampleSimpleRepeat1ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, repeat=5) def testMndlClusterAllocationSampleSimple1ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.1, beta=0.1) def testMndlSampleSimple1WithoutInitialCentersByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.1, beta=0.1) def testMndlWrongStartClusterAllocationSampleSimple1ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.1, beta=0.1) def testBicClusterAllocationSampleSimple1EuclideanByCore(self): metric = distance_metric(type_metric.EUCLIDEAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1EuclideanSquareByCore(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricManhattanByCore(self): metric = distance_metric(type_metric.MANHATTAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricChebyshevByCore(self): metric = distance_metric(type_metric.CHEBYSHEV) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricMinkowski2ByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricMinkowski4ByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=4) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricCanberraByCore(self): metric = distance_metric(type_metric.CANBERRA) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricChiSquareByCore(self): metric = distance_metric(type_metric.CHI_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testBicClusterAllocationSampleSimple1MetricGowerByCore(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricEuclideanByCore(self): metric = distance_metric(type_metric.EUCLIDEAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricEuclideanSquareByCore(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric, alpha=0.1, beta=0.1) def testMndlClusterAllocationSampleSimple1MetricManhattanByCore(self): metric = distance_metric(type_metric.MANHATTAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricChebyshevByCore(self): metric = distance_metric(type_metric.CHEBYSHEV) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricMinkowski2ByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricMinkowski4ByCore(self): metric = distance_metric(type_metric.MINKOWSKI, degree=4) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricCanberraByCore(self): metric = distance_metric(type_metric.CANBERRA) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testMndlClusterAllocationSampleSimple1MetricChiSquareByCore(self): metric = distance_metric(type_metric.CHI_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric, alpha=0.1, beta=0.1, random_state=1000) def testMndlClusterAllocationSampleSimple1MetricGowerByCore(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, metric=metric) def testBicClusterAllocationSampleSimple2ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicMaxLessRealSampleSimple2ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 2, True) def testBicWrongStartClusterAllocationSampleSimple2ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7]], [10, 5, 8], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, random_state=1000) def testMndlClusterAllocationSampleSimple2ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.1, beta=0.1) def testMndlWrongStartClusterAllocationSampleSimple2ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7]], [10, 5, 8], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.1, beta=0.1, random_state=1000) def testBicClusterAllocationSampleSimple3ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationMaxLessRealSampleSimple3ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 3, True) def testBicWrongStartClusterClusterAllocationSampleSimple3ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 4, True) def testBicWrongStartClusterAllocationSampleSimple3ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [5.9, 5.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, random_state=10, alpha=0.2, beta=0.2) def testMndlClusterAllocationSampleSimple3ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.2, beta=0.2) def testBicClusterAllocationSampleSimple4ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicWrongStartClusterAllocationSampleSimple4ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0]], [15, 15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, random_state=1000) def testBicClusterAllocationMaxLessRealSampleSimple4ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 4.0]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 2, True) def testMndlClusterAllocationSampleSimple4ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True) def testMndlWrongStartClusterAllocationSampleSimple4ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0]], [15, 15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True) def testMndlClusterAllocationMaxLessRealSampleSimple4ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 4.0]], None, splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 2, True) def testBicClusterAllocationSampleSimple5ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicWrongStartClusterAllocationSampleSimple5ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0]], [15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testMndlClusterAllocationSampleSimple5ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True) def testMndlWrongStartClusterAllocationSampleSimple5ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0]], [15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, random_state=1000) def testBicClusterAllocationSampleSimple6ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, [[3.5, 3.5], [3.7, 3.7]], [20, 21], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple6WithoutInitialByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, None, [20, 21], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testMndlClusterAllocationSampleSimple6ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, [[3.5, 3.5], [3.7, 3.7]], [20, 21], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True) def testMndlClusterAllocationSampleSimple6WithoutInitialByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, None, [20, 21], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True) def testBicClusterAllocationSampleSimple7ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[1], [2]], [10, 10], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple7WithoutInitialByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, None, [10, 10], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testMndlClusterAllocationSampleSimple7ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[1], [2]], [10, 10], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.01, beta=0.01) def testMndlClusterAllocationSampleSimple7WithoutInitialByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, None, [10, 10], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.01, beta=0.01) def testBicClusterAllocationSampleSimple8ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple8WrongAmountCentersByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple8WrongAmountCentersRandomStateByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, random_state=1000) def testMndlClusterAllocationSampleSimple8WrongAmountCenters(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True, alpha=0.2, beta=0.2) def testBicClusterAllocationSampleSimple8WrongAmountCentersRandomState(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, random_state=1000) def testMndlClusterAllocationSampleSimple8WrongAmountCentersRandomState(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True, random_state=1000) def testBicClusterAllocationSampleSimple9ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [[3.0], [6.0]], [10, 20], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple9WithoutInitialByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, None, [10, 20], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple10ByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, [[0.0, 0.3], [4.5, 3.4], [10.1, 10.6]], [11, 11, 11], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleSimple10WithoutInitialByCore(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, None, [11, 11, 11], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicClusterAllocationSampleTwoDiamondsByCore(self): XmeansTestTemplates.templateLengthProcessData(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.8, 0.2], [3.0, 0.0]], [400, 400], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testBicWrongStartClusterAllocationSampleTwoDiamondsByCore(self): XmeansTestTemplates.templateLengthProcessData(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.8, 0.2]], [400, 400], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) def testMndlClusterAllocationSampleTwoDiamondsByCore(self): XmeansTestTemplates.templateLengthProcessData(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.8, 0.2], [3.0, 0.0]], [400, 400], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, True) def testClusterAllocationOneDimensionDataByCore(self): XmeansTestTemplates.templateClusterAllocationOneDimensionData(True) def testCoreInterfaceIntInputData(self): xmeans_instance = xmeans([[1], [2], [3], [20], [21], [22]], [[2], [21]], 5, ccore=True) xmeans_instance.process() assert len(xmeans_instance.get_clusters()) == 2 def testKmax05Amount5Offset02Initial01ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 10, 5, 2, 1, 5) def testKmax05Amount5Offset02Initial02ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 10, 5, 2, 2, 5) def testKmax05Amount10Offset02Initial03ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 10, 10, 2, 3, 5) def testKmax05Amount10Offset02Initial04ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 10, 10, 2, 4, 5) def testKmax05Amount10Offset02Initial05ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 10, 10, 2, 5, 5) def testKmax05Amount20Offset02Initial05ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 20, 10, 2, 5, 5) def testKmax05Amount01Offset01Initial04ByCore(self): XmeansTestTemplates.templateMaxAllocatedClusters(True, 1, 1000, 1, 4, 5) def testPredictOnePointByCore(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2]], 4, [0], True) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[4.1, 1.1]], 4, [1], True) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 1.9]], 4, [2], True) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1]], 4, [3], True) def testPredictTwoPointsByCore(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2], [2.1, 1.9]], 4, [0, 2], True) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1], [2.1, 1.9]], 4, [3, 2], True) def test_random_state_1_by_core(self): XmeansTestTemplates.random_state(True, 2, 10, 1) def test_random_state_2_by_core(self): XmeansTestTemplates.random_state(True, 2, 10, 2) def test_random_state_4_by_core(self): XmeansTestTemplates.random_state(True, 2, 10, 4) def test_random_state_32_by_core(self): XmeansTestTemplates.random_state(True, 2, 10, 32) def test_random_state_1024_by_core(self): XmeansTestTemplates.random_state(True, 2, 10, 1024) def test_random_state_65536_by_core(self): XmeansTestTemplates.random_state(True, 2, 10, 65536) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, True) pyclustering-0.10.1.2/pyclustering/cluster/tests/kmeans_templates.py000077500000000000000000000131571375753423500257720ustar00rootroot00000000000000"""! @brief Test templates for K-Means clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.tests.assertion import assertion from pyclustering.cluster.encoder import type_encoding, cluster_encoder from pyclustering.cluster.kmeans import kmeans, kmeans_observer, kmeans_visualizer from pyclustering.utils import read_sample from pyclustering.utils.metric import distance_metric, type_metric from random import random import numpy class KmeansTestTemplates: @staticmethod def templateLengthProcessData(data, start_centers, expected_cluster_length, ccore, **kwargs): if isinstance(data, str): sample = read_sample(data) else: sample = data metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) itermax = kwargs.get('itermax', 200) kmeans_instance = kmeans(sample, start_centers, 0.001, ccore, metric=metric, itermax=itermax) kmeans_instance.process() clusters = kmeans_instance.get_clusters() centers = kmeans_instance.get_centers() wce = kmeans_instance.get_total_wce() if itermax == 0: assertion.eq(start_centers, centers) assertion.eq([], clusters) assertion.eq(0.0, wce) return expected_wce = 0.0 for index_cluster in range(len(clusters)): for index_point in clusters[index_cluster]: expected_wce += metric(sample[index_point], centers[index_cluster]) assertion.eq(expected_wce, wce) obtained_cluster_sizes = [len(cluster) for cluster in clusters] assertion.eq(len(sample), sum(obtained_cluster_sizes)) assertion.eq(len(clusters), len(centers)) for center in centers: assertion.eq(len(sample[0]), len(center)) if expected_cluster_length is not None: obtained_cluster_sizes.sort() expected_cluster_length.sort() assertion.eq(obtained_cluster_sizes, expected_cluster_length) @staticmethod def templatePredict(path_to_file, initial_centers, points, expected_closest_clusters, ccore, **kwargs): sample = read_sample(path_to_file) metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) itermax = kwargs.get('itermax', 200) kmeans_instance = kmeans(sample, initial_centers, 0.001, ccore, metric=metric, itermax=itermax) kmeans_instance.process() closest_clusters = kmeans_instance.predict(points) assertion.eq(len(expected_closest_clusters), len(closest_clusters)) assertion.true(numpy.array_equal(numpy.array(expected_closest_clusters), closest_clusters)) @staticmethod def templateClusterAllocationOneDimensionData(ccore_flag): input_data = [ [random()] for _ in range(10) ] + [ [random() + 3] for _ in range(10) ] + [ [random() + 5] for _ in range(10) ] + [ [random() + 8] for _ in range(10) ] kmeans_instance = kmeans(input_data, [ [0.0], [3.0], [5.0], [8.0] ], 0.025, ccore_flag) kmeans_instance.process() clusters = kmeans_instance.get_clusters() assertion.eq(4, len(clusters)) for cluster in clusters: assertion.eq(10, len(cluster)) @staticmethod def templateEncoderProcedures(filename, initial_centers, number_clusters, ccore_flag): sample = read_sample(filename) kmeans_instance = kmeans(sample, initial_centers, 0.025, ccore_flag) kmeans_instance.process() clusters = kmeans_instance.get_clusters() encoding = kmeans_instance.get_cluster_encoding() encoder = cluster_encoder(encoding, clusters, sample) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) encoder.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assertion.eq(number_clusters, len(clusters)) @staticmethod def templateCollectEvolution(filename, initial_centers, number_clusters, ccore_flag): sample = read_sample(filename) observer = kmeans_observer() kmeans_instance = kmeans(sample, initial_centers, 0.025, ccore_flag, observer=observer) kmeans_instance.process() assertion.le(1, len(observer)) for i in range(len(observer)): assertion.le(1, len(observer.get_centers(i))) for center in observer.get_centers(i): assertion.eq(len(sample[0]), len(center)) assertion.le(1, len(observer.get_clusters(i))) @staticmethod def templateShowClusteringResultNoFailure(filename, initial_centers, ccore_flag): sample = read_sample(filename) kmeans_instance = kmeans(sample, initial_centers, 0.025, ccore_flag) kmeans_instance.process() clusters = kmeans_instance.get_clusters() centers = kmeans_instance.get_centers() kmeans_visualizer.show_clusters(sample, clusters, centers, initial_centers) @staticmethod def templateAnimateClusteringResultNoFailure(filename, initial_centers, ccore_flag): sample = read_sample(filename) observer = kmeans_observer() kmeans_instance = kmeans(sample, initial_centers, 0.025, ccore_flag, observer=observer) kmeans_instance.process() kmeans_visualizer.animate_cluster_allocation(sample, observer) pyclustering-0.10.1.2/pyclustering/cluster/tests/kmedians_templates.py000077500000000000000000000100141375753423500262740ustar00rootroot00000000000000"""! @brief Test templates for K-Medians clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.tests.assertion import assertion from pyclustering.cluster.kmedians import kmedians from pyclustering.utils import read_sample, distance_metric, type_metric from random import random import numpy class KmediansTestTemplates: @staticmethod def templateLengthProcessData(data, start_medians, expected_cluster_length, ccore, **kwargs): tolerance = kwargs.get('tolerance', 0.01) metric = kwargs.get('metric', None) itermax = kwargs.get('itermax', 200) if isinstance(data, str): sample = read_sample(data) else: sample = data kmedians_instance = kmedians(sample, start_medians, tolerance, ccore, metric=metric, itermax=itermax) kmedians_instance.process() clusters = kmedians_instance.get_clusters() medians = kmedians_instance.get_medians() wce = kmedians_instance.get_total_wce() if itermax == 0: assert clusters == [] assert start_medians == medians assert 0.0 == wce return obtained_cluster_sizes = [len(cluster) for cluster in clusters] assert len(sample) == sum(obtained_cluster_sizes) assert len(medians) == len(clusters) if expected_cluster_length is not None: obtained_cluster_sizes.sort() expected_cluster_length.sort() if obtained_cluster_sizes != expected_cluster_length: print(obtained_cluster_sizes) assert obtained_cluster_sizes == expected_cluster_length @staticmethod def templateClusterAllocationOneDimensionData(ccore): input_data = [ [random()] for i in range(10) ] + [ [random() + 3] for i in range(10) ] + [ [random() + 5] for i in range(10) ] + [ [random() + 8] for i in range(10) ] kmedians_instance = kmedians(input_data, [ [0.0], [3.0], [5.0], [8.0] ], 0.025, ccore) kmedians_instance.process() clusters = kmedians_instance.get_clusters() assert len(clusters) == 4 for cluster in clusters: assert len(cluster) == 10 @staticmethod def templateClusterAllocationTheSameObjects(number_objects, number_clusters, ccore_flag): value = random() input_data = [ [value] ] * number_objects initial_centers = [] for i in range(number_clusters): initial_centers.append([ random() ]) kmedians_instance = kmedians(input_data, initial_centers, ccore=ccore_flag) kmedians_instance.process() clusters = kmedians_instance.get_clusters() object_mark = [False] * number_objects allocated_number_objects = 0 for cluster in clusters: for index_object in cluster: assert (object_mark[index_object] is False) # one object can be in only one cluster. object_mark[index_object] = True allocated_number_objects += 1 assert (number_objects == allocated_number_objects) # number of allocated objects should be the same. @staticmethod def templatePredict(path_to_file, initial_medians, points, expected_closest_clusters, ccore, **kwargs): sample = read_sample(path_to_file) metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) itermax = kwargs.get('itermax', 200) kmeans_instance = kmedians(sample, initial_medians, 0.001, ccore, metric=metric, itermax=itermax) kmeans_instance.process() closest_clusters = kmeans_instance.predict(points) assertion.eq(len(expected_closest_clusters), len(closest_clusters)) assertion.true(numpy.array_equal(numpy.array(expected_closest_clusters), closest_clusters)) pyclustering-0.10.1.2/pyclustering/cluster/tests/kmedoids_templates.py000077500000000000000000000214131375753423500263050ustar00rootroot00000000000000"""! @brief Test templates for K-Medoids clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import numpy from pyclustering.tests.assertion import assertion from pyclustering.cluster.kmedoids import kmedoids from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.samples import answer_reader from pyclustering.utils import read_sample, calculate_distance_matrix from pyclustering.utils.metric import distance_metric, type_metric from random import random, randint class kmedoids_test_template: @staticmethod def templateLengthProcessData(path_to_file, initial_medoids, expected_cluster_length, ccore_flag, **kwargs): kmedoids_test_template.templateLengthProcessWithMetric(path_to_file, initial_medoids, expected_cluster_length, None, ccore_flag, **kwargs) @staticmethod def templateLengthProcessWithMetric(path_to_file, initial_medoids, expected_cluster_length, metric, ccore_flag, **kwargs): sample = read_sample(path_to_file) data_type = kwargs.get('data_type', 'points') input_type = kwargs.get('input_type', 'list') initialize_medoids = kwargs.get('initialize_medoids', None) itermax = kwargs.get('itermax', 200) if metric is None: metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) input_data = sample if data_type == 'distance_matrix': input_data = calculate_distance_matrix(sample) if input_type == 'numpy': input_data = numpy.array(input_data) testing_result = False testing_attempts = 1 if initialize_medoids is not None: # in case center initializer randomization appears testing_attempts = 10 for _ in range(testing_attempts): if initialize_medoids is not None: initial_medoids = kmeans_plusplus_initializer(sample, initialize_medoids).initialize(return_index=True) kmedoids_instance = kmedoids(input_data, initial_medoids, 0.001, ccore=ccore_flag, metric=metric, data_type=data_type, itermax=itermax) kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() medoids = kmedoids_instance.get_medoids() if itermax == 0: assertion.eq([], clusters) assertion.eq(medoids, initial_medoids) return if len(clusters) != len(medoids): continue if len(set(medoids)) != len(medoids): continue obtained_cluster_sizes = [len(cluster) for cluster in clusters] if len(sample) != sum(obtained_cluster_sizes): continue for cluster in clusters: if len(cluster) == 0: continue if expected_cluster_length is not None: obtained_cluster_sizes.sort() expected_cluster_length.sort() if obtained_cluster_sizes != expected_cluster_length: continue testing_result = True assertion.true(testing_result) @staticmethod def templateClusterAllocationOneDimensionData(ccore_flag): input_data = [[random()] for _ in range(10)] + [[random() + 3] for _ in range(10)] + [[random() + 5] for _ in range(10)] + [[random() + 8] for _ in range(10)] kmedoids_instance = kmedoids(input_data, [5, 15, 25, 35], 0.025, ccore_flag) kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() assertion.eq(4, len(clusters)) for cluster in clusters: assertion.eq(10, len(cluster)) @staticmethod def templateAllocateRequestedClusterAmount(data, amount_clusters, initial_medoids, ccore_flag): if initial_medoids is None: initial_medoids = [] for _ in range(amount_clusters): index_point = randint(0, len(data) - 1) while index_point in initial_medoids: index_point = randint(0, len(data) - 1) initial_medoids.append(index_point) kmedoids_instance = kmedoids(data, initial_medoids, 0.025, ccore=ccore_flag) kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() assertion.eq(len(clusters), amount_clusters) amount_objects = 0 for cluster in clusters: amount_objects += len(cluster) assertion.eq(len(data), amount_objects) @staticmethod def templateClusterAllocationTheSameObjects(number_objects, number_clusters, ccore_flag=False): value = random() input_data = [[value]] * number_objects initial_medoids = [] step = int(math.floor(number_objects / number_clusters)) for i in range(number_clusters): initial_medoids.append(i * step) kmedoids_instance = kmedoids(input_data, initial_medoids, ccore=ccore_flag) kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() medoids = kmedoids_instance.get_medoids() assertion.eq(len(clusters), len(medoids)) assertion.eq(len(set(medoids)), len(medoids)) object_mark = [False] * number_objects allocated_number_objects = 0 for cluster in clusters: for index_object in cluster: assertion.eq(False, object_mark[index_object]) # one object can be in only one cluster. object_mark[index_object] = True allocated_number_objects += 1 assertion.eq(number_objects, allocated_number_objects) # number of allocated objects should be the same. @staticmethod def templatePredict(path_to_file, initial_medoids, points, expected_closest_clusters, ccore, **kwargs): sample = read_sample(path_to_file) metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) itermax = kwargs.get('itermax', 200) kmedoids_instance = kmedoids(sample, initial_medoids, 0.001, ccore, metric=metric, itermax=itermax) kmedoids_instance.process() closest_clusters = kmedoids_instance.predict(points) assertion.eq(len(expected_closest_clusters), len(closest_clusters)) assertion.true(numpy.array_equal(numpy.array(expected_closest_clusters), closest_clusters)) @staticmethod def clustering_with_answer(data_file, answer_file, ccore, **kwargs): data_type = kwargs.get('data_type', 'points') metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN)) original_data = read_sample(data_file) data = original_data if data_type == 'distance_matrix': data = calculate_distance_matrix(original_data, metric) reader = answer_reader(answer_file) amount_medoids = len(reader.get_clusters()) initial_medoids = kmeans_plusplus_initializer(data, amount_medoids, **kwargs).initialize(return_index=True) kmedoids_instance = kmedoids(data, initial_medoids, 0.001, ccore, **kwargs) kmedoids_instance.process() clusters = kmedoids_instance.get_clusters() medoids = kmedoids_instance.get_medoids() expected_length_clusters = sorted(reader.get_cluster_lengths()) assertion.eq(len(expected_length_clusters), len(medoids)) assertion.eq(len(data), sum([len(cluster) for cluster in clusters])) assertion.eq(sum(expected_length_clusters), sum([len(cluster) for cluster in clusters])) unique_medoids = set() for medoid in medoids: assertion.false(medoid in unique_medoids, message="Medoids '%s' is not unique (actual medoids: '%s')" % (str(medoid), str(unique_medoids))) unique_medoids.add(medoid) unique_points = set() for cluster in clusters: for point in cluster: assertion.false(point in unique_points, message="Point '%s' is already assigned to one of the clusters." % str(point)) unique_points.add(point) assertion.eq(expected_length_clusters, sorted([len(cluster) for cluster in clusters])) expected_clusters = reader.get_clusters() for actual_cluster in clusters: cluster_found = False for expected_cluster in expected_clusters: if actual_cluster == expected_cluster: cluster_found = True assertion.true(cluster_found, message="Actual cluster '%s' is not found among expected." % str(actual_cluster)) pyclustering-0.10.1.2/pyclustering/cluster/tests/mbsas_templates.py000077500000000000000000000030601375753423500256110ustar00rootroot00000000000000"""! @brief Test templates for MBSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import matplotlib; matplotlib.use('Agg'); from pyclustering.tests.assertion import assertion; from pyclustering.cluster.mbsas import mbsas; from pyclustering.utils import read_sample; from pyclustering.utils.metric import type_metric, distance_metric; class mbsas_test_template: @staticmethod def clustering(path, amount, threshold, expected, ccore, **kwargs): metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN)); sample = read_sample(path); mbsas_instance = mbsas(sample, amount, threshold, ccore=ccore, metric=metric); mbsas_instance.process(); clusters = mbsas_instance.get_clusters(); representatives = mbsas_instance.get_representatives(); obtained_length = 0; obtained_cluster_length = []; for cluster in clusters: obtained_length += len(cluster); obtained_cluster_length.append(len(cluster)); assertion.eq(len(sample), obtained_length); assertion.eq(len(expected), len(clusters)); assertion.eq(len(expected), len(representatives)); assertion.ge(amount, len(clusters)); dimension = len(sample[0]); for rep in representatives: assertion.eq(dimension, len(rep)); expected.sort(); obtained_cluster_length.sort(); assertion.eq(expected, obtained_cluster_length);pyclustering-0.10.1.2/pyclustering/cluster/tests/optics_templates.py000077500000000000000000000053151375753423500260120ustar00rootroot00000000000000"""! @brief Test templates for OPTICS clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.optics import optics, ordering_analyser from pyclustering.utils import read_sample, calculate_distance_matrix from pyclustering.tests.assertion import assertion class OpticsTestTemplates: @staticmethod def templateClusteringResults(path, radius, neighbors, amount_clusters, expected_length_clusters, ccore): OpticsTestTemplates.templateClusteringResultsSpecificData('points', path, radius, neighbors, amount_clusters, expected_length_clusters, ccore) @staticmethod def templateClusteringResultsDistanceMatrix(path, radius, neighbors, amount_clusters, expected_length_clusters, ccore): OpticsTestTemplates.templateClusteringResultsSpecificData('distance_matrix', path, radius, neighbors, amount_clusters, expected_length_clusters, ccore) @staticmethod def templateClusteringResultsSpecificData(data_type, path, radius, neighbors, amount_clusters, expected_length_clusters, ccore): sample = read_sample(path) if data_type == 'distance_matrix': input_data = calculate_distance_matrix(sample) else: input_data = sample optics_instance = optics(input_data, radius, neighbors, amount_clusters, ccore, data_type=data_type) optics_instance.process() clusters = optics_instance.get_clusters() noise = optics_instance.get_noise() optics_objects = optics_instance.get_optics_objects() object_indexes = set( [ obj.index_object for obj in optics_objects ] ) assertion.eq(len(optics_objects), len(object_indexes)) for obj in optics_objects: if obj.core_distance is not None: assertion.ge(obj.core_distance, 0) if obj.reachability_distance is not None: assertion.ge(obj.reachability_distance, 0) assert sum([len(cluster) for cluster in clusters]) + len(noise) == len(sample) assert len(clusters) == len(expected_length_clusters) assert sum([len(cluster) for cluster in clusters]) == sum(expected_length_clusters) assert sorted([len(cluster) for cluster in clusters]) == sorted(expected_length_clusters) if amount_clusters is not None: analyser = ordering_analyser(optics_instance.get_ordering()) assert len(analyser) > 0 amount_clusters, borders = analyser.extract_cluster_amount(optics_instance.get_radius()) assert amount_clusters == len(expected_length_clusters) assert len(borders) == amount_clusters - 1pyclustering-0.10.1.2/pyclustering/cluster/tests/rock_templates.py000077500000000000000000000030441375753423500254440ustar00rootroot00000000000000"""! @brief Test templates for ROCK clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.rock import rock; from pyclustering.utils import read_sample; from random import random; class RockTestTemplates: @staticmethod def templateLengthProcessData(path_to_file, radius, cluster_numbers, threshold, expected_cluster_length, ccore): sample = read_sample(path_to_file); rock_instance = rock(sample, radius, cluster_numbers, threshold, ccore); rock_instance.process(); clusters = rock_instance.get_clusters(); length = sum([len(cluster) for cluster in clusters]); assert len(sample) == length; obtained_cluster_sizes = [len(cluster) for cluster in clusters]; obtained_cluster_sizes.sort(); expected_cluster_length.sort(); assert obtained_cluster_sizes == expected_cluster_length; @staticmethod def templateClusterAllocationOneDimensionData(ccore_flag): input_data = [ [random()] for i in range(10) ] + [ [random() + 3] for i in range(10) ] + [ [random() + 5] for i in range(10) ] + [ [random() + 8] for i in range(10) ]; rock_instance = rock(input_data, 1, 4, 0.5, ccore_flag); rock_instance.process(); clusters = rock_instance.get_clusters(); assert len(clusters) == 4; for cluster in clusters: assert len(cluster) == 10; pyclustering-0.10.1.2/pyclustering/cluster/tests/silhouette_templates.py000077500000000000000000000075601375753423500267020ustar00rootroot00000000000000"""! @brief Test templates for Silhouette clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math from pyclustering.cluster.silhouette import silhouette, silhouette_ksearch from pyclustering.samples import answer_reader from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.tests.assertion import assertion from pyclustering.utils import read_sample, calculate_distance_matrix, distance_metric, type_metric class silhouette_test_template: @staticmethod def correct_scores(sample_path, answer_path, ccore_flag, **kwargs): data_type = kwargs.get('data_type', 'points') sample = read_sample(sample_path) if data_type == 'distance_matrix': sample = calculate_distance_matrix(sample, distance_metric(type_metric.EUCLIDEAN_SQUARE)) clusters = answer_reader(answer_path).get_clusters() scores = silhouette(sample, clusters, ccore=ccore_flag, data_type=data_type).process().get_score() assertion.eq(len(sample), len(scores)) for score in scores: assertion.le(-1.0, score) assertion.ge(1.0, score) return scores @staticmethod def correct_processing_data_types(sample_path, answer_path, ccore_flag): scores_points = silhouette_test_template.correct_scores(sample_path, answer_path, ccore_flag, data_type='points') scores_matrix = silhouette_test_template.correct_scores(sample_path, answer_path, ccore_flag, data_type='distance_matrix') assertion.eq(len(scores_points), len(scores_matrix)) assertion.eq(scores_points, scores_matrix) @staticmethod def correct_ksearch(sample_path, answer_path, kmin, kmax, algorithm, ccore_flag): attempts = 15 testing_result = False sample = read_sample(sample_path) clusters = answer_reader(answer_path).get_clusters() for _ in range(attempts): ksearch_instance = silhouette_ksearch(sample, kmin, kmax, algorithm=algorithm, ccore=ccore_flag).process() amount = ksearch_instance.get_amount() score = ksearch_instance.get_score() scores = ksearch_instance.get_scores() assertion.le(-1.0, score) assertion.ge(1.0, score) assertion.eq(kmax - kmin, len(scores)) upper_limit = len(clusters) + 1 lower_limit = len(clusters) - 1 if lower_limit < 1: lower_limit = 1 if (amount > upper_limit) or (amount < lower_limit): continue testing_result = True break assertion.true(testing_result) @staticmethod def random_state(kmin, kmax, algorithm, random_state, ccore_flag): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) ksearch_instance_1 = silhouette_ksearch(sample, kmin, kmax, algorithm=algorithm, random_state=random_state, ccore=ccore_flag).process() ksearch_instance_2 = silhouette_ksearch(sample, kmin, kmax, algorithm=algorithm, random_state=random_state, ccore=ccore_flag).process() assertion.eq(ksearch_instance_1.get_amount(), ksearch_instance_2.get_amount()) assertion.eq(ksearch_instance_1.get_score(), ksearch_instance_2.get_score()) assertion.eq(len(ksearch_instance_1.get_scores()), len(ksearch_instance_2.get_scores())) scores1 = ksearch_instance_1.get_scores() scores2 = ksearch_instance_2.get_scores() for key in scores1: key = int(key) if math.isnan(scores1[key]) and math.isnan(scores2[key]): continue else: assertion.eq(scores1[key], scores2[key]) pyclustering-0.10.1.2/pyclustering/cluster/tests/somsc_templates.py000077500000000000000000000040631375753423500256340ustar00rootroot00000000000000"""! @brief Test templates for SOM-SC clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import unittest from pyclustering.cluster.somsc import somsc from pyclustering.utils import read_sample from random import random class SyncnetTestTemplates(unittest.TestCase): def templateLengthProcessData(self, path_to_file, amount_clusters, expected_cluster_length, ccore): sample = read_sample(path_to_file) somsc_instance = somsc(sample, amount_clusters, 100, ccore) somsc_instance.process() clusters = somsc_instance.get_clusters() obtained_cluster_sizes = [len(cluster) for cluster in clusters] self.assertEqual(len(sample), sum(obtained_cluster_sizes)) if expected_cluster_length is not None: obtained_cluster_sizes.sort() expected_cluster_length.sort() self.assertEqual(obtained_cluster_sizes,expected_cluster_length) def templateClusterAllocationOneDimensionData(self, ccore_flag): input_data = [[random()] for i in range(10)] + [[random() + 3] for i in range(10)] + \ [[random() + 5] for i in range(10)] + [[random() + 8] for i in range(10)] somsc_instance = somsc(input_data, 4, 100, ccore_flag) somsc_instance.process() clusters = somsc_instance.get_clusters() self.assertEqual(len(clusters), 4) for cluster in clusters: self.assertEqual(len(cluster), 10) def predict(self, path_to_file, amount_clusters, points, expected_closest_clusters, ccore): sample = read_sample(path_to_file) somsc_instance = somsc(sample, amount_clusters, 100, ccore) somsc_instance.process() closest_clusters = somsc_instance.predict(points) self.assertEqual(len(expected_closest_clusters), len(closest_clusters)) self.assertTrue(numpy.array_equal(numpy.array(expected_closest_clusters), closest_clusters)) pyclustering-0.10.1.2/pyclustering/cluster/tests/syncnet_templates.py000077500000000000000000000051561375753423500261770ustar00rootroot00000000000000"""! @brief Test templates for SyncNet clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.cluster.syncnet import syncnet; from pyclustering.utils import read_sample; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.nnet import conn_represent; class SyncnetTestTemplates: @staticmethod def templateClustering(file, radius, order, solver, initial, storage_flag, conn_weigh_flag, tolerance, connection, expected_cluster_length, ccore_flag): result_testing = False; # If phases crosses each other because of random part of the network then we should try again. for _ in range(0, 20, 1): sample = read_sample(file); network = syncnet(sample, radius, connection, initial, conn_weigh_flag, ccore_flag); analyser = network.process(order, solver, storage_flag); clusters = analyser.allocate_clusters(tolerance); obtained_cluster_sizes = [len(cluster) for cluster in clusters]; if (len(obtained_cluster_sizes) != len(expected_cluster_length)): continue; obtained_cluster_sizes.sort(); expected_cluster_length.sort(); if (obtained_cluster_sizes != expected_cluster_length): continue; # Unit-test is passed result_testing = True; break; assert result_testing; @staticmethod def templateShowNetwork(file, radius, ccore_flag, connection_storage_type = conn_represent.MATRIX): sample = read_sample(file); network = syncnet(sample, radius, conn_repr = connection_storage_type, ccore = ccore_flag); network.show_network(); @staticmethod def templateConnectionApi(connection_storage_type, ccore_flag): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); network = syncnet(sample, 15, conn_repr = connection_storage_type, ccore = ccore_flag); for i in range(len(network)): neighbors = network.get_neighbors(i); assert len(sample) == len(network); assert len(neighbors) == len(network) - 1; assert i not in neighbors; for j in range(len(network)): if (i != j): assert network.has_connection(i, j) == True; else: assert network.has_connection(i, j) == False; pyclustering-0.10.1.2/pyclustering/cluster/tests/ttsas_template.py000077500000000000000000000030661375753423500254650ustar00rootroot00000000000000"""! @brief Test templates for TTSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import matplotlib; matplotlib.use('Agg'); from pyclustering.tests.assertion import assertion; from pyclustering.cluster.ttsas import ttsas; from pyclustering.utils import read_sample; from pyclustering.utils.metric import type_metric, distance_metric; class ttsas_test: @staticmethod def clustering(path, threshold1, threshold2, expected, ccore, **kwargs): metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN)); sample = read_sample(path); ttsas_instance = ttsas(sample, threshold1, threshold2, ccore=ccore, metric=metric); ttsas_instance.process(); clusters = ttsas_instance.get_clusters(); representatives = ttsas_instance.get_representatives(); obtained_length = 0; obtained_cluster_length = []; for cluster in clusters: obtained_length += len(cluster); obtained_cluster_length.append(len(cluster)); assertion.eq(len(sample), obtained_length); assertion.eq(len(expected), len(clusters)); assertion.eq(len(expected), len(representatives)); assertion.ge(len(sample), len(clusters)); dimension = len(sample[0]); for rep in representatives: assertion.eq(dimension, len(rep)); expected.sort(); obtained_cluster_length.sort(); assertion.eq(expected, obtained_cluster_length);pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/000077500000000000000000000000001375753423500230315ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/__init__.py000077500000000000000000000160721375753423500251530ustar00rootroot00000000000000"""! @brief Unit-test runner for tests of clustering algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.unit import ut_agglomerative as cluster_agglomerative_unit_tests from pyclustering.cluster.tests.unit import ut_bang as cluster_bang_unit_tests from pyclustering.cluster.tests.unit import ut_birch as cluster_birch_unit_tests from pyclustering.cluster.tests.unit import ut_bsas as cluster_bsas_unit_tests from pyclustering.cluster.tests.unit import ut_center_initializer as cluster_center_initializer_unit_tests from pyclustering.cluster.tests.unit import ut_clarans as cluster_clarans_unit_tests from pyclustering.cluster.tests.unit import ut_clique as cluster_clique_unit_tests from pyclustering.cluster.tests.unit import ut_cure as cluster_cure_unit_tests from pyclustering.cluster.tests.unit import ut_dbscan as cluster_dbscan_unit_tests from pyclustering.cluster.tests.unit import ut_elbow as cluster_elbow_unit_tests from pyclustering.cluster.tests.unit import ut_ema as cluster_ema_unit_tests from pyclustering.cluster.tests.unit import ut_encoder as cluster_encoder_unit_tests from pyclustering.cluster.tests.unit import ut_fcm as cluster_fcm_unit_tests from pyclustering.cluster.tests.unit import ut_ga as cluster_ga_unit_tests from pyclustering.cluster.tests.unit import ut_general as cluster_general_unit_tests from pyclustering.cluster.tests.unit import ut_generator as cluster_generator_unit_tests from pyclustering.cluster.tests.unit import ut_gmeans as cluster_gmeans_unit_tests from pyclustering.cluster.tests.unit import ut_hsyncnet as cluster_hsyncnet_unit_tests from pyclustering.cluster.tests.unit import ut_kmeans as cluster_kmeans_unit_tests from pyclustering.cluster.tests.unit import ut_kmedians as cluster_kmedians_unit_tests from pyclustering.cluster.tests.unit import ut_kmedoids as cluster_kmedoids_unit_tests from pyclustering.cluster.tests.unit import ut_mbsas as cluster_mbsas_unit_tests from pyclustering.cluster.tests.unit import ut_optics as cluster_optics_unit_tests from pyclustering.cluster.tests.unit import ut_rock as cluster_rock_unit_tests from pyclustering.cluster.tests.unit import ut_silhouette as cluster_silhouette_unit_tests from pyclustering.cluster.tests.unit import ut_somsc as cluster_somsc_unit_tests from pyclustering.cluster.tests.unit import ut_syncnet as cluster_syncnet_unit_tests from pyclustering.cluster.tests.unit import ut_syncsom as cluster_syncsom_unit_tests from pyclustering.cluster.tests.unit import ut_ttsas as cluster_ttsas_unit_tests from pyclustering.cluster.tests.unit import ut_visualizer as cluster_visualizer_unit_tests from pyclustering.cluster.tests.unit import ut_xmeans as cluster_xmeans_unit_tests class clustering_unit_tests(suite_holder): def __init__(self): super().__init__() self.fill_suite(self.get_suite()) @staticmethod def fill_suite(unit_cluster_suite): unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_agglomerative_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_bang_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_birch_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_bsas_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_center_initializer_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_clarans_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_clique_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_cure_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_dbscan_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_elbow_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_ema_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_encoder_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_fcm_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_ga_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_general_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_generator_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_gmeans_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_hsyncnet_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_kmeans_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_kmedians_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_kmedoids_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_mbsas_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_optics_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_rock_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_silhouette_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_somsc_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_syncnet_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_syncsom_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_ttsas_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_visualizer_unit_tests)) unit_cluster_suite.addTests(unittest.TestLoader().loadTestsFromModule(cluster_xmeans_unit_tests)) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_agglomerative.py000077500000000000000000000313261375753423500267510ustar00rootroot00000000000000"""! @brief Unit-tests for agglomerative algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.agglomerative_templates import AgglomerativeTestTemplates from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.cluster.agglomerative import agglomerative, type_link class AgglomerativeUnitTests(unittest.TestCase): def testClusteringSampleSimple1LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.AVERAGE_LINK, [5, 5], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.AVERAGE_LINK, [10], False) def testClusteringSampleSimple1LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.CENTROID_LINK, [5, 5], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.CENTROID_LINK, [10], False) def testClusteringSampleSimple1LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.COMPLETE_LINK, [5, 5], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.COMPLETE_LINK, [10], False) def testClusteringSampleSimple1LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, type_link.SINGLE_LINK, [5, 5], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, type_link.SINGLE_LINK, [10], False) def testClusteringSampleSimple2LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.AVERAGE_LINK, [5, 8, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.AVERAGE_LINK, [23], False) def testClusteringSampleSimple2LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.CENTROID_LINK, [5, 8, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.CENTROID_LINK, [23], False) def testClusteringSampleSimple2LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.COMPLETE_LINK, [5, 8, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.COMPLETE_LINK, [23], False) def testClusteringSampleSimple2LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, type_link.SINGLE_LINK, [5, 8, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, type_link.SINGLE_LINK, [23], False) def testClusteringSampleSimple3LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, type_link.AVERAGE_LINK, [10, 10, 10, 30], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, type_link.AVERAGE_LINK, [60], False) def testClusteringSampleSimple3LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, type_link.CENTROID_LINK, [10, 10, 10, 30], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, type_link.CENTROID_LINK, [60], False) def testClusteringSampleSimple3LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, type_link.COMPLETE_LINK, [10, 10, 10, 30], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, type_link.COMPLETE_LINK, [60], False) def testClusteringSampleSimple3LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, type_link.SINGLE_LINK, [10, 10, 10, 30], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, type_link.SINGLE_LINK, [60], False) def testClusteringSampleSimple4LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, type_link.AVERAGE_LINK, [15, 15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, type_link.AVERAGE_LINK, [75], False) def testClusteringSampleSimple4LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, type_link.CENTROID_LINK, [15, 15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, type_link.CENTROID_LINK, [75], False) def testClusteringSampleSimple4LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, type_link.COMPLETE_LINK, [15, 15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, type_link.COMPLETE_LINK, [75], False) def testClusteringSampleSimple4LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, type_link.SINGLE_LINK, [15, 15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, type_link.SINGLE_LINK, [75], False) def testClusteringSampleSimple5LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, type_link.AVERAGE_LINK, [15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, type_link.AVERAGE_LINK, [60], False) def testClusteringSampleSimple5LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, type_link.CENTROID_LINK, [15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, type_link.CENTROID_LINK, [60], False) def testClusteringSampleSimple5LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, type_link.COMPLETE_LINK, [15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, type_link.COMPLETE_LINK, [60], False) def testClusteringSampleSimple5LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, type_link.SINGLE_LINK, [15, 15, 15, 15], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, type_link.SINGLE_LINK, [60], False) def testClusteringTheSameData1LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.AVERAGE_LINK, [10, 20], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.AVERAGE_LINK, [30], False) def testClusteringTheSameData1LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.CENTROID_LINK, [10, 20], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.CENTROID_LINK, [30], False) def testClusteringTheSameData1LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.COMPLETE_LINK, [10, 20], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.COMPLETE_LINK, [30], False) def testClusteringTheSameData1LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, type_link.SINGLE_LINK, [10, 20], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, type_link.SINGLE_LINK, [30], False) def testClusteringTheSameData2LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.AVERAGE_LINK, [5, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.AVERAGE_LINK, [15], False) def testClusteringTheSameData2LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.CENTROID_LINK, [5, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.CENTROID_LINK, [15], False) def testClusteringTheSameData2LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.COMPLETE_LINK, [5, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.COMPLETE_LINK, [15], False) def testClusteringTheSameData2LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, type_link.SINGLE_LINK, [5, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, type_link.SINGLE_LINK, [15], False) def testClusteringThreeDimensionalData1LinkAverage(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, type_link.AVERAGE_LINK, [10, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, type_link.AVERAGE_LINK, [20], False) def testClusteringThreeDimensionalData1LinkCentroid(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, type_link.CENTROID_LINK, [10, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, type_link.CENTROID_LINK, [20], False) def testClusteringThreeDimensionalData1LinkComplete(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, type_link.COMPLETE_LINK, [10, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, type_link.COMPLETE_LINK, [20], False) def testClusteringThreeDimensionalData1LinkSingle(self): AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, type_link.SINGLE_LINK, [10, 10], False) AgglomerativeTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, type_link.SINGLE_LINK, [20], False) def testClusterAllocationOneDimensionDataLinkAverage(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.AVERAGE_LINK, False) def testClusterAllocationOneDimensionDataLinkCentroid(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.CENTROID_LINK, False) def testClusterAllocationOneDimensionDataLinkComplete(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.COMPLETE_LINK, False) def testClusterAllocationOneDimensionDataLinkSingle(self): AgglomerativeTestTemplates.templateClusterAllocationOneDimensionData(type_link.SINGLE_LINK, False) def testTwoClusterAllocationTheSameObjectsLinkAverage(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.AVERAGE_LINK, False) def testTwoClusterAllocationTheSameObjectLinkCentroid(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.CENTROID_LINK, False) def testTwoClusterAllocationTheSameObjectLinkComplete(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.COMPLETE_LINK, False) def testTwoClusterAllocationTheSameObjectLinkSingle(self): AgglomerativeTestTemplates.templateClusterAllocationTheSameObjects(10, 2, type_link.SINGLE_LINK, False) def test_incorrect_data(self): self.assertRaises(ValueError, agglomerative, [], 1) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, agglomerative, [[0], [1], [2]], -1) self.assertRaises(ValueError, agglomerative, [[0], [1], [2]], 0) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_bang.py000077500000000000000000000171521375753423500250330ustar00rootroot00000000000000"""! @brief Unit-tests for BANG algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.bang_templates import bang_test_template from pyclustering.cluster.bang import bang from pyclustering.samples.definitions import SIMPLE_SAMPLES class bang_unit_test(unittest.TestCase): def test_clustering_sample_simple_1(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0.0, [5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 7, 0.0, [5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 0.0, [5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 0.0, [5, 5], 0, False) def test_clustering_sample_simple_1_one_cluster(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.0, [10], 0, False) def test_clustering_diagonal_neighbors(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, 0.0, [10], 0, False) def test_clustering_sample_simple_1_noise_only(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 1000.0, [], 10, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 0.0, [], 10, False, amount_threshold=20) def test_clustering_sample_simple_2(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 7, 0.0, [5, 8, 10], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 0.0, [5, 8, 10], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.0, [23], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 500.0, [], 23, False) def test_clustering_sample_simple_3(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 7, 0.0, [10, 10, 10, 30], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 8, 0.0, [10, 10, 10, 30], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.0, [60], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 6, 500.0, [], 60, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 6, 0.0, [], 60, False, amount_threshold=100) def test_clustering_sample_simple_3_half_noise(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 2.5, [30], 30, False) def test_clustering_sample_simple_4_one_cluster(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 7, 0.0, [75], 0, False) def test_clustering_sample_simple_5(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 8, 0.0, [15, 15, 15, 15], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 7, 0.0, [15, 15, 15, 15], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 6, 0.0, [15, 15, 15, 15], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 0.0, [15, 15, 15, 15], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0.0, [60], 0, False) def test_clustering_one_dimensional_data1(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4, 0.0, [10, 10], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 0.0, [20], 0, False) def test_clustering_one_dimensional_data2(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 7, 0.0, [15, 20, 30, 80], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 2, 0.0, [145], 0, False) def test_clustering_one_dimensional_data_3_Similar(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 7, 0.0, [10, 20], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 0.0, [30], 0, False) def test_clustering_sample_simple_10(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 8, 0.0, [11, 11, 11], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 7, 0.0, [11, 11, 11], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 2, 0.0, [33], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 1, 0.0, [33], 0, False) def test_clustering_three_dimensional_data1(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 8, 0.0, [10, 10], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 7, 0.0, [10, 10], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 0.0, [20], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, 0.0, [20], 0, False) def test_clustering_similar_points(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 8, 0.0, [5, 5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 7, 0.0, [5, 5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, 0.0, [5, 5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, 0.0, [15], 0, False) def test_clustering_zero_column(self): bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 6, 0.0, [5, 5], 0, False) bang_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 1, 0.0, [10], 0, False) def test_visualize_no_failure_one_dimensional(self): bang_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4, 0.0, False) bang_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 7, 0.0, False) def test_visualize_no_failure_two_dimensional(self): bang_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0.0, False) bang_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.0, False) def test_visualize_no_failure_three_dimensional(self): bang_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 8, 0.0, False) bang_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, 0.0, False) def test_animate_no_failure(self): bang_test_template.animate(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0.0, False) bang_test_template.animate(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 8, 0.0, False) def test_argument_invalid_levels(self): bang_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0, 0.0, False) bang_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, -1, 0.0, False) bang_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, -10, 0.0, False) def test_argument_invalid_density(self): bang_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, -1.0, False) bang_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, -2.0, False) def test_argument_empty_data(self): bang_test_template.exception(ValueError, [], 1, 0.0, False) def test_incorrect_data(self): self.assertRaises(ValueError, bang, [], 1) def test_incorrect_levels(self): self.assertRaises(ValueError, bang, [[0], [1], [2]], 0) def test_incorrect_density_threshold(self): self.assertRaises(ValueError, bang, [[0], [1], [2]], 1, density_threshold=-0.1) def test_incorrect_amount_threshold(self): self.assertRaises(ValueError, bang, [[0], [1], [2]], 2, amount_threshold=-1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_birch.py000077500000000000000000000225601375753423500252120ustar00rootroot00000000000000"""! @brief Unit-tests for BIRCH algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import matplotlib matplotlib.use('Agg') from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.utils import read_sample from pyclustering.container.cftree import measurement_type from pyclustering.cluster.encoder import type_encoding from pyclustering.cluster.birch import birch from random import random class BirchUnitTest(unittest.TestCase): def templateClusterAllocation(self, path, cluster_sizes, number_clusters, branching_factor=50, max_node_entries=100, initial_diameter=0.5, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE, entry_size_limit=200, diameter_multiplier=1.5): sample = read_sample(path) birch_instance = birch(sample, number_clusters, branching_factor, max_node_entries, initial_diameter, type_measurement, entry_size_limit, diameter_multiplier) birch_instance.process() clusters = birch_instance.get_clusters() cf_clusters = birch_instance.get_cf_cluster() cf_entries = birch_instance.get_cf_entries() self.assertEqual(birch_instance.get_cluster_encoding(), type_encoding.CLUSTER_INDEX_LIST_SEPARATION) self.assertEqual(number_clusters, len(clusters)) self.assertEqual(number_clusters, len(cf_clusters)) self.assertGreater(len(cf_entries), 0) self.assertLessEqual(len(cf_entries), entry_size_limit) obtained_cluster_sizes = [len(cluster) for cluster in clusters] total_length = sum(obtained_cluster_sizes) self.assertEqual(total_length, len(sample)) if cluster_sizes is not None: cluster_sizes.sort() obtained_cluster_sizes.sort() self.assertEqual(cluster_sizes, obtained_cluster_sizes) def testClusterAllocationSampleSimple1CentroidEuclidianDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testClusterAllocationSampleSimple1CentroidManhattanDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, type_measurement=measurement_type.CENTROID_MANHATTAN_DISTANCE) def testClusterAllocationSampleSimple1AverageInterClusterDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, type_measurement=measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE) def testClusterAllocationSampleSimple1AverageIntraClusterDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, type_measurement=measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE) def testClusterAllocationSampleSimple1VarianceIncreaseDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, type_measurement=measurement_type.VARIANCE_INCREASE_DISTANCE) def testClusterAllocationSampleSimple2CentroidEuclidianDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testClusterAllocationSampleSimple2CentroidManhattanDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, type_measurement=measurement_type.CENTROID_MANHATTAN_DISTANCE) def testClusterAllocationSampleSimple2AverageInterClusterDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, type_measurement=measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE) def testClusterAllocationSampleSimple2AverageIntraClusterDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, initial_diameter=1.0, type_measurement=measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE) def testClusterAllocationSampleSimple2VarianceIncreaseDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, type_measurement=measurement_type.VARIANCE_INCREASE_DISTANCE) def testClusterAllocationSampleSimple3CentroidEuclidianDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testClusterAllocationSampleSimple3CentroidManhattanDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, type_measurement=measurement_type.CENTROID_MANHATTAN_DISTANCE) def testClusterAllocationSampleSimple3AverageInterClusterDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, initial_diameter=0.2, max_node_entries=1, type_measurement=measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE) def testClusterAllocationSampleSimple3AverageIntraClusterDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, branching_factor=4, max_node_entries=1, initial_diameter=0.2, type_measurement=measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE) def testClusterAllocationSampleSimple3VarianceIncreaseDistance(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, type_measurement=measurement_type.VARIANCE_INCREASE_DISTANCE) def testClusterAllocationSampleSimple4(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [15, 15, 15, 15, 15], 5, max_node_entries=2) def testClusterAllocationSampleSimple5(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [15, 15, 15, 15], 4) def testClusterAllocationSampleSimple7(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [10, 10], 2) def testClusterAllocationSampleSimple8(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [15, 30, 20, 80], 4) def testClusterAllocationTheSameData1(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [10, 20], 2) def testClusterAllocationSampleSimple10(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, [11, 11, 11], 3) def testClusterAllocationSampleSimple11(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [10, 10], 2) def testClusterAllocationTheSameData2(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [5, 5, 5], 3) def testClusterAllocationZeroColumn(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, [5, 5], 2) def testClusterAllocationLsun(self): self.templateClusterAllocation(FCPS_SAMPLES.SAMPLE_LSUN, [100, 101, 202], 3) def testClusterAllocationTarget(self): self.templateClusterAllocation(FCPS_SAMPLES.SAMPLE_TARGET, [3, 3, 3, 3, 363, 395], 6) def testClusterAllocationLsunTreeRebuilt(self): self.templateClusterAllocation(FCPS_SAMPLES.SAMPLE_LSUN, [100, 101, 202], 3, branching_factor=200, entry_size_limit=20) def testClusterAllocationHepta(self): self.templateClusterAllocation(FCPS_SAMPLES.SAMPLE_HEPTA, [30, 30, 30, 30, 30, 30, 32], 7) def templateClusterAllocationOneDimensionData(self, branching_factor=5, max_node_entries=10, initial_diameter=1.0, type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE, entry_size_limit=20): input_data = [[random()] for _ in range(10)] + [[random() + 4] for _ in range(10)] + [[random() + 8] for _ in range(10)] + [[random() + 12] for _ in range(10)] birch_instance = birch(input_data, 4, branching_factor, max_node_entries, initial_diameter, type_measurement, entry_size_limit) birch_instance.process() clusters = birch_instance.get_clusters() assert len(clusters) == 4 for cluster in clusters: assert len(cluster) == 10 def testClusterAllocationOneDimensionCentroidEuclidianDistance(self): self.templateClusterAllocationOneDimensionData(type_measurement=measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testClusterAllocationOneDimensionCentroidManhattanDistance(self): self.templateClusterAllocationOneDimensionData(type_measurement=measurement_type.CENTROID_MANHATTAN_DISTANCE) def testClusterAllocationOneAverageInterClusterDistance(self): self.templateClusterAllocationOneDimensionData(type_measurement=measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE) def testClusterAllocationOneAverageIntraClusterDistance(self): self.templateClusterAllocationOneDimensionData(type_measurement=measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE) def testClusterAllocationOneVarianceIncreaseDistance(self): self.templateClusterAllocationOneDimensionData(type_measurement=measurement_type.VARIANCE_INCREASE_DISTANCE) def test_incorrect_data(self): self.assertRaises(ValueError, birch, [], 1) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, birch, [[0], [1], [2]], 0) def test_incorrect_entry_size_limit(self): self.assertRaises(ValueError, birch, [[0], [1], [2]], 1, entry_size_limit=-0.1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_bsas.py000077500000000000000000000115171375753423500250530ustar00rootroot00000000000000"""! @brief Unit-tests for BSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.bsas_templates import bsas_test_template from pyclustering.cluster.bsas import bsas from pyclustering.utils.metric import type_metric, distance_metric from pyclustering.samples.definitions import SIMPLE_SAMPLES class bsas_unit_test(unittest.TestCase): def testClusteringSampleSimple1(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 1.0, [5, 5], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 1.0, [10], False) def testClusteringSampleSimple1Euclidean(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN)) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False, metric=distance_metric(type_metric.EUCLIDEAN)) def testClusteringSampleSimple1EuclideanSquare(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 100.0, [10], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)) def testClusteringSampleSimple1Manhattan(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.MANHATTAN)) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False, metric=distance_metric(type_metric.MANHATTAN)) def testClusteringSampleSimple1Chebyshev(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.CHEBYSHEV)) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False, metric=distance_metric(type_metric.CHEBYSHEV)) def testClusteringSampleSimple2(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1.0, [5, 8, 10], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 10.0, [23], False) def testClusteringSampleSimple3(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 1.0, [2, 8, 20, 30], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 2.0, [8, 10, 12, 30], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 10.0, [60], False) def testOneDimentionalPoints1(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1.0, [10, 10], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 10.0, [20], False) def testOneDimentionalPoints2(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 1.0, [10, 20], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 10.0, [30], False) def testThreeDimentionalPoints(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 1.0, [10, 10], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 10.0, [20], False) def testTheSamePoints1(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 1.0, [5, 5, 5], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 30, 1.0, [5, 5, 5], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 10.0, [15], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 1.0, [15], False) def testTheSamePoints2(self): bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 1.0, [10, 20], False) bsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 10.0, [30], False) def testVisulizeNoFailure(self): bsas_test_template.visualizing(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, False) bsas_test_template.visualizing(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1.0, False) bsas_test_template.visualizing(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 1.0, False) def test_incorrect_data(self): self.assertRaises(ValueError, bsas, [], 1, 1.0) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, bsas, [[0], [1], [2]], 0, 1.0) def test_incorrect_threshold_dissimilarity(self): self.assertRaises(ValueError, bsas, [[0], [1], [2]], 1, -1.0) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_center_initializer.py000077500000000000000000000331251375753423500300050ustar00rootroot00000000000000"""! @brief Unit-tests for center-initializer set. @authors Andrei Novikov, Aleksey Kukushkin (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.kmeans_templates import KmeansTestTemplates from pyclustering.cluster.tests.kmedoids_templates import kmedoids_test_template from pyclustering.cluster.center_initializer import random_center_initializer from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.tests.assertion import assertion class RandomCenterInitializerUnitTest(unittest.TestCase): def templateRandomCenterInitializer(self, data, amount): centers = random_center_initializer(data, amount).initialize() self.assertEqual(amount, len(centers)) for center in centers: self.assertEqual(len(data[0]), len(center)) def test1DimensionDataOneCenter(self): self.templateRandomCenterInitializer([[0.0], [1.0], [2.0], [3.0]], 1) def test2DimensionDataOneCenter(self): self.templateRandomCenterInitializer([[0.0, 0.5], [1.0, 1.5], [2.0, 2.5], [3.0, 3.5]], 1) def testGenerateTwoCenters(self): self.templateRandomCenterInitializer([[0.0], [-1.0], [-2.0], [-3.0]], 2) def testGenerateThreeCenters(self): self.templateRandomCenterInitializer([[0.0], [-1.0], [-2.0], [-3.0]], 3) def testGenerateFourCenters(self): self.templateRandomCenterInitializer([[0.0], [-1.0], [-2.0], [-3.0]], 4) def testGenerateTwoCentersIntData(self): self.templateRandomCenterInitializer([[0], [-1], [-2], [-3]], 2) class KmeansPlusPlusInitializerUnitTest(unittest.TestCase): def templateKmeasPlusPlusCenterInitializer(self, data, amount, candidates=None): centers = kmeans_plusplus_initializer(data, amount, candidates).initialize() assertion.eq(amount, len(centers)) for center in centers: assertion.eq(len(data[0]), len(center)) return centers def test1DimensionDataOneCenter(self): self.templateKmeasPlusPlusCenterInitializer([[0.0], [1.0], [2.0], [3.0]], 1) def test2DimensionDataOneCenter(self): self.templateKmeasPlusPlusCenterInitializer([[0.0, 0.5], [1.0, 1.5], [2.0, 2.5], [3.0, 3.5]], 1) def testGenerateTwoCenters(self): self.templateKmeasPlusPlusCenterInitializer([[0.0], [-1.0], [-2.0], [-3.0]], 2) def testGenerateThreeCenters(self): self.templateKmeasPlusPlusCenterInitializer([[0.0], [-1.0], [-2.0], [-3.0]], 3) def testGenerateFourCenters(self): self.templateKmeasPlusPlusCenterInitializer([[0.0], [-1.0], [-2.0], [-3.0]], 4) def testGenerateTwoCentersIntData(self): self.templateKmeasPlusPlusCenterInitializer([[0], [-1], [-2], [-3]], 2) def testGenerateCentersIdenticalData1(self): self.templateKmeasPlusPlusCenterInitializer([[1.2], [1.2], [1.2], [1.2]], 2) def testGenerateCentersIdenticalData2(self): self.templateKmeasPlusPlusCenterInitializer([[1.2], [1.2], [1.2], [1.2]], 4) def testGenerateCentersThreeDimensionalData(self): self.templateKmeasPlusPlusCenterInitializer([[1.2, 1.3, 1.4], [1.2, 1.3, 1.4], [2.3, 2.3, 2.4], [2.1, 4.2, 1.1]], 3) def testGenerateCentersOnePoint(self): self.templateKmeasPlusPlusCenterInitializer([[1.2, 1.3, 1.4]], 1) def testTwoSimilarPointsTwoCenters1(self): self.templateKmeasPlusPlusCenterInitializer([[0], [0]], 2, "farthest") def testTwoSimilarPointsTwoCenters2(self): self.templateKmeasPlusPlusCenterInitializer([[20], [20]], 2, "farthest") def templateKmeansPlusPlusForClustering(self, path_sample, amount, expected_clusters_length): result_success = True for _ in range(3): try: sample = read_sample(path_sample) start_centers = kmeans_plusplus_initializer(sample, amount).initialize() KmeansTestTemplates.templateLengthProcessData(path_sample, start_centers, expected_clusters_length, False) except AssertionError: continue break self.assertTrue(result_success) def testInitializerForKmeansSampleSimple01(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5]) def testInitializerForKmeansSampleSimple01TenCenters(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, None) def testInitializerForKmeansSampleSimple02(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [10, 5, 8]) def testInitializerForKmeansSampleSimple03(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [10, 10, 10, 30]) def testInitializerForKmeansSampleSimple04(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, [15, 15, 15, 15, 15]) def testInitializerForKmeansTotallySimilarObjectsTwoCenters(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, None) def testInitializerForKmeansTotallySimilarObjectsFiveCenters(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, None) def testInitializerForKmeansTotallySimilarObjectsTenCenters(self): self.templateKmeansPlusPlusForClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 10, None) def templateKmeasPlusPlusCenterInitializerIndexReturn(self, data, amount): centers = kmeans_plusplus_initializer(data, amount).initialize(return_index=True) assertion.eq(amount, len(centers)) for center_index in centers: assertion.gt(len(data), center_index) assertion.le(0, center_index) assertion.eq(1, centers.count(center_index)) return centers def testSimple01ReturnIndex(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) for amount in range(1, len(sample)): self.templateKmeasPlusPlusCenterInitializerIndexReturn(sample, amount) def testSimple02ReturnIndex(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) for amount in range(1, len(sample)): self.templateKmeasPlusPlusCenterInitializerIndexReturn(sample, amount) def testSimple03ReturnIndex(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) for amount in range(1, len(sample)): self.templateKmeasPlusPlusCenterInitializerIndexReturn(sample, amount) def test1DimensionDataOneCenterReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[0.0], [1.0], [2.0], [3.0]], 1) def test2DimensionDataOneCenterReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[0.0, 0.5], [1.0, 1.5], [2.0, 2.5], [3.0, 3.5]], 1) def testGenerateTwoCentersReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[0.0], [-1.0], [-2.0], [-3.0]], 2) def testGenerateThreeCentersReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[0.0], [-1.0], [-2.0], [-3.0]], 3) def testGenerateFourCentersReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[0.0], [-1.0], [-2.0], [-3.0]], 4) def testGenerateTwoCentersIntDataReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[0], [-1], [-2], [-3]], 2) def testGenerateCentersIdenticalData1ReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[1.2], [1.2], [1.2], [1.2]], 2) def testGenerateCentersIdenticalData2ReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[1.2], [1.2], [1.2], [1.2]], 4) def testGenerateCentersThreeDimensionalDataReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn( [[1.2, 1.3, 1.4], [1.2, 1.3, 1.4], [2.3, 2.3, 2.4], [2.1, 4.2, 1.1]], 3) def testGenerateCentersOnePointReturnIndex(self): self.templateKmeasPlusPlusCenterInitializerIndexReturn([[1.2, 1.3, 1.4]], 1) def templateKmeansPlusPlusForKmedoidsClustering(self, path_sample, amount, expected_clusters_length): result_success = True for _ in range(3): try: sample = read_sample(path_sample) start_medoids = kmeans_plusplus_initializer(sample, amount).initialize(return_index=True) kmedoids_test_template.templateLengthProcessData(path_sample, start_medoids, expected_clusters_length, False) except AssertionError: continue break assert result_success is True; def testInitializerForKmedoidsSampleSimple01(self): self.templateKmeansPlusPlusForKmedoidsClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5]) def testInitializerForKmedoidsSampleSimple01TenCenters(self): self.templateKmeansPlusPlusForKmedoidsClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, None) def testInitializerForKmedoidsSampleSimple02(self): self.templateKmeansPlusPlusForKmedoidsClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [10, 5, 8]) def testInitializerForKmedoidsSampleSimple03(self): self.templateKmeansPlusPlusForKmedoidsClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [10, 10, 10, 30]) def testInitializerForKmedoidsSampleSimple04(self): self.templateKmeansPlusPlusForKmedoidsClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, [15, 15, 15, 15, 15]) def templateKmeansPlusPlusUnique(self, path_sample, amount, candidates): sample = read_sample(path_sample) start_medoids = kmeans_plusplus_initializer(sample, amount, candidates).initialize(return_index=True) unique_mediods = set(start_medoids) self.assertEqual(len(unique_mediods), len(start_medoids)) def testKmeansPlusPlusUniqueCentersSimple01(self): self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, 1) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 1) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 1) def testKmeansPlusPlusUniqueCentersSeveralCandidatesSimple01(self): self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 5) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, 5) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 5) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 5) def testKmeansPlusPlusUniqueCentersFarthestCandidatesSimple01(self): self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 'farthest') self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, 'farthest') self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 'farthest') self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 'farthest') def testKmeansPlusPlusUniqueCentersSimple02(self): self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 1) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 1) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 23, 1) def testKmeansPlusPlusUniqueCentersSeveralCandidatesSimple02(self): self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 10) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 10) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 10) self.templateKmeansPlusPlusUnique(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 23, 10) def templateKmeansPlusPlusSeveralRuns(self, path_sample, amount, candidates): sample = read_sample(path_sample) attempts = 10 for _ in range(attempts): medoids = kmeans_plusplus_initializer(sample, amount, candidates).initialize(return_index=True) medoids += kmeans_plusplus_initializer(sample, amount, candidates).initialize(return_index=True) medoids += kmeans_plusplus_initializer(sample, amount, candidates).initialize(return_index=True) unique_medoids = set(medoids) if len(unique_medoids) != len(medoids): continue return self.assertTrue(False, "K-Means++ does not return unique medoids during %d attempts." % attempts) def templateKmeansPlusPlusVariousCentersSimple01(self): self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1) self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 1) def templateKmeansPlusPlusVariousCentersSeveralCandidatesSimple01(self): self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 3) def templateKmeansPlusPlusVariousCentersFarthestCandidatesSimple01(self): self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 'farthest') def templateKmeansPlusPlusVariousCentersSimple02(self): self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1) self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 1) def templateKmeansPlusPlusVariousCentersSimple03(self): self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 4, 1) self.templateKmeansPlusPlusSeveralRuns(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 8, 1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_clarans.py000077500000000000000000000057001375753423500255430ustar00rootroot00000000000000"""! @brief Unit-tests for CLARANS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import matplotlib matplotlib.use('Agg') from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.cluster.clarans import clarans class ClaransUnitTest(unittest.TestCase): def templateClusterAllocation(self, path, cluster_sizes, number_clusters, iterations, maxneighbors): result_testing = False # it's randomized algorithm therefore attempts are required for _ in range(0, 5, 1): sample = read_sample(path) clarans_instance = clarans(sample, number_clusters, iterations, maxneighbors) clarans_instance.process() clusters = clarans_instance.get_clusters() obtained_cluster_sizes = [len(cluster) for cluster in clusters] total_length = sum(obtained_cluster_sizes) if total_length != len(sample): continue cluster_sizes.sort() obtained_cluster_sizes.sort() if cluster_sizes != obtained_cluster_sizes: continue result_testing = True break assert result_testing == True def testClusterAllocationSampleSimple1(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, 10, 3) def testClusterAllocationSampleSimple2(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, 10, 3) def testClusterAllocationSampleSimple3(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, 10, 3) def testClusterAllocationSampleSimple5(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [15, 15, 15, 15], 4, 10, 5) def testClusterAllocationSampleSimple7(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [10, 10], 2, 10, 5) def testClusterAllocationSampleSimple8(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [15, 30, 20, 80], 4, 15, 5) def testClusterAllocationTheSameData1(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [10, 20], 2, 15, 5) def testClusterAllocationTheSameData2(self): self.templateClusterAllocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [5, 10], 2, 15, 5) def test_incorrect_data(self): self.assertRaises(ValueError, clarans, [], 1, 0, 0) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, clarans, [[0], [1], [2]], 0, 0, 0) def test_incorrect_local_minima(self): self.assertRaises(ValueError, clarans, [[0], [1], [2]], 1, -1, 0) def test_incorrect_max_neighbors(self): self.assertRaises(ValueError, clarans, [[0], [1], [2]], 1, 0, -1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_clique.py000077500000000000000000000202211375753423500253750ustar00rootroot00000000000000"""! @brief Unit-tests for CLIQUE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.clique import clique_block from pyclustering.cluster.tests.clique_templates import clique_test_template from pyclustering.tests.assertion import assertion from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES class clique_unit_test(unittest.TestCase): def test_clustering_sample_simple_1(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0, [5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 7, 0, [5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 0, [5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 0, [5, 5], 0, False) def test_clustering_sample_simple_1_one_cluster(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0, [10], 0, False) def test_clustering_diagonal_blocks_arent_neoghbors(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 0, [5, 5], 0, False) def test_clustering_sample_simple_1_noise_only(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 1000, [], 10, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 6, 10, [], 10, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 5, [], 10, False) def test_clustering_sample_simple_2(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 7, 0, [5, 8, 10], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 0, [5, 8, 10], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0, [23], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 6, 500, [], 23, False) def test_clustering_sample_simple_3(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 9, 0, [10, 10, 10, 30], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 8, 0, [10, 10, 10, 30], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0, [60], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 6, 500, [], 60, False) def test_clustering_sample_simple_3_one_point_noise(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 9, [59], 1, False) def test_clustering_sample_simple_4_one_cluster(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0, [75], 0, False) def test_clustering_sample_simple_5(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 8, 0, [15, 15, 15, 15], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 7, 0, [15, 15, 15, 15], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 6, 0, [15, 15, 15, 15], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 0, [15, 15, 15, 15], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0, [60], 0, False) def test_clustering_one_dimensional_data1(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4, 0, [10, 10], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 0, [20], 0, False) def test_clustering_one_dimensional_data2(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 15, 0, [15, 20, 30, 80], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 2, 0, [145], 0, False) def test_clustering_one_dimensional_data_3_similar(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 7, 0, [10, 20], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 0, [30], 0, False) def test_clustering_sample_simple_10(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 8, 0, [11, 11, 11], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 7, 0, [11, 11, 11], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 2, 0, [33], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, 1, 0, [33], 0, False) def test_clustering_three_dimensional_data1(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 6, 0, [10, 10], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 5, 0, [10, 10], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, 0, [20], 0, False) def test_clustering_similar_points(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 8, 0, [5, 5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 7, 0, [5, 5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, 0, [5, 5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, 0, [15], 0, False) def test_clustering_zero_column(self): clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 3, 0, [5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 2, 0, [5, 5], 0, False) clique_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, 1, 0, [10], 0, False) def test_clustering_fcps_lsun(self): clique_test_template.clustering(FCPS_SAMPLES.SAMPLE_LSUN, 15, 0, [100, 101, 202], 0, False) def test_clustering_fcps_hepta(self): clique_test_template.clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 9, 0, [30, 30, 30, 30, 30, 30, 32], 0, False) def test_visualize_no_failure_one_dimensional(self): clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 4, 0, False) clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 7, 0, False) def test_visualize_no_failure_two_dimensional(self): clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 8, 0, False) clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0, False) def test_visualize_no_failure_three_dimensional(self): clique_test_template.visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 3, 0, False) def test_argument_invalid_levels(self): clique_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0, 0.0, False) clique_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, -1, 0.0, False) clique_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, -10, 0.0, False) def test_argument_invalid_density(self): clique_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, -1.0, False) clique_test_template.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, -2.0, False) def test_argument_empty_data(self): clique_test_template.exception(ValueError, [], 1, 0.0, False) def test_logical_block_neighbors(self): block = clique_block() block.logical_location = [1, 1] neighbors = block.get_location_neighbors(3) assertion.eq(4, len(neighbors)) assertion.true([0, 1] in neighbors) assertion.true([2, 1] in neighbors) assertion.true([1, 0] in neighbors) assertion.true([1, 2] in neighbors) def test_logical_block_neighbors_on_edge(self): block = clique_block() block.logical_location = [1, 1] neighbors = block.get_location_neighbors(2) assertion.eq(2, len(neighbors)) assertion.true([0, 1] in neighbors) assertion.true([1, 0] in neighbors) block.logical_location = [0, 0] neighbors = block.get_location_neighbors(2) assertion.eq(2, len(neighbors)) assertion.true([0, 1] in neighbors) assertion.true([1, 0] in neighbors) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_cure.py000077500000000000000000000122501375753423500250540ustar00rootroot00000000000000"""! @brief Unit-tests for CURE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.cluster.tests.cure_templates import CureTestTemplates class CureUnitTest(unittest.TestCase): def testClusterAllocationSampleSimple1(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2) def testClusterAllocationSampleSimple1OneRepresentor(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, 1, 0.5) def testClusterAllocationSampleSimple1NumPy(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 2, numpy_usage=True) def testClusterAllocationSampleSimple2(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3) def testClusterAllocationSampleSimple2NoCompression(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, 5, 0.0) def testClusterAllocationSampleSimple2NumPy(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 5, 8], 3, numpy_usage=True) def testClusterAllocationSampleSimple3(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4) def testClusterAllocationSampleSimple3OneRepresentor(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, 1, 0.5) def testClusterAllocationSampleSimple3NumPy(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [10, 10, 10, 30], 4, numpy_usage=True) def testClusterAllocationSampleSimple4(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [15, 15, 15, 15, 15], 5) def testClusterAllocationSampleSimple4NumPy(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [15, 15, 15, 15, 15], 5, numpy_usage=True) def testClusterAllocationSampleSimple5(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [15, 15, 15, 15], 4) def testClusterAllocationSampleSimple5NumPy(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [15, 15, 15, 15], 4, numpy_usage=True) def testClusterAllocationSampleTwoDiamonds(self): CureTestTemplates.template_cluster_allocation(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [399, 401], 2, 5, 0.3) def testClusterAllocationSampleLsun(self): CureTestTemplates.template_cluster_allocation(FCPS_SAMPLES.SAMPLE_LSUN, [100, 101, 202], 3, 5, 0.3) def testOneClusterAllocationSampleSimple1(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [10], 1) def testOneClusterAllocationSampleSimple2(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [23], 1) def testOneClusterAllocationSampleSimple3(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [60], 1) def testOneClusterAllocationSampleSimple4(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [75], 1) def testOneClusterAllocationSampleSimple5(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [60], 1) def testClusterAllocationOneDimensionData(self): CureTestTemplates.templateClusterAllocationOneDimensionData(False) def testClusterAllocationTheSameData1(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [10, 20], 2, 5, 0.3) def testClusterAllocationTheSameData2(self): CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [5, 5, 5], 3, 5, 0.3) CureTestTemplates.template_cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [5, 10], 2, 5, 0.3) def testEncoderProcedure(self): CureTestTemplates.templateEncoderProcedures(False) def test_argument_invalid_amount_clusters(self): CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0, 5, 0.3, False) CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, -1, 5, 0.3, False) def test_argument_invalid_amount_representatives(self): CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0, 0.3, False) CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, -2, 0.3, False) CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, -4, 0.3, False) def test_argument_invalid_compression(self): CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 1, -0.3, False) CureTestTemplates.exception(ValueError, SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 2, -2.0, False) def test_argument_empty_data(self): CureTestTemplates.exception(ValueError, [], 3, 5, 0.3, False) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_dbscan.py000077500000000000000000000212151375753423500253510ustar00rootroot00000000000000"""! @brief Unit-tests for DBSCAN algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.dbscan_templates import DbscanTestTemplates from pyclustering.cluster.dbscan import dbscan from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS from pyclustering.samples.definitions import FCPS_SAMPLES class DbscsanUnitTest(unittest.TestCase): def testClusteringSampleSimple1(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, [5, 5], False) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 2, [10], False) def testClusteringSampleSimple1Randomize(self): DbscanTestTemplates.templateClusteringResultsRandomize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, [5, 5], False) def testClusteringSampleSimple1DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, [5, 5], False) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 2, [10], False) def testClusteringSampleSimple2(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, [5, 8, 10], False) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 2, [23], False) def testClusteringSampleSimple2Randomize(self): DbscanTestTemplates.templateClusteringResultsRandomize(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, [5, 8, 10], False) def testClusteringSampleSimple2DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, [5, 8, 10], False) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 2, [23], False) def testClusteringSampleSimple3(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, [10, 10, 10, 30], False) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 3, [60], False) def testClusteringSampleSimple3Randomize(self): DbscanTestTemplates.templateClusteringResultsRandomize(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, [10, 10, 10, 30], False) def testClusteringSampleSimple3DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, [10, 10, 10, 30], False) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 3, [60], False) def testClusteringSampleSimple4(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, [15, 15, 15, 15, 15], False) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 2, 3, [75], False) def testClusteringSampleSimple4DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, [15, 15, 15, 15, 15], False) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 2, 3, [75], False) def testClusteringSampleSimple5(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, [15, 15, 15, 15], False) DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 10, 3, [60], False) def testClusteringSampleSimple5DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, [15, 15, 15, 15], False) DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 10, 3, [60], False) def testClusteringHepta(self): DbscanTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3, [30, 30, 30, 30, 30, 30, 32], False) DbscanTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_HEPTA, 5, 3, [212], False) def testClusteringTheSameData1(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 3, [10, 20], False) def testClusteringTheSameData1DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 3, [10, 20], False) def testClusteringTheSameData2(self): DbscanTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, [5, 5, 5], False) def testClusteringTheSameData2DistanceMatrix(self): DbscanTestTemplates.templateClusteringDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, [5, 5, 5], False) def testLengthProcessedSampleSimple1(self): DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.7, 0, 10, False) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5, 0, 10, False) def testLengthProcessedSampleSimple1DistanceMatrix(self): DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.7, 0, 10, False) DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5, 0, 10, False) def testLengthProcessedSampleSimple2(self): DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 0.3, 0, 15, False) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0, 15, False) def testLengthProcessedSampleSimple2DistanceMatrix(self): DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 0.3, 0, 15, False) DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0, 15, False) def testLengthProcessedSampleSimple3(self): DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.1, 0, 20, False) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 0, 20, False) def testLengthProcessedSampleSimple3DistanceMatrix(self): DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.1, 0, 20, False) DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 0, 20, False) def testLengthProcessedSampleSimple4(self): DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.1, 0, 10, False) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 10, 65, 75, False) def testLengthProcessedSampleSimple4DistanceMatrix(self): DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.1, 0, 10, False) DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 10, 65, 75, False) def testLengthProcessedSampleSimple5(self): DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.1, 0, 10, False) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.3, 0, 10, False) DbscanTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.6, 0, 10, False) def testLengthProcessedSampleSimple5DistanceMatrix(self): DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.1, 0, 10, False) DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.3, 0, 10, False) DbscanTestTemplates.templateLengthProcessDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.6, 0, 10, False) def testPermutationSampleSimple14(self): DbscanTestTemplates.templateClusteringWithAnswers(SIMPLE_SAMPLES.SAMPLE_SIMPLE14, SIMPLE_ANSWERS.ANSWER_SIMPLE14, 1.0, 5, False, random_order=True, repeat=20) def testClusterAllocationOneDimensionData(self): DbscanTestTemplates.templateClusterAllocationOneDimensionData(False) def testClusterAllocationOneDimensionDistanceMatrix(self): DbscanTestTemplates.templateClusterAllocationOneDimensionDistanceMatrix(False) def test_pickle_dump_load(self): DbscanTestTemplates.pickle_dump_load(False) def test_incorrect_data(self): self.assertRaises(ValueError, dbscan, [], 0.1, 1) def test_incorrect_eps(self): self.assertRaises(ValueError, dbscan, [[0], [1], [2]], -1.0, 1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_elbow.py000077500000000000000000000131511375753423500252270ustar00rootroot00000000000000"""! @brief Unit-tests for Elbow method. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.center_initializer import random_center_initializer from pyclustering.cluster.elbow import elbow from pyclustering.cluster.tests.elbow_template import elbow_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS class elbow_unit_test(unittest.TestCase): def test_elbow_simple_01(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, 10, False) def test_elbow_simple_01_random_initializer(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, 10, False, initializer=random_center_initializer) def test_elbow_simple_01_step_2(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, 1, 10, False, kstep=2) def test_elbow_simple_01_step_3(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 4, 1, 10, False, kstep=3) def test_elbow_simple_01_step_4(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 1, 10, False, kstep=4) def test_elbow_simple_02(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, 10, False) def test_elbow_simple_02_step_2(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, 10, False, kstep=2) def test_elbow_simple_02_step_3(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, None, 1, 10, False, kstep=3) def test_elbow_simple_02_step_4(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, None, 1, 10, False, kstep=4) def test_elbow_simple_02_random_initializer(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, 10, False, initializer=random_center_initializer) def test_elbow_simple_03(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 1, 10, False) def test_elbow_simple_03_random_initializer(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 1, 10, False, initializer=random_center_initializer) def test_elbow_simple_05(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, 1, 10, False) def test_elbow_simple_06(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, 1, 10, False) def test_elbow_simple_10(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, 1, 10, False) def test_elbow_simple_12(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, 1, 10, False) def test_elbow_simple_15(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE15, 5, 1, 20, False, kstep=2) def test_elbow_one_dimensional_simple_07(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, 1, 10, False) def test_elbow_one_dimensional_simple_09(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, 1, 10, False) def test_elbow_three_dimensional_simple_11(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, 1, 10, False) def test_elbow_random_state(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, False, random_state=5) def test_elbow_random_state_random_initializer(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, False, random_state=5, initializer=random_center_initializer) def test_elbow_random_state_continuous(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 10, False, random_state=5, repeat=10) def test_incorrect_data(self): self.assertRaises(ValueError, elbow, [], 1, 5) def test_incorrect_kmin(self): self.assertRaises(ValueError, elbow, [[0], [1], [2]], 0, 2) def test_incorrect_difference(self): self.assertRaises(ValueError, elbow, [[0], [1], [2]], 1, 2) def test_border_step_1(self): elbow_test_template.calculate_elbow(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, 3, False, kstep=1, random_state=1000) def test_border_exception_step_2(self): self.assertRaises(ValueError, elbow, [[0], [1], [2]], 1, 3, kstep=2, random_state=1000) def test_border_step_4(self): elbow_test_template.random_state_fixed(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 9, False, kstep=4, random_state=1000) def test_incorrect_difference_with_kstep(self): self.assertRaises(ValueError, elbow, [[0], [1], [2]], 1, 10, kstep=5) self.assertRaises(ValueError, elbow, [[0], [1], [2]], 1, 10, kstep=6) def test_incorrect_kmax(self): self.assertRaises(ValueError, elbow, [[0], [1], [2]], 1, 10) def test_incorrect_kstep(self): self.assertRaises(ValueError, elbow, [[0], [1], [2]], 1, 3, kstep=0) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_ema.py000077500000000000000000000177111375753423500246670ustar00rootroot00000000000000"""! @brief Unit-tests for EMA algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.ema import ema, ema_observer, ema_initializer, ema_init_type, ema_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES, FAMOUS_SAMPLES class EmaUnitTest(unittest.TestCase): def templateDataClustering(self, sample_path, amount_clusters, expected_clusters_sizes, init_type = ema_init_type.KMEANS_INITIALIZATION): testing_result = False attempts = 10 for _ in range(attempts): sample = read_sample(sample_path) means, variances = None, None if init_type is not ema_init_type.KMEANS_INITIALIZATION: means, variances = ema_initializer(sample, amount_clusters).initialize(init_type) ema_instance = ema(sample, amount_clusters, means, variances) ema_instance.process() clusters = ema_instance.get_clusters() centers = ema_instance.get_centers() covariances = ema_instance.get_covariances() probabilities = ema_instance.get_probabilities() assert len(centers) == len(clusters) assert len(covariances) == len(clusters) assert len(probabilities) == len(clusters) for cluster_probability in probabilities: assert len(cluster_probability) == len(sample) for index_point in range(len(sample)): total_probability = 0.0 for cluster_probability in probabilities: total_probability += cluster_probability[index_point] assert abs(total_probability - 1.0) <= 0.00001 obtained_cluster_sizes = [len(cluster) for cluster in clusters] if len(sample) != sum(obtained_cluster_sizes): continue if expected_clusters_sizes is not None: obtained_cluster_sizes.sort() expected_clusters_sizes.sort() if obtained_cluster_sizes != expected_clusters_sizes: continue testing_result = True break assert testing_result is True def testClusteringSampleSimple01(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5]) def testClusteringSampleSimple01RandomInit(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], ema_init_type.RANDOM_INITIALIZATION) def testClusteringSampleSimple01OneCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, [10]) def testClusteringSampleSimple01OneClusterRandomInit(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, [10], ema_init_type.RANDOM_INITIALIZATION) def testClusteringSampleSimple01ThreeCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, None) def testClusteringSampleSimple01ThreeClusterRandomInit(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, None, ema_init_type.RANDOM_INITIALIZATION) def testClusteringSampleSimple01TenCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, None) def testClusteringSampleSimple01SevenCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 7, None) def testClusteringSampleSimple02(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [5, 8, 10]) def testClusteringSampleSimple02OneCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, [23]) def testClusteringSampleSimple02ThreeCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, None) def testClusteringSampleSimple03(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [10, 10, 10, 30]) def testClusteringSampleSimple03OneCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, [60]) def testClusteringSampleSimple05(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, [15, 15, 15, 15]) def testClusteringSampleSimple05OneCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, [60]) def testClusteringCommonOldFaithful(self): self.templateDataClustering(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL, 2, [97, 175]) def testClusteringFcpsLsun(self): self.templateDataClustering(FCPS_SAMPLES.SAMPLE_LSUN, 3, [100, 101, 202]) def testClusteringOneDimensionalData(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, [10, 10]) def testClusteringOneDimensionalDataRandomInit(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, [10, 10], ema_init_type.RANDOM_INITIALIZATION) def testClusteringOneDimensionalDataOneCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 1, [20]) def testClusteringThreeDimensionalData(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, [10, 10]) def testClusteringThreeDimensionalDataOneCluster(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, [20]) def testClusteringTotallySimilarObjects(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, None) def testClusteringTotallySimilarObjectsTwoClusters(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, None) def testClusteringTotallySimilarObjectsThreeClustersRandonInit(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, None, ema_init_type.RANDOM_INITIALIZATION) def testClusteringTotallySimilarObjectsFiveClusters(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, None) def testClusteringTotallySimilarObjectsFiveClustersRandomInit(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, None, ema_init_type.RANDOM_INITIALIZATION) def testObserver(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) means, variances = ema_initializer(sample, 3).initialize(ema_init_type.RANDOM_INITIALIZATION) observer_instance = ema_observer() ema_instance = ema(sample, 3, means, variances, observer_instance) ema_instance.process() observer_length = len(observer_instance) assert observer_length > 0 assert observer_length == len(observer_instance.get_evolution_clusters()) assert observer_length == len(observer_instance.get_evolution_covariances()) assert observer_length == len(observer_instance.get_evolution_means()) assert observer_length == observer_instance.get_iterations() def testVisualizerNoFailures(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) means, variances = ema_initializer(sample, 4).initialize(ema_init_type.RANDOM_INITIALIZATION) observer_instance = ema_observer() ema_instance = ema(sample, 4, means, variances, observer_instance) ema_instance.process() clusters = ema_instance.get_clusters() means = ema_instance.get_centers() covariances = ema_instance.get_covariances() ema_visualizer.show_clusters(clusters, sample, covariances, means) ema_visualizer.animate_cluster_allocation(sample, observer_instance) def test_incorrect_data(self): self.assertRaises(ValueError, ema, [], 2) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, ema, [[0], [1], [2]], 0) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_encoder.py000077500000000000000000000246631375753423500255500ustar00rootroot00000000000000"""! @brief Unit-tests for clustering result representation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import math import matplotlib matplotlib.use('Agg') from pyclustering.cluster.encoder import cluster_encoder from pyclustering.cluster.encoder import type_encoding class Test(unittest.TestCase): def getIndexRepresentor(self): clusters = [ [0, 1, 2, 3], [4, 5, 6, 7] ] data = [10, 11, 13, 12, 64, 65, 65, 68] return cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, clusters, data) def testIndexToLabel(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def testIndexToObject(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) assert 2 == len(representor.get_clusters()); assert [ [10, 11, 13, 12 ], [64, 65, 65, 68] ] == representor.get_clusters() def testObjectToIndex(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [0, 1, 2, 3], [4, 5, 6, 7] ] == representor.get_clusters() def testObjectToLabel(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def testLabelToIndex(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [0, 1, 2, 3], [4, 5, 6, 7] ] == representor.get_clusters() def testLabelToObject(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [10, 11, 13, 12 ], [64, 65, 65, 68] ] == representor.get_clusters() def testLabelToLabel(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def testObjectToObject(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [10, 11, 13, 12 ], [64, 65, 65, 68] ] == representor.get_clusters() def testIndexToIndex(self): representor = self.getIndexRepresentor() representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [0, 1, 2, 3], [4, 5, 6, 7] ] == representor.get_clusters() def getIndexRepresentorDoubleData(self): clusters = [ [0, 1, 2, 3], [4, 5, 6, 7] ] data = [5.4562, 5.1235, 4.9235, 4.8712, 8.3451, 8.4215, 8.6535, 8.7345] return cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, clusters, data) def testDoubleObjectToIndex(self): representor = self.getIndexRepresentorDoubleData() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assert 2 == len(representor.get_clusters()); assert [ [0, 1, 2, 3], [4, 5, 6, 7] ] == representor.get_clusters() def testDoubleObjectToLabel(self): representor = self.getIndexRepresentorDoubleData() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def testOverAllTypes(self): representor = self.getIndexRepresentorDoubleData() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def getIndexRepresentorTwoDimensionData(self): clusters = [ [0, 1, 2, 3], [4, 5, 6, 7] ] data = [ [5.1, 5.2], [5.2, 5.1], [5.4, 5.2], [5.1, 5.0], [8.1, 8.0], [8.4, 8.2], [8.3, 8.4], [8.5, 8.5]] return cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, clusters, data) def testIndexToLabelTwoDimension(self): representor = self.getIndexRepresentorTwoDimensionData() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def testIndexToObjectTwoDimension(self): representor = self.getIndexRepresentorTwoDimensionData() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [[5.1, 5.2], [5.2, 5.1], [5.4, 5.2], [5.1, 5.0]], [[8.1, 8.0], [8.4, 8.2], [8.3, 8.4], [8.5, 8.5]] ] == representor.get_clusters() def testObjectToIndexTwoDimension(self): representor = self.getIndexRepresentorTwoDimensionData() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [0, 1, 2, 3], [4, 5, 6, 7] ] == representor.get_clusters() def testObjectToLabelTwoDimension(self): representor = self.getIndexRepresentorTwoDimensionData() representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) assert 8 == len(representor.get_clusters()) assert [0, 0, 0, 0, 1, 1, 1, 1] == representor.get_clusters() def testLabelToIndexTwoDimension(self): representor = self.getIndexRepresentorTwoDimensionData() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) representor.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [[0, 1, 2, 3], [4, 5, 6, 7]] == representor.get_clusters() def testLabelToObjectTwoDimension(self): representor = self.getIndexRepresentorTwoDimensionData() representor.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) representor.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) assert 2 == len(representor.get_clusters()) assert [ [[5.1, 5.2], [5.2, 5.1], [5.4, 5.2], [5.1, 5.0]], [[8.1, 8.0], [8.4, 8.2], [8.3, 8.4], [8.5, 8.5]] ] == representor.get_clusters() def testIndexListToLabelsMissedPoint(self): clusters = [[0, 1, 2, 3], [4, 5, 6]] # the last point is missed data = [[5.1, 5.2], [5.2, 5.1], [5.4, 5.2], [5.1, 5.0], [8.1, 8.0], [8.4, 8.2], [8.3, 8.4], [8.5, 8.5]] encoder = cluster_encoder(type_encoding.CLUSTER_INDEX_LIST_SEPARATION, clusters, data) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) expected = [0, 0, 0, 0, 1, 1, 1, float('NaN')] actual = encoder.get_clusters() self.assertEqual(len(expected), len(actual)) for i in range(len(expected)): if math.isnan(expected[i]) is True: self.assertTrue(math.isnan(actual[i])) else: self.assertEqual(expected[i], actual[i]) def testObjectListToLabelsMissedPoint(self): clusters = [[[5.1, 5.2], [5.2, 5.1]], [[8.1, 8.0], [8.4, 8.2]]] data = [[5.1, 5.2], [5.2, 5.1], [14.1, 76.0], [8.1, 8.0], [8.4, 8.2]] encoder = cluster_encoder(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION, clusters, data) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LABELING) expected = [0, 0, float('NaN'), 1, 1] actual = encoder.get_clusters() self.assertEqual(len(expected), len(actual)) for i in range(len(expected)): if math.isnan(expected[i]) is True: self.assertTrue(math.isnan(actual[i])) else: self.assertEqual(expected[i], actual[i]) def testLabelsToIndexListAndObjectListMissedPoint(self): clusters = [0, 0, float('NaN'), 1, 1] data = [[5.1, 5.2], [5.2, 5.1], [14.1, 76.0], [8.1, 8.0], [8.4, 8.2]] encoder = cluster_encoder(type_encoding.CLUSTER_INDEX_LABELING, clusters, data) encoder.set_encoding(type_encoding.CLUSTER_INDEX_LIST_SEPARATION) expected = [[0, 1], [3, 4]] actual = encoder.get_clusters() self.assertEqual(len(expected), len(actual)) self.assertEqual(expected, actual) encoder = cluster_encoder(type_encoding.CLUSTER_INDEX_LABELING, clusters, data) encoder.set_encoding(type_encoding.CLUSTER_OBJECT_LIST_SEPARATION) expected = [[[5.1, 5.2], [5.2, 5.1]], [[8.1, 8.0], [8.4, 8.2]]] actual = encoder.get_clusters() self.assertEqual(len(expected), len(actual)) self.assertEqual(expected, actual) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_fcm.py000077500000000000000000000132671375753423500246740ustar00rootroot00000000000000"""! @brief Unit-tests for Fuzzy C-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.fcm_templates import fcm_test_template from pyclustering.cluster.fcm import fcm from pyclustering.samples.definitions import SIMPLE_SAMPLES, FAMOUS_SAMPLES, FCPS_SAMPLES class fcm_unit_tests(unittest.TestCase): def test_cluster_allocation_simple01(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], 2.0, [5, 5], False) def test_cluster_allocation_simple01_one_cluster(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], 2.0, [10], False) def test_cluster_allocation_simple01_centers_are_points1(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.768699, 5.364477], [6.593196, 7.850364]], 2.0, [5, 5], False) def test_cluster_allocation_simple01_centers_are_points2(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.936690, 5.663041], [6.968136, 7.755556]], 2.0, [5, 5], False) def test_cluster_allocation_simple01_wrong_amount(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [4.7, 6.5], [3.4, 6.4]], 2.0, [2, 3, 5], False) def test_cluster_allocation_simple02(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], 2.0, [10, 5, 8], False) def test_cluster_allocation_simple02_wrong_amount(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5], [4.5, 6.2]], 2.0, [4, 5, 6, 8], False) def test_cluster_allocation_simple03(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], 2.0, [10, 10, 10, 30], False) def test_cluster_allocation_simple04(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], 2.0, [15, 15, 15, 15, 15], False) def test_cluster_allocation_simple05(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], 2.0, [15, 15, 15, 15], False) def test_cluster_allocation_simple06(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, [[2.0, 6.0], [8.5, 4.5]], 2.0, [20, 21], False) def test_cluster_allocation_simple07(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[-3.0], [2.0]], 2.0, [10, 10], False) def test_cluster_allocation_simple08(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-4.0], [3.1], [6.1], [12.0]], 2.0, [15, 30, 20, 80], False) def test_cluster_allocation_simple09(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [[4.0], [8.0]], 2.0, [10, 20], False) def test_cluster_allocation_simple10(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, [[0.426, 0.065 ], [5.462, 6.529], [9.539, 11.379]], 2.0, [11, 11, 11], False) def test_cluster_allocation_simple11(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], 2.0, [10, 10], False) def test_cluster_allocation_simple12(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [[1.0, 1.0], [2.5, 2.5], [4.0, 4.0]], 2.0, [5, 5, 5], False) def test_cluster_allocation_simple13(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, [[1.35, 1.21, 0.0], [3.79, 4.21, 0.0]], 2.0, [5, 5], False) def test_cluster_allocation_simple14(self): fcm_test_template.cluster_allocation(SIMPLE_SAMPLES.SAMPLE_SIMPLE14, [[5.649, 5.199]], 2.0, [41], False) def test_cluster_allocation_famous_oldfaithful(self): fcm_test_template.cluster_allocation(FAMOUS_SAMPLES.SAMPLE_OLD_FAITHFUL, [[4.0, 70], [1.0, 48]], 2.0, None, False) def test_cluster_allocation_two_diamonds(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.71 -0.51], [0.99 -0.24]], 2.0, [400, 400], False) def test_cluster_allocation_tetra(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_TETRA, [[1.001, -0.083, -0.681], [-0.811, 0.476, -0.759], [-0.956, -1.427, -0.020], [0.225, 0.560, 1.794]], 2.0, [100, 100, 100, 100], False) def test_cluster_allocation_fcps_hepta(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_HEPTA, [[-0.06,0.02, 0.02], [2.41, 0.49, 0.03], [-2.69, 0.34, 0.29], [0.49, 2.89, 0.78], [-0.60, -2.31, 0.05], [-0.15, 0.77, 3.23], [-0.50, 0.43, -2.60]], 2.0, [30, 30, 30, 30, 30, 30, 32], False) def test_cluster_allocation_fcps_hepta_wrong_amount(self): fcm_test_template.cluster_allocation(FCPS_SAMPLES.SAMPLE_HEPTA, [[-0.06,0.02, 0.02], [2.41, 0.49, 0.03], [-2.69, 0.34, 0.29], [0.49, 2.89, 0.78], [-0.60, -2.31, 0.05], [-0.50, 0.43, -2.60]], 2.0, [30, 30, 30, 30, 30, 62], False) def test_incorrect_data(self): self.assertRaises(ValueError, fcm, [], 1) def test_incorrect_centers(self): self.assertRaises(ValueError, fcm, [[0], [1], [2]], []) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_ga.py000077500000000000000000000253241375753423500245130ustar00rootroot00000000000000"""! @brief Unit-tests for genetic clustering algorithm. @authors Andrei Novikov, Aleksey Kukushkin (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import inspect import numpy # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.cluster.ga import genetic_algorithm, ga_observer, ga_visualizer from pyclustering.cluster.ga_maths import ga_math from pyclustering.utils import read_sample class GeneticAlgorithmClusteringUnitTest(unittest.TestCase): def runGeneticAlgorithm(self, test_case_name, data, count_chromosomes, count_clusters, count_populations, count_mutations_gen, result_should_be): _, best_ff, = genetic_algorithm(data=data, count_clusters=count_clusters, chromosome_count=count_chromosomes, population_count=count_populations, count_mutation_gens=count_mutations_gen, random_state=1000).process() # Check result self.assertEqual(best_ff, result_should_be) def test1CenterClustering(self): data = [[0, 0], [0, 2]] self.runGeneticAlgorithm(test_case_name=inspect.stack()[0][3], data=data, count_chromosomes=10, count_clusters=1, count_populations=10, count_mutations_gen=1, result_should_be=2.0) def test1Center4DataClustering(self): data = [[0, 0], [0, 2], [2, 0], [2, 2]] self.runGeneticAlgorithm(test_case_name=inspect.stack()[0][3], data=data, count_chromosomes=10, count_clusters=1, count_populations=10, count_mutations_gen=1, result_should_be=8.0) def test2Center8DataClustering(self): data = [[0, 0], [0, 2], [2, 0], [2, 2]] data.extend([[6, 0], [6, 2], [8, 0], [8, 2]]) self.runGeneticAlgorithm(test_case_name=inspect.stack()[0][3], data=data, count_chromosomes=50, count_clusters=2, count_populations=50, count_mutations_gen=1, result_should_be=16.0) def test4Center16DataClustering(self): data = [] data.extend([[0, 0], [1, 0], [0, 1], [1, 1]]) data.extend([[5, 0], [6, 0], [5, 1], [6, 1]]) data.extend([[0, 5], [1, 5], [0, 6], [1, 6]]) data.extend([[4, 4], [7, 4], [4, 7], [7, 7]]) self.runGeneticAlgorithm(test_case_name=inspect.stack()[0][3], data=data, count_chromosomes=20, count_clusters=4, count_populations=100, count_mutations_gen=1, result_should_be=24.0) def templateDataClustering(self, sample_path, amount_clusters, chromosome_count, population_count, count_mutation_gens, coeff_mutation_count, expected_clusters_sizes, **kwargs): scale_points = kwargs.get('scale_points', None) sample = numpy.array(read_sample(sample_path)) if scale_points is not None: sample = sample * scale_points ga_instance = genetic_algorithm(sample, amount_clusters, chromosome_count, population_count, count_mutations_gen=count_mutation_gens, coeff_mutation_count=coeff_mutation_count, **kwargs) ga_instance.process() clusters = ga_instance.get_clusters() obtained_cluster_sizes = [len(cluster) for cluster in clusters] self.assertEqual(len(sample), sum(obtained_cluster_sizes)) if expected_clusters_sizes is not None: obtained_cluster_sizes.sort() expected_clusters_sizes.sort() self.assertEqual(obtained_cluster_sizes, expected_clusters_sizes) def testClusteringTwoDimensionalData(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 20, 20, 2, 0.25, [5, 5], random_state=1000) def testClusteringTwoDimensionalDataWrongAllocation(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 20, 20, 2, 0.25, [10], random_state=1000) def testClusteringNonNormalizedValues(self): self.assertRaises(ValueError, self.templateDataClustering, SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 20, 20, 2, 0.25, [5, 5], random_state=1000, scale_points=1000) def testClusteringSimple02(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 20, 40, 2, 0.25, [5, 8, 10], random_state=1000) def testClusteringSimple09(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 20, 20, 2, 0.25, [10, 20], random_state=1000) def testClusteringOneDimensionalData(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 20, 20, 2, 0.25, [10, 10], random_state=1000) def testClusteringOneDimensionalDataWrongAllocation(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 1, 20, 20, 2, 0.25, [20], random_state=1000) def testClusteringThreeDimensionalData(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 20, 20, 2, 0.25, [10, 10], random_state=1000) def testClusteringThreeDimensionalDataWrongAllocation(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1, 20, 20, 2, 0.25, [20], random_state=1000) def testTwoClustersTotallySimilarObjects(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 2, 20, 20, 2, 0.25, None, random_state=1000) def testFiveClustersTotallySimilarObjects(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 5, 20, 20, 2, 0.25, None, random_state=1000) def testTenClustersTotallySimilarObjects(self): self.templateDataClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 10, 20, 20, 2, 0.25, None, random_state=1000) def templateTestObserverCollecting(self, amount_clusters, iterations, global_optimum, local_optimum, average, **kwargs): observer_instance = ga_observer(global_optimum, local_optimum, average) self.assertEqual(0, len(observer_instance)) sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) ga_instance = genetic_algorithm(sample, amount_clusters, 20, iterations, count_mutation_gens=2, coeff_mutation_count=0.25, observer=observer_instance, **kwargs) ga_instance.process() self.assertEqual(observer_instance, ga_instance.get_observer()) expected_length = 0 if global_optimum is True: expected_length = iterations + 1 self.assertEqual(expected_length, len(observer_instance)) self.assertEqual(expected_length, len(observer_instance.get_global_best()['chromosome'])) self.assertEqual(expected_length, len(observer_instance.get_global_best()['fitness_function'])) expected_length = 0 if local_optimum is True: expected_length = iterations + 1 self.assertEqual(expected_length, len(observer_instance)) self.assertEqual(expected_length, len(observer_instance.get_population_best()['chromosome'])) self.assertEqual(expected_length, len(observer_instance.get_population_best()['fitness_function'])) expected_length = 0 if average is True: expected_length = iterations + 1 self.assertEqual(expected_length, len(observer_instance)) self.assertEqual(expected_length, len(observer_instance.get_mean_fitness_function())) if global_optimum is True: clusters = ga_math.get_clusters_representation(observer_instance.get_global_best()['chromosome'][-1]) self.assertEqual(amount_clusters, len(clusters)) return sample, observer_instance def testObserveGlobalOptimum(self): self.templateTestObserverCollecting(2, 10, True, False, False, random_state=1000) def testObserveLocalOptimum(self): self.templateTestObserverCollecting(2, 11, False, True, False, random_state=1000) def testObserveAverage(self): self.templateTestObserverCollecting(2, 12, False, False, True, random_state=1000) def testObserveAllParameters(self): self.templateTestObserverCollecting(2, 9, True, True, True, random_state=1000) def testObserveNoCollecting(self): self.templateTestObserverCollecting(2, 9, False, False, False, random_state=1000) def testObserveParameterCombinations(self): self.templateTestObserverCollecting(3, 10, True, True, False, random_state=1000) self.templateTestObserverCollecting(4, 10, True, False, True, random_state=1000) self.templateTestObserverCollecting(1, 10, False, True, True, random_state=1000) def testNoFailureVisualizationApi(self): sample, observer = self.templateTestObserverCollecting(2, 10, True, True, True, random_state=1000) ga_visualizer.show_evolution(observer) ga_visualizer.show_clusters(sample, observer) ga_visualizer.animate_cluster_allocation(sample, observer) def testNoFailureShowEvolution(self): _, observer = self.templateTestObserverCollecting(2, 10, True, True, True, random_state=1000) ga_visualizer.show_evolution(observer, 2, 5) ga_visualizer.show_evolution(observer, 2, len(observer)) ga_visualizer.show_evolution(observer, 2, len(observer), display=False) def testNoneObserver(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) ga_instance = genetic_algorithm(sample, 2, 20, 20, count_mutation_gens=2, coeff_mutation_count=0.25, observer=None) ga_instance.process() self.assertIsNone(ga_instance.get_observer()) def test_incorrect_data(self): self.assertRaises(ValueError, genetic_algorithm, [], 1, 2, 2) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, genetic_algorithm, [[0], [1], [2]], 0, 2, 2) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_general.py000077500000000000000000000174061375753423500255430ustar00rootroot00000000000000"""! @brief Unit-tests for other cluster functionality @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); import matplotlib.pyplot as plt; import random; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; from pyclustering.utils import read_sample; from pyclustering.cluster import cluster_visualizer; from pyclustering.cluster.dbscan import dbscan; from pyclustering.cluster.cure import cure; class Test(unittest.TestCase): def testVisualize1DClustersOneCanvas(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE8); dbscan_instance = dbscan(sample, 1.0, 3, False); dbscan_instance.process(); clusters = dbscan_instance.get_clusters(); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample, markersize = 5); visualizer.show(); def testVisualize1DClustersOneCanvasSampleOnly(self): clusters = [ [[0.1], [0.2], [0.5]], [[0.1], [0.2], [0.5]] ]; visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, markersize = 5); visualizer.show(); def testVisualize1DClustersTwoCanvases(self): sample_simple7 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE7); sample_simple8 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE8); # Two canvas visualization visualizer = cluster_visualizer(2); visualizer.append_clusters([ sample_simple7 ], None, 0, markersize = 30); visualizer.append_clusters([ sample_simple8 ], None, 1, markersize = 30); visualizer.show(); def testVisualize3DClustersOneCanvas(self): sample = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA); dbscan_instance = dbscan(sample, 0.5, 3, False); dbscan_instance.process(); clusters = dbscan_instance.get_clusters(); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample, markersize = 30); visualizer.show(); def testVisualize3DClustersTwoCanvases(self): sample_tetra = read_sample(FCPS_SAMPLES.SAMPLE_TETRA); sample_hepta = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA); # Two canvas visualization visualizer = cluster_visualizer(2); visualizer.append_clusters([ sample_tetra ], None, 0, markersize = 30); visualizer.append_clusters([ sample_hepta ], None, 1, markersize = 30); visualizer.show(); def testVisualize2DClustersOneCanvas(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4); dbscan_instance = dbscan(sample, 0.7, 3, False); dbscan_instance.process(); clusters = dbscan_instance.get_clusters(); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample, markersize = 5); visualizer.show(); def testVisualize2DClustersThreeCanvases(self): sample_simple1 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); sample_simple2 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); sample_simple3 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3); dbscan_instance = dbscan(sample_simple1, 0.4, 2, False); dbscan_instance.process(); clusters_sample1 = dbscan_instance.get_clusters(); dbscan_instance = dbscan(sample_simple2, 1, 2, False); dbscan_instance.process(); clusters_sample2 = dbscan_instance.get_clusters(); dbscan_instance = dbscan(sample_simple3, 0.7, 3, False); dbscan_instance.process(); clusters_sample3 = dbscan_instance.get_clusters(); visualizer = cluster_visualizer(3); visualizer.append_clusters(clusters_sample1, sample_simple1, 0, markersize = 5); visualizer.append_clusters(clusters_sample2, sample_simple2, 1, markersize = 5); visualizer.append_clusters(clusters_sample3, sample_simple3, 2, markersize = 5); visualizer.show(); def testVisualize2DAnd3DClusters(self): sample_2d = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); sample_3d = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA); visualizer = cluster_visualizer(2, 2); visualizer.append_clusters([ sample_2d ], None, 0, markersize = 5); visualizer.append_clusters([ sample_3d ], None, 1, markersize = 30); visualizer.show(); def testVisualizeRectangeRepresentation2x2(self): sample_simple1 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); sample_simple2 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); sample_simple3 = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3); visualizer = cluster_visualizer(3, 2); visualizer.append_clusters([ sample_simple1 ], None, 0, markersize = 5); visualizer.append_clusters([ sample_simple2 ], None, 1, markersize = 5); visualizer.append_clusters([ sample_simple3 ], None, 2, markersize = 5); visualizer.show(); def testVisualizeRectangeRepresentation3x5(self): visualizer = cluster_visualizer(15, 5); for i in range(15): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); visualizer.append_clusters([ sample ], None, i, markersize = 5); visualizer.show(); def testVisualizeByDataOnly(self): visualizer = cluster_visualizer(); sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); visualizer.append_clusters([ sample ]); visualizer.show(); def testVisualizeHugeAmountClusters(self): visualizer = cluster_visualizer(); data_clusters = [ [ [ random.random() ] ] for _ in range(0, 100) ]; visualizer.append_clusters(data_clusters); visualizer.show(); def testVisualizeOnExistedFigure(self): figure = plt.figure(); sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); visualizer = cluster_visualizer(); visualizer.append_clusters([ sample ]); visualizer.show(figure); def testVisualizeOnExistedFigureWithContent(self): figure = plt.figure(); axis = figure.add_subplot(121); axis.plot(range(0, 10, 1), range(0, 10, 1), marker = 'o', color = 'blue', ls = ''); sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); visualizer = cluster_visualizer(size_row = 2); visualizer.append_clusters([ sample ]); visualizer.show(figure); def testVisualizeOnExistedFigureWithContentByDefault(self): figure = plt.figure(); axis = figure.add_subplot(211); axis.plot(range(0, 10, 1), range(0, 10, 1), marker = 'o', color = 'blue', ls = ''); sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); visualizer = cluster_visualizer(); visualizer.append_clusters([ sample ]); visualizer.show(figure); def testVisualizeClusterWithAttributes(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); cure_instance = cure(sample, 2, 5, 0.5, False); cure_instance.process(); clusters = cure_instance.get_clusters(); representors = cure_instance.get_representors(); means = cure_instance.get_means(); visualizer = cluster_visualizer(); visualizer.append_clusters(clusters, sample); for cluster_index in range(len(clusters)): visualizer.append_cluster_attribute(0, cluster_index, representors[cluster_index], '*', 10); visualizer.append_cluster_attribute(0, cluster_index, [ means[cluster_index] ], 'o'); visualizer.show(); pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_generator.py000077500000000000000000000051361375753423500261110ustar00rootroot00000000000000"""! @brief Unit-tests for cluster generator. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.generator import data_generator from pyclustering.tests.assertion import assertion class generator_unit_tests(unittest.TestCase): def assert_dimension(self, data, expected_dimension): for point in data: assertion.eq(expected_dimension, len(point)) def assert_distribution(self, data, sizes, centers, widths): index_cluster = 0 index_cluster_point = 0 actual_means = [[0.0 for _ in range(len(data[0])) ] for _ in range(len(sizes))] for index_point in range(len(data)): for index_dimension in range(len(data[0])): actual_means[index_cluster][index_dimension] += data[index_point][index_dimension] index_cluster_point += 1 if index_cluster_point == sizes[index_cluster]: index_cluster_point = 0 index_cluster += 1 for index_cluster in range(len(actual_means)): for index_dimension in range(len(data[0])): actual_means[index_cluster][index_dimension] /= sizes[index_cluster] assertion.ge(centers[index_cluster][index_dimension], actual_means[index_cluster][index_dimension] - widths[index_cluster]) assertion.le(centers[index_cluster][index_dimension], actual_means[index_cluster][index_dimension] + widths[index_cluster]) def test_generate_one_dimension(self): data = data_generator(2, 1, [10, 10]).generate() assertion.eq(20, len(data)) self.assert_dimension(data, 1) def test_generate_two_dimension(self): data = data_generator(2, 2, [10, 15]).generate() assertion.eq(25, len(data)) self.assert_dimension(data, 2) def test_generate_one_cluster(self): data = data_generator(1, 10, 20).generate() assertion.eq(20, len(data)) self.assert_dimension(data, 10) def test_generate_similar_clusters(self): data = data_generator(10, 2, 10).generate() assertion.eq(100, len(data)) self.assert_dimension(data, 2) def test_generate_with_centers(self): data = data_generator(3, 1, [5, 10, 15], [[0.0], [-5.0], [5.0]]).generate() assertion.eq(30, len(data)) self.assert_distribution(data, [5, 10, 15], [[0.0], [-5.0], [5.0]], [1.0, 1.0, 1.0]) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_gmeans.py000077500000000000000000000206321375753423500253730ustar00rootroot00000000000000"""! @brief Unit-tests for G-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.gmeans_templates import gmeans_test_template from pyclustering.cluster.gmeans import gmeans from pyclustering.utils import read_sample, distance_metric, type_metric from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES, SIMPLE_ANSWERS class testable_gmeans(gmeans): @staticmethod def get_data_projection(data, vector): return gmeans._project_data(data, vector) class gmeans_unit_test(unittest.TestCase): def test_data_projection(self): data = [[1, 1], [2, 2], [3, 3]] projection = testable_gmeans.get_data_projection(data, [2, 2]) self.assertEqual([0.5, 1.0, 1.5], projection.tolist()) projection = testable_gmeans.get_data_projection(data, [1, 1]) self.assertEqual([1.0, 2.0, 3.0], projection.tolist()) def test_clustering_sample_01(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, False) def test_clustering_sample_01_kmax_correct(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, False, k_max=2) def test_clustering_sample_01_kmax_1(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [10], 1, False, k_max=1) def test_clustering_sample_01_kmax_10(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 1, False, k_max=10) def test_clustering_sample_02(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, False) def test_clustering_sample_02_kmax_correct(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 1, False, k_max=3) def test_clustering_sample_02_kmax_1(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [23], 1, False, k_max=1) def test_clustering_sample_02_kmax_2(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [8, 15], 1, False, k_max=2) def test_clustering_sample_03(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 1, False, random_state=1000) def test_clustering_sample_03_kmax_1(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [60], 1, False, k_max=1, random_state=1000) def test_clustering_sample_05(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, 1, False) def test_clustering_sample_06(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, 1, False) def test_clustering_sample_07(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, 1, False) def test_clustering_sample_08(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, 1, False) def test_clustering_sample_09(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, 1, False) def test_clustering_sample_10(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, 1, False) def test_clustering_sample_11(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, 1, False) def test_clustering_sample_12(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, 1, False) def test_clustering_sample_13(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, 1, False) def test_clustering_sample_15(self): gmeans_test_template().clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE15, SIMPLE_ANSWERS.ANSWER_SIMPLE15, 1, False, random_state=1200) def test_clustering_hepta_kmax_01(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 1, False, k_max=1) def test_clustering_hepta_kmax_02(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 2, 1, False, k_max=2, random_state=1000) def test_clustering_hepta_kmax_03(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 3, 1, False, k_max=3, random_state=1000) def test_clustering_hepta_kmax_04(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 4, 1, False, k_max=4, random_state=1000) def test_clustering_hepta_kmax_05(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 5, 1, False, k_max=5, random_state=1000) def test_clustering_hepta_kmax_06(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 6, 1, False, k_max=6, random_state=1000) def test_clustering_hepta_kmax_07(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, False, k_max=7, random_state=1000) def test_clustering_hepta_kmax_08(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, False, k_max=8, random_state=1000) def test_clustering_hepta_kmax_09(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, False, k_max=9, random_state=1000) def test_clustering_hepta_kmax_10(self): gmeans_test_template().clustering(FCPS_SAMPLES.SAMPLE_HEPTA, 7, 1, False, k_max=10, random_state=1000) def test_incorrect_data(self): self.assertRaises(ValueError, gmeans, [], 1, False, tolerance=0.05, repeat=3) def test_incorrect_k_init(self): self.assertRaises(ValueError, gmeans, [[0], [1], [2]], -1, False, tolerance=0.05, repeat=3) self.assertRaises(ValueError, gmeans, [[0], [1], [2]], 0, False, tolerance=0.05, repeat=3) def test_incorrect_tolerance(self): self.assertRaises(ValueError, gmeans, [[0], [1], [2]], 3, False, tolerance=0, repeat=3) def test_incorrect_repeat(self): self.assertRaises(ValueError, gmeans, [[0], [1], [2]], 3, False, tolerance=1, repeat=0) def test_incorrect_kmax_zero(self): self.assertRaises(ValueError, gmeans, [[0], [1], [2]], 3, False, tolerance=1, repeat=0, kmax=0) def test_incorrect_kmax_negative(self): self.assertRaises(ValueError, gmeans, [[0], [1], [2]], 3, False, tolerance=1, repeat=0, kmax=-2) def test_kmax_less_than_kinit(self): self.assertRaises(ValueError, gmeans, [[0], [1], [2]], 3, False, tolerance=1, repeat=0, kmax=2) def test_predict_without_process(self): self.assertEqual([], gmeans([[0], [1]]).predict([0])) def template_predict(self, path, amount, points, ccore): metric = distance_metric(type_metric.EUCLIDEAN) sample = read_sample(path) gmeans_instance = gmeans(sample, amount, ccore).process() centers = gmeans_instance.get_centers() closest_clusters = gmeans_instance.predict(points) self.assertEqual(len(points), len(closest_clusters)) for i in range(len(points)): cluster_index = closest_clusters[i] distance = metric(centers[cluster_index], points[i]) for center_index in range(len(centers)): if center_index != cluster_index: other_distance = metric(centers[center_index], points[i]) self.assertLessEqual(distance, other_distance) def test_predict_one_point(self): self.template_predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[0.3, 0.2]], False) self.template_predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[4.1, 1.1]], False) self.template_predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 1.9]], False) self.template_predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 4.1]], False) def test_predict_two_points(self): self.template_predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[0.3, 0.2], [2.1, 1.9]], False) self.template_predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 4.1], [2.1, 1.9]], False) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_hsyncnet.py000077500000000000000000000041561375753423500257570ustar00rootroot00000000000000"""! @brief Unit-tests for Hierarchical Sync (HSyncNet) algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.hsyncnet_templates import HsyncnetTestTemplates from pyclustering.nnet import solve_type from pyclustering.samples.definitions import SIMPLE_SAMPLES class HsyncnetUnitTest(unittest.TestCase): def testClusteringSampleSimple1(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], solve_type.FAST, 5, 0.3, True, False); def testClusteringOneAllocationSampleSimple1(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, [10], solve_type.FAST, 5, 0.3, True, False); def testClusteringSampleSimple1WithoutCollecting(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], solve_type.FAST, 5, 0.3, False, False); def testClusteringSampleSimple2(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [10, 5, 8], solve_type.FAST, 5, 0.2, True, False); def testClusteringOneAllocationSampleSimple2(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, [23], solve_type.FAST, 5, 0.2, True, False); def testClusteringOneDimensionDataSampleSimple7(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, [10, 10], solve_type.FAST, 5, 0.3, True, False); def testClusteringTheSameData1(self): HsyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, [5, 5, 5], solve_type.FAST, 5, 0.3, True, False); def testDynamicLengthCollecting(self): HsyncnetTestTemplates.templateDynamicLength(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, None, 5, 0.3, True, False); def testDynamicLengthWithoutCollecting(self): HsyncnetTestTemplates.templateDynamicLength(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, None, 5, 0.3, False, False); pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_kmeans.py000077500000000000000000000541431375753423500254030ustar00rootroot00000000000000"""! @brief Unit-tests for K-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import math import numpy # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.kmeans_templates import KmeansTestTemplates from pyclustering.cluster.kmeans import kmeans from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.utils.metric import distance_metric, type_metric class KmeansUnitTest(unittest.TestCase): def testClusterAllocationSampleSimple1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False) def testClusterOneAllocationSampleSimple1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[1.0, 2.5]], [10], False) def testClusterAllocationSampleSimple1Euclidean(self): metric = distance_metric(type_metric.EUCLIDEAN) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1EuclideanSquare(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Manhattan(self): metric = distance_metric(type_metric.MANHATTAN) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Chebyshev(self): metric = distance_metric(type_metric.CHEBYSHEV) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Minkowski01(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Minkowski02(self): metric = distance_metric(type_metric.MINKOWSKI, degree=4) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Gower(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined1(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined2(self): metric = distance_metric(type_metric.USER_DEFINED, func=lambda p1, p2: (p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined3(self): metric = distance_metric(type_metric.USER_DEFINED, func=lambda p1, p2: abs(p1[0] - p2[0]) + abs(p1[1] - p2[1])) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefinedInfitityProcessing(self): metric = distance_metric(type_metric.USER_DEFINED, func=lambda p1, p2: p1[0] + p2[0] + 2) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [10], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined1NumPy(self): data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) centers = numpy.array([[3.7, 5.5], [6.7, 7.5]]) metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(data, centers, [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined2NumPy(self): data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) centers = numpy.array([[3.7, 5.5], [6.7, 7.5]]) def simple_2d_euclidean_distance(point_a, point_b): return math.sqrt((point_a[0] - point_b[0]) ** 2 + (point_a[1] - point_b[1]) ** 2) metric = distance_metric(type_metric.USER_DEFINED, func=simple_2d_euclidean_distance) KmeansTestTemplates.templateLengthProcessData(data, centers, [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Canberra(self): metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1ChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple2(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False) def testClusterOneAllocationSampleSimple2(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[0.5, 0.2]], [23], False) def testClusterAllocationSampleSimple2Canberra(self): metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False, metric=metric) def testClusterAllocationSampleSimple2ChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False, metric=metric) def testClusterAllocationSampleSimple2UserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False, metric=metric) def testClusterAllocationSampleSimple2UserDefinedNumPy(self): data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2)) centers = numpy.array([[3.5, 4.8], [6.9, 7], [7.5, 0.5]]) metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templateLengthProcessData(data, centers, [10, 5, 8], False, metric=metric) def testClusterAllocationSampleSimple3(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], False) def testClusterAllocationSampleSimple3UserDefinedInfitityProcessing(self): metric = distance_metric(type_metric.USER_DEFINED, func=lambda p1, p2: p1[0] + p2[0] + 2) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [60], False, metric=metric) def testClusterOneAllocationSampleSimple3(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1]], [60], False) def testClusterAllocationSampleSimple4(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], False) def testClusterOneAllocationSampleSimple4(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[2.0, 5.0]], [75], False) def testClusterAllocationSampleSimple5(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], False) def testClusterOneAllocationSampleSimple5(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 0.0]], [60], False) def testClusterAllocationSampleSimple5Canberra(self): metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [30, 30], False, metric=metric) def testClusterAllocationSampleSimple5ChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[3.4, 2.6], [3.4, -3.2], [-3.4, -3.4], [-3.1, 3.3]], [15, 15, 15, 15], False, metric=metric) def testClusterOneDimensionSampleSimple7(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[-3.0], [2.0]], [10, 10], False) def testClusterAllocationSampleSimple7Canberra(self): metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[-3.0], [2.0]], [10, 10], False, metric=metric) def testClusterAllocationSampleSimple7ChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[-3.0], [2.0]], [10, 10], False, metric=metric) def testClusterOneDimensionSampleSimple8(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-4.0], [3.1], [6.1], [12.0]], [15, 30, 20, 80], False) def testWrongNumberOfCentersSimpleSample1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[2.0, 4.5], [3.3, 6.5], [5.0, 7.8]], None, False) def testWrongNumberOfCentersSimpleSample2(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[1.3, 1.5], [5.2, 8.5], [5.0, 7.8], [11.0, -3.0]], None, False) def testWrongNumberOfCentersSimpleSample3(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[4.5, 3.4], [-1.7, 4.3], [1.5, 1.0], [11.3, 1.2], [-4.6, -5.2]], None, False) def testWrongNumberOfCentersSimpleSample4(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[2.4, -1.4], [-5.2, -8.5], [-5.0, 3.1], [6.2, 1.4], [7.9, 2.4]], None, False) def testWrongNumberOfCentersSimpleSample5(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[-1.9, 3.2], [1.2, 34.5], [15.2, 34.8], [192, 234], [-32.3, -106]], None, False) def testTheSameData1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [ [4.0], [8.0] ], [10, 20], False) def testTheSameData2(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [ [1.0, 1.0], [2.5, 2.5], [4.0, 4.0] ], [5, 5, 5], False) def testOneDimensionalData1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], [15, 30, 20, 80], False) def testOneDimensionalData2(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [[4.5], [6.2]], [20, 10], False) def testThreeDimensionalData1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], [10, 10], False) def testDifferentDimensions(self): kmeans_instance = kmeans([ [0, 1, 5], [0, 2, 3] ], [ [0, 3] ], ccore=False) self.assertRaises(ValueError, kmeans_instance.process) def testClusterAllocationOneDimensionData(self): KmeansTestTemplates.templateClusterAllocationOneDimensionData(False) def testPredictOnePoint(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2]], [0], False) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[4.1, 1.1]], [1], False) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 1.9]], [2], False) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1]], [3], False) def testPredictOnePointUserMetric(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2]], [0], False, metric=metric) def testPredictTwoPoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1], [2.1, 1.9]], [3, 2], False) def testPredictTwoPointsUserMetric(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False, metric=metric) def testPredictFourPoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [2.1, 1.9], [2.1, 4.1]] KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 2, 3], False) def testPredictFivePoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False) def testPredictFivePointsEuclideanDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.EUCLIDEAN) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsEuclideanSquareDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsManhattanDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.MANHATTAN) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsChebyshevDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.CHEBYSHEV) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsMinkowski2Distance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.MINKOWSKI, degree=2) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsMinkowski4Distance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.MINKOWSKI, degree=4) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsCanberraDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.CANBERRA) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsChiSquareDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.CHI_SQUARE) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsGowerDistance(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.GOWER, data=centers+to_predict) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testPredictFivePointsUserMetric(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testObserveSampleSimple1(self): KmeansTestTemplates.templateCollectEvolution(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.5, 5.6], [6.8, 7.4]], [5, 5], False) def testObserveSampleSimple1OneCluster(self): KmeansTestTemplates.templateCollectEvolution(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.3, 5.4]], [10], False) def testObserveSampleSimple2(self): KmeansTestTemplates.templateCollectEvolution(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.4, 4.9], [6.8, 7.1], [7.6, 0.4]], [10, 5, 8], False) def testItermax0(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [], False, itermax=0) def testItermax1(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, itermax=1) def testItermax10Simple01(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, itermax=10) def testItermax10Simple02(self): KmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False, itermax=10) def testEncoderProcedureSampleSimple4(self): KmeansTestTemplates.templateEncoderProcedures(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], 5, False) def testShowResultsSampleSimple01(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.5, 5.6], [6.8, 7.4]], False) def testShowResultsSampleSimple02(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.4, 4.9], [6.8, 7.1], [7.6, 0.4]], False) def testShowResultsOneDimensionalData(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], False) def testShowResultsThreeDimensionalData(self): KmeansTestTemplates.templateShowClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], False) def testAnimateResultsSampleSimple01(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.5, 5.6], [6.8, 7.4]], False) def testAnimateResultsSampleSimple02(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.4, 4.9], [6.8, 7.1], [7.6, 0.4]], False) def testAnimateResultsOneDimensionalData(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], False) def testAnimateResultsThreeDimensionalData(self): KmeansTestTemplates.templateAnimateClusteringResultNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, [[1.0, 0.6, 0.8], [4.1, 4.2, 4.3]], False) def test_incorrect_data(self): self.assertRaises(ValueError, kmeans, [], [[1]]) def test_incorrect_centers(self): self.assertRaises(ValueError, kmeans, [[0], [1], [2]], []) def test_incorrect_tolerance(self): self.assertRaises(ValueError, kmeans, [[0], [1], [2]], [[1]], -1.0) def test_incorrect_itermax(self): self.assertRaises(ValueError, kmeans, [[0], [1], [2]], [[1]], itermax=-5) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_kmedians.py000077500000000000000000000261161375753423500257170ustar00rootroot00000000000000"""! @brief Unit-tests for K-Medians algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import numpy # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.kmedians_templates import KmediansTestTemplates from pyclustering.cluster.kmedians import kmedians from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.utils.metric import type_metric, distance_metric class KmediansUnitTest(unittest.TestCase): def testClusterAllocationSampleSimple1(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False) def testClusterAllocationSampleSimple1Euclidean(self): metric = distance_metric(type_metric.EUCLIDEAN) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1EuclideanSquare(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Manhattan(self): metric = distance_metric(type_metric.MANHATTAN) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Chebyshev(self): metric = distance_metric(type_metric.CHEBYSHEV) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1Minkowski(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2.0) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSampleSimple1UserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, metric=metric) def testClusterAllocationSample1NumpyArrayUserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) input_data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) initial_centers = numpy.array([[3.7, 5.5], [6.7, 7.5]]) KmediansTestTemplates.templateLengthProcessData(input_data, initial_centers, [5, 5], False, metric=metric) def testClusterAllocationSample2NumpyArrayUserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN_SQUARE)) input_data = numpy.array(read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2)) initial_centers = numpy.array([[3.5, 4.8], [6.9, 7], [7.5, 0.5]]) KmediansTestTemplates.templateLengthProcessData(input_data, initial_centers, [10, 5, 8], False, metric=metric) def testClusterOneAllocationSampleSimple1(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[1.0, 2.5]], [10], False) def testClusterAllocationSampleSimple2(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False) def testClusterOneAllocationSampleSimple2(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[0.5, 0.2]], [23], False) def testClusterAllocationSampleSimple3(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], False) def testClusterOneAllocationSampleSimple3(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1]], [60], False) def testClusterAllocationSampleSimple5(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], False) def testClusterOneAllocationSampleSimple5(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 0.0]], [60], False) def testClusterAllocationSample1WrongInitialNumberCenters1(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[2.8, 9.5], [3.5, 6.6], [1.3, 4.0]], None, False) def testClusterAllocationSample1WrongInitialNumberCenters2(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[2.8, 9.5], [3.5, 6.6], [1.3, 4.0], [1.2, 4.5]], None, False) def testClusterAllocationSample2WrongInitialNumberCenters(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5], [7.3, 4.5], [3.1, 5.4]], None, False) def testClusterTheSameData1(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [ [4.1], [7.3] ], [10, 20], False) def testClusterTheSameData2(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [ [1.1, 1.0], [3.0, 3.1], [5.0, 4.9] ], [5, 5, 5], False) def testOddSize(self): # Bug issue #428 (https://github.com/annoviko/pyclustering/issues/428) data = [[59.00732, 9.748167], [59.00608, 9.749117], [59.0047, 9.749933]] KmediansTestTemplates.templateLengthProcessData(data, [[59.00732, 9.748167], [59.00608, 9.749117]], None, False, tolerance=10) def testDifferentDimensions(self): kmedians_instance = kmedians([ [0, 1, 5], [0, 2, 3] ], [ [0, 3] ], ccore=False) self.assertRaises(NameError, kmedians_instance.process) def testClusterAllocationOneDimensionData(self): KmediansTestTemplates.templateClusterAllocationOneDimensionData(False) def testClusterAllocationTheSameObjectsOneInitialCenter(self): KmediansTestTemplates.templateClusterAllocationTheSameObjects(20, 1, False) def testClusterAllocationTheSameObjectsTwoInitialCenters(self): KmediansTestTemplates.templateClusterAllocationTheSameObjects(15, 2, False) def testClusterAllocationTheSameObjectsThreeInitialCenters(self): KmediansTestTemplates.templateClusterAllocationTheSameObjects(25, 3, False) def testClusterAllocationSampleRoughMediansSimple10(self): initial_medians = [[0.0772944481804071, 0.05224990900863469], [1.6021689021213712, 1.0347579135245601], [2.3341008076636096, 1.280022869739064]] KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, initial_medians, None, False) def testTotalWCESimple4(self): sample = [[0, 1, 5], [7, 8, 9], [0, 2, 3], [4, 5, 6]] initial_medians = [[0, 3, 2], [4, 6, 5]] kmedians_instance = kmedians(sample, initial_medians, ccore=False) self.assertNotEqual(self, kmedians_instance.get_total_wce(), 16.0) def testPredictOnePoint(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2]], [0], False) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[4.1, 1.1]], [1], False) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 1.9]], [2], False) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1]], [3], False) def testPredictOnePointUserMetric(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2]], [0], False, metric=metric) def testPredictTwoPoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1], [2.1, 1.9]], [3, 2], False) def testPredictTwoPointsUserMetric(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False, metric=metric) def testPredictFourPoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [2.1, 1.9], [2.1, 4.1]] KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 2, 3], False) def testPredictFivePoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False) def testPredictFivePointsUserMetric(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) KmediansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, to_predict, [0, 1, 1, 2, 3], False, metric=metric) def testItermax0(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [], False, itermax=0) def testItermax1(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, itermax=1) def testItermax10Simple01(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], False, itermax=10) def testItermax10Simple02(self): KmediansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], False, itermax=10) def test_incorrect_data(self): self.assertRaises(ValueError, kmedians, [], [[1]]) def test_incorrect_centers(self): self.assertRaises(ValueError, kmedians, [[0], [1], [2]], []) def test_incorrect_tolerance(self): self.assertRaises(ValueError, kmedians, [[0], [1], [2]], [[1]], -1.0) def test_incorrect_itermax(self): self.assertRaises(ValueError, kmedians, [[0], [1], [2]], [[1]], itermax=-5) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_kmedoids.py000077500000000000000000000531741375753423500257270ustar00rootroot00000000000000"""! @brief Unit-tests for K-Medoids algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.kmedoids import kmedoids from pyclustering.cluster.tests.kmedoids_templates import kmedoids_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS from pyclustering.utils import read_sample from pyclustering.utils.metric import type_metric, distance_metric class KmedoidsUnitTest(unittest.TestCase): def testClusterAllocationSampleSimple1(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], False) def testClusterAllocationSampleSimple1WrongInitials1(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [1, 2, 3, 4], [2, 2, 3, 3], False) def testClusterAllocationSampleSimple1DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], False, data_type='distance_matrix') def testClusterAllocationSampleSimple1DistanceMatrixNumpy(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], False, data_type='distance_matrix', input_type='numpy') def testClusterAllocationSampleSimple1Euclidean(self): metric = distance_metric(type_metric.EUCLIDEAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1EuclideanDistanceMatrix(self): metric = distance_metric(type_metric.EUCLIDEAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterAllocationSampleSimple1SquareEuclidean(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1SquareEuclideanDistanceMatrix(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterAllocationSampleSimple1Manhattan(self): metric = distance_metric(type_metric.MANHATTAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1ManhattanDistanceMatrix(self): metric = distance_metric(type_metric.MANHATTAN) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterAllocationSampleSimple1Chebyshev(self): metric = distance_metric(type_metric.CHEBYSHEV) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1ChebyshevDistanceMatrix(self): metric = distance_metric(type_metric.CHEBYSHEV) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterAllocationSampleSimple1Minkowski(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2.0) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1MinkowskiDistanceMatrix(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2.0) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterAllocationSampleSimple1Gower(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1GowerDistanceMatrix(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterAllocationSampleSimple1UserDefined(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False) def testClusterAllocationSampleSimple1UserDefinedDistanceMatrix(self): metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templateLengthProcessWithMetric(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], metric, False, data_type='distance_matrix') def testClusterOneAllocationSampleSimple1(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5], [10], False) def testClusterOneAllocationSampleSimple1DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5], [10], False, data_type='distance_matrix') def testClusterAllocationSampleSimple1WithMedoidsInitializer(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], False, initialize_medoids=2) def testClusterAllocationSampleSimple2(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [3, 12, 20], [10, 5, 8], False) def testClusterAllocationSampleSimple2DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [3, 12, 20], [10, 5, 8], False, data_type='distance_matrix') def testClusterOneAllocationSampleSimple2(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10], [23], False) def testClusterOneAllocationSampleSimple2DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10], [23], False, data_type='distance_matrix') def testClusterAllocationSampleSimple2WithMedoidsInitializer(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, None, [10, 5, 8], False, initialize_medoids=3) def testClusterAllocationSampleSimple3(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [4, 12, 25, 37], [10, 10, 10, 30], False) def testClusterAllocationSampleSimple3DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [4, 12, 25, 37], [10, 10, 10, 30], False, data_type='distance_matrix') def testClusterOneAllocationSampleSimple3(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [30], [60], False) def testClusterAllocationSampleSimple3WithMedoidsInitializer(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, None, [10, 10, 10, 30], False, initialize_medoids=4) def testClusterAllocationSampleSimple5(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [4, 18, 34, 55], [15, 15, 15, 15], False) def testClusterAllocationSampleSimple5DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [4, 18, 34, 55], [15, 15, 15, 15], False, data_type='distance_matrix') def testClusterOneAllocationSampleSimple5(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [35], [60], False) def testClusterTheSameData1(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [2, 20], [10, 20], False) def testClusterTheSameData1DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [2, 20], [10, 20], False, data_type='distance_matrix') def testClusterTheSameData2(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [2, 7, 12], [5, 5, 5], False) def testClusterTheSameData2DistanceMatrix(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, [2, 7, 12], [5, 5, 5], False, data_type='distance_matrix') def testClusterAllocationOneDimensionData(self): kmedoids_test_template.templateClusterAllocationOneDimensionData(False) def testClusterAllocationTheSameObjectsOneInitialMedoid(self): kmedoids_test_template.templateClusterAllocationTheSameObjects(20, 1, False) def testClusterAllocationTheSameObjectsTwoInitialMedoids(self): kmedoids_test_template.templateClusterAllocationTheSameObjects(15, 2, False) def testClusterAllocationTheSameObjectsThreeInitialMedoids(self): kmedoids_test_template.templateClusterAllocationTheSameObjects(25, 3, False) def testPredictOnePoint(self): medoids = [4, 12, 25, 37] kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[0.3, 0.2]], [0], False) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[4.1, 1.1]], [3], False) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[2.1, 1.9]], [2], False) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[2.1, 4.1]], [1], False) def testPredictOnePointUserMetric(self): medoids = [4, 12, 25, 37] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[0.3, 0.2]], [0], False, metric=metric) def testPredictTwoPoints(self): medoids = [4, 12, 25, 37] kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[2.1, 4.1], [2.1, 1.9]], [1, 2], False) def testPredictTwoPointsUserMetric(self): medoids = [4, 12, 25, 37] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False, metric=metric) def testPredictFourPoints(self): medoids = [4, 12, 25, 37] to_predict = [[0.3, 0.2], [4.1, 1.1], [2.1, 1.9], [2.1, 4.1]] kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, to_predict, [0, 3, 2, 1], False) def testPredictFivePoints(self): medoids = [4, 12, 25, 37] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, to_predict, [0, 3, 3, 2, 1], False) def testPredictFivePointsUserMetric(self): medoids = [4, 12, 25, 37] to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] metric = distance_metric(type_metric.USER_DEFINED, func=distance_metric(type_metric.EUCLIDEAN)) kmedoids_test_template.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, medoids, to_predict, [0, 3, 3, 2, 1], False, metric=metric) def testAllocatedRequestedClustersSampleSimple01(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 1, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 2, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 3, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 4, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 5, None, False) def testAllocatedRequestedClustersSampleSimple02(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 1, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 2, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 3, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 4, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 5, None, False) def testAllocatedRequestedClustersSampleSimple03(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 2, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 5, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 8, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 10, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 15, None, False) def testAllocatedRequestedClustersSampleSimple04(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 10, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 25, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 40, None, False) def testAllocatedRequestedClustersWithTheSamePoints1(self): # Bug issue #366 - Kmedoids returns incorrect number of clusters. sample = [[0.0, 0.0], [0.1, 0.1], [0.0, 0.0], [0.1, 0.2]] kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 3, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 3, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 2, None, False) kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 1, None, False) def testAllocatedRequestedClustersWithTheSamePoints2(self): sample = [[0.23, 0.2], [-0.1, 0.1], [0.0, 0.9], [0.1, -0.2], [0.8, 0.1], [-0.1, 0.1], [-0.4, -0.2], [0.0, 0.9]] answers = [1, 2, 3, 4, 5, 6, 6, 6] for expected_amount in answers: kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, expected_amount, None, False) def testAllocatedRequestedClustersWithTotallyTheSamePoints(self): # Bug issue #366 - Kmedoids returns incorrect number of clusters. sample = [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] kmedoids_test_template.templateAllocateRequestedClusterAmount(sample, 1, None, False) def testItermax0(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [], False, itermax=0) def testItermax1(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], False, itermax=1) def testItermax10Simple01(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 9], [5, 5], False, itermax=10) def testItermax10Simple02(self): kmedoids_test_template.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [3, 12, 20], [10, 5, 8], False, itermax=10) def testSimple01AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, False, random_state=1000) def testSimple01AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, False, random_state=1000, data_type='distance_matrix') def testSimple02AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, False, random_state=1000) def testSimple02AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, False, random_state=1000, data_type='distance_matrix') def testSimple03AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, False, random_state=1000) def testSimple03AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, False, random_state=1000, data_type='distance_matrix') def testSimple04AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, False, random_state=1000) def testSimple04AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, False, random_state=1000, data_type='distance_matrix') def testSimple05AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, False, random_state=1000) def testSimple05AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, False, random_state=1000, data_type='distance_matrix') def testSimple06AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, False, random_state=1000) def testSimple06AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, False, random_state=1000, data_type='distance_matrix') def testSimple07AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, False, random_state=1000) def testSimple07AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, False, random_state=1000, data_type='distance_matrix') def testSimple08AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, False, random_state=1000) def testSimple08AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, False, random_state=1000, data_type='distance_matrix') def testSimple09AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, False, random_state=1000) def testSimple09AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, False, random_state=1000, data_type='distance_matrix') def testSimple10AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, False, random_state=1000) def testSimple10AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, False, random_state=1000, data_type='distance_matrix') def testSimple11AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, False, random_state=1000) def testSimple11AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, False, random_state=1000, data_type='distance_matrix') def testSimple12AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, False, random_state=1000) def testSimple12AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, False, random_state=1000, data_type='distance_matrix') def testSimple13AnswerByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, False, random_state=1000) def testSimple13AnswerDistanceMatrixByCore(self): kmedoids_test_template.clustering_with_answer(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, False, random_state=1000, data_type='distance_matrix') def test_incorrect_data(self): self.assertRaises(ValueError, kmedoids, [], [1]) def test_incorrect_centers(self): self.assertRaises(ValueError, kmedoids, [[0], [1], [2]], []) def test_incorrect_tolerance(self): self.assertRaises(ValueError, kmedoids, [[0], [1], [2]], [1], -1.0) def test_incorrect_itermax(self): self.assertRaises(ValueError, kmedoids, [[0], [1], [2]], [1], itermax=-5) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_mbsas.py000077500000000000000000000102461375753423500252260ustar00rootroot00000000000000"""! @brief Unit-tests for MBSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.cluster.tests.mbsas_templates import mbsas_test_template; from pyclustering.utils.metric import type_metric, distance_metric; from pyclustering.samples.definitions import SIMPLE_SAMPLES; class mbsas_unit_test(unittest.TestCase): def testClusteringSampleSimple1(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 1.0, [5, 5], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 1.0, [10], False); def testClusteringSampleSimple1Euclidean(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False, metric=distance_metric(type_metric.EUCLIDEAN)); def testClusteringSampleSimple1EuclideanSquare(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 100.0, [10], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); def testClusteringSampleSimple1Manhattan(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.MANHATTAN)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False, metric=distance_metric(type_metric.MANHATTAN)); def testClusteringSampleSimple1Chebyshev(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1.0, [5, 5], False, metric=distance_metric(type_metric.CHEBYSHEV)); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 10.0, [10], False, metric=distance_metric(type_metric.CHEBYSHEV)); def testClusteringSampleSimple2(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1.0, [5, 8, 10], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 10.0, [23], False); def testClusteringSampleSimple3(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 2.0, [10, 10, 10, 30], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, 10.0, [60], False); def testOneDimentionalPoints1(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1.0, [10, 10], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 10.0, [20], False); def testOneDimentionalPoints2(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 1.0, [10, 20], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 10.0, [30], False); def testThreeDimentionalPoints(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 1.0, [10, 10], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2, 10.0, [20], False); def testTheSamePoints1(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 1.0, [5, 5, 5], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 30, 1.0, [5, 5, 5], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, 10.0, [15], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 1.0, [15], False); def testTheSamePoints2(self): mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 1.0, [10, 20], False); mbsas_test_template.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3, 10.0, [30], False); pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_optics.py000077500000000000000000000206021375753423500254170ustar00rootroot00000000000000"""! @brief Unit-tests for OPTICS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.optics_templates import OpticsTestTemplates from pyclustering.cluster.optics import optics, ordering_analyser, ordering_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES class OpticsUnitTest(unittest.TestCase): def testClusteringSampleSimple1(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, None, [5, 5], False) def testClusteringSampleSimple1DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.4, 2, None, [5, 5], False) def testClusteringSampleSimple2(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, None, [5, 8, 10], False) def testClusteringSampleSimple2DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 2, None, [5, 8, 10], False) def testClusteringSampleSimple3(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, None, [10, 10, 10, 30], False) def testClusteringSampleSimple3DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.7, 3, None, [10, 10, 10, 30], False) def testClusteringSampleSimple4(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, None, [15, 15, 15, 15, 15], False) def testClusteringSampleSimple4DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 3, None, [15, 15, 15, 15, 15], False) def testClusteringSampleSimple5(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, None, [15, 15, 15, 15], False) def testClusteringSampleSimple5DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 3, None, [15, 15, 15, 15], False) def testClusteringSampleSimple6(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 1.0, 3, None, [20, 21], False) def testClusteringSampleSimple6DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, 1.0, 3, None, [20, 21], False) def testClusteringThreeDimensionalSimple11(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2.0, 2, None, [10, 10], False) OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 3.0, 2, None, [10, 10], False) def testClusteringTheSameData1(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 3, None, [10, 20], False) def testClusteringTheSameData1DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 3, None, [10, 20], False) def testClusteringTheSameData2(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, None, [5, 5, 5], False) def testClusteringTheSameData2DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 2, None, [5, 5, 5], False) def testClusteringTheSameData2OneCluster(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 20.0, 2, None, [15], False) def testClusteringTheSameData2OneClusterDistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 20.0, 2, None, [15], False) def testClusteringHepta(self): OpticsTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3, None, [30, 30, 30, 30, 30, 30, 32], False) def testClusteringHeptaDistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 3, None, [30, 30, 30, 30, 30, 30, 32], False) def testClusteringOneDimensionDataSampleSimple7(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2.0, 2, None, [10, 10], False) def testClusteringOneDimensionDataSampleSimple7DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2.0, 2, None, [10, 10], False) def testClusteringOneDimensionDataSampleSimple9(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3.0, 3, None, [10, 20], False) def testClusteringOneDimensionDataSampleSimple9DistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 3.0, 3, None, [10, 20], False) def testClusteringSampleSimple2RadiusGreater(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5.0, 2, 3, [5, 8, 10], False) def testClusteringSampleSimple2RadiusGreaterDistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5.0, 2, 3, [5, 8, 10], False) def testClusteringSampleSimple3RadiusGreater(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5.0, 3, 4, [10, 10, 10, 30], False) def testClusteringSampleSimple3RadiusGreaterDistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5.0, 3, 4, [10, 10, 10, 30], False) def testClusteringSampleSimple4RadiusGreater(self): OpticsTestTemplates.templateClusteringResults(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 6.0, 3, 5, [15, 15, 15, 15, 15], False) def testClusteringSampleSimple4RadiusGreaterDistanceMatrix(self): OpticsTestTemplates.templateClusteringResultsDistanceMatrix(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 6.0, 3, 5, [15, 15, 15, 15, 15], False) def testClusteringLsunRadiusGreater(self): # Two points are noise after recalculation OpticsTestTemplates.templateClusteringResults(FCPS_SAMPLES.SAMPLE_LSUN, 1.0, 3, 3, [99, 100, 202], False) def testClusteringOrderVisualizer(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) optics_instance = optics(sample, 6.0, 3, 5) optics_instance.process() analyser = ordering_analyser(optics_instance.get_ordering()) ordering_visualizer.show_ordering_diagram(analyser, 5) def testClusterOrderingOneClusterExtraction(self): analyser = ordering_analyser([5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) amount_clusters, borders = analyser.extract_cluster_amount(6.5) assert 1 == amount_clusters assert 0 == len(borders) amount_clusters, borders = analyser.extract_cluster_amount(4.5) assert 0 == amount_clusters assert 0 == len(borders) def testImpossibleClusterOrderingAllocationHomogeneous(self): analyser = ordering_analyser([5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0]) amount_clusters, borders = analyser.calculate_connvectivity_radius(2) assert None == amount_clusters; assert 0 == len(borders); def testImpossibleClusterOrderingAllocationGeterogeneous(self): analyser = ordering_analyser([5.0, 5.0, 5.0, 5.0, 6.0, 8.0, 6.0, 5.0, 5.0, 5.0]) amount_clusters, borders = analyser.calculate_connvectivity_radius(3) assert None == amount_clusters assert 0 == len(borders) def test_incorrect_data(self): self.assertRaises(ValueError, optics, [], 0.1, 1) def test_incorrect_eps(self): self.assertRaises(ValueError, optics, [[0], [1], [2]], -1.0, 1) def test_incorrect_minpts(self): self.assertRaises(ValueError, optics, [[0], [1], [2]], 0.5, -1) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, optics, [[0], [1], [2]], 0.5, 1, amount_clusters=-1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_rock.py000077500000000000000000000056451375753423500250660ustar00rootroot00000000000000"""! @brief Unit-tests for ROCK algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.rock import rock from pyclustering.cluster.tests.rock_templates import RockTestTemplates from pyclustering.samples.definitions import SIMPLE_SAMPLES class RockUnitTest(unittest.TestCase): def testClusterAllocationSampleSimple1(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 0.5, [5, 5], False) RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 1, 0.5, [10], False) def testClusterAllocationSampleSimple2(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 0.5, [10, 5, 8], False) RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 1, 0.5, [23], False) def testClusterAllocationSampleSimple3(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 0.5, [10, 10, 10, 30], False) def testClusterAllocationSampleSimple3WrongRadius(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1.7, 4, 0.5, [10, 10, 10, 30], False) def testClusterAllocationSampleSimple4(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 0.5, [15, 15, 15, 15, 15], False) def testClusterAllocationSampleSimple4WrongRadius(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1.5, 5, 0.5, [15, 15, 15, 15, 15], False) def testClusterAllocationSampleSimple5(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 0.5, [15, 15, 15, 15], False) def testClusterTheSameData1(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, 2, 0.5, [10, 20], False) def testClusterTheSameData2(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 2, 0.5, [5, 5, 5], False) def testClusterAllocationIncorrectNumberClusters(self): RockTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 4, 0.5, [15, 15, 15, 15, 15], False) def test_incorrect_data(self): self.assertRaises(ValueError, rock, [], 0.1, 2) def test_incorrect_eps(self): self.assertRaises(ValueError, rock, [[0], [1], [2]], -1.0, 2) def test_incorrect_minpts(self): self.assertRaises(ValueError, rock, [[0], [1], [2]], 0.5, 0) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, rock, [[0], [1], [2]], 0.5, 1, -0.1) self.assertRaises(ValueError, rock, [[0], [1], [2]], 0.5, 1, 1.1) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_silhouette.py000077500000000000000000000253461375753423500263150ustar00rootroot00000000000000"""! @brief Unit-tests for Silhouette algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.silhouette import silhouette, silhouette_ksearch_type from pyclustering.cluster.tests.silhouette_templates import silhouette_test_template from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS class silhouette_unit_tests(unittest.TestCase): def test_correct_score_simple01(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, False) def test_correct_score_simple02(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, False) def test_correct_score_simple03(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, False) def test_correct_score_simple04(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, False) def test_correct_score_simple05(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, False) def test_correct_score_simple06(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, False) def test_correct_score_simple07(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, False) def test_correct_score_simple08(self): silhouette_test_template.correct_scores(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, False) def test_correct_ksearch_simple01(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple01_kmedoids(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEDOIDS, False) def test_correct_ksearch_simple01_kmedians(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, 2, 10, silhouette_ksearch_type.KMEDIANS, False) def test_correct_ksearch_simple02(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple02_kmedoids(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEDOIDS, False) def test_correct_ksearch_simple02_kmedians(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, 2, 10, silhouette_ksearch_type.KMEDIANS, False) def test_correct_ksearch_simple03(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple03_kmedoids(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEDOIDS, False) def test_correct_ksearch_simple03_kmedians(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, 2, 10, silhouette_ksearch_type.KMEDIANS, False) def test_correct_ksearch_simple05(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple06(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple07(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple08(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple09(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, SIMPLE_ANSWERS.ANSWER_SIMPLE9, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple10(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, SIMPLE_ANSWERS.ANSWER_SIMPLE10, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple11(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple12(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, SIMPLE_ANSWERS.ANSWER_SIMPLE12, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_correct_ksearch_simple13(self): silhouette_test_template.correct_ksearch(SIMPLE_SAMPLES.SAMPLE_SIMPLE13, SIMPLE_ANSWERS.ANSWER_SIMPLE13, 2, 10, silhouette_ksearch_type.KMEANS, False) def test_distance_matrix_sample01(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1, False) def test_distance_matrix_sample02(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2, False) def test_distance_matrix_sample03(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3, False) def test_distance_matrix_sample04(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, SIMPLE_ANSWERS.ANSWER_SIMPLE4, False) def test_distance_matrix_sample05(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, SIMPLE_ANSWERS.ANSWER_SIMPLE5, False) def test_distance_matrix_sample06(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, SIMPLE_ANSWERS.ANSWER_SIMPLE6, False) def test_distance_matrix_sample07(self): silhouette_test_template.correct_processing_data_types(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7, False) def test_random_state_1_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 1, False) def test_random_state_2_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 2, False) def test_random_state_4_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 4, False) def test_random_state_8_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 8, False) def test_random_state_16_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 16, False) def test_random_state_128_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 128, False) def test_random_state_1024_kmeans(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEANS, 1024, False) def test_random_state_1_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 1, False) def test_random_state_2_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 2, False) def test_random_state_4_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 4, False) def test_random_state_128_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 128, False) def test_random_state_1024_kmedians(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 1024, False) def test_random_state_1_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDOIDS, 1, False) def test_random_state_2_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 2, False) def test_random_state_4_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 4, False) def test_random_state_128_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 128, False) def test_random_state_1024_kmedoids(self): silhouette_test_template.random_state(2, 10, silhouette_ksearch_type.KMEDIANS, 1024, False) def test_incorrect_data(self): self.assertRaises(ValueError, silhouette, [], [[1, 2], [3, 4]]) def test_incorrect_clusters(self): self.assertRaises(ValueError, silhouette, [[1], [2], [3], [4]], []) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_somsc.py000077500000000000000000000111631375753423500252440ustar00rootroot00000000000000"""! @brief Unit-tests for SOM-SC algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.somsc import somsc from pyclustering.cluster.tests.somsc_templates import SyncnetTestTemplates from pyclustering.samples.definitions import SIMPLE_SAMPLES class SomscUnitTest(unittest.TestCase): def testClusterAllocationSampleSimple1(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, [5, 5], False) def testClusterOneAllocationSampleSimple1(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, [10], False) def testClusterAllocationSampleSimple2(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, [10, 5, 8], False) def testClusterOneAllocationSampleSimple2(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, [23], False) def testClusterAllocationSampleSimple3(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [10, 10, 10, 30], False) def testClusterOneAllocationSampleSimple3(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, [60], False) def testClusterAllocationSampleSimple4(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, [15, 15, 15, 15, 15], False) def testClusterOneAllocationSampleSimple4(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, [75], False) def testClusterAllocationSampleSimple5(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 4, [15, 15, 15, 15], False) def testClusterOneAllocationSampleSimple5(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, [60], False) def testClusterOneDimensionSampleSimple7(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, [10, 10], False) def testClusterOneDimensionSampleSimple8(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 4, None, False) def testWrongNumberOfCentersSimpleSample1(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 3, None, False) def testWrongNumberOfCentersSimpleSample2(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 4, None, False) def testClusterTheSameData1(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, [10, 20], False) def testClusterTheSameData2(self): SyncnetTestTemplates().templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 3, [5, 5, 5], False) def testClusterAllocationOneDimensionData(self): SyncnetTestTemplates().templateClusterAllocationOneDimensionData(False) def test_incorrect_data(self): self.assertRaises(ValueError, somsc, [], 1, 1) def test_incorrect_epouch(self): self.assertRaises(ValueError, somsc, [[0], [1], [2]], 1, -1) def test_incorrect_amount_clusters(self): self.assertRaises(ValueError, somsc, [[0], [1], [2]], 0, 1) def test_predict_one_point(self): SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[0.3, 0.2]], [0], False) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[4.1, 1.1]], [1], False) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 1.9]], [2], False) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 4.1]], [3], False) def test_predict_two_points(self): SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[0.3, 0.2], [2.1, 1.9]], [0, 2], False) SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, [[2.1, 4.1], [2.1, 1.9]], [3, 2], False) def test_predict_four_points(self): to_predict = [[0.3, 0.2], [4.1, 1.1], [2.1, 1.9], [2.1, 4.1]] SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, to_predict, [0, 1, 2, 3], False) def test_predict_five_points(self): to_predict = [[0.3, 0.2], [4.1, 1.1], [3.9, 1.1], [2.1, 1.9], [2.1, 4.1]] SyncnetTestTemplates().predict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4, to_predict, [0, 1, 1, 2, 3], False) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_syncnet.py000077500000000000000000000214411375753423500256030ustar00rootroot00000000000000"""! @brief Unit-tests for Sync algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet import initial_type, conn_represent, solve_type from pyclustering.cluster.tests.syncnet_templates import SyncnetTestTemplates from pyclustering.cluster.syncnet import syncnet, syncnet_visualizer from pyclustering.utils import read_sample from numpy import pi from pyclustering.samples.definitions import SIMPLE_SAMPLES class SyncnetUnitTest(unittest.TestCase): def testClusteringSampleSimple1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5], False); def testClusteringSampleSimple1ListRepr(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.LIST, [5, 5], False); def testClusteringSampleSimple2(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 8, 10], False); def testClusteringSampleSimple2ListRepr(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.LIST, [5, 8, 10], False); def testClusteringSampleSimple3(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [10, 10, 10, 30], False); def testClusteringSampleSimple3ListRepr(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.LIST, [10, 10, 10, 30], False); def testClusteringSampleSimple4(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [15, 15, 15, 15, 15], False); def testClusteringSampleSimple5(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [15, 15, 15, 15], False); def testClusteringTheSameData1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [10, 20], False); def testClusteringTheSameData2(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5, 5], False); def testClusterAllocationHighToleranceSampleSimple1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, conn_represent.MATRIX, [10], False); def testClusterAllocationHighToleranceSampleSimple2(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, conn_represent.MATRIX, [23], False); def testClusterAllocationHighToleranceSampleSimple3(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, conn_represent.MATRIX, [60], False); def testClusterAllocationHighToleranceSampleSimple4(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 0.7, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, conn_represent.MATRIX, [75], False); def testClusterAllocationHighToleranceSampleSimple5(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 0.7, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 2 * pi, conn_represent.MATRIX, [60], False); def testClusterAllocationConnWeightSampleSimple1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, conn_represent.MATRIX, [5, 5], False); SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, conn_represent.MATRIX, [10], False); def testClusterAllocationConnWeightSampleSimple2(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, conn_represent.MATRIX, [5, 8, 10], False); SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 10, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, True, 0.05, conn_represent.MATRIX, [23], False); def testClusteringWithoutDynamicCollectingSampleSimple1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [5, 5], False); def testClusteringWithoutDynamicCollectingSampleSimple2(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [5, 8, 10], False); def testClusteringWithoutDynamicCollectingSampleSimple3(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [10, 10, 10, 30], False); def testClusteringRandomInitialSampleSimple1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5], False); def testClusteringRandomInitialSampleSimple2(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 0.999, solve_type.FAST, initial_type.RANDOM_GAUSSIAN, False, False, 0.05, conn_represent.MATRIX, [5, 8, 10], False); def testClusteringSolverRK4SampleSimple1(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 0.999, solve_type.RK4, initial_type.RANDOM_GAUSSIAN, True, False, 0.05, conn_represent.MATRIX, [5, 5], False); def testClusteringOneDimensionDataSampleSimple7(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 0.999, solve_type.FAST, initial_type.EQUIPARTITION, True, False, 0.05, conn_represent.MATRIX, [10, 10], False); def testClusteringOneDimensionDataSampleSimple9(self): SyncnetTestTemplates.templateClustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 2, 0.999, solve_type.FAST, initial_type.EQUIPARTITION, True, False, 0.05, conn_represent.MATRIX, [20, 10], False); def testShowNetwork2DimensionMatrixRepr(self): SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, conn_represent.MATRIX, False); SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2.0, conn_represent.MATRIX, False); def testShowNetwork2DimensionListRepr(self): SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, conn_represent.LIST, False); SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 2.0, conn_represent.LIST, False); def testShowNetwork3DimensionMatrixRepr(self): SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1.0, conn_represent.MATRIX, False); def testShowNetwork3DimensionListRepr(self): SyncnetTestTemplates.templateShowNetwork(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1.0, conn_represent.LIST, False); def testConnectionApi(self): SyncnetTestTemplates.templateConnectionApi(conn_represent.MATRIX, False); SyncnetTestTemplates.templateConnectionApi(conn_represent.LIST, False); def testVisualizerNoFailure(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) network = syncnet(sample, 1.0, ccore=False) analyser = network.simulate(25, 5, solve_type.FAST, True) syncnet_visualizer.animate_cluster_allocation(sample, analyser) def test_incorrect_data(self): self.assertRaises(ValueError, syncnet, [], 0.5) pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_syncsom.py000077500000000000000000000107311375753423500256130ustar00rootroot00000000000000"""! @brief Unit-tests for SYNC-SOM algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.cluster.syncsom import syncsom; from pyclustering.utils import read_sample; from pyclustering.samples.definitions import SIMPLE_SAMPLES; class SyncsomUnitTest(unittest.TestCase): def templateLengthSomCluster(self, file, som_map_size, radius, eps): sample = read_sample(file); network = syncsom(sample, som_map_size[0], som_map_size[1], radius); network.process(collect_dynamic = False, order = eps); # Check unique som_clusters = network.get_som_clusters(); indexes = set(); for som_cluster in som_clusters: for index in som_cluster: assert (index in indexes) is False; indexes.add(index); def testSomClusterAllocationSampleSimple1(self): self.templateLengthSomCluster(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [3, 3], 1.0, 0.99); def testSomClusterAllocationSampleSimple3(self): self.templateLengthSomCluster(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [3, 3], 1.0, 0.99); def testSomClusterAllocationSampleSimple4(self): self.templateLengthSomCluster(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [3, 3], 1.0, 0.99); def testSomClusterAllocationSampleSimple5(self): self.templateLengthSomCluster(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [3, 3], 1.0, 0.99); def templateLengthProcessData(self, file, som_map_size, radius, eps, expected_cluster_length): result_testing = False; # If phases crosses each other because of random part of the network then we should try again. for _ in range(0, 5, 1): sample = read_sample(file); network = syncsom(sample, som_map_size[0], som_map_size[1], radius); network.process(collect_dynamic = False, order = eps); clusters = network.get_clusters(); obtained_cluster_sizes = [len(cluster) for cluster in clusters]; if (len(sample) != sum(obtained_cluster_sizes)): continue; obtained_cluster_sizes.sort(); expected_cluster_length.sort(); #print(obtained_cluster_sizes, expected_cluster_length); if (obtained_cluster_sizes != expected_cluster_length): continue; # Unit-test is passed result_testing = True; break; assert result_testing; def testClusterAllocationSampleSimple1ByGeaterAmoutNeurons(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [5, 5], 1.0, 0.999, [5, 5]); def testClusterAllocationSampleSimple1AsSom(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [1, 2], 1.0, 0.999, [5, 5]); def testClusterAllocationSampleSimple1(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [2, 2], 1.0, 0.999, [5, 5]); def testClusterAllocationSampleSimple2(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [5, 5], 1.0, 0.999, [10, 5, 8]); def testClusterAllocationSampleSimple3(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [5, 5], 1.0, 0.999, [10, 10, 10, 30]); def testClusterAllocationOneDimensionDataSampleSimple7AsSom(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [1, 2], 1.0, 0.999, [10, 10]); def testClusterAllocationOneDimensionDataSampleSimple7(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [3, 3], 1.0, 0.999, [10, 10]); def testClusterAllocationOneDimensionDataSampleSimple9AsSom(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [1, 2], 1.0, 0.999, [20, 10]); def testClusterAllocationOneDimensionDataSampleSimple9(self): self.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [3, 3], 1.0, 0.999, [20, 10]); def testShowLayersProcessing(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); network = syncsom(sample, 4, 4, 1.0); network.process(collect_dynamic = False, order = 0.99); network.show_som_layer(); network.show_sync_layer(); pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_ttsas.py000077500000000000000000000073371375753423500252660ustar00rootroot00000000000000"""! @brief Unit-tests for TTSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.cluster.tests.ttsas_template import ttsas_test; from pyclustering.utils.metric import type_metric, distance_metric; from pyclustering.samples.definitions import SIMPLE_SAMPLES; class ttsas_unit_tests(unittest.TestCase): def testClusteringSampleSimple1(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], False); def testClusteringSampleSimple1Euclidean(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], False, metric=distance_metric(type_metric.EUCLIDEAN)); def testClusteringSampleSimple1EuclideanSquare(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [5, 5], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 100.0, 200.0, [10], False, metric=distance_metric(type_metric.EUCLIDEAN_SQUARE)); def testClusteringSampleSimple1Manhattan(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], False, metric=distance_metric(type_metric.MANHATTAN)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], False, metric=distance_metric(type_metric.MANHATTAN)); def testClusteringSampleSimple1Chebyshev(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1.0, 2.0, [5, 5], False, metric=distance_metric(type_metric.CHEBYSHEV)); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 10.0, 20.0, [10], False, metric=distance_metric(type_metric.CHEBYSHEV)); def testClusteringSampleSimple2(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1.0, 2.0, [5, 8, 10], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 10.0, 20.0, [23], False); def testClusteringSampleSimple3(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1.0, 2.0, [10, 10, 10, 30], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 10.0, 20.0, [60], False); def testOneDimentionalPoints1(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 1.0, 2.0, [10, 10], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 10.0, 20.0, [20], False); def testOneDimentionalPoints2(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 2.0, [10, 20], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 10.0, 20.0, [30], False); def testThreeDimentionalPoints(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 1.0, 2.0, [10, 10], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 10.0, 20.0, [20], False); def testTheSamePoints1(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1.0, 1.5, [5, 5, 5], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 0.001, 0.002, [5, 5, 5], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE12, 1000, 2000, [15], False); def testTheSamePoints2(self): ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 1.0, 2.0, [10, 20], False); ttsas_test.clustering(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, 10.0, 20.0, [30], False); pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_visualizer.py000077500000000000000000000105061375753423500263150ustar00rootroot00000000000000"""! @brief Unit-tests for cluster visualizers. @details This tests should be run manually to without option 'matplotlib.use('Agg')' to check that everything is displayed correctly, because these tests check that there is no exceptions and critical failures. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import os # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster import cluster_visualizer, cluster_visualizer_multidim from pyclustering.samples import answer_reader from pyclustering.samples.definitions import SIMPLE_SAMPLES, SIMPLE_ANSWERS, FAMOUS_SAMPLES, FAMOUS_ANSWERS from pyclustering.utils import read_sample class visualizer_unit_tests(unittest.TestCase): def template_visualize(self, path_sample, path_answer, filter=None, **kwargs): data = read_sample(path_sample) clusters = answer_reader(path_answer).get_clusters() visualizer = cluster_visualizer_multidim() visualizer.append_clusters(clusters, data) visualizer.show(filter, **kwargs) def template_visualize_adding_step_by_step(self, path_sample, path_answer, filter=None, **kwargs): data = read_sample(path_sample) clusters = answer_reader(path_answer).get_clusters() visualizer = cluster_visualizer_multidim() for cluster in clusters: visualizer.append_cluster(cluster, data) visualizer.show(filter, **kwargs) def test_multidim_one_dimension_simple07(self): self.template_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7) def test_multidim_one_dimension_simple08(self): self.template_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8) def test_multidim_two_dimension_simple01(self): self.template_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, SIMPLE_ANSWERS.ANSWER_SIMPLE1) def test_multidim_two_dimension_simple02(self): self.template_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, SIMPLE_ANSWERS.ANSWER_SIMPLE2) def test_multidim_two_dimension_simple03(self): self.template_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, SIMPLE_ANSWERS.ANSWER_SIMPLE3) def test_multidim_three_dimension_simple11(self): self.template_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, SIMPLE_ANSWERS.ANSWER_SIMPLE11) def test_multidim_four_dimension_iris(self): self.template_visualize(FAMOUS_SAMPLES.SAMPLE_IRIS, FAMOUS_ANSWERS.ANSWER_IRIS) def test_multidim_four_dimension_one_column(self): self.template_visualize(FAMOUS_SAMPLES.SAMPLE_IRIS, FAMOUS_ANSWERS.ANSWER_IRIS, max_row_size=1) def test_multidim_non_default_settings(self): self.template_visualize(FAMOUS_SAMPLES.SAMPLE_IRIS, FAMOUS_ANSWERS.ANSWER_IRIS, max_row_size=2, visible_axis=True, visible_labels=False, visible_grid=False) def test_multidim_simple07_by_steps(self): self.template_visualize_adding_step_by_step(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, SIMPLE_ANSWERS.ANSWER_SIMPLE7) def test_multidim_simple08_by_steps(self): self.template_visualize_adding_step_by_step(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, SIMPLE_ANSWERS.ANSWER_SIMPLE8) def template_save_to_file(self, visualizer_type, filename="ut-test-image.png"): data = [[1.1], [1.7], [3.7], [5.3], [2.5], [-1.5], [-0.9], [6.3], [6.5], [8.1]] clusters = [[0, 1, 2, 4, 5, 6], [3, 7, 8, 9]] visualizer = visualizer_type() visualizer.append_clusters(clusters, data) visualizer.save(filename) self.assertTrue(os.path.exists(filename)) os.remove(filename) def test_visualizer_save(self): self.template_save_to_file(cluster_visualizer) def test_visualizer_save_no_filename(self): self.assertRaises(ValueError, self.template_save_to_file, cluster_visualizer, "") def test_visualizer_multidim_save(self): self.template_save_to_file(cluster_visualizer_multidim) def test_visualizer_multidim_save_no_filename(self): self.assertRaises(ValueError, self.template_save_to_file, cluster_visualizer_multidim, "") pyclustering-0.10.1.2/pyclustering/cluster/tests/unit/ut_xmeans.py000077500000000000000000000566601375753423500254260ustar00rootroot00000000000000"""! @brief Unit-tests for X-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.cluster.tests.xmeans_templates import XmeansTestTemplates from pyclustering.cluster.xmeans import xmeans, splitting_type from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.utils import read_sample from pyclustering.utils.metric import distance_metric, type_metric class XmeansUnitTest(unittest.TestCase): def testBicClusterAllocationSampleSimple1(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple1Repeat(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, repeat=5) def testBicSampleSimple1WithoutInitialCenters(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicSampleSimple1WithoutInitialCentersRepeat(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, repeat=3) def testBicSampleSimple1MaxLessReal(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 1, False) def testBicSampleSimple1MaxLessRealRepeat(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 1, False, repeat=5) def testBicClusterAllocationSampleSimple1MetricEuclidean(self): metric = distance_metric(type_metric.EUCLIDEAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricEuclideanSquare(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricManhattan(self): metric = distance_metric(type_metric.MANHATTAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricChebyshev(self): metric = distance_metric(type_metric.CHEBYSHEV) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricMinkowski2(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricMinkowski4(self): metric = distance_metric(type_metric.MINKOWSKI, degree=4) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricCanberra(self): metric = distance_metric(type_metric.CANBERRA) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testBicClusterAllocationSampleSimple1MetricGower(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricEuclidean(self): metric = distance_metric(type_metric.EUCLIDEAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricEuclideanSquare(self): metric = distance_metric(type_metric.EUCLIDEAN_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric, alpha=0.1, beta=0.1) def testMndlClusterAllocationSampleSimple1MetricManhattan(self): metric = distance_metric(type_metric.MANHATTAN) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricChebyshev(self): metric = distance_metric(type_metric.CHEBYSHEV) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricMinkowski2(self): metric = distance_metric(type_metric.MINKOWSKI, degree=2) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricMinkowski4(self): metric = distance_metric(type_metric.MINKOWSKI, degree=4) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricCanberra(self): metric = distance_metric(type_metric.CANBERRA) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testMndlClusterAllocationSampleSimple1MetricChiSquare(self): metric = distance_metric(type_metric.CHI_SQUARE) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric, alpha=0.1, beta=0.1, random_state=1000) def testMndlClusterAllocationSampleSimple1MetricGower(self): metric = distance_metric(type_metric.GOWER, data=read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1)) XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, metric=metric) def testBicWrongStartClusterAllocationSampleSimple1(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], [5, 5], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleSimple1(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5], [6.7, 7.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.1, beta=0.1) def testMndlSampleSimple1WithoutInitialCenters(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.1, beta=0.1) def testMndlWrongStartClusterAllocationSampleSimple1(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [[3.7, 5.5]], [5, 5], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.1, beta=0.1) def testBicClusterAllocationSampleSimple2(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple2Repeat(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, repeat=5) def testBicWrongStartClusterAllocationSampleSimple2(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7]], [10, 5, 8], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleSimple2(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7], [7.5, 0.5]], [10, 5, 8], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.1, beta=0.1) def testMndlWrongStartClusterAllocationSampleSimple2(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [[3.5, 4.8], [6.9, 7]], [10, 5, 8], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.1, beta=0.1) def testBicClusterAllocationSampleSimple3(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple3Repeat(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, repeat=5) def testBicWrongStartClusterAllocationSampleSimple3(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [5.9, 5.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationMaxLessRealSampleSimple3(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 3, False) def testBicWrongStartClusterClusterAllocationSampleSimple3(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.BAYESIAN_INFORMATION_CRITERION, 4, False) def testMndlClusterAllocationSampleSimple3(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.2, beta=0.2) def testMndlWrongStartClusterClusterAllocationSampleSimple3(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, [[4.0, 1.0], [2.0, 2.0], [2.3, 3.9]], [10, 10, 10, 30], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 4, False, alpha=0.2, beta=0.2) def testBicClusterAllocationSampleSimple4(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple4Repeat(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, repeat=5) def testBicWrongStartClusterAllocationSampleSimple4(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0]], [15, 15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationMaxLessRealSampleSimple4(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 4.0]], None, splitting_type.BAYESIAN_INFORMATION_CRITERION, 2, False) def testMndlClusterAllocationSampleSimple4(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0], [1.5, 8.0]], [15, 15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False) def testMndlWrongStartClusterAllocationSampleSimple4(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 0.0], [1.5, 2.0], [1.5, 4.0], [1.5, 6.0]], [15, 15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False) def testMndlClusterAllocationMaxLessRealSampleSimple4(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, [[1.5, 4.0]], None, splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 2, False) def testBicClusterAllocationSampleSimple5(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicWrongStartClusterAllocationSampleSimple5(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0]], [15, 15, 15, 15], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleSimple5(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0], [1.0, 1.0], [1.0, 0.0]], [15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, random_state=1000) def testMndlWrongStartClusterAllocationSampleSimple5(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, [[0.0, 1.0], [0.0, 0.0]], [15, 15, 15, 15], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, random_state=1000) def testBicClusterAllocationSampleSimple6(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, [[3.5, 3.5], [3.7, 3.7]], [20, 21], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple6WithoutInitial(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, None, [20, 21], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleSimple6(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, [[3.5, 3.5], [3.7, 3.7]], [20, 21], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False) def testMndlClusterAllocationSampleSimple6WithoutInitial(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE6, None, [20, 21], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False) def testBicClusterAllocationSampleSimple7(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[1], [2]], [10, 10], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple7WithoutInitial(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, None, [10, 10], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleSimple7(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, [[1], [2]], [10, 10], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.01, beta=0.01) def testMndlClusterAllocationSampleSimple7WithoutInitial(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, None, [10, 10], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.01, beta=0.01) def testBicClusterAllocationSampleSimple8(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[-2.0], [3.0], [6.0], [12.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple8WrongAmountCenters(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleSimple8WrongAmountCenters(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False, alpha=0.2, beta=0.2) def testBicClusterAllocationSampleSimple8WrongAmountCentersRandomState(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, random_state=1000) def testMndlClusterAllocationSampleSimple8WrongAmountCentersRandomState(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, [[3.0], [6.0]], [15, 30, 20, 80], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False, random_state=1000) def testBicClusterAllocationSampleSimple9(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, [[3.0], [6.0]], [10, 20], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple9WithoutInitial(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE9, None, [10, 20], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple10(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, [[0.0, 0.3], [4.5, 3.4], [10.1, 10.6]], [11, 11, 11], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleSimple10WithoutInitial(self): XmeansTestTemplates.templateLengthProcessData(SIMPLE_SAMPLES.SAMPLE_SIMPLE10, None, [11, 11, 11], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicClusterAllocationSampleTwoDiamonds(self): XmeansTestTemplates.templateLengthProcessData(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.8, 0.2], [3.0, 0.0]], [400, 400], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testBicWrongStartClusterAllocationSampleTwoDiamonds(self): XmeansTestTemplates.templateLengthProcessData(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.8, 0.2]], [400, 400], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMndlClusterAllocationSampleTwoDiamonds(self): XmeansTestTemplates.templateLengthProcessData(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, [[0.8, 0.2], [3.0, 0.0]], [400, 400], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False) def testMathErrorDomainBic(self): # This is test for bug that was found in #407: 0.0 under logarithm function. XmeansTestTemplates.templateLengthProcessData([[0], [0], [10], [10], [20], [20]], [[5], [20]], [2, 2, 2], splitting_type.BAYESIAN_INFORMATION_CRITERION, 20, False) def testMathErrorDomainMndl(self): XmeansTestTemplates.templateLengthProcessData([[0], [0], [10], [10], [20], [20]], [[5], [20]], [2, 2, 2], splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, 20, False) def testClusterAllocationOneDimensionData(self): XmeansTestTemplates.templateClusterAllocationOneDimensionData(False) def testKmax05Amount3Offset02Initial01(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 10, 3, 2, 1, 2) def testKmax05Amount5Offset02Initial01(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 10, 5, 2, 1, 5) def testKmax05Amount5Offset02Initial02(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 10, 5, 2, 2, 5) def testKmax05Amount10Offset02Initial03(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 10, 10, 2, 3, 5) def testKmax05Amount10Offset02Initial04(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 10, 10, 2, 4, 5) def testKmax05Amount10Offset02Initial05(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 10, 10, 2, 5, 5) def testKmax05Amount20Offset02Initial05(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 20, 10, 2, 5, 5) def testKmax05Amount01Offset01Initial04(self): XmeansTestTemplates.templateMaxAllocatedClusters(False, 1, 1000, 1, 4, 5) def testPredictOnePoint(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2]], 4, [0], False) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[4.1, 1.1]], 4, [1], False) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 1.9]], 4, [2], False) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1]], 4, [3], False) def testPredictTwoPoints(self): centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[0.3, 0.2], [2.1, 1.9]], 4, [0, 2], False) XmeansTestTemplates.templatePredict(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, centers, [[2.1, 4.1], [2.1, 1.9]], 4, [3, 2], False) def test_random_state_1(self): XmeansTestTemplates.random_state(False, 2, 10, 1) def test_random_state_2(self): XmeansTestTemplates.random_state(False, 2, 10, 2) def test_random_state_4(self): XmeansTestTemplates.random_state(False, 2, 10, 4) def test_random_state_32(self): XmeansTestTemplates.random_state(False, 2, 10, 32) def test_random_state_1024(self): XmeansTestTemplates.random_state(False, 2, 10, 1024) def test_random_state_65536(self): XmeansTestTemplates.random_state(False, 2, 10, 65536) def test_incorrect_data(self): self.assertRaises(ValueError, xmeans, []) def test_incorrect_centers(self): self.assertRaises(ValueError, xmeans, [[0], [1], [2]], []) def test_incorrect_tolerance(self): self.assertRaises(ValueError, xmeans, [[0], [1], [2]], [[1]], 20, -1) def test_incorrect_repeat(self): self.assertRaises(ValueError, xmeans, [[0], [1], [2]], repeat=0) pyclustering-0.10.1.2/pyclustering/cluster/tests/xmeans_templates.py000077500000000000000000000121721375753423500260030ustar00rootroot00000000000000"""! @brief Test templates for X-Means clustering module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import random from pyclustering.cluster.xmeans import xmeans, splitting_type from pyclustering.cluster.center_initializer import random_center_initializer from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample, distance_metric, type_metric from pyclustering.tests.assertion import assertion class XmeansTestTemplates: @staticmethod def templateLengthProcessData(input_sample, start_centers, expected_cluster_length, type_splitting, kmax, ccore, **kwargs): if isinstance(input_sample, str): sample = read_sample(input_sample) else: sample = input_sample xmeans_instance = xmeans(sample, start_centers, kmax, 0.025, type_splitting, ccore, **kwargs) xmeans_instance.process() clusters = xmeans_instance.get_clusters() centers = xmeans_instance.get_centers() wce = xmeans_instance.get_total_wce() obtained_cluster_sizes = [len(cluster) for cluster in clusters] assertion.eq(len(sample), sum(obtained_cluster_sizes)) assertion.eq(len(clusters), len(centers)) assertion.le(len(centers), kmax) expected_wce = 0.0 metric = kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE)) for index_cluster in range(len(clusters)): for index_point in clusters[index_cluster]: expected_wce += metric(sample[index_point], centers[index_cluster]) assertion.eq(expected_wce, wce) if expected_cluster_length is not None: assertion.eq(len(expected_cluster_length), len(centers)) obtained_cluster_sizes.sort() expected_cluster_length.sort() assertion.eq(obtained_cluster_sizes, expected_cluster_length) @staticmethod def templatePredict(path_to_file, initial_centers, points, expected_amount, expected_closest_clusters, ccore, **kwargs): sample = read_sample(path_to_file) kmax = kwargs.get('kmax', 20) xmeans_instance = xmeans(sample, initial_centers, kmax, 0.025, splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore) xmeans_instance.process() closest_clusters = xmeans_instance.predict(points) assertion.eq(expected_amount, len(xmeans_instance.get_clusters())) assertion.eq(len(expected_closest_clusters), len(closest_clusters)) assertion.true(numpy.array_equal(numpy.array(expected_closest_clusters), closest_clusters)) @staticmethod def templateClusterAllocationOneDimensionData(ccore_flag): input_data = [[0.0] for _ in range(10)] + [[5.0] for _ in range(10)] + [[10.0] for _ in range(10)] + [[15.0] for _ in range(10)] xmeans_instance = xmeans(input_data, [[0.5], [5.5], [10.5], [15.5]], 20, 0.025, splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore_flag) xmeans_instance.process() clusters = xmeans_instance.get_clusters() centers = xmeans_instance.get_centers() assertion.eq(len(clusters), 4) assertion.eq(len(centers), len(clusters)) assertion.le(len(clusters), 20) for cluster in clusters: assertion.eq(len(cluster), 10) @staticmethod def templateMaxAllocatedClusters(ccore_flag, amount_clusters, size_cluster, offset, kinitial, kmax): input_data = [] for index in range(amount_clusters): for _ in range(size_cluster): input_data.append([random.random() * index * offset, random.random() * index * offset]) initial_centers = random_center_initializer(input_data, kinitial).initialize() xmeans_instance = xmeans(input_data, initial_centers, kmax, 0.025, splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore_flag) xmeans_instance.process() clusters = xmeans_instance.get_clusters() centers = xmeans_instance.get_centers() if len(clusters) != len(centers): print(input_data) print(initial_centers) assertion.ge(kmax, len(clusters)) assertion.ge(kmax, len(centers)) assertion.eq(len(clusters), len(centers)) @staticmethod def random_state(ccore_flag, kinitial, kmax, random_state): data = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) initial_centers = random_center_initializer(data, kinitial, random_state=random_state).initialize() xmeans_instance1 = xmeans(data, initial_centers, kmax, ccore=ccore_flag, random_state=random_state).process() xmeans_instance2 = xmeans(data, initial_centers, kmax, ccore=ccore_flag, random_state=random_state).process() assertion.eq(xmeans_instance1.get_total_wce(), xmeans_instance2.get_total_wce()) assertion.eq(xmeans_instance1.get_centers(), xmeans_instance2.get_centers()) assertion.eq(xmeans_instance1.get_clusters(), xmeans_instance2.get_clusters()) pyclustering-0.10.1.2/pyclustering/cluster/ttsas.py000077500000000000000000000127531375753423500224330ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: TTSAS (Two-Threshold Sequential Algorithmic Scheme). @details Implementation based on paper @cite book::pattern_recognition::2009. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.ttsas_wrapper import ttsas as ttsas_wrapper from pyclustering.core.metric_wrapper import metric_wrapper from pyclustering.cluster.bsas import bsas class ttsas(bsas): """! @brief Class represents TTSAS (Two-Threshold Sequential Algorithmic Scheme). @details Clustering results of BSAS and MBSAS are strongly dependent on the order in which the points in data. TTSAS helps to overcome this shortcoming by using two threshold parameters. The first - if the distance to the nearest cluster is less than the first threshold then point is assigned to the cluster. The second - if distance to the nearest cluster is greater than the second threshold then new cluster is allocated. Code example of TTSAS usage: @code from pyclustering.cluster.bsas import bsas_visualizer from pyclustering.cluster.ttsas import ttsas from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample # Read data sample from 'Simple03.data'. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Prepare algorithm's parameters. threshold1 = 1.0 threshold2 = 2.0 # Create instance of TTSAS algorithm. ttsas_instance = ttsas(sample, threshold1, threshold2) ttsas_instance.process() # Get clustering results. clusters = ttsas_instance.get_clusters() representatives = ttsas_instance.get_representatives() # Display results using BSAS visualizer. bsas_visualizer.show_clusters(sample, clusters, representatives) @endcode @see pyclustering.cluster.bsas, pyclustering.cluster.mbsas """ def __init__(self, data, threshold1, threshold2, ccore=True, **kwargs): """! @brief Creates TTSAS algorithm. @param[in] data (list): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] threshold1: Dissimilarity level (distance) between point and its closest cluster, if the distance is less than 'threshold1' value then point is assigned to the cluster. @param[in] threshold2: Dissimilarity level (distance) between point and its closest cluster, if the distance is greater than 'threshold2' value then point is considered as a new cluster. @param[in] ccore (bool): If True than DLL CCORE (C++ solution) will be used for solving. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric'). Keyword Args:
- metric (distance_metric): Metric that is used for distance calculation between two points. """ self._threshold2 = threshold2 self._amount_skipped_objects = len(data) self._skipped_objects = [ True ] * len(data) super().__init__(data, len(data), threshold1, ccore, **kwargs) def process(self): """! @brief Performs cluster analysis in line with rules of TTSAS algorithm. @return (ttsas) Returns itself (TTSAS instance). @see get_clusters() @see get_representatives() """ if self._ccore is True: self.__process_by_ccore() else: self.__prcess_by_python() return self def __process_by_ccore(self): ccore_metric = metric_wrapper.create_instance(self._metric) self._clusters, self._representatives = ttsas_wrapper(self._data, self._threshold, self._threshold2, ccore_metric.get_pointer()) def __prcess_by_python(self): changes = 0 while self._amount_skipped_objects != 0: previous_amount = self._amount_skipped_objects self.__process_objects(changes) changes = previous_amount - self._amount_skipped_objects def __process_objects(self, changes): index_point = self._skipped_objects.index(True) if changes == 0: self.__allocate_cluster(index_point, self._data[index_point]) index_point += 1 for i in range(index_point, len(self._data)): if self._skipped_objects[i] is True: self.__process_skipped_object(i) def __process_skipped_object(self, index_point): point = self._data[index_point] index_cluster, distance = self._find_nearest_cluster(point) if distance <= self._threshold: self.__append_to_cluster(index_cluster, index_point, point) elif distance > self._threshold2: self.__allocate_cluster(index_point, point) def __append_to_cluster(self, index_cluster, index_point, point): self._clusters[index_cluster].append(index_point) self._update_representative(index_cluster, point) self._amount_skipped_objects -= 1 self._skipped_objects[index_point] = False def __allocate_cluster(self, index_point, point): self._clusters.append( [index_point] ) self._representatives.append(point) self._amount_skipped_objects -= 1 self._skipped_objects[index_point] = False pyclustering-0.10.1.2/pyclustering/cluster/xmeans.py000077500000000000000000000671271375753423500225750ustar00rootroot00000000000000"""! @brief Cluster analysis algorithm: X-Means @details Implementation based on papers @cite article::xmeans::1, @cite article::xmeans::mndl @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import copy import numpy from enum import IntEnum from math import log from pyclustering.cluster.encoder import type_encoding from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.core.metric_wrapper import metric_wrapper from pyclustering.core.wrapper import ccore_library import pyclustering.core.xmeans_wrapper as wrapper from pyclustering.utils import distance_metric, type_metric class splitting_type(IntEnum): """! @brief Enumeration of splitting types that can be used as splitting creation of cluster in X-Means algorithm. """ ## Bayesian information criterion (BIC) to approximate the correct number of clusters. ## Kass's formula is used to calculate BIC: ## \f[BIC(\theta) = L(D) - \frac{1}{2}pln(N)\f] ## ## The number of free parameters \f$p\f$ is simply the sum of \f$K - 1\f$ class probabilities, \f$MK\f$ centroid coordinates, and one variance estimate: ## \f[p = (K - 1) + MK + 1\f] ## ## The log-likelihood of the data: ## \f[L(D) = n_jln(n_j) - n_jln(N) - \frac{n_j}{2}ln(2\pi) - \frac{n_jd}{2}ln(\hat{\sigma}^2) - \frac{n_j - K}{2}\f] ## ## The maximum likelihood estimate (MLE) for the variance: ## \f[\hat{\sigma}^2 = \frac{1}{N - K}\sum\limits_{j}\sum\limits_{i}||x_{ij} - \hat{C}_j||^2\f] BAYESIAN_INFORMATION_CRITERION = 0 ## Minimum noiseless description length (MNDL) to approximate the correct number of clusters @cite article::xmeans::mndl. ## Beheshti's formula is used to calculate upper bound: ## \f[Z = \frac{\sigma^2 \sqrt{2K} }{N}(\sqrt{2K} + \beta) + W - \sigma^2 + \frac{2\alpha\sigma}{\sqrt{N}}\sqrt{\frac{\alpha^2\sigma^2}{N} + W - \left(1 - \frac{K}{N}\right)\frac{\sigma^2}{2}} + \frac{2\alpha^2\sigma^2}{N}\f] ## ## where \f$\alpha\f$ and \f$\beta\f$ represent the parameters for validation probability and confidence probability. ## ## To improve clustering results some contradiction is introduced: ## \f[W = \frac{1}{n_j}\sum\limits_{i}||x_{ij} - \hat{C}_j||\f] ## \f[\hat{\sigma}^2 = \frac{1}{N - K}\sum\limits_{j}\sum\limits_{i}||x_{ij} - \hat{C}_j||\f] MINIMUM_NOISELESS_DESCRIPTION_LENGTH = 1 class xmeans: """! @brief Class represents clustering algorithm X-Means. @details X-means clustering method starts with the assumption of having a minimum number of clusters, and then dynamically increases them. X-means uses specified splitting criterion to control the process of splitting clusters. Method K-Means++ can be used for calculation of initial centers. CCORE implementation of the algorithm uses thread pool to parallelize the clustering process. Here example how to perform cluster analysis using X-Means algorithm: @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.xmeans import xmeans from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES # Read sample 'simple3' from file. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Prepare initial centers - amount of initial centers defines amount of clusters from which X-Means will # start analysis. amount_initial_centers = 2 initial_centers = kmeans_plusplus_initializer(sample, amount_initial_centers).initialize() # Create instance of X-Means algorithm. The algorithm will start analysis from 2 clusters, the maximum # number of clusters that can be allocated is 20. xmeans_instance = xmeans(sample, initial_centers, 20) xmeans_instance.process() # Extract clustering results: clusters and their centers clusters = xmeans_instance.get_clusters() centers = xmeans_instance.get_centers() # Print total sum of metric errors print("Total WCE:", xmeans_instance.get_total_wce()) # Visualize clustering results visualizer = cluster_visualizer() visualizer.append_clusters(clusters, sample) visualizer.append_cluster(centers, None, marker='*', markersize=10) visualizer.show() @endcode Visualization of clustering results that were obtained using code above and where X-Means algorithm allocates four clusters. @image html xmeans_clustering_simple3.png "Fig. 1. X-Means clustering results (data 'Simple3')." By default X-Means clustering algorithm uses Bayesian Information Criterion (BIC) to approximate the correct number of clusters. There is an example where another criterion Minimum Noiseless Description Length (MNDL) is used in order to find optimal amount of clusters: @code from pyclustering.cluster import cluster_visualizer from pyclustering.cluster.xmeans import xmeans, splitting_type from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES # Read sample 'Target'. sample = read_sample(FCPS_SAMPLES.SAMPLE_TARGET) # Prepare initial centers - amount of initial centers defines amount of clusters from which X-Means will start analysis. random_seed = 1000 amount_initial_centers = 3 initial_centers = kmeans_plusplus_initializer(sample, amount_initial_centers, random_state=random_seed).initialize() # Create instance of X-Means algorithm with MNDL splitting criterion. xmeans_mndl = xmeans(sample, initial_centers, 20, splitting_type=splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH, random_state=random_seed) xmeans_mndl.process() # Extract X-Means MNDL clustering results. mndl_clusters = xmeans_mndl.get_clusters() # Visualize clustering results. visualizer = cluster_visualizer(titles=['X-Means with MNDL criterion']) visualizer.append_clusters(mndl_clusters, sample) visualizer.show() @endcode @image html xmeans_clustering_mndl_target.png "Fig. 2. X-Means MNDL clustering results (data 'Target')." As in many others algorithms, it is possible to specify metric that should be used for cluster analysis, for example, Chebyshev distance metric: @code # Create instance of X-Means algorithm with Chebyshev distance metric. chebyshev_metric = distance_metric(type_metric.CHEBYSHEV) xmeans_instance = xmeans(sample, initial_centers, max_clusters_amount, metric=chebyshev_metric).process() @endcode @see center_initializer """ def __init__(self, data, initial_centers=None, kmax=20, tolerance=0.001, criterion=splitting_type.BAYESIAN_INFORMATION_CRITERION, ccore=True, **kwargs): """! @brief Constructor of clustering algorithm X-Means. @param[in] data (array_like): Input data that is presented as list of points (objects), each point should be represented by list or tuple. @param[in] initial_centers (list): Initial coordinates of centers of clusters that are represented by list: `[center1, center2, ...]`, if it is not specified then X-Means starts from the random center. @param[in] kmax (uint): Maximum number of clusters that can be allocated. @param[in] tolerance (double): Stop condition for each iteration: if maximum value of change of centers of clusters is less than tolerance than algorithm will stop processing. @param[in] criterion (splitting_type): Type of splitting creation (by default `splitting_type.BAYESIAN_INFORMATION_CRITERION`). @param[in] ccore (bool): Defines if C++ pyclustering library should be used instead of Python implementation. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: `repeat`, `random_state`, `metric`, `alpha`, `beta`). Keyword Args:
- repeat (unit): How many times K-Means should be run to improve parameters (by default is `1`). With larger `repeat` values suggesting higher probability of finding global optimum. - random_state (int): Seed for random state (by default is `None`, current system time is used). - metric (distance_metric): Metric that is used for distance calculation between two points (by default euclidean square distance). - alpha (double): Parameter distributed [0.0, 1.0] for alpha probabilistic bound \f$Q\left(\alpha\right)\f$. The parameter is used only in case of MNDL splitting criterion, in all other cases this value is ignored. - beta (double): Parameter distributed [0.0, 1.0] for beta probabilistic bound \f$Q\left(\beta\right)\f$. The parameter is used only in case of MNDL splitting criterion, in all other cases this value is ignored. """ self.__pointer_data = numpy.array(data) self.__clusters = [] self.__random_state = kwargs.get('random_state', None) self.__metric = copy.copy(kwargs.get('metric', distance_metric(type_metric.EUCLIDEAN_SQUARE))) if initial_centers is not None: self.__centers = numpy.array(initial_centers) else: self.__centers = kmeans_plusplus_initializer(data, 2, random_state=self.__random_state).initialize() self.__kmax = kmax self.__tolerance = tolerance self.__criterion = criterion self.__total_wce = 0.0 self.__repeat = kwargs.get('repeat', 1) self.__alpha = kwargs.get('alpha', 0.9) self.__beta = kwargs.get('beta', 0.9) self.__ccore = ccore and self.__metric.get_type() != type_metric.USER_DEFINED if self.__ccore is True: self.__ccore = ccore_library.workable() self.__verify_arguments() def process(self): """! @brief Performs cluster analysis in line with rules of X-Means algorithm. @return (xmeans) Returns itself (X-Means instance). @see get_clusters() @see get_centers() """ if self.__ccore is True: self.__process_by_ccore() else: self.__process_by_python() return self def __process_by_ccore(self): """! @brief Performs cluster analysis using CCORE (C/C++ part of pyclustering library). """ ccore_metric = metric_wrapper.create_instance(self.__metric) result = wrapper.xmeans(self.__pointer_data, self.__centers, self.__kmax, self.__tolerance, self.__criterion, self.__alpha, self.__beta, self.__repeat, self.__random_state, ccore_metric.get_pointer()) self.__clusters = result[0] self.__centers = result[1] self.__total_wce = result[2][0] def __process_by_python(self): """! @brief Performs cluster analysis using python code. """ self.__clusters = [] while len(self.__centers) <= self.__kmax: current_cluster_number = len(self.__centers) self.__clusters, self.__centers, _ = self.__improve_parameters(self.__centers) allocated_centers = self.__improve_structure(self.__clusters, self.__centers) if current_cluster_number == len(allocated_centers): break else: self.__centers = allocated_centers self.__clusters, self.__centers, self.__total_wce = self.__improve_parameters(self.__centers) def predict(self, points): """! @brief Calculates the closest cluster to each point. @param[in] points (array_like): Points for which closest clusters are calculated. @return (list) List of closest clusters for each point. Each cluster is denoted by index. Return empty collection if 'process()' method was not called. An example how to calculate (or predict) the closest cluster to specified points. @code from pyclustering.cluster.xmeans import xmeans from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample # Load list of points for cluster analysis. sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Initial centers for sample 'Simple3'. initial_centers = [[0.2, 0.1], [4.0, 1.0], [2.0, 2.0], [2.3, 3.9]] # Create instance of X-Means algorithm with prepared centers. xmeans_instance = xmeans(sample, initial_centers) # Run cluster analysis. xmeans_instance.process() # Calculate the closest cluster to following two points. points = [[0.25, 0.2], [2.5, 4.0]] closest_clusters = xmeans_instance.predict(points) print(closest_clusters) @endcode """ nppoints = numpy.array(points) if len(self.__clusters) == 0: return [] self.__metric.enable_numpy_usage() npcenters = numpy.array(self.__centers) differences = numpy.zeros((len(nppoints), len(npcenters))) for index_point in range(len(nppoints)): differences[index_point] = self.__metric(nppoints[index_point], npcenters) self.__metric.disable_numpy_usage() return numpy.argmin(differences, axis=1) def get_clusters(self): """! @brief Returns list of allocated clusters, each cluster contains indexes of objects in list of data. @return (list) List of allocated clusters. @see process() @see get_centers() @see get_total_wce() """ return self.__clusters def get_centers(self): """! @brief Returns list of centers for allocated clusters. @return (list) List of centers for allocated clusters. @see process() @see get_clusters() @see get_total_wce() """ return self.__centers def get_cluster_encoding(self): """! @brief Returns clustering result representation type that indicate how clusters are encoded. @return (type_encoding) Clustering result representation. @see get_clusters() """ return type_encoding.CLUSTER_INDEX_LIST_SEPARATION def get_total_wce(self): """! @brief Returns sum of Euclidean Squared metric errors (SSE - Sum of Squared Errors). @details Sum of metric errors is calculated using distance between point and its center: \f[error=\sum_{i=0}^{N}euclidean_square_distance(x_{i}-center(x_{i}))\f] @see process() @see get_clusters() """ return self.__total_wce def __search_optimial_parameters(self, local_data): """! @brief Split data of the region into two cluster and tries to find global optimum by running k-means clustering several times (defined by 'repeat' argument). @param[in] local_data (list): Points of a region that should be split into two clusters. @return (tuple) List of allocated clusters, list of centers and total WCE (clusters, centers, wce). """ optimal_wce, optimal_centers, optimal_clusters = float('+inf'), None, None for _ in range(self.__repeat): candidates = 5 if len(local_data) < candidates: candidates = len(local_data) local_centers = kmeans_plusplus_initializer(local_data, 2, candidates, random_state=self.__random_state).initialize() kmeans_instance = kmeans(local_data, local_centers, tolerance=self.__tolerance, ccore=False, metric=self.__metric) kmeans_instance.process() local_wce = kmeans_instance.get_total_wce() if local_wce < optimal_wce: optimal_centers = kmeans_instance.get_centers() optimal_clusters = kmeans_instance.get_clusters() optimal_wce = local_wce return optimal_clusters, optimal_centers, optimal_wce def __improve_parameters(self, centers, available_indexes=None): """! @brief Performs k-means clustering in the specified region. @param[in] centers (list): Cluster centers, if None then automatically generated two centers using center initialization method. @param[in] available_indexes (list): Indexes that defines which points can be used for k-means clustering, if None then all points are used. @return (tuple) List of allocated clusters, list of centers and total WCE (clusters, centers, wce). """ if available_indexes and len(available_indexes) == 1: index_center = available_indexes[0] return [available_indexes], self.__pointer_data[index_center], 0.0 local_data = self.__pointer_data if available_indexes: local_data = [self.__pointer_data[i] for i in available_indexes] local_centers = centers if centers is None: clusters, local_centers, local_wce = self.__search_optimial_parameters(local_data) else: kmeans_instance = kmeans(local_data, local_centers, tolerance=self.__tolerance, ccore=False, metric=self.__metric).process() local_wce = kmeans_instance.get_total_wce() local_centers = kmeans_instance.get_centers() clusters = kmeans_instance.get_clusters() if available_indexes: clusters = self.__local_to_global_clusters(clusters, available_indexes) return clusters, local_centers, local_wce def __local_to_global_clusters(self, local_clusters, available_indexes): """! @brief Converts clusters in local region define by 'available_indexes' to global clusters. @param[in] local_clusters (list): Local clusters in specific region. @param[in] available_indexes (list): Map between local and global point's indexes. @return Global clusters. """ clusters = [] for local_cluster in local_clusters: current_cluster = [] for index_point in local_cluster: current_cluster.append(available_indexes[index_point]) clusters.append(current_cluster) return clusters def __improve_structure(self, clusters, centers): """! @brief Check for best structure: divides each cluster into two and checks for best results using splitting criterion. @param[in] clusters (list): Clusters that have been allocated (each cluster contains indexes of points from data). @param[in] centers (list): Centers of clusters. @return (list) Allocated centers for clustering. """ allocated_centers = [] amount_free_centers = self.__kmax - len(centers) for index_cluster in range(len(clusters)): # solve k-means problem for children where data of parent are used. (parent_child_clusters, parent_child_centers, _) = self.__improve_parameters(None, clusters[index_cluster]) # If it's possible to split current data if len(parent_child_clusters) > 1: # Calculate splitting criterion parent_scores = self.__splitting_criterion([clusters[index_cluster]], [centers[index_cluster]]) child_scores = self.__splitting_criterion([parent_child_clusters[0], parent_child_clusters[1]], parent_child_centers) split_require = False # Reallocate number of centers (clusters) in line with scores if self.__criterion == splitting_type.BAYESIAN_INFORMATION_CRITERION: if parent_scores < child_scores: split_require = True elif self.__criterion == splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH: # If its score for the split structure with two children is smaller than that for the parent structure, # then representing the data samples with two clusters is more accurate in comparison to a single parent cluster. if parent_scores > child_scores: split_require = True if (split_require is True) and (amount_free_centers > 0): allocated_centers.append(parent_child_centers[0]) allocated_centers.append(parent_child_centers[1]) amount_free_centers -= 1 else: allocated_centers.append(centers[index_cluster]) else: allocated_centers.append(centers[index_cluster]) return allocated_centers def __splitting_criterion(self, clusters, centers): """! @brief Calculates splitting criterion for input clusters. @param[in] clusters (list): Clusters for which splitting criterion should be calculated. @param[in] centers (list): Centers of the clusters. @return (double) Returns splitting criterion. High value of splitting criterion means that current structure is much better. @see __bayesian_information_criterion(clusters, centers) @see __minimum_noiseless_description_length(clusters, centers) """ if self.__criterion == splitting_type.BAYESIAN_INFORMATION_CRITERION: return self.__bayesian_information_criterion(clusters, centers) elif self.__criterion == splitting_type.MINIMUM_NOISELESS_DESCRIPTION_LENGTH: return self.__minimum_noiseless_description_length(clusters, centers) else: assert 0 def __minimum_noiseless_description_length(self, clusters, centers): """! @brief Calculates splitting criterion for input clusters using minimum noiseless description length criterion. @param[in] clusters (list): Clusters for which splitting criterion should be calculated. @param[in] centers (list): Centers of the clusters. @return (double) Returns splitting criterion in line with bayesian information criterion. Low value of splitting cretion means that current structure is much better. @see __bayesian_information_criterion(clusters, centers) """ score = float('inf') W = 0.0 K = len(clusters) N = 0.0 sigma_square = 0.0 alpha = self.__alpha alpha_square = alpha * alpha beta = self.__beta for index_cluster in range(0, len(clusters), 1): Ni = len(clusters[index_cluster]) if Ni == 0: return float('inf') Wi = 0.0 for index_object in clusters[index_cluster]: Wi += self.__metric(self.__pointer_data[index_object], centers[index_cluster]) sigma_square += Wi W += Wi / Ni N += Ni if N - K > 0: sigma_square /= (N - K) sigma = sigma_square ** 0.5 Kw = (1.0 - K / N) * sigma_square Ksa = (2.0 * alpha * sigma / (N ** 0.5)) * (alpha_square * sigma_square / N + W - Kw / 2.0) ** 0.5 UQa = W - Kw + 2.0 * alpha_square * sigma_square / N + Ksa score = sigma_square * K / N + UQa + sigma_square * beta * ((2.0 * K) ** 0.5) / N return score def __bayesian_information_criterion(self, clusters, centers): """! @brief Calculates splitting criterion for input clusters using bayesian information criterion. @param[in] clusters (list): Clusters for which splitting criterion should be calculated. @param[in] centers (list): Centers of the clusters. @return (double) Splitting criterion in line with bayesian information criterion. High value of splitting criterion means that current structure is much better. @see __minimum_noiseless_description_length(clusters, centers) """ scores = [float('inf')] * len(clusters) # splitting criterion dimension = len(self.__pointer_data[0]) # estimation of the noise variance in the data set sigma_sqrt = 0.0 K = len(clusters) N = 0.0 for index_cluster in range(0, len(clusters), 1): for index_object in clusters[index_cluster]: sigma_sqrt += self.__metric(self.__pointer_data[index_object], centers[index_cluster]) N += len(clusters[index_cluster]) if N - K > 0: sigma_sqrt /= (N - K) p = (K - 1) + dimension * K + 1 # in case of the same points, sigma_sqrt can be zero (issue: #407) sigma_multiplier = 0.0 if sigma_sqrt <= 0.0: sigma_multiplier = float('-inf') else: sigma_multiplier = dimension * 0.5 * log(sigma_sqrt) # splitting criterion for index_cluster in range(0, len(clusters), 1): n = len(clusters[index_cluster]) L = n * log(n) - n * log(N) - n * 0.5 * log(2.0 * numpy.pi) - n * sigma_multiplier - (n - K) * 0.5 # BIC calculation scores[index_cluster] = L - p * 0.5 * log(N) return sum(scores) def __verify_arguments(self): """! @brief Verify input parameters for the algorithm and throw exception in case of incorrectness. """ if len(self.__pointer_data) == 0: raise ValueError("Input data is empty (size: '%d')." % len(self.__pointer_data)) if len(self.__centers) == 0: raise ValueError("Initial centers are empty (size: '%d')." % len(self.__pointer_data)) if self.__tolerance < 0: raise ValueError("Tolerance (current value: '%d') should be greater or equal to 0." % self.__tolerance) if self.__repeat <= 0: raise ValueError("Repeat (current value: '%d') should be greater than 0." % self.__repeat) if self.__alpha < 0.0 or self.__alpha > 1.0: raise ValueError("Parameter for the probabilistic bound Q(alpha) should in the following range [0, 1] " "(current value: '%f')." % self.__alpha) if self.__beta < 0.0 or self.__beta > 1.0: raise ValueError("Parameter for the probabilistic bound Q(beta) should in the following range [0, 1] " "(current value: '%f')." % self.__beta) pyclustering-0.10.1.2/pyclustering/container/000077500000000000000000000000001375753423500212115ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/container/__init__.py000077500000000000000000000002501375753423500233220ustar00rootroot00000000000000"""! @brief pyclustering module of data structures (containers). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/pyclustering/container/cftree.py000077500000000000000000001141671375753423500230500ustar00rootroot00000000000000"""! @brief Data Structure: CF-Tree @details Implementation based on paper @cite article::birch::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from copy import copy from pyclustering.utils import euclidean_distance_square from pyclustering.utils import manhattan_distance from pyclustering.utils import linear_sum, square_sum from enum import IntEnum class measurement_type(IntEnum): """! @brief Enumeration of measurement types for CF-Tree. @see cftree """ ## Euclidian distance between centroids of clustering features. CENTROID_EUCLIDEAN_DISTANCE = 0 ## Manhattan distance between centroids of clustering features. CENTROID_MANHATTAN_DISTANCE = 1 ## Average distance between all objects from clustering features. AVERAGE_INTER_CLUSTER_DISTANCE = 2 ## Average distance between all objects within clustering features and between them. AVERAGE_INTRA_CLUSTER_DISTANCE = 3 ## Variance based distance between clustering features. VARIANCE_INCREASE_DISTANCE = 4 class cfnode_type(IntEnum): """! @brief Enumeration of CF-Node types that are used by CF-Tree. @see cfnode @see cftree """ ## Undefined node. CFNODE_DUMMY = 0 ## Leaf node hasn't got successors, only entries. CFNODE_LEAF = 1 ## Non-leaf node has got successors and hasn't got entries. CFNODE_NONLEAF = 2 class cfentry: """! @brief Clustering feature representation. @see cfnode @see cftree """ @property def number_points(self): """! @brief Returns number of points that are encoded. @return (uint) Number of encoded points. """ return self.__number_points @property def linear_sum(self): """! @brief Returns linear sum. @return (list) Linear sum. """ return self.__linear_sum @property def square_sum(self): """! @brief Returns square sum. @return (double) Square sum. """ return self.__square_sum def __init__(self, number_points, linear_sum, square_sum): """! @brief CF-entry constructor. @param[in] number_points (uint): Number of objects that is represented by the entry. @param[in] linear_sum (list): Linear sum of values that represent objects in each dimension. @param[in] square_sum (double): Square sum of values that represent objects. """ self.__number_points = number_points self.__linear_sum = numpy.array(linear_sum) self.__square_sum = square_sum self.__centroid = None self.__radius = None self.__diameter = None def __copy__(self): """! @returns (cfentry) Makes copy of the CF-entry instance. """ return cfentry(self.__number_points, self.__linear_sum, self.__square_sum) def __repr__(self): """! @return (string) Returns CF-entry representation. """ return "CF-Entry (N: '%s', LS: '%s', D: '%s')" % \ (self.number_points, self.linear_sum, str(self.get_diameter())) def __str__(self): """! @brief Default cfentry string representation. """ return self.__repr__() def __add__(self, entry): """! @brief Overloaded operator add. Performs addition of two clustering features. @param[in] entry (cfentry): Entry that is added to the current. @return (cfentry) Result of addition of two clustering features. """ number_points = self.number_points + entry.number_points result_linear_sum = numpy.add(self.linear_sum, entry.linear_sum) result_square_sum = self.square_sum + entry.square_sum return cfentry(number_points, result_linear_sum, result_square_sum) def __eq__(self, entry): """! @brief Overloaded operator eq. @details Performs comparison of two clustering features. @param[in] entry (cfentry): Entry that is used for comparison with current. @return (bool) True is both clustering features are equals in line with tolerance, otherwise False. """ tolerance = 0.00001 result = (self.__number_points == entry.number_points) result &= ((self.square_sum + tolerance > entry.square_sum) and (self.square_sum - tolerance < entry.square_sum)) for index_dimension in range(0, len(self.linear_sum)): result &= ((self.linear_sum[index_dimension] + tolerance > entry.linear_sum[index_dimension]) and (self.linear_sum[index_dimension] - tolerance < entry.linear_sum[index_dimension])) return result def get_distance(self, entry, type_measurement): """! @brief Calculates distance between two clusters in line with measurement type. @details In case of usage CENTROID_EUCLIDIAN_DISTANCE square euclidian distance will be returned. Square root should be taken from the result for obtaining real euclidian distance between entries. @param[in] entry (cfentry): Clustering feature to which distance should be obtained. @param[in] type_measurement (measurement_type): Distance measurement algorithm between two clusters. @return (double) Distance between two clusters. """ if type_measurement is measurement_type.CENTROID_EUCLIDEAN_DISTANCE: return euclidean_distance_square(entry.get_centroid(), self.get_centroid()) elif type_measurement is measurement_type.CENTROID_MANHATTAN_DISTANCE: return manhattan_distance(entry.get_centroid(), self.get_centroid()) elif type_measurement is measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE: return self.__get_average_inter_cluster_distance(entry) elif type_measurement is measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE: return self.__get_average_intra_cluster_distance(entry) elif type_measurement is measurement_type.VARIANCE_INCREASE_DISTANCE: return self.__get_variance_increase_distance(entry) else: raise ValueError("Unsupported type of measurement '%s' is specified." % type_measurement) def get_centroid(self): """! @brief Calculates centroid of cluster that is represented by the entry. @details It's calculated once when it's requested after the last changes. @return (array_like) Centroid of cluster that is represented by the entry. """ if self.__centroid is not None: return self.__centroid self.__centroid = numpy.divide(self.linear_sum, self.number_points) return self.__centroid def get_radius(self): """! @brief Calculates radius of cluster that is represented by the entry. @details It's calculated once when it's requested after the last changes. @return (double) Radius of cluster that is represented by the entry. """ if self.__radius is not None: return self.__radius N = self.number_points centroid = self.get_centroid() radius_part_1 = self.square_sum radius_part_2 = 2.0 * numpy.dot(self.linear_sum, centroid) radius_part_3 = N * numpy.dot(centroid, centroid) self.__radius = ((1.0 / N) * (radius_part_1 - radius_part_2 + radius_part_3)) ** 0.5 return self.__radius def get_diameter(self): """! @brief Calculates diameter of cluster that is represented by the entry. @details It's calculated once when it's requested after the last changes. @return (double) Diameter of cluster that is represented by the entry. """ if self.__diameter is not None: return self.__diameter diameter_part = self.square_sum * self.number_points - 2.0 * numpy.dot(self.linear_sum, self.linear_sum) + self.square_sum * self.number_points if diameter_part < 0.000000001: self.__diameter = 0.0 else: self.__diameter = (diameter_part / (self.number_points * (self.number_points - 1))) ** 0.5 return self.__diameter def __get_average_inter_cluster_distance(self, entry): """! @brief Calculates average inter cluster distance between current and specified clusters. @param[in] entry (cfentry): Clustering feature to which distance should be obtained. @return (double) Average inter cluster distance. """ linear_part_distance = numpy.dot(self.linear_sum, entry.linear_sum) return ((entry.number_points * self.square_sum - 2.0 * linear_part_distance + self.number_points * entry.square_sum) / (self.number_points * entry.number_points)) ** 0.5 def __get_average_intra_cluster_distance(self, entry): """! @brief Calculates average intra cluster distance between current and specified clusters. @param[in] entry (cfentry): Clustering feature to which distance should be obtained. @return (double) Average intra cluster distance. """ linear_part_first = numpy.add(self.linear_sum, entry.linear_sum) linear_part_second = linear_part_first linear_part_distance = numpy.dot(linear_part_first, linear_part_second) general_part_distance = 2.0 * (self.number_points + entry.number_points) * (self.square_sum + entry.square_sum) - 2.0 * linear_part_distance return (general_part_distance / ((self.number_points + entry.number_points) * (self.number_points + entry.number_points - 1.0))) ** 0.5 def __get_variance_increase_distance(self, entry): """! @brief Calculates variance increase distance between current and specified clusters. @param[in] entry (cfentry): Clustering feature to which distance should be obtained. @return (double) Variance increase distance. """ linear_part_12 = numpy.add(self.linear_sum, entry.linear_sum) variance_part_first = (self.square_sum + entry.square_sum) - \ 2.0 * numpy.dot(linear_part_12, linear_part_12) / (self.number_points + entry.number_points) + \ (self.number_points + entry.number_points) * numpy.dot(linear_part_12, linear_part_12) / (self.number_points + entry.number_points)**2.0 linear_part_11 = numpy.dot(self.linear_sum, self.linear_sum) variance_part_second = -(self.square_sum - (2.0 * linear_part_11 / self.number_points) + (linear_part_11 / self.number_points)) linear_part_22 = numpy.dot(entry.linear_sum, entry.linear_sum) variance_part_third = -(entry.square_sum - (2.0 / entry.number_points) * linear_part_22 + entry.number_points * (1.0 / entry.number_points ** 2.0) * linear_part_22) return variance_part_first + variance_part_second + variance_part_third class cfnode: """! @brief Representation of node of CF-Tree. """ def __init__(self, feature, parent): """! @brief Constructor of abstract CF node. @param[in] feature (cfentry): Clustering feature of the created node. @param[in] parent (cfnode): Parent of the created node. """ ## Clustering feature of the node. self.feature = copy(feature) ## Pointer to the parent node (None for root). self.parent = parent ## Type node (leaf or non-leaf). self.type = cfnode_type.CFNODE_DUMMY def __repr__(self): """! @return (string) Default representation of CF node. """ return 'CF node %s, parent %s, feature %s' % (hex(id(self)), self.parent, self.feature) def __str__(self): """! @return (string) String representation of CF node. """ return self.__repr__() def get_distance(self, node, type_measurement): """! @brief Calculates distance between nodes in line with specified type measurement. @param[in] node (cfnode): CF-node that is used for calculation distance to the current node. @param[in] type_measurement (measurement_type): Measurement type that is used for calculation distance. @return (double) Distance between two nodes. """ return self.feature.get_distance(node.feature, type_measurement) class non_leaf_node(cfnode): """! @brief Representation of clustering feature non-leaf node. """ @property def successors(self): """! @return (list) List of successors of the node. """ return self.__successors def __init__(self, feature, parent, successors): """! @brief Create CF Non-leaf node. @param[in] feature (cfentry): Clustering feature of the created node. @param[in] parent (non_leaf_node): Parent of the created node. @param[in] successors (list): List of successors of the node. """ super().__init__(feature, parent) ## Node type in CF tree that is CFNODE_NONLEAF for non leaf node. self.type = cfnode_type.CFNODE_NONLEAF self.__successors = successors def __repr__(self): """! @return (string) Representation of non-leaf node representation. """ return 'Non-leaf node %s, parent %s, feature %s, successors: %d' % (hex(id(self)), self.parent, self.feature, len(self.successors)) def __str__(self): """! @return (string) String non-leaf representation. """ return self.__repr__() def insert_successor(self, successor): """! @brief Insert successor to the node. @param[in] successor (cfnode): Successor for adding. """ self.feature += successor.feature self.successors.append(successor) successor.parent = self def merge(self, node): """! @brief Merge non-leaf node to the current. @param[in] node (non_leaf_node): Non-leaf node that should be merged with current. """ self.feature += node.feature for child in node.successors: child.parent = self self.successors.append(child) def get_farthest_successors(self, type_measurement): """! @brief Find pair of farthest successors of the node in line with measurement type. @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining farthest successors. @return (list) Pair of farthest successors represented by list [cfnode1, cfnode2]. """ farthest_node1 = None farthest_node2 = None farthest_distance = 0.0 for i in range(0, len(self.successors)): candidate1 = self.successors[i] for j in range(i + 1, len(self.successors)): candidate2 = self.successors[j] candidate_distance = candidate1.get_distance(candidate2, type_measurement) if candidate_distance > farthest_distance: farthest_distance = candidate_distance farthest_node1 = candidate1 farthest_node2 = candidate2 return [farthest_node1, farthest_node2] def get_nearest_successors(self, type_measurement): """! @brief Find pair of nearest successors of the node in line with measurement type. @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest successors. @return (list) Pair of nearest successors represented by list. """ nearest_node1 = None nearest_node2 = None nearest_distance = float("Inf") for i in range(0, len(self.successors)): candidate1 = self.successors[i] for j in range(i + 1, len(self.successors)): candidate2 = self.successors[j] candidate_distance = candidate1.get_distance(candidate2, type_measurement) if candidate_distance < nearest_distance: nearest_distance = candidate_distance nearest_node1 = candidate1 nearest_node2 = candidate2 return [nearest_node1, nearest_node2] class leaf_node(cfnode): """! @brief Represents clustering feature leaf node. """ @property def entries(self): """! @return (list) List of leaf nodes. """ return self.__entries def __init__(self, feature, parent, entries): """! @brief Create CF Leaf node. @param[in] feature (cfentry): Clustering feature of the created node. @param[in] parent (non_leaf_node): Parent of the created node. @param[in] entries (list): List of entries of the node. """ super().__init__(feature, parent) ## Node type in CF tree that is CFNODE_LEAF for leaf node. self.type = cfnode_type.CFNODE_LEAF self.__entries = entries # list of clustering features def __repr__(self): """! @return (string) Default leaf node represenation. """ text_entries = "\n" for entry in self.entries: text_entries += "\t" + str(entry) + "\n" return "Leaf-node: '%s', parent: '%s', feature: '%s', entries: '%d'" % \ (str(hex(id(self))), self.parent, self.feature, len(self.entries)) def __str__(self): """! @return (string) String leaf node representation. """ return self.__repr__() def insert_entry(self, entry): """! @brief Insert new clustering feature to the leaf node. @param[in] entry (cfentry): Clustering feature. """ self.feature += entry self.entries.append(entry) def merge(self, node): """! @brief Merge leaf node to the current. @param[in] node (leaf_node): Leaf node that should be merged with current. """ self.feature += node.feature # Move entries from merged node for entry in node.entries: self.entries.append(entry) def get_farthest_entries(self, type_measurement): """! @brief Find pair of farthest entries of the node. @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining farthest entries. @return (list) Pair of farthest entries of the node that are represented by list. """ farthest_entity1 = None farthest_entity2 = None farthest_distance = 0 for i in range(0, len(self.entries)): candidate1 = self.entries[i] for j in range(i + 1, len(self.entries)): candidate2 = self.entries[j] candidate_distance = candidate1.get_distance(candidate2, type_measurement) if candidate_distance > farthest_distance: farthest_distance = candidate_distance farthest_entity1 = candidate1 farthest_entity2 = candidate2 return [farthest_entity1, farthest_entity2] def get_nearest_index_entry(self, entry, type_measurement): """! @brief Find nearest index of nearest entry of node for the specified entry. @param[in] entry (cfentry): Entry that is used for calculation distance. @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest entry to the specified. @return (uint) Index of nearest entry of node for the specified entry. """ minimum_distance = float('Inf') nearest_index = -1 for candidate_index in range(0, len(self.entries)): candidate_distance = self.entries[candidate_index].get_distance(entry, type_measurement) if candidate_distance < minimum_distance: minimum_distance = candidate_distance nearest_index = candidate_index return nearest_index def get_nearest_entry(self, entry, type_measurement): """! @brief Find nearest entry of node for the specified entry. @param[in] entry (cfentry): Entry that is used for calculation distance. @param[in] type_measurement (measurement_type): Measurement type that is used for obtaining nearest entry to the specified. @return (cfentry) Nearest entry of node for the specified entry. """ min_key = lambda cur_entity: cur_entity.get_distance(entry, type_measurement) return min(self.entries, key=min_key) class cftree: """! @brief CF-Tree representation. @details A CF-tree is a height-balanced tree with two parameters: branching factor and threshold. """ @property def root(self): """! @return (cfnode) Root of the tree. """ return self.__root @property def leafes(self): """! @return (list) List of all leaf nodes in the tree. """ return self.__leafes @property def amount_nodes(self): """! @return (unit) Number of nodes (leaf and non-leaf) in the tree. """ return self.__amount_nodes @property def amount_entries(self): """! @return (uint) Number of entries in the tree. """ return self.__amount_entries @property def height(self): """! @return (uint) Height of the tree. """ return self.__height @property def branch_factor(self): """! @return (uint) Branching factor of the tree. @details Branching factor defines maximum number of successors in each non-leaf node. """ return self.__branch_factor @property def threshold(self): """! @return (double) Threshold of the tree that represents maximum diameter of sub-clusters that is formed by leaf node entries. """ return self.__threshold @property def max_entries(self): """! @return (uint) Maximum number of entries in each leaf node. """ return self.__max_entries @property def type_measurement(self): """! @return (measurement_type) Type that is used for measuring. """ return self.__type_measurement def __init__(self, branch_factor, max_entries, threshold, type_measurement = measurement_type.CENTROID_EUCLIDEAN_DISTANCE): """! @brief Create CF-tree. @param[in] branch_factor (uint): Maximum number of children for non-leaf nodes. @param[in] max_entries (uint): Maximum number of entries for leaf nodes. @param[in] threshold (double): Maximum diameter of feature clustering for each leaf node. @param[in] type_measurement (measurement_type): Measurement type that is used for calculation distance metrics. """ self.__root = None self.__branch_factor = branch_factor # maximum number of children if self.__branch_factor < 2: self.__branch_factor = 2 self.__threshold = threshold # maximum diameter of sub-clusters stored at the leaf nodes self.__max_entries = max_entries self.__leafes = [] self.__type_measurement = type_measurement # statistics self.__amount_nodes = 0 # root, despite it can be None. self.__amount_entries = 0 self.__height = 0 # tree size with root. def get_level_nodes(self, level): """! @brief Traverses CF-tree to obtain nodes at the specified level. @param[in] level (uint): CF-tree level from that nodes should be returned. @return (list) List of CF-nodes that are located on the specified level of the CF-tree. """ level_nodes = [] if level < self.__height: level_nodes = self.__recursive_get_level_nodes(level, self.__root) return level_nodes def __recursive_get_level_nodes(self, level, node): """! @brief Traverses CF-tree to obtain nodes at the specified level recursively. @param[in] level (uint): Current CF-tree level. @param[in] node (cfnode): CF-node from that traversing is performed. @return (list) List of CF-nodes that are located on the specified level of the CF-tree. """ level_nodes = [] if level == 0: level_nodes.append(node) else: for sucessor in node.successors: level_nodes += self.__recursive_get_level_nodes(level - 1, sucessor) return level_nodes def insert_point(self, point): """! @brief Insert point that is represented by list of coordinates. @param[in] point (list): Point represented by list of coordinates that should be inserted to CF tree. """ entry = cfentry(len([point]), linear_sum([point]), square_sum([point])) self.insert(entry) def insert(self, entry): """! @brief Insert clustering feature to the tree. @param[in] entry (cfentry): Clustering feature that should be inserted. """ if self.__root is None: node = leaf_node(entry, None, [entry]) self.__root = node self.__leafes.append(node) # Update statistics self.__amount_entries += 1 self.__amount_nodes += 1 self.__height += 1 # root has successor now else: child_node_updation = self.__recursive_insert(entry, self.__root) if child_node_updation is True: # Splitting has been finished, check for possibility to merge (at least we have already two children). if self.__merge_nearest_successors(self.__root) is True: self.__amount_nodes -= 1 def find_nearest_leaf(self, entry, search_node = None): """! @brief Search nearest leaf to the specified clustering feature. @param[in] entry (cfentry): Clustering feature. @param[in] search_node (cfnode): Node from that searching should be started, if None then search process will be started for the root. @return (leaf_node) Nearest node to the specified clustering feature. """ if search_node is None: search_node = self.__root nearest_node = search_node if search_node.type == cfnode_type.CFNODE_NONLEAF: min_key = lambda child_node: child_node.feature.get_distance(entry, self.__type_measurement) nearest_child_node = min(search_node.successors, key = min_key) nearest_node = self.find_nearest_leaf(entry, nearest_child_node) return nearest_node def __recursive_insert(self, entry, search_node): """! @brief Recursive insert of the entry to the tree. @details It performs all required procedures during insertion such as splitting, merging. @param[in] entry (cfentry): Clustering feature. @param[in] search_node (cfnode): Node from that insertion should be started. @return (bool) True if number of nodes at the below level is changed, otherwise False. """ # None-leaf node if search_node.type == cfnode_type.CFNODE_NONLEAF: return self.__insert_for_noneleaf_node(entry, search_node) # Leaf is reached else: return self.__insert_for_leaf_node(entry, search_node) def __insert_for_leaf_node(self, entry, search_node): """! @brief Recursive insert entry from leaf node to the tree. @param[in] entry (cfentry): Clustering feature. @param[in] search_node (cfnode): None-leaf node from that insertion should be started. @return (bool) True if number of nodes at the below level is changed, otherwise False. """ node_amount_updation = False # Try to absorb by the entity index_nearest_entry = search_node.get_nearest_index_entry(entry, self.__type_measurement) nearest_entry = search_node.entries[index_nearest_entry] # get nearest entry merged_entry = nearest_entry + entry # Otherwise try to add new entry if merged_entry.get_diameter() > self.__threshold: # If it's not exceeded append entity and update feature of the leaf node. search_node.insert_entry(entry) # Otherwise current node should be splitted if len(search_node.entries) > self.__max_entries: self.__split_procedure(search_node) node_amount_updation = True # Update statistics self.__amount_entries += 1 else: search_node.entries[index_nearest_entry] = merged_entry search_node.feature += entry return node_amount_updation def __insert_for_noneleaf_node(self, entry, search_node): """! @brief Recursive insert entry from none-leaf node to the tree. @param[in] entry (cfentry): Clustering feature. @param[in] search_node (cfnode): None-leaf node from that insertion should be started. @return (bool) True if number of nodes at the below level is changed, otherwise False. """ node_amount_updation = False min_key = lambda child_node: child_node.get_distance(search_node, self.__type_measurement) nearest_child_node = min(search_node.successors, key=min_key) child_node_updation = self.__recursive_insert(entry, nearest_child_node) # Update clustering feature of none-leaf node. search_node.feature += entry # Check branch factor, probably some leaf has been splitted and threshold has been exceeded. if (len(search_node.successors) > self.__branch_factor): # Check if it's aleady root then new root should be created (height is increased in this case). if search_node is self.__root: self.__root = non_leaf_node(search_node.feature, None, [search_node]) search_node.parent = self.__root # Update statistics self.__amount_nodes += 1 self.__height += 1 [new_node1, new_node2] = self.__split_nonleaf_node(search_node) # Update parent list of successors parent = search_node.parent parent.successors.remove(search_node) parent.successors.append(new_node1) parent.successors.append(new_node2) # Update statistics self.__amount_nodes += 1 node_amount_updation = True elif child_node_updation is True: # Splitting has been finished, check for possibility to merge (at least we have already two children). if self.__merge_nearest_successors(search_node) is True: self.__amount_nodes -= 1 return node_amount_updation def __merge_nearest_successors(self, node): """! @brief Find nearest sucessors and merge them. @param[in] node (non_leaf_node): Node whose two nearest successors should be merged. @return (bool): True if merging has been successfully performed, otherwise False. """ merging_result = False if node.successors[0].type == cfnode_type.CFNODE_NONLEAF: [nearest_child_node1, nearest_child_node2] = node.get_nearest_successors(self.__type_measurement) if len(nearest_child_node1.successors) + len(nearest_child_node2.successors) <= self.__branch_factor: node.successors.remove(nearest_child_node2) if nearest_child_node2.type == cfnode_type.CFNODE_LEAF: self.__leafes.remove(nearest_child_node2) nearest_child_node1.merge(nearest_child_node2) merging_result = True return merging_result def __split_procedure(self, split_node): """! @brief Starts node splitting procedure in the CF-tree from the specify node. @param[in] split_node (cfnode): CF-tree node that should be splitted. """ if split_node is self.__root: self.__root = non_leaf_node(split_node.feature, None, [ split_node ]) split_node.parent = self.__root # Update statistics self.__amount_nodes += 1 self.__height += 1 [new_node1, new_node2] = self.__split_leaf_node(split_node) self.__leafes.remove(split_node) self.__leafes.append(new_node1) self.__leafes.append(new_node2) # Update parent list of successors parent = split_node.parent parent.successors.remove(split_node) parent.successors.append(new_node1) parent.successors.append(new_node2) # Update statistics self.__amount_nodes += 1 def __split_nonleaf_node(self, node): """! @brief Performs splitting of the specified non-leaf node. @param[in] node (non_leaf_node): Non-leaf node that should be splitted. @return (list) New pair of non-leaf nodes [non_leaf_node1, non_leaf_node2]. """ [farthest_node1, farthest_node2] = node.get_farthest_successors(self.__type_measurement) # create new non-leaf nodes new_node1 = non_leaf_node(farthest_node1.feature, node.parent, [farthest_node1]) new_node2 = non_leaf_node(farthest_node2.feature, node.parent, [farthest_node2]) farthest_node1.parent = new_node1 farthest_node2.parent = new_node2 # re-insert other successors for successor in node.successors: if (successor is not farthest_node1) and (successor is not farthest_node2): distance1 = new_node1.get_distance(successor, self.__type_measurement) distance2 = new_node2.get_distance(successor, self.__type_measurement) if distance1 < distance2: new_node1.insert_successor(successor) else: new_node2.insert_successor(successor) return [new_node1, new_node2] def __split_leaf_node(self, node): """! @brief Performs splitting of the specified leaf node. @param[in] node (leaf_node): Leaf node that should be splitted. @return (list) New pair of leaf nodes [leaf_node1, leaf_node2]. @warning Splitted node is transformed to non_leaf. """ # search farthest pair of entries [farthest_entity1, farthest_entity2] = node.get_farthest_entries(self.__type_measurement) # create new nodes new_node1 = leaf_node(farthest_entity1, node.parent, [farthest_entity1]) new_node2 = leaf_node(farthest_entity2, node.parent, [farthest_entity2]) # re-insert other entries for entity in node.entries: if (entity is not farthest_entity1) and (entity is not farthest_entity2): distance1 = new_node1.feature.get_distance(entity, self.__type_measurement) distance2 = new_node2.feature.get_distance(entity, self.__type_measurement) if distance1 < distance2: new_node1.insert_entry(entity) else: new_node2.insert_entry(entity) return [new_node1, new_node2] pyclustering-0.10.1.2/pyclustering/container/examples/000077500000000000000000000000001375753423500230275ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/container/examples/__init__.py000077500000000000000000000002411375753423500251400ustar00rootroot00000000000000"""! @brief Collection of examples devoted to containers. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/pyclustering/container/examples/kdtree_examples.py000077500000000000000000000024321375753423500265610ustar00rootroot00000000000000"""! @brief Examples devoted to KD-tree. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.container.kdtree import kdtree, kdtree_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES def template_build_visualize(sample_path): print("KD Tree for sample: '" + sample_path + "'") sample = read_sample(sample_path) tree_instance = kdtree(sample) kdtree_visualizer(tree_instance).visualize() def kdtree_sample_simple01(): template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def kdtree_sample_simple02(): template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def kdtree_sample_simple03(): template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def kdtree_sample_simple04(): template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def kdtree_sample_simple05(): template_build_visualize(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def kdtree_fcps_two_diamonds(): template_build_visualize(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) kdtree_sample_simple01() kdtree_sample_simple02() kdtree_sample_simple03() kdtree_sample_simple04() kdtree_sample_simple05() kdtree_fcps_two_diamonds() pyclustering-0.10.1.2/pyclustering/container/kdtree.py000077500000000000000000000664451375753423500230630ustar00rootroot00000000000000"""! @brief Data Structure: KD-Tree @details Implementation based on paper @cite book::the_design_and_analysis. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import matplotlib.pyplot as plt from pyclustering.utils import euclidean_distance_square, find_left_element class kdtree_visualizer: """! @brief KD-tree visualizer that provides service to display graphical representation of the tree using `matplotlib` library. @details The visualizer is able to visualize 2D KD-trees only. There is an example how to visualize balanced KD-tree for `TwoDiamonds` sample using `kdtree_visualizer`: @code from pyclustering.container.kdtree import kdtree_balanced, kdtree_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) tree_instance = kdtree_balanced(sample) kdtree_visualizer(tree_instance).visualize() @endcode Output result of the example above (balanced tree) - figure 1: @image html kd_tree_unbalanced_two_diamonds.png "Fig. 1. Balanced KD-tree for sample 'TwoDiamonds'." There is one more example to demonstrate unbalanced KD-tree. `kdtree` class is child class of `kdtree_balanced` that allows to add points step by step and thus an unbalanced KD-tree can be built. @code from pyclustering.container.kdtree import kdtree, kdtree_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) tree_instance = kdtree() # Do not use sample in constructor to avoid building of balanced tree. # Fill KD-tree step by step to obtain unbalanced tree. for point in sample: tree_instance.insert(point) kdtree_visualizer(tree_instance).visualize() @endcode Output result of the example above (unbalanced tree) - figure 2: @image html kd_tree_unbalanced_two_diamonds.png "Fig. 2. Unbalanced KD-tree for sample 'TwoDiamonds'." """ def __init__(self, kdtree_instance): """! @brief Initialize KD-tree visualizer. @param[in] kdtree_instance (kdtree): Instance of a KD-tree that should be visualized. """ self.__tree = kdtree_instance self.__colors = ['blue', 'red', 'green'] self.__verify() def visualize(self): """! @brief Visualize KD-tree using plot in 2-dimensional data-space. """ node = self.__tree.get_root() min, max = self.__get_limits() figure = plt.figure(111) ax = figure.add_subplot(111) self.__draw_node(ax, node, min, max) ax.set_xlim(min[0], max[0]) ax.set_ylim(min[1], max[1]) plt.show() def __draw_node(self, ax, node, min, max): self.__draw_split_line(ax, node, min, max) if node.left is not None: rborder = max[:] rborder[node.disc] = node.data[node.disc] self.__draw_node(ax, node.left, min, rborder) if node.right is not None: lborder = min[:] lborder[node.disc] = node.data[node.disc] self.__draw_node(ax, node.right, lborder, max) def __draw_split_line(self, ax, node, min, max): max_coord = max[:] min_coord = min[:] dimension = len(min) for d in range(dimension): if d == node.disc: max_coord[d] = node.data[d] min_coord[d] = node.data[d] if dimension == 2: ax.plot(node.data[0], node.data[1], color='black', marker='.', markersize=6) ax.plot([min_coord[0], max_coord[0]], [min_coord[1], max_coord[1]], color=self.__colors[node.disc], linestyle='-', linewidth=1) def __get_limits(self): dimension = len(self.__tree.get_root().data) nodes = self.__get_all_nodes() max, min = [float('-inf')] * dimension, [float('+inf')] * dimension for node in nodes: for d in range(dimension): if max[d] < node.data[d]: max[d] = node.data[d] if min[d] > node.data[d]: min[d] = node.data[d] return min, max def __get_all_nodes(self): nodes = [] next_level = [self.__tree.get_root()] while len(next_level) != 0: cur_level = next_level nodes += next_level next_level = [] for cur_node in cur_level: children = cur_node.get_children() if children is not None: next_level += children return nodes def __verify(self): root = self.__tree.get_root() if root is None: raise ValueError("KD-Tree is empty - nothing to visualize.") dimension = len(root.data) if dimension != 2: raise NotImplementedError("KD-Tree data has '%d' dimension - only KD-tree with 2D data can be visualized." % dimension) class node: """! @brief Represents a node in a KD-Tree. @details The KD-Tree node contains point's coordinates, discriminator, payload and pointers to parent and children. @see kdtree_balanced @see kdtree """ def __init__(self, data=None, payload=None, left=None, right=None, disc=None, parent=None): """! @brief Creates KD-tree node. @param[in] data (list): Data point that is presented as list of coordinates. @param[in] payload (any): Payload of node (pointer to essence that is attached to this node). @param[in] left (node): Node of KD-Tree that represents left successor. @param[in] right (node): Node of KD-Tree that represents right successor. @param[in] disc (uint): Index of dimension of that node. @param[in] parent (node): Node of KD-Tree that represents parent. """ ## Data point that is presented as list of coordinates. self.data = data ## Payload of node that can be used by user for storing specific information in the node. self.payload = payload ## Left node successor of the node. self.left = left ## Right node successor of the node. self.right = right ## Index of dimension. self.disc = disc ## Parent node of the node. self.parent = parent def __repr__(self): """! @return (string) Default representation of the node. """ left = None right = None if self.left is not None: left = self.left.data if self.right is not None: right = self.right.data return "(%s: [L:'%s', R:'%s'])" % (self.data, left, right) def __str__(self): """! @return (string) String representation of the node. """ return self.__repr__() def get_children(self): """! @brief Returns list of not `None` children of the node. @return (list) list of not `None` children of the node; if the node does not have children then `None` is returned. """ if self.left is not None: yield self.left if self.right is not None: yield self.right class kdtree_balanced: """! @brief Represents balanced static KD-tree that does not provide services to add and remove nodes after initialization. @details In the term KD tree, k denotes the dimensionality of the space being represented. Each data point is represented as a node in the k-d tree in the form of a record of type node. There is an example how to create KD-tree: @code from pyclustering.container.kdtree import kdtree_balanced, kdtree_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) tree_instance = kdtree_balanced(sample) kdtree_visualizer(tree_instance).visualize() @endcode Output result of the example above - figure 1. @image html kd_tree_balanced_lsun.png "Fig. 1. Balanced KD-tree for sample 'Lsun'." @see kdtree """ def __init__(self, points, payloads=None): """! @brief Initializes balanced static KD-tree. @param[in] points (array_like): Points that should be used to build KD-tree. @param[in] payloads (array_like): Payload of each point in `points`. """ if points is None: self._length = 0 self._dimension = 0 self._point_comparator = None self._root = None return self._dimension = len(points[0]) self._point_comparator = self._create_point_comparator(type(points[0])) self._length = 0 nodes = [] for i in range(len(points)): payload = None if payloads is not None: payload = payloads[i] nodes.append(node(points[i], payload, None, None, -1, None)) self._root = self.__create_tree(nodes, None, 0) def __len__(self): """! @brief Returns amount of nodes in the KD-tree. @return (uint) Amount of nodes in the KD-tree. """ return self._length def get_root(self): """! @brief Returns root of the tree. @return (node) The root of the tree. """ return self._root def __create_tree(self, nodes, parent, depth): """! @brief Creates balanced sub-tree using elements from list `nodes`. @param[in] nodes (list): List of KD-tree nodes. @param[in] parent (node): Parent node that is used as a root to build the sub-tree. @param[in] depth (uint): Depth of the tree that where children of the `parent` should be placed. @return (node) Returns a node that is a root of the built sub-tree. """ if len(nodes) == 0: return None discriminator = depth % self._dimension nodes.sort(key=lambda n: n.data[discriminator]) median = len(nodes) // 2 # Elements could be the same around the median, but all elements that are >= to the current should # be at the right side. # TODO: optimize by binary search - no need to use O(n) median = find_left_element(nodes, median, lambda n1, n2: n1.data[discriminator] < n2.data[discriminator]) # while median - 1 >= 0 and \ # nodes[median].data[discriminator] == nodes[median - 1].data[discriminator]: # median -= 1 new_node = nodes[median] new_node.disc = discriminator new_node.parent = parent new_node.left = self.__create_tree(nodes[:median], new_node, depth + 1) new_node.right = self.__create_tree(nodes[median + 1:], new_node, depth + 1) self._length += 1 return new_node def _create_point_comparator(self, type_point): """! @brief Create point comparator. @details In case of numpy.array specific comparator is required. @param[in] type_point (data_type): Type of point that is stored in KD-node. @return (callable) Callable point comparator to compare to points. """ if type_point == numpy.ndarray: return lambda obj1, obj2: numpy.array_equal(obj1, obj2) return lambda obj1, obj2: obj1 == obj2 def _find_node_by_rule(self, point, search_rule, cur_node): """! @brief Search node that satisfy to parameters in search rule. @details If node with specified parameters does not exist then None will be returned, otherwise required node will be returned. @param[in] point (list): Coordinates of the point whose node should be found. @param[in] search_rule (lambda): Rule that is called to check whether node satisfies to search parameter. @param[in] cur_node (node): Node from which search should be started. @return (node) Node if it satisfies to input parameters, otherwise it return None. """ if cur_node is None: cur_node = self._root while cur_node: if cur_node.data[cur_node.disc] <= point[cur_node.disc]: # no need to check each node, only when it may satisfy the condition if search_rule(cur_node): # compare point with point in the current node return cur_node cur_node = cur_node.right else: cur_node = cur_node.left return None def find_node_with_payload(self, point, point_payload, cur_node=None): """! @brief Find node with specified coordinates and payload. @details If node with specified parameters does not exist then None will be returned, otherwise required node will be returned. @param[in] point (list): Coordinates of the point whose node should be found. @param[in] point_payload (any): Payload of the node that is searched in the tree. @param[in] cur_node (node): Node from which search should be started. @return (node) Node if it satisfies to input parameters, otherwise it return None. """ rule_search = lambda node, point=point, payload=point_payload: self._point_comparator(node.data, point) and \ node.payload == payload return self._find_node_by_rule(point, rule_search, cur_node) def find_node(self, point, cur_node=None): """! @brief Find node with coordinates that are defined by specified point. @details If node with specified parameters does not exist then None will be returned, otherwise required node will be returned. @param[in] point (list): Coordinates of the point whose node should be found. @param[in] cur_node (node): Node from which search should be started. @return (node) Node if it satisfies to input parameters, otherwise it return None. """ rule_search = lambda node, point=point: self._point_comparator(node.data, point) return self._find_node_by_rule(point, rule_search, cur_node) def find_nearest_dist_node(self, point, distance, retdistance=False): """! @brief Find nearest neighbor in area with radius = distance. @param[in] point (list): Maximum distance where neighbors are searched. @param[in] distance (double): Maximum distance where neighbors are searched. @param[in] retdistance (bool): If True - returns neighbors with distances to them, otherwise only neighbors is returned. @return (node|list) Nearest neighbor if 'retdistance' is False and list with two elements [node, distance] if 'retdistance' is True, where the first element is pointer to node and the second element is distance to it. """ best_nodes = self.find_nearest_dist_nodes(point, distance) if len(best_nodes) == 0: return None nearest = min(best_nodes, key=lambda item: item[0]) if retdistance is True: return nearest else: return nearest[1] def find_nearest_dist_nodes(self, point, distance): """! @brief Find neighbors that are located in area that is covered by specified distance. @param[in] point (list): Coordinates that is considered as centroid for searching. @param[in] distance (double): Distance from the center where searching is performed. @return (list) Neighbors in area that is specified by point (center) and distance (radius). """ best_nodes = [] if self._root is not None: self.__recursive_nearest_nodes(point, distance, distance * distance, self._root, best_nodes) return best_nodes def __recursive_nearest_nodes(self, point, distance, sqrt_distance, node_head, best_nodes): """! @brief Returns list of neighbors such as tuple (distance, node) that is located in area that is covered by distance. @param[in] point (list): Coordinates that is considered as centroid for searching @param[in] distance (double): Distance from the center where searching is performed. @param[in] sqrt_distance (double): Square distance from the center where searching is performed. @param[in] node_head (node): Node from that searching is performed. @param[in|out] best_nodes (list): List of founded nodes. """ if node_head.right is not None: minimum = node_head.data[node_head.disc] - distance if point[node_head.disc] >= minimum: self.__recursive_nearest_nodes(point, distance, sqrt_distance, node_head.right, best_nodes) if node_head.left is not None: maximum = node_head.data[node_head.disc] + distance if point[node_head.disc] < maximum: self.__recursive_nearest_nodes(point, distance, sqrt_distance, node_head.left, best_nodes) candidate_distance = euclidean_distance_square(point, node_head.data) if candidate_distance <= sqrt_distance: best_nodes.append((candidate_distance, node_head)) class kdtree(kdtree_balanced): """! @brief Represents KD Tree that is a space-partitioning data structure for organizing points in a k-dimensional space. @details In the term k-d tree, k denotes the dimensionality of the space being represented. Each data point is represented as a node in the k-d tree in the form of a record of type node. The tree supports dynamic construction when nodes can be dynamically added and removed. As a result KD-tree might not be balanced if methods `insert` and `remove` are used to built the tree. If the tree is built using constructor where all points are passed to the tree then balanced tree is built. Single point search and range-search procedures have complexity is `O(n)` in worse case in case of unbalanced tree. If there is no need to build dynamic KD-tree, then it is much better to use static KD-tree `kdtree_balanced`. There is an example how to use KD-tree to search nodes (points from input data) that are nearest to some point: @code # Import required modules from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.container.kdtree import kdtree; from pyclustering.utils import read_sample; # Read data from text file sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3); # Create instance of KD-tree and initialize (fill) it by read data. # In this case the tree is balanced. tree_instance = kdtree(sample); # Search for nearest point search_distance = 0.3; nearest_node = tree_instance.find_nearest_dist_node([1.12, 4.31], search_distance); # Search for nearest point in radius 0.3 nearest_nodes = tree_instance.find_nearest_dist_nodes([1.12, 4.31], search_distance); print("Nearest nodes:", nearest_nodes); @endcode In case of building KD-tree using `insert` and `remove` method, the output KD-tree might be unbalanced - here is an example that demonstrates this: @code from pyclustering.container.kdtree import kdtree, kdtree_visualizer from pyclustering.utils import read_sample from pyclustering.samples.definitions import FCPS_SAMPLES sample = read_sample(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS) # Build tree using constructor - balanced will be built because tree will know about all points. tree_instance = kdtree(sample) kdtree_visualizer(tree_instance).visualize() # Build tree using `insert` only - unbalanced tree will be built. tree_instance = kdtree() for point in sample: tree_instance.insert(point) kdtree_visualizer(tree_instance).visualize() @endcode There are two figures where difference between balanced and unbalanced KD-trees is demonstrated. @image html kd_tree_unbalanced_two_diamonds.png "Fig. 1. Balanced KD-tree for sample 'TwoDiamonds'." @image html kd_tree_unbalanced_two_diamonds.png "Fig. 2. Unbalanced KD-tree for sample 'TwoDiamonds'." @see kdtree_balanced """ def __init__(self, data_list=None, payload_list=None): """! @brief Create kd-tree from list of points and from according list of payloads. @details If lists were not specified then empty kd-tree will be created. @param[in] data_list (list): Insert points from the list to created KD tree. @param[in] payload_list (list): Insert payload from the list to created KD tree, length should be equal to length of data_list if it is specified. """ super().__init__(data_list, payload_list) def insert(self, point, payload=None): """! @brief Insert new point with payload to kd-tree. @param[in] point (list): Coordinates of the point of inserted node. @param[in] payload (any-type): Payload of inserted node. It can be ID of the node or some useful payload that belongs to the point. @return (node) Inserted node to the kd-tree. """ if self._root is None: self._dimension = len(point) self._root = node(point, payload, None, None, 0) self._point_comparator = self._create_point_comparator(type(point)) self._length += 1 return self._root cur_node = self._root while True: discriminator = (cur_node.disc + 1) % self._dimension if cur_node.data[cur_node.disc] <= point[cur_node.disc]: if cur_node.right is None: cur_node.right = node(point, payload, None, None, discriminator, cur_node) self._length += 1 return cur_node.right else: cur_node = cur_node.right else: if cur_node.left is None: cur_node.left = node(point, payload, None, None, discriminator, cur_node) self._length += 1 return cur_node.left else: cur_node = cur_node.left def remove(self, point, **kwargs): """! @brief Remove specified point from kd-tree. @details It removes the first found node that satisfy to the input parameters. Make sure that pair (point, payload) is unique for each node, otherwise the first found is removed. @param[in] point (list): Coordinates of the point of removed node. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'payload'). Keyword Args:
- payload (any): Payload of the node that should be removed. @return (node) Root if node has been successfully removed, otherwise None. """ if 'payload' in kwargs: node_for_remove = self.find_node_with_payload(point, kwargs['payload'], None) else: node_for_remove = self.find_node(point, None) if node_for_remove is None: return None self._length -= 1 parent = node_for_remove.parent minimal_node = self.__recursive_remove(node_for_remove) if parent is None: self._root = minimal_node # If all k-d tree was destroyed if minimal_node is not None: minimal_node.parent = None else: if parent.left is node_for_remove: parent.left = minimal_node elif parent.right is node_for_remove: parent.right = minimal_node return self._root def __recursive_remove(self, node_removed): """! @brief Delete node and return root of subtree. @param[in] node_removed (node): Node that should be removed. @return (node) Minimal node in line with coordinate that is defined by discriminator. """ # Check if it is leaf if (node_removed.right is None) and (node_removed.left is None): return None discriminator = node_removed.disc # Check if only left branch exist if node_removed.right is None: node_removed.right = node_removed.left node_removed.left = None # Find minimal node in line with coordinate that is defined by discriminator minimal_node = self.__find_minimal_node(node_removed.right, discriminator) parent = minimal_node.parent if parent.left is minimal_node: parent.left = self.__recursive_remove(minimal_node) elif parent.right is minimal_node: parent.right = self.__recursive_remove(minimal_node) minimal_node.parent = node_removed.parent minimal_node.disc = node_removed.disc minimal_node.right = node_removed.right minimal_node.left = node_removed.left # Update parent for successors of previous parent. if minimal_node.right is not None: minimal_node.right.parent = minimal_node if minimal_node.left is not None: minimal_node.left.parent = minimal_node return minimal_node def __find_minimal_node(self, node_head, discriminator): """! @brief Find minimal node in line with coordinate that is defined by discriminator. @param[in] node_head (node): Node of KD tree from that search should be started. @param[in] discriminator (uint): Coordinate number that is used for comparison. @return (node) Minimal node in line with discriminator from the specified node. """ min_key = lambda cur_node: cur_node.data[discriminator] stack, candidates = [], [] is_finished = False while is_finished is False: if node_head is not None: stack.append(node_head) node_head = node_head.left else: if len(stack) != 0: node_head = stack.pop() candidates.append(node_head) node_head = node_head.right else: is_finished = True return min(candidates, key=min_key) pyclustering-0.10.1.2/pyclustering/container/tests/000077500000000000000000000000001375753423500223535ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/container/tests/__init__.py000077500000000000000000000010511375753423500244640ustar00rootroot00000000000000"""! @brief Unit-test runner for containers. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.tests.suite_holder import suite_holder from pyclustering.container.tests.unit import container_unit_tests class container_tests(suite_holder): def __init__(self): super().__init__() container_unit_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(container_suite): container_unit_tests.fill_suite(container_suite) pyclustering-0.10.1.2/pyclustering/container/tests/unit/000077500000000000000000000000001375753423500233325ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/container/tests/unit/__init__.py000077500000000000000000000015221375753423500254460ustar00rootroot00000000000000"""! @brief Unit-test runner for containers. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder from pyclustering.container.tests.unit import ut_cftree as container_cftree_unit_tests from pyclustering.container.tests.unit import ut_kdtree as container_kdtree_unit_tests class container_unit_tests(suite_holder): def __init__(self): super().__init__() container_unit_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(unit_container_suite): unit_container_suite.addTests(unittest.TestLoader().loadTestsFromModule(container_cftree_unit_tests)) unit_container_suite.addTests(unittest.TestLoader().loadTestsFromModule(container_kdtree_unit_tests)) pyclustering-0.10.1.2/pyclustering/container/tests/unit/ut_cftree.py000077500000000000000000000460311375753423500256730ustar00rootroot00000000000000"""! @brief Unit-tests for CF-tree container. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import numpy import math from random import random from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.container.cftree import cfentry, cftree from pyclustering.container.cftree import measurement_type from pyclustering.utils import linear_sum, square_sum, read_sample from pyclustering.utils import euclidean_distance_square, manhattan_distance, average_inter_cluster_distance, average_intra_cluster_distance, variance_increase_distance class CftreeUnitTest(unittest.TestCase): def templateCfClusterRepresentation(self, cluster, centroid, radius, diameter, tolerance): entry = cfentry(len(cluster), linear_sum(cluster), square_sum(cluster)) assertion_centroid = centroid if type(centroid) != list: assertion_centroid = [centroid] if type(centroid) == list: for dimension in range(0, len(assertion_centroid)): self.assertAlmostEqual(assertion_centroid[dimension], (entry.get_centroid())[dimension], tolerance) self.assertAlmostEqual(radius, entry.get_radius(), tolerance) self.assertAlmostEqual(diameter, entry.get_diameter(), tolerance) def testCfClusterRepresentationOneDimension2(self): cluster = [[0.1], [0.2], [0.5], [0.4], [0.6]] self.templateCfClusterRepresentation(cluster, 0.36, 0.18547, 0.29326, 5) def testCfClusterRepresentationTwoDimension(self): cluster = [[0.1, 0.1], [0.2, 0.2], [0.5, 0.5], [0.4, 0.4], [0.6, 0.6]] self.templateCfClusterRepresentation(cluster, [0.36, 0.36], 0.26230, 0.41473, 5) def testGetNearestEntry(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) tree = cftree(10, 100, 0.2, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) self.assertEqual(10, tree.branch_factor) self.assertEqual(100, tree.max_entries) self.assertEqual(0.2, tree.threshold) self.assertEqual(measurement_type.CENTROID_EUCLIDEAN_DISTANCE, tree.type_measurement) for index_point in range(len(sample)): tree.insert_point(sample[index_point]) cluster = [[0.1, 0.1], [0.2, 0.2]] entry = cfentry(len(cluster), linear_sum(cluster), square_sum(cluster)) leaf = tree.find_nearest_leaf(entry) found_entry = leaf.get_nearest_entry(entry, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) found_index_entry = leaf.get_nearest_index_entry(entry, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) self.assertEqual(leaf.entries[found_index_entry], found_entry) def templateCfEntryValueDistance(self, cluster1, cluster2, value, tolerance, type_measurment): entry1 = cfentry(len(cluster1), linear_sum(cluster1), square_sum(cluster1)) entry2 = cfentry(len(cluster2), linear_sum(cluster2), square_sum(cluster2)) distance = entry1.get_distance(entry2, type_measurment) assert ((value - tolerance < distance) and (value + tolerance > distance)) def testCfEntryTwoPoints1(self): self.templateCfEntryValueDistance([[0.0]], [[1.0]], 1.0, 0.0000001, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testCfEntryTwoPoints2(self): self.templateCfEntryValueDistance([[0.0]], [[0.0]], 0.0, 0.0000001, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testCfEntryTwoPoints3(self): self.templateCfEntryValueDistance([[-1.0]], [[0.0]], 1.0, 0.0000001, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testCfEntryTwoPoints4(self): self.templateCfEntryValueDistance([[1.0, 0.0]], [[0.0, 1.0]], 2.0, 0.0000001, measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testCfEntryIncrease(self): cluster = [[0.1, 0.1], [0.2, 0.2], [0.5, 0.5], [0.4, 0.4], [0.6, 0.6]] entry1 = cfentry(len(cluster), linear_sum(cluster), square_sum(cluster)) entry2 = entry1 + entry1 assert cfentry(10, [3.6, 3.6], 3.28) == entry2 entry2 = entry2 + entry2 assert cfentry(20, [7.2, 7.2], 6.56) == entry2 def templateCfEntryDistance(self, type_measurement): cluster1 = [[0.1, 0.1], [0.1, 0.2], [0.2, 0.1], [0.2, 0.2]] cluster2 = [[0.4, 0.4], [0.4, 0.5], [0.5, 0.4], [0.5, 0.5]] cluster3 = [[0.9, 0.9], [0.9, 1.0], [1.0, 0.9], [1.0, 1.0]] entry1 = cfentry(len(cluster1), linear_sum(cluster1), square_sum(cluster1)) entry2 = cfentry(len(cluster2), linear_sum(cluster2), square_sum(cluster2)) entry3 = cfentry(len(cluster3), linear_sum(cluster3), square_sum(cluster3)) distance12 = entry1.get_distance(entry2, type_measurement) distance23 = entry2.get_distance(entry3, type_measurement) distance13 = entry1.get_distance(entry3, type_measurement) assert distance12 < distance23; assert distance23 < distance13; def testCfDistanceCentroidEuclidian(self): self.templateCfEntryDistance(measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testCfDistanceCentroidManhatten(self): self.templateCfEntryDistance(measurement_type.CENTROID_MANHATTAN_DISTANCE) def testCfDistanceAverageInterCluster(self): self.templateCfEntryDistance(measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE) def testCfDistanceAverageIntraCluster(self): self.templateCfEntryDistance(measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE) def testCfDistanceVarianceIncrease(self): self.templateCfEntryDistance(measurement_type.VARIANCE_INCREASE_DISTANCE) def templateDistanceCalculation(self, cluster1, cluster2, type_measurement): entry1 = cfentry(len(cluster1), linear_sum(cluster1), square_sum(cluster1)) entry2 = cfentry(len(cluster2), linear_sum(cluster2), square_sum(cluster2)) # check that the same distance from 1 to 2 and from 2 to 1. distance12 = entry1.get_distance(entry2, type_measurement) distance21 = entry2.get_distance(entry1, type_measurement) assert distance12 == distance21; # check with utils calculation float_delta = 0.0000001 if (type_measurement == measurement_type.CENTROID_EUCLIDEAN_DISTANCE): assert distance12 == euclidean_distance_square(entry1.get_centroid(), entry2.get_centroid()); elif (type_measurement == measurement_type.CENTROID_MANHATTAN_DISTANCE): assert distance12 == manhattan_distance(entry1.get_centroid(), entry2.get_centroid()); elif (type_measurement == measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE): assert numpy.isclose(distance12, average_inter_cluster_distance(cluster1, cluster2)) == True; elif (type_measurement == measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE): assert numpy.isclose(distance12, average_intra_cluster_distance(cluster1, cluster2)) == True; elif (type_measurement == measurement_type.VARIANCE_INCREASE_DISTANCE): assert numpy.isclose(distance12, variance_increase_distance(cluster1, cluster2)) == True; def templateDistanceCalculationTheSimplestSample(self, type_measurement): cluster1 = [[0.1, 0.1], [0.1, 0.2], [0.2, 0.1], [0.2, 0.2]] cluster2 = [[0.4, 0.4], [0.4, 0.5], [0.5, 0.4], [0.5, 0.5]] self.templateDistanceCalculation(cluster1, cluster2, type_measurement) def testDistanceCalculationTheSimplestSampleCentroidEuclidian(self): self.templateDistanceCalculationTheSimplestSample(measurement_type.CENTROID_EUCLIDEAN_DISTANCE) def testDistanceCalculationTheSimplestSampleCentroidManhattan(self): self.templateDistanceCalculationTheSimplestSample(measurement_type.CENTROID_MANHATTAN_DISTANCE) def testDistanceCalculationTheSimplestSampleAverageInterClusterDistance(self): self.templateDistanceCalculationTheSimplestSample(measurement_type.AVERAGE_INTER_CLUSTER_DISTANCE) def testDistanceCalculationTheSimplestSampleAverageIntraClusterDistance(self): self.templateDistanceCalculationTheSimplestSample(measurement_type.AVERAGE_INTRA_CLUSTER_DISTANCE) def testDistanceCalculationTheSimplestSampleVarianceIncreaseDistance(self): self.templateDistanceCalculationTheSimplestSample(measurement_type.VARIANCE_INCREASE_DISTANCE) def testCfTreeCreationWithOneEntry(self): tree = cftree(2, 1, 1.0) entry = cfentry(5, [0.0, 0.1], 0.05) tree.insert(entry) assert 1 == tree.amount_nodes; assert 1 == tree.height; assert 1 == tree.amount_entries; assert entry == tree.root.feature; assert None == tree.root.parent; def testCfTreeCreationWithoutMerging(self): clusters = [[[random() + j, random() + j] for _ in range(10)] for j in range(10)] tree = cftree(2, 1, 0.0) for cluster in clusters: for point in cluster: tree.insert_point(point) assert tree.height >= 4 self.assertEqual(tree.amount_entries, 100) self.assertEqual(len(tree.leafes), 100) def templateCfTreeLeafIntegrity(self, number_clusters, branching_factor, max_entries, threshold): clusters = [ [ [random() + j, random() + j] for i in range(10) ] for j in range(number_clusters) ] tree = cftree(branching_factor, max_entries, threshold) for index_cluster in range(0, len(clusters)): for point in clusters[index_cluster]: tree.insert_point(point) result_searching = False for leaf in tree.leafes: for node_entry in leaf.entries: result_searching |= (node_entry == node_entry) assert True == result_searching; def testCfTreeLeafIntegrity10_2_1(self): self.templateCfTreeLeafIntegrity(10, 2, 1, 0.0) def testCfTreeLeafIntegrity10_3_1(self): self.templateCfTreeLeafIntegrity(10, 3, 1, 0.0) def testCfTreeLeafIntegrity20_4_1(self): self.templateCfTreeLeafIntegrity(20, 4, 1, 0.0) def testCfTreeLeafIntegrity20_4_2(self): self.templateCfTreeLeafIntegrity(20, 4, 2, 0.0) def testCfTreeLeafIntegrity40_10_5(self): self.templateCfTreeLeafIntegrity(40, 10, 5, 0.0) def testCfTreeEntryAbsorbing(self): tree = cftree(2, 1, 10000.0) absorbing_entry = cfentry(0, [0.0, 0.0], 0.0) for offset in range(0, 10): cluster = [[random() + offset, random() + offset] for i in range(10)] entry = cfentry(len(cluster), linear_sum(cluster), square_sum(cluster)) absorbing_entry += entry tree.insert(entry) assert 1 == tree.amount_entries assert 1 == tree.amount_nodes assert 1 == tree.height assert None == tree.root.parent assert absorbing_entry == tree.root.feature def templateCfTreeTotalNumberPoints(self, number_points, dimension, branching_factor, number_entries, diameter): tree = cftree(branching_factor, number_entries, diameter) for index_point in range(0, number_points): point = [index_point for i in range(0, dimension)] tree.insert_point(point) number_points = 0 for leaf in tree.leafes: number_points += leaf.feature.number_points assert (index_point + 1) == number_points; number_leaf_points = 0 for leaf in tree.leafes: number_leaf_points += leaf.feature.number_points assert number_points == tree.root.feature.number_points if number_points != number_leaf_points: print(number_points, number_leaf_points) assert number_points == number_leaf_points; def testCfTreeTotalNumberPoints10_1_5_5_NoDiameter(self): self.templateCfTreeTotalNumberPoints(10, 1, 5, 5, 0.0) def testCfTreeTotalNumberPoints10_1_5_5_WithDiameter(self): self.templateCfTreeTotalNumberPoints(10, 1, 5, 5, 100.0) def testCfTreeTotalNumberPoints10_1_5_5_WithSmallDiameter(self): self.templateCfTreeTotalNumberPoints(10, 1, 5, 5, 2.5) def testCfTreeTotalNumberPoints10_2_5_5_NoDiameter(self): self.templateCfTreeTotalNumberPoints(10, 2, 5, 5, 0.0) def testCfTreeTotalNumberPoints10_2_5_5_WithDiameter(self): self.templateCfTreeTotalNumberPoints(10, 2, 5, 5, 100.0) def testCfTreeTotalNumberPoints50_3_5_5_NoDiameter(self): self.templateCfTreeTotalNumberPoints(50, 3, 5, 5, 0.0) def testCfTreeTotalNumberPoints50_3_5_5_WithDiameter(self): self.templateCfTreeTotalNumberPoints(50, 3, 5, 5, 100.0) def testCfTreeTotalNumberPoints100_2_2_1_NoDiameter(self): self.templateCfTreeTotalNumberPoints(100, 2, 2, 1, 0.0) def testCfTreeTotalNumberPoints100_2_2_1_WithDiameter(self): self.templateCfTreeTotalNumberPoints(100, 2, 2, 1, 100.0) def testCfTreeTotalNumberPoints100_2_5_5_WithSmallDiameter(self): self.templateCfTreeTotalNumberPoints(100, 2, 5, 5, 10.0) def templateTreeHeight(self, number_points, branching_factor): tree = cftree(branching_factor, 1, 0.1) for index_point in range(0, number_points): point = [index_point] tree.insert_point(point) assert math.floor(math.log(number_points, branching_factor)) <= tree.height; def testObtainNodesFromTheLevel_7_2(self): self.templateTreeHeight(7, 2) def testObtainNodesFromTheLevel_63_2(self): self.templateTreeHeight(63, 2) def testObtainNodesFromTheLevel_40_3(self): self.templateTreeHeight(40, 3) def testObtainNodesFromTheLevel_21_4(self): self.templateTreeHeight(21, 4) def testObtainNodesFromTheLevel_156_5(self): self.templateTreeHeight(156, 5) def templateLevelNodeObtaining(self, number_points, branching_factor): tree = cftree(branching_factor, 1, 0.1) for index_point in range(0, number_points): point = [index_point] tree.insert_point(point) total_node_amount = 0 for level in range(0, tree.height): nodes = tree.get_level_nodes(level) total_node_amount += len(nodes) assert tree.amount_nodes == total_node_amount; def testLevelNodeObtaining_7_2(self): self.templateLevelNodeObtaining(7, 2) def testLevelNodeObtaining_10_2(self): self.templateLevelNodeObtaining(10, 2) def testLevelNodeObtaining_7_3(self): self.templateLevelNodeObtaining(7, 3) def testLevelNodeObtaining_20_3(self): self.templateLevelNodeObtaining(20, 3) def testLevelNodeObtaining_26_3(self): self.templateLevelNodeObtaining(26, 3) def testLevelNodeObtaining_16_4(self): self.templateLevelNodeObtaining(16, 4) def testLevelNodeObtaining_34_4(self): self.templateLevelNodeObtaining(34, 4) def templateLeafNodeAndEntriesAmount(self, number_points, branching_factor): tree = cftree(branching_factor, 1, 0.1) current_size = 0 for index_point in range(0, number_points): point = [index_point] tree.insert_point(point) current_size += 1 assert current_size == tree.amount_entries assert current_size == len(tree.leafes) assert number_points == tree.amount_entries assert number_points == len(tree.leafes) def testLeafNodeAndEntriesAmount_5_2(self): self.templateLeafNodeAndEntriesAmount(5, 2) def testLeafNodeAndEntriesAmount_10_2(self): self.templateLeafNodeAndEntriesAmount(10, 2) def testLeafNodeAndEntriesAmount_6_3(self): self.templateLeafNodeAndEntriesAmount(6, 3) def testLeafNodeAndEntriesAmount_18_3(self): self.templateLeafNodeAndEntriesAmount(18, 3) def testLeafNodeAndEntriesAmount_16_4(self): self.templateLeafNodeAndEntriesAmount(16, 4) def templateCorrectEntryDiameter(self, sample_path, branching_factor, diameter): sample = read_sample(sample_path) tree = cftree(branching_factor, 100, diameter) for index_point in range(len(sample)): tree.insert_point(sample[index_point]) leaf_nodes = tree.leafes for node in leaf_nodes: for entry in node.entries: self.assertLessEqual(entry.get_diameter(), diameter) def testCorrectEntryDiameterSimple1(self): self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 0.01) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 0.1) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 5, 0.5) def testCorrectEntryDiameterSimple2(self): self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 0.01) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 0.1) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 5, 0.5) def testCorrectEntryDiameterSimple3(self): self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 0.01) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 0.1) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 5, 1.0) def testCorrectEntryDiameterSimple4(self): self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, 0.01) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, 0.1) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 5, 1.0) def testCorrectEntryDiameterSimple5(self): self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 0.01) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 0.1) self.templateCorrectEntryDiameter(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 5, 1.0) def testCorrectEntryDiameterLsun(self): self.templateCorrectEntryDiameter(FCPS_SAMPLES.SAMPLE_LSUN, 200, 0.01) self.templateCorrectEntryDiameter(FCPS_SAMPLES.SAMPLE_LSUN, 200, 0.1) self.templateCorrectEntryDiameter(FCPS_SAMPLES.SAMPLE_LSUN, 200, 1.0) def testCorrectEntryDiameterTarget(self): self.templateCorrectEntryDiameter(FCPS_SAMPLES.SAMPLE_TARGET, 200, 0.5) pyclustering-0.10.1.2/pyclustering/container/tests/unit/ut_kdtree.py000077500000000000000000000675241375753423500257130ustar00rootroot00000000000000"""! @brief Unit-tests for KD-tree container. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import numpy import matplotlib import random matplotlib.use('Agg') from pyclustering.container.kdtree import kdtree, kdtree_balanced, kdtree_visualizer from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.utils import read_sample class KDTreeUnitTest(unittest.TestCase): def templateCreateWithPayloadAndFindNode(self, array, payload, kdtree_class): tree = kdtree_class(array, payload) self.assertEqual(len(array), len(tree)) for index in range(len(array)): node = tree.find_node(array[index]) self.assertIsNotNone(node) self.assertEqual(node.payload, payload[index]) self.assertEqual(node.data, array[index]) self.assertGreater(len(str(node)), 1) def testKDTreeCreateWithPayload01(self): array = [[4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [5, 9]] payload = ['q', 'w', 'e', 'r', 't', 'y', 'u'] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree) def testKDTreeBalancedWithPayload01(self): array = [[4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [5, 9]] payload = ['q', 'w', 'e', 'r', 't', 'y', 'u'] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree_balanced) def testKDTreeCreateWithPayload02(self): array = [[3, 4], [5, 6], [9, 8], [7, 3], [1, 2], [2, 4], [2, 5], [3, 2]] payload = ['q', 'w', 'a', 's', 'z', 'x', 't', 'y'] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree) def testKDTreeBalancedWithPayload02(self): array = [[3, 4], [5, 6], [9, 8], [7, 3], [1, 2], [2, 4], [2, 5], [3, 2]] payload = ['q', 'w', 'a', 's', 'z', 'x', 't', 'y'] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree_balanced) def testKDTreeWithPayload03(self): array = [[3, 4], [3, 2]] payload = ['q', 'y'] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree) def testKDTreeBalancedWithPayload03(self): array = [[3, 4], [3, 2]] payload = ['q', 'y'] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree_balanced) def testKDTreeCreateWithPayloadSample01(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) possible_payload = ["qwe", "asd", "zxc", "rty", "fgh", "vbn", "yui", "ghj", "bnm"] payload = [possible_payload[random.randint(0, len(possible_payload) - 1)] for _ in range(len(array))] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree) def testKDTreeBalancedWithPayloadSample01(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) possible_payload = ["qwe", "asd", "zxc", "rty", "fgh", "vbn", "yui", "ghj", "bnm"] payload = [possible_payload[random.randint(0, len(possible_payload) - 1)] for _ in range(len(array))] self.templateCreateWithPayloadAndFindNode(array, payload, kdtree_balanced) def templateCreateWithoutPayloadAndFindNode(self, array, kdtree_class): tree = kdtree_class(array) self.assertEqual(len(array), len(tree)) for item in array: found_node = tree.find_node(item) self.assertIsNotNone(found_node, "Point '%s' is not found." % str(item)) self.assertEqual(found_node.data, item) self.assertIsNone(found_node.payload) def testKDTreeCreateWithoutPayloadOneNode(self): self.templateCreateWithoutPayloadAndFindNode([[3, 4]], kdtree) def testKDTreeBalancedCreateWithoutPayloadOneNode(self): self.templateCreateWithoutPayloadAndFindNode([[3, 4]], kdtree_balanced) def testKDTreeCreateWithoutPayloadTwoNode(self): self.templateCreateWithoutPayloadAndFindNode([[3, 4], [5, 6]], kdtree) def testKDTreeBalancedCreateWithoutPayloadTwoNode(self): self.templateCreateWithoutPayloadAndFindNode([[3, 4], [5, 6]], kdtree_balanced) def testKDTreeCreateWithoutPayload(self): array = [[3, 4], [5, 6], [9, 8], [7, 3], [1, 2], [2, 4], [2, 5], [3, 2]] self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayload(self): array = [[3, 4], [5, 6], [9, 8], [7, 3], [1, 2], [2, 4], [2, 5], [3, 2]] self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample01(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample01(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample02(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample02(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample03(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample03(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample04(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample04(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample05(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample05(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample06(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE6) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample06(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE6) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample07(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE7) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample07(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE7) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def testKDTreeCreateWithoutPayloadSample08(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE8) self.templateCreateWithoutPayloadAndFindNode(array, kdtree) def testKDTreeBalancedCreateWithoutPayloadSample08(self): array = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE8) self.templateCreateWithoutPayloadAndFindNode(array, kdtree_balanced) def templateInsertNodes(self): array = [[4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [5, 9]] payload = ['q', 'w', 'e', 'r', 't', 'y', 'u'] tree = kdtree() self.assertEqual(len(tree), 0) for index in range(len(array)): node = tree.insert(array[index], payload[index]) self.assertEqual(len(tree), index + 1) self.assertIsNotNone(node) self.assertEqual(node.payload, payload[index]) self.assertEqual(node.data, array[index]) def testKDTreeInsertNodes(self): array = [[4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [5, 9]] payload = ['q', 'w', 'e', 'r', 't', 'y', 'u'] tree = kdtree() self.assertEqual(len(tree), 0) for index in range(len(array)): node = tree.insert(array[index], payload[index]) self.assertEqual(len(tree), index + 1) self.assertIsNotNone(node) self.assertEqual(node.payload, payload[index]) self.assertEqual(node.data, array[index]) def testKDTreeParentSearch(self): array = [[4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [5, 9]] tree = kdtree(array) node = tree.find_node([4, 3]) assert node.parent is None node = tree.find_node([3, 4]) assert node.parent.data == [4, 3] node = tree.find_node([5, 8]) assert node.parent.data == [4, 3] node = tree.find_node([6, 4]) assert node.parent.data == [5, 8] node = tree.find_node([3, 3]) assert node.parent.data == [3, 4] node = tree.find_node([5, 9]) assert node.parent.data == [5, 8] node = tree.find_node([3, 9]) assert node.parent.data == [3, 4] def testKDTreeInsertRemoveNode1(self): array = [[4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [5, 9]] payload = ['q', 'w', 'e', 'r', 't', 'y', 'u'] tree = kdtree() for index in range(len(array)): removed_node = tree.remove(array[index]) self.assertIsNone(removed_node, "The point '%s' shouldn't be found in the tree - it wasn't added yet." % str(array[index])) node = tree.insert(array[index], payload[index]) self.assertIsNotNone(node) self.assertEqual(node.data, array[index]) length = len(array) for index in range(0, length): node = tree.remove(array[index]) assert len(tree) == length - index - 1 if index + 1 < length: # When root is removed then None will be returned assert node is not None else: assert node is None # Check other nodes are located in the tree for k in range(index + 1, length): node = tree.find_node(array[k]) assert node.data == array[k]; assert node.payload == payload[k]; def testKDTreeInsertRemoveNode2(self): array = [[9, 9], [3, 3], [4, 4]] tree = kdtree(array) assert None is not tree.remove([9, 9]) assert len(tree) == 2 assert None is not tree.remove([4, 4]) assert len(tree) == 1 assert None is tree.remove([3, 3]) assert len(tree) == 0 def testKDTreeInsertFindNode(self): suite_array = [[[9, 9], [3, 3], [4, 4]], [[9, 9], [3, 3]], [[9, 9], [4, 4], [10, 10]], [[5, 5]], [[5, 5], [2, 2], [7, 7]], [[5, 5], [2, 2], [7, 7], [1, 1], [8, 8]]] for array in suite_array: tree = kdtree(array) for point in array: node = tree.find_node(point) self.assertIsNotNone(node) self.assertEqual(node.data, point) def testKDTreeRemoveLongBranch(self): # Create only one branch - worth case and remove it array = [[5, 5], [6, 5], [6, 6], [7, 6], [7, 7]] tree = kdtree(array) self.assertEqual(len(tree), len(array)) for index in range(len(array)): node = tree.remove(array[index]) if len(tree) != 0: self.assertIsNotNone(node) self.assertEqual(len(tree), len(array) - index - 1) # Remove from other end tree = kdtree(array) for index in range(len(array)): node = tree.remove(array[len(array) - index - 1]) if len(tree) != 0: self.assertIsNotNone(node) self.assertEqual(len(tree), len(array) - index - 1) def templateKDTreeNearestNodeTrivial1(self, kdtree_class): array = [ [4, 3], [3, 4], [5, 8], [3, 3], [3, 9], [6, 4], [6, 9], [4, 9] ] tree = kdtree_class(array) for item in array: assert tree.find_nearest_dist_node(item, 0).data == item; assert tree.find_nearest_dist_node(item, 0.5).data == item; assert tree.find_nearest_dist_node(item, 1).data == item; assert tree.find_nearest_dist_node(item, 3).data == item; assert tree.find_nearest_dist_node(item, 10).data == item; assert tree.find_nearest_dist_node([6.1, 4.1], 0.5).data == [6, 4] assert tree.find_nearest_dist_node([6, 12], 0) is None assert tree.find_nearest_dist_node([6, 12], 1) is None assert tree.find_nearest_dist_node([6, 12], 3).data == [6, 9] def testKDTreeNearestNodeTrivial1(self): self.templateKDTreeNearestNodeTrivial1(kdtree) def testKDTreeBalancedNearestNodeTrivial1(self): self.templateKDTreeNearestNodeTrivial1(kdtree_balanced) def testKDTreeNearestNodeTrivial2(self): arrays = [ [ [3, 4], [5, 6], [9, 8], [7, 3], [1, 2], [2, 4], [2, 5], [3, 2], [3, 3] ], [ [5, 6], [1, 3], [7, 3], [1, 1], [9, 9], [4, 7], [0, 3], [3, 5], [1, 2], [9, 3], [9, 8], [5, 5], [6, 6], [0, 0], [-4, -5], [-1, 5], [-8, 3] ] ] distances = [0.0, 0.5, 1.0, 3.0, 10.0] for array in arrays: tree = kdtree(array) for item in array: for distance in distances: assert tree.find_nearest_dist_node(item, distance).data == item; def templateSeachNearestNodeInTree(self, sample_path, **kwargs): numpy_usage = kwargs.get('numpy_usage', False) sample = read_sample(sample_path) if numpy_usage is True: sample = numpy.array(sample) tree = kdtree() for point in sample: node = tree.find_nearest_dist_node(point, 0.0) self.assertIsNone(node) tree.insert(point, None) node = tree.find_nearest_dist_node(point, 0.0) self.assertIsNotNone(node) self.assertIs(node.data, point) distance_and_node = tree.find_nearest_dist_node(point, 0.0, True) self.assertIsNotNone(distance_and_node) self.assertIs(distance_and_node[1].data, point) self.assertEqual(distance_and_node[0], 0.0) def testSearchNearestNodeInSampleSimple01(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def testSearchNearestNodeInSampleSimple01NumPy(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, numpy_usage=True) def testSearchNearestNodeInSampleSimple02(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def testSearchNearestNodeInSampleSimple02NumPy(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, numpy_usage=True) def testSearchNearestNodeInSampleSimple03(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def testSearchNearestNodeInSampleSimple03NumPy(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, numpy_usage=True) def testSearchNearestNodeInSampleSimple04(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def testSearchNearestNodeInSampleSimple04NumPy(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, numpy_usage=True) def testSearchNearestNodeInSampleSimple05(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def testSearchNearestNodeInSampleSimple05NumPy(self): self.templateSeachNearestNodeInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, numpy_usage=True) def testSearchNearestNodeInLsun(self): self.templateSeachNearestNodeInTree(FCPS_SAMPLES.SAMPLE_LSUN) def testSearchNearestNodeInLsunNumPy(self): self.templateSeachNearestNodeInTree(FCPS_SAMPLES.SAMPLE_LSUN, numpy_usage=True) def testSearchNearestNodeInTetra(self): self.templateSeachNearestNodeInTree(FCPS_SAMPLES.SAMPLE_TETRA) def testSearchNearestNodeInTetraNumPy(self): self.templateSeachNearestNodeInTree(FCPS_SAMPLES.SAMPLE_TETRA, numpy_usage=True) def testSearchNearestNodeInHepta(self): self.templateSeachNearestNodeInTree(FCPS_SAMPLES.SAMPLE_HEPTA) def testSearchNearestNodeInHeptaNumPy(self): self.templateSeachNearestNodeInTree(FCPS_SAMPLES.SAMPLE_HEPTA, numpy_usage=True) def templateSeachNearestNodeInBalancedTree(self, sample_path, generate_payload=False, **kwargs): numpy_usage = kwargs.get('numpy_usage', False) sample = read_sample(sample_path) if numpy_usage is True: sample = numpy.array(sample) payloads = None if generate_payload is True: payloads = [random.randint(1, 1000) for _ in range(len(sample))] tree = kdtree_balanced(sample, payloads) for i in range(len(sample)): node = tree.find_nearest_dist_node(sample[i], 0.0) self.assertIsNotNone(node) if numpy_usage is False: self.assertIs(node.data, sample[i]) else: self.assertTrue((node.data == sample[i]).all()) if payloads is not None: self.assertEqual(node.payload, payloads[i]) def testKDTreeBalancedSearchNearestSimple01(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def testKDTreeBalancedSearchNearestSimple01Payload(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, True) def testKDTreeBalancedSearchNearestSimple01NumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, numpy_usage=True) def testKDTreeBalancedSearchNearestSimple01PayloadNumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, True, numpy_usage=True) def testKDTreeBalancedSearchNearestSimple02(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def testKDTreeBalancedSearchNearestSimple02Payload(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, True) def testKDTreeBalancedSearchNearestSimple02NumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, numpy_usage=True) def testKDTreeBalancedSearchNearestSimple02PayloadNumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, True, numpy_usage=True) def testKDTreeBalancedSearchNearestSimple03(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) def testKDTreeBalancedSearchNearestSimple03Payload(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, True) def testKDTreeBalancedSearchNearestSimple03NumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, numpy_usage=True) def testKDTreeBalancedSearchNearestSimple04(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) def testKDTreeBalancedSearchNearestSimple04Payload(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, True) def testKDTreeBalancedSearchNearestSimple04NumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, numpy_usage=True) def testKDTreeBalancedSearchNearestSimple05(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def testKDTreeBalancedSearchNearestSimple05Payload(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, True) def testKDTreeBalancedSearchNearestSimple05NumPy(self): self.templateSeachNearestNodeInBalancedTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, numpy_usage=True) def testKDTreeBalancedSearchNearestLsun(self): self.templateSeachNearestNodeInBalancedTree(FCPS_SAMPLES.SAMPLE_LSUN) def testKDTreeBalancedSearchNearestLsunNumPy(self): self.templateSeachNearestNodeInBalancedTree(FCPS_SAMPLES.SAMPLE_LSUN, numpy_usage=True) def testKDTreeBalancedSearchNearestHepta(self): self.templateSeachNearestNodeInBalancedTree(FCPS_SAMPLES.SAMPLE_HEPTA) def testKDTreeBalancedSearchNearestHeptaNumPy(self): self.templateSeachNearestNodeInBalancedTree(FCPS_SAMPLES.SAMPLE_HEPTA, numpy_usage=True) def templateSeachNearestNodesInTree(self, sample_path, search_radius, length=None, numpy_usage=False, **kwargs): kdtree_class = kwargs.get('kdtree_class', kdtree) sample = read_sample(sample_path) if numpy_usage is True: sample = numpy.array(sample) tree = kdtree_class(sample) for point in sample: nodes = tree.find_nearest_dist_nodes(point, search_radius) self.assertNotEqual(len(nodes), 0) if length is None: self.assertGreater(len(nodes), 1) else: self.assertEqual(len(nodes), length) def testSeachNearestNodesInSampleSimple01(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5) def testSeachNearestNodesInSampleSimple01Balanced(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5, kdtree_class=kdtree_balanced) def testSeachNearestNodesInSampleSimple01NumPy(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 0.5, numpy_usage=True) def testSeachNearestNodesInSampleSimple02(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 0.5) def testSeachNearestNodesInSampleSimple02Balanced(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 0.5, kdtree_class=kdtree_balanced) def testSeachNearestNodesInSampleSimple02NumPy(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 0.5, numpy_usage=True) def testSeachNearestNodesInSampleSimple03(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.5) def testSeachNearestNodesInSampleSimple03Balanced(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.5, kdtree_class=kdtree_balanced) def testSeachNearestNodesInSampleSimple03NumPy(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.5, numpy_usage=True) def testSeachNearestNodesInSampleSimple03OneNode(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.0, 1) def testSeachNearestNodesInSampleSimple03OneNodeBalanced(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.0, 1, kdtree_class=kdtree_balanced) def testSeachNearestNodesInSampleSimple03OneNodeNumPy(self): self.templateSeachNearestNodesInTree(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 0.0, 1, numpy_usage=True) def templateTreeVisualization(self, path, **kwargs): sample = None if path is not None: sample = read_sample(path) exception = kwargs.get('exception', None) if exception is not None: self.assertRaises(exception, kdtree_visualizer, kdtree(sample)) self.assertRaises(exception, kdtree_visualizer, kdtree_balanced(sample)) else: kdtree_visualizer(kdtree(sample)).visualize() kdtree_visualizer(kdtree_balanced(sample)).visualize() def testVisualizeNoData(self): self.templateTreeVisualization(None, exception=ValueError) def testVisualizeSampleSimple01(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) def testVisualizeSampleSimple01NumPy(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, numpy_usage=True) def testVisualizeSampleSimple02(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE2) def testVisualizeSampleSimple02NumPy(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, numpy_usage=True) def testVisualizeSampleSimple05(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE5) def testVisualizeOneDimensional(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, exception=NotImplementedError) def testVisualizeThreeDimensional(self): self.templateTreeVisualization(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, exception=NotImplementedError) def templateTheSameDataSearchAndRemove(self, points, payloads): tree = kdtree() inserted_node = [] for i in range(len(points)): inserted_node.append(tree.insert(points[i], payloads[i])) for node in inserted_node: found_node = tree.find_node_with_payload(node.data, node.payload) self.assertEqual(node, found_node) for i in range(len(inserted_node)): tree.remove(inserted_node[i].data, payload=inserted_node[i].payload) found_node = tree.find_node_with_payload(inserted_node[i].data, inserted_node[i].payload) self.assertIsNone(found_node) for j in range(i + 1, len(inserted_node)): found_node = tree.find_node_with_payload(inserted_node[j].data, inserted_node[j].payload) self.assertEqual(inserted_node[j], found_node) def testTheSameDataSearchAndRemove1(self): self.templateTheSameDataSearchAndRemove([[2], [2], [2], [2], [2]], [1, 2, 3, 4, 5]) def testTheSameDataSearchAndRemove1NumPy(self): self.templateTheSameDataSearchAndRemove(numpy.array([[2], [2], [2], [2], [2]]), [1, 2, 3, 4, 5]) def testTheSameDataSearchAndRemove2(self): self.templateTheSameDataSearchAndRemove([[-2.3], [-2.3], [-2.3], [-2.3], [-2.3]], [10, 11, 12, 13, 14]) def testTheSameDataSearchAndRemove2NumPy(self): self.templateTheSameDataSearchAndRemove(numpy.array([[-2.3], [-2.3], [-2.3], [-2.3], [-2.3]]), [10, 11, 12, 13, 14]) def testTheSameDataSearchAndRemove3(self): self.templateTheSameDataSearchAndRemove([[1.1, 2.1], [1.1, 2.1], [1.1, 2.1]], ['qwe', 'asd', 'zxc']) def testTheSameDataSearchAndRemove3NumPy(self): self.templateTheSameDataSearchAndRemove(numpy.array([[1.1, 2.1], [1.1, 2.1], [1.1, 2.1]]), ['qwe', 'asd', 'zxc']) def testTheSameDataSearchAndRemove4(self): self.templateTheSameDataSearchAndRemove([[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]], ['qwe', None]) def testTheSameDataSearchAndRemove4NumPy(self): self.templateTheSameDataSearchAndRemove(numpy.array([[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]), ['qwe', None]) def testTheSameDataSearchAndRemove5(self): self.templateTheSameDataSearchAndRemove([[2]], [None]) def testTheSameDataSearchAndRemove5NumPy(self): self.templateTheSameDataSearchAndRemove(numpy.array([[2]]), [None]) pyclustering-0.10.1.2/pyclustering/core/000077500000000000000000000000001375753423500201575ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/32-bit/000077500000000000000000000000001375753423500211575ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/32-bit/linux/000077500000000000000000000000001375753423500223165ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/32-bit/linux/.linux.info000077500000000000000000000000201375753423500244030ustar00rootroot00000000000000linux ccore x86 pyclustering-0.10.1.2/pyclustering/core/32-bit/macos/000077500000000000000000000000001375753423500222615ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/32-bit/macos/.macos.info000077500000000000000000000000201375753423500243110ustar00rootroot00000000000000macos ccore x86 pyclustering-0.10.1.2/pyclustering/core/32-bit/win/000077500000000000000000000000001375753423500217545ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/32-bit/win/.win.info000077500000000000000000000000221375753423500235010ustar00rootroot00000000000000windows ccore x86 pyclustering-0.10.1.2/pyclustering/core/64-bit/000077500000000000000000000000001375753423500211645ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/64-bit/linux/000077500000000000000000000000001375753423500223235ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/64-bit/linux/.linux.info000077500000000000000000000000201375753423500244100ustar00rootroot00000000000000linux ccore x64 pyclustering-0.10.1.2/pyclustering/core/64-bit/macos/000077500000000000000000000000001375753423500222665ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/64-bit/macos/.macos.info000077500000000000000000000000201375753423500243160ustar00rootroot00000000000000macos ccore x64 pyclustering-0.10.1.2/pyclustering/core/64-bit/win/000077500000000000000000000000001375753423500217615ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/64-bit/win/.win.info000077500000000000000000000000221375753423500235060ustar00rootroot00000000000000windows ccore x64 pyclustering-0.10.1.2/pyclustering/core/__init__.py000077500000000000000000000002701375753423500222720ustar00rootroot00000000000000"""! @brief Core module provides access to CCORE library (part of this project). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/pyclustering/core/agglomerative_wrapper.py000077500000000000000000000014541375753423500251260ustar00rootroot00000000000000"""! @brief CCORE Wrapper for agglomerative algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_size_t, c_double, POINTER; from pyclustering.core.wrapper import ccore_library; from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder; def agglomerative_algorithm(data, number_clusters, link): pointer_data = package_builder(data, c_double).create(); ccore = ccore_library.get(); ccore.agglomerative_algorithm.restype = POINTER(pyclustering_package); package = ccore.agglomerative_algorithm(pointer_data, c_size_t(number_clusters), c_size_t(link)); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; pyclustering-0.10.1.2/pyclustering/core/bsas_wrapper.py000077500000000000000000000014741375753423500232320ustar00rootroot00000000000000"""! @brief CCORE Wrapper for BSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def bsas(sample, amount, threshold, metric_pointer): pointer_data = package_builder(sample, c_double).create() ccore = ccore_library.get() ccore.bsas_algorithm.restype = POINTER(pyclustering_package) package = ccore.bsas_algorithm(pointer_data, c_size_t(amount), c_double(threshold), metric_pointer) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result[0], result[1]pyclustering-0.10.1.2/pyclustering/core/clique_wrapper.py000077500000000000000000000031241375753423500235560ustar00rootroot00000000000000"""! @brief CCORE Wrapper for CLIQUE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_builder, package_extractor class clique_package_indexer: CLIQUE_PACKAGE_INDEX_CLUSTERS = 0 CLIQUE_PACKAGE_INDEX_NOISE = 1 CLIQUE_PACKAGE_INDEX_LOGICAL_LOCATION = 2 CLIQUE_PACKAGE_INDEX_MAX_CORNER = 3 CLIQUE_PACKAGE_INDEX_MIN_CORNER = 4 CLIQUE_PACKAGE_INDEX_BLOCK_POINTS = 5 def clique(sample, intervals, threshold): pointer_data = package_builder(sample, c_double).create() ccore = ccore_library.get() ccore.clique_algorithm.restype = POINTER(pyclustering_package) package = ccore.clique_algorithm(pointer_data, c_size_t(intervals), c_size_t(threshold)) results = package_extractor(package).extract() ccore.free_pyclustering_package(package) if isinstance(results, bytes): raise RuntimeError(results.decode('utf-8')) return (results[clique_package_indexer.CLIQUE_PACKAGE_INDEX_CLUSTERS], results[clique_package_indexer.CLIQUE_PACKAGE_INDEX_NOISE], results[clique_package_indexer.CLIQUE_PACKAGE_INDEX_LOGICAL_LOCATION], results[clique_package_indexer.CLIQUE_PACKAGE_INDEX_MAX_CORNER], results[clique_package_indexer.CLIQUE_PACKAGE_INDEX_MIN_CORNER], results[clique_package_indexer.CLIQUE_PACKAGE_INDEX_BLOCK_POINTS]) pyclustering-0.10.1.2/pyclustering/core/converter.py000077500000000000000000000006511375753423500225450ustar00rootroot00000000000000"""! @brief Common converter from python types to C/C++. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_size_t def convert_data_type(data_type): if data_type == 'points': return c_size_t(0); elif data_type == 'distance_matrix': return c_size_t(1); else: raise TypeError("Unknown data type is specified '%s'." % data_type);pyclustering-0.10.1.2/pyclustering/core/cure_wrapper.py000077500000000000000000000035731375753423500232420ustar00rootroot00000000000000"""! @brief CCORE Wrapper for CURE algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER, c_void_p from pyclustering.core.wrapper import ccore_library; from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder; def cure_algorithm(sample, number_clusters, number_represent_points, compression): pointer_data = package_builder(sample, c_double).create(); ccore = ccore_library.get(); ccore.cure_algorithm.restype = POINTER(c_void_p); cure_data_pointer = ccore.cure_algorithm(pointer_data, c_size_t(number_clusters), c_size_t(number_represent_points), c_double(compression)); return cure_data_pointer; def cure_data_destroy(cure_data_pointer): ccore = ccore_library.get(); ccore.cure_data_destroy(cure_data_pointer); def cure_get_clusters(cure_data_pointer): ccore = ccore_library.get(); ccore.cure_get_clusters.restype = POINTER(pyclustering_package); package = ccore.cure_get_clusters(cure_data_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def cure_get_representors(cure_data_pointer): ccore = ccore_library.get(); ccore.cure_get_representors.restype = POINTER(pyclustering_package); package = ccore.cure_get_representors(cure_data_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def cure_get_means(cure_data_pointer): ccore = ccore_library.get(); ccore.cure_get_means.restype = POINTER(pyclustering_package); package = ccore.cure_get_means(cure_data_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result;pyclustering-0.10.1.2/pyclustering/core/dbscan_wrapper.py000077500000000000000000000017771375753423500235420ustar00rootroot00000000000000"""! @brief CCORE Wrapper for DBSCAN algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.converter import convert_data_type from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def dbscan(sample, eps, min_neighbors, data_type): pointer_data = package_builder(sample, c_double).create() c_data_type = convert_data_type(data_type) ccore = ccore_library.get() ccore.dbscan_algorithm.restype = POINTER(pyclustering_package) package = ccore.dbscan_algorithm(pointer_data, c_double(eps), c_size_t(min_neighbors), c_data_type) list_of_clusters = package_extractor(package).extract() ccore.free_pyclustering_package(package) noise = list_of_clusters[len(list_of_clusters) - 1] list_of_clusters.remove(noise) return list_of_clusters, noisepyclustering-0.10.1.2/pyclustering/core/definitions.py000077500000000000000000000022321375753423500230460ustar00rootroot00000000000000"""! @brief Common definition for CCORE. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import pyclustering.core as core import os import platform from sys import platform as _platform # Path to CCORE library - pyclustering core. PATH_PYCLUSTERING_CCORE_LIBRARY = None core_architecture = None if platform.architecture()[0] == "64bit": core_architecture = "64-bit" else: core_architecture = "32-bit" if (_platform == "linux") or (_platform == "linux2"): PATH_PYCLUSTERING_CCORE_LIBRARY = core.__path__[0] + os.sep + core_architecture + os.sep + "linux" + os.sep + "libpyclustering.so" elif _platform == "darwin": PATH_PYCLUSTERING_CCORE_LIBRARY = core.__path__[0] + os.sep + core_architecture + os.sep + "macos" + os.sep + "libpyclustering.so" elif _platform == "win32": PATH_PYCLUSTERING_CCORE_LIBRARY = core.__path__[0] + os.sep + core_architecture + os.sep + "win" + os.sep + "pyclustering.dll" elif _platform == "cygwin": PATH_PYCLUSTERING_CCORE_LIBRARY = core.__path__[0] + os.sep + core_architecture + os.sep + "win" + os.sep + "libpyclustering.so" pyclustering-0.10.1.2/pyclustering/core/elbow_wrapper.py000077500000000000000000000033671375753423500234150ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Elbow method. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_longlong, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_builder, package_extractor from enum import IntEnum class elbow_package_indexer: ELBOW_PACKAGE_INDEX_AMOUNT = 0 ELBOW_PACKAGE_INDEX_WCE = 1 class elbow_center_initializer(IntEnum): KMEANS_PLUS_PLUS = 0 RANDOM = 1 def elbow(sample, kmin, kmax, kstep, initializer, random_state): random_state = random_state or -1 pointer_data = package_builder(sample, c_double).create() ccore = ccore_library.get() if initializer == elbow_center_initializer.KMEANS_PLUS_PLUS: ccore.elbow_method_ikpp.restype = POINTER(pyclustering_package) package = ccore.elbow_method_ikpp(pointer_data, c_size_t(kmin), c_size_t(kmax), c_size_t(kstep), c_longlong(random_state)) elif initializer == elbow_center_initializer.RANDOM: ccore.elbow_method_irnd.restype = POINTER(pyclustering_package) package = ccore.elbow_method_irnd(pointer_data, c_size_t(kmin), c_size_t(kmax), c_size_t(kstep), c_longlong(random_state)) else: raise ValueError("Not supported type of center initializer '" + str(initializer) + "'.") results = package_extractor(package).extract() ccore.free_pyclustering_package(package) if isinstance(results, bytes): raise RuntimeError(results.decode('utf-8')) return (results[elbow_package_indexer.ELBOW_PACKAGE_INDEX_AMOUNT][0], results[elbow_package_indexer.ELBOW_PACKAGE_INDEX_WCE]) pyclustering-0.10.1.2/pyclustering/core/fcm_wrapper.py000077500000000000000000000017661375753423500230530ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Fuzzy C-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder class fcm_package_indexer: INDEX_CLUSTERS = 0 INDEX_CENTERS = 1 INDEX_MEMBERSHIP = 2 def fcm_algorithm(sample, centers, m, tolerance, itermax): pointer_data = package_builder(sample, c_double).create() pointer_centers = package_builder(centers, c_double).create() ccore = ccore_library.get() ccore.fcm_algorithm.restype = POINTER(pyclustering_package) package = ccore.fcm_algorithm(pointer_data, pointer_centers, c_double(m), c_double(tolerance), c_size_t(itermax)) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return resultpyclustering-0.10.1.2/pyclustering/core/gmeans_wrapper.py000077500000000000000000000016761375753423500235600ustar00rootroot00000000000000"""! @brief CCORE Wrapper for G-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, c_longlong, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def gmeans(sample, kinit, tolerance, repeat, kmax, random_state): random_state = random_state or -1 pointer_data = package_builder(sample, c_double).create() ccore = ccore_library.get() ccore.gmeans_algorithm.restype = POINTER(pyclustering_package) package = ccore.gmeans_algorithm(pointer_data, c_size_t(kinit), c_double(tolerance), c_size_t(repeat), c_longlong(kmax), c_longlong(random_state)) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result[0], result[1], result[2][0] pyclustering-0.10.1.2/pyclustering/core/hhn_wrapper.py000077500000000000000000000132011375753423500230460ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Hodgkin-Huxley oscillatory network for image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import *; from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder; class c_hhn_params(Structure): _fields_ = [ ("nu", c_double), ("gNa", c_double), ("gK", c_double), ("gL", c_double), ("vNa", c_double), ("vK", c_double), ("vL", c_double), ("vRest", c_double), ("Icn1", c_double), ("Icn2", c_double), ("Vsyninh", c_double), ("Vsynexc", c_double), ("alfa_inhibitory", c_double), ("betta_inhibitory", c_double), ("alfa_excitatory", c_double), ("betta_excitatory", c_double), ("w1", c_double), ("w2", c_double), ("w3", c_double), ("deltah", c_double), ("threshold", c_double), ("eps", c_double), ]; def hhn_create(size, params): c_params = c_hhn_params(); c_params.nu = params.nu; c_params.gNa = params.gNa; c_params.gK = params.gK; c_params.gL = params.gL; c_params.vNa = params.vNa; c_params.vK = params.vK; c_params.vL = params.vL; c_params.vRest = params.vRest; c_params.Icn1 = params.Icn1; c_params.Icn2 = params.Icn2; c_params.Vsyninh = params.Vsyninh; c_params.Vsynexc = params.Vsynexc; c_params.alfa_inhibitory = params.alfa_inhibitory; c_params.betta_inhibitory = params.betta_inhibitory; c_params.alfa_excitatory = params.alfa_excitatory; c_params.betta_excitatory = params.betta_excitatory; c_params.w1 = params.w1; c_params.w2 = params.w2; c_params.w3 = params.w3; c_params.deltah = params.deltah; c_params.threshold = params.threshold; c_params.eps = params.eps; ccore = ccore_library.get(); ccore.hhn_create.restype = POINTER(c_void_p); hhn_network_pointer = ccore.hhn_create(c_size_t(size), pointer(c_params)); return hhn_network_pointer; def hhn_destroy(hhn_network_pointer): ccore = ccore_library.get(); ccore.hhn_destroy(hhn_network_pointer); def hhn_dynamic_create(collect_membrane, collect_active_cond_sodium, collect_inactive_cond_sodium, collect_active_cond_potassium): ccore = ccore_library.get(); ccore.hhn_dynamic_create.restype = POINTER(c_void_p); hhn_dynamic_pointer = ccore.hhn_dynamic_create(c_bool(collect_membrane), c_bool(collect_active_cond_sodium), c_bool(collect_inactive_cond_sodium), c_bool(collect_active_cond_potassium)); return hhn_dynamic_pointer; def hhn_dynamic_destroy(hhn_dynamic_pointer): ccore = ccore_library.get(); ccore.hhn_dynamic_destroy(hhn_dynamic_pointer); def hhn_simulate(hhn_network_pointer, steps, time, solution, stimulus, ccore_hhn_dynamic_pointer): ccore = ccore_library.get(); c_stimulus = package_builder(stimulus, c_double).create(); ccore.hhn_simulate(hhn_network_pointer, c_size_t(steps), c_double(time), c_size_t(solution), c_stimulus, ccore_hhn_dynamic_pointer); def hhn_dynamic_get_peripheral_evolution(ccore_hhn_dynamic_pointer, index_collection): ccore = ccore_library.get(); ccore.hhn_dynamic_get_peripheral_evolution.restype = POINTER(pyclustering_package); dynamic_package = ccore.hhn_dynamic_get_peripheral_evolution(ccore_hhn_dynamic_pointer, c_size_t(index_collection)); result = package_extractor(dynamic_package).extract(); ccore.free_pyclustering_package(dynamic_package); return result; def hhn_dynamic_get_central_evolution(ccore_hhn_dynamic_pointer, index_collection): ccore = ccore_library.get(); ccore.hhn_dynamic_get_central_evolution.restype = POINTER(pyclustering_package); dynamic_package = ccore.hhn_dynamic_get_central_evolution(ccore_hhn_dynamic_pointer, c_size_t(index_collection)); result = package_extractor(dynamic_package).extract(); ccore.free_pyclustering_package(dynamic_package); return result; def hhn_dynamic_get_time(ccore_hhn_dynamic_pointer): ccore = ccore_library.get(); ccore.hhn_dynamic_get_time.restype = POINTER(pyclustering_package); dynamic_package = ccore.hhn_dynamic_get_time(ccore_hhn_dynamic_pointer); result = package_extractor(dynamic_package).extract(); ccore.free_pyclustering_package(dynamic_package); return result; def hhn_dynamic_write(ccore_hhn_dynamic_pointer, filename): ccore = ccore_library.get(); byte_filename = filename.encode('utf-8'); ccore.hhn_dynamic_write(ccore_hhn_dynamic_pointer, c_char_p(byte_filename)); def hhn_dynamic_read(filename): ccore = ccore_library.get(); byte_filename = filename.encode('utf-8'); ccore.hhn_dynamic_read.restype = POINTER(c_void_p); hhn_dynamic_pointer = ccore.hhn_dynamic_read(byte_filename); return hhn_dynamic_pointer;pyclustering-0.10.1.2/pyclustering/core/hsyncnet_wrapper.py000077500000000000000000000025021375753423500241260ustar00rootroot00000000000000"""! @brief CCORE Wrapper for hsyncnet oscillatory based clustering algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import *; from pyclustering.core.pyclustering_package import package_builder def hsyncnet_create_network(sample, number_clusters, initial_phases, initial_neighbors, increase_persent): data_package = package_builder(sample, c_double).create(); ccore = ccore_library.get(); ccore.hsyncnet_create_network.restype = POINTER(c_void_p); pointer_network = ccore.hsyncnet_create_network(data_package, c_uint(number_clusters), c_uint(initial_phases), c_uint(initial_neighbors), c_double(increase_persent)); return pointer_network; def hsyncnet_destroy_network(pointer_network): ccore = ccore_library.get(); ccore.hsyncnet_destroy_network(pointer_network); def hsyncnet_process(network_pointer, order, solution, collect_dynamic): ccore = ccore_library.get(); ccore.hsyncnet_process.restype = POINTER(c_void_p); return ccore.hsyncnet_process(network_pointer, c_double(order), c_uint(solution), c_bool(collect_dynamic)); def hsyncnet_analyser_destroy(pointer_analyser): ccore = ccore_library.get(); ccore.syncnet_analyser_destroy(pointer_analyser);pyclustering-0.10.1.2/pyclustering/core/kmeans_wrapper.py000077500000000000000000000017561375753423500235630ustar00rootroot00000000000000"""! @brief CCORE Wrapper for K-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_bool, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def kmeans(sample, centers, tolerance, itermax, observe, metric_pointer): pointer_data = package_builder(sample, c_double).create() pointer_centers = package_builder(centers, c_double).create() ccore = ccore_library.get() ccore.kmeans_algorithm.restype = POINTER(pyclustering_package) package = ccore.kmeans_algorithm(pointer_data, pointer_centers, c_double(tolerance), c_size_t(itermax), c_bool(observe), metric_pointer) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return resultpyclustering-0.10.1.2/pyclustering/core/kmedians_wrapper.py000077500000000000000000000016371375753423500240760ustar00rootroot00000000000000"""! @brief CCORE Wrapper for K-Medians algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def kmedians(sample, centers, tolerance, itermax, metric_pointer): pointer_data = package_builder(sample, c_double).create() pointer_centers = package_builder(centers, c_double).create() ccore = ccore_library.get() ccore.kmedians_algorithm.restype = POINTER(pyclustering_package) package = ccore.kmedians_algorithm(pointer_data, pointer_centers, c_double(tolerance), c_size_t(itermax), metric_pointer) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result[0], result[1]pyclustering-0.10.1.2/pyclustering/core/kmedoids_wrapper.py000077500000000000000000000020751375753423500240770ustar00rootroot00000000000000"""! @brief CCORE Wrapper for K-Medoids algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.converter import convert_data_type from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def kmedoids(sample, medoids, tolerance, itermax, metric_pointer, data_type): pointer_data = package_builder(sample, c_double).create() medoids_package = package_builder(medoids, c_size_t).create() c_data_type = convert_data_type(data_type) ccore = ccore_library.get() ccore.kmedoids_algorithm.restype = POINTER(pyclustering_package) package = ccore.kmedoids_algorithm(pointer_data, medoids_package, c_double(tolerance), c_size_t(itermax), metric_pointer, c_data_type) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result[0], result[1] pyclustering-0.10.1.2/pyclustering/core/legion_wrapper.py000077500000000000000000000104751375753423500235600ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Local Excitatory Global Inhibitory Oscillatory Network (LEGION) @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import * from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder class c_legion_parameters(Structure): _fields_ = [ ("eps", c_double), ("alpha", c_double), ("gamma", c_double), ("betta", c_double), ("lamda", c_double), ("teta", c_double), ("teta_x", c_double), ("teta_p", c_double), ("teta_xz", c_double), ("teta_zx", c_double), ("T", c_double), ("mu", c_double), ("Wz", c_double), ("Wt", c_double), ("fi", c_double), ("ro", c_double), ("I", c_double), ("ENABLE_POTENTIONAL", c_bool) ]; def legion_create(size, conn_type, params): ccore = ccore_library.get(); c_params = c_legion_parameters(); c_params.eps = params.eps; c_params.alpha = params.alpha; c_params.gamma = params.gamma; c_params.betta = params.betta; c_params.lamda = params.lamda; c_params.teta = params.teta; c_params.teta_x = params.teta_x; c_params.teta_p = params.teta_p; c_params.teta_xz = params.teta_xz; c_params.T = params.T; c_params.mu = params.mu; c_params.Wz = params.Wz; c_params.Wt = params.Wt; c_params.fi = params.fi; c_params.ro = params.ro; c_params.I = params.I; c_params.ENABLE_POTENTIONAL = params.ENABLE_POTENTIONAL; ccore.legion_create.restype = POINTER(c_void_p); legion_network_pointer = ccore.legion_create(c_uint(size), c_uint(conn_type), pointer(c_params)); return legion_network_pointer; def legion_destroy(legion_network_pointer): ccore = ccore_library.get(); ccore.legion_destroy(legion_network_pointer); def legion_simulate(legion_network_pointer, steps, time, solver, collect_dynamic, stimulus): ccore = ccore_library.get(); c_stimulus = package_builder(stimulus, c_double).create(); ccore.legion_simulate.restype = POINTER(c_void_p); return ccore.legion_simulate(legion_network_pointer, c_uint(steps), c_double(time), c_uint(solver), c_bool(collect_dynamic), c_stimulus); def legion_get_size(legion_network_pointer): ccore = ccore_library.get(); ccore.legion_get_size.restype = c_size_t; return ccore.legion_get_size(legion_network_pointer); def legion_dynamic_destroy(legion_dynamic_pointer): ccore = ccore_library.get(); ccore.legion_dynamic_destroy(legion_dynamic_pointer); def legion_dynamic_get_output(legion_dynamic_pointer): ccore = ccore_library.get(); ccore.legion_dynamic_get_output.restype = POINTER(pyclustering_package); package = ccore.legion_dynamic_get_output(legion_dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def legion_dynamic_get_inhibitory_output(legion_dynamic_pointer): ccore = ccore_library.get(); ccore.legion_dynamic_get_inhibitory_output.restype = POINTER(pyclustering_package); package = ccore.legion_dynamic_get_inhibitory_output(legion_dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def legion_dynamic_get_time(legion_dynamic_pointer): ccore = ccore_library.get(); ccore.legion_dynamic_get_time.restype = POINTER(pyclustering_package); package = ccore.legion_dynamic_get_time(legion_dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def legion_dynamic_get_size(legion_dynamic_pointer): ccore = ccore_library.get(); ccore.legion_dynamic_get_size.restype = c_size_t; return ccore.legion_dynamic_get_size(legion_dynamic_pointer); pyclustering-0.10.1.2/pyclustering/core/mbsas_wrapper.py000077500000000000000000000015121375753423500234000ustar00rootroot00000000000000"""! @brief CCORE Wrapper for MBSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER; from pyclustering.core.wrapper import ccore_library; from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder; def mbsas(sample, amount, threshold, metric_pointer): pointer_data = package_builder(sample, c_double).create(); ccore = ccore_library.get(); ccore.mbsas_algorithm.restype = POINTER(pyclustering_package); package = ccore.mbsas_algorithm(pointer_data, c_size_t(amount), c_double(threshold), metric_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result[0], result[1];pyclustering-0.10.1.2/pyclustering/core/metric_wrapper.py000077500000000000000000000036351375753423500235660ustar00rootroot00000000000000"""! @brief CCORE Wrapper for metrics. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import package_builder, package_extractor, pyclustering_package from ctypes import c_double, c_size_t, POINTER, c_void_p, CFUNCTYPE from pyclustering.utils.metric import type_metric metric_callback = CFUNCTYPE(c_double, POINTER(pyclustering_package), POINTER(pyclustering_package)) class metric_wrapper: def __init__(self, type_metric_code, arguments, func): self.__func = lambda p1, p2: func(package_extractor(p1).extract(), package_extractor(p2).extract()) package_arguments = package_builder(arguments, c_double).create() ccore = ccore_library.get() ccore.metric_create.restype = POINTER(c_void_p) self.__pointer = ccore.metric_create(c_size_t(type_metric_code), package_arguments, metric_callback(self.__func)) def __del__(self): if self.__pointer: ccore = ccore_library.get() ccore.metric_destroy(self.__pointer) def __call__(self, point1, point2): point_package1 = package_builder(point1, c_double).create() point_package2 = package_builder(point2, c_double).create() ccore = ccore_library.get() ccore.metric_calculate.restype = c_double return ccore.metric_calculate(self.__pointer, point_package1, point_package2) def get_pointer(self): return self.__pointer @staticmethod def create_instance(metric): mtype = metric.get_type() arguments = [] if mtype == type_metric.MINKOWSKI: arguments = [metric.get_arguments().get('degree')] elif mtype == type_metric.GOWER: arguments = metric.get_arguments().get('max_range') return metric_wrapper(mtype, arguments, metric.get_function())pyclustering-0.10.1.2/pyclustering/core/optics_wrapper.py000077500000000000000000000037071375753423500236040ustar00rootroot00000000000000"""! @brief CCORE Wrapper for OPTICS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER from pyclustering.core.converter import convert_data_type from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_builder, package_extractor class optics_package_indexer: OPTICS_PACKAGE_INDEX_CLUSTERS = 0 OPTICS_PACKAGE_INDEX_NOISE = 1 OPTICS_PACKAGE_INDEX_ORDERING = 2 OPTICS_PACKAGE_INDEX_RADIUS = 3 OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_INDEX = 4 OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_CORE_DISTANCE = 5 OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_REACHABILITY_DISTANCE = 6 def optics(sample, radius, minimum_neighbors, amount_clusters, data_type): amount = amount_clusters if amount is None: amount = 0 pointer_data = package_builder(sample, c_double).create() c_data_type = convert_data_type(data_type) ccore = ccore_library.get() ccore.optics_algorithm.restype = POINTER(pyclustering_package) package = ccore.optics_algorithm(pointer_data, c_double(radius), c_size_t(minimum_neighbors), c_size_t(amount), c_data_type) results = package_extractor(package).extract() ccore.free_pyclustering_package(package) return (results[optics_package_indexer.OPTICS_PACKAGE_INDEX_CLUSTERS], results[optics_package_indexer.OPTICS_PACKAGE_INDEX_NOISE], results[optics_package_indexer.OPTICS_PACKAGE_INDEX_ORDERING], results[optics_package_indexer.OPTICS_PACKAGE_INDEX_RADIUS][0], results[optics_package_indexer.OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_INDEX], results[optics_package_indexer.OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_CORE_DISTANCE], results[optics_package_indexer.OPTICS_PACKAGE_INDEX_OPTICS_OBJECTS_REACHABILITY_DISTANCE])pyclustering-0.10.1.2/pyclustering/core/pcnn_wrapper.py000077500000000000000000000100771375753423500232370ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Pulse Coupled Neural Network (PCNN) @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import *; from pyclustering.core.pyclustering_package import package_builder, package_extractor, pyclustering_package; class c_pcnn_parameters(Structure): _fields_ = [ ("VF", c_double), ("VL", c_double), ("VT", c_double), ("AF", c_double), ("AL", c_double), ("AT", c_double), ("W", c_double), ("M", c_double), ("B", c_double), ("FAST_LINKING", c_bool) ]; def pcnn_create(size, conn_type, height, width, params): ccore = ccore_library.get(); c_parameters = c_pcnn_parameters(); c_parameters.VF = params.VF; c_parameters.VL = params.VL; c_parameters.VT = params.VT; c_parameters.AF = params.AF; c_parameters.AL = params.AL; c_parameters.AT = params.AT; c_parameters.W = params.W; c_parameters.M = params.M; c_parameters.FAST_LINKING = params.FAST_LINKING; ccore.pcnn_create.restype = POINTER(c_void_p); pcnn_pointer = ccore.pcnn_create(c_uint(size), c_uint(conn_type), c_uint(height), c_uint(width), pointer(c_parameters)); return pcnn_pointer; def pcnn_destroy(network_pointer): ccore = ccore_library.get(); ccore.pcnn_destroy(network_pointer); def pcnn_simulate(network_pointer, steps, stimulus): ccore = ccore_library.get(); c_stimulus = package_builder(stimulus, c_double).create(); ccore.pcnn_simulate.restype = POINTER(c_void_p); return ccore.pcnn_simulate(network_pointer, c_uint(steps), c_stimulus); def pcnn_get_size(network_pointer): ccore = ccore_library.get(); ccore.pcnn_get_size.restype = c_size_t; return ccore.pcnn_get_size(network_pointer); def pcnn_dynamic_destroy(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_destroy(dynamic_pointer); def pcnn_dynamic_allocate_sync_ensembles(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_allocate_sync_ensembles.restype = POINTER(pyclustering_package); package = ccore.pcnn_dynamic_allocate_sync_ensembles(dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def pcnn_dynamic_allocate_spike_ensembles(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_allocate_spike_ensembles.restype = POINTER(pyclustering_package); package = ccore.pcnn_dynamic_allocate_spike_ensembles(dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def pcnn_dynamic_allocate_time_signal(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_allocate_time_signal.restype = POINTER(pyclustering_package); package = ccore.pcnn_dynamic_allocate_time_signal(dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def pcnn_dynamic_get_output(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_get_output.restype = POINTER(pyclustering_package); package = ccore.pcnn_dynamic_get_output(dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def pcnn_dynamic_get_time(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_get_time.restype = POINTER(pyclustering_package); package = ccore.pcnn_dynamic_get_time(dynamic_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def pcnn_dynamic_get_size(dynamic_pointer): ccore = ccore_library.get(); ccore.pcnn_dynamic_get_time.restype = c_size_t; return ccore.pcnn_dynamic_get_size(dynamic_pointer); pyclustering-0.10.1.2/pyclustering/core/pyclustering_package.py000077500000000000000000000246611375753423500247500ustar00rootroot00000000000000"""! @brief Pyclustering package that is used to exchange between python core and 'ccore'. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import * import collections.abc import numpy class pyclustering_package(Structure): """! @brief pyclustering_package description in memory. @details Represents following C++ structure: typedef struct pyclustering_package { std::size_t size; unsigned int type; void * data; } """ _fields_ = [("size", c_size_t), ("type", c_uint), ("data", POINTER(c_void_p))] class pyclustering_type_data: """! @brief Contains constants that defines type of package. """ PYCLUSTERING_TYPE_INT = 0 PYCLUSTERING_TYPE_UNSIGNED_INT = 1 PYCLUSTERING_TYPE_FLOAT = 2 PYCLUSTERING_TYPE_DOUBLE = 3 PYCLUSTERING_TYPE_LONG = 4 PYCLUSTERING_TYPE_CHAR = 5 PYCLUSTERING_TYPE_LIST = 6 PYCLUSTERING_TYPE_SIZE_T = 7 PYCLUSTERING_TYPE_WCHAR_T = 8 PYCLUSTERING_TYPE_UNDEFINED = 9 __CTYPE_PYCLUSTERING_MAP = { c_int: PYCLUSTERING_TYPE_INT, c_uint: PYCLUSTERING_TYPE_UNSIGNED_INT, c_float: PYCLUSTERING_TYPE_FLOAT, c_double: PYCLUSTERING_TYPE_DOUBLE, c_long: PYCLUSTERING_TYPE_LONG, c_char: PYCLUSTERING_TYPE_CHAR, POINTER(pyclustering_package): PYCLUSTERING_TYPE_LIST, c_size_t: PYCLUSTERING_TYPE_SIZE_T, c_wchar: PYCLUSTERING_TYPE_WCHAR_T, None: PYCLUSTERING_TYPE_UNDEFINED } __PYCLUSTERING_CTYPE_MAP = { PYCLUSTERING_TYPE_INT: c_int, PYCLUSTERING_TYPE_UNSIGNED_INT: c_uint, PYCLUSTERING_TYPE_FLOAT: c_float, PYCLUSTERING_TYPE_DOUBLE: c_double, PYCLUSTERING_TYPE_LONG: c_long, PYCLUSTERING_TYPE_CHAR: c_char, PYCLUSTERING_TYPE_LIST: POINTER(pyclustering_package), PYCLUSTERING_TYPE_SIZE_T: c_size_t, PYCLUSTERING_TYPE_WCHAR_T: c_wchar, PYCLUSTERING_TYPE_UNDEFINED: None } @staticmethod def get_ctype(pyclustering_package_type): """! @return (ctype) Return ctype that corresponds to pyclustering type data. """ return pyclustering_type_data.__PYCLUSTERING_CTYPE_MAP[pyclustering_package_type] @staticmethod def get_pyclustering_type(data_ctype): """! @return (unit) Return pyclustering data type that corresponds to ctype. """ return pyclustering_type_data.__CTYPE_PYCLUSTERING_MAP[data_ctype] class package_builder: """! @brief Package builder provides service to create 'pyclustering_package' from data that is stored in 'list' container. """ def __init__(self, dataset, c_data_type=None): """! @brief Initialize package builder object by dataset. @details String data is packed as it is without encoding. If string encoding is required then it should be provided already encoded, for example in case of `utf-8`: @code encoded_string = "String to pack".encode('utf-8') pyclustering_package = package_builder(encoded_string) @endcode @param[in] dataset (list): Data that should be packed in 'pyclustering_package'. @param[in] c_data_type (ctype.type): C-type data that is used to store data in the package. """ self.__dataset = dataset self.__c_data_type = c_data_type def create(self): """! @brief Performs packing procedure of the data to the package. @return (pointer) ctype-pointer to pyclustering package. """ return self.__create_package(self.__dataset) def __is_container_type(self, value): return isinstance(value, collections.abc.Iterable) def __get_type(self, pyclustering_data_type): if self.__c_data_type is None: return pyclustering_data_type return self.__c_data_type def __create_package(self, dataset): dataset_package = pyclustering_package() if isinstance(dataset, str): return self.__create_package_string(dataset_package, dataset) if isinstance(dataset, numpy.matrix): return self.__create_package_numpy_matrix(dataset_package, dataset) dataset_package.size = len(dataset) if len(dataset) == 0: dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_UNDEFINED dataset_package.data = None return pointer(dataset_package) c_data_type = self.__fill_type(dataset_package, dataset) self.__fill_data(dataset_package, c_data_type, dataset) return pointer(dataset_package) def __fill_dataset_type(self, dataset_package, dataset): if self.__is_container_type(dataset[0]): dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_LIST elif isinstance(dataset[0], int): dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_LONG elif isinstance(dataset[0], float): dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_DOUBLE else: raise NameError("Not supported type of pyclustering package.") return pyclustering_type_data.get_ctype(dataset_package.type) def __fill_specify_type(self, dataset_package): dataset_package.type = pyclustering_type_data.get_pyclustering_type(self.__c_data_type) return self.__c_data_type def __fill_type(self, dataset_package, dataset): if self.__is_container_type(dataset[0]): dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_LIST return None if self.__c_data_type is None: return self.__fill_dataset_type(dataset_package, dataset) return self.__fill_specify_type(dataset_package) def __fill_data(self, dataset_package, c_data_type, dataset): if dataset_package.type == pyclustering_type_data.PYCLUSTERING_TYPE_LIST: package_data = (POINTER(pyclustering_package) * len(dataset))() for index in range(len(dataset)): package_data[index] = self.__create_package(dataset[index]) dataset_package.data = cast(package_data, POINTER(c_void_p)) else: array_object = (c_data_type * len(dataset))(*dataset) dataset_package.data = cast(array_object, POINTER(c_void_p)) def __create_package_numpy_matrix(self, dataset_package, dataset): (rows, cols) = dataset.shape dataset_package.size = rows dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_LIST package_data = (POINTER(pyclustering_package) * rows)() for row_index in range(rows): array_package = pyclustering_package() array_package.size = cols array_package.type = pyclustering_type_data.get_pyclustering_type(self.__c_data_type) array_object = (self.__c_data_type * cols)() for col_index in range(cols): array_object[col_index] = self.__c_data_type(dataset[row_index, col_index]) array_package.data = cast(array_object, POINTER(c_void_p)) package_data[row_index] = pointer(array_package) dataset_package.data = cast(package_data, POINTER(c_void_p)) return pointer(dataset_package) def __create_package_string(self, dataset_package, string_value): dataset_package.size = len(string_value) dataset_package.type = pyclustering_type_data.PYCLUSTERING_TYPE_CHAR dataset_package.data = cast(string_value, POINTER(c_void_p)) return pointer(dataset_package) class package_extractor: """! @brief Package extractor provides servies to unpack pyclustering package. """ def __init__(self, package_pointer): """! @brief Initialize package extractor object by ctype-pointer to 'pyclustering_package'. @param[in] package_pointer (pointer): ctype-pointer to 'pyclustering_package' that should be used for unpacking. """ self.__package_pointer = package_pointer def extract(self): """! @brief Performs unpacking procedure of the pyclustering package to the data. @return (list) Extracted data from the pyclustering package. """ return self.__extract_data(self.__package_pointer) def __extract_data(self, ccore_package_pointer): if ccore_package_pointer == 0: return [] pointer_package = cast(ccore_package_pointer, POINTER(pyclustering_package)) return self.__unpack_pointer_data(pointer_package) def __unpack_data(self, pointer_package, pointer_data, type_package): if type_package == pyclustering_type_data.PYCLUSTERING_TYPE_CHAR: pointer_string = cast(pointer_data, c_char_p) return pointer_string.value elif type_package == pyclustering_type_data.PYCLUSTERING_TYPE_WCHAR_T: raise NotImplementedError("Data type 'wchar_t' is not supported.") result = [] append_element = lambda container, item: container.append(item) for index in range(0, pointer_package[0].size): if type_package == pyclustering_type_data.PYCLUSTERING_TYPE_LIST: pointer_package = cast(pointer_data[index], (POINTER(pyclustering_package))) append_element(result, self.__extract_data(pointer_package)) else: append_element(result, pointer_data[index]) return result def __unpack_pointer_data(self, pointer_package): current_package = pointer_package[0] type_package = current_package.type if current_package.size == 0: return [] pointer_data = cast(current_package.data, POINTER(pyclustering_type_data.get_ctype(type_package))) return self.__unpack_data(pointer_package, pointer_data, type_package) pyclustering-0.10.1.2/pyclustering/core/rock_wrapper.py000077500000000000000000000031631375753423500232350ustar00rootroot00000000000000"""! @brief CCORE Wrapper for ROCK algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_size_t, POINTER; from pyclustering.core.wrapper import ccore_library; from pyclustering.core.pyclustering_package import pyclustering_package, package_builder, package_extractor; def rock(sample, eps, number_clusters, threshold): """ @brief Clustering algorithm ROCK returns allocated clusters and noise that are consisted from input data. @details Calculation is performed via CCORE (C/C++ part of the pyclustering)." @param[in] sample: input data - list of points where each point is represented by list of coordinates. @param[in] eps: connectivity radius (similarity threshold), points are neighbors if distance between them is less than connectivity radius. @param[in] number_clusters: defines number of clusters that should be allocated from the input data set. @param[in] threshold: value that defines degree of normalization that influences on choice of clusters for merging during processing. @return List of allocated clusters, each cluster contains indexes of objects in list of data. """ pointer_data = package_builder(sample, c_double).create(); ccore = ccore_library.get(); ccore.rock_algorithm.restype = POINTER(pyclustering_package); package = ccore.rock_algorithm(pointer_data, c_double(eps), c_size_t(number_clusters), c_double(threshold)); list_of_clusters = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return list_of_clusters;pyclustering-0.10.1.2/pyclustering/core/silhouette_wrapper.py000077500000000000000000000040371375753423500244650ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Silhouette method and Silhouette K-Search algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_longlong, c_size_t, POINTER from pyclustering.core.converter import convert_data_type from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_builder, package_extractor class silhouette_ksearch_package_indexer: SILHOUETTE_KSEARCH_PACKAGE_INDEX_AMOUNT = 0 SILHOUETTE_KSEARCH_PACKAGE_INDEX_SCORE = 1 SILHOUETTE_KSEARCH_PACKAGE_INDEX_SCORES = 2 def silhoeutte(sample, clusters, pointer_metric, data_type): pointer_data = package_builder(sample, c_double).create() pointer_clusters = package_builder(clusters, c_size_t).create() c_data_type = convert_data_type(data_type) ccore = ccore_library.get() ccore.silhouette_algorithm.restype = POINTER(pyclustering_package) package = ccore.silhouette_algorithm(pointer_data, pointer_clusters, pointer_metric, c_data_type) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result def silhoeutte_ksearch(sample, kmin, kmax, allocator, random_state): random_state = random_state or -1 pointer_data = package_builder(sample, c_double).create() ccore = ccore_library.get() ccore.silhouette_ksearch_algorithm.restype = POINTER(pyclustering_package) package = ccore.silhouette_ksearch_algorithm(pointer_data, c_size_t(kmin), c_size_t(kmax), c_size_t(allocator), c_longlong(random_state)) results = package_extractor(package).extract() ccore.free_pyclustering_package(package) return (results[silhouette_ksearch_package_indexer.SILHOUETTE_KSEARCH_PACKAGE_INDEX_AMOUNT][0], results[silhouette_ksearch_package_indexer.SILHOUETTE_KSEARCH_PACKAGE_INDEX_SCORE][0], results[silhouette_ksearch_package_indexer.SILHOUETTE_KSEARCH_PACKAGE_INDEX_SCORES]) pyclustering-0.10.1.2/pyclustering/core/som_wrapper.py000077500000000000000000000166241375753423500231030ustar00rootroot00000000000000"""! @brief CCORE Wrapper for Self-Organized Feature Map @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import Structure, c_longlong, c_uint, c_size_t, c_double, c_void_p, pointer, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_builder, package_extractor class c_som_parameters(Structure): """! @brief Description of SOM parameters in memory. @details The following memory mapping is used in order to store the structure: @code struct som_params { unsigned int init_type; double init_radius; double init_learn_rate; double adaptation_threshold; long long random_state; }; @endcode """ _fields_ = [("init_type", c_uint), ("init_radius", c_double), ("init_learn_rate", c_double), ("adaptation_threshold", c_double), ("random_state", c_longlong)] def som_create(rows, cols, conn_type, parameters): """! @brief Create of self-organized map using C++ pyclustering library. @param[in] rows (uint): Number of neurons in the column (number of rows). @param[in] cols (uint): Number of neurons in the row (number of columns). @param[in] conn_type (type_conn): Type of connection between oscillators in the network (grid four, grid eight, honeycomb, function neighbour). @param[in] parameters (som_parameters): Other specific parameters. @return (POINTER) C-pointer to object of self-organized feature in memory. """ ccore = ccore_library.get() c_params = c_som_parameters() c_params.init_type = parameters.init_type c_params.init_radius = parameters.init_radius c_params.init_learn_rate = parameters.init_learn_rate c_params.adaptation_threshold = parameters.adaptation_threshold c_params.random_state = parameters.random_state or -1 ccore.som_create.restype = POINTER(c_void_p) som_pointer = ccore.som_create(c_uint(rows), c_uint(cols), c_uint(conn_type), pointer(c_params)) return som_pointer def som_load(som_pointer, weights, award, capture_objects): """! @brief Load dump of the network to SOM. @details Initialize SOM using existed weights, amount of captured objects by each neuron, captured objects by each neuron. Initialization is not performed if weights are empty. @param[in] som_pointer (POINTER): pointer to object of self-organized map. @param[in] weights (list): weights that should assigned to neurons. @param[in] awards (list): amount of captured objects by each neuron. @param[in] capture_objects (list): captured objects by each neuron. """ if len(weights) == 0: return ccore = ccore_library.get() package_weights = package_builder(weights, c_double).create() package_award = package_builder(award, c_size_t).create() package_capture_objects = package_builder(capture_objects, c_size_t).create() ccore.som_load(som_pointer, package_weights, package_award, package_capture_objects) def som_destroy(som_pointer): """! @brief Destroys self-organized map. @param[in] som_pointer (POINTER): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_destroy(som_pointer) def som_train(som_pointer, data, epochs, autostop): """! @brief Trains self-organized feature map (SOM) using CCORE pyclustering library. @param[in] data (list): Input data - list of points where each point is represented by list of features, for example coordinates. @param[in] epochs (uint): Number of epochs for training. @param[in] autostop (bool): Automatic termination of learining process when adaptation is not occurred. @return (uint) Number of learining iterations. """ pointer_data = package_builder(data, c_double).create() ccore = ccore_library.get() ccore.som_train.restype = c_size_t return ccore.som_train(som_pointer, pointer_data, c_uint(epochs), autostop) def som_simulate(som_pointer, pattern): """! @brief Processes input pattern (no learining) and returns index of neuron-winner. @details Using index of neuron winner catched object can be obtained using property capture_objects. @param[in] som_pointer (c_pointer): pointer to object of self-organized map. @param[in] pattern (list): input pattern. @return Returns index of neuron-winner. """ pointer_data = package_builder(pattern, c_double).create() ccore = ccore_library.get() ccore.som_simulate.restype = c_size_t return ccore.som_simulate(som_pointer, pointer_data) def som_get_winner_number(som_pointer): """! @brief Returns of number of winner at the last step of learning process. @param[in] som_pointer (c_pointer): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_get_winner_number.restype = c_size_t return ccore.som_get_winner_number(som_pointer) def som_get_size(som_pointer): """! @brief Returns size of self-organized map (number of neurons). @param[in] som_pointer (c_pointer): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_get_size.restype = c_size_t return ccore.som_get_size(som_pointer) def som_get_capture_objects(som_pointer): """! @brief Returns list of indexes of captured objects by each neuron. @param[in] som_pointer (c_pointer): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_get_capture_objects.restype = POINTER(pyclustering_package) package = ccore.som_get_capture_objects(som_pointer) result = package_extractor(package).extract() return result def som_get_weights(som_pointer): """! @brief Returns list of weights of each neuron. @param[in] som_pointer (c_pointer): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_get_weights.restype = POINTER(pyclustering_package) package = ccore.som_get_weights(som_pointer) result = package_extractor(package).extract() return result def som_get_awards(som_pointer): """! @brief Returns list of amount of captured objects by each neuron. @param[in] som_pointer (c_pointer): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_get_awards.restype = POINTER(pyclustering_package) package = ccore.som_get_awards(som_pointer) result = package_extractor(package).extract() return result def som_get_neighbors(som_pointer): """! @brief Returns list of indexes of neighbors of each neuron. @param[in] som_pointer (c_pointer): pointer to object of self-organized map. """ ccore = ccore_library.get() ccore.som_get_neighbors.restype = POINTER(pyclustering_package) package = ccore.som_get_neighbors(som_pointer) result = package_extractor(package).extract() return resultpyclustering-0.10.1.2/pyclustering/core/sync_wrapper.py000077500000000000000000000126451375753423500232600ustar00rootroot00000000000000"""! @brief CCORE Wrapper for oscillatory neural network based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import * from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor def sync_create_network(num_osc, weight, frequency, type_conn, initial_phases): ccore = ccore_library.get() ccore.sync_create_network.restype = POINTER(c_void_p) pointer_network = ccore.sync_create_network(c_uint(num_osc), c_double(weight), c_double(frequency), c_uint(type_conn), c_uint(initial_phases)) return pointer_network def sync_get_size(pointer_network): ccore = ccore_library.get() ccore.sync_get_size.restype = c_size_t return ccore.sync_get_size(pointer_network) def sync_destroy_network(pointer_network): ccore = ccore_library.get() ccore.sync_destroy_network(pointer_network) def sync_simulate_static(pointer_network, steps, time, solution, collect_dynamic): ccore = ccore_library.get() ccore.sync_simulate_static.restype = POINTER(c_void_p) return ccore.sync_simulate_static(pointer_network, c_uint(steps), c_double(time), c_uint(solution), c_bool(collect_dynamic)) def sync_simulate_dynamic(pointer_network, order, solution, collect_dynamic, step, int_step, threshold_changes): ccore = ccore_library.get() ccore.sync_simulate_dynamic.restype = POINTER(c_void_p) return ccore.sync_simulate_dynamic(pointer_network, c_double(order), c_uint(solution), c_bool(collect_dynamic), c_double(step), c_double(int_step), c_double(threshold_changes)) def sync_order(pointer_network): ccore = ccore_library.get() ccore.sync_order.restype = c_double return ccore.sync_order(pointer_network) def sync_local_order(pointer_network): ccore = ccore_library.get() ccore.sync_local_order.restype = c_double return ccore.sync_local_order(pointer_network) def sync_connectivity_matrix(pointer_network): ccore = ccore_library.get() ccore.sync_connectivity_matrix.restype = POINTER(pyclustering_package) package = ccore.sync_connectivity_matrix(pointer_network) connectivity_matrix = package_extractor(package).extract() ccore.free_pyclustering_package(package) return connectivity_matrix def sync_dynamic_get_size(pointer_dynamic): ccore = ccore_library.get() ccore.sync_dynamic_get_time.restype = c_size_t return ccore.sync_dynamic_get_size(pointer_dynamic) def sync_dynamic_destroy(pointer_dynamic): ccore = ccore_library.get() ccore.sync_dynamic_destroy(pointer_dynamic) def sync_dynamic_allocate_sync_ensembles(pointer_dynamic, tolerance, iteration): if iteration is None: iteration = sync_dynamic_get_size(pointer_dynamic) - 1 ccore = ccore_library.get() ccore.sync_dynamic_allocate_sync_ensembles.restype = POINTER(pyclustering_package) package = ccore.sync_dynamic_allocate_sync_ensembles(pointer_dynamic, c_double(tolerance), c_size_t(iteration)) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result def sync_dynamic_allocate_correlation_matrix(pointer_dynamic, iteration): analyse_iteration = iteration if analyse_iteration is None: analyse_iteration = sync_dynamic_get_size(pointer_dynamic) - 1 ccore = ccore_library.get() ccore.sync_dynamic_allocate_correlation_matrix.restype = POINTER(pyclustering_package) package = ccore.sync_dynamic_allocate_correlation_matrix(pointer_dynamic, c_uint(analyse_iteration)) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result def sync_dynamic_get_output(pointer_dynamic): ccore = ccore_library.get() ccore.sync_dynamic_get_output.restype = POINTER(pyclustering_package) package = ccore.sync_dynamic_get_output(pointer_dynamic) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result def sync_dynamic_get_time(pointer_dynamic): ccore = ccore_library.get() ccore.sync_dynamic_get_time.restype = POINTER(pyclustering_package) package = ccore.sync_dynamic_get_time(pointer_dynamic) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result def sync_dynamic_calculate_order(pointer_dynamic, start_iteration, stop_iteration): ccore = ccore_library.get() ccore.sync_dynamic_calculate_order.restype = POINTER(pyclustering_package) package = ccore.sync_dynamic_calculate_order(pointer_dynamic, start_iteration, stop_iteration) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result def sync_dynamic_calculate_local_order(pointer_dynamic, pointer_network, start_iteration, stop_iteration): ccore = ccore_library.get() ccore.sync_dynamic_calculate_local_order.restype = POINTER(pyclustering_package) package = ccore.sync_dynamic_calculate_local_order(pointer_dynamic, pointer_network, c_size_t(start_iteration), c_size_t(stop_iteration)) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result pyclustering-0.10.1.2/pyclustering/core/syncnet_wrapper.py000077500000000000000000000023431375753423500237610ustar00rootroot00000000000000"""! @brief CCORE Wrapper for syncnet clustering algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import * from pyclustering.core.pyclustering_package import package_builder def syncnet_create_network(sample, radius, initial_phases, enable_conn_weight): package_data = package_builder(sample, c_double).create() ccore = ccore_library.get() ccore.syncnet_create_network.restype = POINTER(c_void_p) pointer_network = ccore.syncnet_create_network(package_data, c_double(radius), c_bool(enable_conn_weight), c_uint(initial_phases)) return pointer_network def syncnet_destroy_network(pointer_network): ccore = ccore_library.get() ccore.syncnet_destroy_network(pointer_network) def syncnet_process(network_pointer, order, solution, collect_dynamic): ccore = ccore_library.get() ccore.syncnet_process.restype = POINTER(c_void_p) return ccore.syncnet_process(network_pointer, c_double(order), c_uint(solution), c_bool(collect_dynamic)) def syncnet_analyser_destroy(pointer_analyser): ccore = ccore_library.get() ccore.syncnet_analyser_destroy(pointer_analyser) pyclustering-0.10.1.2/pyclustering/core/syncpr_wrapper.py000077500000000000000000000074031375753423500236160ustar00rootroot00000000000000"""! @brief CCORE Wrapper for oscillatory neural network for pattern recognition (syncpr). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.core.wrapper import *; from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder; def pack_pattern(pattern): return package_builder(pattern, c_int).create(); def syncpr_create(num_osc, increase_strength1, increase_strength2): ccore = ccore_library.get(); ccore.syncpr_create.restype = POINTER(c_void_p); pointer_network = ccore.syncpr_create(c_uint(num_osc), c_double(increase_strength1), c_double(increase_strength2)); return pointer_network; def syncpr_destroy(pointer_network): ccore = ccore_library.get(); ccore.syncpr_destroy(pointer_network); def syncpr_get_size(pointer_network): ccore = ccore_library.get(); ccore.syncpr_get_size.restype = c_size_t; return ccore.syncpr_get_size(pointer_network); def syncpr_train(pointer_network, patterns): c_patterns = package_builder(patterns, c_int).create(); ccore = ccore_library.get(); ccore.syncpr_train(pointer_network, c_patterns); def syncpr_simulate_static(pointer_network, steps, time, pattern, solution, collect_dynamic): package_pattern = pack_pattern(pattern); ccore = ccore_library.get(); ccore.syncpr_simulate_static.restype = POINTER(c_void_p); return ccore.syncpr_simulate_static(pointer_network, c_uint(steps), c_double(time), package_pattern, c_uint(solution), c_bool(collect_dynamic)); def syncpr_simulate_dynamic(pointer_network, pattern, order, solution, collect_dynamic, step): package_pattern = pack_pattern(pattern); ccore = ccore_library.get(); ccore.syncpr_simulate_dynamic.restype = POINTER(c_void_p); return ccore.syncpr_simulate_dynamic(pointer_network, package_pattern, c_double(order), c_uint(solution), c_bool(collect_dynamic), c_double(step)); def syncpr_memory_order(pointer_network, pattern): package_pattern = pack_pattern(pattern); ccore = ccore_library.get(); ccore.syncpr_memory_order.restype = c_double; return ccore.syncpr_memory_order(pointer_network, package_pattern); def syncpr_dynamic_get_size(pointer_dynamic): ccore = ccore_library.get(); ccore.syncpr_dynamic_get_size.restype = c_uint; return ccore.syncpr_dynamic_get_size(pointer_dynamic); def syncpr_dynamic_destroy(pointer_dynamic): ccore = ccore_library.get(); ccore.syncpr_dynamic_destroy(pointer_dynamic); def syncpr_dynamic_allocate_sync_ensembles(pointer_dynamic, tolerance): ccore = ccore_library.get(); ccore.syncpr_dynamic_allocate_sync_ensembles.restype = POINTER(pyclustering_package); package = ccore.syncpr_dynamic_allocate_sync_ensembles(pointer_dynamic, c_double(tolerance)); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def syncpr_dynamic_get_output(pointer_dynamic): ccore = ccore_library.get(); ccore.syncpr_dynamic_get_output.restype = POINTER(pyclustering_package); package = ccore.syncpr_dynamic_get_output(pointer_dynamic); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result; def syncpr_dynamic_get_time(pointer_dynamic): ccore = ccore_library.get(); ccore.syncpr_dynamic_get_time.restype = POINTER(pyclustering_package); package = ccore.syncpr_dynamic_get_time(pointer_dynamic); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result;pyclustering-0.10.1.2/pyclustering/core/tests/000077500000000000000000000000001375753423500213215ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/core/tests/__init__.py000077500000000000000000000050201375753423500234320ustar00rootroot00000000000000"""! @brief Unit-test runner for core wrapper. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.core.tests import ut_package as core_package_unit_tests import os from pyclustering.core.definitions import PATH_PYCLUSTERING_CCORE_LIBRARY from pyclustering.core.wrapper import ccore_library class remove_library(object): """! @brief Decorator for tests where ccore library should be removed. """ def __init__(self, call_object): self.call_object = call_object def __call__(self, *args): print("[TEST] Ignore next print related to problems with pyclustering ccore") test_result = True try: os.rename(PATH_PYCLUSTERING_CCORE_LIBRARY, PATH_PYCLUSTERING_CCORE_LIBRARY + "_corrupted") ccore_library.initialize() self.call_object(args) except: test_result = False os.rename(PATH_PYCLUSTERING_CCORE_LIBRARY + "_corrupted", PATH_PYCLUSTERING_CCORE_LIBRARY) ccore_library.initialize() if test_result is False: raise AssertionError("Test failed") class corrupt_library(object): """! @brief Decorator for tests where ccore library should be corrupted. """ def __init__(self, call_object): self.call_object = call_object def __create_corrupted_library(self, filepath): with open(filepath, 'wb') as binary_file_descriptor: binary_file_descriptor.write(bytes("corrupted binary library", 'UTF-8')) def __remove_corrupted_library(self, filepath): os.remove(filepath) def __call__(self, *args): os.rename(PATH_PYCLUSTERING_CCORE_LIBRARY, PATH_PYCLUSTERING_CCORE_LIBRARY + "_corrupted") self.__create_corrupted_library(PATH_PYCLUSTERING_CCORE_LIBRARY) ccore_library.initialize() self.call_object(args) self.__remove_corrupted_library(PATH_PYCLUSTERING_CCORE_LIBRARY) os.rename(PATH_PYCLUSTERING_CCORE_LIBRARY + "_corrupted", PATH_PYCLUSTERING_CCORE_LIBRARY) ccore_library.initialize() class core_tests(suite_holder): def __init__(self): super().__init__() core_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(core_suite): core_suite.addTests(unittest.TestLoader().loadTestsFromModule(core_package_unit_tests)) pyclustering-0.10.1.2/pyclustering/core/tests/ut_package.py000077500000000000000000000106421375753423500240040ustar00rootroot00000000000000"""! @brief Unit-tests for pyclustering package that is used for exchange between ccore library and python code. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest import numpy from pyclustering.core.pyclustering_package import package_builder, package_extractor from ctypes import c_ulong, c_size_t, c_double, c_uint, c_float, c_char_p class Test(unittest.TestCase): def templatePackUnpack(self, dataset, c_type_data=None): package_pointer = package_builder(dataset, c_type_data).create() unpacked_package = package_extractor(package_pointer).extract() packing_data = dataset if isinstance(packing_data, numpy.ndarray): packing_data = dataset.tolist() if isinstance(packing_data, str): self.assertEqual(dataset, unpacked_package) else: self.assertTrue(self.compare_containers(packing_data, unpacked_package)) def compare_containers(self, container1, container2): def is_container(container): return isinstance(container, list) or isinstance(container, tuple) if len(container1) == 0 and len(container2) == 0: return True if len(container1) != len(container2): return False for index in range(len(container1)): if is_container(container1[index]) and is_container(container2[index]): return self.compare_containers(container1[index], container2[index]) elif is_container(container1[index]) == is_container(container2[index]): if container1[index] != container2[index]: return False else: return False return True def testListInteger(self): self.templatePackUnpack([1, 2, 3, 4, 5]) def testListIntegerSingle(self): self.templatePackUnpack([2]) def testListIntegerNegative(self): self.templatePackUnpack([-1, -2, -10, -20]) def testListIntegerNegativeAndPositive(self): self.templatePackUnpack([-1, 26, -10, -20, 13]) def testListFloat(self): self.templatePackUnpack([1.1, 1.2, 1.3, 1.4, 1.5, 1.6]) def testListFloatNegativeAndPositive(self): self.templatePackUnpack([1.1, -1.2, -1.3, -1.4, 1.5, -1.6]) def testListLong(self): self.templatePackUnpack([100000000, 2000000000]) def testListEmpty(self): self.templatePackUnpack([]) def testListOfListInteger(self): self.templatePackUnpack([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]) def testListOfListDouble(self): self.templatePackUnpack([ [1.1, 5.4], [1.3], [1.4, -9.4] ]) def testListOfListWithGaps(self): self.templatePackUnpack([ [], [1, 2, 3], [], [4], [], [5, 6, 7] ]) def testListSpecifyUnsignedLong(self): self.templatePackUnpack([1, 2, 3, 4, 5], c_ulong) def testListSpecifyUnsignedSizeT(self): self.templatePackUnpack([1, 2, 3, 4, 5], c_size_t) def testListSpecifyDouble(self): self.templatePackUnpack([1.1, 1.6, -7.8], c_double) def testListOfListSpecifySizeT(self): self.templatePackUnpack([ [1, 2, 3], [4, 5] ], c_size_t) def testListOfListSpecifyUnsignedIntWithGaps(self): self.templatePackUnpack([ [1, 2, 3], [], [4, 5], [], [] ], c_uint) def testListOfListEmpty(self): self.templatePackUnpack([ [], [], [] ]) def testListOfListOfListInteger(self): self.templatePackUnpack([ [ [1], [2] ], [ [3], [4] ], [ [5, 6], [7, 8] ] ]) def testTupleInterger(self): self.templatePackUnpack([ (1, 2, 3), (4, 5), (6, 7, 8, 9) ], c_uint) def testTupleFloat(self): self.templatePackUnpack([ (1.0, 2.0, 3.8), (4.6, 5.0), (6.8, 7.4, 8.5, 9.6) ], c_float) def testTupleEmpty(self): self.templatePackUnpack([(), (), ()]) def testNumpyMatrixOneColumn(self): self.templatePackUnpack(numpy.array([[1.0], [2.0], [3.0]]), c_double) def testNumpyMatrixTwoColumns(self): self.templatePackUnpack(numpy.array([[1.0, 1.0], [2.0, 2.0]]), c_double) def testNumpyMatrixThreeColumns(self): self.templatePackUnpack(numpy.array([[1.1, 2.2, 3.3], [2.2, 3.3, 4.4], [3.3, 4.4, 5.5]]), c_double) def testString(self): self.templatePackUnpack("Test message number one".encode('utf-8')) def testEmptyString(self): self.templatePackUnpack("".encode('utf-8')) pyclustering-0.10.1.2/pyclustering/core/ttsas_wrapper.py000077500000000000000000000015121375753423500234310ustar00rootroot00000000000000"""! @brief CCORE Wrapper for TTSAS algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, POINTER; from pyclustering.core.wrapper import ccore_library; from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder; def ttsas(sample, threshold1, threshold2, metric_pointer): pointer_data = package_builder(sample, c_double).create(); ccore = ccore_library.get(); ccore.ttsas_algorithm.restype = POINTER(pyclustering_package); package = ccore.ttsas_algorithm(pointer_data, c_double(threshold1), c_double(threshold2), metric_pointer); result = package_extractor(package).extract(); ccore.free_pyclustering_package(package); return result[0], result[1];pyclustering-0.10.1.2/pyclustering/core/wrapper.py000077500000000000000000000072561375753423500222260ustar00rootroot00000000000000"""! @brief Wrapper for CCORE library (part of this project). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import sys from ctypes import * from pyclustering.core.definitions import * ccore_library_instance = None ccore_library_version = "0.10.1.2" class ccore_library: __library = None __workable = False __initialized = False @staticmethod def get(): if not ccore_library.__library: ccore_library.initialize() return ccore_library.__library @staticmethod def workable(): if not ccore_library.__initialized: ccore_library.get() return ccore_library.__workable @staticmethod def initialize(): ccore_library.__initialized = True if PATH_PYCLUSTERING_CCORE_LIBRARY is None: print("The pyclustering ccore is not supported for platform '" + sys.platform + "' (" + platform.architecture()[0] + ").\n" + "Falling back on python implementation.\n" + "For more information, contact 'pyclustering@yandex.ru'.") return None if os.path.exists(PATH_PYCLUSTERING_CCORE_LIBRARY) is False: print("The pyclustering ccore is not found (expected core location: '" + PATH_PYCLUSTERING_CCORE_LIBRARY + "').\n" + "Probably library has not been successfully installed ('" + sys.platform + "', '" + platform.architecture()[0] + "').\n" + "Falling back on python implementation.\n" + "For more information, contact 'pyclustering@yandex.ru'.") return None ccore_library.__library = cdll.LoadLibrary(PATH_PYCLUSTERING_CCORE_LIBRARY) if ccore_library.__check_library_integrity() is False: print("Impossible to mark ccore as workable due to compatibility issues " + "('" + sys.platform + "', '" + platform.architecture()[0] + "').\n" + "Falling back on python implementation.\n" + "For more information, contact 'pyclustering@yandex.ru'.") return None result, version = ccore_library.__check_library_version() if result is False: print("Incompatible ccore version of pyclustering library is being used ('" + version +"' instead '" + ccore_library_version + "').\n" + "Probably library has not been successfully installed.\n" + "Please, contact 'pyclustering@yandex.ru'.") return ccore_library.__library @staticmethod def __check_library_integrity(): try: ccore_library.__library.get_interface_description.restype = c_char_p result = ccore_library.__library.get_interface_description() if len(result) > 0: ccore_library.__workable = True except: ccore_library.__workable = False return ccore_library.__workable @staticmethod def __check_library_version(): version = "unknown" try: ccore_library.__library.get_interface_version.restype = c_char_p version_cptr = ccore_library.__library.get_interface_version() ccore_version = version_cptr.decode("utf-8") if ccore_version == ccore_library_version: ccore_library.__workable = True else: ccore_library.__workable = False except: ccore_library.__workable = False return ccore_library.__workable, version pyclustering-0.10.1.2/pyclustering/core/xmeans_wrapper.py000077500000000000000000000022671375753423500235760ustar00rootroot00000000000000"""! @brief CCORE Wrapper for X-Means algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from ctypes import c_double, c_longlong, c_size_t, c_uint, POINTER from pyclustering.core.wrapper import ccore_library from pyclustering.core.pyclustering_package import pyclustering_package, package_extractor, package_builder def xmeans(sample, centers, kmax, tolerance, criterion, alpha, beta, repeat, random_state, metric_pointer): random_state = random_state or -1 pointer_data = package_builder(sample, c_double).create() pointer_centers = package_builder(centers, c_double).create() ccore = ccore_library.get() ccore.xmeans_algorithm.restype = POINTER(pyclustering_package) package = ccore.xmeans_algorithm(pointer_data, pointer_centers, c_size_t(kmax), c_double(tolerance), c_uint(criterion), c_double(alpha), c_double(beta), c_size_t(repeat), c_longlong(random_state), metric_pointer) result = package_extractor(package).extract() ccore.free_pyclustering_package(package) return result pyclustering-0.10.1.2/pyclustering/gcolor/000077500000000000000000000000001375753423500205145ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/gcolor/__init__.py000077500000000000000000000002461375753423500226320ustar00rootroot00000000000000"""! @brief pyclustering module for graph coloring algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/pyclustering/gcolor/dsatur.py000077500000000000000000000127731375753423500224050ustar00rootroot00000000000000"""! @brief Graph coloring algorithm: DSATUR @details Implementation based on paper @cite article::gcolor::dsatur::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ class dsatur: """! @brief Represents DSATUR algorithm for graph coloring problem that uses greedy strategy. """ def __init__(self, data): """! @brief Constructor of DSATUR algorithm. @param[in] data (list): Matrix graph representation. """ if (len(data[0]) != len(data)): raise NameError('Only matrix graph representation is available.'); self.__data_pointer = data; self.__colors = []; self.__coloring = None; def process(self): """! @brief Perform graph coloring using DSATUR algorithm. @see get_colors() """ color_counter = 1; degrees = list(); saturation_degrees = [0] * len(self.__data_pointer); self.__coloring = [0] * len(self.__data_pointer); uncolored_vertices = set(range(len(self.__data_pointer))); index_maximum_degree = 0; maximum_degree = 0; for index_node in range(len(self.__data_pointer)): # Fill degree of nodes in the input graph degrees.append( ( sum(self.__data_pointer[index_node]), index_node ) ); # And find node with maximal degree at the same time. if (degrees[index_node][0] > maximum_degree): (maximum_degree, node_index) = degrees[index_node]; index_maximum_degree = index_node; # Update saturation neighbors = self.__get_neighbors(index_maximum_degree); for index_neighbor in neighbors: saturation_degrees[index_neighbor] += 1; # Coloring the first node self.__coloring[index_maximum_degree] = color_counter; uncolored_vertices.remove(index_maximum_degree); while(len(uncolored_vertices) > 0): # Get maximum saturation degree maximum_satur_degree = -1; for index in uncolored_vertices: if (saturation_degrees[index] > maximum_satur_degree): maximum_satur_degree = saturation_degrees[index]; # Get list of indexes with maximum saturation degree indexes_maximum_satur_degree = [index for index in uncolored_vertices if saturation_degrees[index] == maximum_satur_degree]; coloring_index = indexes_maximum_satur_degree[0]; if (len(indexes_maximum_satur_degree) > 1): # There are more then one node with maximum saturation # Find node with maximum degree maximum_degree = -1; for index in indexes_maximum_satur_degree: (degree, node_index) = degrees[index]; if (degree > maximum_degree): coloring_index = node_index; maximum_degree = degree; # Coloring node_index_neighbors = self.__get_neighbors(coloring_index); for number_color in range(1, color_counter + 1, 1): if (self.__get_amount_color(node_index_neighbors, number_color) == 0): self.__coloring[coloring_index] = number_color; break; # If it has not been colored then if (self.__coloring[coloring_index] == 0): color_counter += 1; # Add new color self.__coloring[coloring_index] = color_counter; # Remove node from uncolored set uncolored_vertices.remove(coloring_index); # Update degree of saturation for index_neighbor in node_index_neighbors: subneighbors = self.__get_neighbors(index_neighbor); if (self.__get_amount_color(subneighbors, self.__coloring[coloring_index]) == 1): saturation_degrees[index_neighbor] += 1; def get_colors(self): """! @brief Returns results of graph coloring. @return (list) list with assigned colors where each element corresponds to node in the graph, for example [1, 2, 2, 1, 3, 4, 1]. @see process() """ return self.__coloring; def __get_amount_color(self, node_indexes, color_number): """! @brief Countes how many nodes has color 'color_number'. @param[in] node_indexes (list): Indexes of graph nodes for checking. @param[in] color_number (uint): Number of color that is searched in nodes. @return (uint) Number found nodes with the specified color 'color_number'. """ color_counter = 0; for index in node_indexes: if (self.__coloring[index] == color_number): color_counter += 1; return color_counter; def __get_neighbors(self, node_index): """! @brief Returns indexes of neighbors of the specified node. @param[in] node_index (uint): @return (list) Neighbors of the specified node. """ return [ index for index in range(len(self.__data_pointer[node_index])) if self.__data_pointer[node_index][index] != 0 ]; pyclustering-0.10.1.2/pyclustering/gcolor/examples/000077500000000000000000000000001375753423500223325ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/gcolor/examples/__init__.py000066400000000000000000000000001375753423500244310ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/gcolor/examples/dsatur_examples.py000077500000000000000000000034351375753423500261140ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of DSATUR algorithm in graph coloring. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils.graph import read_graph, draw_graph; from pyclustering.samples.definitions import GRAPH_SIMPLE_SAMPLES; from pyclustering.gcolor.dsatur import dsatur; def template_graph_coloring(filename): graph = read_graph(filename); dsatur_instance = dsatur(graph.data); dsatur_instance.process(); coloring = dsatur_instance.get_colors(); print("Number colors: ", max(coloring)); draw_graph(graph, coloring); def run_all_graph_simple_samples(): template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE1); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE2); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_STAR); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE3); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE2); template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE3); run_all_graph_simple_samples();pyclustering-0.10.1.2/pyclustering/gcolor/examples/hysteresis_examples.py000077500000000000000000000056351375753423500270200ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of algorithm (based on Hysteresis Oscillatory Network) in graph coloring. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.gcolor.hysteresis import hysteresisgcolor; from pyclustering.utils.graph import read_graph, draw_graph; from pyclustering.utils import draw_dynamics; from pyclustering.samples.definitions import GRAPH_SIMPLE_SAMPLES; def template_graph_coloring(filename, alpha, eps, steps, time, title = None, tolerance = 0.1, threshold_steps = 10): if (title is None): title = filename; graph = read_graph(filename); network = hysteresisgcolor(graph.data, alpha, eps); output_dynamic = network.simulate(steps, time); draw_dynamics(output_dynamic.time, output_dynamic.output, x_title = "Time", y_title = "State"); clusters = output_dynamic.allocate_clusters(tolerance, threshold_steps); for index in range(0, len(clusters)): print("Color #", index, ": ", clusters[index]); coloring_map = output_dynamic.allocate_map_coloring(tolerance, threshold_steps); draw_graph(graph, coloring_map); def graph_simple1(): "Good result - optimal" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1, 1.2, 1.8, 2000, 20); def graph_one_line(): "Good result - optimal" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE, 1.2, 1.8, 2000, 20); def graph_one_crossroad(): "Good result - optimal" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD, 1.2, 1.8, 2000, 20); def graph_two_crossroads(): "Good result - optimal" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS, 1.2, 1.8, 2000, 20); def graph_full_interconnected1(): "Bad result - two vertices colored by the same color" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1, 1.2, 1.8, 2000, 20, tolerance = 0.05); def graph_full_interconnected2(): "Good result - optimal" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2, 1.2, 1.8, 2000, 20, tolerance = 0.05); def graph_one_circle1(): template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1, 1.1, 1.1, 2000, 20); def graph_one_circle2(): template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2, 1.1, 1.1, 2000, 20); def graph_one_circle3(): template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE3, 1.1, 1.1, 2000, 20); def graph_five_pointed_frame_star(): "Good result - not optimal" template_graph_coloring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR, 1.1, 1.4, 3000, 30); graph_simple1(); graph_one_line(); graph_one_crossroad(); graph_two_crossroads(); graph_full_interconnected1(); graph_full_interconnected2(); graph_one_circle1(); graph_one_circle2(); graph_one_circle3(); graph_five_pointed_frame_star();pyclustering-0.10.1.2/pyclustering/gcolor/examples/sync_examples.py000077500000000000000000000066021375753423500255650ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of algorithm (based on modified Sync) in graph coloring. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.gcolor.sync import syncgcolor; from pyclustering.nnet import *; from pyclustering.utils import draw_dynamics; from pyclustering.utils.graph import read_graph, draw_graph; from pyclustering.samples.definitions import GRAPH_SIMPLE_SAMPLES; def template_graph_coloring(positive_weight, negative_weight, filename, reduction = None, title = None): if (title is None): title = filename; print("\nGraph Coloring: ", title); graph = read_graph(filename); network = syncgcolor(graph.data, positive_weight, negative_weight, reduction); analyser = network.process(order = 0.999, solution = solve_type.FAST, collect_dynamic = True); sync.sync_visualizer.show_output_dynamic(analyser); clusters = analyser.allocate_color_clusters(); for index in range(0, len(clusters)): print("Color #", index, ": ", clusters[index]); coloring_map = analyser.allocate_map_coloring(); print("Number colors: ", max(coloring_map)); draw_graph(graph, coloring_map); # Check validity of colors for index_node in range(len(graph.data)): color_neighbors = [ coloring_map[index] for index in range(len(graph.data[index_node])) if graph.data[index_node][index] != 0 and index_node != index]; #print(index_node, map_coloring[index_node], color_neighbors, assigned_colors, map_coloring, "\n\n"); if (coloring_map[index_node] in color_neighbors): print("Warining: Incorrect coloring"); return; def run_all_graph_simple_samples(): template_graph_coloring(1, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1, None, "Circle 1"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2, None, "Circle 2"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE3, None, "Circle 3"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE1, None, "Broken Circle 1"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE2, None, "Broken Circle 2"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD, None, "One Crossroad"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_STAR, None, "Five Pointed Star"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE, None, "One Line"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS, None, "Two Interconnected Stars"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR, None, "Five Pointed Star With Frame"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1, None, "Full interconneted graph 1 (all-to-all)"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2, None, "Full interconneted graph 2 (all-to-all)"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1, None, "Simple 1"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE2, None, "Simple 2"); template_graph_coloring(0, -1, GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE3, None, "Simple 3"); run_all_graph_simple_samples();pyclustering-0.10.1.2/pyclustering/gcolor/hysteresis.py000077500000000000000000000146531375753423500233040ustar00rootroot00000000000000"""! @brief Graph coloring algorithm: Algorithm based on Hysteresis Oscillatory Network @details Implementation based on paper @cite article::gcolor::hysteresis::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.hysteresis import hysteresis_network, hysteresis_dynamic class hysteresis_analyser(hysteresis_dynamic): """! @brief Performs analysis of output dynamic of the hysteresis oscillatory network to extract information about clusters or color allocation. """ def __init__(self, amplitudes, time): """! @brief Constructor of the analyser. @param[in] amplitudes (list): Output dynamic of the hysteresis oscillatory network, where one iteration consists of all amplitudes of oscillators. @param[in] time (list): Simulation time (timestamps of simulation steps) when amplitudes are stored. """ super().__init__(amplitudes, time) def allocate_clusters(self, tolerance=0.1, threshold_steps=10): """! @brief Returns list of clusters in line with state of ocillators (phases). @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators. @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation. If amount of simulation steps has been less than threshold steps than amount of steps will be reduced to amount of simulation steps. @remark Results can be obtained only after network simulation (graph processing by the network). @return (list) List of clusters, for example [ [cluster1], [cluster2], ... ]. @see allocate_map_coloring() """ return self.allocate_sync_ensembles(tolerance, threshold_steps=threshold_steps) def allocate_map_coloring(self, tolerance, threshold_steps = 10): """! @brief Returns list of color indexes that are assigned to each object from input data space accordingly. @param[in] tolerance (double): Tolerance level that define maximal difference between outputs of oscillators in one synchronous ensemble. @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation. If amount of simulation steps has been less than threshold steps than amount of steps will be reduced to amount of simulation steps. @remark Results can be obtained only after network simulation (graph processing by the network). @return (list) Color indexes that are assigned to each object from input data space accordingly. @see allocate_clusters() """ clusters = self.allocate_clusters(tolerance, threshold_steps) coloring_map = [0] * len(self._dynamic[0]) for color_index in range(len(clusters)): for node_index in clusters[color_index]: coloring_map[node_index] = color_index return coloring_map class hysteresisgcolor(hysteresis_network): """! @brief Class represents graph coloring algorithm based on hysteresis oscillatory network. This is bio-inspired algorithm where the network uses relaxation oscillators that is regarded as a multi-vibrator. Each ensemble of synchronous oscillators corresponds to only one color. Example @code # import required modules from pyclustering.nnet.hysteresis import hysteresis_visualizer; from pyclustering.gcolor.hysteresis import hysteresisgcolor; from pyclustering.utils.graph import read_graph, draw_graph; # load graph from a file graph = read_graph(filename); # create oscillatory network for solving graph coloring problem network = hysteresisgcolor(graph.data, alpha, eps); # perform simulation of the network output_dynamic = network.simulate(2000, 20); # show dynamic of the network hysteresis_visualizer.show_output_dynamic(output_dynamic); # obtain results of graph coloring and display results coloring_map = hysteresis_visualizer.allocate_map_coloring(); draw_graph(graph, coloring_map); @endcode """ def __init__(self, graph_matrix, alpha, eps): """! @brief Constructor of hysteresis oscillatory network for graph coloring. @param[in] graph_matrix (list): Matrix representation of a graph. @param[in] alpha (double): Positive constant (affect weight between two oscillators w[i][j]). @param[in] eps (double): Positive constant (affect feedback to itself (i = j) of each oscillator w[i][j] = -alpha - eps). """ number_oscillators = len(graph_matrix) super().__init__(number_oscillators) self._states = [0] * self._num_osc for i in range(0, self._num_osc): self._states[i] = 1 - (2 / self._num_osc) * i self._outputs = [-1] * self._num_osc self._outputs_buffer = [-1] * self._num_osc self._time_contant = 1 # Create connections self._weight = [] for row in range(0, self._num_osc): self._weight.append([0] * self._num_osc) for col in range(0, self._num_osc): if (row != col): self._weight[row][col] = -alpha * (graph_matrix[row][col]) / sum(graph_matrix[row]) else: self._weight[row][col] = -alpha - eps def process(self, steps, time, collect_dynamic=True): """! @brief Peforms graph coloring analysis using simulation of the oscillatory network. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] collect_dynamic (bool): Specified requirement to collect whole dynamic of the network. @return (hysteresis_analyser) Returns analyser of results of clustering. """ output_dynamic = super().simulate(steps, time, collect_dynamic=collect_dynamic) return hysteresis_analyser(output_dynamic.output, output_dynamic.time) pyclustering-0.10.1.2/pyclustering/gcolor/sync.py000077500000000000000000000130261375753423500220470ustar00rootroot00000000000000"""! @brief Graph coloring algorithm based on Sync Oscillatory Network @details Implementation based on paper @cite article::gcolor::sync::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet import * from pyclustering.nnet.sync import sync_network from pyclustering.nnet.sync import sync_dynamic class syncgcolor_analyser(sync_dynamic): """! @brief Analyser of output dynamic of the oscillatory network syncgcolor. """ def __init__(self, phase, time, pointer_sync_analyser): """! @brief Constructor of the analyser. @param[in] phase (list): Output dynamic of the oscillatory network, where one iteration consists of all phases of oscillators. @param[in] time (list): Simulation time. @param[in] pointer_sync_analyser (POINTER): Pointer to CCORE analyser, if specified then other arguments can be omitted. """ super().__init__(phase, time, pointer_sync_analyser); def allocate_color_clusters(self, tolerance = 0.1): """! @brief Allocates clusters, when one cluster defines only one color. @param[in] tolerance (double): Defines maximum deviation between phases. @return (list) Clusters [vertices with color 1], [vertices with color 2], ..., [vertices with color n]. """ return self.allocate_sync_ensembles(tolerance); def allocate_map_coloring(self, tolerance = 0.1): """! @brief Allocates coloring map for graph that has been processed. @param[in] tolerance (double): Defines maximum deviation between phases. @return (list) Colors for each node (index of node in graph), for example [color1, color2, color2, ...]. """ clusters = self.allocate_color_clusters(tolerance); number_oscillators = len(self._dynamic[0]); coloring_map = [0] * number_oscillators; for color_index in range(len(clusters)): for node_index in clusters[color_index]: coloring_map[node_index] = color_index; return coloring_map; class syncgcolor(sync_network): """! @brief Oscillatory network based on Kuramoto model with negative and positive connections for graph coloring problem. """ def __init__(self, graph_matrix, positive_weight, negative_weight, reduction = None): """! @brief Constructor of the oscillatory network syncgcolor for graph coloring problem. @param[in] graph_matrix (list): Graph represented by matrix. @param[in] positive_weight (double): Value of weight of positive connections. @param[in] negative_weight (double): Value of weight of negative connections. @param[in] reduction (bool): Inverse degree of the processed graph. """ number_oscillators = len(graph_matrix); super().__init__(number_oscillators, type_conn = conn_type.DYNAMIC, ccore = False); if (reduction == None): self._reduction = self._num_osc; else: self._reduction = reduction; self._positive_weight = positive_weight; self._negative_weight = negative_weight; self._create_connections(graph_matrix); def _create_connections(self, graph_matrix): """! @brief Creates connection in the network in line with graph. @param[in] graph_matrix (list): Matrix representation of the graph. """ for row in range(0, len(graph_matrix)): for column in range (0, len(graph_matrix[row])): if (graph_matrix[row][column] > 0): self.set_connection(row, column); def _phase_kuramoto(self, teta, t, argv): """! @brief Returns result of phase calculation for oscillator in the network. @param[in] teta (double): Value of phase of the oscillator with index argv in the network. @param[in] t (double): Unused, can be ignored. @param[in] argv (uint): Index of the oscillator in the network. @return (double) New value of phase for oscillator with index argv. """ index = argv; phase = 0; for k in range(0, self._num_osc): if (self.has_connection(index, k) == True): phase += self._negative_weight * math.sin(self._phases[k] - teta); else: phase += self._positive_weight * math.sin(self._phases[k] - teta); return ( phase / self._reduction ); def process(self, order = 0.998, solution = solve_type.FAST, collect_dynamic = False): """! @brief Performs simulation of the network (performs solving of graph coloring problem). @param[in] order (double): Defines when process of synchronization in the network is over, range from 0 to 1. @param[in] solution (solve_type): defines type (method) of solving diff. equation. @param[in] collect_dynamic (bool): If True - return full dynamic of the network, otherwise - last state of phases. @return (syncnet_analyser) Returns analyser of results of coloring. """ analyser = self.simulate_dynamic(order, solution, collect_dynamic); return syncgcolor_analyser(analyser.output, analyser.time, None); pyclustering-0.10.1.2/pyclustering/gcolor/tests/000077500000000000000000000000001375753423500216565ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/gcolor/tests/__init__.py000077500000000000000000000017021375753423500237720ustar00rootroot00000000000000"""! @brief Unit-test runner for tests of graph coloring algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder from pyclustering.gcolor.tests import ut_dsatur as gcolor_dsatur_unit_tests from pyclustering.gcolor.tests import ut_hysteresis as gcolor_hysteresis_unit_tests from pyclustering.gcolor.tests import ut_sync as gcolor_sync_unit_tests class gcolor_tests(suite_holder): def __init__(self): super().__init__() gcolor_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(gcolor_tests): gcolor_tests.addTests(unittest.TestLoader().loadTestsFromModule(gcolor_dsatur_unit_tests)) gcolor_tests.addTests(unittest.TestLoader().loadTestsFromModule(gcolor_hysteresis_unit_tests)) gcolor_tests.addTests(unittest.TestLoader().loadTestsFromModule(gcolor_sync_unit_tests)) pyclustering-0.10.1.2/pyclustering/gcolor/tests/ut_dsatur.py000077500000000000000000000056531375753423500242560ustar00rootroot00000000000000"""! @brief Unit-tests for DSATUR algorithm. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from pyclustering.gcolor.dsatur import dsatur; from pyclustering.utils.graph import read_graph; from pyclustering.samples.definitions import GRAPH_SIMPLE_SAMPLES; class Test(unittest.TestCase): def templateTestColoring(self, filename): graph = read_graph(filename); dsatur_intance = dsatur(graph.data); dsatur_intance.process(); map_coloring = dsatur_intance.get_colors(); # Check number of colors assigned_colors = set(map_coloring); # Check validity of color numbers for color_number in range(1, len(assigned_colors) + 1, 1): assert color_number in assigned_colors; # Check validity of colors for index_node in range(len(graph.data)): color_neighbors = [ map_coloring[index] for index in range(len(graph.data[index_node])) if graph.data[index_node][index] != 0 and index_node != index]; #print(index_node, map_coloring[index_node], color_neighbors, assigned_colors, map_coloring, "\n\n"); assert map_coloring[index_node] not in color_neighbors; def testColoringFull1(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1); def testColoringBrokenCircle1(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE1); def testColoringOneLine(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE); def testColoringOneCircle1(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1); def testColoringFivePointedStar(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_STAR); def testColoringVerification(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE1); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE2); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_STAR); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE3); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1); self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS); pyclustering-0.10.1.2/pyclustering/gcolor/tests/ut_hysteresis.py000077500000000000000000000044151375753423500251510ustar00rootroot00000000000000"""! @brief Unit-tests for Hysteresis Oscillatory Network for graph coloring. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from pyclustering.gcolor.hysteresis import hysteresisgcolor; from pyclustering.utils.graph import read_graph; from pyclustering.samples.definitions import GRAPH_SIMPLE_SAMPLES; class Test(unittest.TestCase): def templateTestColoring(self, filename, alpha, eps, steps, time): graph = read_graph(filename); network = hysteresisgcolor(graph.data, alpha, eps); output_analyser = network.process(steps, time); map_coloring = output_analyser.allocate_map_coloring(0.05, 20); # Check number of colors assigned_colors = set(map_coloring); # Check validity of color numbers for color_number in range(0, len(assigned_colors), 1): assert color_number in assigned_colors; # Check validity of colors for index_node in range(len(graph.data)): color_neighbors = [ map_coloring[index] for index in range(len(graph.data[index_node])) if graph.data[index_node][index] != 0 and index_node != index]; #print(index_node, map_coloring[index_node], color_neighbors, assigned_colors, map_coloring, "\n\n"); assert map_coloring[index_node] not in color_neighbors; def testColoringSimple1(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1, 1.2, 1.8, 1500, 15); def testColoringCircle2(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2, 1.1, 1.1, 1500, 15); def testColoringFivePointedFrameStar(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR, 1, 1, 2500, 25); def testColoringOneLine(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE, 1.2, 1.8, 1500, 15); def testColoringOneCrossroad(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD, 1.2, 1.8, 1500, 15); def testColoringTwoCrossroads(self): self.templateTestColoring(GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS, 1.2, 1.8, 1500, 15); pyclustering-0.10.1.2/pyclustering/gcolor/tests/ut_sync.py000077500000000000000000000111461375753423500237220ustar00rootroot00000000000000"""! @brief Unit-tests for algorithm based on modified Sync. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from pyclustering.nnet import solve_type; from pyclustering.gcolor.sync import syncgcolor; from pyclustering.utils.graph import read_graph; from pyclustering.samples.definitions import GRAPH_SIMPLE_SAMPLES; class Test(unittest.TestCase): def templateTestColoringNegativeConnections(self, filename, solver_type = solve_type.FAST): result_testing = False; # If phases crosses each other because of random part of the network then we should try again. for attempt in range(0, 3, 1): graph = read_graph(filename); syncgcolor_network = syncgcolor(graph.data, 0, -1); analyser = syncgcolor_network.process(solution = solver_type); map_coloring = analyser.allocate_map_coloring(0.05); # Check number of colors assigned_colors = set(map_coloring); # Check validity of color numbers for color_number in range(0, len(assigned_colors), 1): if (color_number not in assigned_colors): continue; # Check validity of colors for index_node in range(len(graph.data)): color_neighbors = [ map_coloring[index] for index in range(len(graph.data[index_node])) if graph.data[index_node][index] != 0 and index_node != index]; #print(index_node, map_coloring[index_node], color_neighbors, assigned_colors, map_coloring, "\n\n"); if (map_coloring[index_node] in color_neighbors): continue; result_testing = True; assert result_testing; def testColoringFull1(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1); def testColoringFull2(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2); def testColoringBrokenCircle1(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE1); def testColoringBrokenCircle2(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE2); def testColoringCircle1(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1); def testColoringCircle2(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2); def testColoringFivePointedStar(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_STAR); def testColoringFivePointedFrameStar(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR); def testColoringVerification(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE1); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_BROKEN_CIRCLE2); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_FRAME_STAR); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FIVE_POINTED_STAR); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE1); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE2); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CIRCLE3); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_CROSSROAD); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_ONE_LINE); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_SIMPLE1); self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_TWO_CROSSROADS); def testOdeIntSolutionGraphFull1(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL1, solve_type.RK4); def testOdeIntSolutionGraphFull2(self): self.templateTestColoringNegativeConnections(GRAPH_SIMPLE_SAMPLES.GRAPH_FULL2, solve_type.RK4); pyclustering-0.10.1.2/pyclustering/nnet/000077500000000000000000000000001375753423500201735ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/nnet/__init__.py000077500000000000000000000371151375753423500223160ustar00rootroot00000000000000"""! @brief Neural and oscillatory network module. Consists of models of bio-inspired networks. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math; from enum import IntEnum; class initial_type(IntEnum): """! @brief Enumerator of types of oscillator output initialization. """ ## Output of oscillators are random in line with gaussian distribution. RANDOM_GAUSSIAN = 0; ## Output of oscillators are equidistant from each other (uniformly distributed, not randomly). EQUIPARTITION = 1; class solve_type(IntEnum): """! @brief Enumerator of solver types that are used for network simulation. """ ## Forward Euler first-order method. FAST = 0; # Usual calculation: x(k + 1) = x(k) + f(x(k)). ## Classic fourth-order Runge-Kutta method (fixed step). RK4 = 1; ## Runge-Kutta-Fehlberg method with order 4 and 5 (float step)." RKF45 = 2; class conn_type(IntEnum): """! @brief Enumerator of connection types between oscillators. """ ## No connection between oscillators. NONE = 0; ## All oscillators have connection with each other. ALL_TO_ALL = 1; ## Connections between oscillators represent grid where one oscillator can be connected with four neighbor oscillators: right, upper, left, lower. GRID_FOUR = 2; ## Connections between oscillators represent grid where one oscillator can be connected with eight neighbor oscillators: right, right-upper, upper, upper-left, left, left-lower, lower, lower-right. GRID_EIGHT = 3; ## Connections between oscillators represent bidirectional list. LIST_BIDIR = 4; ## Connections are defined by user or by network during simulation. DYNAMIC = 5; class conn_represent(IntEnum): """! @brief Enumerator of internal network connection representation between oscillators. """ ## Each oscillator has list of his neighbors. LIST = 0; ## Connections are represented my matrix connection NxN, where N is number of oscillators. MATRIX = 1; class network: """! @brief Common network description that consists of information about oscillators and connection between them. """ _num_osc = 0; _osc_conn = None; _conn_represent = None; __conn_type = None; __height = 0; __width = 0; @property def height(self): """! @brief Height of the network grid (that is defined by amout of oscillators in each column), this value is zero in case of non-grid structure. @note This property returns valid value only for network with grid structure. """ return self.__height; @property def width(self): """! @brief Width of the network grid, this value is zero in case of non-grid structure. @note This property returns valid value only for network with grid structure. """ return self.__width; @property def structure(self): """! @brief Type of network structure that is used for connecting oscillators. """ return self.__conn_type; def __init__(self, num_osc, type_conn = conn_type.ALL_TO_ALL, conn_repr = conn_represent.MATRIX, height = None, width = None): """! @brief Constructor of the network. @param[in] num_osc (uint): Number of oscillators in the network that defines size of the network. @param[in] type_conn (conn_type): Type of connections that are used in the network between oscillators. @param[in] conn_repr (conn_represent): Type of representation of connections. @param[in] height (uint): Number of oscillators in column of the network, this argument is used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored. @param[in] width (uint): Number of oscillotors in row of the network, this argument is used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored. """ self._num_osc = num_osc; self._conn_represent = conn_repr; self.__conn_type = type_conn; if (conn_repr is None): self._conn_represent = conn_represent.MATRIX; if ( (type_conn == conn_type.GRID_EIGHT) or (type_conn == conn_type.GRID_FOUR) ): if ( (height is not None) and (width is not None) ): self.__height = height; self.__width = width; else: side_size = self._num_osc ** (0.5); if (side_size - math.floor(side_size) > 0): raise NameError("Invalid number of oscillators '" + str(num_osc) + "' in the network in case of grid structure (root square should be extractable for the number of oscillators)."); self.__height = int(side_size); self.__width = self.__height; if (self.__height * self.__width != self._num_osc): raise NameError('Width (' + str(self.__width) + ') x Height (' + str(self.__height) + ') must be equal to Size (' + str(self._num_osc) + ') in case of grid structure'); self._create_structure(type_conn); def __len__(self): """! @brief Returns size of the network that is defined by amount of oscillators. """ return self._num_osc; def __create_connection(self, index1, index2): if (self._conn_represent == conn_represent.MATRIX): self._osc_conn[index1][index2] = True; else: self._osc_conn[index1].append(index2); def __create_all_to_all_connections(self): """! @brief Creates connections between all oscillators. """ if (self._conn_represent == conn_represent.MATRIX): for index in range(0, self._num_osc, 1): self._osc_conn.append([True] * self._num_osc); self._osc_conn[index][index] = False; elif (self._conn_represent == conn_represent.LIST): for index in range(0, self._num_osc, 1): self._osc_conn.append([neigh for neigh in range(0, self._num_osc, 1) if index != neigh]); def __create_grid_four_connections(self): """! @brief Creates network with connections that make up four grid structure. @details Each oscillator may be connected with four neighbors in line with 'grid' structure: right, upper, left, lower. """ side_size = self.__width; if (self._conn_represent == conn_represent.MATRIX): self._osc_conn = [[0] * self._num_osc for index in range(0, self._num_osc, 1)]; elif (self._conn_represent == conn_represent.LIST): self._osc_conn = [[] for index in range(0, self._num_osc, 1)]; else: raise NameError("Unknown type of representation of connections"); for index in range(0, self._num_osc, 1): upper_index = index - side_size; lower_index = index + side_size; left_index = index - 1; right_index = index + 1; node_row_index = math.ceil(index / side_size); if (upper_index >= 0): self.__create_connection(index, upper_index); if (lower_index < self._num_osc): self.__create_connection(index, lower_index); if ( (left_index >= 0) and (math.ceil(left_index / side_size) == node_row_index) ): self.__create_connection(index, left_index); if ( (right_index < self._num_osc) and (math.ceil(right_index / side_size) == node_row_index) ): self.__create_connection(index, right_index); def __create_grid_eight_connections(self): """! @brief Creates network with connections that make up eight grid structure. @details Each oscillator may be connected with eight neighbors in line with grid structure: right, right-upper, upper, upper-left, left, left-lower, lower, lower-right. """ self.__create_grid_four_connections(); # create connection with right, upper, left, lower. side_size = self.__width; for index in range(0, self._num_osc, 1): upper_left_index = index - side_size - 1; upper_right_index = index - side_size + 1; lower_left_index = index + side_size - 1; lower_right_index = index + side_size + 1; node_row_index = math.floor(index / side_size); upper_row_index = node_row_index - 1; lower_row_index = node_row_index + 1; if ( (upper_left_index >= 0) and (math.floor(upper_left_index / side_size) == upper_row_index) ): self.__create_connection(index, upper_left_index); if ( (upper_right_index >= 0) and (math.floor(upper_right_index / side_size) == upper_row_index) ): self.__create_connection(index, upper_right_index); if ( (lower_left_index < self._num_osc) and (math.floor(lower_left_index / side_size) == lower_row_index) ): self.__create_connection(index, lower_left_index); if ( (lower_right_index < self._num_osc) and (math.floor(lower_right_index / side_size) == lower_row_index) ): self.__create_connection(index, lower_right_index); def __create_list_bidir_connections(self): """! @brief Creates network as bidirectional list. @details Each oscillator may be conneted with two neighbors in line with classical list structure: right, left. """ if (self._conn_represent == conn_represent.MATRIX): for index in range(0, self._num_osc, 1): self._osc_conn.append([0] * self._num_osc); self._osc_conn[index][index] = False; if (index > 0): self._osc_conn[index][index - 1] = True; if (index < (self._num_osc - 1)): self._osc_conn[index][index + 1] = True; elif (self._conn_represent == conn_represent.LIST): for index in range(self._num_osc): self._osc_conn.append([]); if (index > 0): self._osc_conn[index].append(index - 1); if (index < (self._num_osc - 1)): self._osc_conn[index].append(index + 1); def __create_none_connections(self): """! @brief Creates network without connections. """ if (self._conn_represent == conn_represent.MATRIX): for _ in range(0, self._num_osc, 1): self._osc_conn.append([False] * self._num_osc); elif (self._conn_represent == conn_represent.LIST): self._osc_conn = [[] for _ in range(0, self._num_osc, 1)]; def __create_dynamic_connection(self): """! @brief Prepare storage for dynamic connections. """ if (self._conn_represent == conn_represent.MATRIX): for _ in range(0, self._num_osc, 1): self._osc_conn.append([False] * self._num_osc); elif (self._conn_represent == conn_represent.LIST): self._osc_conn = [[] for _ in range(0, self._num_osc, 1)]; def _create_structure(self, type_conn = conn_type.ALL_TO_ALL): """! @brief Creates connection in line with representation of matrix connections [NunOsc x NumOsc]. @param[in] type_conn (conn_type): Connection type (all-to-all, bidirectional list, grid structure, etc.) that is used by the network. """ self._osc_conn = list(); if (type_conn == conn_type.NONE): self.__create_none_connections(); elif (type_conn == conn_type.ALL_TO_ALL): self.__create_all_to_all_connections(); elif (type_conn == conn_type.GRID_FOUR): self.__create_grid_four_connections(); elif (type_conn == conn_type.GRID_EIGHT): self.__create_grid_eight_connections(); elif (type_conn == conn_type.LIST_BIDIR): self.__create_list_bidir_connections(); elif (type_conn == conn_type.DYNAMIC): self.__create_dynamic_connection(); else: raise NameError('The unknown type of connections'); def has_connection(self, i, j): """! @brief Returns True if there is connection between i and j oscillators and False - if connection doesn't exist. @param[in] i (uint): index of an oscillator in the network. @param[in] j (uint): index of an oscillator in the network. """ if (self._conn_represent == conn_represent.MATRIX): return (self._osc_conn[i][j]); elif (self._conn_represent == conn_represent.LIST): for neigh_index in range(0, len(self._osc_conn[i]), 1): if (self._osc_conn[i][neigh_index] == j): return True; return False; else: raise NameError("Unknown type of representation of coupling"); def set_connection(self, i, j): """! @brief Couples two specified oscillators in the network with dynamic connections. @param[in] i (uint): index of an oscillator that should be coupled with oscillator 'j' in the network. @param[in] j (uint): index of an oscillator that should be coupled with oscillator 'i' in the network. @note This method can be used only in case of DYNAMIC connections, otherwise it throws expection. """ if (self.structure != conn_type.DYNAMIC): raise NameError("Connection between oscillators can be changed only in case of dynamic type."); if (self._conn_represent == conn_represent.MATRIX): self._osc_conn[i][j] = True; self._osc_conn[j][i] = True; else: self._osc_conn[i].append(j); self._osc_conn[j].append(i); def get_neighbors(self, index): """! @brief Finds neighbors of the oscillator with specified index. @param[in] index (uint): index of oscillator for which neighbors should be found in the network. @return (list) Indexes of neighbors of the specified oscillator. """ if (self._conn_represent == conn_represent.LIST): return self._osc_conn[index]; # connections are represented by list. elif (self._conn_represent == conn_represent.MATRIX): return [neigh_index for neigh_index in range(self._num_osc) if self._osc_conn[index][neigh_index] == True]; else: raise NameError("Unknown type of representation of connections"); pyclustering-0.10.1.2/pyclustering/nnet/cnn.py000077500000000000000000000422161375753423500213330ustar00rootroot00000000000000"""! @brief Chaotic Neural Network @details Implementation based on paper @cite article::nnet::cnn::1, @cite inproceedings::nnet::cnn::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import numpy import random import matplotlib.pyplot as plt from matplotlib import rcParams from matplotlib.font_manager import FontProperties from enum import IntEnum from scipy.spatial import Delaunay from pyclustering.utils import euclidean_distance_square, average_neighbor_distance, heaviside, draw_dynamics class type_conn(IntEnum): """! @brief Enumeration of connection types for Chaotic Neural Network. @see cnn_network """ ## All oscillators have connection with each other. ALL_TO_ALL = 0, ## Connections between oscillators are created in line with Delaunay triangulation. TRIANGULATION_DELAUNAY = 1, class cnn_dynamic: """! @brief Container of output dynamic of the chaotic neural network where states of each neuron during simulation are stored. @see cnn_network """ def __init__(self, output=None, time=None): """! @brief Costructor of the chaotic neural network output dynamic. @param[in] output (list): Dynamic of oscillators on each step of simulation. @param[in] time (list): Simulation time. """ ## Output value of each neuron on each iteration. self.output = output or [] ## Sequence of simulation steps of the network. self.time = time or [] def __len__(self): """! @brief (uint) Returns amount of simulation steps that are stored. """ return len(self.output) def allocate_observation_matrix(self): """! @brief Allocates observation matrix in line with output dynamic of the network. @details Matrix where state of each neuron is denoted by zero/one in line with Heaviside function on each iteration. @return (list) Observation matrix of the network dynamic. """ number_neurons = len(self.output[0]) observation_matrix = [] for iteration in range(len(self.output)): obervation_column = [] for index_neuron in range(number_neurons): obervation_column.append(heaviside(self.output[iteration][index_neuron])) observation_matrix.append(obervation_column) return observation_matrix def __allocate_neuron_patterns(self, start_iteration, stop_iteration): """! @brief Allocates observation transposed matrix of neurons that is limited by specified periods of simulation. @details Matrix where state of each neuron is denoted by zero/one in line with Heaviside function on each iteration. @return (list) Transposed observation matrix that is limited by specified periods of simulation. """ pattern_matrix = [] for index_neuron in range(len(self.output[0])): pattern_neuron = [] for iteration in range(start_iteration, stop_iteration): pattern_neuron.append(heaviside(self.output[iteration][index_neuron])) pattern_matrix.append(pattern_neuron) return pattern_matrix def allocate_sync_ensembles(self, steps): """! @brief Allocate clusters in line with ensembles of synchronous neurons where each synchronous ensemble corresponds to only one cluster. @param[in] steps (double): Amount of steps from the end that is used for analysis. During specified period chaotic neural network should have stable output otherwise inccorect results are allocated. @return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ iterations = steps if iterations >= len(self.output): iterations = len(self.output) ensembles = [] start_iteration = len(self.output) - iterations end_iteration = len(self.output) pattern_matrix = self.__allocate_neuron_patterns(start_iteration, end_iteration) ensembles.append( [0] ) for index_neuron in range(1, len(self.output[0])): neuron_pattern = pattern_matrix[index_neuron][:] neuron_assigned = False for ensemble in ensembles: ensemble_pattern = pattern_matrix[ensemble[0]][:] if neuron_pattern == ensemble_pattern: ensemble.append(index_neuron) neuron_assigned = True break if neuron_assigned is False: ensembles.append( [index_neuron] ) return ensembles class cnn_visualizer: """! @brief Visualizer of output dynamic of chaotic neural network (CNN). """ @staticmethod def show_output_dynamic(cnn_output_dynamic): """! @brief Shows output dynamic (output of each neuron) during simulation. @param[in] cnn_output_dynamic (cnn_dynamic): Output dynamic of the chaotic neural network. @see show_dynamic_matrix @see show_observation_matrix """ draw_dynamics(cnn_output_dynamic.time, cnn_output_dynamic.output, x_title="t", y_title="x") @staticmethod def show_dynamic_matrix(cnn_output_dynamic): """! @brief Shows output dynamic as matrix in grey colors. @details This type of visualization is convenient for observing allocated clusters. @param[in] cnn_output_dynamic (cnn_dynamic): Output dynamic of the chaotic neural network. @see show_output_dynamic @see show_observation_matrix """ network_dynamic = numpy.array(cnn_output_dynamic.output) plt.imshow(network_dynamic.T, cmap=plt.get_cmap('gray'), interpolation='None', vmin=0.0, vmax=1.0) plt.show() @staticmethod def show_observation_matrix(cnn_output_dynamic): """! @brief Shows observation matrix as black/white blocks. @details This type of visualization is convenient for observing allocated clusters. @param[in] cnn_output_dynamic (cnn_dynamic): Output dynamic of the chaotic neural network. @see show_output_dynamic @see show_dynamic_matrix """ observation_matrix = numpy.array(cnn_output_dynamic.allocate_observation_matrix()) plt.imshow(observation_matrix.T, cmap = plt.get_cmap('gray'), interpolation='None', vmin = 0.0, vmax = 1.0) plt.show() class cnn_network: """! @brief Chaotic neural network based on system of logistic map where clustering phenomenon can be observed. @details Here is an example how to perform cluster analysis using chaotic neural network: @code from pyclustering.cluster import cluster_visualizer from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample from pyclustering.nnet.cnn import cnn_network, cnn_visualizer # Load stimulus from file. stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) # Create chaotic neural network, amount of neurons should be equal to amount of stimulus. network_instance = cnn_network(len(stimulus)) # Perform simulation during 100 steps. steps = 100 output_dynamic = network_instance.simulate(steps, stimulus) # Display output dynamic of the network. cnn_visualizer.show_output_dynamic(output_dynamic) # Display dynamic matrix and observation matrix to show clustering phenomenon. cnn_visualizer.show_dynamic_matrix(output_dynamic) cnn_visualizer.show_observation_matrix(output_dynamic) # Visualize clustering results. clusters = output_dynamic.allocate_sync_ensembles(10) visualizer = cluster_visualizer() visualizer.append_clusters(clusters, stimulus) visualizer.show() @endcode """ def __init__(self, num_osc, conn_type = type_conn.ALL_TO_ALL, amount_neighbors = 3): """! @brief Constructor of chaotic neural network. @param[in] num_osc (uint): Amount of neurons in the chaotic neural network. @param[in] conn_type (type_conn): CNN type connection for the network. @param[in] amount_neighbors (uint): k-nearest neighbors for calculation scaling constant of weights. """ self.__num_osc = num_osc self.__conn_type = conn_type self.__amount_neighbors = amount_neighbors self.__average_distance = 0.0 self.__weights = None self.__weights_summary = None self.__location = None # just for network visualization random.seed() self.__output = [ random.random() for _ in range(num_osc) ] def __len__(self): """! @brief Returns size of the chaotic neural network that is defined by amount of neurons. """ return self.__num_osc def simulate(self, steps, stimulus): """! @brief Simulates chaotic neural network with extrnal stimulus during specified steps. @details Stimulus are considered as a coordinates of neurons and in line with that weights are initialized. @param[in] steps (uint): Amount of steps for simulation. @param[in] stimulus (list): Stimulus that are used for simulation. @return (cnn_dynamic) Output dynamic of the chaotic neural network. """ self.__create_weights(stimulus) self.__location = stimulus dynamic = cnn_dynamic([], []) dynamic.output.append(self.__output) dynamic.time.append(0) for step in range(1, steps, 1): self.__output = self.__calculate_states() dynamic.output.append(self.__output) dynamic.time.append(step) return dynamic def __calculate_states(self): """! @brief Calculates new state of each neuron. @detail There is no any assignment. @return (list) Returns new states (output). """ output = [ 0.0 for _ in range(self.__num_osc) ] for i in range(self.__num_osc): output[i] = self.__neuron_evolution(i) return output def __neuron_evolution(self, index): """! @brief Calculates state of the neuron with specified index. @param[in] index (uint): Index of neuron in the network. @return (double) New output of the specified neuron. """ value = 0.0 for index_neighbor in range(self.__num_osc): value += self.__weights[index][index_neighbor] * (1.0 - 2.0 * (self.__output[index_neighbor] ** 2)) return value / self.__weights_summary[index] def __create_weights(self, stimulus): """! @brief Create weights between neurons in line with stimulus. @param[in] stimulus (list): External stimulus for the chaotic neural network. """ self.__average_distance = average_neighbor_distance(stimulus, self.__amount_neighbors) self.__weights = [ [ 0.0 for _ in range(len(stimulus)) ] for _ in range(len(stimulus)) ] self.__weights_summary = [ 0.0 for _ in range(self.__num_osc) ] if self.__conn_type == type_conn.ALL_TO_ALL: self.__create_weights_all_to_all(stimulus) elif self.__conn_type == type_conn.TRIANGULATION_DELAUNAY: self.__create_weights_delaunay_triangulation(stimulus) def __create_weights_all_to_all(self, stimulus): """! @brief Create weight all-to-all structure between neurons in line with stimulus. @param[in] stimulus (list): External stimulus for the chaotic neural network. """ for i in range(len(stimulus)): for j in range(i + 1, len(stimulus)): weight = self.__calculate_weight(stimulus[i], stimulus[j]) self.__weights[i][j] = weight self.__weights[j][i] = weight self.__weights_summary[i] += weight self.__weights_summary[j] += weight def __create_weights_delaunay_triangulation(self, stimulus): """! @brief Create weight Denlauny triangulation structure between neurons in line with stimulus. @param[in] stimulus (list): External stimulus for the chaotic neural network. """ points = numpy.array(stimulus) triangulation = Delaunay(points) for triangle in triangulation.simplices: for index_tri_point1 in range(len(triangle)): for index_tri_point2 in range(index_tri_point1 + 1, len(triangle)): index_point1 = triangle[index_tri_point1] index_point2 = triangle[index_tri_point2] weight = self.__calculate_weight(stimulus[index_point1], stimulus[index_point2]) self.__weights[index_point1][index_point2] = weight self.__weights[index_point2][index_point1] = weight self.__weights_summary[index_point1] += weight self.__weights_summary[index_point2] += weight def __calculate_weight(self, stimulus1, stimulus2): """! @brief Calculate weight between neurons that have external stimulus1 and stimulus2. @param[in] stimulus1 (list): External stimulus of the first neuron. @param[in] stimulus2 (list): External stimulus of the second neuron. @return (double) Weight between neurons that are under specified stimulus. """ distance = euclidean_distance_square(stimulus1, stimulus2) return math.exp(-distance / (2.0 * self.__average_distance)) def show_network(self): """! @brief Shows structure of the network: neurons and connections between them. """ dimension = len(self.__location[0]) if (dimension != 3) and (dimension != 2): raise NameError('Network that is located in different from 2-d and 3-d dimensions can not be represented') (fig, axes) = self.__create_surface(dimension) for i in range(0, self.__num_osc, 1): if dimension == 2: axes.plot(self.__location[i][0], self.__location[i][1], 'bo') for j in range(i, self.__num_osc, 1): # draw connection between two points only one time if self.__weights[i][j] > 0.0: axes.plot([self.__location[i][0], self.__location[j][0]], [self.__location[i][1], self.__location[j][1]], 'b-', linewidth = 0.5) elif dimension == 3: axes.scatter(self.__location[i][0], self.__location[i][1], self.__location[i][2], c = 'b', marker = 'o') for j in range(i, self.__num_osc, 1): # draw connection between two points only one time if self.__weights[i][j] > 0.0: axes.plot([self.__location[i][0], self.__location[j][0]], [self.__location[i][1], self.__location[j][1]], [self.__location[i][2], self.__location[j][2]], 'b-', linewidth = 0.5) plt.grid() plt.show() def __create_surface(self, dimension): """! @brief Prepares surface for showing network structure in line with specified dimension. @param[in] dimension (uint): Dimension of processed data (external stimulus). @return (tuple) Description of surface for drawing network structure. """ rcParams['font.sans-serif'] = ['Arial'] rcParams['font.size'] = 12 fig = plt.figure() axes = None if dimension == 2: axes = fig.add_subplot(111) elif dimension == 3: axes = fig.gca(projection='3d') surface_font = FontProperties() surface_font.set_name('Arial') surface_font.set_size('12') return (fig, axes)pyclustering-0.10.1.2/pyclustering/nnet/dynamic_visualizer.py000077500000000000000000000310211375753423500244460ustar00rootroot00000000000000"""! @brief Output dynamic visualizer @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import matplotlib.pyplot as plt from pyclustering.utils import set_ax_param class canvas_descr: """! @brief Describes plot where dynamic is displayed. @details Used by 'dynamic_visualizer' class. """ def __init__(self, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True): """! @brief Constructor of canvas. @param[in] x_title (string): Title for X axis, if 'None', then nothing is displayed. @param[in] y_title (string): Title for Y axis, if 'None', then nothing is displayed. @param[in] x_lim (list): Defines borders of X axis like [from, to], for example [0, 3.14], if 'None' then borders are calculated automatically. @param[in] y_lim (list): Defines borders of Y axis like [from, to], if 'None' then borders are calculated automatically. @param[in] x_labels (bool): If True then labels of X axis are displayed. @param[in] y_labels (bool): If True then labels of Y axis are displayed. """ ## Title for X axis. self.x_title = x_title; ## Title for Y axis. self.y_title = y_title; ## Borders of X axis. self.x_lim = x_lim; ## Borders of Y axis. self.y_lim = y_lim; ## Defines whether X label should be displayed. self.x_labels = x_labels; ## Defines whether Y label should be displayed. self.y_labels = y_labels; class dynamic_descr: """! @brief Output dynamic description that used to display. @details Used by 'dynamic_visualizer' class. """ def __init__(self, canvas, time, dynamics, separate, color): """! @brief Constructor of output dynamic descriptor. @param[in] canvas (uint): Index of canvas where dynamic should be displayed, in case of 'separate' representation this argument is considered as a first canvas from that displaying should be done. @param[in] time (list): Time points that are considered as a X axis. @param[in] dynamics (list): Dynamic or dynamics that should be displayed. @param[in] separate (bool|list): If 'True' then each dynamic is displayed on separate canvas, if it is defined by list, for example, [ [1, 2], [3, 4] ], then the first and the second dynamics are displayed on the canvas with index 'canvas' and the third and forth are displayed on the next 'canvas + 1' canvas. @param[in] color (string): Color that is used to display output dynamic(s). """ ## Index of canvas where (or from which) dynamic should be displayed. self.canvas = canvas; ## Time points. self.time = time; ## Dynamic or dynamics. self.dynamics = dynamics; ## Defines how dynamic(s) should be displayed. self.separate = self.__get_canonical_separate(separate); ## Color of dynamic. self.color = color; def get_axis_index(self, index_dynamic): """! @brief Returns index of canvas where specified dynamic (by index 'index_dynamic') should be displayed. @param[in] index_dynamic (uint): Index of dynamic that should be displayed. @return (uint) Index of canvas. """ return self.separate[index_dynamic]; def __get_canonical_separate(self, input_separate): """! @brief Return unified representation of separation value. @details It represents list whose size is equal to amount of dynamics, where index of dynamic will show where it should be displayed. @param[in] input_separate (bool|list): Input separate representation that should transformed. @return (list) Indexes where each dynamic should be displayed. """ if (isinstance(input_separate, list)): separate = [0] * len(self.dynamics[0]); for canvas_index in range(len(input_separate)): dynamic_indexes = input_separate[canvas_index]; for dynamic_index in dynamic_indexes: separate[dynamic_index] = canvas_index; return separate; elif (input_separate is False): if (isinstance(self.dynamics[0], list) is True): return [ self.canvas ] * len(self.dynamics[0]); else: return [ self.canvas ]; elif (input_separate is True): if (isinstance(self.dynamics[0], list) is True): return range(self.canvas, self.canvas + len(self.dynamics[0])); else: return [ self.canvas ]; else: raise Exception("Incorrect type of argument 'separate' '%s'." % type(input_separate)); class dynamic_visualizer: """! @brief Basic output dynamic visualizer. @details The aim of the visualizer is to displayed output dynamic of any process, for example, output dynamic of oscillatory network. """ def __init__(self, canvas, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True): """! @brief Construct dynamic visualizer. @details Default properties that are generalized in the constructor, for example, X axis title, can be changed by corresponding method: 'set_canvas_properties'. @param[in] canvas (uint): Amount of canvases that is used for visualization. @param[in] x_title (string): Title for X axis of canvases, if 'None', then nothing is displayed. @param[in] y_title (string): Title for Y axis of canvases, if 'None', then nothing is displayed. @param[in] x_lim (list): Defines borders of X axis like [from, to], for example [0, 3.14], if 'None' then borders are calculated automatically. @param[in] y_lim (list): Defines borders of Y axis like [from, to], if 'None' then borders are calculated automatically. @param[in] x_labels (bool): If True then labels of X axis are displayed. @param[in] y_labels (bool): If True then labels of Y axis are displayed. """ self.__size = canvas; self.__canvases = [ canvas_descr(x_title, y_title, x_lim, y_lim, x_labels, y_labels) for _ in range(canvas) ]; self.__dynamic_storage = []; def set_canvas_properties(self, canvas, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True): """! @brief Set properties for specified canvas. @param[in] canvas (uint): Index of canvas whose properties should changed. @param[in] x_title (string): Title for X axis, if 'None', then nothing is displayed. @param[in] y_title (string): Title for Y axis, if 'None', then nothing is displayed. @param[in] x_lim (list): Defines borders of X axis like [from, to], for example [0, 3.14], if 'None' then borders are calculated automatically. @param[in] y_lim (list): Defines borders of Y axis like [from, to], if 'None' then borders are calculated automatically. @param[in] x_labels (bool): If True then labels of X axis are displayed. @param[in] y_labels (bool): If True then labels of Y axis are displayed. """ self.__canvases[canvas] = canvas_descr(x_title, y_title, x_lim, y_lim, x_labels, y_labels); def append_dynamic(self, t, dynamic, canvas=0, color='blue'): """! @brief Append single dynamic to specified canvas (by default to the first with index '0'). @param[in] t (list): Time points that corresponds to dynamic values and considered on a X axis. @param[in] dynamic (list): Value points of dynamic that are considered on an Y axis. @param[in] canvas (uint): Canvas where dynamic should be displayed. @param[in] color (string): Color that is used for drawing dynamic on the canvas. """ description = dynamic_descr(canvas, t, dynamic, False, color); self.__dynamic_storage.append(description); self.__update_canvas_xlim(description.time, description.separate); def append_dynamics(self, t, dynamics, canvas=0, separate=False, color='blue'): """! @brief Append several dynamics to canvas or canvases (defined by 'canvas' and 'separate' arguments). @param[in] t (list): Time points that corresponds to dynamic values and considered on a X axis. @param[in] dynamics (list): Dynamics where each of them is considered on Y axis. @param[in] canvas (uint): Index of canvas where dynamic should be displayed, in case of 'separate' representation this argument is considered as a first canvas from that displaying should be done. @param[in] separate (bool|list): If 'True' then each dynamic is displayed on separate canvas, if it is defined by list, for example, [ [1, 2], [3, 4] ], then the first and the second dynamics are displayed on the canvas with index 'canvas' and the third and forth are displayed on the next 'canvas + 1' canvas. @param[in] color (string): Color that is used to display output dynamic(s). """ description = dynamic_descr(canvas, t, dynamics, separate, color); self.__dynamic_storage.append(description); self.__update_canvas_xlim(description.time, description.separate); def show(self, axis=None, display=True): """! @brief Draw and show output dynamics. @param[in] axis (axis): If is not 'None' then user specified axis is used to display output dynamic. @param[in] display (bool): Whether output dynamic should be displayed or not, if not, then user should call 'plt.show()' by himself. """ if (not axis): (_, axis) = plt.subplots(self.__size, 1); self.__format_canvases(axis); for dynamic in self.__dynamic_storage: self.__display_dynamic(axis, dynamic); if (display): plt.show(); def __display_dynamic(self, axis, dyn_descr): if (isinstance(dyn_descr.dynamics[0], list) is True): self.__display_multiple_dynamic(axis, dyn_descr); else: self.__display_single_dynamic(axis, dyn_descr); def __display_multiple_dynamic(self, axis, dyn_descr): num_items = len(dyn_descr.dynamics[0]); for index in range(0, num_items, 1): y = [item[index] for item in dyn_descr.dynamics]; axis_index = dyn_descr.get_axis_index(index); ax = self.__get_axis(axis, axis_index); ax.plot(dyn_descr.time, y, 'b-', linewidth = 0.5); def __display_single_dynamic(self, axis, dyn_descr): ax = self.__get_axis(axis, dyn_descr.canvas); ax.plot(dyn_descr.time, dyn_descr.dynamics, 'b-', linewidth = 0.5); def __format_canvases(self, axis): for index in range(self.__size): canvas = self.__canvases[index]; ax = self.__get_axis(axis, index); set_ax_param(ax, canvas.x_title, canvas.y_title, canvas.x_lim, canvas.y_lim, canvas.x_labels, canvas.y_labels, True); if ( (len(self.__canvases) > 1) and (index != len(self.__canvases) - 1) ): ax.get_xaxis().set_visible(False); def __update_canvas_xlim(self, t, separate): for index in separate: self.__update_single_canvas_xlim(index, t); def __update_single_canvas_xlim(self, canvas_index, t): dynamic_xlim = [0, t[len(t) - 1]]; if ( (self.__canvases[canvas_index].x_lim is None) or (self.__canvases[canvas_index].x_lim < dynamic_xlim) ): self.__canvases[canvas_index].x_lim = dynamic_xlim; def __get_axis(self, axis, index): if (index >= len(self.__canvases)): raise Exception("Impossible to get axis with index '%d' - total number of canvases '%d'." % index, len(self.__canvases)); ax = axis; if (self.__size > 1): ax = axis[index]; return ax;pyclustering-0.10.1.2/pyclustering/nnet/examples/000077500000000000000000000000001375753423500220115ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/nnet/examples/__init__.py000077500000000000000000000000001375753423500241130ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/nnet/examples/cnn_examples.py000077500000000000000000000050721375753423500250460ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of chaotic oscillatory network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.cnn import cnn_network, cnn_visualizer, type_conn; from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES; from pyclustering.utils import read_sample; def template_dynamic_cnn(num_osc, steps, stimulus, neighbors, connection, show_network = False): network_instance = cnn_network(num_osc, connection, amount_neighbors = neighbors); output_dynamic = network_instance.simulate(steps, stimulus); print(output_dynamic.allocate_sync_ensembles(10)); if (show_network is True): network_instance.show_network(); cnn_visualizer.show_output_dynamic(output_dynamic); cnn_visualizer.show_dynamic_matrix(output_dynamic); cnn_visualizer.show_observation_matrix(output_dynamic); def chaotic_clustering_sample_simple_01(): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); template_dynamic_cnn(len(sample), 100, sample, 3, type_conn.ALL_TO_ALL); def chaotic_clustering_triangulation_sample_simple_01(): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); template_dynamic_cnn(len(sample), 100, sample, 3, type_conn.TRIANGULATION_DELAUNAY); def chaotic_clustering_sample_simple_02(): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); template_dynamic_cnn(len(sample), 100, sample, 3, type_conn.ALL_TO_ALL); def chaotic_clustering_triangulation_sample_simple_02(): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); template_dynamic_cnn(len(sample), 100, sample, 5, type_conn.TRIANGULATION_DELAUNAY); def chaotic_clustering_sample_simple_03(): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3); template_dynamic_cnn(len(sample), 100, sample, 10, type_conn.ALL_TO_ALL); def chaotic_clustering_sample_simple_04(): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4); template_dynamic_cnn(len(sample), 100, sample, 5, type_conn.ALL_TO_ALL); def chaotic_clustering_fcps_lsun(): sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN); template_dynamic_cnn(len(sample), 100, sample, 10, type_conn.ALL_TO_ALL); chaotic_clustering_sample_simple_01(); chaotic_clustering_triangulation_sample_simple_01(); chaotic_clustering_sample_simple_02(); chaotic_clustering_triangulation_sample_simple_02(); chaotic_clustering_sample_simple_03(); chaotic_clustering_sample_simple_04(); chaotic_clustering_fcps_lsun(); pyclustering-0.10.1.2/pyclustering/nnet/examples/fsync_examples.py000077500000000000000000000047301375753423500254120ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Oscillatory Neural Network based on Kuramoto model and Landau-Stuart oscillator. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet import conn_type; from pyclustering.nnet.fsync import fsync_network, fsync_visualizer; def template_dynamic_sync(num_osc, steps, time, frequency = 1.0, radius = 1.0, coupling = 1.0, conn = conn_type.ALL_TO_ALL, collect_dyn = True): network = fsync_network(num_osc, frequency, radius, coupling, type_conn = conn); fsync_output_dynamic = network.simulate(steps, time, collect_dynamic = collect_dyn); fsync_visualizer.show_output_dynamic(fsync_output_dynamic); return network; def one_landau_stuart_oscillators(): template_dynamic_sync(1, 100, 20, 1.0, 1.0, 1.0); def five_oscillators_all_to_all_structure(): template_dynamic_sync(5, 100, 20, 1.0, 1.0, 1.0, conn_type.ALL_TO_ALL); def twenty_oscillators_all_to_all_structure(): template_dynamic_sync(20, 100, 20, 1.0, 1.0, 1.0, conn_type.ALL_TO_ALL); def twenty_oscillators_all_to_all_structure_weak_coupling(): template_dynamic_sync(20, 100, 20, 1.0, 1.0, 0.01, conn_type.ALL_TO_ALL); def five_oscillators_grid_four_structure(): template_dynamic_sync(9, 100, 20, 1.0, 1.0, 1.0, conn_type.GRID_FOUR); def five_oscillators_bidir_structure(): template_dynamic_sync(5, 100, 20, 1.0, 1.0, 1.0, conn_type.LIST_BIDIR); def two_oscillators_different_frequency(): template_dynamic_sync(2, 100, 20, [1.0, 2.0], 1.0, 1.0, conn_type.ALL_TO_ALL); def two_oscillators_different_radius(): template_dynamic_sync(2, 100, 20, 1.0, [1.0, 4.0], 1.0, conn_type.ALL_TO_ALL); def three_oscillators_different_properties(): template_dynamic_sync(3, 100, 20, [1.0, 1.3, 1.6], [1.0, 4.0, 2.0], 1.0, conn_type.ALL_TO_ALL); def three_oscillators_different_properties_weak_coupling(): template_dynamic_sync(3, 100, 20, [1.0, 1.1, 1.2], [1.0, 4.0, 2.0], 0.1, conn_type.ALL_TO_ALL); one_landau_stuart_oscillators(); five_oscillators_all_to_all_structure(); twenty_oscillators_all_to_all_structure(); twenty_oscillators_all_to_all_structure_weak_coupling(); five_oscillators_grid_four_structure(); five_oscillators_bidir_structure(); two_oscillators_different_frequency(); two_oscillators_different_radius(); three_oscillators_different_properties(); three_oscillators_different_properties_weak_coupling();pyclustering-0.10.1.2/pyclustering/nnet/examples/hhn_examples.py000077500000000000000000000117301375753423500250430ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of oscillatory network based on Hodgkin-Huxley model of neuron. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.dynamic_visualizer import dynamic_visualizer from pyclustering.nnet.hhn import hhn_network, hhn_parameters def template_dynamic_hhn(num_osc, steps, time, stimulus=None, params=None, separate=False, ccore_flag=False): net = hhn_network(num_osc, stimulus, params, ccore=ccore_flag) (t, dyn_peripheral, dyn_central) = net.simulate(steps, time) amount_canvases = 1 if (isinstance(separate, list)): amount_canvases = len(separate) + 2 elif (separate is True): amount_canvases = len(dyn_peripheral[0]) + 2 visualizer = dynamic_visualizer(amount_canvases, x_title="Time", y_title="V", y_labels=False) visualizer.append_dynamics(t, dyn_peripheral, 0, separate) visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True) visualizer.show() def one_oscillator_unstimulated(): template_dynamic_hhn(1, 750, 100, separate=True, ccore_flag=False) template_dynamic_hhn(1, 750, 100, separate=True, ccore_flag=True) def one_oscillator_stimulated(): template_dynamic_hhn(1, 750, 100, [25], separate=True, ccore_flag=False) template_dynamic_hhn(1, 750, 100, [25], separate=True, ccore_flag=True) def three_oscillators_stimulated(): template_dynamic_hhn(3, 750, 100, [25] * 3, separate=True, ccore_flag=False) template_dynamic_hhn(3, 750, 100, [25] * 3, separate=True, ccore_flag=True) def two_sync_ensembles(): template_dynamic_hhn(4, 400, 200, [25, 25, 50, 50], separate=True, ccore_flag=False) template_dynamic_hhn(4, 800, 200, [25, 25, 50, 50], separate=True, ccore_flag=True) def ten_oscillators_stimulated_desync(): params = hhn_parameters() params.w1 = 0 params.w2 = 0 params.w3 = 0 stumulus = [25, 25, 25, 25, 25, 11, 11, 11, 11, 11] template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=False) template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=True) def ten_oscillators_stimulated_sync(): params = hhn_parameters() params.w1 = 0.1 params.w2 = 0.0 params.w3 = 0 stumulus = [25, 25, 25, 25, 25, 27, 27, 27, 27, 27] template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=False) template_dynamic_hhn(10, 750, 100, stumulus, params, separate=True, ccore_flag=True) def ten_oscillators_stimulated_partial_sync(): params = hhn_parameters() params.w1 = 0.1 params.w2 = 5.0 params.w3 = 0 stimulus = [25, 25, 25, 25, 25, 11, 11, 11, 11, 11] template_dynamic_hhn(10, 750, 200, stimulus, params, separate=True, ccore_flag=False) template_dynamic_hhn(10, 750, 200, stimulus, params, separate=True, ccore_flag=True) def six_oscillators_mix_2_stimulated(): params = hhn_parameters() params.deltah = 400 stimulus = [25, 25, 25, 47, 47, 47] template_dynamic_hhn(6, 1200, 600, stimulus, params, separate=True, ccore_flag=False) template_dynamic_hhn(6, 2400, 600, stimulus, params, separate=True, ccore_flag=True) def six_oscillators_mix_3_stimulated(): params = hhn_parameters() params.deltah = 400 stimulus = [0, 0, 25, 25, 47, 47] template_dynamic_hhn(6, 1200, 600, stimulus, params, separate=True, ccore_flag=False) template_dynamic_hhn(6, 2400, 600, stimulus, params, separate=True, ccore_flag=True) def three_sync_ensembles(): params = hhn_parameters() params.deltah = 400 stimulus = [25, 26, 25, 25, 26, 45, 46, 45, 44, 45, 65, 65, 65, 64, 66] separate = [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12, 13, 14]] num_osc = len(stimulus) template_dynamic_hhn(num_osc, 2400, 600, stimulus, params, separate=separate, ccore_flag=True) def four_ensembles_80_oscillators(): params = hhn_parameters() params.deltah = 650 params.w1 = 0.1 params.w2 = 9.0 params.w3 = 5.0 params.threshold = -10 expected_ensembles = [] stimulus = [] base_stimulus = 10 step_stimulus = 10 amount_ensebles = 4 region_size = 20 for i in range(amount_ensebles): expected_ensembles += [ [i for i in range(region_size * i, region_size * i + region_size)] ] stimulus += [ base_stimulus + step_stimulus * i ] * region_size template_dynamic_hhn(len(stimulus), 4000, 1000, stimulus, params, separate=expected_ensembles, ccore_flag=True) one_oscillator_unstimulated() one_oscillator_stimulated() three_oscillators_stimulated() two_sync_ensembles() ten_oscillators_stimulated_desync() ten_oscillators_stimulated_sync() ten_oscillators_stimulated_partial_sync() six_oscillators_mix_2_stimulated() six_oscillators_mix_3_stimulated() three_sync_ensembles() four_ensembles_80_oscillators() pyclustering-0.10.1.2/pyclustering/nnet/examples/hhn_segmentation.py000077500000000000000000000164521375753423500257300ustar00rootroot00000000000000"""! @brief Segmentation example of Hodgkin-Huxley oscillatory network for image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import os.path import pickle from PIL import Image import matplotlib.pyplot as plt import matplotlib.animation as animation from pyclustering.cluster.dbscan import dbscan from pyclustering.nnet.dynamic_visualizer import dynamic_visualizer from pyclustering.nnet.hhn import hhn_network, hhn_parameters from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES from pyclustering.utils import read_image, rgb2gray def animate_segmentation(dyn_time, dyn_peripheral, image, delay_mask=100, step=5, movie_file=None): image_source = Image.open(image) image_size = image_source.size figure = plt.figure() image_pixel_fired = [-1] * (image_size[0] * image_size[1]) basic_transparence_value = 255 y_global_max = float('-Inf') y_global_min = float('+Inf') for dyn in dyn_peripheral: y_max = max(dyn) if (y_global_max < y_max): y_global_max = y_max y_min = min(dyn) if (y_global_min > y_min): y_global_min = y_min print(y_global_min, y_global_max) ylim = [y_global_min - abs(y_global_min) * 0.1, y_global_max + abs(y_global_max) * 0.05] def init_frame(): return frame_generation(0) def frame_generation(index_iteration): print(index_iteration) figure.clf() figure.suptitle("Hodgkin-Huxley Network (iteration: " + str(index_iteration) +")", fontsize = 18, fontweight = 'bold') ax1 = figure.add_subplot(121) ax2 = figure.add_subplot(122) end_iteration = index_iteration if (end_iteration > len(dyn_peripheral)): end_iteration = len(dyn_peripheral) dynamic_length = 100 begin_iteration = end_iteration - dynamic_length if begin_iteration < 0: begin_iteration = 0 # Display output dynamic xlim = [dyn_time[begin_iteration], dyn_time[begin_iteration + dynamic_length]] visualizer = dynamic_visualizer(1, x_title="Time", y_title="V", x_lim=xlim, y_lim=ylim) dyn_time_segment = [ dyn_time[i] for i in range(begin_iteration, end_iteration, 1) ] dyn_peripheral_segment = [ dyn_peripheral[i] for i in range(begin_iteration, end_iteration, 1) ] visualizer.append_dynamic(dyn_time_segment, dyn_peripheral_segment) visualizer.show(ax1, False) visualize_segmenetation(end_iteration, ax2, step) return [ figure.gca() ] def visualize_segmenetation(t, segm_axis, step): image_result = image_source.copy() image_cluster = None if (t > step): t -= step for _ in range(step): image_color_segments = [(255, 255, 255, 0)] * (image_size[0] * image_size[1]) for index_pixel in range(len(image_pixel_fired)): fire_time = image_pixel_fired[index_pixel] if ( (fire_time > 0) and (t - fire_time < delay_mask) ): color_value = 0 + (t - fire_time) transparence = basic_transparence_value - (t - fire_time) if (transparence < 0): transparence = 0 image_color_segments[index_pixel] = (color_value, color_value, color_value, transparence) for index_oscillator in range(len(dyn_peripheral[t])): if (dyn_peripheral[t][index_oscillator] > 0): image_color_segments[index_oscillator] = (0, 0, 0, basic_transparence_value) image_pixel_fired[index_oscillator] = t stage = numpy.array(image_color_segments, numpy.uint8) stage = numpy.reshape(stage, image_size + ((4),)) # ((3),) it's size of RGB - third dimension. image_cluster = Image.fromarray(stage, 'RGBA') t += 1 image_result.paste(image_cluster, (0, 0), image_cluster) return segm_axis.imshow(image_result) iterations = range(1, len(dyn_peripheral), step) segmentation_animation = animation.FuncAnimation(figure, frame_generation, iterations, init_func=None, interval = 1, repeat_delay = 3000) if (not movie_file): segmentation_animation.save(movie_file, writer = 'ffmpeg', fps = 20, bitrate = 3000) else: plt.show() def template_image_segmentation(image_file, steps, time, dynamic_file_prefix): image = read_image(image_file); stimulus = rgb2gray(image); params = hhn_parameters(); params.deltah = 650; params.w1 = 0.1; params.w2 = 9.0; params.w3 = 5.0; params.threshold = -10; stimulus = [255.0 - pixel for pixel in stimulus]; divider = max(stimulus) / 50.0; stimulus = [int(pixel / divider) for pixel in stimulus]; t, dyn_peripheral, dyn_central = None, None, None; if ( not os.path.exists(dynamic_file_prefix + 'dynamic_time.txt') or not os.path.exists(dynamic_file_prefix + 'dynamic_peripheral.txt') or not os.path.exists(dynamic_file_prefix + 'dynamic_dyn_central.txt') ): print("File with output dynamic is not found - simulation will be performed - it may take some time, be patient."); net = hhn_network(len(stimulus), stimulus, params, ccore=True); (t, dyn_peripheral, dyn_central) = net.simulate(steps, time); print("Store dynamic to save time for simulation next time."); with open(dynamic_file_prefix + 'dynamic_time.txt', 'wb') as file_descriptor: pickle.dump(t, file_descriptor); with open(dynamic_file_prefix + 'dynamic_peripheral.txt', 'wb') as file_descriptor: pickle.dump(dyn_peripheral, file_descriptor); with open(dynamic_file_prefix + 'dynamic_dyn_central.txt', 'wb') as file_descriptor: pickle.dump(dyn_central, file_descriptor); else: print("Load output dynamic from file."); with open (dynamic_file_prefix + 'dynamic_time.txt', 'rb') as file_descriptor: t = pickle.load(file_descriptor); with open (dynamic_file_prefix + 'dynamic_peripheral.txt', 'rb') as file_descriptor: dyn_peripheral = pickle.load(file_descriptor); with open (dynamic_file_prefix + 'dynamic_dyn_central.txt', 'rb') as file_descriptor: dyn_central = pickle.load(file_descriptor); animate_segmentation(t, dyn_peripheral, image_file, 200); # just for checking correctness of results - let's use classical algorithm if (False): dbscan_instance = dbscan(image, 3, 4, True); dbscan_instance.process(); trustable_clusters = dbscan_instance.get_clusters(); amount_canvases = len(trustable_clusters) + 2; visualizer = dynamic_visualizer(amount_canvases, x_title = "Time", y_title = "V", y_labels = False); visualizer.append_dynamics(t, dyn_peripheral, 0, trustable_clusters); visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True); visualizer.show(); def segmentation_image_simple1(): template_image_segmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, 7000, 600, "simple1") segmentation_image_simple1()pyclustering-0.10.1.2/pyclustering/nnet/examples/hysteresis_examples.py000077500000000000000000000041751375753423500264750ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Hysteresis Oscillatory Network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.hysteresis import hysteresis_network, hysteresis_visualizer; from pyclustering.nnet import *; def template_dynamic(num_osc, own_weight = -3, neigh_weight = -1, initial_states = None, initial_outputs = None, steps = 1000, time = 10): network = hysteresis_network(num_osc, own_weight, neigh_weight); if (initial_states is not None): network.states = initial_states; if (initial_outputs is not None): network.outputs = initial_outputs; output_dynamic = network.simulate(steps, time); hysteresis_visualizer.show_output_dynamic(output_dynamic); ensembles = output_dynamic.allocate_sync_ensembles(tolerance = 0.5, threshold_steps = 5); print("Allocated synchronous ensembles ( amout:", len(ensembles), "):", ensembles); def one_oscillator_weight_2(): template_dynamic(1, -2); def one_oscillator_weight_4(): template_dynamic(1, -4); def two_oscillators_sync(): "Comment: Different initial state - state of sync. will be reached." template_dynamic(2, -4, 1, [1, 0], [1, 1]); def two_oscillators_desync(): "Note: if initial state is the same for both oscillators then desync. will not be exist. It is very important to set different values if desync. is required." template_dynamic(2, -4, -1, [1, 0], [1, 1]); def five_oscillators_positive_conn(): "Note: Oscillations are dead in this case (sync. should be in ideal case)" template_dynamic(5, -4, 1, [1, 0.5, 0, -0.5, -1], [1, 1, 1, 1, 1]); template_dynamic(5, -4, 1, [1, 0.8, 0.6, 0.4, 0.2], [-1, -1, -1, -1, -1]); def five_oscillators_negative_conn(): "Comment: Full desync." template_dynamic(5, -4, -1, [1, 0.5, 0, -0.5, -1], [1, 1, 1, 1, 1]); one_oscillator_weight_2(); one_oscillator_weight_4(); two_oscillators_sync(); two_oscillators_desync(); five_oscillators_positive_conn(); five_oscillators_negative_conn();pyclustering-0.10.1.2/pyclustering/nnet/examples/legion_examples.py000077500000000000000000000145371375753423500255530ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Local Excitatory Global Inhibitory Oscillatory Network (LEGION). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils import draw_dynamics; from pyclustering.nnet.legion import legion_network, legion_parameters; from pyclustering.nnet import *; def template_dynamic_legion(num_osc, steps, time, conn_type, stimulus, params = None, separate_repr = True, ccore_flag = True): net = legion_network(num_osc, params, conn_type, ccore = ccore_flag); print("Created"); dynamic = net.simulate(steps, time, stimulus, solution = solve_type.RK4); print("Simulated"); draw_dynamics(dynamic.time, dynamic.output, x_title = "Time", y_title = "x(t)", separate = separate_repr); draw_dynamics(dynamic.time, dynamic.inhibitor, x_title = "Time", y_title = "z(t)"); ensembles = dynamic.allocate_sync_ensembles(0.1); print(ensembles); def one_oscillator_unstimulated(): parameters = legion_parameters(); parameters.teta = 0; # because no neighbors at all template_dynamic_legion(1, 2000, 500, conn_type.NONE, [0], parameters); def one_oscillator_stimulated(): parameters = legion_parameters(); parameters.teta = 0; # because no neighbors at all template_dynamic_legion(1, 2000, 500, conn_type.NONE, [1], parameters); def three_oscillator_unstimulated_list(): parameters = legion_parameters(); parameters.teta = 0; # because no stmulated neighbors template_dynamic_legion(3, 2000, 200, conn_type.LIST_BIDIR, [0, 0, 0], parameters); def three_oscillator_stimulated_list(): template_dynamic_legion(3, 1500, 1500, conn_type = conn_type.LIST_BIDIR, stimulus = [1, 1, 1]); def three_oscillator_mix_stimulated_list(): parameters = legion_parameters(); parameters.Wt = 4.0; template_dynamic_legion(3, 1200, 1200, conn_type = conn_type.LIST_BIDIR, stimulus = [1, 0, 1], params = parameters); def ten_oscillator_stimulated_list(): template_dynamic_legion(10, 1000, 750, conn_type = conn_type.LIST_BIDIR, stimulus = [1] * 10); def ten_oscillator_mix_stimulated_list(): template_dynamic_legion(10, 1500, 1500, conn_type = conn_type.LIST_BIDIR, stimulus = [1, 1, 1, 0, 0, 0, 1, 1, 0, 0], separate_repr = [ [0, 1, 2], [3, 4, 5, 8, 9], [6, 7] ]); def thirteen_oscillator_three_stimulated_ensembles_list(): "Good example of three synchronous ensembels" "Not accurate due to false skipes are observed" parameters = legion_parameters(); parameters.Wt = 4.0; parameters.fi = 10.0; template_dynamic_legion(15, 1000, 1000, conn_type = conn_type.LIST_BIDIR, stimulus = [1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1], params = parameters, separate_repr = [ [0, 1, 2], [3, 4, 5, 9, 10], [6, 7, 8], [11, 12, 13, 14] ]); def thirteen_simplify_oscillator_three_stimulated_ensembles_list(): "Good example of three synchronous ensembels" "Not accurate due to false skipes are observed" parameters = legion_parameters(); parameters.Wt = 4.0; parameters.fi = 0.8; parameters.ENABLE_POTENTIONAL = False; template_dynamic_legion(15, 1000, 1000, conn_type = conn_type.LIST_BIDIR, stimulus = [1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1], params = parameters, separate_repr = [ [0, 1, 2], [3, 4, 5, 9, 10], [6, 7, 8], [11, 12, 13, 14] ]); def sixteen_oscillator_two_stimulated_ensembles_grid(): "Not accurate false due to spikes are observed" parameters = legion_parameters(); parameters.teta_x = -1.1; template_dynamic_legion(16, 2000, 1500, conn_type = conn_type.GRID_FOUR, params = parameters, stimulus = [1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1]); def simple_segmentation_example(): "Perfect results!" parameters = legion_parameters(); parameters.eps = 0.02; parameters.alpha = 0.005; parameters.betta = 0.1; parameters.gamma = 7.0; parameters.teta = 0.9; parameters.lamda = 0.1; parameters.teta_x = -0.5; parameters.teta_p = 7.0; parameters.Wz = 0.7; parameters.mu = 0.01; parameters.fi = 3.0; parameters.teta_xz = 0.1; parameters.teta_zx = 0.1; parameters.ENABLE_POTENTIONAL = False; template_dynamic_legion(81, 2500, 2500, conn_type = conn_type.GRID_FOUR, params = parameters, stimulus = [1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0], separate_repr = [ [0, 1, 2, 9, 10, 11, 18, 19, 20], [14, 15, 16, 17, 23, 24, 25, 26, 33, 34, 35, 42, 43, 44, 51, 52, 53], [45, 46, 47, 48, 54, 55, 56, 57, 63, 64, 65, 66, 72, 73, 74, 75] ]); one_oscillator_unstimulated(); one_oscillator_stimulated(); three_oscillator_unstimulated_list(); three_oscillator_stimulated_list(); three_oscillator_mix_stimulated_list(); ten_oscillator_stimulated_list(); ten_oscillator_mix_stimulated_list(); thirteen_oscillator_three_stimulated_ensembles_list(); thirteen_simplify_oscillator_three_stimulated_ensembles_list(); sixteen_oscillator_two_stimulated_ensembles_grid(); simple_segmentation_example();pyclustering-0.10.1.2/pyclustering/nnet/examples/legion_segmentation.py000077500000000000000000000045441375753423500264270ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of LEGION. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from PIL import Image; from pyclustering.utils import draw_dynamics; from pyclustering.utils import read_image, rgb2gray, draw_image_mask_segments; from pyclustering.nnet.legion import legion_network, legion_parameters; from pyclustering.nnet import *; from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES; from pyclustering.cluster.dbscan import dbscan; def template_segmentation_image(image_file, parameters, steps, time, ccore_flag = True): image = read_image(image_file); stimulus = rgb2gray(image); for pixel_index in range(len(stimulus)): if (stimulus[pixel_index] < 235): stimulus[pixel_index] = 1; else: stimulus[pixel_index] = 0; if (parameters is None): parameters = legion_parameters(); net = legion_network(len(stimulus), parameters, conn_type.GRID_FOUR, ccore = ccore_flag); output_dynamic = net.simulate(steps, time, stimulus); ensembles = output_dynamic.allocate_sync_ensembles(); draw_image_mask_segments(image_file, ensembles); # draw_dynamics(output_dynamic.time, output_dynamic.output, x_title = "Time", y_title = "x(t)", separate = ensembles); # just for checking correctness of results - let's use classical algorithm dbscan_instance = dbscan(image, 3, 4, True); dbscan_instance.process(); trustable_clusters = dbscan_instance.get_clusters(); draw_dynamics(output_dynamic.time, output_dynamic.output, x_title = "Time", y_title = "x(t)", separate = trustable_clusters); def segmentation_image_simple1(): "Perfect" parameters = legion_parameters(); parameters.eps = 0.02; parameters.alpha = 0.005; parameters.betta = 0.1; parameters.gamma = 7.0; parameters.teta = 0.9; parameters.lamda = 0.1; parameters.teta_x = -0.5; parameters.teta_p = 7.0; parameters.Wz = 0.7; parameters.mu = 0.01; parameters.fi = 3.0; parameters.teta_xz = 0.1; parameters.teta_zx = 0.1; parameters.ENABLE_POTENTIONAL = False; template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE12, parameters, 2000, 2000, True); segmentation_image_simple1();pyclustering-0.10.1.2/pyclustering/nnet/examples/pcnn_examples.py000077500000000000000000000103241375753423500252220ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Pulse Coupled Neural Network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.utils import draw_dynamics; from pyclustering.utils import read_image, rgb2gray, draw_image_mask_segments; from pyclustering.nnet.pcnn import pcnn_network, pcnn_parameters; from pyclustering.nnet import *; from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES; from pyclustering.nnet.pcnn import pcnn_visualizer def template_dynamic_pcnn(num_osc, steps, stimulus = None, params = None, conn_type = conn_type.NONE, separate_representation = True, ccore_flag = True): net = pcnn_network(num_osc, params, conn_type, ccore = ccore_flag); dynamic = net.simulate(steps, stimulus); ensembles = dynamic.allocate_sync_ensembles(); print("Number of objects:", len(ensembles), "\nEnsembles:", ensembles); pcnn_visualizer.show_output_dynamic(dynamic); return ensembles; def one_neuron_unstimulated(): template_dynamic_pcnn(1, 100, [0]); def one_neuron_stimulated(): template_dynamic_pcnn(1, 100, [1]); def nine_neurons_stimulated_one_sync(): "Just dynamic demonstration" params = pcnn_parameters(); template_dynamic_pcnn(9, 100, [1.0] * 9, params, conn_type.GRID_FOUR); def nine_neurons_mix_stimulated(): "Just dynamic demonstration" template_dynamic_pcnn(9, 100, [1, 1, 1, 0, 0, 0, 1, 1, 1], None, conn_type.GRID_FOUR); def twenty_five_neurons_mix_stimulated(): "Object allocation" "If M = 0 then only object will be allocated" params = pcnn_parameters(); params.AF = 0.1; params.AL = 0.0; params.AT = 0.7; params.VF = 1.0; params.VL = 1.0; params.VT = 10.0; params.M = 0.0; template_dynamic_pcnn(25, 100, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0], params, conn_type.GRID_FOUR, False); def hundred_neurons_mix_stimulated(): "Allocate several clusters: the first contains borders (indexes of oscillators) and the second objects (indexes of oscillators)" params = pcnn_parameters(); params.AF = 0.1; params.AL = 0.1; params.AT = 0.8; params.VF = 1.0; params.VL = 1.0; params.VT = 20.0; params.W = 1.0; params.M = 1.0; template_dynamic_pcnn(100, 50, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], params, conn_type.GRID_EIGHT, False); def segmentation_double_t(): image = read_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE10); image = rgb2gray(image); for pixel_index in range(len(image)): if (image[pixel_index] < 128): image[pixel_index] = 1; else: image[pixel_index] = 0; params = pcnn_parameters(); params.AF = 0.1; params.AL = 0.1; params.AT = 0.8; params.VF = 1.0; params.VL = 1.0; params.VT = 20.0; params.W = 1.0; params.M = 1.0; ensembles = template_dynamic_pcnn(32 * 32, 28, image, params, conn_type.GRID_EIGHT, False); draw_image_mask_segments(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE10, ensembles); one_neuron_unstimulated(); one_neuron_stimulated(); nine_neurons_stimulated_one_sync(); nine_neurons_mix_stimulated(); twenty_five_neurons_mix_stimulated(); hundred_neurons_mix_stimulated(); segmentation_double_t();pyclustering-0.10.1.2/pyclustering/nnet/examples/pcnn_segmentation.py000077500000000000000000000136671375753423500261160ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Pulse Coupled Neural Network in image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from PIL import Image from pyclustering.utils import read_image, rgb2gray, draw_image_mask_segments from pyclustering.nnet.pcnn import pcnn_network, pcnn_parameters, pcnn_visualizer from pyclustering.nnet import * from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES, IMAGE_MAP_SAMPLES, IMAGE_REAL_SAMPLES def template_segmentation_image(image, parameters, simulation_time, brightness, scale_color=True, fastlinking=False, show_spikes=False, ccore_flag=True): image_source = Image.open(image) image_size = image_source.size width = image_size[0] height = image_size[1] stimulus = read_image(image) stimulus = rgb2gray(stimulus) if brightness is not None: for pixel_index in range(len(stimulus)): if stimulus[pixel_index] < brightness: stimulus[pixel_index] = 1 else: stimulus[pixel_index] = 0 else: maximum_stimulus = float(max(stimulus)) minimum_stimulus = float(min(stimulus)) delta = maximum_stimulus - minimum_stimulus for pixel_index in range(len(stimulus)): if scale_color is True: stimulus[pixel_index] = 1.0 - ((float(stimulus[pixel_index]) - minimum_stimulus) / delta) else: stimulus[pixel_index] = float(stimulus[pixel_index]) / 255 if parameters is None: parameters = pcnn_parameters() parameters.AF = 0.1 parameters.AL = 0.1 parameters.AT = 0.8 parameters.VF = 1.0 parameters.VL = 1.0 parameters.VT = 30.0 parameters.W = 1.0 parameters.M = 1.0 parameters.FAST_LINKING = fastlinking net = pcnn_network(len(stimulus), parameters, conn_type.GRID_EIGHT, height=height, width=width, ccore=ccore_flag) output_dynamic = net.simulate(simulation_time, stimulus) pcnn_visualizer.show_output_dynamic(output_dynamic) ensembles = output_dynamic.allocate_sync_ensembles() draw_image_mask_segments(image, ensembles) pcnn_visualizer.show_time_signal(output_dynamic) if show_spikes is True: spikes = output_dynamic.allocate_spike_ensembles() draw_image_mask_segments(image, spikes) pcnn_visualizer.animate_spike_ensembles(output_dynamic, image_size) def segmentation_image_simple1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, None, 47, 235) def segmentation_image_simple2(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE02, None, 47, 235) def segmentation_image_simple6(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE06, None, 47, 128) def segmentation_image_black_thin_lines1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_THIN_BLACK_LINES01, None, 47, 128) def segmentation_image_black_thin_lines2(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_THIN_BLACK_LINES02, None, 47, 128) def segmentation_image_black_thin_lines3(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_THIN_BLACK_LINES03, None, 47, 128) def segmentation_gray_image_simple1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, None, 47, None, True, False, True) def segmentation_gray_image_simple5(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE05, None, 47, None, True, False, True) def segmentation_gray_image_beach(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BEACH, None, 94, None, True, False, True) def segmentation_gray_image_building(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BUILDING, None, 47, None, True, False, True) def segmentation_fast_linking_image_beach(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BEACH, None, 47, None, False, True, True) def segmentation_fast_linking_image_building(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BUILDING, None, 47, None, False, True, True) def segmentation_fast_linking_image_fruits(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_FRUITS_SMALL, None, 47, None, False, True, True) def segmentation_fast_linking_white_sea(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_WHITE_SEA_SMALL, None, 47, None, False, True, True) def segmentation_fast_linking_nil(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_NILE_SMALL, None, 47, None, False, True, True) def segmentation_fast_linking_field_flowers(): parameters = pcnn_parameters() parameters.AF = 0.1 parameters.AL = 0.1 parameters.AT = 0.8 parameters.VF = 1.0 parameters.VL = 1.0 parameters.VT = 80.0 parameters.W = 1.0 parameters.M = 1.0 parameters.FAST_LINKING = True template_segmentation_image(IMAGE_REAL_SAMPLES.IMAGE_FIELD_FLOWER, parameters, 80, None, False, True, True) # Examples of simple image segmentation segmentation_image_simple1() segmentation_image_simple2() segmentation_image_simple6() # Line allocation segmentation_image_black_thin_lines1() segmentation_image_black_thin_lines2() segmentation_image_black_thin_lines3() # More complex image segmentation examples segmentation_gray_image_simple1() segmentation_gray_image_simple5() segmentation_gray_image_beach() segmentation_gray_image_building() # Fast linking usage examples segmentation_fast_linking_image_beach() segmentation_fast_linking_image_building() segmentation_fast_linking_image_fruits() segmentation_fast_linking_white_sea() segmentation_fast_linking_nil() segmentation_fast_linking_field_flowers() pyclustering-0.10.1.2/pyclustering/nnet/examples/som_examples.py000077500000000000000000000206001375753423500250600ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of self-organized feature map. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.som import som; from pyclustering.nnet.som import type_conn; from pyclustering.nnet.som import type_init; from pyclustering.nnet.som import som_parameters; from pyclustering.samples.definitions import SIMPLE_SAMPLES; from pyclustering.samples.definitions import FCPS_SAMPLES; from pyclustering.utils import read_sample; import matplotlib.pyplot as plt; from matplotlib import cm; from pylab import *; def template_self_organization(file, rows, cols, time, structure, init_type = None, init_radius = None, init_rate = None, umatrix = False, pmatrix = False, awards = False): parameters = som_parameters(); if (init_type is not None): parameters.init_type = init_type; if (init_radius is not None): parameters.init_radius = init_radius; if (init_rate is not None): parameters.init_learn_rate = init_rate; sample = read_sample(file); network = som(rows, cols, structure, parameters, True); network.train(sample, time); network.show_network(False, dataset = False); if (umatrix is True): network.show_distance_matrix(); if (pmatrix is True): network.show_density_matrix(); if (awards is True): network.show_winner_matrix(); def som_sample1(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, type_conn.grid_four); def som_sample2(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 100, type_conn.grid_four); def som_sample3(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 2, 100, type_conn.grid_four); def som_sample4(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 100, type_conn.grid_four); def som_sample5(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 2, 2, 100, type_conn.grid_four); def som_lsun(): template_self_organization(FCPS_SAMPLES.SAMPLE_LSUN, 5, 5, 100, type_conn.grid_four); def som_target(): template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 5, 5, 100, type_conn.grid_four); def som_tetra(): template_self_organization(FCPS_SAMPLES.SAMPLE_TETRA, 1, 4, 100, type_conn.grid_four); def som_two_diamonds(): template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 5, 5, 100, type_conn.grid_four); def som_elongate(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 5, 5, 100, type_conn.grid_four); def som_wing_nut(): template_self_organization(FCPS_SAMPLES.SAMPLE_WING_NUT, 5, 5, 100, type_conn.grid_four); def som_chainlink(): template_self_organization(FCPS_SAMPLES.SAMPLE_CHAINLINK, 5, 5, 100, type_conn.grid_four); def som_atom(): template_self_organization(FCPS_SAMPLES.SAMPLE_ATOM, 5, 5, 100, type_conn.grid_four); def som_golf_ball(): template_self_organization(FCPS_SAMPLES.SAMPLE_GOLF_BALL, 5, 5, 100, type_conn.grid_four); def som_hepta(): template_self_organization(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 7, 100, type_conn.grid_four); def som_engy_time(): template_self_organization(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 5, 5, 100, type_conn.grid_four); def som_winner_matrix(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 10, 10, 150, type_conn.func_neighbor, init_radius = 6.0, init_rate = 0.1, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_LSUN, 10, 10, 200, type_conn.func_neighbor, init_radius = 2.5, init_rate = 0.5, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 10, 10, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.5, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 10, 10, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_WING_NUT, 10, 10, 200, type_conn.func_neighbor, init_radius = 6.0, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_CHAINLINK, 10, 10, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TETRA, 10, 10, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, awards = True); template_self_organization(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 10, 10, 100, type_conn.func_neighbor, init_radius = 6.0, awards = True); def som_distance_matrix(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 32, 32, 150, type_conn.func_neighbor, init_radius = 6.0, init_rate = 0.1, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_LSUN, 32, 32, 1000, type_conn.func_neighbor, init_radius = 2.5, init_rate = 0.5, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 32, 32, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.5, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 32, 32, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_WING_NUT, 32, 32, 200, type_conn.func_neighbor, init_radius = 6.0, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_CHAINLINK, 32, 32, 1000, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TETRA, 32, 32, 1000, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, umatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 32, 32, 100, type_conn.func_neighbor, init_radius = 6.0, umatrix = True); def som_density_matrix(): template_self_organization(SIMPLE_SAMPLES.SAMPLE_ELONGATE, 32, 32, 150, type_conn.func_neighbor, init_radius = 6.0, init_rate = 0.1, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_LSUN, 32, 32, 1000, type_conn.func_neighbor, init_radius = 2.5, init_rate = 0.5, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 32, 32, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.5, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 32, 32, 200, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_WING_NUT, 32, 32, 200, type_conn.func_neighbor, init_radius = 6.0, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_CHAINLINK, 32, 32, 1000, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_TETRA, 32, 32, 1000, type_conn.func_neighbor, init_radius = 3.0, init_rate = 0.6, pmatrix = True); template_self_organization(FCPS_SAMPLES.SAMPLE_ENGY_TIME, 32, 32, 100, type_conn.func_neighbor, init_radius = 6.0, pmatrix = True); def som_target_diffence_intialization(): template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 9, 9, 150, type_conn.grid_four, type_init.random); template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 9, 9, 150, type_conn.grid_four, type_init.random_centroid); template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 9, 9, 150, type_conn.grid_four, type_init.random_surface); template_self_organization(FCPS_SAMPLES.SAMPLE_TARGET, 9, 9, 150, type_conn.grid_four, type_init.uniform_grid); def som_two_diamonds_diffence_intialization(): template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 9, 9, 150, type_conn.grid_four, type_init.random); template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 9, 9, 150, type_conn.grid_four, type_init.random_centroid); template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 9, 9, 150, type_conn.grid_four, type_init.random_surface); template_self_organization(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 9, 9, 150, type_conn.grid_four, type_init.uniform_grid); som_sample1(); som_sample2(); som_sample3(); som_sample4(); som_sample5(); som_lsun(); som_target(); som_tetra(); som_two_diamonds(); som_elongate(); som_wing_nut(); som_chainlink(); som_atom(); som_golf_ball(); som_hepta(); som_engy_time(); som_winner_matrix(); som_distance_matrix(); som_density_matrix(); som_target_diffence_intialization(); som_two_diamonds_diffence_intialization();pyclustering-0.10.1.2/pyclustering/nnet/examples/som_recognition.py000077500000000000000000000204251375753423500255670ustar00rootroot00000000000000"""! @brief Example of application for digit recognition based on self-organized feature map. Digits for 0 to 9 can be recognized. The application has GUI that provides following function: learning, drawing, recognition, dump saving/loading. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.som import som, type_conn; from pyclustering.samples.definitions import IMAGE_DIGIT_SAMPLES; from pyclustering.utils import read_image, rgb2gray; from tkinter import *; from tkinter import messagebox; import math; import pickle; import os; import random; class recognizer: __network = None; def __init__(self): self.__decode_map = []; for index_digit in range(0, 10, 1): list_file_digit_sample = IMAGE_DIGIT_SAMPLES.GET_LIST_IMAGE_SAMPLES(index_digit); for file_name in list_file_digit_sample: self.__decode_map.append(index_digit); def train(self): samples = []; print("Digit images preprocessing..."); for index_digit in range(0, 10, 1): list_file_digit_sample = IMAGE_DIGIT_SAMPLES.GET_LIST_IMAGE_SAMPLES(index_digit); for file_name in list_file_digit_sample: data = read_image(file_name); image_pattern = rgb2gray(data); for index_pixel in range(len(image_pattern)): if (image_pattern[index_pixel] < 128): image_pattern[index_pixel] = 1; else: image_pattern[index_pixel] = 0; samples += [ image_pattern ]; print("SOM initialization..."); self.__network = som(2, 5, type_conn.grid_four, None, True); print("SOM training..."); self.__network.train(samples, 300); print("SOM is ready..."); def recognize(self, input_pattern): index_neuron = self.__network.simulate(input_pattern); decoded_capture_objects = []; for index_capture_object in self.__network.capture_objects[index_neuron]: # print("\t%s" % decode_map[index_capture_object]); decoded_capture_objects.append(self.__decode_map[index_capture_object]); frequent_index = max(set(decoded_capture_objects), key = decoded_capture_objects.count); print(decoded_capture_objects); return frequent_index; def save_knowledge(self): result_saving = False; if (self.__network is not None): file_network_dump = open("knowledge_recognition_memory_dump", "wb"); pickle.dump(self.__network, file_network_dump); result_saving = True; return result_saving; def load_knowledge(self): result_loading = False; if (os.path.isfile("knowledge_recognition_memory_dump") is True): file_network_dump = open("knowledge_recognition_memory_dump", "rb"); self.__network = pickle.load(file_network_dump); result_loading = True; return result_loading; class digit_application: __color = "#000000"; __widget = None; __user_pattern = None; __recognizer = None; __master = None; def __init__(self): self.__master = Tk(); self.__master.title("Recognition"); self.__widget = Canvas(self.__master, width = 320, height = 320); self.__widget.pack(expand = YES, fill = BOTH); self.__widget.bind("", self.__paint); button_recognize = Button(self.__master, text = "Recognize", command = self.click_recognize, width = 25); button_recognize.pack(side = BOTTOM); button_recognize = Button(self.__master, text = "Random Image", command = self.click_image_load, width = 25); button_recognize.pack(side = BOTTOM); # button_save = Button(self.__master, text = "Save", command = self.click_save, width = 25); # button_save.pack(side = BOTTOM); # # button_load = Button(self.__master, text = "Load", command = self.click_load, width = 25); # button_load.pack(side = BOTTOM); button_train = Button(self.__master, text = "Train", command = self.click_train, width = 25); button_train.pack(side = BOTTOM); button_clean = Button(self.__master, text = "Clean", command = self.click_clean, width = 25); button_clean.pack(side = BOTTOM); self.__user_pattern = [ 0 for i in range(32 * 32) ]; self.__recognizer = recognizer(); def __paint(self, event): # calculate square that is belong this click if ( (event.x >= 0) and (event.x < 320) and (event.y >= 0) and (event.y < 320) ): x1, y1 = math.floor(event.x / 10), math.floor(event.y / 10); self.__user_pattern[y1 * 32 + x1] = 1; index2 = (y1 + 1) * 32 + x1; index3 = y1 * 32 + (x1 + 1); index4 = (y1 + 1) * 32 + (x1 + 1); if (index2 < len(self.__user_pattern)): self.__user_pattern[index2] = 1; if (index3 < len(self.__user_pattern)): self.__user_pattern[index3] = 1; if (index4 < len(self.__user_pattern)): self.__user_pattern[index4] = 1; display_x1, display_y1 = x1 * 10, y1 * 10; display_x2, display_y2 = display_x1 + 20, display_y1 + 20; self.__widget.create_rectangle(display_x1, display_y1, display_x2, display_y2, fill = self.__color, width = 0); def click_train(self): self.__recognizer.train(); def click_load(self): if (self.__recognizer.load_knowledge() is not True): messagebox.showwarning("Recognition - Knowledge Loading", "Knowledge represented by self-organized feature map has not been " "load from hardware to recognizer due to lack of saved dump of that object. " "Please save knowledge dump after training and after that it will be possible " "to use load it at any time."); def click_save(self): if (self.__recognizer.save_knowledge() is not True): messagebox.showwarning("Recognition - Knowledge Saving", "Knowledge represented by self-organized feature map has been created " "because training has been performed. Please train recognizer and after save result of training."); def click_recognize(self): digit_index = self.__recognizer.recognize(self.__user_pattern); messagebox.showinfo("Recognition - Result", "Most probably input digit is " + str(digit_index)); def click_clean(self): self.__user_pattern = [ 0 for i in range(32 * 32) ]; Canvas.delete(self.__widget, "all"); def click_image_load(self): self.__user_pattern = [ 0 for i in range(32 * 32) ]; Canvas.delete(self.__widget, "all"); index_digit = int(math.floor(random.random() * 10)); list_file_digit_sample = IMAGE_DIGIT_SAMPLES.GET_LIST_IMAGE_SAMPLES(index_digit); index_image = int(math.floor( random.random() * len(list_file_digit_sample) )); file_name = list_file_digit_sample[index_image]; data = read_image(file_name); image_pattern = rgb2gray(data); for y in range(32): for x in range(32): linear_index = y * 32 + x; if (image_pattern[linear_index] < 128): self.__user_pattern[linear_index] = 1; self.__widget.create_rectangle(x * 10, y * 10, x * 10 + 10, y * 10 + 10, fill = self.__color, width = 0); def start(self): mainloop(); app = digit_application(); app.start(); # digit_recognition();pyclustering-0.10.1.2/pyclustering/nnet/examples/sync_examples.py000077500000000000000000000124101375753423500252360ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Oscillatory Neural Network based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet import solve_type, conn_type; from pyclustering.nnet.sync import sync_network, sync_visualizer; def template_dynamic_sync(num_osc, k = 1, sim_arg = None, conn = conn_type.ALL_TO_ALL, type_solution = solve_type.FAST, collect_dyn = True, ccore_flag = False): network = sync_network(num_osc, k, type_conn = conn, ccore = ccore_flag); if (sim_arg is not None): sync_output_dynamic = network.simulate(sim_arg[0], sim_arg[1], solution = type_solution, collect_dynamic = collect_dyn); else: sync_output_dynamic = network.simulate_dynamic(collect_dynamic = collect_dyn, solution = type_solution); sync_visualizer.show_output_dynamic(sync_output_dynamic); sync_visualizer.show_order_parameter(sync_output_dynamic); sync_visualizer.animate_output_dynamic(sync_output_dynamic); sync_visualizer.animate_correlation_matrix(sync_output_dynamic); return network; # Positive connections def trivial_dynamic_sync(): template_dynamic_sync(100, 1, sim_arg = [50, 10]); template_dynamic_sync(100, 1, sim_arg = [50, 10], ccore_flag = True); def weight_5_dynamic_sync(): template_dynamic_sync(10, 10, sim_arg = [100, 10], type_solution = solve_type.RK4); def bidir_struct_dynamic_sync(): template_dynamic_sync(10, 100, sim_arg = [100, 10], conn = conn_type.LIST_BIDIR, type_solution = solve_type.RK4); def grid_four_struct_dynamic_sync(): template_dynamic_sync(25, 50, sim_arg = [50, 10], conn = conn_type.GRID_FOUR, type_solution = solve_type.RK4); def dynamic_simulation_all_to_all_structure(): template_dynamic_sync(25, 1, conn = conn_type.ALL_TO_ALL, ccore_flag = True); def dynamic_simulation_grid_four_structure(): template_dynamic_sync(25, 1, conn = conn_type.GRID_FOUR, ccore_flag = True); def dynamic_simulation_bidir_list_structure(): template_dynamic_sync(25, 1, conn = conn_type.LIST_BIDIR, ccore_flag = True); # Negative connections def negative_connection_5_oscillators(): template_dynamic_sync(5, -1); template_dynamic_sync(5, -1, ccore_flag = True); def negative_connection_10_oscillators(): "Comment: It is not full desynchronization" template_dynamic_sync(10, -3); def negative_connection_9_grid_struct(): "Comment: Right coloring" _ = template_dynamic_sync(9, -2, conn = conn_type.GRID_FOUR); def negative_connection_16_grid_struct(): "Comment: Wrong coloring" _ = template_dynamic_sync(16, -3, conn = conn_type.GRID_FOUR); def template_animate_output_dynamic(title, amount_oscillators, coupling_stregth, frequency, order): network = sync_network(amount_oscillators, coupling_stregth, frequency, ccore = True); sync_output_dynamic = network.simulate_dynamic(order, solution = solve_type.RK4, collect_dynamic = True); sync_visualizer.animate(sync_output_dynamic, title); #sync_visualizer.animate(sync_output_dynamic, title); def animate_phase_locking(): template_animate_output_dynamic("Phase locking", 300, 1.0, 1.0, 0.995); def animate_global_synchronization(): template_animate_output_dynamic("Global synchronization", 300, 0.5, 0.0, 0.9999); def template_animate_phase_matrix(num_osc, strength = 1.0, steps = None, time = None, conn = conn_type.ALL_TO_ALL, type_solution = solve_type.FAST, ccore_flag = True): network = sync_network(num_osc, strength, type_conn = conn, ccore = ccore_flag); if ( (steps is not None) and (time is not None) ): sync_output_dynamic = network.simulate(steps, time, solution = type_solution, collect_dynamic = True); else: sync_output_dynamic = network.simulate_dynamic(collect_dynamic = True, order = 0.999, solution = type_solution); sync_visualizer.animate_phase_matrix(sync_output_dynamic); return network; def animate_phase_matrix_400_all_to_all(): template_animate_phase_matrix(400, 0.4, None, None, conn = conn_type.ALL_TO_ALL, type_solution = solve_type.FAST); def animate_phase_matrix_400_grid_four(): template_animate_phase_matrix(400, 2.0, conn = conn_type.GRID_FOUR); def animate_phase_matrix_400_grid_eight(): template_animate_phase_matrix(400, 1.0, conn = conn_type.GRID_EIGHT); # Examples of global synchronization. trivial_dynamic_sync(); weight_5_dynamic_sync(); bidir_struct_dynamic_sync(); grid_four_struct_dynamic_sync(); # Examples of global synchronization for various network structures dynamic_simulation_all_to_all_structure(); dynamic_simulation_grid_four_structure(); dynamic_simulation_bidir_list_structure(); # Examples with negative connection negative_connection_5_oscillators(); # Almost full desynchronization negative_connection_10_oscillators(); # It's not full desynchronization negative_connection_9_grid_struct(); # Right coloring negative_connection_16_grid_struct(); # Wrong coloring animate_phase_locking(); animate_global_synchronization(); animate_phase_matrix_400_all_to_all(); animate_phase_matrix_400_grid_four(); animate_phase_matrix_400_grid_eight();pyclustering-0.10.1.2/pyclustering/nnet/examples/syncpr_examples.py000077500000000000000000000071031375753423500256030ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of Phase Oscillatory Neural Network based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import IMAGE_SYMBOL_SAMPLES; from pyclustering.utils import read_image, rgb2gray; from pyclustering.nnet import solve_type; from pyclustering.nnet.syncpr import syncpr, syncpr_visualizer; import random; import math; def template_recognition_image(images, steps, time, corruption = 0.1): samples = []; for file_name in images: data = read_image(file_name); image_pattern = rgb2gray(data); for index_pixel in range(len(image_pattern)): if (image_pattern[index_pixel] < 128): image_pattern[index_pixel] = 1; else: image_pattern[index_pixel] = -1; samples += [ image_pattern ]; net = syncpr(len(samples[0]), 0.3, 0.3, ccore = True); net.train(samples); # Recognize the each learned pattern for i in range(len(samples)): sync_output_dynamic = net.simulate(steps, time, samples[i], solve_type.RK4, True); syncpr_visualizer.show_output_dynamic(sync_output_dynamic); syncpr_visualizer.show_pattern(sync_output_dynamic, 10, 10); # corrupt a little bit by black and white pixels for _ in range( math.floor(len(samples[i]) * corruption) ): random.seed(); random_pixel = math.floor(random.random() * len(samples[i])); samples[i][random_pixel] = 1; random_pixel = math.floor(random.random() * len(samples[i])); samples[i][random_pixel] = -1; sync_output_dynamic = net.simulate(steps, time, samples[i], solve_type.RK4, True); syncpr_visualizer.show_output_dynamic(sync_output_dynamic); syncpr_visualizer.show_pattern(sync_output_dynamic, 10, 10); syncpr_visualizer.animate_pattern_recognition(sync_output_dynamic, 10, 10, title = "Pattern Recognition"); def small_mind_image_recognition(): """! @brief Trains network using letters 'M', 'I', 'N', 'D' and recognize each of them with and without noise. """ images = []; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_M; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_I; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_N; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_D; template_recognition_image(images, 100, 10, 0.2); def small_abc_image_recognition(): """! @brief Trains network using letters 'A', 'B', 'C', and recognize each of them with and without noise. """ images = []; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_A; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_B; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_C; template_recognition_image(images, 250, 25); def small_ftk_image_recognition(): """! @brief Trains network using letters 'F', 'T', 'K' and recognize each of them with and without noise. """ images = []; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_F; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_T; images += IMAGE_SYMBOL_SAMPLES.LIST_IMAGES_SYMBOL_K; template_recognition_image(images, 100, 10, 0.2); small_mind_image_recognition(); small_abc_image_recognition(); small_ftk_image_recognition();pyclustering-0.10.1.2/pyclustering/nnet/examples/syncsegm_examples.py000077500000000000000000000077771375753423500261360ustar00rootroot00000000000000"""! @brief Examples of usage and demonstration of abilities of multi-layer oscillatory network based on Kuramoto model for image segmentation. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES, IMAGE_MAP_SAMPLES from pyclustering.nnet.syncsegm import syncsegm, syncsegm_visualizer from pyclustering.utils import draw_image_mask_segments def template_segmentation_image(source, color_radius, object_radius, noise_size, show_dyn): algorithm = syncsegm(color_radius, object_radius, noise_size, False) analyser = algorithm.process(source, show_dyn) color_segments = analyser.allocate_colors(0.01, noise_size) draw_image_mask_segments(source, color_segments) if object_radius is not None: object_segments = analyser.allocate_objects(0.01, noise_size) draw_image_mask_segments(source, object_segments) if show_dyn is True: syncsegm_visualizer.show_first_layer_dynamic(analyser) syncsegm_visualizer.show_second_layer_dynamic(analyser) def segmentation_image_simple1(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, 128, None, 10, show_dyn = False) def segmentation_image_simple2(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE02, 128, None, 10, show_dyn = False) def segmentation_image_simple3(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE03, 128, None, 10, show_dyn = False) def segmentation_image_simple4(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE04, 128, None, 10, show_dyn = False) def segmentation_image_simple5(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE05, 128, 4, 10, show_dyn = False) def segmentation_image_simple6(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE06, 128, 4, 10, show_dyn = True) def segmentation_image_simple7(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE07, 128, 5, 10, show_dyn = False) def segmentation_image_simple8(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE08, 128, 5, 10, show_dyn = False) def segmentation_image_simple9(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE09, 128, 4, 10, show_dyn = False) def segmentation_image_simple10(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE10, 128, 5, 10, show_dyn = False) def segmentation_image_beach(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BEACH, 128, None, 10, show_dyn = False) def segmentation_image_building(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_BUILDING, 16, 10, 10, show_dyn = False) def segmentation_image_fruits_small(): template_segmentation_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE_FRUITS_SMALL, 16, 4, 20, show_dyn = False) def segmentation_image_white_sea(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_WHITE_SEA, 16, None, 50, show_dyn = False) def segmentation_image_white_sea_small(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_WHITE_SEA_SMALL, 20, None, 50, show_dyn = False) def segmentation_image_nile(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_NILE, 16, None, 50, show_dyn = False) def segmentation_image_nile_small(): template_segmentation_image(IMAGE_MAP_SAMPLES.IMAGE_NILE_SMALL, 50, None, 50, show_dyn = False) segmentation_image_simple1() segmentation_image_simple2() segmentation_image_simple3() segmentation_image_simple4() segmentation_image_simple5() segmentation_image_simple6() segmentation_image_simple7() segmentation_image_simple8() segmentation_image_simple9() segmentation_image_simple10() segmentation_image_beach() segmentation_image_building() segmentation_image_fruits_small() segmentation_image_white_sea() segmentation_image_white_sea_small() segmentation_image_nile() segmentation_image_nile_small()pyclustering-0.10.1.2/pyclustering/nnet/fsync.py000077500000000000000000000316011375753423500216730ustar00rootroot00000000000000"""! @brief Oscillatory Neural Network based on Kuramoto model in frequency domain. @details Implementation based on paper @cite book::chemical_oscillatorions_waves. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import random import pyclustering.utils from scipy.integrate import odeint from pyclustering.nnet import network, conn_type, conn_represent class fsync_dynamic: """! @brief Represents output dynamic of Sync in frequency domain. """ def __init__(self, amplitude, time): """! @brief Constructor of Sync dynamic in frequency domain. @param[in] amplitude (list): Dynamic of oscillators on each step of simulation. @param[in] time (list): Simulation time where each time-point corresponds to amplitude-point. """ self.__amplitude = amplitude self.__time = time @property def output(self): """! @brief (list) Returns output dynamic of the Sync network (amplitudes of each oscillator in the network) during simulation. """ return self.__amplitude @property def time(self): """! @brief (list) Returns time-points corresponds to dynamic-points points. """ return self.__time def __len__(self): """! @brief (uint) Returns number of simulation steps that are stored in dynamic. """ return len(self.__amplitude) def __getitem__(self, index): """! @brief Indexing of the dynamic. """ if index == 0: return self.__time elif index == 1: return self.__amplitude else: raise NameError('Out of range ' + index + ': only indexes 0 and 1 are supported.') def allocate_sync_ensembles(self, tolerance=0.1): """! @brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators. @return (list) Grours of indexes of synchronous oscillators, for example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ return pyclustering.utils.allocate_sync_ensembles(self.__amplitude, tolerance, 0.0) def extract_number_oscillations(self, index, amplitude_threshold): """! @brief Extracts number of oscillations of specified oscillator. @param[in] index (uint): Index of oscillator whose dynamic is considered. @param[in] amplitude_threshold (double): Amplitude threshold when oscillation is taken into account, for example, when oscillator amplitude is greater than threshold then oscillation is incremented. @return (uint) Number of oscillations of specified oscillator. """ return pyclustering.utils.extract_number_oscillations(self.__amplitude, index, amplitude_threshold); class fsync_visualizer: """! @brief Visualizer of output dynamic of sync network in frequency domain. """ @staticmethod def show_output_dynamic(fsync_output_dynamic): """! @brief Shows output dynamic (output of each oscillator) during simulation. @param[in] fsync_output_dynamic (fsync_dynamic): Output dynamic of the fSync network. @see show_output_dynamics """ pyclustering.utils.draw_dynamics(fsync_output_dynamic.time, fsync_output_dynamic.output, x_title = "t", y_title = "amplitude"); @staticmethod def show_output_dynamics(fsync_output_dynamics): """! @brief Shows several output dynamics (output of each oscillator) during simulation. @details Each dynamic is presented on separate plot. @param[in] fsync_output_dynamics (list): list of output dynamics 'fsync_dynamic' of the fSync network. @see show_output_dynamic """ pyclustering.utils.draw_dynamics_set(fsync_output_dynamics, "t", "amplitude", None, None, False, False); class fsync_network(network): """! @brief Model of oscillatory network that uses Landau-Stuart oscillator and Kuramoto model as a synchronization mechanism. @details Dynamic of each oscillator in the network is described by following differential Landau-Stuart equation with feedback: \f[ \dot{z}_{i} = (i\omega_{i} + \rho^{2}_{i} - |z_{i}|^{2} )z_{i} + \frac{1}{N}\sum_{j=0}^{N}k_{ij}(z_{j} - z_{i}); \f] Where left part of the equation is Landau-Stuart equation and the right is a Kuramoto model for synchronization. For solving this equation Runge-Kutta 4 method is used by default. Example: @code # Prepare oscillatory network parameters. amount_oscillators = 3; frequency = 1.0; radiuses = [1.0, 2.0, 3.0]; coupling_strength = 1.0; # Create oscillatory network oscillatory_network = fsync_network(amount_oscillators, frequency, radiuses, coupling_strength); # Simulate network during 200 steps on 10 time-units of time-axis. output_dynamic = oscillatory_network.simulate(200, 10, True); # True is to collect whole output dynamic. # Visualize output result fsync_visualizer.show_output_dynamic(output_dynamic); @endcode Example of output dynamic of the network: @image html fsync_sync_examples.png """ __DEFAULT_FREQUENCY_VALUE = 1.0; __DEFAULT_RADIUS_VALUE = 1.0; __DEFAULT_COUPLING_STRENGTH = 1.0; def __init__(self, num_osc, factor_frequency = 1.0, factor_radius = 1.0, factor_coupling = 1.0, type_conn = conn_type.ALL_TO_ALL, representation = conn_represent.MATRIX): """! @brief Constructor of oscillatory network based on synchronization Kuramoto model and Landau-Stuart oscillator. @param[in] num_osc (uint): Amount oscillators in the network. @param[in] factor_frequency (double|list): Frequency of oscillators, it can be specified as common value for all oscillators by single double value and for each separately by list. @param[in] factor_radius (double|list): Radius of oscillators that affects amplitude, it can be specified as common value for all oscillators by single double value and for each separately by list. @param[in] factor_coupling (double): Coupling strength between oscillators. @param[in] type_conn (conn_type): Type of connection between oscillators in the network (all-to-all, grid, bidirectional list, etc.). @param[in] representation (conn_represent): Internal representation of connection in the network: matrix or list. """ super().__init__(num_osc, type_conn, representation); self.__frequency = factor_frequency if isinstance(factor_frequency, list) else [ fsync_network.__DEFAULT_FREQUENCY_VALUE * factor_frequency for _ in range(num_osc) ]; self.__radius = factor_radius if isinstance(factor_radius, list) else [ fsync_network.__DEFAULT_RADIUS_VALUE * factor_radius for _ in range(num_osc) ]; self.__coupling_strength = fsync_network.__DEFAULT_COUPLING_STRENGTH * factor_coupling; self.__properties = [ self.__oscillator_property(index) for index in range(self._num_osc) ]; random.seed(); self.__amplitude = [ random.random() for _ in range(num_osc) ]; def simulate(self, steps, time, collect_dynamic = False): """! @brief Performs static simulation of oscillatory network. @param[in] steps (uint): Number simulation steps. @param[in] time (double): Time of simulation. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' is True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of output dynamic. @see simulate() @see simulate_dynamic() """ dynamic_amplitude, dynamic_time = ([], []) if collect_dynamic is False else ([self.__amplitude], [0]); step = time / steps; int_step = step / 10.0; for t in numpy.arange(step, time + step, step): self.__amplitude = self.__calculate(t, step, int_step); if collect_dynamic is True: dynamic_amplitude.append([ numpy.real(amplitude)[0] for amplitude in self.__amplitude ]); dynamic_time.append(t); if collect_dynamic is False: dynamic_amplitude.append([ numpy.real(amplitude)[0] for amplitude in self.__amplitude ]); dynamic_time.append(time); output_sync_dynamic = fsync_dynamic(dynamic_amplitude, dynamic_time); return output_sync_dynamic; def __calculate(self, t, step, int_step): """! @brief Calculates new amplitudes for oscillators in the network in line with current step. @param[in] t (double): Time of simulation. @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated. @param[in] int_step (double): Step differentiation that is used for solving differential equation. @return (list) New states (phases) for oscillators. """ next_amplitudes = [0.0] * self._num_osc; for index in range (0, self._num_osc, 1): z = numpy.array(self.__amplitude[index], dtype = numpy.complex128, ndmin = 1); result = odeint(self.__calculate_amplitude, z.view(numpy.float64), numpy.arange(t - step, t, int_step), (index , )); next_amplitudes[index] = (result[len(result) - 1]).view(numpy.complex128); return next_amplitudes; def __oscillator_property(self, index): """! @brief Calculate Landau-Stuart oscillator constant property that is based on frequency and radius. @param[in] index (uint): Oscillator index whose property is calculated. @return (double) Oscillator property. """ return numpy.array(1j * self.__frequency[index] + self.__radius[index]**2, dtype = numpy.complex128, ndmin = 1); def __landau_stuart(self, amplitude, index): """! @brief Calculate Landau-Stuart state. @param[in] amplitude (double): Current amplitude of oscillator. @param[in] index (uint): Oscillator index whose state is calculated. @return (double) Landau-Stuart state. """ return (self.__properties[index] - numpy.absolute(amplitude) ** 2) * amplitude; def __synchronization_mechanism(self, amplitude, index): """! @brief Calculate synchronization part using Kuramoto synchronization mechanism. @param[in] amplitude (double): Current amplitude of oscillator. @param[in] index (uint): Oscillator index whose synchronization influence is calculated. @return (double) Synchronization influence for the specified oscillator. """ sync_influence = 0.0; for k in range(self._num_osc): if self.has_connection(index, k) is True: amplitude_neighbor = numpy.array(self.__amplitude[k], dtype = numpy.complex128, ndmin = 1); sync_influence += amplitude_neighbor - amplitude; return sync_influence * self.__coupling_strength / self._num_osc; def __calculate_amplitude(self, amplitude, t, argv): """! @brief Returns new amplitude value for particular oscillator that is defined by index that is in 'argv' argument. @details The method is used for differential calculation. @param[in] amplitude (double): Current amplitude of oscillator. @param[in] t (double): Current time of simulation. @param[in] argv (uint): Index of the current oscillator. @return (double) New amplitude of the oscillator. """ z = amplitude.view(numpy.complex); dzdt = self.__landau_stuart(z, argv) + self.__synchronization_mechanism(z, argv); return dzdt.view(numpy.float64);pyclustering-0.10.1.2/pyclustering/nnet/hhn.py000077500000000000000000000631701375753423500213340ustar00rootroot00000000000000"""! @brief Oscillatory Neural Network based on Hodgkin-Huxley Neuron Model @details Implementation based on paper @cite article::nnet::hnn::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from scipy.integrate import odeint from pyclustering.core.wrapper import ccore_library import pyclustering.core.hhn_wrapper as wrapper from pyclustering.nnet import * from pyclustering.utils import allocate_sync_ensembles import numpy import random class hhn_parameters: """! @brief Describes parameters of Hodgkin-Huxley Oscillatory Network. @see hhn_network """ def __init__(self): """! @brief Default constructor of parameters for Hodgkin-Huxley Oscillatory Network. @details Constructor initializes parameters by default non-zero values that can be used for simple simulation. """ ## Intrinsic noise. self.nu = random.random() * 2.0 - 1.0 ## Maximal conductivity for sodium current. self.gNa = 120.0 * (1 + 0.02 * self.nu) ## Maximal conductivity for potassium current. self.gK = 36.0 * (1 + 0.02 * self.nu) ## Maximal conductivity for leakage current. self.gL = 0.3 * (1 + 0.02 * self.nu) ## Reverse potential of sodium current [mV]. self.vNa = 50.0 ## Reverse potential of potassium current [mV]. self.vK = -77.0 ## Reverse potential of leakage current [mV]. self.vL = -54.4 ## Rest potential [mV]. self.vRest = -65.0 ## External current [mV] for central element 1. self.Icn1 = 5.0 ## External current [mV] for central element 2. self.Icn2 = 30.0 ## Synaptic reversal potential [mV] for inhibitory effects. self.Vsyninh = -80.0 ## Synaptic reversal potential [mV] for exciting effects. self.Vsynexc = 0.0 ## Alfa-parameter for alfa-function for inhibitory effect. self.alfa_inhibitory = 6.0 ## Betta-parameter for alfa-function for inhibitory effect. self.betta_inhibitory = 0.3 ## Alfa-parameter for alfa-function for excitatory effect. self.alfa_excitatory = 40.0 ## Betta-parameter for alfa-function for excitatory effect. self.betta_excitatory = 2.0 ## Strength of the synaptic connection from PN to CN1. self.w1 = 0.1 ## Strength of the synaptic connection from CN1 to PN. self.w2 = 9.0 ## Strength of the synaptic connection from CN2 to PN. self.w3 = 5.0 ## Period of time [ms] when high strength value of synaptic connection exists from CN2 to PN. self.deltah = 650.0 ## Threshold of the membrane potential that should exceeded by oscillator to be considered as an active. self.threshold = -10 ## Affects pulse counter. self.eps = 0.16 class central_element: """! @brief Central element consist of two central neurons that are described by a little bit different dynamic than peripheral. @see hhn_network """ def __init__(self): """! @brief Constructor of central element. """ ## Membrane potential of cenral neuron (V). self.membrane_potential = 0.0 ## Activation conductance of the sodium channel (m). self.active_cond_sodium = 0.0 ## Inactivaton conductance of the sodium channel (h). self.inactive_cond_sodium = 0.0 ## Activaton conductance of the sodium channel (h). self.active_cond_potassium = 0.0 ## Spike generation of central neuron. self.pulse_generation = False ## Timestamps of generated pulses. self.pulse_generation_time = [] def __repr__(self): """! @brief Returns string that represents central element. """ return "%s, %s" % (self.membrane_potential, self.pulse_generation_time) class hhn_network(network): """! @brief Oscillatory Neural Network with central element based on Hodgkin-Huxley neuron model. @details Interaction between oscillators is performed via central element (no connection between oscillators that are called as peripheral). Peripheral oscillators receive external stimulus. Central element consist of two oscillators: the first is used for synchronization some ensemble of oscillators and the second controls synchronization of the first central oscillator with various ensembles. Usage example where oscillatory network with 6 oscillators is used for simulation. The first two oscillators have the same stimulus, as well as the third and fourth oscillators and the last two. Thus three synchronous ensembles are expected after simulation. @code from pyclustering.nnet.hhn import hhn_network, hhn_parameters from pyclustering.nnet.dynamic_visualizer import dynamic_visualizer # Change period of time when high strength value of synaptic connection exists from CN2 to PN. params = hhn_parameters() params.deltah = 400 # Create Hodgkin-Huxley oscillatory network with stimulus. net = hhn_network(6, [0, 0, 25, 25, 47, 47], params) # Simulate network. (t, dyn_peripheral, dyn_central) = net.simulate(2400, 600) # Visualize network's output (membrane potential of peripheral and central neurons). amount_canvases = 6 + 2 # 6 peripheral oscillator + 2 central elements visualizer = dynamic_visualizer(amount_canvases, x_title="Time", y_title="V", y_labels=False) visualizer.append_dynamics(t, dyn_peripheral, 0, True) visualizer.append_dynamics(t, dyn_central, amount_canvases - 2, True) visualizer.show() @endcode There is visualized result of simulation where three synchronous ensembles of oscillators can be observed. The first and the second oscillators form the first ensemble, the third and the fourth form the second ensemble and the last two oscillators form the third ensemble. @image html hhn_three_ensembles.png """ def __init__(self, num_osc, stimulus = None, parameters = None, type_conn = None, type_conn_represent = conn_represent.MATRIX, ccore = True): """! @brief Constructor of oscillatory network based on Hodgkin-Huxley neuron model. @param[in] num_osc (uint): Number of peripheral oscillators in the network. @param[in] stimulus (list): List of stimulus for oscillators, number of stimulus should be equal to number of peripheral oscillators. @param[in] parameters (hhn_parameters): Parameters of the network. @param[in] type_conn (conn_type): Type of connections between oscillators in the network (ignored for this type of network). @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list. @param[in] ccore (bool): If 'True' then CCORE is used (C/C++ implementation of the model). """ super().__init__(num_osc, conn_type.NONE, type_conn_represent) if stimulus is None: self._stimulus = [0.0] * num_osc else: self._stimulus = stimulus if parameters is not None: self._params = parameters else: self._params = hhn_parameters() self.__ccore_hhn_pointer = None self.__ccore_hhn_dynamic_pointer = None if (ccore is True) and ccore_library.workable(): self.__ccore_hhn_pointer = wrapper.hhn_create(num_osc, self._params) else: self._membrane_dynamic_pointer = None # final result is stored here. self._membrane_potential = [0.0] * self._num_osc self._active_cond_sodium = [0.0] * self._num_osc self._inactive_cond_sodium = [0.0] * self._num_osc self._active_cond_potassium = [0.0] * self._num_osc self._link_activation_time = [0.0] * self._num_osc self._link_pulse_counter = [0.0] * self._num_osc self._link_weight3 = [0.0] * self._num_osc self._pulse_generation_time = [[] for i in range(self._num_osc)] self._pulse_generation = [False] * self._num_osc self._noise = [random.random() * 2.0 - 1.0 for i in range(self._num_osc)] self._central_element = [central_element(), central_element()] def __del__(self): """! @brief Destroy dynamically allocated oscillatory network instance in case of CCORE usage. """ if self.__ccore_hhn_pointer: wrapper.hhn_destroy(self.__ccore_hhn_pointer) def simulate(self, steps, time, solution = solve_type.RK4): """! @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model. @details Output dynamic is sensible to amount of steps of simulation and solver of differential equation. Python implementation uses 'odeint' from 'scipy', CCORE uses classical RK4 and RFK45 methods, therefore in case of CCORE HHN (Hodgkin-Huxley network) amount of steps should be greater than in case of Python HHN. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] solution (solve_type): Type of solver for differential equations. @return (tuple) Dynamic of oscillatory network represented by (time, peripheral neurons dynamic, central elements dynamic), where types are (list, list, list). """ return self.simulate_static(steps, time, solution) def simulate_static(self, steps, time, solution = solve_type.RK4): """! @brief Performs static simulation of oscillatory network based on Hodgkin-Huxley neuron model. @details Output dynamic is sensible to amount of steps of simulation and solver of differential equation. Python implementation uses 'odeint' from 'scipy', CCORE uses classical RK4 and RFK45 methods, therefore in case of CCORE HHN (Hodgkin-Huxley network) amount of steps should be greater than in case of Python HHN. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] solution (solve_type): Type of solver for differential equations. @return (tuple) Dynamic of oscillatory network represented by (time, peripheral neurons dynamic, central elements dynamic), where types are (list, list, list). """ # Check solver before simulation if solution == solve_type.FAST: raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.") self._membrane_dynamic_pointer = None if self.__ccore_hhn_pointer is not None: self.__ccore_hhn_dynamic_pointer = wrapper.hhn_dynamic_create(True, False, False, False) wrapper.hhn_simulate(self.__ccore_hhn_pointer, steps, time, solution, self._stimulus, self.__ccore_hhn_dynamic_pointer) peripheral_membrane_potential = wrapper.hhn_dynamic_get_peripheral_evolution(self.__ccore_hhn_dynamic_pointer, 0) central_membrane_potential = wrapper.hhn_dynamic_get_central_evolution(self.__ccore_hhn_dynamic_pointer, 0) dynamic_time = wrapper.hhn_dynamic_get_time(self.__ccore_hhn_dynamic_pointer) self._membrane_dynamic_pointer = peripheral_membrane_potential wrapper.hhn_dynamic_destroy(self.__ccore_hhn_dynamic_pointer) return dynamic_time, peripheral_membrane_potential, central_membrane_potential if solution == solve_type.RKF45: raise NameError("Solver RKF45 is not support in python version.") dyn_peripheral = [self._membrane_potential[:]] dyn_central = [[0.0, 0.0]] dyn_time = [0.0] step = time / steps int_step = step / 10.0 for t in numpy.arange(step, time + step, step): # update states of oscillators (memb_peripheral, memb_central) = self._calculate_states(solution, t, step, int_step) # update states of oscillators dyn_peripheral.append(memb_peripheral) dyn_central.append(memb_central) dyn_time.append(t) self._membrane_dynamic_pointer = dyn_peripheral return dyn_time, dyn_peripheral, dyn_central def _calculate_states(self, solution, t, step, int_step): """! @brief Calculates new state of each oscillator in the network. Returns only excitatory state of oscillators. @param[in] solution (solve_type): Type solver of the differential equations. @param[in] t (double): Current time of simulation. @param[in] step (uint): Step of solution at the end of which states of oscillators should be calculated. @param[in] int_step (double): Differentiation step that is used for solving differential equation. @return (list) New states of membrane potentials for peripheral oscillators and for cental elements as a list where the last two values correspond to central element 1 and 2. """ next_membrane = [0.0] * self._num_osc next_active_sodium = [0.0] * self._num_osc next_inactive_sodium = [0.0] * self._num_osc next_active_potassium = [0.0] * self._num_osc # Update states of oscillators for index in range(0, self._num_osc, 1): result = odeint(self.hnn_state, [self._membrane_potential[index], self._active_cond_sodium[index], self._inactive_cond_sodium[index], self._active_cond_potassium[index]], numpy.arange(t - step, t, int_step), (index, )) [ next_membrane[index], next_active_sodium[index], next_inactive_sodium[index], next_active_potassium[index] ] = result[len(result) - 1][0:4] next_cn_membrane = [0.0, 0.0] next_cn_active_sodium = [0.0, 0.0] next_cn_inactive_sodium = [0.0, 0.0] next_cn_active_potassium = [0.0, 0.0] # Update states of central elements for index in range(0, len(self._central_element)): result = odeint(self.hnn_state, [self._central_element[index].membrane_potential, self._central_element[index].active_cond_sodium, self._central_element[index].inactive_cond_sodium, self._central_element[index].active_cond_potassium], numpy.arange(t - step, t, int_step), (self._num_osc + index, )) [ next_cn_membrane[index], next_cn_active_sodium[index], next_cn_inactive_sodium[index], next_cn_active_potassium[index] ] = result[len(result) - 1][0:4] # Noise generation self._noise = [ 1.0 + 0.01 * (random.random() * 2.0 - 1.0) for i in range(self._num_osc)] # Updating states of PNs self.__update_peripheral_neurons(t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium) # Updation states of CN self.__update_central_neurons(t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium) return (next_membrane, next_cn_membrane) def __update_peripheral_neurons(self, t, step, next_membrane, next_active_sodium, next_inactive_sodium, next_active_potassium): """! @brief Update peripheral neurons in line with new values of current in channels. @param[in] t (doubles): Current time of simulation. @param[in] step (uint): Step (time duration) during simulation when states of oscillators should be calculated. @param[in] next_membrane (list): New values of membrane potentials for peripheral neurons. @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for peripheral neurons. @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for peripheral neurons. @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for peripheral neurons. """ self._membrane_potential = next_membrane[:] self._active_cond_sodium = next_active_sodium[:] self._inactive_cond_sodium = next_inactive_sodium[:] self._active_cond_potassium = next_active_potassium[:] for index in range(0, self._num_osc): if self._pulse_generation[index] is False: if self._membrane_potential[index] >= 0.0: self._pulse_generation[index] = True self._pulse_generation_time[index].append(t) elif self._membrane_potential[index] < 0.0: self._pulse_generation[index] = False # Update connection from CN2 to PN if self._link_weight3[index] == 0.0: if self._membrane_potential[index] > self._params.threshold: self._link_pulse_counter[index] += step if self._link_pulse_counter[index] >= 1 / self._params.eps: self._link_weight3[index] = self._params.w3 self._link_activation_time[index] = t elif not ((self._link_activation_time[index] < t) and (t < self._link_activation_time[index] + self._params.deltah)): self._link_weight3[index] = 0.0 self._link_pulse_counter[index] = 0.0 def __update_central_neurons(self, t, next_cn_membrane, next_cn_active_sodium, next_cn_inactive_sodium, next_cn_active_potassium): """! @brief Update of central neurons in line with new values of current in channels. @param[in] t (doubles): Current time of simulation. @param[in] next_membrane (list): New values of membrane potentials for central neurons. @Param[in] next_active_sodium (list): New values of activation conductances of the sodium channels for central neurons. @param[in] next_inactive_sodium (list): New values of inactivaton conductances of the sodium channels for central neurons. @param[in] next_active_potassium (list): New values of activation conductances of the potassium channel for central neurons. """ for index in range(0, len(self._central_element)): self._central_element[index].membrane_potential = next_cn_membrane[index] self._central_element[index].active_cond_sodium = next_cn_active_sodium[index] self._central_element[index].inactive_cond_sodium = next_cn_inactive_sodium[index] self._central_element[index].active_cond_potassium = next_cn_active_potassium[index] if self._central_element[index].pulse_generation is False: if self._central_element[index].membrane_potential >= 0.0: self._central_element[index].pulse_generation = True self._central_element[index].pulse_generation_time.append(t) elif self._central_element[index].membrane_potential < 0.0: self._central_element[index].pulse_generation = False def hnn_state(self, inputs, t, argv): """! @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator. @param[in] inputs (list): States of oscillator for integration [v, m, h, n] (see description below). @param[in] t (double): Current time of simulation. @param[in] argv (tuple): Extra arguments that are not used for integration - index of oscillator. @return (list) new values of oscillator [v, m, h, n], where: v - membrane potantial of oscillator, m - activation conductance of the sodium channel, h - inactication conductance of the sodium channel, n - activation conductance of the potassium channel. """ index = argv v = inputs[0] # membrane potential (v). m = inputs[1] # activation conductance of the sodium channel (m). h = inputs[2] # inactivaton conductance of the sodium channel (h). n = inputs[3] # activation conductance of the potassium channel (n). # Calculate ion current # gNa * m[i]^3 * h * (v[i] - vNa) + gK * n[i]^4 * (v[i] - vK) + gL (v[i] - vL) active_sodium_part = self._params.gNa * (m ** 3) * h * (v - self._params.vNa) inactive_sodium_part = self._params.gK * (n ** 4) * (v - self._params.vK) active_potassium_part = self._params.gL * (v - self._params.vL) Iion = active_sodium_part + inactive_sodium_part + active_potassium_part Iext = 0.0 Isyn = 0.0 if index < self._num_osc: # PN - peripheral neuron - calculation of external current and synaptic current. Iext = self._stimulus[index] * self._noise[index] # probably noise can be pre-defined for reducting compexity memory_impact1 = 0.0 for i in range(0, len(self._central_element[0].pulse_generation_time)): memory_impact1 += self.__alfa_function(t - self._central_element[0].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory); memory_impact2 = 0.0 for i in range(0, len(self._central_element[1].pulse_generation_time)): memory_impact2 += self.__alfa_function(t - self._central_element[1].pulse_generation_time[i], self._params.alfa_inhibitory, self._params.betta_inhibitory); Isyn = self._params.w2 * (v - self._params.Vsyninh) * memory_impact1 + self._link_weight3[index] * (v - self._params.Vsyninh) * memory_impact2; else: # CN - central element. central_index = index - self._num_osc if central_index == 0: Iext = self._params.Icn1 # CN1 memory_impact = 0.0 for index_oscillator in range(0, self._num_osc): for index_generation in range(0, len(self._pulse_generation_time[index_oscillator])): memory_impact += self.__alfa_function(t - self._pulse_generation_time[index_oscillator][index_generation], self._params.alfa_excitatory, self._params.betta_excitatory); Isyn = self._params.w1 * (v - self._params.Vsynexc) * memory_impact elif central_index == 1: Iext = self._params.Icn2 # CN2 Isyn = 0.0 else: assert 0; # Membrane potential dv = -Iion + Iext - Isyn # Calculate variables potential = v - self._params.vRest am = (2.5 - 0.1 * potential) / (math.exp(2.5 - 0.1 * potential) - 1.0) ah = 0.07 * math.exp(-potential / 20.0) an = (0.1 - 0.01 * potential) / (math.exp(1.0 - 0.1 * potential) - 1.0) bm = 4.0 * math.exp(-potential / 18.0) bh = 1.0 / (math.exp(3.0 - 0.1 * potential) + 1.0) bn = 0.125 * math.exp(-potential / 80.0) dm = am * (1.0 - m) - bm * m dh = ah * (1.0 - h) - bh * h dn = an * (1.0 - n) - bn * n return [dv, dm, dh, dn] def allocate_sync_ensembles(self, tolerance = 0.1): """! @brief Allocates clusters in line with ensembles of synchronous oscillators where each. Synchronous ensemble corresponds to only one cluster. @param[in] tolerance (double): maximum error for allocation of synchronous ensemble oscillators. @return (list) Grours (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ return allocate_sync_ensembles(self._membrane_dynamic_pointer, tolerance, 20.0, None) def __alfa_function(self, time, alfa, betta): """! @brief Calculates value of alfa-function for difference between spike generation time and current simulation time. @param[in] time (double): Difference between last spike generation time and current time. @param[in] alfa (double): Alfa parameter for alfa-function. @param[in] betta (double): Betta parameter for alfa-function. @return (double) Value of alfa-function. """ return alfa * time * math.exp(-betta * time) pyclustering-0.10.1.2/pyclustering/nnet/hysteresis.py000077500000000000000000000313261375753423500227570ustar00rootroot00000000000000"""! @brief Neural Network: Hysteresis Oscillatory Network @details Implementation based on paper @cite article::nnet::hysteresis::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from scipy.integrate import odeint from pyclustering.nnet import * from pyclustering.utils import draw_dynamics class hysteresis_dynamic: """! @brief Represents output dynamic of hysteresis oscillatory network. """ @property def output(self): """! @brief (list) Returns outputs of oscillator during simulation. """ return self._dynamic; @property def time(self): """! @brief (list) Returns sampling times when dynamic is measured during simulation. """ return self._time; def __init__(self, amplitudes, time): """! @brief Constructor of hysteresis neural network dynamic. @param[in] amplitudes (list): Dynamic (amplitudes) of oscillators on each step of simulation. @param[in] time (list): Simulation time (timestamps of simulation steps) when amplitudes are stored. """ if (len(amplitudes) != len(time)): raise NameError("Length of list of dynamics of oscillators should be equal to length of simulation timestamps of steps."); self._dynamic = amplitudes; self._time = time; def __len__(self): """! @brief (uint) Returns number of simulation steps that are stored in dynamic. """ return len(self._dynamic); def allocate_sync_ensembles(self, tolerance = 0.1, threshold_steps = 1): """! @brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators. @param[in] threshold_steps (uint): Number of steps from the end of simulation that should be analysed for ensemble allocation. If amout of simulation steps has been less than threshold steps than amount of steps will be reduced to amout of simulation steps. @return (list) Grours of indexes of synchronous oscillators, for example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]." """ clusters = [ [0] ]; number_oscillators = len(self._dynamic[0]); for i in range(1, number_oscillators, 1): captured_neuron = True; for cluster in clusters: neuron_index = cluster[0]; analysis_steps = threshold_steps; if (len(self._dynamic) < analysis_steps): analysis_steps = len(self._dynamic); analysis_start_step_index = len(self._dynamic) - 1; for step in range(analysis_start_step_index, analysis_start_step_index - analysis_steps, -1): neuron_amplitude = self._dynamic[step][neuron_index]; candidate_amplitude = self._dynamic[step][i]; if ( not (candidate_amplitude < (neuron_amplitude + tolerance)) or not (candidate_amplitude > (neuron_amplitude - tolerance)) ): captured_neuron = False; break; if ( captured_neuron is True ): cluster.append(i); break; if (captured_neuron is False): clusters.append([i]); return clusters; class hysteresis_visualizer: """! @brief Visualizer of output dynamic of hysteresis oscillatory network. """ @staticmethod def show_output_dynamic(hysteresis_output_dynamic): """! @brief Shows output dynamic (output of each oscillator) during simulation. @param[in] hysteresis_output_dynamic (hysteresis_dynamic): Output dynamic of the hysteresis oscillatory network. """ draw_dynamics(hysteresis_output_dynamic.time, hysteresis_output_dynamic.output, x_title = "Time", y_title = "x(t)"); class hysteresis_network(network): """! @brief Hysteresis oscillatory network that uses relaxation oscillators that are represented by objective hysteresis neurons whose output in range [-1, +1]. Examples: @code # create hysteresis oscillatory network with 5 oscillators. network = hysteresis_network(5); # set initial states (from range [-1, +1]). network.states = [1 0 1 0 1]; # set initial outputs. network.outputs = [1 1 1 1 1]; # perform simulation of the network during 1000 steps in 10 time units. output_dynamic = network.simulate(1000, 10); # show output dynamic of the network. hysteresis_visualizer.show_output_dynamic(output_dynamic); # obtain synchronous ensembles. ensembles = output_dynamic.allocate_sync_ensembles(tolerance = 0.5, threshold_steps = 5); print(ensembles); @endcode """ @property def outputs(self): """! @brief Returns current outputs of neurons. @return (list) Current outputs of neurons. """ return self._outputs; @outputs.setter def outputs(self, values): """! @brief Sets outputs of neurons. """ self._outputs = [val for val in values]; self._outputs_buffer = [val for val in values]; @property def states(self): """! @brief Return current states of neurons. @return (list) States of neurons. """ return self._states; @states.setter def states(self, values): """! @brief Set current states of neurons. """ self._states = [val for val in values]; def __init__(self, num_osc, own_weight = -4, neigh_weight = -1, type_conn = conn_type.ALL_TO_ALL, type_conn_represent = conn_represent.MATRIX): """! @brief Constructor of hysteresis oscillatory network. @param[in] num_osc (uint): Number of oscillators in the network. @param[in] own_weight (double): Weight of connection from oscillator to itself - own weight. @param[in] neigh_weight (double): Weight of connection between oscillators. @param[in] type_conn (conn_type): Type of connection between oscillators in the network. @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list. """ super().__init__(num_osc, type_conn, type_conn_represent); # list of states of neurons. self._states = [0] * self._num_osc; # list of current outputs of neurons. self._outputs = [-1] * self._num_osc; # list of previous outputs of neurons self._outputs_buffer = [-1] * self._num_osc; # matrix of connection weights between neurons. self._weight = list(); for index in range(0, self._num_osc, 1): self._weight.append( [neigh_weight] * self._num_osc); self._weight[index][index] = own_weight; def _neuron_states(self, inputs, t, argv): """! @brief Returns new value of the neuron (oscillator). @param[in] inputs (list): Initial values (current) of the neuron - excitatory. @param[in] t (double): Current time of simulation. @param[in] argv (tuple): Extra arguments that are not used for integration - index of the neuron. @return (double) New value of the neuron. """ xi = inputs[0]; index = argv; # own impact impact = self._weight[index][index] * self._outputs[index]; for i in range(0, self._num_osc, 1): if (self.has_connection(i, index)): impact += self._weight[index][i] * self._outputs[i]; x = -xi + impact; if (xi > 1): self._outputs_buffer[index] = 1; if (xi < -1): self._outputs_buffer[index] = -1; return x; def simulate(self, steps, time, solution = solve_type.RK4, collect_dynamic = True): """! @brief Performs static simulation of hysteresis oscillatory network. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] solution (solve_type): Type of solution (solving). @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (hysteresis_dynamic) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. """ return self.simulate_static(steps, time, solution, collect_dynamic); def simulate_static(self, steps, time, solution = solve_type.RK4, collect_dynamic = False): """! @brief Performs static simulation of hysteresis oscillatory network. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] solution (solve_type): Type of solution (solving). @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (hysteresis_dynamic) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. """ # Check solver before simulation if (solution == solve_type.FAST): raise NameError("Solver FAST is not support due to low accuracy that leads to huge error."); elif (solution == solve_type.RKF45): raise NameError("Solver RKF45 is not support in python version."); dyn_state = None; dyn_time = None; if (collect_dynamic == True): dyn_state = []; dyn_time = []; dyn_state.append(self._states); dyn_time.append(0); step = time / steps; int_step = step / 10.0; for t in numpy.arange(step, time + step, step): # update states of oscillators self._states = self._calculate_states(solution, t, step, int_step); # update states of oscillators if (collect_dynamic is True): dyn_state.append(self._states); dyn_time.append(t); if (collect_dynamic is False): dyn_state.append(self._states); dyn_time.append(time); return hysteresis_dynamic(dyn_state, dyn_time); def _calculate_states(self, solution, t, step, int_step): """! @brief Calculates new states for neurons using differential calculus. Returns new states for neurons. @param[in] solution (solve_type): Type solver of the differential equation. @param[in] t (double): Current time of simulation. @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated. @param[in] int_step (double): Step differentiation that is used for solving differential equation. @return (list) New states for neurons. """ next_states = [0] * self._num_osc; for index in range (0, self._num_osc, 1): result = odeint(self._neuron_states, self._states[index], numpy.arange(t - step, t, int_step), (index , )); next_states[index] = result[len(result) - 1][0]; self._outputs = [val for val in self._outputs_buffer]; return next_states;pyclustering-0.10.1.2/pyclustering/nnet/legion.py000077500000000000000000000527401375753423500220350ustar00rootroot00000000000000"""! @brief Neural Network: Local Excitatory Global Inhibitory Oscillatory Network (LEGION) @details Implementation based on paper @cite article::legion::1, @cite article::legion::2. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy import random import pyclustering.core.legion_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.nnet import * from pyclustering.utils import heaviside, allocate_sync_ensembles from scipy.integrate import odeint class legion_parameters: """! @brief Describes parameters of LEGION. @details Contained parameters affect on output dynamic of each oscillator of the network. @see legion_network """ def __init__(self): """! @brief Default constructor of parameters for LEGION (local excitatory global inhibitory oscillatory network). @details Constructor initializes parameters by default non-zero values that can be used for simple simulation. """ ## Coefficient that affects intrinsic inhibitor of each oscillator. Should be the same as 'alpha'. self.eps = 0.02; ## Coefficient is chosen to be on the same order of magnitude as 'eps'. Affects on exponential function that decays on a slow time scale. self.alpha = 0.005; ## Coefficient that is used to control the ratio of the times that the solution spends in these two phases. For a larger value of g, the solution spends a shorter time in the active phase. self.gamma = 6.0; ## Coefficient that affects on intrinsic inhibitor of each oscillator. Specifies the steepness of the sigmoid function. self.betta = 0.1; ## Scale coefficient that is used by potential, should be greater than 0. self.lamda = 0.1; ## Threshold that should be exceeded by a potential to switch on potential. self.teta = 0.9; ## Threshold that should be exceeded by a single oscillator to affect its neighbors. self.teta_x = -1.5; ## Threshold that should be exceeded to activate potential. If potential less than the threshold then potential is relaxed to 0 on time scale 'mu'. self.teta_p = 1.5; ## Threshold that should be exceeded by any oscillator to activate global inhibitor. self.teta_xz = 0.1; ## Threshold that should be exceeded to affect on a oscillator by the global inhibitor. self.teta_zx = 0.1; ## Weight of permanent connections. self.T = 2.0; ## Defines time scaling of relaxing of oscillator potential. self.mu = 0.01; ## Weight of global inhibitory connections. self.Wz = 1.5; ## Total dynamic weights to a single oscillator from neighbors. Sum of weights of dynamic connections to a single oscillator can not be bigger than Wt. self.Wt = 8.0; ## Rate at which the global inhibitor reacts to the stimulation from the oscillator network. self.fi = 3.0; ## Multiplier of oscillator noise. Plays important role in desynchronization process. self.ro = 0.02; ## Value of external stimulus. self.I = 0.2; ## Defines whether to use potentional of oscillator or not. self.ENABLE_POTENTIONAL = True; class legion_dynamic: """! @brief Represents output dynamic of LEGION. """ @property def output(self): """! @brief Returns output dynamic of the network. """ if (self.__ccore_legion_dynamic_pointer is not None): return wrapper.legion_dynamic_get_output(self.__ccore_legion_dynamic_pointer); return self.__output; @property def inhibitor(self): """! @brief Returns output dynamic of the global inhibitor of the network. """ if (self.__ccore_legion_dynamic_pointer is not None): return wrapper.legion_dynamic_get_inhibitory_output(self.__ccore_legion_dynamic_pointer); return self.__inhibitor; @property def time(self): """! @brief Returns simulation time. """ if (self.__ccore_legion_dynamic_pointer is not None): return wrapper.legion_dynamic_get_time(self.__ccore_legion_dynamic_pointer); return list(range(len(self))); def __init__(self, output, inhibitor, time, ccore = None): """! @brief Constructor of legion dynamic. @param[in] output (list): Output dynamic of the network represented by excitatory values of oscillators. @param[in] inhibitor (list): Output dynamic of the global inhibitor of the network. @param[in] time (list): Simulation time. @param[in] ccore (POINTER): Pointer to CCORE legion_dynamic. If it is specified then others arguments can be omitted. """ self.__output = output; self.__inhibitor = inhibitor; self._time = time; self.__ccore_legion_dynamic_pointer = ccore; def __del__(self): """! @brief Destructor of the dynamic of the legion network. """ if (self.__ccore_legion_dynamic_pointer is not None): wrapper.legion_dynamic_destroy(self.__ccore_legion_dynamic_pointer); def __len__(self): """! @brief Returns length of output dynamic. """ if (self.__ccore_legion_dynamic_pointer is not None): return wrapper.legion_dynamic_get_size(self.__ccore_legion_dynamic_pointer); return len(self._time); def allocate_sync_ensembles(self, tolerance = 0.1): """! @brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators. @return (list) Grours of indexes of synchronous oscillators, for example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ if (self.__ccore_legion_dynamic_pointer is not None): self.__output = wrapper.legion_dynamic_get_output(self.__ccore_legion_dynamic_pointer); return allocate_sync_ensembles(self.__output, tolerance); class legion_network(network): """! @brief Local excitatory global inhibitory oscillatory network (LEGION) that uses relaxation oscillator based on Van der Pol model. @details The model uses global inhibitor to de-synchronize synchronous ensembles of oscillators. CCORE option can be used to use the pyclustering core - C/C++ shared library for processing that significantly increases performance. Example: @code # Create parameters of the network parameters = legion_parameters(); parameters.Wt = 4.0; # Create stimulus stimulus = [1, 1, 0, 0, 0, 1, 1, 1]; # Create the network (use CCORE for fast solving) net = legion_network(len(stimulus), parameters, conn_type.GRID_FOUR, ccore = True); # Simulate network - result of simulation is output dynamic of the network output_dynamic = net.simulate(1000, 750, stimulus); # Draw output dynamic draw_dynamics(output_dynamic.time, output_dynamic.output, x_title = "Time", y_title = "x(t)"); @endcode """ def __init__(self, num_osc, parameters = None, type_conn = conn_type.ALL_TO_ALL, type_conn_represent = conn_represent.MATRIX, ccore = True): """! @brief Constructor of oscillatory network LEGION (local excitatory global inhibitory oscillatory network). @param[in] num_osc (uint): Number of oscillators in the network. @param[in] parameters (legion_parameters): Parameters of the network that are defined by structure 'legion_parameters'. @param[in] type_conn (conn_type): Type of connection between oscillators in the network. @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list. @param[in] ccore (bool): If True then all interaction with object will be performed via CCORE library (C++ implementation of pyclustering). """ self._params = None; # parameters of the network self.__ccore_legion_pointer = None; self._params = parameters; # set parameters of the network if (self._params is None): self._params = legion_parameters(); if ( (ccore is True) and ccore_library.workable() ): self.__ccore_legion_pointer = wrapper.legion_create(num_osc, type_conn, self._params); else: super().__init__(num_osc, type_conn, type_conn_represent); # initial states self._excitatory = [ random.random() for _ in range(self._num_osc) ]; self._inhibitory = [0.0] * self._num_osc; self._potential = [0.0] * self._num_osc; self._coupling_term = None; # coupling term of each oscillator self._global_inhibitor = 0; # value of global inhibitory self._stimulus = None; # stimulus of each oscillator self._dynamic_coupling = None; # dynamic connection between oscillators self._coupling_term = [0.0] * self._num_osc; self._buffer_coupling_term = [0.0] * self._num_osc; # generate first noises self._noise = [random.random() * self._params.ro for i in range(self._num_osc)]; def __del__(self): """! @brief Default destructor of LEGION. """ if (self.__ccore_legion_pointer is not None): wrapper.legion_destroy(self.__ccore_legion_pointer); self.__ccore_legion_pointer = None; def __len__(self): """! @brief (uint) Returns size of LEGION. """ if (self.__ccore_legion_pointer is not None): return wrapper.legion_get_size(self.__ccore_legion_pointer); return self._num_osc; def __create_stimulus(self, stimulus): """! @brief Create stimulus for oscillators in line with stimulus map and parameters. @param[in] stimulus (list): Stimulus for oscillators that is represented by list, number of stimulus should be equal number of oscillators. """ if (len(stimulus) != self._num_osc): raise NameError("Number of stimulus should be equal number of oscillators in the network."); else: self._stimulus = []; for val in stimulus: if (val > 0): self._stimulus.append(self._params.I); else: self._stimulus.append(0); def __create_dynamic_connections(self): """! @brief Create dynamic connection in line with input stimulus. """ if self._stimulus is None: raise NameError("Stimulus should initialed before creation of the dynamic connections in the network."); self._dynamic_coupling = [ [0] * self._num_osc for i in range(self._num_osc)]; for i in range(self._num_osc): neighbors = self.get_neighbors(i) if (len(neighbors) > 0) and (self._stimulus[i] > 0): number_stimulated_neighbors = 0.0 for j in neighbors: if self._stimulus[j] > 0: number_stimulated_neighbors += 1.0 if (number_stimulated_neighbors > 0): dynamic_weight = self._params.Wt / number_stimulated_neighbors for j in neighbors: self._dynamic_coupling[i][j] = dynamic_weight def simulate(self, steps, time, stimulus, solution=solve_type.RK4, collect_dynamic=True): """! @brief Performs static simulation of LEGION oscillatory network. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators, example of stimulus for 5 oscillators [0, 0, 1, 1, 0], value of stimulus is defined by parameter 'I'. @param[in] solution (solve_type): Method that is used for differential equation. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. """ if self.__ccore_legion_pointer is not None: pointer_dynamic = wrapper.legion_simulate(self.__ccore_legion_pointer, steps, time, solution, collect_dynamic, stimulus) return legion_dynamic(None, None, None, pointer_dynamic) # Check solver before simulation if solution == solve_type.FAST: raise NameError("Solver FAST is not support due to low accuracy that leads to huge error.") elif solution == solve_type.RKF45: raise NameError("Solver RKF45 is not support in python version. RKF45 is supported in CCORE implementation.") # set stimulus self.__create_stimulus(stimulus) # calculate dynamic weights self.__create_dynamic_connections() dyn_exc = None dyn_time = None dyn_ginh = None # Store only excitatory of the oscillator if collect_dynamic is True: dyn_exc = [] dyn_time = [] dyn_ginh = [] step = time / steps int_step = step / 10.0 for t in numpy.arange(step, time + step, step): # update states of oscillators self._calculate_states(solution, t, step, int_step) # update states of oscillators if collect_dynamic is True: dyn_exc.append(self._excitatory) dyn_time.append(t) dyn_ginh.append(self._global_inhibitor) else: dyn_exc = self._excitatory dyn_time = t dyn_ginh = self._global_inhibitor return legion_dynamic(dyn_exc, dyn_ginh, dyn_time); def _calculate_states(self, solution, t, step, int_step): """! @brief Calculates new state of each oscillator in the network. @param[in] solution (solve_type): Type solver of the differential equation. @param[in] t (double): Current time of simulation. @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated. @param[in] int_step (double): Step differentiation that is used for solving differential equation. """ next_excitatory = [0.0] * self._num_osc; next_inhibitory = [0.0] * self._num_osc; next_potential = []; if (self._params.ENABLE_POTENTIONAL is True): next_potential = [0.0] * self._num_osc; # Update states of oscillators for index in range (0, self._num_osc, 1): if (self._params.ENABLE_POTENTIONAL is True): result = odeint(self._legion_state, [self._excitatory[index], self._inhibitory[index], self._potential[index]], numpy.arange(t - step, t, int_step), (index , )); [ next_excitatory[index], next_inhibitory[index], next_potential[index] ] = result[len(result) - 1][0:3]; else: result = odeint(self._legion_state_simplify, [self._excitatory[index], self._inhibitory[index] ], numpy.arange(t - step, t, int_step), (index , )); [ next_excitatory[index], next_inhibitory[index] ] = result[len(result) - 1][0:2]; # Update coupling term neighbors = self.get_neighbors(index); coupling = 0 for index_neighbor in neighbors: coupling += self._dynamic_coupling[index][index_neighbor] * heaviside(self._excitatory[index_neighbor] - self._params.teta_x); self._buffer_coupling_term[index] = coupling - self._params.Wz * heaviside(self._global_inhibitor - self._params.teta_xz); # Update state of global inhibitory result = odeint(self._global_inhibitor_state, self._global_inhibitor, numpy.arange(t - step, t, int_step), (None, )); self._global_inhibitor = result[len(result) - 1][0]; self._noise = [random.random() * self._params.ro for i in range(self._num_osc)]; self._coupling_term = self._buffer_coupling_term[:]; self._inhibitory = next_inhibitory[:]; self._excitatory = next_excitatory[:]; if (self._params.ENABLE_POTENTIONAL is True): self._potential = next_potential[:]; def _global_inhibitor_state(self, z, t, argv): """! @brief Returns new value of global inhibitory @param[in] z (dobule): Current value of inhibitory. @param[in] t (double): Current time of simulation. @param[in] argv (tuple): It's not used, can be ignored. @return (double) New value if global inhibitory (not assign). """ sigma = 0.0; for x in self._excitatory: if (x > self._params.teta_zx): sigma = 1.0; break; return self._params.fi * (sigma - z); def _legion_state_simplify(self, inputs, t, argv): """! @brief Returns new values of excitatory and inhibitory parts of oscillator of oscillator. @details Simplify model doesn't consider oscillator potential. @param[in] inputs (list): Initial values (current) of oscillator [excitatory, inhibitory]. @param[in] t (double): Current time of simulation. @param[in] argv (uint): Extra arguments that are not used for integration - index of oscillator. @return (list) New values of excitatoty and inhibitory part of oscillator (not assign). """ index = argv; x = inputs[0]; # excitatory y = inputs[1]; # inhibitory dx = 3.0 * x - x ** 3.0 + 2.0 - y + self._stimulus[index] + self._coupling_term[index] + self._noise[index]; dy = self._params.eps * (self._params.gamma * (1.0 + math.tanh(x / self._params.betta)) - y); neighbors = self.get_neighbors(index); potential = 0.0; for index_neighbor in neighbors: potential += self._params.T * heaviside(self._excitatory[index_neighbor] - self._params.teta_x); return [dx, dy]; def _legion_state(self, inputs, t, argv): """! @brief Returns new values of excitatory and inhibitory parts of oscillator and potential of oscillator. @param[in] inputs (list): Initial values (current) of oscillator [excitatory, inhibitory, potential]. @param[in] t (double): Current time of simulation. @param[in] argv (uint): Extra arguments that are not used for integration - index of oscillator. @return (list) New values of excitatoty and inhibitory part of oscillator and new value of potential (not assign). """ index = argv; x = inputs[0]; # excitatory y = inputs[1]; # inhibitory p = inputs[2]; # potential potential_influence = heaviside(p + math.exp(-self._params.alpha * t) - self._params.teta); dx = 3.0 * x - x ** 3.0 + 2.0 - y + self._stimulus[index] * potential_influence + self._coupling_term[index] + self._noise[index]; dy = self._params.eps * (self._params.gamma * (1.0 + math.tanh(x / self._params.betta)) - y); neighbors = self.get_neighbors(index); potential = 0.0; for index_neighbor in neighbors: potential += self._params.T * heaviside(self._excitatory[index_neighbor] - self._params.teta_x); dp = self._params.lamda * (1.0 - p) * heaviside(potential - self._params.teta_p) - self._params.mu * p; return [dx, dy, dp];pyclustering-0.10.1.2/pyclustering/nnet/pcnn.py000077500000000000000000000475221375753423500215200ustar00rootroot00000000000000"""! @brief Neural Network: Pulse Coupled Neural Network @details Implementation based on paper @cite book::image_processing_using_pcnn. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random import numpy import matplotlib.pyplot as plt import matplotlib.animation as animation from PIL import Image from pyclustering.nnet import * from pyclustering.core.wrapper import ccore_library import pyclustering.core.pcnn_wrapper as wrapper from pyclustering.utils import draw_dynamics class pcnn_parameters: """! @brief Parameters for pulse coupled neural network. """ def __init__(self): """! @brief Default constructor of parameters for pulse-coupled neural network. @details Constructor initializes parameters by default non-zero values that can be used for simple simulation. """ ## Multiplier for the feeding compartment at the current step. self.VF = 1.0 ## Multiplier for the linking compartment at the current step. self.VL = 1.0 ## Multiplier for the threshold at the current step. self.VT = 10.0 ## Multiplier for the feeding compartment at the previous step. self.AF = 0.1 ## Multiplier for the linking compartment at the previous step. self.AL = 0.1 ## Multiplier for the threshold at the previous step. self.AT = 0.5 ## Synaptic weight - neighbours influence on linking compartment. self.W = 1.0 ## Synaptic weight - neighbours influence on feeding compartment. self.M = 1.0 ## Linking strength in the network. self.B = 0.1 ## Enable/disable Fast-Linking mode. Fast linking helps to overcome some of the effects of time quantisation. This process allows the linking wave to progress a lot faster than the feeding wave. self.FAST_LINKING = False class pcnn_dynamic: """! @brief Represents output dynamic of PCNN (pulse-coupled neural network). """ @property def output(self): """! @brief (list) Returns oscillato outputs during simulation. """ if self.__ccore_pcnn_dynamic_pointer is not None: return wrapper.pcnn_dynamic_get_output(self.__ccore_pcnn_dynamic_pointer) return self.__dynamic @property def time(self): """! @brief (list) Returns sampling times when dynamic is measured during simulation. """ if self.__ccore_pcnn_dynamic_pointer is not None: return wrapper.pcnn_dynamic_get_time(self.__ccore_pcnn_dynamic_pointer) return list(range(len(self))) def __init__(self, dynamic, ccore=None): """! @brief Constructor of PCNN dynamic. @param[in] dynamic (list): Dynamic of oscillators on each step of simulation. If ccore pointer is specified than it can be ignored. @param[in] ccore (ctypes.pointer): Pointer to CCORE pcnn_dynamic instance in memory. """ self.__OUTPUT_TRUE = 1 # fire value for oscillators. self.__OUTPUT_FALSE = 0 # rest value for oscillators. self.__dynamic = dynamic self.__ccore_pcnn_dynamic_pointer = ccore def __del__(self): """! @brief Default destructor of PCNN dynamic. """ if self.__ccore_pcnn_dynamic_pointer is not None: wrapper.pcnn_dynamic_destroy(self.__ccore_pcnn_dynamic_pointer) def __len__(self): """! @brief (uint) Returns number of simulation steps that are stored in dynamic. """ if self.__ccore_pcnn_dynamic_pointer is not None: return wrapper.pcnn_dynamic_get_size(self.__ccore_pcnn_dynamic_pointer) return len(self.__dynamic) def allocate_sync_ensembles(self): """! @brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @return (list) Grours (lists) of indexes of synchronous oscillators. For example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ if self.__ccore_pcnn_dynamic_pointer is not None: return wrapper.pcnn_dynamic_allocate_sync_ensembles(self.__ccore_pcnn_dynamic_pointer) sync_ensembles = [] traverse_oscillators = set() number_oscillators = len(self.__dynamic[0]) for t in range(len(self.__dynamic) - 1, 0, -1): sync_ensemble = [] for i in range(number_oscillators): if self.__dynamic[t][i] == self.__OUTPUT_TRUE: if i not in traverse_oscillators: sync_ensemble.append(i) traverse_oscillators.add(i) if sync_ensemble != []: sync_ensembles.append(sync_ensemble) return sync_ensembles def allocate_spike_ensembles(self): """! @brief Analyses output dynamic of network and allocates spikes on each iteration as a list of indexes of oscillators. @details Each allocated spike ensemble represents list of indexes of oscillators whose output is active. @return (list) Spike ensembles of oscillators. """ if self.__ccore_pcnn_dynamic_pointer is not None: return wrapper.pcnn_dynamic_allocate_spike_ensembles(self.__ccore_pcnn_dynamic_pointer) spike_ensembles = [] number_oscillators = len(self.__dynamic[0]) for t in range(len(self.__dynamic)): spike_ensemble = [] for index in range(number_oscillators): if self.__dynamic[t][index] == self.__OUTPUT_TRUE: spike_ensemble.append(index) if len(spike_ensemble) > 0: spike_ensembles.append(spike_ensemble) return spike_ensembles def allocate_time_signal(self): """! @brief Analyses output dynamic and calculates time signal (signal vector information) of network output. @return (list) Time signal of network output. """ if self.__ccore_pcnn_dynamic_pointer is not None: return wrapper.pcnn_dynamic_allocate_time_signal(self.__ccore_pcnn_dynamic_pointer) signal_vector_information = [] for t in range(0, len(self.__dynamic)): signal_vector_information.append(sum(self.__dynamic[t])) return signal_vector_information class pcnn_visualizer: """! @brief Visualizer of output dynamic of pulse-coupled neural network (PCNN). """ @staticmethod def show_time_signal(pcnn_output_dynamic): """! @brief Shows time signal (signal vector information) using network dynamic during simulation. @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network. """ time_signal = pcnn_output_dynamic.allocate_time_signal() time_axis = range(len(time_signal)) plt.subplot(1, 1, 1) plt.plot(time_axis, time_signal, '-') plt.ylabel("G (time signal)") plt.xlabel("t (iteration)") plt.grid(True) plt.show() @staticmethod def show_output_dynamic(pcnn_output_dynamic, separate_representation = False): """! @brief Shows output dynamic (output of each oscillator) during simulation. @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network. @param[in] separate_representation (list): Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage. """ draw_dynamics(pcnn_output_dynamic.time, pcnn_output_dynamic.output, x_title = "t", y_title = "y(t)", separate = separate_representation) @staticmethod def animate_spike_ensembles(pcnn_output_dynamic, image_size): """! @brief Shows animation of output dynamic (output of each oscillator) during simulation. @param[in] pcnn_output_dynamic (pcnn_dynamic): Output dynamic of the pulse-coupled neural network. @param[in] image_size (tuple): Image size represented as (height, width). """ figure = plt.figure() time_signal = pcnn_output_dynamic.allocate_time_signal() spike_ensembles = pcnn_output_dynamic.allocate_spike_ensembles() spike_animation = [] ensemble_index = 0 for t in range(len(time_signal)): image_color_segments = [(255, 255, 255)] * (image_size[0] * image_size[1]) if time_signal[t] > 0: for index_pixel in spike_ensembles[ensemble_index]: image_color_segments[index_pixel] = (0, 0, 0) ensemble_index += 1 stage = numpy.array(image_color_segments, numpy.uint8) stage = numpy.reshape(stage, image_size + ((3),)) # ((3),) it's size of RGB - third dimension. image_cluster = Image.fromarray(stage, 'RGB') spike_animation.append( [ plt.imshow(image_cluster, interpolation='none') ] ) im_ani = animation.ArtistAnimation(figure, spike_animation, interval=75, repeat_delay=3000, blit=True) plt.show() class pcnn_network(network): """! @brief Model of oscillatory network that is based on the Eckhorn model. @details CCORE option can be used to use the pyclustering core - C/C++ shared library for processing that significantly increases performance. Here is an example how to perform PCNN simulation: @code from pyclustering.nnet.pcnn import pcnn_network, pcnn_visualizer # Create Pulse-Coupled neural network with 10 oscillators. net = pcnn_network(10) # Perform simulation during 100 steps using binary external stimulus. dynamic = net.simulate(50, [1, 1, 1, 0, 0, 0, 0, 1, 1, 1]) # Allocate synchronous ensembles from the output dynamic. ensembles = dynamic.allocate_sync_ensembles() # Show output dynamic. pcnn_visualizer.show_output_dynamic(dynamic, ensembles) @endcode """ __OUTPUT_TRUE = 1 # fire value for oscillators. __OUTPUT_FALSE = 0 # rest value for oscillators. def __init__(self, num_osc, parameters=None, type_conn=conn_type.ALL_TO_ALL, type_conn_represent=conn_represent.MATRIX, height=None, width=None, ccore=True): """! @brief Constructor of oscillatory network is based on Kuramoto model. @param[in] num_osc (uint): Number of oscillators in the network. @param[in] parameters (pcnn_parameters): Parameters of the network. @param[in] type_conn (conn_type): Type of connection between oscillators in the network (all-to-all, grid, bidirectional list, etc.). @param[in] type_conn_represent (conn_represent): Internal representation of connection in the network: matrix or list. @param[in] height (uint): Number of oscillators in column of the network, this argument is used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored. @param[in] width (uint): Number of oscillotors in row of the network, this argument is used only for network with grid structure (GRID_FOUR, GRID_EIGHT), for other types this argument is ignored. @param[in] ccore (bool): If True then all interaction with object will be performed via CCORE library (C++ implementation of pyclustering). """ self._outputs = None # list of outputs of oscillators. self._feeding = None # feeding compartment of each oscillator. self._linking = None # linking compartment of each oscillator. self._threshold = None # threshold of each oscillator. self._params = None self.__ccore_pcnn_pointer = None # set parameters of the network if parameters is not None: self._params = parameters else: self._params = pcnn_parameters() if (ccore is True) and ccore_library.workable(): network_height = height network_width = width if (type_conn == conn_type.GRID_FOUR) or (type_conn == conn_type.GRID_EIGHT): if (network_height is None) or (network_width is None): side_size = num_osc ** (0.5) if side_size - math.floor(side_size) > 0: raise NameError('Invalid number of oscillators in the network in case of grid structure') network_height = int(side_size) network_width = int(side_size) else: network_height = 0 network_width = 0 self.__ccore_pcnn_pointer = wrapper.pcnn_create(num_osc, type_conn, network_height, network_width, self._params) else: super().__init__(num_osc, type_conn, type_conn_represent, height, width) self._outputs = [0.0] * self._num_osc self._feeding = [0.0] * self._num_osc self._linking = [0.0] * self._num_osc self._threshold = [ random.random() for i in range(self._num_osc) ] def __del__(self): """! @brief Default destructor of PCNN. """ if self.__ccore_pcnn_pointer is not None: wrapper.pcnn_destroy(self.__ccore_pcnn_pointer) self.__ccore_pcnn_pointer = None def __len__(self): """! @brief (uint) Returns size of oscillatory network. """ if self.__ccore_pcnn_pointer is not None: return wrapper.pcnn_get_size(self.__ccore_pcnn_pointer) return self._num_osc def simulate(self, steps, stimulus): """! @brief Performs static simulation of pulse coupled neural network using. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators. @return (pcnn_dynamic) Dynamic of oscillatory network - output of each oscillator on each step of simulation. """ if len(stimulus) != len(self): raise NameError('Number of stimulus should be equal to number of oscillators. Each stimulus corresponds to only one oscillators.') if self.__ccore_pcnn_pointer is not None: ccore_instance_dynamic = wrapper.pcnn_simulate(self.__ccore_pcnn_pointer, steps, stimulus) return pcnn_dynamic(None, ccore_instance_dynamic) dynamic = [] dynamic.append(self._outputs) for step in range(1, steps, 1): self._outputs = self._calculate_states(stimulus) dynamic.append(self._outputs) return pcnn_dynamic(dynamic) def _calculate_states(self, stimulus): """! @brief Calculates states of oscillators in the network for current step and stored them except outputs of oscillators. @param[in] stimulus (list): Stimulus for oscillators, number of stimulus should be equal to number of oscillators. @return (list) New outputs for oscillators (do not stored it). """ feeding = [0.0] * self._num_osc linking = [0.0] * self._num_osc outputs = [0.0] * self._num_osc threshold = [0.0] * self._num_osc for index in range(0, self._num_osc, 1): neighbors = self.get_neighbors(index) feeding_influence = 0.0 linking_influence = 0.0 for index_neighbour in neighbors: feeding_influence += self._outputs[index_neighbour] * self._params.M linking_influence += self._outputs[index_neighbour] * self._params.W feeding_influence *= self._params.VF linking_influence *= self._params.VL feeding[index] = self._params.AF * self._feeding[index] + stimulus[index] + feeding_influence linking[index] = self._params.AL * self._linking[index] + linking_influence # calculate internal activity internal_activity = feeding[index] * (1.0 + self._params.B * linking[index]) # calculate output of the oscillator if internal_activity > self._threshold[index]: outputs[index] = self.__OUTPUT_TRUE else: outputs[index] = self.__OUTPUT_FALSE # In case of Fast Linking we should calculate threshold until output is changed. if self._params.FAST_LINKING is not True: threshold[index] = self._params.AT * self._threshold[index] + self._params.VT * outputs[index] # In case of Fast Linking we need to wait until output is changed. if self._params.FAST_LINKING is True: output_change = True # Set it True for the for the first iteration. previous_outputs = outputs[:] while output_change is True: current_output_change = False for index in range(0, self._num_osc, 1): linking_influence = 0.0 neighbors = self.get_neighbors(index) for index_neighbour in neighbors: linking_influence += previous_outputs[index_neighbour] * self._params.W linking_influence *= self._params.VL linking[index] = linking_influence internal_activity = feeding[index] * (1.0 + self._params.B * linking[index]) # calculate output of the oscillator if internal_activity > self._threshold[index]: outputs[index] = self.__OUTPUT_TRUE else: outputs[index] = self.__OUTPUT_FALSE current_output_change |= (outputs[index] != previous_outputs[index]) output_change = current_output_change if output_change is True: previous_outputs = outputs[:] # In case of Fast Linking threshold should be calculated after fast linking. if self._params.FAST_LINKING is True: for index in range(0, self._num_osc, 1): threshold[index] = self._params.AT * self._threshold[index] + self._params.VT * outputs[index] self._feeding = feeding[:] self._linking = linking[:] self._threshold = threshold[:] return outputs pyclustering-0.10.1.2/pyclustering/nnet/som.py000077500000000000000000001145541375753423500213600ustar00rootroot00000000000000"""! @brief Neural Network: Self-Organized Feature Map @details Implementation based on paper @cite article::nnet::som::1, @cite article::nnet::som::2. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import random import matplotlib.pyplot as plt import pyclustering.core.som_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from pyclustering.utils import euclidean_distance_square from pyclustering.utils.dimension import dimension_info from enum import IntEnum class type_conn(IntEnum): """! @brief Enumeration of connection types for SOM. @see som """ ## Grid type of connections when each oscillator has connections with left, upper, right, lower neighbors. grid_four = 0 ## Grid type of connections when each oscillator has connections with left, upper-left, upper, upper-right, right, right-lower, lower, lower-left neighbors. grid_eight = 1 ## Grid type of connections when each oscillator has connections with left, upper-left, upper-right, right, right-lower, lower-left neighbors. honeycomb = 2 ## Grid type of connections when existance of each connection is defined by the SOM rule on each step of simulation. func_neighbor = 3 class type_init(IntEnum): """! @brief Enumeration of initialization types for SOM. @see som """ ## Weights are randomly distributed using Gaussian distribution (0, 1). random = 0 ## Weights are randomly distributed using Gaussian distribution (input data centroid, 1). random_centroid = 1 ## Weights are randomly distrbiuted using Gaussian distribution (input data centroid, surface of input data). random_surface = 2 ## Weights are distributed as a uniform grid that covers whole surface of the input data. uniform_grid = 3 class som_parameters: """! @brief Represents SOM parameters. """ def __init__(self): """! @brief Creates SOM parameters. """ ## Defines an initialization way for neuron weights (random, random in center of the input data, random distributed in data, ditributed in line with uniform grid). self.init_type = type_init.uniform_grid ## Initial radius. If the initial radius is not specified (equals to `None`) then it will be calculated by SOM. self.init_radius = None ## Rate of learning. self.init_learn_rate = 0.1 ## Condition that defines when the learining process should be stopped. It is used when the autostop mode is on. self.adaptation_threshold = 0.001 ## Seed for random state (by default is `None`, current system time is used). self.random_state = None class som: """! @brief Represents self-organized feature map (SOM). @details The self-organizing feature map (SOM) method is a powerful tool for the visualization of of high-dimensional data. It converts complex, nonlinear statistical relationships between high-dimensional data into simple geometric relationships on a low-dimensional display. @details `ccore` option can be specified in order to control using C++ implementation of pyclustering library. By default C++ implementation is on. C++ implementation improves performance of the self-organized feature map. Example: @code import random from pyclustering.utils import read_sample from pyclustering.nnet.som import som, type_conn, type_init, som_parameters from pyclustering.samples.definitions import FCPS_SAMPLES # read sample 'Lsun' from file sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN) # create SOM parameters parameters = som_parameters() # create self-organized feature map with size 7x7 rows = 10 # five rows cols = 10 # five columns structure = type_conn.grid_four; # each neuron has max. four neighbors. network = som(rows, cols, structure, parameters) # train network on 'Lsun' sample during 100 epouchs. network.train(sample, 100) # simulate trained network using randomly modified point from input dataset. index_point = random.randint(0, len(sample) - 1) point = sample[index_point] # obtain randomly point from data point[0] += random.random() * 0.2 # change randomly X-coordinate point[1] += random.random() * 0.2 # change randomly Y-coordinate index_winner = network.simulate(point) # check what are objects from input data are much close to randomly modified. index_similar_objects = network.capture_objects[index_winner] # neuron contains information of encoded objects print("Point '%s' is similar to objects with indexes '%s'." % (str(point), str(index_similar_objects))) print("Coordinates of similar objects:") for index in index_similar_objects: print("\tPoint:", sample[index]) # result visualization: # show distance matrix (U-matrix). network.show_distance_matrix() # show density matrix (P-matrix). network.show_density_matrix() # show winner matrix. network.show_winner_matrix() # show self-organized map. network.show_network() @endcode There is a visualization of 'Target' sample that was done by the self-organized feature map: @image html target_som_processing.png """ @property def size(self): """! @brief Return size of self-organized map that is defined by total number of neurons. @return (uint) Size of self-organized map (number of neurons). """ if self.__ccore_som_pointer is not None: self._size = wrapper.som_get_size(self.__ccore_som_pointer) return self._size @property def weights(self): """! @brief Return weight of each neuron. @return (list) Weights of each neuron. """ if self.__ccore_som_pointer is not None: self._weights = wrapper.som_get_weights(self.__ccore_som_pointer) return self._weights @property def awards(self): """! @brief Return amount of captured objects by each neuron after training. @return (list) Amount of captured objects by each neuron. @see train() """ if self.__ccore_som_pointer is not None: self._award = wrapper.som_get_awards(self.__ccore_som_pointer) return self._award @property def capture_objects(self): """! @brief Returns indexes of captured objects by each neuron. @details For example, a network with size 2x2 has been trained on a sample with five objects. Suppose neuron #1 won an object with index `1`, neuron #2 won objects `0`, `3`, `4`, neuron #3 did not won anything and finally neuron #4 won an object with index `2`. Thus, for this example we will have the following output `[[1], [0, 3, 4], [], [2]]`. @return (list) Indexes of captured objects by each neuron. """ if self.__ccore_som_pointer is not None: self._capture_objects = wrapper.som_get_capture_objects(self.__ccore_som_pointer) return self._capture_objects def __init__(self, rows, cols, conn_type=type_conn.grid_eight, parameters=None, ccore=True): """! @brief Constructor of self-organized map. @param[in] rows (uint): Number of neurons in the column (number of rows). @param[in] cols (uint): Number of neurons in the row (number of columns). @param[in] conn_type (type_conn): Type of connection between oscillators in the network (grid four, grid eight, honeycomb, function neighbour). @param[in] parameters (som_parameters): Other specific parameters. @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering). """ # some of these parameters are required despite core implementation, for example, for network visualization. self._cols = cols self._rows = rows self._size = cols * rows self._conn_type = conn_type self._data = None self._neighbors = None self._local_radius = 0.0 self._learn_rate = 0.0 self.__ccore_som_pointer = None self._params = parameters or som_parameters() if self._params.init_radius is None: self._params.init_radius = self.__initialize_initial_radius(rows, cols) if (ccore is True) and ccore_library.workable(): self.__ccore_som_pointer = wrapper.som_create(rows, cols, conn_type, self._params) else: # location self._location = self.__initialize_locations(rows, cols) # default weights self._weights = [[0.0]] * self._size # awards self._award = [0] * self._size # captured objects self._capture_objects = [[] for i in range(self._size)] # distances - calculate and store them only during training self._sqrt_distances = None # connections if conn_type != type_conn.func_neighbor: self._create_connections(conn_type) def __del__(self): """! @brief Destructor of the self-organized feature map. """ if self.__ccore_som_pointer is not None: wrapper.som_destroy(self.__ccore_som_pointer) def __len__(self): """! @brief Returns size of the network that defines by amount of neuron in it. @return (uint) Size of self-organized map (amount of neurons). """ return self._size def __getstate__(self): """ @brief Returns state of SOM network that can be used to store network. """ if self.__ccore_som_pointer is not None: self.__download_dump_from_ccore() return self.__get_dump_from_python(True) return self.__get_dump_from_python(False) def __setstate__(self, som_state): """ @brief Set state of SOM network that can be used to load network. """ if som_state['ccore'] is True and ccore_library.workable(): self.__upload_dump_to_ccore(som_state['state']) else: self.__upload_dump_to_python(som_state['state']) def __initialize_initial_radius(self, rows, cols): """! @brief Initialize initial radius using map sizes. @param[in] rows (uint): Number of neurons in the column (number of rows). @param[in] cols (uint): Number of neurons in the row (number of columns). @return (list) Value of initial radius. """ if (cols + rows) / 4.0 > 1.0: return 2.0 elif (cols > 1) and (rows > 1): return 1.5 else: return 1.0 def __initialize_locations(self, rows, cols): """! @brief Initialize locations (coordinates in SOM grid) of each neurons in the map. @param[in] rows (uint): Number of neurons in the column (number of rows). @param[in] cols (uint): Number of neurons in the row (number of columns). @return (list) List of coordinates of each neuron in map. """ location = list() for i in range(rows): for j in range(cols): location.append([float(i), float(j)]) return location def __initialize_distances(self, size, location): """! @brief Initialize distance matrix in SOM grid. @param[in] size (uint): Amount of neurons in the network. @param[in] location (list): List of coordinates of each neuron in the network. @return (list) Distance matrix between neurons in the network. """ sqrt_distances = [[[] for i in range(size)] for j in range(size)] for i in range(size): for j in range(i, size, 1): dist = euclidean_distance_square(location[i], location[j]) sqrt_distances[i][j] = dist sqrt_distances[j][i] = dist return sqrt_distances def _create_initial_weights(self, init_type): """! @brief Creates initial weights for neurons in line with the specified initialization. @param[in] init_type (type_init): Type of initialization of initial neuron weights (random, random in center of the input data, random distributed in data, ditributed in line with uniform grid). """ dim_info = dimension_info(self._data) step_x = dim_info.get_center()[0] if self._rows > 1: step_x = dim_info.get_width()[0] / (self._rows - 1) step_y = 0.0 if dim_info.get_dimensions() > 1: step_y = dim_info.get_center()[1] if self._cols > 1: step_y = dim_info.get_width()[1] / (self._cols - 1) # generate weights (topological coordinates) random.seed(self._params.random_state) # Uniform grid. if init_type == type_init.uniform_grid: # Predefined weights in line with input data. self._weights = [[[] for i in range(dim_info.get_dimensions())] for j in range(self._size)] for i in range(self._size): location = self._location[i] for dim in range(dim_info.get_dimensions()): if dim == 0: if self._rows > 1: self._weights[i][dim] = dim_info.get_minimum_coordinate()[dim] + step_x * location[dim] else: self._weights[i][dim] = dim_info.get_center()[dim] elif dim == 1: if self._cols > 1: self._weights[i][dim] = dim_info.get_minimum_coordinate()[dim] + step_y * location[dim] else: self._weights[i][dim] = dim_info.get_center()[dim] else: self._weights[i][dim] = dim_info.get_center()[dim] elif init_type == type_init.random_surface: # Random weights at the full surface. self._weights = [ [random.uniform(dim_info.get_minimum_coordinate()[i], dim_info.get_maximum_coordinate()[i]) for i in range(dim_info.get_dimensions())] for _ in range(self._size)] elif init_type == type_init.random_centroid: # Random weights at the center of input data. self._weights = [[(random.random() + dim_info.get_center()[i]) for i in range(dim_info.get_dimensions())] for _ in range(self._size)] else: # Random weights of input data. self._weights = [[random.random() for i in range(dim_info.get_dimensions())] for _ in range(self._size)] def _create_connections(self, conn_type): """! @brief Create connections in line with input rule (grid four, grid eight, honeycomb, function neighbour). @param[in] conn_type (type_conn): Type of connection between oscillators in the network. """ self._neighbors = [[] for index in range(self._size)] for index in range(0, self._size, 1): upper_index = index - self._cols upper_left_index = index - self._cols - 1 upper_right_index = index - self._cols + 1 lower_index = index + self._cols lower_left_index = index + self._cols - 1 lower_right_index = index + self._cols + 1 left_index = index - 1 right_index = index + 1 node_row_index = math.floor(index / self._cols) upper_row_index = node_row_index - 1 lower_row_index = node_row_index + 1 if (conn_type == type_conn.grid_eight) or (conn_type == type_conn.grid_four): if upper_index >= 0: self._neighbors[index].append(upper_index) if lower_index < self._size: self._neighbors[index].append(lower_index) if (conn_type == type_conn.grid_eight) or (conn_type == type_conn.grid_four) or ( conn_type == type_conn.honeycomb): if (left_index >= 0) and (math.floor(left_index / self._cols) == node_row_index): self._neighbors[index].append(left_index) if (right_index < self._size) and (math.floor(right_index / self._cols) == node_row_index): self._neighbors[index].append(right_index) if conn_type == type_conn.grid_eight: if (upper_left_index >= 0) and (math.floor(upper_left_index / self._cols) == upper_row_index): self._neighbors[index].append(upper_left_index) if (upper_right_index >= 0) and (math.floor(upper_right_index / self._cols) == upper_row_index): self._neighbors[index].append(upper_right_index) if (lower_left_index < self._size) and (math.floor(lower_left_index / self._cols) == lower_row_index): self._neighbors[index].append(lower_left_index) if (lower_right_index < self._size) and (math.floor(lower_right_index / self._cols) == lower_row_index): self._neighbors[index].append(lower_right_index) if conn_type == type_conn.honeycomb: if (node_row_index % 2) == 0: upper_left_index = index - self._cols upper_right_index = index - self._cols + 1 lower_left_index = index + self._cols lower_right_index = index + self._cols + 1 else: upper_left_index = index - self._cols - 1 upper_right_index = index - self._cols lower_left_index = index + self._cols - 1 lower_right_index = index + self._cols if (upper_left_index >= 0) and (math.floor(upper_left_index / self._cols) == upper_row_index): self._neighbors[index].append(upper_left_index) if (upper_right_index >= 0) and (math.floor(upper_right_index / self._cols) == upper_row_index): self._neighbors[index].append(upper_right_index) if (lower_left_index < self._size) and (math.floor(lower_left_index / self._cols) == lower_row_index): self._neighbors[index].append(lower_left_index) if (lower_right_index < self._size) and (math.floor(lower_right_index / self._cols) == lower_row_index): self._neighbors[index].append(lower_right_index) def _competition(self, x): """! @brief Calculates neuron winner (distance, neuron index). @param[in] x (list): Input pattern from the input data set, for example it can be coordinates of point. @return (uint) Returns index of neuron that is winner. """ index = 0 minimum = euclidean_distance_square(self._weights[0], x) for i in range(1, self._size, 1): candidate = euclidean_distance_square(self._weights[i], x) if candidate < minimum: index = i minimum = candidate return index def _adaptation(self, index, x): """! @brief Change weight of neurons in line with won neuron. @param[in] index (uint): Index of neuron-winner. @param[in] x (list): Input pattern from the input data set. """ dimension = len(self._weights[0]) if self._conn_type == type_conn.func_neighbor: for neuron_index in range(self._size): distance = self._sqrt_distances[index][neuron_index] if distance < self._local_radius: influence = math.exp(-(distance / (2.0 * self._local_radius))) for i in range(dimension): self._weights[neuron_index][i] = self._weights[neuron_index][ i] + self._learn_rate * influence * ( x[i] - self._weights[neuron_index][i]) else: for i in range(dimension): self._weights[index][i] = self._weights[index][i] + self._learn_rate * (x[i] - self._weights[index][i]) for neighbor_index in self._neighbors[index]: distance = self._sqrt_distances[index][neighbor_index] if distance < self._local_radius: influence = math.exp(-(distance / (2.0 * self._local_radius))) for i in range(dimension): self._weights[neighbor_index][i] = self._weights[neighbor_index][ i] + self._learn_rate * influence * ( x[i] - self._weights[neighbor_index][i]) def train(self, data, epochs, autostop=False): """! @brief Trains self-organized feature map (SOM). @param[in] data (list): Input data - list of points where each point is represented by list of features, for example coordinates. @param[in] epochs (uint): Number of epochs for training. @param[in] autostop (bool): Automatic termination of learning process when adaptation is not occurred. @return (uint) Number of learning iterations. """ self._data = data if self.__ccore_som_pointer is not None: return wrapper.som_train(self.__ccore_som_pointer, data, epochs, autostop) self._sqrt_distances = self.__initialize_distances(self._size, self._location) for i in range(self._size): self._award[i] = 0 self._capture_objects[i].clear() # weights self._create_initial_weights(self._params.init_type) previous_weights = None for epoch in range(1, epochs + 1): # Depression term of coupling self._local_radius = (self._params.init_radius * math.exp(-(epoch / epochs))) ** 2 self._learn_rate = self._params.init_learn_rate * math.exp(-(epoch / epochs)) # Clear statistics if autostop: for i in range(self._size): self._award[i] = 0 self._capture_objects[i].clear() for i in range(len(self._data)): # Step 1: Competition: index = self._competition(self._data[i]) # Step 2: Adaptation: self._adaptation(index, self._data[i]) # Update statistics if (autostop is True) or (epoch == epochs): self._award[index] += 1 self._capture_objects[index].append(i) # Check requirement of stopping if autostop: if previous_weights is not None: maximal_adaptation = self._get_maximal_adaptation(previous_weights) if maximal_adaptation < self._params.adaptation_threshold: return epoch previous_weights = [item[:] for item in self._weights] return epochs def simulate(self, input_pattern): """! @brief Processes input pattern (no learining) and returns index of neuron-winner. Using index of neuron winner catched object can be obtained using property capture_objects. @param[in] input_pattern (list): Input pattern. @return (uint) Returns index of neuron-winner. @see capture_objects """ if self.__ccore_som_pointer is not None: return wrapper.som_simulate(self.__ccore_som_pointer, input_pattern) return self._competition(input_pattern) def _get_maximal_adaptation(self, previous_weights): """! @brief Calculates maximum changes of weight in line with comparison between previous weights and current weights. @param[in] previous_weights (list): Weights from the previous step of learning process. @return (double) Value that represents maximum changes of weight after adaptation process. """ dimension = len(self._data[0]) maximal_adaptation = 0.0 for neuron_index in range(self._size): for dim in range(dimension): current_adaptation = previous_weights[neuron_index][dim] - self._weights[neuron_index][dim] if current_adaptation < 0: current_adaptation = -current_adaptation if maximal_adaptation < current_adaptation: maximal_adaptation = current_adaptation return maximal_adaptation def get_winner_number(self): """! @brief Calculates number of winner at the last step of learning process. @return (uint) Number of winner. """ if self.__ccore_som_pointer is not None: self._award = wrapper.som_get_awards(self.__ccore_som_pointer) winner_number = 0 for i in range(self._size): if self._award[i] > 0: winner_number += 1 return winner_number def show_distance_matrix(self): """! @brief Shows gray visualization of U-matrix (distance matrix). @see get_distance_matrix() """ distance_matrix = self.get_distance_matrix() plt.imshow(distance_matrix, cmap=plt.get_cmap('hot'), interpolation='kaiser') plt.title("U-Matrix") plt.colorbar() plt.show() def get_distance_matrix(self): """! @brief Calculates distance matrix (U-matrix). @details The U-Matrix visualizes based on the distance in input space between a weight vector and its neighbors on map. @return (list) Distance matrix (U-matrix). @see show_distance_matrix() @see get_density_matrix() """ if self.__ccore_som_pointer is not None: self._weights = wrapper.som_get_weights(self.__ccore_som_pointer) if self._conn_type != type_conn.func_neighbor: self._neighbors = wrapper.som_get_neighbors(self.__ccore_som_pointer) distance_matrix = [[0.0] * self._cols for i in range(self._rows)] for i in range(self._rows): for j in range(self._cols): neuron_index = i * self._cols + j if self._conn_type == type_conn.func_neighbor: self._create_connections(type_conn.grid_eight) for neighbor_index in self._neighbors[neuron_index]: distance_matrix[i][j] += euclidean_distance_square(self._weights[neuron_index], self._weights[neighbor_index]) distance_matrix[i][j] /= len(self._neighbors[neuron_index]) return distance_matrix def show_density_matrix(self, surface_divider=20.0): """! @brief Show density matrix (P-matrix) using kernel density estimation. @param[in] surface_divider (double): Divider in each dimension that affect radius for density measurement. @see show_distance_matrix() """ density_matrix = self.get_density_matrix(surface_divider) plt.imshow(density_matrix, cmap=plt.get_cmap('hot'), interpolation='kaiser') plt.title("P-Matrix") plt.colorbar() plt.show() def get_density_matrix(self, surface_divider=20.0): """! @brief Calculates density matrix (P-Matrix). @param[in] surface_divider (double): Divider in each dimension that affect radius for density measurement. @return (list) Density matrix (P-Matrix). @see get_distance_matrix() """ if self.__ccore_som_pointer is not None: self._weights = wrapper.som_get_weights(self.__ccore_som_pointer) density_matrix = [[0] * self._cols for i in range(self._rows)] dimension = len(self._weights[0]) dim_max = [float('-Inf')] * dimension dim_min = [float('Inf')] * dimension for weight in self._weights: for index_dim in range(dimension): if weight[index_dim] > dim_max[index_dim]: dim_max[index_dim] = weight[index_dim] if weight[index_dim] < dim_min[index_dim]: dim_min[index_dim] = weight[index_dim] radius = [0.0] * len(self._weights[0]) for index_dim in range(dimension): radius[index_dim] = (dim_max[index_dim] - dim_min[index_dim]) / surface_divider ## TODO: do not use data for point in self._data: for index_neuron in range(len(self)): point_covered = True for index_dim in range(dimension): if abs(point[index_dim] - self._weights[index_neuron][index_dim]) > radius[index_dim]: point_covered = False break row = int(math.floor(index_neuron / self._cols)) col = index_neuron - row * self._cols if point_covered is True: density_matrix[row][col] += 1 return density_matrix def show_winner_matrix(self): """! @brief Show a winner matrix where each element corresponds to neuron and value represents amount of won objects from input data-space at the last training iteration. @see show_distance_matrix() """ if self.__ccore_som_pointer is not None: self._award = wrapper.som_get_awards(self.__ccore_som_pointer) (fig, ax) = plt.subplots() winner_matrix = [[0] * self._cols for _ in range(self._rows)] for i in range(self._rows): for j in range(self._cols): neuron_index = i * self._cols + j winner_matrix[i][j] = self._award[neuron_index] ax.text(i, j, str(winner_matrix[i][j]), va='center', ha='center') ax.imshow(winner_matrix, cmap=plt.get_cmap('cool'), interpolation='none') ax.grid(True) plt.title("Winner Matrix") plt.show() def show_network(self, awards=False, belongs=False, coupling=True, dataset=True, marker_type='o'): """! @brief Shows neurons in the dimension of data. @param[in] awards (bool): If True - displays how many objects won each neuron. @param[in] belongs (bool): If True - marks each won object by according index of neuron-winner (only when dataset is displayed too). @param[in] coupling (bool): If True - displays connections between neurons (except case when function neighbor is used). @param[in] dataset (bool): If True - displays inputs data set. @param[in] marker_type (string): Defines marker that is used to denote neurons on the plot. """ if self.__ccore_som_pointer is not None: self._size = wrapper.som_get_size(self.__ccore_som_pointer) self._weights = wrapper.som_get_weights(self.__ccore_som_pointer) self._neighbors = wrapper.som_get_neighbors(self.__ccore_som_pointer) self._award = wrapper.som_get_awards(self.__ccore_som_pointer) dimension = len(self._weights[0]) fig = plt.figure() # Check for dimensions if (dimension == 1) or (dimension == 2): axes = fig.add_subplot(111) elif dimension == 3: axes = fig.gca(projection='3d') else: raise NotImplementedError('Impossible to show network in data-space that is differ from 1D, 2D or 3D.') if (self._data is not None) and (dataset is True): for x in self._data: if dimension == 1: axes.plot(x[0], 0.0, 'b|', ms=30) elif dimension == 2: axes.plot(x[0], x[1], 'b.') elif dimension == 3: axes.scatter(x[0], x[1], x[2], c='b', marker='.') # Show neurons for index in range(self._size): color = 'g' if self._award[index] == 0: color = 'y' if dimension == 1: axes.plot(self._weights[index][0], 0.0, color + marker_type) if awards: location = '{0}'.format(self._award[index]) axes.text(self._weights[index][0], 0.0, location, color='black', fontsize=10) if belongs and self._data is not None: location = '{0}'.format(index) axes.text(self._weights[index][0], 0.0, location, color='black', fontsize=12) for k in range(len(self._capture_objects[index])): point = self._data[self._capture_objects[index][k]] axes.text(point[0], 0.0, location, color='blue', fontsize=10) if dimension == 2: axes.plot(self._weights[index][0], self._weights[index][1], color + marker_type) if awards: location = '{0}'.format(self._award[index]) axes.text(self._weights[index][0], self._weights[index][1], location, color='black', fontsize=10) if belongs and self._data is not None: location = '{0}'.format(index) axes.text(self._weights[index][0], self._weights[index][1], location, color='black', fontsize=12) for k in range(len(self._capture_objects[index])): point = self._data[self._capture_objects[index][k]] axes.text(point[0], point[1], location, color='blue', fontsize=10) if (self._conn_type != type_conn.func_neighbor) and (coupling is True): for neighbor in self._neighbors[index]: if neighbor > index: axes.plot([self._weights[index][0], self._weights[neighbor][0]], [self._weights[index][1], self._weights[neighbor][1]], 'g', linewidth=0.5) elif dimension == 3: axes.scatter(self._weights[index][0], self._weights[index][1], self._weights[index][2], c=color, marker=marker_type) if (self._conn_type != type_conn.func_neighbor) and (coupling != False): for neighbor in self._neighbors[index]: if neighbor > index: axes.plot([self._weights[index][0], self._weights[neighbor][0]], [self._weights[index][1], self._weights[neighbor][1]], [self._weights[index][2], self._weights[neighbor][2]], 'g-', linewidth=0.5) plt.title("Network Structure") plt.grid() plt.show() def __get_dump_from_python(self, ccore_usage): return {'ccore': ccore_usage, 'state': {'cols': self._cols, 'rows': self._rows, 'size': self._size, 'conn_type': self._conn_type, 'neighbors': self._neighbors, 'local_radius': self._local_radius, 'learn_rate': self._learn_rate, 'params': self._params, 'location': self._location, 'weights': self._weights, 'award': self._award, 'capture_objects': self._capture_objects}} def __download_dump_from_ccore(self): self._location = self.__initialize_locations(self._rows, self._cols) self._weights = wrapper.som_get_weights(self.__ccore_som_pointer) self._award = wrapper.som_get_awards(self.__ccore_som_pointer) self._capture_objects = wrapper.som_get_capture_objects(self.__ccore_som_pointer) def __upload_common_part(self, state_dump): self._cols = state_dump['cols'] self._rows = state_dump['rows'] self._size = state_dump['size'] self._conn_type = state_dump['conn_type'] self._neighbors = state_dump['neighbors'] self._local_radius = state_dump['local_radius'] self._learn_rate = state_dump['learn_rate'] self._params = state_dump['params'] self._neighbors = None def __upload_dump_to_python(self, state_dump): self.__ccore_som_pointer = None self.__upload_common_part(state_dump) self._location = state_dump['location'] self._weights = state_dump['weights'] self._award = state_dump['award'] self._capture_objects = state_dump['capture_objects'] self._location = self.__initialize_locations(self._rows, self._cols) self._create_connections(self._conn_type) def __upload_dump_to_ccore(self, state_dump): self.__upload_common_part(state_dump) self.__ccore_som_pointer = wrapper.som_create(self._rows, self._cols, self._conn_type, self._params) wrapper.som_load(self.__ccore_som_pointer, state_dump['weights'], state_dump['award'], state_dump['capture_objects']) pyclustering-0.10.1.2/pyclustering/nnet/sync.py000077500000000000000000001304031375753423500215250ustar00rootroot00000000000000"""! @brief Neural Network: Oscillatory Neural Network based on Kuramoto model @details Implementation based on paper @cite article::syncnet::1, @cite article::nnet::sync::1, @cite inproceedings::net::sync::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import numpy import random import matplotlib.pyplot as plt import matplotlib.animation as animation import pyclustering.core.sync_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from scipy.integrate import odeint from pyclustering.nnet import network, conn_represent, conn_type, initial_type, solve_type from pyclustering.utils import pi, draw_dynamics, draw_dynamics_set, set_ax_param class order_estimator: """! @brief Provides services to calculate order parameter and local order parameter that are used for synchronization level estimation. """ @staticmethod def calculate_sync_order(oscillator_phases): """! @brief Calculates level of global synchronization (order parameter) for input phases. @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it tend to 0.0 when desynchronization is observed in the network. @param[in] oscillator_phases (list): List of oscillator phases that are used for level of global synchronization. @return (double) Level of global synchronization (order parameter). @see calculate_order_parameter() """ exp_amount = 0.0 average_phase = 0.0 for phase in oscillator_phases: exp_amount += math.expm1(abs(1j * phase)) average_phase += phase exp_amount /= len(oscillator_phases) average_phase = math.expm1(abs(1j * (average_phase / len(oscillator_phases)))) return abs(average_phase) / abs(exp_amount) @staticmethod def calculate_local_sync_order(oscillator_phases, oscillatory_network): """! @brief Calculates level of local synchorization (local order parameter) for input phases for the specified network. @details This parameter is tend 1.0 when the oscillatory network close to local synchronization and it tend to 0.0 when desynchronization is observed in the network. @param[in] oscillator_phases (list): List of oscillator phases that are used for level of local (partial) synchronization. @param[in] oscillatory_network (sync): Instance of oscillatory network whose connections are required for calculation. @return (double) Level of local synchronization (local order parameter). """ exp_amount = 0.0 num_neigh = 0.0 for i in range(0, len(oscillatory_network), 1): for j in range(0, len(oscillatory_network), 1): if oscillatory_network.has_connection(i, j) is True: exp_amount += math.exp(-abs(oscillator_phases[j] - oscillator_phases[i])) num_neigh += 1.0 if num_neigh == 0: num_neigh = 1.0 return exp_amount / num_neigh class sync_dynamic: """! @brief Represents output dynamic of Sync. """ @property def output(self): """! @brief (list) Returns output dynamic of the Sync network (phase coordinates of each oscillator in the network) during simulation. """ if (self._ccore_sync_dynamic_pointer is not None) and ((self._dynamic is None) or (len(self._dynamic) == 0)): self._dynamic = wrapper.sync_dynamic_get_output(self._ccore_sync_dynamic_pointer) return self._dynamic @property def time(self): """! @brief (list) Returns sampling times when dynamic is measured during simulation. """ if (self._ccore_sync_dynamic_pointer is not None) and ((self._time is None) or (len(self._time) == 0)): self._time = wrapper.sync_dynamic_get_time(self._ccore_sync_dynamic_pointer) return self._time def __init__(self, phase, time, ccore=None): """! @brief Constructor of Sync dynamic. @param[in] phase (list): Dynamic of oscillators on each step of simulation. If ccore pointer is specified than it can be ignored. @param[in] time (list): Simulation time. @param[in] ccore (ctypes.pointer): Pointer to CCORE sync_dynamic instance in memory. """ self._dynamic = phase self._time = time self._ccore_sync_dynamic_pointer = ccore def __del__(self): """! @brief Default destructor of Sync dynamic. """ if self._ccore_sync_dynamic_pointer is not None: wrapper.sync_dynamic_destroy(self._ccore_sync_dynamic_pointer) def __len__(self): """! @brief Returns number of simulation steps that are stored in dynamic. @return (uint) Number of simulation steps that are stored in dynamic. """ if (self._ccore_sync_dynamic_pointer is not None): return wrapper.sync_dynamic_get_size(self._ccore_sync_dynamic_pointer) return len(self._dynamic) def __getitem__(self, index): """! @brief Indexing of the dynamic. """ if index == 0: return self.time elif index == 1: return self.output else: raise NameError('Out of range ' + index + ': only indexes 0 and 1 are supported.') def allocate_sync_ensembles(self, tolerance = 0.01, indexes = None, iteration = None): """! @brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators. @param[in] indexes (list): List of real object indexes and it should be equal to amount of oscillators (in case of 'None' - indexes are in range [0; amount_oscillators]). @param[in] iteration (uint): Iteration of simulation that should be used for allocation. @return (list) Groups (lists) of indexes of synchronous oscillators. For example [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ if self._ccore_sync_dynamic_pointer is not None: ensembles = wrapper.sync_dynamic_allocate_sync_ensembles(self._ccore_sync_dynamic_pointer, tolerance, iteration) if indexes is not None: for ensemble in ensembles: for index in range(len(ensemble)): ensemble[index] = indexes[ensemble[index]] return ensembles if (self._dynamic is None) or (len(self._dynamic) == 0): return [] number_oscillators = len(self._dynamic[0]) last_state = None if iteration is None: last_state = self._dynamic[len(self._dynamic) - 1] else: last_state = self._dynamic[iteration] clusters = [] if number_oscillators > 0: clusters.append([0]) for i in range(1, number_oscillators, 1): cluster_allocated = False for cluster in clusters: for neuron_index in cluster: last_state_shifted = abs(last_state[i] - 2 * pi) if ( ( (last_state[i] < (last_state[neuron_index] + tolerance)) and (last_state[i] > (last_state[neuron_index] - tolerance)) ) or ( (last_state_shifted < (last_state[neuron_index] + tolerance)) and (last_state_shifted > (last_state[neuron_index] - tolerance)) ) ): cluster_allocated = True real_index = i if indexes is not None: real_index = indexes[i] cluster.append(real_index) break if cluster_allocated is True: break if cluster_allocated is False: clusters.append([i]) return clusters def allocate_phase_matrix(self, grid_width = None, grid_height = None, iteration = None): """! @brief Returns 2D matrix of phase values of oscillators at the specified iteration of simulation. @details User should ensure correct matrix sizes in line with following expression grid_width x grid_height that should be equal to amount of oscillators otherwise exception is thrown. If grid_width or grid_height are not specified than phase matrix size will by calculated automatically by square root. @param[in] grid_width (uint): Width of the allocated matrix. @param[in] grid_height (uint): Height of the allocated matrix. @param[in] iteration (uint): Number of iteration of simulation for which correlation matrix should be allocated. If iternation number is not specified, the last step of simulation is used for the matrix allocation. @return (list) Phase value matrix of oscillators with size [number_oscillators x number_oscillators]. """ output_dynamic = self.output if (output_dynamic is None) or (len(output_dynamic) == 0): return [] current_dynamic = output_dynamic[len(output_dynamic) - 1] if iteration is not None: current_dynamic = output_dynamic[iteration] width_matrix = grid_width height_matrix = grid_height number_oscillators = len(current_dynamic) if (width_matrix is None) or (height_matrix is None): width_matrix = int(math.ceil(math.sqrt(number_oscillators))) height_matrix = width_matrix if (number_oscillators != width_matrix * height_matrix): raise NameError("Impossible to allocate phase matrix with specified sizes, amout of neurons should be equal to grid_width * grid_height."); phase_matrix = [[0.0 for _ in range(width_matrix)] for _ in range(height_matrix)] for i in range(height_matrix): for j in range(width_matrix): phase_matrix[i][j] = current_dynamic[j + i * width_matrix] return phase_matrix def allocate_correlation_matrix(self, iteration = None): """! @brief Allocate correlation matrix between oscillators at the specified step of simulation. @param[in] iteration (uint): Number of iteration of simulation for which correlation matrix should be allocated. If iternation number is not specified, the last step of simulation is used for the matrix allocation. @return (list) Correlation matrix between oscillators with size [number_oscillators x number_oscillators]. """ if self._ccore_sync_dynamic_pointer is not None: return wrapper.sync_dynamic_allocate_correlation_matrix(self._ccore_sync_dynamic_pointer, iteration) if (self._dynamic is None) or (len(self._dynamic) == 0): return [] dynamic = self._dynamic current_dynamic = dynamic[len(dynamic) - 1] if iteration is not None: current_dynamic = dynamic[iteration] number_oscillators = len(dynamic[0]) affinity_matrix = [[0.0 for i in range(number_oscillators)] for j in range(number_oscillators)] for i in range(number_oscillators): for j in range(number_oscillators): phase1 = current_dynamic[i] phase2 = current_dynamic[j] affinity_matrix[i][j] = abs(math.sin(phase1 - phase2)) return affinity_matrix def calculate_order_parameter(self, start_iteration=None, stop_iteration=None): """! @brief Calculates level of global synchorization (order parameter). @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it tend to 0.0 when desynchronization is observed in the network. Order parameter is calculated using following equation: \f[ r_{c}=\frac{1}{Ne^{i\varphi }}\sum_{j=0}^{N}e^{i\theta_{j}}; \f] where \f$\varphi\f$ is a average phase coordinate in the network, \f$N\f$ is an amount of oscillators in the network. @param[in] start_iteration (uint): The first iteration that is used for calculation, if 'None' then the last iteration is used. @param[in] stop_iteration (uint): The last iteration that is used for calculation, if 'None' then 'start_iteration' + 1 is used. Example: @code oscillatory_network = sync(16, type_conn = conn_type.ALL_TO_ALL); output_dynamic = oscillatory_network.simulate_static(100, 10); print("Order parameter at the last step: ", output_dynamic.calculate_order_parameter()); print("Order parameter at the first step:", output_dynamic.calculate_order_parameter(0)); print("Order parameter evolution between 40 and 50 steps:", output_dynamic.calculate_order_parameter(40, 50)); @endcode @return (list) List of levels of global synchronization (order parameter evolution). @see order_estimator """ (start_iteration, stop_iteration) = self.__get_start_stop_iterations(start_iteration, stop_iteration) if self._ccore_sync_dynamic_pointer is not None: return wrapper.sync_dynamic_calculate_order(self._ccore_sync_dynamic_pointer, start_iteration, stop_iteration) sequence_order = [] for index in range(start_iteration, stop_iteration): sequence_order.append(order_estimator.calculate_sync_order(self.output[index])) return sequence_order def calculate_local_order_parameter(self, oscillatory_network, start_iteration = None, stop_iteration = None): """! @brief Calculates local order parameter. @details Local order parameter or so-called level of local or partial synchronization is calculated by following expression: \f[ r_{c}=\left | \sum_{i=0}^{N} \frac{1}{N_{i}} \sum_{j=0}e^{ \theta_{j} - \theta_{i} } \right |; \f] where N - total amount of oscillators in the network and \f$N_{i}\f$ - amount of neighbors of oscillator with index \f$i\f$. @param[in] oscillatory_network (sync): Sync oscillatory network whose structure of connections is required for calculation. @param[in] start_iteration (uint): The first iteration that is used for calculation, if 'None' then the last iteration is used. @param[in] stop_iteration (uint): The last iteration that is used for calculation, if 'None' then 'start_iteration' + 1 is used. @return (list) List of levels of local (partial) synchronization (local order parameter evolution). """ (start_iteration, stop_iteration) = self.__get_start_stop_iterations(start_iteration, stop_iteration) if self._ccore_sync_dynamic_pointer is not None: network_pointer = oscillatory_network._ccore_network_pointer return wrapper.sync_dynamic_calculate_local_order(self._ccore_sync_dynamic_pointer, network_pointer, start_iteration, stop_iteration) sequence_local_order = [] for index in range(start_iteration, stop_iteration): sequence_local_order.append(order_estimator.calculate_local_sync_order(self.output[index], oscillatory_network)) return sequence_local_order def __get_start_stop_iterations(self, start_iteration, stop_iteration): """! @brief Aplly rules for start_iteration and stop_iteration parameters. @param[in] start_iteration (uint): The first iteration that is used for calculation. @param[in] stop_iteration (uint): The last iteration that is used for calculation. @return (tuple) New the first iteration and the last. """ if start_iteration is None: start_iteration = len(self) - 1 if stop_iteration is None: stop_iteration = start_iteration + 1 return start_iteration, stop_iteration class sync_visualizer: """! @brief Visualizer of output dynamic of sync network (Sync). """ @staticmethod def show_output_dynamic(sync_output_dynamic): """! @brief Shows output dynamic (output of each oscillator) during simulation. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @see show_output_dynamics """ draw_dynamics(sync_output_dynamic.time, sync_output_dynamic.output, x_title="t", y_title="phase", y_lim=[0, 2 * 3.14]) @staticmethod def show_output_dynamics(sync_output_dynamics): """! @brief Shows several output dynamics (output of each oscillator) during simulation. @details Each dynamic is presented on separate plot. @param[in] sync_output_dynamics (list): list of output dynamics 'sync_dynamic' of the Sync network. @see show_output_dynamic """ draw_dynamics_set(sync_output_dynamics, "t", "phase", None, [0, 2 * 3.14], False, False) @staticmethod def show_correlation_matrix(sync_output_dynamic, iteration=None): """! @brief Shows correlation matrix between oscillators at the specified iteration. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @param[in] iteration (uint): Number of iteration of simulation for which correlation matrix should be allocated. If iteration number is not specified, the last step of simulation is used for the matrix allocation. """ _ = plt.figure() correlation_matrix = sync_output_dynamic.allocate_correlation_matrix(iteration) plt.imshow(correlation_matrix, cmap = plt.get_cmap('cool'), interpolation='kaiser', vmin=0.0, vmax=1.0) plt.show() @staticmethod def show_phase_matrix(sync_output_dynamic, grid_width=None, grid_height=None, iteration=None): """! @brief Shows 2D matrix of phase values of oscillators at the specified iteration. @details User should ensure correct matrix sizes in line with following expression grid_width x grid_height that should be equal to amount of oscillators otherwise exception is thrown. If grid_width or grid_height are not specified than phase matrix size will by calculated automatically by square root. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network whose phase matrix should be shown. @param[in] grid_width (uint): Width of the phase matrix. @param[in] grid_height (uint): Height of the phase matrix. @param[in] iteration (uint): Number of iteration of simulation for which correlation matrix should be allocated. If iternation number is not specified, the last step of simulation is used for the matrix allocation. """ _ = plt.figure() phase_matrix = sync_output_dynamic.allocate_phase_matrix(grid_width, grid_height, iteration) plt.imshow(phase_matrix, cmap = plt.get_cmap('jet'), interpolation='kaiser', vmin=0.0, vmax=2.0 * math.pi) plt.show() @staticmethod def show_order_parameter(sync_output_dynamic, start_iteration=None, stop_iteration=None): """! @brief Shows evolution of order parameter (level of global synchronization in the network). @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network whose evolution of global synchronization should be visualized. @param[in] start_iteration (uint): The first iteration that is used for calculation, if 'None' then the first is used @param[in] stop_iteration (uint): The last iteration that is used for calculation, if 'None' then the last is used. """ (start_iteration, stop_iteration) = sync_visualizer.__get_start_stop_iterations(sync_output_dynamic, start_iteration, stop_iteration) order_parameter = sync_output_dynamic.calculate_order_parameter(start_iteration, stop_iteration) axis = plt.subplot(111) plt.plot(sync_output_dynamic.time[start_iteration:stop_iteration], order_parameter, 'b-', linewidth=2.0) set_ax_param(axis, "t", "R (order parameter)", None, [0.0, 1.05]) plt.show() @staticmethod def show_local_order_parameter(sync_output_dynamic, oscillatory_network, start_iteration=None, stop_iteration=None): """! @brief Shows evolution of local order parameter (level of local synchronization in the network). @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network whose evolution of global synchronization should be visualized. @param[in] oscillatory_network (sync): Sync oscillatory network whose structure of connections is required for calculation. @param[in] start_iteration (uint): The first iteration that is used for calculation, if 'None' then the first is used @param[in] stop_iteration (uint): The last iteration that is used for calculation, if 'None' then the last is used. """ (start_iteration, stop_iteration) = sync_visualizer.__get_start_stop_iterations(sync_output_dynamic, start_iteration, stop_iteration) order_parameter = sync_output_dynamic.calculate_local_order_parameter(oscillatory_network, start_iteration, stop_iteration) axis = plt.subplot(111) plt.plot(sync_output_dynamic.time[start_iteration:stop_iteration], order_parameter, 'b-', linewidth=2.0) set_ax_param(axis, "t", "R (local order parameter)", None, [0.0, 1.05]) plt.show() @staticmethod def animate_output_dynamic(sync_output_dynamic, animation_velocity = 75, save_movie = None): """! @brief Shows animation of output dynamic (output of each oscillator) during simulation on a circle from [0; 2pi]. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @param[in] animation_velocity (uint): Interval between frames in milliseconds. @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure() dynamic = sync_output_dynamic.output[0] artist, = plt.polar(dynamic, [1.0] * len(dynamic), 'o', color='blue') def init_frame(): return [artist] def frame_generation(index_dynamic): dynamic = sync_output_dynamic.output[index_dynamic] artist.set_data(dynamic, [1.0] * len(dynamic)) return [artist] phase_animation = animation.FuncAnimation(figure, frame_generation, len(sync_output_dynamic), interval = animation_velocity, init_func = init_frame, repeat_delay = 5000); if save_movie is not None: phase_animation.save(save_movie, writer='ffmpeg', fps=15, bitrate=1500) else: plt.show() @staticmethod def animate_correlation_matrix(sync_output_dynamic, animation_velocity = 75, colormap = 'cool', save_movie = None): """! @brief Shows animation of correlation matrix between oscillators during simulation. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @param[in] animation_velocity (uint): Interval between frames in milliseconds. @param[in] colormap (string): Name of colormap that is used by matplotlib ('gray', 'pink', 'cool', spring', etc.). @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure() correlation_matrix = sync_output_dynamic.allocate_correlation_matrix(0) artist = plt.imshow(correlation_matrix, cmap = plt.get_cmap(colormap), interpolation='kaiser', vmin = 0.0, vmax = 1.0) def init_frame(): return [ artist ] def frame_generation(index_dynamic): correlation_matrix = sync_output_dynamic.allocate_correlation_matrix(index_dynamic) artist.set_data(correlation_matrix) return [artist] correlation_animation = animation.FuncAnimation(figure, frame_generation, len(sync_output_dynamic), init_func = init_frame, interval = animation_velocity , repeat_delay = 1000, blit = True) if save_movie is not None: correlation_animation.save(save_movie, writer='ffmpeg', fps=15, bitrate=1500) else: plt.show() @staticmethod def animate_phase_matrix(sync_output_dynamic, grid_width=None, grid_height=None, animation_velocity=75, colormap='jet', save_movie=None): """! @brief Shows animation of phase matrix between oscillators during simulation on 2D stage. @details If grid_width or grid_height are not specified than phase matrix size will by calculated automatically by square root. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @param[in] grid_width (uint): Width of the phase matrix. @param[in] grid_height (uint): Height of the phase matrix. @param[in] animation_velocity (uint): Interval between frames in milliseconds. @param[in] colormap (string): Name of colormap that is used by matplotlib ('gray', 'pink', 'cool', spring', etc.). @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure() def init_frame(): return frame_generation(0) def frame_generation(index_dynamic): figure.clf() axis = figure.add_subplot(111) phase_matrix = sync_output_dynamic.allocate_phase_matrix(grid_width, grid_height, index_dynamic) axis.imshow(phase_matrix, cmap=plt.get_cmap(colormap), interpolation='kaiser', vmin=0.0, vmax=2.0 * math.pi) artist = figure.gca() return [artist] phase_animation = animation.FuncAnimation(figure, frame_generation, len(sync_output_dynamic), init_func = init_frame, interval = animation_velocity , repeat_delay = 1000); if save_movie is not None: phase_animation.save(save_movie, writer='ffmpeg', fps=15, bitrate=1500) else: plt.show() @staticmethod def __get_start_stop_iterations(sync_output_dynamic, start_iteration, stop_iteration): """! @brief Apply rule of preparation for start iteration and stop iteration values. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @param[in] start_iteration (uint): The first iteration that is used for calculation. @param[in] stop_iteration (uint): The last iteration that is used for calculation. @return (tuple) New values of start and stop iterations. """ if start_iteration is None: start_iteration = 0 if stop_iteration is None: stop_iteration = len(sync_output_dynamic) return start_iteration, stop_iteration @staticmethod def animate(sync_output_dynamic, title=None, save_movie=None): """! @brief Shows animation of phase coordinates and animation of correlation matrix together for the Sync dynamic output on the same figure. @param[in] sync_output_dynamic (sync_dynamic): Output dynamic of the Sync network. @param[in] title (string): Title of the animation that is displayed on a figure if it is specified. @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ dynamic = sync_output_dynamic.output[0] correlation_matrix = sync_output_dynamic.allocate_correlation_matrix(0) figure = plt.figure(1) if title is not None: figure.suptitle(title, fontsize = 26, fontweight = 'bold') ax1 = figure.add_subplot(121, projection='polar') ax2 = figure.add_subplot(122) artist1, = ax1.plot(dynamic, [1.0] * len(dynamic), marker='o', color='blue', ls='') artist2 = ax2.imshow(correlation_matrix, cmap = plt.get_cmap('Accent'), interpolation='kaiser') def init_frame(): return [artist1, artist2] def frame_generation(index_dynamic): dynamic = sync_output_dynamic.output[index_dynamic] artist1.set_data(dynamic, [1.0] * len(dynamic)) correlation_matrix = sync_output_dynamic.allocate_correlation_matrix(index_dynamic) artist2.set_data(correlation_matrix) return [artist1, artist2] dynamic_animation = animation.FuncAnimation(figure, frame_generation, len(sync_output_dynamic), interval=75, init_func=init_frame, repeat_delay=5000) if save_movie is not None: dynamic_animation.save(save_movie, writer='ffmpeg', fps=15, bitrate=1500) else: plt.show() class sync_network(network): """! @brief Model of oscillatory network that is based on the Kuramoto model of synchronization. @details CCORE option can be used to use the pyclustering core - C/C++ shared library for processing that significantly increases performance. """ def __init__(self, num_osc, weight = 1, frequency = 0, type_conn = conn_type.ALL_TO_ALL, representation = conn_represent.MATRIX, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore = True): """! @brief Constructor of oscillatory network is based on Kuramoto model. @param[in] num_osc (uint): Number of oscillators in the network. @param[in] weight (double): Coupling strength of the links between oscillators. @param[in] frequency (double): Multiplier of internal frequency of the oscillators. @param[in] type_conn (conn_type): Type of connection between oscillators in the network (all-to-all, grid, bidirectional list, etc.). @param[in] representation (conn_represent): Internal representation of connection in the network: matrix or list. @param[in] initial_phases (initial_type): Type of initialization of initial phases of oscillators (random, uniformly distributed, etc.). @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering). """ self._ccore_network_pointer = None; # Pointer to CCORE Sync implementation of the network. if ( (ccore is True) and ccore_library.workable() ): self._ccore_network_pointer = wrapper.sync_create_network(num_osc, weight, frequency, type_conn, initial_phases); self._num_osc = num_osc; self._conn_represent = conn_represent.MATRIX; else: super().__init__(num_osc, type_conn, representation); self._weight = weight; self._phases = list(); self._freq = list(); random.seed(); for index in range(0, num_osc, 1): if (initial_phases == initial_type.RANDOM_GAUSSIAN): self._phases.append(random.random() * 2 * pi); elif (initial_phases == initial_type.EQUIPARTITION): self._phases.append( pi / num_osc * index); self._freq.append(random.random() * frequency); def __del__(self): """! @brief Destructor of oscillatory network is based on Kuramoto model. """ if (self._ccore_network_pointer is not None): wrapper.sync_destroy_network(self._ccore_network_pointer); self._ccore_network_pointer = None; def sync_order(self): """! @brief Calculates current level of global synchorization (order parameter) in the network. @details This parameter is tend 1.0 when the oscillatory network close to global synchronization and it tend to 0.0 when desynchronization is observed in the network. Order parameter is calculated using following equation: \f[ r_{c}=\frac{1}{Ne^{i\varphi }}\sum_{j=0}^{N}e^{i\theta_{j}}; \f] where \f$\varphi\f$ is a average phase coordinate in the network, \f$N\f$ is an amount of oscillators in the network. Example: @code oscillatory_network = sync(16, type_conn = conn_type.ALL_TO_ALL); output_dynamic = oscillatory_network.simulate_static(100, 10); if (oscillatory_network.sync_order() < 0.9): print("Global synchronization is not reached yet."); else: print("Global synchronization is reached."); @endcode @return (double) Level of global synchronization (order parameter). @see sync_local_order() """ if (self._ccore_network_pointer is not None): return wrapper.sync_order(self._ccore_network_pointer); return order_estimator.calculate_sync_order(self._phases); def sync_local_order(self): """! @brief Calculates current level of local (partial) synchronization in the network. @return (double) Level of local (partial) synchronization. @see sync_order() """ if (self._ccore_network_pointer is not None): return wrapper.sync_local_order(self._ccore_network_pointer); return order_estimator.calculate_local_sync_order(self._phases, self); def _phase_kuramoto(self, teta, t, argv): """! @brief Returns result of phase calculation for specified oscillator in the network. @param[in] teta (double): Phase of the oscillator that is differentiated. @param[in] t (double): Current time of simulation. @param[in] argv (tuple): Index of the oscillator in the list. @return (double) New phase for specified oscillator (don't assign here). """ index = argv; phase = 0; for k in range(0, self._num_osc): if (self.has_connection(index, k) == True): phase += math.sin(self._phases[k] - teta); return ( self._freq[index] + (phase * self._weight / self._num_osc) ); def simulate(self, steps, time, solution = solve_type.FAST, collect_dynamic = True): """! @brief Performs static simulation of Sync oscillatory network. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] solution (solve_type): Type of solution (solving). @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see simulate_dynamic() @see simulate_static() """ return self.simulate_static(steps, time, solution, collect_dynamic); def simulate_dynamic(self, order = 0.998, solution = solve_type.FAST, collect_dynamic = False, step = 0.1, int_step = 0.01, threshold_changes = 0.0000001): """! @brief Performs dynamic simulation of the network until stop condition is not reached. Stop condition is defined by input argument 'order'. @param[in] order (double): Order of process synchronization, distributed 0..1. @param[in] solution (solve_type): Type of solution. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @param[in] step (double): Time step of one iteration of simulation. @param[in] int_step (double): Integration step, should be less than step. @param[in] threshold_changes (double): Additional stop condition that helps prevent infinite simulation, defines limit of changes of oscillators between current and previous steps. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see simulate() @see simulate_static() """ if (self._ccore_network_pointer is not None): ccore_instance_dynamic = wrapper.sync_simulate_dynamic(self._ccore_network_pointer, order, solution, collect_dynamic, step, int_step, threshold_changes); return sync_dynamic(None, None, ccore_instance_dynamic); # For statistics and integration time_counter = 0; # Prevent infinite loop. It's possible when required state cannot be reached. previous_order = 0; current_order = self.sync_local_order(); # If requested input dynamics dyn_phase = []; dyn_time = []; if (collect_dynamic == True): dyn_phase.append(self._phases); dyn_time.append(0); # Execute until sync state will be reached while (current_order < order): # update states of oscillators self._phases = self._calculate_phases(solution, time_counter, step, int_step); # update time time_counter += step; # if requested input dynamic if (collect_dynamic == True): dyn_phase.append(self._phases); dyn_time.append(time_counter); # update orders previous_order = current_order; current_order = self.sync_local_order(); # hang prevention if (abs(current_order - previous_order) < threshold_changes): # print("Warning: sync_network::simulate_dynamic - simulation is aborted due to low level of convergence rate (order = " + str(current_order) + ")."); break; if (collect_dynamic != True): dyn_phase.append(self._phases); dyn_time.append(time_counter); output_sync_dynamic = sync_dynamic(dyn_phase, dyn_time, None); return output_sync_dynamic; def simulate_static(self, steps, time, solution = solve_type.FAST, collect_dynamic = False): """! @brief Performs static simulation of oscillatory network. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] solution (solve_type): Type of solution. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see simulate() @see simulate_dynamic() """ if (self._ccore_network_pointer is not None): ccore_instance_dynamic = wrapper.sync_simulate_static(self._ccore_network_pointer, steps, time, solution, collect_dynamic); return sync_dynamic(None, None, ccore_instance_dynamic); dyn_phase = []; dyn_time = []; if (collect_dynamic == True): dyn_phase.append(self._phases); dyn_time.append(0); step = time / steps; int_step = step / 10.0; for t in numpy.arange(step, time + step, step): # update states of oscillators self._phases = self._calculate_phases(solution, t, step, int_step); # update states of oscillators if (collect_dynamic == True): dyn_phase.append(self._phases); dyn_time.append(t); if (collect_dynamic != True): dyn_phase.append(self._phases); dyn_time.append(time); output_sync_dynamic = sync_dynamic(dyn_phase, dyn_time); return output_sync_dynamic; def _calculate_phases(self, solution, t, step, int_step): """! @brief Calculates new phases for oscillators in the network in line with current step. @param[in] solution (solve_type): Type solver of the differential equation. @param[in] t (double): Time of simulation. @param[in] step (double): Step of solution at the end of which states of oscillators should be calculated. @param[in] int_step (double): Step differentiation that is used for solving differential equation. @return (list) New states (phases) for oscillators. """ next_phases = [0.0] * self._num_osc; # new oscillator _phases for index in range (0, self._num_osc, 1): if (solution == solve_type.FAST): result = self._phases[index] + self._phase_kuramoto(self._phases[index], 0, index); next_phases[index] = self._phase_normalization(result); elif ( (solution == solve_type.RK4) or (solution == solve_type.RKF45) ): result = odeint(self._phase_kuramoto, self._phases[index], numpy.arange(t - step, t, int_step), (index , )); next_phases[index] = self._phase_normalization(result[len(result) - 1][0]); else: raise NameError("Solver '" + str(solution) + "' is not supported"); return next_phases; def _phase_normalization(self, teta): """! @brief Normalization of phase of oscillator that should be placed between [0; 2 * pi]. @param[in] teta (double): phase of oscillator. @return (double) Normalized phase. """ norm_teta = teta; while (norm_teta > (2.0 * pi)) or (norm_teta < 0): if (norm_teta > (2.0 * pi)): norm_teta -= 2.0 * pi; else: norm_teta += 2.0 * pi; return norm_teta; def get_neighbors(self, index): """! @brief Finds neighbors of the oscillator with specified index. @param[in] index (uint): index of oscillator for which neighbors should be found in the network. @return (list) Indexes of neighbors of the specified oscillator. """ if ( (self._ccore_network_pointer is not None) and (self._osc_conn is None) ): self._osc_conn = wrapper.sync_connectivity_matrix(self._ccore_network_pointer); return super().get_neighbors(index); def has_connection(self, i, j): """! @brief Returns True if there is connection between i and j oscillators and False - if connection doesn't exist. @param[in] i (uint): index of an oscillator in the network. @param[in] j (uint): index of an oscillator in the network. """ if ( (self._ccore_network_pointer is not None) and (self._osc_conn is None) ): self._osc_conn = wrapper.sync_connectivity_matrix(self._ccore_network_pointer); return super().has_connection(i, j);pyclustering-0.10.1.2/pyclustering/nnet/syncpr.py000077500000000000000000000524771375753423500221050ustar00rootroot00000000000000"""! @brief Phase oscillatory network for patten recognition based on modified Kuramoto model. @details Implementation based on paper @cite article::nnet::syncpr::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import math import cmath import numpy from pyclustering.nnet import solve_type, initial_type, conn_type,conn_represent from pyclustering.nnet.sync import sync_network, sync_dynamic, sync_visualizer import pyclustering.core.syncpr_wrapper as wrapper from pyclustering.core.wrapper import ccore_library from PIL import Image import matplotlib.pyplot as plt import matplotlib.animation as animation class syncpr_dynamic(sync_dynamic): """! @brief Represents output dynamic of syncpr (Sync for Pattern Recognition). """ def __init__(self, phase, time, ccore): """! @brief Constructor of syncpr dynamic. @param[in] phase (list): Dynamic of oscillators on each step of simulation. If ccore pointer is specified than it can be ignored. @param[in] time (list): Simulation time. @param[in] ccore (ctypes.pointer): Pointer to CCORE sync_dynamic instance in memory. """ super().__init__(phase, time, ccore); class syncpr_visualizer(sync_visualizer): """! @brief Visualizer of output dynamic of syncpr network (Sync for Pattern Recognition). """ @staticmethod def show_pattern(syncpr_output_dynamic, image_height, image_width): """! @brief Displays evolution of phase oscillators as set of patterns where the last one means final result of recognition. @param[in] syncpr_output_dynamic (syncpr_dynamic): Output dynamic of a syncpr network. @param[in] image_height (uint): Height of the pattern (image_height * image_width should be equal to number of oscillators). @param[in] image_width (uint): Width of the pattern. """ number_pictures = len(syncpr_output_dynamic); iteration_math_step = 1.0; if (number_pictures > 50): iteration_math_step = number_pictures / 50.0; number_pictures = 50; number_cols = int(numpy.ceil(number_pictures ** 0.5)); number_rows = int(numpy.ceil(number_pictures / number_cols)); real_index = 0, 0; double_indexer = True; if ( (number_cols == 1) or (number_rows == 1) ): real_index = 0; double_indexer = False; (_, axarr) = plt.subplots(number_rows, number_cols); if (number_pictures > 1): plt.setp([ax for ax in axarr], visible = False); iteration_display = 0.0; for iteration in range(len(syncpr_output_dynamic)): if (iteration >= iteration_display): iteration_display += iteration_math_step; ax_handle = axarr; if (number_pictures > 1): ax_handle = axarr[real_index]; syncpr_visualizer.__show_pattern(ax_handle, syncpr_output_dynamic, image_height, image_width, iteration); if (double_indexer is True): real_index = real_index[0], real_index[1] + 1; if (real_index[1] >= number_cols): real_index = real_index[0] + 1, 0; else: real_index += 1; plt.show(); @staticmethod def animate_pattern_recognition(syncpr_output_dynamic, image_height, image_width, animation_velocity = 75, title = None, save_movie = None): """! @brief Shows animation of pattern recognition process that has been preformed by the oscillatory network. @param[in] syncpr_output_dynamic (syncpr_dynamic): Output dynamic of a syncpr network. @param[in] image_height (uint): Height of the pattern (image_height * image_width should be equal to number of oscillators). @param[in] image_width (uint): Width of the pattern. @param[in] animation_velocity (uint): Interval between frames in milliseconds. @param[in] title (string): Title of the animation that is displayed on a figure if it is specified. @param[in] save_movie (string): If it is specified then animation will be stored to file that is specified in this parameter. """ figure = plt.figure(); def init_frame(): return frame_generation(0); def frame_generation(index_dynamic): figure.clf(); if (title is not None): figure.suptitle(title, fontsize = 26, fontweight = 'bold') ax1 = figure.add_subplot(121, projection='polar'); ax2 = figure.add_subplot(122); dynamic = syncpr_output_dynamic.output[index_dynamic]; artist1, = ax1.plot(dynamic, [1.0] * len(dynamic), marker = 'o', color = 'blue', ls = ''); artist2 = syncpr_visualizer.__show_pattern(ax2, syncpr_output_dynamic, image_height, image_width, index_dynamic); return [ artist1, artist2 ]; cluster_animation = animation.FuncAnimation(figure, frame_generation, len(syncpr_output_dynamic), interval = animation_velocity, init_func = init_frame, repeat_delay = 5000); if (save_movie is not None): # plt.rcParams['animation.ffmpeg_path'] = 'C:\\Users\\annoviko\\programs\\ffmpeg-win64-static\\bin\\ffmpeg.exe'; # ffmpeg_writer = animation.FFMpegWriter(); # cluster_animation.save(save_movie, writer = ffmpeg_writer, fps = 15); cluster_animation.save(save_movie, writer = 'ffmpeg', fps = 15, bitrate = 1500); else: plt.show(); @staticmethod def __show_pattern(ax_handle, syncpr_output_dynamic, image_height, image_width, iteration): """! @brief Draws pattern on specified ax. @param[in] ax_handle (Axis): Axis where pattern should be drawn. @param[in] syncpr_output_dynamic (syncpr_dynamic): Output dynamic of a syncpr network. @param[in] image_height (uint): Height of the pattern (image_height * image_width should be equal to number of oscillators). @param[in] image_width (uint): Width of the pattern. @param[in] iteration (uint): Simulation iteration that should be used for extracting pattern. @return (matplotlib.artist) Artist (pattern) that is rendered in the canvas. """ current_dynamic = syncpr_output_dynamic.output[iteration]; stage_picture = [(255, 255, 255)] * (image_height * image_width); for index_phase in range(len(current_dynamic)): phase = current_dynamic[index_phase]; pixel_color = math.floor( phase * (255 / (2 * math.pi)) ); stage_picture[index_phase] = (pixel_color, pixel_color, pixel_color); stage = numpy.array(stage_picture, numpy.uint8); stage = numpy.reshape(stage, (image_height, image_width) + ((3),)); # ((3),) it's size of RGB - third dimension. image_cluster = Image.fromarray(stage); artist = ax_handle.imshow(image_cluster, interpolation = 'none'); plt.setp(ax_handle, visible = True); ax_handle.xaxis.set_ticklabels([]); ax_handle.yaxis.set_ticklabels([]); ax_handle.xaxis.set_ticks_position('none'); ax_handle.yaxis.set_ticks_position('none'); return artist; class syncpr(sync_network): """! @brief Model of phase oscillatory network for pattern recognition that is based on the Kuramoto model. @details The model uses second-order and third-order modes of the Fourier components. CCORE option can be used to use the pyclustering core - C/C++ shared library for processing that significantly increases performance. Example: @code # Network size should be equal to size of pattern for learning. net = syncpr(size_network, 0.3, 0.3); # Train network using list of patterns (input images). net.train(image_samples); # Recognize image using 10 steps during 10 seconds of simulation. sync_output_dynamic = net.simulate(10, 10, pattern, solve_type.RK4, True); # Display output dynamic. syncpr_visualizer.show_output_dynamic(sync_output_dynamic); # Display evolution of recognition of the pattern. syncpr_visualizer.show_pattern(sync_output_dynamic, image_height, image_width); @endcode """ def __init__(self, num_osc, increase_strength1, increase_strength2, ccore = True): """! @brief Constructor of oscillatory network for pattern recognition based on Kuramoto model. @param[in] num_osc (uint): Number of oscillators in the network. @param[in] increase_strength1 (double): Parameter for increasing strength of the second term of the Fourier component. @param[in] increase_strength2 (double): Parameter for increasing strength of the third term of the Fourier component. @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering). """ if ( (ccore is True) and ccore_library.workable() ): self._ccore_network_pointer = wrapper.syncpr_create(num_osc, increase_strength1, increase_strength2); else: self._increase_strength1 = increase_strength1; self._increase_strength2 = increase_strength2; self._coupling = [ [0.0 for i in range(num_osc)] for j in range(num_osc) ]; super().__init__(num_osc, 1, 0, conn_type.ALL_TO_ALL, conn_represent.MATRIX, initial_type.RANDOM_GAUSSIAN, ccore) def __del__(self): """! @brief Default destructor of syncpr. """ if (self._ccore_network_pointer is not None): wrapper.syncpr_destroy(self._ccore_network_pointer); self._ccore_network_pointer = None; def __len__(self): """! @brief Returns size of the network. """ if (self._ccore_network_pointer is not None): return wrapper.syncpr_get_size(self._ccore_network_pointer); else: return self._num_osc; def train(self, samples): """! @brief Trains syncpr network using Hebbian rule for adjusting strength of connections between oscillators during training. @param[in] samples (list): list of patterns where each pattern is represented by list of features that are equal to [-1; 1]. """ # Verify pattern for learning for pattern in samples: self.__validate_pattern(pattern); if (self._ccore_network_pointer is not None): return wrapper.syncpr_train(self._ccore_network_pointer, samples); length = len(self); number_samples = len(samples); for i in range(length): for j in range(i + 1, len(self), 1): # go through via all patterns for p in range(number_samples): value1 = samples[p][i]; value2 = samples[p][j]; self._coupling[i][j] += value1 * value2; self._coupling[i][j] /= length; self._coupling[j][i] = self._coupling[i][j]; def simulate(self, steps, time, pattern, solution = solve_type.RK4, collect_dynamic = True): """! @brief Performs static simulation of syncpr oscillatory network. @details In other words network performs pattern recognition during simulation. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. @param[in] solution (solve_type): Type of solver that should be used for simulation. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see simulate_dynamic() @see simulate_static() """ return self.simulate_static(steps, time, pattern, solution, collect_dynamic); def simulate_dynamic(self, pattern, order = 0.998, solution = solve_type.RK4, collect_dynamic = False, step = 0.1, int_step = 0.01, threshold_changes = 0.0000001): """! @brief Performs dynamic simulation of the network until stop condition is not reached. @details In other words network performs pattern recognition during simulation. Stop condition is defined by input argument 'order' that represents memory order, but process of simulation can be stopped if convergance rate is low whose threshold is defined by the argument 'threshold_changes'. @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. @param[in] order (double): Order of process synchronization, distributed 0..1. @param[in] solution (solve_type): Type of solution. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @param[in] step (double): Time step of one iteration of simulation. @param[in] int_step (double): Integration step, should be less than step. @param[in] threshold_changes (double): Additional stop condition that helps prevent infinite simulation, defines limit of changes of oscillators between current and previous steps. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see simulate() @see simulate_static() """ self.__validate_pattern(pattern); if (self._ccore_network_pointer is not None): ccore_instance_dynamic = wrapper.syncpr_simulate_dynamic(self._ccore_network_pointer, pattern, order, solution, collect_dynamic, step); return syncpr_dynamic(None, None, ccore_instance_dynamic); for i in range(0, len(pattern), 1): if (pattern[i] > 0.0): self._phases[i] = 0.0; else: self._phases[i] = math.pi / 2.0; # For statistics and integration time_counter = 0; # Prevent infinite loop. It's possible when required state cannot be reached. previous_order = 0; current_order = self.__calculate_memory_order(pattern); # If requested input dynamics dyn_phase = []; dyn_time = []; if (collect_dynamic == True): dyn_phase.append(self._phases); dyn_time.append(0); # Execute until sync state will be reached while (current_order < order): # update states of oscillators self._phases = self._calculate_phases(solution, time_counter, step, int_step); # update time time_counter += step; # if requested input dynamic if (collect_dynamic == True): dyn_phase.append(self._phases); dyn_time.append(time_counter); # update orders previous_order = current_order; current_order = self.__calculate_memory_order(pattern); # hang prevention if (abs(current_order - previous_order) < threshold_changes): break; if (collect_dynamic != True): dyn_phase.append(self._phases); dyn_time.append(time_counter); output_sync_dynamic = syncpr_dynamic(dyn_phase, dyn_time, None); return output_sync_dynamic; def simulate_static(self, steps, time, pattern, solution = solve_type.FAST, collect_dynamic = False): """! @brief Performs static simulation of syncpr oscillatory network. @details In other words network performs pattern recognition during simulation. @param[in] steps (uint): Number steps of simulations during simulation. @param[in] time (double): Time of simulation. @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. @param[in] solution (solve_type): Type of solution. @param[in] collect_dynamic (bool): If True - returns whole dynamic of oscillatory network, otherwise returns only last values of dynamics. @return (list) Dynamic of oscillatory network. If argument 'collect_dynamic' = True, than return dynamic for the whole simulation time, otherwise returns only last values (last step of simulation) of dynamic. @see simulate() @see simulate_dynamic() """ self.__validate_pattern(pattern); if (self._ccore_network_pointer is not None): ccore_instance_dynamic = wrapper.syncpr_simulate_static(self._ccore_network_pointer, steps, time, pattern, solution, collect_dynamic); return syncpr_dynamic(None, None, ccore_instance_dynamic); for i in range(0, len(pattern), 1): if (pattern[i] > 0.0): self._phases[i] = 0.0; else: self._phases[i] = math.pi / 2.0; return super().simulate_static(steps, time, solution, collect_dynamic); def memory_order(self, pattern): """! @brief Calculates function of the memorized pattern. @details Throws exception if length of pattern is not equal to size of the network or if it consists feature with value that are not equal to [-1; 1]. @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. @return (double) Order of memory for the specified pattern. """ self.__validate_pattern(pattern); if (self._ccore_network_pointer is not None): return wrapper.syncpr_memory_order(self._ccore_network_pointer, pattern); else: return self.__calculate_memory_order(pattern); def __calculate_memory_order(self, pattern): """! @brief Calculates function of the memorized pattern without any pattern validation. @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. @return (double) Order of memory for the specified pattern. """ memory_order = 0.0; for index in range(len(self)): memory_order += pattern[index] * cmath.exp( 1j * self._phases[index] ); memory_order /= len(self); return abs(memory_order); def _phase_kuramoto(self, teta, t, argv): """! @brief Returns result of phase calculation for specified oscillator in the network. @param[in] teta (double): Phase of the oscillator that is differentiated. @param[in] t (double): Current time of simulation. @param[in] argv (tuple): Index of the oscillator in the list. @return (double) New phase for specified oscillator (don't assign it here). """ index = argv; phase = 0.0; term = 0.0; for k in range(0, self._num_osc): if (k != index): phase_delta = self._phases[k] - teta; phase += self._coupling[index][k] * math.sin(phase_delta); term1 = self._increase_strength1 * math.sin(2.0 * phase_delta); term2 = self._increase_strength2 * math.sin(3.0 * phase_delta); term += (term1 - term2); return ( phase + term / len(self) ); def __validate_pattern(self, pattern): """! @brief Validates pattern. @details Throws exception if length of pattern is not equal to size of the network or if it consists feature with value that are not equal to [-1; 1]. @param[in] pattern (list): Pattern for recognition represented by list of features that are equal to [-1; 1]. """ if (len(pattern) != len(self)): raise NameError('syncpr: length of the pattern (' + len(pattern) + ') should be equal to size of the network'); for feature in pattern: if ( (feature != -1.0) and (feature != 1.0) ): raise NameError('syncpr: patten feature (' + feature + ') should be distributed in [-1; 1]');pyclustering-0.10.1.2/pyclustering/nnet/syncsegm.py000077500000000000000000000301501375753423500223770ustar00rootroot00000000000000"""! @brief Double-layer oscillatory network with phase oscillator for image segmentation. @details Implementation based on paper @cite inproceedings::nnet::syncsegm::1. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import warnings from math import floor try: from PIL import Image except Exception as error_instance: warnings.warn("Impossible to import PIL (please, install 'PIL'), pyclustering's visualization " "functionality is partially not available (details: '%s')." % str(error_instance)) from pyclustering.cluster.syncnet import syncnet from pyclustering.nnet import solve_type, initial_type from pyclustering.nnet.sync import sync_visualizer from pyclustering.utils import read_image class syncsegm_visualizer: """! @brief Result visualizer of double-layer oscillatory network 'syncsegm'. """ @staticmethod def show_first_layer_dynamic(analyser): """! @brief Shows output dynamic of the first layer. @param[in] analyser (syncsegm_analyser): Analyser of output dynamic of the 'syncsegm' oscillatory network. """ sync_visualizer.show_output_dynamic(analyser.get_first_layer_analyser()); @staticmethod def show_second_layer_dynamic(analyser): """! @brief Shows output dynamic of the second layer. @param[in] analyser (syncsegm_analyser): Analyser of output dynamic of the 'syncsegm' oscillatory network. """ second_layer_analysers = analyser.get_second_layer_analysers(); analysers_sequence = [ object_segment_analyser['analyser'] for object_segment_analyser in second_layer_analysers ] sync_visualizer.show_output_dynamics(analysers_sequence); class syncsegm_analyser: """! @brief Performs analysis of output dynamic of the double-layer oscillatory network 'syncsegm' to extract information about segmentation results. """ def __init__(self, color_analyser, object_segment_analysers = None): """! @brief Constructor of the analyser. @param[in] color_analyser (list): Analyser of coloring segmentation results of the first layer. @param[in] object_segment_analysers (list): Analysers of objects on image segments - results of the second layer. """ self.__color_analyser = color_analyser; self.__object_segment_analysers = object_segment_analysers; def get_first_layer_analyser(self): """! @brief Returns analyser of coloring segmentation of the first layer. """ return self.__color_analyser; def get_second_layer_analysers(self): """! @brief Returns analysers of object segmentation of the second layer. """ return self.__object_segment_analysers; def allocate_colors(self, eps = 0.01, noise_size = 1): """! @brief Allocates color segments. @param[in] eps (double): Tolerance level that define maximal difference between phases of oscillators in one segment. @param[in] noise_size (uint): Threshold that defines noise - segments size (in pixels) that is less then the threshold is considered as a noise. @return (list) Color segments where each color segment consists of indexes of pixels that forms color segment. """ segments = self.__color_analyser.allocate_clusters(eps); real_segments = [cluster for cluster in segments if len(cluster) > noise_size]; return real_segments; def allocate_objects(self, eps = 0.01, noise_size = 1): """! @brief Allocates object segments. @param[in] eps (double): Tolerance level that define maximal difference between phases of oscillators in one segment. @param[in] noise_size (uint): Threshold that defines noise - segments size (in pixels) that is less then the threshold is considered as a noise. @return (list) Object segments where each object segment consists of indexes of pixels that forms object segment. """ if (self.__object_segment_analysers is None): return []; segments = []; for object_segment_analyser in self.__object_segment_analysers: indexes = object_segment_analyser['color_segment']; analyser = object_segment_analyser['analyser']; segments += analyser.allocate_clusters(eps, indexes); real_segments = [segment for segment in segments if len(segment) > noise_size]; return real_segments; class syncsegm: """! @brief Class represents segmentation algorithm syncsegm. @details syncsegm is a bio-inspired algorithm that is based on double-layer oscillatory network that uses modified Kuramoto model. Algorithm extracts colors and colored objects. It uses only CCORE (C++ implementation of pyclustering) parts to implement the algorithm. CCORE option is True by default to use sync network in the pyclustering core - C/C++ shared library for processing that significantly increases performance. Example: @code # create oscillatory for image segmentaion - extract colors (radius 128) and objects (radius 4), # and ignore noise (segments with size that is less than 10 pixels) algorithm = syncsegm(128, 4, 10); # extract segments (colors and objects) analyser = algorithm(path_to_file); # obtain segmentation results (only colors - from the first layer) color_segments = analyser.allocate_colors(0.01, 10); draw_image_mask_segments(path_to_file, color_segments); # obtain segmentation results (objects - from the second layer) object_segments = analyser.allocate_objects(0.01, 10); draw_image_mask_segments(path_to_file, object_segments); @endcode """ def __init__(self, color_radius, object_radius, noise_size = 0, ccore = True): """! @brief Contructor of the oscillatory network SYNC for cluster analysis. @param[in] color_radius (double): Radius of color connectivity (color similarity) for the first layer. @param[in] object_radius (double): Radius of object connectivity (object similarity) for the second layer, if 'None' then object segmentation is not performed (only color segmentation). @param[in] noise_size (double): Size of segment that should be considered as a noise and ignored by the second layer. @param[in] ccore (bool): If 'True' then C/C++ implementation is used to increase performance. """ self.__color_radius = color_radius; self.__object_radius = object_radius; self.__noise_size = noise_size; self.__order_color = 0.9995; self.__order_object = 0.999; self.__network = None; self.__ccore = ccore; def process(self, image_source, collect_dynamic = False, order_color = 0.9995, order_object = 0.999): """! @brief Performs image segmentation. @param[in] image_source (string): Path to image file that should be processed. @param[in] collect_dynamic (bool): If 'True' then whole dynamic of each layer of the network is collected. @param[in] order_color (double): Local synchronization order for the first layer - coloring segmentation. @param[in] order_object (double): Local synchronization order for the second layer - object segmentation. @return (syncsegm_analyser) Analyser of segmentation results by the network. """ self.__order_color = order_color self.__order_object = order_object data = read_image(image_source) color_analyser = self.__analyse_colors(data, collect_dynamic) if self.__object_radius is None: return syncsegm_analyser(color_analyser, None) object_segment_analysers = self.__analyse_objects(image_source, color_analyser, collect_dynamic) return syncsegm_analyser(color_analyser, object_segment_analysers) def __analyse_colors(self, image_data, collect_dynamic): """! @brief Performs color segmentation by the first layer. @param[in] image_data (array_like): Image sample as a array-like structure. @param[in] collect_dynamic (bool): If 'True' then whole dynamic of the first layer of the network is collected. @return (syncnet_analyser) Analyser of color segmentation results of the first layer. """ network = syncnet(image_data, self.__color_radius, initial_phases = initial_type.RANDOM_GAUSSIAN, ccore = self.__ccore); analyser = network.process(self.__order_color, solve_type.FAST, collect_dynamic); return analyser; def __analyse_objects(self, image_source, color_analyser, collect_dynamic): """! @brief Performs object segmentation by the second layer. @param[in] image_source (string): Path to image file that should be processed. @param[in] color_analyser (syncnet_analyser): Analyser of color segmentation results. @param[in] collect_dynamic (bool): If 'True' then whole dynamic of the first layer of the network is collected. @return (map) Analysers of object segments. """ # continue analysis pointer_image = Image.open(image_source); image_size = pointer_image.size; object_analysers = []; color_segments = color_analyser.allocate_clusters(); for segment in color_segments: object_analyser = self.__analyse_color_segment(image_size, segment, collect_dynamic); if (object_analyser is not None): object_analysers.append( { 'color_segment': segment, 'analyser': object_analyser } ); pointer_image.close(); return object_analysers; def __analyse_color_segment(self, image_size, color_segment, collect_dynamic): """! @brief Performs object segmentation of separate segment. @param[in] image_size (list): Image size presented as a [width x height]. @param[in] color_segment (list): Image segment that should be processed. @param[in] collect_dynamic (bool): If 'True' then whole dynamic of the second layer of the network is collected. @return (syncnet_analyser) Analyser of object segmentation results of the second layer. """ coordinates = self.__extract_location_coordinates(image_size, color_segment); if (len(coordinates) < self.__noise_size): return None; network = syncnet(coordinates, self.__object_radius, initial_phases = initial_type.EQUIPARTITION, ccore = True); analyser = network.process(self.__order_object, solve_type.FAST, collect_dynamic); return analyser; def __extract_location_coordinates(self, image_size, color_segment): """! @brief Extracts coordinates of specified image segment. @param[in] image_size (list): Image size presented as a [width x height]. @param[in] color_segment (list): Image segment whose coordinates should be extracted. @return (list) Coordinates of each pixel. """ coordinates = []; for index in color_segment: y = floor(index / image_size[0]); x = index - y * image_size[0]; coordinates.append([x, y]); return coordinates; pyclustering-0.10.1.2/pyclustering/nnet/tests/000077500000000000000000000000001375753423500213355ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/nnet/tests/__init__.py000077500000000000000000000014361375753423500234550ustar00rootroot00000000000000"""! @brief Test runner for unit and integration tests of oscillatory and neural networks. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.tests.integration import nnet_integration_tests from pyclustering.nnet.tests.unit import nnet_unit_tests class nnet_tests(suite_holder): def __init__(self): super().__init__() nnet_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(nnet_suite): nnet_integration_tests.fill_suite(nnet_suite) nnet_unit_tests.fill_suite(nnet_suite) pyclustering-0.10.1.2/pyclustering/nnet/tests/hhn_templates.py000077500000000000000000000020271375753423500245460ustar00rootroot00000000000000"""! @brief Templates for tests of Hodgkin-Huxley oscillatory network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.hhn import hhn_network; class HhnTestTemplates: @staticmethod def templateSyncEnsembleAllocation(stimulus, params, sim_steps, sim_time, expected_clusters, ccore): result_testing = False; for _ in range(0, 5, 1): net = hhn_network(len(stimulus), stimulus, params, ccore=ccore); (t, dyn_p, dyn_c) = net.simulate(sim_steps, sim_time); assert t is not None; assert dyn_p is not None; assert dyn_c is not None; assert len(t) == sim_steps + 1; assert len(dyn_p) == sim_steps + 1; assert len(dyn_c) == sim_steps + 1; ensembles = net.allocate_sync_ensembles(1.0); if (ensembles != expected_clusters): continue; result_testing = True; break; assert result_testing;pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/000077500000000000000000000000001375753423500236605ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/__init__.py000077500000000000000000000037411375753423500260010ustar00rootroot00000000000000"""! @brief Integration-test runner for tests of oscillatory and neural networks. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.tests.integration import it_hhn as nnet_hhn_integration_tests from pyclustering.nnet.tests.integration import it_legion as nnet_legion_integration_tests from pyclustering.nnet.tests.integration import it_pcnn as nnet_pcnn_integration_tests from pyclustering.nnet.tests.integration import it_som as nnet_som_integration_tests from pyclustering.nnet.tests.integration import it_sync as nnet_sync_integration_tests from pyclustering.nnet.tests.integration import it_syncpr as nnet_syncpr_integration_tests from pyclustering.nnet.tests.integration import it_syncsegm as nnet_syncsegm_integration_tests class nnet_integration_tests(suite_holder): def __init__(self): super().__init__() nnet_integration_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(integration_nnet_suite): integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_hhn_integration_tests)) integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_legion_integration_tests)) integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_pcnn_integration_tests)) integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_som_integration_tests)) integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_sync_integration_tests)) integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_syncpr_integration_tests)) integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_syncsegm_integration_tests)) pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_hhn.py000077500000000000000000000022221375753423500255040ustar00rootroot00000000000000"""! @brief Integration-tests for Hodgkin-Huxley oscillatory network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.nnet.tests.hhn_templates import HhnTestTemplates from pyclustering.core.tests import remove_library class HhnIntegrationTest(unittest.TestCase): def testGlobalSyncWithSameStimulus(self): HhnTestTemplates.templateSyncEnsembleAllocation([27, 27, 27], None, 600, 50, [[0, 1, 2]], True); def testGlobalSyncWithVariousStimulus(self): HhnTestTemplates.templateSyncEnsembleAllocation([26, 26, 27, 27, 26, 25], None, 600, 50, [[0, 1, 2, 3, 4, 5]], True); def testPartialSync(self): HhnTestTemplates.templateSyncEnsembleAllocation([25, 25, 50, 50], None, 800, 200, [[0, 1], [2, 3]], True); def testThreeEnsembles(self): HhnTestTemplates.templateSyncEnsembleAllocation([0, 0, 25, 25, 47, 47], None, 2400, 600, [[0, 1], [2, 3], [4, 5]], True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): HhnTestTemplates.templateSyncEnsembleAllocation([27, 27, 27], None, 600, 50, [[0, 1, 2]], True); pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_legion.py000077500000000000000000000051671375753423500262170ustar00rootroot00000000000000"""! @brief Integration-tests for Local Excitatory Global Inhibitory Oscillatory Network (LEGION). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.nnet.tests.legion_templates import LegionTestTemplates from pyclustering.nnet.legion import legion_network, legion_parameters from pyclustering.nnet import conn_type from pyclustering.utils import extract_number_oscillations from pyclustering.core.tests import remove_library class LegionIntergrationTest(unittest.TestCase): def testMixStimulatedThreeOscillatorsByCore(self): net = legion_network(3, type_conn = conn_type.LIST_BIDIR, ccore=True) dynamic = net.simulate(1000, 2000, [1, 0, 1]) assert extract_number_oscillations(dynamic.output, 0) > 1; assert extract_number_oscillations(dynamic.output, 2) > 1; def testStimulatedOscillatorListStructureByCore(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.LIST_BIDIR, True) def testStimulatedOscillatorGridFourStructureByCore(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.GRID_FOUR, True) def testStimulatedOscillatorGridEightStructureByCore(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.GRID_EIGHT, True) def testStimulatedOscillatorAllToAllStructureByCore(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.ALL_TO_ALL, True) def testSyncEnsembleAllocationOneStimulatedOscillatorByCore(self): params = legion_parameters() params.teta = 0 # due to no neighbors LegionTestTemplates.templateSyncEnsembleAllocation([1], params, conn_type.NONE, 2000, 500, [[0]], True) def testSyncEnsembleAllocationThreeStimulatedOscillatorsByCore(self): LegionTestTemplates.templateSyncEnsembleAllocation([1, 1, 1], None, conn_type.LIST_BIDIR, 1500, 1500, [[0, 1, 2]], True) def testSyncEnsembleAllocationThreeMixStimulatedOscillatorsByCore(self): parameters = legion_parameters() parameters.Wt = 4.0 LegionTestTemplates.templateSyncEnsembleAllocation([1, 0, 1], None, conn_type.LIST_BIDIR, 1500, 1500, [[0, 2], [1]], True) def testOutputDynamicInformationByCore(self): LegionTestTemplates.templateOutputDynamicInformation([1, 0, 1], legion_parameters(), conn_type.LIST_BIDIR, 100, 100, True) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.LIST_BIDIR, True) pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_pcnn.py000077500000000000000000000076321375753423500256770ustar00rootroot00000000000000"""! @brief Integration-tests for Pulse Coupled Neural Network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from pyclustering.nnet.tests.pcnn_templates import PcnnTestTemplates; from pyclustering.nnet import conn_type, conn_represent; from pyclustering.core.tests import remove_library; class PcnnIntegrationTest(unittest.TestCase): def testDynamicLengthNoneConnectionByCore(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.NONE, None, [0] * 10, True); def testDynamicLengthGridFourConnectionByCore(self): PcnnTestTemplates.templateDynamicLength(25, 20, conn_type.GRID_FOUR, None, [0] * 25, True); def testDynamicLengthGridEightConnectionByCore(self): PcnnTestTemplates.templateDynamicLength(25, 20, conn_type.GRID_EIGHT, None, [0] * 25, True); def testDynamicLengthListBidirConnectionByCore(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.LIST_BIDIR, None, [0] * 10, True); def testDynamicLengthAllToAllConnectionByCore(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.ALL_TO_ALL, None, [0] * 10, True); def testDynamicLengthGridRectangle25FourConnectionByCore(self): PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_FOUR, None, 1, 25, [0] * 25, True); PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_FOUR, None, 25, 1, [0] * 25, True); def testDynamicLengthGridRectangle25EightConnectionByCore(self): PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_EIGHT, None, 1, 25, [0] * 25, True); PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_EIGHT, None, 25, 1, [0] * 25, True); def testSyncEnsemblesAllStimulatedByCore(self): PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 20, [1] * 25, True, [ list(range(25)) ]); def testSyncEnsemblesAllUnstimulatedByCore(self): PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 20, [0] * 25, True, []); def testSyncEnsemblesPartialStimulationByCore(self): stimulus = ([0] * 5) + ([1] * 5) + ([0] * 5) + ([1] * 5) + ([0] * 5); expected_ensemble = [5, 6, 7, 8, 9, 15, 16, 17, 18, 19]; PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 20, stimulus, True, [ expected_ensemble ]); def testSyncEnsemblesAllStimulatedWithVariousConnectionByCore(self): PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 50, [20] * 25, True, None); PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.GRID_EIGHT, 50, [20] * 25, True, None); PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.GRID_FOUR, 50, [20] * 25, True, None); PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.LIST_BIDIR, 50, [20] * 25, True, None); PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.NONE, 50, [20] * 25, True, None); def testAllocationInRectangleFourStructureByCore(self): PcnnTestTemplates.templateAllocationInRectangleStructure(20, 4, 5, 20, conn_type.GRID_FOUR, None, [0] * 20, True); def testAllocationInRectangleEightStructureByCore(self): PcnnTestTemplates.templateAllocationInRectangleStructure(30, 6, 5, 20, conn_type.GRID_EIGHT, None, [0] * 30, True); def testVisualizerNoFailureByCore(self): stimulus = [ 5, 5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20 ]; PcnnTestTemplates.visualize(16, 20, conn_type.ALL_TO_ALL, conn_represent.MATRIX, stimulus, 4, 4, True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.NONE, None, [0] * 10, True); pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_som.py000077500000000000000000000221771375753423500255400ustar00rootroot00000000000000"""! @brief Integration-tests for self-organized feature map. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.tests.som_templates import SomTestTemplates from pyclustering.nnet.som import som, type_conn, type_init, som_parameters from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES from pyclustering.core.tests import remove_library class SomIntegrationTest(unittest.TestCase): def testTwoNeuronsTwoClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], False, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], False, True) def testTwoNeuronsTwoClustersByCoreStoreLoad(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], False, True, store_load=True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], False, True, store_load=True) def testAutostopTwoNeuronsTwoClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], True, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], True, True) def testAutostopTwoNeuronsTwoClustersByCoreStoreLoad(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], True, True, store_load=True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], True, True, store_load=True) def testThreeNeuronsThreeClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 100, [5, 8, 10], False, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1, 100, [5, 8, 10], False, True) def testAutostopThreeNeuronsThreeClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 100, [5, 8, 10], True, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1, 100, [5, 8, 10], True, True) def testFourNeuronsFourClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 100, [10, 10, 10, 30], False, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 2, 100, [10, 10, 10, 30], False, True) def testAutostopFourNeuronsFourClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 100, [10, 10, 10, 30], True, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 2, 100, [10, 10, 10, 30], True, True) def testTwoNeuronsFourClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 2, 100, [30, 30], False, True) def testAutostopTwoNeuronsFourClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 2, 100, [30, 30], True, True) def testSevenNeuronsHeptaClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 7, 100, [30, 30, 30, 30, 30, 30, 32], False, True) def testAutostopSevenNeuronsHeptaClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 7, 100, [30, 30, 30, 30, 30, 30, 32], True, True) def testFourNeuronsTetraClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TETRA, 1, 4, 100, [100, 100, 100, 100], False, True) def testAutostopFourNeuronsTetraClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TETRA, 1, 4, 100, [100, 100, 100, 100], True, True) def testTwoNeuronsTwoDiamondsClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1, 2, 100, [400, 400], False, True) def testAutostopTwoNeuronsTwoDiamondsClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1, 2, 100, [400, 400], True, True) def testFiveNeuronsFiveClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 100, [15, 15, 15, 15, 15], False, True) def testAutostopFiveNeuronsFiveClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 100, [15, 15, 15, 15, 15], True, True) def testFourNeuronsSquareClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 2, 2, 100, [15, 15, 15, 15], False, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 100, [15, 15, 15, 15], False, True) def testAutostopFourNeuronsSquareClustersByCore(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 2, 2, 100, [15, 15, 15, 15], True, True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 100, [15, 15, 15, 15], True, True) def testOneDimensionSampleSimple7ClusterByCore(self): parameters = som_parameters() parameters.init_type = type_init.random_surface SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1, 100, [10, 10], True, True, parameters) def testWinnersByCore(self): SomTestTemplates.templateTestWinners(True) def testSomVisualizationByCore(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4) parameters = som_parameters() network = som(5, 5, type_conn.grid_eight, parameters, ccore = True) network.train(sample, 100, True) network.show_network() network.show_winner_matrix() network.show_distance_matrix() network.show_density_matrix() def testSimulateCheckWinnerFuncNeighborByCore(self): SomTestTemplates.templateTestSimulate(type_conn.func_neighbor, True) def testSimulateCheckWinnerFuncNeighborByCoreStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.func_neighbor, True, store_load=True) def testSimulateCheckWinnerGridFourByCore(self): SomTestTemplates.templateTestSimulate(type_conn.grid_four, True) def testSimulateCheckWinnerGridFourByCoreStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.grid_four, True, store_load=True) def testSimulateCheckWinnerGridEightByCore(self): SomTestTemplates.templateTestSimulate(type_conn.grid_eight, True) def testSimulateCheckWinnerGridEightByCoreStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.grid_eight, True, store_load=True) def testSimulateCheckWinnerHoneycombByCore(self): SomTestTemplates.templateTestSimulate(type_conn.honeycomb, True) def testSimulateCheckWinnerHoneycombByCoreStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.honeycomb, True, store_load=True) def testNetwork2x2RandomState5ByCore(self): SomTestTemplates.random_state(2, 2, type_conn.honeycomb, 5, True) def testNetwork2x2RandomState5FuncNeighborByCore(self): SomTestTemplates.random_state(2, 2, type_conn.func_neighbor, 5, True) def testNetwork2x2RandomState10ByCore(self): SomTestTemplates.random_state(2, 2, type_conn.honeycomb, 10, True) def testNetwork2x2RandomState10FuncNeighborByCore(self): SomTestTemplates.random_state(2, 2, type_conn.func_neighbor, 10, True) def testNetwork2x3RandomState5ByCore(self): SomTestTemplates.random_state(2, 3, type_conn.honeycomb, 5, True) def testNetwork2x3RandomState10ByCore(self): SomTestTemplates.random_state(2, 3, type_conn.honeycomb, 10, True) def testNetwork1x8RandomState5ByCore(self): SomTestTemplates.random_state(1, 8, type_conn.honeycomb, 5, True) def testNetwork1x8RandomState10ByCore(self): SomTestTemplates.random_state(1, 8, type_conn.honeycomb, 10, True) def testNetwork1x8GridFourByCore(self): SomTestTemplates.random_state(1, 8, type_conn.grid_four, 5, True) SomTestTemplates.random_state(8, 1, type_conn.grid_four, 5, True) def testNetwork1x8GridEightByCore(self): SomTestTemplates.random_state(1, 8, type_conn.grid_eight, 5, True) SomTestTemplates.random_state(8, 1, type_conn.grid_eight, 5, True) def testNetwork1x8FuncNeughborByCore(self): SomTestTemplates.random_state(1, 8, type_conn.func_neighbor, 5, True) SomTestTemplates.random_state(8, 1, type_conn.func_neighbor, 5, True) @remove_library def testProcessingWhenLibraryCoreCorrupted(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], False, True) pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_sync.py000077500000000000000000000061461375753423500257140ustar00rootroot00000000000000"""! @brief Integration-tests for Oscillatory Neural Network based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet.tests.sync_templates import SyncTestTemplates; from pyclustering.nnet import conn_type, solve_type; from pyclustering.nnet.sync import sync_network; from pyclustering.core.tests import remove_library; class SyncIntegrationTest(unittest.TestCase): def testCreateNetworkByCore(self): SyncTestTemplates.templateCreateNetwork(1, True); SyncTestTemplates.templateCreateNetwork(10, True); SyncTestTemplates.templateCreateNetwork(55, True); def testCreationDeletionByCore(self): # Crash occurs in case of memory leak for _ in range(0, 15): network = sync_network(4096, 1, type_conn = conn_type.ALL_TO_ALL, ccore = True); del network; def testConnectionsApiByCore(self): SyncTestTemplates.templateConnectionsApi(1, True); SyncTestTemplates.templateConnectionsApi(5, True); SyncTestTemplates.templateConnectionsApi(10, True); def testFastSolutionByCore(self): SyncTestTemplates.templateSimulateTest(10, 1, solve_type.FAST, ccore_flag = True); def testRK4SolutionByCore(self): SyncTestTemplates.templateSimulateTest(10, 1, solve_type.RK4, ccore_flag = True); def testRKF45SolutionByCore(self): SyncTestTemplates.templateSimulateTest(10, 1, solve_type.RKF45, ccore_flag = True); def testTwoOscillatorDynamicByCore(self): SyncTestTemplates.templateDynamicSimulationConvergence(2, 1, conn_type.ALL_TO_ALL, True); def testThreeOscillatorDynamicByCore(self): SyncTestTemplates.templateDynamicSimulationConvergence(3, 1, conn_type.ALL_TO_ALL, True); def testFourOscillatorDynamicByCore(self): SyncTestTemplates.templateDynamicSimulationConvergence(4, 1, conn_type.ALL_TO_ALL, True); def testFiveOscillatorDynamicByCore(self): SyncTestTemplates.templateDynamicSimulationConvergence(5, 1, conn_type.ALL_TO_ALL, True); def testSixOscillatorDynamicByCore(self): SyncTestTemplates.templateDynamicSimulationConvergence(6, 1, conn_type.ALL_TO_ALL, True); def testSevenOscillatorDynamicByCore(self): SyncTestTemplates.templateDynamicSimulationConvergence(7, 1, conn_type.ALL_TO_ALL, True); def testOutputDynamicCalculateOrderParameterByCore(self): SyncTestTemplates.templateOutputDynamicCalculateOrderParameter(True); def testOutputDynamicCalculateLocalOrderParameterByCore(self): SyncTestTemplates.templateOutputDynamicCalculateLocalOrderParameter(True); def testVisualizerNoFailuresByCore(self): SyncTestTemplates.templateVisualizerNoFailures(5, 10, True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): SyncTestTemplates.templateSimulateTest(10, 1, solve_type.FAST, ccore_flag = True); pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_syncpr.py000077500000000000000000000061141375753423500262510ustar00rootroot00000000000000"""! @brief Integration-tests for Phase Oscillatory Neural Network for Pattern Recognition based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet.tests.syncpr_templates import SyncprTestTemplates; from pyclustering.nnet import solve_type; from pyclustering.nnet.syncpr import syncpr; from pyclustering.core.tests import remove_library; class SyncprIntegrationTest(unittest.TestCase): def testCreateTenOscillatorsNetworkByCore(self): net = syncpr(10, 0.1, 0.1, True); assert len(net) == 10; def testCreateHundredOscillatorsNetworkByCore(self): net = syncpr(100, 0.1, 0.1, True); assert len(net) == 100; def testOutputDynamicFastSolverByCore(self): SyncprTestTemplates.templateOutputDynamic(solve_type.FAST, True); def testOutputDynamicRK4SolverByCore(self): SyncprTestTemplates.templateOutputDynamic(solve_type.RK4, True); def testOutputDynamicLengthStaticSimulationByCore(self): SyncprTestTemplates.templateOutputDynamicLengthStaticSimulation(True, True); def testOutputDynamicLengthDynamicSimulationByCore(self): SyncprTestTemplates.templateOutputDynamicLengthDynamicSimulation(True, True); def testOutputDynamicLengthDynamicSimulationWithoutCollectingByCore(self): SyncprTestTemplates.templateOutputDynamicLengthDynamicSimulation(False, True); def testTrainNetworkAndRecognizePatternByCore(self): SyncprTestTemplates.templateTrainNetworkAndRecognizePattern(True); def testIncorrectPatternValuesByCore(self): SyncprTestTemplates.templateIncorrectPatternValues(True); def testIncorrectSmallPatternSizeByCore(self): patterns = [ [1, 1, 1, 1, 1, -1] ]; SyncprTestTemplates.templateIncorrectPatternForTraining(patterns, True); def testIncorrectLargePatternSizeByCore(self): patterns = [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1] ]; SyncprTestTemplates.templateIncorrectPatternForTraining(patterns, True); def testPatternVisualizerCollectDynamicByCore(self): SyncprTestTemplates.templatePatternVisualizer(True, True); def testPatternVisualizerWithoutCollectDynamicByCore(self): SyncprTestTemplates.templatePatternVisualizer(False, True); def testMemoryOrderByCore(self): SyncprTestTemplates.templateMemoryOrder(True); def testStaticSimulationByCore(self): SyncprTestTemplates.templateStaticSimulation(True); def testDynamicSimulationByCore(self): SyncprTestTemplates.templateDynamicSimulation(True); def testGlobalSyncOrderByCore(self): SyncprTestTemplates.templateGlobalSyncOrder(True); def testLocalSyncOrderByCore(self): SyncprTestTemplates.templateLocalSyncOrder(True); @remove_library def testProcessingWhenLibraryCoreCorrupted(self): SyncprTestTemplates.templateOutputDynamic(solve_type.FAST, True); pyclustering-0.10.1.2/pyclustering/nnet/tests/integration/it_syncsegm.py000077500000000000000000000033611375753423500265640ustar00rootroot00000000000000"""! @brief Integration-tests for double-layer oscillatory network 'syncsegm' for image segmentation based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.tests.syncsegm_templates import SyncsegmTestTemplates from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES class SyncsegmIntegrationTest(unittest.TestCase): def testImageSegmentationSimple13(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE13, 225, 5, 0, 2, 4, False, True) def testImageSegmentationSimple15(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE15, 225, 6, 0, 2, 3, False, True) def testImageSegmentationSimple16(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE16, 225, 2, 0, 2, 3, True, True) def testImageSegmentationSimple17(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE17, 225, 1, 0, 3, 3, False, True) def testImageSegmentationSimple18(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE18, 225, 1, 0, 2, 3, False, True) def testVisualizeSimple17NoFailure(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE17, 225, 1, 0, 3, 3, False, True) def testVisualizeSimple18NoFailure(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE18, 225, 1, 0, 2, 3, False, True) pyclustering-0.10.1.2/pyclustering/nnet/tests/legion_templates.py000077500000000000000000000034531375753423500252520ustar00rootroot00000000000000"""! @brief Templates for tests of Local Excitatory Global Inhibitory Oscillatory Network (LEGION). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.legion import legion_network; from pyclustering.nnet import conn_type; from pyclustering.utils import extract_number_oscillations; class LegionTestTemplates: @staticmethod def templateOscillationsWithStructures(type_conn, ccore_flag): net = legion_network(4, type_conn = conn_type.LIST_BIDIR, ccore = ccore_flag); dynamic = net.simulate(500, 1000, [1, 1, 1, 1]); for i in range(len(net)): assert extract_number_oscillations(dynamic.output, i) > 1; @staticmethod def templateSyncEnsembleAllocation(stimulus, params, type_conn, sim_steps, sim_time, expected_clusters, ccore_flag): result_testing = False; for _ in range(0, 5, 1): net = legion_network(len(stimulus), params, type_conn, ccore = ccore_flag); dynamic = net.simulate(sim_steps, sim_time, stimulus); ensembles = dynamic.allocate_sync_ensembles(0.1); if (ensembles != expected_clusters): continue; result_testing = True; break; assert result_testing; @staticmethod def templateOutputDynamicInformation(stimulus, params, type_conn, sim_steps, sim_time, ccore_flag): legion_instance = legion_network(len(stimulus), params, type_conn, ccore = ccore_flag); dynamic = legion_instance.simulate(sim_steps, sim_time, stimulus); assert len(dynamic.output) > 0; assert len(dynamic.inhibitor) > 0; assert len(dynamic.time) > 0;pyclustering-0.10.1.2/pyclustering/nnet/tests/pcnn_templates.py000077500000000000000000000105021375753423500247240ustar00rootroot00000000000000"""! @brief Templates for tests of Pulse Coupling Neural Network (PCNN). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ from pyclustering.nnet.pcnn import pcnn_network, pcnn_parameters, pcnn_visualizer; from pyclustering.nnet import conn_represent; class PcnnTestTemplates: @staticmethod def templateDynamicLength(num_osc, steps, type_conn, repr_type, stimulus, ccore, **kwargs): params = kwargs.get('params', None); net = pcnn_network(num_osc, params, type_conn, repr_type, None, None, ccore); dynamic = net.simulate(steps, stimulus); assert steps == len(dynamic); assert num_osc == len(dynamic.output[0]); assert steps == len(dynamic.allocate_time_signal()); return net; @staticmethod def templateDynamicLengthFastLinking(num_osc, steps, type_conn, repr_type, stimulus, ccore): params = pcnn_parameters(); params.FAST_LINKING = True; return PcnnTestTemplates.templateDynamicLength(num_osc, steps, type_conn, repr_type, stimulus, ccore, params=params); @staticmethod def templateGridRectangleDynamicLength(num_osc, steps, type_conn, repr_type, height, width, stimulus, ccore): net = pcnn_network(num_osc, None, type_conn, repr_type, height, width, ccore); dynamic = net.simulate(steps, stimulus); assert steps == len(dynamic); assert num_osc == len(dynamic.output[0]); assert steps == len(dynamic.allocate_time_signal()); @staticmethod def templateSyncEnsemblesAllocation(num_osc, type_conn, steps, stimulus, ccore, ensembles): net = pcnn_network(num_osc, None, type_conn, conn_represent.MATRIX, None, None, ccore); dynamic = net.simulate(steps, stimulus); assert steps == len(dynamic); sync_ensembles = dynamic.allocate_sync_ensembles(); if (ensembles is not None): assert len(ensembles) == len(sync_ensembles); for expected_ensemble in ensembles: ensemble_correct = False; for index_ensemble in range(len(sync_ensembles)): sorted_expected_ensemble = expected_ensemble.sort(); sorted_ensemble = sync_ensembles[index_ensemble].sort(); if (sorted_expected_ensemble == sorted_ensemble): ensemble_correct = True; break; assert (True == ensemble_correct); unique_indexes = set(); time_signal = dynamic.allocate_time_signal(); spike_ensembles = dynamic.allocate_spike_ensembles(); sync_ensembles = dynamic.allocate_sync_ensembles(); for ensemble in spike_ensembles: assert len(ensemble) in time_signal; for ensemble in sync_ensembles: spike_ensembles_exist = False; for index in range(len(spike_ensembles)): if ensemble == spike_ensembles[index]: spike_ensembles_exist = True; break; assert (True == spike_ensembles_exist); for index_oscillator in ensemble: assert index_oscillator not in unique_indexes; unique_indexes.add(index_oscillator); @staticmethod def templateAllocationInRectangleStructure(num_osc, height, width, steps, type_conn, repr_type, stimulus, ccore): net = pcnn_network(num_osc, None, type_conn, repr_type, height, width, ccore); dynamic = net.simulate(steps, stimulus); assert steps == len(dynamic); assert num_osc == len(dynamic.output[0]); assert steps == len(dynamic.allocate_time_signal()); @staticmethod def visualize(num_osc, steps, type_conn, repr_type, stimulus, height, width, ccore): net = pcnn_network(num_osc, None, type_conn, repr_type, None, None, ccore); dynamic = net.simulate(steps, stimulus); pcnn_visualizer.show_time_signal(dynamic); pcnn_visualizer.show_output_dynamic(dynamic); pcnn_visualizer.animate_spike_ensembles(dynamic, (height, width));pyclustering-0.10.1.2/pyclustering/nnet/tests/som_templates.py000077500000000000000000000100741375753423500245700ustar00rootroot00000000000000"""! @brief Templates for tests of Self-Organization Map (SOM). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import pickle import matplotlib matplotlib.use('Agg') from pyclustering.nnet.som import som, type_conn, som_parameters from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES class SomTestTemplates: @staticmethod def templateTestAwardNeurons(file, rows, cols, time, expected_result, autostop, ccore_flag, parameters = None, **kwargs): store_load = kwargs.get('store_load', False) types = [type_conn.func_neighbor, type_conn.grid_eight, type_conn.grid_four, type_conn.honeycomb] sample = read_sample(file) if parameters is None: parameters = som_parameters() for structure in types: network = som(rows, cols, structure, parameters, ccore=ccore_flag) if store_load: dump_network = pickle.dumps(network) network = pickle.loads(dump_network) network.train(sample, time, autostop) winners = network.get_winner_number() assert winners == len(expected_result) if sorted(network.awards) != expected_result: network.show_network(awards=True) assert sorted(network.awards) == expected_result total_capture_points = 0 for points in network.capture_objects: total_capture_points += len(points) assert total_capture_points == sum(expected_result) del network @staticmethod def templateTestWinners(ccore_flag): types = [type_conn.func_neighbor, type_conn.grid_eight, type_conn.grid_four, type_conn.honeycomb] sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3) for stucture in types: network = som(5, 5, stucture, ccore=ccore_flag) network.train(sample, 100) assert sum(network.awards) == 60 points = list() for i in range(network.size): if network.awards[i] > 0: points += network.capture_objects[i] assert len(points) == len(sample) points = sorted(points) for i in range(len(points)): assert points[i] == i @staticmethod def templateTestSimulate(connections, ccore_flag, **kwargs): store_load = kwargs.get('store_load', False) sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) network = som(1, 2, connections, ccore=ccore_flag) network.train(sample, 100) if store_load: dump_network = pickle.dumps(network) network = pickle.loads(dump_network) expected_winners = [0, 1] for i in range(len(sample)): index_winner = network.simulate(sample[i]) if (i == 0) and (index_winner == 1): expected_winners = [1, 0] if i < 5: assert expected_winners[0] == index_winner else: assert expected_winners[1] == index_winner @staticmethod def random_state(rows, cols, connections, random_state, ccore_flag): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) params = som_parameters() params.random_state = random_state network_1 = som(rows, cols, connections, ccore=ccore_flag) steps_1 = network_1.train(sample, 100, True) network_2 = som(rows, cols, connections, ccore=ccore_flag) steps_2 = network_2.train(sample, 100, True) assert steps_1 == steps_2 assert network_1.weights == network_2.weights assert network_1.capture_objects == network_2.capture_objects assert network_1.awards == network_2.awards pyclustering-0.10.1.2/pyclustering/nnet/tests/sync_templates.py000077500000000000000000000121711375753423500247460ustar00rootroot00000000000000"""! @brief Templates for tests of Sync (oscillatory network based on Kuramoto model). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet import conn_type, solve_type, initial_type; from pyclustering.nnet.sync import sync_network, sync_visualizer; class SyncTestTemplates: @staticmethod def templateCreateNetwork(size, ccore_flag): network = sync_network(size, 1, ccore = ccore_flag); assert len(network) == size; @staticmethod def templateConnectionsApi(size, ccore_flag): network = sync_network(size, 1, type_conn = conn_type.ALL_TO_ALL, ccore = ccore_flag); for i in range(len(network)): for j in range(len(network)): if (i != j): assert network.has_connection(i, j) == True; assert len(network.get_neighbors(i)) == size - 1, str(network.get_neighbors(i)); assert len(network.get_neighbors(j)) == size - 1; @staticmethod def templateSimulateTest(nodes, weight, solution, ccore_flag): sim_time = 20; sim_steps = 50; tolerance = 0.01; network = sync_network(nodes, weight, ccore = ccore_flag); output_dynamic = network.simulate(sim_steps, sim_time, solution); dyn_phase = output_dynamic.output; index = len(dyn_phase) - 1; value = dyn_phase[index][0]; for item in dyn_phase[index]: if ((abs(item - value) < tolerance) != True): print(dyn_phase[:][0]); assert (abs(item - value) < tolerance) == True; @staticmethod def templateDynamicSimulationConnectionTypeTest(num_osc, weight, connection_type, ccore_flag): testing_result = False; for _ in range(3): network = sync_network(num_osc, weight, type_conn = connection_type, ccore = ccore_flag); output_dynamic = network.simulate_dynamic(collect_dynamic = False); # Just current state of network is required clusters = output_dynamic.allocate_sync_ensembles(0.1); if (len(clusters) != 1): continue; testing_result = True; break; assert testing_result == True; @staticmethod def templateDynamicSimulationConvergence(num_osc, weight, connection_type, ccore_flag): network = sync_network(num_osc, weight, type_conn = connection_type, initial_phases=initial_type.EQUIPARTITION, ccore = ccore_flag); output_dynamic = network.simulate_dynamic(collect_dynamic = False); # Just current state of network is required clusters = output_dynamic.allocate_sync_ensembles(0.1); assert len(clusters) == 1; @staticmethod def templateOutputDynamicCalculateOrderParameter(ccore_flag): net = sync_network(5, ccore = ccore_flag); output_dynamic = net.simulate_static(20, 10, solution = solve_type.FAST, collect_dynamic = True); assert len(output_dynamic.calculate_order_parameter(0, 20)) == 20; assert len(output_dynamic.calculate_order_parameter()) == 1; assert len(output_dynamic.calculate_order_parameter(5)) == 1; assert len(output_dynamic.calculate_order_parameter(5, 10)) == 5; assert output_dynamic.calculate_order_parameter(20)[0] > 0.9; @staticmethod def templateOutputDynamicCalculateLocalOrderParameter(ccore_flag): net = sync_network(5, ccore = ccore_flag); output_dynamic = net.simulate_static(20, 10, solution = solve_type.FAST, collect_dynamic = True); assert len(output_dynamic.calculate_local_order_parameter(net, 0, 20)) == 20; assert len(output_dynamic.calculate_local_order_parameter(net)) == 1; assert len(output_dynamic.calculate_local_order_parameter(net, 5)) == 1; assert len(output_dynamic.calculate_local_order_parameter(net, 5, 10)) == 5; assert output_dynamic.calculate_local_order_parameter(net, 20)[0] > 0.9; @staticmethod def templateVisualizerNoFailures(size, velocity, ccore_flag): net = sync_network(size, ccore = ccore_flag); output_dynamic = net.simulate_dynamic(solution = solve_type.FAST, collect_dynamic = True); sync_visualizer.animate(output_dynamic); sync_visualizer.animate_correlation_matrix(output_dynamic, velocity); sync_visualizer.animate_output_dynamic(output_dynamic, velocity); sync_visualizer.animate_phase_matrix(output_dynamic, 1, size, velocity); sync_visualizer.show_correlation_matrix(output_dynamic); sync_visualizer.show_output_dynamic(output_dynamic); sync_visualizer.show_phase_matrix(output_dynamic, 1, size); sync_visualizer.show_order_parameter(output_dynamic); sync_visualizer.show_local_order_parameter(output_dynamic, net); pyclustering-0.10.1.2/pyclustering/nnet/tests/syncpr_templates.py000077500000000000000000000147761375753423500253250ustar00rootroot00000000000000"""! @brief Templates for tests of SyncPR (oscillatory network based on Kuramoto model for pattern recognition). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet import solve_type; from pyclustering.nnet.syncpr import syncpr, syncpr_visualizer; class SyncprTestTemplates: @staticmethod def templateOutputDynamic(solver, ccore): net = syncpr(5, 0.1, 0.1, ccore); output_dynamic = net.simulate(10, 10, [-1, 1, -1, 1, -1], solver, True); assert len(output_dynamic) == 11; # 10 steps without initial values. @staticmethod def templateOutputDynamicLengthStaticSimulation(collect_flag, ccore_flag): net = syncpr(5, 0.1, 0.1, ccore_flag); output_dynamic = net.simulate_static(10, 10, [-1, 1, -1, 1, -1], solution = solve_type.FAST, collect_dynamic = collect_flag); if (collect_flag is True): assert len(output_dynamic) == 11; # 10 steps without initial values. else: assert len(output_dynamic) == 1; @staticmethod def templateOutputDynamicLengthDynamicSimulation(collect_flag, ccore_flag): net = syncpr(5, 0.1, 0.1, ccore_flag); output_dynamic = net.simulate_dynamic([-1, 1, -1, 1, -1], solution = solve_type.FAST, collect_dynamic = collect_flag); if (collect_flag is True): assert len(output_dynamic) > 1; else: assert len(output_dynamic) == 1; @staticmethod def templateIncorrectPatternForSimulation(pattern, ccore_flag): net = syncpr(10, 0.1, 0.1, ccore=ccore_flag); try: net.simulate(10, 10, pattern); except: return; assert False; @staticmethod def templateTrainNetworkAndRecognizePattern(ccore_flag): net = syncpr(10, 0.1, 0.1, ccore_flag); patterns = []; patterns += [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1] ]; net.train(patterns); # recognize it for i in range(len(patterns)): output_dynamic = net.simulate(10, 10, patterns[i], solve_type.RK4, True); ensembles = output_dynamic.allocate_sync_ensembles(0.5); assert len(ensembles) == 2; assert len(ensembles[0]) == len(ensembles[1]); # sort results ensembles[0].sort(); ensembles[1].sort(); assert (ensembles[0] == [0, 1, 2, 3, 4]) or (ensembles[0] == [5, 6, 7, 8, 9]); assert (ensembles[1] == [0, 1, 2, 3, 4]) or (ensembles[1] == [5, 6, 7, 8, 9]); @staticmethod def templateIncorrectPatternForTraining(patterns, ccore_flag): net = syncpr(10, 0.1, 0.1, ccore_flag); try: net.train(patterns); except: return; assert False; @staticmethod def templatePatternVisualizer(collect_dynamic, ccore_flag = False): net = syncpr(5, 0.1, 0.1, ccore = ccore_flag); output_dynamic = net.simulate(10, 10, [-1, 1, -1, 1, -1], solve_type.RK4, collect_dynamic); syncpr_visualizer.show_pattern(output_dynamic, 5, 2); syncpr_visualizer.animate_pattern_recognition(output_dynamic, 1, 5); @staticmethod def templateMemoryOrder(ccore_flag): net = syncpr(10, 0.1, 0.1, ccore_flag); patterns = []; patterns += [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1] ]; net.train(patterns); assert net.memory_order(patterns[0]) < 0.8; assert net.memory_order(patterns[1]) < 0.8; for pattern in patterns: net.simulate(20, 10, pattern, solve_type.RK4); memory_order = net.memory_order(pattern); assert (memory_order > 0.95) and (memory_order <= 1.000005); @staticmethod def templateStaticSimulation(ccore_falg): net = syncpr(10, 0.1, 0.1, ccore_falg); patterns = []; patterns += [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1] ]; net.train(patterns); net.simulate_static(20, 10, patterns[0], solve_type.RK4); memory_order = net.memory_order(patterns[0]); assert (memory_order > 0.95) and (memory_order <= 1.000005); @staticmethod def templateDynamicSimulation(ccore_flag): net = syncpr(10, 0.1, 0.1, ccore_flag); patterns = []; patterns += [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1] ]; net.train(patterns); net.simulate_dynamic(patterns[0], order = 0.998, solution = solve_type.RK4); memory_order = net.memory_order(patterns[0]); assert (memory_order > 0.998) and (memory_order <= 1.0); @staticmethod def templateGlobalSyncOrder(ccore_flag): net = syncpr(10, 0.1, 0.1, ccore_flag); patterns = [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1] ]; global_sync_order = net.sync_order(); assert (global_sync_order < 1.0) and (global_sync_order > 0.0); net.train(patterns); global_sync_order = net.sync_order(); assert (global_sync_order < 1.0) and (global_sync_order > 0.0); @staticmethod def templateLocalSyncOrder(ccore_flag): net = syncpr(10, 0.1, 0.1, ccore_flag); patterns = [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1] ]; local_sync_order = net.sync_local_order(); assert (local_sync_order < 1.0) and (local_sync_order > 0.0); net.train(patterns); local_sync_order = net.sync_local_order(); assert (local_sync_order < 1.0) and (local_sync_order > 0.0); @staticmethod def templateIncorrectPatternValues(ccore_flag): patterns = []; patterns += [ [2, 1, 1, 1, 1, -1, -1, -1, -1, -1] ]; patterns += [ [-1, -2, -1, -1, -1, 1, 1, 1, 1, 1] ]; SyncprTestTemplates.templateIncorrectPatternForTraining(patterns, ccore_flag);pyclustering-0.10.1.2/pyclustering/nnet/tests/syncsegm_templates.py000077500000000000000000000044731375753423500256300ustar00rootroot00000000000000"""! @brief Templates for tests of SyncPR (oscillatory network based on Kuramoto model for pattern recognition). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.assertion import assertion from pyclustering.nnet.syncsegm import syncsegm, syncsegm_visualizer from pyclustering.utils import draw_image_mask_segments class SyncsegmTestTemplates: @staticmethod def templateSyncsegmSegmentation(image_source, radius_color, radius_object, noise_size, expected_color_segments, expected_object_segments, collect_dynamic, ccore_flag): result_testing = False color_segments, object_segments = [], [] for _ in range(0, 10, 1): algorithm = syncsegm(radius_color, radius_object, noise_size, ccore=ccore_flag) analyser = algorithm.process(image_source, collect_dynamic, 0.9995, 0.9995) color_segments = analyser.allocate_colors() object_segments = analyser.allocate_objects(0.2) if (len(color_segments) != expected_color_segments) or (len(object_segments) != expected_object_segments): continue result_testing = True break assertion.eq(expected_color_segments, len(color_segments)) assertion.eq(expected_object_segments, len(object_segments)) assertion.true(result_testing) @staticmethod def templateSyncsegmVisulizationNoFailure(image_source, radius_color, radius_object, noise_size, expected_color_segments, expected_object_segments, collect_dynamic, ccore_flag): algorithm = syncsegm(radius_color, radius_object, noise_size, ccore=ccore_flag) analyser = algorithm.process(image_source, collect_dynamic, 0.9995, 0.9995) color_segments = analyser.allocate_colors(0.01, noise_size) draw_image_mask_segments(image_source, color_segments) object_segments = analyser.allocate_objects(0.01, noise_size) draw_image_mask_segments(image_source, object_segments) syncsegm_visualizer.show_first_layer_dynamic(analyser) syncsegm_visualizer.show_second_layer_dynamic(analyser)pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/000077500000000000000000000000001375753423500223145ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/__init__.py000077500000000000000000000052441375753423500244350ustar00rootroot00000000000000"""! @brief Unit-test runner for tests of oscillatory and neural networks. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.tests.suite_holder import suite_holder # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.tests.unit import ut_cnn as nnet_cnn_unit_tests from pyclustering.nnet.tests.unit import ut_dynamic_visualizer as nnet_dynamic_visualizer_unit_tests from pyclustering.nnet.tests.unit import ut_fsync as nnet_fsync_unit_tests from pyclustering.nnet.tests.unit import ut_hhn as nnet_hhn_unit_tests from pyclustering.nnet.tests.unit import ut_hysteresis as nnet_hysteresis_unit_tests from pyclustering.nnet.tests.unit import ut_legion as nnet_legion_unit_tests from pyclustering.nnet.tests.unit import ut_nnet as nnet_network_unit_tests from pyclustering.nnet.tests.unit import ut_pcnn as nnet_pcnn_unit_tests from pyclustering.nnet.tests.unit import ut_som as nnet_som_unit_tests from pyclustering.nnet.tests.unit import ut_sync as nnet_sync_unit_tests from pyclustering.nnet.tests.unit import ut_syncpr as nnet_syncpr_unit_tests from pyclustering.nnet.tests.unit import ut_syncsegm as nnet_syncsegm_unit_tests class nnet_unit_tests(suite_holder): def __init__(self): super().__init__() nnet_unit_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(unit_nnet_suite): unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_cnn_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_dynamic_visualizer_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_fsync_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_hhn_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_hysteresis_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_legion_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_network_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_pcnn_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_som_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_sync_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_syncpr_unit_tests)) unit_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(nnet_syncsegm_unit_tests)) pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_cnn.py000077500000000000000000000111461375753423500241620ustar00rootroot00000000000000"""! @brief Unit-tests for chaotic neural network (CNN). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.cnn import type_conn, cnn_network, cnn_visualizer from pyclustering.samples.definitions import SIMPLE_SAMPLES from pyclustering.utils import read_sample class CnnUnitTest(unittest.TestCase): def templateSyncEnsembleAllocation(self, stimulus, steps, connection, amount_neighbors, analysed_iterations, expected_length_ensembles): testing_result = True; for _ in range(3): network_instance = cnn_network(len(stimulus), connection, amount_neighbors); assert len(stimulus) == len(network_instance); output_dynamic = network_instance.simulate(steps, stimulus); ensembles = output_dynamic.allocate_sync_ensembles(analysed_iterations); obtained_ensemble_sizes = [len(ensemble) for ensemble in ensembles]; # critical checks - always determined assert len(stimulus) == len(network_instance); assert len(stimulus) == sum(obtained_ensemble_sizes); if (expected_length_ensembles != None): obtained_ensemble_sizes.sort(); expected_length_ensembles.sort(); if (obtained_ensemble_sizes != expected_length_ensembles): continue; assert testing_result == True; def testClusteringPhenomenonSimpleSample01(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.ALL_TO_ALL, 3, 10, [5, 5]); def testGlobalSynchronizationSimpleSample01(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.ALL_TO_ALL, 9, 10, [10]); def testDelaunayTriangulationSimpleSample01(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.TRIANGULATION_DELAUNAY, 3, 10, None); def testClusteringPhenomenonSimpleSample02(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.ALL_TO_ALL, 3, 10, [10, 5, 8]); def testGlobalSynchronizationSimpleSample02(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.ALL_TO_ALL, 22, 10, [10, 5, 8]); def testDelaunayTriangulationSimpleSample02(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE2); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.TRIANGULATION_DELAUNAY, 22, 10, None); def testClusteringPhenomenonSimpleSample03(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE3); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.ALL_TO_ALL, 3, 10, [10, 10, 10, 30]); def testClusteringPhenomenonSimpleSample04(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE4); self.templateSyncEnsembleAllocation(stimulus, 200, type_conn.ALL_TO_ALL, 10, 10, [15, 15, 15, 15, 15]); def testClusteringPhenomenonSimpleSample05(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE5); self.templateSyncEnsembleAllocation(stimulus, 100, type_conn.ALL_TO_ALL, 5, 10, [15, 15, 15, 15]); def testChaoticNeuralNetwork2DVisualization(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); network_instance = cnn_network(len(stimulus)); output_dynamic = network_instance.simulate(100, stimulus); network_instance.show_network(); cnn_visualizer.show_dynamic_matrix(output_dynamic); cnn_visualizer.show_observation_matrix(output_dynamic); cnn_visualizer.show_output_dynamic(output_dynamic); def testChaoticNeuralNetwork3DVisualization(self): stimulus = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE11); network_instance = cnn_network(len(stimulus)); output_dynamic = network_instance.simulate(10, stimulus); network_instance.show_network(); cnn_visualizer.show_dynamic_matrix(output_dynamic); cnn_visualizer.show_observation_matrix(output_dynamic); cnn_visualizer.show_output_dynamic(output_dynamic); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_dynamic_visualizer.py000077500000000000000000000052511375753423500273050ustar00rootroot00000000000000"""! @brief Unit-tests for basic dynamic visualizer. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet.dynamic_visualizer import dynamic_visualizer; class DynamicVisualizerUnitTest(unittest.TestCase): def testVisualizeSignleDynamicNoCrash(self): t = [0, 1, 2, 3, 4, 5, 6, 7]; y = [0, 0, 1, 2, 0, 1, 2, 0]; visualizer = dynamic_visualizer(1); visualizer.append_dynamic(t, y); def testVisualizeMultipleDynamicNoCrash(self): t = [0, 1, 2, 3, 4, 5, 6, 7]; y = [ [0, 0], [0, 0], [1, 0], [2, 1], [0, 2], [1, 0], [2, 1], [0, 2] ]; visualizer = dynamic_visualizer(1); visualizer.append_dynamics(t, y); def testVisualizeSeparateSequenceNoCrash(self): t = [0, 1, 2, 3, 4, 5, 6, 7]; y = [ [0, 0], [0, 0], [1, 0], [2, 1], [0, 2], [1, 0], [2, 1], [0, 2] ]; visualizer = dynamic_visualizer(2); visualizer.append_dynamics(t, y, canvas=0, separate=True); def testVisualizeSeparateListNoCrash(self): t = [0, 1, 2, 3, 4, 5, 6, 7]; y = [ [0, 0], [0, 0], [1, 0], [2, 1], [0, 2], [1, 0], [2, 1], [0, 2] ]; visualizer = dynamic_visualizer(2); visualizer.append_dynamics(t, y, canvas=0, separate=[ [0], [1] ]); def testVisualizeSeveralDynamicsOneCanvasNoCrash(self): t1 = [0, 1, 2, 3, 4, 5, 6, 7]; y1 = [0, 0, 1, 2, 0, 1, 2, 0]; t2 = [0, 1, 2, 3, 4, 5, 6, 7]; y2 = [ [0, 0], [0, 0], [1, 0], [2, 1], [0, 2], [1, 0], [2, 1], [0, 2] ]; visualizer = dynamic_visualizer(1); visualizer.append_dynamic(t1, y1); visualizer.append_dynamics(t2, y2); def testVisualizeSeveralDynamicsSeveralCanvasesNoCrash(self): t1 = [0, 1, 2, 3, 4, 5, 6, 7]; y1 = [0, 0, 1, 2, 0, 1, 2, 0]; t2 = [0, 1, 2, 3, 4, 5, 6, 7]; y2 = [ [0, 0], [0, 0], [1, 0], [2, 1], [0, 2], [1, 0], [2, 1], [0, 2] ]; visualizer = dynamic_visualizer(3); visualizer.append_dynamic(t1, y1, canvas=0); visualizer.append_dynamics(t2, y2, canvas=1, separate=True); def testVisualizeDynamicWithColorNoCrash(self): t = [0, 1, 2, 3, 4, 5, 6, 7]; y = [0, 0, 1, 2, 0, 1, 2, 0]; visualizer = dynamic_visualizer(1); visualizer.append_dynamic(t, y, canvas=0, color='red'); def testVisualizeUnusedCanvasesNoCrash(self): t = [0, 1, 2, 3, 4, 5, 6, 7]; y = [0, 0, 1, 2, 0, 1, 2, 0]; visualizer = dynamic_visualizer(3); visualizer.append_dynamic(t, y, canvas=0, color='red');pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_fsync.py000077500000000000000000000151631375753423500245310ustar00rootroot00000000000000"""! @brief Unit-tests for Oscillatory Neural Network based on Kuramoto model and Landau-Stuart. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet import conn_type, conn_represent; from pyclustering.nnet.fsync import fsync_network, fsync_visualizer; class FsyncUnitTest(unittest.TestCase): def templateCreateNetwork(self, network_size): oscillatory_network = fsync_network(network_size); assert len(oscillatory_network) == network_size; def testCreateNetworkSize1(self): self.templateCreateNetwork(1); def testCreateNetworkSize20(self): self.templateCreateNetwork(20); def testCreateNetworkSize100(self): self.templateCreateNetwork(100); def templateSimulateStaticOutputDynamic(self, num_osc, steps, time, collect_dynamic): oscillatory_network = fsync_network(num_osc); output_dynamic = oscillatory_network.simulate(steps, time, collect_dynamic); if (collect_dynamic is True): assert len(output_dynamic) == steps + 1; assert output_dynamic.time[0] == 0; else: assert len(output_dynamic) == 1; assert output_dynamic.time[len(output_dynamic) - 1] == time; def testSimulateStatic10StepsTime10(self): self.templateSimulateStaticOutputDynamic(10, 10, 10, True); def testSimulateStatic100StepsTime10(self): self.templateSimulateStaticOutputDynamic(3, 100, 10, True); def testSimulateStatic100StepsTime1(self): self.templateSimulateStaticOutputDynamic(3, 100, 1, True); def testSimulateStatic50StepsTime10WithoutCollecting(self): self.templateSimulateStaticOutputDynamic(3, 50, 10, False); def testSimulateStatic100StepsTime10WithoutCollecting(self): self.templateSimulateStaticOutputDynamic(1, 100, 10, False); def templateGlobalSynchronization(self, size, steps, time, frequency, radius, coupling, amplitude_threshold, connections, representation): oscillatory_network = fsync_network(size, frequency, radius, coupling, connections, representation); output_dynamic = oscillatory_network.simulate(steps, time, True); for index_oscillator in range(len(oscillatory_network)): assert output_dynamic.extract_number_oscillations(index_oscillator, amplitude_threshold) > 0; sync_ensembles = output_dynamic.allocate_sync_ensembles(amplitude_threshold); assert len(sync_ensembles) == 1; assert len(sync_ensembles[0]) == size; def testGlobalSyncOneOscillatorAllToAll(self): self.templateGlobalSynchronization(1, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorAllToAll(self): self.templateGlobalSynchronization(5, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncOneOscillatorGridFour(self): self.templateGlobalSynchronization(1, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.GRID_FOUR, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorGridFour(self): self.templateGlobalSynchronization(9, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.GRID_FOUR, conn_represent.MATRIX); def testGlobalSyncOneOscillatorGridEight(self): self.templateGlobalSynchronization(1, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.GRID_EIGHT, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorGridEight(self): self.templateGlobalSynchronization(9, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.GRID_EIGHT, conn_represent.MATRIX); def testGlobalSyncOneOscillatorBidir(self): self.templateGlobalSynchronization(1, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.LIST_BIDIR, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorBidir(self): self.templateGlobalSynchronization(5, 50, 10, 1.0, 1.0, 1.0, 0.8, conn_type.LIST_BIDIR, conn_represent.MATRIX); def testGlobalSyncOneOscillatorDifferentFrequency(self): self.templateGlobalSynchronization(1, 50, 10, [ 1.0 ], 1.0, 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorDifferentFrequency(self): self.templateGlobalSynchronization(5, 100, 20, [ 1.0, 1.1, 1.1, 1.2, 1.15 ], 1.0, 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncOneOscillatorDifferentRadius(self): self.templateGlobalSynchronization(1, 50, 10, 1.0, [ 1.0 ], 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorDifferentRadius(self): self.templateGlobalSynchronization(5, 50, 10, 1.0, [ 1.0, 2.0, 3.0, 4.0, 5.0 ], 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncOneOscillatorDifferentProperty(self): self.templateGlobalSynchronization(1, 50, 10, [ 1.0 ], [ 1.0 ], 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def testGlobalSyncGroupOscillatorDifferentProperty(self): self.templateGlobalSynchronization(5, 100, 20, [ 1.0, 1.1, 1.1, 1.2, 1.15 ], [ 1.0, 2.0, 3.0, 4.0, 5.0 ], 1.0, 0.8, conn_type.ALL_TO_ALL, conn_represent.MATRIX); def templateNoOscillations(self, size, steps, time, frequency, radius, amplitude_threshold): oscillatory_network = fsync_network(size, frequency, radius); output_dynamic = oscillatory_network.simulate(steps, time, True); for index_oscillator in range(len(oscillatory_network)): assert output_dynamic.extract_number_oscillations(index_oscillator, amplitude_threshold) == 0; def testNoOscillationsZeroFrequency(self): self.templateNoOscillations(5, 50, 10, 0.0, 1.0, 0.5); def testNoOscillationsZeroRadius(self): self.templateNoOscillations(5, 50, 10, 1.0, 0.0, 0.5); def testLackCrashGraphics(self): oscillatory_network = fsync_network(5); output_dynamic = oscillatory_network.simulate(50, 10, True); fsync_visualizer.show_output_dynamic(output_dynamic); fsync_visualizer.show_output_dynamics([output_dynamic]); def testLackCrashGraphicsDynamicSet(self): oscillatory_network_1 = fsync_network(2); oscillatory_network_2 = fsync_network(3); output_dynamic_1 = oscillatory_network_1.simulate(50, 10, True); output_dynamic_2 = oscillatory_network_2.simulate(50, 10, True); fsync_visualizer.show_output_dynamics([output_dynamic_1, output_dynamic_2]); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_hhn.py000077500000000000000000000014541375753423500241620ustar00rootroot00000000000000"""! @brief Unit-tests for oscillatory network based on Hodgkin-Huxley model of neuron. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.nnet.tests.hhn_templates import HhnTestTemplates class HhnUnitTest(unittest.TestCase): def testGlobalSyncWithSameStimulus(self): HhnTestTemplates.templateSyncEnsembleAllocation([27, 27, 27], None, 600, 50, [[0, 1, 2]], False); def testGlobalSyncWithVariousStimulus(self): HhnTestTemplates.templateSyncEnsembleAllocation([26, 26, 27, 27, 26, 25], None, 600, 50, [[0, 1, 2, 3, 4, 5]], False); def testPartialSync(self): HhnTestTemplates.templateSyncEnsembleAllocation([25, 25, 50, 50], None, 800, 200, [[0, 1], [2, 3]], False); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_hysteresis.py000077500000000000000000000067331375753423500256140ustar00rootroot00000000000000"""! @brief Unit-tests for Hysteresis Oscillatory Network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from pyclustering.nnet.hysteresis import hysteresis_network; from pyclustering.nnet import *; from pyclustering.utils import extract_number_oscillations; class HysteresisUnitTest(unittest.TestCase): def templateOscillationExistance(self, num_osc, own_weight, neigh_weight, steps, time, initial_states = None, initial_outputs = None, conn_repr = conn_represent.MATRIX): network = hysteresis_network(num_osc, own_weight, neigh_weight, type_conn_represent = conn_repr); if (initial_states is not None): network.states = initial_states; if (initial_outputs is not None): network.outputs = initial_outputs; output_dynamic = network.simulate(steps, time); oscillations = []; for index in range(num_osc): number_oscillations = extract_number_oscillations(output_dynamic.output, index, 0.9); oscillations.append(number_oscillations) assert number_oscillations > 1; def testOscillationsOneOscillator(self): self.templateOscillationExistance(1, -2, -1, 1000, 10); self.templateOscillationExistance(1, -4, -1, 1000, 10); def testOscillationsTwoOscillators(self): self.templateOscillationExistance(2, -4, 1, 1000, 10, [1, 0], [1, 1]); self.templateOscillationExistance(2, -4, -1, 1000, 10, [1, 0], [1, 1]); def testOscillationsFiveOscillators(self): self.templateOscillationExistance(5, -4, -1, 1000, 10, [1, 0.5, 0, -0.5, -1], [1, 1, 1, 1, 1]); def testListConnectionRepresentation(self): self.templateOscillationExistance(1, -2, -1, 1000, 10, conn_repr = conn_represent.LIST); self.templateOscillationExistance(2, -4, -1, 1000, 10, [1, 0], [1, 1], conn_repr = conn_represent.LIST); self.templateOscillationExistance(5, -4, -1, 1000, 10, [1, 0.5, 0, -0.5, -1], [1, 1, 1, 1, 1], conn_repr = conn_represent.LIST); def templateSynchronousEnsemblesAllocation(self, num_osc, own_weight, neigh_weight, steps, time, initial_states, initial_outputs, sync_ensembles_sizes): network = hysteresis_network(num_osc, own_weight, neigh_weight); if (initial_states is not None): network.states = initial_states; if (initial_outputs is not None): network.outputs = initial_outputs; output_dynamic = network.simulate(steps, time, collect_dynamic = True); ensembles = output_dynamic.allocate_sync_ensembles(0.5, 5); assert len(ensembles) == len(sync_ensembles_sizes); obtained_ensembles_sizes = [len(cluster) for cluster in ensembles]; total_length = sum(obtained_ensembles_sizes); assert total_length == len(network); obtained_ensembles_sizes.sort(); sync_ensembles_sizes.sort(); assert obtained_ensembles_sizes == sync_ensembles_sizes; def testOneSyncEnsemblesAllocation(self): self.templateSynchronousEnsemblesAllocation(2, -4, 1, 1000, 10, [1, 0], [1, 1], [2]); def testTwoSyncEnsemblesAllocation(self): self.templateSynchronousEnsemblesAllocation(2, -4, -1, 1000, 10, [1, 0], [1, 1], [1, 1]); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_legion.py000077500000000000000000000102721375753423500246600ustar00rootroot00000000000000"""! @brief Unit-tests for Local Excitatory Global Inhibitory Oscillatory Network (LEGION). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; from pyclustering.nnet.tests.legion_templates import LegionTestTemplates; from pyclustering.nnet.legion import legion_network, legion_parameters; from pyclustering.nnet import conn_type, conn_represent; from pyclustering.utils import extract_number_oscillations; class LegionUnitTest(unittest.TestCase): def testUstimulatedOscillatorWithoutLateralPotential(self): params = legion_parameters(); params.teta = 0; # because no neighbors at all net = legion_network(1, type_conn = conn_type.NONE, parameters = params, ccore = False); dynamic = net.simulate(1000, 200, [0]); assert extract_number_oscillations(dynamic.output, amplitude_threshold = 0.0) == 0; def testStimulatedOscillatorWithoutLateralPotential(self): params = legion_parameters(); params.teta = 0; # because no neighbors at all net = legion_network(1, type_conn = conn_type.NONE, parameters = params, ccore = False); dynamic = net.simulate(2000, 400, [1]); assert extract_number_oscillations(dynamic.output) > 1; def testStimulatedOscillatorWithLateralPotential(self): net = legion_network(1, type_conn = conn_type.NONE, ccore = False); dynamic = net.simulate(2000, 400, [1]); assert extract_number_oscillations(dynamic.output, amplitude_threshold = 0.0) >= 1; def testStimulatedTwoOscillators(self): net = legion_network(2, type_conn = conn_type.LIST_BIDIR, ccore = False); dynamic = net.simulate(1000, 2000, [1, 1]); assert extract_number_oscillations(dynamic.output, 0) > 1; assert extract_number_oscillations(dynamic.output, 1) > 1; def testMixStimulatedThreeOscillators(self): net = legion_network(3, type_conn = conn_type.LIST_BIDIR, ccore = False); dynamic = net.simulate(1000, 2000, [1, 0, 1]); assert extract_number_oscillations(dynamic.output, 0) > 1; assert extract_number_oscillations(dynamic.output, 2) > 1; def testListConnectionRepresentation(self): net = legion_network(3, type_conn = conn_type.LIST_BIDIR, type_conn_represent = conn_represent.LIST, ccore = False); dynamic = net.simulate(1000, 2000, [1, 0, 1]); assert extract_number_oscillations(dynamic.output, 0) > 1; assert extract_number_oscillations(dynamic.output, 2) > 1; def testStimulatedOscillatorListStructure(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.LIST_BIDIR, False); def testStimulatedOscillatorGridFourStructure(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.GRID_FOUR, False); def testStimulatedOscillatorGridEightStructure(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.GRID_EIGHT, False); def testStimulatedOscillatorAllToAllStructure(self): LegionTestTemplates.templateOscillationsWithStructures(conn_type.ALL_TO_ALL, False); def testSyncEnsembleAllocationOneStimulatedOscillator(self): params = legion_parameters(); params.teta = 0; # due to no neighbors LegionTestTemplates.templateSyncEnsembleAllocation([1], params, conn_type.NONE, 2000, 500, [[0]], False); def testSyncEnsembleAllocationThreeStimulatedOscillators(self): LegionTestTemplates.templateSyncEnsembleAllocation([1, 1, 1], None, conn_type.LIST_BIDIR, 1500, 1500, [[0, 1, 2]], False); def testSyncEnsembleAllocationThreeMixStimulatedOscillators(self): parameters = legion_parameters(); parameters.Wt = 4.0; LegionTestTemplates.templateSyncEnsembleAllocation([1, 0, 1], None, conn_type.LIST_BIDIR, 1500, 1500, [[0, 2], [1]], False); def testOutputDynamicInformation(self): LegionTestTemplates.templateOutputDynamicInformation([1, 0, 1], legion_parameters(), conn_type.LIST_BIDIR, 100, 100, False); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_nnet.py000077500000000000000000000412251375753423500243510ustar00rootroot00000000000000"""! @brief Abstract network representation that is used as a basic class. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import math; from pyclustering.nnet import network, conn_type, conn_represent; class NnetUnitTest(unittest.TestCase): # All to All connection suite def templateAllToAllConnectionsTest(self, network): assert network.structure == conn_type.ALL_TO_ALL; for i in range(0, len(network), 1): for j in range(0, len(network), 1): if (i != j): assert network.has_connection(i, j) == True; assert network.has_connection(j, i) == True; else: assert network.has_connection(i, j) == False; assert network.has_connection(j, i) == False; def testAllToAll1Connections(self): net = network(1, type_conn = conn_type.ALL_TO_ALL); self.templateAllToAllConnectionsTest(net); def testAllToAll10Connections(self): net = network(10, type_conn = conn_type.ALL_TO_ALL); self.templateAllToAllConnectionsTest(net); def testAllToAll25Connections(self): net = network(25, type_conn = conn_type.ALL_TO_ALL); self.templateAllToAllConnectionsTest(net); def testAllToAll1ConnectionsListRepresentation(self): net = network(1, type_conn = conn_type.ALL_TO_ALL, conn_repr = conn_represent.LIST); self.templateAllToAllConnectionsTest(net); def testAllToAll10ConnectionsListRepresentation(self): net = network(10, type_conn = conn_type.ALL_TO_ALL, conn_repr = conn_represent.LIST); self.templateAllToAllConnectionsTest(net); def testAllToAll25ConnectionsListRepresentation(self): net = network(25, type_conn = conn_type.ALL_TO_ALL, conn_repr = conn_represent.LIST); self.templateAllToAllConnectionsTest(net); # None connection suite def templateNoneConnectionsTest(self, network): assert network.structure == conn_type.NONE; for i in range(0, len(network), 1): for j in range(0, len(network), 1): assert network.has_connection(i, j) == False; assert network.has_connection(j, i) == False; def testNoneConnections(self): net = network(10, type_conn = conn_type.NONE); self.templateNoneConnectionsTest(net); def testNoneConnectionsListRepresentation(self): net = network(10, type_conn = conn_type.NONE, conn_repr = conn_represent.LIST); self.templateNoneConnectionsTest(net); # Bidirectional list connection suite def templateBidirListConnectionsTest(self, network): assert network.structure == conn_type.LIST_BIDIR; for index in range(0, len(network), 1): if (index > 0): assert network.has_connection(index, index - 1) == True; assert network.has_connection(index - 1, index) == True; if (index < (len(network) - 1)): assert network.has_connection(index, index + 1) == True; assert network.has_connection(index + 1, index) == True; def testBidirListConnections(self): net = network(10, type_conn = conn_type.LIST_BIDIR); self.templateBidirListConnectionsTest(net); def testBidirListConnectionsListRepresentation(self): net = network(10, type_conn = conn_type.LIST_BIDIR, conn_repr = conn_represent.LIST); self.templateBidirListConnectionsTest(net); # Grid four connection suite def templateGridFourConnectionsTest(self, network): assert network.structure == conn_type.GRID_FOUR; for index in range(0, len(network), 1): upper_index = index - network.width; lower_index = index + network.width; left_index = index - 1; right_index = index + 1; node_row_index = math.ceil(index / network.width); if (upper_index >= 0): assert network.has_connection(index, upper_index) == True; assert network.has_connection(upper_index, index) == True; if (lower_index < len(network)): assert network.has_connection(index, lower_index) == True; assert network.has_connection(lower_index, index) == True; if ( (left_index >= 0) and (math.ceil(left_index / network.width) == node_row_index) ): assert network.has_connection(index, left_index) == True; assert network.has_connection(left_index, index) == True; if ( (right_index < network._num_osc) and (math.ceil(right_index / network.width) == node_row_index) ): assert network.has_connection(index, right_index) == True; assert network.has_connection(right_index, index) == True; def testGridFourConnectionsMatrixRepresentation(self): net = network(25, type_conn = conn_type.GRID_FOUR); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsListRepresentation(self): net = network(25, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST); self.templateGridFourConnectionsTest(net); def testGridFourConnections1MatrixRepresentation(self): net = network(1, type_conn = conn_type.GRID_FOUR); self.templateGridFourConnectionsTest(net); def testGridFourConnections1ListRepresentation(self): net = network(1, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsRectange40MatrixRepresentation(self): net = network(40, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.MATRIX, height = 4, width = 10); self.templateGridFourConnectionsTest(net); net = network(40, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.MATRIX, height = 10, width = 4); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsRectangeList40Representation(self): net = network(40, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 4, width = 10); self.templateGridFourConnectionsTest(net); net = network(40, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 10, width = 4); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsRectange10MatrixRepresentation(self): net = network(10, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.MATRIX, height = 1, width = 10); self.templateGridFourConnectionsTest(net); net = network(10, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.MATRIX, height = 10, width = 1); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsRectangeList10Representation(self): net = network(10, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 1, width = 10); self.templateGridFourConnectionsTest(net); net = network(10, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 10, width = 1); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsRectange1MatrixRepresentation(self): net = network(1, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.MATRIX, height = 1, width = 1); self.templateGridFourConnectionsTest(net); net = network(1, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.MATRIX, height = 1, width = 1); self.templateGridFourConnectionsTest(net); def testGridFourConnectionsRectangeList1Representation(self): net = network(1, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 1, width = 1); self.templateGridFourConnectionsTest(net); net = network(1, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 1, width = 1); self.templateGridFourConnectionsTest(net); # Grid four connection suite def templateGridEightConnectionsTest(self, network): assert network.structure == conn_type.GRID_EIGHT; for index in range(0, len(network), 1): upper_index = index - network.width; lower_index = index + network.width; left_index = index - 1; right_index = index + 1; node_row_index = math.ceil(index / network.width); if (upper_index >= 0): assert network.has_connection(index, upper_index) == True; assert network.has_connection(upper_index, index) == True; if (lower_index < len(network)): assert network.has_connection(index, lower_index) == True; assert network.has_connection(lower_index, index) == True; if ( (left_index >= 0) and (math.ceil(left_index / network.width) == node_row_index) ): assert network.has_connection(index, left_index) == True; assert network.has_connection(left_index, index) == True; if ( (right_index < len(network)) and (math.ceil(right_index / network.width) == node_row_index) ): assert network.has_connection(index, right_index) == True; assert network.has_connection(right_index, index) == True; side_size = network.width; upper_left_index = index - side_size - 1; upper_right_index = index - side_size + 1; lower_left_index = index + side_size - 1; lower_right_index = index + side_size + 1; node_row_index = math.floor(index / side_size); upper_row_index = node_row_index - 1; lower_row_index = node_row_index + 1; if ( (upper_left_index >= 0) and (math.floor(upper_left_index / side_size) == upper_row_index) ): assert network.has_connection(index, upper_left_index) == True; assert network.has_connection(upper_left_index, index) == True; if ( (upper_right_index >= 0) and (math.floor(upper_right_index / side_size) == upper_row_index) ): assert network.has_connection(index, upper_right_index) == True; assert network.has_connection(upper_right_index, index) == True; if ( (lower_left_index < len(network)) and (math.floor(lower_left_index / side_size) == lower_row_index) ): assert network.has_connection(index, lower_left_index) == True; assert network.has_connection(lower_left_index, index) == True; if ( (lower_right_index < len(network)) and (math.floor(lower_right_index / side_size) == lower_row_index) ): assert network.has_connection(index, lower_right_index) == True; assert network.has_connection(lower_right_index, index) == True; def testGridEightConnectionsMatrixRepresentation(self): net = network(25, type_conn = conn_type.GRID_EIGHT); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsListRepresentation(self): net = network(25, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST); self.templateGridEightConnectionsTest(net); def testGridEightConnections1MatrixRepresentation(self): net = network(1, type_conn = conn_type.GRID_EIGHT); self.templateGridEightConnectionsTest(net); def testGridEightConnections1ListRepresentation(self): net = network(1, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsRectange40MatrixRepresentation(self): net = network(40, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.MATRIX, height = 4, width = 10); self.templateGridEightConnectionsTest(net); net = network(40, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.MATRIX, height = 10, width = 4); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsRectangeList40Representation(self): net = network(40, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 4, width = 10); self.templateGridEightConnectionsTest(net); net = network(40, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 10, width = 4); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsRectange10MatrixRepresentation(self): net = network(10, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.MATRIX, height = 1, width = 10); self.templateGridEightConnectionsTest(net); net = network(10, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.MATRIX, height = 10, width = 1); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsRectangeList10Representation(self): net = network(10, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 1, width = 10); self.templateGridEightConnectionsTest(net); net = network(10, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 10, width = 1); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsRectange1MatrixRepresentation(self): net = network(1, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.MATRIX, height = 1, width = 1); self.templateGridEightConnectionsTest(net); net = network(1, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.MATRIX, height = 1, width = 1); self.templateGridEightConnectionsTest(net); def testGridEightConnectionsRectangeList1Representation(self): net = network(1, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 1, width = 1); self.templateGridEightConnectionsTest(net); net = network(1, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 1, width = 1); self.templateGridEightConnectionsTest(net); def testGridFourStructure1GridProperty(self): net = network(1, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 1, width = 1); assert(net.height == 1); assert(net.width == 1); def testGridEightStructure1GridProperty(self): net = network(1, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 1, width = 1); assert(net.height == 1); assert(net.width == 1); def testGridFourStructure40GridProperty(self): net = network(40, type_conn = conn_type.GRID_FOUR, conn_repr = conn_represent.LIST, height = 20, width = 2); assert(net.height == 20); assert(net.width == 2); def testGridEightStructure40GridProperty(self): net = network(40, type_conn = conn_type.GRID_EIGHT, conn_repr = conn_represent.LIST, height = 20, width = 2); assert(net.height == 20); assert(net.width == 2); def templateAssertRaises(self, size, type_conn, height, width): try: network(size, type_conn, height, width); assert(False); # assert must occure except: pass; def testInvalidGridFourDescription(self): self.templateAssertRaises(10, type_conn = conn_type.GRID_FOUR, height = 10, width = 5); self.templateAssertRaises(10, type_conn = conn_type.GRID_FOUR, height = 6, width = 2); self.templateAssertRaises(10, type_conn = conn_type.GRID_FOUR, height = 1, width = 11); self.templateAssertRaises(10, type_conn = conn_type.GRID_FOUR, height = 0, width = 0); def testInvalidGridEightDescription(self): self.templateAssertRaises(10, type_conn = conn_type.GRID_EIGHT, height = 5, width = 8); self.templateAssertRaises(10, type_conn = conn_type.GRID_EIGHT, height = 1, width = 2); self.templateAssertRaises(10, type_conn = conn_type.GRID_EIGHT, height = 1, width = 1); self.templateAssertRaises(10, type_conn = conn_type.GRID_EIGHT, height = 0, width = 0); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_pcnn.py000077500000000000000000000125111375753423500243370ustar00rootroot00000000000000"""! @brief Unit-tests for Pulse Coupled Neural Network. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest from pyclustering.nnet.tests.pcnn_templates import PcnnTestTemplates from pyclustering.nnet import conn_type, conn_represent class PcnnUnitTest(unittest.TestCase): def testDynamicLengthNoneConnection(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.NONE, conn_represent.MATRIX, [0] * 10, False) def testDynamicLengthNoneConnectionFastLinking(self): PcnnTestTemplates.templateDynamicLengthFastLinking(10, 20, conn_type.NONE, conn_represent.MATRIX, [0] * 10, False) def testDynamicLengthGridFourConnection(self): PcnnTestTemplates.templateDynamicLength(25, 20, conn_type.GRID_FOUR, conn_represent.MATRIX, [0] * 25, False) def testDynamicLengthGridFourConnectionFastLinking(self): PcnnTestTemplates.templateDynamicLengthFastLinking(25, 20, conn_type.GRID_FOUR, conn_represent.MATRIX, [0] * 25, False) def testDynamicLengthGridEightConnection(self): PcnnTestTemplates.templateDynamicLength(25, 20, conn_type.GRID_EIGHT, conn_represent.MATRIX, [0] * 25, False) def testDynamicLengthGridEightConnectionFastLinking(self): PcnnTestTemplates.templateDynamicLengthFastLinking(25, 20, conn_type.GRID_EIGHT, conn_represent.MATRIX, [0] * 25, False) def testDynamicLengthListBidirConnection(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.LIST_BIDIR, conn_represent.MATRIX, [0] * 10, False) def testDynamicLengthListBidirConnectionFastLinking(self): PcnnTestTemplates.templateDynamicLengthFastLinking(10, 20, conn_type.LIST_BIDIR, conn_represent.MATRIX, [0] * 10, False) def testDynamicLengthAllToAllConnection(self): PcnnTestTemplates.templateDynamicLength(10, 20, conn_type.ALL_TO_ALL, conn_represent.MATRIX, [0] * 10, False) def testDynamicLengthAllToAllConnectionFastLinking(self): PcnnTestTemplates.templateDynamicLengthFastLinking(10, 20, conn_type.ALL_TO_ALL, conn_represent.MATRIX, [0] * 10, False) def testDynamicLengthListRepresentation(self): PcnnTestTemplates.templateDynamicLength(25, 30, conn_type.NONE, conn_represent.LIST, [0] * 25, False) PcnnTestTemplates.templateDynamicLength(25, 30, conn_type.GRID_EIGHT, conn_represent.LIST, [0] * 25, False) PcnnTestTemplates.templateDynamicLength(25, 30, conn_type.GRID_FOUR, conn_represent.LIST, [0] * 25, False) PcnnTestTemplates.templateDynamicLength(25, 30, conn_type.LIST_BIDIR, conn_represent.LIST, [0] * 25, False) PcnnTestTemplates.templateDynamicLength(25, 30, conn_type.ALL_TO_ALL, conn_represent.LIST, [0] * 25, False) def testDynamicLengthGridRectangle25FourConnection(self): PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_FOUR, conn_represent.MATRIX, 1, 25, [0] * 25, False) PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_FOUR, conn_represent.MATRIX, 25, 1, [0] * 25, False) def testDynamicLengthGridRectangle25EightConnection(self): PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_EIGHT, conn_represent.MATRIX, 1, 25, [0] * 25, False) PcnnTestTemplates.templateGridRectangleDynamicLength(25, 20, conn_type.GRID_EIGHT, conn_represent.MATRIX, 25, 1, [0] * 25, False) def testSyncEnsemblesAllStimulated(self): PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 20, [1] * 25, False, [ list(range(25)) ]) def testSyncEnsemblesAllUnstimulated(self): PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 20, [0] * 25, False, []) def testSyncEnsemblesPartialStimulation(self): stimulus = ([0] * 5) + ([1] * 5) + ([0] * 5) + ([1] * 5) + ([0] * 5) expected_ensemble = [5, 6, 7, 8, 9, 15, 16, 17, 18, 19] PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 20, stimulus, False, [ expected_ensemble ]) def testSyncEnsemblesAllStimulatedWithVariousConnection(self): PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.ALL_TO_ALL, 50, [20] * 25, False, None) PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.GRID_EIGHT, 50, [20] * 25, False, None) PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.GRID_FOUR, 50, [20] * 25, False, None) PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.LIST_BIDIR, 50, [20] * 25, False, None) PcnnTestTemplates.templateSyncEnsemblesAllocation(25, conn_type.NONE, 50, [20] * 25, False, None) def testAllocationInRectangleFourStructure(self): PcnnTestTemplates.templateAllocationInRectangleStructure(20, 4, 5, 20, conn_type.GRID_FOUR, conn_represent.MATRIX, [0] * 20, False) def testAllocationInRectangleEightStructure(self): PcnnTestTemplates.templateAllocationInRectangleStructure(30, 6, 5, 20, conn_type.GRID_EIGHT, conn_represent.MATRIX, [0] * 30, False) def testVisualizerNoFailure(self): stimulus = [ 5, 5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20 ] PcnnTestTemplates.visualize(16, 20, conn_type.ALL_TO_ALL, conn_represent.MATRIX, stimulus, 4, 4, False) pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_som.py000077500000000000000000000221311375753423500241760ustar00rootroot00000000000000"""! @brief Unit-tests for self-organized feature map. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.nnet.tests.som_templates import SomTestTemplates from pyclustering.nnet.som import som, type_conn, type_init, som_parameters from pyclustering.utils import read_sample from pyclustering.samples.definitions import SIMPLE_SAMPLES, FCPS_SAMPLES class SomUnitTest(unittest.TestCase): def testTwoNeuronsTwoClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], False, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], False, False) def testTwoNeuronsTwoClustersStoreLoad(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], False, False, store_load=True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], False, False, store_load=True) def testAutostopTwoNeuronsTwoClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], True, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], True, False) def testAutostopTwoNeuronsTwoClustersStoreLoad(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, 100, [5, 5], True, False, store_load=True) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2, 1, 100, [5, 5], True, False, store_load=True) def testThreeNeuronsThreeClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 100, [5, 8, 10], False, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1, 100, [5, 8, 10], False, False) def testAutostopThreeNeuronsThreeClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 1, 3, 100, [5, 8, 10], True, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3, 1, 100, [5, 8, 10], True, False) def testFourNeuronsFourClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 100, [10, 10, 10, 30], False, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 2, 100, [10, 10, 10, 30], False, False) def testAutostopFourNeuronsFourClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 4, 100, [10, 10, 10, 30], True, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 2, 100, [10, 10, 10, 30], True, False) def testTwoNeuronsFourClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 2, 100, [30, 30], False, False) def testAutostopTwoNeuronsFourClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 1, 2, 100, [30, 30], True, False) def testSevenNeuronsHeptaClusters(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 7, 100, [30, 30, 30, 30, 30, 30, 32], False, False) def testAutostopSevenNeuronsHeptaClusters(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_HEPTA, 1, 7, 100, [30, 30, 30, 30, 30, 30, 32], True, False) def testFourNeuronsTetraClusters(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TETRA, 1, 4, 100, [100, 100, 100, 100], False, False) def testAutostopFourNeuronsTetraClusters(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TETRA, 1, 4, 100, [100, 100, 100, 100], True, False) def testTwoNeuronsTwoDiamondsClusters(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1, 2, 100, [400, 400], False, False) def testAutostopTwoNeuronsTwoDiamondsClusters(self): SomTestTemplates.templateTestAwardNeurons(FCPS_SAMPLES.SAMPLE_TWO_DIAMONDS, 1, 2, 100, [400, 400], True, False) def testFiveNeuronsFiveClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 100, [15, 15, 15, 15, 15], False, False) def testAutostopFiveNeuronsFiveClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE4, 1, 5, 100, [15, 15, 15, 15, 15], True, False) def testFourNeuronsSquareClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 2, 2, 100, [15, 15, 15, 15], False, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 100, [15, 15, 15, 15], False, False) def testAutostopFourNeuronsSquareClusters(self): SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 2, 2, 100, [15, 15, 15, 15], True, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE5, 1, 4, 100, [15, 15, 15, 15], True, False) def testOneDimensionSampleSimple7Cluster(self): parameters = som_parameters() parameters.init_type = type_init.random_surface SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2, 1, 100, [10, 10], True, False, parameters) def testHighEpochs(self): epochs = 1000 SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1, 2, epochs, [5, 5], False, False) SomTestTemplates.templateTestAwardNeurons(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 2, 2, epochs, [10, 10, 10, 30], False, False) def testWinners(self): SomTestTemplates.templateTestWinners(False) def testDoubleTrain(self): sample = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1) parameters = som_parameters() network = som(2, 2, type_conn.grid_eight, parameters, ccore = False) network.train(sample, 100, False) network.train(sample, 100, False) assert sum(network.awards) == len(sample) total_capture_points = 0 for points in network.capture_objects: total_capture_points += len(points) assert total_capture_points == len(sample) def testSimulateCheckWinnerFuncNeighbor(self): SomTestTemplates.templateTestSimulate(type_conn.func_neighbor, False) def testSimulateCheckWinnerFuncNeighborStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.func_neighbor, False, store_load=True) def testSimulateCheckWinnerGridFour(self): SomTestTemplates.templateTestSimulate(type_conn.grid_four, False) def testSimulateCheckWinnerGridFourStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.grid_four, False, store_load=True) def testSimulateCheckWinnerGridEight(self): SomTestTemplates.templateTestSimulate(type_conn.grid_eight, False) def testSimulateCheckWinnerGridEightStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.grid_eight, False, store_load=True) def testSimulateCheckWinnerHoneycomb(self): SomTestTemplates.templateTestSimulate(type_conn.honeycomb, False) def testSimulateCheckWinnerHoneycombStoreLoad(self): SomTestTemplates.templateTestSimulate(type_conn.honeycomb, False, store_load=True) def testNetwork2x2RandomState5(self): SomTestTemplates.random_state(2, 2, type_conn.honeycomb, 5, False) def testNetwork2x2RandomState5FuncNeighbor(self): SomTestTemplates.random_state(2, 2, type_conn.func_neighbor, 5, False) def testNetwork2x2RandomState10(self): SomTestTemplates.random_state(2, 2, type_conn.honeycomb, 10, False) def testNetwork2x2RandomState10FuncNeighbor(self): SomTestTemplates.random_state(2, 2, type_conn.func_neighbor, 10, False) def testNetwork2x3RandomState5(self): SomTestTemplates.random_state(2, 3, type_conn.honeycomb, 5, False) def testNetwork2x3RandomState10(self): SomTestTemplates.random_state(2, 3, type_conn.honeycomb, 10, False) def testNetwork1x8RandomState5(self): SomTestTemplates.random_state(1, 8, type_conn.honeycomb, 5, False) def testNetwork1x8RandomState10(self): SomTestTemplates.random_state(1, 8, type_conn.honeycomb, 10, False) def testNetwork1x8GridFour(self): SomTestTemplates.random_state(1, 8, type_conn.grid_four, 5, False) SomTestTemplates.random_state(8, 1, type_conn.grid_four, 5, False) def testNetwork1x8GridEight(self): SomTestTemplates.random_state(1, 8, type_conn.grid_eight, 5, False) SomTestTemplates.random_state(8, 1, type_conn.grid_eight, 5, False) def testNetwork1x8FuncNeughbor(self): SomTestTemplates.random_state(1, 8, type_conn.func_neighbor, 5, False) SomTestTemplates.random_state(8, 1, type_conn.func_neighbor, 5, False) pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_sync.py000077500000000000000000000207771375753423500243720ustar00rootroot00000000000000"""! @brief Unit-tests for Oscillatory Neural Network based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet.tests.sync_templates import SyncTestTemplates; from pyclustering.nnet import solve_type, conn_type; from pyclustering.nnet.sync import sync_network, sync_dynamic, sync_visualizer; from pyclustering.utils import pi; class SyncUnitTest(unittest.TestCase): def testCreateNetwork(self): SyncTestTemplates.templateCreateNetwork(1, False); SyncTestTemplates.templateCreateNetwork(10, False); SyncTestTemplates.templateCreateNetwork(55, False); def testConnectionsApi(self): SyncTestTemplates.templateConnectionsApi(1, False); SyncTestTemplates.templateConnectionsApi(5, False); SyncTestTemplates.templateConnectionsApi(10, False); def testSyncOrderSingleOscillator(self): # Check for order parameter of network with one oscillator network = sync_network(1, 1, ccore=False); assert network.sync_order() == 1; def testSyncOrderNetwork(self): # Check for order parameter of network with several oscillators network = sync_network(2, 1, ccore=False); sync_state = 1; tolerance = 0.1; network.simulate(50, 20, solve_type.RK4); assert (abs(network.sync_order() - sync_state) < tolerance) == True; def testSyncLocalOrderSingleOscillator(self): network = sync_network(1, 1); assert network.sync_local_order() == 0; def testOutputNormalization(self): network = sync_network(20, 1, ccore=False); output_dynamic = network.simulate(50, 20, solve_type.RK4); t = output_dynamic.time; dyn = output_dynamic.output; for iteration in range(len(dyn)): for index_oscillator in range(len(dyn[iteration])): assert (dyn[iteration][index_oscillator] >= 0); assert (dyn[iteration][index_oscillator] <= 2.0 * pi); def testFastSolution(self): # Check for convergence when solution using fast way of calculation of derivative SyncTestTemplates.templateSimulateTest(10, 1, solve_type.FAST, False); def testRK4Solution(self): # Check for convergence when solution using RK4 function of calculation of derivative SyncTestTemplates.templateSimulateTest(10, 1, solve_type.RK4, False); def testLargeNetwork(self): # Check for convergence of phases in large network - network that contains large number of oscillators SyncTestTemplates.templateSimulateTest(128, 1, solve_type.FAST, False); def testOutputDynamicAroundZero(self): phases = [ [ 0.01, 0.02, 0.04, 6.27, 6.28, 6.25, 0.03] ]; time = [ 10.0 ]; output_sync_dynamic = sync_dynamic(phases, time, None); assert len(output_sync_dynamic.allocate_sync_ensembles(0.2)) == 1; assert len(output_sync_dynamic.allocate_sync_ensembles(0.1)) == 1; phases = [ [ 1.02, 1.05, 1.52, 5.87, 5.98, 5.14] ]; output_sync_dynamic = sync_dynamic(phases, time, None); assert len(output_sync_dynamic.allocate_sync_ensembles(3.0)) == 1; assert len(output_sync_dynamic.allocate_sync_ensembles(2.0)) == 1; def testDynamicSimulationAllToAll(self): SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(10, 1, conn_type.ALL_TO_ALL, False); SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(50, 1, conn_type.ALL_TO_ALL, False); def testDynamicSimulationGridFour(self): SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(9, 1, conn_type.GRID_FOUR, False); SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(25, 1, conn_type.GRID_FOUR, False); def testDynamicSimulationGridEight(self): SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(9, 1, conn_type.GRID_FOUR, False); SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(25, 1, conn_type.GRID_FOUR, False); def testDynamicSimulationBidir(self): SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(5, 1, conn_type.LIST_BIDIR, False); SyncTestTemplates.templateDynamicSimulationConnectionTypeTest(10, 1, conn_type.LIST_BIDIR, False); def testTwoOscillatorDynamic(self): SyncTestTemplates.templateDynamicSimulationConvergence(2, 1, conn_type.ALL_TO_ALL, False); def testThreeOscillatorDynamic(self): SyncTestTemplates.templateDynamicSimulationConvergence(3, 1, conn_type.ALL_TO_ALL, False); def testFourOscillatorDynamic(self): SyncTestTemplates.templateDynamicSimulationConvergence(4, 1, conn_type.ALL_TO_ALL, False); def testFiveOscillatorDynamic(self): SyncTestTemplates.templateDynamicSimulationConvergence(5, 1, conn_type.ALL_TO_ALL, False); def testSixOscillatorDynamic(self): SyncTestTemplates.templateDynamicSimulationConvergence(6, 1, conn_type.ALL_TO_ALL, False); def testSevenOscillatorDynamic(self): SyncTestTemplates.templateDynamicSimulationConvergence(7, 1, conn_type.ALL_TO_ALL, False); def testOutputDynamicLengthSimulation(self): net = sync_network(5, ccore=False); output_dynamic = net.simulate(10, 10, solution = solve_type.FAST, collect_dynamic = True); assert len(output_dynamic) == 11; # 10 steps without initial values. def testOutputDynamicLengthStaticSimulation(self): net = sync_network(5, ccore=False); output_dynamic = net.simulate_static(10, 10, solution = solve_type.FAST, collect_dynamic = True); assert len(output_dynamic) == 11; # 10 steps without initial values. def testOutputDynamicLengthStaticSimulationWithouCollecting(self): net = sync_network(5, ccore=False); output_dynamic = net.simulate_static(10, 10, solution = solve_type.FAST, collect_dynamic = False); assert len(output_dynamic) == 1; # 10 steps without initial values. def testOutputDynamicLengthDynamicSimulation(self): net = sync_network(5, ccore=False); output_dynamic = net.simulate_dynamic(solution = solve_type.FAST, collect_dynamic = True); assert len(output_dynamic) > 1; def testOutputDynamicLengthDynamicSimulationWithoutCollecting(self): net = sync_network(5, ccore=False); output_dynamic = net.simulate_dynamic(solution = solve_type.FAST, collect_dynamic = False); assert len(output_dynamic) == 1; def testInfoAllicationWithNoSimulation(self): output_dynamic = sync_dynamic(None, None, None); ensembles = output_dynamic.allocate_sync_ensembles(); assert ensembles == []; matrix = output_dynamic.allocate_correlation_matrix(); assert matrix == []; def testOutputDynamicCalculateOrderParameter(self): SyncTestTemplates.templateOutputDynamicCalculateOrderParameter(False); def testOutputDynamicCalculateLocalOrderParameter(self): SyncTestTemplates.templateOutputDynamicCalculateLocalOrderParameter(False); def testVisualizerOrderParameterNoFailures(self): net = sync_network(10, ccore = False); output_dynamic = net.simulate_static(20, 10, solution = solve_type.FAST, collect_dynamic = True); sync_visualizer.show_order_parameter(output_dynamic); sync_visualizer.show_order_parameter(output_dynamic, 0); sync_visualizer.show_order_parameter(output_dynamic, 5); sync_visualizer.show_order_parameter(output_dynamic, 5, 20); def testVisualizeLocalOrderParameterNoFailures(self): net = sync_network(10, ccore = False); output_dynamic = net.simulate_static(20, 10, solution = solve_type.FAST, collect_dynamic = True); sync_visualizer.show_local_order_parameter(output_dynamic, net); sync_visualizer.show_local_order_parameter(output_dynamic, net, 0); sync_visualizer.show_local_order_parameter(output_dynamic, net, 5); sync_visualizer.show_local_order_parameter(output_dynamic, net, 5, 20); def testVisualizerNoFailures(self): SyncTestTemplates.templateVisualizerNoFailures(5, 10, False); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_syncpr.py000077500000000000000000000072021375753423500247200ustar00rootroot00000000000000"""! @brief Unit-tests for Phase Oscillatory Neural Network for Pattern Recognition based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet.tests.syncpr_templates import SyncprTestTemplates; from pyclustering.nnet import solve_type; from pyclustering.nnet.syncpr import syncpr; class SyncprUnitTest(unittest.TestCase): def testCreateTenOscillatorsNetwork(self): net = syncpr(10, 0.1, 0.1, ccore=False); assert len(net) == 10; def testCreateHundredOscillatorsNetwork(self): net = syncpr(100, 0.1, 0.1, ccore=False); assert len(net) == 100; def testOutputDynamicFastSolver(self): SyncprTestTemplates.templateOutputDynamic(solve_type.FAST, False); def testOutputDynamicRK4Solver(self): SyncprTestTemplates.templateOutputDynamic(solve_type.RK4, False); def testOutputDinamicLengthSimulation(self): net = syncpr(5, 0.1, 0.1, ccore=False); output_dynamic = net.simulate(10, 10, [-1, 1, -1, 1, -1], solution = solve_type.FAST, collect_dynamic = True); assert len(output_dynamic) == 11; # 10 steps without initial values. def testOutputDynamicLengthStaticSimulation(self): SyncprTestTemplates.templateOutputDynamicLengthStaticSimulation(True, False); def testOutputDynamicLengthStaticSimulationWithouCollecting(self): SyncprTestTemplates.templateOutputDynamicLengthStaticSimulation(False, False); def testOutputDynamicLengthDynamicSimulation(self): SyncprTestTemplates.templateOutputDynamicLengthDynamicSimulation(True, False); def testOutputDynamicLengthDynamicSimulationWithoutCollecting(self): SyncprTestTemplates.templateOutputDynamicLengthDynamicSimulation(False, False); def testTrainNetworkAndRecognizePattern(self): SyncprTestTemplates.templateTrainNetworkAndRecognizePattern(False); def testIncorrectPatternValues(self): SyncprTestTemplates.templateIncorrectPatternValues(False); def testIncorrectSmallPatternSize(self): patterns = [ [1, 1, 1, 1, 1, -1] ]; SyncprTestTemplates.templateIncorrectPatternForTraining(patterns, False); def testIncorrectLargePatternSize(self): patterns = [ [1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1] ]; SyncprTestTemplates.templateIncorrectPatternForTraining(patterns, False); def testIncorrectSmallPatternSizeSimulation(self): pattern = [1, 1, 1, 1, 1, -1]; SyncprTestTemplates.templateIncorrectPatternForSimulation(pattern, False); def testIncorrectLargePatternSizeSimulation(self): pattern = [1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1]; SyncprTestTemplates.templateIncorrectPatternForSimulation(pattern, False); def testPatternVisualizerCollectDynamic(self): SyncprTestTemplates.templatePatternVisualizer(True); def testPatternVisualizerWithoutCollectDynamic(self): SyncprTestTemplates.templatePatternVisualizer(False); def testMemoryOrder(self): SyncprTestTemplates.templateMemoryOrder(False); def testStaticSimulation(self): SyncprTestTemplates.templateStaticSimulation(False); def testDynamicSimulation(self): SyncprTestTemplates.templateDynamicSimulation(False); def testGlobalSyncOrder(self): SyncprTestTemplates.templateGlobalSyncOrder(False); def testLocalSyncOrder(self): SyncprTestTemplates.templateLocalSyncOrder(False); pyclustering-0.10.1.2/pyclustering/nnet/tests/unit/ut_syncsegm.py000077500000000000000000000037761375753423500252460ustar00rootroot00000000000000"""! @brief Unit-tests for double-layer oscillatory network 'syncsegm' for image segmentation based on Kuramoto model. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.nnet.tests.syncsegm_templates import SyncsegmTestTemplates; from pyclustering.samples.definitions import IMAGE_SIMPLE_SAMPLES; class SyncsegmUnitTest(unittest.TestCase): def testImageSegmentationSimple17(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE17, 225, 1, 0, 3, 3, False, False); def testImageSegmentationSimple17OneObjectDetection(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE17, 225, 5, 0, 3, 3, False, False); def testImageSegmentationSimple17OneColorDetection(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE17, float('Inf'), 1, 0, 1, 1, False, False); def testImageSegmentationSimple18(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE18, 225, 1, 0, 2, 3, False, False); def testImageSegmentationSimple18OneObjectDetection(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE18, 225, 5, 0, 2, 2, False, False); def testImageSegmentationSimple18OneColorDetection(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE18, float('Inf'), 2, 0, 1, 1, False, False); def testVisualizeSimple17NoFailure(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE17, 225, 1, 0, 3, 3, False, False); def testVisualizeSimple18NoFailure(self): SyncsegmTestTemplates.templateSyncsegmSegmentation(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE18, 225, 1, 0, 2, 3, False, False); pyclustering-0.10.1.2/pyclustering/samples/000077500000000000000000000000001375753423500206735ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/samples/__init__.py000077500000000000000000000053121375753423500230100ustar00rootroot00000000000000"""! @brief pyclustering module for samples. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ class answer_reader: """! @brief Answer reader for samples that are used by pyclustering library. """ def __init__(self, answer_path): """! @brief Creates instance of answer reader to read proper clustering results of samples. @param[in] answer_path (string): Path to clustering results (answers). """ self.__answer_path = answer_path self.__clusters = None self.__noise = None def get_clusters(self): """! @brief Read proper clustering results. @return (list) Clusters where each cluster is represented by list of index point from dataset. """ self.__read_answer() return self.__clusters def get_noise(self): """! @brief Read proper clustering results @return (list) Noise where each outlier is represented by index point from dataset. """ self.__read_answer() return self.__noise def get_cluster_lengths(self): """! @brief Read proper cluster lengths. @details Cluster length means amount of point in a cluster. @return (list) Cluster lengths where each length means amount of points in a cluster. """ clusters = self.get_clusters() return [len(cluster) for cluster in clusters] def __read_answer_from_line(self, index_point, line): """! @brief Read information about point from the specific line and place it to cluster or noise in line with that information. @param[in] index_point (uint): Index point that should be placed to cluster or noise. @param[in] line (string): Line where information about point should be read. """ if line[0] == 'n': self.__noise.append(index_point) else: index_cluster = int(line) if index_cluster >= len(self.__clusters): self.__clusters.append([index_point]) else: self.__clusters[index_cluster].append(index_point) def __read_answer(self): """! @brief Read information about proper clusters and noises from the file. """ if self.__clusters is not None: return file = open(self.__answer_path, 'r') self.__clusters, self.__noise = [], [] index_point = 0 for line in file: self.__read_answer_from_line(index_point, line) index_point += 1 file.close() pyclustering-0.10.1.2/pyclustering/samples/definitions.py000077500000000000000000000327301375753423500235700ustar00rootroot00000000000000"""! @brief General definitions of samples. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import pyclustering.samples as samples import os ## Path to samples module. DEFAULT_SAMPLE_PATH = samples.__path__[0] + os.sep + "samples" + os.sep class SIMPLE_SAMPLES: """! @brief The Simple Suite offers a variety of simple clustering problems. @details The samples are supposed to use for unit-testing and common algorithm abilities to found out run-time problems. """ ## Simple Sample collection path. COLLECTION_PATH = DEFAULT_SAMPLE_PATH + "simple" + os.sep SAMPLE_SIMPLE1 = COLLECTION_PATH + "Simple01.data" SAMPLE_SIMPLE2 = COLLECTION_PATH + "Simple02.data" SAMPLE_SIMPLE3 = COLLECTION_PATH + "Simple03.data" SAMPLE_SIMPLE4 = COLLECTION_PATH + "Simple04.data" SAMPLE_SIMPLE5 = COLLECTION_PATH + "Simple05.data" SAMPLE_SIMPLE6 = COLLECTION_PATH + "Simple06.data" SAMPLE_SIMPLE7 = COLLECTION_PATH + "Simple07.data" SAMPLE_SIMPLE8 = COLLECTION_PATH + "Simple08.data" SAMPLE_SIMPLE9 = COLLECTION_PATH + "Simple09.data" SAMPLE_SIMPLE10 = COLLECTION_PATH + "Simple10.data" SAMPLE_SIMPLE11 = COLLECTION_PATH + "Simple11.data" SAMPLE_SIMPLE12 = COLLECTION_PATH + "Simple12.data" SAMPLE_SIMPLE13 = COLLECTION_PATH + "Simple13.data" SAMPLE_SIMPLE14 = COLLECTION_PATH + "Simple14.data" SAMPLE_SIMPLE15 = COLLECTION_PATH + "Simple15.data" SAMPLE_ELONGATE = COLLECTION_PATH + "Elongate.data" class SIMPLE_ANSWERS: """! @brief Proper clustering results of samples from 'SIMPLE_SAMPLES'. @see SIMPLE_SAMPLES """ COLLECTION_PATH = DEFAULT_SAMPLE_PATH + "simple" + os.sep ANSWER_SIMPLE1 = COLLECTION_PATH + "Simple01.answer" ANSWER_SIMPLE2 = COLLECTION_PATH + "Simple02.answer" ANSWER_SIMPLE3 = COLLECTION_PATH + "Simple03.answer" ANSWER_SIMPLE4 = COLLECTION_PATH + "Simple04.answer" ANSWER_SIMPLE5 = COLLECTION_PATH + "Simple05.answer" ANSWER_SIMPLE6 = COLLECTION_PATH + "Simple06.answer" ANSWER_SIMPLE7 = COLLECTION_PATH + "Simple07.answer" ANSWER_SIMPLE8 = COLLECTION_PATH + "Simple08.answer" ANSWER_SIMPLE9 = COLLECTION_PATH + "Simple09.answer" ANSWER_SIMPLE10 = COLLECTION_PATH + "Simple10.answer" ANSWER_SIMPLE11 = COLLECTION_PATH + "Simple11.answer" ANSWER_SIMPLE12 = COLLECTION_PATH + "Simple12.answer" ANSWER_SIMPLE13 = COLLECTION_PATH + "Simple13.answer" ANSWER_SIMPLE14 = COLLECTION_PATH + "Simple14.answer" ANSWER_SIMPLE15 = COLLECTION_PATH + "Simple15.answer" ANSWER_ELONGATE = COLLECTION_PATH + "Elongate.answer" class FCPS_SAMPLES: """! @brief The Fundamental Clustering Problems Suite (FCPS) offers a variety of clustering problems any algorithm shall be able to handle when facing real world data. @details FCPS serves as an elementary benchmark for clustering algorithms. FCPS consists of data sets with known a priori classifications that are to be reproduced by the algorithm. All data sets are intentionally created to be simple and might be visualized in two or three dimensions. """ COLLECTION_PATH = DEFAULT_SAMPLE_PATH + "fcps" + os.sep SAMPLE_ATOM = COLLECTION_PATH + "Atom.data" SAMPLE_CHAINLINK = COLLECTION_PATH + "Chainlink.data" SAMPLE_ENGY_TIME = COLLECTION_PATH + "EngyTime.data" SAMPLE_GOLF_BALL = COLLECTION_PATH + "GolfBall.data" SAMPLE_HEPTA = COLLECTION_PATH + "Hepta.data" SAMPLE_LSUN = COLLECTION_PATH + "Lsun.data" SAMPLE_TARGET = COLLECTION_PATH + "Target.data" SAMPLE_TETRA = COLLECTION_PATH + "Tetra.data" SAMPLE_TWO_DIAMONDS = COLLECTION_PATH + "TwoDiamonds.data" SAMPLE_WING_NUT = COLLECTION_PATH + "WingNut.data" class FAMOUS_SAMPLES: """! @brief The famous suite offers a variety of popular dataset that are mentioned in articles, book, etc. """ COLLECTION_PATH = DEFAULT_SAMPLE_PATH + "famous" + os.sep SAMPLE_OLD_FAITHFUL = COLLECTION_PATH + "OldFaithful.data" SAMPLE_IRIS = COLLECTION_PATH + "Iris.data" class FAMOUS_ANSWERS: """! @brief Proper clustering results of samples from 'FAMOUS_SAMPLES'. @see FAMOUS_SAMPLES """ COLLECTION_PATH = DEFAULT_SAMPLE_PATH + "famous" + os.sep ANSWER_IRIS = COLLECTION_PATH + "Iris.answer" class GRAPH_SIMPLE_SAMPLES: GRAPH_BROKEN_CIRCLE1 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphBrokenCircle1.grpr" GRAPH_BROKEN_CIRCLE2 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphBrokenCircle2.grpr" GRAPH_FIVE_POINTED_FRAME_STAR = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphFivePointedFrameStar.grpr" GRAPH_FIVE_POINTED_STAR = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphFivePointedStar.grpr" GRAPH_ONE_CIRCLE1 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphOneCircle1.grpr" GRAPH_ONE_CIRCLE2 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphOneCircle2.grpr" GRAPH_ONE_CIRCLE3 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphOneCircle3.grpr" GRAPH_ONE_CROSSROAD = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphOneCrossroad.grpr" GRAPH_ONE_LINE = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphOneLine.grpr" GRAPH_TWO_CROSSROADS = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphTwoCrossroads.grpr" GRAPH_FULL1 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphFull1.grpr" GRAPH_FULL2 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphFull2.grpr" GRAPH_SIMPLE1 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphSimple1.grpr" GRAPH_SIMPLE2 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphSimple2.grpr" GRAPH_SIMPLE3 = samples.__path__[0] + os.sep + "graphs" + os.sep + "GraphSimple3.grpr" class IMAGE_SIMPLE_SAMPLES: IMAGE_SIMPLE01 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple01.png" IMAGE_SIMPLE02 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple02.png" IMAGE_SIMPLE03 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple03.png" IMAGE_SIMPLE04 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple04.png" IMAGE_SIMPLE05 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple05.png" IMAGE_SIMPLE06 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple06.png" IMAGE_SIMPLE07 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple07.png" IMAGE_SIMPLE08 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple08.png" IMAGE_SIMPLE09 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple09.png" IMAGE_SIMPLE10 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple10.png" IMAGE_SIMPLE11 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple11.png" IMAGE_SIMPLE12 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple12.png" IMAGE_SIMPLE13 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple13.png" IMAGE_SIMPLE14 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple14.png" IMAGE_SIMPLE15 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple15.png" IMAGE_SIMPLE16 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple16.png" IMAGE_SIMPLE17 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple17.png" IMAGE_SIMPLE18 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimple18.png" IMAGE_SIMPLE_BEACH = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimpleBeach.png" IMAGE_SIMPLE_BUILDING = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimpleBuilding.png" IMAGE_SIMPLE_FRUITS = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimpleFruits.png" IMAGE_SIMPLE_FRUITS_SMALL = samples.__path__[0] + os.sep + "images" + os.sep + "ImageSimpleFruitsSmall.png" IMAGE_THIN_BLACK_LINES01 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageThinBlackLines01.png" IMAGE_THIN_BLACK_LINES02 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageThinBlackLines02.png" IMAGE_THIN_BLACK_LINES03 = samples.__path__[0] + os.sep + "images" + os.sep + "ImageThinBlackLines03.png" class IMAGE_MAP_SAMPLES: IMAGE_WHITE_SEA = samples.__path__[0] + os.sep + "images" + os.sep + "ImageWhiteSea.png" IMAGE_WHITE_SEA_SMALL = samples.__path__[0] + os.sep + "images" + os.sep + "ImageWhiteSeaSmall.png" IMAGE_NILE = samples.__path__[0] + os.sep + "images" + os.sep + "ImageNile.png" IMAGE_NILE_SMALL = samples.__path__[0] + os.sep + "images" + os.sep + "ImageNileSmall.png" IMAGE_BUILDINGS = samples.__path__[0] + os.sep + "images" + os.sep + "ImageBuildings.png" class IMAGE_REAL_SAMPLES: IMAGE_FIELD_FLOWER = samples.__path__[0] + os.sep + "images" + os.sep + "ImageFieldFlower.png" IMAGE_FIELD_TREE = samples.__path__[0] + os.sep + "images" + os.sep + "ImageFieldTree.png" class IMAGE_SYMBOL_SAMPLES: @staticmethod def GET_LIST_IMAGE_SAMPLES(symbol): default_path = samples.__path__[0] + os.sep + "images" + os.sep + "symbols" + os.sep number_sample_symbols = 1 name_file_pattern = "Symbol_%s_Sample%.2d.png" list_image_samples = [] for index_image in range(1, number_sample_symbols + 1, 1): file_path = default_path + (name_file_pattern % (symbol, index_image)) list_image_samples.append(file_path) return list_image_samples LIST_IMAGES_SYMBOL_A = GET_LIST_IMAGE_SAMPLES.__func__('A') LIST_IMAGES_SYMBOL_B = GET_LIST_IMAGE_SAMPLES.__func__('B') LIST_IMAGES_SYMBOL_C = GET_LIST_IMAGE_SAMPLES.__func__('C') LIST_IMAGES_SYMBOL_D = GET_LIST_IMAGE_SAMPLES.__func__('D') LIST_IMAGES_SYMBOL_E = GET_LIST_IMAGE_SAMPLES.__func__('E') LIST_IMAGES_SYMBOL_F = GET_LIST_IMAGE_SAMPLES.__func__('F') LIST_IMAGES_SYMBOL_G = GET_LIST_IMAGE_SAMPLES.__func__('G') LIST_IMAGES_SYMBOL_H = GET_LIST_IMAGE_SAMPLES.__func__('H') LIST_IMAGES_SYMBOL_I = GET_LIST_IMAGE_SAMPLES.__func__('I') LIST_IMAGES_SYMBOL_J = GET_LIST_IMAGE_SAMPLES.__func__('J') LIST_IMAGES_SYMBOL_K = GET_LIST_IMAGE_SAMPLES.__func__('K') LIST_IMAGES_SYMBOL_L = GET_LIST_IMAGE_SAMPLES.__func__('L') LIST_IMAGES_SYMBOL_M = GET_LIST_IMAGE_SAMPLES.__func__('M') LIST_IMAGES_SYMBOL_N = GET_LIST_IMAGE_SAMPLES.__func__('N') LIST_IMAGES_SYMBOL_O = GET_LIST_IMAGE_SAMPLES.__func__('O') LIST_IMAGES_SYMBOL_P = GET_LIST_IMAGE_SAMPLES.__func__('P') LIST_IMAGES_SYMBOL_Q = GET_LIST_IMAGE_SAMPLES.__func__('Q') LIST_IMAGES_SYMBOL_R = GET_LIST_IMAGE_SAMPLES.__func__('R') LIST_IMAGES_SYMBOL_S = GET_LIST_IMAGE_SAMPLES.__func__('S') LIST_IMAGES_SYMBOL_T = GET_LIST_IMAGE_SAMPLES.__func__('T') LIST_IMAGES_SYMBOL_U = GET_LIST_IMAGE_SAMPLES.__func__('U') LIST_IMAGES_SYMBOL_V = GET_LIST_IMAGE_SAMPLES.__func__('V') LIST_IMAGES_SYMBOL_W = GET_LIST_IMAGE_SAMPLES.__func__('W') LIST_IMAGES_SYMBOL_X = GET_LIST_IMAGE_SAMPLES.__func__('X') LIST_IMAGES_SYMBOL_Y = GET_LIST_IMAGE_SAMPLES.__func__('Y') LIST_IMAGES_SYMBOL_Z = GET_LIST_IMAGE_SAMPLES.__func__('Z') class IMAGE_DIGIT_SAMPLES: @staticmethod def GET_LIST_IMAGE_SAMPLES(digit): default_path = samples.__path__[0] + os.sep + "images" + os.sep + "digits" + os.sep number_sample_digits = 25 name_file_pattern = "Digit_%d_Sample%.2d.png" list_image_samples = [] for index_image in range(1, number_sample_digits + 1, 1): file_path = default_path + (name_file_pattern % (digit, index_image)) list_image_samples.append(file_path) return list_image_samples LIST_IMAGES_DIGIT_0 = GET_LIST_IMAGE_SAMPLES.__func__(0) LIST_IMAGES_DIGIT_1 = GET_LIST_IMAGE_SAMPLES.__func__(1) LIST_IMAGES_DIGIT_2 = GET_LIST_IMAGE_SAMPLES.__func__(2) LIST_IMAGES_DIGIT_3 = GET_LIST_IMAGE_SAMPLES.__func__(3) LIST_IMAGES_DIGIT_4 = GET_LIST_IMAGE_SAMPLES.__func__(4) LIST_IMAGES_DIGIT_5 = GET_LIST_IMAGE_SAMPLES.__func__(5) LIST_IMAGES_DIGIT_6 = GET_LIST_IMAGE_SAMPLES.__func__(6) LIST_IMAGES_DIGIT_7 = GET_LIST_IMAGE_SAMPLES.__func__(7) LIST_IMAGES_DIGIT_8 = GET_LIST_IMAGE_SAMPLES.__func__(8) LIST_IMAGES_DIGIT_9 = GET_LIST_IMAGE_SAMPLES.__func__(9) pyclustering-0.10.1.2/pyclustering/samples/graphs/000077500000000000000000000000001375753423500221575ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphBrokenCircle1.grpr000066400000000000000000000003121375753423500264540ustar00rootroot00000000000000c DESCRIPTION: 6 Nodes, 7 Edges c OPTIMAL NUMBER OF COLORS: 2 m 0 1 0 0 0 1 m 1 0 1 0 0 0 m 0 1 0 1 0 1 m 0 0 1 0 1 0 m 0 0 0 1 0 1 m 1 0 1 0 1 0 r 0 1 r 1 2 r 2 2 r 3 1 r 2 0 r 1 0 pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphBrokenCircle2.grpr000066400000000000000000000002461375753423500264630ustar00rootroot00000000000000c DESCRIPTION: 5 Nodes, 6 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 1 0 0 1 m 1 0 1 0 0 m 0 1 0 1 1 m 0 0 1 0 1 m 1 0 1 1 0 r 0 1 r 1 2 r 3 2 r 4 1 r 2 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphFivePointedFrameStar.grpr000066400000000000000000000006101375753423500300530ustar00rootroot00000000000000c DESCRIPTION: 10 Nodes, 10 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 1 1 0 0 1 0 0 0 0 m 1 0 0 0 0 0 1 1 0 0 m 1 0 0 1 0 0 0 0 1 0 m 0 0 1 0 1 0 0 1 0 0 m 0 0 0 1 0 1 1 0 0 0 m 1 0 0 0 1 0 0 0 0 1 m 0 1 0 0 1 0 0 0 1 0 m 0 1 0 1 0 0 0 0 0 1 m 0 0 1 0 0 0 1 0 0 1 m 0 0 0 0 0 1 0 1 1 0 r 2 3.2 r 2 2.7 r 0.5 2.2 r 1 2 r 3 2 r 3.5 2.2 r 1.3 1 r 2.7 1 r 0.9 0.5 r 3.1 0.5pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphFivePointedStar.grpr000066400000000000000000000002561375753423500271060ustar00rootroot00000000000000c DESCRIPTION: 5 Nodes, 5 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 0 1 1 0 m 0 0 0 1 1 m 1 0 0 0 1 m 1 1 0 0 0 m 0 1 1 0 0 r 0 0.6 r 1 1 r 2 0.6 r 1.7 0 r 0.3 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphFull1.grpr000066400000000000000000000003551375753423500250230ustar00rootroot00000000000000c DESCRIPTION: 6 Nodes c OPTIMAL NUMBER OF COLORS: 7 m 0 1 1 1 1 1 1 m 1 0 1 1 1 1 1 m 1 1 0 1 1 1 1 m 1 1 1 0 1 1 1 m 1 1 1 1 0 1 1 m 1 1 1 1 1 0 1 m 1 1 1 1 1 1 0 r 0 2 r 0.5 3.5 r 2 4 r 3.5 3.5 r 4 2 r 3.5 0.5 r 2 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphFull2.grpr000066400000000000000000000004311375753423500250170ustar00rootroot00000000000000c DESCRIPTION: 8 Nodes c OPTIMAL NUMBER OF COLORS: 8 m 0 1 1 1 1 1 1 1 m 1 0 1 1 1 1 1 1 m 1 1 0 1 1 1 1 1 m 1 1 1 0 1 1 1 1 m 1 1 1 1 0 1 1 1 m 1 1 1 1 1 0 1 1 m 1 1 1 1 1 1 0 1 m 1 1 1 1 1 1 1 0 r 0 2 r 0.5 3.5 r 2 4 r 3.5 3.5 r 4 2 r 3.5 0.5 r 2 0 r 0.5 0.5pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphOneCircle1.grpr000066400000000000000000000002501375753423500257560ustar00rootroot00000000000000c DESCRIPTION: 5 Nodes, 5 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 1 0 0 1 m 1 0 1 0 0 m 0 1 0 1 0 m 0 0 1 0 1 m 1 0 0 1 0 r 0 1 r 1 2 r 2 2 r 3 1 r 1.5 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphOneCircle2.grpr000066400000000000000000000003111375753423500257550ustar00rootroot00000000000000c DESCRIPTION: 6 Nodes, 6 Edges c OPTIMAL NUMBER OF COLORS: 2 m 0 1 0 0 0 1 m 1 0 1 0 0 0 m 0 1 0 1 0 0 m 0 0 1 0 1 0 m 0 0 0 1 0 1 m 1 0 0 0 1 0 r 0 1 r 1 2 r 2 2 r 3 1 r 2 0 r 1 0 pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphOneCircle3.grpr000066400000000000000000000003601375753423500257620ustar00rootroot00000000000000c DESCRIPTION: 7 Nodes, 7 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 1 0 0 0 0 1 m 1 0 1 0 0 0 0 m 0 1 0 1 0 0 0 m 0 0 1 0 1 0 0 m 0 0 0 1 0 1 0 m 0 0 0 0 1 0 1 m 1 0 0 0 0 1 0 r 0 1 r 1 2 r 2 2 r 3 1 r 2.5 0 r 1.5 0 r 0.5 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphOneCrossroad.grpr000066400000000000000000000002461375753423500264400ustar00rootroot00000000000000c DESCRIPTION: 5 Nodes, 4 Edges c OPTIMAL NUMBER OF COLORS: 2 m 0 0 0 0 1 m 0 0 0 0 1 m 0 0 0 0 1 m 0 0 0 0 1 m 1 1 1 1 0 r 0 1 r 1 2 r 2 1 r 1 0 r 1 1pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphOneLine.grpr000066400000000000000000000002461375753423500253700ustar00rootroot00000000000000c DESCRIPTION: 5 Nodes, 4 Edges c OPTIMAL NUMBER OF COLORS: 2 m 0 1 0 0 0 m 1 0 1 0 0 m 0 1 0 1 0 m 0 0 1 0 1 m 0 0 0 1 0 r 0 0 r 1 0 r 2 0 r 3 0 r 4 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphSimple1.grpr000066400000000000000000000002461375753423500253510ustar00rootroot00000000000000c DESCRIPTION: 5 Nodes, 4 Edges c OPTIMAL NUMBER OF COLORS: 2 m 0 0 1 0 0 m 0 0 0 1 0 m 1 0 0 1 1 m 0 1 1 0 0 m 0 0 1 0 0 r 1 2 r 0 2 r 1 1 r 0 1 r 1 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphSimple2.grpr000077500000000000000000000004771375753423500253630ustar00rootroot00000000000000c DESCRIPTION: 9 Nodes, 12 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 1 0 1 0 0 0 0 0 m 1 0 1 1 1 0 0 0 0 m 0 1 0 0 1 0 0 0 0 m 1 1 0 0 1 0 0 1 0 m 0 1 1 1 0 1 0 1 0 m 0 0 0 0 1 0 0 0 0 m 0 0 0 0 0 0 0 1 0 m 0 0 0 1 1 0 1 0 1 m 0 0 0 0 0 0 0 1 0 r 3 3 r 5 3 r 7 3 r 3 6 r 7 6 r 9 6 r 3 9 r 5 9 r 7 9pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphSimple3.grpr000077500000000000000000000011301375753423500253470ustar00rootroot00000000000000c DESCRIPTION: 14 Nodes, 20 Edges c OPTIMAL NUMBER OF COLORS: 3 m 0 0 0 1 0 0 0 0 0 0 0 0 0 0 m 0 0 0 0 0 0 1 0 0 0 0 0 0 0 m 0 0 0 0 0 0 1 0 0 0 0 0 0 0 m 1 0 0 0 1 0 1 1 1 0 0 0 0 0 m 0 0 0 1 0 0 0 0 1 0 0 0 0 0 m 0 0 0 0 0 0 1 0 0 0 0 0 0 0 m 0 1 1 1 0 1 0 1 0 1 1 1 0 0 m 0 0 0 1 0 0 1 0 1 0 0 1 0 0 m 0 0 0 1 1 0 0 1 0 0 0 1 1 0 m 0 0 0 0 0 0 1 0 0 0 0 0 0 1 m 0 0 0 0 0 0 1 0 0 0 0 0 0 0 m 0 0 0 0 0 0 1 1 1 0 0 0 1 1 m 0 0 0 0 0 0 0 0 1 0 0 1 0 0 m 0 0 0 0 0 0 0 0 0 1 0 1 0 0 r 6 8 r 0 6 r 2 6 r 4 6 r 6 6 r 0 4 r 2 4 r 4 4 r 6 4 r 0 2 r 2 2 r 4 2 r 6 2 r 4 0pyclustering-0.10.1.2/pyclustering/samples/graphs/GraphTwoCrossroads.grpr000066400000000000000000000005571375753423500266600ustar00rootroot00000000000000c DESCRIPTION: 10 Nodes, 9 Edges c OPTIMAL NUMBER OF COLORS: 2 m 0 0 0 0 1 0 0 0 0 0 m 0 0 0 0 1 0 0 0 0 0 m 0 0 0 0 1 0 0 0 0 0 m 0 0 0 0 1 0 0 0 0 0 m 1 1 1 1 0 0 0 0 0 1 m 0 0 0 0 0 0 0 0 0 1 m 0 0 0 0 0 0 0 0 0 1 m 0 0 0 0 0 0 0 0 0 1 m 0 0 0 0 0 0 0 0 0 1 m 0 0 0 0 1 1 1 1 1 0 r 0 0 r 2 0 r 0 2 r 2 2 r 1 1 r 4 2 r 6 2 r 4 0 r 6 0 r 5 1pyclustering-0.10.1.2/pyclustering/samples/images/000077500000000000000000000000001375753423500221405ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/samples/images/ImageBuildings.png000077500000000000000000002140031375753423500255340ustar00rootroot00000000000000‰PNG  IHDR¥¥²IªsRGB®ÎégAMA± üa pHYsÃÃÇo¨dÿ¥IDATx^Lýe$ç7ŠÎ‡ûឈsï{^Ø5Hh*®dæ¬Ìª¬,fæªfæîéfiP0b–,°À²À’Ù–qͼ^ïÚ»¦5­í×ÞõÜinœ8Š'2²«GÕUù{~”¸£¾ÐšžJ)•KJFg¼_Æ<¬)^“Efx¤yŽÓ(ZÁiãdT0MSQ»]^¿ëÄÆ•sg¶.¿xÿK_}óÁ·žÜ¾~89ž®ÎKcÙÊD±»Ð_™ªŽwBé0iÕ¤” .P^#$ƒVC°î¥B#”Dñ ”R=¨àÁ%”Ñ<¸^p’¨“òSÎȘv)\™*‡Ëád+Uœ(ii=7šgÂÜû\࣒Q°¬J–fÑNvrÅ©ZyºoÄírÈÌ`ÀJ¢Kµ“0²½¬]«)·yx“ùó­…vc®zàÂÊá»VV¸°xé‘cøÊ‡ÞzøÆ³—'Ö:£ËÝö\7Vʲäc”W8p¼Ÿåü,r2Æ«¸ÀçM&9QÑ…‰^JF9•”t„¬ >ÒT¦÷¯>òÑç¾øÓï|å—?xóûï¾ûËï|ï¿~öò·ß¹øá{Î?wí…¯¼öìç_Ú¼rÀ¬Ä$Û¢deZ–] Æ#ZØð’~á·’Ñr§¥E"¸(ófØÇÉ»½X´\)ŽŽr¡àNŸÇó¨"ɱȎæR/ÚLÚõX¨b#Œ áJ”ÐNÊ‹ð$«H$Ë"8‰`4˪ʹÊOó~^$ ݪš›óKçm^=q扫ùÚÛï|ï3WŸ¿gêÈ\¤í­´Kcùêdefsnbe.ZÌÑZ€”˜ ûYÀL)&!븤R²†³"Jq-Ò¼Ž3ªá]~ÎGÊ(£úhщ“#UÁHYÁLHŽÊ™†]ŒÄ«‰\·«Æ›s-=m C\¾B¬‘ŒÖÁ’ À§{ùÚ\3ÖˆGªáPѼ¹U Eª˜©v*ÕNÇ >"ª)=ÙJÇêI˜L &ö]Ú<5wø®µSwoŸ¸¶uäÒÆÌVwj³7µ1Þ˜nªQÓA š¼}”¡=å&)7ÁÀFXÅG)n\¤¨K!Á‹¸S¾»ÌO‹qkbßʇ>óÑïüÇO¿ý§ù盿ý¯¿ýí¿üä?ùâµW|æs/m]9jÄ|*‰K2+´¤¢ +ôb³š­æqžM¹Ü©¥+RGP >Á™Ûîïn·ƒ$%;̦ó½àÝÍŽïH#¦åj6P˜(ó¶xc"Í©2N3~”ÄIŽad?Êx1ã%\Uù¨U˜]¿óøè¡åå î~å‘·¾ý©'Þ~fñär~*Ÿì$jÓ•òx©5Û™Þ˜oL©‘(Ê+Àl”×½´ŒÀL— R°e1Šò©bAÔ4/F $K°²Ÿ=(ï#$‚ø(qØ»IR¢¥d´$ÊX5” ‡s‘PÆ2ÓÁòx%ÕHÒF¢žŒTb±z"ÞLÙÕ¨Q E›‰òL%RDê¶] [•Y4Ì‚,†¬r83ãÍdn¬¨gM%¥›…°œ D«ñ©Í±ýç6öŸ[ÛnuãÄܱµc3S›íîR­>]N7Ó¬)øÝÃ(榸ÝnÔCb>šôQ´ #áÆX)Á|uc‚ åaxpé«£ÒHVÅr3´›§‡XTÈZ“ÇÖ®¿úè?üþGßúóO~zó·ÿðÛï=ö‰=üæS˧7¥´>€»|ˈ:¯€zŒ$d*ùR«¬†UZeì,l[b·Û±Çã¡T½>1S茉¡.iÀ%BUQI ¤âûÎßQž­Á°bЪژI‹aà¿Ã½ÇIø žÃ(† 8Qp0+)ç6"–QÊtö.¹ÿ®÷ž=õØåçß}í•/¿~ðÚ‘T/­ÙõÙJ²ž¨NÔ{‹µ‰¾’ƒ‚ù`ưÚ{C–³QA$ÉΧ{ó“íÉn"—” •%Zè ï§{))b¼âcX‰"ÌV5œ³áK*–f¥lVç)• $Œx9Qê•âÕ¸™ šY3Z–ÇíšhÞe@:ÚˆÄ[±X3 ë¡RÈ,ÍB(T › ü…°”ÐbTa¼ª$MÖc•xw±3±6ºtpvíØÂêÑÙí3ËóûÇÆV›àS©FÒÊÙ¬!ã²H©ýÍê£p^Wô°%è “0SY?)À¬õ¢ãaxoJBi"h¤%ýOôaßÍøüaÁh'ïÜ÷Â?¼ùî/¾ñí?þøóÿòg¹kæÀ¢UŽ¡" oH±ª¤ÞÔ,=]N%KqÕVÌdÐË ^ó²4¼g´PŽäÊN”öSb š Ä“–62ñ_xrGu¾Qž­†k6u1xsÑÉzwy‡Q—À}x軃 ÎpÃRš¢eâ…éîü©ýǺtð¾>Þ/~ñ£O¼ýìü‘…l/]M.µ³­€=¾<“¬aŠ €­z(ÅKƒ˜k€7(*ð|PO׋“+Ó…f®ÔÌg++ns²Ò×vF¦Øvƪ(+¹pjÈïÁ<^%šQ8N"©!Ð~õ1ˆ”2µL² HX¡œ­ÚñF4æ_º›ˆÖoÀŽ7߃¼j‡Jsæ7àmä-Ζƒ…Hª]†ÕKµ ñh)Ö˜©/ìŸ]?¶´~|¡½P^<8Õœé*æ;3e3…eØÊ~3£á\µœÈç”`ˆà$/Î:ýTr\ðb0oÀF(À£å€ ߤ,E†5:p…h¶hèíX÷Ðìݯ>ü̧_*ÎÔ#ÕT¬’6â6Fò Ì@Z÷1° ¤¼Èá\¢Ð­Ô'ëÙZ¢ÚÍWÚ…x.nFÂF8*6#™j0Aòº $QŽÅ%ÖCû‡ÎR"ídcHœ%d&"” ÅŠÑX |=š¨E¢Õ°]F«¡xÓN´@ÏÃ᪄=ZÈ#VÙ¿·«1`6à͆e 7Õd(]/g›U-Tcz¤dW'‹+Gæì¹}ãÝÅzmªœifôD5?Ïît¹™‰gõn«X¯†ã Õ´XIG)N“"`BÿGÀ›äüç'┟ µ‡Fn§\C*–˜©Hk·ìñY´Z !:¥&ƒ¹vÉJÆJ pže%A–9™7"T9žªÆXƒò°.éŠ"˸)ð\teØE ºPÁ <ïã)Lcv´W:@ñìD1X‰ì¡FbÍ o+RD‚2)âwxý`¨¬¤v˜y'æcMyz{ù‘<ó‘/ü…Ï¿þ‰ï¿{ÿ«^zúzc©%Døâh¾3[/µsc‹“Í©Ñd¹ …Bðç!š¢¬î§ûKJ6iÅàF(/´«å^5SOÎ7ºÓ•B#ÏÛ…z¾3ÑËU+’a’‚ QãDœï€ÜÏÒ(Ä I¤E!‹úHœ‘ˆ©8Oš‰lÉ¡L(Y'ëñXÅN4¢¹^ª<™Owã@q³°û3 Úg-š®D€ß„Éò5µ•öË”–°Š]øåt#-G’õØôæØÒ¡™õã‹kG—Î÷–ºÅ^¹2ÞÈ4J|P Åôb=Ûm”êÅT6•ÊfâÉ´eÇHZ¨0‚ÃI§ú%x?Î1’1â'œíaYÄî¡|·á#b.¨Æv~2Äú,z$öz ŠÇ0–5¨e«™R·`eMTö»YkrnÆ Ê‘°“"‡lØ…ÞÊ[nœtS¤ƒÆÐ¿£±XÏN”rS o€wJ4¢ r4hÄCÁXpÐ54âu¹1ÔJgb…B®VÒêtÓ^°®½§÷Ý÷Ü7^|ð[¿øî‡?óÊÖÙmÉFʨWÇæ{…faóÐVc¼§ÙÖ×:ÞOõÓ Ê(¤ ã¼"‚F4Í¥Jíju´–(FfÖºo~æÅr7Ùž.uf*š-4'ªñZ®–CY‚×TtŒqVqúV òº ¼Ÿ¡0ÃáhÎPÂÙ¸™ Ó:‡É„Q¢¥h²žÌ´ÒÐ c™PQd•pÙ—±†3 Ö|ÏÑ[ñ@>H‡EÆVÔ¬­dlÆRé ]°!…dZ©l;UèekS¥ÎBcb­7·=µ|haõÈÒÊá¥Ù­™òX9˜ Ƴzk,_i¦’™`¡/¹L¼Õ¨&c±h8Bâ4³‚ “Ð9™dèŸnœõRý ‡ð<"rˆÄ ¯æP™Ûb)˹ Ú‰QC^Xçò£LeU>œ±GGƒÙåÛ)ÇŸˆzœª\8È…Cò£ˆßï÷ø}"=<³‡Âü!mGu¶”èf#íâ°@ Ò„‹£1‘¥Dšdq‡g¥0à4¥(#ð?38.àŒÆ "ê$JL™Ù7{ú¾3ϽóüÝOß3¶2ÎYÙf¶Ü-[ÅÑÙñ¹µ¥b£.„?(ɃoaŒÄ) ^Äa{äSV2œ(ÆAÖÍÝûøÅ»=îúáéµVmUž˜¬Ž–kåT1×$.“ˆ—ò+†„¢4 À˦ …ü´@:œE> ÑŠèghV~†Üãvù¡é±bN$¯—ÇG’0¿I‰wâFç•„–ÐpÐR†ž ñP),f”TÌ eñz=ÎaçðâñŠœ/ ð…ôŽÆ\9ÕËJñaža Oûœ{†w8vë1 ™vˆER”.%3aIƒT Æd²½ÜÌþÙ­sÛ«Ç×€FV6ÔïÞ©rje{­9Ö‹e³œªº(-À° N4fäØúh»Ð(*–ÉZ {§]Ü÷cwÞxêÊù{Ž_}øüÙëG­Œ^+$+±æd3^H'KE9vôCgŒM„¼ v¡ðöq4khV69ˆ¸}1*¥_ÀÉ`º‘Ë4³¥ñb¤—‚‘J(˜×B=Z/K†QðqÒ@q³Õ4g×ÒZZdT3§¿·s&šn'2$ X7 æ¹^zéðü‰kG^>´~beuklystûà챓ë'Nî=~|ïÖÞù±^-ŸgR±˜ºeišn…#A£$ã%7§¼$Mˆ‚hÌxÄÎ$bù4à=‚ø)I!Å…1. çiIadùŽ‘!\`]„ ×L!Nº9¯ƒv‡K‰Êt77ÖJwÁbV´ÌHÌ6šC}ÀRe»¶#Ó‰… O£ïÀ\# ñÍJ@dÄã ³£Ýv-‹è¦ÙœÈ׋fÜ´Ò}'«‰p¡¿o«<]©ÎÖJ“åH)’ª%ïÆD£6Z[Ù^OÀ'£´¤b,ˆ°„³2ÉÃ'ÖXEÒg«¥™•¹îL'œ[™ãwZÜž¾óþ³ýÌËßø§¯\zðüÌæøÙë'÷ÚÛ™kç[9¬§«¥îìlºÒD3~FÂEÙDz¹Ÿã¼ ía—€Ã˜ÏÏÓ¨È8Iÿî!ÖH†cådg¡›l¤"åH¬àcÐÓšÑpÂZ¿Žóqº bÕ ôÒ”]K†Š0-0"+ÕŠº6ë¤ã¹d3¿‚õÅCs'¯-µÆ³ kÝý‡÷nÏ<´|øðÚÒâøÊòT2®Trv$OÆZݶ¬)œ"}ýL¯&´*+á`$—ÎÔKx˜ÕÁ4T;BÉš›`(3äÅ‘X0Ãx6”Œ‰0oʬÁ’¦_ÂÞ7r›‘äÇj*B…ôBý¹b!ž€¨Ë ¤Ë¢VÌ–VæwdºÑPÙrK˜W¢ä¨ÉÄÒÇ…Ej٘ʓî‘Á;n¿æXVæPUÂJ¿ðdCRD —íÊL5;š³+‘l;[+çÛùîlw~c¾=ÙSBa¤›•1V†B…Õ AŒ²Ý™ñ™µÙ‰¥±r/?ºÐ<}åèÕ‡/¾zrt±ûò;/þè—ß¿þØ•KÜyöú™swŸÛ{|«9ÕäS“Ë‹OŸNWë(/¹)fÅýÔ  DgÁ1Qƃóä0\>Âdh«3™f>œ'"åh¼ƒÂ¦¥(lÁ’)$DÒ¢©0'%õ` ¢{Ü®ØVÑ  ù€4à HÀð P¼2U„&r‹èðck¡¾v`jastÿ±åÃ'×–ÖÆ–WÇ\Ú»w~ïÞ…R)1¿8Þ­e ‰R#oDôl5ßœ¥R>†v­IZÔC:´F—ä°L&¤å¡ÀÛCò{܈bÌx¬Üi5'ÇŠÚæÆ]^áBÒûw°–"'Bƒ„ÿv¯ó íÙíu#$E±œ'\$ÅGìäXwâèþ…±dº“B4R„|_ÍÕZåX$Ð/'i;ªÁË*OÑn·Ë¸÷¸÷ :$åF«/ú¯þÓwž{ûÕ+ßX:²C”S…n(€ð†!À(Èû-º; èýW`~‹ ’‹ Ž£T2<”r»ÈcµH¤jÛ}àCÁbЪ„£˜]ëïl6ûþ.¹HÝ•ûÓ"\µÀïaýÖëðo`$ÚñêT! DOˆñbpi{êàÉõÇWNßyàÀñå̓³‡fœÛ€ò¿û›¿ý쯼QŸ®WÆë¥ÑTüd-k¦mƽ,NiýÝò>è ù|¼TC*H¼ƒÀ –º(\¶C`Uv>m¦ãÿsÏíïÞÍ*mTâUòr4P]écš!ÅjõÙCWΜؼ|vÇèR+×Êȶ’($Íb"¬hoÅV¦ ÑùJ*« ‡–æÊñDH×ý¸WèàßÁtP*FÚè®ôÅ(Þ^ꤛéölkvs¶>^OWÒÁxÄÏÈB „fµ £MK×JËÓJDÍ·s½Åöá ûN^9üÜODËa-eúdÊÉ¡°ôJ$àY`Už0ÄL·úæ—>õò§ß —S»PÇnÌ9DxÁ¢Î [™l žti#‘¼¥ðÀl˜°S–¤¬ºpÚ-SPžós”hiÁLXŽÊÑJ4TæGséNÚÌ›b\â£B?”Tít/•ËœzN äuÀت„`ð†•[³áÖ€ÙÐÏðÍx¢j‡²º™”sèòöä¹Ë‡6ÌŒÎUZÓùgV>üΓ?üå×~{óg¸ùë/~ÿÝgßøPe²­$föÎצZf&ÌÆŒTlGnsŽ ¢ˆ—cÕXTO$œé¸]^Ôôg0“lÍNÛ…œ‡¥Ý 5„!ÁQ%b©Ñ°³K½nytâ}Ã.L7Æ÷î]?wzõüÉíkçvÌmNµ§›v6’)¦Z ˆtÁn.’U©º%­4ò“…T+P)ŠÂ0„ð3·ÂJ¤‰ìT#Õ˜oæÆò@ñú\£Ð+Œ-¿+½J®ž3b6Â*¤l½wèS¦5£Ì2«ãíÙ½ éfk®¹tpáì='ï{úúÒÁ9Ñæ£•¤š 1A™ ©LPAd×9fñaƒÐÅp1m’˜Ê! í—I7‹"èß=ö‹G Ål£ lØåöÆàîŒ6o²äpâdFH#øhÆK“r8¨f’µ4oñrLÎv²0 q¤Úé`4M:H¤Q.`LMKF}<«Æcv!/G"CæfAìñz!»˜‰x¦^)´õÉqβÙp¤09¹|òøèöÆÖå³×^zbÇòöÂôÊT©YjtjKóë³£SåT^£kAq£S^l”Á"(êóa4þ­GõL#Sê3Âxxú¨ÓÜÞÙöl;ßÌ—;e=bAeò1ýÝæ´j’Š)¤'×f›3í‰Õ‰Éõ Àûݸû‰«B˜Å4RŒUÆén{n¼3?ÊÄßK×(.ó0Þ³4T ë’­ –‚+ © »½ÎÛCJT9]«vçæÀ­ÝDZÃT€y EctBNõa0n’à %VL¦êYHìl#t×»mõk”ïÔ–0`\·ÁØ`À ŒP%#Â^4…,aýÖoo=ÑŒA˜ÏwS¹v"U ÇJf±›èÌ•÷Oî;»zäòöéûŽÞûü•gßyâÛ?ÿÚg¿û©'>úèÝO__?¹.Åð—4ÌïÌ·ñxxÚAã»ü’½ð "sF&¯•¤(ÈRÄ'˜¬|`Øácy¨*`m~¨PV¨ØnÖÇ{±R~$ƒår}yaã™…S‡Ï=qãñO¼¼c~m¶=ÑNåÓ@ù©Ñ#단1WNÎã[cõ Z[¢YA(žAFì¬]ëGñÎBØ/&Š|w±»´~•®¦¡+–á£7)b¢F©\†|a–óÛ‹àô½¥îê‘••ÃËO}äÉéÍ)å@D¶{{¶›®å„ b&í@Ü&‘ hÐL™´§oH¥ BP-÷ê0 æx|õêjÔ ¦ãf*~ÛÈð⇙PUçÍ °ÜGs~Jô`ì{åPðR$­ˆxÈLYt€“l%^M(q UÊàÔ„Q™j¤ºéh3j–L ļ˜o“–·P¿5ný*ÞŽÃ 2]¦šQ€<ßI†óz¢jU§òÓ[c+Ç6άî»kïÑ»ÞûüÕç>þÔ'¿õö[_}séè²[ô{Dœ4%èT;ýîAñË<¦I°tqÔ0…z:V/–'¡¿vR­&¡éj<é¦y/#8 ÚK³N0ÏTK•n“üšªWRÝñƒ›û¯Ÿ?õȵÇÞyaÇäìx2“d‰cé°®ÔS‘VËYÂ0éDDLkðõxà¶‘n QíÌVÙ²Ó$$iAI¤)”ŠÏm®TF›f2¯d¬lŒPØÊX ÄÃMã?°s—à·sÍF0•º£¨“ Ü$åÁÙ>Þ2Â2ŠeÆ ©p6ªDtL&õ„™nä²íR(Ö IÙÑü-¼o‘`¾…ô-ÈoÑÆÿ ¿U·`ØþQ×þ±WÐùŠ­Xù^ê”·L/U«ŒnŽ.\ÚiûàåÍ÷¼ñÂõ'ßx|ùز“!¨îÁÝ­Oâ¼" CŠÁûl‚È# *'í`1mæÒÁ|ÎË j,…Iš“`DfA]8N'rµ2¥I‘f¥²<×Ú\*/O{à®Ã7Î=ò±gwtF;F(H3P1ÊçQqÿh&:[J” ~±QP?|wŸÇà$§àß¹F®3×)–2­ Xˆ9D¶Öbø=ºØËµr™Z¦Ò­HA \—5BU)*AÌite¢9מß?èâ¡Õ£k÷Ö(™…”“£}’4B2FD­Ú§¨{)ÞàN u÷žIá\rt{eéüÑC÷ßuíåÇ?öƒ/¼þíON]ØQªV–럱Kdm;o™íd¤—¶-Œ—Sa­¿—“E˜2„@™‰`¬ëÌu+ãÕþ)‚ íl/å{~ÿÈ{ºž.¶‹¥v1SÉH¦‚I€Íšz®S[<°V+KQ)ÙL¸°ïâƒç|þÑ•1)ª&jÙ@ʦt>UK¢‚oÈ?HH$y]• S³ì!·gEA3$ÃXÙÚ{ñêå©…ÙÅÍåõCkPꌤL‡8|]ùàð.T … Nk©J”&ŠxC—ÅEqÈ`´€3‚ËޕN³9Ѱ1‘¢5>œ) Þ–Ò“va¬.‡…¨@)<@&ŒÔâv5®DB% ]¨ ù<Ü?{ØßŒ„Ù ˜PÏ"Ðæƒ3_®²+v¨hÁÿx'{¹Ìx±0U,M¥göu¦¶:3ûÆg¶'g¶fæö/U¦Z¡|"ZÉÒÑx£°~òàÉ»/nž>´tdëØµ‹•¹æâŒ ‹Ñ0Ý´x;(î"Y0PJÕHE#›Ý·ÙÙ·\ä4ÐݱÑR§Í™E-µrép&Iæö ºÝ^ÌáñùIB4ÔR§ÊL$q‰’Âzoa*Q)ìñ¹9È•rðM‹]ø¾å\3/Û°Y½¨H[Ùx¤˜4ÒáX5©ÄŘdäÉͼm$cïÿÿœ(÷1îÃ\±#Õ<(ôVÅ W¡¼õOµ€7µÞYØ79½16±ÚÙ;µ°~v{ˆ±zl£1×Y:²~ï‡|ñSùü¾òÌÇ^Z9ypöðöØæjcq®0>j—Kl0äaxDRë^^FÝÅŠ¤*MÍ,Ÿ9¹xùÄâõãW_â•o}ò¹Ï¿Ú\ë&;ɪ  êÚ­\&_FS·1Ñ™m—YÜéó Xq=ZóANëéz&VШű ŒühybcfþÀ2Øp±WnN·òõ\µ]j5ù¥Š’ŠWsûÏžÞ;#Ç…l7qù±s÷}èʽÏ^Φwùw’F´5Pû|·F%7Ž^/O¢"ë&ñ!¿oÄ5^A:™Ïë¥l%“¯¦æ–ÇŸÜÊTb”Œ9Ð!)(äëâÞíôºûGÅaP ríÐnwA­ÈjÁˆÃ… ’Ί²‡hãËÔò©jV «J4n:s“DÄEAU3•°e&BŠ%+!E· > øhW±-3… a-ÕÌE+±h%’jÅÃ¥`¨±Ê@ýXÿXK5®D­2È@Ø,À¯¬p¥_ß¡¬ßªò±š=¾ÜZÚžÞ<º¼~xqyÿìÂöÌüö  >±>¾rtuéÈÊkï¾ñû›ú÷›¿ÿÍÍ?|û?üÔw¿úÀËÏí=wråøáýÎnž:QcM“ Y˜ªûÍ'«nIåéÂÌ|ïྭ‡.­?xöÚ[O¾úíO¼÷d |ºÚáGqCÓË™t·o§õh8 V (¬ñ”AG0ˆ;­Å43̵òV6 E¹·<^-'›Ù½§÷7ç:°Þ™ïM¬L6Çã³½™… (ô «‰ZqéàÆÂåD½ðøìãgî;zéÑ3k'æÕ¤8H 87àËã-pMTfœ´÷ bž]Çí#Cƒ>/i+‘`)]ÌnØlO4×g®ÜsîØ™}Jˆ“‚0ø@T‹æãƒ^ÇÏ=àuïr9ß?0ð÷{öìñy1Y2R »5ña/²{Øm„c‰|ì å¨H>™k• ±h`|u®>=ê7CÁFCÁL5`£,†ó!r~†òѨ…w¸†!Ã'ë¹x-.Úy¤;4òý³f Oùm³`Ze >ù®¿'®àHy4Ûš*O­öì¥}3Óëã«£“ëã[§÷ÞÙ^~ãôÖë_zû¿ù§_ßüý·~þßÿí?~wóoßýåOyé¹çOoŸ>¹uòÄüöv •ìªiXÀ0Ë•êÒRuy9ÜkÎÞuxíÆ©ó¾ÿáO<—š.…Ñúlu† á€1V«.vçµÉbð¶8RÀ=`dápír‘î`Ær:ÅT-kZó]À¸0VY9º‘jåʵ™Í¹¥ý˳«3Ë› Këó èr±PcflíèÖüþÅõãkó¦ÏÜ{ôÀÅõG^¾·2•ÍõR|˜Ûƒð–lf¢Ræ© Ì@݃ˆÇIbP¸QŽ%%Q2¡xÄJX3ËSc³;¯¾÷¡K¥fŠUñD1RlåbùH(ðŽx(ÜK“#(²ÛãBÿ~ÇíÿÇßÿžˆ5¦'EzßžÁÛG0NPmÛˆGúÇòI»˜t1~å+ôê·vlñ!S ‡™€>6?ÉÄ0‚=ê£I¨ìn‚ðÒ4. C¨Wy=i8©‰@¼.ÍЗ·†U¶l» /ö÷ÁÝÚ=¹ÝªÃÕ` ~,˜Ñ¼™k&ºsÑÅv}²\šÌÖ+“•ñµq«ds)ÙθëØç¾ÿå_þíw¸ùŸ¿»ù×ßßüëooþå~ô½O=¶}êøæñ£…ùÚÌT ›ÆÍ€U¯N:°töÔÄñýë÷½úæ×ßx|óÚ2.¨¹@o¥³ƒÅ‰¸iε[æ–;­FÌÒxXbÂïvîñøaaŒÎ«1#ÓÈF‹±b·T¯¥À­§›Ó[ó¥±t;ߘmÏî¼W¶—·onܘ[íÎ?ôÜãw=pybmâôõ“{O®º¸yù‘3ûήÈ1:ßK•Æ nÖíaý^CJ´ q8`û240ÛÏа¡u;867‘)§Gg:kû/ß{vãÀ<%ùxŒåÃñbT ˪­øúކüÞ=^Ôî¿ï}Cƒ{ü¾Û]Ž¿Ü=ˆúGÔ†a»}TæÂ…T¤œ±K)"À¿ß¹›ÐE>l0A=\̳Á “"“¥‚dès¡¨—쟅áx€ÜÃPt@%4܇ ÉéV>ÙÈ$Z©hPB‡Œ|𽋠£Ù€w¨ B/èzNÕ²²QЬb UÆŠ¡dÅ.æ+ãÅl+•¨Å2­tmº–ëô´,FïÂDuß…ÃO|ä™ïýÛ?þ꯿ûÓÍ¿þéæþÇÍ¿üô·¿xëóŸºë{f¶ÖöŸ?½|ì`e~ª¾:?{âÐú¥³î¿|èÑËÏ~õÍ˯<ê¦p›Õr‰±”Ç#áX9j÷/‰ªWŠ!#©ËG>'Žy…cUž;+$¬Œ­DTôòX5\Œv—Ç7Nnƒ…ƒ‘޽űéõ™Õ}+ûŽì¼×ö­Üyï¥×?ûÖ—¾÷å§_{êøå#gî>þôG9ã8€kÆ$ÆWGÍtÐÇ£0™úçÓ³$ÂÁeúæˆ') ‚¡&‹™å­•É…ñÕíÅsWŽ<¹Qj%#=”Ô‚I3 {cZÔpÂ'&  ¡þAÄ?Œcˆ(xXæíÙõßwÝ6Bá|$ 1ÇȧqCál#Ù*‡ŠÉp9͆Áù&¤±V×T•]ÐÚyãyIÁÀXãD?Íù(ÖÏpNœÀ$QŽ„qE¼Ã3 6dåãÀõþõJµ¾€ƒ[Ø·ðþ2;T6ÍbÀ,êÁ’n—Í$à] G‹VºϵәV*YO$jñL;›ëæC[OÁ1+S Èn£+o\úâ·¿ü‡›üÕŸó«?ýûÿ¾ù×?ßüë÷ÿíÇ÷=ýÈ}züðÕóóÇöo^:µuíÜÚåS¼tæC÷=ò©W/t›„˜Ñ‚¥ÐèjwïórWL:™D7—,„j* ävïDÆŠÛ´&š±ËLÂ\0å…n)×-Nnôûˆy¶[mÒƒo\_ÝZ›ê4Fk‡ÎÚ:¹ï¥w^úÝÍß|æŸxî­'zážÎb5Ù°cË'¸ÃËH™™f~ti²Ük‚Aâ’$>*^È€¨æj¹îTsr±{àÄzs¼ˆpåNª:šÏÔ“Á”A2’`žÜJë$ñ·çøP‘DT;È„d¯¹~îÄèÖJiv¬0Õ©ÌŒŠñP “bV¬V”ãa\—Ý),Ïn. ‹Ñ$#‘Í )^‚ð‘§Êf,ÍÆS¥´Ñ›c•r;;³ÒËV#šÍä±±ÅöØR¯;ß©ŽW“•̆w ¡^ZWvz\~DBSËcj26LaÁRvôÀÚ¡—zVk³Õ™òì(T\"ÕªÕ¦Ç],y›Û*Ð8Ëìòù=${ëœZ€´‡`F %ðBPÆÐ!ܪÎgbåb¨gù ¨z²Ž7·ÄœµY9)êv ¸•X®9-Ùˆ¿Çéx´l­³íL¤•¢²“qÉ1’ѵlu²µ°o¹Ò«,í]Fi^ðÚ~ú½ÿ}óϺùg€üWÿõ»Ïýð«Ïö£½õܱG/ßõÒÃ_ùí^ýÆ'Ïn!n&‚%+^¥‰žK¨RL2!ÂY)m'£†®ó8åñÄ iÎT)C±òI3eõÅ|´¯$—­¶z™Nøë•¬Bd|e²5Ó†}L)Ñt؉(9ÛLWÇK{¯¹p =W˵!§:sM#D†œ+çûï€hȃ'hQô`(J‚&%rɉù‰Ù•éæXõÂÕÓÇÏlŽ—pуpN/=ŒËH¢]ì…2!:Àpd·—%åˆ ˜)òNŸ‡ h»/·0Ý«ïÛ¸~züØfaqlãâ‰ã÷^®ÏO²–‘¨W$Ûòñ¬‡c1EÁuͯÈ>AMÛƒ±n”!8Hé’Ÿî«:Ê ‚ôÐ4èï:„¹åaéh©¨–å$ð;$%TT'H”J$ÓËêÀøaf’y ÿÞ~·ª•î¥"ÕpJZ±?¢•h¾—/—­‚©Ä6ñÈL[Õ‰Fu¢ #×.åš+ª´K¥f¡PÏ5F«§ï:þÙ¯~êë?ú@þÏøÙ§¿÷…ßÜüóÏnþî‹¿ü.î7ðùßx:TŠVk¥WžªÔ¦«­Ùúމb12Ëq;$³4êô{âq3•‹êaÕGùÓµB¼š72q% g#ÀoýK>÷Î5ç»Ñj ‡¼f—bׯ–Æ7m(¦˜/§«íb¡™åMv—ûöt-qêòñãwYÚ7—m¤²t}¢L1L…QE/…sš\¬×ô`âXA•䀬šJ,iŽÖš£•ùµ©Ë÷]Ø>º–(Ú(ç¡,Y‰ç=ŒÁôÏ?,&œ¤ßEãJ4\–ƒŽ”¡ÉAÔŠS‡6öÝ8ô‰«{ï=³ïžsw=ûðö§CÅ " ¥Ñ^ ÷0ô Šºh•e:h a[µb%úcd7Nø1Ay(Š”e/Kƒkñè†Â#¶‘J:9¿Uc´‘·pƒfÂ$vhe@ú!z¤ÞÈ›ïY{0ÝM Áp9lC†/…cÕXq¬Tž¨„òaŸˆzÀÆ>˜`†/¥bE°­0瀭…âf$ޤ-àÀ±ó‡ž?|íÑkÿqóOÐÔÿõæ¯ðçùåÍ?}ý@Ù(„ô¬o$rÝÜØJ¯9]ß1Y©µ²Y˜F æ‘ÂéÞ-ÅSÅ8«³»<{”h‹]LA$ITRv¾]X=¼þÞ‘N¸ó¼!«/î_ÞwrÿÜÚ,Á¡Ínuzq¼3ÝlÏ4­Lpby¬3Û¶Ò¡ùÍyRHLiqÞ6´Ë‰ùGï ×ÍÈÒɳg’é$NâœÈJš¦01ÛÙØ¿4¿:yâüáƒ'÷‚žË!žQ¡¹’åx}²ªÄdBí_G‚J$bB!C9hÂ' Z*‘íuŒ4õÆÂô‘{î<þäµó/=xí£O>ö©Wïyù©Êü¸5(¹7ˆÅ=½Çãí5gYRSù Eˆãoœ•ûÎM1¬¦‰A*8¤R“ÕXy/ÇJ¶­'·NÀJµ‹ÑZÆ#b.‘⺖zetrAÖ,€µÇ93;šWSZj$˜\ª´íêt=QOq–8€ –줼 ~^Õ¢f´Œ“bPDJH6¢=¢Å ÑÙµ©éÕÉætãÈ]G_ÿ⛿»ùÇßÜüã¯ÁÎñ­ O_ËM”ý@l!V‰ô–º…NnG=•]ëÕ+nçJ¸!š/Í”ˆ¨“q ¶,GõP.Z«ØPƺó½õ£›ÅÑêTÒ#è9Œ¹}‹óÛ‹g¯ŸKâÁh ]HLÎM-O¬XéÌ´kcÕP*ÉEW¬÷æÆã„du!ÇE!`d+•sϧ3 Qbíh0™±›ÝòìÒhs´´º=wþêÉÞLƒ–1ébTúŽá;Œ¸‘ke!ÐÆ«ýK8÷ #¼¥ÙÅL ߃ú"•’œˆy$Þ S«‰ÖK­ùÅ+‡/½þ臿õÉg¿øÖÞ˧K»Ýã¤5ÍNgÅ@ÐG2N”pb$ÄoŽ;pÂKðÃ$¥EA£§†CV:Á›Ú âÂ|”®Pº “ðVc1< "*''BbÌaü>™ d#¬=HºG/°ßÈ…#µ¤ž~ç…˜e=\‰Þº:5ZOäzE(uTˆ1xÉÖh£T– ˆ&£Z¾6Ö„"Y*)S‚Q–ÈëcÕúX§ï¡ ‡¶În_}úîïþ濾ùû~ýí­»&[éþAfJ s±²]êåØŽj*7ÕíYA'};‡oC|¤dƒ£X 3õþn„H9-Å¡ƒA2¯MÔ÷-.×gZ@ëÂX(’x¯ZÛ8² S¯=Þ°ãÁJ«fShæsõ,ÌJ݌Ύ/l¬d*ÅöĸJ¡ ëBq7F8üÆ ¡hüÀ¡ýéLLÓ;¢g ѹ¥ÞòÆd¾mO”AÉsµ¤ Ùíܲønç`ªœ•lI‰+éV¦1Û!=»ýaª˜jÖâõª‹gÿÛÞÏGÃ…‰^ev"ÙâÚ‘‡Þ}éµ~þÎJM5‡Y|à½k8@L0’÷¡´‡^À8lÀëÝíòøIÁé§½8ç%˜·gñQ2Ï›ŠT½,ááR—0* ÙÒµ[ç&†‚(ü‰àºh•ÒÐ÷I¯‹Ç·–¶Âå$Ì€H5ÅÚ’–1íZ<ÞJ÷Ï}®Æ!ùZ…(°«1ÝáMÉMùQž0â¡D1]jUãm-”lÖx¹KL1–1½5ݘݜ9pþàæ™­•“ë7>üà£o<ªØéfº2ZªOT ®œ¬ÆÃÙÐŽ¨64Ýé¶âA?ëÃU\KëÅÉRyº’j§Ô¤Ö¯ƒí|ºž¼Û³…íÅt#›ï•"å8ˆ¹UŒ‚°ÏlÍoß‚4Wé”—6æÁ¿“ù˜²t[O‚$í@$Ë¥BñþÅF3KpJ€5 Ž¥1FRÐÊêB½žËdì|1Ú+?½u÷s§/›­7ÇJº%9üÃnÜKËP‹‰h.Åšà ™bÎ0á&¼>‘yïûîÙ!@î`1—mo?µrþȵ·ž|êëo<ø™&Nn°é_åQAp£$Jpéòà^?éÅ(˜…Nua˜7"º¤½h8DÁܨDœð–îÀõû'š1FŠ»‘M‡ Y" S¸“%q]ↃÁ=5Hú”¤,$¬RJŒx€sð>6"K¶]K€ëƒXF+I= e#ÜMÈŒ`Ê‘\¯_•ÝŸîµçŽì?xõâö]gxýù¿ùñ}œK,4ÈT`˜Ç‚Ф1ZðÞ> (ü°®—sÈëóàœÃO{pÖ ÖŽ¡~–bxª™EŠ1)ªúDŒÐX!¬s!1UÃz½p¡0B’„ªB[Æ1'Ez8"$55³Éd³r‡Ï¹óx%Ê-àC”wˆò¦`—“éàÂ*¥sÅ^–~ï_˜ 3 ©– kI[ÙF(ÉÖóâh•!$ÂH‘R¤»ØY=ºúð‹½çL©›ë<ú¡‡žíÙ{¹öÒ›/<ñâã;PJp㤋Âö ND#@ Ú«íd7Ù˜¯Åj+ìεj£ål-¹rh¾2žÍ¶ÅÑl¬eŒÊXyqßâò¾åîì(!ÒÙjÁ‹£Œ Ⱥ.ª_‚¤¦óÅ\¹ Ïz3³™JÕC¤$Œø¼>w!>/†´ºýû·GÛv­Üm×F{ÍX"Œ00…@Ì@xÜCûosìvà^7…üÏÀE6”°=ŽÝ®Lè_D2‚“C8õ§g7F €–ÏÍ90{üÀ¾ëçÏb'è9 ™£,>T ×ë­åfu¦œ¬ÇÀê+½R¾–›ïN¬vê3…Âh*^ ‡sf©›‡¢5¾8¾ud+]ÎjaÓN%ÌH„“UJøqŠ¢ŸŸvyINLäŠK›[Ýé7ûhbÐë¼}hÎSjPçAÕe]“5I0d)¶šµR¥ é’ô{)ÄEúRµZöáÃl×°‹$;R,ÃC#¨H(‘‹†ý&˜F<—¬Ô3͆ïô“.r5ä,%¥Q!&T ù Ô9B’yÃÙ€Ðý eyICÓøQÔ“I'M»yn„¦FhzÚ<Ã#¢äÐ'CùD×Dm»!.ȇåT@Jêdˆsò^Æ’ü åWhDe`ð¶¦%-ÞRCÂ’­äZ9+Ê·²S«ãån±Ø,U»õB£”(¤ÊÚÚÁÍS—Îìð€’û!Ùr¶jm5Hf¦öMf{iÀ»5ÓHW“ùZvãàz±›ËuÒ¹N&Q‰E‹‘ÆD}ncnfmv|~B4ÞFÄnt{Št#˜¤HŠ“dy^ÑšÉUkF,ê@ý÷3¤ŸÆÜ#¼*UšµP88<4ÀӔ³¦¦M]”yêÙ9²ûý· !ÎD%ËD 1 è‚ A…”8V‘=8á!(Í £äÎxÅ#*TØժ͕ÜüD~alû¼xå¥Gö]=•«:b€ðyxá/Åy–ä•A—o؇0ª¢FBÁTÄÊÆŒd ¸dJÈÊUæ÷X;z¤1;‘häé @[¼”P£¤U‰†«±T7ÇE¥!Bˆ2«†s¢¸Ÿfa"úhðF‘Òu¨mn–EÅ#ðÃ|`Úè¨`²Ò‡œ¦G|÷ßî¢F¶WM4óBTà † ñ|T‘â†W"¡æñ]Nô¹nåcP•âzÂì_WM&« 30z¦–ÎÕòåvµØ,'A3²q(uÍÉöNÃss$’ô\ˆKáš=º1oÄ’õxm¢š®¦{Ó½•íU;Qcš•³óíb®Y¨ŽÖg×öÙg§cFÔªuÛ¿›££’œ“Ùœ¢êÍz!ûÄ0$"Q„Âí£ÉA/d#L€ë…lN&³–çI (rÈðã½õ»!1ºè$|·9öxŒÒ„d%+¦]„O ›>Šê;N9p ÈífET5PÝR©êâüêùS[WÏï½væÕo|úÒ‡:ûôÝSGVâÝ¢W¡vcn»i ª¶—d Nv¡ÄíC#·k§“@#Ð׋ˆÜ»}„ž(ȱL¢Þ:páÂÂÁ}¹ÑÆòѽÑzðæcr¬•²ëñd7i$†9΋BÀäu¼½$ +Ào„ãqIæ :: ’:¤zÁ ¿bD7-ÀÔ½,,9€ÜA~‘Ä}·{† ª§Â©VÁÌE…b-˜Íð›ÉTP~ëiËH‡=¬ßH…’54лªÉZu¬ÜœlÅl5Ÿ«*Zµ×(¶+éjv‡‹fý’°qî&œtXP2z¢h.4Ò4ä2è`•^mqs*11‰¡41œMÛõñ…™Å½ësë+Z8Xi7ù\ÀÛɯ(z(dXV:›‰%â…þyg"ÊP#~πDž°4!ò¹dÓ,5›…Z¥¿ßü~p0ô[CÓ(Št¸/8ê¡1Zÿ~àŽ=>§ÔjãÐ%K>dSýSÊ)æklFôK¢ê¸i¦G{õå…Þ½v牧>óÑw~ôåÇ>õáùs[¹™Zv¢ÂFÔ;üÃ;}Ž!Ô7ä÷*{œ‡’ ~‡Ã¹Óé@E“„¿À¨TklîÀáÍ3gOÞ{ýÀ]çÆ·–Ú«SZ.ìÓ )­‡ªQ>}_g¢ÒNbˆ`…þmãXÞáGÜÞ[» ú—y’Šˆ'¬L—'Eù8ÑÏÉ^Zr“‚‡|¬äçú·æ—q¤‡©ï‡*/KÒº¤ÅCf&*DB4Ìf,„µäP>ÌÚd0˜±òbu¼škeìÚx%^Œ5Ç[ùzÈ ¨[•B«œow¸9ÞÅÑ»0·KÄBåhm¾Y›«·[µéz±WÎÔó½¹ñÉÅYÑ 0šêçàÓ~–æó+ûö-lnØ™4 —¯Õš&ž•¥`4Ïf8I´£v£Uß:¸"ºn¡ss{©~XÛé!x¾Xk0‚´{Ï0†’˜¥ ’Àp7üç×ghY€T\mçZµaÔë$NW¼®‡CÉBáTPœ$ç¢x\505€ÀWÒã[›çO½ÿÊÙ'îÛ~þKonÝsñÌÉ©Šš Bv³¨Ÿ§¼4I+²l†Füè×À@æư! Ä :Ãäô‰{ï½øèÃÇï½úÌ;}äµç½Ÿ 즘…¤(Úxˆ»rùP7‚»üØÇoäÆ EnÃá…`(V, £˜Ÿl£ \ÿîdà§xh´ŠÕ /Í ú| ¥UE‹ØZ4Ìõ`.aW2ñFAÏØ„ÁK±@¢žI@´Zž° ‘t#Ó˜jD +LVâX Ò©³a€ªgë…T%ÛÇ[ˆFMbÂz¬™«/tÆ6§ÚËþ…¾óí\»Ø˜ì#éÊr+úYÙMò”âV}t²Ò¥$•׬¢BnÈI,ÖkÕvËŽÇM$N Ë×K Ë|@ÙåÞírûüw ìv¸F<~·C1zxÈ…ú06™ËëtyH†µÁŒ:ÖÔd®Q¯ŽöàË``Ï—k·ÃÁ«ªfÙ~V¤À{ç`«\Ȧ͒J5–]½ëÆËÚý<ò»_}âÊK—ÖzÿÃ{¸Oõ²b\AU2²´XTx)hD³Y€gÀë“,[G<,çf9Ò0õ|!9Úß·wõ̉óÝÿÒ»¿òìCZ!"gƒwÃ0Ü f–cé±2j²»H‡Ãåƒ:{1,œ’JQ1Q‚ˆî IÈçy8›ë¿ñ=”ôÞ} \4r?«ÑÝ»Çí÷Ñ<£HIu¤ÃIYÖcQ=Õ?T¯§£ZÚ¦‚"Íœ«&cå¸SCÙP¦‘IÕRån©7×mMµÀ¿c­ÞÌXk¢Sh–ÓÕ\_ÏS½6ŸÛõ\wmº6ßN´Òµ¹F{±Û˜n%+™©•…±ùYH[ý¼›„ k¢á£%Z6ä`„ÓLÉø^Óu)¨w:n·ÙíTj¥d:KÇ¢éËøüÔ°œõ34%Éö°Ç?èôܶ¸Äù¡þ¦BIüØåÝ=4âðùÐÀXìƒCCïÛ³´wÀíáTM Zw ¹Qf"h^V"”€‹Ñh²ÕÜwñÜ‘ëw}äžÙã[‹göºq¾¼:Z\î¼Ûe7âÁ¢åW1Ê`ríB$ÇD¦à·s—ËÉêz¼T‘íØIP,0¤Lª±¶”Ÿ;~àcßúÒsŸy³4ßå’2* ò§Œz5BÉXf)>Â#n™pºýÅ¥9â=fƒŒã8¨··»-qEÍdŠÑÍTA#{ÕÇj>Fì½´ c‚†° îD)'Jº0XA±h©ÀÛA5‰ÕóÁB ›]ŠFKBXȶ²…nÁ·Óõôèüho®Wl—ê£MÀø í)QLC^ëã½÷â™±íÕñí¥‰­ùp%¦eŒÎr¯6ÝÈ4óÍ©ÞØÂ¼ ïqð@>R† çjQœ7•PŠ‘C¤¨÷oýJ ” Ð’•¦ßM;ÏdR¹l,›èN/Lw&ºÍñ6´sJæß ¡F4fDb°]†\^Ÿ ûwäÜN¿×ƒúü¸×C£s¡øn§ûïwÒÈn·¦9£hœ¬{ú’@qÃ~—ß‚—Jcãck«3û¶^øäǾú/?øñŸ~õú?|föØÆôѵH7„¹aÉ'¥´òtm6è—PÆà>8r;4×aÄé¥0Ñ?=à43L2nNkÕ+½}ë{/Ÿ=xÏÅÏüã×zýC)°ÿ¤v;9´‡u²q5PŒ¨Ùp¢]´*éÛ‘Û‹}~£õÓ8¦(;ý>>I!I57Ói(èœ d ðö­…€›–†1(÷¬ø9åÖõA#¡¬ŒÁ ¥†}(&Knžñ4aˆÝ™Pª•ÑSz ¥ç:Ùd- å»Ô+UGA½ó•^¿‰Õz @"à zž©åvì¿vqß•³sG7j‹Ýh=Yš¬€sÃô¯Ž·ºsS‰R7Á¡¬†0º“H)Œq§Eï`,GËÙïítä¼0µ)†‡\²Ì°KDs…L¡Z¬w›©Ñd1ƒñô°ßã¥H3O—*ZÈö›=~—qŒx=nÔï#¼~ÂéE^23ÌëÈîé;"`vûq—õ¢Ô÷Åð*É™Vkzïú©»¯|ógÿøû›ÿõ»›ÿùåŸ|{ùÔ¾öú´Ý̶üAtÑÈt;çæ¼>Á¯D5>(èÑÀí#;™~ìÏgUBUÞ?2² AË6Š…@%7qxãÎg|ùËŸxæSY»pÐ¨ÆØ„â à|RÛ•ãñfÁ*¥ð€¸& '¢ëD°]N÷NgŠîÁ±;PÿÇpQÛ®”•D<×é(Ñ(Hú ‚ûD QLL áZ€¥bzXy… ¾.äý›190JDÁÍ0C$6BcJÒÊU#ýC,P¤x5ZÍ÷–c•±þÍ Ê¥v­1ÖšA¼Se;ó`Gkkiëò©ã7îYËtfÇëãc„¤81†”‚n\òÑš—VQÞÀyƒ’B¼fw&U+îƒÙ@ ·ðöá$É ¹¤iñd Oå3­1àw7 !,%: J–†½¾÷ïÚ½kh%i 2ö°Ûéðy½€79âA¾jöÞ‰ø­áô.^ÜýÞ@hÞ‰÷o1ÌÉj©ØkÅ«ùÆìØs{å;?ÿÇïþ⟎];©å°€€ø=¤¸`¤jýKŸb…˜öyi¿di²m:(ì.‡[à|l®8?¶yéø}æ¥/~¬·o.X i²y9Hõò±fHV™êȱÐNŸÓAc$'2² }ŒR5Ç ’„Kˆpð¨Ï£É…©‰æÒBqbüƒ.Ì0 6e# ÊŠúÝÉKAñ‰ªØECJ‡4'zûçQñ>¶-è¿ìåøšÜƒy!µ'ê©v6V‹ZÅ`®“Îw!¸Å |—{ÃK©J®Øªv§Çoèß ç·ðN–Ó;¢¥³¯>ÿÐóŸ~õüCwµºéF¶Ð.WG;¡TÊ…3nR¤dÛM@š€0©Ã ä !’]ÛÔˆ¦N ‹±‚Ÿdü §xZVÀ0¡åË¥J«I'½$æ!¡G¥iE2ãQ;•ä5Í‹ã> ‡šÎ°Âð°×0hÁ9ý¤ÃG€‡¹0Ú€Ñ.„rxq§—𣠂@AÇI»]à44­Ê‘|ª2ÚBêNÏ€3Vì½ñÌ#‹7‰½Ý3‚©"®‰rÔôñ˜Ü|?(ŠA0J&U[Eb„ð8 Ó$%+MO,?¸uùä¥çîÿÈW?~çÓ÷D»™ül-Ñ͆k1«M´2©V¾4ÖÈwë¤*îò8…Xî!(›5M(Œð,ŸŠgf&†ß2y&Ñk[•¦k;½^Þ¶ãívnz:;1)g².I‚œ(*˜n¸¡˜q2 @ÝCò ®<„S\QÝÚrÞýQËÇ É@ÌÜqߛϿöÍÏ>òæs«g¶m˜¶àü™|«Â¨ò·VB¬óR)E )â’F*?#úhÔb³ë£8?Åy0³ä!Àza‰öo­J¹vxýœð‘l”cRå"!rÿëö÷ÿ÷üókÁ€ ñ§kò:Ê’Œ‚Ñ’ÐB¿7<çðS#^ aüȭטÃpèMSÐÍRËíR8ey)­Ðƒ¾áA¯Œç®¿ƒSØ9âö1ý›Ñšˆð„sR ˆjVÊt#ÃØÐ :ìñP1ÑXšj¯Íf»ç»zâÁ ÷¿úhq®Vœ­˜eëvt§–ÑÓíl eÀVJ×òàPÃ^/ÔÄpVôo¦ª^EòT¹˜míÛØÿõ¹ó''NÞ{í®Îöd@øI!_œšX½pfóÊÅÕ;ÏN9ÐÞ»V[^ˆuZ\,FYa˜ˆ¢úDÙ/Êhÿ.ñ@wÑ'H~©Æ´]ÎFª©@¶c¸l7­ãÕpq4Wêïb»Ò™žhNŒ–Û5ˆlÐŒ` xÛYð3sÇG¾û…§?ÿúù'îž>´d×âh¬\T¨ý»a|aM$D»ÿ„AbtÃEP('Ò²J¤q^f÷ÛFzqº÷e„ôá ÉHº)Zð¼Çx‚)Qö¤ ÇþÇmï¿mh÷°Ïé§1„_“$E`yÅœý7âÁÝ þ<«…Ôp‚Uƒ^‚¼ÝíCY‡ô¸Hv>ÔRH4e7zÕÙ•©±Ù® ³ƒîÝð¯p'yÆŒDÀSÕ$úÇÚeBKêïcÁ<›ÓÙd)Í…q q’#CøerÕ¹îÖ…cÛwžš;¶÷¹Ï¼úàko_>œË«"¨:DǪ±T=¨¤¤êDàkø’FÈþíC\4íäX¯* Ùdnazö܉­W·î¿6zâà©§¹þÊ [—/ŠéDar|ëÎó×_~îÞ×_ºôÂÓûï¹¼xîÄâ™ãÓ‡4V–"º–ÍPÁ ¢(~IAe`¹ìeà7"+¸®„Š©Òd#ÞHÇs©V4Û‰gÛ‰êdéÞ‰öèÜtºRÌÕ`nAÍ%±`ï/ÿû?žxôjue¼<׉ճ©FA‹Y´÷F>`¹p~ÐÇ |ÐϘ¤ûX3BÃ(Nɪ´ ViVØ…¢|mÄ‹УœPK@£‰ š–ûwig%VÒ|$½Çµ B<ègu næõB¢Ð°‚VLÕmœ‘†¼ØJ0f(QoÖgæôD &øÒ¿{X»Ãƒ;=}ý 9g‰pÂ.ÖKùZf×È8‡8üƒ”ˆ¿§ønǰ¦Kf«X¡Ú~ÇÈ«I¬&2•©eŠBk¦Hü2Š´œ13µÍ‹ÇüÈ3}äɇ>òD~ªªF©ÃÙ™š›»ptß;çOÜwùÌÊñƒ\ØDeè-¼‹ç?RAQÃ1è'öxpÍJB-” ³73ž*Ç Ù‹É®pQ7bZÆDAçq!³»ƒ”Ì…³q#Vc¦–ZŸW"F8ŸVÛíÌk'×.8ùÈ]oû³w>|­»8a¤ÂýDSc‘ 1¤(åM-Ûã÷;i¢ø0K÷«—`bJH+פVcîÆÕÖÕ³+Ï?røÍç?öûŸ}çæ¾ô¯d—¦<†ÄÄBÁJ®½<óúgßþsÿ°ÿüçßýâ?nþí_ÿ÷ïßùÆ—>óƒoï¿r穇8ÿäû®]ëlïKN͈…Ò¤2á".VÀ%¦Ðª@dÉUSÍÑJ¥U(5 Åz¹Öíäªu3–&…«F)ùšRŠm‡2q»ß1b£·w¾:;n‹R8îÄy”Õû£ÿÔ/ÉCrnŠõAò%T32½ñ‰½ÛÝåe9bcÉ&ìt”×x#XºÒu;È©2-‰zÈf¹Aª4+ÒK²ƒ~d—×íáÈ]~¦ò‚mÔ§Çì|šÒäN«hZ ìôà;]ÞAŠŠôšsçŽÎ_öÛŸ¿§ÎTX·.Г‰jÊž\›»ñäƒ_þî×þØ¿Þóoßøé¾ðÃoÿîæÍùëŸë“>päÞ{çOœÝw ´¸Ì§sB"K÷˺*Å¢™‰Ù¥ñ…ñîT«Þ+'óÑZ»ZiÕºS“²âðFí½þ¬‚ û9Ž5ÔP&º£¶4ºqöÈÒábØòS¤DhÕO©°DXÅÏH ï ¢l0(ò3Ó­Õ•åãG§ö®…r >m1¢f0fì€T$CaU‘‘ûí[3c‚öâ\ÿ)8¹ÇçD}ЃQ…~£2[ï–ºMRÿ×·;}èî—ÃC²ÎE£™Ù‰¹sÇV®9ñä½Ï}ác/¼û±“7.ׯ߻§ÅV}eFÎÅݲèäÅœ†¸o$pÑì?”ÇSÕüØâxk¦¥' ŸÐ¿¾ÄAs´ó&En·kDݹ‰ÞÂT}º§Äƒj*d×Òg¾òüîžýä+ '7_=mçâÛ Å±t´B¢¢ð‚DÑËËÖ(Î#^ã¤A?N(//QfTJŒvgëáö¿ðä]ï¾}õ+ŸzóÿúÙÿýë+{Em•˜T$PL»Eš±ôd£®9Õyäù'üïÿú“ßýòßoþå7oþìÿÇooÞüùßþ뛿øÅo¾µÿÒåí».¯¿XZX²šm­X¢"a5›j.LM¬Í7§Ú͉F©]HâåV¹Ü¬åk5ÈÅ(-¼î%e”ïy¼ûG5yZ‰˜;*³Ýl·a P´Ü„ÀÈ–ŸT}¸ì#?ÝÇÛÇŠ´PñìÔxum!1Þ)ÎOl¯´—¦*­T-[hÒ¥T, ÅCzX×,H:¯©¡XZ Æü´0Œôof»Óã>„ôÂh3”OrA­Ÿ_Eyàv»ýNAók„£Íf~q&½49éø]¯<þ¹ýÎÏnþá«ÿú½{_|ôø;Ç®,œ=Ð;°š™ Õëˆa9ÝÍP)ˆ ]:hF nñAÅÃàˆÐ )’E¥þiF¤Ä¿o÷#¨ÌÌHFô¤Ý?‹Y"ÛK‹G7?ò…·òç_üúæŸn¼ü„’Œ«Á€³ÃQ[Rd /ÒRÖjùjÈåÇYyÈ‹Ã6d£©`½5{îüÌå;}äù“{ùÿøÇwþøó~ôõê¡ $f6׿‹“Ý eCZ¤”©Nvâ•̱Kg_ùä[|艧?úòû+€ü×7ÿ,ÿùþ×—þñŸ^ÿÒWîÿðË._];aéÜ¹ÆæF¸ÓÖ‹)§ñFi¼Öœn¥«éb«Ø/Ùå"8+ë`m«Ò²åcTƺ g‰­+¤*ì(M¢À`\Ð<¸Hp&Jéà~"Û{Oˆã$>d…J…ìÜ8hìØ‘ÍöÖâÚ¹#g¸|þ+«‡7*½J¾‘+5‹ÙJ 7£¦“ ªAîBðÝ^ÿ†â~¿ Õ3You§3òûÀßÿÝí·í†>³kÐ࢟ì§ÂÎúÆÜ™ã™•©™‹Gî{û…·~ðÅïþñ§ÿ~óÏÿ~óOÿÞfNn,\Ø?wnÿüÙÃw#Ž^¬zÓ+ê^f “껽#~'.ó„ª20­Ç„<èC|4éÄÔ?Œz‚«‚—'õ”MBn´Zœjn]8úÉoqbÿ’–±)•geA64ISqŠ$HŠå‚¤Í ],7ü3脺 :1©X>ÓÊ/,mݸ±tßõ…‡ï¹ðé7^ÿÍ¿€˜o?~Ÿ?ÚÉaÑfIKF| H‡b•l(¯Lt6Žì.ÎðV ³0÷ñ¯|ù—ÿùW@ý¿úÕ—ÿñÇ?ýó_¾ÿëß<ûÎÇïzúé#=0yêhûàfgÿZyq¢4өδ‹ch†0¦lÂJÄ}$Å«B (£ ,À§‚ý£ ïeh'‰í¨Mõå’d†I^vÓ x¼˜â%d  ) ŠåÙ©Ù3‡.Ÿ;èÜÓ÷¿ô¥¿öå_|øj´’ˆcÉr²5ÙlŒÖ­DH ©’!ydÇ;àÇöø‘(l 9Â`˜.„Ëé=¸[°œ©Þ>2¸kÄž¢y % äL4º³GnÝsyåêÙû.<ñîë÷|ôÉOþã—þùo¿ü·›ÿþîO¿~ãõÇïû™æ¡¹é3Ûµ½ó‰©nsc5ÞëEM>a-s„ôy9ÔÇ÷6*X~=´æ@I7±¨ £>…áŠÀ˜xeÚ”="*&íbªN·ÌXª›ÆÀìI &.íÁ„"(Žõ 0‡åpúÕ¯œ~ú±é Ç×ï¾xìÑ{fOîëîï¬NõÏbnäÓµ‚•Œ‰cyJPú´2 ti˜ˆ”Ä(5ä§ Ý1¹ºh¥Ó8Û¿+ŸŸPpÆ@HÝöõœRBB(HeÊ“sGLŸÙ?qnûðcWÞúÁ—>õã¯]|âžê\Ç+ RX‰æcã cãóãv* `Cv@·&I//¸yÎͳNžÚ…y(/m)·yosþÏÝô³”Ç=¶s÷Aƒë•Hzlc+Òm'ç&V®Ÿ[¼zâÆ;ÏŸ|âÊ¡ûNÝóÒ_ø—¯~ò컯|ÿo?ûøO¿|íõÇ–/.­O,Ÿ?:yx{l{]Íļµ  æ,B%osî"ÔþÑñÛØÊszÐGÓ™Z-šÏƒ—û A‘ø:i Wû‘Q dë±z¾8Ñ"Miˆð:((?G8 ÂGyý“ïL“ ˜‚A%‘‚NN·+½öã'Ol=|ÿâý×.}úÍ×~ùOûÍ¿zö¡;f·@ÒVÀÃ’>– …VùD9k—2RÌÊuÍÙ ÉÁçáŒg¤ªÂ4=}ýúÏþô§ß÷ý/¿ê‹üÍOþô‡WÞxþO¾öÔ»o{øêÖå“[w«L·sJ8›%cÏCŠô‘ %h(#3jš J5É!¼„K  ;¦W—äP¥À{ØMQ|ÐG¨n§ ¡ªèz&½yöÔÂɃºséÚ±g¾üÖçÿí;Ï|öµìTCL(ƒÇ%ʈ Íb¥SIS`á¬Ââ<5‚£R,"Ç#ˆ&"ºmwî;Ð)n²!ÕLE˜øÑìˆÛ‡R<ÌÄæÜò±ã+ÎvnŸ{ñ±K¯=qâ©kûï=IÆùäXæðÝÇ^úÒkÿÑç¾ðëo~ìŸ>÷…ß|ãŸ|þì³W¯|øÁ>úÌ«§ñç}~Ågd5ÑæHtÒ~¿À)‘ä€%3Éb9œÉR ÌwÒCÓ>–½¹ƒB¡8øÚ+PˆÌJÑ`¤’ATÖÁa|D棨BíAF|Î…* ©‰e.^ô*†[6 +•_»zyó¾»»g/?x÷ý_ýÌSßÿ*8·Ø-¯.Bpa²ÆP–`5‘ÖEB—<"-ÇÃÉF“E1Dyž”eɲ0Y†ÚYžšºÿÅžyçís>¼ÿž+ó—N~ôÇ_õ{_>û¡‡–.½ú£ן{äÞ=Ú˜KÕJñb^†A"ÙOr<”¥HŠRÌþ93$÷z5·£91ˆFYÇY¡dq”Ñ!×Ñz˜ǬR);Ñ­.MMÛÛ9ºüÂ7Þù⯿× lÜu4F¡<†ð$.Т!‡“v8aK çp?Ýáv à”f1n%»ÕX«H„$)Z<¼9±±* âvÇÈðmƒŒ¨ÀG f «'O¯?wîéÇöÞw×Ç~òg¿ú±+¯>lu’r(;™O¥G·ÇO>|îÙ/¼üî/ÿáãÿü™oþé»_úÕ×Þúî'/>}==QtÁLr‚ 5-ÉiUŽ©DÈxœe·Ûë@ûMa—Û{»Ã5àïß>Ýϳ^ކáa)û!³FBñZ!;VËMÖ­jRˆkd¢C´KŒéœ­éÙf¨»IÒ!©˜×J­Úʾ•«—î|åÅ+{í_ÿô¿ÿùó?úÆÌµ³\=‹ÇL·Ä M+<£ð¬ ¡‡07?† 7O` ¬ }ûȈlY^dCDT%PÈmo.œ:6sòÈÚ•óÏ|õS¯|ÿ‹/~ã³ ´‘ñêÔÑÍ;Ÿ¸ñô›/ßûô£Û'¶§§TËF .r"ÊŠªãô.ê¾þ]É%Å;0Ú‰3;Š­š‹0ŠîDiV A‹Åt9– äsåñƒ‰‰úê]G÷Ýöž7ž|öÝn_;™¯Ò¶JåaÌë£ ŽRgÅ#©BÖ°ƒ(ƒ zN݃zY+@R´‘ãc:QbÌ(Dâ·{†ú·)U$ÅȆåg„üØøìÑÃG¸{ýúùû?ñÊ«ßÿ“ï¾6sz]-™|\Ð3Zÿ”øN¬„òóÕg>÷â~þÅoýñ[_þåW®½xÏøþéPÿ!‘ÂXº8ž°ËŠš¤Ò-»8–O6²f6ᤨþST1ÒS·öÐ¥9pbÃ÷x½ E^–FÎÃã¼,I¤H#ÓÝœÊOU‚;ÙM³n'º ¸Á„«i1e°Ôˆ$ó™Bq~}ãÎ{V¯_>úôc~þß¾ùŸß¿yó‘¯|šo™b·^‰ÁD†’Xo¬—P6¨ ª¸ñzEÎI“~žCÁKÓ`‚#ÎÛV´Q­,Ìt÷o´lLœ>|à‘»Ÿþò;|â¥+¯>™˜mYb¸U˜Ü·råñ®?þÐÚ¡ån—Ó^’Áx†Ž¡¼‚p2^Ϋ~Vq¼çvÔ':²e"q†ÕBð R âšiŠ¥¹©ùӇϚ:µy׋~å×ßøí]~þ×NÅÛEŸLƒîñºœ•¥hFE]eeÑûnÞ=àw{9JŽ! ²6Àl×Ó0؈z›p˜ö}±‚!„áÕhbáèáµ;O_|þñcOÞûæ?ýÃ3_ýØég®;‰H+fW,#¥˜i1I-­z5D)ê½½ËÏ_zó›o¾û(ࡦ´ÚL%×MXW‡ýò€™#KŠ©^‰þ «_x'ÁŒ`”›qc¡8ìñúåNœðPÂq §n’F|nG—SFs¥;º9Þ\jt×:ÉV Ó|ˆâõˆÞt·ì”ýºìÕôP­5üÜõç_;þÔ£û¾ñÄ—?÷ÖÏ~ô±Ÿÿ¸sæ°+n©0tn5aG²‰$¬X:)+^Ï#ªð¿†(š¤xƒ¹Pª:à÷íF|ˆ&GZµÑ{§Néž<0{åô‰ç¾ðÒ£÷¾ù «[¨¯M™•T¨”_[L7ªXTµ#¤¤¢œÔ?‰bIEïBå%?+Þ(¯AvóÒòŽñ¥iÞ„àNƒ™Ã¯IÕଈOÄ:ÍÙ“§Oí›»°ÿž·žz拯½ýƒÏø o,ŸÞ¢kÀð>8<ä%iœ$=È+ºËŽx½8Ç2²ˆqÔŽ=t…“£¦1\D¡m™°Bì"œ|Ü”“¶’ˆ’IÎf:ñƒ{·î¾°~Ϲg¾úγ_çÉ/´¼wT*«'W‹½LªbçjqF'be[ŒI>ÕÏ%8«š>0“+h)C²å|; Ó•¸êˆ–µÂhRMÊC”ë6ïÈ.Äï è/¾ÛùI'΂¾ÁvA8Áˆ'Ä H_ÿi6Û6_±S¯NÕ'6ÆV.,˜êÌWZ3…òh2R˜)¥=×̶‹”¡(Édomï™û}æ­ÏÞûÖk}ÿÍ¿}â?9üÌ#ƒ¶6hŠä“¢ÆÃ¹j>[ÍE =mõó¿È1ÍŒŒà’ æ²Ëí¦ºjÙTyivýê…Íû¯¬Ü×ÉWŸzú[Ÿyìs¯ÝóÚ“‘±’Ýɇê³”̵ÌtÂEõoPÐ?«ê¸¡LF XB¢„šíçDÐsÀ›€Õúޱå)è¸,ªâa9*`²Ùx»YYšY»trêôÖÚ=Ç_úÞ'_úÖÛ¾ñäÖÅClTÝ…:îð ûyÆCP#ø VÑ-Ͱ1š÷à$%м¦ÚåÄ<ºƒP™Û={†(7n²RÚø}àÿÜI:Р€–rtÐÌw{µùÙÈh­}xuáʱ»ßùе·Ÿ^º~ˆ/C/ÖföMq¹ÒLϯŒÙÉ@ ª„sVº•™?8ÄíÞ]ƒ¸ÃÏí¬¬Ä\Ô@¬d¹skãÄ2~:²õÐÁ`ÿô®Î/DV°Q£•« ãø(ö½çòCžâ‚ñD¹ÓèÍw:³Õ…½c+û&&«‹›Í“ã³¥¹•öÂÆD¶–6âÖäÊÊ=?ýü›Ÿzãs_{ì3Ÿxû'?üì¯~úñýÇú‘-$q‡µ;h?ҿМæ4Q³tÙRõD0XD#~U„ïnf2ˆu±ÿ\!Ád‰4t½˜;¼½}ÿÕÅ{.Ì߸xäÕÇïþÜGþÔKÓÇ×0[Œv C¬?‹Mm®€ €DQª† Ì`/û(–†DJÄØ@¿õŸ®/ûx—F«\ÿÉ„ª‡¥I]gB¡H½Ú\]œ9¾áüá­g¯¿ýÔK?øä‡¿ýöco=ÓZêÑ!£0˜!Šl)VÂHÁq^¤ð»ÊF û|C^7Q7îÝéÜíã {Hƒ-Ï4+ ÷û÷ Èßyöì¡‘Aw \c~~ùıÆöâêõ“~æåÏß{×J‘µ²Ip#*uÇ*Ѹ.ÈD0ª…Ó!΄|ŠPÙP& Ü—fX$ñŽD9|ðÜVo©í—q¨û{p” ˜²Ð£1õÒâ A('Ö?9îö!çWÿi]$¼TDçÉгåX¾.ÕíÞxvcoïàáéí}c«kÍ}û¦öퟟjÍ-Í>ñ쇾ùýúþO~ù½ŸüúãÿôÃwù¯¯}ÿ›ÇŸyĘhFëž°êPÒP´h(–Kc!FãÔ¸‘hç¡âûdÁIÓ¡lÆn×Ïñ”¦zxÈÝÚX>ùø^~ú؇»ò¹×úÎg¯|ö•µkÇÕ¢%¤‘fFˆ±Z.VΡ~p"ÀeˆßKn¡Dã™z3×l'+u=šb´0.š(g숕’L@bLõv¯KIƹX$ÖmNÞÞ¼znâäö…—~óŸ¿òô×ß|é[Ÿ(͵;‹V>ÊÄM¡eÅGÒ‰l±=:%©Á‡oăyqÆQ~š&ÊÒ’©©aTÝân ã·ù‡ÞçÙó ÝÖ¿nÁPCÍOŽïÝ<óÐ÷_|ò‹}û_þáúÇžZ»ï˜;Fï–jA/Oä“E«X-¡XI˜¶$hT8ü»=ï¤<Œ!e%¢Uy§kx—{P+ñrl|uÜ̆”T—ÐT*`$ëâèXªÑä­°—ã}œÐ¿òÅö¸}Ã>Ô“ðu\(>âA¼E‹B¶/ÕâzGùõ±¦ç*Ûû&æçë.9¶÷¾û¯çûßýÏ›7ÿzóæ_nÞ„–üÓ›ÿõÕÿרt×m«®ôA¨/É 3C™Xª’íŸtï]-ð>×(/´ÑXAñ]7)*!Íl6ÑkC ?òøý^ÙÿÌÿäkïüáŸîýì+í³áz¬¶Ð¶Êñùýkµ‰ÞN§ƒzý«%ƒ€aMR4‹«Z}jjly¹·¸˜®7åpœ”M`ù޹õ%#¡P¿&™•Bb¢ŸîÁ'>ðàµù‹ÇïzåÉ/þö'¯ýðËÍ}K#,ie3J$ì¡)ÞÐ!Õk¶Ëf@À=xÿ6,>ŠÃX˜¢”0^3âýLJ ú¼Cþþ¥1à‹Pv?0<8€xwA”9ÜP…DdtkýàÕ»&í=ÿ¡ûýô‡ïûÙ‹/ܧ7£RÉ’œVÕZ88Û™¯"ÝTÁ„I)…F}>Ñï!¢ÆêV1™íÕ 2!9Ó)›Ù˜O IMb ¥Hf&k—VÏ®-OD[ÅX³ÀÙ脨Èz(rÄïòô¯wð?p#yNRеb,mãŒ/ÕŠµd¹‘\ÛšÞØ?³¾=³}hiz±·ypõÕ·^þþO¾ÿóßýò/7ÿë77ÿúoýã¯=ŸŸj¹TÒg°J!ŒY—„…ˉÒx½3?Þ›ŸŠæ3è÷ƒŽ!¿,ó9N7‡ ø ,IK” s¥Þþ}¥­µú‰}3wŸyñ‡_zýŸ¿þðç>²yýD¬›*O•jÓµx%ï£ÛŒÁK).à‡M+¯ûh¢¨²sNwyñì}w/Þ¿pp[°CV.£D#;ªÝ† ra#Ò,U–gª›‹K—NçÖfa<ýÅOÞýÆ‹×_á‹OàñÐM`ȱÓåõè?§V©÷äá@ûÍØãò û°þ‰…(çÁ¡e)C1èGýœQ‚’ÁÑûÕk§ÓÕßïÆ1^¥-#=Öž9ºÿÀµ;O>rÏÏ?ðÐ;Ï]yé¡îY<Êùƒ CŒM7ç«…nR áŒêIÍ^²5šš˜«ê1©8ZÈ´³j2 ÂGµÂd“²'O¨©®K»ý.hV”"ò5Vά?0foue´8ßš;º>¾wÞÈF¸Úß±*p8Ç!€Mxü.ÆIj2ŸUƒš—ðÒ`©5žw§k³«£3+½ÉÅv²Ní­#k׸ôس½ý™7ÿ|ó¯¯öc û–³mðŒ-2Q‘ËÍ•QÌ` F(±`(‡mõ??xdÃ;|^ǹqÚ t!D6“®Ì,ì½~mýÁ»Ç¯œ:óƳÏ}÷sïüôï?—/¤û(N%ëÉîü˜•J¨A!‚Ñ!ÄIa‚ ÍhÅ ¦²V.§Ä#íåÙó^_:º5±w±>7ºqê`oezGwºg$ÃlX‹4 íÍÅéûW.Þ¾qéÔ3½ú/¿ò/]~õY©ž”YDQ‡Qâ@è&IÕGòLàv:†‡|^;.ŒraŒ‡Ô&8Qv·ÎÃè†ÍE²y+•é?ð–¦÷ø<>‘E4Ñn”Ö/œØºrvá Ôî+z÷M(÷§¿J§ÔÑí½^H—6;µ16¹ÚÎ7#±œÒè%¦*Ó…Îx6Wм™2½œ§oà¿íú;·€¿ßµ‡Â“‰1AÕA¡„"¨‘P²”[™½ö¡ŸÿÜG?ý£¯<ñ±:Óc›s‡î:¯å©ˆµ ‰íq»½$…Ð,«hÙJ5S.𺛔VÈ`"Ph¦+½ìøBc|¾Ñ/XI5š5ÖöͽëØùË'ï~àÒƒÏ<üØ‹Ä- ôØ`²Ö>tôÈãoøÕw>òã¯<óå·zæE+;– ­x- :AHЀ$Œ‘1ZeÄÅ›>RvÁœ5¬d­–i7BÅTª[Z:±¹ÿÎ#7^xè¡—[9¾ÞXhïXÝ¿šï”"•Tsybõì¡õ»NLÜwþ¹GžþÂ;‡½ûÞ7_ìÙüÿø‡ïÛÜ>F ¡‚2èÇ ¼ùanÒ¤2Á;õhD4L(ûƒ(î%xÁáÌÂMÒ‚ %3ñb)‹AžÜÝs†‰¹éÎÆ]'¶®Ÿ]8híÒñ'?õ‘»_ybúØÆ„ ‹>ÂbÉ md“k½µƒ³’§kó+­ÑùÅj½ŸšïT;%J†Ï ¦‹ö!5Dx”x(RÎêI›Ð& ›ÉH}¢·uêð_ùäþã§Ÿøîü§Ÿÿÿ~óÜáñÍ…öÒÔìöZ}f\‰Ú˜,’*ô"Ð$®ÒëæêeR¦)ÐKÎTS+½"¤Ÿ^º9‘O—B’[ iukêÂåcç/»pùø± GO]:¹|`©»ÐÍvrá÷2¬¤ÿmÏÿú¿ÿÿë¤QmÐÐ\®Ü 'rnŠF!눤À]Oä{›û€Ü{º·›åC7n|éÍ×òÕ­ûN—[Ùñb²±Ê±òdÓHG¡©zQFbý‰òS² ãP^áC!«m-Lmœ:`–íÍóÛç¾ðÈGùÑïô©ï|êÊ“—wL-OTÆ*S{g¯?sÿóŸ~í±·?üôg?úÄg^;øà¥™³{G7F‚‚?fìè‚¢uËEñw¸|.ŠDÛFF|,Séu ­¦™H@ß9âÈû}"y”Sv9}tìqûÝ8Õ¿HŽï?Ó+ЬˆuJÉÉZr¦1~ÿ~ðòËðÊäÁu)k0>§€ŠqíÿÇÔ_Éu¥Û¢¨þßxqï{çìÓ½» ’Š’33$333gV3ƒJÌÌhɲ%Û’e-33SÛn·±í¶Ýܽ{ïÝ]o¦|NĘ‘±ªJªÊœc~ãc͹¾ѡ֠Ù4æë±¡‰ÒÀhnp83¿Ð˜Ÿ¯ dòŘÇïøåí?WaJ³ÇB9TKv!2èæÝ+ÜÀü­ ¿£…ÌÄÆ…êTÿð–Ù½¿ôëwÿ°úŸßþóÏWŸ¬97Ö;7ž&>ªäíñ°´Ýý‡NÔKþtTEid¸Lͨü)wßd-’sû–J"Sñûc¦PÂÒìOÏ/mÝ9·ïÐæ;·ì]™\œé+ üYŸ#æÀ$$¢RB펇Y“éë»ÿÇ¿¯%CGÔ)GºTÀ·0 œGt–`­wòàÁ•Kzî¿ûØ‘×nõúÁÇìW ²ÆÝ±z>TÊ*hurœÆ8X+kS ”¦Ó‰n{°”Ý8³ûÜæbkÿÝû^Þä¾C߯þöÇÕï>øá5ñRÄì7†Š¡§v¿ôë׿Yýýÿúñƒ¿|µý®cÍ-3‰‰Þøx/æ·vr$esB¼ApxY«ó©ü==–UÓ4"p´AÏ™M4ÈÓœQŒÁA.†g½êR!7=OÏ­=`Ö©eJžpd›§‹óýŽztäàÒå·nÜÿîÓ[Ïñ•2ݲ–¯‡¥¤‰£LŒ/é18øpÒYo%ë½±rÅ?6š[\hŒK…D_Ã!…FFñ¤ÞnÐ:ôjéÁ@–ËÚŽ Ýìâ(O"Òœ •Ó‚ÏRkm:¶÷‹¿ÿøë?7µkÓÓ¼qøžóƒç’ícçéÁ†#5Çž\<^Í-,À”‘å|ýSµê`:[5G2SK½[wOïØ;»²ele󨮽‹GOl_Ø8¹y÷Òøü`k¬V.û²ùVÎq ¾NÑ îz¹jm·R ³ÉlÓ` ¬ë†€Ö‘"Œ”ä9_0=95thÿøÇËG¶ùð…+_¿uòµëÕíñ‘¼)j²ÇÖ˜/?Ü/¸rŠ–ou‚µ‚ñF9Jc¼øoXd­QoÿâèòÁÍsû–.=}éâ¶œÞ8±käÂc§ï~òŽ7¿~yM0ã5ùuŒòå}ûî<ðÞ÷¾ý»?ùûWÏ}þÖö‹GÍNÞ®´ ¤×®´=8C[¼Ó³^wˆÎívD"ÿóöÛoíéV„`¶ìJÔ ¾Nªx÷hõÍÎþ࣮S(ÿ· ‡X´ÅɾM§÷,œÜ6ulã¾ëgοöÀÙç®.ÚÉ:¬*ž–Ó¦çX‹Ö°;‚V³Sëò²±Èd½ÍÈøX®Y‹&#þ™‰qÈ)”ÒnY'øS‡ªh5kT¬bDK©9¤p£×È$£ð³žÛq³HXu•©¡‡_{î±w_ùä¯ß¿ú_¾ñü®‹§&÷l®ÌŽTçFrã-mÈ«¥ãÕ„7í•ÃÅLïDirCßè|½6˜˜\lì;²|ü̶=û¶î˜Ú¾kŒ³VZF¦Ë‘ùMCÓ­¾ñF}¸Ö;Ö×£Q(1 ¦8VgûÅí2’³1‚Cªv¦½}Ž[]áÁÂÆåô–Åì¾s_¸òÝû÷|ñÚöGîˆOUbévÓº´/RÍ»2Ç+¾§-Â*0·” C6aÐÑV}¨œ˜Þ9¿ùÄö™½sO}ðÔ•î«ÏU4F…%©Ý:pæ¡ãkµÐXXé_ZÚ²}rÇMã¶LÏ.„SnƒõF¬½#•åmsÃÓCS0g0vÊ4´hÅY«É¿eF®fa`¥Xƒ9™íß½³±g`ÃdbÏÒ]_¾u÷—oÜñþS£'¶”—¬I{0çKÕÒÕñQÎ ¥¸n¬}*\A°´ÁÚ£AñvÓ{‘·Ý©@q´:µsfûÙ‡î9|ùé{wß±'ÞŠ3nº“\ßI­µ"k’•x ãÕ{EÆFè|‚=eÝzrë£oÝxã›·?ýÛ—¿ùÏïŽ

3Õ;²sC°^ñ—+R†»U ÉVÅ ÿ×/<æh¡,Ú ¬}{U ] e—L!‡°N%ÚÑ]*¼S‰À¬Öäõ[ü~Úl˜Ø²tâê…ÇÞ{þïõ鿾mß©}îRïö‰n†9¾ü[‹Éê÷=kàÖõÜ&è)“eAæ*GFFŠý}©þVjl¨2ÔlønŽ¢• ™\)‘i$0£‰•¢‰Z%«Ñ(aä4jð8z ¥×Êq¬…”±D7ƒ’‹¯™om™Ýsï™}WÎíºtbËùC÷½üØŽ ‡CT´–Ùf€=ºØ_nM­ôÍmœÝØ¿i×ÄÖÝScÓÕ`Ôls²µfrïË›§wØ<¿a<žñkɱÆÖ=Æû!&8†n7hÔ©pA‰i5¤ ¥­= ŠÒÚq“Ó]«ÏŸ?=qç‰æÙ}{_}äÆ_sõ›·6^;9{fçà¶Ép5ÆYèÊ@±ZÕ‚¤.%-"‚iß`ñÍÀ,ËuñrÆà7»ÒîÙÝ3û.î}å³W¶ŸÜ©%]Ÿ1l!¬4l@U¢zM ô§ý–€Qtq¦€Ö¶û ®•ÃËç½ã…O_úÃêßõ—/wÞu¤47T˜I:2iAßCѰްV õ`$¡7ËqªK˘9ŒJUi»[¸ Çø%vK·„¸`uøÉp> œÒòíÏòæ;?|úâWïœyêžñÃËÚ¤SJ£@ ¬“Ë8FjyBd“¨B¢¥9¤ZÏ4š™Áb³‘š¯mÛqùî¯Þ¼ÿÛwïýõË“§wÌßëËZ¶l=“(f­^Áh夠f´0«ÓP¼ §T8!XL 6 ­Rc¼Q+×&+ýK½Çï;¾çÌ!O:Jy°èEÉvˆÃ­ÃìŠx|)Ÿ7ÙîMqSïLuéÀ±û޽ùÛwXýËëß¾þ‰+›ç³ãÕÙ S"ÒE·CpN®‡°5Ú¡Røo\ÙîA*aLªF{4$ˆ8 GºÕx‡îÑ`0Ã3F#®$ìÊDŽ]¹ðø{/¹v^—rýê¼M%¢Ïê÷zãQ‹×…f ©JB0¨¨gú‡ê£c­Z- Ù3™Àð`Ãn±¡0a±Ø]^§ã€1Ó°jˆãF\Fɲ}¹h%‘¨f¼É°Õ¨)R`0ɪI¦Å$ÙŒBØÃG=îF&4XÊL5'ö-_û驽‹bÈ$ú´þŒ+QôUú“ƒSå±ùÆè\mb±9»q`vãàÄb X½…i%ÆÂ¤€£ â Ø*½…B-ÃêHV$L6]µUŽec¬Ž‡)R†¶÷aÕŒNÙe¤¡æ0Ѫâ´Ùññ͗ΞÜ;pnß‘7»òÍÛÿöÝ-WOef[ùɦè5EŠqܸȩh^AiÁo@€dDÞnd‘$kA÷äòä‘ó‡÷žÞ½°{vbëèÌŽ™l³BhE„cœÑ`e¨•k•unÓ޳F­/áO´'z¬Am},ߘ,-µ–.ÞùøÅw¿ÿð»Õ?|ñßߟ~ärkãt}qÂ_/ØÒq•V”³¼’»JÑîOËJÔ¸ ˆP!$x]¯@»¡ö‘9ˆÑ\~K§ôçk;oí’ú³Žuë!¥è±Ç¥±mË´×| $‘Qˆ'Î7kT¢ñ[»×õ¨¤R£*^ÇVÅÁ‘ÞhÌÏr˜NÏC^ƒÑÒÑ„*gó¸­^G ôgüæÉvqNÖ±&ð3-gÕ¯SH4)U!j”V¬%d M¹l¶\ÂÛÈëÓþÈP©¶<<¶k~û¹½j5cö¨9–÷ëáþ±üø\mt¶:4Už.ÌÖ¦–ªýYgÈBëIB$h=Gˆ`a©1»L6¯¦ ¦$Xl`´ÃÖœ§`†T’¤ §º1º ãd¬5:›[ íܲíÊ…á³{çî?ué7¯<úýû§^|Ðןõ×Ræˆ ×3­‰!‹ß%'0%Å«i=`Œ7À´ ÂH„fXV0j ââÖù=Çw:·ÿÂgïxàôô–©\½¢·9`Šfz?„Ž]¯ì^T4à­Õà‰ºƒIà/m¹f$Ó 7§Šó{¦ŽÞ{äùO^øÍ|ùÑ_>{úÓW7žÙ››jÓìh¿#“TòBLô Œ’ËMî¢G‰É4¤BCW%!HqN†sí*cVðå(-b¬Øöl8±V.¿M.³EC‘U²VΨ¿Ô_¤£¸HK …R@$¬ÂÔ¤@ù#þj³ìö;Iu¼Ûçtæ_ÜÞÕ)SÉQD†©>s¨•C¨‰Ö¢ö˜½îê„$@÷yãÖ`”©1™ŠÃ”Šâ Q+øÜ±¾úàÖ¥Åã{¶_8ràÞSǯm̵x7¯dd¶ >Sò5ûããÓå©ùúÄludª48Y˜¬ŒÌôSJOâ"IÚ7ça«–5Š(ø˜Z‰*Y=KrDµ·2»<ÇèBËãz-a2ÃSûÈ›hT,–x<;:XÛ4—ZËí™ÛøÈ¹‹=sÿ§/õî˜6&ÝÑj:”[¼ÎL­¬aiÑéÒÐÚve ÖæP…Rj”`Á겇áѾþ±ÞÞÑúòö¹‹×Î]¸vfd~(]̹|‚ãt“'äg €ÿÕkPÖ BS¼IðÇ]…FÂÒeÁÖL©1]ÜÐ:ùÀÉ׿~óã¿~vãÃg®¾qcï½'ãÃÀ$TÃ2ípjÃ:Þ­¡e0§@x%xÕ0 ­€)È^б€Òe­ÂX„ Vï §€€¹½K&Ñ #°FKû™Jq«´CÍ¢ÖËä³Ü£Û¢&áNED#óhqÙZÃý‘dŒ8‚¦H–ëV@¿ìªIؼ_J×KHf&D¿øKÕ/üE¨ÖûŒLÁšµ6¿‡à…†”* 9D¥ÃØöTä¦ Ç÷÷o™ëÛ45²}fËÉ‘jèÞJ¦JR500”šœ.ÏÎ×§çjõñÙúÐTmbaÐwcŽkYÒ SѬ‚dQ­‰·–BXR0ë\A7%Ò±L¼9Ô¢t<ÂÓ¤ÉàH&"†§TÂ1Ôá 7k“{·õîX L7Ïî8öÚCG_¼ºíʉüT³2Ö $Bƒã#•Þ¦ÑåR1 ª3ÂŒ¦ÚÇ !œUBŒ:£!òç éJ£Pí- Oö>½ïì¥ÓÇÒ•ÉQ‚NÇ |¡ZZÞ¼\jE3·†Ñƒ¹0ÁC´ÕcŠå|ጣØ­Œ$cuŸ¯èl,ÔO=|ú•¯_ê×/|ð×_òŸßœ{â¾ÒìPef<74œ¨÷!¢UIè¨"ŒaPÂ1Æ2 f°‘FÜ®ßÅ+FªÄ×u©:ºÕ4g¢Xc—ê‘#*”!ãÍÃê’[dk×kzþÇÚŸýRr;&’rLÕ£‘C4¦L4{‡üÑN3rµ¦G¡Îþ–ÅZ…ºG‡ÁuÈxå¿IÿígòŸÉ8©1 \óéÚ[zÖý|Ýmk{¤r¡‚X qÑd FRý}C›—gìØtêÀá+ç¶Ù;¼2š¬Ç=q›+dÊU‚­þøÄDnv®:;_›_lÎ/µ&盃ÕÉÅáp6Ü.PÍ3 µÀ¢Aíx\ä‹,¯H&ap˜ãùT¦’BB­Ç™ìÚ´©µ²’ó÷6‡¶­l»xbéÂá±3»Ž¼òÀõïÞ>ðÔÝ…åÂx½o¢ßôMLN–juRÔ)®!VPZ„`ŒQ’¤»ÝžHÄ ÅL6o´JsK—®ž?|z/È5$AƒI¯UnŸsh¬/œôÑ:l P8Àõ#4‡±4)`´.÷%BY›7mÊŪӅp3˜›Èm<½åõÞyéÛ7ýß¿}ñËw¶În[é_\Ê´†¼)àÇBc%LjXD ƒ`òèÜ!GÞ#8h½‹OW’žÏå:<áõ=ªnàU‚Uq»DkÎxdîÊÜdzb`úèŽsÏ^»çõGæŽ­Ø ÞOû ¶|_°:ËÌÍ5Â{yÓÄôòèàL}¬·<Ú›¨‹>‡„Æ¥4©MËHRͲiå9‡Þàä´€x±T%•m¥sƒ™Út%Ñ—Øpt+`‘ç~ýþCo¾zìÁö]½oçC—gï:zÇ›O\ÿâ­Ko?¹xn·/eÊzÜÅp¤–r'ÁdÔîö°¼VŒ ­££L‰¡Ëêµö #˜õÅkÁ¥ý3ý‹õ½wìxøÅN\>Yì¯Ã,£jW"8 ÅÛp“O°øõooÒ£f4kÔ ²ÂϵŸ9ÓŠf·-œšÙd9Éyò}‰ÖB½>_Ý~Ƕ/þùÅ+¿}í®ï9óÔÏ|ùÊï=±ñ޽ÕåQC*À܈Ùh'¬édd¼Õ·weìÐöé#{æí ×k*AÄ´F%ÎÜÞ­ÐYœXJ£ë¥2À(‚Å,Aa“ßóóîµ ¾q#y³÷Wôö˜Í¶²6QN!ëTÊõ*¨Sƒw@Øÿèìø¹¼ëInQ‹ÚŠóv ÔÊõ( “Ëm7GÈ›µÛ4Àvz£Öí5…CJñÀ=¶Üqtë]Çîzéá7îÌN—hmˆѲ«ÔêKMÌ”fgs3½ ‹ƒ F‡§«¿=æ÷å“´Ã,e€·’cب«TûÛw¿_]ýòŸÿññ_þòú÷ß=üé»'^¸þôw¿zø×¯ŸxêJuãXl¤l¦Üùp¶¿œ¨äŠÍšÝë%ž$yšÖQŒ^S8Ƀ?HÔbÉfdlSÿÉ+‡|ñÊ™ûOÌõkŒg@Á áO¹½I«=lÐ:˜|o:]K®•¯x·Â@„ø çÛDáz»„x©•KU"¡¬»1UrÝÓ¼¼ÿ­ïÞ|þóÞúñݾzõ¥oÞüzõ÷ž¾ê,Å치#›ˆ5닇 ìÝœÛ89¸ËÆó'¶œ;µéıâÈh'Œ!œ¾C©1–â RÕºn©Öd¤3¤^o Öª$¨ŽÖyŒzŸspÖˆ5HIùÿoíÏ:4íþí ¾×)a)Aw“fnU¯Ê™°FK~ÁFÿþ×ÿÕ%ï“b÷F”«!@' "lj6r(áË£{6ŒX¹øÂƒ;']e¯9iŠÖ|ɪ·Ø ŽNçgæª ¾gg[ ‹C3 ƒÅFÆà2À®(Ámƒõ"[ÆP –é!@âAÁ«ZÃCˆ€ÓZZÐñ[ê+5ƪs½•±bk¾uì¾SOðòWÿõ»Õ~ö׿þ¸ºúíêê+øò?uß›OOÚl)„,Y¿9é‰Ö3Ñr:UÍ’±h: ²/QœU#4-Ž1‘Btdihp±YŸ.œøäå'.Œ® ˜ *%J…aÇTr±|¬ä+d3õxm¸"ÇäkT(÷ÿ†p;ÉëšUãÂV¯-ßÈ–û ‘œ/ߊWF2ÉFÈ_tÝýÄù?­þþ»Õo¯¼|uï¥ÿíóþðk- ŸR\rÏíÙ~ìÚå­÷ž]¹|ꎗŸxü7^}ã•#Wî«MÍHbu*Œ»­S±¶S¡†)™)Kfëu­Ó¾N ¸7ùm®¸§êÐyt¢S»NÕñó®[1-göù¡C…Ü*UH)œ´iažj%½mF V®À¤Œ– Èâ uH‘ûf¡)^ ,&S<é­Œl_Ü6øóÀ[Žìžs–ýæ´%XõfZádÅÓŒÏ,Ô&¦J ‹ýËFV6MLÌôEÒ2¥¸êæ3f„”"º‰v)&¹„"ºp¤þÈ)Bò¤ ⮦#…` çq§…á|º?›,ï>{ì³?ÿþ›ÿüÇ««ß­þóÿýîúû/{ð®ÄpÕœò™“^[Ò‚Û ifÝâ‹FQ§5Z ¼Ýä‡ÒHhñ;ç†öÛsàÎÝÏOï^98›iE ^A‚t+1¥D)M|s´Ø;ž¯ç&–SÕ¨+ê0ºm>ÿ ò6ꘀÀ¡êêÂàžˆ·ÒWÄÍ%îd[‘ÊhfÓ‘…W>{þÒS›‹ÍÃ÷½ï…k¹ñJ¼¿0³wÓ/?}ìÁK‡nÜ{åW¯>õÍ'Ï|ýéÏ?’°—'Ÿ 7ŠÁZ^kób€9ÒkI=—¬¦Byß¾Áù¾¾™fs²a Úz0o·¤õ…ÛÞûú7_ýí÷Ç/UóF¿Óö†‹©H!eykÃ}ÅVciÛ€7ÎñRÊp´Á`öºQÿôæ¹ÃwÞqrÛ‘KûÏ=x|fÇp¶?l‹ˆ¨Øîœ¬ 'â$Çs‹—u†ô(«P“25©L”R?áÍ(F3J˜gŒ@éÀ$Çè ÍðFC4“ÊUó½ƒåz+M;cYWc83¹¡Ï7 Ìך3¥útyxãà–[Ÿzÿ¹ç?~åÝï>þò_¼öáKg_¾±ñò©ÆŽeß@ƒôû¤ZR4vÀí¿(k‚p­\EªÔ”FCõH¡µ=Ên ‚‹Z)‚Ðo5ê]ÖÛe*‰ ÓtCªÛ¥@af¯ßIš¼~Xdä ²»%dp'̬‘"ëä¨ÄêuÚ¼~»/v{Ô¡ÄåGmæH8>R·×bÖJdë‡/>{íðÕ3®¢¿›‘®ÇÖ¹S¶Ò@ª6˜›©MÏ5gæ›¶ŒmÚ6µ¼y²Ñ_09t Á ‰òœŠ¢!^„D€ÖëtAo¬U©ÌŽTf‡³½ÎX‚³ÙP-/#5ž”?˜¦ oÚÅÙ™L/P¿Q³ÏŽð´=èÏÖ«ézy÷±ƒƒ3ã¼ÅΦBÙd¡Ue’Ñ\Ú ŠV³=à7»\jœPã¤Ãa–Žä“¥ÁÚÆ}›_<´ûìŽSWœ¹v´<–J·‚µ±¬5„«tôJÀ`R™­„ký©L9ËùÕ¤Âä6þ¢óÖ5@ µû™Ã”D…Ë4 t˜Ô*`º­§Ãͪæ¬Ýçkö•ëÙJ#Uª'òÕH¶,µbýS¥ñåàöæt%ÙŠ¥R{Îï{æÃÞýî£w~üõc¿ysôÄö¹;&æ†Å´6c1âpÏŒ†Öc¬I 1 %¡P`Ê.9üs Þ`œÔêÛA›œÙ°N.éTÉe(,C‘¥r\!…1ˆæQ^¼]Ñ>óäNºIÊZ1à=q±FJk5€ ’jˆ9ÚQRŒx]¸Vܹ8¼iÇåc§Ÿ¸çÑ÷žÞ»hK9q ÁXÉ`ÎSÌM.ô×ûÓµÞäæmSãÓ ['Æf[cuÞÈ¢ ®¡„ã^‹ëL šCt{"‘èk¤‡{KÓƒý›§——ûæƒå<¤ç4ZÒsù AsدÅ\ a$t.=&’¢Ý(ÚÌþD´ol0]Ι]öH:éGRåb ™H‹¼ÑØ?6 K8“® *PLCRËX.GØ=Sßqv÷‹Ÿ¿ñȯžûvõïw¿úÈ–»Ž¦gÃÃÍæ¦¥ÚÂ|qbJë+­ŠÖªÛEXLß¼‘ÎZ=¹ gHѨ!Ù[»$]Š£,OZ IK4p—RÓ­‚ºÕíRjÀ±ÑwÚCÆR_ª9\rø­…b,GjM7^ˆ:¯ßŸÏnœ/. åûw\:zÇ“÷-Ü„šH`óD»«¥#)ºîOäBŒ‹fÓË£c ÕÁ|¾‘‘ƒà¦Y”Õj(Q°z×õáñí<{æò3í½tHý¿zwç¥óÍÍ‹‰±Vya¬¶4(êñÔ`ÎW J¡H9 ¡')=Ë%@d§‹Ùh:ϦL[$Aˆ'AŒVg >/DñÙn]Gétf·£ÚWޤýî°5ßLŽ.öí9µ 8ä`Ù[›*;’6܈»âîD%ÌDƒ©˜Õc÷…\Þ€×1´@kp¤K.Uø_,JÆMN§Å{”0¤,ÁƒŒò:J‹œJÁ‰NŒ÷·ûF¶«Ùå£ÙZªØL'‹AÜfñ œ æÜþ¬;ÙŒÅ{ã û—6ßòü—¯ßÿö/VÿÒ·ÌØ®îÙÚ»q©¹´¬Ö9—WÅéd ÑÀòëzTk{4j\L.,ˆç Røe[¨Pë¤Êöqfšk׿ÅH÷ Еaty•¡"aÚ@zÓ•þl¥/Í„€öÀytëI;ñÂHÿüÁí3G·.Ù}àꙥcÛ=…°F@Ô´FªépµÙ®OÿQN9vÁÂ{bž\3Ó7ÙÈ6’ÉraÚMjqNÄ9ƒ†Ô)pQNŠZ_°oiáø÷<ôÖsO|òÚ3Ÿ¿ñÍêê}o¿8¼s~qdd߆Å;[›Æ¼Õˆ-í2F-:¿AÍk3||4{#¾h&îúâÙ4ˆºd¡ht¸(Q1"%t6')êÁçkºÙmOdCƒ£•ÖP±Ô›L”³l_Â_ðFk‘nRÒ‰Jœq¼š/ô5ê£ÃÑ\&[Èš­¨W’@IRÃ2Ybp Pd@hÛ«­€Û}!‚UcÆòîP¸>4˜mV£ål؆b"[Ï–Zù|=™*…ãÅ€;j e=æ€Î1KÁÁ•áÖòÀÄÞ™OþñùŸ¼ðÚï>xóÇ_»™ÌôàôÁÝ[V½MC$JÙí‰81üÍ |€:„P:“#“â-ëek»UR5¾^¢–¨Pð® ’U¢DJÓ¥Pu*T”Ö´N¦’ÂjÖÄ—û €“‹ÍL4V j˜¡@®íQƒÏ;¶qi÷Ù£w>qÿùg®]~õÑ3ßÓ\Q ¨ŠÖpF N1ŒDÜ>g<³¸-„H³fÑt†‹ñâ`!Z …³aA$‰±"ÆÔ„¶KMQ&j´t˜1Ü|ÇÁóÏÞ¿ïÚ©«¿vþµ'ö=r÷ŽûÏ}ìòñÇ/OÙäïM¸JA{Æ|£%lì0Áf)x¢^"äŽø‹½õP:å‹%À8¯CQCr‡‡ÖU8%ZlŽ` š‰åKÑщ  Gùúh!\ôCkÜκ´2áœ–ÊØHul<ÝÛ?¿u{¶Pîà ŠáP’Ö`íÆ·kª‹Çjõ:äÎ@ } ÂÒx‰ Ið9À[ïtfƒÞïöeã±J&QI§*)`Êk…d)<½2ZÌ»â¶H)­E£õøÄö©ÒLyë¹í7Þòã¿yêÆÝ[.^8±wöÈžÚò¬³”³ç2±Þ^{"©`ØnQQ,Ιdj¥ @3þ’ëà¢Sˆ @®DÈŸð^/•­“ÈoïV­•´Å*qÈŸð¦JÑX6ÄÎ(Øü{0q,ç° -ÏœäÞÿøÅ[?~úÀ;OÏÙê¯Ä%„RCÃâ$ª7êìN›/ì×'m1_.¯Å½i·?P`Ç$Ðz®¥t. Ư‡q•NdüvG%Ö»mrו㹳Ƿï¹qéþ_~ð“WÉEÝ1_ºVˆæ3ñb„5Ïè­0 t¢8€`¶‚ÕP¨oÚ2µ°ÐZXê?qf×èL#ߌçû3Ùœ'`ÝFÚa¢ìVÞíaœÊæ‰jé\Éh°¸]>›Ý £T»›=B®9{éT¶–1:Íþx8˜ˆë¬69p÷jœêQA0Å’ÑÛì퇌I2hµ~—3 d£ÑB<[K—ûòáru°0<×·´kÎ4ú Âp±4^®ÍV¦÷M͘{æÓŸýì50Ýïýùë—NOÜU[š+ÏM5ç3CƒöD3ê;ÔÀ7ó©Çh£b»å8p†À°õ( .È4äO!ŽPœ #$jM·R#Žm›Fœ§CÉ@² §ü‹Ø|_·( mmd³ &ƒh³`zm'B®p9Ún «(˜" hÀ{C(“†4@¬ 3ÚÄ€ß[ËU–FÆ-/žÛ±påÔöwßùþ³7~ûÞ¹WéÝ3oª„ظ•ð‰–Œ;P†«1[ÄfôíA;À;”„²Ñ\³ìûÍ^¯ Å!ZÐP)Zn È_Âð€Ï­>o"Ÿ¯ gçç{žØš¯†…ÀØÒpït+TNÐc¤^ Wk°ÑªÒš•¢EAiñ¬V41§3 †H h›Zóá×ï¸ëx¶™·œ®°ßŸˆQZÐ&`Zð`€ ð%ðH˜Þ Ï1“»íòÙj>YLšù¡éþT5>0ÓÆÃ“r‰n¡9]ÜÑzpá¥;=ÿÖwïÿêo_~¹úǧ?{ëÒKyü §eÆ#½Õúìd¢·¦hW«áÆØ­$ÀÀY“DIþûm¹†6Ø|$o&˜C7!š–@š¥ZQÀaƒ GjùH&⋹ì~3%‘LÜð’:í­2IªÆ-‚F“N!7ÖÈŽÖ1 '§ % [<%ÝÙb1Ýl€Ùn‘Èó¤Aß…À‚Ë«&ùP´œ‚yqX˜ Á‚‹6„·¨9£œ×Qwr´5wl×ò¹}c‡W¶=rç¹7øË·î~穱£› ÅîÓicvcÜáÎù3ý9wÊ)EŸÝ‘Øå­Ï{‹£¬ÞE1Z§;¨3ÚÛM'ö¾ÑšçýÂÙGÎ7æû&wÌ%{ó‚ ÄnÈèÞ>ÃKòZF9•&8 u”ÖÑ¢Ùìô‡“ù|µ PÏVK¹Z>]IF²~_Âî[€n÷ÍÙRtzydjed~×ô©k'Ÿøà‰ßüó«m÷ÌÛðüWoNÜÐØ8Q^Ùpr_yzLÊ RèF)ƶK¯kˆnÜ%SßÖ$4e°ÛÍ^7cÖËHd­F~»Z)ÁX5k Œ­Óf 93‹ò(cäìÑåÔ´Ë1¼Íb ûl1eâ:=‚¡·šE“ÁáóR¯FÁrD£‰âE^o$XA ²´!Õ¡’ N³9äÅŒZKãf³¿X\ÙXž™µf³†t27;9v`×Ⱦí“G÷n½|îž7»ÿí§Î>qïÜÁMÙ¡²/ðŽñl$§r±t1‘©¤ãå„?ôåB‘J2^ɺb!ÞfFxNøƒ@D!¬$o”ýIµ±(üˆÐL»â‹EÒpÆ70U/ fûfZÑZ†÷¸<À.%6yÊóþúJbdWbtgfx£Í—À)Þâô:}!JÔµ›S“Ôš‡Þxøáׯ¿zê¥O_[>°Ù‘ð™ŽX1+ätvÐ)à“ ³Ñæ‚à ÆÍh%íÞp,SÈUk™r1]ΦÊÉL5‘k$€”(4âÅZ¢5XZØ41¶ÐßœªLïœ8víØË_¿úÄÇÏ<ûùË_®þðħ/ï¹÷Ô¦s+“¹‰A!R‰¦N”VPíúQˆlN‡ˆŸßºî·¯ïQµûsƒ°“ᨇ!APRZ@­&o€ê»!øTRoÓ;‹2¬š •EêÛg‰-¥bൠ€­ÆÀç`­àðy´fÎ2M3¢£Ng nŸ) ›Ðò˜Ž‘œÆŒA_²Õ¬ÍÌ oÞ2¹{wz|4164´{ÛÜÉÃc‡w/?~êÙë~ðÜÕ·ž\:¹3>Xˆ73,ÎB- ð˜½\- ˜¼Ý¸¹Éö—ýé˜ÑëBE^AJ’†åô«×"LiAþ^T‰Q²íÂ(ð§¤ÖÂimlªNVÂö¨•¶ R𛱿TvhS´µâ¯-&G¶å¦v'ûçy‹[f‡ÛŽ.£Û-8lkN?têÚË×îzüîç?záìçÞu< ;#^w,L_îPaJÓvO¦ÁÌ£½å"pç¬Îb°¹Â©L$¦.]Nç™r_®ÜŸ©ôeªÍt¡«µ2©r(Y ÷ÎÕF¶m<µñÙÏžë÷ï±úÝ÷«»öö“˧÷¸j‰‘+¡f/ë Ih弊6—“B„TU©Bþ· #DÑ‹y“q½ËÓ 1ÚHˆFŽq&˜+‹Ûì¸^/àïÛ'4·HÖËq5ÊGã, 9 Àç$Ï¢4E‹§Ó¡@]Grb»™V»wÜ£Q@ñ,2¶X¨86<¶uËâმNÞ¹­¹yyxßöéûÏ=pãÞûÞñáž?qãîúòˆ3 £a 3¡|5“)$ò• ¸HâÁt¬ÀçÉFÎòq³š¦¥(¦ hu»³„¨À89Â*Pîfs R† ŒRS4D“Bƒ2­•ÉÔ¢éZ„6ᘞÄM:c0n–Ò} ¥ñí©Á•Üø–øà¢>œëTÃàSؼ^«×kò¸ãå‚'[óÈ›_~úîËOÞýÄÛ¿õÅ›ï~ùîÁss€Øm:{ÀLF´#D`EDÞ.¬M´ïÃÜ t@ì"ÌZ‹Íêqûã¡D! ¤~¶–ÊTã™J4™ñ‡£vÄjt²Á¬sx©·¹Q/ï¿wÿ•×®}±úíoþõíç«?ìºçXjªžžès—KÖt^DP³C-” E¨Ne»lÊ@œMN :_,é…’¸­(S—é”+! &‚ÞÇáq-V„c´(Óàà¿ÈQ03cjÇYÒ`3¹;,,&%0t‚Ñ o’ œ•ª4N*¸Cу ¡gE—¥61|øÒWŸæ¡×_¾úê çžztû¥s£‡wŒß¹óÁ w¾ùÄýŸ¼rñ¹'÷¯Ä‹žRÔ‘ô… ±\-ËD’ÙX±šK’ž°ÛqG‹q`îmg5£‚¨ nv ¸6ظÐ~"fdÈhí½R˜À˜'dxã,¤³±ùz<׈ñVŠ6³ŒÕ@˜¬¸Ñc‹V¢µÉhc258¬ QvÃdZk3 #eÔº“SÄ»fó‰ ÑfpjÇøå'.¾úɋێlzòõÇßq¨Ø_4{-&—Ø­¹Ýîfá|Fá ˜¨ÿ„7pê Áh-w8Ï'³Õ'éJ¸áL>œÎúc@®›1³—«çúj­¥úò±ÅÃ׎<ðÖõ—¾yó›Õß_~åaÈv,8JùÄðhqz6Þ?dŽ¥©Y­‚`×ÉÔ?5é¼S¦éV@ÝJh½Ts{Š1VàÎADâ,)f<·Þd@qJ¥Á1R„0®m:Q\ t·YÏè8‚#õV€Ü HžÂo0‹(ˆr%Œà K°<[0˜D“Q°€ôÀôÀrX¤¦}íůÿëo¿oŸSø×—«ÿùô—ºqïÎî¸ãõ×~ýòåŸÝtfl°ä*FƒÕ”3鿢@Ó€U˜.¤ò•\<÷„=þd0U͆ò1Û¢aÉÈPJÞn(ª)ÝÍFÁ‚ åðºÝÚOŽÓ]¤FÕ$˜s@ù%ÂÁ¤3r˜<"¡'$¨ ×Ô ðu¯à‰:ÓEw¶ óû,~O—J¦À4ëB ’ Øšx+¤ÖÉ|ÇÖc˽úàè†þãw¾ûá ûNíÉÖÓ7ïîŸA^i?Ë3Ê« æX½Áè°ûb?5œ.å¹L9Q¬$s…p"ãåôÂJl!1ZõÕg‹ÉèÀæ¾…cKW^{ðéÏ^ºë…«gŸºç­ßÿf`ǦÁíÛÆöìžÜ³§¾°àÎH«CÃë4¬VEò Ÿ)º[ßÞ!ï’i4˜Ð-§4˜A¡¡Ûç>ŒØçñ¹Ü^·BÁBPªmŸ’k›7Þ 2Z©Zr‘hÒ¹^ƒÍÜ)ÞPDr<-ˆ Ä6‡ÕíR`j5 Ë0•ŒÐÐV}º¿~üê¥_ýùûÚçV¿]ý×+üÍõÏßxèóW/ôôÑî+ϸK1kÊ(N3‘HÛ•,±l,” E³±t5›(§½© ÙïT‘T»}Þn.Çx€´•„NMéaÎDœÕÝÞ‹#I··sx0æ¶yôÀy{b–t5êM¸Y³ˆð<Ìë$(Ó¡!Õœ–4[X‡EïsD ))¢ì†dR\y‹býZD¢6’kŠ£éêD.Xrú²Ö ûfú窉Âî[ž?0±Í´@ÁQ};À:PìŒÈc¤’‚ù‚yÑ2Ý ¼ÜÖÚüijŸ}ðéýñ»Õþvõ¿>XýÝoÞ<öÂ}K÷ô¿^IZâw:˜ï+‡²Q<Ð7ÖŸ.¥§#àL—3ùfÑ— ZüvGØ3<Ì´7`@Îîèn -Ex%¡…X#¡³ë\AK ªu{ £‰0E‡Þ†­óƒ“ÖhYïdÂYÅgÂÈBgPQ\—¦Ý=WAa\ R{$ÇE ×RJîÄd¤StCkÆ7l>´°óÄÆâP"Õ ,îæõ±|k²Z./ŒLo˜L•Rí§0Dã‚QâärJ·S Á‚,Žs£Óì6OðAªP/ÄÓ¡þ¡j©ž2;xÌ:¿elÛ¡%°žÜ‹%nˆ÷EG·í½tàéO^øì¿¾yÿÏŸö¯?o¾pröؾÙ#ûš+ Ù±a}$ÌyeÃ=ÂóÕH-« µ€»“Áp.΂¥_¨ö×=Ÿ?LR`Rá@:âŠú“N\%5®Äx³{ ¦Ý‘—Ö+Ú-Ò\æ@¬>>•nµ¢Õ2ç´ NK¦–Ýsd{ÿx5˜vÚƒúíWêCÎ,Øü^£ÛcöøíPÊ2UrÊHR€|±bÒè·òƒ6déÝ0º¦:’]j:¿sûÑ¥¹íÃK»ÇÇWz'6ôõO×ú§³'‡¦,^Ë:i‡ ‡Õ8 &M‰*”*L7{›ØÁ:Q®³Z‚‰X±^.6 ¹J*™¤ ‘Ú@~d¶92×lM–Y'cÇm suªÒ\ì]8´|ã'¿[ýó+¿ýÕûýnÿýw67Ï¥'œ¥L|°73Òî¯È:]2|¤KJTDï’a·®×tªºyD—äèp<80ÔryœŒB0£t—DÀîV(…Lµ¿Qj–LNc‡¬ePѤ±nóØí^§;è5;m”À*` o@©A$*oÒõ¨å¼Ù sX$¦d)H/À&dÖj㾑=+úú;ýâèã3˽¾±Œ1àTs¸‚F´Ns MµÛoçÁÒ÷FD8QHƒk_<䊴Ûé@ £ gUð]œ¢Íç¼ œGE3"šñT¤R\ZHõÕ=ù$m×ûR¾éã}“µÉ ƒc‹ýNíì­§JéX>kry8£¹ãiŒ3s”Ñ9˜X.ÉDAZÑpˆJ@miïâ‘­k†æZ½“å¥]“[/ì;³ùÄÝ{êcéêp 3¶880ÝÉE«åÀûC4¦!Þ˜Á€j»ß@ý'í$4G8ŒŸ;’N–[5 ØcùX¹¯Ø?ÑlVªýÙrÚrö¦}3Ü`6;˜ÛsÇþç>~õÓÿøî‡Õÿzû¿9õؽ¥ÅÑÔxkñØÞÞ ³™‘G&…™Ì= » ¸BTa‚Úp“i@öUÚÜ–|9£5 0:I0<Á Ãö¨´WS7âÑYµz›._ü“ÒYtf§Åásù†1@«+de[–2`“0I yK×z E íCа’a ­ˆt–ê¤QÂcª.î¸ë›îVŒO[5 s¤ŠB HÇŠ½àãg\!_0f“ñB&šx‡Í©å¤¤®¥d0 ¬—Š€d“ãíÇ+‡±9­Ñ¨),Ž V¦††7Ï÷λ’®¡ùVs¢´¼{feïÜÊÞ…p.+$"Ù )êÔ@Ó¤ÞntG: ßq[\V[ÀÁX_>2»wåÙO^[3¿u,™úh®5YØ~xáÎŽMlè×Cs €w´VSšNUŠ€¥Bލå°Fà1kSz·QÀàšGi¹¸^”æi­^0ƒ5OÕ ™z!VLdjéÖX½5ZÍUc6ŸÎâ“åp}¤”m¦ª£•¹ó‹û6<ý«—ÞøÝ‡?¬þýÒK îœ?ôÀ…Ý—Oe§ 3#‰Á–3›¦lvÍIQJ Sˆ’"À¤²ÝíZ” ùH:XnæÍv„A*¶ ¦hŒePŽÒ»L¸–ÁÇŽzJÍb¦œæ<)€áC‰0B¡@ÁBÈ7àËhkHM¿ìì”@ŽND“‚¢Õ¯ä9ÚiÅl:Ô.ºËÑôXÅVðÉMˆRâBûϱFm,ŸÎ7*iwØPO•€XO…Òq€·În†h\! W ¤&›ºY•‹S3ZˆÓé½@¡àΤBÕ‚3Ú<»åô¾;½´ñÐÊñˇ÷Ì,íÙ°~zË„=l³¶»þ:$D Ìj –[ý¢Ý¯ Å|8HtZÆè±$¹òDëð}g×ôOôNƒQ¯dÇ—+»'¶šoŒfó­De°` ZºÔÝ·K;z4@$µ»TÈ`• jO%%èqV4³ Èà›© ´Žà à›€Û5$ÍXLþ\*Y/úÓ‘p.Úiô6ò•D4åõ†¬Þ°Íî7Z<úB3;µa²n`ùÈÆç>{ùÓÿøâøõs矹ï£ÿøúž×n,œØ5sdçò‰“»·Ç[MÂbíBðN`ÏZ‚02ŒVà¸-è.¶ áJ¶š E\¦–*`°.!­ÍbpÛì!w ²,jRe÷Y{‡‘tXȱyl—;D @Íň]k6Ü”o,¥ÕI TÕ®’ß,,É´kåãT7Š)JÉ‘ŒÃà-D=ùí⥼J…B´È±Ñêu€#™„=à'ŠÙd)çOD<Ñ À*1¾YoB…‘*¼m²»Õ¨ £0ÀNN·ÞïO4ëéfuz89Xž=°qߥ£—Ÿ»zãÍ÷=sÏòÁùéãSÛÇ*c%ÚÊRF„…FM0¢Åê‡Þþ¸-U B ¬‰v»Û ëiKÊ¿¦Ô*Ž/ ϬŒÖ‡sÕ¡de0^Nù’æpΓ(Gh#Õ©êF8 Í 9ƒÑb€H\@–hoƒ¯‚bT(àv-ÎêÛÜN² –¡ì{<.¦SÀ—×òÅz®XMg Q‡Û`uhM6‘Õâî }p¢fÓÔĶñ;»ãúÛ~ô×O¿Yýñ³}ûá|uç ͟ؽýâÉM§&€bwt¤”d ^¢L†¥L~[®7[.fkq£µÖ ©Ñãð$BÀìê}ÆÛ•·ÃÀ[ðX¾–-6ò€ØE³ µhÉxù&‡j "yF4éêN¿a€Œ"”í~yXD¨)AòÓ+€‚:Ô LÏyÓa_&Ä;EX‹0"ðËÅ Ų)gÐk󻨑l·3äð¼i½dÊPrè_R,8BtkAsV‡#÷dR®L<Ù_÷—¦÷mØvnïÝÏ]½òò×ß|dǹíÍ…ÚÀJ«6]6ELrF ÞÄr]*DE°(Ë f½#$³¥XKMZE ,, ®e=#ìk€ªœl M5J­D¹?‘m“o$ï¬Jý9”G×É;@¾1¹íåVµ6ÐH—s&§¡éöné̓­0)ªQ^±`¨1| ˜åtJ^r a5¹’Ñx9Ë%¹X±’.UR>¿-vGc>£E0ÛtÙbªw¤Ölc±²ýŽ­Ÿþã׿ùçWoüðþ‡ÿøò®—NÏ´š›gꦽÕ]¶718ÓÌ÷¦½q¯hÓß*éP3¸ŠAD·^ðˆjNéŽ8i-ÏEcÙ%‚‰7ØõZ³V…ªØÝЉ 0+x›vyr”V‘B—tݼ¥°:5ÉÁ,pPíÆÖ´QpE<ΰÓâ3Û]þ¦ÔÆ#þX¸¹S±T9HFäl9w€w‡¼iÀåÛ¾7ŽOE¢‚ÖàñyÓéX­lK„ü•tr¨¼ýŽ}G8sõµëW_{ðÌ£g§öNö­4û64#ÍëfY§ÖpãZ=xŸJœëQ#jÕZE`Ý}a›^/’Áp,Ð%@[´«E›ù5€Üâ¹H±™º9ZL”üÅV"Q 4'*ñªÙoì‚#âÒ{LñJ²>ÖÛœèeã¬QQ , Æ¢WÁ „ 7G{+¡”Ó¢z£’çÕÏÙ,n°äsÉt!•ÎÇûk¹|ŒXܯ7qò@Øí Ùú¦+} •…Ó+Ç—{ïÑ߯þñÍÞ{䃧““•ʆ‘Ú†‰øpÓQÈâ1ÎçǬvS<1²yci|ˆvè=n9Rµ¤#dw†= w¶õQ!½^Ýóï’[eŒ‚¶2¬¥ª9Ð(7JŒH ™Z®F!„Ä0š ÀÏõ:£ÕBql—L.˜l¼ÉÁ›@!‚äª$øµ2H>/NËP¼87 &šÑ1V9WM¢A½Å`uÛƒñ°;ì ¥¢¹z)]É&ñí ûAòÄΙtë¤]HûަDˆ›”N"Ïš-–`À›IFªùp=må6߾w>sïчϜ¼~vóÉ-S;&§wNÇ Œ“ÅÍ”#á7½€€¹¹D¢A!’ÐÛ œžô”ѨSµ{"(Õ.˜Ð +å4ºÆê±j-¢ÃoÏTÓ ÆŠÎÊúÒî± Ã™¾dª7–h„ #i@ ý›‡‹³ÌHYô›¹¸Åçat €^êîV‘¤ˆ“‚\…ª vpBЪ)åL–ÁÎè°…‘L1ÌÅóåt³¿’-ÄÌv­Ý¥wûL$§gœ[öÏõÍ”&6õo>ºðÊgÏþæ?>>úÀ‘ O_pêÄ£wì¿zìØ§f·ÎN,ŒL¸£^5½ÎP>K›Í¨¨‡9aE€4À-;I“Ža N‚ U£j ¼¤°Z†Ákf–gÀ5»­átÔt2&âàt#“i¥GW†òé»?·x`r`SsîèâàΉÌdedët~¨>¾aÁô(4,o€ÛeôBÉT0˜T˜h³=DÒ7ï»ñÀ”<¯µ˜ýÑP®R(ÔŠòb5 ry(î DˆÝh¥^±w(³²srx®²°sxißø_>ÿú×/ÞxÿÑWÿ|ôáó}Ûæ—ÏMMMø†òK‹½{·–¶Í»úÊvÍÜoŠD)£E‰Q*„\ߣk€YW(p„2Šr Ü“íÖ¾‘XJg°€ %q’E0J©FÀ5xe'á4'€Bh`\õzœ^g4I[=$#k‚ã4Q2Ò.Úªƽ©|(³ë{l>»#àx‡Ráp:ÉÄ~Šu ~ÚçB³IB`»”2ˆ !”×À‚¾Q¯µÚ¡@  ñfº6Ó\8¸|ቻ/8ÑW®Ofû[&å0¦¡8Îhe´FŒæAƒL¨!9ÈOí²ÍâOQnu»óÕJßÈ`­U/ÕKùr6‘‰&³ÑR-×è+nØ<‘-úýÃÄBc`º°´{tlSsÇ™•‡ß|àõïÞúrõ‡Ïþõãé§Ü»µwÇÏ`o~óìÔ™O~ñÑc¿ûÔ¯Þ¿ðÈuÎr-„3ŵ+="0ÌÓGj¢}ŽæýÁ(ˆcÖo€. ®e Åàû`5¨4¨\ w)T”ÎÊæÊÃ#陾ÅÅâÄ„·\TêDÏÀÞt3áP:ˆïnÛx$‚Øôc, ŒŒ`2 Ô,¦X6íEHW¢ðŠ€•…’l»ÙésCþˆ×x´"‰zÒ‘tš"f[Ò>·waåÈæÁ…¡T)í û}0Ø,þx<˜Nû’©p¡Ðî‰K3V ¨ ürHR¸Þ¤gy§Úgp1‡¯ë³×³FCÂG¢xk Ðá Š“Z—^ëÒÆ«1peHq4säÒ¾§Þ}ì•Ï^:{ýÜäîÙ—¿x{jïJz´771Xš#6)Eu#(@7XIZ@€”ÃYL*P ä?˜æñÐYí±L¶tdj~vpl8œˆ˜A²ó9R¹D³¯21Õª6âsKõþäèl¥w<3½µolKkßÝ»ÿàñ—¿yó7«?|üß?{ìêн{6°/¾ñô™gyö‹_{ìº)¡ÌVF™ Hø§Z4mé r€ÒqŒ×þ WêO4¸î–(ÀOA ¼AéÀìõšþÂÀÀž=KLîÚÑ·²œÌŒ Ú2qÚmÑúlî„/ò‡”¹+Ã9ÁdRaín¸‚¯¬^I§µ‹ ‚pŽƒ)Jd9H0‚Éâò{ÂQð¿€U e"‰J²w¢·5Ù›ïÏrÑrxdiŒÆX#’Žð&1›×*—)`›SÕ¡a‹?,Y‡R)Ñh”(,‡Tª6$Œª fm8rúÝGã"¯s9Öèl£Ór»¤s¬[´™D»ÑH0…5dÂG/ÞthÃü®éÖl-?¸tãÂ3ï?õæoßùÝ꟟ÿâí÷œÒ¦Æ|ÌŽØ2Iµ(tªÛj(FT3KðÀ'(€ kï p’eõ&»7Pí훚Ÿo ÙÜN’¥9‘N&–ŠTëé•Mû® •9g¡74»u`lcsùÐì䞉{_ºÿ¹/^ÿÕ~ûÁþîÔ³_zë¹{Þ}þá_¿¹ÿÁ»—NòTò·jÔ¤ÙÊšm …wÊÔ·¬ï¤¢µYT$u!òJ0æpù@XÿDààK‰L%WBàºGªë€Ñl¯ Ñ&#`¯ƒw^¸çé'ïyî髯¾¸ãÎsÖBª¾a61Üë.¥\¹h Ð>ÇÊA”{#1_4nóúŒòE‰âí»$-QŒW0„ÐŒ'ŒçOÛŒ(-hÍw(ˆƒ”òD€[ %KñæH­5VšîÛ¸kitnpril`²50Þ7>7î z8£6’MÕ2µZ¢T.öõÜ%A®•Iå(Œ°ÀÐ# '"SIô&m¥Y©õ5­>7o1‘Fý9¦ÂxJE G±fÄŒY«a1% .o?ºýáç],f†æ›®|àù«oûΕ×~û/Ÿýjõ‡÷Ÿ5UÞ¾ry~ÒSÈ€–Q#„Ò‚NøB0T8 ÞÉë9½9KæÊµ@4.èŒ ‚e†Ùföì K£}…¾¡‚ÖŒf*þÑ…zkº8¾epz÷ääÞ™«o<òòwï¿÷÷¯~»ú_¯þéócOßðÑË}øêâ‰ý†DH ø”\ûi T!Šë’·Ãf Æs¼ÙHˆHk buzP¸GRà0NïÈT Æk0?#´OdKpl|ë¦~ÿ»ß¯®~ú?¾ú÷ÿúÃÙ§®ošÚ¹at׆ÖòDv .Æ}É€;êñER_D0Úa’»¹¹@BD›f@ú¡$ˆd€±ÞæðÇ*ŒkQgsX<^O$HÆA.&C _sáx6˜Ì‡«½¹ [æ†ÇûFš¥j¤¼j_ÕæwÙüîx!/âÅb8—³´Ñ(ÃP) QAk7:šÔQ@Hâ ˜Ëîqä«¥`ªí§h³qM—FÚîúÈSJÙí²n«âIÇze·7È· 3ýöˆÅ6EóÞ“wÜxpéÎÇ/¾ôÍ[Ï~ýæ©ç¯Îžßwð±Ëµms™™¡ø`Ó &UÚ>:¯¡µ*`ÒPD9Âh1V‡P¼h¶é­NŠ×‘œÖ`u€U®FqN+Zlúf«Ð7X®4RÅZ,™÷<µmy×Tsª4±mt`ÓPseàîïïoŸ?ûÍ»oýíË}×ïÜ~ßé˯=uáÙG’Ã-•Nv¿˜+^ë&N/g°ÉŠq¼Å롵Z "ä€7Õ•`P¼\êÖ`$&» §/Hr¢#Pƒ®ƒB3c¿óê{ùþ½¿~ÿîß~÷Òï>Û|ñøñGî9ýè}KGvf+îTÀ÷R!W ®5»n>fÛ.‹¢Ü·oIAÛÓÞTçÀ %Ó‰|D<%j¡ 3pG‚mƒžÇóñX6Iù€ú‹g•zviyºÙ[Ng¢&“H³¥e“Î&óÍZ0JV*…Þ^«ßÏ[̘ÀÑ&#쵇\´‘%ô¤Þ©wÜ·­¿m]w‡Éa³ú<€Ì ߪBÇ9Ó«ž“bˆŠ&$ˆ8W*\쫳!kÐÒ ­×Û™JfbãÈ®s»¯¼úðé§/OÞ:|lãù×íÛ·4~h«£”è_š‰sj²ý¬‚†âêÜÌ+D‹í¶ œ;ÆiÕØŒâõrVkätF„ 7Ût™B¼Þ*ŽL4ÝvúüÁ…ÍãvÏ”GóñV<=’SXà…“[ÞúÓ'{8³ùÒÑãO^9þØ}ᡚڢƒÌúµ@³0Ä F—ÏŠ f»ÆÀä¢ +˜Ì2QÀL2Jï”)U(Áꌌְ^"—ªa5F‚×n…šàDZÔwk VùNöW›[fNì;¼mìðÖC×/|üÊžK§‹c®lØv;€ 8)ÁLò&œ5 ”VƒkÄÈ!ð;1„ÖK”X…‘X©ÙÙÄ·?sEBÞD$˜‰G²qàå"™p4ÁIzJÕÔôìðà`}|l€cˆ ßm4·Õ´'Ž—óÁ4ÈÛ•r¿7'´¢h³Â,ˆ™·é»1ÒH9"N£Ý„ I¬—ËÖ)å]²FÍ¢– šµb)ŠM«$€ÞÆÍ‡hÕC "XJGؽÆhÖ?4×?¼2R]lm¹kßýÔ¿s¡¼0æ®dº\.p=$Õ c ‚ýI$ª1äN@ã%° H¢@OÈA¬¯—Ê»•êN¹’ÖêÛO* Zp–øN‡L!^Ã(ÒA§»‘kíXœ8º-³8¸tç«<²wy`ûÂÀÖE1âëfHµV«æµ*ZhŸwCévúÄB€¤˜ô›çè~ŠoÇ èlô`  ~‚8ZÄ¢3¤CááZ~qdêøö¾½ ½óòÛ{üîÊʈ)ëó”bñFÁòØ€)€­ÁÚ[G7ÁnŸ®ùˆ5°€@æ,˜ˆWûz3åbsh ÒW—’ùV¾:\© ÓÕX4ˆçƒ™JltºoióÌØÔ`³U5Y ‚À‰¢`u9´N‹)äñ¤c‰j)RÈ1@¦!0ʱ0Cš<6o"`8­›3å2„ ˜“i*éV€EZü~ƒÏ éÅ5¿”uÞ"ïÖpLwlR‘ëeJ@k l"0˜V¯—v×¥VÈq(Øö!akÜV/n8¶2whþµoßxüWO]ïÆ®Ëû¸w.<œ×ƆˆÓt±&=Ê08ÂÈþ)¸o‚Ý&s™¦Ý-¬*„nŸ¼Hs¥ÞZ(`WúªKã3}ž\ í±î˜-ßLM5Ggûç7Mõ4Ò…$FIâqŠÔYÍŸÓ‰ i_&鈄HVŽëEfƒÑeu„Ýî„Ç•tÛ“KÜl™!0¼K®Pá„-²†Ã¤Õ²æew¬T³t‡F-aM³Rï«Q†¿éÕ*È`äŠvi4˜–÷¥"ÑRܳ‡Jþá•þáMýw>~ÇÛß¿5u`ª¼\½ÿ'ÎïŸ/÷'ªåloƒ2nWÈÀŸ8IJ¨ ö@°Ax¾¹ðU è¬VÆè”¬|8Þ`Çþ1Ùµf>B"O3ÅX,œÛ6yê¾c߯~ÿÛÕ?œxìî‡ßþÔc÷¥Æûú6-¶–çu¡ ¬7ªQIr@$¶Ü`œRË”ˆ§–'ð& )êÀxéN…ŠÖ`š]'•÷¨¡ŸP§LF_%;¸}©Õnº7²é®Cç_~ðò[76Ý}@—w¼cƒE€7,ûœ4­n7ËЂÌ}“Ìÿwp·µ„$ ƒ¢ŒNŒdâ¾X@g3¸BÂ?8Ó¿a×ÂöC›Ç—†Â9¯3b.÷g6윜îXéïe£KF½C1ž5=îlÜ ±vZ˜eÔ$ÒŸÝï¶úœž¸/^MÄêq_Ñçλ•°Õ€w%UiÀ‡R$ˆÂå\ƒ™ÁeÅõZ)ŽÃœ ÇÈ کаz²]2…‚eà?¶;É(T*š$tœ3ì"tcÂ&7-íJ„·Ýxãýë÷½q_}{ëò[÷Ÿ|âBïÂX¬ZlMÅÎXŒ„ARk6s È]j5˜km °À¼kAÎꥬAJi)£Óä ÑífÒæR®ò’±X¹”ëí¯LÌ ¶Æ+ñJpãá o}ÿᥗþÕ?¾ý~õ¿O>r¥µq¡67iÔ© çð@œ¤ðv…Pœù¤o(sŒHç÷Su”Ÿâ[0[Ín/¸î+U8 Þ΋þLº45<¼sCcóÌöË'®½ÿìÏ^ÞuÿñèdQHÛ=x ‘҇쨖ÂV… R… ýØíŠ4(Ð 7e ¦Da€J 28ŒàÃY½6gÈ-„¦7Ž=`Ïñm}Sµx9PÌÎm™hŒVZÞ±¦/ág¢=àeô:Îlâ]6­ßE˜õr—X[Vã(%ò¼I'XtfŸÕôØvÑ/Nœq€t¦Vwzóñ³NµÅH½º¦êe× i4¬W)×+•@ÎáÞh‡Lª€¡©¤G¥„þg=]àù³1kÀ¡$:ך¨¦ë!kD¬NæŽ_;tüú‘sÏœ}åÇW?øû'÷½x½<9P™¨Œ÷ûò Â$vBÊ`6eò¸$ì+ä æWC2mbgµRR€uv­—a<%ZqZôÈL ÏrÅb.Wl7yª ä3µh~ ýðžêòÑÏ}úßþvõ¯Oˆ ÔòãC}‹óþB7˜¥«qÆ„1J+Q#r•%@éVj:å*ñ •ì.ÑlëQÃëå*\ÔáZ½ÙٰػqjdßÒÀžù‹/?ôðGÏáþ¡›L^Y2güëYÀv •A0Fs*˜U#`0@4¨pº}ü”¤Ô)Ç`–ÒÕ|4Ÿ°zí‰B*UL§K)'ð¹iw¦« ú&ª`4GKÕ¡B®™ÊÔR…Þ¼ÁedMB u}®X³™•ñ˜ŒÁ”4ÙÓ®ÇhCß>7#r\ÓKnSÞþséÏþMò?þ­ë≒”Öl1¸\€bÝéÄôî­k¬¡/“J6*¼Ó¬IÌÄ)9äuþr½ºÛà¶tk¤]J‰D%—"êÿ%]÷3UgÅš9HŽ>­9ZwF,Έ)uŒ,7Ï_?þø»>ùÁCOüØûþø¡wŸŠ æÒ£åx_.Ùʳ}¢’“!&º•J™†pº½ÇL°`1Þ¨¡€D0Ö@‹F4Sœæt8ͺýþd&N„¢é`}°86×?4לÛ3}á±ówRêÍ€Pè›­Îí?vß»ž8ÿè;׿]ýîÛÕß_yõúÈŽ¹Üxoa|ȓ͢Z³’Ô1Ÿ T' "”©†)•†üÞ`H4¨’dD·'P,f†Ëó£S§–7_ÛõèWÏ<ýÛ—tìòžÇß¹~áÙË¡‘Ü]/>°éìG.®¥Æ6Îûë”^$¡½gHàMüt‚]¸WdÒ¾ñSZ„Öá¬@n´{Àâ‚‘Ó‹þ˜? lL-]h¦êcù©mCËfŽ]9ôúW¯|·úÝoÛ"îÇ^|xë\~¬xeÉ™Hc:+Â[!Ú$…h9XR*ðW4mÈÛ¨øBŽà2Œ Lf_1_™ž¨ÍϤ§ú–/°áŽW.â\ue ÐJÃí/¦—Õ¶ÛóÊPúãÒrœ¿“L àËô¦PÐ×ç'†¶,”g†Õ´.`÷¤Â™ZÑé÷Xì¶b¹púŽc¥zÚq$sáHÒg÷ÝA{¹·hóZÀ²öÅ|©RÊ÷·» éYÒÈ„êqSʱž”q#fn‘öÈP ¬-ˆ`eTC´VôÆ‚þdåQˆ#é$g0Ü&í"LBkqlË™}c{Ö ZNÅâ2ŠÖ2r,\KBÎ%þÏŽŸuhºÿ׺_H …Ùi£‚J‡ÜŠub6:TMt  &ç­ZWÄ Ñ]pÇÑR°2œ^jn?±rññ ž¾÷ñO^©mY8²íê‹7ò##ÏŒ/ϵ814ÈÜ7OCp#"´2µŠàþÏ~š¨!µj ·3ºŸ¢œDà=8½àxé 'b/¦7ì›™Ù12½sìžgîzåó—ÞþþÝ?¬þåÇÕ¿]{õñ•™©›Ç7oN÷¨Ì™¤íª"LŠíÛ^ Û5æØöõÀ¢¨ZàŒ‘`¤·Z™ŸÞ¹qtÿÊ“_½tçë÷œ{á®Å3[’¥p+kOE×ë4 ¯Àx¼¼Ô›*«)Îe6xÝ0`æÀ0£à­ÀhÁv@¨ŒbX'ðå¡X#79˜iLïß<¸yfÏÇvœ:8¼8ü·ÝãÒôñd<ñ¶ñ3ÃS cébûü.­¥ù°m0ƒÉ1DcíÓãv3*п¬_§‘ö`JI;Tݯ…7qvŸÕ°<†ó8LaˆÁ<¹^%½MÞó‹ž.%KYcA_)í+OíÛ|á©Öàš¶rz¿)ÖH¹²>w΋j-mãu>‹ÞcQÓ(­ž•£jÚÎäFr‘ZÖ#p§’VC,Â[DdÀ»v'áÍ4ÒÑrıÃk&P[{òƒ×žùàK?¼÷ì‰n ¢ÍF˜Ð2`Ö“ÅèõÛBQs0¢÷`Q/'Ø„’KCéT Ä ­†Ô¢˜PÎhÕZì´VÇô¹JiÛÞ­ñ| Ðë( Ìׯ6õo9¾áþ¯|ü§¿úïßþqõoŸÿçwŸ¼Ö·<=²eÃàÊR¼ÑäÌn„1Ê`VQJœCxgsS$H:Íîrªº<^XØ»tö…^üþƒGõô‘Oçêæ´+9PŒ7 „Qä­V Åj€¹§ Á«!%7[÷0ŒR+ú«¥H£¼HbCavhúÀ–…#Û|õÉ{žx°1>`ñ8ôfÃr ëLb¹^›^X™Û¼sãÄüx®š³zlËÛVúÆ-^ Ù …­“Kº5ÊÛ¥=^§”+IôÖžµ·vßbp´Ï' l%br §HêH5 SF‘³™MAi1‘6Sj°9³wûô¾mc»7ž~ô>àǼ†€É“õƉP5ÆÏe·¬Õt .ƒ'²=¾xàmrYqG¤òå=”•TÐ 5«¡ Œ`ÁŠ‹6½ÕïpF<Ψ›µòàGÅlZÔ¦÷’§ï¿ÜšÄ Z£ßÛk¤8¦áXÚl6úîT:Z­fŠ£c:Ñ{0ª"$'Ã&(p/C ÉÓZ3Ƀˆç,nw¹·ê‹9Rå@8ëjŽ·Y7çªw?yñ£?|ôÙß¿øô¯_<ñÁ §¾4¹{ãЖÅÙÝ;£Å†h (pQÖ£…ãpÚ’qw1mLãcõÖŽ¹þ} »¾kï…cs»6ºãAœcD½Þh²Èµ`Bl†Ñ~0¦¦¦¦½m Ù;20:;™(æD›YŽÁí}KŽmß禸Ûzä]J•„–ÄyµÁNE3ŽpÚfpR®ˆÙàÒA,J›tz¯Ç•Jj ZO);³Çž»Ï-Ûè-ŽîZY³¼w1ÙL8’}Ðà-­ ëÿð¥“×î ù~~Û/JlM6,a½#f æý”‰º]¾V  ß*Y ”Ám5zlœE«¤! N£>èî$ÚaA ZܨœŽnf­C‘&£!às$ž|&Ò¨•§Ç‡6¯Ä{›¦pD-è$#qCi”VIjBcÀÎHÞ@ ˜b¤ ½ ³[HUµ¡\ÿLma×Ôü®©ÊdñÜõ3ïþî½W¿|ã‘·Ÿüýê<øÆSƒ[çF¶,Ì-»¢yˆ3‚t®æu NÀmVs*f-ÄõÙ`x¬RÞ26|dùìËמùáÝû?xjï=Çb­¶¦‰µå±!«"Ú÷€>‚IhI & Š—!„%€¶ïÖóÚt$8TÚ³itßæ™c;]¿{ãÙ}î9Õ¿<­fé¨ÑaÃ) Eq'•%08KfJ¹Þ¡> ’|±pÿøÈÄÂlÿĨ/mív2 r½BÕ©DÓ©Ðt+傉"€mñ¢E#Xàv¤VÖà6£ZXµu0Âú\ÃÛWÆöl©-O¾véðýwo9wtÍGß½÷é¿:yß 1r³>d&¬Œ’ƒÖª»Â…ø­’µRXÁ9,Õ9Xàz›•@ÆëŠ9­;oÕIQu¬bÀšrÙp-'½Y=ˆ;Ö¢ (…¶š1½â90`‡x–²ɘ9´¥b¥©Ñ¾ó[—ú6-Ôæ¦‚Õ²èó$¬¨ 0­bôjZè;LéHÞ䀼}˚nj.‘5Ùz|ÇáMñÒüΩ©­£½ó{Ÿ¹çÓ¿üú«ÿþöûÕ?}ñÏß]yõÑ…C; Ã#ý3RA9#BzãZ ëæiµM(îYOVÓK}û=7unë¾Çξq^µy²áH%íËÄ´N̲mI° ¸iüi´ý‚P ÃqV;°»ZÅÞKSGwNÛ±÷êÙko>õį^Ù{×ñxoÕÑ0G 4 £›$iŠet#ζÆ·R¤IJ'š•;¦–— ½½¡ X"³Ï¯aXðW$ZŽð Þ£RãË÷&=ꟙܤÁÅè\¢?f­¦ujH£Õ¹ËÙ…c{§îØzþø]Ï=vö±Î?ñðš¿ÿÉ·ÛtxÅ“óz À5ŧÀ»t±jÒðÝ&»Ýrì:Z‹ûbvàzS•ˆ?å‰äÂöKï²PF­Š&Hƒ–2êÀ… ƒ`Ž¢ô©8›EC£Z‘6›p½D¶”@ì± ýìHkpó|sãLsóìÜñÝàµ2?>¾c³)јي- Êe¤(#n; ´|€œŒm¹N!ž¨Û²Û–pÎßš¨M¬ ,õÏØ6vï3÷þæïŸþ__ÿ~õ¯ß®þñמ^YÙ°¥:1ãÊŒ±˜TÇ«Ös™¹Á‘C›Æo<µõò»ŸyéÊÜ…íá±¼9éu&BÎxÈèuQzÊìÍÝ<áf;ˆv¥ ÎJ\‚â¨P¨74ÞLÏ ×¶ÌŽܲtfïå—½ôÂCgo\ÎÖt~+À›™U'$… ˜B©&YÖðÙ½­Ù Œ“ Ã`š‰åò›÷îô'Ó¤Þˆ Z5 þ ü^‡ŠêRÓ¸h¶ƒ ç!BTZ},©“ñV˜5cF¯Ár¾M¡¼^0Ÿ;››gÞçc¾¾óÎS©‘Þ5 »§]);¬‡:°NÆ%DÉH-.ÇõT&ùnù¿n]<*÷fZÕÖH!oÌ/&{ƒ°æ¬&“Ï£w;)£^E 8?a)%2&&jQA@EAÃ2JŠ Lz[4(¦l© )éKŒÕwÝ{*>ÕÈ,ô_ÿø•`qzßÖäpïøŽ-úpH£Ó#sL¶!¹å(LðårZÛ®uÊ[õKÛ7ì9¶±X1<·erh¾5»mbtep~ïì7îÄþûÕ?ý~õ/_ý÷ïÏ=tmjûÎÑ-[æìóÕ˺TÄß_ÉÌ 5¶Ï–6OžØ:n×¹ï?þÔÝÙå^•ƒö—S®xTçr:}[·«E· LRU¢íbòömRŲ¼ÛåÉ¥#•äLÿèÍ[.=úðÅÇ?ziïÝǦw/9R^Ö.bZç)„ÄIšD ² ÃFÒé\µˆ'LN—ææn‚= erîh‚Ô™¥( F7Œ¯WÁ”–ÚÀïvoºÑLVò¼…Gx•ÖA<Œ#b0ùô°€t£ âȺîZzhÏâ– ‡/½øèÃo¿æVÂãk|9nB8‡špÒΆªq€w°Á ¸ï!&ªK­dc0?6Ý×;P±¹6¯5˜ óf=pÒfsÀ'8ìˆÀËq [P …U©À`\£‰5™ph.âhƒ×,$£µlb T[vÖcµ-c‹çwßýög¿{o`×ü™Ç¯ÌÜ>{`gkyÞ–JÖ…´F5oPÒíÚEê¶b)G\´Ñrª+ÜqxïÊîÍ®ˆ“ÔcÃs}“G–vÏŽmšÜ>q×ãw½óÝ{_ü'ˆò¿?ðò³G¯Ü3¹{ûøží‰±þôôPbª¯ºezôðæÆÎ™ œzú¾ãß=z{a©å¬DâͲ;&€ Lø»jŒ—Ãìö LÎÊpZFÑ„Åìʦ²#ý¡R`°8slÇ®Ë'¯½ñį=6ºm&Þ›µÇ\Z—6rQhÔ¬ :œ‹ÍIñb(™Ê”ÞI“Óƒ²È”ÎÔÓ¾Ó÷¿oÛµ7ò³ž…€¡^3]ƒLŽx$THXCvBéÝ"m"`Z«ìøy÷íÀD„йP5oÊù‡÷.l½xèÂ3×vÜy4>P¾•¯¡m„ŠWR%Bˆ‰ÌTÊãuWÚÓwI‰îPÞc ˆÍ‘lÿX©ÚÈTª9ƒIô¼Íãd :$¡ªŠìA‘NH#AaÖìve; D8޵|j»å¸#ìw'‚¦3Ñ*ô¯Œo:»;3W:0øóá/_¼úñÓ×?~áûÕ\zéÑÄhc÷Å3;·Š¿%‡Dƒ‚B¸^-¦í-RÀ8 Øw£q­RΘõ³›—6ïݲiÏJ{ÃtËäÀtcnûÔÒÞù±Í£wÞ¸øÕ?¾þú¿~÷Ü'o·ú_ž~d䦞š:º#=?8{zOsçÜÖ{ŽŸñÁ§?sÇ¥£‰ñry±?1TòeS·æ´ ŒQµoùéÔ@ÛCŒ»ÙÑgzpJ)Ú ?Þßè]šß¿±²4ÚÊ©ÝW^º¾ùäN ~m1'g«¨µé9½À¼Åîp¸¼œ ·¹}®`Øìô¶ÒàÚGôC”¿`T’|DH±vuQ)à'jñ 6¯\4¬ÇIÔd ³ÉzÑäûÊ RõKÉíJV2(mÑgZµ±­‹‹Ç·NY©­ í¸x¸0ÝB¬œ”C@|»i¥ÔõBûï<Ò·0hŽXD߃¯札ÉBïX»qO¹šªU‹£–d(­Ùˆó<Ä0* Ø'M‡F-ÁTä)½ˆñ4Æ‘”–EhŠàýÒŠö1 Ú TGz‡–&–lÞtj玻l¹´ïìK÷ÞõîCûž:óüŸÞ}éÇ÷¿Xýý—«š?¾sþÈ®¥£ûF·l2E¢„Ù¦bEðÉU¤Ð.hÔÞàV‡êÍ@Ù‘f aÐ:~zeîÇ¿ÿpèôþ±ùÁ©ÆôƱÙm“­ÙÆìÎé+ÏÞ÷η|õÏ?üØ.ªô Ï]Þ·2~dëØ‘­ý{—Aò¾úî3WÞzêâ ¦&j|Ø’.ÚR~ÎnÃDC;Îð Êfl+&¸”`å,O:ìîb¶43Ö¿yq ø®Ë'ïzæÚ¾KÇvŸ?`I8(;kðY Ë[M¯5ëµFƒÇ†ãF«3U¨Ø}AŒåÀ¾#¤ú憽’à`V‡ &9Áw¨ñn˜’€ÜAj ³;Ü;µ ±$f³sw°˜¯Ž ÅËyToIƒiÑeÉ´ª[ì=~ß¹»ž»r÷‹W¶]Ü€w‚*!ú-k†—ý?a¡xÖ‘ö¶†ôAïÒ­D¬˜«.îéK–›á‘‘f«YÓëÞ´ÎbFÀ9¸'Ô,« ) Ç,/bÑjÀ8ap|“aIžG(Bލ)=[í=r׉çõò¹_üúõ×ÿøþ®‡Ž<þÝËþîÅK]¿þÙsO~þÊW«|îË·÷Þ{föÀömgŽ;³iG2EYìJŠWݼ¥ðÖ€žJ0öP\Noôºå84<=òÚ{¯ÖK3ÆFæúªCùædµ1UßùØÝ¯~ýþGûíoWÿþø¯ßØqß©é“;çÏîÁ}çË<ýå;§Ÿ¼oöÈVsÆgÏC´1ìYPM r ¤j Qz5¡S`¢f»jD#ew:²™üähßæ¥¡+ÓûV®½úø¹G.í<·??R–Ðr£‚Þ©ãM3¾Ÿ¸ç|G§Î‘~¨êùÞ÷yžªzß×f©·[Â6ÒFy<±ÖðÈ|ïØŽb÷pf~yp|ºkd¤·5›£`$X‡×G ±¤hÖ3àü ‹Ù‹Ö7¥A` Y€1+ˆFàC©C†hÔ:[ØÑ??øÕ_n<ÿéKïÜúðÇ_~÷ñÓï>>úÀŽõWO½w§(ð‰_|ÿ—/¾Ùømå‘£ís£…¹ÉÆþ[,ŠJVˆQÎ =a‚I˜ÌêÔs"l€*tÖ "¸,Þ¶žÖB~x¦¯­¯9”òöL–..¿ïɾúûïݺöć/ý¼ñ·g®¿¹ýÁ=O|òê+7ÞäígØ™ñ.WS8Õ—·DÜF§$œ3ƒ…ÐbJ÷bIQCð*‚’ÂàôÈñx²¿»xÏÜðþ¥þ= »O|þ£7Û§z›ú[9ŸDÛ´Ì0²¸H’# &°û)˜ü ‚„£8'VA˜§-Ê@jqZ…jŒÖl¥ŽØ¦Á40»y_Ä™Ê÷î+¬­µíº§}çR÷âRvt\ª —éa˜5Ù‚AW¤Ž”L„ÈÆóM‹‡Vï=÷à?]»pùâ±eH&ŸÀ-˜Lo_nhj%Ø‚lE·IubCg<Ùm*$:²ÃÝS½ssÃËËó3³3µá(Ãñì¾²ICwžyÔÀx酆Ì`ÛC­Ñ£ oF1ƒls‘ C™hÑ%Y‚–Ì@fæàÌ…Ë®~wõòÍ«Á¸´2çIDATW¿ÿ©÷ŸÚ3ïÏÄš§×_ýúêç»yõÖ§ßoüé«ÿ¹}ðéSÅ•ÙÞåžlªT¨ÇK•(Í9j˵ÜäÀLf`‡–GKíÊE“ÍÆÛm¡D´µ§#Û•Ë[Çw Luµd&—fׯ¦ÖÆö?¼÷ÃÞÿãÆŸ¾ßøé‡?|·ñ‡7n¼ûì'¯8w¬07(¶¸kÝÉÚP&FHÁñ¥ÆŒHqÀ%[aà~^g€˜ d‡)ê×&ï[iá}î¾'ß~q×Ñ}Ý3ÃÉÎfO2„ðd™¦’•M®7CP …àˆ½TI"€Ð3Ë:V›˜¶ØI†Z¥G´®C %„‚­Pjhpø½-é©íæîBîàžÂá}‹=²röÌ—.Ê‘0°¸´¸œ®` J§AŒ@Ù‘„UŠòg^¸ôÜ»—ërM:@z1¿3ð5Õnê_q4x+¨êjZ¡6©;p6˜l«&Ü™|bfn´µ5†æ:{Š6·3qšE©ÒÓk|R ÉŠ[«TZ”2˜,UjX <²ÍKEÙäHd~ ¦C8Ô—òõìèž<0þúï_¹µñÓ·ÿøöÅO_ž¿wÉÙè—êþLÄ‘ò÷, xûú§þê½Û×omüõ‰O^9\ºQ5qdu|ÿZ´³‹rxu¬\˜ô´È(I 7c–aš¥xÑæówô÷5µ·&ZR±L¼g¤kln`t®w~u|r©fuxreðèùC¯~ú§?üËÆ/?oÜ~íó7ϼz~ñèrf(+¤ƒ™h}®1Ý•“<ì`Ê„ƒ:‘âµ ”šž€n íŽmO Ž\š>¶Ü»wªoßÔÙ—.ŽîÚ^ŸOó>.q‘ÁyÚò"4®Ô«pš`y–¢I§Ë^WbL&ÎåA%d’ˆ!À¬ÖÃz¯Rij`TCÔ@Á‰V.OM÷.=\˜:øÖË]ûðµ›_ÍÙÏz’×Ɉ¼ìvº>ˆ$ìÁë°Wbh†áfk Õ¤ç8ˆg= wcȶmrĽ&¿”íbjŒ5¨Nu'Ó] ÑæººDÀå“QB'ËÂÔÔD°.ÌŠ€7ü9m©EiL?\\Æ(!L¡Gï´ìf`ÇJ¥–é¢ìÄêÃé˜'ád‚©þƾ]Å{Ÿ¸ýùÕ[Ÿ­_:ýê7>øÊ“}ËsÝ‹³³‡ø3Ùr„"­Þ;“ÅN%ZTy{W¾XÌ»[{ ‰lC®'Wíì›(L/ mïÚuxvx¡gû¾ñO}ãó×þ°ñ‡_7~»òÍ»÷œXëÚÞÈF‚-õ¡L4ÙÞÔRl³x]8slFÄhî˜dÎí·D¹ñá©Ã+]Kããë;O¼vnÿÓÇ?r"ÞÑbt[k(¤Ñ,¼ÕïòFBz­R+õÌpFAÁ@(4Ç:\oÖÐ,ÄpÍê1ÂI¢4I„TãDŠU‘4jw{[ í »GŽï=q¬ïôý/þòý…Ï?>öÒ¥ºÎ¼7•xk0˜•»×­‚!£ÕBš¥*xWa¸š¦$^‰é«I½š…! Û´MW%äTw³?„XËiÓÅ´ýÎlŒ@Ì¿¥ênµ¾&–ˆDãQ#/–Jà¥ÚI„ªL£[ª”J=ˆh+Ð5ì#Æ :’±xü‰–œ#Jæ[’Íö˜Ç“ö5ö7­ Æ{£±bÔš´Ú’vGÒmò›nIg ãm õ. ·Nv®>|èÚŸo\ûÏoonüv{㿎¿p~`e~dmWïâ¼X&í®‡ 5a|ܪš õ4‹0&›?ØÜ 0mëëlêÈ4¶&[c «OíšÚ58°½0²Ø;`æÀC{{åìù×Ï~ìÞüD!Ò·E]¾Æ7¬M×dzFK©i$É”úûƒÓÓ`,ÐP¥i…N¯3žçsÙ±ÉC»‡öέœ=òÊ7ï<ôöã;¦‹IA@*ª$ Êl2Ê"%V†uL±4Ës ËXd‹U¶"M œª„PÀJ€aû,g”ÌVŸHà»4Ú­aŠÄš¦f‹{.Ü{è©o\þ¿¿=ùÅ'‰Ñ~SØŸêî`d /HÉ.»C2•²B«Ù¦ÕÜ­Õ”#0@ºÖÉuw¼Ž÷ÉRÈÄÙ¦2MµÑ.ÖZ»µÎ^Ÿ™k­ÿ®Þ‚ò¸?æ`¬.žJV«TEƒÀÖß È0D•Êùu@ŽØfOK€‚óFã¶ÚZ¹6ooZœ-ζMöLì›-.öÉ ²'ëue\rÒj­“ëj#„ˆiaÃͱh>Ù>ÞÝ<”å£kúä×ß?íͯþqëãß¾>úÌ™HOvtï. à¸_+ð¤ÕVƒ4wºéBF¯Â¯‹ö`¨¥«3•Ï&²É\2Þíé˜^žíÙQ[ì™ïØ^œï+L]É`s»ÁçŠy"ÍÑ@2ä‡Â©¨Aà08 € ˜»Ô˜2‘V§9Žwtd{£Ý­£{N¼øØ…÷ž{èÍ ý{Ç£ùÌ­¢ Rf㘥”¨®LU½¥¤$Üê²[6ârŽç€¬Qcd„Vê …Ñ „¾TôDc'z1`s%|À¼ 1*T³ÐæÝó))í¿VßU¦¯¶×y’­w]¦ÈŠš Ð40¦†1…ªTkÚhõøìÅë³úür ÈÙ(g2X­ÎHÄŸjhŸÉO E;s-c=ãûv¬>t`Ï™m³…Xo2ÔVWÛN÷7[ÂömP•–A V®\[ÎÄ"-q°ó8¿4¼{â㟯rû‹×¾¼zág¯þðٞǎõ.Ïd&ú2ã}B$ˆY­¥;F^càÀ†MR8oÆyÉ©—ýÞÚÆX{¡¹³T­ÓÞ—Ÿë‰úøÂà䮑ñ¥‘ÂXG¼#áiðùƒì–žl¬9nˆ$šxÙ‚P0:°(^G—žßpÞ€3‘Ì ö÷/Íul™]_>wåÒÙ·Ÿš=¶”Îø¢Õ8¤g)Ámgíœ7VêÔåjeµN­ÃQƒ‰µ:íuÑúX2aw:à;=*䀪•RªaùÃj0¼†·"°Ö,¹sÙÌÜöŽ=«½÷;uâå_~zäÚǯ¼îÕ;-¤Ûö”åjQ@šjŠ41o%Q²ämˆ' mÁt\EÁ* Úª­Ü¬Ú¦f 2¸jf +T5òjDƒðT®®@k¤hÁçàœ¶JHw·BQt©ŠN£ à]®Ò¨Qœ±Xy§‹±Ê¾Dœs:tFÆðÛµæ?VhÍOçgGB…¦å‡î}øµ'§×wŽíŸi™Èû²A9á°'\õmq)(«(=.ÒKšl’Íï¢$ÆUïI´7ˆ!Kaºû£[×®ÿé닾øËÆ_ÞøËñΆ{[÷Î:2îT#ew¡’¬¦¹ŠUÓ¦êR“D+Ì ‚ËC‚·¾®gl דOd©|rxº8¹c`p²«8Ö>6?8³{rx~¨{¢;Öå míýíé|:‘I¤³)!šλt_•0Éftûl±X(×Ò13>}hußÙãûÎ;xþþ¬e§:’ƒÞc'Í<ï²k°Œä¸у|«ÅjŠ` ±†d®½Íåõ¨õb(u5Ò x «QLOQ¥nÖ S‰cÛŒð{cÃ{VÚ÷­Yxòüå¿þñ¥[7gN¯4s°ËbðÚ)»Tª^ ¸(Á(:åjH[¡WW :Ì,ˆmx¯Ù÷›<’žCaoÂH`JÝ'7W–AF’0³Õ¸®Óš¼Áçúw•r«Fƒ°\¹F§Á@”k•À3`d¥F¿EQS®ÕUèõ5D‰'ô&#ã´ ~O$ß’ˆwç ËgŽu-Mì;ÿÀá'O&‡rMcmîæ ÑÏKaÙ—ÆòIÎ%ª)=efu‚)”!í~§-`7ûÌž„7QHޝN>qùéÿþ˿ݼö—_ý÷ÏݻǻvO´Î ÷--ø3-ŒÛ§fy­IBDYIà ˆ‘íàÚ9BÎÒÌÓ\ª- ´úÜÒä®ÕÙ‰í­ÅÑÂÐlÿðÜÐØÂX¶˜KšRm©¶Þ|*×OÅšœÄ—ê–irL’n¯$­l&ÖS^Ý9}hå¡Wžz๳;ï¸gÜÕàÃV,¢äué X†ÒK`P¥V­Ðiõ®†¡½Î`âÙ Ä9n u(®A1¶R¯×ÎóŒÍƸ\–úä™úºÌŽ™¡û:}|õÅK{ž¿xéëÏM©X…À^û?+Ëx¿#–KùãµZ F9JK¡´  ¥ïÒÔü¯ßýó¿TnvF=í#µM‘R tT…J†M¢ÒÁ ®Z¯­Áaˆ3Ü­QTáë¶£¢‰¶ÙªPTER:¸\¥SêPŠ“p#/Ø]F«¼¹ª€]iK?–LbÈ/äZÇúÇ×–zwNOÞýè•νó"ÈÃ-SÝzîLÖæ£ÀB"ƹ2¤ÀÔÄß‚Ô6Q)·]°‹ÎCp é®ÔàÂ`ßBÿÊ©=Ï|øñÉõÅ箿uå×{VfÆö­Ì8X›o£ÜžÖD9܈2<£a8B2WÃH$òDjcÍ c;&ú'úîY›™èmïiiïÍvôç;Úú&{'—¦Æ&Öš:šš;2¹Îl²)Ñ”My<PÆd®­s76x›SÙ‰¡îÅ™é#«Î?øÌ‡¯?ûÑësGvsAk¥†Í$j2ò.»–Ä«ôÚÒs#Æ€i€·ª¶1Pà Ò“l©¡3FQAhÉa Šj[Áïó6¥Ý™´Â,„ú»»÷¯tÞÓ{üðùo¯¿üÇŸ^ùéfËü ]B=öÕ(¶Àj“ÇFÛør}u…®š’Œ¶'ÝÝÉ5US¨Êˆƒ°sÀH;Òmƒ…‘bs±#˜ŠƒøF5ªÅp”52²™÷88·à½Y¥¨@ L+a¤Æ4¸¡4ÞI‹Ü™ˆÅ²²¨3C“²€ ‰,»}jhxeGÃ@G¬7wñ£×Oξo93ÑIùE…BeÆó¢"ù/eÿ¶¹j‹à²ØCî fH`Z(žÕaed†²yK˜ ÊmÍÝ™X>Ö5Ý3°4zσ{?þõ«Ïþó»o7þüãÆíyìÔäá½³÷ìÞ¹#32lôp»CŲ–…x°¡‹dö¹¼ÑСëë'Öw­.÷µugóÝÙ¶ÞÖ–®ÀÙ‰Öäö•¹Ã'Ì-ÏÌ·ó‰¦R‹0ÊdÀE³Hr4,„ý¹ÉÁ¾åíÁ®¦¥ÓG»úÂóÿqõإǢÝ95 H‘ÀEd4è ”'\W›L$³-QتTp²UO‘Ã8üþD&c”¤j­|‚UjÉÅ:ÕQ!r”l†^Á2åFºœg##ý‘ñÁèö±Þû\øöÚ¹›Ÿ=úÅÁ¾.Âç©âh•`$f)äæ<–Rä˜Ñ!H~ÛÝꊪ¸«Š„• ŽYMrÈËÆ3]Ù†¶L®·st~ûÈüÜ&¥ª4¢ ¯'Ô˜ˆ´¤ŒNk5oѪªPDo4VÃèÿÇ[‹ªÔ¥¬^®Ök€y`9Tà.»\r5Ö×ZÚ¦w=xhç‰S뻑}ú`¬¿Å×El´Ò©Øä6sveKïØÖ&ë-wúBip1†.ˆX°YB (#Òf§IÕ%óÉLo“ Væõ‹oß¼våÇ/¾úï?ý¼±qñ“+½Ëó]Ks®æTÓð íóèDA/ð„Õ¬¢HÉçº)Ý‘]Ú¿{õðêÌÂTïPOKG&O¥ÛÓÉ|C"ßÐОjío›YÞ>±srdûH×`gS> 7šYƒMD­¼;«ïÎŽî[\{ë‘·Ÿé[›v4‡ì)´+Íxƒ3ûmÎ:/f$X o²ˆH-°[•U@Áê „GašRÖ( @eƒøÖ:Ñλk]'ÏtFÙ,+U¿þÄ™Û×ÿúËÏÿóÎío~÷ùÈÝkKñþîÚŽô!‘”-¸YpGëLN+8áÑãS‹S­]­-í-™¶L*ŸŠg“õ-ñxkCc!“êl.Nö'ûzÆ‹í}mïXºÞê“)»‰t‹‘Φ¾ÝS=Ë“÷ízøÊÅ—¿yÿÅ/ß¾oUJ5‚$” @ó(mà…úÝf”fºj0Wª5z8.¯„à²ÕÝUÕ:‚d-VÀîd$”Žúë-a?á´ê,‚ÞnE|žÞýkŃ{fΜœ|äø©O¯<~ó³Õמä;+yÆð!ýN]UªµÑ³¨‚Pù ®0íªífm%锢í͆p ^+ûݰã SŠONØT!å*u ¸ÚVxs=Gý›¢¬ÑT"ZnSƒ¯°j\£Çjô„ *=©eÌ6J²ŸíkH¸bÉž¶í‡W'ì:pþÄÓ¿~თï9sĵm¥°•°Ç=î„¿¡=í¬u›dA©SU©€OTÐ&¶J]¬ G!šÒÀ}"j ¦%^ƒé –TÃ*ÞÊY\f›ÏiŠû"”]Ô‹,æ°ä&G?ùí§÷~ýöÇ|³ñ—Óo<Û·:?~p%Ö[hæünX4ÉuÉï’ƒn[ÐYêê鉦¢©\:Û™kéÊ5¶5År ñ|ª±³¹¹¯­u°£c¸³k´»0XÈ[;zÛ:‡:›òÁÖXóxaîþåýÓÛ\yöË·žûòÊŽSû½í JÑ “L¸ÙªÆ`ÓÍöhwl.+¯ÒhË”5w•Wá ŽALÍ ¿7WTlU*+45†Ñf³Ž"D°3²3QÊ¥ÌÑZ­,¢>—#Ÿíڳܶºkèøú™ëïŸýòƒÓÿq%¹2u—•Ƽwc’úÊP}%®ç½6C](qÔék1ù,ž†Z“ߦ\özëÁ62”ÀS¢„qbþ¯/< wýþ IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageFieldFlower.png000077500000000000000000001061771375753423500260320ustar00rootroot00000000000000‰PNG  IHDR€€L\öœgAMA± üa 0iCCPICC profileH‰–wTTׇϽwz¡Í0)Cï½ ½7©ÒDa˜`(34±!¢EDA‚"Œ†"±"Š…€`Á  Ä`QQy3²Vtåå½——ßg}kŸ½÷=gï}Öº¼ý¹¼tX €4ž€âåJŒŠ¦cû ðÌ`²23B=ÀH>nôL‘ø"€7wÄ+7¼ƒètðÿIš•ÁˆÒ‰Ø‚ÍÉd‰¸Pĩق ±}FÄÔø1Ã(1óE±¼˜Ùð³Ï";‹™Æc‹X|æ v[Ì="Þš%äˆñqQ—“-â["ÖL¦qEüV›Æaf€"‰í+IĦ"&ñÃBÜD¼)ñ+ŽÿŠœøRné¹|nb’€®ËÒ£›ÙÚ2èÞœìTŽ@`Äd¥0ùlº[zZ“— Àâ?KF\[º¨ÈÖf¶ÖÖFæÆf_ê¿nþM‰{»H¯‚?÷ ¢õ}±ý•_z=ŒYQmv|±Åï c3ò÷¿Ø4 )ê[ûÀW÷¡‰ç%I Ȱ31ÉÎÎ6ærXÆâ‚þ¡ÿéð7ôÕ÷ŒÅéþ(Ý“À¦ è⺱ÒSÓ…|zf“Å¡ýyˆÿqà_ŸÃ0„“Àásx¢ˆpÑ”qy‰¢vóØ\7GçòþSÿaØŸ´8×"Q>j¬1 ä×>€¢s@´ýÑ7|8¿¼ՉŹÿ,èß³Âeâ%“›ø9Î-$ŒÎò³÷ÄÏ H*P*@è#`l€=pÀ‚0VHi€²A>ØŠ@ ØvƒjP @h'@8 .€Ëà:¸nƒ`Œƒç`¼óa!2D UH 2€Ì!äy@þPÅA‰BùÐ&¨*‡ª¡:¨ ú:]€®BƒÐ=hš‚~‡ÞÃL‚©°2¬ ›À ØöƒÃà•p"¼΃ áíp\ƒÛá ðuø6<?‡g€¢†! Ä D¢‘„¬CŠ‘J¤iAº^ä&2‚L#ïPEG¡ìQÞ¨å(j5jªU:‚jGõ n¢FQ3¨Oh2Z m€¶Cû #щèltº݈nC_BßF£ß`0FcƒñÆDa’1k0¥˜ý˜VÌyÌ f 3‹Åb°Xl –‰`‹°{±Ç°ç°CØqì[§Š3Çyâ¢q<\®ww7„›ÀÍã¥ðZx;| žÏÅ—áð]øü8~ž MÐ!8ÂÉ„„*B áá!á‘HT'Úƒ‰\âbñ8ñ q”øŽ$CÒ'¹‘bHBÒvÒaÒyÒ=Ò+2™¬Mv&G“äíä&òEòcò[ Š„±„[b½DD»ÄÄ I¼¤–¤‹ä*É<ÉJÉ“’’ÓRx)m)7)¦Ô:©©SRÃR³Òi3é@é4éRé£ÒW¥'e°2Ú22l™B™C2eÆ(EƒâFaQ6Q(—(ãT U‡êCM¦–P¿£öSgded-eÃesdkdÏȎК6͇–J+£ Ý¡½—S–s‘ãÈm“k‘’›“_"ï,Ï‘/–o•¿-ÿ^®à¡¢°S¡Cá‘"JQ_1X1[ñ€â%Åé%Ô%öKXKŠ—œXr_ VÒW QZ£tH©OiVYEÙK9Cy¯òEåišŠ³J²J…ÊY•)UŠª£*WµBõœê3º,Ý…žJ¯¢÷ÐgÔ”Ô¼Õ„jujýjóê:êËÕ Ô[Õi4 Ý3šªššùšÍš÷µðZ ­$­=Z½ZsÚ:ÚÚ[´;´'uäu|tòtšuê’utWëÖëÞÒÃè1ôRôöëÝЇõ­ô“ôkô `k®Á~ƒAC´¡­!ϰÞp؈däb”eÔl4jL3ö7.0î0~a¢im²Ó¤×ä“©•iªiƒé33_³³.³ßÍõÍYæ5æ·,Èžë-:-^ZXr,XÞµ¢XXm±ê¶úhmcÍ·n±ž²Ñ´‰³Ùg3Ì 2‚¥Œ+¶h[WÛõ¶§mßÙYÛ ìNØýfodŸbÔ~r©ÎRÎÒ†¥cêL‡:‡GºcœãAÇ'5'¦S½Óg g¶s£ó„‹žK²Ë1—®¦®|×6×97;·µnçÝw/÷b÷~åÕ=Õ==›=g¼¬¼Öx÷F{ûyïôöQöaù4ùÌøÚø®õíñ#ù…úUû=ñ×÷çûwÀ¾».ÓZÆ[Ö}w> Ò Zôc0&8(¸&øiˆYH~Ho(%46ôhè›0×°²°Ëu— —w‡K†Ç„7…ÏE¸G”GŒDšD®¼¥ÅêŒÆF‡G7FÏ®ðX±{ÅxŒULQÌ•:+sV^]¥¸*uÕ™XÉXfìÉ8t\DÜѸÌ@f=s6Þ'~_ü ˵‡õœíÌ®`Oq8圉‡„ò„ÉD‡Ä]‰SINI•IÓ\7n5÷e²wrmò\J`Êá”…ÔˆÔÖ4\Z\Ú)ž /…ד®’ž“>˜aQ”1²ÚnõîÕ3|?~c&”¹2³S@ýLõ u…›…£YŽY5Yo³Ã³OæHçðrúrõs·åNäyæ}»µ†µ¦;_-cþèZ—µuë uñëº×k¬/\?¾ÁkÑ„)*0-(/x½)bSW¡rá†Â±Í^››‹$ŠøEÃ[ì·ÔnEmåníßf±mï¶OÅìâk%¦%•%JY¥×¾1û¦ê›…í ÛûˬËìÀìàí¸³Óiç‘réò¼ò±]»Ú+èůwÇî¾ZiYY»‡°G¸g¤Ê¿ªs¯æÞ{?T'Uß®q­iݧ´oÛ¾¹ýìýCœ´Ô*×–Ô¾?È=x·Î«®½^»¾òæPÖ¡§ á ½ß2¾mjTl,iüx˜wxäHÈ‘ž&›¦¦£JGËšáfaóÔ±˜c7¾sÿ®³Å¨¥®•ÖZrö}Ü÷wNøè>É8ÙòƒÖûÚ(mÅíP{nûLGRÇHgTçà)ßSÝ]ö]m?ÿxø´Úéš3²gÊÎΞ]8—wnö|Æùé ‰ƺc»\Œ¼x«'¸§ÿ’ߥ+—=/_ìué=wÅáÊé«vWO]c\ë¸n}½½Ïª¯í'«ŸÚú­ûÛl:oØÞè\:xvÈièÂM÷›—oùܺ~{ÙíÁ;ËïÜŽ¹Ë¾;y/õÞËûY÷çlxˆ~XüHêQåc¥Çõ?ëýÜ:b=rfÔ}´ïIè“c¬±ç¿dþòa¼ð)ùiå„êDÓ¤ùäé)Ï©ÏV<žñ|~ºèWé_÷½Ð}ñÃoοõÍDÎŒ¿ä¿\ø½ô•«ï-_wÏÍ>~“öf~®ø­ÂÛ#ïïzßG¼Ÿ˜Ïþ€ýPõQïc×'¿OÒþ˜óü7E; cHRMz&€„ú€èu0ê`:˜pœºQ< pHYs ð ðB¬4˜tIMEß 59 ²ì IDATxÚ¬»i¬m[v4š9W·›söio÷Þ½ï½z]½¦ª\år56v¹â8¸‰"’8‰# Q0(HDââEB!¤`D0vbH‘!!`Bâ6.ÛU¯z¿¾¹ï¾Û¾Ùýjæcðcí½ï¹÷½* Âúqï:笽ל£ýÆ7ÆD33»x³ºTÌcS "vUQU0¢™™!""ÏAÙ $ˆ ’˜"¶/Z< JÐ~Î/Ü<¸pyóÐ3B€ª†f˜’å1ÁhÄa uL1*3E…5oR‡ffÄTunI#Ö–<1 d„„µç±ËÁ‘'‹  àšØŒ£Ÿ*\®U—k{°îŸú½[ü ±•E{¯ªíí=+ˆ!¨jûŒªZL¦fÚŠR@Á̘À •¨!D¶Å±½C@%\,h¹Z|è†W+·ÅÆj?Gd„`L@„ @]ˆPD5Š ƒ@dh#˜A£‚ÀÑ,ˆ6€ ÔÀÍ€T#@ê2 `ªÚhR5V‹*#=0 À 0h Æ<²TÀE5ˆHk­¸‰ˆÌÌLl¡µ•ÍÚ…o20S4[<‚ˆfJˆÊè ‚Ik™ôÀž[c![šõE;_™úR5Öþ€ˆ+•]Ø/ µ 0P€( „ÁÌ‚ "Ùróºô¾`hTAÌÌh0$# €h€h­ê ˜§M`çÐPQ UT€ˆPAø%2€µÿ¶*P[캵'¢ˆ†Hí’ÚðÒJ™U À˜Ð ÍÔpáìÐz €!¨€©¢¶_Mˆ Þ€"š"‚©"2*|„º.êC ‘¢™µkµið !¶ äÉÀ/¡ ß)„A D5$DAÅÍÉÌ‘ LÁ(QÈMkc§ä9…:pZF°ÖäÁ– «Â705@À¦ž«1F‡Lˆ`bd¦‹p¤AŒ‚¢¨E0TYìÛ4Àd*€¢ÆàØ­„éT…É ,.£‘ÒJ f­ uÀb=Öµ‚ Ê~Í ¡ H¬ç5%H™r¥V› Há sv6#%Ò:úˆµ ES k73ð&.%Ù.èxnš @— !è:I14æfQ'kãh`¨ÀŠ?Ê­`i|à0 (ª ‚z&B$RT3SE15C]˜Þ#Ò1n£("!š±<È­fÞƒÄe§Ö·¨ÍOØ áC©&yʦ24̘¼…”çlxÐP‰ÑE2 &bZàúÖôT—´Ïâ"Zæ„nÊ«øáC%£Ô)"µVLà™Œð‘‡ –+Å6Ê=ßpÿÈÕ — 4$fB‘¸bWªjEo¦€,uÆ|# `ލï[Ö-Š,S0 ¦ €èPKA16’3{à*i‹CÍ€ ÌÀEciÑ–Ém)kz„%‘€DˆÈ±Ÿz¾Í׈fº^K¡Û÷À,m™ÕÊÿa„ð/s-…‹Hä‘ÁlAÓ@›.°^Œ€¢‚aÁ‘ÕÒÄ%,f¼ªV_ä˜@$%$«€Ó ¨†@ŒLä;FEF2$€œ¡Ž‚ˆ†è0*"’1#F3REZ‘Òd6Da~„™â’~Œ?CFü¾¤ÜÊ`ϰ¶>lEeÊØ²…-m‹KP#S@´ÖZ³fmš. vR03¾ð4˜(a3! (€ŒhD€²Ü‰9[Rr=ÄÜS¥Ø÷f`U0çœÃÅEL¾]ЪC²jÔ¬\û"S½¢Nÿ?_Z1pÑÏ>lΟYur¾wtÂ]ƒˆ¬ðhû§(@Ñ%&IzѼœ÷-µhBHÄ Ø#j¢Ô@ƒ"Z &€ØrÎ-ׂû¶ôW 2X›NT4ñÎåYò‘^‰ãâ‚V™àAÃë_:P´r¹Ø â¥ÜÕ»V½Š•g\|x•®L ÍPU °%~8›±-wÌLDV;½ §2$UQc3 !j$B€6m;t-F23D3u„D$Ú–\ˆ&¨‹Ð}­¤óˆO¬\áÿ_´Öºzׇ5±B«åµ:X:ñÂVTÕTÔÌZê·•5JŒÐ,9±EƒgAÛW¤[«ªˆ©š* š :3òL¨JÑØ‘É*gdfÌ21™šÆ¨Â D˜1±¡ûæ{5¹ÿy.~êûy+Í•%¶ÒäE+|@]¨>1ÆÄ(´„;‚"«"#¶RÌÙ|’ˆ3¯Tû¡­ …(­1Q"`‡A #0 “5‹Æ«aÜ6±à)“KеL™3ã‚pD³ïíE³ªÈ>R”Žã–þÅg.†¯Uôbô‘õGÆÆÕ}+¸ÕgW³-ûHˆIâUUc@b0Ul+)&D]<¼üªJ-¨¢¦%Š¡™é;“AKÞ[Àt¹C@6óÎØÔqB„ &¢ÀÌîÂìÑžð‡a<€]tƒmUÈ\Œ$«x²Bx+«\½xe­½-‚Vࢥ8 µ™à‘ü´Rá‚G¢¶Ö7ftÌ- UÇè@DÚΡˆ¬^·Úï#¦fjºÀQ@ªŠÄ-gÜV/ j ‡š;Ç`ˆÜro„M?lRfæ.$®ï‰@.f‚UÖR•‡ ö‚apa?  ˆ«JbQ¦-''àáºôÁõ½ÂãJdmZ^iô!ƒ0óÞÅM#‘÷HÆÄè];ññ`û­<ôTZ2Š”œId&j9H3Cƒ•Y‡CꈙьAb ¤—}ŽÕÖÚ¹•…¶ÎøHv½X /± ¦(ÌÔ¬m™!¢ rl-§^-7‡@øÀÐL5ÑÅ4Û“GðÕ*¶\üåj<ÜŠ¯UI![¤VU0ðµRÄ̃ ABF[”£Ö¢ 0jÒÖh ¦ JÑÀY η] A KAlˆ F3SFß"€ã^o˜åÕn¡Eî‘hðáàÞš|›©Vd2 Z ª"b`H$Jˆ-Q‚ˆ dhí ÄöCÉãgæ‹¿ü>`weìιÖ#™YDZgUՖ˼™ŒÐ˜’(F5i»mä 11µ¶¬b33Q,(ˆ£ƒv–@5U!Be1#§¦L´ÀV\ÇEòEÈýDAí~bŒ«/ H$†-Û¨†bÊHÐ{Ør^èˆULW‘’¦"b’$ÿ¯àìGèex¼˜ Ú½­²‘‚šb;J#¶(Ž@–ùƒˆVÝø§ÍuÒZû¥è´ Y¨š‘i[ç³"qÛË_&’–Ô\¨¼¥÷-—ýý€¬©ÚGUªÚ®³­Ì %¢<UT0QfU1`b55C$#@Oä#šª“9TEˆ„Í 7ΜFE`C@Rhk_[!…¥­ ‚EµvÁËáœU½þ@"H¨‹jÛ•3ôˆhª!4‘RÓe¡o&1ª!2!-(wb23Óé Œ˜LŠÌ#¨¢[ÍOàB¬‹t¿‚†ÑÚüˆÔ¶ôMUÔT›–5vÎ3ÅåØeÛÏ51SE¯fur$´®fªäÈ$w”¥®mU´Ê‹12³ª B!ª)²±†Õm9.‡(æ#( ‘©c`sH Ö‰ˆš)³W ¨ìÉ?Amºh ÀÔXÕ´u v¤ A¥íp"€´ùR!„eã iÑ \XÁ²éÖ6ÌZ”¥.q$*ª‹. c¢ÖV-áA-B&Ä´ bdÁ [Û–"Q@Ø94ÓF©D$5 !Š)‘KÚ…¨ªƒ% §Iš’á,^ !Σ²ó†h@„ºbö=¡)€!8 …͙т‚LÈš’ *`¦]’ÝüàþÑùý{÷ÞÀG å,"ØNX¶m%C£`¦f@ÔöЃVÁâã`m°xxº`5mf€„Œ@¡SdUT ˜1×U­ªˆ Ä­ÆˆÈ·³"„ˆÐšv²(ØB¾j¦-¸DD!²ÖP• ‘™G-ÿ¨ªhÚëYâTä4ƒ ¦ÐŽ,&µ`ÚTÚ°‰dÔ¡PˆFX¢æÂQì÷^?<º]tÜËŸùÌ}ãŸzéS¿ù}8>MÎr·J ŽûÍ ªH´3Á:„²‰Œ¬º) Æ@–4™ˆ±©,B<²ª^˜°]´Þ@¥[dEê-6s%1msd«b33çPD©LFbâ%.Ò+¢"†ƒ¢kÛpÄŒ -~sÞ¥Ž=#š:"G )Gß ‚yïEÚ¡2®¤ 'hûEf¶iiÂgãy·H¼+FV0´ISõ]b†ðÝïÞ<=ü›?õÓðÊþþïÿF?ß}ûðà¼Æápþä~žO®ö·²ê²ÓETP}µµ…e•9Ÿ:fDX5µƒªIŒPMj£@"j`AÀ HÈ""µé HBY×­ÀÍPZy¶À1Ò ˆ"¡0!-X} B*MÁ¨i4FRŒ– ¡†–f@oœX0#C < xBV(˜U4qÔR4fjâÉ Z ‘5K ÚØƒ, @RÅÉ?ýý?úÝ·ÿç¿ý×þëý<(t¦Fg'ÿù¯üW¿ðWÿ¯>÷ýã_ýNyö—¿ø¥Ã7^9Ý ÌôÞùHÉ™;žtk׸ýäøZ6s(Ë¡>5ä>˜^NŸ@45#E3"tÎÅ JÛpc1£ePBÅhÒ¦+ÕhìØ‹mT!5T½À@¡¶S Ð;a‚Ú†ˆ¶h"™zÇ1†4MóÄ!XêÉ9—xbAÉ#˜Š…”P՘ѡOS×4QUšèTÕ  ŠBMDê&ʺFˆ çÿçïü£¯½ö¿¨ŸUSûí¯ýÚ7ÿàúgþæŸ|ûµûW>÷Õßúéôµÿæ—ÿ­Oþ¯Œ‹oýس??žM°·smýù8·W޾2…h1ëßûòûï|çôðä©kWÞºy8ŽvntïíÝ?PëJ¨æÖ§»wh^“ó¡ v%é'—;Gwîö×¶èäÍ{v›gïYµÿÔºóIaë…`@á|8&fQÀ¿öŸþÌÉážœuÿé¯ÿ¶BbCm¾¦;„ ™xǺä Š,޵3éê( &jlf º,OLPÝ¢›Ô;—09‡…÷fæ½Cmbâ}[Óy6@dDsÎϪr½ÛŽÇÑB¯»ÄççCï“UŸ¹{…¨`‰cçD¿òúWÿá?ùõþZïÚΓãÓÓÓóƒ¢ç§³Ó²qwï éùç¯}âÒS»O_ýÖ[ß,«Ù½Ã×:ÝÁÜŒa-gì˜bõíw!_óÃÉéæFg=¦g£Ùõ'7úýî ÝEo}‘óØØ”æî“Ïç[ƒ­ñÑá7Î÷6¾šz @Í]Ñí ¹Y?‡‘/}³£¡+†Ýµ±ÏðãmW•>¾ÝëL“|‚ ßpe´3”u—–16½9€Ä*8SС£:—ø4KðìàÝ[Ì“wj:ß>হuÿkW¿ð Ÿï÷®A99¹ßT«|'»0©O×R¦Îz6×›ƒî'¯lþÔKÏþÙ~ÞclT±Ó$©C@g8— £rïø‡·³Ù{ç­ßŸé`cíOö_ûô‹_xæÆ³œjQ¥ÿèkøê¿;ô¿öͯ\¿¾õ{_›|úÅ¿üÂ3Ç'÷æáôìü8J‰¨ìk3sŽÔ¤GbB£¡ìÝ+c°^—®??H™4V•ÔεsÑ@€Á…(BÔ(3U'Jb#DjÅqCdr‘Cá™D \ÓÔ¢ª˜qY–Î;S5fSc¦–«^1Þ"ÚRMHÈ ªê½GFdbUÆtÑ)5E@QIÓl>ŸãôË?®ÆÇécOj s½7¹5…aãFî$ZoW#IzIÕ° W|^ëYŒ³Ôõ¨{¥ªÇÞåŽrMž~éúÏ…²üÊ7åÍ×ï¾ûÎ3׿ðì ×ÎÆçÿÎ_ùÛú¥·>xýààÞptÈ~šÕ¿önQðÉùþöÎú¼>Ï|) r¤¤…LU$TDCb4ÅÐÔÎù ±1iÓíxN¬FmOÁ¶ÃßÍ !5/PŠ1dF@¬¦!4Yª–Ø®Q V‰P†ž|ê¼C‰mN‹¡í–Ą̈mÝX£‹qH$ÈVœ&! $ÌMD4UQòí11BÀÿà¿øâåÎV©F³ âŒ}ŸÈvùÛçï§|\ç½³óZ«¦ÛÇ·¥®z~²öõoÝìïö.]ªž½~ tÌ)¸¼ˆÕ¼‰¦.gd'ªÊÆu²ËYµveã‰Þ`ýÝÃop ‘JÑÆÐ‚vc“4“j`-ËJ׉iž±ƒšÈ½B¬ƒ6 J¬š&ªŠ)UfmcY1Dˆ¢H$& 3¨0Q€’ÁDŒÐD$#&#¢DLØ”¢x&%äMÌYK©0s‚"4(Æö »‰z¢’”t&ŒµòšL34‡^½¨P;h)F•`Σ ¹%¥ÖIðÔg.ËýÉ乘ÿéOüÄq9©p¾79 MÚìÌïÌb޶@†éf*mîºë÷›cüÆa{§NzµN1¼“ekH(Z&ɳ)ŠòdØK†Ÿ¿ IDATú–?T±";âõ^ße•4I?fWÀ0‰¢l ‡ØXUÆjš¦T‰&èÀ:‡”#’š‚™9s   fh¬&â]_4(jdñ’,ç É5$&C ™’Fvd"r™®‰T`"!‘š 2#eà3àÚ‚C6‹ÖÎA›i4ñàJP@Î ë=;ï|l*ï}4E0“è*œ×6;:¸ÿôàÅ·çß>™MGa±ÞJ:Çgv>¯ï½]>±•w(ó éミ¼??x+=øø§ŸL^ÿ.TgIÂ&éîÖî¼QIÖ8DCFTk”Ó¡ ËZR×#> 1o‚k›Cp¬“¦½Í+ÆMÃxZ6µÆ™ITÄ„ÐE²Œ”Ìq*Í„‘‚O$D5D mjEdÇR« 2š Ð`ÑPѨí9’!1¥™Ä‚«TDv"©0;"p–I u‰³Ð6 ¥0SµÀÖ63Õ€™‰…t%G`b3DŠì•S'jf†žÁsžÔ¢løK÷y"‹!é¯T·§Óº M?íIu~¬ùÆ,]?8¸¿ÑÛºô\îêœÝ-Jvs_®gGæÓºôdasФ:˜„“µN7ÎæçMaäCÓ¬gé8Tk9°ÓŠ(¬½1šÙSÅZÄ” rœœMÆàoŒš‘"‘æiFH14ã^¿hJk›±X-Q³„ë¦Ìr˜(Š"±“J iÌ5‘ˆP£FEPpÞ@;ŠdH$µ¬w{gå)ZL8ö*HèLcÔ°/ý0`ãÔÍÁ2p±* —–I $5E‚õz+@Uú@ÚÔ„ýšeß¹£CŒ†ˆ8wrYºål>)Ä,"&*,(;¾šôf³¡KýÙ&p§·‘o~wÛÇ!Öe?fe®—Î'²í¯<ó|FîÀ¼|-¹w>`wS0º¨›8—°–qWùݲœå9Ï?vâq‚a\:Ç0‰„óVë;ðÞÑäs[³÷ÞxblÖC¯†Ã|k·oR6ÞiÇdzÒ7°vV+Φ}*  ó;ÇÓ°;è¾nk9Îçóõ‚£ºt^5)ÆŒ|êêèÒ¦ &Ç›ým=l¿±èP÷\&ej.¸«¶¹g{¥2S²å‡p7HÇû ‡>R T+:åÚ…y,¤¾#ZòìnN­B2ÓHŠª0êT—NâI2ò”ªJ.ó;=ºZ¢uc!AFÈë8®‚W“¦%Ä\Âêm}^MùþŠïtgH)À5…ñÑÎîàøôàæ|sVÍg!AÅ·Î1ÎÕg¶7¡ñx2ëÖ@·57xç\Þ¯Öò³½ºÛ;‡t4]ß cg4–ÙŒ]κ])ìï5½õǃéÆç,}ëÀ^¸txis~igØ[¿÷©ñz2ì÷ªR† ‡Y_kWñ–sæ\’ùŽGl¤èúûþýáôjÿ1©¬›ö Ó5—0ÔlD+'g ¿4 ô>?YÑ —…Ù³5ó!r–z‘Q=ƒÞ•½Ê>–¾vg>üüãÝÉðÈ:5—³øÝÉF¡å{Òôr¨Î³lËÃpÔp¯èça*‡€ v6“ü¤šç±ðó«Å¬Ó½r°¿÷ÔõþÙÈWIÂÉoçÊÆM|RL«„ÁTî÷q\6ŸKšÏJp¬œBUp=åé|4LÜ£ˆMBÉÈ}Ê+˜õªÝ¤ƒi´3uü6UH«œ‹¦–”X<Î'sKëÙ<á¬b Õ*Z3SßS¨“nZOñ•¶1Œp|Ö PÏ¢ûøÀî ݽ;¬oÜÔE/¾y€O­'šÍó¾L\Ïf1ÏŽFÓ“ÓÞµk6Ãé×ÞN6ò¢W4R®môgyÓ|íØ]½Nßyu#ëMºÙÆžj–'¡‰ å¤èì×w¦Ç«ƒö87£Ç¶×tzk­™7ýN"ÂùÍã:ÏòÂÛÙéL»~<…ˆëmÎçw!¹ÒA×ÈIH8ï¹² ´•ê¨/³­ÝðþÝ8dØŒ÷jŽ¡óÔe÷þÉ¡X×o5iÕáí v=™6»1Müäüø±5hh{Þ †§“ç‰ôÏeb Èw‚ŸÆ ³Xnuýp^0Ñ„y~‚“ˆÂF_Òûxo‡.‹{,/Îe˜ŽÁúËi• Z? ®¶2GŒÈýß̲{IxrÃ&š‡ Òz˜®÷#ŽîÞwE¶Ö‰iV ß=éÜ¿síŠ{÷+“k/휟4Ÿx¹üÍo¸ßz ¶’|¯ k*Ü/O‡´ï6Wܽ7ØÛ?’HOö¶÷ÃtŽTÌ;ûá¼»>˜”³¢'CM¼œ÷2 >Ï kó٬·¶>œÒ¸–“Jî«ÝN—PD]ˆR¤ó~o<ЍI&ÐO†yçieUîE9ªùÄòwOç̃£j88¯;.îN:%oX”–ó¸:ôr~>Ù.r.6kàÓãYwcS¬ØŸ”6wìÅkeÂ÷žî½Ÿ@Ñéß¼Ú;ÊS=<ŸÇ­B_Üž ïiÓéÊ[ÏevýJœ4äÓÓÍòø¦ÛYsPæ=¾ŸAyDµJy<êx¬T¶5dD¢ySóŸúé5~ïë7^›ÌNè™Aõõ»îÚ:_³íµMã|VÑÉy¸r©L“ñ«.}rÖüÑé mŽôñõz{c÷ãk§}_Ø•ÿýÍ.ɳ}™ý¯|W Æ“®¹ÑÞì°«Ïö†å¿™ä÷÷Nмð¬i(ƒëÎ˺'ç»›þl6R«2˜H‰¡‘Ø-rŽ®¬ÇiZ8Ò“‰ßÊããƒò¥ËÕá­“ëV.$4H‘ê2z+2ˆ!÷ÙîDì|V]–еdT×ÓÑÜÒ¼ÉÅfiy©W§ë´5v~P4?²Ýr.wOÂ~• Ëêh’ÜÜ«nUÉkw¥ŸêѤÚ;ûøo^Òl¯:Ê2Þ9ÿfÅoíO6¯ôï qïîôñýžì¾w¤W·GÛ{<±?µvp>­v7“ªfj×wΛò ª³êô´š×ÎwFã†éoÀ­×6/?qOǽÇzÐtl½Ø‡ù;œ5Iox\þd¯Ÿ"îàÎW¦à«ñîb6‹óˆ®öƒ¤UGúÌZüðæ«§ÿÝŸ½¼¦óÏ<7zkýëñÊÇF_ú4÷OïÏ¡zúÉ«Õlœrs öÙµ“ë½ùwÆU?ÛxçxÒHúÔΕ׎ªE§;<›mÎ$Ë»ˆz£›®vÚ‹3eÚþÙý ÛI>ó(Fv\»ÜË\<×lV‰¥÷gZ[ƒ´5„²Wì GwKHœÏ¾xu[iìê&¸ r·vvûêc鸹,wVô êæÏwžôóÎüäÍõ¯W·7ãå+×'wO×ß½mw¨û‰—²îÌ5œluÓº(nM3Ü;ßkú[Ùá­3¸=ÕÆí”ã½÷Λ«É,f£Ú×tô©KõÕ+îàüžù9æÏ\ëïûõ.wüõf5ò·Îλ3’yÕ½´£{ÇöÅgÜìt„…ûúIµ§'M½“5Õ¬†t„›—ºý£ó½²šéL¯u²iéûGÜݘ:Ü®h2Ù'6õý:ò2Ž)Œ³É¬9NéÞ-;éåé”]'§ÇÓ©ëcï,žwñŠ£À¹;«0ŸUîéÁì|Â醭әKôþÄÍkl°úäNïh<’â,]wkïÏö¶²ÁqÍmõ(é¾8oDµ"7¶¤SMîŒæÛ,€Â¤ ðÎ${&ÏóÎð,+ÖžÙ.ºêjÏgaZWåþSOõ›iÿÕÙík‡2©Ìy½›TOìij:=>Mw/Ç?y/ÌeNÏ;ç4j‘Ñz9–0zl­ã÷‡÷'$Íi?uç÷"žÞGáa„ŸzòÞÉ nÎÇ3¢žÇØ=ŸNÌûwÇ(õéµÞeMu{ûh#áZº{ÓXkr¥(èÉôð<’LÝÚµ¸pe·ªKž'™/6«ã”ÒÓýó0í¥ß¼ïO‹†ñ©k‰ÏÞ>ϲ~¥êioTTuåû|ø¹­Wg£ãÛ£µìcÃü&{U}¥·Þßê7Ùûu¾/kÓXåy9;žz5ñŸÿ¹ú¥§‹“ýr=¥ašnÄz£ì÷;y'ù•>®'u¤d¹uŽ×w6›&ŒBì2ŸÖói™]é\}»ºûºùØ¿¬/UÕ`«ŽpæeðÍ£üµ“q–êWOd\\}âçŸß^Ëç“ï̺ERžå™_¼qï¨Âñyxéc£<Ðëûëf¯õ»î8©Ÿ¤G¯ÞIÔûAšæ½a'ŸÛêgUíªÙÝ}¡ßN¤?§rç™užK”Æ÷û]Õê°žO'O¬mOìĨ›Ô‰Ï7±Ïöëº?û…âó ¿ý¶ô«_x±-{ífóãWé .ʸÓÛzsx^5ý‘L&6°™ô‹í{û£Éhò…'æ÷Ž‹$=ùŧüKO„ëkK>™þ“ÓOÿþOÔ0lžxŠÞy{øâ³öÌ¥ÍûçÓtæCvô‰^ÿ¹gè_}qöõoW;ùK¿ú»§e6øÖ«Ç_ú‘Íe÷¿;*’°> |V–›’Ρ²;‰‹?´QMÆÍ+²¢<ÇÔuªÉÙÚ½rv¿„ƒ½ÎY6nÊAŽÝi“ ïìû/zБñÔ?yzrþ—>?þìÇ&§ûëü™ŸÎ_ÛÃK;kÓÉa‚W9­¼ÅÞZq™çêüÖ-ý¯]šól®Ý“2Í«­µÞ{çØÉ&OæóJÜ͡Ӳ»&½×çpÜÄ"Ýøîo[®]º„ïÜŸÝØHw×'·Æaû»VýÅOÎöï¢øê›i´99?ÕÔk¸²3¦ÓÿÔSoïfßy‡üsÝ´¿zv­×™4ÓÎíªÎa}k+ö ¼¼†¯¼wþìÆÚýóáv¾)i}V¥Ý´ÛñîýÉV:Ó*œ7õ•qàïÜOþÌ“³òŽo wztšm]úüNóÕ›é¤åãÝÎñ<Ú+_íeëW?8;zññÓ³jӜͦÉÿMÒþ꺆A_ózæçß=žùŽö½ž¯cûÚÆqb;q£*IB¤TIE¤ $¨ ­•ýBUm#¤©@T JpÓ¦qÓ¤v<ßñœsϰç½ßñyŸyÍ‹ùG~¿Bû7_DOOÛ~ð`ØKˆ)¥J»ÿüËÕ—o‘‹JXÿýT¿÷mÝy~ ë7î¥ÇCsV„<°?ñ ùþIÆøòºÕ¯ï›ër~|@œ6Ó£ÍGøG’GK’3‡?÷Õ#9ÑV<¼“Áΰ®üuŸ–üaãNWÁñÁòñ2œ¤eUÓÐ]îô82Åâztt¯¬ì+⬡Œ¡x…ÔéO¤{ï’.,¨N×ï—ðjCþÍ· ôÕ“N_Ãçtn˜ 0»:»ÞO晆°®zkaoèü+¯›‡ýT¨!ösrcwÇ,ú•¯v‹Çˆ%¯4t÷·¿×üâmK£vSsã|Û”i?½¸ŽÝBÚk:ÍŽùæh…A¢ËâîÁÁ¢ ËÞh~þKÖâ[7ñ–]×°M&~ôcͽ!Ÿéze÷.áòÙ¶·¤èîݵ;³‰i8CòÒåÿï7—ÿÅSùÞ2ÍâyѬómÝ7£É‹¾ûÆ{=ô£ƒ ƒaœ òx­ïî=9{Ö›¦‘Ô¸ÉÞÌØòëŸr‘à7ÿrÒº6‰I[w ó˜1%Ôßx£þá$#vÖÞJ8(«"ÎG…”Ç@~°*8*¶ítÿÙ“uÇ‹by¢FÒï’=^L;½µk.¿óøcÿæê}¹Kƒ£øÍCòk¯ó×^ ð4„¤~á üÒ-õÆ äýK&}“O~¬sMôn“EÇN ª`×…ÜK·Ÿ>Q‹êÊn²Ç­„ûæ%Ûµ~~o[% HOE(õd1ÓfðY풥Ш0ž§US£1×BpXl¶O(½\Ft‚Š5 zmnž/úo‡9–°†éKw`ýÀÝ;ÈwOÀSD8æÁhL/Ê ë^ gï]~$Ÿ¼îZ>¢½h¯=r÷~”_’+ü™¿œÅ1ÇVÙ yµc½©Ÿ¯ƒ+`¨Æ}/ÖÝ6Œ™–¾nvWvÈpH’{n´ÿΙû?®>{Ô¼uºï¸}u?"@v–ôñ_{]ýèøöè•ðâ䯽·Òƒç[ûú'4úö³ò …—Üqu.7ß{GÞŸ=/NXtÝ ka o e§&¿¢’Tzûˆ.¶®³äÞXÕ:+ª«8O)ªÒaЬºÙŒ¼~˜ß”Ë$LJˆÝ}õöæ×Í…bš2cd;-óêñssÖÀ¯½0øø|ñÎýõ7æO»ÍÛ?âOdÞ×Õg_-ö¿aîø§^Wßúsª´—‰âMÓk±]„=~uàÎúøæÌ's‹ü诂i$…”@BÆ^_TŽhøù/Ã{žv¢í ú= áêP†àys±‚·ñË?Mµºµ7uZ•œã|DÚ$t£Ž?xï4Hg!G”}­^9þä ®žIõ×÷Å'^„óƒæò:ê¶è_nš‹«q«Úl”<ºÚH›N‚ˆÐo¿_Ë”0Y |Z#žVýöÖ„5¶«PDÃQÊa¢HæÁÄ3t³-±Í[߃„/Öy<ÊÓôªh ÚÍGáZVQt´kv8M+ÛµÜÛëÝ)¹®"ÚïÞªYÙù{1{r¼z»ù­o©¿öuò¥Ñö"¹Òu”»^˜Ó¶Äêô긴òªÇVZí«/ùvßTp©s/á­;머žßFV€îÞ°ýä´J|¾ã·"ìò·Oÿú×'. æÛVY%#ÄˆÞØÝü»oÒþûà÷Vâ0œöÆ~äùôžý+?»<ÒíûáKÄý‰;÷È@[‡|$Êw/ûéhøÙÃæc÷Åž5²ŸL£ºÉlbŒËI ú¸6Åiü­çæù敵¶ûÙk‘îy6ÁõåùÁd@0ÑN’‰®MpËÒaœ²ÌW «~¯ìOy”íÇ‘vWVgÚ׃I¹¼I“Œ@ê Š­ÄŽã›Ö†ÈÙÝ+ûé'xS GóUÌUÐlû(ÄžåuE…5³ÅU‘YéÜ$µkËn—Ñ|ðð}ðgï45}€Åæ þ`¸ì·/Ew”ãÓíiGŸ¼Õ|&,¦Ç³¯¼6ë‡iôð‚, ó=‰âéÃ%¨ Pzyº]×Î2Ñê•åõçÿàÌÔ€íZ³ì×E'„±EªÅ&?øÁ;1Úc´]u´k»M ¾{Ó¾õÁA÷§gà‘ ð—~¦=·Á§°Ý~)3 ”ñ÷Wö›˜øƒ=U«e²®/ö¦YSî>ñ’à6É 'ÙùåÓ_ýbz}}²V/-vïÍü¥Û¯–íâ³B¥ ×e²wÿ^¼ ½R‰½$¼|V|èC‡‹«UÅÛ2ììMßeÃáÔX±ó¾q”÷¢±ÍØõ¦õ'¸, /•u³ê8¦a¾,êk [Q,{³¦1Vr±Àš=[šïžîfù½•650y&B\¿8‡³q¹»à±Éaȇ¯ÎñáþÿóV}±ôï4·~ÿîCèîÚ€$:YÝ,dd5âñ>ìÚƒ‹ÊJ8йoªæä\£pØT×.šnW›òÃ<‘n·=FÉj·QÆ{Þ‘zУuc'ÑÝqôBXœÕyQò÷ü“ÿÞ=Õµu·«™9’'HÚÐ À»í©€ÇÝ퇠'Àµ‡]·ý±OÄŲ¾w;Œ{õ\P!”Oêa0”MjÓÝžEo×5•žX'ÜhüÝšìöòcm/Ö;6 ŒO×ï Æ·¤«ó<*úµA2Äüáóëi¾çiûñYU›XßÚ0u½Œr-µë¤gØzb{:¡²VÈ0y±Sß²Òu¶3?]ÒŶ¬®ÕþGòƒeµBa|ÕèÝÛn&ß{Z¸˜yrG¶½›ÔOyM2\éI COýÓ…õ9¬]w¦²IŒûRöRû8L°ÀÊóm‰ÐT«ÑÖl˜šCj^áU}§ðs.­cQ…¹ś{³ô¿øºÞêElÔ{ Q“EùNõÐù›F½4€œD0—ÞJ»kkjÂ@ôR¸úFº¨ŽZ¨ǃåzD4‚Á™T8-ÄUisfø PµÓ;цº­xípûô§h'wÒ'ÔÖ„žz'ÄÁÉv)HI®»àùI…ÒúÍ® ÿå/ò7'þŸ?”œYH‡Ü«$°—²ÍjJÑ®(¿óhò‡‹pnÐÂØ€Æ“à?ú‰_ýêÑ¢\ qòÈ]ï{øâñÞµÚÜŒêÅU2 iM_kít2ÛÿäusÉ0sÎ I¤u-i`=t×›“€Q¨]¼ÝU,zÙ†aF´@ïQ†77[ÄQJÍnË.à CŸC;JõfšÒºjÅka#Ê”·Äˆ7Ð:gu (³¶ET3?¹iv”„J¶ÎºŒe÷Öo÷vf Â9«‘JPF["FFéMÕÐpX”å © ¼s…ßzØì0ó4 X R»Áhôììá?ùµÃ¿úZuQßy,\Þìó'{ÓlðÝï»·¶úïÿªùÚaùo¯$èŽÙÞèbGæ ¯­dÖf$ß]<ƒ>Mì{ç«ßùCŒoh”c]ë”ÑQÄ!ŒÁF¸ùdŸc]›ÆŠêþÝQgKïl­h¥TÛ¶7Åù¶í  Pxë)å‘Ô-„Zj+ ¢Ô8-Üõâx?o´âH{Ê«b!J7á0À[ó¡xûæƒð¤—Kµ%Q@·âW¾‚~r”ü«¹iÈA¢oŠfWuÓ|°ëvÆå„ÑžaÔ*`|ŸÆÁf¥ vÞ¢Ñ0ÀbÜØvÊj€!vÅv3 "íêÝUq ][vZ´ JRHØÅÍ $X E»ºÞiÜÞºCA°¼ÒÓovq£5]/4~ývüþeûýwÕEC½;uóã}²ÜÎ÷o/tçõíFãÏOÒ¶Ô »&£`g¾»|ÿǧÃ÷6+ÐñÛ‡c±±Òb@!þð×qlUzeC€-\[‡Ý œGñBPÙAšxÃ!®¶õ|x(z`ÐL²(6qiÛv‘dú@\ 9ÉHkMFúZÙA”B ¶‘Òl³|(¤0¨ÉâðäaéѤS›˜‘‰1ü¿·¼öàAž÷Éns|ëÖâjk öºùÐ ×j k›vgªh³œHÝX 5ŸŸµš‹£lRWÛ8 ëJWªÆd §ÁDvS~½¾ôHO#Bú®ét—¥C J OA Éz PÜ™†lmyoïö7?Na=`»7b?xxöK%yª—>!î[¬5zëQ÷‰#ñvÅWÚæ¾uV÷{óî2¬ÖÏ;3v¢ IDATïL«Ð¿0|µh·‹×ñ)†NŒqâpCP`½uPx4ßíŠÎ¸Nª$qWž¦Vk×ûaHI%vuß6=¥½y4²Ds7M…½Þ°Ãcüî{+ÑúÖ«$Å] ‡ÑPT\hÕÒâŸdØÈKL[]™ 5iêîÏÂÓàêf ªK.¯–Šñù()6Ö±B•a ¬íƺ’j:o²lâv d&“®uˆ1Öi€|Ew-¡¬”ŽÆÐôÃ$h›*!”/V£A<ÎÇÔ‰˜MkùiqöšZaŠƒTRš¼zþðI=œîsö͵KæDvbé,5|4)v›O¿þá«õÇ«½oü>ºŠèóåO~h9ЗŽêÛÃ~Uþ°Â®êȘ<˜ß+ESþÞÕ­IüØYüÉŸ”ec5ˆ@¦©Ót½Ã8m[©ŒµÀYç9¥]«ó¯Veßµ“ñ~[»ÑxðÁÓì _®jãT³m÷&) àʹ‘t¹’ÐNIXÙÂŒ&-Âtw’ãFt½‡«R§ç€¥ËZÑAÆ~p&iVn¹ÅR]ݨQ ¬K §ç½ú@(#”ûÄ‹Ÿ¸¸^[â›b¡Ô 2nœÁUSvL†{Ú) ÀÅóv2<|rÊÃ@ö ùÂ2MÒwß{¦œŽâQ×Tº÷yœB‡æ³iµYXòˆ­ÇöèÒ\‹U ,·?ñ‚ž»õû%ÎA_ÒŠþç¾|oýxO<8ú³wú·W·«?¼ö 0ŒÒÐ>ºº ’aW[‰6”)Ý$)Ã÷?—Ö²ñ)¼óÖ(zk-‰ƒ`UTˆ0pÌckÅ$Ÿ>¹¹šåS€ ðDö é{ÎÆ mLk«ŸåsŽÉòª™Œ)%ƒËË~³pƒ$e}áq …j»kËòN~¸‘µ0öúJÆI< "yE]¹íA6 óVÁ”‘•Y¥Õ’Äa„øƒ‡Ë|˜ 0F=º¸hÃ(kuk?=[^ßl÷æOž\¦lCK ¦LÎ!²Øçu†)ˆóiÓUÀ"ÝÙ|˜–;‰è0 Cd0z:žu1Ù·“)Ù‰êXLö¯ÿÆ=ûò}à0ð*â ÈÀ/¿,€‚ß[Aç]SÈádôÎÃgnE3þò½â ¯e?ø@ØltVi±±Zµ¶^O D¨»“X«^á—>5i½Ž-=[l•rÀ;±w.fP¾¬:éf]ާl„N (Žé®¨µde_±¨º•ßaÔ ˆa+ •´5>Ü‹C>Þõe€iðÁh`aµ¬[£ ÷X’઩¢äfÌQí¶”Õ&É\„Wµ˜é«Ë>ËöÕÚ$zpvQ(£9J4¨*m#~PÝì$ƣܭI44Ø»º‡ÛÚLrµ«u£í¦ƒj¹QÎÐÝ£»F—½‘½éØEf4Ì™´0æˆÓL»¶i‚–‘uÑ>]LÿಈQ€)Yo­ã?úaûÛß^¼÷a+»Þ˜lƒöí¼²7†<ÙÜrÜ^_¬»`³ª¢±s-v½¹sp°Ý\}ôþ8¼ yƒ’ i®mƒM-$ôØ#}£!ì,áFå~TÃvŽÅKY‘~a>ZmTmíø Ž‚l<,ÉxÜ‚Ðc§Ÿ\_]µ'¶QcѪâƹÞÒ+ëudr¹ñ½ ód Ãg$‰ÏnçC¡M+lÀ‚ljuéÑ8u>ŠÅ=:˜“”x¦Vk°%ù0ôÀ´½¤úHpùÞzŸæèõÖÐFrMDïÃ~Lt_¶h”5V î¾l{==Š÷ÒpQhbÅèm püzwZªK,êÚër}²'?úóE2¶BÁ¾ï­CjÞýá6¤¤ë»ffû°Ü*ÃÖ, œ×žá4ŸíšÅhß)ãnV»·Nßg³õvD”¨$$$¤Üë1½m¶òþäàs~òáÓ'Ñ ÄËrUÜ•EÛ?z²<µÞôrñê ÓÄ,’R—BCÂí¦o;Çz¹©{ ¶msÕ•÷†yHàóg;[+­6Ãy ¼DÚú$ÎN¦gIHœmábƲ ”ëÖTf4¶ Œ»|¾“ :ã­°ÀÒaïÊöv>‚d:…£}ÆŠ×ò×ÍâÍÏß C†fƒ1mêžsŒ¯koApë Ï©lJ½2Ï(ü~6Ò"Éï>y~e‚ýÍÁK³“ÉAü/žûÿú¿¿ß¾3ÜïU$ §±œì£½;sk{°>…æ AƳ8’lv…ÐÚÀˆájÕœžQDÙ¶UŸ>\ƒÐã0N8‡l±ÛEå\|âµãwð¯‘ÙŽöÆÛMmLWw ØõçOOI ‡VnkÎH€'Ûí–1Je$ÜuF«Ⱦnm­"p>$1ey¸›p?ZÃM\®Z¡¼ÁHw€ÞÜöv4²øQžÆ!œÍâͶ$·}ßy\jŒ¡1‰bÎö//W:ùˆfÞãåYRWv2S²YlqQª|4{rú,ÆI½áÎkCBë ¨0±| 0€ëÍšc0ËÓÿåðçGî`ZìÚ”…À@S7—IFèAxóóoåâêwþ¨Úí7—•ëŸúKÃ͓ͮõµôÄa}öóG¢!qªÖׂÕÖn4ØÛ®ûnã¼ÃŒ«î=@W—80JòåYý í{ []cS£0”á4²ïæ7͉0Í|r((Öþ'^}íOÞk»†UÕÜ®ªËÚúW_…„x°YUƒÜÝ;×Ö?ÎRS®Ç^ž]ÍÇc+˽1Ù–+Ë­d¾‘%þðSŸ_‰éÚüüÝUÂ'(N%ž1Ûu4£ÑÑ‹x¥€¹ÁÎâƒAÔ,át‡|¿4u#ˆ åüüüæÇ>ñúõy¹Ý6+Ìp’D d»ë|ÔM Ú?‰F^.N9`$è²~Œn×"âÐj¯EðO/ƒ›~? Û[£cÈáwE»ò¨iþ;ùpáƒÑ½1±8åêÃûŦíÃ=‘ìÃZ4ÒVÖ£[¤Þd{éz½ñHÅœ0Ì»NCÓííSʲ§Ï»Y6?Èï¢l6²ƒPLÃ]Ù²KÃÀꮨV”ÛÁ`PkÁü?ÿHÿöû¯¿scðþkàÞá=©ð½„Ëí V9LZhçúˆN«¦O˜íµÛY~{¹='4Ò¼o>H²ãw¾·zé#I·K…X¢›ÎÍ÷cet]•„³Mi™¯cÖ4aq Û–ÏFm ¯Ï%¦ílê£q~µjµ”–YÚ!È5 ëEÐ(õ]O8mÚvÑj: ËÚ¦#».$ AHab2ž]înÝŽ"ÎHcÙÞ>SÒ nÝÞOÒr&»Âß,u–zÛíïá$’Þ¹Ãý[»v;H]šgHº0Ë­+B^l—ŽŽ Ê„—,™ ]ñŒØ¥,ûú—&ï§ÖÏOªa’{y¶7Ú“ÕÐù ´–SêY†à $,Ѧ©¥D€ÄœÄ£Ë¦Ê`ê}Òáû²})×A¸Fp³+ÕtäÎ^~E/o4 0$ŸS)í /°€Á®µ³½}ˆõÕõ)f³doõ埼ûäûðæR"’°3 …„P H’ó0”JIëÖÚ8ˆºŠ›¶¸}z Ö;€:)µÎÓ æa7f!˜”UyrQîäô«Rð|ä­ bÆ­­Õvv4"Œøé€S$öögå–Ž'¬m»[G{µ|öàÞ”‘ÀZ­´__´ã²Äd“.É5!€ÐaÝ\²„A)4ÁÔ)ˆeó\v[i‹éô8£ììjk€¬ª¶Ì÷¿ÿüÿãð­ñù­lzvu…Èã]c\!e´³-¥Êx¿Zw4¢ŠÐ»‡ûÚYЛÖÍ’i7ª¢|ˆ|e9¢ÀÑL{„’ÌÆÈVÂH ö#ر땫ühj×…:Þ#Ÿ+KX_¢~:ÞžøñL'4Úå|šðD¶Ø#mµ6IìËJçƒøÁñ@u8ˆ'È–óÛ *)î¶ŠLsÈ\°—ç ÂÖ[¿Ëó0ô­@Ó7(ä -·ëfv ½…¬#ƒ~„r›a„x!D``Ýö„¥ÁÁpÜCZÒ4m4ÛÔJù¨Î®Ý§>59yj&3ÇÎûŒ†°o{šæóë¶OrÃQ(@Ü50›Þz®˜Æùý¿)º í• .áx@V:%Ä!•Nöw¦ei³’(¤½]U†rá¼C UÍ:‹ç“sÜœ­àŠZg!Dyîky•ŒË(EQgqÌB\%, S’ }ÓÉ8&ØMÊ®?¼Cؘ?úQ#íÎÂe<í’!¤§tZ2††³Q2 ü`À¤¬_¨Ò¤ŽãðέÙáˆI¤| .‹NÅUY6= –ÎtÈÒ„yÏ •몽uï¸D4$Oà <^.ë”yO­–c‹-É0@“aZVMcê 1˜áÛwu»Aó8VÝ#«mf]Ý+‡ÝÉÍÓFôRM×ôFò€õ¢3Ì"¨&µëjÛ_ko¶ua é­’Ò&á8ôim;îÕ-0Ø)[K{a€JvRwq Ç¡<ÍF„±(™xÐI”q$°ËU,"ÖÓ SÄ"ÐÉ&KS§P¾lZ«EÑfãkYlƒÈ¦‘BÔ ]dChŒˆs¤˜1”Y”ƒÁm¶—ÓñÔcaFÈ—U9¦„¸¦+)CÚ(MÆQî\—ÅÍr„!zUZ×í@ pD+ v@߬×Ûz% r I¸©n„@QÛ½;½÷š Q°“ÚýÅpj rŠL¨YÐw­¬û•GŽã¤ë æ0 ûrI’„x°-D:HšÎhÕ •’ƒl¬©ª8dŒä9(I‘·Ì8¢ñ@NçX²øñ^¶ÙVƒlOk0J)%ʦðÛµ5ªï”vu§L#”Gâp~!:µÈ*…1Ž…eƒÚ1–! 9¶#zÌž1Soõ ÷T'šW?¶ŽÒiÑj0Žè=ÒNwÕîÚ¾Nèî, ÂNË]/0]VŠ3ûÆ(²qPI_iŠ- ÖKböú˜ ŒDR1†÷'c€LÑØE³ª{e€ ¢@P/û¬*û˜+ëCÈ7Àf£)âi©l‹¼Éj¬1š«ÒÁÈaÛÖ”€„Ǫ퇹]\¬‡C¢%&vèB´[Îén-,êz+[9ÈÈ0‰âˆØÀ¨=ß (vêJ#¡âApòì ÊY€î…Š¢to<†V5»õ(M=è"ÆÕ}¹XÄÖU‹jC ÝÄaj9PŽºŽ{xݱ°Vv†e#ä°ÁHH½…çÂ:%&t)OÛ ”ª>;žRž”kro<­ú³}‚À0—f Áí(‰*ekáòîÆ°ß|"«¦»ÞÞU suZ¢Ã“ˆ3Õ®€¿ P{ P?žÈE¢è­òu ½J*\² :Ê¢N©´5³déM€{ÁºF—R倣û *¹ì['Ùîúáx~]¶=èU3âÄX¥)ï(ÏÛ%å!O2ûáº0Q!Â¥2ØÆ„qeáz+ê ¦¤#Ê£@ËÞŒŒ‡Ê)kòÞ„„ŸPYêó4M•¥‰Þ›N“Ì6»Æå=Î4Â!%„aÚí–>Š )B \cs$êŒØ*‡!ú Œ`žÇùòm·v ÿÇ'×mqq°?êµ×€ ƒxNi ›ÖTJ# èc uX,ѶéÍíý§ÅóÖ¤…ܲGÏ®ë%"'×P:æ, Öe“ÄqUw½tƒY¬¼ïT9œ¤»ò†Ød»î€Ï¶kÁy¢œ? h[Bè%±ŠP.…ö í0Þù$¥cåI€ë¼Î&C2ˆˆ‡žR¯,Üé†8©ÚqL©p^qÆ«ºÊã™”*„ Zž%$4Jj8—‹ ô!׋¾nDÕÖ1£Âåv§¨£ÞD!KcNœÁ®÷ÎöRM‹ßüŬ­ 7턞ŠxWo<¢XArì#£tÎÃFƒm!÷Òae¤&ÑЃâ GZÐBj›VG8j Ai„1ܵ öX{h° i¸Ø4£,NöZÍ“¼èµ·8¦µn Œ–½Ò!‚ú.B„ÇBu]c9‡”ú¶í;iÓ)`’tX7½µª•…{Ømp7e/¬ ‚9 <Ú”E…ªà  €C=ÀFµÎú(„Þ3ekxÕ7aÀx4æ!‘%Â8¡Ih9T‹G à™ç!Œ['ã0èŒO” a$¤Ê‰Ó¦¬:%8r‚üåVÌØkDÐ,B½.;¶Fzßxä1RKmjŠ0 ’ 땬 ÝÔ*à±Fn[÷½ÖøìøPֽŹX×[i\×ü8Œ¦ä»Žg|¨ÚŽ’°í\Ñ:&r ¬J |Õ·Ëöð@é3$‰ º­^,ÔÙ5æ™èzŒÉf×@'Ù!õÐvJJX"MÏ€uÒ§´qih]ߺjÝhëÂ8©«f4wÒñ‡‰ŸLã¶[…q´)«²®¨ 5JƒÞ¥ ½TVXš§j:§)¥|WJI¡$B(ðFB9¤­õ˜VRÔS Ç)â/v¥ÈZ#€‚; Œêáe/[e8×ÍŽð€èt‹˜Î!Ø´e¹êmѶÆÉho0®ªC«¦…(lº*¢<dÙF{é !@DfœDQQ˜ I¬uPÑ^Д"À{_µìÓG»Ó@f±Ñ]%š]Q™Ó¨¹)UÉ¥¼h­FEC|}B,o)ÅbÈãš– rÕáýx°¾–½ê„Ž·Â°,×ý²„ÈkŽX÷H“îFÕ¸Ó‡¹G@ÝÆ”¦}²¾.E¥,D& =¨e"šÖCva]ÂLHzÞ£V8rXrë²»´­jZÂ=ðP»Úh°ÇPÅØ)×ÐdÇ>|jÎE»‰ƒTkå¡Q²ZäiÆÒŠÀôš“¸n: '­T|?+ÛG¡®+lGqˆêÖ¶-€kåÂp`<(j³Ø4µ•NDºº•· zÌ/ÎNn–MÕšF”ÉÐWMD ¸šFr<÷B:\aªµÆu»&q×iÄ讪8‹ЫÉ^Ä)]¯uSÚˆÆÄÛŒ³ép¾Ý*ÇûÝaBz¹3Í`­ëa'ñʶ/îÍ×—ýÍué åÞö,hš áF¶ƒ$¡Ô‘)£÷waMs`Q6@ª7¦Ug–H¥”ï2ÀÁ,pƒ¼ë·_Œÿêë·¤mwMã PFSJ…j”Òñ€GÛfÓ+­¤‡’‘`úÖËùæñê…©¤Ê8RÑ:»«M%u-q§âZºª¡çç•Ô}Õö”¢%ΠMÕR¢”æ1 Æ0ê„Fò ˆ)Auá¬QÞZÊÝÖkyø÷5âQ€) qi'1 ®oº¦³¦ï‹ªöÈõÊ"ÚŒ¦û·«Å¸sZ6ªï Vyµ±q>¢BY0î[ƒ ß.´³NIÒõr»†aVW­Q[ )Üvë6ú&z€¹¸´6°’&0-kÆ8fV‰ŽúX7ðs_Ž»)¢«EPÍ0\_­­Ò(L½“3÷ÙÉòÓô‹_ ?¼8ªqÑ ¨éÖØZÄXdcV½‚˜W;i$Êÿw^}ú|F|å%ûëŸi?>;Ï)l*ÐËZôT7šÖ¶ï]%cƒîîEi¤mDß“<Î*mˆîz‰Œs¢ë8 ×›Õ]Á¶Ø꺉ÊX ƒTí’¾d7Kp˜†Õ¦qÆA ¼'m§ÛÞKša -–ÂTï( b¿Û"øVŠ(ÅÃ$­vD„0è-Ò,%X«>Èh$[µÞöëRÕeÀb§¥kKi¹•Ð0Œ±ngwƨtS†A|þäñËGô;—_Û#_ùf"‘¨œ°£fYAÝ8â¾´ç,NŸ¼·ùóÅC q±íÊy¨½ÕŒ`ÎcÑC0ëóÚc÷#ðÚMªË’ÅW?~,„ŠRÀŽZ »Æb µÝuŠ´Ì²qþñ™øèg‚oÿÉñwOÒßüÝñÓj\tÔ–=™àö0z;è¾ß͆LI$•2iiîxžr E)´ô]‹P·E·)Ð*è•QŽíj„@:Ï€Ò»E%RD{»Àq¹º„ûvÈR‰[µc³p«8Î)ÑXè­wÔ(×õxgìd$¬u»n¿m¶Qêk+³Uv¾ÛæA %`4QÈÇ>pƒõÙTƒVx£8äƒÀì¯WW¢ë2ÀÓßøYq+F_¸CÿÖ J+40œG0fz · ?Ì»ÆöWçøö-üäm³·¯fI<Ìi¦$öP–û6P…awï¶ùŸ>¿:¤Ë’Jí‰MmÚN#Db\wrw½“ üŸþéðw—ý¿z÷èI]«;ÅUÌRÖå¥[ïøŸž50Fă<Èk½¬k… R¶2mßÈ9·×Ef/Âh'[ä‡4\Z› W#†œ ò«J1”hÙÒ *+wp0Ÿ÷õOƒ¹b‡'<gÃÝÎ45ü@ ˜#ádž«Þ¬¶=Å×JãEÕÐ]È¢”<â=‹O϶¶×ÉV=µž çÁüvp¹A¯Í/Ë‹ÙÝ{{sÙ/'—ÀÐñ,v'«Iž‘8¯ËÕø£æoþwñÛ‹Ñ7~`>¨“ü`>dstòµO‘7Æâ7ÿcûÑcL˜iµ¾uŠNmo Ç#iº[[qÔm>>ö?÷¹ãÛw·5ñè¿ýß®Ÿ¯îÿÁw’ðÛ˜5ûë.BÙ,Ciú^©Üâh¼kÌþèU2`Øäð µýɺÈ_>¼zVʾ“jí%è!у1=º?äP‚ì¥1 9ÀØÈŒ@a.$\¨]Σñpry³Œ³yç0F}:'Q„‚À„$PÆ­êÅg_Y} å_܇?~,~ã†jÙ÷QŸx¥ŽF½Yƒ¨ïËšA”PfäDþÂüäüÙà—‹Õ†ÆYI iL7á#‰j'e0m"å8Înäõ®ïëÍŧï¿ô¹›/ÜE·ÓY]í`Üw5Ý,›(?ôR¾~„+¥›~ãýxÓ²íŸÿÈÿêϦ VAœÿ_ÿZ7Ë]·;º=m›ÝnÓM#Ñóé,„ôp¾÷þÃËë­øp÷×mK2Ÿþß¾ónãî¸Ûû…WꟺW¼zÐu–$œ€š¯Na¾ûðüÎýCçèÕÅ"r°\ÔóѼªªñ0Áˆdñðú¢ÐžRè­Œ…aD• 9Ƈói–ÄÏ AŽùèÖa×vBë‘è;|÷ ÎC[ŸGûwô¢C!C‹ÓàðÅ+ÓŸ-WŸ»ë׿¶¸.)Ž›Ë%¸y´†qm6»[ãa#°ïÜxm›6ã˜0ªL;¢£¿ùÓ]ÊÝlˆh¿™ §ßZ÷ÐDŒÛåÚà 6Ø Ÿzx5N†©<ȇÏ.á ÿèïÌ¿pxþ¡”|í Úxô­§p±½ä7§R¶lïÃüû¿{ó³¿øæßd×6èöÞ¼i«o=îÊeòöóÍo}#ž¼ö¶‹@TJÿú+ãÞm^ýtP-Z?Ñ·ºËá®çÏŽlb¾ùv°7ÞýàDñUâRüù—Ú/}|ûëŸù<H²Ã?züáAî+/ž_· ð²uóáPà²6ýh<¢œÉÝIŽŸ_•Тڨª01 ¡ÀNôÎ0rÚìÊJC&ƒ¨i· x¬êÞ³„./ûIã½W‡·˜Óç¾»¹êyJMo˜@Èlž'åVÜ?œÿ³·Ve7/½ÿÑÛ¹™l¹è&‚åYƒffÀùZWiõE›°é$“ö}{¾Èþ&ÐùE IDATá?Pß1ÑÛ×D5Þ#J1$›€­o)™&iQu¾ChÐ>z\òå×#röÿGŒ‚ò,ާâ½ó1f4'“óÓõì~8Žõè|ë›7£½Xº˜¸ñÝî>Ìi˸ن“[ï=,>õUY/‡Â—ŒcÜEç×âþ‡T¥U …îîÇù¿½(ÒÉè\èdye&³¼nÜÛ¦õÓwŠÍ{лUúöÉõ`.~øì,Ìy†Ýã§êè–Ò(¨âp žee[D½U@[?ˆ©ŒX;›îE œ_˜%›^¤A½.³¢¯Æ#˜!ÚûDÁ¦&Ö˜ ,<çY?õÅæm½c{G¼ˆ†ûðêZîÏó'Oûè˜<¾ÐÁxðÖû•&ô{ííƒÉ'×ÕN&¦€1z4J(öpœÇ½»VÄ“éeÓ‡ÇþZ€ ¥áºÖ:Û€÷ïM×c°ä=|éºÚaX¢½ä·~¯ûðo‹§2þÓ‡ Ãáå‰fÒÎ]éaâeXþø%*ØlÈ?þ øÚ¬üÄ­ò«?6òhõÎÒߎo.Û H’˜_\÷¯½©»Y© b柗嗞Û|n¶îªÇüh„’l/I”¿×ð _È«®IæS¿.Ê‹ó>ùP€`€) Ä8͵WPñvS.ûZKÌ#®Œæ$tʶ,ðMç îâˆY¨rJ¶JÆ£ ;ì¡Ö„¥Œlõ®­ó$BÐ 8æðôy¡½ Bâ&Ñp·¾0¶M-ouÛ aê©§¦êŠ%ÊG±ÜÁ©Fp£†¬.WmÓUƒAº.äa€>}¸øÏ~ÊþÚËÉóõ"clÍ3ä½·LC&¦y'`˜te‰`_Pv%´ã®]Üß;:/«÷®P8fmoiXei˜Ue¹«+=ÛOÞŽkXþ³ þþ7î~ëÑÝ?y»™Ì“ù +JŒ) ¢„ÜÝ|ëÏ”€„äùõ €°°®Í²Á⿬Œ´«—ïâÓ‹‹½ø¨í±ñ~[¬—•V—‡4¥¸ÃãÈjñ\hW— l¡q:¸³7YµUçJ9–pÌâeyé –¾ÛíúÙ|> ª5v}×G“å²è: ¼ ·5Àžq>Ȇp9j ¨’0ªGYwbÝ©džêq'úÅ€Æ>†aæÆSz¹¤®Ðû—õÿúËúÿ­þþO‡LŠ:Z[B“€xú ÒÅ<~íŸÿ“·¯BÂe‡ ´õ}Ç*éËf{ÿø(…#ŸÿÿÁyŒmçAðo;ûv÷{gî¼™y›ŸŸ÷؉8vp!$u){A-*¢*- µ´jQ)Tý¯B•Š*@]TÑ"T© ’hXb›8‰—çí-ófŸ¹Û¹÷ìßw¾µ¿ße8ö|ℲÜ$q_„~t÷aE°Ý'cÓPÐ¥Ã`Ð P²emVÖj¦X 9SK>Y|·ñž’×Oôÿ~´é£¤k /«Æñ€¬à ꔺ˜Á(R'Ù9s€‚Ëë,îu%7¯w>˜§np9z怞k…(¬áJðV1„þpÜH)\;ؾB|ß”C5\¯E‘ŠP@ÂÖÅ좨8qÔj“!"agiѶ-•ŒkM¼^ÒýÛX ò¬$ÚÊ??Ë\ßFboÛn¸ä\ÙžôlÝ4$Úª—G*p5q"ËÜ&B»GGlgOø&Ž:l¿ø£é’YåY»š±‹U„\Û¼åmŸß»y”ÓÙ©¿0ìèÜhÇABÒJ؉ç!írR*ÐVke©[·’²$ËUzëæ Sæyº.ç8©‹Õ²Öã³Mì°Z-Ù•]ïý×€1V”t,Lµ‰Î[Ø4Á¥˜÷F¤ë¢­è¥¾¾µmLãvÐüÅØŠˆG],ràc´Ü°ܾ¡¯öv†'›óUÆV1pãyÍd2¦iµ¨d๜¨®3ÒµqýÎöØ*–ÖÆTìPË>6í¼3ߘš¬RalËÖrÀ¶ã©Yeìi![¬8w"Ò;<" ¯· wV¨´Ö ÀPó€tðö³Á`Ë‹Èípg•rwSà±59:8|ùÅëÌ[éiŽã~¥€Í…\íŒÃ,³þç[ð£ãøÞôGÀÂnH£2²ÂÚëYáG¾raº-£ã­@èÊÓ½Ëe†bcÚ¤0Uy¡ 7f«LFÌB—õ&\¬tu€Ÿ9¶ñ|l!ײˆ„骼vË)òðàþI’8a ¯iˆ×T›Ñžc–Äý>ÎÆ;Îáñ&L|.dC[;ð,Ø$A‡3Yó0=cX! AME.‰E0t£x´ÎJ×µi[ÄK,R¾ëQ×íTõ¦bÀuþÈNøñá¶íVXZ+°’åùhjÊ9Ö°l•ëy¢n¤òÖ›ìV¸ûqÞ¢·›ÌÌd+B€U+‰$Û{úƒo€Ÿùû¿ú/¿û¿(‰2¿ô…ò—ìáþVpk¤(“³yuyÒåCGkA–Eçw?Lã ùaáüé{HPUâ@9B‚ÑôƒÃÏM(ÀÁ/Vm¶–ƒÛõ{ô÷®oM, 딢¬œ0QŠé(ùúæhõîjΉÛFºì\¥ŽE ‚€8.®Kyty†ñÀOd°u’ôý—^y@vq€²IaÙRsŠÂ­îÝ×£ý.•r¹Ô­]m%k¤’Íp8šZ¾ö‰ÛÈÚ ¡-l"ÂÅe¾u ŒB/ÍR­Íjq¬‘ƒ‘#TÝNúÑż˜G•õv8XÜýX65„ 2Žu¹¾„'ŽqÀhê­Ó}¡F¤ìЧ°ò,ϲ ·‘5‚YBQËsfKì]‡¨mŒ<à ¯-Š\:¡»”­=ñvÓßâó2§i¿ÛlÿÛïû·Ÿzìäà ñ Æ&Ž1@„,»á§$bSeŒ+.QCÑÕëÄ ŠXVòÒ¿p-Mg¦‹L¡?üèýÍBü»ß>ý‘Ÿ'¿öÛáÈ7öŸ¿Fÿɲõ+¿5ŸñŠQmQ?Ïøpo6)§ütva4†Š “àüˆÊ;ØëtM'†ÈjÔIÏóºÞf#¶x 5@–ã#h¥ó‚8¦œ—ÆŽ ÑZë r'¶ËiM[*Yc~äAdÆ[糄2_2Y¢¦Öã¾O+3t<'!@­aüäÛ;W’›7†ž€ÖŸŸ™$쳺¼ºÓ¿EãóuùÎj½ÊxY*©—ÂõÞ›ø”rÊ)BÊC>Ú‚Já²M°›Ó•ëBÇC^àxئÀÓÓ±œÍŽ~ïkðÚ—¿çsýƒQZX ÖT`)AÒíC ´ë•…½6¯ukPgK5Þ} @ËJׂñ¥‹„EuG»D˜¤­Y~:wÞ¯íØæ‰bÿú7ãûú©o—[¿?÷gMw-­åÚªù%à0ieÛn•ƒºÒŠÕ2»q5yø1s}ДžRÔuŒëN?ºs$ÖÅŲ*ãZ P—À04íªvà+ZQuºAöšRƒ-)¡¤‚2¸\Ò–ëÎ$È+i¨*2=;³‹2Ý,GÛã¦Öó‡õ¯ÎÏÁÃ{i¾*•Q¨(á¿<9Ä,'9¶f˜…£8nd €½^ªaOF6AŽ[5‚ƃšÛ )žœ«ÃdLU×v}é`Ï,_ýøÍ{oX˜Z]\TÕªº…. #ßK~y¢œ^«éY8p¶•¢ 6´3XGpàÞåûÑ#Ï\Ûyõ±ýµ]}ÛšµÖu-y‹‡®ÿúå7Û1D[ä?>jŽsøÞÍž'eòô§½ù%»`Ñâè4 EÝ¿ûYø Ï^üå¯{?ýRþâu6и)k6sqZÙ0^mŠ­žÉVÈróþ$¨¸fV3§eëâ€j®.. d¼â VqfÇM·«¨y1j+°*So™Wöm!-ìë{»Å¹H´Zq ½jÑ*ÙÚ¾SgØêj4·Î/ íëùŒ;^½¬Û’Z¾k²º¶(]£kÔ2c»Me#ˆ¬Á Ä@ÓF6 w=Ðïõm§l—›6vûËÕÌqlV…çÇCœÓ–Ñ"UÑØllëpDØÜqši$JÁ„aäL.. O>ŸᎷü›ß{ñ¯~òø~Éÿç_0Ÿyút¯oMwƒ$Bï¿».ÛŸâG›šdYeÛžUs¹¬8ôPK™’ÎÕ)^§¢ŸôÍþGýxÞOhhäí>ýág³ÏÝ–Uî=4s&=‹´T›¬7f8Lægðâa©ûè'öt“e |‚#'É×M·sÍH,…i4õ]»,·æ'%­y•Õ;ã‰iKY“­Áj]>,Nî•Gl®Ëš×yíÅš3 5‰—èàþªX7éö¸>¼˜îö %h)ämJ]‚%°%0ðPÝbdPt´‘ØYVjé(”À £QS7“í€Ò&poܘÞXmŠeÑØ–Û*<¿,WçCÇ©+-»¬LƒÀr×sæFâì8ôº¶~å€çD­jLgØë/¾°úùŸp|O"¨Âø~‡"²ßÅAÔpÜ}ëž!±Ýe^ÚU¸ñ%ùøiM/²¯n·EË ÓJVÔª*ùÊs# íÁ$2¼UZ7¹j+é8¶›àñ”i£z!äŸyþ»~èÑ-ÞAU)Û‚øZžÎŒÄˆàtµØÝêJÆxË{üZUo£T÷«¥Ö(J©ûîà×VÓîT4› ë)eêBN†£ª–ÄÅ^`ŠŒCbߟ‘·qº.ìf^<÷r/ÏSš»pÝJÿìpÓ¶Žëõúá¦(²Ün¥’AàBD‹ 泺X ¨ápgëMQk£Iw37í|UæÍz‘9ýáâ<+sQ7uÜqéªÈøØK&¾IUÀ²@E^"—Ø›š-×dÒq•£Yú'®ƒûb™ê&W¬A=jÙn÷ð€n Éëo_†ÝXÑøÚµ.òÁQåAÄZ+î*UÆM½¤Â‚ŽÎ. ¨ÅþnˆtzkpßÈ/}›‰,˜—’SJRàø<×WÆ´®Þ ®t¶±mx zÖfß^€åö~KQèj àTE)OV&°œ")¾sÄ^; ~ç¿¿ñW;ñ^ñÖæµ9ùÚpÀï噆ŽÙÝŠ³9iÞ¨†›qo7Óñ`罓ƒ¿vfX Þè ³Ü¢nÑžG Ó›ZiZ ",ËÙ\4Êiu™‚AŸyB…“Ô\ØvÔ4ÇŠ„²jÅ‹?p•«·”wd#*ÎB]"éÚ‰o?qm;²|L!sŠxLÚìË:Uñ-´>ÝÀ â+Ÿ €fSä!G©í©¾¨€‹ò3Õëºãi‡«º¥$Ïë"Ç^`±Ì쇧T¬({úfwSr ÙþöÎWþtvå&¡T îN 0£]9ðC®×6Và¼þ~¾HºÀn…öjðæ¹fg*Ú²¯§f®Ý}ý«ég¾;޼$3…ƒ;?¦Ž9¡ö3×íõÑÑâê^o‘—±Ó=|°AÀ¹ù­×ÌuÊÄf%m„4ndåMnà<%7žÍç' ƒxýP)Ú1zò©q³,3¿€¬î½0îí&a× ªœ.Ï\…«¦‚ã'ðú˜yApqE«8–½IDzF?óùx}þå¿\˜‘0LJ’òü}G`zó&Lk‰+t‹-Û`¶cæ›o¦ýQ’ÖM` h:×ÓÄÓ†5„*×ADB[Ój:Œƒ–]樭Ô^)ª›ãnèûQ*·wû[[n) {ž]¾ûtý“ñ[ï½ß4Y*Á(Œ×-ÝÌøvo\òìÑgôÇ%Ü ¹˜/T‰Æ»ázVx],J4½åæ…÷ç§ÕöUòÙOMdÜt·¡±­ƒyäyÕ¬Ù½Õ'ã–.Û(Šë’ÕYKÚ‚Z3G &4lP”8ùLÚ0.tAó&Ëï~ø•’ÇÈ#Óe^ôB»L!qí8DLº*±Ë‚® zÊB6oÛ8‰ÜÀ,g;xmYÁAÇWbu¶\¦—©]ÖäNèôç©O< ˜—Kµ«Í%÷Ž©‰Pbº+Ñ ·×'Êr×ùaa‡I}m¯ß¶VoâkÄòè^ã 0=¦¥X®Oü»çBÕE’¬¼(œ-ÓZK!¯»3×­/ÞEÙjvï#ànóuqV¸(H:VIî}˜ÖT`\žÎwž„ÆPL]K‡"£(1¦©Ø¿®fÚÔ qx+›ÖùòW_níDWV¥Þáq‡£àÙÛ×Ç~÷Îëg›¹åøŽÐ°Z%ù|†˜-q]n¾^b[Bfg’б¾~ïÝ•nÇ£y·kcE¶Œ’[m”à4B0×m{›€ªÎ7-±é2ÕZHWMž ¬Žýô'H¶Q4³Y°Ì¸jô˜£M‹„eˆvz³8Ü#.+Ø P¿ë¶y‡€†å¹•‹Óê¼eXœäËMcl¢ÛÅßùqø (Rª6éYËÓ÷•°x#«-)Ú}Õ•…c¡½ûdñä#7_}zÿü’Ýù£»ƒ/ÝëŸVÑ·’`•)Dò‚.…Ó1š¡ªj®|2D¨iGY)8¨‡rn`§EòÆn÷x±©D9vº€iZkµAGÁ•¸ÿæÑž_y*ôR JôjËÎ>>\]°h¼òê@iv#7HÊc–µÚ^„š°û|ÁM¿‡påáë߬õÖ†¡%¨ë„àütÚ±7òNÎ÷·#=®…ÆL©’¶²Å5Ë…Ô¬…ý(”‚&]7èjX¥(&ý^Û¶Êᑘ"X®9Â\y͹ë$M+íš‚½8Y·r܃³ÞÈǾàgQÏSaÿ/~„¾tñ¹öù›;í5o|§²‚¥ª.õÕ›Ò†ÑÎâ¬ê&Þd„¨*@‡üg_‘£-Ó¬7³Åº´LÆåá]ù#_ ¯NO÷äô=S—3¼ôÆn~±TÚ»:ÎÊ9Ð9ë÷£Åeµ5ÙZnªïݘƒJØZžwv¸";è¸Ó°D4—JnûXš‚m‡Ø‡O;v±t?óäS¿óÍw¯~âÙo|ùÞç^}êÃoŸE]]ÖÒ¬*‡Óĵ®6yf=ÿ];,UD“f­Tå"£åxKi[6t_J˜t}ì8y™ 'ƒãÓ2 º Åz¦•åz(kÛv¢0.©²±Q –U-µ(êܵÉ å´ß‰–é¦dõñ!µ\Ý鄇çŒbh\# FRÕÜ‹ûY¸³z ëx§ÿä÷ ýŽ0—4ª\HÞþ±qÔ4ür¹ÄäÚ™_ä B  b:Ìj3ñµåÖ– §¡Y7º­äµaÜ•£éÔ9Y–_ýÚàËßZ®rR¨¶ïáó³&±¶]×›šà'B±]-ÀÙïïð‹Oœ~zG" 3á»>Úµý~ HúAÞŒÁV¹u =½W~#«Î.Î'ãð¥W>©Î/ž|açðà”ÞÙak”}úÅg6i™DNºÀW¯Çù¥»² ækÏu™XáþSA<êw”)<8™mÎ‡Óøâô<]jƒüÈ•zN Ï7š :KIè{Jn„z³ÖŦlÇö`‘+Q©þd´^-I×Y,Ùsûqï²®Ûã»fÒ0Þ›v׎QWå•5›Õ“©óàõûAl$ÓôKþ¸ë‡¿ø¯—÷ØÕ?™/V”8¤]­ƒáÐnÊJÔ#*8TñS·Én-þÍ‘Ÿú¤xñqñÄÍÎû÷…¢-¼igûÑÛÃÿûÕûÃQйšýÕÆ}dg›´Îd\¥´tµ`³K~}ÇÜdñ0EÛ,v§°ª]ÞlòCýÃ/îóSj>l»ÝÚj6o?uc<ìî=xû°ÁËûĸµœº•çÇõ ÏDM3fNszÿì{Ë+›{Áù¬±mxöééù•þøîÝÙs/ÜøÎëÛdâïªíýhµi‰eãѧ m"%± >jóįOï‡þØhÃØvœÜñ‹4•ĵósŒ’ª-›0­$*Lîû[гü5UFÁ › #¸±`ÐúV*€tβ¸¼Ñ4{÷À´M»ýF­— ýÛhëÑ–åâÛž²öÅíç|Lî¯O,¤0ŠUÃÛØpt~²öõµGéþéf»W6\ay,Ý¿¸€%cÚžuÍ$WmoÀõÒ~éÙg©V«c™òÅ¢t¦~JI»»à Ä÷s%ÓºË 4™îYGÇu £œ­¾½€å ÃË–Öµý/o_¿Ý?øðäíM]p·Pw¢×±ÚÊiM–ôÆ™ú˜¾ wïÝ[mh#\¬ þOÿÙàg¾ý™kpïLóÞÁýSWØkY;= ¬ö4·b÷žÆÛQ^/hË'#Ÿ1" Hs 1Jq0AyU &S°9w.×"î¢á`µ(/òîÎÞö´Döý»4ÞªéÚó:êàDfÔðÚ‹y+uÌ5ò<™ðlÓ´öé¬ì;m±DÃ<ºÃ½çËu¹³åùµÞ—¿ôÀÞAyJ1ð¤DÀØ½Ž™Ÿ ­.µo͇¯Ãyë…ÉjÿíÛ_ý`õ U®se«×Âw?: F^CMLFoçõþxxxÏ¢ë,ê„YZjoÓ¹oÝ¥Û‰›ËòÉ›N–Û>˜Ý¾ºó¾ûsÊNGD«ÒyN+O úÏGGËF팓kSshÍåz1Þ¾†šÒ¾öhŒuð×q&\ðø§º«³Yuj½ñuÙE`Ú¡7úöÿùÃB"•éïÆIZÉ[¡ªB"AÍr>ßšô†ÃñÅqÕ KAÜеæ B6yES/g<öít%‡}GR˱u]Ð0¶]g9š š6MÝZŽU1-Ûòœ8L€vp¡‚N8[¥XãºÆÏ98¡. <Ï?yp ˜‘°±‡¥ß–¸åŒ‰&“MY,UÙ0F+ %ɳZJT®[d˜`r1q~î4?õká/Ù}}öäúcþïÿxñWHâA߃Z;.rº~Ëkâ?øóצ½wNf9[ïߊÊT³6ØŒûü¾gšÅa) >Ú»¥¦»ÛܹüÆ›ï>?x4x9?IûÛC¡ÛG3½–ZPæMqö=áe^_ˆ¶×ßÎ%ómÉ„HvIDATòüôüt²¿ýéÏwf;“Û–"¢Y¿ÿ{ßžþÌoæ<³)Ç$AÛ7üËYÙ £§^ºª…ÄŸzu/]ZË–ÑéÎär~:ꇧïN<"6¬*žÄq•ñg»ùà~º©±,¶ík×¢ÅJ¶HÝØzå½õQ~óz’SeYÒ‹mJ L±£+C7jêVæiqÜ"<ÀºÞѽF[çm¸qˆ¯êˆ&Â`çÊnQTÓ«}±¦ªD†®xèÆEM5lm>ìeÞš'¯5ÈÁåJÛåtìË%<çiÇr$»;$Æá$~ãèâæ 9xgUùðvk0Ü íƒ;E<À/?›ü‡_Õÿ𳸠¼ø¹¿žU3mægж{Þ•àää£Ù±´ˆ ¶¹«q'þ$ÉO< Ðe”öQi¸Íº,Ë¢]G0±weØÕá;ìæ­ÉlyÜ£=x±l€ëÃNQTö®Ü¾¬.i[Ã|Ѝºµuãÿt……¬oî}IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageFieldTree.png000077500000000000000000001064101375753423500254610ustar00rootroot00000000000000‰PNG  IHDR€€L\öœ pHYs  šœtIMEß" àC IDATxÚT»g˜Wu6¼ÖÚû)§—éU3Ҩ˲%Û’«p/`01Ý Åô` %$@b‡v%|äÄt'1lÀƒqÁ½I²dI–Õg4š~Ιӟº÷^ï3&ï7óofž™¹Ö~Öº×]6vmXXŽjøhab0ìdž´ˆ öìuX$Bc CÀðÑMÍ =ü›ÅßÝ·|/û‘•’nå‹:\ÍŒ Xi0&ˆùW~æÍ…ÒÆoy¿ýÁÏ~ŽâùV-H÷­ ®í¤z†ÖÅiÙÓ;!•S.>6ùÔ–ÞK¾tÿÔ‚w߇/\}":~LL^/¯í×ëmˆ—}ÍFÕ¶2‘”‰Ÿ•îyvéQðýõퟹüÓn"•,X±Wæ^uõÓ‡þqÏ3‹ÍÒæþõ/.¼ØÅn!ŽZõnH?R™ÖÉ«Õñ–ÁfÁ†zy9•·(¥Á›03,}ibùÆé5«G~ÿæ¿g@B@P®Y¹Œnú`[l̽æÃÉî>¹÷Áëó¬ÙkTý6úŠm¿•”ñüTCÍÖ“…d1Îö–{Þž{ÃKêð [^/Wg!ÖÌ:•´ÝØk“•¡åÎ~Íè2" Ç&¾q´f+øVéŠcÖ*oï-BDD" L 0㊻?z^¨@nÔ¼–§¯^?^k,‘L¦í8¿ú¢T¡Ï+RúÏ|ѬÒßYüÊ•»z>nxƹß<½ôä®äU{ð™Ó£'÷<Ð~hfdÿ"½j\¶}ER!ÁÀæîí¿9v—ð°-5¶V_ ç;ö¢_k—ÏLÏ-,¯®—¼_?û«ë/¼@´°TÓv>dx9ê¶Û¾Ìg¦§fsç<ëZ¸ªëÒòPy÷…‡–m‘ÿ³ÁÈɲœtJÇ1ÚÊñ7Ê™1:ˆˆh@GtùÖŸ *ÉS¡š‘¹á×cŽ$w@hÑ{¯-’‡¦Ï?ñ¼_¯ºù‚×l;¨ 3l„@@ Ö†®³ÿíÈ—R½…Ö|# ÷Bî88´ð‚Ž•¿Ø¦MS˜«[‡6û} mÀ0 .çZº_Õš·_üÙ?ïyÛB«êZ ´O=ðÒž'ª3 Ck/ÜpöÙW]rä…='«3ã…±‡¦§çËÏ(s¦öôžfx¼ð&𑿣䉇¿°?=B«ÁÊ´—Ä>õ¥üŵvõœ^i7>¿ê¨ [lLTñí\R7JØ–†w/½îdåÄÇî$…]W jC‘WÓ!DQ˜H8kæ‹éTRŽd|­tˆî*‘’ÎSçïoÕƒÙ‰+ÒD(,!…ÅêŒOß@€Œh !#²%­Ç¦Ú¥Ho{dý:ÇŸŒ£BB €€„ 4–½àŸ~|ì®'Ï\:¤‰PHb*hPvm P!Á‘ÉSödiþ$“…»í·ÒòŒ5¨ƒ9»?átüÍaw°¬–ÏwÎ CöBͱJ&R?Ÿ¹ëŸ/û—ƒçk¥,AžßjÎO/MFOÏœ„¤Ê÷ör<ùàpfh¦tìq¼|9$B—žŒ®nÈU Ì í±Ê³Ñä3É„[N¯+[›®ˆÙd½xóxêºÍ«×Œ­Ý22ò0? Òc¬d":UïËCò«­ ActñÂ>ƒ21‚­Ú!¤ðÕGÏ­ ¶Û9,ÍÍ…íVËQÕ>ÅÉj­N"!’×åHX–«Dkµ5÷á<’Š Ð@&&Ô:]Hnêçj`df@dda[xpÊÓÌù¤¼rØ 0x-ßMNRK0 I^¢—ªKs”´t), ]ŸÜ ³[RH7š¤U?Sªfª÷‡ ö%d¶¶6O”_;tuFK6$’á¸VžiùÕîD~ÝÎW^{UÚ=òûHŽHlE»[¥”ÝÁK]8y$÷.`M€F0q+³º0ÿì&Û¿°_ô¥­¿ù‹×µªSMcÒ”^³ö¢ë/ûÉé{Ëói "!þrÕ;ÿvàCåÅæwéÇ•V5cR1êä–¢ŠÂ°jÛ9wg}ÃŽÅu“Õ²ˆÄ–“RZ³Ñqúa@$$¹¢(O¾?¨N *!5w¦kdFD`fB–Ò„ R*Ñ™<$„aÍHÀÀ€Æ k#¤DŒ  1Žc$ ³4¿d7ë Æ–Z0V½6Ï—=ÅU;€½‰‰ã&Hø&h­bÒÕ:rÓ®jÝ̶~²øŸ™´­#‡Ö'=õàö oUéÑ=™šK­Ùà°#(Ž 7+eÅúØüÉkÎ;]™ÝÓ°,SbËÂ}Gß&B$FC€D@vú­7ýE"݈ '‰ä¼þ¢‹>ö»>òãφ ÒX¹ØÕ±B#²÷Ïýë7—×·Ýšÿí‰× Mô|ä¡ÏÛ"jµ5£‰8‘Ng—áºÒ9žœ³8zÀy¦»{p¹RVžñÛu¿õ-ÌL˾ð-0{C¤M.‰ „€ D`@3ЬˆmˆÁÃÌd˜˜ £ "i`$ ˆL²,ökf&|¡¾çéòÞÒý޳¬­qHh´™iM¹àêXsTý_/ßC׬Îol/—2nºU« lT°¼,ɪ6Él’ÝŒ•ó`kñè}?{¹6òûw®M§S!¥ÅÄD³ã5W÷MŒÞw÷Ýû›O?tßýO±’y(c!c=±G1( XçåÂÕ#cÇîO'Ó½›Î/OÏËþá;¾ñýžU½üîÿŒ¯ö—ƒÉso»q½œ¨,Ïì>ðÛ+/yëH¦Ëpî‘ùgš®÷ö±›~?ޱ…H ƒOãǵÝ.Žm\¿îWዾ×öÛžåZ¶%"Ï?Uìãç~Ù²Œ#IJ”DBA†‰€‘˜€;­ÌÌÌ +È‹ÜÁlî 72ĆÏï 4££Øaà‘ð¹]–â »ÎvY/Qù׿—Kå)–k1€hDý±R¶k£;L¡×ŒÛnÂo‡]«V‡QØ367ÚkEÍ-©ÞœûÀe‡Þ¹¹¯ÙŽ"¥¢ ìZsî¦o~åßOÜ?Ü7ö‡ïY*Å'r!óDåÙîö‰Åž>¥‘†Õò* MãÈÚ±Mµòb*ß³í5»zÇ{ÿóS·;­™~§þÆ-W^œº†qÌ‚Qv‡ú†z%’N.›ŸãT÷I´”ø’üX1ÝEŠtÖ„({iVÌ·-ßâV;l*é¥"1¼ë}ñ È ˆÄˆ„í“©SJFFF  S~d`@$D„W>™ Xr¨DŸ«Ó±2)Wüj&y|érð.±aûl ]½3?5÷žš}A „HQ¦e |$Ê}¤eÞKgŽ$Öעȥҹ\ua6ÓÝU_šOtuk£e:™Èº´¸&>~êºñpÝàjA˜Øòªss…ìÉ'O>zÓÍï~¥ú[o«'’HpCõ…¢Äë­s %˜¦[¼åÊ5kׯŠ}“Ì l¹ú¢LOâðƒÏÜ»ïâË.®Îl‹Fe>06Ì „V2™Ú¸ó¬Ã/Þ¿ÿÅÅ¥¹At¬/å0ó­ÁϧšµšÇ&_îÏå,P‹Ý5ŸŽÜ°ºXŠÛ ‰¥ãHF‰Hl€‘ɰB‚N9ˆ-͆ˆ 0³AB6†:GÈ $Ð0#"20¢AD!øG'“»zýÐàîeGX ê9~hþÇxuŒ€¡jRq][-'µåoMß…Õ—öÿ’÷Òà #b4šrª'ù•L±´–Y„dš~Ó~Obpá㟼¥LÛ–lyñÔÉécÇJÓKÛv]=µÿøÃÿu÷©…ÉÅ'YëÖö&w\pѱyzŸ\PR’Hñæ‚k÷nk$ç# ùþÌìËgN?¶íü‹Ã8Ší5Q•=èuS #?hVÛ=£ÃÍvu±t¢||±˜Ÿ[s%\ð‰59}¤ZY:3;=9}œ"?‘Ld»ŠO½ðTj /Û”Îë Ä:~×Ö·ËR#6`€€MÔéJff£€™™;û(³`bfFf 6 Ø™J€³q„–/ºŒF Ã,€Àdœ(ÛôÊÄ`·³ÞÌ<‚(lx gß`Dе¯ý£šÏüt*åfò»>àôW8Yâ°œ² –ÇåDhųîZ|oÞIÅjPž®Ì5N>•ðDÛo—NõØÒÙ¸Ð~voæUÂÿoøÔö³ÆÓ¸MÊýðöuð¡'u-Ä¿ÜìÖJMnF‰¤MÚ˜V¥Vè ¿R€R­ˆµT&©TÔ üBW1[È”Ï,-ÍÌb½êW欑õ·Èëj³G“–¬Åž– jAz‰±Õ»^T ²"t!Šêª/±z)W âmç~B"2uÊ (˜5 X tŠ‹óA@Ã’ÁbdC„@€ ˜˜ÑX€˜ ²Ãhˆ™±ÓUˆš„·–ÍîLô6™¼9µ>d™ £€8`BGèz:>Ç {ø<껾Yó°ê²>ÀtL»¹øˆ;œ” ³3yÃ×߸«Z à JÛÌ­RÆ>²vÕ;ËîöÊžß=q*wÊAˆ_5–ºóµý§«A;Ôív³Öò$‰ÿ¹&Ùr²#vd|_Q¡?›È$V_°åÄ3/ø3~[I“t“ÿsç×ÓÅU×^yýuo¾!ÑŸ’3Ïý¬T;ã1Ý5(©508Öj–?9ãk&{OwµOÈç_\˜rÇRi²UµÎ,n^{ÖÏþì_çþp¿è”;HjÀ $"ƒÀ0ÑJ¢aÒ…„ÌÀ¤ÉH†™% …@ÀŒ,Ь°`2-”hŸÓÛ”µN¶8nh¥N_j§®00»*lJIQøÙ(ñ¢½ªH‘b$¨¶Zuõ ëÞžø{Ëj)ÀªEƒý½Ná¼á>©e*òŒ@qßÜU{ª­– y0K‹DE¶tºòVm¹ì{&£‚ÐîuóIô«:†áÍcõJ-Éø7÷W¾¸S!2@†·¼çÖ¿¾ýóёñsÆ·ôžÕ:qlr±¶jóö®sçm»|ã%[Oî=œêîŸ=qeÆÝ¼þîÊ×±³Ç• IÌ$Ë•† ¢·\{S²^ô¼VÏk®Åµ}R3#6À@g™1Ù0" æ@jî,G€lL§-:0€F ÌÊrÔ^dÀ2 Ffå)fÉ3" ¨:€ÀÈš;˜"¬ƒ¡s‡×ž#É%+ë?æ¼4a\°¶x“ŸíYÎY£ÉWoÌC»Uì¦T&A:™v2‹¥jqÕÈοýýB]Ýz^ï‡væëÍ0hµÛ^+V:ŽÃ ˵…5cŒHª08nRï¿~â³?9ö½=e&zÇZùºþÀAˆnJê”sbê…ŸÞ÷óõë¶ð¯ÝyÝÙƒÖÐHº7ÿ̯н€lY¯µ¥Àþlî¾â3_ÛwgÊÍè(ˆKmÊÛ–‹Õ¥Ò'6Ü:Y©Ý󙉮 Þ€ˆ‘:HŠ( €@0À„ØØŒˆ( ãÊLbDHС¿`xEB쬦 :¿„: @@ …Ø¡xˆ¤:(n€aåË „õxS~)öÛ”q’c]ñÑ:D,ú‘”dìÖ;MÜ;]‹´†6f²Ý™Âð°LfH¹îüá)N$FGŠw>x²Ö”'áæÁôªþ¤íˆ…r]G± Û¡ï½t|¾WüàHøþîŸ;¸¤€H°NÍüVÕv]r‰«_üêÞ‡O½åÏß“KG›´(–+‹‹­&¶è¹õõÅ¥ÅT*Å ´“xâדý Q Ñ™¦t• Ý·v‹µàw¾ÛcË?d$ì`+ BRÀD Œˆ¤´@dDÌŒH +P ™ô§Ý " lˆA`&@ÃL kB4 ’ƒ £ÒÀˆA¡õ|U}™Û–èw‘0œ®QŸK)i­4·mãm‚ ˆlÚÞ0d ‰:Œ4`}¹™ÌgÑAhûñ¿¿ëõ[{&_<Ù5ÚU/µz{ãåù©É™‹3'+õÜîÏ9û²«¡Ò˜†- ØDNù%͘¦êמ»ëÆ[nýEá/ïúÅå¯{U=þå¶î+—Š©ä¾=O§Iš>V(ô§ª))™´Ã8–˳ÿ´éó7?ýÞË“VwÂM§1+¤#¦ié‹ýèç¾ó¢û¢÷"²èè9‘æ R¶„´‹—­q’¶h‡æü1Ùò´kB € ³Àò @#;m™Ói„N70v‘A€AZ™VˆQrG|Bv©Yø SnWÊM§Xʼn¾~L˜Øc+ãh¯Œ.ÿJ6FU}õ¦s{’i[Húc¤í§ˆ(>.ퟗý6Xæ_¯þÑÖþíæÓGrdÐ ˆR¤98vǰ <ïé'&›{g›(•O¿\½pÛꇟ› cÐÌ€Œ½Ï]g_º±ë/®ÿÜ]/_¾±pϾÚC{–Ü„ l:­ƒÎl˜X ‚0`ˆ:*#’ æ Ôˆ`YvÔ‚’RBµ³¬Rƒý±Š’=Éæ© fÂ@Déú ‘¥Ùœ=”xãöîFÃ÷#A0?5Åóm9yRŒl»`]>çôÿñGû×ì 1c³“Îú~Êuo¼èÆZe¾º¼äXbçk/yôpiñÇ×ÏO×ÿÏ¿w,¾òÚ˻ƇœƒN§¥•ttµY+/^¿óU‰î´µ‡ÜÁ3§æ–MiÝšsýÊüê±­žÄO´ok7Q·t\iOšf”ß1 V'ÐBÚ¯®:û:ËJžzÝ¥ç‹-×ÿ•k"õåà/v,G\t iÿl` V[æäbÐð4vå¬éù–(`Ó©ç­WvýûûÏÙ²¦ûD]ä¼f{÷Ð`÷B=š¯x$P"ðŠ¡ƒ¦Ã©;Ú*  Üé…ƒÄÊP#Ñjó=F3{qzlÀ˜@€4~d|•UéÏìüÆìüh¥áIi¯ïuo½¤'•°mIk‡2·þàH¼\J·d‘WõX6={¼ùoüýK­'—¯ß1XtM>i=|¨4RÈ)¥‚zÍ7Nï@!¡@ŽŒ÷-–ü_üâŽë.½áJ9»ëÂMã}™ùÓ ÉBwïÄh¦ÐeY.Eb=º~µWmž\lœ7±nhh$ÓÓÓ=Åkó£ð’ bð€Ëñà;Ïn±R†u9È®é~×Ö·£þÁq&ãW|Aø^ð6:1˜!‚Øp 9aS\ié02‘Bfãûæ¥S•Íãݹ´³cS÷»//ÜzýúŠÏs-óò\à+úã±vÕSÃyÏfË@\Aæ•6@DbÀ΋ÏH´Â´ ˆ hÅ´Ÿ{Ccv£Ë‘H¶òƒèÈâ'¯ùîk·^tÉ]·.×¢w_¹ªè†Žm³6]ùÉŸœº÷ˆzสüø¶Ÿ„ÛŸÍþöźoċӵ÷¼zÃ5_ÞóákFÂåzT¯ ™ï \Ϧ^Ç y®æï}ü—kκz$mعµtbvirZ«Øo4‘u{©JµMKÈDÂj”›ÃýÌåS®“Lª Z÷;]·ŽÜ4Ð5ù*Þ–h©ˆ%rË´=÷ò‘K×_ºª8FR ©6õ¨¯þýö„m p…±#wD_Z‚ÖJ£A;Ž®¿x46èŒö'®9'ç+ˆÆÄ‚‚X©¨#Œv†;B‡_3 qG(;K«éà4u~Q°‰3§Û‘H'WšØBËpŒ)g¢8úõgõíèYlø¡Öâ†-ÙüÒn'›³ž†Lÿä'EÖÁHÈz2f¹–Èl @sÓ3é¤Ì'°hnÈvoð=ÿ&Zºñ’ÑÓ‡çš.>ÿÀñÐÌ‘ß?ÿúûï|ñž‡„·› Ð^Œ/cò™´Qª|r¶»7Wظ¦6ßh—J2ûûô켊•L§n½q×ù—_÷Ì_KYÇhØŸ¬¸Éäm¿úÌÁÛ_*%m‚¿ã„+mÔÚ „² 1¹æÓÒ²0RFk¨yDˆ•J`ÙB)n…ºpæšñd5®·ccÀhSiE¶-{{’úTÅ–Ö +@³òž#vê`:+,0 @dÖŒH+ò¶ ¡q , ›²®áÒz·þ&hoòt¸}MÑ7ì ¬¤H®o.îÅ|V»á}/µˆXH´s}-0RZ*еbÇ&ئ=¹ØþÂ×´ŠÙUùV+ Ø6ì<÷ÈÞj} =$»í.>øíf†±‹Ï>µûHky®Õ¬f“iÕäZk±§¸v`ËÚÂH¿ÑŒšzâcW^VòµÓÛ5‹A4í#GÇßtÓ›w>X¾òm"ov‘I$’éCÏïÛ½ï…M·ê8C—¾ÿªÍÙ¾‚ƒÚ`¨ d’ŒÆézLLRm¡RÊ0C1çê³31óBKÍÖ£†Æ°,p,9Ôã:Q}ÅYCìаδ2êA®HBð Ëëˆâ€ˆÑ:þmÊÝ’w6ÛÕW[ó0ËW‚ÎRˆ4_¼>‘ƒ:‡ 8’=C–ÍÏì?óÓ“ŽM„„L:–…€œ|×èµ[ 猸§—ïo cƒ`ŒÒ¬T&>>[Î<–¾æªTW¾ /×½Þ±1Vñ3þfuÙ,Ô ³MuÑß½nóM®}òÅ?Üp×ëÞwÎÍòʳû[qFBʦ0ÖŽ C*l)}¦Á9W1Gšm)…• Œ`dl@Eœ²Ø‘¸ÔD,@£€Z=xqrÙ±,%I£Ù˜ŽÅüІÔyë€Èc¨ãr‚@DmC” XÀ †ƒÜA…†ùIÝþó«»JË­üØè¾r¯³ÿâò?c`ˆ…‘õk®¾a~f.l6•Òð ojû±m©„ëxÕFýÔ’]è5ÆàìèÙ›„ìÚ¶Ãl¿iº×õWÏ”ZµvÜnùq€&蓉ˊƒ•C{²Ÿ'Ó]F™f©Ê2ÑT¡ýøÓ§y”„B:¶[&¹fóª»~ø«­¼Äå¥j_¦ç–ï*/×sûò³¯ƒ”üæÒ×d-2¶ I¡1Ðdh†ºC#Kbd°+)«¾QF%]+C(ˆcc \òtÚÆÍ=‰P‡'KjJ;ØòŒm[Wž;xßSó®KÀº!sG‹fD4¦ƒÃ ‰Q3ƒ@ š:: aBÁÔ1:b‡`0ÆpG_2€kzœÑU‰ls¸'3vÉÉ…o>J¡E,µa8»Ï^œ_TZë(@’餛JgZE#¬SSó¦ê¥Ü<°"!º6.µ·œ#ò=ÛÆ¹ºQLùþâòö v÷ä²kdeyõ­7±ö-”"YÈG“SS'¹£«†üåbßxn xß¾Òµ×5[nßóŽgÿæké`y±¶øçÿúñ³/X=>|fz±¼Tõcµ-sÞù/¯’RSóBK €P ŒŠ¶È GBSCÊO Döc`cHÃ&Œ0b˜kÄ^¨,IQ e¨+%NÍ6G$êÄ>¨c‰  IDAT(3›/c0ÁÇtò,¸b "ïè+4B`ÔÐDŠ3£îÍ'ffTš„|Ç¥ýOï^7—94ì|¸¤„޼ †#k„¥™ÙåJ½PÌ©PÉr+Ý“e² ƒE”ص~ûì™ÅÑLAÅA²˜Xš©þáñCn"ñÚË6ÖfË2›É¬ßѳª?BLt¡×lýþ+_qzºÇßó±Ñ‰aÇÆ¹ý/MÜWLK7 •kÒ]xyÕÙ—î¹c÷‘“Ó/™b¤V«(ÂH[ß&>sÛm‘fW - !RÖ†£È­˜f?Fe PÚ0 .5Á‘F–ñb¥ÕR©ùä*u°÷ÿù w€I ®¢ˆÈø¿V~GMB@¦ŽdÔQç:,MlI¸`Ĺb\Lää‹sí7ïìI¸ DZzs‰¾ž‰+7îy¡Â€ˆ¼e ñw»œv£*V^S„ñéÝ¿DY Û"ai¤ã\&•L'3=97éüòÞG5Ãèx?hÐÊ➯D™Þ‹Ö£0‰Zº6rénék2UÈÎO.û±Oæ ©_œ*dzŠƒŽIå²±2 豧 ÖmÝÐXŽ<ÇÁf[©Èrf­m[–©N§R–´&ºEš•æz¨+-cKìMAÆU_•VUöÿôÌ9c…«6¦Þ³‹³…üø¥ç§ú ’I¢Å ;;&±)µU=ÂJ=LÚb8gmîKÃs-/›°Ÿœô_š©!™¹ª–‘Àxi&lùq*aEŠû»œÁåÔé^AŽ (M'å¸BËxÅô7æ&€:i_âN: ™±æ›’¯».¡f­æ§gÇG»ôL±µ<]…zM5»Iú¾û—þû»?øLò©àæo:˜¹:3ÈlÙVk,µÛ‚“aÄLW2ÜnùkûˆÐ®ÊPg;û_í¯"âg_=°emÛ* ß+ü:ïeÑQ¬€Lu9zôßvWJ¥ù†Ðµ¤LÁá|¸ÎI¤ˆðé}“ñòÙ¹ò—î>NÒ1:tyªä¿þÍC³‹µT&³wß‘B6!þá¶ÛVö ddŒ4Ï7UÙ‹kîIROÊò´ÊHGÊvÌå–šoê3•Ð •c /TˆÔh‡õ¶‘®-–ãÙ²gKìËÛ/Oµ…èŸ7¦³ÚП˜ÀŸ’ï€@ø¿1¯Î·¸³¨ò+Oð¾ÞØg%A9Žc9nÜjKÕ(8ù§ÏØ]ýçn:üâ‘fË_½fgsùXéÄÞm¯êUÇn¾ÇJ¤²ù¾dª ˜˜D&—Ë»2=½8Ú:VRð¿Y@#]¼>÷¥›V5Û´¤6ñ#÷ß÷S?$ kD0Úúø«oo{m&Ìf\"«kv£ÙœzJ[KK³çŽˆ„t,kõhfï2KÔo¹râÆ­9áÕ„zƒ œ9³ n¿ý6Ó‰t"2€Ö`z“Ö@Æze4ÝiK)¥,‹–! GÊ u¹^¤[žòBÔ íÈT‘EÆ`ÛSÅ|J µ°âÊí`úSÝWœäN¬‚Q"òŠ}ŒÔq½ò‚ã+7 qåVA‡œý?{'âŠh+ýÀ–¤Š§rYë]W®A!,[,W—³›.™[nEqw_÷Èøèê-gaiá{wþ¦gâ¼Á‘"‰$,!ÅOf 5%ÖvY쇿?žª#­ø¤@Ô‰¡A¥}ïÑ…û÷.¼<¹üÓ»î*ü¾‹ˆ ˜5.Á‰µ½[× NdSÉ0Õj@Úôâù™{~øÍC³“go¼„¤ˆ‰j-U[n ²ç¹\6jyõzSDZxý>±Ð2®5Ûˆ$bB"!EŠë¡¶$°@J;¤ „»–0†Y£A’cX²1L(kD¨•Yª…–Ì@¬#"Q§Ô+—ãÊA¾RûÿßÁ¬ BA¨ïúÐ&A’… `nå…Ó'…´2ÙŒ°HkH»Î½ïû®ß¶±ìª¢“Ȥ{úºó…lQ„¯¿hÕé#')ÉFËJ"CçŸ"šQ3ÌÖõDNþÕuÅïìÿ®6›NHJ7í¸¹Ä/ÝwyïG y–Œ­L&qîe;6^¾+›î¾ç'?*sýÆ7¿u¡ÜX*/G^Ônz„EQÜnz-/Šu«²@õª>½¼ä?}Êb²U‹Øt#R)]É] Kkîܼ¨ñ\#Xòõb=ž©GÍÀh R€%¤ã)0jZcX 3¥õÚdÖ€h:V01 üScåú‚!@°’EAZÉÃt8"!!ø‘yÏ®þŒë’cLÅÉBÖ9udöÔ³½ý«ºzÒ…B>›Iœ¨y÷U7ö\ÿaí5¾ö´ÿØ¢ëxÕBwn÷ÃL=õÓ_~÷Û^àmóºgÞÕwÆF–$àO}Gš9E|ë…#‹KF³‰µ1ÌÌD˜L”&Žºs)ás/œ&Lfrª57³XY¨îzÛ›ñìÁ0”?¼çîå– #U¯-GQXo4§Î|äÇÍÓGÛÇž8²÷wâýT#ÐKM½Ð +h®®J^ 4 EÄ`Z‘ ”™iDõÈ,{ºê«¦¯¼ˆ#†XÃz´ # ?Ž´ý˜ …Ú03snÂk†Óù¤µX :¡ÂtXØ+Ê ÙÄBZ ‰˜YjþI,ÅJ‚Ï’tfÙ{ÿ£V¨ã8YÌ7¿uÇñ_ýO£SßÄ€¯g¿ÿ¸ùöïOÊ0¼í­[_µÊb?8ÞÀƒKñ¯]sßWÿíäs§ ]½ã[W^ˆ°)Õ:dqåZP§™'ºí+'õæâÝûî–±X [¶”„ ‡‚¸¹#óÁXqå2©ÒÒ”ð¡VjØÒ ¤¸üõo¨/Ì×AèEq£X…ă{ËÇÿ8sôh¢kH|ôSÿà) c]m)­À‹a®553pÓ×Í–ZzzY·c£bÝVºÖ6б #èNÑk‹ëz®Gç¼v`”2Zi/ŒÃȸ5[èžBâ©‹ HFÃ+áÞŽYƈ´B$-só…™©RhÛà‡xãZû/×›]qëJDÊ j”Þád43´j Í=üÀÌÝßû¯ã'×_úºö¯»žtøÞ‹{¨¹¹ïÿmçÈ…¶Lçc°‰I h¹  %PI@FdÅÑ[Î.Ž$¾ÿü7BTh@K"Y„l6¦®Z—¼ÈJZ^;fÖA+6íÈJ§Yq,¬ª¿;ñÀc/ýf"³UDZŽCÕnÇå’÷ò¾ÙÅ£‘ŽrÙ>i ÌP©©…ÌQÌFnùz a @£ŒiGJ7xÃPª^ Zö#ÇšAX„IµæJ#dm».ª˜ÀÒ W2˜XÃáÓµTÂ…XÅ10l`ûD&ÍÑÙf£ôÜ„Ô{ÝÈXo:ŽÁÊ¡2{—>qÓÄ=Ç’­öÍã°X­ÏÍÌÞ­˜|xùÙoõ½õár©‚Fo¼úЧ~öý³&¼úCÙöGL­U¥SAOõÌ´6derûMűÚ5L?ÿ]­gËÙ‚&9±1Y&íÈ€@ŒX ,Qìà~?\" •®,GÑÛÖÿ‰«>sçG~pË÷Þ°œØ¬d÷Pé8TU]KlLe`I$óžFYµ¥ei'ÒÝéZóÌ~Vù(Ù¾v䵄l±®ž~Ùã\¢ ÜÄ™å99”µŸŸnÙ’c!%jÛ¾†–0Zi4yÿd3Vµbm´f•qìÙJ¶-ËÀ`¢0–ƒ2ËrÍ·¥`f pÕ@rz),E4ðêó ‡2«úR«z¬±lªQ´çXõèB’<6Û˜^ô”† #¹jÍ«úJd3ìÊõãÃk7¯JÿßwôßÛ׊°¼XÛ°i´63;¶ë?“Ÿš|JD™›¿úÏ;ßû=]Ź…e¯ÑØ¿øÚ-D÷ØpÔ¤Äæ­0”–‘ÈäŠä“õÌBûsÆd‰c À$øX©ýæo¿ñò³vO¬®—– ŠXE±tƒf™öwç3AsÉY>ÊØW<éïYÕX¬X‰ìíÿýFŌ̿]øñöÞ‹»0—¦ /ïݸóáåœKÞ412$Ÿ<Ý8S5vd Ç’$VVÁ 6a¨¥@m€Y!6q¬xyvºÞ“vN,yíÀÄ¡f†0Ò‚¤1œË¸Šâˆ-›V÷Ø¡œ=–}Ç®a@óüÉæïö-åÓN. ¯gkñ\9 ײ*Ãä:8Û4wì©ovãî\zͪB»yJ½éýç_K§<½p‰°Ø—Y·mñÀ#=Ý;£¨Õ,‰b¹¹ÿ7ß½ì㟨záé¦üÍ‚{ŽÐdÉñ­gUË5†H»î©m$C«2þ—nYûƒ¯_àsÙ(Ç€A( kGdI#j~ªQžÂi'–E–p4½ñüâšÕ)kùd›­†™Í÷ Ï>Ø÷†?Kåsw?ñýgŽ?‰JºEgµ\ɦ]M¿ºtzÊIؘJ¯9o—Õ]0(ådY…1‡±Qm‰&6ÒB[`¬ ÅìX"VưѵÒJ£RZ¯Ü¾Ã…jPiáá¨m9b¹†±F!hÛ²€eÕ„axÖHòÃ×… ‚ ºû¹ÊL)ΦåáÉš°kŽ5ÇÐ`¬#rmcŽZ^KÊIÐ1}i{Šª~PQMvõ¶žB›ÈAY–}æä‘õlËf2½T-½ÿÖó.{nß=ëZ2ûÉMÎk¶ †‘9}j†¥é:r)Äkz«²è oß^m鉮mû–žT:bÔ€d#-a¹µ#´ „¾ôçN=¢ wÙ»V¿å’îw4ÚÕJCgµ®ÄŒ =çîÿüöê;2}ýß{ü_Ón6ôC åTxÔr„nE¬Â 1ê]K– Â’Ëme4 Rܵ˜Š°  ´‘DR‚ÒFim˜”†(R*6Œ$b–š UW ´ŒŒ1hYRņ ˆ˜â˜½PA@9WÃC‡J“‹:R¬½È¤“N;Ô~¬$6Æ EdG‘‰{AئÚÕ†“K,6›>³KéÜkG‘°Ôˆj5ÿÁï|uâê¸1wô¸?sÖM |/sþÕÃý‰Ò©fwÖi¶C×¢ÔØÄüBÙb庉PóÆLxó[7UšÚ±íMãCûça šTlXƒp µm;ñòÒ«»Çr]k×-Ï—Tü7?Ôn‡ÕZ‹QI@ŒÂ€w?÷6*Ÿºìü ~ûL}šÚ–Þ’ït9‹³gj¥Y&’ÒFD;™AÛaR+0¾H#‚ˆc] ¶-(±aƒ~d5ÄÊÄy$˜ f‘1–ˆH´1Â"m 2$êË;Ã]ù§WKuï‡*GZ~Ì'ZD(PVüX’ bGHT&ÒH àÚ™•ÒZ`P`€àÎ} Ãpº~h-š >tèÌÿyp.“^hÞÚ]ùÙÏïúæ>RYl5œ±sÎýéùJ_>ÁΔۯZŸy1˜\h õd뀅ÍÛ¼OG ];iß÷ÃÈ@Ƶ¥'ú¶Æê‡Æc»HQ=Faˆl¥ƒ [þBXjsL¬J7–ÛR¦ÒެøeØ`a$“’±ñªk.{ÿ»O>ù³_ÿæÎ¹þŽR}ù»O}=,ÌKþ\ù˜ ÉL¶¨µFËâÄÿ%ê̓mËîú¾ß°ÖÚÙïôÞ»ïõøZ¦VKh@†PL39!ÆLIS!)Wᕲ ;)RåP–q ƒ« fÁÐ"aH©Õ³ºûõ{ýî»ó™öÙ{¯µ~¿_þ8OäŸûÇ­»ï­{Î>{­ßwø¬KÍPÇ_ö?…Tm+y˜ˆXL"bÐGM)'QŒ}•¬. ©©nÓHLÌ4©h\ó¨òIíöéFÕB(ΖztÖ#ãÕiÕvÙ9¯ff¨¶…0 3"îcU°­{vÙ¦E‡t»EÚNª§î¨d¥º~úgÂßþÿr~ÅÄ›¤MJIwÆEýô­å3'铷ׯ/Ï{¹rýÖ—1f.üþÁÞ›ßö¨ª)踬>òÿþÜp6èÖ©¨Ö>Î7ì8tl¡fËŠYW«x}ÿß~þgçóÕC{_4ª]VL±ËÊþðkûãáá#ïXüñ¯~Ï›ßýÞ÷^úÄß\-ìëê3z|ç“™4§ùkOýüþ¼w0™á?ù­×$ tYUQÕDSŸ³m#Sf1#f3á­¦  F̆DˆPzˆQSh£š¸‚4«'ÚŸùù2w)'±¬¦j1*!«dóUQD‰PÕr¾–V ò¥Ò;]/ ôøù§ŸûÿvïÛüà­ïh:Aå g fã:t)o:‰%æÙ¤4SdcoÎ>ôOL§ÃNdkC”ŽëïÃ+®BìzgeMϨT„¢DrÆÌˆø¦+þ;Oü·ÿú©ïûú¿·Zwg——4•v÷&°?Ïep·^½ç ?› îÝ9þî¿ûÎG»9½:Ý9yçÕêW>ö‰ãõø•‹æ©ó ¿ï;þ{UàmKÉT %+‰&SPËBŒ[‡ ïÓ#Ô t뵨s¼ÝuQ71·Ù’ ª&…¬Y3 XN¢ä.[VD1Uݶkè¾âÛߨÂLbF„éùöÇ'‡¬•×Úº/~ß»_zå/ùª|ëÓ·÷žìºœrŽY³š*¨"H†,’AEͺM•¯÷wŠŠxfDðD¿û7¿vou¦}¬jGÁYÛׯ…Ç>ê¶žï\~âZý]÷ž}ésüðŽÖõä…SY¿ýáݳÓKW†Ê‡MÌÞÑùÝ‹Ý+;Ãéä}_öõ_öÁ¿ýð‹Þüþ¡÷}Ûýßd/?ûêü}ßûCüþïúÑ^`Û~!‚$¦*"[1B¶†œAÌ ‰¶‘)TЭŸî‰q[|1#t¢`  `†"*Û¤"+d0N)ƒA05%ç,xämBe›!ÝμÄn[d¢¿¼úòk7MßF1:¿w&˦Ý=| ÊÍ) Ì@³ŠBÎ’õbYµïrJjÛÞ!£ƒ'§’e2ð¢v²ŽÃ¢úÝÏüzU”9Š#dŒËèJfPPÔNCA® 9µvÄ<ù˦»XtY ¨xÝô{ ¡dÁl9å“§Ÿß{ðº˜g;Ï>óüùÝ{Dò–·¾qrõêÅ£WþèÏ~ã]ïû¯øŸýÔ?=Y%@¸2«Ž/»,¢Û"ž~¾²º-m©ÁÖ;7ç ïç( ƒ(Ƥf¢Šff&¦``jÛk Dõ~)€ѳŽDÀDmkÂlmäû¦éÕ¡Üu§§ËM‰íÙWž»“GozèZ³Z)õmÛÖ“À´Me…>iÌ9EQÑ-h!‹˜mUOjbÊâß|ìÕO»g–“‡þø¹_2&UCì.#lI³ µ'S†Ý'žxÇâr€~˜Es֦ɯ¯ÒÕÝÊI^œÎ÷Îð7>ùÛÿú_\½ùÄà¡}UØ\,<|ðæ£.x3{tÿ‘£ý'ß¹ÀßöÿCì’,6r¶Èy«ø™n}ɲ‹Aaû°Aü[ˆ–nEe35@PÄíÕ¢j ºåy€Þ·ãà¾ïD€‚(ˆ˜‚: 3S#0T 3 3CdlúÔƒ{d§|ðMþò‹ð*\¿Äñ®ØµU\½9[º¯mßå¤YDD·.“š˜ª ©* ,:xêÓÇMOëÎFµ› f}wúòÙ'UE;“NÃг㴑ªF³‚…_®–†¯{éwžžŽ?.ƒ¯Véßz·Xh”²Ýè /ÿåo·ëÕ¯ÿêGôvÞxàÚÃ×û˜û‹à™Cyûäô‰kü†ÿÐÙ:6õÙú¤ª’’ª ¢“œ¶¹¶-®Ñ·!Û&N̲‘ €dT“íUÛìç6·«ª¸mÀl¿CŒ†HY-8t€Þm-050ÛiLq[Deæ£N—T=õRk¨uepfúJšV”gƒÕÙñºÚÍYúLÙì~z~›Á(Ø9!©ª*(-Ûȃ’²š©xïzìk›Ï\ñÍ·?øcÓ¿·÷æ¯J«—0%7ØwH—i´yïϸàvv¯Þ¸zëõ3.>xû#ÿé÷}í7~Ù°ýéßüç_×þ€˜ìíí~ÁŠ*×ãw?þþÅ9þà/¿Dªf9瘶Ä@@BUUµíž]dûl1ûÛ×ö¾±’¶‹³Ü þ¶D/jh‘U·Ÿ~B6  ÆˆÊlÁ3184UD¤(²n2!ÙaÛš•Þšnw^&Û%Å»n¹|tÂ/®Õ!£°sFD„ÀL¦€dÌè]¬-eP„"`pgRí©rø7î_¶øŸ>yqrÑvi“DÑÏ÷<ÁmR{û¶/¹þo»ö‘_ü‰›7¾m³lU}~vîDÓlg§¯~Á\10ïv¯Oõ7ÿuúÜÅ;¾ú;÷®„¢rãÇnýͧšùŠßõÍ?¼•ÚÀLÔ˜QDˆî×äõó»˜-â>Öãó5 FÜr9Iô~À˜ Õ€ÐTKGÙD•Qƒ#$‡³1?¸_÷1ïŠjHªžÈ9œŽÜ°äIå÷ýµ2÷ă£‘….ªª1!;5SUÄK f€ÌÛÛH‰iëЉJËYRÖ˜d[ÿV˜ $Ãt&Wxv QäÎåús÷VôÛ§«#rî~ôÊÔ½÷fýƒzýҲ^{ÏK/Ý8Ü}áùW%¥œò¶ ZOdzk×êqí˜Úu÷Æ7|Ñùïýõì‹ÞnÝþÌÅyIËÕÇ~æÇ€¨éýŒ¦1£™šléKFªÛd§2²’¡ª‘À9 IDATêv42Pcf41%0$T3B6Sð``V_äZRDuŒ’uû‡ÎW2¸‘Ÿ¯£cHIê@*²;)*ç†%cáÐf‰‘T E“©ˆÆ„m/伈8¿Å×m¿’2³lÇ 0@r E¬£¶Udò)§{çr¾ê½Ã:ÐKwÛu»½ã&µ`¬£ÃÝúƒo¹r¸S<~½È Ž›ì03¥Aí_¿{< ¶otFÌFåt8 ËàrÖõæñsýìÉgûÇßÙÕ·:}+ŽË/zˇ\ D„[z äŒÌdšÉ9%FD`BD#£-)k[,b‡˜ ÑÌ "iŸTÕ Ô÷ÞYá)'óË‚¹˜ ¸?ôuÀ‡v«(vºîsÆ"P]bV„²ë#³!lÚ jØô9KJB`F Û©­ Þ3m *d˜EEP,:É@L T©Ë& I5Ç^¢B›¥`Þ4ˆ”º˜²ÍÅ_ôöܵ‡NŠAü·¯Üªïo?{÷ŸÝþ“€ƒ]ÞÿÀͯß{üÉ»/®ÆAʓӓ¾ÜüÜÓúßÿa®¼‰€b4 Ðâl=?zñ~æ'>ð=oÕÉ[ÆÍxòUpˆ˜ =+*Û}ž ¢8ïsF"0ÌYªÀLÆHÁC̦J†à™¢Š±ç(Ö·)Úî¸Øz“Áñ¨æƒ±_÷â ÏL6(葽ÊÀº(ê×M2DǬšKO¡rÜiÚÆL ¶k;T0dtæLuKÝQD"T0QõL‚HDÈàÉ#* JÇœ“Ðr“_?ïË€’ '‡h­ÄÂy…ÌZÍéWïä߀°H¶±À¯œ˜2àp:yú¹O{W¬c~êì£\}ôc?þ—>t# ¾ôæèÏ?ûü3x|uò#_òØ¿J”ú®GÄÞälX?°³ÿ•ßú)\ž^Þ®ò«Ý)~ÿ/¾€ 0«%!Uq$c  >I–¬ÎѺ•釅g¶{ó\—ìDñ|‘x6,æË ƒ½ó±ÑÐS4;_÷¢x|ÙnÔƒÛdI„ªÀj˜s*Øy‡ ì壮K¦¥ƒ½‰¯={)ká0Ä„QrÎ`*–MX@»NÌ¡iäí¾“Ìl{ãªgè£eÑAéÏ—¹I™ˆ/– °ïµ“l†H<.8 ®é³wªŸYöG… $–¬ž ÇP˜‚…ªIã½ÓË%+u·6¯ýÁIãˆwÞnÞŽ þéÿþñ“ykb1e‰ÝÕëôS?¶¼þ.ï~ú“ÿ×Í7~CÜÞ:Þ1šŒ+ŸMÑ mçØ³¡ kWj'¸n”=\¬sVtŒì™Û`Ž"LþhÑï Â[;%fSgðæ+UmRQðP¨êþÐߘTE€QáˆlÝÚ닞ï.Ó«M@R•AÁ`*Ù Fæ€=CÛ™¨mzë £-µT=±n©Fh&UE‘ˆAl¹ÉË>›’‚8âM¯Q2š‘h€9ÖñýKM*ôº(öFÚ)F•ªïµð ÷ÑêrÙlv«pçÅÓÕº½m¸þ«EfqB·n-(x:ÿìoýù~Ù[ßw±^V…_4ý¦éžü®ï_lôùWϧaA‚süžoúa‡z¸SLjb­pTngH£Ý)wjLB}Îe‰Ó’'ÿÊI÷¶ëá½7GMÖ×.äú¤¼6qïy¤ÚŸ¸‹E¢—OúE']R"Ó7;%NŠÀzeìZV;Yæ—N&lº<¨E‘°f¬2nÑ-HD¦˜QT³˜€ªBT8ßdF—$€¨d¡$Ò' „ÂcÓ™÷䞬4ª +—EÌ7’3ˆjJ¶­® àvúŒƒ¢hýgž)Ò,¤Õ¦XÙ$GÔ÷}]1³œ\¨}Z6&ŒÉÈPùbr±\²+¡ @Æ$é—>úo^9~õìã/¼ã½_r|t¾\µ‡72_Te¸¸{¶jNËòó”Þ®N½»cvÞÙ° IM³Š{ÕW.ÒY§ öÀ$¼ñZab»#¿;Ä^r¯ä@N7} :[ëbç½|ÒŸlôt%¯]ÈÉ:‘¯yó¤ò;Âaåz‘^ök§`epÛ4”ˆ™Y0À>K€^-©e±¬ÆÄDÐôºŽ¹íÕ@²¡~>[ԋŬ@ÖF;^ʺ•»‹|ÖäIÉM›V­t’ûÞÄ,‹´Ñ:AÉI ÉiÆÅÑÁO·MB0.\êD7 .›•u‘»HŒÎ9ˆñâõ‹Ý+S ¾ŒérÞ€ßú¦_¼pzú¼µjV(ÇáõW?—ïéïøáÿöÞÝËͺ›íN˜ ïº³Óæ#ÿò'ÞöÞ/å·}ÓÎ*çØ¢YL–²ž^Ÿç˜Íå,ièè oT«>1€ª¼ñÀ;‡G‹¼ìlPâåOVRä;ºì'?0áu—×]Þð‡žØ©½FE›ƒçÀ bY@VQ$"”…?_´Up„Ð$Y§,FÛ³>£ fUØtz¼JMŽ1åmÀ ‹%5D…E—»1#ÎJŒIš¨)I×meËjMRQÀ˜t;«kªW‡?¹Ð£¸IªªMë+¡ @§9&%4$jNVQ°:˜x¤u„åÅ&uÍ·<ö“×F×ßÿ®o{ÓCG×Íñ½в i™í-·ßð#?trtÑÇT–aº3¾ugÅðÙ§>úÚÝ#瀈, /Ö¤·/aÑÊ#Súàãå <[÷ÇM€ÅFóé_¿L礬hveDDv¹I­“·=P‰ZÎòäuøÊÐ<§UÏ*@¨$¦"E°àhÕeu°4Ü´ùÓÏÍŸ¼9™V´î°èrU0ÈŠfóVÛ¦eÌÙÌÄ­‹JÄfˆ IÁ”’šG%‚ÊÙz£³¡slí&÷y;7¢Þ +vMŽ9GÊ"„ÞMþï w»[*ŠíN¤“nÙ 'E ׬ãZ5õƒI)˜¡É½)’Àõé£o¿þ¡”Ú['øgÿñ³ã¿_èT‘Öú–ýweóާ?þóËËU=.ëX JÇø³ÿá7××ÿèÊlöÚ_ÿ•cÒœ‘<îÕaÞdÇžXf%~Í›«6MÊ"&¹³´³l¢– “š–±ˆÉ@¦œ5œ“펰ô°é NýÎ(ô%›BLÂD•ƒai.„óuŠ}ZgÙôv¶ê뢚L F]w`"%AK°ì4eÈ*] 6øu›Ú„•‡˜4*;gjRñÎå^›” 2#»XJp¸3r©O f3…¼S`;Çc2M"Ûi>§¤ ¶¸ò;i‘tÝ™£¸ê+F-<ËÕª/\Š- ÂøÊ¤]7!5arËóðäÏô/~á·?ûK''·ÀøÚ›w劻Î}kó »›ýƒ]xôûâOë÷Ý´|ïWÍl2øýÏÜyþÕ§>óÙÿð`¹÷¼¿ïže´ÝV_:޳šë‚n&ÀéJ2èÑJ²`Ì8.,漕yÍ^½HU€Â¹3hŸ@¶ú´@Ìùá½òæžwÿóÓó·ÞþÎÇo[ß÷•×êßÜ麄³!Ÿ¯º·\]6¹W{Ü$hzÝ6Ù»˜&£¢z÷¢—-õ ˆKÆóeD"sL*rV¬+—Ìú6aÖl†h^PÕH!›bRÉbˤa»òÔëá#]g~8È›¨1Å6Co†ºì²Æè¦eI.eá@M¡Ä·ïqû‚ÿµÿçWnX?\†‡ìfùöoIßñ€^‹}ð±×®—§·O ÌÑ`\Ÿ}ö¤ÄÅ«ð>7^qßûïž!´@8¨èÞe¯îòݳX8,BÛõ|rïÙ;«ªt1©ŠæàÙ ’hº\wƒ²`´.[åqX‘ˆõITqÕ¥“EÜ$õL Ö&C4@Ö¬³ Ñd蛦ù𻮥$‹FÏV!:·­cztØõСåu— 3öI O}„sJÆtWˆ˜sàrÕpÔ­Ä¥y[÷5³œ„ˆ’dcf@ ¨Gýãù|%]ï RᲘe•åÆ!"B¹S­æÅ¨"ç8ç¬YSFa=÷ǯ=ú%×ÒÂß|ï¯ßÃèêý‰”=´_b³^o^~ùÚ¬8ôEõÌÙâÝ»áïzË_|ôø­ÿÅ?º:â:èé"¶É ²£U+Ë^;ÁOÝZ^6vmÚ(QÌ!‹ZÌ–2tYœ£$æïCtKGmÒå&Ÿ¯$nÉ(Y·8vTQUk{éDS–é Î9«ÙѼV޳.ãù²¯Kˆœ#f^®cá|Á4FÙv’H—%ei“ª¶IÛNÄ4+&“ Øõ’RŽ9IÎ1‹(¤,"š20"êèÓgøg©ëQ<ç˜pûyª  Q[¬f§Àˆ’Äè>^¾kw_[¾}’¤ÀÚöß<ýöÇoFæ¨Vøñþ^ŒJJv¯õ:H8_ß~`¸7ÒõlX¬V›z\»‡v‹¯{Ëð¼Ñ={yeæNÚgÛ©¬dŸM/-ƒ«=Üí Í¢#€š9FOؤ8*|Û`Ó禷Å:õf–Òý†ü}ÕH½£'nT]ÆA UK_ìOµ‹Á_¾¸xøpÜ%×¾íõ¤i–9@U!ЍŠBÊQuËýÀ$ð¾­„HÛ–K@D Ó«›Ë J}r¥ï/Úr諃"7‰£8Bë{*ÊÐ-zöÛ„lä룻éêÛwºE6’%;5¸Ú=üðßzÅ¢þî«¿Ü7ÿìëÿg÷“ò?%~/~åÝE—šõòb¾<~…¿÷‡~´ôF÷–ùl)mŽY Ó wGAÕØ Y!‰ªcÜ þV:bÐwýiXôÙKÏ»5®ûto‘ÕDÕ²Üg-"JÜúƒ‘¯ lÚ40fUBˆj»%_ß)š.9Äù&Þ>m/[€NdÓeAÈ¢Y¡éR—m“Ô#*@è£f±lš³øà‘ˆ†%"€~Þ3SïT¡›>ÕÂÝÜg"”ó¦ÜRo QÈ!™$44ËdÈ)õÃÉàt±Ó<,16ý–rºèšG'oøëó¿þƒÛ¿úŸîýâ«ëgòyx-¾øŸoý6²5²øñwþTè&ªÍ]½€ÿêwžë²ÑKÇݲMª÷ë*Z0B`d¢MŸ ÷G<*QÁ»ÒY®K¿hTM¢Šß»Œó.Û}ó·‘©=œW&Eéy“Óº³ƒ!PÊiVŸ½»>YJ”ŒèSEˆQlÒ­«vŸÉ‹…Cb͞ݶ‡&¢9'vŒˆ f€m œ¨Üçµ”Á)˜‰¿ýØ’Žr½GT@ÝBcÉÔ¼“œˆÐR’Màúµ›w–—çgªÐ°ÕÝ ëe¯ œ!{€$@Þ×l‹ìvÊ<_‡º„%ó/~ÓS¯½Ü>\ÙÑëgM’xܽ°@TUCd­„® j€­€u¤[^€ šÁë—y[e¹:’zì#˜eI½PŸÕTÌ ª ª"’ÆlÁ¤¬SúòÇg}¶ù&uQ.›<_gÕb¾n͸ ›³uêU @R–­¯,fAÍôó½$t–óöä ”’©dD fÍ¢f ·'K“zçÔ´í“)™Ob$zûüâÓõî°·.¡RáÒKŒ®ð9*;³ ä`Ó®¾ë oüýžýoóu·Õ]¡‰õ¬¼x©ñ;emÉHuÎ’­Å•‰}û®*ó”¿îw?Õ>ýòë?þõÆÓê¥ø~ËÏþ¹äí¤¢ÄŠ–ÅLœ ±ÞßKnSr€[{/8ðÐ4,»ä¼Ñ>‹*‘ZN ú¬1`¨%ñá$Q˜Í u6¼6lŽ›Ñ~]ö”8(®ä<Йa2 óòƒ]ëL$~Ç»D»Í'ÿã~ω¨ª)lGL¡û/7‹f@ïLDЈ ‡+ÇË6‰Ù$Pf‚qáÀ,IÎj 6\©f³*ð¤òL±rTS>oáÎ…ž¯S—¬ËRy&žéxÙ©À t>PÎQ‰½¨0yݚ͊ŸÇI#)hÌ’%ÓýÂ+‰máÕ¸e0Â}ó˜E@!3#¨õQ úÖzüÃë# *îRƒ>Y˜Ðz#õ*D.̇;¦þž{a3mS-‰*z°ö…K·_“Z–<ô)7kªÒÃâ§Ñ*ѤâErÒœ(j.|h¨~î§?þÜ¥¯9ÛæîÔH£Ü.iDŒ)±óh ÁÓ¤d‡Ö&E£A¡f“PQQÔŒÉR–d–sŽLì b†6ÊsÇéW‡E’ÎQ®–‰`é¨,(g­\€aåW›¤Æ‹Îú 9¡Þ—-¡`3@3Û©ý À¤fÄpm·—©v¾I1›wœ²ÄÙ ºÌYLÔ¨Ï" ŠÈ –M¶ÿ36L¤Š¢†€¦…ˆyûø€„hÐÅòàÙœ›²D£2Ìo-q§@2R“Œˆˆ)M`çÁðOs³ÀL£*3%~wŸÒÑçšµ”†]å°Æ.ºÕPq{†éç骶¤!YoÎt ‚'Ó‚H Œ EõL"Š Q ™$q‚¶M €M/eA›h ‘v¾ É„¢ ,9 ZwÖ&qÎMK=–MoMD…d††jR{Š9ݘ„Ý‘[õzmâ†%¼~ ËQ‰¢¸ìR“pÙôënKlB0T460"Sû¼½2˜‘¡oC&˜y«Ãžrß'ÅÂú¢u“#ôHI Ìâážþ“ll°=/2q=yü¨ú6Jìýúbã¸Ìü&ZY9ç)ÜÏ¡;B#ä”ÍH<‘:§ž80˜"€¦h¢na]ÚBÌ©¡‚&eÕ,B„ %caDZÍéj½jùb“s6DÏj%»+cî£,:2¾‹ÒœÝ¸0í…D IKp*BDCï ,öjH¾PÇΔßöÀèã//»D¦èL“1¦lð€uŸ“˜ª©²*z‚Nìóðqµ@(fÐÀø>¶…¶·#mS“¥Ñ‘v˜ºuç+×½SE âÖíLÞ¿‡ÿ0CBã-À¨<üKxð'}Ä.‰ä´hB”uSúzdÜë§¿& CD3˜¨P*À¨ØKf&ÍhªÐ,IfPìT…41‚±© 0¨eAWYR ÈL°a`°ƒYx•ËçrÚ%4ö,¹[ Ï‘¸"Ì¢`ª>YD%$¦É1°RÔ\8g('hžè^KÁ)“Yrdi°t«œ5Q “˜ä-,M{–œ‘†£‰¢‡!Ô–³@ßJQY!S‰)’KQ<¡¬š r±±Ï¡alÓ¶h>NkQ®NªÉô«ór×…ßG³,5•võ×¥Òýb>/Ê9Æ€ÖλƒÓe/È~ñÿ9ØÆŒ(¨9ZYAÓš#P1_±G"æÅ9Š1¡’r"¢ ‰ƒ3ÉŠˆì˜Ø!bÛÅ¢2RBl›lNEQ":§Þ <_æQU¥.÷Qƒç˜-9*Áu*D .”Œ@-jn |¥«&†àÌd0¬šî/Ñ€Þ4*XdïsTDU#bÓŒ¾Ç, ¹0SD‹âJŽÛV‘"±ËÂÞåù\‡5 )™jäœÅ¡ë¤”åç>å˜ )”U(< 'èjóÁÈ÷Yû>ë¨(Öm4t8¤ÚhÒ6¨!ÑfÝàò¢æÂÑï~ôÅ×}—ù ß½ã‹ÂÌØWf<¬ëCåJv®ªÊy—6´{PçÈe󍨭jïÀ+ ÷5C©ˆÎéB(™ŒºUè"ç> k.Š!* ªQN8(F›††Ã*7·ÐÌu\‡À%:( ¥,Ø3‡² ”Іe6¬F>õ\ j£Ñ(v0úi8.Fµ·ÈD8(vÕ@Aw¯Œ´wu]!úA]H"Ϭ†ƒAÊVkÖ"ebïëb"™<žL‡b€VoV82p‰JÑåA=Ž'n¿Þ=t× wúú ›JY3¸è¸<¿'žJ@ñ8C•c>Ä6Å>ÒüÞzruÒ,šÁ¨Þ=Ü ÌˆÆïø¾]SYK pœÃhärêg;®KPÇ@³:Wš¨t¼3 *ΰï{˜MCÚäzàð`6žÏ;Ï$‚EEE&fâÅ…1å¢ ³™ÅØ ‰S°+WÊØåÉ”A={ «ºã™ §ŸZ7¡ #àl0¨Ç>õX\”\Õ€ƒºP€ª`‡Ú.‰É*®'3ÐNL|ðVWŽÑÏ6é±. v¹ruAš=ðdZ8BMùÊußm°ª .$N (Üæ¯îUëu"¤àPÌ Yìg“º¹Ùž›lêfSD³IÑ·¸YÈ´® ¬1u›^rvEh.;W’sêr¿éo¾ñz¿éýdÀ~ûlºŸcF"Ì–•òjÇ;‚ÞÖ¢ ØG ¬†Š€ÂÙ• ›pr'˵í*.› †ìUòzm@zç娷ºwX1àʼn&#§˜ÁèöË›Ãk³u+Á94rÁ8H³ŒEI1Ét U]„ UЧ¼±á‡52X×Á°F€Ô÷i8fví:«ÐxÊ›6Ç].«¼ZäQ]+JpΠלíû¸a….T F»îòl*†³©JY¯ˆP©š¬ïótR^®6ƒ“¹ËKMmŽÑÖs !Ü}}j2cé|Ò~ÕˆvöúÝnTa5Pæz6Ÿ-ÔùN ‰ãªÝ,Ú\×ôe¤M{û³žQb䇾e°¾ÔrŸûTkZæÞ€íâ^º8!n³Aè‰ÛÌcÒÐ,%x¾÷j Á¥¤ƒ1 ØmT[ŸY ÔŸ]Æ«‹šÚ9<€§wÖ®$Ì –Üeìj*ˆØƒˆ¤>÷:š”÷îl°[ÈhVÌ/€??Mr~”Ú ù:ŸŸØ¦éV ©j¦B– ` ”ÚÀñ=l~– rì=‚VÃàJ~ºŽêù¼?¿§Š½Ä Qº.ŸÝJÒ‡ÍR’¨w|C œýâ$Ç”«¾“vea^{6ï\AÅ\fWJ¯ëµ †Üm” ]œùý"ö–"ÇbÚß»rïäØÛˆf–Òâh]ë˜"!# KP2¬Š’˜o|ýp²Sßé=…ýCA ›u*+W‚ïb¬*LMŽE­ jgØœÚdZ³—0Y\@»r~ǃ2GÊÙêÊ« ’‘B(~y/ &ev=€ŽP¢v’µ'1-À­ÚM«Ø¬ûþ3$é–×¹ß@»„áØYÎîêxb«¹+šßóä3*­Î¡o“iXIYb×Ñ ânUT%ç“véÂÅÂtm¯mÅ.uJôŽŠ½Ã,¹Šý}@]«¹µé4äX §¶Z4W¯Wó»vã^­a0 Ý%­Ööaÿ*çŽØ3ƒ>`Û¦ñ¾Bö âi°ÕSL­k»œ]™£©äíQ›ãý2FÞß) ¿õ¿™ÖÃÔl`vˆeóÌ® ¤¢§«‡Åx—ʉ\¡õºLŠÏÐùÒ³¦ € œöa¹ÜäMà’&¼¼ˆY(* ®³õ¼O&ÜÅܯ<›Õƒ°YißÇÁ˜»÷÷ Õxý±"›N¯à`R¯ZU‘ •Ü?0s<šŠ¯#—å`j£²¢ÐU1 ®šô¡¢º êû¤É4ÞWµ¼3­6­Žöáî+i¼ï•¸áhGûhu㫱oY¹Ÿíí*]}gÓA½wö<9‹ãYÝwÉ\Ãü²aÕÒøË’O_Í@ Š!ÙêH bçË2¯a8lbÌYsVDZŸµ®ÒçmrÙD“Á`DëUŒj¾úÁÙéIí°œsßêtsCµòEŒ’"ˆÙúû¬] ˹§n±ŒÚ¢ô†¹ÅfÇSç´§œ²ãX¯>êÛeÁÍ*ÏFþâ$O÷ Žó`XÏçýä€<Çi| ÁA¨iqÑ9ädÔ,úùIÜÙ¯ÖëÖDÛÖ¹,»”hµìc´Ô·€eŽ èbo]Ç]› WjFÐpôj?¬ýå\—«v8,!1 ®/Ð{AZß+Çcï+ð7Ÿwãý@7®×½¦Ô…éAîí^óí2aÙ+ß\ºº" }àfy9ïEl³ŽÖC1ÀÔi1JƒaaÊÈ2¬ªá8°‡åî퇮¥såHœ/]0‰ìË|rKoV}«ÓŸÙ`,\Êyw\¡)mÛ„qvµ l7 v˜À”¸ï ›:«†³n±JׯT1iö—0ç>Bì,îü4®–våÊH“2»“ÓîÆµaÂ$`9ꛯVýdo´Ü¬Bi“½‘¸5ŠÛt2úÜRU–ënÓ·’¤^ ¶‘ %káñú̓>¥Ñ¨X¼ž†3âkß8V%b¼8IQ¨<;ôÉŒÊQ¹:kó)©!¶`vM»‰±EZ]X;Ç®S3þÜsú´8GD9¾xÎq IDAT•˧ڬԙß@'« àØS0¸JÍ98GÝÜe“‹{'BÍRW‹”zœ„f£~¯=ìasÁy³r„Ø«¥Ÿ76rÓªw¸\û´êÒåÝj°×o.="•—gm(ª~Ž®àMŸ´WWÛé¦~µNËËè|8920è32e•Û9+ˆ¯Üf)—ó6 »”ŒÁÝ}¾ŸìVÇw‚-.äöËËÆwo÷¥?1÷ós„L~sâu»1aé¢wÔ®“¦ì<ÕößyesnW0¼¢—ÇÆW>\_>Ÿðü…\N‹Qí3]_XèË“ã†é2Ãâ^ s·¦“:¢¼¼´ÑwöjŸ–Fy=ŠV–åz!iÕH–§:Ùñå8œ½¾ýùˆ®_ÞVöئn~Ô»`–öyú€C).N"\zuËWQ6Qï}:Q³ŒuQ!a¿‘k\ÞÕ‹ó~grKÍR’æ“—²´¼9ó/.—kƒT¬Öf9Ÿ¨C¿Ìë&µ—j@í¥ÍFtçé6mÀ!X_ öu<å—ÿ²%Î[n]¿ÂÜçv™g;õ+³.4?‹14g¹š¤Å…x- 䕤õ1•#i›„Jõl~i‹;IRt†Ø¯£¦HüäÚ(ÆtõQ¿|9Œ÷C]UÇGkÁå½6ßáouyúOŽÚÙ´jϳô7¹[kQÔµž׎ Ñå‹0Ý­g‡e¥µ0œVñÁF‹“ãÈlæpë¯×ãñxylŠ]Q”~~͹ ÷ÊhÚ”ƒÎO7ë[-´j>êe¡}¬CM?»^v—ºs­¾¸X§ÚŸ ±Pж ‡–‹ã,’ò¹Å…<ôNVzðÆÁÞõ }¸8»ÓW®˜ßN*àÐQÑõ›õ\çÏÆ«ö¶eŸeë áH}lK_Þ{i1WI-\Ün®Þ¨uUú¦Z®ÓÎÌ—å`u×_ݙĬ»‡EÙ†"KNvEŒ¶:΋#¬À'Éý¥e†,àöG®¬#v›˜¯¥Õzá8/²?þ³é~Á.vt4óYHz¼:®ÃTb9*”ÓjÞÓܦ×½[q04ò’, œÜNªÊêäù~x…×2_l¦atãI9yÑ\i»W*+zŒ¾˜AåÝr!³}?œ@^OŽJ8?ivÓ„à†Éuÿj͵ íäjœ]sýÒ&»…õì-‹X Áà0Ï_Ïû׋Ë{qÕ§«7|Ói(aç!T[_ÆjBX;Ûކ»pv«?¼1€ÐSWÍöB±‹~„ဆžë8+«2P9 H) ûêAš?­´¯©!FiÛ8ÙüÁg¯eY‚ Ôí÷>þúçMDdDVšÊ¬šÊCÁ jaFBHhø„ÄDˆ¯#ĺ;«Ë¤«Ìˆ óâÙëïñgûÍZZ"ÃÑÌÚÒ?½òcf*ÇRH‘3M@ÇS.0Dc{|òIf{mŒMi<ªD4÷@{`(s"áNâNÛ€’5Z\#Ǩ ‰°¹iãi ·oerLÙjF“]a "dt<®wüMž9Ì î¦ÙÉçˆÅPcøê«Dœ›Ç[glv9d†ÁÑ™†´½=¹ˆY¢%ÂL{èÅ'žoE†u€ÙuÆÀÝ­+ŽðtQ<Þ4Få¶í\§Vé¡ñNÂýÊŽÄÃÇöâ‹”1œÎÙõY h_®tˆpTÐrãú=JÇ»Fõç_E«û!‹2·ðü™Ó’:cëj8{Æ R¡`[©àœA¶«ýÜ^œLÁ!%<ƒ“  0ó_þ÷£Ý“¿¢0 ã+6º¤’®<õˆ /ôÃÇž6º€°mi“9ÂÜËšXŒÓ1‹Ø«Æâù].»[?LϳícÏ8mnlr b’×®kw!‰MI[µ‚#1A‹Õ}ŸŒyÝxÌïXîÓ‚`è:i÷’Eð°rÅ"ºû—(ž\\ß…¡D fý`»ÔK <ˆ($•ïCGÒ¦Ó‚ñÑ}ü¹*ñn)1BÕ^Çå‘Yÿ¬¯‹‡7õìl²Ù——/“íGÝ«`49bË{éb€ŒN€npLLÑP’‡ï=ÁàéÐL£Ü°~ù#T¸/w²˜q@ü~ååJ-®ùÃÉH6@ö~6•kÌ £ÈH\®z> €¸ÍCD‰µ •;< €!¯‰m½Üä:•¶Ij[êLjXŒÞÅõûž§<Ÿá›¿Ôl„ŒŒÁ ñ³ÿ=€·{3~ÉåÁÈ2{0:Š”’O·“ñü¤#º|§’ˆ–Zí`zîÕ{Ú;ÀsÑ/}ð.Ÿõ/.øTË>O3ìýÐYpÀ̓*ΙZ‚ò½^|’¹Ö5÷êô F2höôÅoã§Cev,¦XG ×•Ž #ÌÃ`zp~ΚAc¶o†Éif+o†ãOD4òõSÞ˜Ú÷µc<ì´g{ÐÖ:‹P«A'B@eXG‹co`,`Ô)N ÄÄÔàñ{óéï'ËŠN!ª×rtN&ÃÊZM¤ÑB `¹Â,%ÁæÄëÊ7­!¨m‚,`vîÞ2…Ô ý{uþ,YÞÊ“ñ¨Ü–bžB'ç—)+|µS¨ŒòcÒƒ0>ùÇBi8=ó$޲ˆqŒŸÁ«/p5Ç‚ç(“zDäG'hrtÉLÐY ŸŽÚƒ;~žD‰5Úeg¹(É¡‹†Ù´ÈÎŽÀè”Â\!‹Ôǯï|·lÚ÷$˜M."žOñЂ$‡¦ÚÚñ±È3ÔYG€Ð­?ý:Ž 8OA¼µÞ#À"SÌô(EÔÕ ž\ƶ£gŸƒ¡„ã(k”>;ÃMocé*M²mÔøˆ ÌMS-‘ˆÜåWñô¥kJÅ.šÐ„Q©ÅÜ7¿Œ\‹'Sf$˜_؈Ð$DàÉ©wÁ%Å‚r §WºQîh:<޳Âc=EZ G°®ÝÚô7=TÜíØä·.4e˜rˆÿ³ÃÖæ9ØÄ¬ëà!Ѓ÷"„l×÷¦ÈX·†è,¡QnïÍÑ3¾}ò‚‘ ¡RšZÚKä‚js*;XÖñÖàÐÕM2I íÚi¯iŽuk1EÁÃû]œ"ÓÀf+‹)‹ î”f‚ÞÿTËÎÁÀv»ØÔ2â VäÃ]ãzçXÀ4G»ÕÀEµÕšñ±³J2˜Õ¥Zo³,ÊkOœó˜v8¨g¯Ð`” ¾ïtÑ $’Ý~XŒÄþL¯Ìþ²  «]ˆFèPÚÙBÜÿjh $À°MYÕìúß<õƒ7˜2ÃÇm1EuífÇäp0i ¡b½©|Ë\l‰cÐ9ÄÐ]@(xÛ½-o°·JîÑöÉyàgiG»=+WÝ(öÝÖh¸m«›@ˆ¡*{øµ´5ã– ô´K‹9ÜCgŒ€¶rÿyt ê zú¹ÞÝ%!r¬ô¸½s}'í“]¤IÀÎÕ8ЉªÀ‡ïÚ¶õÙ(¢„Ô»þr>bã\íWÝùq&=^p,Pd±àYÎ=~ßäyÖ½ö«·Ò4ѺíÜRIŽ,¨Åæ–¦9nöƒ`¹"O?¢Ñ¾ûѵ%@Ï6Õž»øþ­ŒrX­!aüæÛ†aaZ^ÿ¨›½%‘f.Ù¼w²R~‹ã<üdú. åZ—wžBh¯¥zl ºÕ+Æ0¯–n"D¼o¹®}uP|ðáÉXGÕ`-å=¸ùiÐÚý­sR‰Mlmݧ£§qPõr1·‹²l½¬É<Ôín´K^àˆˆÐt6ž4 Ã_ÂÝFGYÐißyÙs/mûˆYb½$”¡¸À,E¾k…ç£ç¬ÜêNu¬`ª•‡¥Ÿ³ãEDcÓn¬Õ}zðËRFV 3LIibyúéã;튚0˜Ž@õ³Ž&8HÊga¿Ÿ…ý­ô¶ï±ÍgøçÖ7µß¢Ç´:¸Ñq"ï=ŽB2…Q~ÔB#xNpD»’¬Ôt’ož£‘þôz ì°=øì‚£"ÍŠuOßöÎÃ@9q 0ØÎãˆh¡@8y5J;éú¥z¸³;輈1ƒlë¿(0š›XÖ¸ýwÎR‡¹Ð÷Gnÿ(»{GV P¡bj›Ó­0ñõS%¼k%Mð`$%Ô çp\–C³ ^xÆðtÂö]ÝÞ é"U;Û×ö<»Ÿ4Ä‹ncP‚ªM@[ê(e¸ÝÜÂí¦#ˆÆÙÃ_KE]–ÀºôúÌ^P’ê½óaèh½SåÇnö‚ bí@Y´»йH¦jFéÝwuñ ³öU¨WJÕd)ÔïT0T5®Ý[YAýˆ:=P£<ÖuÏfäæ?·Ñ„ ÄëÛ6ZL4çf笄ÝÓ€SŒØî\” L0ÄCˆ¿þ_¯Ÿ…ÈebröŠ5[-rÖA­-˨® ŒQûÑèÄD‚DŒ„Ðá`î­iýÕ×ãõåùW³fÓyhÆ»'e ÑPùf j_>脉Ù' ¾3¤ à:æ$BQAÊ;ßk5OwÃ$gÇIÝ É8†­§s¬—6Dz†£ ‡*©fãhXÂNêþ;ÿ·¼W&glÖ”æêIóžöÅÀ×ÊËrìžD:ç°÷çÏg­Õœ¢ó¯Åög3}E·¿¶ l@ßÚdÁŸ~¬YÂ’¹1ýøÏÝÅï³ýßeœòrÓÌ?MýmÆ|Îué(3¯ù8Çä Þ½0›¶™-bÈÃ$Âgg±Íwl|IPÔ™!¶ñ@‡Ø¥o@úLdo4˜ŠWýä…Àܪ’¶°gB($9u l¡d9˜_·Ý\~9ÊâÄT69Ã(ñÝ}&b!Dìke®þ8Gjõ/íõ‹íƒºøŒÂ N)ïK˜_Y(È@› ¨®,›ÑiAØyj6-rr2ø™.Ì_r¼øŸ£x†ekëG ÛÞ›Ñ\T¥ƒÐCáZíF§¼êë$e£Òm:$ ±JIÚ¬åâ«5ènÉG¡¯ÍpY í;ˆ:b4°7îêåq׺Ñ'Djáä B¬Ý€‚ææ‘3Œ·[#{æÍ‹¸ytÌÂF+ÂPµ£QÜ­Íf ëABo‡|Fš¥&)¡#‡$;EÓÙ9ÇkeŽò&>GbèPàM9{†,E8Rmåó<¾û¾¬î½äy0P! Ú˜ýc³y?ôyý@¯˜)52ÏüòÇv>Ç>[lk ¢¨­*Ÿ‚À¼‰½—»ƒµ–Ð@áÄorœÄj˜¥ô䌶÷Vm!àÙE~ÿÝ@AÊìžÔÌf~2’ ŽãÄ•TµA–ç€6Èu®À<¾rçaMÇO-féíO#XsA3£|·W]åg'qš°0à*Ä4qt‰¬—³—+Na¨Þ:äH½„c×±tñ3rØõ Ã& a‡Âˆ è8Á~§RC¿!Õò@Pw7.ð÷*,+ RH7T‚3ç$ÌÇ¡HÉîŒæ}Ôo=r–B?ìB³µ‚˜%.D‹³øx’~øÓ°8ëýÞ­ùÙQtTÄ›²ŠÎ!O,,0ص@)Ó-ZÙJ0%0UÙM¦ e" ¶¼£ŒÎY19Ða¨‘‡2£˜7"{>¾)ßC‹Œ÷ÖkèæÐ6kxˆ8qF3Pß+G{Mí|ZBÏ0§²AQ¡ßé(µépB\ ®ž¥þ@A?r¥Î¦„F`’$”QäþaÐOÁ,°¬Ÿ=ƒÒÚXP‡”݉ù7`»×*À‹“)²â Û“—§¡µ u0—ï¥Áísº~è®^1sÀÓ,B9ä#œ‘¢tc;2 —QêÒh†»´¸Š´4˜Ëȱ‰y `ζˆÍÜþ 9»Í°{\Gû'hZ¿ÿ Û=TЯ÷åßÿï:ÙùQš/0ðDe7>‰²X˜Ãà[dµÏ`–L!+€Z!Љ®\Ô'H8ûÚ«Œ®í) ¬«ç¨ÜÈÉøéç¸DÛÕÞØ…ĺ*e·òñ52±rÞô[שÐÜ©fƒ!u×ßDû¡ý ±ÅÛ²Nνîüöq§·ìäSΈKQÊžíozÀaWK6Eå¾w?Y81Äã¸ÛÌà¯ïÜÂÊìdÛ<†aÀ7?w½ïw[õ|:®†^9»·;¹Šr(¢î6ƒÀ¤ÛFG—I° Ùi*ªîàöð8Ïï«ÏþÃD)Ã.¬¬Æ&­2žD-l‚ðO?ø(#ÝÁEØ®zdœ Ã`ë26lParšX â ÚÑùKÞl[4bµ6OßW±O w¼ã›·‡„g²2ÚU„0S³v'«²Í3v÷n‡ã%ÞÞhÚ3/ÁDD‡åQºkmÙ¹óË({†W7ªÜiCmSKB[–"Ýx_cÜü«ððkÃêtGG¸l€µŽ%îüf¿ûC#:ÜRiLž§Ë›ÞDZK¢N9‰8£v„Þ¾íŒ÷Œ;4réXxmÚ½ ÷,™AD)M l€*uj£Áy &ðémo•Ž&±Ù@/ÝᵺžO×;½Ý,Aj£P¬]zF ÀnßІYÝAê?‘óÓ¬ÙtFìJv£J&Ü;S݇CÝÕ÷. ³ß¿‰’Ø;G›F.‰í@ïûþ`6R3Ça˜$û“2z!±¡k2záׯ=-@ó¤²kvø`(ã€(™mmþŒ˜?½ò¡GüZù»Lùôº8:4Ú¹ýã0¬°×.éÐH긭LI«¥§ž’Ä>Â4Ó$ª¤ ¥s’¸=6ÂDc˜¥éð û-Ì2¨[¾f'ió õOfÑý»jq•7‡îéïÝÉó´Ü};åœ/ߨä9mW ÍCXÓa¯§a€Ó"©ªõŒ'Øl¤H~4ÉÞ~”Ù”?üROÎ ìðàҘ뭉”£(Œ¬vzœlÝô"ÛÞÔ8$ÝA™ÚÉІނµR½L7Û*™´bûu’Iš>7ËjP¡'Òm?£s–?笀¦7ä#[…Oÿ@{ƒ­³ãªUy.ÔÖäc è(C‰Œj,DHê°û>¨­z¼1¡Õ¡û_ ‰ën£Ò“a þæD‚‡ƒ Ä »ûAî)Ôpù—c¯>Z–‘n’×÷ý¶ªb@rRAÍÁ#,p«×CzŠÔƒ[?ôÞ‚nÝ ÷з®þ¨bŒeëv÷’BDSL¢ëuÝÐ3ôðÿUÓxìm6Ñ)®8†,9"=4QŽÁÈÔ€½wGÇÑ𨲗%è?¨X³!êÍ‚„´}Wý5¸C´ßtí[{ø ŒZÕªË2Ή¦dFÂúƒ$6+ŸÌCu·ºYù¢0›Pµ³ÛPQ‡%,54ú/N6‡Í²áPZäݨÖôž“ÃkÊK ¿íåínúŸMª’U¥¨ZZåä~ù­¢ã öª|èÂ>°¹M¢Õðè‹„Ž±ëØÃÃ/ÚA#ÝÑ‹”rì%ì:4Þ@K¶¯A}'…ªPXÀ¤K÷›n2Mžnk¹3ÍÆ˜u€:éfϳú¶ç¼A*©Y#»Õ;W.ëY”ó ï~hŽÏ¦ƒ3êg,÷îöõVõêê’s”vßš>4ÃÆD3øUAª8hg{Ìf´]ÊÑ„mïÚÃw½’Fï ['øÝ›Šcîš ¼»©£óØdÊ8¿üëÀZàË2!™¶[Ù>*™Ü9ï”f'ÿ©‘N§ÒîÉà:¶ýÒ´ZF€©_iu ñÄóE|¿Þ^¾(N?'Õ^êȧcÂÆ¨ªäÉoÒxqÉ·‡.O™k=‰ÈèŠSЍ`îúžœ²~š»!ιƒÐ,}w0õßàAH]|.´W¿–y@AÄéø’Qk)#!¶êÊç‹›e¥ˆ³ØWfóº[ýTG®`#Õ£Ú¯mÓöíÇAxAÐK7|vU€žý7ÙÝw2†aî§WÑá¦gTÌãè2tKæ±^»âŠaŠÆ/A SÊcX´ŠFבˆéê—A¤”"Z“’C£æ¿¥t3lßZºÆÇßdéU´ú»SÆ!oÿQtò눞£“Íý†^’âtòáç5èô"×6?¾vÓ9ç' ‚+È»4f¢ü˜F TÄŸçõ“B&ÊæøâóÁÚïrô /¿WÇÅ<ò)^p°#ο/¿šc#POÀZniDeíóQ´ü¾ÅŠb,àœ9þÊ¡©^¥§Hyèñ9ÄÓ¸»×~pGV„ÙêÛNïõÕFÀƒ«»ho´6jrÕ‚úhxÁÆÏÒ¦óùoDá¸%Ÿ‡Ý<”Âpt1ÆdŠ2V¼ ˜%)>XD»Ê]~‘”{K/À ç<ÇÑÈÇ#FbL[2ù„:¢«qã‹ùµ49¹N`F“Iô O¢k€ntòÒñˆ*>Œò\Âô9Ç‘8¥“Ãúƒ$@Ÿÿ!¸u Œ2(;ƒNñé«Ü=Q&Xð0G©Òk¶ßÊr#1wÍ–HŸŸûaé!¤ãWèú߬p“Iܾé%¼àéˆE'¡\—ù5¶Ÿ\Å£³¤XÄåS·øöª3JêmÓiãÛn“¹h÷v¹Ñ ð»» emñuŒ† GÜ'2;…¹qB>ÑFÇŠbhÁ ¸°³Yvô \®zSƒ¶7ÐóéWB; æ›óÏ#Ž¢¡ò$À K¦ÞuÖ3?xeœã‹ðþ~—òø_ÿ¯u£¨O=…òQ©Á'¿åwoþŸeUqšÚRw›’ÃÉG,žÐÑ'4›ÐaP¤'õÎO>ÝN¥0a˜eH§Éá¾Ån_ü‡øö½Î/,Ü‘úÁa%R~íÈ ‰aØÞ†üw÷>:v @Hð€¥jqnÂ~í@Ê›Ž”7,Ð@Ð M\€¾Õ>P[Ú`azFv¸4ÝÊp"†[k<ú$õÆ»b€ŠöV g¸/Uq\¬¾¯£15ÁÔúä³ÙúãŽNi6ÆÖ8;[;9ø¨àõÏÒt¡µ!¡ÌQCøøC={‘<þÔ]ýßÿÐj ’#Ú/öŠÎœAa™jýòÛjú›býs3»àåCWiµ3¤eš„ÙÛÿ’…Æ{Ê~}GËu7ZàÍ_õã·]|F‡5†z‘RÛ¹ž„“‹¤[9åÓ¬9 YÎõÁ…‰•[?ýZTw tñúOuò Á˃cÂwOÇŸŠógÓ_¿_¥!Žãq,ÙÛ×ë—ÿ8o·Æa%°Û£"°Lb”ÄIÓY]Z”{c²)wèƒ•ÑØËÆFc* žb¼®úüˆÈ; ž,¨¸Û™äÊ&‚ñÆX· é Ìò¬-œ ¨u‡õMÛ´Ñ-Ï)Í¡²ºü =ÀšãO³‡ï[À¸4=¢b›Ræ#&7È·@×nþŠQÊ·C:Ú?zµÖ ÓY¡j_•Ý‹éhxù®‹Na:§„Õ[Å(ÔhéøŠgs¹\©„‰¶tYË¿êâdÜÈ4l,½ÆfØ¿úòôÝKë]:æò PkKeXìªEJ{à wIDAT†c”OÄæ¦D¬”nK}ô»œæ >ÝÒ‰‚¢³o ‡ÙódzlÝv@ž}µï´‡A(v`wÛ÷1ª¶v!eûû.&‹’ÍÛ6Nâå÷HYqÄ® ‰ ²Q¡ñ SÓK(·q#|äªÍ=,[SÑ>´(ƒ˜"@!Ì š’Ž@µÑlðÜ£ý!bž÷´=þ-÷Ä3 Ë{ݼV££8Ñ”ˆ‡•Å„cK#®„y“u¨£Ñˆô»A×ÞUn{cë§¶mûZv[C19zÎâ+˜ä‘–ñ`;ç,bó0Œ²xók©×¡HñúC°íÐ#býøœö·ªühEÌÃ.>eÆùA{o|ã¬(“i4>‰cˆ]äÃq€Ä-ßù;à«Géw¾Ûš(aý¦ïn-òqp‹«Á°ž¶ ùý¦²)j–¶z´Rè•~ ¯lr*äOz~Mð‘•)×½yÆ(² ¡Ô€{ÃÑóˆå@ìì3¶klõÀŽ•Ý!N‰ìƒß»¡ÑàE¶r¤Åí3Ñj)ûÚEí[é7enh;U‚¡6p|žúà||c›í¾½5”@§ƒ˜ññ+Qýgpý¶·ÖÆ¢…°­(¸TÛöÙ7㣗•oû‡mŸñ¸‘~×ÖØ¢ÕJú-ÔÎqèaµ7tÄÙ@š¶J.Èô\lo•^š8F½’Ë_ãy Aœ¼ E® bWK©µ±ßÝ:îIÝHNa/±û_]6Ï»Á´?¾ ‡?[6nþ´¼<+º;ŒDBš5Å9¸Ù®‹‚˜IŽxÇZaæÐæ±1¹$a¼@ëû¶©lukÒcøå?,È9íw’X1~z•¨ 0%Ê&âþ]é×Apnj '`ûmë7îú¿c ܚ⡆D@ ÷êðçÐÿ¤Ø Û J›ÇŽY°x|•¥‡ŽºGŒ‚ܶwZ·=Té»0ºÈ|‡²K:/ØòOƒ‹•Úy·ÅíÖ©¦vÎ@Kò“Dn¤YC4 µêf/¸jñnéÉ©t¤³{8}6Ìn«”ÆD>™ñ×Ñ€l–u—‡Ú¬¢ôq̲œÍpsÛ§¹Hç>¡Â>xÌpªÐd„¶Ã;'o5Uxò< ~tDã2ÆàË^F“¤ÿØ#îßÖÃn@È„î!t[IjÖ-¡á2öbxé ¬ss"pµ6Þ„®ãnãgÅAu¦·³E²•Î=3æÎäçš pz›Ûáî¯Õ ˜‘œÌ.’²–ÁÁÝû6ÅÔR«b˜d ">y)Œ×äܤ'\Þyè,P¬ûhq«Ab«GÀ ‰Ÿ&1Ãȳ|’ Â`ëýáÆuOÆ‹¬‘¢©}½éqì1ƒPÊvxoEÁ×N™òG×î<Ô°ó ÛFX°,ekÙ>ËË7Ò,MÈ‘Üè8‰û[©vèìy¹oÊÝ((-{c]«Ç—ÙÙ¿/–oªä˜0Ÿ~PpKÅÀÄ„M>/ö?J…{±€„ùê¶6]3lq4˜Â,IŒ‚t€¨?Ø“oØb@ý8Î÷?Éšë_ÿ-í⸈†Æä×#`)MjA“`%H€î,r`·k\€ÕO–H D0AAv?tús@§¿Ï{Þ ¦™*µY…lA`)Ås6ú FÇÜDöÛÿeþð·2ý$~ôyžhæÆÏÐýwÄ}vëÃà*¯@!ÖóÜš¡~Pãs1´Fš0ìšXb1ÂÞà ì1â0Ë’ÙIl{Ô=º˜0‘™ò»vû/2Î3Ý bÊXFléNÿ;¶¡~”&6"&Ý{h˜Ã ¸ùIš…ÒjýÞÝþŸ6ÒÈRú•'34ù”š3TбÏlüÌG/pq™F9)jåž¡èØÎ_¦h6ÉÞÿ§ÍhuKÑ[sx¬í«Ê´¦8©@óQÚ…þâÕq½Ò]ÕÍ®Šz)ó,·O(J¸ÝÁý¦»{×òµ[`∺CȾ¡Ã“©7’æÀ*D\¢",?úѧؕԯ]zÛmÙiÉ2oiiå†ê¡4¯;”ãñ+È@$]þ¹ËÇq1¢ƒÍ¯Rݨg×ÿÅ|ÿ¦î‘r%H¤g1!ŽsBÖÄÀ{´ªþ,~Ã6¿N{"ÃQWuHa6`½7ÄÝmÛ½SºÒXÛëÿqÒýÅF×BÄ”EéáíÀ1ö((@JK#±¿é´·Z‚J÷fãÉ”×oêÅWE'Uù£)~Ìš(fè5Ñ[ÙhM‘€š‡-!B³¸{²‡-$àâ÷E2bíF^|:.uv”ì«êèU6Éú}E22»LR÷ß_dU_7oüâwñí»ŠÇÞÔ>‰ùPjVЄr˜¢õ]‘´@¤#U%ÝŸþ—¤¨Z×QÆ‚òxm‹¢»?íN?K7‡ãÏ燛&š‰î£Šhn{ H!qô6"H>Þ|é ªV1ã—gb=˜ú¡VK ”üWtx’0Î`‹4GñömÝø¨èz! ,H]W ï@r.äÒÙ#' t:0€)ìØÁWïzÍTz…ßÿËîÙË…Œ‡ÇŸ›dDBå¿vÙç‚'‚s\=ÈxŠº¿ëôš‚–5¡_œÇͯXÝ,ç$æõ;YüªÚ<µ$…¦Ñé8—ÔXi‰¦ÎxˆÊþâ•èj£vàè"«7Íä*ƒ=Ë¿ˆA»Û Ô°ú§!ÏEýN’½ IèžX{·òå¶+âiD” DÃö‡28“EqûVõÞ10wÿé@} oPËÚèD¸HMc‹EL+Hº=gÞËî^ÙÚÛGàZ3~1J>gðíŸwR8f¢—`óV ¡… ýÛîè¬ðÈ/¦ÉÕ̪C ›ÚP!U›°‡vk)Gªî‡AQÛwƒ Ö@W6Z°ËkÖoÃxyD’1ÍÎâê õ ”zü"k~aÅEÇdâ6ÿ¯<šÄÕ^¢¦9™±Töºß*ÿÚîä“©ËÑþ±É&âñÛÒ9 H·5 ÷ñsÞ­=£žMxšGÎã L{gbÊ#«wC´`ÈcÀ“oL¹íV¥q0˜×æèS¢Ûd`°Æåã€HžàFôÀ•”$;ßb½€ùùøÐm¼8¢ Èö­š}žª[ ­„ ‚Ÿ(òž$G`ÿó@N ›º(ÅêÖx¯ž!1&bD’8rNR@}_ýîºîõxÆÛÇ!E´pj…há¶W0Цn*š%ë$<ìö~€ýà[))ŸzWÂùq¡ƒùâ?ž­V (Glÿ§ö»ªÄ\ªp{]ñxŠÌ¡Gä§ØÁæàQm¶? zåðíÊ Ù3j¤{¯*ÓY/°+CÝš?u‹ß¥¡wýJN®B»×Ù<²'ÎIw€Ñ ñÏôhœ}|câ˜Kk˜ßÝ7,#Õª1ÄY.?ŸÔ»Æ¨åPÈ© ÎÇÇIõÑcqËoFZ¿·‡×ýñbü"ÁŽèÁ4K3zš@ì¡«a샆éó„hL–\1yÅO>z!Í`¡ñ;Ó{Ýßšhñžx8ä4¥€ùAš£OSe|‚=B.r!0°ªL0á¶é(‰ïVýæm[\,™c¾š;~ =þõõ­V>Ô]7´„ ”Ì(­EO:3`áj£óÄ‸yÓÍþ˜7·ª®á°7úèN3ª_«('è°qëM5~woõä$jÿª©'ú^ë5Þ-~—J‡0ä£g̨!P˜Í){dxùKGç>ËóÃC\`-gÙ1§ç$¤­Ñ¹>ú`\C¬{–‚°:TÛ$–O2HB1…4á˜b–“þA ´'_§ß•Èc"ãô8å‘®õüî–ÎÏ7Töû|üob"¡TÞU~v‘_ˆúΜþ^0Š ÑÈá‹ÿ)£§ LÀ柷ýfȯ’ýºEL¯mÓágǨ.Òãoèþ£_|1}öå¨Ó:‰pˆ½ò0€p€ù“Rƒ.È!èŸÌA'£ÏÀœ¹7V¹dë·&8S=vI­~Ö"áùdx@ç’#ÁDØŒ®32¥.…쌻üÿ…œûqnÈXIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageNile.png000077500000000000000000000634231375753423500245130ustar00rootroot00000000000000‰PNG  IHDR€€L\öœ pHYsÃÃÇo¨dtIMEÞ %:~¬ IDATxÚì½i³$ÙuvÎÝs©õí½fÅ`Ì ‚¸€¤Ä%$ʦC¶>øþþrøß8‚ÙŽÃ2mI$e’ A,3˜­{zºûmõª²*·»œãùÞë×Ë Ú–²»+º²²2ï=û^¸óÕÿ"""\=P Šá`æ” !PJ@ñè*D!ÄðÊÌÀÌÌLD „Î\^yyÁå.¿ŽˆÌL”˜éòS¾8^~÷òzfº¼j8ùÑå†Å\Ýã•Û"0ã•k.W ÀÀT×uÁ9gŒfRâå>†§0 ÿà|kp¸æòéjx\yêå+°¸+k•R¢|± ¼8†µ""]nþòÓKd =þ¸DÞÅÒ°ø«8"BW1wùõáõ*ž€/<Ù§oˆ€È…BJ9À0Æà}PJ•åH*•RŠ1h¸\ÞÓ"ð@‚ˆ ÌÌÄ+Wˆç½¤Ö˵òÅŠ®RÜÅííg8 !Ä€ƒK”œßíb•Oì€ÑèÓ9éàc{cæsð\ p€òUŒ^½ÿå ŸàÎ+xâ' N<Ú< %Q ”„ÖeJ)¥ÍÀ‹R*"b¦'¸€.!Šˆ6 <ÿåJžcþšÃÕç 8xRÔ^¬‹Õ_¥¾«¤ý‘^%ç'çúÌŒøØ‡W.{Œc®âò*iÉWŽ«P¾<ùÄ …5)Φ”RJ„Ôc¢ Ô2ów&b¦4È€sB=_#_`}  ®nì ±€(PÈ«P¸à‹û§Åú%žŸ)ô/árE¶à3áÂðlî¾z1]²Ë寮nç©Û~œÄÀG ‹ÈÀ!†s²@”J3³™ˆá1ò¼”´)F&d> qމK¨^H”KŽT?‚TáR”_Y× ‚ÒS@¿Š‰«o!ð4.á>ÉÀÃÊ?8¼z‡«¯W©äilÁ':xé°8f&f8'@€œˆø\ºã#òxÄX—‚.eÆ9ôùÉå© M;pÜ¥Š@DÀÄÌR!–¼P=Wü ¾Èð‘ñHPž »K)aí ìr.|žÐ¨Cˆž ê'®yúŸô ÀÀÈWíŽsÒd`† Q€/è.T02 ˆ(*yÁL.ç9ˆ€ã1ÜÎw‚ Iˆ‰@i9è¿/)“/ø8DÎá;üp©HŸ&Ç‹­>IæOƒéYÿIÉüÙ”?Häó7W¶ÈðH„ðQŸˆ ©rU 1ˆƒìšáÀ |nhÓÊãVГË"&")åd5èɧåÏ'¡¾OB°ÿ0Çcšø™çŸ±@{n˜i­µñ„Íýq›Uˆø±Zé©„õ•ŃüiYücqð‰þƒÏNƒ€½„ÉÓÒòÜ[ú‘¦à%ÐÔÇ AJ9 ´ÖçXé);òqc®Òú¥²}ø¦Î¥û‡`x¦|úüzèª]÷ÔøY ÂsOpð‰Î_u;~„‹ó#6rÎÌ,ÄcÎð¥/6±ƒG>°UŒq åŸ@÷EþX‹ÿÿŸÇ%M«Ѓn¾<8{¹«Oˆ¼Ÿ~6ÖäÿÇpÀÌ Pà¹~a¨3°@‘˜"¢”¼÷D„RœK°+òñ2?Šmþc€øX=²h”ræáÀÁaÌZD©Îƒ®Ä)%`ÆGÖ÷ XùYr“Ÿ©ñÿÓñÈ%¸‹B |éü\8{(„)…RC¨3QJç!åG®ìO!jþÓñDäF¡,?;8(Äa¢#¥ô Ûöj@ä?n™þ—Z%ŠÁÀ¿L›  ¢!€J1 ñ?Ï ÿ§Ï0?3"ýãuÃã×ü¿‹‹~ ý뼌¨+xžnLçÁÈGÑm”’b"&¼€þÇxñ®õYºáÆEWÞ|ŒºùYÉ´OrŸOô(üI¡r EÌB `)"Äù"×™¥”«…€ø§ÞþãøñÛÿ¸}}BüXÂü™)'þIápþ¥¥ÒW aâÜã(Bð“B Ð9íÿXè\<ùQíâ%Áže $Y¢gHX!ê!ÓŘŠ„ ‡ø:2 H PŠ12 2"‹IËøÔ`&ñø¥ àgª®DC™‰‡,¯@ ”À”És`2Qú$üxAqçðÕ”‚‹  B`ÄçÁwÉ,€1‘1J b?DÒ ÛYÀൠ0žçø`Ϭßyëÿhê•ýÿk¸}cïsŸ} ˆ?üè]€&Óª_ío_ÿÃþ5ë&ï½÷Á¿þã?zG–;};ÊGÛ]‚E")Ÿ¹ùg[03µ‚[f)rB!¬€ 'ŒWoþ¬| 9~ñ×ñ©ôᥲz6bŒ!ÄKkg(^zÒBzÖB™!%ÒÆ Pª»“–aéÞk·³/¼¼…ëï~ë?øãCŽ›e½ÊËRªÐj—ÿíÖm˜oݪ–ððÁ©ÖV"5]{hdõ;¿þÅϽ°uçÝï,ÇRY‰Va&ɈKuzµ´éê6é¢þ'¥DáŒâqߟƸqC+$bˆ8äí.ËupŽ|Öá©´âåG1Š`Ac$§¡­…@}ÐÊ(T]]k‰N"+Ýâ,†\6²=,yqòÞ_½²WÿW¿ûÚ¯þâ+ÝêÃoþÅ¿³ ú¦ÕÊõDºÈ¤ÐZÂÙl6›' ”î#¹Ò¹Ì­«³2³èƒ†4/ìoþê/=wmöÝ¿úSêjˆÄ(9Š…V CꥄHk£|×qð##e·¶±«|ûå[ Û{9žä¦P´\œæeéC$ ÁC‰sb?¡qŠqÀymðŒ{\’ 0QêA1ŠîÝùî´è¤H‘”Ê2FµÜ´./”Á®«M®£¯ l¸ºóÍkEukZÿóß~ý‹/ïß{ÿõ?ýÑ›o~¿÷Ž`®«% ô½wJ—FO§å|>6Nž¬ë 4~³Ú¬š¦ùÊÏ¥[··®?wôÑb³©3Ã…ì~ók_ØžÙoýÍ7Æ…­}+m.…MIk)PIÄ®ëÉÚM­!L\JÕ{aùf¿øÞþ—_½1 ¾ýÃwîíŒú¾Ù¼ôÒ+‡‡GÊJ€I2!BdA„ðwVÎrüâ¯ãqñq¸Zà" RøÔ#¬tz(ü‡›fYÁ"/Œ Ë>Ò&.~àÖoŽùè…møênî¥iI¼û·ÿêý£7ßz/+v–$0‚Ͳª©Ñ}ÓZ­S¢ñxÌÌJi`²,ËŠÕj•9C|ïí··æ[¤Ëõ¦>ëúÕ¦YHERãW¿ö•ã;§GKòJ£dŸ †¾J3åüÉÑΛ³w«“ï€ÿá¯ÿê7>—OFðïÿÝŸþÁïÿÁ¯¿ôæ÷ï£i9žÜ¹÷žM{rÄ¥Ì(’Aü J7ðúoÿËA¸= èáW-Îó8µ@”T–8¬\º¿oÏþÅïþÂ_ÿÍw*þÎ÷~`³q ±wZú•öóøÒµIfUh;cåz³úÿè¹öÜ|±ê# &&Æ7*NOOCŒJˆÂZ-ÔÞööööör¹ôL­o# b@1ƒ"SF„øóo|Á((JÕÖg¹S1Æíƒ[‹u*fךTþoÿç_ûoßn\Nw|mtµ® jSuüü ·®o)ÕLÇBòf³8|ðð¨kñäè¬Ù$m ЙÌ3Uä÷VNŒ_CœP²R+”QkEIŠ¿‹J¸Êø0<;è6|*XÀ±ÚÇõ_{ýú7þø–«û¿øÊÁs3õ¥÷þÑ—_ù•Ïß~ãötG¬Çª×Ø+„Ùt|rzúÇÿþOÉÈet–¡”Êèñt( ÷öö¶Qj6žhãñØ{_UëÆw!¥˜@imæ½Ï²L+•9÷λïJm]V:WŸh¥¿÷íï¾ñùϽû½ïm|õùñoýõ­Ò·«wæ£v»ì>ûâä³Ï™ÿì·_ÛÛä³;ï¼µ3šÎóÝ?ù7™åeà>s£³Åº(F§‹I©¶î¢-ö!©…Í2†ˆ‚Xâ³ °~‚ꀀ«9â§b{5º\hs„¤9LAÓ¦{ÏmÉúÁ½ÂÚ¦onÞJœ,NOOOêf“R2yyZ­ÿÃ_üõŸã[o¾sw±é³ÉnŽ}ßÚ,ë}?ͼ÷yžw]7-Ëܺ"ËÖ¤ŒÑÎHcbâùdqªµR @J$><>]¬êùöΫŸùüÃ')Á[ßëæµŠ©«–äûе³Q~úà£Wž»uç­7'NÏGyQæïþð?¼[¯›‡=üÂë?wãöÍ£³ãíkÌ8žNö¯íÞwF”“¹ï13#cËu] …À @<Ëz<7k~l"ðÆïü÷€â /ãªz–9•˜$xÃaýw~íç'¶ý¨}pb‹éÝÓaµgβ¼Zoú¦MbìªÍr’BŒ³é¼ö Is+µH˜e™±†b’R6MÓÖõþÖVf-·¾ocð{Š}GRXãlJ˜$0„iƒRûÀû×^}õ—~îKîÜå8ú‡N¥‘÷ŽÞùàƒç_xáþGöö>úð¾ÖÚ*7CßömÿúkŸ•:ûÁûïïíît¿sçNô!ĸ®ª_}ãí6Ùä•UØ7%…B’¨YØË*ÄG¶"üN›œ¼üuq^……W[ ~ÄA20¼ðÇqóæïÿãWSw²<­²Ñx6m¨÷§«SÀ„‚³ÌØQ¡‹Ì W”¶ÈUŒufa”[«­÷½µ¶­£”ï½@H!Œ‹’‰¤”‰ú"²f]Õm×Å…@‰|߃„–šííwß{ÿÍ7 Œ~ñÅ¿ûï®6vgçßý›£úT—öáÙ!a¬ûZZ„ž»ÉdΘìí·Þ=^¬·vö¿ñÍo¬›åÏÿÂÎV«I9ïšØ­W_ù…/½ùƒ»¶ØÕy™ˆA ƒÐ€ê‰:å§-Ó“M»õ{ÿA–Ñ#¤¥ ‘Q€, 8#&‘ÉûvÌm\¼ùó¯eÔüÐÈ0¼÷Á½ñ|r磻>„Äd¬SÊ8mÖMWNg)×¶mꮫ&ö!4}cèû „fÒM}H­oºPw}ƒ’9V×÷KèW±ïdPMÁ+% ±ÀŒ‘¢`’€ŒzèÝxZ¤Ëé+¿ Ø6 Aû(Î%ÅLu‹®^fYÑö$Hà¹?aurïÛ¿ókŸïëC­ ¤ò,òr¼×ƬV+mÍz³ÖÆ03Wë 17mç²,¦”ˆP˜åø™Y[R2ÆtM ÀyQ.W«éd º®ŒÆeuÓ2@žMÓ­%BJ©$"mLL)¦ˆÚ˜bïv”RŠ‘A"î{?Nëº.ŠbµZ ÍxLTo“ÍÝTJ›g™ J`Á'§Ëº^?ÿå/f¿c¬H ÅÖ¡MB™@õh‰‘cJ! 5âЩú´nãCr‡8â\ ‡±5|¦ÃG¿ü…[ЯVÕ2ŠÄ”zÅ5ú³,¿ÿçÿìÿÂsûEŠ+ürÓ¯ê媊1ðÐO¥äx2Yo6Ìœˆ´1!Ƙ1£J@ð1H¥š®C!bJuÓ@µÙ()ÖõÆ÷=‚êº^+Uç¤ZmÖÛû.sËåÊe†{ïC mð}èA J( %×MÝ4mQ]×­×Õ|kÖõ5Z,ò|¨­\¯7}בֆˆû®.Š2³Sß)„ \®»~€ÃdRzïÏ«?|+·ôK_þôñÑÃã£q®S‘ˆ9F$B`d>oí¤ËpÃSf(£.&ƒ¬!vcWµ‹o¿pÐ_+û“»?ìš 9õ¹îxó¡ñ‡X¿ÿËoÜv²íê£ÃÃûw>º÷àô̳0Æ8£“v¶ëûýýýõfcŒRãq–ÚX‚˜P*Y­×Y–÷ÁçE‘£²ë{%•Trµi"Qf­Vªïº2Ï„6U×Öuã\MÓ! s.¤˜ ¡$TZ )#¥”h<™H©´ÑÚè®kc 0qJ1&­53L&Sk­RJkR†¶a «u& I‰:¡ì¦M)Šh”eFááýÎíÍÇÏ]ÛýÛ¿ùÓi!jÁ½fïÇ®CÃØE— ¦Ïè–‘ã—¾.„ëZtƉ°Þ5‹{ÿ÷ïýús‹ùáÛý…O¿´©NbWÅöäøÎwö§ñ3·Ë—?µµY~ÔÕËïu}§[Û, 2#21@ï}Ó6uÓfyÆ€ "/Š˜RÛum×I¥ËQÙ÷ý|k«÷^iCÌB©ãÀ1‰(+Kf^.WLtóæÍu½Ùøž„4ÖúˆYc­kÛÖbÈ\Ætþ'ø ¥¬Ök¡dŒ‘Rrþ ¤,ì¢(×ëuÛu}ׇCˆM]Å@mÓ‡˜€EZo>´åh.Ð9Ut1+ ²)ú“£‡Gýà?ÿ½¯?|÷מÛÉêèÎæø½­yb¥µd£B$"dB¥‡:óËú+9zñ×}¼,Cýð`Ò¿ÿ'ÿâŸ|IÓÉGwÞßzûóÙd”©‰£W_Ü¥öøè轺>^oÖ«jåƒMgDX×-02PJ€‰HHI Œ,¤ˆ qµ^‡˜\– ) µ];™NVÕÚZ»^o´1UU'“>c] ±nš¼È XZÅëª1¦$¤bbDa]Öu]Yæ‹Å©VÊ÷}Œ‘‰Œ1e9#úÞ@fmž¹à=!¢>Ï‹¦i2—¥”œsÞ{­Œ@èúNHÊK…Â+…Rê"ÅÄ(( @ÅBlÚ&g|ßõgËûŸ{õSVøk[ùŸ¾mhµXÕ`Fm_3‚¶.׃x¢ñåøÅ¯'žšq»üðÏÿ‹ßüLËãÇÛ¤ÓÓ“åéátb«åáwßEë.h«ÑÚb2™1‰Új¢ï}+„ 1FJ}è¥RR+a´Ë\&¤DD%u¤”b2ƶ]ëCBúò¢ð>0ÃöööºZ¢±¦éÛâáâXhÑÅ ÃP2#$.—ËÂjµ—EßvÖZçœÖZ"ï•Ñ!&ç\×µ}×3mom«‹<1¦D½÷R*!ät:K‰””B’Öi2sJ¡1XuMý*†$¤ÎGcaTà€ #cÓ{abJ}SW¿ø Ÿ»ûÎ÷~ë×¾òÍ¿ýá*hãlb˜‘3¢ˆç%n öœ¿úkP¸+´÷¿ýO¾öé Ö±ß,«zÝ„»‡G7o?—i£ˆéèôøöó·"€¸»µ=OÊ¢,Š2¥èCÏœ¤’)QB@k´ËÜzµ2J ÁRa–»}L‰ˆ\æR$mÌÐw>H¡˜h½Ùô>dyÑ4µÖg£YÛz©lL”¹BJéCPR¥”vv¶‰èSÏÝö1\;8ð>ô]'PXcRJx°•2sÎûÞû"Ř˜ ï¢ˆ1!¢÷$Ü8躖bÑ)3kæ[cgL‘}¾ë}×j-C×åÆŒK‹,V''Ô÷ǼôÂóÿöÿ÷[·®_۟ݹó–4…$” U Ak„ •  ‘—ÅÞõ¯¿¾5÷w~åç ÑÕë³Öû“ªÚ¾ys]­}Ó2±6¶nÛƒ×7M+Pܸ~½_7RË̹ºoÖ›uÓµ½ïXH­@ADÖØåbñ¹×^ˬk»6QêûÖ:³^¯•VBJ—eMÝ(¥ûÞ€²ï=JÉé<Ó LH‰_¸ýÂéñÙÞÎÁééBKLRHg]Œ!ËÜjµ"JMÛVU5Íšºö½¿èÐMÈ*™9ú¾®7£Q¹µµ5™Î‹U½i¤TãñxèÿÙl6ʨ¼,Ï–Ë¢um/ R Æ Öz4šgãI»^;£Hä›M®øð+_ùåŸ{­6/¿ôâ{o}ëS7&¾YrÛz£ $æPFÁ̉@I!D’“<Ýœñþþl<²£‘ûæ7ÿò¬ªÁÃÃã½½ý²ÈcŒ!x¥11@žç‡‚BÊÈbHÌ‘©A+Ã< ˜âË/¿ôýï¿é}/¤PZûÞçyA‰R"Œ1yïµ6BÊ®ï´ÖÀ}j³€R2Æä™;<:ʲ¬iêbT2{ï뺾qãÆb±pÎ)¥êºfæÍfC)Q¢à{&j›V=ßÚšÏçZkk­”rµZ­×5w]/ )bŠÆ˜¡E¥Ú¬o\»vxøÐ#µ²ÆdYF”zß½üòËßùîwæ[3m¥RÂ9mªë곯}æî»7oÞøÔsÏ-ÏÎVËe9}÷oßìzû0)Šƒ@eòÒsÇ2Dè#·!µ‘<%’¿ó+¯|îµëüý›ã“û?øÁ÷v÷÷&óÙý‡Ç»×?¸óAî†`“B)Ú¶­ëÚe™1¦¾‹!mšF-”RJûÞ§€˜îÝûp:®×"6M“eY|H‰bŒÓé´÷¾íZ)„ DƘØ{ßvZk&4äl:}øðp2œ-—ÄœçyžçÌ<ŸÏµÖ}ß+¥®_»ÖµmôÁ;*GÌIHYoêÓÅâøø¤ë:"2ÆÆDÚÚ¡öi¾µe­ÎfYž7m»½³ûÑý{{{{ëªÚšN‹"¯ëMÛ6Û;³wÞy{6›-ΙsãI!0ÄžÿTæì+¯¼ìŒÙl6õ¦vÖX—}tïðôá}“º­QÞ7M>w1%TŒ"AHìQòPx!ßxýÆŸýù¿­Ûš(\Û;>9©»^H}z¶ÜÙÞ9|ø`ÿæ­[ÞûЇeÙÂ^×5 ©­å‹èF"j»5m×ö¡O&MÛeBpÖfY&„¬7õt:ó!0q×÷BÈñhÔ·RJEæ²<Ïœµ)F!$u]W”eµ®ŠÑHkBèº.„p||<´¥gÎ!Àƒû÷‡ v AI¹®ªa¢ÌfSÏfó“u0XcºBUUÍçó,ÏŽ»®ó}ˆm×eѵV*/rèû~¾5 ¡ÕÊøà‹¢ØõÍÖöÔ]oV{»»C÷ܧk6MSw¯¾übl«/¿þšH}ð/ªežïO)!H ƒŸ–HZz ÎɃk ¤T„Ê0S]¯oݼùÁÌæ³¢¡šA0±R&±±QÐy0Cç»Þ÷Yž1°Òj ´àÃx4ºyëæî2³RJkÃmß!#0G#%dßõ¾i%жi‡YSmÛdyWzÒ»®ëºn@EѶíh<€“ñxhkc"`ȳlµ^àfS‡wvvOŽOÆãÉÉÉâöóÏ'J“é´iš®ë¬µC‡H!•d¢HI¬–+"’Rø¾)Ę”Ô>„cÝééIž[guî²uµ†Õr EV T!øÛ×ö1ö_xã³Æ#ô¹l IDATêoç[_üÒk'‡^à®"ø(™äý_ÿæ·¾+$*m„Уɼa½Þ0°bÌUUÕéb1´‰õ}/¥T(µ™uˆ¢mZï½@Á 1E묱¦ï;­•"Æ …(ó"1‘”ʇà}0Æt}¯­¥”ŒÖ£¢ >Œò|k>õÕW…ËåRJ1¸u(\´L€sn>Ÿ§”NOOó<_œœ Ä0‡8%JÔw!··w‰—eÙr¹šL&Œ|V­¬5MÛ!A RƒR†™)¥<"Ä”D‰ Ërì},ŠÜ9W¹±*sv:™Ü½s§Ì‹Q9îš.s¹”¢]¯Û®>;;;[ž¾øÒ [ª““%HØ'`Œ‚Yþ7ÿô—VÕÙ‡‡ η÷&ÓYL 3EßûñxÜõÝt:b5ÌÙ,ù´Yo¬uy–ƒBŒ6yYæyî½wÎ :C*©”bA°8[Ôug¹µ–ˆó,gDãœÑ&†|ŸzïŒåzïÏÎÎbŒ‰ J­˜9ÄHDFëÙlvrrrvv¦”ÇeYú¾ßžÍ–gK¥¥4œ6Á‡<Ë6M³Ùlæó9"ö]÷Õ¯~õþýû.Ïðf³P;Õ¾ïA ‘RJ"0‘sÖhe.˲¶íƒ”À¹¬íÚ­­-gužYBnÍ·Œ¶J(Jlµ>;]TëÍõ›7»bêŒHèׯ¼öÜ¢9]œ•£yÛ A@y0Mß~ûíéÖög^ý4o6 6J!¸»»Ý4­sN3DU±÷A*íòlS×›z³©ëD$¤ ]ŒJ(ß{etŠÄ4MSä9%ªëZ ¡¤ªªÊÓ¶mJÉZÛuRÊ:WE]oB”’’2„ „ìû^ ¡)ŠbPÞûíííº®)&gm×¶Rß÷D$…(˲®›¶ír—w}¿iWggË®CŠò¢¨›&Ä`¬9=:á”´ÒDIk“b€b ~«7ëºp™ÕÆ[äyß÷¹ËBßi¡´Ôuµ¶ÆE‰ÄœbˆZi¸Z,3ç´T¾ëÚ¦µÖs-µVÓéøÖ­›£ÉØy^”Úº¡×%îó77mC)E®P È2ÀcJAk…B³T ˜5›ˆ‚Þ÷QII)*å½'¦Äˆ9+¥Äý@Ña°}?ŸÎú®€RÈ”¸,+Fåjµªª*Ïóº®wwwNËQôᳯ½ö™W?ƒ›j(ŒÒ(¥–F X75æeIÆZc­Ö:¥D!j£ÏG0 "€‘šRŠ!ƲˆûÛ»Òl2¹qãÆf½A!œµ c(²мÐJ'"L̉¢µ6³v<÷MÛÖõd4FMÝŒFcfšLÆe‘_»v°»»½½=W. Òf€Rh“RJ€¢Ìr+¥`Þ,«Â$/0%öA2(%…@)ÄÉË3Wæ™’²È‹QQLÆã<Ë8Q™ãr¤„D<Ú„”¾¿À Q–e1ƾïëºîû~¨è+‹¢k»®ë¤“É$¥d´öÞw]c4ƒs_×eY.‹ƒýýÅbãÑèôääÏþäOSŒ¿úµ¯!@³®><¬6›ýƒkÒ˜ÒÖöÎîÎ^h{+UníµƒƒØyƒR&f5ÊËæ†,¦“Ižç¾ëcL>ÄwÞ}}ŒU]/V«MÛ„DËªŠ‰ )&@1.˾ë‚6Z+M‰ŒÖ³é,ÆT–£Û·Ÿ»qãz>Q"JÙJ-ˆH¢4µüåŸ{RÊíÙ\*Ud()HJ )„R¢¡s(YŒ!u7Æd™Ëó|ì1FÏ)^̦” ÈòQYv}? œL&xah‚(ÏóÛ·oÇÛ¶½˜M-FãqLI4ÆîììÜûèÞx<>:>VBŽËÑÑÑÑÝ»w ¦trrâ½ßÙÝDÂd:Y®Vûûû§§§‹ÓÓñh¼©ªÒåF›®n¤’0HN£õЭµs똥4FoÚº!R"æñdr^ÅDDÌ‘Hh5žLŒˆ˜¹,¶=ìïîNÆ)u‘—¯¿ñºµÚ¶Ž¡w™•¹†dB J DD ù»¿õ%Û¶uÖv]ß÷”2† ”0ÚHTœ8Ëó2/J!TŒQJUäÙÞî®÷}QÕj5š®‹LFk¥Ô0'„@ÄR+)Ï£:Y–­×ë®ëÛîܽÛ6­Òz(‰1ùHuÓdY®¤:|x¸;ß©«Í|2SR Àeµêƒ7Öö¾'f@ô1Æ]æBÖ¹®ï@kƒ»¶K”VÕÊ“e DfN!"¢µ6¥¤¤e×¶Ffˆ ¨dÑ÷]ž}× ”Ëõ&!.ÖkB`DfâÄú“ã#Ât6µ™SF¥ùt’»âå_Ì›j±YŸNÆÙkûF %…ÓJÆ•TÀÄò7~íóÚ¨Ðw]Û¶]§”Æu¸Ì)©‡ &è[/„ !†>„QŠ“““¶mN‹Ùlê}?CŠåxTEµª”ÒιD¬´–Rö]眈Cq907M3Ä*””LÀÄ”ÈhcJLJëÅb©„,\V¸LKB².;[.Ñt:m».Ähó¾WJ%bçÜ0\bkkëäädþMÛlïlw]×{ŸeÙjµ¼åA /øàû>†À RZiôYµjûn6õM—ÛììlUΦ«M­3·n7ÚHƒrše£<ßßÛ³y¦^œ-NNŽ…¯¿þúÞö.Dfò™ÅQa‘FIg@)¤‰DÃDû3Ë_ùÅ—¥D ÖÆH¥ÚÆ…®« …À!7ÂÀDZ)%#ûcŠ£ñº®íûþää$Ò0h—­6ø|ß{"êûn:™,—˽½½ù|~Þ†/Dæl×´P…@‰Þ{%% af)D–eëÕ:¥dñ}8PJ›õZ qíà@+%¥ì}² 1Fïýááa–e›ÍæË_þòýû÷ÏÎδÖι¦i†¬À`Ÿ´m{nŒYË̳ÙLŠ¡JÃ1€µ¦kÛýÝÓ“ePŠLq6¥Þ—ÖîílgÖt}wrrœå.sn:ìïk¥Æù(Åà};9­d–YcŒRF´>*ôG”_þÂ--"Ä'ãÉl>÷WZ÷}?8P!†aÅ˳eßwɇÆ÷M×"‚1€ó<+ŠÂ:›Y›bJ1N¦Óâ åŒ1ÎÙä3SL]ÛzqŒ˜Š¢Q!DÓ4€Y fÎ…º¶ÏçÄ´Z/¥è½/òâèè°ª*£ QÅt:B´mûüóÏWUU–å½{÷q>ŸQ³,[,£Ñh2Îf³Ú´ÖmÛN&S­5 NgS@.ó¬­ë×?ÿ¹vSK)¢oµÀqž‰·'ãQž•y¶5›H%bL!…¶i}ÓµM³¿»›;Ëó¢HRœ· HæÇ I…òw¿þy!Dî²k×®ïlï cµÞ¤˜BðÖ˜vSûà·¦Ó¼(¬³]ÛnÖëj½)ŒÖeYrJˆhŒAD˜[zß·íÅü~Ž)RLÎ`F>Ť)R‘¹CŒR’RMÆgÝ×™¥8›ÏªÕŠbrÎ6MÝw]–eFkcÌÎöÎöÖ–@œMgÐu½unP-ãñ¸®ë®ë†É/1Æ”’Rªïû”’ÖÚ3N|ø`2û®«g7nÝX,Ns€ µ’B¬–ËÓºªNŽ…Ëå’( ÊñññsÏ=Bˆ1æy~Ù,¥”Rj­µÖƒ;BpιÑh$„0ÆÌçs­tU­¤V.s!xkôj±¸qýÚ+/½ HàRëBi§äÁÞ^½Y5Õrg>±ÎM&ãºm‘…tÆ=| %Îç€$¥ætŸÏ?`¸B¾¶ßúê§·æ[E^¾ÿÞûƒ ? Ѝ«õ¨(RŠmÛ­«JHùч÷¶·¶RŒSnmfŒdT(¢ e™€SL'‹Åf½1Ö8ëÖ« 2çq:¶mk´vÖE¶\ž ‘€ÁxµÖ,—g7oܘÎ&Ïݺ}ÿþýѨLD‰RÛ¶Ûó­Éd “餩›<ÏGåð Ï¿p÷îݲ꺎1^›ß¶íÀòu]¾…”²ëºÅba­],}߇ŒÑmÛÐl6ÝTU™gãш£JFˆ›û{£ÌnO§{;[>t“2Ϭ Áûïܽ»^oF£ñµƒk)ô·o_HΙz)ÄÐmte0Ø#M ÿÙ?ú’ïû¡:lÈmc)%k­D•yßõBÈ<ÏVË•òððpogÏ)3ŸÎœ6Ϋ´U:…Ø{ß4mµ^—y1šŽCˆHú0O¬µY– €˜N§UUµ]ã»¶©ë¶mP+}zº@ÄèýdTŽÊÑx:éûîðèhÈyQ×5%*Ëòèèh>Ÿ÷}ß4M9µ]|||ûöíÕjuûöíº®‡¡ Ã46)eß÷eYN&“ÃÃCçÜ £wÌ{ŸbÚÛÛO&ïX+5›N—‹ÅÖl*íÎf7ööœP¹Ó™³Öh«%{o¬­êõ¦î²,ßÛÝ›ÍæZ g‘™Œ—ƒWˆž5ÐAþþo|~6ßzxxì2g­­ªÊY[­*Î\æœË󅨪j6™E¾¿»[-ÏbfµÓj2* gw·æãQN1Z­(„D‰RšM§Fk¢T7õ¦m@ÀÑÉñl6¿~íúñÉ  ÈóŒB‰´u$°ó}V!¥µË²ãÅi–g«UL»®“ ðølˆÆDè»n>›t]çSºyãÆé驳vµZ ?‡‚(¤’CØ9] =íûÞû^)é}ßum‘g@4*K&Êœ«Ö›³åÂY{ýúµú³“ckõúlÁ1äÎùÐmšõÙòôðè~>*šzSN§‹jí.ÎÖ/¼ðâÍ·Úºñ¾ÕRd™¥˜””. ³/fû !äüÖÏÕu“RJUUíííňÒx4BDk3×u-¥L) ÀÅééòì8³ (ömÍÈ÷m™»­ùÄ[¥Øto»“ÓŨ]»q½éjgmßwóùüììLJµÙÔÁYG ¬U|Y®ŽUÓ„ýƒëmÓNÆå|6{ÿƒ÷¯ìK@( …IJ9üþÃð;4òw¿öªuYÛwïwÅœµFkcôlúÿôõf=–e×™ØZ{íáÌwŠ)çÌX,²DR¤Z”(Sƒå ø¡[R«=HTÃ’_lÿ ÿ~²Ÿ ðÛwÛ­n©Õê’HªXU,VUV‘1ÜñL{Z~Ø7nE•‰ÈÈ÷œ³÷Úk}ë[ß7ãÈ›Í:x/IƒÒ*3Z+S”3äE™¦È†aô!ã8ŽY^A8Ë󺮟?{Þ®×îÞ™U¿º¾êúí0ggÇÛíÑf·ÕFsì»N‘€édšZð @ÝívZëÙlîCÆ!ßµmSUUQH¥#cÛîNOOËÊZ»Ûí¬³>„„™Ä-”RRÒl:=Z̳,C;Z­Ô׿þõ‹Ë “e‚ëvM^„qüöÏ~ãñ»÷OOÓÉòâòx>[__@•eÃóO?Ým¶“Él³Þõãp}½ÆŽÎMUdFÀin&ÄùÝÌ”í'ú/÷ß½}öüÅb>pÿþùùËq””R’VêÅ‹]ÛJ"€èƒ·vŒ!ôCçƒ$àåËó¢,”R(Hk¥%ey¡”rÞw}¯µÖZ5E~:k‚fM£^]\Þ¹sºm·MY1ƒó^g†½÷JJBa­UR¥Â-ë´»¶õꢆ“Ó&ïß/²ìÃ>®'SÇ1¡R)î3€”2Ý÷º®¥”]×Å¥¤Ì˜ëår»Ùzç&“¦k»v×ú軮ˤ8žNOšÉ“;g¥T¾ëŸ<~ô£ü`ÚÔëåòK¯=©‹âh>½{rz<Ÿ,Bȼ¬\ä¶k‘ðÙóO£÷oùKC×j¥(éKDDoê{eVDúÏÿ“¿½ÙµÚ¶ã¸X,¼³Þ»ÕjÕµíØhŒ ÁÍf3"œLIjÇ4Ÿ&%åY.I™n &χ~ ¢Ív㼫´òm{4›WUyçìt6mVëõb>]^¯Hê#†‰$DÎLvuuyzz¶Z­RšEQäEa²,5ú³Á»Ýv+}ˆBÊT¤|_kíœ#Iã8¦ÐBpÎ¥ÿ"É‹&­Ç¡ïaÇ¢Rpÿèä›_ýªf΄Ø\_ΛæÙÓOá;¿˜i£JDBpÃÐÔU¦T¦3eÌàÜ~˜_ãµ£ã£Ó““*Ë´"ÄyŸ‚ø9£0DúÿƒoUu½Ül…ÀÉdÒum‘ç&3»Ýv>›m‚÷im !? iÊÓ“ESvìëªààš¦Ì3- VE) Dëýf½&I“é´2æÍ×_+ŠÂY·mwJ©Ùt*…hû±ïmà¸ëZëlêyi¥ïÞ½ë}HZQƘOÆqÌL>ZëC0™IÃV‚¡Ýn]ŒÃ褔RÊ$ÂVÂ8'“IZn§§§eY&¸Â:‹eQČɌ1ÎùÅ¢)šå£ã“¯¼þú—^{RæÅ®Ý,NޤRÚ¨ª(Žó¢ÐJ)î»6rpÁ£4,hèûW¯Îæóy3É2ƒ’Ú'AØ».~&ð#„ ÿâ{¿®uº¶íºÖh-Ý¿/xß÷ýý{w9Fï\YÁ{!ðÎÙ™D®r]Ù¬©^{üèþݳ"ÓJŠºª2£c ›Ývµ\9ïÑh•²þõf³ëûÜä(Äf³Œ$u;ضíFo§³iŒ1ø€——[¦D;LÖyžÏ¦s$q½¼¶vìv»4Ójò|µÙVUÕu]:0œs©ø 1&—”r³Ù¤´€Ë¢X­Vprzjû¶)ò¯¿ýv“™B«‹‹ ÆmYà«‹ D$.¯.Ê¢È3mŒÉÊLgYZm×/^¼*Šâѽû/Ÿ=ûêÛos C×rð¹1 ¡ DLÚ“· ðè?ýÍïXçó¼tÎ^_]))¯¯®´RI¹LksþòEže³é´ÈóÅ|BÈ,5G7¡Ê Ä)™=ŽVkSVÕ8Óù|2›õ}b蜽ÓJ¯7[QœsÁ3 çœR 8ĺª‡aÜ7‰Ú¶Íf¯½öÚùËWƒwíN­pÚ4€IÊ„–Søf¥¯L&£µ‰vã0¼:µ˜Ï³<7ÆÌ§ zû­}ùìùdVÓj7vP8ï„ÀÌè³³c€èƒ5™a¡ÔjÛýäƒ¿ó ¿øàÞÝ×?’B Φh¬”(P$ Àþà·¿«³<ÎóœHl·›:7ÛÖÒY[–…1úåËyžžKE/.^ž/¯Dfº¾$QÐØõ“fbÇjm”ÎÊIsqyùêå9 Á€È°8:’Jë¦I“Ú¨fR/WË9n·;!…1™@á¬}òäñr¹ìºv:\\\¬×ë£Ó£Ín]4å`{ë, ìQÒ8ZðÖµ] ÎÚÉt6Œc•—v×åy>t½RÊ9o­õ˲ÆAÔDîœ=¹? }.„ï6góipn:Ÿ ~Ü´m?öÞù«—9ÉI‘Uy–k­”~u±Ty-ef#_¼º|ôðq»k‰dôQ(ý(­‰ÄÈ!ïíþÃIû±?øíï#ICBÑn·ÓF›,€²(´”}×Y;ž•e9tÝËårííõj³ëǦ™Yë•ÊÎ_^€”(e; ×ËU‘—y6›Cäv»c­õ8Œ>x“emßm¶[©D•›í®užó²F7Íœs«å²Èóëë«ãã#ï}ªxµÒÛv£ŒðnDŒ1z!PCJ ±×PÊLÖ4Í8X©”É ¸ðèÞý“ãã"/¶ë.2!D7ôÝn÷kßýå~³Þç‚Þxð`^äï¼ùºA>™Ï/——”™Ö'§§Ûu+QUY~4›Y¦•r.ü›¿üA6Yüå{½º¼zýñ“ç/_žœýä§?õ!\.W§wïJ)¢³(0Ähˆ€Y"@pÞûø×d9$1ˆDršÍfÖ»«ë+"*Ê2†àܶ½{÷îÓ§O˲ 1¶»]ÞTW—M]_,¯«¬xuuCÀ¡;Z,¬µ]×…Ç®ÏÊr:™dy~}½´ý`’$Ѭ™\_^q$ ±Z.«¹HÓÍjm´*мmwÇÇÇ××ן~úižç»vWVùÉ|ñÞûœn¬ŸÕÍÅÅEÔš=dY!¥r>ô}O’.//ONOlô¦*NïœuvÌò ·C[HSóáß]_^þÂÏ}KàÑéÙn·Ë²’¥R&·>ƒ³çG'Q*á902(ÉF¿ýÍo½û“Ÿ-_…ç½µ}Y•AªËõzèÎNNæ‹ã~· Z*IèÀ‡½€iäáóXÐüý_eD!dŒqß ˜Ïç‹££¦nšºžÍfu]w]W×õn·{ùòe3™0‚RZM‘_\]©<ÆQK©”ÖÆ èµ~tÿaQ]×¥c´Dê»®nšèÃf½nÛöèølµÙuÀ€‰SæyÛ:;;›N§Ÿ~úél6›N§ÞÙÕÕÕÃûW×KE$@ŠIÝt]O$Û¶“RIIJI©"ÇõfÝÃÅÅÅ®mQ ÑÚ{!°óÈ|çÎٓמüËýgï}ðžÊ´Îs!ÕâèX)Ó¶ÝzµÙnwç—׫õ«ÕÕÅÕu;mßmvíàܳç/îÝ¿ç9² ¾ûnÝLvC_W̓'O®¯.ü8‘$BöþªÄŸ™Dïeé÷ÿÞ/ߨ• dà¼(qGŽRÛ:u®±®ë²ª|à$e¹¡¬ëÝÐO›‰‘Ф<šÀj¹BÄÜäëõªijB,«ŠfÓéÐuÖZ@DZå«íλ`²|‡ºª8„¦iÀ9w}}}||¼\.™™„øµ_ùîG?ýèwçw~üîó,ú¾©ª®јl-Gö>H¥|!úp~q¾0AôÎ×Uåc¬¦“jÚ\o×?þÉ{y]:å¬ùËþðƒ¿&ët´ IDATÿòÅËgOŸ>}úéfµÞn·“é”$aDŒaØua'e…fõôÕ«ó1¸ívû•¯|åüâb¹ZK­=z„À¹Öˆ ¤D!bB€ÂsL…zêŽíe°þôý¯B€1‰0sd1:ï!²¸IZ‰¨ï{¥T q~7Œã8>{þ¬(Ëív;[,ªºª²L£Ø¬6“fBô.”eE‚6»í§/>L¦ý0š,+ëæù³ç//^E¹i»ó«õ«õnðqmQ!xnÛ]ÊgR3/ñã †LQz„Ïž=«ë:Al£ (d]7“éìåù9"Eç$¥ÑI2c<;9½\]íúîh>Ó$ví†ꪬërfò_øú77«µ"Éw»6/‹²®f“™"Ò‚í4‘ ±\nWÛ]ëG§àé'Oó¼8ùÊdyß÷=þ™·Þ²m{vzâÇÞh©Ý8Jéýìa”Æ‚€þà?üwé|ï›+Par¡FäSS)Õ/BˆÑŽ!²1ùåÅeY”Šd–åÛõFΧ“¾ë꺞N¦£w~³\÷»n´Ãñéñz¹²Ãˆ›õ:Ë3-AÛ¶wžQˆ®ï»¶=99Þ¬7&3Y–M§Óív› "Àã8üñÇÓéTã$UR/Ëjµ\ù°w†&!ê¼Xo6ÓÉTHŠÌÛ¾Ûv­ó¾™ÔË«kEB0¼ùäñã{4`¥Õv½,ó¬ÊLiÌñÑüòêâòòU?ô¼ÿã~·Ôy¿Û¸a Á¹–G‹ù£Å[¯¿~ÿÎ%ÑZwy})Ý»s6týûï¿÷ðáÃäè|´÷¾i著ôÿѯÃ~ÄbŒiV#;kÓE¦¶j3Ö: Œ¯^½âÈEÝÑt>)«¾ïµQeQzëbˆUQ.f ¢ívï¿ÿÞÙéIÛµã0ÖuÝõ=GγBeÙO?ùt»ëï“‘“‡qƒ÷RÉÍf“Rx‡À‰Ä«‹ËºDóêÚ,/Š¢DÖºÍfS7 €ó õvè‡>0xaRÕÜ ÄI3Y.¯«ªÎò, ±l6çÜv»ÍóÜZ{–(ºˆ“ɤïû²,‰dŒÁh‰BG!µÐdƒ‹†ÑûèGKŸþÊ·þ«o¼n j ­E´óÙtÖR 1¤ÅG;2pÝÔDb³^õm›g&×tïîÝÈN’`öûh90HA˜ùÞ{ÿjpÿìï]}òüyôãk÷Ž :£„T:0i©!‘ ‹›)%$ózŽ1|^Ô]£bäÄj"ˆ‚ϲ,½ ]Œãxtttó™& ÒÝO\+I`ý`Ý¢ëúözy•àI€˜N'cÒŒ ÜõÝb±Øl¶R«„ÖfY6ŽcÓ4 ¸8>>NOEk= Ãb1ïÚV)½ÚµÖGe¨ëZ­„!˜Ì¦ËåV“XL³\ß?9šfZ[Ëå¥ï¶E]JC¡*’pyyE¤ÊªÚn7}×*¥rcªÜ4u¡”êÆÑÚ;'%¥÷¦„`d†¡C-ÿÅ÷¿ÿ'ßt•ÿÙ¯ÿÖùúüÞ$+ë*2z™öŽaDBLK\0ÇCÜÃÖ‚O½ÉÈ©x"%VJ¦S‘ˆ¯F)u}}ÍÌ»]ë½WJ#Ša»®·Ö9ë™!8æˆÀ‚„Êó2ÏJ%I’’™IJ)eßõ»ÝN†a·Û¥^."¦vÊóçϳ,[¯×zsn­!†èƒy‘GoB†~y55Ti8™o¿þxR˜íúúòòES˜‡wïyN€„‚2D’(µF›ºo«å8ÍšiS)ÞÌRÒÍG- bð~:˜¼ÜìÚMowÿ·ÿ÷Ÿö”Ÿ¼ö¥6àdºÀÈCÛ…7Â9޾÷߉Á‡˜˜~ýoä+o¤,ñàŸD$B炵6 pM&“,ËÆq@”Öúív«”†amUÕYž À®ëpmß B$å\˜N(i¹ÝþðÇïGA€BìÚN)†°’ÆAâZi­1Þû„ˆœžž&RÛv»-‹²íº¶L– DCÄ};Ëò·_{ˆ~|óáýŸûúWªL—F…Z-¯H’ŠH D"áÀyÿÓ>Îór·Û-æG‹…Q$ cp™#§¨Œ,ùæÙ‘"T¬µh‡áû?þéç×1"K½ÚmôÞû//¯ÞxýÍ8Zbn¤^J)(™6"Ê£ ”H{*!梗œ¢‘!2Ç´}pI‰\0s×u‰Eêœ>L¦s¶m»ívÇÌ}?h­‚Þ…X(e¶›v6›M&óÙ|öjyBH¥V]W6Ó±ï'M“S¶«UQ‰ä¼ÿÕ>$hz±X<}ú4Ƙ¦BŒRªº– •·Öwí·ßù™_ýöÏGßIÜ›?å“"DC|ü¥×…GðÌÙ…|@,Ľû‹¬´uµ˜Ï½cˆ!‚VBÉsd12 è `bŽÎMŠòì丩ëÕ(¼s(˳=½–ÍÉòù'_{x¶]mösÈH1&Ñ, ßý»ß‰B¸‰=‡Scˆ1²wa¼Yœó13K%I"c¸¾¾ºïޮ݆T¦¬狹µ¶ë;@úqèìf³!œœœtm«”ô~ìÐ ½–*²ËµúÆ×ÞY.¯¥–]×ad©tQ*“g&Ë2-ÑÚa×v“ɤëºétêœB ÃÀ!/æež¹ÍZrxûµ‡¿ô·¾¥0æ’€òÌ G¥TšŒ1z­õL @„cÄœÑ:3Úmí—¹$")# ÷"†‘c@À#­UQäeQUî"ŸžŸÌ&ßÿÁ÷¡,u•«õê?ûÞﺫ+3Œež…Èb™eÞ9ˆô;ç‘ÒfŒbDŽÉí"I6Púœ¤TR"!0ÏØ¨ädÚX纡k¦“~”ÖW×»Ín2£»®ÕFÄÑY‘K%!ú¯õíyS|òÑÇ÷îß¹¼Zrˆy–Üm‡!2^¯–Þ Z˾&Óù0ôι¦i¼÷Y–Åë²T̶Ý}ëk?ó¥‡÷¾òæk™B“)£L„É·SÛ¥»vÜlvãè¤C?TEP0I 1ú£ˆ@aO§‰Ý,‰<3MY‰ÁŽ£wý0(ä;u¶Z/òôãÀ¡(³Ù´^”ùëwNåè|tAˆº®7ëMn ’@@úÞoüÒ>ñL]ì=§5ÁÞV•ÙßÌ¥¦¯¤¦ù~°Ÿ(FfÀ<ϵUYÆW××Z©ÝvWWep¡iªÄ (ŠŽO¢Jéà=2K!‹£í¶ýè£Oîܹs~~¾éÚÍf;x{rr£ï‡¶©'hŒ™N§Y–%ÆUUURIëìÕåÅo¼‘Y¹–„! 0Ü\¦Æøþ•ÌÐeÝ ¥Ì CÅèv&L°’Šˆ´ÒRÊ©VJ©¤„ðYìf)¥É³»‹“ï¼ó­o|ù­ëWçÂ'}pïÞIï»l¾°$ëI@&$v¤›øe7%J¸7KFém%h,Q<Ò¥)m"2Ú0ðz½ºº¸dŽXùÕå¥VÊíýØ÷}ÝÔ}ß…àû¾÷>¬WEr·Þ¤n…QæôøäÕ« ÒŠ¤Ìʲz“™qCðZëq°Z)¥”wÎZ«•rÎu]7:›eæääÈ=1OÊR¡Hó§iu¥¹LïÓÛN>@Bi£³Ì…ª« H{CÄÌi|=å,ifö@í‡T÷…~xŒQ*c|4?9Í‹³£ùÃw~ôÃ?‡¶(òÅñ샧Ÿ¾\íNîÞ@"Bˆ@¿ÿ÷õ¶˜eº¿)[: ¦éLÏ?±YSq@V“TI1Œ}žå‰zŸ|ò‰@Œ!X;e‘(_D‚ÆÁÏÞû“££ª,fu³Ù¬óE×öU]¢O?}&Ubìú®®K%Õv³•´ŸîËó<)=­“Í}f4{OÌuž×y6mjgmøÆq’¤’i¹¤4j˜vvQdYž1Ä´üF  AZi%UZ‹‡ËOE ¡BŠ4«•J}SÄà H %ŠÌtëe­äÏ}õÖÅ?üã?~òä5b6’"bÜ×ÍšÃ綃Ímú݇í’j‚”§ÛqÄäoáœFçÜt2QJ5u= ”²ª+¥UY–»í®,«lò,„Д Ì3syq1›LëI#Zëvm;Îú¾‡´VŠtfLU–©W#õ]?ŽCÝÔCß»q<šÏž<¸ÿþ»õs?÷Íà½LCË1¦Ý“e&E•dhcd¥Gvp£¶™’ÔTå ÃÈÌDÂ#„HƒIú X1ÇDNó#¢2Š///¯_½|x|r§ž@Û aõêü·¾äÛVy MÂËmÞÖÁÚöÒ?Sn~@·oÌ÷#bž™ºªcˆDªëZ>ÓÇmÛ/Ú¶Ç1ÄÀ̤4J)DÌR@–e³I½Úî<`&DmtñàþGO_Ì«†‘Ý8&{ó7?üðÃn×–e $„²ÝìæÍ¤Î³/¿ùøñîý{.’BKBìû»¾#)´VÞ{çcNMC¢>V†P†"²¡”Fð¡ëºÔ’J{=ÝD$€g.òB J½¤U×ï¾ôä1…PåÅñl±º¸:ÿô“;“R¸à¶ÛBŒ"Òïýæ¿sj‰?>?¸ä¥MpJŸ¹Ü|ZfZË´1RÑ4Z›–RŒN)ò>@fLˆ1øØu=KRE>= ðÎZ;6ÍÄy?›ÍbŒ=þ·ÿæÏ§ÓyQ”âõòêh¾xñâ…sîìô´È‹»wî\]]K) )bv΢Ï>9>>ún:Ÿ ]g”ÑZçEã¾§cH’Hs7¼q‘#ÚÑ'%ÆBìË£táI4!±1…8Â~uJ"‘ÛÝn, ™+­3Z­}pý0Øh¯_O‹üÍ÷%B¢ÊTߦ‘”øŠ´âM"”´F½÷NJ™ÎéÃàCz0É .½<„0ŽƒRäƒKÛ?Æ8›Í…Zi)©®jk-#]­VF*$@ÖuµZnf³ù`‡;ÇÓ——Ëï—ñÏôã1†Ñö“ù¼†ÑY»v5 »yS¼|yþ¯}­*J­bÈÕInrˆ8 ã°ë½òEQz‰ˆ¼w1²ÒZB¦á H1ú²¨)Ý®ë÷G#:%´NJ"Iã0)A 0:âä?ÌÖùÍÐg&  b»Ûi­IÒ:ë¼ÍªìQu·.‹ëë¥1Ú€L¿/©“$»8…Å´Lˆ’îCdŽ!p¼i)¤cí°{À”P¤ƒе)}ˆˆ8ˆ!åÑ€1žÎæ×K¥ôÐ;çÉ2A̦u^–Petùâb¾X<¿¸l;Y,V××ÛÝÊ(5Ÿ4Njţûwꬌމb–åUžsŒW¯–gÇÇ„ ZŽ‚ˆBD¤”r~ðÞ¦ì(]…”ÒûýÛV‘#s¢/–UB  Ò=A¡F|)%0Œ};ô ̳×›µRJëŒæh] ")sç`ž7Í«/W«õ´™@ ÈAfY–tLÒ¼N`?D¡´œoTjöi(@2ÂCó íP!@$Péöžò©ônJ !úˆ°k· |Nú.$ Yûàˆ„ððÁË´u€!ÆÇ=#¼8µ¸sçâü|V×UYìÚm]”ÀQ<:ZxkïœÅ˜#Z;2Ç›«@DvÎ…ä`Óµ¤)šØu}1]òAÛe·Û…êºNg@®O“—DcгÛm[UÕÙéÜÚÑÚ ”´ÎJ©’v "ËÕÚ˜l6?2yaCÐB™Ö{šcNÕÍíA²töî…jnÒ>ôn-ÿ=\šnz —·=¢œÈ´?bDÆþèh‘ˆÍ‰˜ÄEHÐs]5ÊOÎÏÝŒÞýÑ™ãݳ³¦® ­¯//4jI1ø4ù-<¸Ìãè2c!„ %¥>7"Z; ¥$ Œ%U*3={"©µNÅf:çÓ9H\¤ýÝu]’¬*JÓ4“x“¼„ÈRQJéœË²|Á›,ïº!/ª®ïÎÏ_½þäI°#GÜ«8¤©’ôknÏ’¥µpX¼RÊ™ˆàÆ]4åB7øj* ÷ÑI)uËrýo°íû!®ªÒZ'%…Î9k (ú¾BÝ9=Íë~Ó÷×ëµ E‘ܽ+v̳º”„"Ùˆr0Zs ÛÍFI!IŽv(‹"F"‘TŸˆÄ¡°Ú+0hm”ÒÌŸ¹‰§š?MÔ¤kOÔëD“IÊD"ù€dJ¥öQ’zAFDRÊheœs©Á(¥|òø‰áüâêËo¿Ó;§‚,Šb»Ýcš¦IÃüdâ@ÆJóÍiŒãÈ, ÷Ûé¬N±þPÇ¥ÖfŒ_ôN‰1–UÉ‘@Ja툉 p>2cŒÜµ­ ,óêd±øà§ºÑ*A}ßöÛí¤i¢·”k f™ Î}OÈE63F;;JRýÐ Ä<Ïé†Ã‚ˆÃ0†‰(I9çÇѦìþvf‘BSú;ie2Ž´"¥RÌÀ,HjkCQ(dÛ 7J›t}½ Á•U.%yç×ÛmQ×Zk© 0°@„d檪¬µRÊÔ~ÚsoØp ¨PJµm{Sã Áng¢éˆ> ·;k‡×§eø™4îñnà}LKûÈ6&/‹&/ªí8<¼/ ø‹¿øA‘Ü4³éd躾m«<3Y&‰1+%Ñz½ªËÒM„Ì!øaè÷{:†XJM$™ÁZ[–eY–i–&Ýí’`ZÂçbš³L×e³>c²¼ÔZ/W›¡bŒRfð>¤ ¢! ¬jFœÎæéˆPv]—”Á’Œc:fÁ.U øÝ3·Cˆ·q÷]æ} A¤er ì…§o{:§×ÂëþÅÖ™Ìh­ÛÞ fB̲<˲ûŸ¯–úœòÌlÖËèãbÚp Z«º(g“Él>7Ætí.ÏLž›è=0#‚uVTJ…à}pû7‰@¤‰ˆ¤1‚v»‘L:Ý-‘tëÓ¸@š.ÚçÙi¯0È 1…þa´«Õ&-»U×/æZ›Bj/ B ÖÚqÜl·€÷ì Cˆëõ&í¯¾’´"ZkÓt @jÅŒÉrbïµrËäóóæÙŠ—›ˆŸŠ¸ý“;|ËÍ`!Ddfb½Ý)¥©(¥T–åR*gÇYUO&Ù¤>:>}”¹”.”õÄ9gû^!€ÑJ ²@TZ‹(9‡óRJ†¤n÷™Ù}âsì…ŠmLÙ†ãèR>Ã>zçpŸ‰$[¢tB烔R‘Ç‹Bµv3Ž"+뜤³9ô1Ø0ö]Û†Ü%$G™î¡s^‘¬ ò¼`fç’vvkÂ4ú’JÄtħpnZ·Ùg%¸Ÿ$E@’Æä™Ö9 ¢®ë‘HM§Óª©•VDÒ{Ϙ{ I›H¦))eJöSPMeÚM‡Ç'hþ E‘>­‚-&ùô¸ ²É½ôÏ?þßÿéÓ­º{ÕßüÖ—¿ùÕ7ãÈà¥1ú³–äáïC ¿‰ìŸ{<éQ'Äâ}æäúùÅ~;ò¤G•10Øç Àƒ”ZÐZ%8ŸŒbŒÖ‰ã¯¤Æ!M“/—Ëí®mÛVJϵŽÌÎÙ¤”Þ±$svç~ßÙÙl±ÛuÞD!‰²¬Ð:_,Žû~$©Fë„Jk;Ž$èÞðûnÂìíí›Î¶t0Ó ËJ#JB-vmï sú¿üß?xÖ/¸ºÓœÿøGï6eýèÞÃÈ~¶û^O*ðSŸsǽ‰àiñzï“~Ã!úßTûÈ“àòÛgÀm›âÃC >X?ø0†è#ûƒ÷ÖT–¹”‰DŒž’f€8öm&e¡e“™ï~ûÛ¯?|›ìøød½Þ^^^7“idܶ­óAjo»‘Ù\\l™ Cpf³cʪš!ªÑFçYéB«‚¤a‚Ì!8ç’Hgbü¥¯Z’L,™eYæyžrÑ É£ÉlQOØ»~òÃ7Þº•y5ÈúkÿÝÿôçÿê§ËÝU,b:„áÐu9$¹_/·ïcÚ€‡®äíû{úÝD÷Ð?H5Ç ¼XB$‚ H !ÕãRR>ÕqD´[oŠ¢Jê,˯¯×W×뺨óYò.¬›Š$um'ˆ”*9ê"/›ºÞl¶>EY“`Q”DR)]×c2g‡\BR·bŒ>ìg>nBñg‡åYžåÙ~í2„ Á˜£*I’6ëÕ铸/ÿˆ‹Rg§C[Ÿœ<üþðþÚ¯¿eÛsúÞo|çÐ×= o|ÁÃü wóP¬¥Ý÷ÿwÌ~fÎ 7)éÃÚMê¶ã⣋]Û9gÑyÏÒ›±£-ÊbèÆñjµ¾Z¯AH%¥GçÝÑÑ"Ë2­””Ä!†À¤t² úäãg󣋋K©²a­µR)­uÛv»¶õ!ŒÖÙ¡çè…Ø“<"ÇbŒÑùŠ2­•1šˆQ"J2y&•bR+¡H¡ ÖùØgÐÆõòÓéB6§G_ÿÖwÿèŸÿ•ƒ™ lèÖNDX}øÎ“û¼÷_PÓº $ÜŽ…D ŽIDATƒØð…3 ÝÙÃ#9 {‡sûö+S-Æ Sk ·ãèb –HÜ›/j£cdc4 ̵Îv»Õz ÒDï^{ð Fÿ“?|òèáb>—H(U?øÅ¬yúôéÑÑ4!ƒ!€ªªëõú… ©Ú®ëû>/ %D·a-ur<>Fë\Èyï]dŸv-" èaÛvý8&C!e´Öa(&•îf8X‘µ?}ùñ£Ÿ}ë¿ÿoÿdVÜ] ¥2 û•oýmò+yƒ:á!¡<ÜèÛ÷ þšM÷¡¸þa£tÿÿúÏ9ìèT&¤t(øp))e¿ˆücRêàÝ+ò"Æ •Úl6MÓ,ŽævÓˆg!¤ ïÆ¡ú8Æà“ßd–i;ޱ(’Ït2Ùn6Ç''1IJ¸Bp>5)½¢,r@ÁãHHD*-Ñ}ÊLD…¨5ˆhzä´jÎþìGÝ¿z÷Õôî™ràg!ŸmEÝHK¿÷›¿”n)ߪeoŸÀ_ˆE‡ÃqôYù{ë5‡‡÷…Çóõ櫸çLJÔ*H°RR·2©š&ò¨Çž>(8Ä*Ë'“æî;eQ£sD˜eY7Ú‰ƒ©ÁÑ;7ö]笈m»ƒ÷À, Sy?Žãá¸J¾M`L²’@­µ$iŠ¢(Êtð¦3`ß\¡CˆÔÃ<þÓwÇÿæø#sü榳BCÅBxç®Î?þ…o¾|tcâŠþIç!Ç?Ô·CÓáa‰¿ñ^ß®™¿ÀÏFÄàCî'}Œ‘h?™së-Å”¶»¼ó œçyeò/^ŸÍgS;M]!3öCcc¼¸Øäy±Ùì’îkß'²‰l‡!I,VU…‚DÊáRBx{BÉy…#ã DRR@‘zI~¿›}ÐÒÈ2x2ÿøßûŸÿ¯gÍÝ¿Õ!€ÚDŒ> Dùƒ§—ÿÇ?ù¾Lñ'8Þ)·ŸÄíDèvdÿ U¾yý¡Ùò… ùªéC €™cšA"™&œ³ÉÁ0r¸•ï20 $°íZ£Íf³‘ î?~mÇgÏž¿öøÑ8޼o¼$žu¼R+Þº=,ƒ×J’”I¢_’ˆÁ…8è^N†(Ë2)±ízD!¥ !8ç‰htAL"à©tUJåy.X;ô’~|Ýÿ£?ùivôNëM AF‚#G'TéxñOþâSq¹>G·:lüÛÉè*µCjœî{‚Î÷Î쟿ûbK"†$šM‚¾SÓí°ß›ªÊ¾ïcŒ ÚK?9UmÌ‘ˆ´6ÎYÚ#öÅ‹1Æ«««}æÎƒŽ8:;ÚaðÎ `­¤VR zïÜ8r ÎYkG˜ÊÚtí ©ªZ1¡”€­µˆB’JªRiV%R1Fç=¢c…gÿðÿü‹‘î:YDÄ"KVÇaì{Ì[y”° ý¸Ìí(8»½ºoûGcªf_H¥Ÿ§æsÓ4)Τ%¥D´?Š"xbäS&DŸ~^j« DFB‰ÑZi*ˆÜL&'ÇG!øÕj5mj)eŒ>x°ð{ä™Έˆ(IH!„D†ED’Ä.ÞŽ®Zk¥dŒŒ™£wl­“R3s? .†¸o÷£Öºi𴀆°+›ù¿ý {÷'£<:öŒ’F;£Ò1ÄH:‚^»Lºµüy@y?)Ï1†‰¿× à(4ãgèær§›*aßPF#pô~/fÊŒ ÆW"DbØ«L!@bm"@$<ûcU7—ëöþÙi?´Eõ`lûÙ¤A¥¤ó ¡}Û'}:[‰èyCàØï¿¡w…äc`¥¤Ð÷ín»ÑFy´6B ‡²ª˜… iR'ñpÕ}ßgÒ_îÜý?þãæÞÏv$F,€ˆX+}ËÎÏ‹¹L¸‡ü…þ"³@1r"ï5:€AàÞø?³éÞs.?“O]e)i‡ˆq”"«ô® iä#"R¢€£àiG$V’`A€‚1/ ¥u=UëÝÆö+_ykÒTežïÁ²BŒÞ§˜F6ñf1³—RÞ´öR·Fxocp$‰…躮5FíÏÅÀ¹Ýíœsã8"Ʋ,•ÎBÄC7§Þ{þ£?{wÈN{2‘‘ED”l!r„Ewýÿ)±‡®8IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageNileSmall.png000077500000000000000000000164541375753423500255060ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰ pHYsÃÃÇo¨dtIMEÞ &gå“1ËIDAThÞ­zÙ¯nÙqWU­iOß|æ;ô{ðÐÝž:íQnbŽåA”@ˆ‘ÂÀoð ñ/¼å"!ÄV‚R¬$ĦÝvävÛnßv÷Ï=ç|óÖPÅÃ>÷ôuÛŽ-’õðiiïõíUµj\U?Üýü¿BRˆˆˆ€dˆ0ƨ´R@DZkaæ”’RŠ™•R " ”BDæ$Âr>E¤_Œ()%­uÿ—ó׈ÀÌý/ ¢Ö›z“˜«ªJ1!©~kN •B$L)1³FD"ê@¢~c­µRJH!¢RJDˆ¨'ˆˆúí{:úcL)!ž?'ßCD„þïýè¿pAýùH¨¬I‘•q™1J)J)¾Ï6 €0£œ PDúý)#" ´f$ffæ~i?ï?w1韧”@ú‡ýé@J|!– r/&O¸R„DDècL1’Ò!qH =¯ˆB eP! "h@RˆÄÔ…è¬Â(’Dz÷l3Š$fA<§à eò4q"‚xñÇóqAñÝïÏY WBá^z¢D„A*¥ŒEPD€‰DADz:ˆ@„.túâPûÝ/ŠôüÀÏ£ï—xÎê…Öp¯{H”åùù7Aé|‘îÍô Ý µñÞ;ç$À÷Mò'ÉÅœ¨¶¦¸ NwŒ’ÉĘH(è•\Hï‚ ``!.=Ñ¿¼?Öç¡ðI:à½ZÝÏ3­^ÊOþüLF'é¶i³|n²ÜÙY\{q¼]„uxøîqüþ»¾˜\‹åD Ðj Àˆ„Q"E…hã/¤ûÂÕðökOÜE¬}_ÃRŸ õœˆ"ÈùæhøÞwnMæöëã;ïÝùËwßþ~³^2oÐo®ä_ùâs‡ùI}üƒù¶6ùØô*NDð$v³°HÛwBw¦˜‰UÀŸmÊ?Ó¬ÕàÖk±L„ß?ßnsD©kCg B&œœ–ѬîìÆ·>}½{íEüá_ýïùñýõºÎ†ùîxg<Ý}x:÷dßΪ|jðµOÞ¼µðÝ¿(¢¡"1‹t¬P…V¯Þt?~nïNsÿ/ zûä#7ÖËãUÖfv±9æ0‰SŠÔ/ôIxéïÿ›^OrÉóE$eBÝsÕÿQ?úúg^ý”Œ0´õÙfµ\µßxó{’[…\ª.xgíØfUY,6›:¥€wª²[n>ñ±—§¥zôàÞáÁåéáî·¾ÿîý“yfõ>õüýï¼?¹R¯šÌ¼·Y·µ÷Z Kè@ý´ÞÿW~ýß"’‚sz?úbbíÃoýÁo•wÿï÷ß^%­êº¥„ëírg8ò©sEN‹"7Ú.ó+»»ÂrZ¯×Á¯”& ©PÚ‹Ü8ºòñ^øÞo7þξ«µÎtÖ´°Á4.&‹Ö…}üðd½lÜô#Ò‹ÁjEf@ˆ"OÈÇŠDŸý{VÁ–XMÉDDädû¡Ù{ó»¯w"mW·Û•5¤•ìÃA}[U†àRÓa^ûvÕ4‘…¥*G­OF™åzûÆwßÄÁðÎãQ‹¡Åv0.<˺I˜Çg‹»÷mÚm5ÌUXî p±ìÀªè5kƒIaÇ$:v´ ¹Ð5~ö ›ŽÇáž[úvQã0Ûxbæ¯éÓ—Xüñ¶M1µÁÇÄ€Ô6mRT (¤„D1%£P¶¡õb1&a6t¬¨q±^3CÛv!zá•2"°Þ¬@4¦Y–•óÍÃNÚÍâÞ‡žÛ×jq²è"P ¢a¾;÷ßD‚P£[_B.,A¿q5}«åiZ¾u{üøùÃt|ÿ­;5I)â$b\FFi›“Ö‘ÅfYH Ș6øºó]†e™Y·žˆBd1¹DFÌÆØ”¢¤¤µV!D£MLÑ·QR¤“O2®OÞUáø`,Ÿè¸†fET°jÅPésŠ[_Ò–wÛ¯õ•á;ok¾¸7³õHÏON~¸ÚÌŒ"‡H]h°õ-ŽŒ‰Iu1"‘!¦”•³xŽ›®NJ¶'¥u:ß´"Éh£¼HŠÁiU9 xïÐh×µ[“wÆ‚o$…Žq•2™8Ü›í8£¾ù>1¨ƒ-=¬º´f5Ö'gw³¨m½þÆÍ›º€mÓ¡Ñ  é<Ö]CÑcŒ%T1FRŠ$q¦ !rb“¹¢t]×¶- HLe^³$Y®ÖEQu­·. )UUµÙnE„ AÄj¥tݦm»Åòd2T…ˬ‹!¶ûêáÇoìÜ¿wí0¦:”¨~ã‹/¾õî½Ë×nnš¶¿ŸÍ牑0Ñh8ª·5ŽQŒVÊ(†ÄF™¦ë¬uhŒSÊ‘¹rxT7µQ%w3´Ò0Äh”æ4–e%Ó¶iŒ1¤udVˆMSk¥À˜\kS•Ùl2Xž-ªbXÕ£û÷›fûê+/drzït©ô'£FƒöúÛ’Øj‹ˆÆ—e¤4 *cÎæó˜’5&#ËB,$LÀä}Š>) 0Öl¶Û&tŠtQ]ÛfÖqJ( ”Ú¬VE¦w³ò™«—O6‹ÁpR·MƒOˆiRZ„¢Ó¤A „áx8È\–™È#ïLg Ñ·Íl:Ì‹*l·#§>ûҥ̿{P5ú¯¾z|6O‚ P³õ]Ó…˜b°Zoê¦*Ë¢5v2š$‘{ï+¥œÉ‘Vë‰$ë\×y¥Ôr½Êó<ÅhH1 &™ŒÆ…3»Ó½GÇ•6ëf+š”1¤wm6›ª,UŒ¡mGy>Û·õ¦Ì3Ji0šjDD ]7ª)z@Am3£nÎàÅ¿û‚ÎrõÚç^ kê¦ÎŠ"oKЉÛ&­…“ﺩ׫ ­cˆ)±÷žˆŠ<¯7ÐJ+­ò‘€´]BЀ)¦#ŠŒt¶;™UE¹6È(BÔJ.Û,–e^D­3û;úð :/³"—äÕç?u[¡”.—˜4a`€.s"‚¢€e:žÔM“Xm´RÌœç¹1&ňʘ¶mCŠ1ƽÉôÞÝ»{»»mݬ7õ`2ÉËJ£Ò€y–!‹¤Ôß]µRE–TMÛ¶¡kBg•.\ÞøF‡en3ñéê¥+e9øèG>Ü6›½I¦4 "iõå/},úÎÃ1i­2¹pUÛz)Š,Ë3ç2Ðä}$c,²È¶®•R]ÛuÏ\£´1H”q1ÌŒ}xò.æ€d]†ˆÂ9¥7ëMžeçåMD«MôA™¬“$Œì¹f9«7ƪ’”÷¾ êfû‰—?víÒÕfs²?«ŠÌÎJŠ(¬¾ðéÛ(¢´AR)F­MвÙlŒÖóíJ‚¯› ˆ «aŒ)¥$‰g³)§„ ¤È‹f[³°µ¶ÌóvÛpJ!ù¶m3k‰ˆ”Ž12óp8\®–ι¾Ã ÌÆ¨ªAˆÑdÖεm“[í@n\¾¤¸*«Ùxœk=Û)ËÜc™ÏóMÂÏ>÷ÜfS¿óÞý"ËÛz{ù`׸g¾ùúëÀ)DWV¸Únw§“ÇO­Ö‹Ó³Ðyët–åÌ2 •6«Õ2p"Å€¤‘£qJÜù.D‡]×- cL_AÊóüìì¬,KD‘à»:l@9}èÖõ d6(®_½œgæîÉé;?”AotŽOJˆhŒQ¿ùkK!Ý»ÿP)}Våz¹Þ®7—ŽŽ2eJëTb-`´®ªÁƒã‡EQbèí!Y¾Z®º¦¹þÌÕýýݳ圴*\Î1€1ö]çœëï"1Æ‹{ßv»€¦®'³)k”QUŒ3÷ÒÍ›×BaÔÉ|£ìïííL kÒù¥‰PýΗåtµ6ZG²Ìކã¶mË"m3Èͤ*v§ÃÝñ€„ëíÖ¹,˳U³ )MÆÓºi9ƨ0[kÏ–K¥Ív[§›.€ÁÜÙ:¥m‘ª²ì|cDĺ®9£u¦uæìj½ Kˆ]½^îM'DüÞÝ;{{;›®}p¼üä'^Q1´™Ñ"@ʈD$õ;¿þ©ÓùÂjí¬Ù™MOŸ¢'$ˆ11'$¬Ê\£´züèчn<#)<<¾_•¹0ÔÁ"Ǥ´ñ!@ Q£ŒrFвîB戴m‹tÞ3FÆÎ+¢ÝÝ|.òÜå˯¾ør½ZŽ«jw2´DɇźyûÇïÊáÁna-F£ ‘DDýÁ?ùÕmçÇãaŒþÑ£‡™³’93UƒAÙÔgMU晦²(OçgãáàÊlº·;”yбic"@ÄA5ˆ!@JÉ:§ëÍZRŠ‚ÆèÔ÷›˜cŒƒÁ %®›ÚhM«åjo\~ùÕÏÌò|=?ùøÇ?n r£÷§ãQ5ì’,·›ë7žÙŸN0f$Dé»{ê_þîk´8;›M&(2›N !ÏÜþÞÎ3{ãýÙ+G£2·ÖžÎOËB>Æ® šLf³G§‹. ­oÛN”"­µ±¶®ëè»ÜemL}¹‰±/!!ÄEàà`ïòt¼_–“I¹ææøäDk¼zåˆ4êÌ}ïí;/ôÅ\©$Ñ h­I”óî•úýßþBU6ëUÝ4‰ß]¿þ̺^¿ýø:2È ÆŽ§;‹ù"Äd­$—çÛí¦ëºkºˆ eQ×[­•{i»Ð *‚ÈZ3XcvÊaŒ1¤èS¼txmûòí›»¹s$5ûuÓ„m·[ãÁàÞñé²áq5Œ‘·›zÿà8ZmHR¥úö©úýü¢šíìtÁÏf38::òÞŸœž61lÛ®îºG§óÜeOOÇ£ÉdB¥›ºN!|øÃ:>>&DK˜:Ÿ'))2“hkŽ6Û­"Òq¾þò¯þÍül2'Óm×eù@H5˜<‚׿ëßúÖÙj¹Ü¶÷ (ÒÆ4›mÏY×¶Eƒá.ºRi£2ãj0?[` ¡ñ.ǃ½½÷ŽÏR×lŠ"…)%QD'óùr³!jm€I¢GËzÛn–¹Ö×÷wÊ¡L†Ù¥ëWÈ:´÷>|ù¹ëÓ'Ÿ¿áòìd½~ÓÐÝ?ÎX}ôùÛ€ €.J]ä»  ™8`gL‘e]ÛjÀaárÃ<Å (E"*ÙÙ›ìîOCiÛ‘5;ƒŒ0 GÕ ,ŒÒ™uI»ËWo(ãºunÚ:*&ƒJRL¾8SßTY×f!Ž­µ©;:Ü%-ëù™U¶i…L¦2Ëádö¹çŸ}tï¡vêßý^RF ¦$1%æ¤YHê»Êˆ$¤`8¬œsMbJɃBDDV3§²pëµììŒVËuUÚ(@½^­€È9×;™ãÝI)YgÛ¦‰¤Y"¹ŠàÆÑþÞ¨úäKÞnVUžÏÏßùØíŒGUYËxXqòZCJ 5Ò¯Æ^¦ª Íóa®TâØƒcìB옣ÑBg ˆ±v2™ô&aŒchš¶é¶,a[¯8ϳB۶κ>Ä*¥zLˆˆÄͬqh•m®„BûÌÞì•ço¾úü͸<ÝäU¦†ƒ<Ïʳ“khgXìO+kÀ¥µ2šÓ·øÃ?üã?ýÏÿóÏò›g¾“£R („.q Ñ3'–(ÂZSŒž9ø®K)íïï×u³^o7ëz»mªjÔ5Ü5¬Ðͦû¤ôv»E¤‚Ë2ï»õz ˆ}_ˆº¶]o6 0±ö+¿òÊ?üÂǾòÅOîL‹&lÕ»¶Mëc¼tx˜k´ÈŠ›ÄV ÔŠ,ÒoÞ?û×ÿñ΢[Œ) "©ßýÏHbŒ‘½Þ‡X)ÒŠæ‹ùx2RVyŽM×5M3?YeSHÉ#ÁåƒYž»³õªÊÊ.²RDà „ÇûpygçhTþÚg?uýÒÞÁxšY­µÒÖt!mÛ"[gfÓ! (m(2&$@”Ñ`àò|8¨tÚ¼~÷ngíï}õ«Õz -jRÿô|HõuvŒ1cº®€¢ÈE„„ˆl·ÛÂe¤Pk*Š‚Cæn<ÏçË“Å|Óù¬Èbò„z<÷b9=;ùÄKÙ rEZiL)¢Ë\JB7–xÞ•!Á¾Ð¡ˆ(˲ĩõ"¼xóÖW_ùÌÉüÑo¾>»¼³JkãÕ?ÿ­/ôIEß 3Æ0³Öºï#‚RÊZ’B6ë5„Øj­Œ5õ¦A¢£ÝØ4»û«fӆضV*·yŠÑ£”bqžŠö'“·}Yæ¤(qáp€Z¥43km­5=@Š)«µ6`« «xµºzpôµ¿üæGnß2’ÔïýægžîÞ¥”zÀ“Ö:„Ð7c i0Œ£¢ÈIñl¶³^¯#ƒ*2ƒREèºA58~wóÖ³·® ‹b m³7N'ãÉh»ÎhH!v)¦Hd”ÒYV"žG½åHDι”RqÛTîÝ»·u‚Ö:ÔÊ FãÄ Hz¹\çyžçyµX,ˆ°ë|žDÜu¾ïÑ+E}þ$"]ÂÓ8¢b"1åp<›æEqkw7t™Q\Ú;P¶Û5Š‚Ø†ÙhS×µÖºëZ"rÎdY|êëÊŒ¨YXæ'§©óüpq\–{™¤Ç«y}ú0'"k-ƒOvüŸþÛqÊ+@L»~ˆ— €újYh5!ôÍ0‘“÷ЯBDŽÎhKDÌ™¶Š´u Q€€€‚Ĩ$Tèl9pãA¥ˆP­ i¥™E‘RDZiï§¾èËëÕ·>ß6+­¸ª*¥úÆO÷ïÿË×íìš`$JLgRöÿr–ò‹w¨ÚIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple01.png000066400000000000000000000004531375753423500252050ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dÀIDATHKíŽË 1C·ŽTNu\¸Ð@Èb+ ž|˜$h%´O–„óÌ~Ìß <.×nÐôrt9ÛíÎOŸ¬ˆv„ß3 ${ x35 ÞcÝ$Œ‡2U÷‡=bŸûã@;cv±SPp5@U˜=a$=†±ÐfÊàÒò/Ðök» MÀwe&qÈžðõGZ@@/|»ìY…ç³G3SêîvÏÌRÈì"|Oƒô_ H³àuù÷*ˆ»!¯!`ûË,¦pÝ`wx˜Ì–sd~ p(ƒÉ¬¥(Ä5¡Ë’ÌÀ¤¹ }ýê“âžW/¢Ùf*KîÚ[p|¸~Èÿ#“ö*.ŽR?÷òÚ]„é1úIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple03.png000077500000000000000000000012111375753423500252030ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+IDATXGµ•=NÃ@…×iÒ„hRÒÐ n§  †‚ä œ€jj .@O(@ü”)@$Ò¥ ~?g<™Y¯Cø$Ë»k{Þ›Ù±]| ¶§¡äbôNëFô¼Éf<÷?ãY‚XÀŠç°(,ѯ6‚ÂD 8æëDô³@^oTÀ£­2„1rïÑ€vÂÊ0÷YVI’µ¤‹X.20¼y —q|¼»UÁþÕ(Ü ªÙÞÇë½j=:{B@Žç–8&AÃ@ Ïœ¨çm4 0C4‹|ÏAÛÞ£¤Ë°P)¬hS0£ Yk 6ÀàxMôAäX#÷c9G_x=QÐÁÛÒ‚YêL­¾ !³ »ŠSÐÊ܃ϘÐpmM'ÑåõÊ-IV +ºä]¨¿„oq!ô‡³3˜œUƒ’§µj ØÇkÅóKµà£º:‹€(…¥°w:? ŒTg] ÎÑ Þ›ÐCæuöÙÞŸ7+®Éõ ¬·€æŠé8Ì~F,1³Ê* ×ïf‰Ûhè"®88¼Ë—[ÕkÍ\÷ïï€Ô߆yrq*…-ðHmMwì’»MVv¢Ñþƒ•U ³–Qo½¤iÀº1ÕtVã&Ä,Òp."…0^öåý‹r2H J´8¾¤’2¹å{ U,þŒXï;2ÑÙPܺ¦IôÑjßË@L „_EEÎíÜÌyIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple04.png000077500000000000000000000023211375753423500252070ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+fIDATXG}–Oˆ•UÆÏ½1c0³("šE&h³šEEáJ0È… •˜)›(f$ÎbBÁ›Û"–¨¡$´ ¡\Ìj¨(¨ME4P3È­ß©ßÇs÷zàã;ß{ÞóþyÞç}ïím¿¶wðýþ kûõ½…ýÎoçËOœ©22מÉå©É¡óQ·7&;1ú _ÎußËϬÔ}?/ÈÚêU¼ôÃŽúä"°O7^(_ܼgœãÔ@ æèÜj÷p™€zeP­“Öòâ¶ï†P)Y˜å(DFe¬mÏúSÏÍ”S¯¬×‡…3öï­ÌÖý¨53ûXáa™%‹ ÆyÈØ@ÍX{?Ÿüª&Ð_¿µVe¾U°–BN$2›GÞ~º\úp¢œøs_5¬sßm"èpoêÙ™Î-ƒY·¤K9‘D­áq%ÁNAÆ»C˜)oJ "ë)I¢óÉO[«1JÁ¹ ‚²ŽMTß â·Î3ˆÞÎoæÙr A@JæÎ¿TÈ8¡Ô †í˜qPg`£«]})YÀž XJ$Œœ/ðKfdo}0Õµa"ˆb£€²5_yíj½hÍ Èrdp£2Ξ'À!¨e©,i@bÛ‚9+8ƒ.²³æÖvpì™úÎ€Š£8É•åjI–e º(þß$ÁÒÇvBÞéÓïÙó"A 8·î‰ú9å¸Ìdí€Bf™8³=VÊ*ÐŽdê”Á‘9!ÁÌ=œÁ$[fÚö?¤eÕAã[¼,ñøÎiy/xwܰÊÀz‡·Lw8ûê‘z¶yó³úžx~wyÿòåNÿå¬2Î}·Èï+¿ÿV¸sO~Y+úêýqôG)"[~x¦`Ìõùæßu‹î.ükP=öÈ \çÈÞ]Z*-ÿ÷ãþ…ùòúâbÙ5±¥ô1€€¥!³Ç1 c>8@nàê ë¾Ù';çØæüÂ;':?rèÀÒ73ßÁž ˆ·rÎ2k¾MÀ€pˆ™€ŽéÞ¯>Þq`\͸ Á„5žF ˆŒÑ%p18ʈ|è/YK3Ã84h½ùFŽ“ÔÍL“ØÈS{µ<œ°C”äYÈ ö~#»³úuöŽ?Öñ!Ñ18ít%ÀØ›/tºéHèd0F„Ö·ù¦4mp®sK µ­saã bqQ†ç^g™aî N$~ö5 ædäY?uzÀpò­<ß蟛~¨ê£ëƒŒ{­Üom §:ˆœv ›%0#'ŸY˜Uê™U[yä@sÕ.È)˜MÈ À¹Ù$µ–ÄèÓz|§%2-"9úm¦¶OŽáÑ-áÚß:‰»dÞö¼¥È;=AV£¦ ÁµNò—0;ÙnÉÛÛÉéô$À.f9r2:^%иÖCî/_û+é|°p¦"’Ù"Kg\Nöf†Œ÷ýYnÿ[È!;ï•Ùx`é¼¥IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple05.png000066400000000000000000000004501375753423500252060ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÂÂ(J€tIMEÞ6˜~ÀݵIDATXÃí–Í €0…©é\ÊA:ƒ°”+pÖ‹&¤ö×4¨ œšàë{@ê`‡Æ Ãc‚—à ÀTö‰óRI6‹=±aùþºóuF¹}ðßl ~—œ vðif¥ï)®¦@\\«OA¬ÖÍ)oÉŽÅUÈõÉôætOÁˆX õ&Œ•P „šô…UL-M¨ëiƒ#àýI‚À˜Hš› üî‡Ä§^bB0Í8{©)g}r KIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple06.png000077500000000000000000000003711375753423500252140ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÂÂ(J€tIMEÞ&%žÕÂÒ†IDATXÃí–ÁÀ C ñÿ¹;-1FÜ›]²r$¨O¨H$„–› `€Qômb·Š]ùÿU‚YÛU*gþq£;ݼZ“Š›÷ÀÛ50f++â+Å?qøÖ T:Iå (Hâ9e±]„#D*êßCÈDxB¤²|â;å0€Ô—<;5 VIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple07.png000077500000000000000000000003731375753423500252170ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒkIDATXGcü ˜ ô€Q`¦ ( 4Ü€2¨†h`SCàÅÑD8ê€Ñ¢xÔƒ0â*åhTŒFÁq Û´o0o4 о2"”9€œ¦Œ¦$0ꀑÞ$c`z…5l¶SE½IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple08.png000077500000000000000000000005221375753423500252140ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒÂIDATXGíVÛ € D·Ót;u×SIð¼,i0Ü|”Þ¥½›í€`D«¾l°V`îuº1®ƒ:ùa»ûÄ;QW‚PâThB$9D\ÐäÔ"ØMX° Ðöb0t Ð*JNM.a´ÀE’ƒ\¢>Fÿ»ªIœä1"Ø[<)¯¢m”Ë5aìbrÅ—[ ´ ¾¸OP#úâÊmAìºâÉ^Câ²¼ÉPƒ²{@ÈPbêfuÂÀüG$ÄÎôËè–(dIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple09.png000077500000000000000000000003521375753423500252160ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒZIDATXGcü ˜ ô€wFt2ŠAY´åÿ_AY£Q0ê€Á˜ è F£`Ôƒ/ŒÖô£ iQŒ+A&Bd0øÒÀhADo0ê€Ñ6á;€²Ñ(ÕƆIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple10.png000077500000000000000000000003051375753423500252040ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€ZIDATXGí–± µÿÿçjhp(²(Œ¸[toŒr×IZ:`Æ¥&Ψ,‹O\jâ€Êâ5•Å#Ð;wmõ¨,6*ËOÎi0~{¦Èñ¯ðõ@eqôd@ë:n„ €Êb ²l[à,jâä¯ã°PYlTZâ¶Ù¿J\~ Öî_éyn/eÔLÛî €ÊBg@KfÐg@r¤Û‚Æ€Øú-íŸrú9 —‘¢JäJ•Òïì„Rs4åî(-µŒw@)iÙðÔ´œ!èG f‚D™ ‚%d ˆäL 0 ¦}KâGR¨:`IJ˜«&¤ÝBñ@ZBî™R™—7`”Õ„Zy´´"µsˆ0MoYd‚亭O°IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple12.png000077500000000000000000000006031375753423500252070ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒóIDATXGí”;Â0 DG §b¸ ÔÜ…š»P“Ž«0Tô\ØŒ“1Ž?’­ÄyC“·–6,Þ_¨"KsV£zõ¼Ö[óD´zÞÍSÕ Øràþö¡ $K…˜K¨ T¸TU'àÊ8_ÁüOX5Àít¬rðŸ+èn&ù l¡ +ÀæºoÏÇ¡iÏ1¡Krœ‹DØàÜ^*?p[ûÆÒÑçà€tì% J“§&Q¼’pÖ°;_Ìï \Ùä1F7úp_®ÝÑ´å €——ì:G؈…Ë•ƒAŸh,9uÀ¥TNDô‹Òh{ߎŽÀIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple13.png000066400000000000000000000003241375753423500252050ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒDIDAT8Ocd``øÄ(àÿ !0`d)GLPšl@±$yx/P@ÿïa,`$„¶ä  ­Ã (4€BÕŠà/IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple14.png000066400000000000000000000004761375753423500252160ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒ®IDAT8OcdXôâ?ð?VÊb`x'« e10=¾ e100Ai¬€qñK0¬ùx PlÖ0@ö; à Æÿ@ó+`ÓŒ€ €²Éˆp”7ù‚1©€Qi£Ö0¸ë·ÊÂÀˆÍf˜ ``âýçR —$ŸCD àýò[ €òp¬{ÎÊ" àÀ4‘¢P\@ªfeÞ9_(¬5tIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple15.png000066400000000000000000000002751375753423500252140ustar00rootroot00000000000000‰PNG  IHDRóÿasRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒ-IDAT8Ocd``øÄ(àÿ !0`d)GLPšl0jÀ¨ 0jÀÀÀÀ;¬ÒèrŽIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple16.png000066400000000000000000000003001375753423500252020ustar00rootroot00000000000000‰PNG  IHDRľ‹sRGB®ÎégAMA± üa pHYsÄÄ•+bKGDÿÿÿ ½§“tIMEÞ&%žÕÂÒ0IDAT(Scd``øÄ`ðÿ?œ LP' ¨€h,¦¹H€<An‡JÉÀÿ’ ÉÑ{³IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple17.png000077500000000000000000000002131375753423500252110ustar00rootroot00000000000000‰PNG  IHDR&“ )sRGB®ÎégAMA± üa pHYsÃÃÇo¨d IDATWc`Xôˆþƒˆa” 3@9 ÔÙ"+(ø IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimple18.png000077500000000000000000000002211375753423500252110ustar00rootroot00000000000000‰PNG  IHDR©ñž~sRGB®ÎégAMA± üa pHYsÂÂ(J€&IDATWMŠA Âfÿÿ³e] (À#öõ#ÔI÷ €Ôß r¾sIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimpleBeach.png000077500000000000000000000013321375753423500257670ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+oIDATXGíV9KAž5 ˆ' ‚£x‚ XY؈ˆÿÀÖB[ÿ…Ö‚XØÚˆxV¢ Xx¡#ˆˆ¨‘˜ ּݼÉÛÙ™ÙÙˆØ8Ø9Þû¾÷½o6kíÜ¥lFFmY„NµÏ©Ï,ß¿}ûòœi®6Êc%24j÷>ÍZ*J=‰Âãg1U£ÖhDT[ñÖÖa¼þÎVìõc¡ÝHV&3(ÎäeJŽSHËTþò#¯žÓÙójò"å9žpO~³ï¼åÿ7U’`ò]ù…ßþCéäÄ TúÎ'A!徟I’\§TgŽ‘”Lô†“8·±÷ZŠ3Ãxåågck_úÝ/Ç#=Ï¿ø8súÎøÜg>ûÛûñßÿ×7c÷ÆåøÉŸøÉ¨Õ—âr·òú­¸¹{Í&%··ç—û¥¸˜«LåI…ÙRd˜ëŠ{…;GI#eCöÌQûàÇþæ'£RCX:Ü6½„5µýÂ6ånªÏé[¡Í>S˜8•æÁµè¾õ\üÊ/ÿRT+ñü•Ã8{ǽѕxê‡~4ö‡£xôÒSñäƒwÆÂB3^ójüß+1®.Ç¿øÜoÇ•7^ŸýàÉøÈûî‹Ë7âUªbÀùÊŸ4JòYìšlr¯J»%bìãUŽMfápš8¡]Qª´êÀZ ÈÉœP?ˆõ\&q´‹’jŒ±ÿ,V›õøëO‹ëßþÏñ÷þá¯Æ WŽâéŸú±ºy&š­v4jÀ½ÓŠV«­öB´9O'ij­#ÍØ\^ŽÍ³çbýì{âËÿã;ñ÷ýÓñøñ£ø¹³+ÌVC˜do®9âËyÚßN©…/üå—ó”O…p^ÅokŒðXU6BªŒ üÌ8ªÉjxqîDµ¹ðœ`õ¿ôø]ñžê•øå_ûTTZ+qñÁKÑDÈF«…p`\F³­FU£Þpf*dQôšulÃÄÍ……¨Ö›Ñ$6lž¹o~'þÖßù»ñÄÙFüåÇOÆÝTºÆ™)çEöÛÂÉ+G¹—o¾3:¤ÀÌ“çü8¨´{Ä å¶æÄ8:ÛpDX~¸Ìà¦BõY¬·:ñó?|:.¯Æˆ N^¸È#d³‰µªÑ@PýN†g8ö©s®â¦^§s#P³õJáºQ×ç‡(®†›Ñ)§¡ûì‹Wã‹ÿáßÅÏr1â±Óp¦òàSäj t®üOH%Ä›BÜÊ–Šð~~¦äòäÔ –÷U‰©Q}­@¦(¥†w®¯Å«_ýø“ç¿GøôˆØX¯7tŠ5‰ì|´’ã*@\¢µj-Æü(èd<Œá¦¡UɈ4ŽÁ1I Ôk(F¥Ðgiu-Ú jÍø¹_úDl¬-Æâ¤x1XŸÅˆá*¼&ƒZ4yÕ¤ ¿Ó&D¢C¡ 240ŸìOc±ºß9:xmð³Q˜8½¯=ûob»rgœ:{yb’w\ ÎX Ž °é8&ü]$)˜Â*-S ™Dæ+(g"*7  2ϼ­N3Öl·cóܽñÖµní\!xÞŒ‹ëµø wUâZ4kF{ùO¦“g ›¨ð««ΕÑãÔ¹½WBj£\nV´Žç|u…ûàùÍøÒg%"WVS›æÑ‚ øéh”4„ç”o«U0ƒ¦>XeàsŠÅMdLžªNGüEÍôO`XKÖŒC(¸ÕnÅÊêzÔ‰)ÿþ+Ï‘qjñ½·n’%F±<;ŒÜ1‹§ÎTb©ip…2nZæ,s‹NáO·.¨.Hdme„Gp°âþÎð).lÆ?ó«±táÑ8vþn,N°‚y]y2ÜÀ¿ü§Ì *V›(Áy!¤q4Ì,Ñeð4€ˆ5#Ó {Q "w¬¯Ä'þöGbióÎX?q:ª ¤Á %Œ“aεœA›y”F'Ú&ÜÈÚ‚o…þc,©‚œ»½Ñ¿bî™qCUp‚°ULgîè¦PHµ;Ô¸Â*nøkÿô³ñW>öá±×E ûû±ÛÆ›×ÞE!ñØÆ(~øä ޵FÑ>r¢J¦ÒÀivXsFøä®mäë‹‹ñÖ·¾ïýÀGçVÒl *ѼCªš Ä`Œ ÈžN+Ò>£BðƒZÞ‡œŽ>/C#n½s9®_}-F‡;´–ÛžE±\8¹7­BcTA–ˆs¾z'‚I¡}òÔñÜ‹—ãüÙ“¸`-Kñý£ÃØ?8J·¸¹µÝn/.¶ûñÄÆaoöQó@O×—±-£eÊ/j1’'ö_Šë½j¼çþK ˜sN¿‚f­ Õ¤E¦G@”Ã¥Tå Äê“^¯ÜеF75/BHñY¹¦@Ø>LŠ„ Á°† Õz‹‚ú jÓ)Ùʾ ™Ç%ª£³¾×÷ºñø=gâÙo¿[¬/¾m+zƒØß;Œ·oìÆöÁA@ÿˆ8{ñÄj7N´£êÈ…"</ÐÆ¯Wâ_ÿÛ/EHÖÉÍ2âÑ¡æôÑz›Ù}<â>*ÑšlEcÖKfS»[ÐoÕu”ŒðÞ²úv=…!ÔR@eĦÈøcÕ`T¹\×q=ë†)c’蘽)µ+£qüþüQ|æüÕ¸|c+®ïÆÕë7cûp{qíݽØÞÙ‹qo7PÖÖÎNoÇûVöâTg }'ö›LWc}i%¾ûüïÇ{ß÷tBÎR5™(Ò'< ßqëú•¸ùöË1êî`°¥ •çVh3|Wøffà¨Og¬˜˜ò°6™ Ý%– kL±%q-u™)sªb%âäÅ"«Š;PiÄòÊJ|î™ßŒ%ë øÛ뎉¿Û‹[Û¬HâÖÁaÌ(ܶ÷¹·Û½ÝXn™ŠaÂÅò›ž¶¿ûõxõ•«Ę&s¯¹}ãÄ 'üG¤ÌóÈœs]BÅÚŸ×h™¿M˜Mÿ¡Ñ¼ªë&¤¤°@?ƒ 'Þg2‹¬ ®ÒU™Ü6>•IôeR#ŠnS(½øú;ñ‹í§c0F„máû‡}ŽGq%\½¶“è8<<Œ[Û{(å¶®¼½›ÚîÝÜŒ?}áÿÄê± |‘, oMD8•`Á3"‚ϘD>ÊÆ…>/; iœ)„2H9a«‚ñHÊÝEݦ–W@ï@D¥¥¨4'Q–ØfŸ±(JQS ¸ahLõè:bcã8?ŠEj†îÙbV%&u‡Ó¸ŽÜïÞ¼7vŽpAPps'Ñ}ýÌT4Ž×þg´6ÎÇÚñSÉ´ð´øPÓj#CXVÔ)LÜ`ŸdœŸ¬Âè'|3º[ÿ5$-•¦f GE§«ºÊ?¹Sã©ÖÎE™¥uËg5O«‹”DZÍý+qêøR¬;ÿíÛ¯Æ#÷\`4!Ý1…µ‰?-P¬kÜ:ÅÖA8ŠJÚ­­e—éYÜsêD|í+_Š6ëöN¿ãky*—(«È'LÊÄü|Œej nÿ,»`…È\ÔP‚¥1œ§’´¾Ösl‚+i•…”8÷ZÈ{ÔÁ,Öªýؘ½‹ãw³10‹„Âi„f£Å*ŸÆŸÿÐcÄÊ ÕÚ$:”Åæ~‘buÛïÆÎa/®‘1nììÓ'e™ÆkøŸbùäùÂDNŒõhÔÚ~ ˆ\ÐUxŠŒÑë0‘ÁM¤ J2æÜúž1"ðdÐRIôÆ(™ʪ¯@=•ÁßõN?úʃÁ5] VPê$+OÝ‚‰2 À·NPn@¯N¿õÕXêP-¢œ`7Cp3Ö"1¨…2Z¤OæoYú̇ájh©×·¨³U€¾@ÙbÄàÆ$¢AÙÒjÂ{Πp4¥©”Ì0/¤›k{Ð$µ¦ø´p!®Mƒå^QœËaDÏk«ÀTË⇠­3D°Á-‘}Vúfš= ¾D•¸X§3ÀÓN8H$,TH½ÐžM†™ž0{+½7Yå £Þî¤2á„2å ŸùJ­ÏspxAé !cÄÄcŽQ%ub(WŠ)­ SŒ/Jäë9 M‰?~† &ñż¢É 9 W™e|êC]8;(ù‘Ž ÎW¤§¿ DšœÏqª/éÍaÎXi¹ˆ²ÁvÇÎ(Âì3ME© 1 J÷"­7©–Xäu@)ÖÕSbjÉ`3%š*@±'÷¬øò-ÝûoCeP^e–I5‘fñ¾ÊËSÚ’¯;G²žµ=¢H"säxÛ= –iT’Ê5ïã\Iù¦(§dƒ¨Jƒ93§˜S1ðˉuI…¥²îËp~ _¹Q:“1À“ë{(½‰3»‘]´èXÓ†~]·ÔM8 óâÇ ë¼t’Âr~è&*„¿àbNæ ÷§²Õ€”@ƒ­(½*‚© û{N¡•V–*íM]5íÂ1åv¢P墜2»‚ÛêxÇÎíC­¢™·%ˆê´-² YYY‰ãëqêÔ™8{f3.=öH|ø‰Ç¢ï#5RZ·çöôæÊT]ß…W g•؇ö`ÒŒ^u9†øíŒHææÍ°s6&ËwÄ[;¢þDPjÂr¨­ÜÇP²Õ|L–DôÚ“?öãŸôAåbìÅ`ê£ëz¬ÔYÅa•>ç-´=œo€ ámòq„ \zäÞŒâëëñØý÷Ä¥‡ˆÕâü™ãðZ‹W^}!M?Ø_Lã¢x•>Q ªíÿÉoÌjÕN¬ÍÞ‰Au%öFí8ÛÜ#„ÛŸ.Çï ?H軫 qØŸÄÅYìݺG]úîEïpý[à^³L&}ù©Z)åÉŽT”ˆcgï¸W·cJ{`ÛCÁgÖÛqk¯§NŸkW¿£J;žxèÞxñ;¯ÄѬ› •ØŒãââí7_³¸ëÂ…¸råí˜è~ôÒÃ(²_ýê×Ót“Ñ…^³ Pø˜%0“O¬;ÜiÊè-t€}æe´s4®D—B'aˆé'äØüP÷ëúö7¾þµ¸üæu˜w7æb?ÿhœºÈ÷Â#qâܱºyW,oܵSÑY=ÎJs9ª”©õV;š ëÑh-å†g¢ˆ§¥ nZÅx“™Ú8¾"P—6ØÖiÑ7a%Ý€µ“¼ y÷­ òZÛ4ha¢¯Yu"‡Ö·D§‹>7­É¾ìÓÀYô9+XMæ žiÑB‰y¬â¼®5Ú) $ òi½­&%'çV`¬ë´×´l.;Ì.¢¢Üƒíe#ã ôRÙ|sN®\ÜHËõˆµ†= pf¥)Ô ¥/dÙ|[xÉ„)øhRï˜Ô1%•B…Æ dÐÍè«øBÀlÓYùÙ?cYÎÈÕþUf*0ù‚F—œ©K× 2ÐfÑôšv—ª OBVxf…5¥Õ˜Ã –«Aø°¯<†‹ Ì­.ùáÌC–q”r¶uŸ$è“‹8èXHI+—Ó¦Mó4t-‘ݸQrX1e¤Ú ,C¦ :q.l¿Ù! DßLrbªâ§%[ÔYX$ò/Ç&AëÜÙ“qáü¹xÏ]wƽ÷Ü>ôÞxâýÇ?ðxüÈSï=ýDœØ^øã?ž÷¼”Øb½f˜ÁÒýEùËÕëÞ%ÀC¢ù´¾Ó0>÷-Uª›Œ: TX™Ž:@Ú‡Î+µï7_‰¡-U%r_Ñ2³„cécy[>*¿Ü@c¥‰Ì¢)7U9£øÝßû/ñ{Ï>ôÒKñÒ[oÆýÜ—}Óå¤-Ÿ|-¡âðÅ/”(×G¸± p¦Ûh€ÛoÓP9~|ˆ¹ÕÐÜßQ§Ì8¸a£Ã!bpºý昻2"@2Wsž1‹“dÚá^™Â6ûäEö³¥ L¡9Ò!#4=jÙV«MJp_§kð‰(¿ûÞ„Yí9>ŸèUh>¯à—yÍÇk?YßpûíDæì¨02áy¦&ã7ŒØNä{~v.¹èÕ ÜÄŠ-È•ñùÇs¾…`fÛog…¹>RYÅúåkÐsej\òÅ*ljB·ßå')cr¹›B17’ä9tdÃUæˆÀnÔOëܧSöº^©#Pª/";±J(HÐoe¡=w°„ú2_‡³|Ûfn[ÓüäeÞ¢¯óóSZ€Ðõ/%¦=¡Ÿ­*L–a¸E.î Ë=„QšÜþt~ÇÒO¤k:w]ÀiáªV´¢ØmöRÌI ŒKµ‰}¹bâ¹1 ƒ“©üc'ŒÍuµ“À™ÖÉÝ[Žùô‡~vsŒ4“žBäú» *釴°Êñ£åJ RiVhIŠV­æ…Ù‰~´+»÷sÓS*âø×¾wdŠ+hCA’FÎaÄδiÞ°f!I00'‡ ¤IˆÓ-ßÝE#yŸ{5™ªnÃ02K8C\;_Ÿ÷Ô¾@“®-`Ô•#‹Î å ÑФ°aýÊÝrocu)GGɇ÷ Ä»;7bçûßË4— IB*šÌ•[môS {îçBIÇZ‘"bD@a¥eŠoëÓ;s¾ûæZFeøtÅu›Ù@âé*LàbÃ~LÇü¨,—¡©4ÏQ˜9ÙÚÂÅR¹Ò£OÎïõ\!ü©ùº=µè~÷(ùn¡ç;‚Ê×X\£Ã.•øå›ªÉ„Ò)x ] â’Ï)´Fªu`tÙ˜»£ÀZ‹«„„$'ú]"B¦æè°’¥*=³MÅk çõ‰´ j/.rlp¯kn–¢?J—…®ëƒk“²É3àè¶ü@¡“|ɺ‹ù†ð½¹:ŽÕN7Ö–F±·ÿj,-1Á,:|†€ÒŸ¢=„裵޸šƒш«×®ÇŸ¾|9Þx{ ˜ Ö^óô¢Ba¼FnVhá©âZÍ& ˜Z¾ÀÔlaU:åBø…vÓ-|AËßH˜g*FAÅ”X‹^XbÊËËÉþ–¿¾âãÿ/Ào¨w…ïõc0=rëhûG“Ø"¶T¾ñ…4k¢á1qá!vòQ3VN7à˜ïø±âJ>VÓ¯ÓYÌœ[CAZhc`¥ŸUD¥r‹ZÞwƒÝÌ•ßY¥8Û;ÛñòëWzæèEw\G|4žùÂÊzƒA?>þ±Ÿw®ÝŒ.{ø¾{â˯Å[;qþÌéèQÝ.,-Äèè ß#ì,­ÆéÇãëßüfôc»?Êý͆ëõ0Ôá©rÃÞ.2£€ÿúÌ'(ªÁ„M»ÕÎ]œ% ™A¦ÜûTh­Ì¡º³oj†O86›-A•ÖngÔÕßµÞÀ÷ƒ8:ÞX,̸J¦*>åõ7P“[h4+˜·¥9Š 2 ™åÄp÷ Òw5j h‚æ3ùùñŒf«šáD,¶áånäKÔF7q2(þ7?=Cñ *¾Á‰™s!â'ÿ «Ò7ýÒ¨ï `y}t„4ÿùAßïás«¤)SÛÁf±Ú¥Kš#¢é‰ãKÀw S˜ÿo.,£"u¿—Ê3¶-¶—2Óx˜Ï/G _ÿÏÐlåƒ\MXsá„r@ü`¯‹À(–, :LÙf2Ñàš+M]id¼SVúÔ>þê“9Ø$üï DÔ ZM—àÛý^ˆêª«’¸Ô¾}E¿éMK7|CŽV_¬q„î+1¬¶c+«5W㈶^,A÷ö•¸ÉùÞ »ãv|%M›qÐe76@ÌÌj‹ð$bà‚£» Æ·ÌŒ_"¨»˜ãàà°¸¨1çnÒÖ6n¡ÀÊ3ÿòS3;˜¢|çvJ,ôŵ崰;7V„S,!È7`r¤öÙb®AI¾ŠúB£äv5L y_–îãÇ¢ÌRÙÿ9ë6f¬¤ÅÌ )¾ šÌQ6?µ sá0æ‚Ùǵ¿†ðUØÃn?{5€ªˆÍ±ÝØX_ÉX¶¾`”¨ËÂhy¡Qù­õi*ES¢Öt*Bd\ƒØV¶¤ÔQ2˜±n¦Õ‹àùÏ 0bŒðÅHõ솩>ë–µÁÓËÒù&w›>–¢¾Ñ9p_å1^˜²P‚ˆs U’ÊF¦\hÍõ£|Ê\óù%uýšû‡GÑÀ÷§ôMb¬r‰Rë7q|À“±ÈŸÏ?óë3'²dL!ÌÙhÊ8ªÐ®L„›L|$Í ó=‚%#/•– ‹Uª´çú° S¦Ná«©V|¦Ç²/ ˆWöæ2às,p¶ŠTq*£O ÌbǪã}ûðã˜Øÿ(€¼Jº-ƒhë§‚q_*ÒE¢);%¬Uâÿiê“ß‚«IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimpleFruits.png000077500000000000000000000736741375753423500262630ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsRGB®ÎégAMA± üa pHYs."."ªâÝ’tIMEÞ C²Àâw>IDATx^í½y°\Ù}ß÷»÷ö¾¾ýáaÀƒÙ‡³‘Ã!)Š‹IÊ’åH²-Ù•(Š;‰“”—*±Dý•T9v\qEÉVÙ‰*²%K²eÙ’I“Ôp†Ë,ä gÅ`ßÞþ^¿Þ—Û}»óùž~=xÀ`HÑU!ÏL£ûuß{î9¿åûûþÎ9÷\o@±–Øâo½ÿ°ü€–ÀxñQ`ÞÖ_ÅÏÛöÅËÿ¯‹CG¤t^?TþVqàa?ä‚?˜å‡à¼ 9À¨øß_øï|¼a¢!>ŸúÃoŠ@$½ûŽ¢J)J½c³? Uß‹r8Ÿ8êÝRáÐôo5Íë‡fÝ–y1¾áóÀâØe³ÈYÏÙÀ8VG_=ÿ‡åý—ï#È…edò{”µ­×^1¯}þÑ1¯úm~kš£Q]‹x· o~k‰sü6f~æ(Ç6¬ŸÜo~çë) %ažŸà˜¾3Œaùg#.%GÚþy{qßó¿÷Nþ×Þï‹ @;½ z6¨]4¯yÂúaˆ·/Ø sÊb¾oÝþºùòînÙúñ¶Yª€‘Ä9ÇÇó§-ê­Z¿É÷Á˜Åb{,òøÍRæ'˜7vŸyÁ„y©iw…e4ßï"ÅŽ”ÝëEÖ¬ÕxU­ÓÁØ;¡õº= ècz¬`y^™LÁbñÀ¿ýÜïgqà _f€ÜÌjHAµ>ö,*Ÿ4«¾b~t¨™¾€€Ý”]D±=³HŠ[ÅîæïSœ‹ç;Z0a}¢£Á£ø:Ç„ ‚—µ~ên„ ”¿CxÜüÜNó„ îòß_v1êÅ»|ꤕ¯ÐÏÍMkc´Ý°cA&m^59xCñ«Ï›Õ^$vGW È?cQ8²fášùÉ ŽëX_D¯·ŒR=‹‚)~ ,BPñÞ%ëûŒfÍâÁ~Сbƒ(&ù­ÍçY.5!ì£~Œ(ó´y…ƒ–˜|Èú Ç¨/&Þ%ð¤Ý°mWN±…·ß²êÂ’EªÕ®,[¯V±^«kõÊ&Fj–/:™HÖ|n%–²3Ó–™˜´†pðÚŽ»@u»ËüY–wB€cäé{áù‚üpã´ÅÚ—Pöy𰃿œÆÒ6h÷-F¼Ç@€þx<Ãß&"žÇ[Öï´¨gÚ‚ü nupÑ´A|·ɺ më÷cAV½8HàßÏq%‹²‡éÐ8Ha{ʼñ‡ÍÏN#Fõé{+ÌÁ ²Þ½8Ñνúªµ–׬‰÷‡ç/Xu³d±Åu«µjïôhS_½³d"mݨgÎWØLM:YŃÀfŽ1/±ì¾ý¶óØ1»ë£O[q Gø3.ß[ÐðÖÀzW¾hýúK¤pU´/ûl€ßñb 0‚î"ŠSª—á»6—&ó-7Ågb>ì?hÙ,þÞ…;¼A=xôÌÙ`ñÿƓȤè^Êzd ‰ hÝ MŒ8’ðžÜ‰|Øâ;Ÿ²ArØU,ùî†=”yÈÄ1–æíò›'ðú7-¼‚â—V,º²dƒ’µ+eó{}K`$ƒýB®½¸/ñØ Õ²^!M´ã;Œ¹Õ&Iß‹-üc®ûï“.Æ&­ß#C`(}²†$0ªâZû9÷ õ»Sp†]ÞŒ%ö| cà3ünNÞÚ‡Èøö·lþõ×lóÄIë üA£æ”ÔæwP(D4Æ…|4žMç­áE¢üf݇†Õ:F‹(²!„dâ6ÿéD}‹1›+Z×”MÝ{ÜfyÄ}ú36qøÀV+¾·%øÕÏþW·> ì}HH8±°½ðŒù寡´¼÷"…w†éÔ,Ç€ý:Wô@‰#CCH$À ÷™5¾Mì>€‡lšŸžƒ‰á+Äw ¢ü ‹÷S?â9ÈëbFÖEù°ÃA¯DZXàGÏÂf9 Œãu„аfƒXѼdnËÀï¬#†¶šö—¾`«¯½n'OXÔ{«ëÖxë”(>Êë¡!vFäîˆúжñ{šë·5Â(”™›%Ì5-‘ˆ“ w }}›Ø?kõŠÅiZµÕ¶Ôú†…Ëô½bµÒªÅòyËÍîªÇ5ÿÎúp³r¨8»S#PEX¡þ(‚ âõ=Hb þ€!x 97uevq]2Œ`€’úÅ݈WÙÁ0ÿ¾eA!ÝvÃÞüÚ×lýÍ7ÍÊxñúºÙó¤´ó‹–Âð xþ8ÞìCæ“@÷ç>m÷ýòÿlSxÐòûï²ØÔ¸­½`áéóÖÃBÛAI¶UoCeûVºÃ 9áÃ0â~‹ŒF…ÐT*Ö_ZÇÉê›·ÌÂüIäöN}õúò.põQë @gøîœ…] FRžÖº3Fl®Åt®Ó€Èå,–œEÏOY¼ýäŽXî›_|Ø¢æ2 Ä3cã„  ‹Mü(Vÿ5”˜µÙŨÞÇžâZ'@™ èñ!T_Åë§0œ*vYÔ&„äɽÖíÔˆÉë±6?nQÁc¬~aßm{‘²“sÄûù—_¶paÕÄüôúº¼l9êHïû1p¨K½ûöØôOý„ÿÏþŠÕ–Huý„uëu{û¿h•ó-¬W¬…cˆGD–yÄþ¾³( I§-Œ£mÎIåé[>e!a/‘ˆY¬K¦P©[8´lZŒp’Ú1G¿bC}}åÝ!`«Æ[+"Cª3ØxÞ¼îY”‡°»eÎÅ®}k÷bN ô€wë_è Aä`¶}HbÐ}Àù1”~Ÿ8 2äï¡ö Œ$”ç,ŠíĘúxÞZä Ÿ!d?7_ÆCjñ=uܬ²`׋,…V5’ ìÇÈð˜.á!útŽ›¸ôбޭîÜ  ¸æâ™3vù¥W¬}ù’e––,·¶fžŸ„¼ yúâ ñ¤u“ Ë©P“8LŠGœøÊÛ—A ÂAñ^ݳ^2OœûCÒ_âŸ1Pi¬¿yÚ‚úk°kŒªùpHhÁ ´ÎQ[×üÆ ß‘ ˜Aˆçìý9‹6ÉZ(ÎíÃ5ÂÕyÚ™D°û­×½L[öRÿ:^tž«¹Åw‡‚aFÓ·F©dg^zÁÚ—.XïKV ²+kÖ[ß´& ?Ä3›1ߪÈ+½g=ýkÿÐ;v7mõÄÛ¶öÆVyãuk;ó¯Z…ÐÔ§òX!kµPN"äèÒ¼¤U1ކ·—ái¦Dž€§¤ÆÕ™a§FÏ\ÁëWß&Õ+mZwcú @Ïï }”‡È­‹²‚dÚ >hÿ7“6ct ÏÅo¿lå×Þ´úé3ÖàÜuxÙ”UÖõ8¿çEÖÆÀFë’Qð—d .,/"Æ´âÁCvøÉ'Ìê5ÄpÑô+’röBË&„¶ —µÌþ}®Ýw Þ…ôé¢ÊF“CÛ‹FÄôm¯úñ»A£@€Î& xŠa¹È¶ ú!H§Ùü~BñŠ|½v ¸†œ)s4Iß@ŠõqàRuï¤YxÙ~ý÷!o¯Û`ç™Íò‡A øâá±>é!&¬£Ì,iQæ”MÕy‡„*ì&H-­½Q$,¼j¶Ê«x/†°dÝå×ñÖ|ÀYªë—Š`¹±¹a¥ù‹Ö>wÊ¢Õó×`ý6á(¦CµnhP8”³‰C‡ìÐO~Öb¸Ý D4–VlŒ¡V‚¹#“&Êí`{ +Å …Œ5µÎdèBVz)ÏBÈdcHS²^ +þ[­¶íùé·É>b¹bÆ2¹4©´gõW^·ö7^¶ËÏ=gk¯¾ _º3å«Ü” ß\ùüFˆèµ6ðª* "õf\$ ^^Óõé´ççaÂü‚'Z—ã@ñ^Zñh€¢+mJZ“ðßMÓ Ú—´Všn’yŒaã»f­ôöiê\¶É»Ùýã¯[ñÈ!K§ÒÈ„ç4N¾måï¼i‹'ÏõlÉéÊÍs!”‚^ á %À3—†FG«o¯ÿÎ?¶êË_%ïnÐbô máʼUé{ ì’~'óÇA¦°‡óa¼¿W%Ïß,ã‰üƒt¸E{A‚A# tÄi›› L„–w“–\7éY< bMåmöØœ¥§³dÕ‰ó6׸4oÑÚiä²ÕV )Ó“¶Aˆ«cزè0^ÙµÓ'mé7ñ?d úÞn¹¥Hé ï ä¥ß*!P µK^ ©r«~@€XœœtN]í7[n G£tw³çѱ°†ChVÑã5^*aé)Xzê1ýiÔ"8OàšB†÷;A”ªáäè2H£d:ËßýÚ*@ƒ7­Ǽ)Ôþ<šö-,C"M úѯ‡'“Pƒ®U/¼aÕ7~ÏZë2ϪkËvæÓÚWJ´ØÙëÄaú¾­#ì:D¾G›:› KÂÈóé”õVJÖ)WmíÄI[~…”h §u­†A åDþŽxùYÂF.áP@ƒ‘ú­ÜÇ‘A—ß«õ2×Àˆ³1»°¼nË™MLfÁ–ÞzÕjó´3Aÿ =õTÆJð¡WUü„Ìbãâ%«¬£Ûå¤ÜÒ¶s‘t‰õ^‹Æ´~öɽi /’©+µëAøhG/l:ˆB8GüáqÇwó>†`2Äá!ˆG”Ñ$A”ªõƒ8Ue±ú:¡„x<‚CânµD‹ê°g¼h€`x›ÚŒñ%Òcáåâ+ô¡ áê£À5<³‰rK5묜¶æ™…ößùuà{ï#Åk÷QbÂZd0mMh¶iKØg‘¹ÅGm‘EREƒkhd®èl€Ôa4=˜ÿ@Лø€\?‰#Ö×Ú(:.Ê“Sœ‹áîØ…ªöÌé+ö¥³Kv”ÜHvìO¼ ‡À$áý ç­06f=Ú õªnyTÉNêë¶„ÜI¹µl½B€þ4V83M\Vº¥ÜtÜüvÁ÷ >hø‡÷'a8ßxzRŽÒá1BCŸøÝmž‡îM¨ƒØ?PlŒ!VÂ…ß#Öyx{nc îKˆJwˆ¡E÷c>ìR‰’´ÎÀOL¹QÀ°é‹ ¨n(U²Ö¥‹µ¾%òÀb¼g•5ˆ¯ ,O«ž¿ŒÐN‚H]øÂïX‰P£eY>€”ûÝÀâ@ê8)Z(‰Á]Rñ¤e0ôÞøìE«Ÿ9gmSzþ[¤}ë@=¢5Äÿ~µb5­Ãßã³s–¤/cSE~‹ÓV®÷,™´v`í¹çíÕkVjiæ±k—È^:Á”µWÝ<@þáíÞg52œ$¢ñ`C ¬ ©Ü\˜·U^ f#§½U¹¥¸£GÆ@‹ñ>Ò>)í¾F±þ~?‘#ÞÂFépø@¥VÿÆ3°sÀ! ùGC±ñ¢›è±–îæ0_i„OëPvyÉ4¥‘µ€˜×£Ã2„>Þàà|§E%}´êM>BjIHðQ449¡Ì£›b,8Ìj=@*å[a§Oj€¶£”5/œÃcC[:}ÁZžÕ[=kB¸$ˆ”L ø:ŸnÂi4-5«ÄúE«¼þº­¼ñ–U!€±åU‹Ñ„â§1‹XBKãÈPRi}Ý&1Öf¥:¶B(™+ØÃ{wÀ}êv¦Ü°ìxÚ>uטý§ì´Ï&íòW_¶Óû¬zæ6¾`ë½¾ÒmãCDûGõQ³“!(T%eí4´¢êöÊ­ `TdP¼Ôñ°µŒ°ù³±FG3XóÞMþÈãÀäÿX§…2¼&ìs!°M;u• R\"òQ²$[ “À<¼Vþ<­ Žív´‚`$ñlΑJ #‚  :XB0Ä}4gV «@¹ƒ.¸²ÕÚÂ)v³!ܺˆ+ݱ ,Äð°Ø!7ô)áH±A oC=òT:ݺ½LY7n„q‹ÅðHÀ|p2@Y? ´l6†w'¶kí!#‰áŒA(#(˜˜-ùvÒôRc>‘ËÀ¦ A¹£–À+úïÃ3À{%u…!…%ŒÈŽc ½(Pj ‘KŒ¥ÔI?kµ†Õ«eȞ뜞ÕúÞÖP—…6„ôõà*Dv71# -c[~CÚ8(Ð^<}YLc@öÌØœÁ;SÔ™ ²–é¦l‚üÿ®É)ÎmZ¢ìÊÒ=jÖÚÀ†-²v1fÚzïÏý¼íúøGlîñ'ÍÏ筃̅BZQ<3=AvÅq(Só+a§ÿEùûvÊ»çnQd5­…gÍ+Cºð’ÄÏÓ€ÖbI@€0:ªAͨ!5ç…ˆaã¯aê3üŽ˜!5"óý1BHÑ¥ 3d(Z«|-VÕ§Ó^–ïñVo€gË?&Pç& ¡¨Ó´äÏGï}`ÒKb0pˆí–t ßšx~جU‰¬ƒ§WiÎUµ”tüQ;ùå/ÄÝåì9ÂÅnI§9 ¼q R a«cË X7t‚Ÿ™†É ƒ†jS’?ÓY¯bh+4Á¨»‹ÁÏÝsDéÙc|À8¾Ïöîž³Xý˜²8H·QÆ";„Çò91{2˜…+f‹W¬º´bmœKœ¨³(Mm@43î²ÜŽ)Ûuô¨MïØ!u½gy_!@%HîÄ\aðõKÖÑ]µÂ—ã( ÂÕ@2¡,å)£…’‰Iô†—hX…)“ÐèÌÀú-ÇñónòÆ'öŽmW8~±r™”Ò‡{ËÐ×]|ͼd«å¦W† P@L6صÂO/и»¸ —Ãøò3}K¦!~Õ¤ °YG¡Óûöãñ4KÊF,]P­„¶}”Àñu¼¬Š%/áñosõóãí@ÈúÅ:JéA$'ææl|Ï>ˤóî>€ P°T.OVA;0ÆD©nézÇÊoŸ²8²Jgá &bn:x,•³½¹qRNà¿Ò°±}ãìI;û»¿kç¾ø%Hà)Є6Zš ÒTÂ’[vޱ Y~‚pzåÎ !aŸx%±8½Û"R¹Pëï€ü8ß+½éa•„΋ŠÄ[¾‰›¡¼¨DlVª¢øÔPc% ©lƒÚ%ó×J–œ~Ôüc¿B”s¹u‹H3D- ñS)l‰NÃÞ½±ÃfEøA’´jsxSI !kÚ¶O؉Àþ&M†W´V¹>ÈXYQ@¼ÌÁaœ…}GlçþCŽø˜0€ë§g (yϽL¬?ëE¶ˆ±T © Ó/+5ƒÕ e°LXø¦ÕJ¤‡“c–ܽÛ2ûwÚ@³uÈK¯SïZ´RµÚ‰ykžX°ò©E™F?gù€ctûò+b)‚|¢0—€Ï`Àµ³lóÂ’]>7oí:•uİܠUD[S P*X’y«2JßàA@x<}0¨ZT½ÄÅa»Þ4q°e„ŸŽöÊkð ˜4ï³À>i›:/ÇÐ\”Ùî@„$pºB8õû<ˆ^{Ñ îøfëîƒï}bæ8ñŒZZ€¢,¢fÁän³Éø–ëA¢|ÒEg "%ó‹A˜EÐÕw§|”Bv¸ÛöÜucF‰ U(”á?˜Žj³áBS·Þáõ(CÇv”_òÞàýÂÒªUJ›Ö,m¸Øœ¶Â½Ç­?=CÛÆm÷ƒÇ0è8Þ³òZÍúë@øJÙÖ¿ó¦ÕÞZ²ÎÅeë®V,ÊZ*S´Ä#vð“?j;ŽÜe]­ ^X·'«õ˜<¦OHkžpÈ·—/ŠpÂHnä:yƒrýøÀû@D“@Pà@0†°sÖCáíÖ:y1q>>mí&JѸ?VÝ*áO-r~òÿpo×€ü* $‚È(¶ ÛÇ×4c'þ¶\'£HBöà(2¦A Ý;(HlcDb¾ZI«ØÏwƒò†¡Ùà î׬Á7 U”ØiÕké*Š­ãù|Õ¬Â3)ŒS©ZÁ {öZMh'BÔ4vЦ}2†¼Fı«»–i‚n Ñ¢™®B_p)«`.-ˆ`§R²ÞÚ²…p­þÍîÚmÓûˆ•1îØž9#ÿ³ˆT+×Ü,§_jZëš5.o¸™ÓxaÚ¦>ða{øüïì©ÿåWíÑ_üEÛ÷éA†3DµŽUúÄ| B(2Ã@ª[dG‰Ù)7ð–,-›Ïaº7/##ÀþïÜt®G¾VȉyOŒ“z{¨Ûi­ÆB@™ÉÝp W±®îŽí'h`ÒÂéKGi ¾sCŸ½&‘·þ§1¼%ÖY#ÍB G· X!Çï€åZ<‰ûõQš—!°÷Åö[T92ð¹ŽQ`$ƒ cABH}Ð#I%H_D ¥Q^“°Ð#†Ò¡c?åúVܽ 56Ê“ujî#krBÂ,6Kœué-ÿ è[#Kct],¸Y­Y›´¹¼·6¬GŒî¢Ÿú„åŸxâ:NøÓdgU uiÍl¡l±Z˲»Ùá¿üWíÞ¿ö—lêÐPLâ"Yø‘–€xMn†a #H[DÜêc¹;-ßÈŽ»QB•ë½}»âGå}„P/«•4x Ö6´¸L!Ô1F­¿ulÔ)’ó[£‰§´R¯À° ȤªÄï¡HƒÙ0óFáå¦ÀæüŽê®ZÒ3 Êôšô¦µÌ_-[sÓ7IJôfÀ5.®¸X*&¯áfB#ÒÎC" Øh´²/h†\¡i欰ï¨íÚwÐÈ=‚lÒ0¥eºaªJš¨i- Ý ¸ßµ¤Õ1L²8g:¯‹WQv‹÷__Z¶ê†¼hç;7F6þÀ½ìÝ úÄIlÈB0z²KÂA[MYñè1+9L‘(WZ[±µ‹°þÐUYá¢4 æ“i¨m }BFf¬hű1²‘ìþ%Ò@)ýzc @?ÜøÇkÊ–Ù h€ŸÈ¹%ÎAn‹ÀË«+Ò–þkã¡Q¸aýj‰Ô‹T/‘A˜Ä$ ½YG™±<Èä£÷ú1µF<Ö<¾è/-YO7¥éBÖZþˆŒ¢_ų3y¶ËX|Œz2¤e]ˆÜÆ*Ùlz× Õ2ì²ÅQt_«7@‚)_X¬±¡[³}¼ƒÌ€Ÿ,l‚Eâ-,<gÀÓ>ñÓ?Gz‚ Ê “ ¸‡d'V \»u€_ló†Í¹¨Tã!µjÙÊË+¶rö uu‰Ûk®úôÂëo8‡€„šÎ$èOE7 +oœ¶êÙ‹ð’¾­_¼hç¿ñ‚-¿ùºÕWVH_9è÷ŠyËì&CŠžÊ¸fr‰´sª‰im‘#Ù^«i)ßø Ê» àFå£Pð-ñè ˆ=s#ˆi”Ó$%N“ÏCX`âÝô Öok¦š·XkÉ4¶‡ÀaGÞHYc-ˆeYŒ²º0[ tÂÀlÐ Äâ‘Hßݱ.r&ÿăhU@ëužÒÀ¹Y‚¤ûÔêjþ¨>ððTqÖö~ðS6½çC+ÅÌã>i»f-…b´ EUhDkth@¡ëu%Q½{2çä-!kà¨)Å( `0 dRãèM²‘FZ¹U·z§e ­•Å ¼¾Á{‹Ž58gmmÍÊð…¥E[-áõ¼ž¯ã6QzÒGN|îpAaŒ¢C8éÇK‚jYÍ ^§üQ!Áõåö àF‹¼ïã°æ¤@ òä)™ƒÄ#) ïþµ@sÐÇë:y˜¬2ˆQƒÎ—ãļ+‚ŒåA Ò¾f 4 vkñÀ‚1Ðp ¼4Q@wØ7í) ißô F»Wç.¥+¯âY„ ² ȧ¾°ß9:ÄxÁ¸VG1BÈôAI8"vŠlŽ \ЙÌíØSá= }Ôâµb6×®hÝŸ³B¹JÌ—ÈýE QBƒÎÊ+•uDÔÛÖL"ç –ºD %—[mÛ sUʇ+hú¸J:PÁ0x{¹Ñp¿wéGK!…¶uHG›J{Å_„@ZOJ’„¬$Æž·!åflÿfå}Ý'¶ßeJ %}RÁn¿ª1kõS.¯…ËÖÐr//¢ÖQÖ«É—:ð9‡Ð’&­ÜÑ aBF­L}Äêè ©‚ú&¨Á@•Ÿ«W"«­/yµ«¹1Ž­à•Ô#lt%tŒHdRÆÓ¬Ñ6R°v˜ Œ$â)!ðLï´£OþˆƒþíE<üóѦH 3 YÙ‚mÂoºxxÔQØyUVE‚M¬CJÒ˜¼¦)Zp2qºO¸¥àÊšK^Qá¸Ö\!G Åâyï*tð]ˆµ›dK…Â_‡ëhY…êÔÈÃßw¨KH£fë¾Â´Û| ‡È}̡ؔ÷mòˆ8ÖÛ}¿%2<¥5ãG,¬lRë8ž”CÌ™<ü ‰`·b6–Âråq„‰FÝ2y”KÎ߯‹;pƒT1fµM) L !¦íQrønæQ§`=UÀÃp)â†x£&õ”aÞbÿpˆÙG¯“6?Û"ÕÚ#÷Æ«óæíù€ßó„í|è)›ºëw L´ëà{è'ÊfޱüÞݶóþû!–“´X© Fi! "wù,Ewã9ЂcZ-- oÐqZ£ánŸnã|Ý87J |  1ú|§9eM™êæ7ZCé€>ghFÚ´#‘-XHJY(ŒÛD[ÃãwZ‚_ýü¯ÜÑtð;…ÆÉ[23û¬±x¥ãÉ—‰õ0vØ´-4 3h•­ìu¹ ¥Ån¢(Œ!<¢£YC)ÆÝ$¬OÊ/æ Œ^µI!tMBsûZüÑ.ñ=ÐØ%!÷‘ªÖŠÆd$ Q¯›sóö~ ]CPa'¬¯Y˜ž¤‰»¬+Hާí®þŒe&¦€÷k}@BLàUÚã/(Âm´ÊÎL§mùÒ¼3Áo Á{ðºHÆ€ABÆ6A¡º`%ÊP´˜#†^×fÓy«áñ 7}K+d„„§)RÂðØ”§s¾Hâp7ú…Ç)i7›–¢Ía2e…9í.6aùñ¢=ùç>c9Bšƒ†;(ïTh#ólòþÏZfò€»…+1~å”, 7è77¬…a¤ÂA“¶ÑqÒ¶~,´åõÈJAÑÁ±ã=ÍàÁ(µY!þ!«6y{µ 'imÇ€{í£¢Y;¥o| ‘$FVàŒù ? A9=­èÝÜ0+´âÔ~ë'mr×Q›<þ!›Â˵Lý]…¯´aå¾£Çl|jÒö> ô@qË!hñAp¿™s“XÀ¶b:§j²Hð9ìáîxA×OÚ¢2^@ë("ïÉÿ5í¬ìb¹\³ªÆP:´Åy¾Œ\7á„@¥žJC„^ãs¢· ›q{ &‹c6EZ|3ø^å»2€QIÒ˜Ô‡±xFÎÛñJ,[çC© Žc¹ZæA`Й`Ì&v*_mšŸ@Pn`#²&Ò$cá šö › ãÃêŠVôr=äáƒ֓´ªäøâ Èa¤,þ 4ð´ÀØnRÄ ‰|vï£;¤qÖ{‡åý‡€mEì9M Ò÷ã@¯x6-è¯Ydzµù3B*U-AÇúžk-Ñ‚Ñî~¹qïÒ17çïÖº/ha6)¯B Ú« )Ôæ 2߯á%d]žE[4¢J­Q„'ĦZ|ÎÅ×ü=OZnŠ˜þè'·Z¯åW…¨ð”Íe!ŸÄ[¸!àF©ì•¶żRx1í¢Oñ™1ŽmÔ@šÄ¨Ý=œ×òx<_·†¥¤dÈ¥¾ŠêªJ-#þÐk§†‡ #ºU†äê§¾.!E»ÎØç6‘ˆžö¼Ëžþä'hk^;ãò=AÉLK®gH 3sG-3¶SŠåY/öŠ{ÍËÁ9Ó ŸZÕü¶„‰kxF›”FK¸èdˆ ÔʉDH7Ãmc'! î€/è€4uòü&iNDZi´GV!OẉÜnâþ¸ù™‚uVçQ D,Y°]O~ÆÙoéù¦EJ)NNÛìŽ9›œš¶ñÉ)Ûß1K혡nŒ,róï2 !‰nÓ3;èLèÎË÷†)"åg"ô1kl®bb甓fev›]`Ì%PÐä«ÏÏÓ»¦™¿ûÊ1¡ebøâÃL ]ÃSˆ§÷¨§§Õd1ž‘ïuÿA6 L§,˜ÂØPºOŠª´ýÔ¸ðˆð+Ž‘ÝJneÕ7(ߥè‚£‹¢$I“ÿÓ(=5³¯„´Ô«Öª×ø $ ~j@¾¹ºóî­q¾‚„”¯Û €S¬V¥¿‡iHÁßd?îoÅÆncI²½tÜâÅ‚Kýz0éxq‡ùéi„èY|cÀSÇï}ÒöüÈ_>‰ß®‰Ã6ÆÌUn<€BŸHç yíLÒ¶ZiÓ2™¬KÚäëm² …­q²š× PžZ¬Áš ÉØykx™ï’ZÃhtÑhCI ™ïs±È1ýmŠƒ )^ Œ£Þ‘A³6ƒü’(¾8»ÃvíÝk÷=ò˜àêÎé!×êaöñVå»4.(Üúk{‰'Ò6¶ûnëµë(xÍâã{aêk7´|ë uˤf‚b$Õ*“ûŽÒ1à[óï.Ýk À.¹–6›‚bïò 2”Ý!;ð€Uol¯ã ‰¹û,9³ŽQŒÍY~ßQßÿ€í~ê'‡æ ®Ê0þ¿— P(SʗŤZåân…:17É÷«'ðØ8ˆC±y  Ö¥XÎÐÖq1ŒD3ÚX+еU׆ ÊT\ 8Ɔ“pH™+ŒÙ`¬@jšÁ¸Çlrï.Û¹sÝuï½öÁývнӥ÷ê×ÕòÝ#€ó¢w›€:¨)âüŽýVØw¿UÖ®XvbÆBbqŒœXóñmRºî;ë]ÀA³zbý¤… ‚ß'anËø›Òæ{ÝÀ‘޵ǎ¥ÇÆ-5½÷ÊCD}?òˆåv¶>m¿€ciÊ»Êv¸Yq«á=…t«—»Ýk(VËu'ævZ¬]r)‰ú«QA[ÌùÆÀ² ‚&‹d´ÛÖÖ°dNï¢xºÑTui ½uã¢y £\_@ šÂö=Nf2cã;vØg~ò/b€ GVoX„ÞÛ¼A_ÉÊÎEe¶²t}sCø¼ú½î+.-]²¥—¿D·«o,Ùò·ž±^£aÕËóCO.7¬ÙæW:ž@ zTŒ Xá½kHÝb)%ùÝÃÃ÷ÁÒ–;p¡Ã-×wî·™‡Ÿ²©Ã:j…ßöÀlyáÖÇ­rµ£÷í B”³º¸`‹ óvêÍ7­´¶n›ë«våÕ—¬vî$F"Ș”KåZoÐ'ÄQèÀ*äötMšåwÍÀ#è_޶hky¾d+ GæEs–;x¯ïÙcbÿŽ]ûìÇþòÏ&´3ØPþï]¨ÓYÿu4Ü,ú¶*Ú^T)/)ö&ÊýîhàEéÛúÒE»ôüŸ °6B\¶7_…'TmåôiˆPÜÂj¡ …(a"#0# M$´~¢o³Ç²ÜܬMzÄÖNÍváõ»žús6q79±&p ¤˜-¶OÍ}s£{è¯í‹>ÿV¬–HJÒQ½ZµógOÛüÅ véÜY»Dû—¿ó’µë P¬ãÖ2Ê«]¨Â΄:Ý-Ù ƒ&/ïŽÓ×T,憵at<•²<©Þì}aÌ÷Ùøì¬»ÿ; ô;ÓYwÄüiøH†}{ßà6„¸Í¢A]Z×ÕeÝé¡6cš?ñ²yá«VZ½lçß|ƒ´°nKóK– &Ó1tNNÜ·±LÜ­|?~·Mï±1HÈ™¸Ãá§>kcw…lÁðµ!JDúw{q6ËWB[ÀÕþ E4ѳ]~QÔ³ (iþ’-`ÏþÞoY}yÍ6à9º5K&ãvÿâƒ0V¨ó³(]K¾T‰8Épsé8¨ˆ ô€Œal¢@6µÓøäÛ̾»ìà±{lϾý.h‰šú§­øî\oï.Û `«w× íÆEÇbÇ×콊ŽÅ¶.¢çB’'êoþÛß³ÓÏ~Å^úã?°âŽ]vî­·ÜX€¦ÓY+îš±ãO>aG²éCG¬H¦1wߣ–ÌL{ˆÊßß«8ª .nÞøØw÷I­S\*Ð9Ï;ųµU[[^°Òú†½úµ/ÙK_þ²Í_^t#ƒê³&{´¨d¸ M!‰T’øƯ”Eò{±˜·}wµãxÔ>ð°{èqR½‚Šœ3$ÆCÒ:,ºamؘëÛ{«²½ßÈhT22oW!Ÿoh]Ãc¬óß0[½B•ñ–Ïé¶.|½²¾l'¾þ§öÕßü »üìs–¦ª ñ š×m[ºƒXp©åZšêâNþô_¶þü_·xÌÅÁ¾öÒ-;åß ÕE×ò÷ W `¨¬¡4äq7¨…H1nÊvh+ðˆñ­o¿dßøê—íì©Ó¶°¸b¥FËê …x‰ž% È%öГ¶¿øW~ÖŽl“33–Ê-¡9u]vJ麲ÐbÔ¶¡$MÊû2‚«ehïUFÆ!ƒp±Pmã»;„ QÓ©›+‹öï>ÿwìâ3_6kx–²óÔß#LÄèT„?Igõ ©º‘[£ä¶7lQª', )(…uûð/}Þ>ø ¿hù±ëw]λUÑ]B·*CBmuý–ò•?‹$ï5ì´Ö#+(/]° ßü’½ýûÿ/Y&Ó·ÉqßR)2*Ö¬øj•üǽv÷G~Þfþ´§öº%ßàï¦ýºŸÅ¡Âêb{¹µŒÊÖEœŽ âv ­U6ì ¿ñkvöÿý'Ö©5-³'b»XZ Õs¹3ÁRy­x°#}H>I WƒìôHK…qt¨[©¤[¦½÷sŸ³ŸüGÿ—»»ç½Êí(TF¼EåfÈ€›­ª]zî¬òÜÿJZxÉ …¸Íj¹;q>)íÑéÖ•ûY^ B,IßP8)p»—µ~-nõé·ÝŸúŒ`·M:`±É¢e´DûØ]b@½r˜ÙÆàÚ–Öß JBRÒÞ9<( =ZEyv”X]\¶Âî9+Ì͹ب¼§òUàRTïì¿ÆþúÌš_û"JHY?‘k‡ƒÛÔ£í?¢Š ÈDbÚ¹LOM­LòÔ>)‹öaœ:)k˜§A17„åv-¡ç‚2-^ñ"Î ´•>F@ˆ æàøkΖ½fÕ¼âAgž£2$ƒÃOîu‹î©Ÿÿü/ÿª³”­ø1$L4á¼·|tlb< Ø€sÓw[”·XC‰­[”(Û µþ a(Ñ(ó&ç¦Í#«aÉ}èãèT1’ uí¦muŠ·a¿¶úvðÂûÖO70€÷.ªÊág/<ÿ {éK_±Å³g­q!£L«'s€hKu¡nLðŽ%ê¹R¼ÖÁkeŒ¶7u7üÙ½µ5 Jo76¬ÉwÍ ­[.»2µ¹’ôaÛµ± K.6áÚ€wE¶ã“cèy†Ø­¯Zôöïý×Äuíd†'êH4Ý÷«KOrbÿ5œ œÇô¬¤"¯Iâò(±‹åÑO‡Hä\¾Êû¥ßƒL‘Ú}˜.“Itù½ô‡f@¿ÛB?×é. ÛÓ­¹,@w$÷¸Žâ¹ödvû$-½FÈ9aÍzzNâø1§÷á /#e__®ýþ:¬¸uÑÄ äú¿óª‹ùÕÕ¥á,Š8Žg—ál±H'34±¡€J×.›Xj›i™¿(E‹ ½4^²t‹×qõNïX•Ϻ§¾qe™ß†{m,.Ú[_yÖ*d"•S„‚l&g3³3 KÌm¤¬¡B8¥oqŒ¢›ÂE“ 1sƒ4õÌ«¯[mmÙåé£â£|•pá$¤t¢ù'Ö«ÕÍkÇ{µï!íŒÓ/È\´Óín–cçBz¦azyõK0úÃd!„Âü',*}+%Eô¦à KÖßõ_›¿ï×àÄï ‹ç>Êç‚ùã±^ãò˜ãš/óÝŒ3`í ªÓ_ Mì![_ÆmŸÀ¸0BBSÔ¾ˆJù¾yÉ¢ó„­/F¶Ãà{ërÇðêË/Û«Ï~Õ.<ÿžYv™§¶Iik±$‚)ŽÛx~‚N¤K@¼¦?Û@¤nŸÒ•B°6ŠéÆ€$ž”O¸û›¤FºO¾É9Õ¾x Ý\¢´‘ôI&ƒÍMkc@)ÒH=W@;k×àÚ—'z„mÃ÷‚öðSñIÓ@ì¤-—‹YymÉ´ï~bvÎöÞ­'”â @ HßJÏý:p|–pRE„R‚ö8 ŽzÔ&8n³ûÙ4©^fÞ£SA2ceØaÅ=<»Ë]CWˆûó+«¶P-[}ÄÓµ¤+¢~ÝfÝ%Œè]wõV\dcÓ;€á´ÕHû⤉©»I/‰¿±¡ë[½AfÀu F1 «41RRÄ·^µWû7­¯Pqc³qå” V¿Mv±ò¬Ã,Qd솅!·EÄ²ß Þµmúä)…ƒ?ÿ˜‹Ëƒ„n™OXß ‰ÿÛÀqʬñ-®’À˜0ŠìG€ì· ¯`8d>Ë„ƒOCޏ6_¤uЧÅIؽ (wpÎB9K€‚5Ô‘ò•ú)”j“ l&EÆÐºláü×h'Æ#ÂåˆÞ{—Û6€Xÿ×¾j+gÎýájƒG¥x°iw¡üÌXÞ¦õ°Ã™)›Ú³Û&gvÚÞ› Sõ†vç`Á>h Ý´ëo|µJýebZ%­#u¢_-îiÌŸ èI¡ŠÛqÒÁÞ/B¸ mÖªVÓDP.g)²Š‰ fyŒNýNgœ×µ"Fš‚iQ·¤:´{GÙxñ›vúùg]¨u^B;Öžý§(œ|~íŠ38Ý›Øož£Ý=Œ@?˜ÆÙoÀ=¼HÔà8·ÇúÕâÁÄSûQYHímb7±¹IKìÃCÏY´üZ¿þ xÅ:¡ïë­ÿ–ÅÚËè1‹ñ¨ð€Ü=ÖOcà ¡cÕÝ?<„èÁ&ý?@hœJÏ xâöÌÏÛ ‰Á,üÚ­§ž–à /ÒN4ô`ý¸:Š%ÍKk™éQüºq¼§g0Ep6<…! =×@–EŒlA&íœmTn6‡skP|DÉ‹—.Úü™SÀ[‹Ç3ùnG2üG6Mº§±µâwóÂ%kÌÏÓQÒ½½»-15f©TÜÆ`®yàznnÊqru ÙâážKÇ-(’ÂLYl.aç«%m@j+õ²å9?‡…«ëÖE"’«+¶qò¬-|ë÷´®YH%êØ±£« ª %kG÷¸º¢}þô!N;{„-MV-^<‹°´ëÈ%k_|ÝZkuú'aF(בŠ36¨78VŽÕêÝ' t}‹ô"%´ WTølTˆÚ6Øýi<h¼I®Üä:Ñ*\&eþ$@ý¬Eå¯ÑÿYì1"Jø@0…3̹¬À„-Z7þ8äIc,ül9¾Ç»c(5hŸFÖãÖÀ¸Ê ¾kºís]À Få]£„[å¶H îày‰ØùÄ)Û\]†ºnGûÙtñ~M~ì€üI±=WÁÖϵðò‚Æ¢>¡P5öxÅò¾%Ò¤†¹„¥'ð0Xº— ,ÐÃu‡q PFiÓ;Ç,­ ÝmEÃKi[¨M) Õ‹—̇<Ö*#ø@·ÙÂ[Æé˜0íÑÙ¤H)!D·^õ¢Aò7íßñÀý¶óîííßý_mpêKÏ€õ>]"­ÌÇH5©ÃÒÈ8Œ?Ì:ÏŒ<Ò1ÐʅᨀRæ9Ž­ý°öÒ×ÔÁa·—ž5¢§§@Ï~é Œ=a~õ›(ð†¡…£œÁI0ÓÚÂ^_`dèPHÈÑÆúOƬ±ž×ÕºÉ(æçvsRÑ8(E(ò‹G¶‹q”áä:|•á¯ïQtÁj¹jë ‹4ªc)È^’ôI77jmzxΡ` _;bVϱFžéõ,Sšµ Þyß.›Þß·wOZrJ-¦¬¦›éœ»k˜FvQVèï ¬£Q³<¹3q»‰g : Œ®myŒ-µ‹ç²¢ñ4h"²¨9IG·hç&Æ­™Ò•6²ˆ4ФeXmÚ§I'ÿè÷JÏ*ßù’›XrO#li…Žînts ÌÅ~ŒÔ`jê¸/íd¡›>>)bý]µ4©PDìOŒ‘«ïŸ³üÎŒMÍdlrWÞ )·¡ÂÂzÍVJU«TðÐx‘ T í:êx·eã–Ó&Èäø RËU¼_œÒ#[ÇR)â|×Òå ©Çµ¥á'IíS:hW; E§dBÜÅI ZšU;q‚öÖZ½ì¤ôø¬[ݵ~¯B±:<…4´ªÆ´ð!c´p ö¡ >©nçHX7ž°Xá Z±Ç¼óÿ¸- ÐNÏGØ|¿daé¬_yѺëpÚ>Ð(_æ~ÚƒKÁ›üØŒ2ïw!‡´Ùëï²¾6¸„ ¼Æ ªBÚJ߇û šp+B“FaIÂÇèѹ®“Rü¶P°¥ÿ!"ŒáܼøVƒxõ*UR=¬Aü NÕ2½2ž·†8ÛÄò  h½Ö°%x‚³•NÝ^#K l½¿hås–Ï&¬¸{Ú&wÏX/Þ±Þ¶¡ £“3vöR r•±ñ™½–Ìaáñ§‹–¡sè‚2Ú,?†Åâ–ÞëÝ"ÏMZžl`:ž±4Bë‚J½Lš¸*§…$!‚›Je-OHÑfÏÙîpT³²¾naµammƳ+MÕf–}åáp¯VçKmzÕt¹R|õ{s0ðóÀ4ÞÛº9”ªøK–#&+7ƒ øÑ%Ðŵ$%hæs+½ ëÇ€3G1yeÒü¶ Ó²N’ %=vßÏMS!åëb?–Æî´|L‹`”2ýZ*­Á¢.Q²è7à¼÷á .\W®Eœ“Úú…ж¿\Ù²¼FO¢ZÖ 4N‹45õ!°K#T=FµCƒõH7m÷^Ø{ÀÆÉšû€+rê“+¾]©ÔíÛrÞ^úWìÌï¼hkðªM^ í£÷Üo¿øãµO|à.»çÈA«ÂuöÞ}ÜÚl˜ÛºÕ $I¦0Ž©)=fÙ ^€z!’öå©…-+»½ˆˆó0`õÂ?ÓHŸˆP“T®‹‚å$Öm„vî_2m+£m;$%ê´,ìÃ쳈·!Þ Oè©"¼k´È>ØÍ÷héú#L5ÊÖÝ| ®3bÌZ¨¬p/ ûOBø–þ5ø¦íÞPPæ^ù¤”-øL}Óq˜ng ´&ƒ©œÇ'á UŒŸ,¡I:šN.i…³ÛÈZÆ¢Áòi”¾aF¥¹žž¼¾¥ÚkŠKů"—»ÑQgx¦Æ½ )ÚôPsíZB(RØG‚ºíùÐTѲ7 ôf€ÊS3¶cfÊÆÆÇèXÌ^¹R³o½uÂÞ^lÙ"Dj¼ýÌFÝέ·m¾x嬽ü·ì̙˶º´hO~èIw yNÏ \ÅÂik­Œ»›#§öî²±ƒ{¬H†¡7kfºˆRè—V%yÄnm©’òâ¼ÈaKi ‹ïCúPA‘-Ú z(b —·¯ÿÞo¹ý‡{Q}óA8m§Ý=þÝi[Š´–Õa¸C}R2À ÅøÛ×ãîh3.«Yâ>¹.¬ÿ±ù © <ÂËZL3 K¿M{5èU¿„Ü“T—Ýî´0ċ婟\?$ Á£úåH$môʆ×÷@ƒ¸š~”ëÀ zÔ`¨èƒ£‡º¼¦\ûÝpEÐvp¹#_l½Ëã—–íÍ^ fé© tžŸtÓcôXov,B9>Z˜œ´ 0¾k§íÞmGfÚ8ÙÊ?=g?úÙ{ìþGfíÁ´£:jž˜ƒ©¦ìÄÅ5{×Z­k?ù3?n{î² _ÿªy‹äá´5VkÖäU§ã¾ö!ÊÙJq«--YMÏím ,²“!*?™Ç€Ú†¼œ´^P·¢ë¾~ÍD60‚}Ëötl| ”Qðª6™«ŽgdXH—'Ѐ—òpûƒ¾wKìµ®fI¹+‚r‰Ñ Ãb°Ýˆ‡Ó ðàAÙÙ½à¡^RÏJÂìä½ý1P eö0ÍnÁ÷”ÛkVOãû^—0˜,‡P²ÑG“Ú2€yZEnÕU›÷ŽÎálŸ4›ôÜ#LL¤Eï]„’\uhîâ(ÕňÑ;v¬Íˆ”¬G˜‰©ken KÖX·ž¦Í!–å÷©â¸Í`{&'l,ŠoÛñã FÌJ—6­ºÙ²•…KVY«Ù¯-­ÛýÇwÚßø/~ÌþþÿþKvðÀ´-¼ü‚µç7-¨v!ž=«×È©ñÞqâüþ{ï¶9 /n’h® äì—ŒA„ަl¬áMˆb‚ä ÀÀ1iÁ½nã¢'nhX‘hCŸcvéì<¿^­»Ðá͘…ë_{­ŠBŠüŽñ{ ZÔ@ñÄvŒÊ‹¯QD á+/ÓúÄÞ# r‡ð¡,„ìmØþ„äý½<Êé\Aád"°¯aÜM-ïl­Q(c0ÈtÐãaÁ+ê–Âi»FÐt$F¨µÊ@„É~#í¼Ø˜õ’Ó"©'òD»•¾Wñ‡J*[#M×b…fó²ÚƒÛ1“ÄÜhžVÙzÄ^-ƒÒrÙ6βÚÙÓ¶vá¬t6–Ÿ:IŸâ-+•[Ö(µ¬²Ñ³•ås–ÎDöÁO~Ô>úÙŸ°#wï¶åó'ìò³_³ÊÉó6¦‡M6<ëê¹:dÝ8)ãØ±3aSûCâ’V_\rB•S§0b5p/‚(h’ònmäu†§(¥•’Ƶ?ƾNÚEÔ-* @7”ÝèÆ]šH d/1BH ¼®~b 1L€Gv:“x)! 3<0B€æï…šƒú)8Á ¦?‰!€Dë@zF‹1eöÁ'“ØS‡ib…jä³BÎ_¥/ƒqú_·n¯Jˆ@Þ¤¯¤Ï…ðé"Ôãûeõ·,ÿH€0a¸ 8'ü~«âj“绂­Ïï¼S£òíd:e @kxô.±H©%SH.âbÚàx’øŸ€‰kŸËôTÒB`¹¹ëÆZ›]+ò¶kßn;vü˜³k¬¼nk—^±ù_²µOYx"„Uk“d †ÜµgÎ-òèc„åµ5”¾`+—/›·^A!0d„ÔZxºg“°ä$¬_cçtŸ—gõŠ#}òlT‡P~úTåxmæÙ~/] Šhy¶VØàÙp†vT$”ôÑÙYKö;ÐÝ„û ä~wÅâ\ÂÓµ²§ß"ë‘®B„ÝC3!’jà HÊþ% Q;á!Mbذ¨±Ìñ3fíË\Óæ€Ð¢¬GOñ&Bó§P¬·ZMK¸§«‚„‡žËØ­p]ä¯ù!ÝW M¥#Dˆ6A*8ÙŒ @ënU®Áˆ!¼»d HÚ' û†Osaˆ!Þ¥1‘#%ÄuúüÉÓäÓUk­oØôá#“#ä¾Y›;ôˆí~àÏlnfÂRÆdŒt«¡A¦EçÊVd¬UÂ*!Ÿ}8mUBÀ8F3Fº‰X¯Z³V­fÉ“î ¡­U Áx0ð&¡A+ŒbxµžcàÓ®.BãORŸÂºv¯z„Ú›¤íõÀ~ „#ú•ÍtI-„¥\]­çoy–ˆmb.r “c=`YO;íwĶ |‹‚!¡Î™ãZÑËß=-«Ö/Ï[T¥zºi<Ïq%W7™¡ù.µ–rHë–‘7ê6ÐøC§FX©¸¸¯Ûʻ⠌NˆF¤¤žàÞfh{ÎZ EcÓ¢7ô}‹òŽÜLùšuÒCˆòS“–å5¥A¦ÛÅajïÝïýfÍ-­oÙÆâ,1eklç=Ù£?û vðñÛჲsÚ䎇ð¢´Uίšm¢ÌÞµZI„¥Õ±l=–Æ×ÛôŒµ&àe„¸ºaMbfwiÕ.>ÿ²•—‘gǪd ÝBàMAË]×nýç„*9ð·œHÑD@]A‡Æ³YÛ÷Q7,ÜA î±0ˆ%Þ´ ®ÀÅQ. H͸!Ù^Tà:3Øtu{íMœ×2x`‡Ø®<OŽR„¼ŸØÝŒï±püá@ÖÐß\ÖiA„¢!‘~JÏ9ÈO= ‰ŸÆÐkré—1”ަÓ;ôOÛÔrlSYˆò=Hæ@Ðã7d CºU¹5KÀŠâñÀ&¦gI•r¶yÙ€€ÀIÝV§mbV%ßM¢¼ý?÷èt)A'!9ýJíLjI•òIåy°«‘Juh¢G›/T/¬Z]0)O¦^íÞ­°%n¯±=¹kúÈÝöà‡?nH`vrþ€G‘²ù-êòV'ö6+ô‰k$Š{P¶¶¶C!pOÃÓ˜“ž3äiö^¡Alã©Ôïctqòû²¸ëã?jþ—?a;Ç,çsÆ*$Š0,¯O¾êôQ¼tákÒ#ÒAƒ\Š>ùn-bHHÏí'ç&Ê—­SÉHGj C'=ï%D^FKfCi£¤MסïxŸÿ•_¾­5…|ÖÎ^ºàbñÒòñ…/©[ÆMu"ä81G£Uš„Ic Ò§4FѼ²fu QOŪ,.Ǻ¶ð–Ò––­ž¹`éñ¢U–75 `˜°¹±é¼_IÅPxŸsì £@Žä-ØÜÃÛ'ê§PÊP@G{ÚªkódgP‚€"xbœÆÚ¥ ÂHÞ:Í<„~‰,è6Ò6Žéw>Њ÷¨ÞDXV‚S÷òŠ©/‰YMËŠµyË7+–¦­±ìn2‰òq_­ÆkE/!FKàw—tX¨àé2ä¬ÛÐBúÔ.Ã+j¤â9òÄÔ^ !œ=…Q=ϱ[·Äø 8•-×ËM ë3å¶ @S•÷¿Ç¦÷ìs'Ó Ü*,C@;ˆDK²B<±Á—"ˆBÁfÙêt¨Åçêü²5Ö6ìòÛo[gU·}£ƒœ#B‡R›0qM)w1Ýÿ†Æ±ŒÈóäÃ2m™®fk½~ff €,¡D%Râa]„[G1-P£ê÷Ý3€0ù)ß&,Ÿˆk‰BÆ>û7ÿ6Я'†J(f}ä36~ð>·[Æ+D ) rsx|dBÁœ ¨Ûź‹nd4$튔.zxt7k6G_,Úıãöèg>g““|7òu)ͲÅÇ´Ž?ƒ® |b³ŒO–»Ç´}]¿±` <'§»}ñÊj›cÛÄeL^ÐíÔ!Š]kc3nwó:}"Ã1â¶ž¨"Ö¶ ]¡$X÷NjËû‰îµCë ÏŽx †‘*¤†ÏL¨àýé#8Ð&ˆƒ!¦ V߼ѭãùDxT»&ïCFªùöú ¼ÙšÀaî;Ð?xãôì.[Y]µj¥ìrV aÇŠX«KXˆýÊ}˜¬”£\OÉ HM£68'†‰’n#Eí÷£1m ÓGéMÒ:Õ©¡Úð¢çëȺåå"‰zŠVÄ‘ƒ¸GQ¶Õ*µ6@À¹=KgïnCKÖÍ`xqƒøÐOÿ¬=öÔ‡Ý-ÚÛ¡P7dgvÛÚ¥sh¡J,‹ˆózê™ÛªÂçoàx+©¬' á­d¡d°ÆÜÓÑô[²y®¶®ñ¼,qE*Ë"¡.Êè¦ÛR>@Ÿ´>FàB…a©^MIñ’½—!Ô o|?ΦGQÉ ‹Eóò8äÛØ. á¦E ¾¨ñÆà¤t×,zA‘°†ß·hÉOLÙÂÒËâ•jêJaè¤rlMˆ¸ }â% Y¸°×æ³î îò™(èÆ4öU%$è–°f»ƒ" (ÄÊy¾@J-Ñ­bzÖ?ÎoHROÒÐ3ùâÀ°Œ¥ÎµršA²»€FÐ$bu3ˆòõCü =øÔS¶ï ¦I%„«e4`¢}ˆZ5˜µ–Táýîq7úÍ4Cð@¬9¾‡‘hqª˜w+ªP.mið‡kê´ˆø4Ð-Y+mŒ: ŸÂ‚P«÷p bÄË4᥅µzBš“ú^Æ!@C$³Áu 'ýìa ~"^‚L½ÉÃÖO-;}Àf|Ú šIO·.´ý†à”ô9–}£âÙÌÔðS´Å…Kލ)çÔ¶nnÏ)z>™LXv«½4W† k˜µ®•Ä2yÂìpL ·Žh°æüC®’– ŸËë»ýÜbQêqqÃi xi©•†£2„&JÇ"ÅL<7IÕ%XBKØ®£wÛ=?aO|øÃ‘®ßTÒ¡õäf÷ÙÆùW¸¤ðµŒ[¶AŠ«åY>žÙj`TÒ–Ö#jÒ…´·9lÖÈF²â*p/azŽ 6ÅKs&(w×"R¯Œ@áUÛâ«?ˆÄ!Ä Ê"Bu¶È@ys@ÈÉßÿ3¯±bñÙcÈ#n‰LÑ’c;lìÈÓV˜œq×¼Ý|þó×í¢>ªUÃÌP©ñ× Ie›X.ŠÞ…—õY«ll8Åcô4œF£M§Šj)–æâuçpOh¼¿¥Pù†+õ¼€2¡%Ük‰S'ÐãÖäiÝ „‘t8NOÌnc,J9ÅÞà ²§p€‚´ÀT©?°ßšõ†%³RžoSؽO>aùô§!~Éwúpµ?[ƒ àmX|PÔX|ËâÄX?; ߤ=Z‹ªeÈY†HQƸø@ žPØ¥obþ!mÖµh®«€PÐmLµ~ODw÷Õ~…=¬¶ÏT†ã-§Ýç ñ\šþó5-þäødšß³¤z¿¸ä,ð!›;ú8틜ln·¿òË£ ¡@†e›PnRt„ qïž(1nåÒdXË­å‹( ˜×#Vez®¾oôÔiŒCUŒË0䥎ÅJ’6e]: o™«S‡rÍú›š™F@Ûûy}4÷-?½ÛÖÏ¿îæßCÐ@O"ÿ‰j›ô7g1 +jÂp’ÅJÍA¼ÒaE*ìE}R4‘µ&AЧ:5«§ÛÅütÚ²³3–&íÛÿàýnû{÷í»-ÉH)Ú¿@£†ÝÍËè ¢DûÅ ´Ñc?7nƒò¢3NÍ3tµ"—v÷ó;ͪ¼A(êÇ4#îùMKôŸÖ8kUÒö#‹8ˆ6Ä“âœO(!Óð0bÝO§­ì$ìL‘šn´/>yÐö~àS–Êä\ýÎFú¹âõÔš;(ª[†€‘»Ø(A¨(~åµöÍg¾L>=oWΟ·ZiÂʦ­l”­¶9 Ò¡¸ÎKY@8ÕL¢”«§‡jhTÙ––™)4Š‚oè@Ý\Oóy.ª…žŽ“WêüX1kùü¸yðŒ$©^:_°{÷Ø®»ï¶'>ò´ñÝhÄïv‹âä—~Ëê+çiílV€ì¦Å´­®2ñÈPw·P¦H^âÍH(æo‘>-…H^â?×,^ÐþH ðå÷aüRþ8§ÝKY"zF¤}™¯_6?7g‘no-XòÀÇ0¬¾¥wßK¶©û?e³{ï–ùwÉÛ0„;6€w ļ%)w1gtx~qžö§_²KÏÛ¥s­¼¾n››% ­n­2é ^£Ã´j5®Ê;0·3×–¢µC¶¬0@E AÔ/¶ŸæØâä„•AmÊ”"l¤Æ¦-‘Í–s–›³©={ìÀ=÷ØSùð°]GåvnTÔ'­ª9ûÕnÍÅ3n%æ&Ú›—]´§ü‹ÜUNÑlÝBŠÖ_sëûzn¡Äµ>"lG–Hñ‹NÉ‹£zÏtï§ìB›Fâòp§ ¿k8\áSJæQü,V±iùw5(³Ô‘­0½Ï&Ò&fæ8—ó%7Ú쌢·[Æy3wÊPOúâÚ¥&•íÇê«6øÓg¾j«‹‹vúÔ «®mX£QwƒAeÂD«´É…{(Sm÷ÉûK$!tç^KÊãz-=OA¾¨Ó‡ ¥aÞRd!Þç –+Xaj†ÜwÎ&Æ‹–›˜±GŸzÒffg]]#¥oý·kÃGÔuíüWÿ•µWÏYmý±ÅÁyºÍ% €ÌdåMëe¦,ÞX&áþ£¦óz hiÓšˆ>k„Ïó@7úª-ãô B = CƒLƒžI,÷­K³Áð69~Âû–˜8`AaÎ:åó6ùØŸ‡øMØÞ§Úй¼sžíåú¾‰k¯$oôÓuzôz¡Àöº2Ĭw+~¤ÑT aº#øþå«ðrS= ãÒʆ½ò‹væÌ)›?wwéY‹P°¹±I–U‡-C~P6aøë9ìcH”.ieFã’zœ ¤(™æÔNÍN[â§¹‰Ií8ÞlÚÀýñcÇÞñx×N^× åv @ÅK[¾ó‡ÿŠ«[jOÃu÷[ ¯ k_>mIȧu6ZïiéŒ,¥×šûÃU¿zæ‘…Ä{å… „†•I­,Âãé£ϸÝFõW-¾ã!¡iŹÈŠ á`|y$ížOýçÇcXºéõfé9T@¼7- €Æ&¯ˆ `ë;'@j‘‡n/úu7×'3Îsž€_˜_°·Þ|Ý.]$ÅjØ:œ 7Ðj[M€¨.·ác8\ÍÕp”ÀݡӴcˆ’¬,#ÔOY*—u¡@Fßuü¸òµréúG«ÜÈî¤è\QNuÿ _„åoØÚÅ–!¬ÕJ lƒpw¡H͉t!Œ©^/Ä`´ ¡*†2"x‚î~V¶0¨¬ó}Ú¼¼æ61‚ÂE½d^ñoÊÍ•L~””´m…C[zrŸí{àƒ8×µJÇ>oP\Ž! r“rØ‚ŒQáo r{‘òo%V…úD6« ¸Á»reÞV——¬Y©n‘gñ€;­öц¡bXy ¥g´ 5Ÿsð¯‡*iÝÀÞƒ‡ìÀá615M¨@¸„ˆïFÑïUFµú(}õì [;õ¢µË+„òíY€Ñ¹{Qx»¼äfâ:’۱㖩aÈZy\_pë/ïRD‘ZÈ×Ru…‹8äu ÝBb¤™ Ÿ™&›™vÖìÝOØŽ»Žƒ˜Òƒœñj_ol:„Ùràwéx«\c×z‹.´õ=ª¼¾¼ ú)B‰¡ÇÈúø[Zçƒ{ø¢®!#¢1šùkù%H¡¦‹+2„ò¦éq¬Z¡¸+¦+Ë•p¥p…€I¼bÇÎ9Û±{§Û*V&ªvx5wE5ã{nW墾! Ðié¯ÛúÛ/;ÜnnZ¯¹)Íc¤´Õ+„-‹¥²ÖY¿d‰±ntVD“¹Y +K¼OB @ºœ6× Ü4w»Yqæ Åò“vðŸ Í!¤w×ÅkûçD»õù]…ìÂ=·QªØ’˨?îýZ £Ê‡_ë ë±þzå;O§B}ï*E*Nùï}V½z {¡jGaE1ÛÝÙÊgmå"!bt]Õ­-_BqÎWìµòVeÔéïi¡]Z‹%mþÌËÖ¸ø†ã=͵Ëzë k¬^ÑÈ.DuÒ6ß~Öbã{é°v1kÃ@-ˆmØ&¿§}mŒeÆ\:‡Ý÷îMí»×Æ÷µ‰ÙCž$™É‘Ô÷í¢ÝVn„ï(šß$sWœÃ#SÉu»\ëéRÇPA*7òxg (Ü)ô÷ ËÕº†‡\ßÚÑy£ëÊÛF­by—· »þÜ[—ï¥! ›?4reG>h¤ÛÊVÏ}Ë:k Ö©o¸ ¾xr[_™ ¦Ñ®Zmcɲs‡ÝzÅ}­{LÆè!E8HcÓG±ñâ„L‰ú‡ø6”Ë(Ì^×éUzÐ먌úýÎÆÎz\\ñºn.SåZ…o/7S¾Ê0c—²$Œ­/·Š$ >*£kèz׸­õ;2¨á»¬Öý¹UôÇu}òÝÁЋ”¦^K2õyø› B¤~ ¬¼¾h›Ë—IyW,†g‡0ÿ°Õ€ÌjÇ‘:ïiët›6¹ç¸ðƒ±¹V›2H3µ¶â]eôÝðZ`·ïj‘l‡ÇÝŒ\_†àrÄ+_å½¼_ºéïjÄV( jXÔÈ]O¿Z>ü}¤øwNåû« Ðû;?ܲ\=ïÎÊÕvÎ*aTÞi5}JEŠVàhO_ÍSŠ úü­YQ…:çÙ BŒ—PWcà¼jU-{µî«å:£P˜ÕÿŒBðö²]'ïe [ Ïž1ªtôù> Â(¹ßø¬÷›ÕUp7+Ròèl½ëx½ÔÙá¹W `T—:»õqËôÛí+÷êq·:åÖí¿¶Œzpµ8\¤•xìV»‡—ÂúÍjW_†m»*‡áçk‹ûEÇqð¨­ïì®Ï|åœPß¼ãä|ñΉªÕ¥{ª@äëÝeô½^:]/Yœ:¤²U¿+Ãã†ßß¾ðtííµè³ÎÕ÷î‹ëÊÕㇿËÛ†¸½kê˜áqÃã‡ç]þíÕumy÷R½»ïúO!dX·[J>Ôò ŠŽÓkTã“æ¤kÛÍ7ÈGßhI™du|Ýç«{ÝŽ&T¯–!ËÖ‡¡%¹¿õI_n]h;¼¸úø{ëmøï¶ßß»¨ùÃr­\[®UÆöÏ:hÀúü.^mÔMФ—êRýýgW®mëµ Uxx§àÆïêtrãòÌ#Ç! P®ϹAyׯ²ÒëORÝzøŠfœ¶³LgÍ4Þ)ɽ¶~x¢c‡¯Xè ÊP£ŠõÇè¥v^½àvCqõoµùj¹Ñut̨®Q¹ÑqßÛ2’Á»Û¯vlËÆ$iwË!oY0ñ —ÑmÓãvÙl/à "T¿{ÆSWP"Õª\õÓ¡¥¦u}¼ž^O:Fwuo}¾³2´ê«^£é5ªëj×^cd\£ó¶_[ßéïíÕߣºGe»a ËõëþÚÖ/W󶿯íóöúFP?:fôÛ®©~ú<¬o$gÅzé`ûËŧǡ>G¢Ó_ú¶¾:£4ð‡å±¼ÛÔ~X~ Ê ຘý•)gA7ŽH²IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageSimpleFruitsSmall.png000077500000000000000000000173061375753423500272420ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞbKGDÿÿÿ ½§“ pHYs."."ªâÝ’tIMEÞ 0\â&ESIDATxÚå›y´egYæï÷í½Ïxçª[SjJHUe „’ ˆ  (ˆšnmm[Û¥Ýíj[mÇn–èr muÙ¢¶HlH20B’JR©JMw¨º÷œ{æ½÷7¼ýǹu«*©"ûg­»Ö=w»÷ùžï{ß÷yŸçÝ¢ªÊ·ðËô[@åÿ'ÿ¼ÐLDù',9z:¾ŒŠA$ùçÀ7¾Ç-;Äރпü1Ä*Øb!A+{ÀlÅLÝ€©o_GXþiKÀeQ`’„Z½¾ñ÷oö%£* òtW‰€!t&¶ï„Þ'í!²‚R"b‰:Àøœ¨5$Ɉqa/Ò¼Ùô ìÔ¾olͪˆËGŽpèŽÛY{àAºKKD’”æ¦MLn߯önâò½p ±1ß !ªÊÓ ÄPàþ2¸ "î4bj3Le3ê× Û†Ž;Žz,j·Azfö;Hv¿y†ÛÖ^^æþü=+Ÿ¼ƒò§WPçP§àÓ ç=“[·0}ýõ\÷3ÿŽÏ¿~¸g À8ÊE¯Ñáþ>’ß±‹ºGÀÔ ö™‘ØGý1Lã9h\BÍå0\Bãi´·¦fRÙ‡6^Fvù±_÷‹=pûí<ô®wá¿p/fa‘šwÔkuÒJ•¶+qÞÓétyÏTµ>P™cÿOþ×þ§ŸCÒô`Î=nÁˆâл‘â‹hh¡ÅA4‚b‘æ>ÄN}h¾•=0ñ³àÊõ„¸e|í¢åãÄî˜üÜ¡÷}ÝZqï‡þC·ÝFz×ç¨y‚™²dnf–«ù?sÍïÿ6S—? ±†¹Ms¨1äÂÜjÝ5ÿÆoð…õ„¢à™Psv™~ùµÇ1åW!‡² ¦‰4.El’]hȉl¼…Ö®@¢é<±w c'ÐXCCe í}•èîÇ/|é‚÷;öÐ,~ôãÌÜýy6-.2_¯ vüЛɗNqüÓŸe°¼L¡ˆÊÜ ~~&'èÔjˆ1œ~÷m<ò#ÿ×é>ó*p¡¨T » ‚Ð"Æâ=FZÐÜ”G‰6@XBIañ>4» ìv¤ýI4™!ÆYL}7±û„“„5ƒI—åH6_…¤µ›õ;+yÿØúÈ# O.Ðõžróïü6na‘!ÊéÛï`°Ö¦/‚ hd“Mª““ì¸ö9œü»÷óøûÞG#Wþéÿ 25 ‡³'@Ÿ Ý#àúˆöA"bÆ&ÄX Ã¨i`l•¸z9íO$$»þ#8ƒ®}Ž€AdÕ ­€Öa¨ÄáñøçˆÇÿ⑞WZýÇOS}ü0űÞ14†Ù«®Ä-,pôCeueg…n9bÍt}Hĺg ó{/eÇKo¡žZÊOü_üoo#Äðô!p& 6@Ch=î8Z. >G½5B K(— =Ll£¶·I\;Õ«Ðá䄲Á£ðÕ ôrü©ÇˆGïfôåwF]4NCïD¾·ÔBdÂŽ÷*K¤,XýÐGÍÎЬÕ8m@CĘH*¤àªÙY/,ó¢K/aS?g©ë(O&t:dõ*xÏèÔ)žxð¡ pQÞË>A«¨!‰GK‡D‹†1éP§¨/A¡‚X é$bë`,š;” ÐÐC£b¼âÖ„Qßà‚a©å8qøÃ`ˆ*xïñÞ#ÖâV£§],¶Ûh’0c-“Q˜ãº]ÛùâÑcƒþA„k®}{¿û5”ÕETÒ,Åå9í…“ßX3¤@Ì œ˜¬Ô•`ø\Vx0é˜ap$A}Éêèp ÉR(úhL‘dŠ8ìBˆD *t;°Ð.‘ K•>Ê´I‰!ÐVC 1277Ëæ+® èaºG’jÄ=¾À¥ÏÝÏ•¯Ý“ ø•>‹G9ø¥/ÅPívXòžMqÖRÅ7€Ø ­ÍVŽb‚%9â#¦Á¦H,ˆ1Û†ÐA²ðŠ–]ˆ¤ÚÐࡾØ[Ä0ì–äkŠÁ ˜ÙÂÔ%{X3Ÿ§[:ÒœÂ$ÄÄ’e~УÑj“TjL]ólœ÷¤§O³ÖîÓ¹ï\ÈD½A„ùúm`áî{è÷z”ªøl&&hÎÍ=e‡½BRŸ§ˆ‚G; 6f$£’$€(I%j€’$PÉ€¼G½G]²‚HŠ/r4*R5¸…j…-—ÝÄæ«žË£ïº¾T !fHŠÒR…Î Øfƒ¹—½„ÞCÉ¿x/n¥‹/Pݳ‹½o|¡; ŸZ>÷Ž?bÕ;*õƒ²¤¹kÛžõ¬ 7Î"˜j¨áŠ*9uœ›fÔ/tV«ä=KÅá[Í ZB„Gh·$Z”€%¶ºøµ.‡<ŠzCayÎ+¿‡^õjVKÇ@ # ª2PÅÅÈh8¤ßï³ÜZåÔ‘Ã ÚklzÁ·ÁÜ4íñý©MºäÊ,?zˆ˜&$• ±^£/–Ë/cçÞ=gK¼êz²‡„3r˜ÊYB,ëíd}å Op?*I“9Ü À&UÊN ÒÌðƒ!É 'M1ŠAÁ(#RɈý6åÀJ%Ä’r4Mìþ-LoßÅôö-”§Z$q¼p< Bª‘Ü9‚Y\$䇾üBY"Ó“´#ìɪEΉwþËOL»4 –Ž‘÷׈£œl0βeY&ˆ(&I©Ìn&™ÞIe÷•L_~ {^z+¶ZCÄ\P¤iNNò‚×¼šà<"–‡¾ôE­S$D4zª’ ÑV xO"ã¤=)7Õ¤¾{—|Û¼þ­o]W õ¬û£òdäâv– :Žº hîò뙿â&ŽÞ{O|áS¬ >Ìpá8ÅJ‡L̘¨’TS¦vn%Ýv%ÓÏ}1{^ò¦vîïÁÈúUÍݹ­ÛyÑë^ Õ ,<òñ¡^”óTeL–!1†4F¬lb˜ö•ì}ùËùžþQIÌyj÷†uµQúECP.è Êzl^À¬Ð8>´F8}ìw¾÷|þƒâð×"É2.Ý·“Ï»ž«nyû^ôrSóOQdT×ÊóTéñYÿ¨sŽû﹋ÿÉ;øÒ'?Í`8«âUI„HU Sµ:{ö]ÆKþ?ðœo3s›×O¯ѯÞzŽ/pî×RÂE½À~{÷ýÈ­´î}ÛëSz,J™Xfwîà¥oÿ¼æu„rˆ5çûúä÷ ²~¿'稑~À£ä/ë—X¾÷nvV#ÖZ^òoþ-ßöC¿Àôü&$zt£à Âô#Ìá¼w"†~gýú¯òøŸý/¶a*Iè9G¢T1F(×YWY„[øöwüû¿û{Á»ñÉ2ö"VXØØ}U$a¸ø(í»~»vN11áÉRiŸç ;ždêy¤—ÿ Õ·Btë*°¬›#ßcÄôœ[M†»>ô!þíÿ¡ý™;™˜-“•” ñ"÷ó^ÏÖH݈s“_¿ßçÏý×Yûø§àø1>R‹ë¶_Bœ™%Í2&öì"âà£ô¡–X®Ä•޶FúưíÇßÊwý÷ßÀÚ D.`])*–xú^âáw ÅQÔÓA“cj UPd .<êrÐ dR¿Ó¸¶|Éܵ Á^4$¯g³âSQêu»üñÏýð#È¡ƒÃÄìJ$@“Í`›(D=‘>:\…££ãø•ÇÆ!ðtˆÀù­'3‡:ÇÄæÍì>ps›æ˜KSê©¥–&ôÈ3˰‘šŸ”h=ñ9L™Z$KIDÆ¢(†Ì+þÑÿÄå–?ûnüéc„¢Dl•èS¤ŽÍ”rm^‹ñCbçA4DâðqTŒ•—þW fH²‰Š˜ˆF]Ð>:Èð4þägÎNÓï.,‡¾ò|épÁS‹‘†À¡}×é2Õ¨±§‘°ìs†2®¯Ifè—ŽéšaÂÔö úíŸþ»÷b«U†eA5ËH'…Ùàéûë…ràè/Ÿbå³·±©’c rŒQ4Î]¢< [œ$zAtÌ$Ú=Š$)PCt ÂJ}\ÑDÐA…¢3n ÄŒ ÂSè †èã‡I]I¡ˆ:Xm±-˨lj2“¥45G%.t<Ïß5OÒà½bT)ŒeóæMWrÉÌkù"AŸZ¦¼!#¢.ðè=wÑ?üÓ{‚7ˆD4¦h>×üþ±1¤³ccF&ÀE]‰æ9bi@s;îü´Ž©â°D hP&=lmrêŒe³d¬éo°B,:M¦€wL%)±Ze~fŽ\J>{z™J¯MC ÓI—l'¦–½W]ÁŸen~«ýEv]º‡,É´ÛôŠ.!d™/)£RjÜù×É•¥Rö¾5Ä Z¦c£56 åIlµ õÍèð(ÒœEGO RE]A<ý•14’Í“õðbå!Kðö>ªcš/gdñ3DH Öœ÷øHŒ…Õ»¯ØÏ¦ÉŽ>ÀÀÍೌãí!‡O¯ñªW¿šµ‡¤R¦œ|ø &·Ìƒó؉I’6äÝ>•4¡á=ÎzÞ3ÐHÝŸûüÝ\}sƒ<âsÅ—JV­ ý2µÊUpžhtì9VªP,€]I¦ÀO ¾MÌÀUTJÔY%1OÑJ-\ œiSÏpÿZ­NœšÀ¨¥ ßYCÑú%hšÐYõ83âªý{¹ñÆÍ¾ç øåÃΈFµBu~+“&­GáÄÄàË4B(0k,h å"½¾£^›  h”òT›tºF쵑Z†KÌXŽa²-D’:":ì¢Åì$"5b¹6.w¥¢PH;¨BÙçÉúG¢œOÓ4avÏ^–øÃà˜C¿,qÕ™ÍÌlÝÉÜsGŒŽ?ŒM#­ƒ‘Y¢ë¡4§gÈú}V–—)œc´Öa˜±@ˆ’‡@M ¡d”Znxòöà_39Q0(,Í~ 1ÑXAÈÑÒI-3ÂàÑL`GCx$«Cå(õ0ˆ )1DT<~P¢5!1r^›w!Y\;®¸‚v’Ò"ô¼ãĉÚ_¹ŸÙ™)êe¹-×Aº ;ÌhT b¤Úlâí­Ñ=vœÖ‰“øÑaYÊ’T±B7"¨Mø±_ý5Ú*„´Fá« ÚÊ‘ ~~œØ‚Cû¡Õ!Æi>ò‡]» õÇEA„AŸ8 Ä(ø¡'K1T\¬QF‹©N>etî)ï¹òºçQß±h,.‚*ù`@ç±C,¿÷ýôO/Q&àÐ]î0,Kæk5úeI%/(VW™%CÑ(¼#ÚyA·ôtôÄPÎN²uûN6í>N-Epé&‚V)‡Ô]&÷*¸'–xÞ›¯¡ž¶Ý’ØÎÑa €S|''ÚŒ|è)C‘«Qz‹­MO…Õ\`DÆnzÁ øðÕWsòäy‘³â= ùµ.ýÁˆÊéÎZ²j…^·Ké=•L•µ¢¤æJú>¬ÏE^ŒŒœ£O¤4 =kø™÷¼Ê;¯¿…Ñ—;ø¸L>òôº Õj†$ i¥ HÀØiB’(›:wãJ ÕB¾ŠXA4\ ‡©4¶ ò¢Š¯Mâõ©=$Ye]=·R³þ»nPáT”W¿ù-¼ûñÜ~ø!Œ5t\à¡™žÆŠÇXËš÷˜ÄR„@é=ÙzõÚ„4I(€Qˆ4ŒÐŽÊhlÝŽ×Àå7\Çk¯#häº×ÿw?úÄVˆñ1M&cT ð iÐql£H$ÃhI,VˆjÐ2bB tJP‹[ÉÉu/ Ú˜B’ vr;ƒjw zn7¨çŽGå[¾ýÅ<ôå×p_‘S>̪*¡•®„à„^÷æ#UlbI×Á ªDÚ!Ћ‘lûVB£I:7Ëëí7ש·avû¦ö߈tâý$NŽa\‹X8|!¸¤ ¬·½‚1%D°IÄ!„H9D (kÄrH¡‚ŸØ é6*³Ïfës_¹!ÌžÑ!TÏu‡Ÿ”½s¼õ§~Šß]]呼`¸´ˆ–%6F¢w˜U""¨‚µLŠ¡#Ã0(FÖ%ðf“JV!f^ð/”]—]¶±¡pùËÞÄáý †Œ¼[‹âS[ Þ"ˆA1VIÁ¦ã™e#• ¾ˆ8çùitf?ÑTHj³L_uËØyRÓwÁ2¸‘E0¢üôùEÞ!£ŸúíãÇöû´UIP`I,F„R•µàQÆ–Xª’”F³©7©nÝÆsÞø½¼òûß°!¹¿ˆ°ußsY¸ïY”«OàÒœ¿”tø8y9¤U(G¨€‰‚­B°c(­–„RÑQ–BˆàëSˆVHf.§~éóÙ~àx#F¼+ôÂjé8*BŒˆþæÏßÉ=ïù;–âÔZ<5„dÝ­MT)š Ê–$¡H+Ô›M¦¶l¡¶w/xÓ÷sów¾‚ãSô@‘|ÐáÁüam.ÁÚÈ[ˆ"™b¢7¶Œ1X‰„!¦8­$ƒ¬‰©5Iw>É}7³ï¥oÁƒÀÓ ˜'›g‚"Žcû‹_ú2·¿ç=œ¸ï~Nž¤èvˆ1â¼'ÑH†0a ,£^«19·‰Mû÷±ã†çsók¿‡¹M›6ŽÞgùUvZ<þ‰¿`tò~B9ÄwO¡½ã aü‘?cpò ªŽ²³„k/€/ˆ£’V‰e*[!1ff+¦>Ëä%ØúÜW°sÿuh]nh¾˜§ÌÄ‹/ž¿ø³9ÁœUÉÇ‚ù:"Õ@ŒÊ°(è¯ut»ø<‡4enËf¦›cŸÂ¼žé£, ¬-`ñþ;ž:L,=¾ì ÎãCNÈ 0Ö Éä<éä&êó»9ðâדVªç©?*ç¦zsÖxA\y&ô¬!~î®o¨Éz ˆ€®C+ëRÒ¸´„ ä/f¼>=ëÿ·þ97ê³¶tœÖѯ1XYDC‰bˆ"Ôg·3}É>¶ì=@µ>Æ0>»rÆ;{½ æWz¦žI|ÂÙ]«¶O-OyžíW)žHúzÎ3Â…Ó€žÀúX›ƒIÆ #úq¥±ÆŽË[ƒ.Æ®ßÏl켜)ï"=÷4ŒW”ãjD"º~_Ýh66ÿi/¨ž £¯‚œçDO>Óè8;SqÆWq|‹Yw…Ÿrü#ãissÞyLPÏСsæ ¢ŽÝs½àN=ùQYÝVUexé9 ä³òü¦ôz†[žlãŸs8ÞóÐ3'AÇkÁœüyIð[õáéoå×ÿ™éкKNIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageThinBlackLines01.png000077500000000000000000000006711375753423500266130ustar00rootroot00000000000000‰PNG  IHDR@ -ÿéÓsRGB®ÎégAMA± üa pHYsÃÃÇo¨dNIDATXGÕQ¢ƒ0½ÿ¥}˜«­&±©o~*„]–Nsi K˜Û¥a{&FFu7·ËW¹Ôwà1tÍð[Au7ØhUðÌkÁ`­Ð­Ãœoõ ùj¢@ë ¦#ÿÚͰ…®¤„ÏÊÞ ºAZI2ûP®ÐÍ‚K*ýë#Œ\:Á+î¶WÝ%ŠÔ>„CÐnA+ÈQ;è-6¨Sœ:¨™ñEéY–šÉÒÒ[Y  ±n\ˆ4ôÆ£hG=@Ñ ê:Þ¹‘„"-sjýrD’l£H ´Æ’[}"‘Aý}zÖµdò5¨¿ Òé=Êâ¿A·¼:ÜÐ4| ÙÁƒ4Z)öÛW‚âe>oÅó)áß/Å¿¸á]pÀéÛsh$¤Û˜ø- fPØÚs?ÁéíÙ#ƒ’Ô5æù o×BcΛ(IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageThinBlackLines02.png000077500000000000000000000002641375753423500266120ustar00rootroot00000000000000‰PNG  IHDR@ -ÿéÓsRGB®ÎégAMA± üa pHYsÃÃÇo¨dIIDATXGíÕ± 0A'ûïLšlàâ…ô×P[2pf&›Ý?E±B4мB4¯JVH%+Dshî€JVˆfšhë¬ç`%ß ¶ßgIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageThinBlackLines03.png000077500000000000000000000006711375753423500266150ustar00rootroot00000000000000‰PNG  IHDR@ -ÿéÓsRGB®ÎégAMA± üa pHYsÃÃÇo¨dNIDATXGÍ’ÛÂ0D[ÿÿŸëê:ˆ¹0$!Ôó N›Àð¼®ëç<'/:ñןÏøÜ§átx|¾ÇAu@ ø'ì[…g ó^‹¸ov¬‚K0¦)@<{×xVgŒ²ŠÅpĞȼ@H83QáXg]Ãph]o©±GèÁˆÍÚc}µk& •Uð.C–JLàoªƒúb¶1Va'®/Þ#ô*th;Ï¿Øc¶)òzc®‡j“'à3Oú“ˆ~ èУ•ýa¤ ί èÄ ¤šQ¤а@lâ&hQ”•¦ò\θjïݰ#zÉ÷ãèÐЉANh0Z—:t~b1ŠT½>=QÄg÷åóöÍ¿ú«ýïÿ¯ÿ°8®Ì xh›Í0iНŽû1nÖëù¬Y¯ÇnÚum­fL¤@f uªâØ+6Á¢‹‹Ë]Ÿ5¡ED0CBç1í¶{‡hî(ÇóIíþöç¯>}v6Ÿ/Á‡4Òb±ˆ)µuG þ¿Y?}Pwgÿ73ÐBÆE#{$@@U$,%:fðÝ€„`jˆ€j€jÀtwyQ#üî·ÍÀDö›oþóßüoÿÍ¿>êû¥®u]×’óÎ)ñðfã°Ǿ” DïnÎ&ó!Æõv噘Ýñl‰d÷O–M[á¨ýv×§ýtê¾~ñ•wnØ'JH«ÛÛ”t´G‹®ž´õƒÇ¡òg÷&!x@0vTrlªÚ!"@å‚g W‹"e¿ú˜ŽšiÃM ïÙ™ ½{õÖyŸbtŽK|=¤¨äs)W›]ÍMꪮo®nʘ!àN7½þ›?›55¿{óBâˆF ðæÿçõ›_ˆ%0E¼3.¡V;à#Úw_‹Þ­"0‚*¨‚Úo[~ë`W»öñb2GäÏÿüG”RSÓǽw®ê–9ö.Tľiº€Ø†ÊWUåƒ-YÏæº¦¹X_¿zñîO¿øÑå¸}w~UÊxy³i<«¸¦âºA&·vˆxt´Œã¨¢ä<"˜‚8»Ý–œoœ70‡Ž‘ ¶Œ–ŠLÚÉÄ7]Ûè¾ß¯n×Ó¶›ÍfqËãÝ~[OÆ”çítLéfµýæí壳Óí°›Í¦d¦H\ªjPóOOÇõúWÿøwÞUÃîæöâ+-[É¥ÝC40PËD€ˆHtgèÃb ‹øÝSD°Ã 2³÷׬/ HïÝÈ4gËñþqp\íÇ5ÿàOží·ë{öÎTCÕ  !»Ê9Ÿ‡½9_ÏçMS]¯×ªöøäI–ry{9­¦ïÖ7í¤-V´ÂÛ·»xL÷#~F¸'B¾ÝlÇ”ÅÀ;_²Ù›óÛù¬«={œ÷ã8*`JCW5uðA$UÞõ1 ¡"ÚlÖÆ”¥UmÚŠ³/_¼iëêüòòþÉ|·ëKÌä0„*xÀÌTUÆÒt {÷å/ÿúâÍÏúÕË?ûóG¿üåËùâ™ ÛÕ@ÔqáÈ  Ùûp$ ŒwÍ€ÍÞ{ÎwÞcE 1é´+Çm~yñ¥·ÀÏ~øØWMLc]·ì|Uwˆ¬’ŒÙ剨©ZUlêêòæJÀžßîݤHœuGÏîÝ{{þ²˜®Î÷uÈØ,*Bˆi)jdqì½sª‚†RÀáôx~y½ÝÝ®çó ™x»Ûo÷{(‰ÉK)¢ÚÔ)Ž–/×7GËeÇÜÓ0Žj6k猜bD´É¤}tÿøìd9ÆñÞéY?ô7땚Uõ„ILµr|«äŸ><Þ}’áæòwÌ芙«—•oѼ£0$6³~–@6@-àa=> Œìƒ§ÜF0>øªŽßœo>y0¼ºxÝÔ üGñ|:]NNÈp?ì‰H¤øPç82sUµæ½â~;ì‡1-ÚeSµ—«oï/SJ7ﮇÍÕºß÷Ë£ÉÑ¢Ë)X¼sNÕbγ®¹¸X‡ÖH[Q. ÑÝ®û/.>úèØ 0æ²G)%8N9iìšv:”l¯.Î×ýØ€'ff,šJí[¼¸¼XïÖ§Ç‹ùr±ÚÜžœtM»¶]Û¾=¿ñž›¦Ý UðÅDÑ9·ÙÅ'«Iç?úôñã'÷Ûàþ³¿÷\…é1 ™'ðĈHwûñ‘º)â]Î03»Ëx—”_è§a(KY?;Iˆ¸ßíùÿêÇŒ…Ù9G\D6ûÛi;gƪnÖÛkU†­)ˆ@ÊqLùÁÑÃ,ñ›ó7÷çò~(Ø«¯/ºYhgM14ÕùtyÿøÞú¢éx~\RêÚnÖ->{úy̹ªç@d*«›þôl¡**9Z­ßǵ Õñý¿Ú¯^|þÿüèþ½Ÿ|öƒoÞ¾‰)Þ;^Œ©SlÃÔ9'ª÷Oï•< «©i›vŒ±í*f…(ܵœJâ˜S¯”ßœÛÛYÝx†º¶{gÝ_ÿÇÿBBK®=䂃‰U> "US{¿å(è`ÿ»%Áß“xá}VPÉû£ööx«Ý­ŠñÓ>¬œ+"YR?ö7«õ¤ j2©'CLjŠH V» f8¦ôéÃ'/¯Þ¬û C¼¼¾~u{½Û 1êÃN~øñ'm÷èè‰ZyrôÉñâ9Àðâõ‹›Ëòü£GO|¼ßôM˜L›Y€0H:¿¸4ƒébê\ˆc ž“Ùf»\žß?j¶`]Ót]SûÐú¶»wºüÍ»w±HÝtÁqÑÒ5“BQeâëÕ !ú‚ P$-gGŒp®3µÉ¤}üàñ|:gbÝîvu€{ÿå׿üU5¾E_) ww&£CPë±È¾¿Ý ÕÞãÑjýß]€ÝQ{ûÍÛWëý»œ3ÿàÇŸ²£1Ãf×_]ßΦ])eÛ§£É$«sÐ’˜NªjãÓ{^]½=žuýùͺi¿M ü—ö'qÈ?:ûä«w¿ùã¿xþèÙ¤ÉQi½é_üæÕü9)æ¬c÷ql»úÝÕåj³/»à©¤1Ô;9=~xÿ“‡§ÏÆñR¼£’c±²Ûo¯o.ß]Ãðé³K)Û페ÑÌÈN&µ×o÷©DïÕ|}u廊‘ŠÃ^™ª¡O¤µÂ¸ÛôLRrâ°¿ÿèøüÍuîsÉ%4OühÂûeP;d‚»âïÒ/"0 €}о+#îÈTö?ÿÅ/gɲqèøÁ'ú1õèª)%˜Îw7·7ë]QQQUAcÚÞìÁã““>—··ÌuíQÀºÖݬÒ|6ùñ'?ŒcêB@ÐÇÇ¿ºxýó¯/V»·«íæâÝí>ùãcê¯W·/ß¼þÍËW.»–¡(м«JÞm·kQAƒWo¿}ôðÉj}[RÁÍ&³1Ž‹é|µ^¢"£‡*@T…à¼s ¨>OÀBUKQÉ%ÕU¥&fÂú}.%eѤ¹ßm_¾¾q!]_|©E›îXÉ©£»ÍûÞÜßeÞC,Ãl@`føÝþÿþ¼w5Ð<üúË_ÿ»ûp½Y9d¾÷Ùý> “ºKq  QJ>:º·¾Ý,æóo^¼^ݦœð«¯/Õ®n¯Ÿ=z8©›Ûa3DÍ »QV·Ãtê>yòñ¬›DMÄ®®ÜßþòïTu߯eÄÕmnZ÷ñó“ÊuFúìÁƒ££îç¿úÍÉé$0˜±P&7m&ûqƒæ}Ü—\ø£>µa·!Ô˜£ˆ¡YQpÎðd69}°¸<ßჳ¥˜L›Âl>+1o†]Õ µý/ÿÓÿü嫯œ<Úê¸Û­ÁnW×ëwïÞÞ\\Üæ"Dóm*»~ÍàÉ“³\’™HIˆû]¼”¼‹:f©ƒw„»a_…jÙ-·Ãîh~d1¥}Ü¥œ˜øtyªª›Ý†ˆ$+!!"©){·Ý¯UJSµ9'âÀXŒ¡”cvÞ±waL{X!-'•ó³£ÙÓ§‹£Y½¾½©'è{•­êas(Ó íó÷  , ¨™\ {¸rÜݨ\" yŒ?ÿ£ç(bà˜Ð|ÒÆ’M´›`מ }_¹YÝ,êʦS?Ñ»Ðïzdûõ?¾{÷vC(’åõå·gǧ«~µÚÞºº~xúhß÷Ë£úūƋw·R¤ªøä¤sŽ»Ö傪`Ìl*ÙÀºªÕÝ~=Žë"e³[ïúTrÉ’wÃ.–±Sb+X4#Ï&³à†j·] 1™) ñ© Þy‡S̹€BS >¤”™I@²dÏ!çd&ˆHHqܳ££Åäâ*Ngð}ÞBCR¸+‰ÎA@@®~vDõ¡b€÷A ¯7—Žß9ΕƒŠƒcb$ ³Ê¦q'-´ËålÆ”ò8¾©ªå×/¿ì÷Á=Ýo¿],gÄpñf}rÚíÆØï"3¿ºmB·É«¶i›ºþÕ‹_mÖ??ÚþÅj»®«Š­n¨©]4gì¹XK6rNRrìK¨ë¦ä¸ßo¨­î-ϯÏEAW›Þùª cÌYD:ì|ÄP²)šl·7γ$ÉýÛ¦EB+BÇ«Y%æ64bº&*¢L*¥c½¹½<:z<îo±=þ/÷¾F@ý'¨ÿûiáûß¶;äêuûÝ(X"ð~ò©ªåR éÚéüرۮoÑÌU•ÍlÞÍ–Óvâ„Ên\µ][â€'fÓy{z>ONçÓ “Ùdv2]þôåÏšöù¯ó4é*zødDh¦¦Jf’KÀºjºªšOf.DsÌUUiQ4æ!æ¨@Á;&60ï\SI¥¬úÝÑdZ·”\¤x玦G©d©½*¤>x°šˆ(:Ç„I44N Z©|`&3­}­j¨¢óiõòÏÔÔÍâw-úï|ó þé5ß§Q ûv?¾ôdª€ø?þ$«šn+¢9+ŠBÎÙ»Jň`½Þ™Ùñr2Ÿ7V4T~:›8‡Zl:mÛ¶rŒ¥4Ì97·WŽ|Ëì<;ç=¢t|:Eï3åTÐŒÀ´è³'ÏÑ mÒMÆ8îb¬‚+1G±Cd%„>f*%«ç}JÉ{ïÎgS~·[3³÷>—²ßï§ó©ó¾kR‰u¨ÅŠ ¢™ìj·PU5q¾ª¼/&Ž9¦äÙX‘’b-¢Zד¯ýU³ø´jæøÛ¶%ƒ;ÌyW5 €©ü~P55åÞÉ ÆŸ™©cuàgŸ?+bfÐuœ'v\’ŒÃ™93Í%£³Ù¼ µg¢ã{'Ä䑆¾ ²áûMQÄYTP ÍÌÔyo*ŽÑ;¦Z ˆ! ýã@†]Ó¨j“S$"B¦ýӔ̚̚ÖsµÞôqHqßwÍlÚKÚ/–÷·Ûý®ï+ïL QsV‘”rSµ1•ÊnFQ‹˜,BéëªÓœ÷à™¦¬“PM½Ÿá¹¶­ç`ïËá ùŽ…P$3r€ï­ÿ{Ja`@@ÌÉ®ù¦æÊ<9~öù³ÀLLuåšÆ•bRTsÉDüêõ›ëۛɴó΋ª u8??ŸÎgHPÒè|¨kç˜"ctLÌä|Åì\IðNµˆˆeÂ(…T*¨åbŽ1)›ýfÖÍú±oªZUE¬!¦ªªRÊ)Î…ãjuix4ö×Cß›ZÖR$©J.¥XŽYBS£³ÅdS$¢Š½Ji'Ï ­¤¢`ÀΑ¯ÆáM`®Cl=V¶b..Ëüì©Ú‡xoýïpæî¿|¸ÊÌ „ö(7œ¾ þäÇŸf‘i[gG´Û'¹„ºbçš¶žÍ§ÞùË“cŽcï=;F0fb‡uö±˜xGffLXJñ¡ÄœïZ@5pÎ@$ïPA¤ôEÕ€Ô¼ ¦ª`mÝ*˜óP׾ﳙå@s®ëBбÇÐqÚï•\[W÷ÎÎ|ÌL¥ÜÞ\ùàë¶bG>VRÙ [ö¬HcQìǤ*±ï½¯ÁS˨ U3÷õQE·èîÑ]#àù¿t ¨‰ ½¡ô•[90z4mªª XöQj`B“4F_ùº©C„¬™ªÈv»[,RÄ‘C`U;µ«mC_êÊ@Îw”!±ëw+• €ã°@Q%@&Æb$ÂH"Ž]àÚ#3"Õ¢â|ÕÌNÚvšsjëIMµ§¼Ë¥°䃊®¯7R„½#ÍqÔ¼]_Çq¼º¹Ù¬6»õ¶¤ÒM[$Ì¥„ªº240œÍçU¨U ¼ãÊ33ÅXØ1”XÀìð«å$«Û5‘©þsÖ·þÔ @AþÁ?SÕ$ÅÄêN—G9Ǫ뼣ØGɆˆJ uh}ð̨ª*‚PÌ4À}?23˜9FC„ºrˆˆ pþn‹@Ýlºï{ïœJ•¬b‡î8ÇŒM HàE ˜+É£Šªf0€õ†‡p+BäÇËYÛMšöêöÊ9ÏL¦RØó8Ž)çœì¶[SefQ%DUEœµkk3†ì3‚daÏ€XJ!æx³ÛÜ^½îŽÿü¥ÿÿZÿ4!`‘m_#ù¢5 3ßÿì±w¡ÄM$§¾ßûŠÈ°Y‹ 1‘#ƒÒVí$4£¶iœwRʽÓããå<Æ´Ýí+ïŠà+çÈ1—"Ö´-³3Õà]W7E3bh¦`jª`– Œé®hwÌE¡frŒèT²!‰*«™‰z‡)fÁ‡àØ¥U¥mZª®íÅWQYÌgm×rXÊ©HiÛf·Ù-Rd:›‘¨†À¢êJ*p§rPÇ.„úõ›ýù›Õüèih&ø‡àŸó µ5ÛKQM©"ðÓ=-"¨%fqŒ¥”˜â"!zfÚïÓ¸/±×~5\½º¨¦MN¥›ÔÛýv?Œ9%SAöWכ餋I ¦TU5(™yœÍ')¥T’hf✳óUŠûR"Z‰f`€jÆÄ`ŹsRQbÏ\!’Š€A!¸ˆd“*‘9ò¥äj0Xï6It÷D0é¦j²Ùnâ8”œSJˆÎúq•®|(Së*˜™¨ ‘ˆPÝLCÕ8ç~ù³_…ÐÕ>4€|h}w¿$*!1îÏÝG¥%«ç30~þÅs@£,Æ ]× 9/EÐa¨88öûß¾x³Y­›ÎW•÷Á5!¨YØoÇÝv¸wr@Á3¥\ˆšf‘Ò¨¢•g(%yçS)ˆ`€DÄÎ#9030çkDk)"Ý©oÈ…’"8öë€†š‹š AK6ÑÙl™sb*& àÝݦnTKJ±ª*"2@d§H$ˆ¥HÎ…`‘Ⳙ-Ž!úÅlò£ÏŸÜüÙ»7/ëî„8 à’;œÿ¢œpèä°?¿|ûnÛßB7m)ˆðÙÓûuUW®&"1II@ÄbÑ’’!‹ b¦ë«½¤âØßœo<¹"EQÍ`èË»××WסòÓIåLõíÛëÉdÁä«àˆ½äHŽ½ãª ¢ŠìéÀ©³sxàvÕ”´ˆ)#zfOD)õj©j<²{Õ¢š]Þ“ ¤Òï÷Y•‰Z)±ijf*¥L&ÓaC¨\›ý0i«Ê‡RdŒ1É¥ÔÁ{ïTŠ™‰ªsìØ™að!Ž©®Ãí:lÖ»éâ!qe†wt´ý'úÏF%3eWmv·½zP¾¬Ïø³Ÿ|šKâÐǸ¤«8Ûˆ]ãŒc¢b`GËySw›ÕFD}tvv6Q³’ ª&ŒC†xr<'"÷y³ÚÎæHe»ë«Z/ÎWmU;bD–C#HU‘‘LÕ‡F$9ª²«¦œ½òaQó°÷u È¥¨2³©  o3y¢À\D‰‘ó©s.•ÌÞÝn{5É…íê$Ÿœœ-vý°Û¢"9•Rˆ¼3_§Ô‡šBU…æázµk牂ٽù¾5ÿ/£f|í)¤ý°[«{šf³îK13kÛˆToŒ€D··çšš‘9ŽÑ†±LU*U5¬«ððὦ©§]3Qc×—×÷ž¦’›Úåœß½Û†à*ïXT Ë<–RÀÔ‡M™¨˜Å¢¢fV ÌQ ☢Uåà!ؤ˜7m`¢®ë*_íãsÁ13 f-][‹iI¹ ÕÉñr2™`6éú1öãX9dç‚"ÙqÍ>HIbY¥øððÕ7狳'€•ô‡øcö/MÊf `UhJ‘›í9Ü{È?{âƒg¦óÐGˣϹHÑ!J.f mÓˆ*y*ÑV×Ãíõw›øðÑ1š3L@R9fGÁs\.åÀöûáèdªbfªÌÀ0æÈlž™ ™TT%ç]8€MB$"`vì}Kˆ`ÕÈ1ÚµŒ*ŠLHÐ„Š‰DÔ1ïvytÞ‰¨¨2R‘²YmçíüÙ“'mÝT.8vC?”TÈÐh‰ÌŽ™,Û8FSÕRRÊZ„{ø<ÆÛéñ§ŽøÀÁ|èÌü¾ø†ä{ ™È0K±ÝÅöÝþÁO>µ®ªx2©CpMU墄TDRÉMع:Ô¥(*÷}¼|»=¼ŸšeѶ«¥˜•‰Cp„ RœgU£q?6ÓJ²!#Å\ºIEÇ¡¨jŠ}ðŽˆBðEÄTEÄÞ÷öˆ9/bZ@˜‚™‚™,ÚÖÀIDLœsu U]g55óÌû¾Áq–ÒïwûýÕŽæËy7/æWç—77·RJÝ6f6ÆA¤,fK@Q4Ì%{ö„j%»®n€ÙO¦ ïTˆßËøÐÿp,R®‡ /ŸtOE Ì1±Ãœ‹‚æXÐp·а‡ëífÒÔíÄÍŽšëóýÁɶ›>Tà«Ê YŠ¡!¡ÍçÓ˜Ò3 ®¾ZÝLšF À3`ŠÚN›¶âINˆ¦F„"JDfÓh&ÌžTŠB‹11#ivÅLD‘¼GDßÔŒæC[5#ä’‘ÀL+ïSUUÁû’sÌqu».Z|ð‹£ELq³Þ ±¯«‡˜@E`K.æ˜BUÕmsu ˆ<[yr"Eª®F³\TÔˆÀ׬*MW"†à¦ËNJffBl?™bß‹ÓR6·»P…‡÷No·Ûß^NÚ ‘E1øŠKɳn‚h„䜙™OÓÝnŒC®gs“ÌŽå@ ©@¨[DdÓ"‹¨iå=G¬fYE‹¥ ì@DDŠs¤ZœgfF„œ33µ¢¦RrÉ!|ൠ•¬"9g‘bf€ÈıdÕâÉ3»"jjÄBÅÌ×·îäÁçì;÷Añð¾ãr`¦0!‡0ýVeðfõŠ¿ø‹/J.u]9ïUÔÔyjº0?š•~H¹”“û3rxuyÃÌ•ªàÁïö£gŒý°½Ýw“Årº¸z»é&Ôu¾ïc‘,*¹äºª¥QË–D8”$Îq¿Ýß?6IÁ…RÔ{ÓD€fê\ D2ÛôqÑÕjfŠÖ:o`¹ŽÁáOÎ HŽKЇ¤(k³€™1#ƒQSQHY‹ª™" ”‚ÌûýŽ Å hÌÌÌÁ{æ`¦·ëÙâÁŸÄßF5fh€`*q»ù5BïøÿpüßXV4{»{ÇT5L¼Ùî/.¯O–Kd,¥„zÂLÌ´ºÙ¥1ÂúzÏÎÏ–Óœ…âfŸ½§~»#ïÃúz•bJ—¯÷Ëå§U3ìw‚H¢B]²Æà˜wÆ<;df´ÆÕf``fŠˆˆÄˆZ$Š‚q BB…¬Jˆ€BhH&R´”¤ˆUŠ„Cî}1í€ÑèÐ8<m=s.JˆÀÌï¥èXìØÌœ«B¨ÍÊ×_nÃô“åé³÷âÏ÷º ƒ6 Íbc¼ÞnÖ¡^:®~_¶ßzlözýŠ?ÿóåXVýöáÙ™¯<V¡Únw†¼ìæÌ VØóƒÇÇÓYÍžØ#y3:»²8]ø&Œ»¡›8éšZîXh4´1IÛÕföêÅË£Ó£à»ÉôÁéÃ+HŠ·)Þ^ßœo6½Ùpu9žu˜ˆ¸É¬nÚêÀ}³ASšßWÑý~œNÛûgt»ÞŽcK³É,çd¦žüju‹ˆÝ¤ Á?ÿøÙ›7¯·ÿªjçÆÏR¿^œŒjÓðíWÿ»w!§çO&""$rdju]KÑqÔnÞþòg¯§Ó{‹{Žè>Lè}À<"Ùìƒ^ Ïîý¤ßïC·HúMêP¿Ÿ‚ À ňÀܨüü‹§¤dª¹ä‹›õf?xO°¹¾½¹Ü`)zy~;™VÓ®k›®©êºjDJ¨û°Û ã~œ¶ÓÍö¦^<Ÿ,"±'®ª\ƒäûíE¨JU9KòêËW7WûåÑ}BØ®ßÆa‡lH¤¢%ª~È«S)T…É8ì»¶ÕIW„ɽÄ‚™ $"55 Ãÿè‘beHˆ$R@Õ#¡có|˜£S*Í©öÁD«ªrìCF`V‡'‹ù?þÃåfcϾøwÝÑF ÷rè;ù޼“”S0UHb&%IŽ*Ù¡;ÌwþVwÆPãp¾~ÃÏ>.Yã8"RÛ†*PÉÀº¦3°œ¤dQÕfªIT©äÜyì÷“i @oÞ\!Иdqúœ}ãC@W¡D,yþêÛývÌýöìÑ‘ìÅ×ßÌgË{÷!§ƒ”ÀLUÈ#š˜ ±¯}=k;9ôðKnB›rB4@rDˆ„”%ÞeMd8ôZE•73)A«Ê›¾›»3ÈZ2u¡êÚUu½ZçÁ¬i§U]}ýÕåõeþø>Ÿþ@ ¿7ªwüÑTTóõù¯¶›ó~{„ª ˆµôã¸UÍE2 :¬Þ{E‘©”a÷výŽŸ}ñÌ£_oÖ@LÎùÉtÒ4•wÎh:_µ<™4ìˆÌ4æXJÁ»Ð©MWU•s” ÔNU½8 C&çXŸ}qúø'‹“g“–sî¯.ÞÌçUU“Ac)Ž]ÎÅûPTEŠHI9qó0mfYKÉù —7€*Ôo¯n½oì½>Êa8(Õ˜È!SÓ”ãPRï½#¤CKNDD€SŸs×5’²ˆ0¡ª†àÙ*N'³éúë/Ÿ<ÿ·'§?€ß[ßîÆ´ÄËóŸoV¿ªüzÖ}Ü#Ž›˜ú8d•X"ArT*ÿƒ¨Ý TW7¯ntÏ_üÅ¿yóZU'Ó©sÎn®Vã0NÛ‰g§ X…PLvã¶©Úi3afE Þ!†éôèøôä‘Zó⫟_·ÓS :ÄÜÊ…Ùü¤›ž„v Hè»ÉÓýfsþúÝäø™£ ›i*Ù±wìH¤1 Å"Èdž],‡JˆHU®×ÛI;%&D"ržŠaQeP9ÐeuÓô}H¶`ŽYÁœwMú!š”àïaÎ3S¤êíÛý0vÿØù¡¶Ã|‡ ñ`É~wssùóÇOκz{´pàŸÄ¸Åå’™‰Ú¦­ë&¥QT‡1©HQ)ñöæe¤Ì?úÓÏsÎî?ªšJLAa»ê%©*¤\öý¾ª¼w¾r¡öM‘bfÎ91)ívcŠÅb¢ÛÛÍÍõÍóÙÙ5“¥‘¿Û0ì)4Hî0Eˆ`ˆX/î‹àù·?==[†ªaï+WÔbÉ„   ò‡”Ç”C.ªf"¥¨©‘™VÁßYB•˜v›„D`ÊLÆ·»m]ÕÎ{ÉÉÝQ†ºr%&+™С:6äÆ9á¿ýò˯?zþ_ÕÇQݹïm5+Šª&i4£qõ¦骵—â‰j{¹¬6Gg“׳vxð ™MK—Á½¥ùtú”Æ1cîwýê|{ýÙSãÂíãNRÊ… "’aLåíÛëíVs,‹£¦ª*³l J)šw»ýÇ\d»¦“¦ª="äTRNÞqÓ>œNOÁù÷ é":xŽÀWÍä$×ç—㘃fb LŽÑ¸¦š#°£`¢JÄ´{cbDêÚ©¨–¤ÎW„&"º¾Ý«Ž¥ä¢¹òƉ0T^JA$„¦  ’ŠСùÂwÂU]/çÓ/¿¾œLÞ{òºæûcÙfïÕЈ¨RÒîæâ5¢€fM;çÃ~»î&G;r5qX]_\¿ý ]~YÖçîÁç)ánµßï¯w»Gþúæ›ÅþÿÑ£Ù¢•±ß¨Š˜ãaèsN˳î€)ïn¥®ª±­ëºuÙr"3owCÓ†óíå7‹£çÀÌ®>à BD´ŽÄˆÎùvrŒ8»½ìß½ø¶d%fꚆT‰²0t\18UqÌ)JK‘2ÆÈä®Þ^;Çuͦ: ©©rîâÝ*Ô\¤¨;ò¾RC ïñ€!ÑÀL‰˜ÔÈUHì|M®Žå“_ÿâ«!…'Ÿý×è*"GßÇØwE@É’öÛÛ×Óæ¦í°_µµ×"€(%k¼µñÆWöœ{ `¨ ¶³&ÎÛþ7ëý^ËTõìlÉÜÌšÖ‘ƒ<ì5§Ùâ$Ôa¶<š/Ùá|Ú€ Ù! ;GH$¥8vƒ#^LÎ9Vdô®óaþêÅßÌÐ ù‰Óœ`wSRw¸Ø»Æ… „öt·‰/¿y÷Õ¯¾½¾Ñœ§ì¦m…uU12jÛuÞù\òò舊‚øÚùʃfï OfóiƘƒ÷m×û†‘Í÷o@0E¦ƒ?rpXJFæ@.ôûòË¿ÿ†ÃÉãý›f²$$D~|ÌônJFJÒ<Ä~µ¹}ñð‚Z"‚JQöh©X*š‹¯ù0iÇíns>–rvT_ìКÎ?x4 Êõìèè´%R@c_¥”‘ÑqÓÏŒuS1‘¨ )æ˜k_n‰``RÔBJ).ð8 cŒ·W/ÙÖÓÙT-¦bª” ß›Xð>˜Àdv¿éŽ&Ýœ˜ùêâ›ëóÕõU õ¤“BGËûgÇGuÕ”R̤ÈXo`Àx·C2@!ÍØMCÕx@‹itwé¢ÏN ÐÝÍB~ .4ì»ÝN~õ‹Õ“ü›ãGŸOfLjx ŸÀTÕCÙšb¯%ÅýõõåO»–·&QM<»RЍ¨šiQb$B3UǨ*Îó8Ýd1ñ1÷ÛÓ?ýÔg^Ü»wroʈ¸P‹IÅäŽD"1-"D8ƇԵ]?ìC׫ëË‹ÍåÅŠœ‚Àt2äÉ|z|vúðì'?ÿÅßÖuÛÍ|W•£»ëOjJdPåª6öUÝL¦g“ÙÙòäCÔ2Þ^o/ßm¿ýêêË—·¿ùæ6Fh§Ý ‚!„ภÞìúq:©c.DXqPSUï}åB1-fžH,!y R3òÒÒù.ëòç?_ÝûøÞÓ?¯›%¡cb"BÕ» \r’4Ƹßoo®V¿~xÒD‘ìØW>¤”“&"F9€)#2¢Ó‡Š&E?yzrræ!a³˜5Ítuãß½\öÃGƒÇ¡ôyâ8j²ª uW›ê]ÄtRŠš¤ëªµÙdJHE¬ >˜C5éÍv;»zö¾|ñïƒo÷~ø^Að]!x§™™={¯hÖM—¢’†Íì쓸_ooß EÍ[W…÷W·7r /^êýc·XNšÐ@à‚Te±ªòhIü¨{èˆE £šý ‚T4EöÌä|3îôgÿFìêÁG4[œxß©Éw“À83-RRÊ)öÛëÕå×ÝwC„YƒDÎ1"ƒ‰ ÒúÐp¾˜WUxûí¯wÛUvËnqÜÖ3žOgM3󪺜uM „§Ç'!„ÛÍ*8_r.¥8çJÎHÄÈuÕ8ïsÉŽ]×¹¶¦\t¿ßϦ³˜£™;U©]˜Ÿý·oÿ“¯U3 ÷¾Eg rwS$"<| "±ó¾evÄ®™,ªö¨žÜoÛ{‹ã¶³‡ÓÙY†ë‹Ëëë[…q1kÌŠ!U0”£d R1pug`jfà‰³««£qï.Þž|ýË×»>ÌŽ>9¾÷ƒÓGZ5'í{|ƒ ˜•Õ4n¯$m‡Ý×7×ÿ°<‚eU“Ä,LÔq,åx²ôÌ!ÔZ·(²óÌà=×mÓ4ÍËo_¤Ø#À¤é/>9®ÙO÷̈p1_09ÇŽ‰û¾7³˜bõìѬq¨ª©‡‹ë«rh³XqÞ‘ó]5 !$‰šÊ8웪ùÿ({¯f˲ä¾/3—Ýîœs]¹îšž ÌpPb€#$FHzâ'ÐÕ›ô û¢ ÐàØîéîê2׳Í2™É‡}«»zÃ7ê¡¢nÔµöÙéþ¿ª*¨Ôn8Û¿ûMèžXì·-©oP•Œ¯‡lp±s6kc»i†K›‡¦=·q×í^,ãáöÍí$/¾÷½(,ÆZ$¬ÌŠD*€ˆè, Ö*Î[CÖ…Íiܾþòáí«9-‡ó‹——ÿyì¯vWŸ™µÚZsUa\¦CÎÓí»Ï®ß}w±s…GBÑ*ÊUPeLiÓ´…ë*±ñÎk–eY+¦ëJ.KZÖ²A›kùüî^|úã®wúO^:ïIpN³ƒ°Î5„Åyw¼{pÎô]óWõùŸþäSt`­%¬Ö¡"ž‰ÇP~Ož¿wÑü]Tùý¼ãð·Æ¨¨ª¨ÂRE<Þ}óÕ¿Û_ÿªi(6áüêÂ9ã*äZA7ßÜññ0§iéÚXZAŒþ9"˜x›Þ5$û¾Æ~/J_ÿ`–4)èiúÝxÜ/û/öûÛ‹óvw޵.€â-ãR0dòR^žkSž±VñÞ B—ÐmÀùv³½¾~[Æ}c,ƒ'CÍÐØçϺû»C)e™A±dÔY_k¶Æ¥’ÈbšEUÆS¾¿UõÝÍýÕ“-8Ì9]¿¹óÑ£ ¹J×E†º¦Ì9—œÞm†nÏ^~ñ»¿i¶§& ¢yü|Èû|è0‚Ö~8FE5¬ðˆÞDçU!<û¤é6ãþí8ݧzwSkeã‚ñþ£—}ææ:{oPáa?Ÿ–RÆË«òòÇ¿Ø\¼\ûwkcMskv‚T?˜–|:ß^¿þ7iI}¯?þá€V"£ sÍ*ê-æÊ"\¸”¢ *ê“s)åÑa‚K¤w_}©ÖÌ,DQsZÐþì¿ùy×Ï^^>Üž8³æóß¾k;{~¶Ë2‹Èv»‡JÊöþ~zw}·Û múk-w÷ÓÅå¦V½бõËRÆÓòò{O µÎyX¾¾½¸üþ¿0Ö{ë߃ßĺˆŸGoaOóX@=~Høxuxýõï_¿úw YëÀZÍe.%ÕZE@Jš+—'O?!÷=æôü£ŸÅn *èšoRk€Þ«£!ó7O‚¯y|ø[Ч|þѧ®¾5TKM)ÏHª•Je©Š@6¸Á¸àÃJkMKvÖ¨j$ƒd’pN)qkH ,ªBˆÿêþW¹ÖeÎïŽ.˜»w‡Ã©~ïO@uØ4MC¢ÅƈÂ"LìÍ¿ùëÿèûÓ?û¾Ô#UwwùÅ“æ4Ï]ôDôˆ_3LÇÑù°»|þîÍá«ß/—ßû¯®^þYŒ=˜÷AaQó^`¦†pUþ!Šêj8…ß/1ð*$ADÃ\Ê2©ˆpe.*²b¢Uj1>4Ã9ï}D2«â*ÚÖ¿Éü¨´:Þþzºÿÿ.vóÐu÷‡ã¸$kV†€Ó’º®»ÛO]ã WF¢’ÕR†¦E¥è "²¨l}PÕ¹QžrrÂx;6íFÍ“OžÛ ¾øõÛÃÝXŠ0Ãña.¥¼øè,-³‹®. u_~þºæ $ý6›¾ïcN¹°6‘²[JÌ•k•R$†`Œ‘¶!tçÇÛסÙ4Ýà£=›®æeß Â€ß èï\!‚*ÀÆzë‚ ]ˆ]h‡ÐnB·µ¾ ÝÎÆ¬[›Hdð&¢o|gª<¾Õ4ïßü›fxò–Yªh­bè‘ç!°†V\GP«ªÊœÓúüT‘GÛ¿šÈZœ³vNÉ:C>4ˆè¼7ßûÉ'fz9>L, úøJîûˆˆ%ecÝáaL¥‹g1zea¥i‚ó_½»m£_MUÀ;‡ˆ*Ì\Ú6ÞßÜ–e<{þs@t‘•VÝÛc“Ìûä™ß¿ðïP)@ –Ö|q‡dÐXE dQÕ¸@äqµ&x”®—® ð>¸WE„<ƒH:þ_ï¯wÝ-23³xšxº?« ‘ë|kЮŠbG^„ŠÏe6Ö-e1NÇ2Miq6ftæ°LÎúiÉK®û’‚oÝã#†æOþâGά­<޹ʓçy)%sZÊf»¾#â­-¥È“gO×Óš–üõ×·‡ýxûöuά(›¶E‹ËÌÆ²D xgæÐ´ñîíÃpö©oKðÞ÷ßóÿ*€øÍ‰DƒÏéÿç¥b„he=i„•iAc^Œïº› ª¢Êt¸¹¾ýmߊ3dˆ­1BÈ\08¯Š¤0¥ ¨*TD—1ø}Œ¡QåeÉ•ëi9-ey¾=_ù˜‡ãt¾é…µs^QÍŸüÅDœ ÍÆÍûi9Í»]——Ì•Ó29놭%¢»´,†`Øì@õíÍ}®|{ªÌÛM·Ù¶WCßDC4%ÁVu 3¼½;|ôâeZr»ý]×ö>æQ`,Ôœ„øÁ¡ÿƒ§ÿøéy$¦ßw,¿eâãý=¶‰SÜuúû PÌi.ã/ß¾ù×1îCÈHÜF3s>¥¢µž0xS9 fUD²†*+Yãj-g›.×â=v¾UóhÈT…³¡#Â9åÎO €«rR¿¾yÎÁn»ýÙ/~øÃŸ|œS&RkdžŠØ, Ãn{v>ø¾oR®gÛn»í¬§~3To †@† °²ö]½ÿí¯¾jÛ–ƒ±~­c5¢úþ-$ºv®ÿÖá[\¿Id?·„@”@ ~×C?tz@æyº?<|qØÿ–0G€ÈU8Õ²i7]ì„9FßÄÐ6³¦ ± ÍÊ ;GÆgíœ5+¨»þ_©Ö%/~eØú¨&"C"z±í‹Êœ—›Û¶µÝÅ\ ":oÏ/¶ÛMßt !#ª¥®ì­šcp†  Ñ[X¤Ìy9-¤‚P¥ÖÃ1mûÍ’áÍ›Cašèû™ª€0¼×pà·æËðG’o$$ú8‚|oETX•™ór¸ûòøðƒl-‡Æ*3ïã›ý1Uf®"|ªw÷D&†è¬dÑZË’æÓ<ó” —ª}ÓâÖ ™*êBˆ1xE}3í‰Ð"P+¢ÞZQlº†V£L£ÛË~™óéxúáË­³ïÞÜ^^K¥Ô›ëç½³®íòÞáÓýM:ë}Œ= 8ŸD4x·úY@ïïÞÌ£òÉ­ïÿÀÖÅ ¢þq‡ùwô÷ #„ú̇@D¥¦y|u³ÿMš}$o¿öާŠÆ@UÈÌóï‡æÝý~ ´T™™YU@Â0 w‡=©À{ñšÌl­ÑOóCÈÓ¸–:ÑtçÛÍö²õð¨Ú@Ñóg»‹§[`8NÎÛ³³ ìZ‚™Çéê|c´ÎÏãtÜß¶Ýpq~††¡m‡¼Ìªj_Uj»Î¸a¿—Ýùå³Oÿ¥ozúƒÂë1ûüÆõ»¾åˆ€Xå;Nà® ÿ-÷¨á´ôÛ[Aõ0Þ¼»ÿm”ãÕ@.ˆ0§Z‘E WÍÌÞ»vQDïOKb‘”³*«Š±‘•£K^‚ó©äR (ˆY=Ç„sßtH¨ª§“Sã¼EóÓ_üÄ{o¬¬Ÿ4g"è°ªzlÖ}÷ôõº€GòîÿÕ¢˜KyýåÿÖw‡œ¾ìÃýfÐHî8OUÕ9ûd3 ΄Rò8v]ïÉx낵g}' K) J¨¥¦ã<©‚uÖz“ç”k"C† €rftà¢1ˆKN#'rVÍOþéÕ®C[Â̲0ZkšÆùà/Ÿô€ª( Xg}⥒‚TÝl;tÖÞ<<¬Œ—ùÑÏ ¬ÆˆäÄÖ’¨ªk‚7¥ÔçO/jÕiL9eQPç®6&´mÛGèëB#PCto ƒäŒƒ8ù·¿¹~öýÑœ=³ ˆŠßº2ƒ~§ÎÒ?xŽé[׿4ÿäÐû[DE$ ãýguù òÉ‘ô›N§%MãLµ$Eró2sƒ KͪHY%¥”+£’s.DJó¦ €6-©r]‹Cg¬÷!—Š@Ue)i‡Ã1å$c)Îø¥&"´DÈ+¶«Š1Xf‘÷¢Sïv»¡ßvλw¯® `ž98ê›P%§X«°‚8C]ç4—jˆ¾xuŸK5ÆvÛçk ß›añ{ߣ‚A4D?È.õ;}ý£ñZ'¼Á!׉´œ_ô›m«ŠK*è¬WÐ%'T™çež¦T–*«qG4ÖŽË´?DdhÜù®[!ç]×FçÚ¦PïüZW®Ì ¾Ÿ/‹j¢µ¤]ˆ]Î9šNsÉš©Õ÷YIáq*´ÌåþnQ%ëºm¯¢ó´ìo÷‰Å*‚±Ä+ô#’R.9‰J©UTKÂÏ?»»¿ž~ý·_?F`àZkþÐYôï)pˆÐ|ðÚ^[lÿPZ„tòªß^VÉ™ˆj®9åé4ç\\ô] 0çl›v8ÎÇý¸?Ge®€—¥\J)õéÕ– ks­Þ’3‡v@}tkTе?ÛÄpœNMë‚·Ê|µkúè)Ä("ÇÃa:ÞK­Â²LÕz[ò2MÓ8N•k)Å r©ÃÙ°=ßAt¦ŠžÆÓ—_|5‘=Lc¡ë:V±ÖzïÛ6cîò2û¸CcйøaÈ´ô O¥ú²<XDïKÝèÕÿ_¼®ê&y^Œµ%"–nÓª<ò9}Œ¨PŠ2OwÏ6íCã­ >çµ!„ç/¾WY¯oggý’Š%;OÓÚ}A‡ªZjaàœ…EEåÅù•1Ö ²0¨ŠE²Ç…=²ÁyâRÖ.׆H9ú ¨±õ%ñnÓX"(¹~ó¤†è‘l "Øí>9;ÿØX¿Ún( !TVU…’¼õJª€A¿©—Ar.y÷äüê]÷÷AWìàú¡2Öß¾ù­ðŒ¨ˆ¹iÚ4\«Š±Îg­ˆäR+K.Rj­RA•Y€ežçó³óÓiìûßæ¼ÌËt¾Ýí³ªÖZ¢©Dˆ>lû–YÇii¢SîB Á™ÿîøçÆ›iœ¯ž=q&®|aßáê¼åÊ JÎ!‘0¡Ø*Ò5 "Yg†Öª!yGÆRÊ«¸$ÓöÁ8:À°ybco ­&s€ \¯Û¸‡I IDAT_ÿíýõ絤~xòÅïÿŠËb|U"ûXhˆÔñáõí›_æå8ïÕ· K¡oÛ<DôÝ X]3ˆÈûn<܉dÆ&¸Z³³¾ïº¶õÇqnbÑûã˜Kíbs\Nˆ»FY–º(èYß9Kmßså&6 Zj9?ÛÇRxÓo¦e6ˆÁ»g—gÞX)¨‚Tr&DcÉ"WÙl»àc­UU+sßÅè†ín÷›/¾4ÖXkE„ŒÉóÉùfÉ¥0çZ7mª÷§Üxk‰@±ÖªT C!c™gáºë>¼èéæ—_ýúi‡§ËòYšþ- ýú·;çý§ÿä²®%Dà’_}þÿìï¾à¬*öêå/@¸;{òmmöF‚oÚGª]‘ÖqnÏ?áº|ùùÿ:œÑÐx.¥ÛìD¹8g_ßÜGïÑ:-§9ÍMh´ä Wg;ïƒÌã~É%åmloïödÈÇã’fg½ªÖZ!¨1FDŽ·Mì6]¿Ôżüñ'Ӝ޽zCmÓˆä9¥m»¡—*‡qDÀ¾˜kN“±Nð4M·7÷¯®o ™èÝý’=R*UÍû<4Î[…ʺ?,}ËÍö‡«…àáæ·Ãö¥±bŒQ¤ÓiÞmzrÝáæõù‹ŸYÖ#®Ë´ßÿ¿¡žbS‡WK¾µ0{wÂø8øÇ¨Ä÷ÃÎo£GÒH¼o÷_" 9/7·w€`5©r©\ª ‚Î)ͧTªôm Ö9kPÇqR‘µ¦lb[JqÖߟD¶u.xŸs2ƨêiœRÎg›sk\ÎÅ\}üôù‹§7oÞÞÝß?}vÕ7žkÝ }ˆáw_½òΑ1)¸$#µTV@ìšx¾mà××o§y¶MèïbÏ%ãúªYõzM3(Úëë·×_ÿmÓ?µ1°² îïߢë§ñ—dE™Rªw·ãÍ]öäÉÇ?Çu0@¸œnÆã/7»€œ}0Æ6¹ò»·¿œ‡®¿r¡}¼€Çùþ=.ï·}À÷­v$ ºöÇÛœÍv}hÒ2[gîŽÇ\WI2yK*ªUˆ€0z²†–œÇyöÖ„K®Î:g-Š3WÐRyÛ¶CE J–C7çT¸Î9 Mg~ög?Èó8\úñþôGˆ˜ç#” e9nß¾ù›N•«³¾ÔDd·›Ëýþ W¶~ã›ðöâß±ixŒ"ü[\·É!"¼ú쯺M#uj›ƒ;N'ïì]pæqW€¨,¥"¢5Ôx[jõΩ`ªµïk­µÆZ7Îc-µrM, °kš9×iÉKΕ%8ŸJêš¾r§Ùüù_þÓ¦Ú`\Ó4M|ýîa³NãÛlXrЦÛb)I¼³Žð8ÍãœE¸Î‰¯._('˜æ™ˆ Z2FU1¢šR±V*kÉ:ß^¾üËÕõ+ij/~õä”?úÞϦS¤Ýù÷¬ß¬Ç3®Ç[fÝï¿F|Û7xšN9çq>E€Sìl.o9cÎEUÉÉ{îÌ„ðÛyÀŒ•ª”šÒÝWÿa9Ê“çݪ•¹<Û"’¥.•Â"}ÓùÆe4(›¾ocìƒC€Ó’¬µ—Û>åÉ;2SY@˜µ ñ^¬s`mš¶ý´L}Û¦ñl3˜OþéŠ,¤ÂC×°hðTJîúfZ*"žŽ³E='26„à ²h®µ ¾‰!Æ‚¿Së ¨i›8Žã4ç4BÌ™K‘ãXާà­;Äý훳'Ÿ"ë›~ûòtÿf™dY–ãñáÓŸüKtžŒ™Þ|ý»ÿûîæo_Ž_<{âXÄ;Ï*Û~(\¬‹¬h ¤ÑNMw¥Ì*LÆ)ÂÔμ.gÄo'‘ß:¾ˆjIãáúWÇãC;P×·Ó2}}wõæ’E¡Ý’s•BDÎù¾é0çt?MðXUR©m–±Ðx·Þ´ !æ”–”JÉιqWC‹MßÛÃýõfs®@¹²#.§Sý¦ÿøÑó+k4çHHT2ÇÎGï­qŠjRÉÕ(T][j®Â»ÝNË·ÊV"ÚtÝtª#¼¾¾í7OÎ_üŒÌº†ÍîòéÓrüøå/|h*"ƒªãáÍéðÅ8¥¶›Î.ã’Ô:×*ÁúËó+f¾¾{‡ˆ6Ü¿úì‹Óý›Ë§»³:!§¾5οŸí#ü}Û½I4ª@h+S:í <1Ô %tÎ{cœssZXY›¶5Ö¤%!€(] »iN¦ê´ÌLl O5“3P„S)9±ª§Gùcìú”æÐ=ˆõîþôÐŽÖüè?ð.ŒsÎÎóÔ¶í4MMãs殥ÔãáTŠL§9¶Ñ{“S]癵°‚=ÇýÃ)çäBQD±Æ¢>ªT´Ôb06³>ìSÓvÏ?ýoíªMC0d†Í“íùs·ÎoÀ<²•7o~ùìå_†æÝùåfZŽs^rÉÖ ?–´´m+Ê14Ó$mï¾þò˼L5æÓÍrxWÔˆeF­Hö±Ôï¬dSEQÈÓÝÍ›ß,ûëg?;÷ñêÉåi Ñá45ÁåZS.!zf ]í6¹T眨v]"`Ê53Ïs’*UDÑ™œÇ’“s®í¶ãø ÊûÃ!x/*–ÐFߌK²uØ´™y34Þû~X”Ö=ˆÎûeJ&PÓDf.Õ:HŠØµíx\T¥i!#`ÝJF€Î!¨qŠ”Å~@( ³8kíw¢:MûyûAcë—»ET@E*› îj{Ö¶mðáîá.g¼þé/þù«/~ûöõ\ý{úã×Wý³¦=g¶Dk.@Æ:øpÚ¾oP« c‘œ{÷æuìE·ÜÍ}Óð‹«3fAgLɥ亾ÈîsqÁOãlŒÇY­Ö\ ‘õŽÐE`}Ì%j¦yÇ‹°PÎYA™¹ K1ŸüäZÙEkg×&‰¨MEÇ4o6=Z]ç5*ŠÊ"h YÊ)Ç6ÛΌ㈂«^Ëk‡]¤R{s¿|ïû?m‡O@¤ã>T$+H9>¼}ûê¯?þþÕþp¬%µÎ­^ú¥”¡ïÏ7ÃýñÀ"Ò)—‰áhÚ´Û¹—›«‹0¦iû™”}Yލl…«u¾½úÕ»KAXEjžç㯧QUæ)½üÁËR—Ê,‘sNU€œ#Âcš— „ó¼ bÓ4€ª¬±m°ä”JºDê8/*€h„PKÍð§qÓÛ®7Ÿüè…±vU“UÑ` #ªMçµ°"ȼœ¼ï½·"ƑͲ‚S”r½¾¾vMÎ s ¦Œ›¦áZA¡æjœ7Æ!êX»’ÓpþÓØœÃƸNù®e<|ÙoLÊÙ2ÞÚ³¡kšˆ)—œó4ë‚·Z¹ Íöj¸¸¸Øœ]nRæË/_÷oÒ¼Ï95¶e2VAÞË´ûÂr÷ö×7ŸmϯÚ΄è™ófÛ¦“#;—BÞ{U™§ SÊ€Xs±Îzçi¿?ÌÓ¼Ù DÈ¥:çW=<@ÉóÍšçͰÙmw*ZJÓbþë¿ü¹%báU#$JàY%*\‰¼m4X|õöÍÕÙvætØÎÙü²,!zBTÅœSÛZ!5jXdͲÐ…øÕ«„Ÿ>ý¹ó !TÅ4Ï~5-~"•Úׯþú“ï?™Nã˜æU¿¹ë»>F®‚šÙ¡yöô‰ã‚ëÀ½8ß©æëÛ·‡Ãáür{¶s¡yBO§wÓts{û¹ €ñ±a!£`ª—ÛÃíÿÉå‹áŒ»/ŸõçWý2N¤¸6‡ÓÑZ[XÏ/žµ•ë2'çlZZk¬Áað÷×û§—ç›¶©yζÁ7>Bf¶dóRKQT$´»Ë«¼Ìó4Å•üÙ/~L„_~õF‘VÃÎu›“–bŒqÆ„à¢ós®¬5›JÑ‚Çñ”–¥i[¬V•@•+³T1Æ" ªªDøâõ;Y6ÍÕO½o‰¿üý_·›+$Ã]hTEUKórxóúkf`©d¤Nˆ¥×¯¿¾ž§åêÙelZÌÞÙ·77à¼ÉRöã1•ëív»°Ýº®Çézåxo­á €\ËôúáößõÃÇKz·LKIiÕb‡.®Pw)æyVkmÎùüòb:Î{6w¶m"çÅXç}pÖ"Àœ’!ãÚFKAc ÔZ®YJ6«Ñ‚ùù_üöãþápqy©¨€ÚX „VY‚ +®cLób­çy °hQT„õî8ù`È¡!/J"P«"!¨Zg™q;´ã\Yκ³gÑF2¶g/ÆÓýjˆþá®vK*`ܸ{:Ý”ó»*+âÍSZºn㣶}£7×w$ZTNóZ/¤„¶”º,i»Ýæ*ÇiV¨Hb½}¸ß'yP™EŒ ×¼o¿@EÖ¯¬µ—ƒ 8¥Å:Óë›È ¥D`Ñ”sÍLsJÔÆFD†¾9f%R„\9…Rr.Åù˜–ÓÃÃa™³õÖ¯ª`ÜÐEÎK°æâÉ V1 Éï÷e7 ïÞ¼;GïƒsÞ’Q@­%„À,TjR–JD!z²¤s®Û>¤Â "ç‘•3KãŒ5Ö¹æpÌ¿ûÝ}Ó?‰6’5@æa„µî[„U ¬u]ˆ;@ô€Ìä‚ó±YÆeè6ûãAëÃTq³Û:gφ‘ú¾Ù ›1©”à=ZëI…3k®e3ôçO»ÐÁøÎ¦¬%çùáÕ²ÿ¢Ù>1t;ÏK•‚Ö¬¦6gœTúYôý®Wk-\ž_¢(ÏsF"gm ½w¡¤EEš¶‹M»XJqއؕ’E¨‰>/“7&Ħp1?ûó?1Îß¼½ÑǦyþÑó¡2úÐxGàœeaÝOÓa\P 4å¥iº²°ª: D4OÉ“@k yk½¡Rʼè¿ÿ›_¦‘ \3\…Ð%§ÆFcÜ#2‰ïë%Q0ÖcÛþ*¥;‹×Ó’šè˜ëÙv³,óÐùîü™óÔèÐG0}§)¸àAk©ÖŠDÓ’ƒ5>À<ïÌå–¯>ÿìß—|ψ?ýIûÈ•—œCã}Œ+opu~u8ïîïKÉ¥H©J5åZxš§iAJPUž–\¸.%!B¬„¹L¢Å‘¹8ß><S)µdD·,‹sÖwÓ¸$ó“¿øé0 »³Ýîü,çcH¹æùضŵþ5†Œ082)•"Ú¾+¥Je¼86»»=yï ‘ˆ¨(umsÿp3ÎSün×õÓ%‘°ÐП!(È{$imP¯ûôqô >„{·ßïÛNÇ×ä&€RÄy묕|C˜ÆÃRR)¥Žó´¤Å‹ ƒk›†È@Ѷ>tþâ¼é»x~¹yùñùÍím-Õ8œN"øNãxqu‘RçRYÉM-Œ56lÏcŒ¨¨Q$dæ!z͵²è4sN¢¸J}äúúA„SšT%62Y}{5?ü'?‚ØFï\H×_ôÝþ^ÑyW©ð°Ùä\~ÿåQ£’¹i:®‹scJáwïîÏ6ýZ§K€kbc 51:Go®ÇÓëf³«Fc-¹Jee6Æ(ªy/]]<¢ë÷ûÏX2À^,DB¢iI)§¶ŠÈÍÃþö0 HÖtn¿clZïCN³!J)P©Õ`ç)ñÃÃÃi¿a僷ˆ>4gÝn*9•²‚Þ ŠD¥Ìœs7œ9k@dYæÐBZ–´jšR©–P™ÅÇ `J®†ÐË * èW£ì\jô®kŒùÑ/~DƤyyûæ]×g̲,i)„ÊÕ*zd{öûqNãi>æ^< Î —œ&çÜ8§aÓ†à\pŠj£Ésn¬ïB >¤’}ð¥RÍa̬â6¥Ó8]³ÁZSåÅZSÊÀ P0hµQW$•pÚ=lWVÁƒµÐîv;cl©y^&ÌYÁºåœYôæá6:o#$ÕaÓ¦4!0’’±€øõ¯›.ƒ.cCÕº¦㔺¾q€˜rB´1‘r8çšs^*›” ËÙn;´AtµIQ •ÝÐo†¦aœ‘ šh»H B h^üèÔÊ}Cß*ª¨9ÌsãcÊ9ZÓµ-Îór8¼/_\n†Öc}lzc  h ^DÑÃ…‡¶G+>lÚ¦÷>´O.ìýýÝíÝß4±¼yý·Óé Îw5ÏMwñöÝk¬ ð~[Uͱݥy:Ü¿êºÈ59krÕ¶i†íŽõ¼äëÓ4–Ä>ºM·¹¸ß‰=‘C0HÆúëÛwÞ{© èâ}‡„5çᬠÞt}dÖªZjÍ)ÝïïÓ’„Kh µ™­5D(«! V"ªÌMpüxÀÌ—Û¡¤ €ã¸(€%_‹Z‹çgƒ0W–Êl~øóïûàKžChT”@…õ„8/ùpœœu·÷{ç,C!xﬨ¬í&G•ˆHª K}ŒÁyo=3+‚šª—ç¶oéúvBOŸ¸Í` qÓ µ ~ûûß¿|öC!šSF´(5x¹yû;UÚn/«tÏŸ?3®j?ûüHpˆó”·ÆRta<ÞK©Ch/¶—©,Þ·c*‚HM×—T³ÞÇTfTh» 㔎˸?>LóÌÂmß—”Ò4‹pˆK¶†RÊ ¢Á E‹Dd@Á v>^ï’3‚8C}ðÁ¹‡Ã(,K‘ZS¾²Èе¸é[ó£ŸýÐXKèDÁy—æ,ªó2‡ïî ièZðÞM¹,9“õ­Lƒª¢Ea`æue)@¼±àœcAVÔsâRµV¾¼j¶CèÛU<1p9!5Uv‡Ó]lw¿úÛÿÝ…¡iú÷.IHØ”ìî¿›™ëoûöááôö­çŸ^5/žîr))-µÔÆ7¥ƒ¸²'›®÷ãXÅ”Z@µm["©5Å8˜ç¥Ôz8-yvÎïšÍån+YKͧeNs¥ ›~PcÐX Ñ!€VQ¼wÎ9o­E”\9—C$ÄwCמær]DÑ)×’R®ÌÛ¡7Ï?ýhÉ)Ƙç4ôý«¯ß:ïãqœÆŸ>9ßn¦e–ûý±iZ@8ÛlA‡¦áZQ$W5–¬3«Flµ=‰÷ÖV.Ì‘˜9z/ÌM´ µëÛZD§e¬Ë¿¿qΚíæåõõgWç/îî>ï./> ¨Ü4}y.šaób»ûÁ'/ÿ¼ñÛ7¯¿žÓ¸Ù49§%'èckŒ­\AtÜU!Ë”+Oy$C$Z2À¼œ`N¹0‹je.\Ϻ³&ú&Z"Ûøn]ó>3sf®HDDÞùþ¬…íå–ˆ˜ež'g³œsÖq­C×å\R.©0ƒpÍ!¶*ª  ¢ Þf6ßÿé§7o¯5ÆD__ß Ñç³tM´ÆzgKçwëZ)\!TðÎGŠP³°h»i¯ßÜ?{¶uÖÜÜ?”RÖTYT£UرÖf–Óé>§iJËœ²óýq†yg‡—ÿøóÏÿ5súóy¼.’ïV‘¢ñ16O»îŰyÞ Ovçß±ûûW,ÇyÉcôñìòÜ8ª9÷Û»ÃáÕoÛ³!z£@DlúÆz"‚Ó~Iµ¶MH¥z\Ó׆è½YJÍ)1/›¦kúX‘Šâ<-€v:M›m‚1¬½ZxÓ Ó4O)×Z—’ç¼WßtѹZ2¢öm3†ž^žÆÙüàŸkch Ò¼¤]gƒ³wû‘ÅÄZEJMëA K.…,’‘”—**RW¸fV²æáö¤¢ÖÒ4fU˜«TæÊ "d0ÕZUî÷‡û‡‡Ãé˜SÚ]-ÇOžmÚH×·#A©ESÏÏ^¦åôêí¯·»—ö½}ÇŠXçdV]¯r¹Cw»¤B”œ Z’u·,kSêìò,å0θ³MË y)g—Ý’J¼¨²H).Î7ˆ8´-nÛ¡kZ!„¾ë¬3ó’»aÈó"¥ôÛ å%—R¸T=-Ë8%³dñ6ä.öÎã!Ʀ‰-ömƒ¨›¾ãZÍG?úb «\,x³ä²Ý­¾ñ*Zk=M§‹í`€ÈP.5w8@á’¸ «ª–Zcì—9ßÝ·©Ê’ëaZÀhe ÖB6-%¥JH16}×ÁÒƒÍyIXQx&s¶Û=ßôƸ¾âcÿ¸‘xí`{‡«¹ýêþ¦2ŸÆô{çËBýf»œF磅¦9¥‘ óœRöÖÏe)I­CDÊ¥6Ñ/)wÁâº~hÝö¹vËàÝþnØDÎz€Æ[Eº¿¾ËsžNcIe³Ý8ç@´äz¹ë‡®Ù‰EÑEj<ƒ†’”¾m¢uCèÍ'ú}aöÆ+B®™lhb7ñú6ZoªÔ¡É°ÆDïç…EDD¡²L§%'¶Ö¨RÎåp8=yv^«5,ŒTê²hfÉ¥V´¨(۾͵¢ªœõC­Å³Ý˜R¨Ö>¸nèÏœ ÚÓñ!„†Éöïh{”s9oo¯ÿ´ì,V®h.yZfɹ¨ˆsn7 jÈÖRž]ž“҇Q2×.ø¾iŒs"rÖ Þº·û»¥”¹VVÈÂoD¤oš`m‚óöêl7ål½Ï)¯8PeÎKZæ…u\ 3‡Ï/·Ó4€‰ašÒ’s©¼icð6ÕÊ9™ŸÿÅOHœqdŒ·—šÎº~Ó4ÁZfOÓf·ë¢Ÿ§ÅZ×6ATjJR‘ŒSI1„zf9NsìýÓ‹¡ïÚh]ð¡mãÛʼ:Z0K­<:K¬b 9kj- Ëb¬¥¶¹>Nùmž-˱HÙßÿ~{ö|¸Ó{œ‰dœT§ûÛ׿¶ú.6Á÷Ý଑eY˜y],"!ØÍ°]÷®ë=ÑÈI k®Îkwî8NÌÜÆx8ž¬w :Ž£Š( —Zƒ³!¸MצRÊ’žì.R^ÉXò!¤”4xÛ]©Ù9³é;eUå®.ÔPan¼o‚ŸS§ýþ”…ÍþäÓhmʵr±™‹¢vMP…Ræ&6Ö†Û»û|ZFD4Öáõõ3ïΆ` Ù6„*óiJWç­¨xPÁY“KVP5` pU$Â\’"vÁ;k¢÷µ²ˆ¸ÐpÍ“½Ø¿=ðq)ËÒmž’áÍö…1ÎGïiÈ0öãøîþö3ïqÈšªÖM¿9N»ÝÎûPk ÁõÝF„—ã©?»˜ç©oãÂEjª¬ê¬õÎy羺~»ÚÙÔ"µp–ÌÀKI•«H%€&„ûýþæááéù¥·nœOU™ûÍ µŠè'Ÿ<3–ŽÇ Œ·ä B´vÎ+eÁ9WrFDRÕ\ÙZ꺰êч!païÉ{š•eG0qKÍ&%ªÅ><œJ®ml¢÷ŽT8ç’EÅYº¾Ÿo¦iZNÇýÝí[cÌR8í—¯~ý6MÛ@ÕZSYÖ„«Š¾è/L ‡‡ë_½ûêߦéZdQ$ÐuMº¢è·6O ¥ÎûýïÕØ¦‰Ml—4ך½uçgç"c Á!è8홫oVä)C-:ÞO"Ê,}ß­ãèŸ|ü‰5Æ·é;5d¬q5•¦iœ÷‡qúòíÛ¡kWÙÏ’g©d€sñ>lúžÇ㬢ÖÛ4¦œRÛÄœyI©ýO5×’G’¦#ÂC¦8¢ U6Éf7[رٛÝ÷€5›«5›5ëaw“Gdf({q8ïfžîñÿßœQâÀ±–þ˜á/ÿò1ÅÁa甼ˆè_Í(¢µÐë†Ìr:”V?þõÇ¿ýýÓeYøÝ¥d¿›´âŽlÁ´ŽŸ_‚w`³îTZ'f][3`:â´KÂÚ¢ÝM~7¤\ké˜K½lyŒ!ŽÕ¬!ûÝ>jÝ O§Ó%š<è쯥ô[rߣ•fQe}^/_–ågkÕ׿ٕœKYÀ„Ò²s.çܰ:ﻨ” rŒ©×²n%"D‚ûðø@HÖBG,µyçv»]'ܶb€ÑŠ‘¬óĆœóÛVHĂ޻y¦¿ÿôwkÍû·÷ϯçÓùê¢÷É¥”¢çuõ!-933h%$Áù^[ðA”†ßþé·¥“ˆr hB¹æ²›’6leÛrP­u£Uëýéé< Ã×ÞÜi̬­îHcL—-+¥[GòVk£Ác#d¢!F­ešÂ†ª“$Jë ëÝݽõþËÓ“vŽ*­×‹÷ví8¢Þ\×ëËét½–ŠÝº!Ɖ ;á§ë˾üßóéÓ_~8¤¨r¿n× .j-¹¬¹ä£""*½°¹¬•èš Š‘o>¼¢ó7Cßn?<=OãÀ˺ £ˆ1æ’E¤·&‚½öàýš‹6ÆtÄZ è,1Æç§WeÀXo{éˆýº\[o¥q-¨v`”ÒCJ,ÂDð§þíÍ™¬µZ–fi„—u‚³œõ!:"ZךoÁMÃ|¹^¿úê~FDJ¯H¤„õ²lõ‚×—6¿Q´ÃØ;öÖ5"¹èßRn½5Z»koÄDD`·ÞÚ_åÙÖðã¡¿9ÚÇû} ¼‘Ëéü³æèÁ½|þ¢r˜ú×ϱ’üêIDATïRŠ®p#¢NŒˆÃ0^Ëfœ-—庰ðr]^Ö—­×`#+£´X018KÚXgk©àm§~¿Û#›Ëõ,š‘Èø¥¨Q÷ÎkcBðs KÎDTJ=÷¥õ—çÓñ0ǘD 6êØÎ׫(5£oñ1öÞ…xYWV þ·?[gJC0Æíƒm]˜Å(³mÅ1ŒCºlµw:î÷oîîþñÓGâþôòš‚ë½wâÖ Iˆ%F¿^ZÙ‰^?mÇ7IkÕ©[gSLÞzé•ÂBÔëu+ÎÃV6gvŠ!¼^^·šs˵W$ã`+Õ¢ïÔà[Fóùé”ËjTùîk AiU•&kÔ`Ã97e ÷úîí£ˆ¦^™9çŽ7C1Žv­‰xžã¶UcŒ¥ŒêçË…z¿nÛºfçl'f$$c¬Ñ<³0ƒ…è]®­¶~;E´ÿ_ÃPJ©¥·Ò•âiœÁÀ4N·R0eÍ­5é„ðí”Ö¢hH¡TÄÆÆØÖRrGDÚ_HréûÝx¸ XåùéùÃo¾F…¬ “ÒJƒw9Wa‰ƒ;½žkåaoö4X°ˆE‰"–óëòôt>Ɔm+­cm½2€uÖrGFbÞ¥Œ(¥oÅ&¬½XÓ‚;kùôÕCcê̽¾‰óX8·v«žÝ÷ã‘ÈÔ®•° vi_ZeÖÞAÉD¬†äµÑ¯çu]sLÉǘϧJì7Ödm}¬f²Ö‰¨ÖotFqÁi£†·õÚ[CÄZkkÆ€bc¦!iADl­§!õŽ"ʹÐYwDø§ÿãççË—×—`8RšJ®­Vå¼K!“õ>W|}=;m6ãÆyï½gÕ•XˆX›Þéïÿõ‹ó ´Z.¥WüòñüÓ¯ïïCtCLZ)ùþû·Ûš[­CòoŽ»—ë‚ÈJ”kÀäš•RÞúäâR³‹&VF¸”¶]Öëô4„!yÍ¿bOðË颵YK‡a«¥š·æÃ›»’[©Tj£­u»!æž…e·늢”6º×šKi…î‡Zj^ó8ŒûÃÑ0¾lI ÆháNÎ9BD¢<8KD`! qY×iîvÓîéåËq·CÂ~;\‘­4ë3 €Îõ×6|û‡ïr«Á‡ì0°·ã´ûôüÜ¥y XÞù´lëºÖV·qÚy½wÆë!9çµÑ¢Æ{Çóu}ófÚœOù†¤|ófÿæaBB¥ô0%ïc{ûxðÎzçIÀŽÃ(JõÞ•pð67ïJo, ’?¿TDk4!Mó4„±·ÊØ ˜4Œ!ħóå’@fJù”R`Œ^óf­õ1­Öm[‘)—l[7êH ¢‰Umµ[°­Vb­kïLù÷ß#kŒ¾;ôÃÝ‘È4êŠ4ñ²ec4÷~¹^Y$¦h-$¯Œhïƒs®Ô~¹nµãq¢ó_ž–[S;ýæÛÇuY}pÁ;b朮5Ì¥óM{êüÍ÷Û¼µc Cp¥³ a)Y‹ks­1 ˆ¨ŸÖ׎íuyaaÉ%x÷õ4ŽÊ(ï½1ºåÖK«­õã~·Ÿ§\Ê×Þ‰’Z™XJËÎ¥¤ÖÕ»¬ç—Ë‹w¾nëýûVÊz=[ï·R•Òûqxww(­Ýt,Î;쨕ÞJA4½ßÿH,wûc)¥£ˆ(ª[UÂÖZ¤V–ÜkSÆRGcඥ‡>ÔŽJ©è}ë‚=mk®Õù`-ä¥/×¼my?MBÆhÁû°£÷.`‰JëÖÛºÖyæ!ŽC<Ê—§ó-ÒbøÏÿ÷ŸÇÃþ›¯^_/ÃDëy­µËº>/»ýÌÄ!zçbWJ:QimHñuYÇ4xc´’ÖQSòæ¼'Ff™âDÒµ¨»ýÜ4îR¦pºžöóátyU¢{ë×ëz·Ÿ‰˜˜ž_/ÁzlÔz'¦ÚêœÆÖ¶üöÍ»­n ~óÍ÷)Î{{Ï¥j¥îæÑƒÍ­‘VJ„K©Æ˜ƒuF˜kÍJëàa?]NJ3ã0N£ ~]W£Ušï™Qk³-×­T$døê÷_]·ÕY·›ëຬçËâœÛG£MÍíºlOO§aˆÖ‚qY‘£µ€JLرµZÅØ“¶J”(áÓåLذõ|ð»ß}£wD°fÉUkÅDˆ8M#2[g6 YKH÷ûÃu[?=¿ ¢ˆ:Æ”¢÷ãXZ®­õ†yËÎL>~x|$fgaNƒóîãó—œó~š•Èáxl­ÓnÙ2¤X[;/%×Úªñ–X®yÑZ%™¨ôu¿?\®­áõüRÊš‚kÑ(e.×+3cë!†›Ä¥#vÂý8ßÈ£cŒV¥6bêMV2Žƒ¸œÏcLV5­Íìµà¯Ë®øðÃƃ·`C°ÀÛ@È+4Tik^”(VzžmtCÚÖš¼.u쥔jCtÖa_Á@-øñÓÓøþåé¹·òøðæûïÀz)qðK/¹·äÃ4ˆTkK1hcœ…ÁÙÚÛa7åRßH,Ò–ŒUøí›‡%o`!€†á¦=ºÛíó.—ª•ØOOVû»9í§±¶Š"!ïÂÝñx¹^s­$ê Þ}ý0?¿\Œ1)Å‚ˆzyz)µÞþqæiŸKqÎMÓä¬3Vûo¦¹Zj댱`sÛR,Xc`)‹ˆ2 Â)ÆmÝJ)„ä kkMð–˜kÇÛ]ÞÿÕ§y×­€1ÖZïMí|.üøã߯q)õVß¿»Ÿ‡O?ÎçåóÏgcí8øšq÷KnLHÌ¢ÌuÙ¬q§óåýÛ‡#³<=]>¾|ùrÁýÇÿùëò”§û¤Y¬µÏ¯'ê8„H½;¥ŒØË’çSËÒYèþþ/µ~ª/×ë0 Zéa ˜ý°_Ë6Äù´,HÈ µËÆ„ïùòùrÝò–{o[ÉÁùç§çy?ùjë…ˆ5ZëeY„¥Óa>”R˜¹c÷>þñ»ožž_ˆp<1—R-€³.ø˜†dÀiVˆ8ïÁ¨k¾ !! i° ÇaôÑóØr5> «ÃaÿúzZÌ™¢÷™Yàwÿòý»‡ÃRÿôòrݶZч Î9/Ë¥·6L“Ö:ø(D¥ö?¿Rç¶Ñùzþñ?½ž¯»Ý ²Ö)Qû<ÎÁû/O/Ÿyþ_ÿû|ÿÝ}^·/O×§ç«-ZRL>¥TpNk=¤°l™DEç·šç!iQ>€(åã%÷NØz­½”-—Z´Ö¥g­Öú§/?¥ö‡ãr½ ¶¯Þ<––IóËi™Æ¨”êzkµ¶y?÷†Ì$¢À[ïmGz7?½^œs¬¸öjZmÎy‹Ø‡4|úòôîñþº•°ÒJ÷ŽÌ\[½]Óâ< óN3¦0ôÖŒV¢QD18·®u¿ò¶i1 ·oõÄ€ßþù; ÀLk.ÂrSaL±–j½%nb”a‘ÎFƒyùrb!¥µÁ"ßÿðÕ<§aàãÇOO_žîwÓ8Îãd-(%‡ã4ŽéÇ¿}™öã7¿ÿ°ßM뚓ҺÕüöá¡a›RBêÜqÚaï§óæ<4dÃ4ŒûitXÄ9w]×Ö+X›bÚÚcüöýw­^•6ÉÙâÂyÝ”’àýýÝÎûp½®` ݬr¢À€=§ E¼7ï+ÄÚ(ÖF›y˜®ku.LsÒZ7ÄÝ.)QÖ†\‹wvšFDº‘\Š%o÷ãØzñ΃ÑÈÜIùà´5¤(¸P¶Íyh½cïÂl¬c%š[ˆ¾ÿ§ß€\0çN¬‡´VyÉ`-ö¾;ìÁ˜ÜH)åÁckÛù”7B"!î]°ón˜wqžöŸ~ù»ˆyxÿðåó/çëÉF~|·ßr6ÞŽóðôz£½3Gæá~^saªÆkmιµ.¢íív†MƒÑ΃6Ö¨dÖª#²ãœ#¡­e$‘k¾^/Kïèœbúüô¤¬ë$ÚÚÓµN»a½®Z+RtØÒ¶-OÓè­‹Î~z~™æT—mÇÝ5—¬DiãH”(o·²ÝÏ­Õëu©H÷»‰¾œÎŠP”4¦ÚQ%æÇÃÁZKÌ×¥€54h­µiµ„!‚QÒ²g­µV) ø·?œ_—ýaúÇß¾`§ýnTʈRzoJk®œ×~ë6×ÚÏç,"‚Jk…JAë»ó{'¥õÃÝ4ï'íüíOß~ûN)%FÕ¹¯,¬A;«Ç êNœko‡4xç”’¢1¦1]Ö–sS,Ø5`Lô>צôx£Pc¬±Ñ…ݸ?Îó°»®§aH¨õó󕘵R%W&´Î¿9Þ½\Ίe©µtrV‡a­%¤@È1„‡ãQªc·äÖÙ"Öš‰˜{Gg]nÕóã—g-bµÖÆÒ| 'h“BÎñëuŎ൷ž„±ô¼d&ŠC ÂF„§ñ®cƒïÿü»e¹†Ÿ~y É[g´’¥âí¬(ÂÎ:£ÔÇOÍeg%êôº)g-!i­[ÅNýáͽOAÍÈb ä†„H§Kž§ôÓ§'D6FƒS[ËowJËÛ8Ä`RJ´6ÊZmD˜J|¾l‡¹#±Á¹Š‰¦8î’UÚz°ÖØyœœsØqݶ—ÓËWïÆ4üòra%Z”²Þ°1λ[ùptöZßí¦Áû»i·ö¶¼. û0ØyL»iÞÏóy[c´Ì|#VXcµVÆÀiÝÆ­ÑÁ[FbQ¨•sv ‰nNÐ1¥¿üasà„ùæoí¥Ýˆ3 ¢Dtk©Ã¿üϾÛ['°°?LF+$<Îio¸?¥Ô/O¿ùÝ7F+&LÁ€5Ãè¶­0Ãj/>„qŽ­ulèSpÁ¯—;m¹ŠV|«¯õæ0øpZ—1I1Ž1ôŽk.Ziç hc”&¤‚´cŠ~]ëýýŒÈfpþf¦ØY CCˆLÔ{Ï\úrºh­B J©iöìãqo´9­+³8ÐYæ!Î×å²lZ©£"¥Ž»ÃVKG­™ÈmÁîÇñëÇ·×uµ¹µÚ™6÷÷{EDoïÞˆb!<ìv"üùõ< ƒÖš˜†a¤Ž>ÑÊ{§µöƒ•&7É#üñ_ÿTZ-e Þݼ ¢•ʸØ”€¹^г&LnšB!dkŽ÷óýýÞ5ìý|Þ !Þ¹Î8BFkíù²QJ¾U´r­­!³1ÆSZ/µÝïç¬w{ß–Í£‚‹^N«÷vËmžS ¾³t$d‰:JïYÐ1vQú´n€5mÛb]¸å‰Y‰ùæý›u]±“I>Õ^‘yH1x0Æ4º‘I$þüòT{_¶Ú+õN>ØyÞ ÑërqÖ‹ðËeíØ˜ÔWïß Ëåõ´âmÍÞÛÒÚeÝöC<î§Þ)úˆo¸+íC'fQŠUéôîí$Jàñû·¬øç—­?Dýš¯Sš@ùoÓÖ›;9Ðó8ÄàÀ˜à‚eb¥„…õJ©†MiEDÄ4MóËë©¶þîíÃ_ÿúóýÝ¡QÃŽJ©Ã8Ä!…à\®ÕPLÆo½Ñ¦`CD1F;€|ÞVa«µRKÁÒ™{m¢1—\ji•­ósò¬fÑleŶÇÖjë‘EU©vÒc ½u"&æ-熸uB–ÚZm]”(-ƨ]w×ëJÈ6ú?Ñ‚=¥H¢¼³wû\êÍIìƒ#æy5Îûu+¶#Z ` 1QoJ³JÉbç˵Âã7ÌÜ®k=¯oµÖ2册Ñà­°F£ó.àÛÆÆ9`QDÜjICòàÿ[¾Ã)Ä»ãÝó˳s~š­µsvËùþñ¨•&&1&c«½3èÖòƃ6b6Pë Ö ½SíEDŒ5Fi%::¸³½÷ÌËyûü鯇hœú•ÒÂŒYjAB-‘,ØN½U´.vîCŒŒDÂZkìÈÌXDnAº•DDqï»ýn]Vi½å¼ŽÓ~ï°ó¶DÞï’µ0OI+HÇãAXBκëº-놄ƔZ¹W-·çv­„ wsÒ†»Ãñr]½³÷Çv&¦Ú©5ŠÑ[€ÖQ+±Öc÷ã€,HtÙ2"Go‰»´eáÛkâZ¶­l·Žùn޵5fž¦¤´ÒF‡è/§KðÖ:÷+lϘxãÄQZ<"b/!Œ„èC$Bp±–¾m­µÒZ©¨À˜9o¢S^_ׇ·Çýà•R!„º¬3ó”¼ó`ŒÖjÙrˆöÞ™vcZ·õ–}¿%sI”Ö¿ÒlÀ(0j VkðÞ¼ * Æ8c4Q·Z©4$"zÿPj¯­÷ιÔRêâº"¶·(?ö.">Äèœ&"­¾ùÓ·¯//F™aŒŸ~yyû°ÛJ) ™íºl›ó ”DÁ³ÒZwæÓ²,7N×--Å¢D9kotf0ðüôL„HJ+å½Í¥Æä_ž_•Ñ ðöÍ}ï%ødÀnù Æ´V…À°%øînï|TÄ)ùZ{ˆ[1ÖÔ²‰ ÷îx<–RKݦ™À¿]VQrw?ѳ2ÖZc-±ô^×¼Eﻣ;k¼ó,ÂLˆÄJ?ÞïµÒ18&T"Þ‚µ¦Ýt~9OD½µl ´VÁàm¹îæÝóËéºn1¥iœ¢Ë²®¥ïîŽ[­½÷ÌÈZ7)ç:Së~øçßßÂìÖ[ž§0AX­K±Þ­Ëf½±Ö–Ò‚óÞùÝ. ©µÞF«³`…• FŒ¸Ð +1´ À½>¯ó~ÔZjk-Wç­³.y¯J]˜ÙZoŒ5Æ"ó-RjК̚K©hb°¢@) ŒÖ6 ÉÁÂùºÔZ§1€uµôÂ81‡˜˜Ézh½7ìļ–Bp~ÂZ õãaÏĈ„Ø]ðDh´¢ÞóZ°#þZÔµ¶†H­’÷^ˆ†!Õ-Óœ·³à×ïÞ_×KŒ>óöþ~Y_þñüìƒõΗÖÃ0,ç+hÓ 8$Z×ë|˜I˜áOÿú{ ` ÜøÌØpp¾3,½kÍ,ŒÑ­V笳VX‹¨óºuÄÖZY”RÖhE¢”rÎ8ç»br΀ ®Öª\Bd£ –m .j¥K¾zçÇaÇŒ"âÀXkAô/§«cêŒÌÆ "a‰ibá­6}c*’ " ÏSôÁ—ÚßîóÔ[mÝ9ËJ9g×ÜE)Ũ´ÒÚ8kò–Çic¡c÷Îuk!Z¯E3]i6,ï—Ëõ¦[ 10qk]–¼¼½¿Ÿ†I„ŸOχݑ•1CŒëšc ÎÙß|x4Æ ËmÏR"ã0nÛÖZýÿc›4Ã`ôàIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/ImageWhiteSeaSmall.png000077500000000000000000000204431375753423500263210ustar00rootroot00000000000000‰PNG  IHDR@@% æ‰ pHYsÃÃÇo¨dtIMEÞ  Ç4Ê€ IDAThÞuºY¯eirž߸¦=}†œ³*«²†îV‹¤Ú HÀ’à{ëB?@?M·‚ Ù¾0in‚fÕÍêꬬœOžsö¸ÆoˆÐÅÉ"›Mp]í}±ßõÅÃkáÿòÿç,Èiš8'r>Ç ÈH¤³†õ|9!?u¹\SÛ®–«®ï²1…Ö$ %§­2ço^?>{¨ŒšÆÑz' Æç¯¶_|òØ[ƒ¸øöÕ¡¼ø÷Þ×û«oæç¡dBÛ‹˜@@@YbÿâÙ™ÏÞ«/ÿà“&ŽÁú2¥¨«¬[Îæ»Cû£Ç?þù×_-Ö‹—/Ç^Íf.s.ª*§¨MIÆiª|áQ)…“fUYsu}S×UYC2aà_þæùÅjiŒ!DëàîÅâý‹¿{ñü›°ûeHEÙ¬@0I$@" "fÌH”"ù8÷ÓN=þâaa½6žEˆˆXS„89ã _}þðÓ_<öþÝf¹(ÐÊ4MÌÇ1䀂Κw—[¨sÛ®‹}ÛîÇÁ*¦ÁÛºÝ×§ó÷NEäêú•1Ú”Nß¹{Žpó~uÙœT¶T·Ç ‚ ˆníƒð½¹Æ)Þ™½9´ïÔ£/îÛq³ÛŠ ²(c0…¼^Ì÷í>ÄñíûݧOž~zöhQ7§ë;Ûã~sÝ­f'W›ÍÕvG&YBmí'O>YU3ÀÔ ‡ýq¿kwÎî^m®”Qζ´m{ô•c(œŠ1I¦ÂÎ2‡ö¸¿xh¾ùêYŠÒÌïÊ­äïϲ !Hþ 0¿zù ­:ûôÂjïŒR¨Ç~zöìrèa&LDðÍ»öb]×…óξ¼ÚÌ+÷ÿýô›ÿðc4xuu¹<©4¡*Œ‰aL‰4¦,ëb a˜F$B`g fFÊC·c²„~­Å¯_|sï¾ýæùÉÝÏDˆ€8Ý †$(@",ˆ8N£Çß‚ôêã/Ç0*­rÌZÓ½÷cÀ³u]V%!>ÿö²(é“Ï>nÃ0MÃbvçÍÕ‹ß^õaãÁ>K‚4ŒSÌyºÊ×1G£ý¾Û6ebàÌ!LY@RˆCŒA$§3‹ä0<¸·:YÕ?,¯·Ê¸„?¸j"ˆˆ@D"2Œ§ß:´3ÎÛBQÖïÛ#@êÛí›7Ééèœ=Y—¯¾ÛüöW¿…õì»oþPU•^. ²%päQ«ÒB4ÝÒö°‰œ²\{çoŽÝI=›7óý~ëŒÛînÄPL€rfT’‰µ"Ncº8Bê0|¨;$¤ìW °€8íøcRO~øqâ¬4H×…©´ÇÙÜ­×ó²r…×uS£MF¤k[kŒ!º¸·4Zƒ°d®ŠÊ jªzGM*çÜOÃÙ+3†H‹ù"…„ ©®ç9'"$E8ÅT”³$X`²ñËWoÃâä1€ Âmo@ÄÕ3ˆÙÙñ¯I=þòqUXcÕ2½y÷f¾˜‹p̱l àì½Q EÀEÚzæìŒKqb¢>'¡Ä!j톡'D£mŒ ÑŒý 1uÇ!1Ý`b%]×Ï—sÐhP‡ÈóhR´nLu PnSñwkË·¾4Tz7%Vh ¡ÑtqqÎÂÖZgm¦,ÀÌSÌœDD ?A°aA-¢ÐŠVcŽÆÚz~F¨jïcŒÚúþØ‹ªÚnº~è]Nqë **Ë21…=ö¦ÄCœ´IíöUfùÁÿè ¥«Y¤nŠqè÷Û›Ì<õã8„¾Ÿú=0UeÕ Â|Ѥ™E)çŒñÞ#(M 5’±,yÇ)f"Q¦ic‹â¶Ý(¥\i»˜CÊëåJ)Ýöƒ±Æ³Ûí’Äýñ 5)­çóRXrŒ)³RÝ/~úŠouË?QBH)96'djõàéMž…9 !öíðíWß‘¶”3üæ×¯îß»«Hú!6u’8§™SÊ´µ#*å …‰Yi­´:î¶å¼Œ)câ%JNY´œ3…ÌÎûã0M1ÞCSŠFù¢¨>ûòã÷ïvesŽDðOc!C°?»ëÅB-a`PS€Â‚P”FD‡)ݽ3ïÚ©ª«ƒ÷æÝ«›“ó%Èôîíöd±H™H ‚•$æÀ,!%àŒÚ!sˆSU—•s´. Dº®×J5…[Ìf¯ß_#gm´ÑEJmY¯·;å« D –ê$ÔF;¶¿P=üì¢ÕþЄÚbzþÛ›Ãq<;_“fuY•>eNŠR@FfÆq ΢5*OSâLÚ [#g EÌLZ—¾¥iÊiìÉéó'ŸCÊÖØ¢W„ ã¹Æ16`΋rùýXñ;Þÿûs‡è¬Ò ˆˆE(†Á¯@㈚œÖ,™úº‘œ)çÉ¥*¤ÃqÏÂÆÙ››ëª¨Ç…sØY"“½kýÿ~†þÝüýþ6„t?Õ½'÷ª¦êûIk⹬|ŽÓ¼©¼§ív¸~{óäÓ¿yö¶,ÕVk"H ”½z½Yœ­A™³6Ö*3MI)("9§ÌÀ‰¦Þ^}ÙoÞ‚µ5Ê)MS2 UÖ¦œ nAa!M™•ñ1E…¢5iF­A“0ʬš}÷jhNÿ¸9ùD+¼¥GÎq·y%¢šÙùú0´ŠÔ-µ±à~s©ñÑn·[,fˆxzºÒê¦ iº’vP5V+;y¶¼Ö•j9?ýáG?zûêå¬1J1DA¦©? ý¬ªûqàÌí0Sˆ!Å$’cÏy2ÖB–Ì$Y4‘Q DY§/_º‡ŸþH¸R¯Þ} ñoº~³íÇ1d .¤€ üæê7êþ“ÎÎOåå³Ë¡í¤tY$æ¸ÛóYyØ·aÀÕÅçhë¥ÖV@5ëÞ¾º,l*Š E§”ÉY»o»$šsÒÚÆ”¬¶ x·”bç]?F)@£@ŒÆ" äùböõ³Å“ý)iG%Åöæ/Oê¾±íù‰2æÐ4“jÿ2ž<|ÿæm×o"¼S'÷.z.}¹ÙV'jfT(®Ð )Iè{£g¾^!‘VȤi¹~´¹–ï~ól»¹®ŠU]ÍH£!Â0qHÓØc° ¢÷ïnœSÞW”ABFDBíÊù/Ï?þ‰/¤è6ýRÛw¿==ïÃAÚ9^ÅÔ-å‹ðëíhÏ/Ôâü´œÔZ/—3£¶†Y8 ! Ã4 a6¯\åºã®Ý^Í8g@@,ËÅbý âìêjÿÝß½HI·Gµ>¹SÖ•ÖÉ:Âh-Z­æ‹2 [í"g¤Û PY5wþöo÷Oò¿VõŠHƒ ‡±Û›ÃöÏ 3¢1Œ ŒIˆ˜H ¡=YÎ==}üXÕ'ë;÷NPÔМ“Ò*qa1Æ()ÎŠØØ%åh|} ¤@ÈXíÊÙòÞúâéúÁAÍ|1ßwøâÕf<îž:c3$RmÊ2çõ~¾ýžþËkÝ’"çœÂ8uWo^þÕÙª`« g¶ÆYCEUOCŽ×OÖ'ªYŸÞ¿¿vÆk¥A‘&ÀÊëË×G_¸¢´uÕ¤œúv_øªð:×Ö6èNP>4ID"D´¾.ëU³z0_=Z~*æä—ûÕjY(ãIcN ´&çú>j½ººjö7j}ï_ßùè'ÚTš@@rŒœ†íÕ×ß}ów.q11" 3ŒQÂ\/W›Í•Wz»»ÔeSÓºÃX×EH“&:îÃ0N 0µÇ˜sBå;ì÷'+\.¯.~Ú|h>ð«2‚Æ":ƒçå'ZÛ¯~þ8e“ð|eÇ~B ajž|ñ?ûˆ‘@”‘ºÝËËWQ”êËÏ\?SŽdrí ’ÌÙm¯®ÇÄD!† ÿíøwož_¶ý”èþƒåb¥I«iûí`¬Y¯Í®Ncå]‚§\–ÍÕ%ëæ/ÿ+ÌÌŒ·B1·ìÈX‰IaäœD²0§8¸ÙÚ(ƒô=$ BÈÒïߤãÿ9¯åf{S”&åœ#bÌ¥geÁ m’‚ýa9+k)¥pñø¤mG~ñü:&LadfÁ¼XVD~·™ºnºÚì”5Ç8_Àöåÿ@Úþ°òCõ»Ø¤A#²qÖ•µ-f¶šósÒöV=ˆ€0OY ä›÷ÿ—Ñaˆ±åxÙbU9o©H,@2ÉøÝõ›ëãþ˜C7¦IÈûšÔÇ?xäµÏ+qèǾïÎﮌ±eáǯ·G$˜7®)KFvÖ[ãÞ]õËõ©**eAaa [xýýÙ‘¾ïÊrûûmÊÜfÐí=ôýñý‹ÿ­¨…Ç~­RóÊM¡G ¥TÁå¬ )Na¸¨g \Ã"d5E`°R¯KÒòøÉ½È´}¯HŸ®¬bgj# ¬‚qJy’ËËÎ3ÈQ‰è÷¤ÿÈïŒ_¿Z@É1^_ýúýÛÿ×ù]æôv{LÎú¡Ÿ´vÖYÃ0ÅñØOFYIŒ ÙY{ˆƒQ¨î>~¼˜@œÍËÅIýæå•5f}Zbæý¾%â“ÕRr¶®ÂYÒ®‹»OþÔù9~‚ôG€˜ ðf÷L%„À"‡Ã›ýáo{eu@ß~P‡Ý³Ð½jjÎ)YE‹ª8_ÌÛax»ÛfaFÐZk«5Zm³"²ÙCJ@êínG9aˆ’²hC9ƒ°¬ÎNœ7o_\…™×5 §­%oiò¯ý¶Z|”Ò¨‘(ˆ(B£‘n±ûŸzè÷¸\H©8\žŸm™1N}×õÛý.夹ÜoPòrÙTÞ-êZ˜6Š4D`B"Ðóº"µÛîS–œàx<ô}ÃXU…µ:DÙî7Â8ô£ÓJ+­Ð¼zöºjδ²·ÕßÐ?˜\)¸åpùçBðý¦_!N‘™­·Z+Nr:[7EŠÔb¹Úú²pÝÐ;k•VýÐ…(ëÙ"å¬kgéoþòçD$,7×{£•€C×u³yU:7L’‘g… 1fŽÎ/¤% °€E´¤¾þœ%¥I˜ÿù " sÒîñõ> ñØè¦ñ@±òñòj׎ã‹wïÇ2ÈbV—¾àe³†TV&‹VÿæOÿ8¤ì­oš¢ô¶'[)R†óZ‘8¥SÎ)¢š­}ÛÌ×w 8üâ§ÿ™0½~ùÿçq¨æçˆ°¿zþÍÏþÛas=?»wK6¿·ÙÛbŠ ÕüÎÍÛg³zRJ,ç»c;Å”…Û±÷…›¦á|}B·ÎDé»HÂùr!ý8–Ϊ‡O?úúç¿úèÑݘ¦fÖtã¨5¥2â±m_¾¾Lˆ¥)ˆ­Ó†ÔÕæÚº3S”}{ÜÇøþ¸ß^¿~v÷㟠¢íÕ_W³}šž_¾ýUiïX_ч‡u߯DðCA17×_7³âz»!dÎyŠ©íÆUS `NÒõƒ³žˆ¶Ýñl1ÆQÇœ+¨ñêøã_?{‰€)FM¤”&¥BYºœ¯óMuR–D„42ŸýêGíE¹ÃáuJéν§ø'ÿiì÷ýÍûífËqOFšŠ_¼ø/c{Íœåïÿ{+N„ÅÙÛ7m޼hf•÷¥ÑÎz)KOˆã49§W‹Yʱï!•¢‡À€Î¸íq¯}ùH‘. ß}Y•„Ô·ƒ2®)LˆÙ;?¥\û€‡>KÎÂIMÑi·ªçw–c›ù=?[÷óÿöͯþ¬™„¢U… ¹¿y÷ºp§ˆ âí##€[nŒ)>ÿÅÿ}~uµ¿@g]L±ªÊº!Œš4 kCÖ˜Ì"Âι£Ñz˜F­PRÈYk•ÄÄœó8L•V)¡7ºkÓϛ¢€¦.Ã8!âùEs¹ÙŸ^<É9œÞùììîg"@¤ÀΞ|yúòòµÙUz?«|OýoùgˆÖøúÁÓ?±Î Ñöû.‡ÀSÞßëY$D"œsB[ÙÓrÕöHúqά•¿ÞÞTUsè9%«î?¾ï­ªaD¯±²+&s‹‚ÃÉPYú’@c,ªbäÅòì &‘Ûu?ÿúÏë9C˪ðÎxkÛ¾ú[ðÇwU¿ýæ§íîÒci|%ÀÀ,a¶7_÷ûõåo­Ñ:‹0çaŠœ9Æl½Q(!æ˜" EUx¯~òÇ?Øî[ 4N+…F+ÝO6îíû›º¬øöŸ Yc$sÞ‚2æ‹»ûÃMY4YDsÎ9÷Â×ÇþÐ8·¬ëýîØ¸Â/šµöûvã 5;±9ïo®¿šÚTÍg]NÃîÝ-šñÁGgC7kúqœ/WÃÐ#PNùìt–ÇPX=+½ÕšHí-ÛbŽœ E5[Ïo®÷ƺÒNìC"Ryò8öhé8Dë Ѷã¨HYãrŠÃt>›_”Íj¿ï‹ @´"ã×o¾û÷zJí”§²¬ÆØJÄS³(]ÀBu´:íwÏrðíÕW,ç8q°^E% ǶE$£•³6%.J?„œbÄÌy§¢*IÆqu~¡>ýÑÓqœŒµÚÀ¬™+Bض]Î"$šsœBÒ¨ÐhœÆñ»ç×9˜fvNJ[ßüÃðCæôâ‹®}3NÛºr˜b³:’óóÕ8ŒÆ˜)E­)„\ÏdV»÷¿n»í~|±ÙîЬOÖo߽ό, !†™™c¥“³J‘>´­d²…½¾9ªOü´(}QXºê޵sλë«ÍåõæÎéE÷@jBá –Z;£/ÎWß½|•l 32¢(Bšˆ@Ó¬kŸMÃPe?MUU½|wÉF3p$m(G”ùÜÏçôú»×J‰w¶*g}ŒŠTÊ9Lƒ¯šG²v†¦*cÌSªKwl[gŠbUõøóû’³-]Û†tŠA2§”îžžio 9çrÎH°,kJ¨îÜ;´»Þ}µßü‚ãå¾Móú‰ )V»ëWÞ±Õúìb³‹‡ã•±´˜ôcpZ[…í0YC#)]ÖÆ{»íú÷×ï%gm !Q˜FPúAjçBŒ$ùt^»A@ãùIbT¿øˆ”å,ã8rNZé˜rŸ¢÷¥30! gA@«UYTˆ’ gE|~q²^ÈÀÚÓí±ÿæë?¿sïËÌ©*î\¾ûí͆»vnTu÷B½¿¹6¨aeܱ2dBÅœ½·Ý0û¡†û§g$úÝÕ•±h…ÓZyï’V”r.¬Ý·Ýsˆ¢ú¡ðV>8ÓHC7†D°©kæì¼#"6¨µSãcä嬸ÞìŽ!!ÒHš^¿~1…TWÅvŸ­ÖœÂqûz~òHY·>ûÁùÅçëó'iJï¯ÿÎYžÏëÂØï¾{7[7Tz«4í63—®(J+9Îf †)M¼ZÏêy3tR:§Ôöc7EåŒb. W®®J­´²Î±REŽýà –š¦,›c‡$”•1îú¦ÏmÐôÑ4ea2ójyÒö½¥i½ÚïvîÁÝ0Ò8t¾(H+2…kÓ¤< ¦¶œõË‹%…4y6)³±Ê£HiR»¶kÊšY†ãþ¤,+çn®œ·J©YŒv¤¬Äe5 4¥«½§e]Ç­ñH8¯Š‹õ2D@€YUb‹žH)m]iî/?¾w÷bqÆ(Ç.ŽSˆ‹™ŸÆÉÆ}´Ý›÷¿ <ÅéoßPH‚zón(|]uÛvÓd½X‚HU»À9å\UE? !ÄËÍÕ®;dáªp‰Ó£ÓS£•/ü8ާ§ Á¼˜ÕgËYáláÌ¡¾yùZ=ùü#c°x¯•‚Ìrõ~ƒÆ__µ)LĻ®K ûÃ6#ÊõëýÉYã­Ž1O!zkî_¬oÞ<Ûï®O–+¥Œ0*­˜áòÕ߈&TP¥¶Ê ”#£>îÛår¦ ï]Ûl½»ºÙ{ï4QH!2¯fMŒ‰APPk9!‹õÑg‰ÚqX6õ8 Ã0æŸ?÷“?úœYÆ<)47Û–Yliã4ãP”Ål^ #»ªÚ[˜ÒɺZΊöx½ß½F"Kõöò/ûݯ>ýx¾=ns†M»5J•…½Úï†ý´>©Oë• ˜çÍâýÍ•+ý4Ž9eŒ9ÝòÛ~˜$1‡ñصakµQ:Ƥ¾ü—O…€2ãaÛV¥«f³˜øtµxþâ•/Ü4¥)³Qêõó÷Î7ŠÔÍM»^7mß Cïßu»}·ŸzÙÀª!×Ï_=»:¬W 8ÒM;>zpÿpضm@Eš”fçT; œùòý¥/«ã0hm kI"†”`˜z£U{ŒEᚪfNe]õm?†¨î>¹w8¶¾ÐCÛGdMÖ8ûêåÕÇeݱsÊ8ûöõuŒéúòà¨89i”ѧ˲ïGëÌ”²°AãëC‚1´Çns¶Ò)€p¹¹!R1·çë±BÀ¦ª†0ëSÆ®=Öå|ú““Õâ²R¨QåÌd‘¦Ú™Y„„D‹0©iJêãìÞjj qÙÌ)ßï¯Æ¼u³z®H_ï6ÚN¹(Ìåû›®€…E´ÕcLMáÛýÄ¡.›aV‹å0 eé9‹QÆ:ưXŸvÑ€¼ÕUSM÷ÛC£ˆúìÇOCÊÓÇ1 /͘bˆ2vÃ~;vããOÖu]½}û¶*ýrU××F™º8Yͧ4-ïí‡aQ5}ß“5«Y“rìDZ›:F®«:ÇiUWý4)cNÖËÍfk¼Ñ¨æM•c(gs‰)LÁê"Š(£NæM;N«Y½ÙíÑÜ^kêÆŠ (S ë ±:{tw3§¬¬ÆIö‡(9ïwÃ4DɲÛÏï,bÎUe×ûc_4¾Ÿzmp1¯ŽCŠ9{ëŒR¤èjÛzm §Ñ›Š9mâ”C˜Š²zóþb…Îù”Ò˜óÝż›¦U3+KÏ !DÀBˆ Ý8åSΑ³&<ÍŸ½|YŽ›c³¬R`£ õ“óG"bQ„1G¥ÕaÓÞ;Êë“:¤PÍ,Bã}×ö›}‹šÒ3gEX–EÊÙ[Ë)fÁº°Y¤©*"b­maʶBÊ7‡}ÕTÖªÇwÎßÞl½±Qò².öÝ 9Ö¦œ§)ùÂ-–ps8:kÊÂÖ¥”œ1"œb6ÆQ¤59oÔúñúÙ³WËÅ<Ä H#Â|YÓ¸^̬w˳:sBÀ‰}á7»£ÖN!Tu匙R¨œSDmß’qÀ2űp¦¹ïûv®ßnšÅÌ`¦.GÈY™Y%sæ|sìSì§11/ëÙÍf×M½F×Ë&…`”²Þ®fõ¡23‘ÇžHçĪ\W>zwysq¶hûÐÁ{c´ª­S¾Ù¼SVD )ûÙ¼aRè —B°¾Ìi2 ”Ak æ„@‚ضSš:&[9ßùxuøèÑ ‹(’è/¿ˆ¶IDATÛÅ)³Š’2Ž!Þ’U É8oí€d„Næóý¡0sÛMΚqE¤r„éÎú €O–µ!•…Çq:¶F£Œn‡¶*u`œ¢0XRÎEÛkí8Î\e×n½+ÇœAp':¦lñ¥7¾<_5»Ãþâ¼±…Dï¬u¶c7öBèX4)œ‚Ó’à¦mcÞ™®¯o”Âù̬fv;¶ÚªfV[ëÐøC”øß´d©¶«öÜIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/000077500000000000000000000000001375753423500234235ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample01.png000077500000000000000000000007001375753423500270520ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dUIDATHKí•=Ž…0 „SRRRrŽ@¹%%7 ä”ƒ£Q²#<9&hµÒï+žÇãá'¸ëùyapGß÷Î9ünÛÆh‰²¯k¨´É¤Jk°ï;1’µmË2Н.nš¦¡&FÜ`Yª˜¦‰{7çyj›u]¹ñÀ<ÛbJkæy–ü‰T£¬A×u¢Ã0àI¹»(-É©F˜ Éã8æ« h.Þí êÕª@$€ë ÊDçjžÝCÍ+®ë æ_ø‘ÈÌõ‘®C‚¨žk†* à:$ˆâÝ2·ºKz² ±Ñ·]*N¶5¨9ýI©É¶5§ßSìˆlèÓk•Ѹý}ž9ùqgß(õÐÕAæäÇ ÀUJõã³eªgîsìñH‘¯’æëh(V9A¿sMMuP6ø%ƒ×õ _~«aÅÐßïIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample02.png000077500000000000000000000006301375753423500270550ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d-IDATHKí–½‘ƒ0…ñE„„„Ð %Ò!%@]@It@ˆßÞ1Âì®<ãaÆ_‚¼?z+!-~lÛ]ÉŸ—q ùyžó<HÀ>Ž#ãDpL ¦iʲŒ¡ qÃÀ„–Ò’$á4&Ð`Î Y@,¼®k¸Ú¶Ýîc -BHÓ”y¸©EP»‹Ñ! |—ʲ\ו 4¬~ù4™0T Žé²,n€qƒOº)N·œ]"vüÝ‹‚|½@ß÷iüžÕ#t¼q p%÷f…+Ië‘ü+©]xKÀh iÆ™ÍJðû—¨ñÒkµÍq~ÿ˜«ë:úN‰¢(ìn(oô‹†F°×õM5Œ}÷Q(°ª*NùÏ;…ïÜÿMƒ\,EO.¾3}åU‘IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample03.png000077500000000000000000000007351375753423500270640ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨drIDATHKí–1’ƒ0 EÍV”””pŽ@II™Prèàp$n’ýˆc,Af6ÅÎî+ôeÙ(‰Öu5Ÿä‹ßão ÌóœçyEøÇ‘V ²Â4MY–Ñ5DÇ]×Ñ;„&€ìI’0“JÓ4Œ9 Ãp1»EÒ `׌{P×5¼r¿ß‹¢ “1mÛòC@À댔Ýâjà}ÏjwAí6ä¸ _À-Ÿ¦  ûŒ9Dù/Ú²,vòíâ Ú}£Ð­ï”ö}—eIÓ†?®1ì³ëìQ8ðý<,?0ìú¾çêqÈ\í<öñ„ÖwZ¤ôˆÇ-Áá¥ñ”Ä*4½â[Ý­ÌȽ? {»Ýl Ð5ð”~òP ÀÕ‘A œûC$•ÂS4¼ÔžRù ,< Ô®d¢Ð5NS[4€UU1åÆÅÔ–ÿ¿Ž§üvc¾‰±4êÿ¬IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample04.png000077500000000000000000000007221375753423500270610ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dgIDATHKí–»‘„0 †Ù‹ ¡RJ º ¤È  Z¢BNƒ~~ DÃ0 úfúºÙKäÖ‡ŽBᎾŸ\–È­OUU\xÈ8Ž(…@t`ì6cê±Û üíî+‡ µ3ÃÞÙ2ôî*QÜžP¦Ø‹ÀßÖ¢W”¨? ÃAUO®tE n`ÕÑuZ„¿­CŸ—ï èYvÚ3â•¶ïD]@‡J]×FîLT@Øÿ•6°ŒªyþTüõ×Iò ?0o¬øûIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample05.png000077500000000000000000000006261375753423500270650ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d+IDATHKí–A®ƒ0 DÓ®X²d ·à(›p ¸ÜŒeþ´™Fic©R¿Ô·!Mœ›«ï½û$W>?ÆwlÛÖuÝå˲pÁÎ@a]×¶mú ªªyžQB3€z]×TÍ€±ÅæÐ Wïûž£–R š¦¡Œsã8rÖûiš8{\8@6@úxV¤6z²Aš>§2{Ћ÷‡@L?Á) ¹U྇¸±„ÿ’ñõq¤s+ã™ô„9%a9' ¬Yv¯YDà>u§1} ðw.>#Jéƒ÷ ðf^zޱäÒ ˜>Ð B¥‡aØ÷=ÄëiÈ¥%ñˆ`ðÒ/SÞ’ 9! Ò"NK~ÿ‹Šü Šüwçþ‹í Å|qŒIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample06.png000077500000000000000000000007271375753423500270700ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dlIDATHKí–»‘„0 †Ù‹ ¡RJ $$¤BJ€ º€’è2N{#ËÆ³3w3÷%+?¤ß²±µ¯}߃'ù¢ßÇøMó<§iú:{GsgpÉ4MI’Ãè†æI¸q«8DQD4Š¢X×µm[j„aHžgd¦iÈO£ª*>`2Ф A ë:òøÁŒË¨ëgŠIq£Cžç°Ôkæ@ht1“àúò}¢#Ž$¸€Z>&uyàH‚ à$Àùˆ- «µ½±%q› &qçc—eÛ¶¡ñ†„¨÷£ ÔP×½,Ë‚ÜM4^ÑàFƒõû úþŠÖ÷=YŒ÷AhØ.¤¨êmgOпew©R°ÊÁž. _Hý¾˜@\³Þ™o;`shºT uT¬‚ 6ʬ£ä|F€ÙeY’·G\…,€è{Ÿ¬£Šÿÿ¦—<,ßÌôÛzgúIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample07.png000077500000000000000000000007061375753423500270660ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d[IDATHKí–»•„0 EÍF„„„Ð %P!RdÐ¥zuðƒ£5–4Ÿh÷3Æcëba‹É¼÷î“|áûcü)Áº®u]gYFŸÔF¯ =äG†UU-Ë‚¶`Û6 „)t-(Ë‘œkš&¹”<Ï%‡!˜¦ 1œkÛvßwüàý8Žøá@rhJNQa>EGïO¸†èehž~ïÜAmôžhLr®ë:t ô}FÞ! xöÑ%CëÃÐÛ`qò•)ûa0뱚҉ º;Zxh+\㣀éR1Ï3ZGZÑzc1Ïæ‡ã \Ÿ¤«îN޲# ®Uôóø ý<¾%ˆ mò<¾%à÷.m‡×J¡å‚dŽ2£oå´à:\÷âEÊkÏô­œð L é­iZ1Ëf…0CDAôFä(ôŽ( ¸ã© œÿ?¿Î}²€-]ÿ9ŒêIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample08.png000077500000000000000000000006371375753423500270720ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d4IDATHKí–½ƒ0 …T”””° £P²%#P°¥ób?8ŸcKnR%_ƒ-KzþÕñ°Öšoòä÷kü”Àq]×=hlÛÆr ëºÖu͘€¶m1D§EÓ41_AFX–…iÃ0À8Ï3ûUUÁÓ‡„(û¾ß;Ó÷ýyžp|Ê`­»Pš¦a¨1Qö›H]8$LŸA×Îä€6Öç=±W´:$pú4å] \Ф»6ýÌÝû‡‹(`_#< š¬•ª)^¬o>Ÿ!?RìJëZ’÷AdHÞ ðÝÐ$ߢä­È@«,îED "ʾE`Gåk²((÷"Ú‘†œè›KdEÑ<ªL®^• A#—üÿìTþ Ƽ<ôšk@IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample09.png000077500000000000000000000006641375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIIDATHKí–½ƒ0 …T”””0 [0%[0%lÁJl@Itø…ÆBâ.¹äkâèÇOÈÆæ±,‹»“'~oãG†a(Šâ±Bƒ²,ÉŸ -²Ä8Žyž#î¹ú¾G¨Œ(@Éišb2$IT¸@×u˜ãMUUó<“«m[˜VTˆu†×^×5 .s®Ȳ ©Îùª£°¨|$ µs¸LB/¦SêœÔ¥p„Ê÷Ps|¼Ô%Qÿ5Ô.í¬|`2€‹ÀÕð AHÙEÓ4ù-€|­Àt¥|µ«qõ„ÙP»º³ª{îˆ'¤m½°¼™Ë® · Xv]èØºDOS ªßE'¯}(Ð4 ’ä;‹fçç9]pÄè|ÞÂÂvIDzÇ—úË(.Ž*cC d# ÌæPD}àÐK*7ÉÍ9À¹—fùÉàœpÒ?‹–eá•Ï‹÷È{å›ÍDÈæ¬@mæÙïÞLˆl°§=Úâ” æeó·è˜0mÛòÂ¥ïû¨— "›cÂÞÏEb áÐl8‚a 5=P ®æ¬ \êL¸vF0Oµj“ÿ_G•_$É.±‡e_]+IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample11.png000077500000000000000000000007371375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€tIDATXGí—1Ž… †q+KKK½G°´´ô–zK½…ÞÌ’õ·¼ÉÃK6î&ïK&š 0?˜é u#_æyÿWÀqª®k•eÙã¹m›ñ$‚¯ •u]uQøzž–ç¹^–Å´“$`ßw]UÕK`jã8šÖ2ÄœÎÚg)"D¸”·m«Ïó|øñlšæÅ/€Üa}ßišŒ×OP€4¸…ŠÀÆDöBx`G»1°My´A`WD¯€²,“ƒ[zÛ‚õÒÙ§·¸ýCËÀ pgÝþÒe`ØŽ°wf¤ËÀ^HPß-Œ[ŒdœÏqü7\»Ö¼)5ϳyû%° )Ã0x PIqøJ8 ÌólM¬†„U’§iJ&*Ër_×õü^ß÷Ï\%X*¹š"Á ¼^¯G‡u]_Ÿ˜¡$8Œ]×=:rI.ÁðÞ)€“ðûÒ4Í}?7 šÀ0 äEQçœîQû1­M@÷Ðäøå²/Ó(hòˆŸ$ðZ `~µ?j´z Š¢«u\­p’$Û¶ícÄ1ªg[òöãøx¢®–¸ETÞ>×';Aç;êü踞j&ðvŽÑ®øîåp˜©}QÛ¹®t€%  Û¯è«ê^á;xK7fFØ«ªztâ*ëî03 Hðt@pSB1Ü–n( 5@¨m[²n´ÕN€M‚ —"ÆY@â*âZAy `ðbuM,ùïÿŽ…øF¹ÙžHL'¢IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample13.png000077500000000000000000000007161375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€cIDATXGí—±„0EÍE„„„Ð%P%Ò!%BÐ!Ç?™“Íxlo°:Ý>ÉZXÌÌ[Û Þì¼0oäË~¾¿-°®«©ëú§á8 ¬P–e9«ªÂšQú¡¿†*°m[pRÚò’KÕT!¥”ƒ&÷3¯WJ}ÜÞ¡m[ïÛÓ+èFw;Ò¦EKTÀIh-dß‚@ŒDÌë;XàÆ'’²oøü3úüwc¾Ti{ô¢BGÔIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample14.png000077500000000000000000000007361375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€sIDATXGí—=Ž„0 …a+JJJ¸ G ¤¤ä”:¸G£dç­’ÝŒÇNœ¬Vh¥ù$kùñÉãL~=ÈnäÃüÞÆÿ°ï{Ö4M–çù—áï¢ÁÐrÇU×5ö kEQ\˲˜Þ:Ôà¼,KÖ15ˆÜ¶ÍŒô£ 9ïºî:Ïóšçù¥ ÑÐÀ9†Á´þ!}ß?õ›¦É´Êxh»ŒãøÔÑñ! Hq‰¶m¿Ç„–BPUU´s DÀ±ë‹‚( Õ¹Å] _XÈeW@ ˆ‚;‡”–ììnø‘j©¸Ë E`Áð%©Ðóƒ-Ç8Û-Ls¡¹ÞåøO¬ëjž<`PðÚÚoÐdSP€¶¬Rp”»óHÙÄ Ðäoz”K°-4c£@¿Þw”‹Òh´"¸*êCl¥Q‰€cî¾*d^yœzé”Ã4UÔŸT„Ö´%<(Ĉˆ½;¨ä1½tºëØòþsz³€,ûðVdv+°IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample15.png000077500000000000000000000007501375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€}IDATXGí—1Ž„0 EÃV””ÐÁm8%%%7 äÐÁ-àHÜ€’’Q&Š'íhµû¤fHìoGÄ&¹ˆò%¯ã-ö}UU‰$Iîë<Ïò lA Û¶]eYbû¬c9ÓM”€eY®,ˬŽõ1Ž£\A$Àu×u×yžW]×ÏÿÒ4•+iØàÜ5ë@«ç¾,°Øœ7Ms;³Ñ÷ýsž/ ,yž¿87£6 É‚W¢q®àfÁ+ÀŒž ² ¯Ã›cÃi16z…¾ Tœb£W`ï}ëVõÅ¡Ñ+t6HfúcñÙ ËqQâ8ùë^-ïÂ@RØlÕPwþH¿¼{?d|ʹDgà§øð;¬ë*ïÂ@¯èo Î9îƒs”“Ìs­UÑLpŠš­u”“€^Ó1 Ÿª{¢p @MoÛöŘˆpš¦{ž-b5\­p P˜ÛÁœ ÊBEpË7[€µ51=Ã_ÿ:âGª¼áœAIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample16.png000077500000000000000000000007271375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+yIDATXGå—1®ƒ0 †Ã›á&Œ‘‘‘0rF¸Gc¤u©œÄIì©zzŸU­ãøí7;Ÿ¨/òs½~¿+`Û6U׵ʲì½à=|.z@¾ïgUUÐ7äÊóüÚÉC$`]׳( 20^ °iš×þlÓ49º®;ãxÙÇqtìœl°PÁ‡a¸¬¿€¾ï}±,PõnÛö}kŠyžý±,x@p»Þ±à[DÒJÇõæ€}CÖ²,ìzsÀþ!H+vN à3B8ÖeYØÎ!¸g8Vœ~¨{*ɰ£¤é0’,Vè~®cI(v÷§`_"–E# vLí~é%¼RÁgp.q«€”ºMõóÍÁ+€3Lh¨àÜ2À£S ­>yv$Q=¬H¿=NœäJd+)?ÝŽ<ÛÜ TP½¸ÃŠ#ÁYà,é°‚! m÷‚o}Xãí4Ÿˆ;‚bþû¿c¥Aã÷fêýIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample17.png000077500000000000000000000007551375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+IDATXGå—1®ƒ0 †Ã›`cd„ÛpFFFnÀÈ`ƒ[ÀÍ`ãa”Ð8‰•ª¾÷IVÓœ¿6‰M°í°òÃ??Æ-ó<³,ËX‡ÁxG>ë ¤€Ê0 [š¦2Ô`®ñ$`š&ë²…aè%Â)œÅqŒ.f2VMÓh΋¢Ø–eáW¼hÛörU„Q@×u‡`UUñYL„ Tä\{žçè¿ÆPEÀw¨€$I.N¨‹ êº>ïuE /î ;–}Øžô(†ÃE€L“ˆ¢ˆ­ëzŒ÷(°]Ô1VÑN¾ïùèûâ#v AÈÈù‡-÷áYæDK~„ï.”TZ˜n¢Bñõåøü]äí ¡ ü$ì ÔílàÓX¨È~lµDÅCÜH)§j)·¡ÍªåÔ7 j)w¦¨¼»QPs•rT€j·«ö”RnLÜTĘ:fja¡+ËRsL1Ÿ*j PÓá2S×lÂ)@àr§uþûÛ1c¿-¦¤ÕÑIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample18.png000077500000000000000000000007021375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+dIDATXGí—1ƒ †±“£££ÞÊÑÑÑ[xÝôz3GÛ¿–Ràý4ML“~ÉKkøà)`vÜP'rÑ¿§‘,°m›ªëZeYö\OÓ¤ïH)`Y×õ(Š) FUUÇ<Ϻ† -Àtn"ÏsZ‚(Ëò­“}ßïѶíK™)g$h4hwÐ4.y2 ÃË=Œ-àŽ#÷‘*ñq bø$BPxí»®Ó%a\‰Ð,P)£·±Ÿ›Ð,P­Ù3£7¸³àCÇQl$†]×—±E{ú}¯ž„”QÀTF„^½RÄí›A¸5H¬ßÛŽ¿Í_à·–eÑÿ¾^ÃÌzCZIEw!Áu ÒJ* €¾ï`˜£–ÁÔCøVRJÝT0ÌFF 7’„{Šmd´p%øÀHm|GøÐF–$|RÄ1É EB:A}$`À´ú>JL0Ç·“?Ï•ºÓíqÿ4Å&IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample19.png000077500000000000000000000007101375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+jIDATXGí—1Žƒ0Ea+JJJ¸ Ç ¤ä”n7£tö¯ìÕ`í±³RvµyÒ(üf‚Ç)Õ'Å ùЯ/#ÙÀyžE×uEY–_÷û¾ëlh„ã8TÛ¶h—UU©mÛô'ÓÀâu]³â&rMD ÌóÌ Žã¨–e¹]ƒ‰u]õ2‚°@@˜b›@àš¯ôœ–½ï{u]—ÎÞá*!mkÀGøÄ ÈC8Õk iš›¸]v\%b°è"Rqƒm"ö{p  üt¦iú¾?Ö GÁ.ÜïÁ‡£@ÅSËO±[áÙ†Øß V*ÉZoþ4o¿ÛÀS')x )Ò $†tGu2Ò $†tGe3´ 8¥bûЎʠÑb‚;K„`³&8ÑE8‡&'›'^{>ÎHŽ8Ö&†a¸-* é$ 7ˆ`?¡Hãb†˜‘qðßÿÅXßôŒ®LchIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample20.png000077500000000000000000000010101375753423500270460ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+ªIDATXGÕ—=’ƒ0 …ÍVÐ¥¤„ÛpJÊ”¹AJŽ@ ·€›‘ŽåíÚ3¶,ÿ†ÉÎ~3š Ò³ìHNqœˆ?äK~&³m›hÛVEñcø¾,‹MHe]×ãv»!s–5MsÌó,Ÿ “,Î]Á••e-"ZfÙq9ƒˆ¢¸R~¿ß忌ãhŒ?ŸO9â&(€ Þ÷ý±ï»|ÂäñxφDxpÁé¬)Öuñ2ãÂ+ ®kÃQ(¸‚ŠðmJ§Ì>'¸"XÁÁ àRŸÝ”\XϹ©çeÁðnê)4 ëýèY ¿+‚üÝÙ+ôÚ@—ÁjÇèl 2”ÍëõUUÉ+Óov;NÁÛ¦‘ÜRvú¾B×ùÈè>Ï%Î} ¯Î±O  >½{ ëˆEÀÑÍ 2 ª\©„êŠu'T¹R˜¦ÉðÅÕ6‚þœä@Ýý V€¾ °Ô“.×M]'(V]Dňà‚ûJºs‘¡xà Ùà–¹Ss¨Ÿw—X‹ifA GDl' p-‹n±ÿ÷ßñ5ñ ;—7âƒï‰IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample21.png000066400000000000000000000004601375753423500270540ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 3 ÛÜɪ½IDATXÃÕWÑ€ ‹ÿÿËöÞ¥ ™¾¦0vcõÞûµñàÚ|{Ñ̨{QB›*ñó> Êä+o[4ð[e£d ˆ$š}óØ€’þQ¼’6ŒtB™°ZCתY2ïÊб݊¡Ô‘ÃJûý%^AÿaV€ŒŸ”ãí`ÝYÉøzI†¢•2à ٵ«ŒfŠu¿%%ö4eÞ¯Y†zÉBâm¼Y…:`p«¨ê¨…ä-h33¨‚2IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample22.png000066400000000000000000000004561375753423500270620ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 3_bˆt»IDATXÃåWÉ À Ãû¯LÿU!Î¥´*_ 6Î ÖZk4.Ík²l÷""N/èÓ9‰‚GïˆGîÓK­$pÏ‚(ã5 ´Ÿ€5Äc83$DšZšÍöB$ÅÅ¢Â{ø<Ö…ÿqÁ.ß«@´(¥ô‚ &ã¡dVÀ’,¨vƒDR¨ŒÀ“ªfDS7®´ŸÈ(¶ƒ™ŒqDD*™Á´ükftØÚ2#ì3Tiï†JEc6MÔ÷IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample23.png000066400000000000000000000005021375753423500270530ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 3.y»¸ØÏIDATXÃåWA!+ÿÿezê¡-$ º3ëcÑÜÝ_×`‚Í,Œaó‡Îâ³DÐ%m–øP@fÙÍbÍ,TÌáî¾T½ æpÅ€Q)R`²cI V¤eö´Ý‚_+Úd½…Ê®¦ø¡]¹ìZ[üSá '@uÂÝÏ2*‡Å÷ó@¶‡W]Gœ¬ÿ’@… Ù=`³ ÌD¶}F$ØqNzŽWj(¥‚âÜf„ÿÂ`þ†l†hTFÿ‡Ë} /ÿœvÍ‹Ÿõªòt9ÑzÅEIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample24.png000066400000000000000000000004531375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 4ê,#иIDATXÃíW[À Äû_™ý¡õ‘eþÚH)TÌÌžƒ«DÀ"ÒÝËæQ 5.CBÁ³ø!On–u¤eÂVð^ÀvJè­½H)ÔÌdƒ”CQ¡†TVfY”y ½ì(ÃRG¨Ëà©ð=àN¸ÛŒŠ6’+KpY(r…¶(%‘Fè|§¿Ve>$ÀPaÖ2ú˜ô‚FÌêÝñ~F«2§¾ i}€õ4‹à ;£D× ™Qj'HàIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_0_Sample25.png000066400000000000000000000004731375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 4n’bÈIDATXÃåWAÀ ÿÿ2;-ÙajaE—Ì£,EX1w÷cãj#3ë~‹ÆÓ—>c€qÈ^žŒ7NÜ})¢)r|íe˜{pmÜ ƒÈËŽ‚@ơҫN¨£Ú"S»JJSÀ°€ úKú@ ˪ ÷–ØÂÀ( ße º'Hô€Bœ`Gí/‘d4;O²\¥zmè%,#´Šž &Œ£»‹({ÆNFoÞ¤e+dfײ΢©‘Άʞñ¿áhrÈm7žʨIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample01.png000077500000000000000000000005541375753423500270620ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–1ƒ0 EI'ØY{+ŽÀÈ áŒÜŽÄ ÂF-ü!¤b;‚¡*o(¶“ü/ uëº&wòÂõ6›Á4MïaP¡§HOQ¼*MS”$ ã8²:ƒª„v©çyí Hhç…æ0 ¡Úä¾ïçyFbFßÙ7§,K Kó­÷Þ#ºÄà ^U‘\b°ßXV'_b@oku‚+r‰³ymÛ’Ð^`u¹„ùÀqÎq \hþš†¾u]ÇÀvêºæ…Êï¹E˲dYƱfmÌ¡oÚ†;2#ˆ1Oª†ƒ¦iè—ÞpNÏyþ:ŠüºA’|+Ò† P/IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample02.png000077500000000000000000000005201375753423500270540ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dåIDATHKí–½ „0 …“«())¹­Ø6a ¶€‘²%gñžº;–@º"_ƒm?Lܶ-ÜɃ×Û(&neYž;Ó41¤#]ä¢il¬ªŠ!ŸÀ<ÏÈUqHöº®™;„axCÅ!p`Ô"«È(lJ‰¾ ýæíd@×u¼ma|Í.¬ëÊšÀgUiyš[[z®*z†ÎUò*!ÝÑ‘p¸9hKÇq”\ç~Gv~¾c„‘¿«Ì“"`RLþI@æ-û)‹¶m¹Ç³Ëñ}ßÃ8O“›ßCx¦V{"„1IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample03.png000077500000000000000000000005361375753423500270640ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dóIDATHKí–± „0 EÉU”””¬Â6lAÉ ”l#±%÷ïüEè„m"$ ^qÿOHHëºfWòâÝÆ4Mu]ÃÀØF`§,K¤äyÎØ€Ï@ž t]Ç* ß„¤€A,Ë"åcNc¢c’û¾gÉÅç=ÙÞ`­†uX ó<3pA£CÆq,Š‚ ?ئ¡÷û«ج¡ôÛ©7MÃRº¤«ª¢Ø¨£žAºÁn͈:`œn€o•J‘:`Uºv¨ÄÒ‚¨Æîó`Û-Œ‰¾óàÊc ò¨¸ âMЂ۠m[\ã“瘛ýüžàbƒ,{£ò(c®/ážIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample04.png000077500000000000000000000005441375753423500270640ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dùIDATHKí–± „0 E“«RRRrÛ0%%[P2%l›QrþEȎ銼ì8ÿG‰±ëºš'yáùÉ@$Î`žç÷Æ8ŽH‰ÐW¤'ÏsžåœCJ" ï{Vg•ÐÖMÓ”e´70 ¡­ó›ãÁ€„ª®m[¨`LB¨£)Š’ÆTU…·» Â)ËrY× ök'uÊ#¾n®Ô‘½Ñ€Ž ùµ3œ$KœÖu]G*MÓ þÂêb‰è†c­ååÄÔD’Èßp7ö‡ ‚í¸É„C™a0|ŽÖ€oŽ4­_kÀЭW×5änª=éçWÀ˜"I‰yÔèFIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample05.png000077500000000000000000000005771375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–± „0 E«())…’- cJÆ`%6 ¼³Îÿ¢HâätÅI< )ŽÿÈzf±®kÓ4˲Àö“)PUEÛOŽoŸ³ ˜ò“,ÀÙ˲Dú_Hq,˜õó@ Žq·mƒAÔuF ¤`žg¬ù°ï;|~´‡Ò ðQñy?ggà:WFà "HDà°÷¾ï1Ò5€ Àdo$# õ鸎ã–ÖuLoxïâ‚ýÀáÀ´mk«‘tIqîÞ¹“n­Ý×S1.â¦i’¶,™gÎ.†,R`Œ‘~UÚ]”Á-åˆr DIà_9ŒÔ¤ È'Èý®EI»ì2ø÷&½]úšâ)|²‹IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample06.png000077500000000000000000000005111375753423500270600ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dÞIDATHKí–» „0Dí‹ iÅ!!%Щ;0Ðr+íÈBœÄØ'ü¼ÏH`y±û¾›'ùàù/4˜çÙ9ç½GL‘œNAwUU…#Ã`Y–º®Õ@@–‘ÚwRP`$õýª ¨1’úš¦êÔ¼oš&H3Ž#VwÕ‡a ‚[ ⡺®Û¶M’ˆo1hÛVµ¢º ACÊUŸ¾Ÿ¾ï£º êb¹®×u=!k­.®7F²çA®A™”b@y¡Lc¬ÒÈ6Ð ê8®)¿Ž”70æ Èm'˜óÓ©IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample07.png000077500000000000000000000006171375753423500270700ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d$IDATHKí–;ƒ0DM*è()Ém8Gà”n7ƒŽŒ²#ËJ–ŸM¤HÉkðîÂ Øø-Ëb>É×ñÅã8ÞŸô}Ï” ÆÀ,ËD!Žc¦4< †auY ¨§iJí',høØÎ±° qÚ ®kª:°¦qÎÀU/Ë’­« Ú¶¥ž1EQLÓÄà*Ûõ¢ŽŒ„@nP9dÐu]žç3FÔã@·gºž…K ^~y¨Û×Ìz¼¨»Ò ÞªŠYÖ¼ °ŠÉóª:*`¬±Ukš¯©QŒ5‚¶Ì(Ф±!rÍŽ¶±ç}A’$ó<£ÑrW— /°kŸØ¨„[v‡á—- 5°³}Pù‘0Û%|çøÝÁ˜ê)£‹¯âIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample08.png000077500000000000000000000005611375753423500270670ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKå–½ ƒ0…íT””Б(-(a:Æ€‘Ø€’œ¸'+18>NAŠÄWÀa›÷Î?ØØu]Í•`ƒ„ª\®‹é yùN¿m[¶IÈ]×qÖlS tíûžSÓ4 ­ˆnqêº^×ÕÚ€Í |]écvDèÄpécqlĺÀº|]–eÛ¶Á@úxŸa¸ÇÎ3ê„ïØóƒig¿ÆÅç:NQxD‘0 7.LÀÝmëjø÷¿kcÞjùøÜW IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample11.png000077500000000000000000000005341375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€ñIDATXGí—Ë „ @aO9z¤;ðH va¥ -É<º ³ìâ&3B–dÃK?ÉòŠišÞA†ÁÏ…c\È+>Ïü „ã\È+Æqôú¾´V2Ú¶M¸W{/¤”ØòØ¢‘%¦üO6¼K¨U  dp_ÂØâ“EÀeJ_»íkõ׬ â \gáe dIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample12.png000077500000000000000000000005351375753423500270630ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€òIDATXGí—1„ Ea+ílíðvÞÂÒkx =7ÀÎun`³_ˆËKˆ#füß ‘o;ìA^æúÅ@²eYX×uzLÓdfãI^„mÛ2)¥Ž«ªbJ)Ç’TúúCœX×ÕDT+Ìó¼5MCÕsÊ%gâ·ð‰Ó@2~‰÷}ïÜ£Dgœ‰öJT†Oœ°çQ‚!qÂ~†ÌB8ßâ„ý%˜1Ž£WœH1¥àœ›H;0Qe;.Šìж,Ë ®ëO7„¶eY*0 ƒ‰ð¶,ÛÉÈ®òÊlkà¨Â¾_èk,åløï{"ͧ›iIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample13.png000077500000000000000000000006421375753423500270630ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€7IDATXGí—1ƒ0 EC'Øaƒ[qnÁÈáp$n[‹S§J( 6¸ªÔöI&±ð1‘ ® êƒ\ðú1D àò<×£ë:œ¥!ò Ò4Uã8j; C5M“¶)œÎìÞæyF‹Æé Ø»7py*ëÝ2p„¾ï¯qÃVŸ‡C|Áap` Ø ^–¥sÏ- I'ì9,ï¦iœ@&8`Ïs {¯S_®Üy«€­÷¾œv¸zÇ^kÛg÷ÙðªèÖ,Gðcl*^Ôà@]׎¯g–eÎC_7ؾT¼žö®ö‚GˆvDA ¥ åç;:¢3¼Mµ5­(е5Í@UUhÑ[3ñÿî—ðÿ Ä@ñq` q9ºõuñ"äòëE¨Ô Ð ×ÏÈ%ŽtIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample14.png000077500000000000000000000006031375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGí—1ƒ E—T––Úy;KKà-ôØé-ôHÞÀÒ°d fFHœ$¾…Y÷³»‚²U'r“ýi0MäyÃ0È{‚¤ MS˜ç¢(‚eYä¨A0ÆäõqÞ)èºN^9‚peÇ5Žc\ò£QñJʽõqÎ)hÛvçÜ Œιv½Q![ô}oä½(ŠÏ hšÆp†M¼÷Æ=+ ¬ö,Ë GØêºÞæõ1*VI’N0ì¸r…>GåÐâ¹àªª2œ#ú<•C =ôèüo  ¯,ËÝÊ>¬vBÜpDÈ»=>‡Ñ÷Ÿ†¾\.—€ß€ÿ® ΋­ß[O!ÈVìÿ!ÀRzÄ8‡ùCIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample15.png000077500000000000000000000005531375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGí•Á „ E‡=éÍ#–c–`¶áÑ.¤$;ЛëØ(1»3 «^BÀI”ÿ?†QÛ<ÈËÍ"Œ1Ð4 Œãè*t’$P×5Ìó EQÀ²,®JCœºÇÍ‘u]íÌAœ€wïá~N”ÀÑ},¢B÷Èm ¤pD'på¹%Tî-˜‡iš¶ªªÐæåàÂ~Ck}Ú0Ã…uÃ0œ¢ïºÎÞ~ž¶mÝŠò“0ú}3[÷Ï8ökØÖ8„ÑûÍŽµÈGð-z ä{ ,ËO³9¾¢”r«s 9¾ïíŒîS"%ð/²€, ÈĤMI,@Ú#Ľ@ÊÃÿÀÿwc^~ȘIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample16.png000077500000000000000000000006511375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+>IDATXGí—1®„ †Ç­´³ÔNâ ,½ÞÂcXê-´ô8Þ@;—!Cæ=a„d¿„ìàÊþÿŒÀbt à‡|è3˲@UU0M]q+‚yžÏ4M±šgÇtÕN°Gç9lÛF=™E÷yXz]¼iŠì©À5û}ßA<êÝãU̼,KCq—`ž OºkãðÈÀ8ŽÿŠw]Gw¹Á2€ÂEQü)¬§w˜±Þçb1 ƒ! šXj§˜ír.è×¹XG\3WŠ,ËŒï¹XGô}/¸®kCX¡‹s' â´á:™RÏ$Š"Šdú¹ã½úúwü„×Àkà5ðj€õ>@xoÅI’Àq2Ƴ H9xW@?‚+#¼ ¬ëJÑ3¼ ´mK€8PäN°W³§üx|ÿ¼ D? —åIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample17.png000077500000000000000000000005711375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+IDATXGí—MD0…“YYZ²s;Gp·°äÜ„#¹¥IwõLELEZblòU¥òï½îP›B<È‹joÆqeYоïiÄÈ€/Ã0@±$IB£n9‚<ÏŲ,Ôà¨uŽ÷Ìó¼çâ3zàoð \aš¦-MS¼ñÌÂá’›8lgâMÓÐJ7ز,;ê}.¬mÛîÄ>Ñêc\œw˜âu]ÓÌÍàÌ‹¢Ø‰TUµ­ëJ+n4ðë†3Å}ž‹u‡9¤Ýô5\¬;º®û^Øöxùò6”RR PË`$W‰¢h ˆ‚P¿cÔâÄ€úZÂZ½1±æððï¹oØÂËÂå#ôÿIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample18.png000077500000000000000000000005171375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+äIDATXGí—Á ƒ †¡'ŽÀ*ÞÁÜÂ#n 7Æp4”Ghò´¤þµ¤$-_B@xÉÿEI@é<¢ ·Øã·–e]׉išâ íŒãH{)´¦iâì9Yxø£¡|,0ÏóSø×¬µ®mÛ2©×ÎÊ%Tø0 »g”·ÖuuJ©]ÖÚmÛÖù< \IáÇïÍà ¾†U¦Âû¾ß…|ª<¾vúÞ)x TiŒ9 '®d=Ž¥”q âè5õ8®U  T¬þ6G8YüM)ôþÀ =Bý7üw!îm·Õ@”Û?IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample19.png000077500000000000000000000006401375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+5IDATXGí—AE0†ë­,-ÙqGp·°´´´äÉ Øy¦•–¢c¼H^|ÉD_«¦j´m ¶mC×u¼W-,Ëâ-êã.OAY–¼¥Æå LéŸøi²,[‰+P¡( |ÕÝAEÉ@]׃ëºÏø&ŽÒGâqlýÏ×yžóh9H<ÏÛ‰#I’Ì}h†‚´4MŶû­Æ(HEoÅ£(â#–ã„ÑÛå†áøÆ[–1„ÑËy?GT ·bÇq ïû±•+ÞªI¸³ùÏì£;¿‚¶?¢Û2p7Æ€1` ÿc@µNh3°,Z´#5Þº’BÈÈÌ*IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample21.png000066400000000000000000000003451375753423500270570ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 4/Aý‰rIDATXÃí–Á À Cmñÿ¹ž• é ²ôæAóšŠÑ""±ze³™Më/½x#×½«ýÿs€ €²ÿNݧÐâ)€'qÄ+îLñm¼YŽÌ¯ô%D‡§3Å·#8ñUP@€è½z@51é _RDÊH–IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample22.png000066400000000000000000000003641375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 4;['ÊôIDATXÃí—;À0CâþW¦s«L¬VdË‚Ÿ`EÜÝñX5€ˆÜîÑ|t‘àY‘V€¨!ž@‰§ÞÄ+/¹<„Õ5¢¥´HY¥t‰oìŠgôôЕ:Œ“nFÆÈúßv<0QKž@2k{Z`耟ûœ^.u(BÖw‘ºIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample23.png000066400000000000000000000003331375753423500270560ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 5 Šëª5hIDATXÃí—1 Åðÿ/ãæä"žA“2é@zÑ""ZaøI²™Ís¶ŽNˆ¯îרø k7@Šÿ׺ú-€•81Ãz¥øo`{Ó«C“Ð+lW  @À>§Äª.w`öLJȱsTIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample24.png000066400000000000000000000003511375753423500270570ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 5pä—VvIDATXÃí–±!C¥ñÿ™Ûnr®—†¤NNðZ•™™K¸6£HD¼ûª,ñS½@êÀI}Õ¨¬Ÿ},õ-€Só/³ Êæ%¦í”QÌŠ(Õ·_3@¡l~}þü2ÌcÀ0Àx€Í*ÔML¹±>J£ŠpõIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_1_Sample25.png000066400000000000000000000003501375753423500270570ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 5)±…ŠýuIDATXÃí—;À CIÄý¯œÎ•ŠDƒ;Ø ~ùÀ""Q³»™½ÖÙxi^‘²&+òræi´y `eÞ=ÅÎ4ßjÂ/säìJ7!zpz×¼Û˜ÿD§ï*h*°ô@€ €öçôʳü¤nêFFñϰIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample01.png000077500000000000000000000007001375753423500270540ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dUIDATHKí–1’ƒ0 Ea+è()¹ Gà”Ü€’#PÂ-àfБŸ•ÆcŒ±™Ìl±¯HlÙüo+2N¼ï{ôM~øûkü1ƒeYʲœ¦‰ûðh˜ç¹( z$I’ax@Beõ,ËHÝÐ÷=‘ ¼êûÇ‘']#äyÎ’QÔ4ͺ®¦.<éÁË'-u "9R$J0°—Ï¡_Ú¶¥ ¸ Á€T€Y>Dñ€T‡Â«"MÓmÛÐ8O‹ã˜aá u]‡O,Ÿºœ8n‰¼·q§p9zÁ§p9zÁ=û…DupÃÀÉL]×<DkpVG¥òXÙÀI ÐdÆ28Kƒ[êÀoà•wÕßÀ.Dâ4á1 Ókx,M¸¸ YX]ˆav-VU¥,Ä0ƒsê¯@ hîKp00w¡ÍÁÀ¾ •|z£y±×!ÖØÿŸ_(zøÍ¿þÊpy'IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample02.png000077500000000000000000000006701375753423500270630ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dMIDATHKå–±µ„ EÙj%¶a vah †Ú…-ÙfþwþÌò9€3ˆg£½ ¼³ ¼Îó4Ÿä‡?FªÁ²,MÓ¼PE›"u]ëºæ®1Ð:Ï3÷Ž¡TUÅJ×E1MP Xã®ëö}§ø8Ž}ƒ5yH˜¾È¤kƒuDs%Øü`î Àš MÝPਃd@ÀÍLwrH2àú5ÜϘ0KÒ`»v®_#dIúІaÀ³ï{ª àO¢ÂqTø‡€±,K– ŸxêX.7¼yd ªƒ|ƒui¨n@ÚÛ_upà ”²:H5ðrB¨ê@7È›¸E1'ž.M(Þ‰vWHî“!MH)ŽŠ´›nÛF…¶m©Ű»|"Ñ+Œd^TÂGy‹îz„ïÂ÷\~31æß°Ô^‹&â–IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample03.png000077500000000000000000000007161375753423500270650ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dcIDATHKå–»•„0 EÍFBÆvC „Ò!%BP@Æjí7>Œ1B†3ÑÞ€Á[OòODÛ¶©Oò…ß!˜¦é[3 LBhŠxú¾/н5Ô$#þ¾âB ë:x}'Žc¡'0Žcš¦py€4Ð…Ȳ ΔZ–ÅÛ¶…I)IœÜ(U×5LŠÝØ%IˆÐ~±O¦s¸ƒ–$ɺ®ôrìE‘ya†¸sÐ4 =i~Ló&iB» ƒNÑyžÏólÞ/‡ßEtgXï¢ÙÓyH¡¿?z°²˜5·8‡ã ‘Àñ¾z'®œÀ˲´×†N€¶£xUUAÞ‰Sg=C·øœ2p#p‹GÀ)òõôâð–ÛxàûqìNíÝv¢'-¬28g¡—UÓs›Úb"ª&­><·©-¹?4^-.&‘=û’û|ÿÏÇïM”ú,5xÒý4IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample04.png000077500000000000000000000007621375753423500270670ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d‡IDATHKÍ–1’ƒ0 Ea+JJJ¸%%%%%%· ä”p r#Ž@Éþ‰´Ä¶0d2³¯HŒeÿ/ca·m ¾Éÿûñx<², ÿÓ4q¯VàÃ8Žišòœ'Q ÃÀa7'ó< ]A×u<Ôfõ8ŽYÉ Ïsn=éûž'ØpÕëº^ו¢h”eIý¸WÔiÅn ÔÛ¶å€<8¬n¤=–$ Ou¨<âªjƒç©ê€]5ØÓÇMç.4 ðµ 3Óß·Ô ”Ç]2Ø«^I_<úB¥åUU•’¾Y(V}¡–Õ-Ë­ÇÜuu Ý>! NK€878JŸÜ ÍÀ* ô‡Cà4Àù|<é.Ikâ7¤ iu‘ømiâÍ@¨ûï¤ÂË@¨˜øÎËÀóˆ¾ øÑWaƒ=}¼ÿP f!¡f‚1EQXC&l]’ÓÙþ©B9é/dÀø2 ‰‚‹·°°Áføód'a<MÓ°ê§ñÏ>~oðeƒ øH¾‡%ÈtIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample05.png000077500000000000000000000006651375753423500270720ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dJIDATHKå–1ºD0…3¯R*•¬Â,Á”v ´%»°-Ò;ßä¼ù2qoˆÕû›ÉÄuþ"mÛÌüð÷6þ‰`š¦¢(;ЉC,ÒÀM0Žcžç,•H’5¬–Pó<‡£_ÀÁs$TA–e xR×õº®<ö¤ï{3möî>O•¢_´mkk! Üá³KbéeòS´,‹m4Mc"8[(zÇÎ/Òù_ÁIvíÍ@¤§iÊø¯ ¼ôÀµ^œOÑ‚¨t'ˆM‚ éà”ÑÞºt2 °XºçÓÁ ë:¦þ•B/=6Ú¢ †a`°1UUi ê!²À}`>I²À]®?I²€ÙWçÝå`WQ–%[—¡èíK‚×ÍÝCØÐëôîý ÑßdåÜ*U°GS†„›·ïÆü„ÿÓòLçIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample06.png000077500000000000000000000007021375753423500270630ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dWIDATHKÍ–;²ƒ0 EM*JJJØ%%» d ”° Ø%ïV<Š?²qÂÌ;EB¬#ü¥8ÏS=É‹¾ã†`]×¶m‹¢À'®)]eÛ¶¦i¨ÁEY–˲Ðß"q²WUE‰?5ª‰ 꺦|Ju]7Ž#ý¸À£ÌóL·úˆИ2)5 ƒNÓD¡7ˆè¿\$ïÔNÑ7\# ‰$àsE"µ¾!䦱éë9(ʺ±]Ãbüf«ÀêÓn¶ÿ´UäñÁ¾ïtåå‰|¬„¢Œ¯Vvï|˸ûkh6ç°b­ýUX+÷ná@^‰7· 7$ ܱ¹z·?—¸Àš* ¥pCD`eO/Ü ¬ì· 7H~àäeAʧÜ_dA/ß æ•ü>¡ Ìy™Ž÷5)(àa:î±, ²&kß÷”•áŽÖïïJý²Þ ÃIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample07.png000077500000000000000000000006661375753423500270750ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dKIDATHKÕ–1ƒ EI*KKK=ŠGðÞÂÒcè-ôHÞÀÒü ;"0&“ä5!„ýŸ]1ìm]WõIîòù1¾m0MSQ7~†AV;Á3`Œã˜¦©¬ã$IÒ÷½ÄðdY&!à!1|­TÓ42µ§ë:Y¡K‚ >ê-#ö®×°$h°Y™ra&!S{è)šçYP=p>bt`Ë]¾¶D뺖©=4^çί¦m[­–e‘Ù= z0ÕÙöÁ+8`yž‹¶RUU±íƒÓÖëíWç ,uTƯb ¬²ÿó߈2°6"ÕAØàŠ:Xꧤ5>ƒëꀼEPóßôeu@ Dûš: }.t=` "ù¾H·'&ÇVÝMY–îþåY(Û…óZ¦æeP†ÇØyÞþ½»Vê4èd†–nB_IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample08.png000077500000000000000000000006761375753423500270770ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dSIDATHKå–1ÚD0†íVtJ%·q¥RéJGPr ­[ÑÙyvæñÌL"¿­þ·‘ÙïñÚ÷=ú%o:þ /Á4MEQ¼®@êÔC¦H§ë:êjÇñ8ŽÔOÀ!PÒ§C Ã@1QT–庮tbßû¾§.‡&Ȳ #ŒtÄpPÕBœ‡o§#g´©zE慠JmÛb7é"Ä…"6`øðglÛlÛ–$ ¶Ù(q¡J:°, µ$¾×Á€óÛ4 ý8f ÒQàÃ<Ï”-%\éišR¼<#]™É¬[Ïtàžžç9q>¾;p¦n Ë[z8ÆÍD|~  ìô[ш(0Ò¢^ðT:ÀLÁùýõÇt€Pöé€&¸¬vëgú£ÀîšÌŽæü’¨ëšZ'þÉÇo8QôÞÀµQA³ÿIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample09.png000077500000000000000000000006651375753423500270760ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dJIDATHKå–1Ž„0 E™­())áV””Ü‚’#PÂ-àf”Y|!“ØN4ÒJû"ÇñOœÄäåœË¾É¾_#.°®k]ׯ+d™ç6”"ƒišŠ¢€k@UUäWU`YH:yžÛª@Y–ˆ±Óu:œ†Ö[C éct–5M³m:\†4` øôa’à0ÈtÍŒütù¢ÑA<b/'êùè¢ÑAËཌÚ4£÷$e«äŽc÷ì à'ÍðŒÌQƒ¢ó«Ä'^ý°zO€B{õ#~Žñ!–¦ht". †ÖêGH\À«zé¡"ã8"ðNJN<,~iâ°ÞDðNú­´pTžú2s¢ ö³è„ú.J¯Ø6à]ô~ŰžI{¢Î_B"Ú_]Aß÷h¥Ñ¶-ZWþÃã÷Yö 2ÔîêiJÉIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample10.png000077500000000000000000000006661375753423500270670ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dKIDATHKå–1¶E0Eó~¥T*™‰Ò”J¥( AÉ,˜™2ÿ®ä|+O’›ˆ¥ú»Á%g'BøH)Å›ü`û±‚}ß«ªú(hg]WœB·(Ȳ,yž£ÁeYRWø ÆqD¤E–eAG@0Ï3Â}ßOÓ„EÐÁ ¶m;ïLÓ4Çqà„”¦†¨ºàEQ C3]c:˜Ap´¢®k”¾¡¾ë ˜Ap‚`{s(Yp‚³=Í-JúÇO— zïôŽ/çÑRA¯7öÔ8R0bU‹DÁ%›$lïŸNÜ\>>¸! ŽÓ Š`E0ˆØÑDL:8£Û¶µ—&œà2™šÈŽŸxvúÝhW`®ÕiÑ·Àü=I'Ü‚³û4Ÿ(¥âœ_‚øß ·`´Žãöó®ëÐ:fžþÏ¿i2/ „øl›Å;IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample11.png000077500000000000000000000007721375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGÕ—1²ƒ †ñUÚYj§§ð*–)-SÚYzíô^)70]ž¿Yõ ‘Œó¾™@Áýp¼×„¸*/㔀¾ïEš¦Âó¼ÅÐnÛ–z€%0¥ëºW’$X2ÖЯi©ÆHÀ0 ÆŽ÷V×5}åVœ‡axøqXžç¯qç¾(o·Ûæ½ïûó;¬€(Š6\;T÷p,Çèf°v^=å¹ßïË8Ý,°q;[ÂtÝð|>EÔRýš`2ö"°¦ D5;Œ£!ö€üBèfóìc~]¬TS7œÐånæN à’“É²}$À…c‰•]V4ÉG PeÅOKŒ9?ëXb$`Ÿ’mÖ˜ÃHÀ·œV¦-À5l:ŽãX<jÍ ¨æ6­OÓO5wX¥ã,Ë–{JÜ Nƒ%Ð.¶†`U–å\Â9U°{ç:œï΀3Å3¨µ…]‚ªª¨öf @žqLwª0σCäF7.¾ž ñ Ï£Håž8#IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample12.png000077500000000000000000000006771375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€TIDATXGå—1Ž„0 EÃVÐQRÂM8Gà”\n7ƒ.‹£dPŒM0öIÉ茉=‰ÞQäÇ^?Æ÷X–EUU¥’$9 ¸7M“ÝäÅ<Ï:ÏsÈ•àHÓTãhw߃4@‰»k‚4PÅA¨m[»¢uß÷‡50qÒ€/à‹;Î&îF< ÑØÖ,ËÔ¶mf¾GA­ëjæD>îëìLýá"€»ï é›\x÷4WiÄŠÑk¯àmD Ã`gÀ+xÂù¨nšÆ®ðxd T'öCÈ®òˆ6ÕQ¤Ä[@¸,˃ðq€e~*Bá–. `âÂÔ€d¢]¸jÅ$A øâu]Û»Ú´\XBúöpÚ3´úmV,œö -F~› ëLίPp®Î|÷;NÞü÷ÇJý ±ñhRîéIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample13.png000077500000000000000000000006711375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€NIDATXGå—=®ƒ0„M*JJJ¸%%· ä tp 87 $™ÄHŽñÏó½ä“VÁfÇ›e½I¶âƒÜäø1þ¯€qEY–"I’ƒá{ܧ@„0MÓVòÆiišnÃ0ÈUvh¬cÕ Â- Ï󃃪ª¶u]åŒ]×½ÍñE >Ö4¼s;ßçù¢pJ€= .èB„ìÞa–°ó¿³Íó,?à'`PˇþƸ #жís|dÿs´Ý/Ë"¯üóé0 XeYFï\&ÀäÜU+v¢ØJ4ãD 0í:Ä98-5>Ö9r W„\‡`rn:ŽC¡˜œÇìZ… —Ö«œJÀ_9T?Ú „|ï­·ËЖ÷}/Wx@|¨GñCݰ5§”½Ç;c¶æ”êB]×¶äýõÇBÜà—^íNê]/IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample14.png000077500000000000000000000007371375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€tIDATXGå—±­ƒ0@ͯ £¤„IXƒ’’’ (6 d%6€ŽÏåÛ‘q|¾s°EÿI§˜ û¶#:NÄù‘¿ã{¦iEQˆ(ŠmøÏØ\–e9ò<‡=ƒœÇQö a @ò4M­I͈ã˜-ÁÀ’WUulÛvô}ÿrŽ+ÁȲì2xÓ4òÌS„#A ÃpK®ð• ô«‡)ç`“À ô`½¹˜¤Ø«A|o1½/Ù Ú¶}ášN½/Ö€i¯ëú"Áežg²{4µ¦Ô] °=;lð/Ç[rL<¸€Or ˜$¶½¨¨%»-€%æ$Þp%†ànVox…H¬` „N¬ BM5)`Öª SÀ¬B&V8Þ©|q–åëºÊ–eYÊÖ³<Ç+ÛŸfI’ˆ}ßåÑ}ÎW²8—Pýᜮëd+ çk]¶4 áÀ,­lqgsþ÷¯c!~H?šB-ŸóöIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample15.png000077500000000000000000000007311375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€nIDATXGå—1΃0 …C'FFF¸ G`däŒ\ n7c¤yQu°C¨ª_ÿ'EÐbxÏÜdÓ¨ò²ÇŸqÛÀ²,ª,K•$‰9Ã`¯‚)aÇ­( LÛÇèºÎFɘçÙ+ìŽP"ϲŒlšf«ªêð]ß÷öNÖ%^×õ¶®«ØÌ¹k"MS3UXyžÄÛ¶µWŽÀ„]Xñüôn¼v#Â2ÛaB ¡ñk#š¦Éž=¦àŠÂŠÙc6°QnaqEx^1dQÎÙsfw1@mVR¢ PâÒìA”XqpÛöúXqlYS¯å;â È•uŒ8ðe}~-ß5@FLÖ.—(ñ'²vñxb‰Iðà:¡«î×$m™×õÐÐ!é ½‘ÛÙÄ M(]3öÓ'Þ†7rè‚4GîЯp¡”nÛí™}ɹÁüF‚ÿþïX©7ƒDQþ4 eÃIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample16.png000077500000000000000000000007361375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+sIDATXGå—1’„ Eq#Í 5ÓÌ#z C`¨·ðJÞ@3מ…¦„Ï:5µµ¯ªk@)ú7´4íâƒ|ÉßñwLÓ$ʲQÝúô‚ražç½( Ê£Åq¼ã(G»dYft¬"0 Ó£º®÷u]oïú¾zç+ GOÎ9&. úä*ráZo”|úÄgPäjœk¼ðÌ?ƒ¯ÂÞôIÛ¶•Oí\.Ù®·£<ÏŲ,²wS [¯¼¥èÎí’- ´WÂ+—  o>MÓ»sÓaŹLœÌvXéüZ€­:ú|ªD°€³²ì¹"H9×÷Z7ßÈALwÔ±À“-Աຠ@ø$› ¨ g¼7$À®¬ªªÓÛ1½£|q,1c»šA[$‰Ø¶Mö0Ž«™8rFö@å¸ë:Ùz@å–bÐ5M#GüÀûŠÿþïXˆo9K Ùãß?IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample17.png000077500000000000000000000010101375753423500270560ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+IDATXGµ–1Òƒ …׿2¥éÌ)¼Š¥eÊÜÀ2G°Ô[˜#yƒØùûÈ ÑeQòÍl‚ òž ÂÒÈ0 s–e3}EQs×uº§Œ œ¸‰4MƒLˆ l‰ßï÷ùù|®~C„˜Èó|%q×LH°wÅ ® \ûhÛv50Çãñøô“L…È€þªªô¯Û¼ßo%l›à0ƒ! àà Ž`âÕmÝÑàcéÄr¹\hš&Õ^RJKT›#IÝRtë›?ýÍÒ4nÕu­[‘@bòÖD7à·&ª,Pw»ö½5Q à©qÚˆ½Óæ´½R"NØÇœK6+Ã!gRîd`Oø¨8ØZágÅÈ€»±Ä6x l-´Âïat½^iG}Eê  ö0z½^+ñåÉ£Š6îÓ{’u6îÓÿQ=ʲ¤Ûí¦ i ß÷z„0{àï³¢”+ãØ5`—bgàÊ8v ìR ,ž}±TÆú.¾Œ¥¿D¼Ñ?»h©,PÇIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample18.png000077500000000000000000000007561375753423500270770ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+ƒIDATXGÅ—±­„0 †ÃUÐQB[0 %%[P2%l#±tŽ’“Љ–Þ'Eä¸$þíX‰‰Žõ|̓Ͳ,ª,KE‘~NÓdþyDÀÇ<ÏGQ©ÛcÆq4³x°dYæ4èjq‰` pªªÊùZˆ¯?^œ¢ïû?ã¸"¼®á¿Ã%‡W^°m[ó–æ*ÂGö¾¢9>¼Q’$jßwÝ?Cª¶mÓý;àŒ°x–÷D]×™žú ‘„uã(0†ËF°Q8“P?EHÂ=7,â·ažçj]WóKh ¸ÀM‰s¶L4¡Þbxâ½"ðH¼4MuÒÙÆå•ªPáÜ–Çà^¸zjpWž…‚Hya  ¼®ëú8oG3ê^® ‡öÆkÌ­—q ¯1¤—q)¯1¤€oÜ W†aÐkØÜF•sä]€‹ ¨r޼ p)&AÓ4¦wAÇ—Øœý‡ä< ýæpæŠ$a(õÂ!LB~îIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample19.png000077500000000000000000000007141375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+aIDATXGå—=ƒ …1•v–Úém<‚¥¥·°ôÚy =’7Ð.a Ì A\~’L&ß A’÷¸,ÑB¾È×_ÃÉÀ²,¤,KE«ÇqäO€%À2Ïó½( X²—ýÓ4ñ‘xÐ@[h²HÛ¶¼÷Iß÷‡ç6&œ èЙÀÌ šÀÌ:%IBö}gmÓWäqtȶm¬}:t]Çjºþ¬>CŒ„o Å W?ÿ›¡8$Á À9aCð=ç9Yוúà'¤,~õÆ0`|€£Tu]ó§f¼ Ð÷þ ,Äiâ#ÌxЉ«ÕÎTñªªÐÿZÆÉÀ0 AÄkjfä#XÐ¥e>âÚ€NÜvÃé@x—8€2 &¤¡Ä”YÜ¥˜î ¨ÃHN³\9KÏP‡‘œf¹Bï¼uäßoÇ„<U‘oÆÒ ŸIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample20.png000077500000000000000000000007041375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+YIDATXGÕ—=ƒ …1•¥¥¥ÞÊÒÒ[Xzíôz$o`i|™uBpA0'ßÌ&BÞã­âFTÞÆ˜¦Iäy.¢(bï†a Ú°\ÇqͲ ëÆ*â8^û¾§ÖGœ @{¬rj€[Ù>„wŒ8qìë³­å‚Ö'î£Ç*ZêMBh üBh3¢+ÙÏ%`€¯B¶³œ!k ÈÙï3dmF´g?!(Ë’ž¶©† z¾…›ÿœ ñâ–õº=±IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample21.png000066400000000000000000000004131375753423500270540ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 6ßw…K˜IDATXÃíWÑ€ sÿÿËô\‚+/»l¸Á\03Ä%ƒ¼tõÜçQbµ °])ðè»ÒyêȾ¥ðtΫUÀÛÆð <[Ü7| Ó,é ”a‚—àGz‡~ |š;­©F4㺫ÙJ¨O’‹–zŸsPÉ+þ fCªÇÜyy M‚®XöKp,é:PSáPüIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample22.png000066400000000000000000000004451375753423500270620ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 6\¤Œ²IDATXÃÕWÁ€ ÿÿËt¯P!ű§ncHªª£1$³™ˆߢz$f­‹ðÛFƒ©KÙ°ÇŽÏܹPœU½Z·²Q ™àŠC#ÄKDnæàjõ+;¤#íð Xàé_q5xÊ‚YʡݰBuÊ$x˜ÜmÊoèD„jTÜ ¾U„èÍ•#wËDtôa)`Küaò‰‘ìW¤ªè¼–•¡WÀXOtà^ØIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample23.png000066400000000000000000000004341375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 6'}ô9©IDATXÃÝW[À “†û_™ý.KTž#ê·X(DDFãÁh>ì1""õÝÁ\úµ[9Jð·ýì Ž<¼ŠLë4¼À»ÜjÅ+ýÕjî¶ËY9¿·E¢Ö(ᬨh×üð,•èOc`EwÚ4Ì.Ý,Ò厨ÝxŠ,Å à° ³<ÑgNEtE~Æ>݆ïkDZF,…{þB¢ù#¸SùhÓõXL†nÂÙIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_2_Sample24.png000066400000000000000000000004361375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 64ù®µç«IDATXÃíVA€0Âÿ¿ŒwuX+šÈQ mºÑUÜÝ·B‰Èé[e”­Žz2D424ž%&P­( « I|ì‘éq¤p÷ÛWÿfJhÙG½Ð-`W;Cžç' hu¬m+ꄌçY;d/å,pt…­ ¸D`&55’±Óž–‘Fß÷Qq?ð¶m˽TD÷}Ÿ#鸮ËT9÷¢(Ð^×5¿? þª{ Dq%äü®ðúoŠÝ&Ãá3~SIUUlíòû¡N°ùw³,c‡Â ™išNÓÄn…£Æ´øW¢mi±WÓ4ÜOpT@æ×m5§7yEJ×lržç¬à8r×Ïóæy†E@’‰k2¹,K2Hæ™ËJ¦v4}êYtœkP´Ù\³aŽãHö‰=À¼’$Ù½@ ÛåŒ? ¨:Xʺ<_Ùñ„M€™ò qs¾«·Msç¡Pïü4±{‚ZhÂ&쨗»íÛo׎säçxÑ7IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample02.png000077500000000000000000000007251375753423500270650ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨djIDATHKÅ–=r„0 FTÐQR’“ÐrŽ@É (9%Ünùiˆ×¿ò’L^³^­G‘¼çyª¿ä“?=lÛöu±, ‡RA>æy.Š‚÷)UU"ü›¯`š&NüJªÆ-X×Uvƒ,ËxŸ·ÉÉ”Ú÷‘qùû¾ÒÎ(nÁ®ë:]ô}Oqy¡C¶A5HMaiZD¤l꺦Åq´ˆÀ"ÆÛÅÑ #»qþ>D¤Ö_\€¶›H`d¿A Ï›<ˆF— ÃÀû\$œÁí 8Þhº¦iØàï»÷@wøúî‘D‡ÇS_¸“13ò<§µ-yÙD®ë«Ž¨iü^,Ë’RµmË! S€Ô´[8ñ@´ÐÝg` ô&Š!®ŽèýÚaásØãÏ7\cèçaç%£Û]—=m„/·H’;Ç+ œá]Fü÷¿ë§(õ î+R|IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample03.png000077500000000000000000000007641375753423500270710ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d‰IDATHKÍ–1’‚@E‡0#”Œ=Š!!¡!!7Ì#ê-àFpÈØ_v¯5cOÃjվĩfüߦ§§æy6Ÿä‹?Ct]÷}çv»qH 2iÛ6Ë2ÞmLÇ—Ë…Ÿ)\¯×$IXÛâ|>óŽ’~)ë-@ðæ}"’ýfªªBdGHS Ú&#œN'E]Í3^‰6õ}Ï«_Ps–׬îƒ4M‡a µæ»Ú> š¦y¨£*´pÏC•„(Ë’£!TN¯åyn—]Fe°ßïYû¸»Zeð8û^`#4ÊÀ>û^„¦[Qd”áx<²ƒ18üà™íD]×ìðâü«òÀ¡"ï‹zÃD›¦i·ÛÑz©öž‘E-–j뮊 ¸˜½‡Ãaõà@R6Ô´(—r`ùwC¦zÇêöÐæ¨…²›VN¹U§ÄÒG—ðªAðæYòJx €ÞC&ü@ðÀ8Óœóçw360æåã -l=φIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample04.png000077500000000000000000000007511375753423500270660ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d~IDATHKÍ–±™ƒ0 …“«BG ]ض ¤Ì”Œ@º°ŒÄ¤Ë½³>ÇFÂÜ}÷7Ù¼‡ ²||<‡ß䋯*Ã0dYv|‚v×uÜ· f s»Ýâ8æÑçó]p æUjÛ–âðóu E¸þ†¬ K kâ"Mˆ;WUU¬gðOG!üÓõv‡o9IÕ*'¾Œ'IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample05.png000077500000000000000000000007461375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d{IDATHKÍ–½‘ƒ@ …ñEáŒJ!£BBwAH AÐdÜ$6H„&§P z ˆñ'¼iäYB€M'ò Û#ÄgG]×|ãÄ ô¡†(ª2Ó'kUUh1ö81 ]à Þ]¬@|¡8pœk.'F%Û+ þÇÇï_ø²@ýäúÂî£Z÷IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample06.png000077500000000000000000000007121375753423500270650ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d_IDATHKå–±µƒ0 Eɯ £¤„QØ‚’’-(:Ø6ƒŽ¼•[² !UnÙ~±%$û¾Gßä~¿F¨À²,EQ<`LÓD ^pEnæyÎóœ¼509Ž#9Éx°{𦴥EÇä'ã0þ{Ó4]×Ñà€üd<ïí°5M¨I@c™‹iŠP+Ãûø•4EF‘ÂqŽa§Y™v¾a °ó9Ú÷=-Ë„ °ïð¾n¡Fúëà(1ÐY×µ®kRp^×E…q, iAã# k°¥éS€ë"…(²ƒqOGK’dÛ68„®îéhmÛ*CÉèÜÖ“¥òÇŸå¬,Ëð¾8 Y6ÿ°È² KlVØèU¤ª*š}Á (o@c£F!´ðÂ#à¨Å•Àå¨gØ`o ¤ÒÍ 8J‹£1ˆ·¨áí9®0%Ó ¤ßùø½H=¥ÖÆÞóðÒIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample07.png000077500000000000000000000006551375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dBIDATHKí–½‘ƒ0FñE„„„P P!!R!tQ!÷ Z{’vlÏ\p/±,Ä÷Œõ³<¶m‹¾É}JÌóœçùã Úã8Ò5<Ï0 Y–Ñh‹8Žq‰…}ßSžCœ~{]×è캎¾ï32„ hÛ)eY®ëJ];¶ƒºÈs°, µ,¦i¢ø÷.HO’„â?.8¥›Ya¸ @´wÎyT7`ý`Óˆ0*w£½ÀUf7¨ö¢ôÂì¸Ë“lÀ¶¨ªŠâwBŽ›‚â®~Wø]ý™z€Ü4Ü4m=¸Í¿@ä @á-ŠB[lŸà.jyÙב¦)z˜mé"݇.D›qJ‡æè>.[ea8?”í`ŽIe:ðükMÓÐ}:ø²ã¸'%ƒXÔ<ƒX€˜þÌËïm¾,ˆ¢_%ÞäQrŠkÐIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample08.png000077500000000000000000000006711375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dNIDATHKå–1Ž„0 E3[AGI ·âp J®@·€›AÇZë?( ± ƒFÚ×8‰?8vÂkÛ6ó$?x>ƹÀ<ÏeY¾,¨;Ž#†O¡ILÓTæ¹$I2 æ©h’w&RCèºÎŒišæh$ 6*h¶L2¦)m57N—AšzpÖ¢Ã_ ¢f-Æd.äy¯ob2õ‚¹ƒc‹S vvÚè<"+îs"¦ân poŒ¥»Nš¦ëºRƒ¢´, mîVrÛ¶Ü`™ü! —sïÀ‘° Žu/T%+Žð}'Du]sƒ¾7òRìû- ½¡wg»^> …4Ë2ž_U¬.¾€W>º†}:Q Áêœw$H{NF̰.Ô#ᑎ , !ŽÅk(¯Ohâ„.C+…~ç?ü›Þäac~½¯xKzÀ’*IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample09.png000077500000000000000000000007251375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨djIDATHKí–?–D@ÆÍFB!G‘9‚º[p Ž$”‘Ùï©âõè¿fgÞn°¿`¦¦T×7ÕªšÇ¶mÞ'ùâïñÆqL’ä!gß÷d÷ÀÀ0 Ap¨„ïû]×q¨‹@ÇœL48Tƒe‹Š¢ £,K^±Ó4 ù×u%C ¯¸ ¶Ž×Û2¼8QMÓD¶9Ãí6¥¦:³cëÈв×áŠÜT?í¢¤Öuü'ó4Ã@8 Èÿ[v*¡Óp8s]¦ˆ2J{7YÉEƒ½o¢»ÞöÀÁùJÆ%áo<0«iš:õ.ìõD†ð[Ïá ” ðïEó<ãçp۶䱂¢Ù’a!ªªè’cè}qÎÙ{ X–©)ýÇ^ u]S$!O¢BˆE2kv ‹5ä“5Ë2,áËϨ€8œf ÙV¸häynÈLÀ ¡Üq™ÿ—_ ž÷ µ¬%ëk,wIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample10.png000077500000000000000000000007251375753423500270640ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨djIDATHKÝ–-žƒ0Åé*pH$Ç1HnPÉÀÁ-@r+pìÛd~Ý4M†³Ó$ÌËç mÛ‚;ù¢ßÛà¦iʲìñ»®£ ]°D>’$¡ Ïç“âX80 )™‡¦i(Ô'€þÈRUÕ˲E¡0jõsæ­ëE‘.ïv?sŠæy¦’5ŒãÇ1ut?&Ð÷½™ÝÚ'R dišîÄ×Ñ4ɃlJ¬ª*íLøpª çyQÉ« ©N÷,F…ÏTÏî(ËÓàø`+KTK×ur”¶»JA5Á6àWA5Á6°­DQË4M^½Á{ ØØšÀõ?7êº&gá’ §C^v"¢vÈÿ‰è¬5 @—ËóüÔ $Iò­Ghw×]ÎU¿6ðkq^ŽÐ pêׄiƒr¡@;…°ú1gg3‰»žì,®³€ d&}ÄÁβP–¥62¡&Ä\;"UX_Ò6Ôàˆ«S&ŽBmÉ\¬&#¾b&nþ{.ÄŠÍlè¿\ƒIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample15.png000077500000000000000000000007621375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€‡IDATXGÅ—A²D0†ã­ØY²ã(naié–Ž`É-8’°óü*™ŠL"&å«êšŒ ÿéNÒ=Á¶Ã^來³€išXžç,‚“áÚ0 ü.*ã8nq#eZ ÃpëûžßMƒ,Àæ\˜«²€$INŽêºæ3ÛÖ¶íi"¨à¥:çUòÂÎ9@ŠîøÙ9¦)›ç™;ðÑ5?9°5eç{”øˆ"ðÝîpá‘soÛP޳,;9V ó!·Øœ £Dã–uÏð=u×m"­.'£€z2zd¦4x툢(bëºã= lY–c,ãµ#jš†ØGˆŠ÷žÝ’@çÊkP#lx¥B#õEQÜk49¤ ‰è-ØÕ!rE×uÇóÂLg(›P«dY–|æ’ü*º½ï>ûQB/¿Ð&§êÜÔC Œt•ÍÕlÎÁe‚ºªª´/·Å9 ­0!XpW9Wyùï9cÿøN°œÜ¤ IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample16.png000077500000000000000000000007141375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+aIDATXGí—An„0 ECW,Y²„›pŽÁ’%7àp ¸Ë´¿J$Oê8N‰Uꓬ‘˜0ÿÇIìLe¿0òá>³9ÏÓô}oªªz <Û÷ÝR€ äp‡íºYc¶msoÅÉ2ñ¦iXA.êºvoÆQˆ‰OÓäFX»®ëïSYPÓN…C0s?.•µ:;I„™ÈÚZ°\Àš‡{E¢˜ØñL-WܬØ€ÅNG‰¢tË@Û¶¬ ±lÜ2@Ï; ¬;W”8· ÌóüýÃã8ÚëºÜÓWB#aa*² SH…ém÷´j•üõ} ÿÞb×·(Ø„1Pé†aH–S î"C øJž]-œxØœD´Òá,kÉ錢_é\¥¤S¬-‹P^iY–EÕ}HwÑàšŠ6$aOÒÈ1¡¥¨ xB#¹b÷Ïi)6`Ì'IµÅà†äkIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample17.png000077500000000000000000000010251375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+ªIDATXG½—=’ƒ0 …ÍVÐQ’nAÉ1RR¦Ì (9%ÜŽÄ ’.Ëcä¬qü#ØoFAŒž,;ⵃq_yž¿„ë±ï{ºÂ'X€Ôd¡B‚ xš¦ÆÀªÅqL#ü Ȳ̰,ËsmÛÒ(7A™ p»Ýèì÷ûý}[… ÈÊ<·‡Ë͇Ey«òìüÐñ¦i"Ï¡¸\.bžgúö@æEQl‚/ï yP=˜zCUUtÕÏn¦®ˆ)ØuÝáf·95MÆiË»¨˜ÄøÒ¡šQ]×®*Þˆ$I’ˆçó¹úKÄ"lõumD*MÓ'V!Ã0з-§UpªpZ€^#¨€ 44•o¶Z„fÂ)@n@0•¾v @`9Ø7ŸMè;(Nzc EkÛÄxŸªV»ÏX T6¼ô}÷]P˽^éì'^h­j`¾EFÏϰÁúa}+ž\zMZ\Ù–àá2Wö€-@"Äöæ« PAvúÒË ,9u1âpêbäGˆ_ uDËUiÕIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample18.png000077500000000000000000000007701375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+IDATXGå—A’E0†cVì,Ù±s$K;naé–Ü‚#¹;ã7É+RIt2“²˜¯ªëñâé?-þô öö"_üó5¬ÌóÌò[³àÙ·Õÿj5¦õT ™äŽeƒzJ¬gwí´¤Ùÿ@Ù» 7ŽE™g^NÙˆYÁF»øÓPRÖa;ÄIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample22.png000066400000000000000000000004741375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 7 úoPÛÉIDATXÃÝW[€ f÷¿òü2! Òî¡Q>×n-›633!VkmºG†‚žÏ±$6I^(Y¸³€}¦,(\Q`3»”Ù£½K‚P˜@øÒ(h™ªÁÃf&MoDLæýs„Ìæf:ãã%‘F`Ô êBöQ™Ê$8*÷À«&,¹†Ù7âß 2ü¿îaÄ•Ò Dfþê]}òÊ…Wr°Nzwx,ú Fy Ë|w£ZÑFÂfŽ’×쀟kD;cbXUï¡ÑIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample23.png000066400000000000000000000004421375753423500270610ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 7.×}ܯIDATXÃíVI€0kþÿe¼yêihÕ‘£a­ffå hT¡ÖÚüŽÆ¡«ŽWEXÎQ€Â¤!Q3»3êWÊa‘hôÛÛ°ç”ÕP ˜³€6ˆzÿf Ò‹p–ª-]0d-kyÓ‘Æ€7®­ƒ¨ÅJ* é oÃo-£×¢Çh¤²– º²…i y¯ˆQäHéꌖëê¥O²oÀ™ ÷Ma#\3Œþ£8":qQBíg~IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample24.png000066400000000000000000000004561375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 8ß=f»IDATXÃíW1À +ÿÿ2ºxRˆ@u([Ï"!DARU½6š Dd®­ä"Ù ã(®¦4 6  šò´Æ Ï7šùR : _›M*²^¥¿„Lð4€Yð#î„î¢> ¤ýx ¶CêhLj8[˜³JÑV‚(±­ˆ€Ø.€xjíšÏ/A¦Ý.õ‚¯ß)ð» zBbôñÚ¬µfíùÚŒ²ãV$!ö³šðüÝ$ÊJ¸Tg„Ú omTKÉdWIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_3_Sample25.png000066400000000000000000000005001375753423500270560ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 8[.|¸ÍIDATXÃÕWÁ€  ÿÿËtí™ ÐòjÂØt©ª^_‡—¬"¢áJ(£‰gÉ-p!H`ä[‰|ÒVº„ªúÒzõ1ñJò í! *­B¢z•#€9;ù6fÉŸ{\]¹e^ÛzÁ„dïÑìe‰*۱煔Jà©­ü´ ZVŽ$[̤øæHÖêTÙŒ8b"ÎY.9CŽŒÈ3†EÇ8Ó ÑñÛª¶{Ʋ⌞?cN¼WX’ Èy¶’]Ñï~N¸;A_N©IŸ“IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample01.png000077500000000000000000000006021375753423500270570ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKå–± „0 EÉUÐQÂ6°#°cPÂ0@ÇYÄBáppl„t¯9Ç—äÛ‰“`Öužäƒ¿ñq˲ìûÛ"`®†!MSèÇ1º$ð›œçù4MÖf;Ÿá—hŸ½®kkÈØòðÒ¶-ö XLfX–evöªªÐ%äJÀ žgô ñ ìŨüûâdøAQ]×aÛ-ƒqî­xÐ{ÄFÀZÀ ]G«‹øÛ|>Àn!à†ÏÂVqU$I², 68Îà ®Š¦iкå‹fŒ±†&ƒ{ùOxAÑ @³É¢7N“èÓd^£€&¸AÑ @#`zà7€ò$‡óÊs âa(ú¨ZK,\ïU…IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample02.png000077500000000000000000000006041375753423500270620ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí•Á ƒ0 E“ž`ض`¶` ¸Á0ÀZäUÔI0©•ú.8‰±ñ'Nô²,êNxÞ†?Á0 yžw]‡±’ÈM’$äEÆB< ú¾7ßA`Jˆç'§i:Ž£±Ýž6<ÿ`‹^–¥1Ĭuð„ëC¸$ ׇpIt>ÄZ<8R/˲¶m1¶cMP×5Âs Ž7‡5 AE©7̱«(5M¦^¸‹ÛÁ{¸7¨»¸|‚-©7°À÷ ßZkXNØwwð}@ÛV0|‚ªª`sæÊÜr‘ÇqdAùaq¹Mcƒ&".ÂÈ;ÈêË5r€¶m¡²Éú&§ÜµÚe÷ž‡üy€”ó˜€Ï£~_=?¿ó1ÿHy-À-IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample04.png000077500000000000000000000006141375753423500270650ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d!IDATHKÍ–AE0 †õ­¸#8·pK7°uvÜ‚›±óòägÌmÓ3ý$mšDKmÛ½É÷×#À<ÏEQŒãÝ ª•4MÉ2Žcè.ˆŠ¬”bAbü‡=E}ßCòcœ¢,K ¹`OÑ™ŸeY¨ ,˱¤èšï?øEt<Ìa 0M{'(?Ý¡©<χa€®Çà||Cò/À]UUaè‚&ÔZt]w^0ñ$€¹¼54ÀEz–¼îøÅ±Ã›ñY¢eYheâS ï{Z™H:ôsb( ¾É¹ø D¹·Î2Za’ä¥Ñ¿W·ùù=ÍÅEñ"^9…8è81IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample06.png000077500000000000000000000005771375753423500270770ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–±ƒ0 Eq*F€m` JJ¶` :ØFbJ¢ œïbìï8TÉk„cYò׳ï{v'ôƒ3}ùõè˧¢Tý(¯2.êGß ð]øZtv@ô#VÛ&©Evœ»³u8`æKð]\¾ÃO9<£p™ ª-žQ¸¼ƒ¾ïa´m ë¤?ýÔAû ÿA~<3ŒI týKIƒÆpódÙ9Ä.%Nº‚hIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample07.png000077500000000000000000000006361375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d3IDATHKå–AE0 †y+G°t·p·°tvÜ‚#¹¥—‘ŸéTÛD•oñ^Ú¤ýI¤Û¶%oòÃyžË²Çã[ЈäyN‘Y–a|UŠÒ4eCl¡JѾ Ð÷=¬8ö£Á%DTU…©;ÈUt–к®T©lëRD-kïX;Úîãñqæ‡ÀÔ²ûÞš¨ëSpH—rOÓ„=\»ÀñD I tÈ˲°Aùa#]躞ø¢Sî/QþÄí6×SaÖ@ßÞnq={ §¼‰CÀ¬NZOâ(0¾0 –yp˜Õ)r»“ÍË×píp [À— k#ÌJ%DØmÛòJ:ÞÀr ±ŸÈ/ýwÆ^ú‰пœ#š¦¡_ÍcüåÏ÷$ù:ñYç‚u:IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample08.png000077500000000000000000000005641375753423500270750ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d IDATHKí–Á ƒ0 EIOŒÀ‘U؂؂18Â0p¤þBT1ŽIƒ„Ô¾ &NøŽ­8¸u]³;yáyaišªª†ïW¡éEAÓò<ÇûEÂ5pαœ)ò€(˜Ê³%ê”q1Oši)O@€?Á`èj”ZŠ(ó<³Ý4 —„>_ô„O@ÈC//·ºƒS_0?Ü)JS^BŸX·ä|]×aÝ>F=,A‚o_Y×5ô}_–%ú(AB7ÝÛ§ÿ G„"So•A m[X(]˲l›p„ˆ¿ô‘Ö*’ðò`ãq‰àã쵿ðóûYö{Váý&Kž…IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample09.png000077500000000000000000000006551375753423500270770ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dBIDATHKÍ–½‘„0 …á"è2J. é‚2 ƒ. $:€ŒÕXïߜֿËÌ~ÉJ–ð3’m6½®+y’ü>†“À¶mMÓ,Ëß *‘•¢((3Ë2ø>ØÖuå¥òÁÞä²,÷}gÛšü{îÙû¾gÃõ&'eRõ꺞ç¾D”€Kó-ã8òì†40–Á"Àk$ڶŇø–]”¦)ÇqP)ؾ¹£†IL»hš&XªÐ°|Qï!c®ÁQ¾ÄÛ˜Þ^ªFÿ‚p˜€uù'ð%ä˜~ÿ¼[>Œ{ù"UUQ) ¾Q@Þ¦yžŸç ÇqFÞ¦Ã0ÀŠG½‡Ô’®ëðð/ˆID}ôcOòGÐ/ªP!¸œD"¼æ‹öææ¾¸ÉŽ_ˆp>íÖÿ2QÍ…‡{$/!Þ3í²ÔîIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample10.png000077500000000000000000000006331375753423500270630ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d0IDATHKí–Á ƒ0 E¡'F€£Àl[pd¸Á0p¤þD ܘ”"Ujß¡µc“ŸØM¨?ϳw'|߯)aÒ4íº¾T"•0 )3ø.è}ßóR ¹ 79Š¢qÙV“è=0³EÁ†Ë>l Oʤê%IÒ¶-| E ®kL/ œi¾"ÀSY–ah‡øJ“}ßgcš&Z)ÛµLbkrÓ4°–:ÀreÙ‡Œ½>G ø/cÛóEõÁè„ß0Ë'0ta«€ÜºÝ®ž/„öœY> ×m«OËÇè Û8Ž^ALBˆŸWÁ“Bò<‡õ ´§ª*„%èXð¾u—^úW¯ŠðPùn3/‰KeYÒ§ý6ü‘?¿ïãyOk¼ Å&SOIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample11.png000077500000000000000000000006371375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€4IDATXGí–ÍD@ €Çž¹yoáèè-=7Þ‚GòܬJÉ c¶Cwe_ÒèTþí:ㄸ‘>oãÿhÛVDQ$êºFËE ¨4M3zž=3º®‹ÖkX5a¢ë:<ÍÁ£vr ʲT>ž¦)j*Ö%‚ Pð}N=HÇhݳøQKD  (Šõã }ßã›=²…^rã˜n° §Ät{@ö¥`lBh¨mãMµÅÆ1<3vŽã Fó?Ì€îößà0g—K¨K‡ÈÀÓÒ± Ãp}¿تªRl´%ÓhLÈ0 xš#@ím ÎŽZ’$¨YØ’ç¹’JL}Þ*²öÿ„l{àW<<<°`»EÙȲl~RAÙ7¡-7÷€oÀÅ:ýBDx·IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample12.png000077500000000000000000000005661375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€ IDATXGí—Á ƒ0 ¾~° cðä[ðdøÁ0ð¤qäVPQâ„ „”“¬XnDŽÔ%T,¸‘·áŒÆq„$ITô}OU{Œ›0Š"˜¦IåAÀ<Ï*·Åx>‹#yžSfñ!(pñ ~V¶mK™Cð+à†!,˨z¶À0 ßÅ1d÷Ó'ç` ¬ïc”LÓt麎*zØëÅ˲¤ê–¤|>PEK išÀ?8s~aÍä6ß%&Í·žÇE;3ŽãÍ…¹ÁEû *Š‚²‹ ‘CêºÞ½Ë£àâôÐæ zÖat^À 8À·dSœ TU¥Fy\«‘ƒÿsz³Àø8êXaIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample13.png000077500000000000000000000005661375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€ IDATXGí•Ñ „ †Ë=éúæ*náná>:†#±¾y–”‹^rÐb‰ç— !Xÿ¿)fÛyÑ|âæy†¶maš&Š\ClA]×`­…¢(`YЦ#NÀC+òY0Ž#­A¸TU…¿ìF×u½†È‚£üè?ÖÁUØ|˯ñq‡ÓAù¶9äGXpåOjRN‡\ùý¹=AŠÄaYÀ•?¥IE-ÈVýT „¤úý9Ƶ¢Hª_ݬê#êò#¨À/ŽòÇFÓ4§=— eYº®´“¸öDЂah•Ñk#KÈÍ“À“€j)R5ß7ú¾w3Õ>¿!À‹öxâWGŠ|IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample14.png000077500000000000000000000006331375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€0IDATXGí—½ ƒ0…M*JJض`¶ dè` ‰  #zN,Ãù'¢Ÿdq>Nö³ïâ˜`YòÀó2¬ à ²,]×Áã¥À„¾ï—(Š(mK†ðÚc\I’ˆqÑÛË㨓EËÚ.u]o[/›ŒF‰ãø5yžçðºÁ@ŧ®~š&¼qƒ-@]=µ=$0MÓ¥m[xx°¨“¯Åï)Ðô§ÉÀ)¾³÷:N£Õƒ‡š®ø~&`Ÿ{]ñ©1&DMÓ|ÙÆ¢eDG³Ó4]iö´{ˆSEÌóLïl_»Bœ‚ªªhu"˜‰º®W©ÝºxgtcZÌ'"‰WNK¿u":ƒ¿¿¯ðß’¯xç´œ¼nDvn´ÚfÆ%nÈIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample16.png000077500000000000000000000006351375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+2IDATXGí—1„ Ea+KKíô&ÃÒÒ[XzK½…ÉXº Á qAfcvãK&Lt¾Ÿ`¯v#/5ÞYÀ4M,ÏsÃ0¨«þ— MS6ϳ̣(b˲ÈܲÛä@UU*;8€eGpë! -n?@xÔ i ôÉëºVÙIÀ WØ —à ûô\b?¸èºmß÷kQrÄ€$Égò²,ÕÕot¡â#µŠ”ºcÇ)`ÿöGM±Buœ(M·:ÌÛ‡ö[ÏÕT¯Åb­„Éã8&5¥ÔnX+uë!ÄÖSwìèõXŒ•{ë}‹±2Ë2cSl`w`ж­±16°;v(圫L( ´ü½Cihÿ#þ|& i9ROKÏÏéÍ{Þp µ‡yžáIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample17.png000077500000000000000000000006321375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+/IDATXGí—± „0 EÍU°t° cP² c@[ÀH”tÐqqäHáI|¡Óñ$ ˊȱ-¬¸‘=oƒ%`ȲLZ×u=ë$Iã8J? C˜çYúg`e@mŽ”eIÞ9X‚€<€«j÷·ŠÐΚ¦!ïb°\ˆã?º´¢((ºOß÷kžçkÛ¶9ÆY€ÚM´E÷QbE«Rä'u]oØ`­¥§Núާ9 ÷?N?œ‚&8óÂÚŸÕoÛœ fÀ7ýˆZïðzs `;é/Û«~lµ4M7ët³a\¡Ÿþ[³a¬išÈó‡Q@UU䙵!»CH/ÿ„—¶¡oïl÷/mE,Ë"}ÛýÁKôf»?xɇï€7Ðj"ÊWÅìIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample18.png000077500000000000000000000006101375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+IDATXGí–Á … †Ë;9‚Þ\Å-Ü@7Ò£[èHnàÑGMyRb^â—4¬PþDìx=#(€eY i˜¦‰zªª`]W(жm£Þ{ „ @ªÒùŸÇ‘Zn¢jSÀ¡,KÔü°¶m©×DùÈ¡?ìÐóˆ…x&¦FX)@iul“ÇÂR@m?…ë“l è“÷}O­D WÌóŒKùÙ\?o ¸ò#YRU~‰WU%W€súÝpÁ9ýt”¯gX§ç0 Æ€òô£7nt.NOßêq{ÖumLª«çyïÇ«çÕʸÆÅº º®£–<ä8‡Åt%ó‘íg”“7€7€7€¤„ß–¾õÞ‡±:i¤IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample19.png000077500000000000000000000006311375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+.IDATXGí–Á ƒ0 EžàÆn¬Âl[0Ü` ‰ àÖbä J°Ó¤\x’U˵‚ócÔ{näE¿"†a€,Ë ë:ŠØc¥@’$0Ž#AÓ4QÔ«”Räüz‚â#@ù]"V@˯ù»û‡—eIž=b\ž?"R iòÎ(*À%ŽcÜòjyžSôˆÎYF”"fØô}¿=m™úçÈ>‡»¸Ý/íV๺î~ KÉì{QÀ×îWPu]ã66»B’‹³°ó£(:,*1Ƭ4M¿.Ì5Æ(Š‚HL„aó<¯>ç‹Iü:¾¢ª*ò`+Ä„sÉeä\)OO^ Àùçâ¥}p^Ý^î 7÷Àô0ÕÅÚPIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample20.png000077500000000000000000000007041375753423500270630ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+YIDATXGí–Í„0 …Íž ¸A'ÐÀ‘8Ò7èÊáHpcñÊ…цØLZi?)çgÂÃyIð¶x/úe1Ž#dY}ßSËçˆ2EÌó ¾ïò,Ôú"žçQàjåDKplmÛRä\abÎJžçÔzd†-MÓ­ë:j±Ã€«‡cÙ H=G”ÈݤÔb‡eBå~…é/WLÊò€þð²,):‡}V`ÎxOÿ˜z5Ž» Vºùlš¦aUœŽzû=ýÔcFÏáÔ„\óéHh4!^È1+Éfö¾»ˆ£3 àˆh6ÜaUH‚¯–œIÿM¸VŸÁÙ…IDATXÃíVËÀ ³„ÿÿåî¶£A¥#.pò Riy€$G¡Ù(6_¹ à=g%®<  ØN”•¡¢TïÔ@f÷¶JþC”Á·(Èž¦ü}ÄßVœ«ƒe§~dJ#:¡ÊÕAL³ò¿i˜¦Å“ Sö 30½ÉD5Ô4W>â &+H–¦IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_4_Sample25.png000066400000000000000000000003571375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 9Û<C|IDATXÃíVAÀ ³„ÿ¹»íä6 ²¤ž<)´@’kðxæ1€ûÞ…ÛÖð°Jˆ‚NïòÎòWŒêt›RÀéài NLn›Ìþ± wÁwÙ¿ªXx!‘‰³*PïT;É4UZH@À»?ÌšØx.Å(HÅ" IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample01.png000077500000000000000000000006021375753423500270600ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–1ƒ0 E¡###…[02r®À·€›1Ò/좈Ä6¡VmßBäØþ‚Øñ²,Ñ<øy‡¦i*Š"VÃ0 à‚O¤3Žc’$ì­7Žq°²,ãMÓpŒƒ}Èx}Z˜žA>ã¯ðõè^­§M ä»®c«ÉZK"JæyÞ÷=ûÉz‹a×Ô0Ú¶¥\[Íó\×5©awrMè'ÀNƒ­ç€«Á&«ª–Ržÿ¨0y“FPY–á;ÖÁT"k-í¡¤w¶Ò4¥$€­á ¤æ8o¨a ï½ÞÆDXÀí %;_íˆFUU˜} A™#y7~äßô 7 DÑ/ˆ%#hIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample02.png000077500000000000000000000006271375753423500270700ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d,IDATHKå–=n…0„M*JJèÈ­()¹ W ƒ[À‘¸%á‰8Þu!!åkÞ>ÿÌ`›õ’íûnžäƒ¿k°,ËçÁ0 lŠ[¤2Ïsžçœðu]ãÈÑWt¨EA¥0xN¸¢”eI cÚ¶eäÑu'\Ñ (–Q °?”;-%ªªZ×ÕÆòÈÊkêÔ±?6ø-Ê ²,³AÚãƒ×d2°ÉŒ59ðwš&v‡ÀÚ8( ò+”ÃÅ@¾!,²‡bÐ÷=e¾qévî Ý@19{°Éã¯GmƒÎ›^Ó4Þm€Ôc$pu ·JÇVH£Sø@¨EŠÓ²eܤ\é_î†ZGÿªp¨Ò–¨38Û4M³m;"ø?ß¦É û¨²,ãøìs Z¢eYȀú®UUѧ‹Û¥:EXw24ƒ-Þææ_@ä1Jãqù[Ã5$x販ë:î“P Ü­w ƒ‹J m[D¬ëšŒ_ ,j¨L¬R!j<,@˜S kœ–·:œ¦†oÏÞÉI’lÛ“ÀöP£É³™Ü4 $ãò¯Šðmš]ôáÚ ßþ×ð€\¥1¾ƒˆÇ@š¦4¦,Kn½%$`å­UÌè;Ì·ÇÔÒð*Ârˆè@ |2áèàs¿'‰¢o ªwz7äIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample04.png000077500000000000000000000006651375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dJIDATHKÝ–1’ƒ0 EÉVpf(á9· ¤¤ä”nÇ¢ƒŽý»ÒdL¼’ØLf÷5ÑȲlK2—mÛ‚WòÁ¿/ãÝÓ4]¯×8Ž/Y– ÃÀÓ\p I’pÜ„aÈÓŒÌóÌÖ”eÉ– ´mËqV¤„¦8_2ÌÈù÷izž'PHv1ß%¾¯Zƒã<Ò4íûžƒdl”/é!SÃpKÁÇÔ8X>®ª®qPÜi°×ã¸p5¤Mœ}Ñ¢(Z×6±, 9]ÎZÓ4dŒÏ/¼Éz7|k«@oÈóü¹ÆàóuÓô^*)Æq¤u»öhXšf"Ùåá>ÚìÚ£ ÔuM3¥ZíºŽ@UUìÝ£ ¯o›¸ÓÀÉ ›Ò(Š‚<4 wºø+<Áæ†t8„-$ }iâ¯]Á'ÈWYþÿY6IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample05.png000077500000000000000000000006301375753423500270650ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d-IDATHKå–Á ƒ0 EiO°Ü`؆-82l#±ÜèWlEQâ¨i%ª¾ .ŽýK°cçyfßäÉׯ+°®kÓ4ŒyžÙ¡€·ë:ë&ƒ- ²,Kžçàk8À J ,K΂ ¢8ZÅãÈ?ú¾§õ&QU„}'#f±Åmªèmn& [¸Ý £^u^ê€ÂŸ¦‰yHA(³©ØÍnX%@é¬>25."é¸.Šâ8xˆ}ßé¦ER™Ã@Ɉ¤Ô+¾<÷îd̶ü$mQUUÛ¶‘ýù-Âß×ÙQÁd@Ù3²m[_uÃ[×5Ç+Ø!!ûhFZÇ€›—™F0φk®³Yàbðj‚© ïöù4"ójþçÓñm~] Ë^Æ"@ ð (IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample06.png000077500000000000000000000006761375753423500271000ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dSIDATHKÍ•1–D@†Í>¡LÈQÜB(t À„Ü‚›‘xöߩώêjÓ»ÞÌкª«”ê_ßÖuõ®ä‹ï—ñ ÆqLÓôf¦¾ïÙõz P×uìj>¼à€¥É¾ï/ËÂ*¦8–O´^–åý~Ñ4 ™ÈG€%Ú¶e'Û—TÐVÆqLÑó<ç©×Ñz€BƒišÎ´ZäTÅÇÊgíIee=ñÓì!–`±ŸŠ–ÀÚXˆ€]Íh HDĦ²ý$Þ ë:š7árÌóE®#61Í‹¸ì"­ªŠÆH£7ÜýD ÃðLî:ØA÷ 4A%È›”Œ32˲䪀êŽÐÝSä: E<%!Ûš—ÞI’dââ‘ È$"Ûörµ"¥ÆäØÚEQp 3zt UGˆÕXãnüIgx“þ‘‹xÞ7¯J-·ÓÜIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample07.png000077500000000000000000000006521375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d?IDATHKí–1Žƒ0E­(¡£„[ÐÒq JJn@É1àp3èØ¿øÇJ;òF)ûŠddç‘ØsÙ¶M½’/~¿Œ7ÌóœçùŤãÈi¬L–eLõ Š"N»âþeY2ò ®kFŠì¤iŠ´ã£yâÞ¦øsuàÌ<å¶i Ï Ì™8ßò§ìK-Á¼3pD†a`ž… Àö•nJ°Ø•¢(íÈGÄ-èû^jš†C;ft]ÇÑn@Û¶4(Gï ,ËRU•Ø#ôF[×5I|"†J=n=h(ŠбÖ<ð;w²Ðÿ´U 1à¶ñm 6~VÚ‚çU3M“.8tƒ$à$¥„f€êq3ïYžó} u/G]# n›“Óê@O‡­:p46P×ðÿòë@©o¾jì!âÕæIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample08.png000077500000000000000000000006761375753423500271020ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dSIDATHKå–=Žƒ0…ˆ:ŽG¡ã”””Ü€’#@·€›AGžâ‰åàŸ±Ñî*_ƒ1ãy²=~æ¶m›ø$wz~ ^`žç4Mo@Ø8Ž4L%ò0MSz€0 iä F IzŒªªhä F m[ÊÍÕ_EX\Ù`#­ü*ºÈiYµöŠ´òÜ 'Ä®¢P‘]×Q›Vš¦¡8Œerã×`ôe)ŠbYÙFžçôAÙo¨ƒfQ]Ãt¿ ÔRÃ5‰K ®k)àšÄÕ g]×(ŠdÛšên4¿Y}¡å—`™Y–õ}Oïnøl½‰r8UÇ2FB½ïØôãcõd¤Þ¹·²©vÝr)™av©éT »Ðÿ'üx²§À<ʲ¤46ü©%>‰)£_ ,ÿýïZˆ% j{k^IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample09.png000077500000000000000000000006701375753423500270750ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dMIDATHKí–1r„0 EM*è £$7á[Prèàp3èÈÒ0¯-9žl‘™¼b×c[ÿcÙÂd×u™wòÁÿoã ö}ÿ¼Yו»l"•mÛš¦á€0yžs€…nuD²†Hß÷c¡ÔuÍ"^u Ÿ¢,˨¡ÎôòN‘Œb0Ï3·’¹w"ȳÃ]×q×Q6ùÙáã8"«ƒ”";?iêßÐB¼„*U½, OÒ „§ÆÐ4M<«Sß6¡»þÁŸ¾Ušîì©þ?~Œù‘sr ì¨ÛSIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample10.png000077500000000000000000000006751375753423500270720ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dRIDATHKå–1’ƒ0 EÉVPPC Gá’’Pr:¸Ü‹:ö/bl™2Ù}E¢Èòÿ#ÛÜæyvÞÉ¿_`Ð÷}Ç·H¶mËEx2Ap©(Šš¦ái+vß÷Yà®ëò´û Ã@ÏX¨ªŠ’ Y–q´boS,7ÖJ-ÿ¡MOò„µ?À¨ëš³V–¦à:ÚÆW° µYOFe»AQJÓtGüħÒ첇ÝÀÄv¯ ¯ѳœ2[N=rÖ°¼ãhWé‚+Óó¼iš`•Д¼sÁN.Ë’²Q¸æÒÇö¦`¯öѳ·q’$‡.^Ÿ'm C˜üN×u$8µA2àI†þÆyÇE <°A2Àçy»ƒs/ ò<çá ’éf×¢U’8âa’&,„ÉF–&þúÛµã|(8umt¦IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample11.png000077500000000000000000000006231375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€(IDATXGí—ODP ÆËÊÖŽG±s K·°t;nÁ‘Ü€ñ™Jf oÚ!¿¤ñ¯O?úZ5ŒÐ‰Ø¼= µ€¦i( C²,Kd𭪊G¯€h‚)S™ã8<úÕÀÓÛ¶>kI’ðÞ'ªIèû>µmKãQ×u|v*ÈéŒb˜‘ëUÁÑ\WÀ²Ö‹¢à+J0 ¥ ž1d˲,cO9*yž¯~5­u'\2öƒ!Žã7*e·°T•eÉWÍö9îûž\×¶@Ú-+CóÏGOA_hÛõÝ ðý¢È¼¢Ù æÀžç©Êª®ëÉ6 F¯×ÖkÀkK5 F/Iëݲ4Mù.f¾ÊüE„48½'©Mà™ûÏèðô#ºÅ×Ì*IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample12.png000077500000000000000000000007311375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€nIDATXGí—A’E0†Û¬,©²°äîà–––n`éÜ‚#¹;“ÿMò /¢cRõ¦fæ«ê’¤’ôOëÞ* 7ò!¯oÙ€¾ï)MSò<ïiècÜBÀa†5˲5Š"„Œm¾ï¯]×É]^a ˆãXë€cq;Ó4ÉÖ9EQÐ<ϸ)jÛVŽ•e)[¯°³1U0—°ø=Yp—·l‹«Ø˜@pÀÔ3»*6&œ€ÝÁ[‡¢è¬MÓìÆîˆ` •í騪*9ºW"l` 0q>'@]×»§À …³Ѳ,†áã „ˆÇ‡é g…ÅK){_‚88?Ú~5f)Ç‘ò<ÿ^‰å‚QÇ/ۜƹë”qÐÎÚnÂM'8‚`·–ƒvî\mr•Ópœ$ÉÎ1l[-MhèÊëVÚ:§Ê¸ÎÁés:Šàšs` ”[ÇŠË7åL>Ç¢ÔÊY÷ùëÇDŸ`Á¹¬VuIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample13.png000077500000000000000000000007151375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€bIDATXGí—O®D@ÆÛ[±tncév,ÝÀÒ,¹7cçù¼êL£ô‘—ø%MOu}SSÕz¼yA<È]ãÿ†AÄq,<Ïs2øt]G«0 lˆ¢µrÉ|ß§UŽXg Ïs¹“eŽ8uR*qpÓòvÁ+à²nO0ö<ºÀ|Üdèù¦iÈÃÌ×H«ªŠ¼ô8 À·SƒEA3ó\×õff#ÂI@Y–ëÂišÎã8ÒÓx–$ÉF„ép`Ã^²Ö¶-͹å@2M“Ãp½‚E„X„­ã=·ì¸üþt÷'è”57¡íY-Ü*@- b8n=”"õAÐÝšm}0Ö€<Š]ÙfQ FêQ iÔµ‡ô= e°ßá\Dô}¿ñå0 Ü6‹Ìœ½t˜;ÄrX œSß*ÖÀUgÁ“ öûå¨ÍSMXòþ9}X€¿‡+¬ûš'2IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample14.png000077500000000000000000000007451375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€zIDATXGí—M’D@…ˬ,Y±ä&ŽaiiÙ7°tvÜ‚“agêéÊñõCÍ˜Ž‰é/â…j¤|”ÌÒÎÌa/äCl_†µ¾ïYÇÌq©p¬m[q¶LÁUº®›=ÏÃÔVEsÓ4â +V‚ &1Éu]q…«)†AŒËó7±SY–âèž,ËÄhŪ 0Ç„EøŽ¿[?Å· lK㺮ő“ภÂLBÙUU%"ÔÜf€¤ªÂÊꙤi:㸈—Ù.9IVÿ„•^çË…y{öÈÌ F†•³</x ²©¸u9ž¦‰ù¾¿l7ÁøÓYÆÄ­} ‹¢¿ž†Žüʉ®u¿[ñíŒ­ï€ |ù$I¢íd:·ýrBÓ:¢5†á¨ëd*°PbÔ­$¦`SO'ðÔpî61¤êšZÛNFRÁ>YbHvç„Ö€n9+ÕZ->WdJLœ2@˜ŒÐÒ|…÷Ãÿn€±O·Ÿ7BÅuIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample15.png000077500000000000000000000006711375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€NIDATXGí—=Žƒ0FÍV””ÐÁ-()9GàtnGâ”l¾ÈŽœ¬'ž±EÚäI£8qð<â$çõF~ôk¶mSUU©$I®ö²,º—ಮëY–%*ÆŽ4MõÓnØHŽÁ\IžEß÷z7l<Ï \áKjÃ^„˜Só¬EˆÅõ*X(ŠBíû®ß½¡vòËüêV$Pøš Ã<Ï×-‰@;±¡"Ñ8'¤,êªëúÏgR –À8Ž·®CÆî—J°8„JD. QÀ£„—\H$¿Q/$!D†A·˜` \àÒ4hOOÓt7ÿ]×éRÀ\@¸Û ÂY–Ý’·m{Ç¡{iH$6ƒù$Ðg'Gp’Ràq;IBr%#@ˆ„$9x*¸XpܲÛü¯F!|>]@©_) ÌwR–-æIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample16.png000077500000000000000000000007351375753423500270750ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+rIDATXGí—1Žƒ0EM*èh(áœPRRRr Ž@ ·€#qè?²%Çë ã­vŸ4 ÈÀ|ÛcÇÛvĹÉ߯á$`š&‘e™ˆ¢HxžÇŽ4MÅ0 ò+.qc¸Þ ß÷åWžqr`žgyåNUUòê§I;¯‘ü®IxÿØPt×7¬T H’dëû^>é[ ‰-¹ ´w]'ŸæÃÐ4Í#QQÛ²,[Û¶?D \Ýp*Å6lBàWÄÇÙKí["N 0Ýxµéœ*˜"pOqº &,Ç…KŽd뺊 äÝ®‚HqÙ™»u“¥å7ÏóÏË-x…*¿œÙl‚÷TP¨#ÆÔÅsã"‘B¬ çxÁuaÇ- C¶d«¹¦*ÚÍäu]ËV;´¼Ó]z‹ÍGO¨ÇQrp(À¶Ùp‚“ ."ʲ|lN\X%‚Û[ýß±w78©NÞ9w‚IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample17.png000077500000000000000000000007431375753423500270750ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+xIDATXGí—O²D0Æã­XÚÍ’£Ø9†¥¥X:;nÁ±ìØyùè<&1Q¯¦j~U]¢t’O$ÝÍ$âù¡ë)š¦¾ï ˲Œ†çUUQ Xu]žçaµNú–eI£Í°<íÀG̶mm†ý Ú¶¥Ö3qãEž,Ë2ò˜ˆ¢ˆZ ¤# 9ØêmÞÅ¡S€M¥8Ðm—K§à||®€mă!êEALp 8 ÂcˆzyžSÏ}ØÎDÂ4M©·¶„Ñåà2úÑ“‰®ëéV>0°=Ø–‘p;ù ÃðÏÂuIHqK=Ð÷½p]w¼)BHac{Ë-ÇÊïOw“ #ã:ÜÄrߘö­’$Yí·Ö„XzÇqèn\mjÍÜ^”"B*tS}“KÊï öËë³`¼BåWQmË6é` Xžg˜©ÆW˜þ!t°l+â3fÊ,àŠˆ½äÅ 8"dobÅgÿ_Gˆ_{â–5¯X¸hIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample18.png000077500000000000000000000007331375753423500270750ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+pIDATXG헽̓0†ÍWÁ”À¬@Ç”””l@ÉÐÁ°t|¼Ñ9r‚ŽŠHy¤‹À9ìÇq8ƒØLÓ´EQôˆa¨õXXa ULÊê¾ÓÁhÛöeÀ³áû>õtäoOp’¦©H’„ÎÎS–%i +agbúuªª¢ ;>ö ¬xžGG{ÏîôS°–àN~?ïÀ-©‹8ŽEß÷”uÔHãÆÙ ër*&W‚%€e纻,˶×û$X²Þ»êûû¾À‘` œA'aãrð.aã þo dâ6º®Ÿ¶e`=|º®":{¬½r›@…”˜†ù޽`žg‘e™Ç‘Zܰ÷, ÛC© y ¢( j=ÂPo©¦i¨Õ rd>¥ÚK@½¥Øñº®£ooCjØfX˜AžçÚlkl³, Ûñl™»l‰M„û6¤rk!r#Ä?Sè„ÏIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample19.png000077500000000000000000000007211375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+fIDATXGí—1Žƒ0EÍV:8 G ¤äÐqJ¸‰Pzó%³rœqüà ¢h÷I£±=ÛüHßPoäËü¾—,Ë¢òkžÁ¿€Ï’€ÑHÆD›ÀcÂõ€,ËîÎ¥€ ãhFðC 0Ã0˜Qd~- ª*½m›i©uß÷mÚ¶5ÿ>B pk€›ÔEk”{@Æß–eùÓÏ·'(G{ö$§ îr@„Íé€+Âæ²wB_9¿ÄŠ}N .™4MÕº®æìÀ àŠ¢àýݢ뺻ä·ÇØ0!öZàîàp@ôÛæB °a Þ Ý‚S’Ü“àš‰¯ÀH‰¾ä€ y;¡ºA GD0uƒp'u]‹Éì` øë_ÇJ}†çOŠ]å]þIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample20.png000077500000000000000000000007661375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+‹IDATXGí–AŽE@†Û¬ØÙH,93Ø9‚¥¥¥X:‚%·àHnÀÎø¥[šÖ­ÈÈË$ïK*¯‚Vÿ+Õ]eÍ ìƒüðßñô}Ï¢(bžç1˲Ȇ!kÛ–¿åÔß÷Q+̶mþr†aàÞ}²,ãž y âß]ðH*ûV¥›@ PÀ£WÁ\×5_AãOƒ¦iøJ3dØË"@š¦ó8ŽëõªªvÁ…áyв(Ïs~e-û]qY•cF®²ðJ;v‡MÓ´úKØ’Õ?ã•s ,Kî±Mˆ–5/ ->‹Ž×E± 0ãk#RZè¼:R:è·*0ûÅqü¼»Ý5 #f?Ê1j¢ëºõ=Ât(wäEÔŽvë\×ݽK‡rG>@àß±œ‚»À0]Š€c3Ê”c×ÂLÁÁint=þ8hÀ? K’d›Lh?ŽNÅäå }u,œ Wv•ò#F2ºŒÜù·*óü =z¡85ÁTIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample21.png000066400000000000000000000004231375753423500270600ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 9&Ø` IDATXÃí–Q €0 C—Ñû_¹þê`¬íR*cý´†å™UÕV8b½À皥[¢Ž‚V3Ü[ñ” YÀäöZpôŒoþl ØÕáΕ^t ¼¼¤0àA‹âñ¥LvÐ ŒÂ)ä§10 µ°p^”ç·wÙí*¿¨ã´(°\9-™‘<[ƶ¤g¥ŸªîwuÉŽø³º 2ZCEnS™IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample22.png000066400000000000000000000004211375753423500270570ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá 95 1™¾žIDATXÃí–QÀ CíÒû_™ý.‹S@Y‚¿NyRÛ ‘Q8®Q<ʸšp´¹FÝ–€»>eÈ0LKÐ @ËÇ»dôØ4´Ìñ"Â$Á¬Å§?,zŠÎæ½ a¼Aµ@¡å9æ‚ìGˆ;2°ÔnüÕ‰ô šhŠj¥»¬‹#‹/]à¹|"b^GÍIV§>u ³æ7At$±CF1—áIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample23.png000066400000000000000000000004431375753423500270640ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá : ”zç@°IDATXÃí—KÀ DÃý¯LWMŒµ–ÄjdÙ40òÌÌi¢å4Ùh¤3Íï½$“ÇñAÐ3éݦ(ÇË 8òÌ\³ {±TÈÐ P# A ¡Bð–âV@"$d Zÿc­–a˜ù!V"j¿N¨-Åð |aØsi0ü{”ü4§ é„·ÓžK32MÃR„÷½€¯ÕÌ@‚-n,!Ïré°±ˆ%í‰j!Þ=aúbr yMK@p¥ÞIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample24.png000066400000000000000000000004141375753423500270630ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá :€{»™IDATXÃíVAÀ ¦ÿÿrw_æ,£ÉÚë´ UÜݯծÍe3› ׌6ÈGГ™QÍf€f×1‚"P¨W p¾å °Î¹dÂDh'ìIœÍŒ¦ï}‹‚ú‡ä ô B~¶¿‚#Œ¨Ò°aÅ’4|6ŠÜnÖ’é8ÎZ®,ŒX°‘jMi«™ýi=u†°­j­YøAGäú«¡IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_5_Sample25.png000066400000000000000000000004151375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá :(A¦¤šIDATXÃíV[€ s¤÷¿òü%Ü:˜(od]_QTU‰§“Ït°.ˆH×Ká-FÒ¹S°>€ÞHn B1TÕõ-)"1¥xòˆÐ>YÓ `oé(z†Zf}]‚+P ]Dðeôí*®MäÝŒMFm’Úõ&jÖµ©W²’ñÌ|ïcÖæQ°ÈÊ÷ozàwt:UB~'‡IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample01.png000077500000000000000000000007121375753423500270630ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d_IDATHKÅ–1š„ …u+KKK½…G±´´ôA;½…ÞÌÒÍÊ[>žÀ:ã71ÈCŒÁô8ŽäI¾ðÿÿض­ªª4MåwYxýÈŰ®kY–˜c Îyž1ˆ% ÙóŸs¬ã ³>ìºP¢/Ö%úf}À±Ž78p„P.³OÀ††¢ ˆÝ@ÈÛG MÀKˆŒ €Ì ^Ð^Ckš†]/¼G‚ Ð÷=¿íØÆæ k€_U÷)£;}ù¦»,ä^”¦é¶m005”žœ"q“!ær/꺎 È]Žuœÿ’ë^ö {-œË7¼l`HšçjX8Àåwt¡_4àÕðžw n`xyøúE Ø¿²¸Ê0IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample03.png000077500000000000000000000007171375753423500270720ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨ddIDATHKå–1’ƒ0 EÉV”””p+Ê””Ü‚#@·€›Q²¢1F²ÙuR剑¿dYJû¾gŸä‡¿?F\`]׺®°ÏóÌë,pD*˲TUÅ‹lò<Ÿ¦‰ßÑа{Q¼GŒ°†.P–%¿ý¢m[ž{Ñ÷=Ïl½  ÃÀïiûºˆF`™" î7Mæ|×ýmÛØš€/ð^÷_ɸÝ4€ûHS8Ú8Ž<:.¡@ˆ·Ÿ8 Ðî@Ò+õŒO䟌B GÔ§WÏÿÑÂSáþ㢠xŽ?øá Úã]@@¶%¸275Bj‡¹Ùã„[/¸³ÕÀ÷Ñ®ëhY4] z¸È/µ%NÓÒ¢~áÓJÀ&ƒÓ´{¸á ÜŸ<6øÓ° Êu?œ*à ¸A®ÌµÂÉ@YqÕ°ˆºL¢2wv‘U™›[ßðç7‰,ûÎÔ}'zëéMIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample04.png000077500000000000000000000007071375753423500270720ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d\IDATHKå–1΃0 …ÓNŒŒ°Á 8##·`äŒp 87€Z䥉q Q¥_ú¿¡uíä½§mÛÔ/yâûgÜ0˜¦)ÏóÇÃ0  CÈË8ŽY–a›(Šº®Ãˆs<¬´ Uû¾ÇhÉ€Ôã8†Ò›º®Û¶ÅÚ &pœ¸ê$Ú¶-ËRU•›wá ,uYB†7H’Úaêc@ˇv°:Áœä4MçyÖ±[½ sÐuZ¾B`v@UáË'þR/ú¿Ù゚ JɈ:„Ü…4’Ûˆ,®xH&æ‰3›×ÃoÀfËYÆ€&\™iz ÅÁ¼EMÓè`]W°EHFŸ ¦”ð|ÍŽ‹_3ŸëAI=€;.o ¿'t×£¶ƒì §eëâ=.wú¼uÙIþ–‡ ÝÌzŽgƒ‚‡wíƲ)ËòÊÚ5ÿêÏï7(õýË>4Ó:‡{IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample05.png000077500000000000000000000007251375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨djIDATHKÕ–±‘„0 EÙ‹ !ƒN(ƒ.(º`K¢BîÏHxll³Ìܽd½²­müÅkß÷äI¾ø÷1þŒÀûý®ªêu€ö<ÏÜgfY–²,y´Eš¦<"HHÀ—Ú0 õã@ö,Ë8ÓA×uèêûžþbÓ4ÑxºÀÏ씚ض ©)Ý(] ÏsšìÔlN ×FÇ‘&ƒèü(RÀÞœ¦i8z)`oöš£œûŽÍ!¤Ùá–RCÄcðn݇³‚¢(Öu¥ö#+0ÙqÔ¸Ž³‚ÛxíZø³Ê)ÓÆÃŒÃØ·! 7`yŽ€±ÉO ت#€«Ë3×ÍøáÓpO’º®9Ä–Q­[ ˜cPG«´mKS‡,dÈ~¢3Q”&ŽZ(¡*b´4)¢"¢þp‡‹ø$ð½ŠoH”@iÒÀy d”&¯À4û Q‰Ö¥ÿþu$ß\yZÿ8wE"IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample06.png000077500000000000000000000007531375753423500270750ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d€IDATHKÍ–1rƒ0EåT””ÐÁM\ú”””Ü€ÒG€ná+qJò'»Ñ(bW’C˜Ék,ïJû-Yûá¶ï»¹’þ¼Œ °,K]×7|EÓQðh¼^¯ªªxÞ¤æyæ©:ªªçyÎŲ,‹jÈ^õ¦i¶m£ÔóùäèР¸†,P0¦ë:Ž:X1ë" Ðb]EÀùpùàHDèä²,×u¥ñ1û.BØê8œAØZ‰ç>ðw0Mþ üL{Aq÷9t_€ªê,Í-Ç‘–„Q0† „Ý"ÅŽTaxäm«àu?ñú§×¶-çŒmpB""ðx<¬Íyô}Os› ¸&z)žt”‡-K¸ßïRp-C~Jkâ×ã›°¥ûî+p=Ò-]H»×Cë£ÄóB×Ã8¶+L‚s¿~dzOv‚”Ü÷CT7(jxºÄ9Á€Lâû@DÀâ)%V¿¾ó NÎMë÷HKäIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample07.png000077500000000000000000000007511375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d~IDATHKÕ–=–E@…½‰„B2v% íÂÈØ;bBs§ûršþ}μsf¾D«juû§ªÛkß÷è“|ñù1þŒÀ<ÏEQ¼ÐÇ‘>7Ø/Ó4%IÂâ8†=ìøE.F×uìgÁ#€ïLP×5ŒmÛò]€WÙÙˆKà¶22ºDÕÀ<¶m£CÃ%¦)cD‘–²,᪪Š&V _†êØo,Ë–k%gY¶®«lÛú„`®ƒ¾ïÏè¾lpâö÷ x¦iœJxtðßÿ®£è]Rïk\\ÜxIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample08.png000077500000000000000000000007161375753423500270760ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dcIDATHKÕ–1’ƒ0 EÉV””ÐÁ­())¹G€nÁ•¸%ûk=–°…’™ì+G–ôm‚?<ö}O>É}Œ(yž«ªzüñ8Ž4w .QˆišÊ²¤<˜Ee Ã@mTÒ4Õ5ü˲dYF=êºÞ¶ Sølš†¢º†G@t7}Ïô}O‡EOHѽm[šða5”4)繩z÷H˜–O½ßÔ°“\ź®fìÆïÀšíŽå›Á}ØpJÍà]ËßáEwøa¥àu7¥P’à@è>jxÚM©îàBð]ª÷ÁMuk¥à즦dfÏ0®ë¨â Òé€âØL«£ õIgA¾Ýtȱe#[ ìÚÅÝ…82j¯’²kÉô›#£b×—®ÃSˆã‰Fþ{@<þ(ÊñG…†÷N|¸ú€«q‰rC@¤†~\4à=·.zwðßß®“ä¬/¶¹çw¨IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample09.png000077500000000000000000000007031375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dXIDATHKå–1š„ F­,-µÓ[YZZz ½¥ÞÂ+yK'c²|!aÙµÚ×L$_&!ø:Ï3{’/ú}ŒXu]›¦yYÀ# ’[þ"™mÛ꺦Ùwò<_–…æP zQCÕœèmÛÇ®qiôÒÀAI ,KŠ‘e}ßÓè7FÃwÙàõq= ‡ žƒªªö}G;4'†`™šèðúh$ríÃežgrGÔ± ¿Þ¤*‡†RaìôšºL†Iò_¥—¸dnCú¤ŠÖ„I@@æÇ­‚–F#·#E t†!ù]×Ñ$±Ij‡°[ y0U— ¾ËGÌ´ Ø/Ó4¡ñ+>Û¸3 ºÔË$¦£0H Ù„ a_GBGá• Ë×p.;¡£·fköÃŽžx£Ž‹ZÊ’ k¨ÑEñeì/ ™ÿómšÌÃYö)ŠºܬrIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample10.png000077500000000000000000000010171375753423500270620ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d¤IDATHKµ–1šƒ …7[ig©ÞÆ#X¦Ì-´óÚé-â‘rÓ¹ïsfq@òiþ&8Â<ÂÃÛ²,?ßä—¿FÀ4MEQÜ ð8Ž#¿öƒyx>Ÿyžs×-Qu]ÇýÜø=IÎçòÃ0ð §À>ûãñ WmÛrhK¡¸ˆ,€I™ÙUjÅ<Ï÷ûÝõÖD¨ëšFþñ‡ØØ7N¼r2;ؘu/Ëuà'ؤiJÙÁ%ÙÁF€s_Q…@}8ýÑéûmvY–½^/j«ày´©ì¨5.A¯F §d7…SZöI Ø÷=w ó%øyõ/n¹AŸ+‚@8‡V œUUYgÍ48¬4Ô®yÄ?•°”Bíš»¯„œdóVà„ pXVð èsÇñûýFKF(è\j¨${ô9P÷ dB¾š¦á–Ÿu æNAÿ¾óÖÃÿ£sß<;af?¼—ìý1±×°>“Bn=[À\4”@̲À;ÕÖgÈþœ»€_㣠U˜ å<á³Ö,Ë›Pqa ­ÔMIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample11.png000077500000000000000000000007611375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€†IDATXGí—=n„0…M*è(—nE %·€@·€#qèˆ_b+xÿdÃ’Hù¤ÑÊòxüfll¯·rؼ‰ßÛ°0Ž#K’„yžwhèkÛVx;€%01 Æ!–ÊÊâ8^»®£õ ËäÒ|ßôœ @ÖÈ„.ŠBx|1ÏóšeÙÎ׆S¯Çã± x49¥ª*k_p( ieâ4M?²¼‚ºá0ù•ì¢(ŠØ4M¢ÅÏœñ %Z?rà[ßNÎ×ñÒÉRš=)Î%( Ù¿¥8R%¯ÈüËè*~—€í'—ç¹öú¥ß¾ïÅh° %eYbç=e.W1P¾‚eYX¢õ}PIœ 6ì–€ž|8 QgüÞŸ ‘º®EË  ¯Si.åÜ.!OÄjìNÀàm [peÓ±&‡ž©kJàP ™à‘b ¡ã´—‘fó™áQ³£CÛ{&ÂÕtè{9g/^[3=N¶¸VÄæeüÿçôfŒ½OÁ&Ëf®IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample12.png000077500000000000000000000010101375753423500270550ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGí—1®ƒ0 †áMŒt£܆#0222vcäŒp 8Ro@7^þ6‘LC©ª'½O² $Äœ`§á¢¾ÈþýWÀ0 A–eA†+Ã3´‰ÁØKÓ4Ø7›E‘îég—€q—4MN©UU¥ßð³K@’$+Gyž/ó<ëÖcˆØa/ŠâmçÀ+Àv8? ¯€O„ Àì©ó³ÂNaSñõz î÷»¾S ¶»†MDÔ¹ú´ôÕ¹°@f3|bö࿽-`š¦UQ:µ¡Ù˜ WPŒº®Ó=yv $XÛ¶ú­mX˜  Îã8^91† ˆ>ôÞïû^æ†P×õj0—s»ô"SRá¸æ``0êŒWóíHpð­ :c’íÏá`/ƒoM RÞÿÇ#¸\.Ï_ Djiž×Ò4îMDp¨NCúî%È—hœÄ è^ð-…}ˆá p}ã®l‡g´ŸoÊ[„1dÆÛívèì¸KØá2Éñm·€Ë²t:5&ÉàŠ©ãËò Lº6‹™;JIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample13.png000077500000000000000000000007341375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€qIDATXGí—=’ƒ0 …ÍV”””p+JJJnÁ ƒ[p4J/oÆÞ1^I–I24ùf4!–žåöÄ<Èû|Œ¯€Û¶m3mÛš¢(.†ßàSƒE˜Ã¾ï¶i,\Ñðκ®®O–¬ªŠLHYY–®%J×ë®ëìqî-k§iºø‡apž¤$§z­ ®!) ®ëKâ¸×¯’&W¯CDó<_|1j8üúO #,žsÞ͹­Ü·÷¡ ¼ößbÄ X–Å=ÑpÅ–U°(¸ -F¨ØÆ)XàƒáŒ×&Ž m%Xã8þªPÇr\R‘€Àa Ø¤c9n+!zÃi𦩘®°„è§AU¾%Do<”©+•<5b²¼“pðÌm­;ÉAR@¼ªañ…“º+jïI€ƒêlÐ&*ë¡ïûÉbËIÔ<Ühܽ+f ð„Br{òðßsc~Â.qаµ²IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample14.png000077500000000000000000000007261375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€kIDATXGå—1®ƒ0 †Ã›áVŒŒŒÜ‚#À·€›1RÜ—HNj'vá©zê'Y¤`’c;4;NÌù±Çñ,Ëbêº6Y–½œ‡ë" 4Ìó|TUyµ<ÏŸ¾)TÆq$ãL"B,`]×£( o¦iŽ}ß­Ç/Ã0x>)"ÔâáÂJ‡H@Y–Þ„]×Ù+½ñlÛfG 1Âw &ùÔ ó…#)èûÞ›,–ÕT ö¿ü=eÖ¶­7)4"*p.,Õ"Ž0`N×SÕ¢@E"f¢RµGTbb£º#Ç[”ÉSc¾ýß±1~áIk×IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample15.png000077500000000000000000000010101375753423500270600ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGÅ–±‘„0 Eá"È!ƒ*h‰·BèJ¢È8>kߟmI»Çí›Ñ¬XŒõ-c‰x?ˆ>È—úý/ ˜ç9ªª*ŠãøbøoG5Š ¶@Â0 {–eØ6¯•eyŽã Ð÷½3 Ë’$a‰` ˜¦é×Ê›¦Qw÷ýñx\îÁ ‚‚%À|]Wu÷Š-„‚% ÏóˤæÊ]hÔ8@ Àê%Á¥…¨(ŠhYuu(CÖ3ø±zåý!È€;ýwÜ‚»Ó‚[p{ú2àâ?Ò¼3Ûg@ê¼ù¿m’>¼ÌIqö]ÕÐgÜ>X$Áµ½ÝŒÌÉBMÈÄîo5#s"Ó¨Rl‹Àu‘*¸¦mÛŸg¨,xàÁW‚´jóÙÞBÔuòžÔu­<šC¼òh‚¥8MÓhÛ¶ÓǤÇÊNŸ>R5áRlfB¸_¼øjfƒ „0ßøœ³íª¢>H®³a÷êå%®WŤ` ¶˜n<¾&Å9ºlÀ%Âgܺ!8"$EK,@ã" üdß¿û|ÒÌZW±IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample16.png000077500000000000000000000007301375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+mIDATXGÕ—1ƒ0 EC'FFØà‡‘‘›pF¸‰0R~•H4µ‰“U}’Õ´øc;MöõCúÓ›eYTUU*I’—a?ž^n°±·Ýw·g¾uŸ‚@sÄ s¾D`,J7<ß•*>T2†n(á Û¶}»NÚ’£0ØY‘|$£¨ëZä•g<áf ©žÎ Hš8¤UOdÀ .˜dESm[ 9“ÚbÜþ¦‚ûtNV*·ÏÆØöû¶íË\]ÊBÎ ¢—%ÈWË%$4°áÿœÆâÇ”z›þÜXž{IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample17.png000077500000000000000000000010201375753423500270630ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+¥IDATXGÅ–»…0Ea#BBÈ J $$¤BJ€ ºx”D„¬ïÊ–üXÐ;Òðo®Çxìôb$_ä‡?¿F”€}ß“º®“4MICý¶m¼GX‚>ŸÏ•ç9–ËkY–]ëºòžn‚Ä8!xØœ÷}ÏkU¦iRÚ…àl…0†:¾vRÀ<ÏŠã˜Ac Eñºs` Ïþ†tЉ=ˆô{Ƥ0 àt¾{ ê"¨(J9 è.ò8T @Ž‚+|>ô;… k©…Ð-¥#;§–Ò.‹¡ÿ +BîOAÖØ¶UŒˆq•¾t Ƕ¥\éÖ–º]·*¯ ‹ˆ±¦iþ¢I$Ü™»œƒ`Àö_P–À®ëdý±¯kËßIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample18.png000077500000000000000000000007351375753423500271000ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+rIDATXGí—»‘ƒ0†ÅE„„A„”AHHH„”@]Ðêü3âF–WÒÊg ‰¿™žf?iõ'ò¸‘u¼¬ë*ªªI’œG\³A ÞeYY–%JøišžÏ8¼%°m™XHp@ò,Ë^¶m+Çq|ºÇ!H€JŽÄÇq¨7¤œ¦é¼ß÷½ºã†-@%ç&qÁˆ•xb&^<Ï£%Nyž£&N½õí1°  özëõ©öI¬»aQbßwuõ0 _û7ÖÍHOÞ4:‹z€k9#lë:ÊäÛðܵ1Y®%õ j}°€Eaz/@è"$¹ú7.œÃ0üý2èÊ•ÑìEª”NL=½pº,ãúû&N`¶BÎÊh®'&^@IÔu­žÚ¡Êe”¦˜mtsÇ [¸Êá [¹‚U×ud[¸ÆJ°ÀWÄ7P¿;7 ñ üÙ¼¶‘˵!IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample19.png000077500000000000000000000010271375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+¬IDATXGÕ—1®ƒ0 †Ã›;ÒÞ†#0222²ÁÖ#´Ç(Gê :òp”H&µ‡‡„Þ'Y-4±œ`§Ù²bNäÇ}žÆÿ0ϳ¹Ýn&˲Á½çóéFE€=°‡iš–Ëåû‡µ²,í8‰d¯×Ë:¦R–ç¹›I“$‚SOݶ­±,ŸÏgišfó»D’€¢(6Žëº¶)î÷»ƒÅQ¨ ð s¬E%àñxl‚ÓET@¸îUU±ißC´_¯Wó~¿Ý•1kp³îlwõwÄBÅ_×ýÐà›¼ë\wŒ¸PV=G§ÞÃ.Ôy ~HðØ<„EÇÃUÃÐ4}``g¾èhƒ{ƒ>°»aGž0+±¡OïI¥Ø÷o’•˜Ìí Jë &`Ø´(AÁ '{K-Hx.…ºyR öA…{(%ø8Žî›d€#e7‡„néD@×uG (apé À˜Ð ôö}ÿubŽ`¢<Ü[!™æô¤h³&˜1I8Âìh pòßsc~‡/QåëBëšIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample20.png000077500000000000000000000007671375753423500270760ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+ŒIDATXGå—1’ƒ0 EÍV””ÐÁ­()97à”pJ¸Ü€’å3fÆhm$;ɤØ7£‰cäè[Ʋíê‹üèϯñ²€yžUQ*Š¢ÓІA?€%¥ïû=I,áÍâ8Þ»®Ó^Ï @˜ZÛ¶ÚÛM€išþ̼®ë3 Ù‡LlÛ¦GÙ ¦é-í²,Ïþªªt¯o4õ˜¹eYtë/4õ˜é«ˆØÖ[_ btÝ]©÷E$³ÿDp : ²,Sëºêo‡~ˆQ)6ƒ³×­7 OòQB/g$?6†–ÑîÜyú%@ÕØ}·­wªB%Aú%ì„Ñýe%°B¸®ã™ÄžÉpUßçšè½Fä ”3å,W ‚Q9³!ØSS"š‚ €5›¨"„ü¡É,¯N5¢c>`±‚ÊIÓù¿ˆFqJsY7#âRIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample22.png000066400000000000000000000004451375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá ;í²IDATXÃíWA€ ³ ÿÿò¼²•MÐÈÕ–ÖµUÕcá’cñZN x7¸ýîuT"ÁS-È7[пJ=C®Ì‚3¾OMAtlìµü¡ùž$̪ yzîßÝURº@UÍ–pÙ'Q'g÷Ö»Zê €¡%>3¦¡]À(ðï݈z'‘ð’FΣ°žÖ`¬=°¾Œ¼ÖŸÑUÇ[\HF$¼D©(ŽT✞ýÌY:8#¦JIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample23.png000066400000000000000000000004261375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá ;—»|£IDATXÃíVI! RÒÿÙ9ÍebLéP—DÏD.X[k­,<(‹1àZ« ǘ 5ù‹õâ¡&O-ÁÈæ¨H‹¼¾Wãè0áï˧ŽaÆÊÀªæÛfa¥ýg9pÈoϘ’ô‹÷ˆ@æðÜa„(±*äaÄŠØ;Œî*žÍ`,϶îj¡ýûYæíþÞÅ 7ÎCV„O‡‘Ú‰? LFv‰K$IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample24.png000066400000000000000000000004661375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá ;*¶öÉÃIDATXÃÕWK€ ÷¿2­ÚøJa´ÜU* 3|w÷vpÙÊ!yý†â± £Oû¢Žh;¼twÈK4нŸ£4Aô—ޝDC+„G×@ßÿÍúoG`‡?[áD/P%DRÄ™p/XÕÄì\Zî>E9r¢¤õïhi…ñŒi½ =½õüc…ˆU•Q½Šò¹˜š³Â„R%Ñ?£ŒF&¬W41RѲ¨ž¨¡µcƬx|"ºM=b?^wùIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_6_Sample25.png000066400000000000000000000004521375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá ;6¢ª†·IDATXÃíW[À Âý¯Ì~—eSʨÎd~“RË£*îîmáѶø,"áØ¨°MŒ$GÈRK!až¼¨R°£Ú¢Ce•É3$´ªë·Ýû`mìï*0£á1Ì.§×ÎàOÊdI)rk†!iÐÔèÉ{%+"ÝR¤Ì¨ˆ6#e”˜Ñcþf¤H-ã+!ÕÊŽžò(Eý`ˆýfë?‚§¾ˆJÝ%5Æ­sKöVBÉC“þIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample01.png000077500000000000000000000006011375753423500270610ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–1ƒ0 EC'FFØàVŒlp ŽÁÊ-àHÜ€‘þ ¹ÄŽ%TUêÀ Äÿ‡@²m›»“oã«óå®Ë"¶ë¢(–eñ±~–v7ÅÆwd‡}hÐV`³´Øì¿€¾öiHjBÔ«û,ÀW§rísä&›Ûë‘›loïŽ\>è>0Ørø”SdBèûGÛóÿ_G‘_pî = \”®+6IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample02.png000077500000000000000000000005721375753423500270710ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKå•1ƒ0 EC'Øaƒ[q¸Ç€‘[À‘¸lÔ¿¨€‚l«¨Rû†ö+"þqœ8Á²,îNø¿ß6†!Ïó@}Öu¦ "ûȲ  ÃÓö\eP–%”€yž¡ÀÈDÓ4ˆâ\UUÝc7èû>ŽcŽ^FOØ ’$áèÄ4M=a4 å#¶sc«HÓtGÖ׌m‹NËgáeÍCÇûáÁ‹ÁVދóa©õtxè³ö¡®AÛ¶Pk{€º€‘£ÚB½Eªý!ì‰_}p>‚΀Þ8(1ºÈ[І.E z¡Ë Š"~å³tÔuM¿òå–^¤âßî› œ{§5Ê,~èsIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample03.png000077500000000000000000000006021375753423500270640ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–» „0D×BF9„„”@Q¥Ðr+<¶||wAH÷,³žãc¦i¢'ùàúG´¦ïû,ËP!€‹»®Ãâ_¶ Tê^Õ¶-$Û\‡Ez áØ6P‘$ ´‰Š¢À¬ã®ï´‰Ê²Ç7w߃4M‡a°ãM©[mÚ4W¯ªÊ–ÌÏq…º®!1‡ƒÙ ¸ë¡M”çù:zÏÞØ8Ž%êŒÚ TgŽÕµAØõ¼±˜ÝGgF/Qga8m³@a†s½Gamq8©A˜>¦dH«}>òô-Ò1Æ8ý(ŠìX‚Ú@Xïyÿ_Åß੪5C¤ö€Ü=x÷yûß5ÑÑ?Ýò:^ IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample04.png000077500000000000000000000006321375753423500270700ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d/IDATHKÝ–1¶D@EÛ„B2[± ¡Ð.„–@Æ.X’P&45ú}§6º«Œdn¢fZ׫~êÁº®êIþp}Œsq³,ëû¿ï@ÙÄqŒe&išv]‡,çabÚ‹,çUU…ˆOQˆ4’2 CEÈ¥TY–Xøç®€ù´ììÄ-¦iûCvB.`š“ç9þµ ¬_– B§õ;*¹]٠ɰK’dš&;·³‡]Û¶{v*_Wlç`°»Ñ9&<³ñ/:Ç„'À-Ÿ`Ê'‚ò F›A *ßÿ…áÛ¦Ôˆ¶W "ôAœÈü!|-’ùCxYDˆ¸þPe>'` Ÿ^'˜çY^ÃçÀûA¸¨ëšîtNæS~õÛô‹<, Ô ¶t0”IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample05.png000077500000000000000000000006171375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d$IDATHKÝ–± „0 EÃU””ÐqÛ0#°%#@É0Prù ë`ÐI÷ ˆœÄ?|,ÅÁ4MæI^x?†[ ïû÷LÛ¶ÍØxà‚âMÓ`‡,Ú’¦)¦•TU… nZ‡JÂ0DŠ·q QÍÔu c²,CtaW@H×uQÙìyž#ʸ$À³ã8b‚qI ŽcäÞø¶â/À­ßËNx œZ¿â)ÀÍqZ¿â#@ÇGîCs,j¯ÊAtµ€¤r8:aåpòÊá(ä•Ñ ¨*‡#½2“$†ÁŽ…[,Ò+sÍNÇ·)ówœÀýAHŒÈ"o‘Eþþ#újì@{|âG}ш¨ÁHH ,Kzzüaâ_›ßÛ0æ`I˜T,‡IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample06.png000077500000000000000000000006341375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d1IDATHKµ–½„@ …‡‹ #„Œ.hÉ  Ê ¤ (‰ ã¬ó[kt·ÜÚ–æKÖšÞÿˆ!»ï;¤ä ¿é  þ²m[Ó4Ø¡†Y×/Þ8Ô™<Ï!ñâ}‰ÆqDddDŒ¼Ìó ¡ú¾Çj„ßàWŸº®;ÏÿEø ªª‚ö³:á4X–Ú?•yR'<Tœ²,E«x ââüsvÆlgš&¬>c6ã,c3ˆÿ±8ŒÁÀÔ[Á``ê­`0€¶®·‚Ö ®>–thw[‡GÐ^™Y–q@Õ§—>ÇÌÊý‚êNÞ÷‘Uu]ÇÁq’ D”=¶Ï–¶m©Q•¨(Šëº( ù¡)âE%ª äfgÚ1•$’4™à$MÖfàÆ6E„ð Ú¼ Öjj*¬IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample07.png000077500000000000000000000006231375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d(IDATHKµ•AD0Ecvv–ìÉÒ ¸…¥#8 Grvæ×øR)f2Ý­¼]ÁÿÝI:’mÛÜ“¼xŒÇ ¦èÄ8ŽeYò±|Õ÷=U¾ØÔ=T9ø2EMÓ0ÒSU#¬`>³,£–s˲ðÁÁ]ƒ<Ï©í\Û¶ ¸e0 µ¨ƒ[>ýº®9tÁn¦zÑ \ÛHúÀh®m$}`1@úÔþ½¶ËiZÅ<Ï{ü÷sõa7M“WGú{ãS‡”Sßr4ŠÎàoß^ÑP[¬agqH€âUÉÁpEjîýxgöjï‡Hû@·÷¤$I²ªô¨t/#=¢ Ì D˜ˆ*HÓt]WÚô¨‚®ëp5¤,ÿêÿçÞÏ%/€5¦IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample08.png000077500000000000000000000006151375753423500270750ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d"IDATHKí•MC@…ÉÊÒ’·rnáì¸Grvò*Ý¥&)&óºÊ"UùÒ%ã½þ1#Þ÷=º“‡þÞÆwƒyžË²Œ½`Á8ŽúÀhÑÓ4E¡“$É0 *ápb`Pà¡'-ªëZ#‡¦iô‰wPnš¦²fÛ6 ÞÐ…&\upš„Ý DØ ²,Síku`4@úªíUÆœçù²,û,;¹ïûCéKpɫޣûUUé­khƒ®ëD¬ëªw¯¡ ¨ô=dm }œ {à†Œñjô:y4ò#…Âöp-bûˆáË£QxSxá»×…¨€Ø½DǨ±YÎ"Š¿ÁWƒðwß…0hÛWêÆOf8¿>ä(z°xF’‡2HIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample09.png000077500000000000000000000005771375753423500271050ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–AC0†“®,--]ÅÎÜ€[8;nÁÍ,õo2õàßhZk[`úØëm-'@ÀŽt¼2û¾§*šWŸü\\À´èâ©à|Ø w~¶8aqmÙÃìîýÇžFðSŸŽNþ¥ž××÷”ºúÌéIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample10.png000077500000000000000000000006211375753423500270630ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d&IDATHKÝ–=D@…ÙH($ãVB¡[Ì18’í+Ó5Õµfén+Ù/ ‹š÷ú‡š‰·m‹žäE÷ÇÌó\–eǸÃ@Om EGŠ¢ ×J°pGRÙ t]G+ô$IB*;aǺ®u]Ó:1MÓÐú3!}ß“öAÜ5˜¦)MS§^U=eÜ2àê-¥ »Á‡ú±9»A–e¤ý] ÎË1øôƒƒåX xúÁÁrÔ—ßåj>ÛËôÎ@>[Î@>[Â@5[ÂÀ>ØÒR[ú@zªÀþì¤=ËÅD§ œ(ÚwDŠdˆ*Èó|Y +öˆ*ðêø¹\ GT€6} ª@ÛwŽÈ m[\ ýÿzøýQôP^Üs6VÀIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample11.png000077500000000000000000000006521375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€?IDATXGÍ–MD0 ÇcVÜ€Gq K;ná,Ý‚#¹»™Æ Ïø¨¶É<ó{¯OŠi“¿4ï­€yÑõ1þß¾ï!IðOÖþGž_³GÀÍ„x¾Ö~IfaIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample13.png000077500000000000000000000006321375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€/IDATXGí—» ƒ0†íT””ÐÁ6ŒÀlAÉÐÁ0P_t6sç‹H‘O²pbáÿ¿‡èÕ ä…×Çð˜¦IåyþÃ0à¿‚@ ®È² JÄpß÷¸Û¯¦i7¦Œ(Šp·=^€„‰3n R×µ%^U®ì7àŠ—e‰+LjhÛÖ/Šb]–W30ŽãÇ1I1àŠÃ¸#ˆH’Ä¿j:—`=W~¥iªæyÆ_Æq» ‡Q×u–¸‰g \¶µ÷÷3ØÜ3·ë]Ø$¢XÜÎçF°NAhçoa‚àÎß à¦?r $ÓK š~9Zkœ…GüþwÁ·!0¯Ø8“lÀ¼t~® ü?N6 ÔhÙ˜¢”ô®[IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample14.png000077500000000000000000000006151375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€"IDATXGí—;ƒ0 †NŒŒ°Á­ÙàFnGâŒ4ŽÜІò° •ø$+<óÿ11±HàDԞƵ ŒãyžƒBµ]×Ñ™-}ß¿¯Õãy#8¾‘eΖˆ¢ˆzýd7UUÑV8eYÒ–ÙežçEv`Ù:’$Q¡¯ëšzÚbeÀ†a–8ŽÄ&ñ¢(TæŽ6`?õš ¡âˆ·qÄË—8âe@/5_qÄÙ@Û¶l∓=õXj¡8­Ò4…išh@Ö9Èw<íùáô9^‹ËÔ‹+T,Àôãå¯àÂúèé·¼íëG §Ÿ ë àÊæ×è‘k¯ Áÿ`©yÖš¦Q-g ÷¯ÙmàdOÉžC$Ž‹/fIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample15.png000077500000000000000000000006031375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGå–± ƒ0EíT”´t°#°%+ÐÁ0PäD9Ü?‰Dy’aîÞ6vq˜ ¹ùãe|gã8š¢(ŒµV<ð|ß÷~Æè=yž£/è‘$ÉÒuŸ5L0€¦i‚J‚ˆ €a†MUUù;aÔ?Ã,ËÌ4MþÊEðazÕ¯ mÛÍË]öþ, hõiš>Õ—eéïÄQ+Á^ý<ÏÆ5 ¿zJ °nìÕy9P1p¶ñ^¡ „²?m€ÉPØìe€ÍPØìW`@Â~Í—".†~ .Š~gÑÒD%ÐÒD%PÓïÀOç&{@ï,¿Àѽþ¢êº^lz;fù÷&4æþ«ß…*ÜÞ4IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample16.png000077500000000000000000000006111375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+IDATXGí—Ë ƒ0 @“žàÆn¬ÂŒÀŒÁ¶€‘Øn4®ÜІ@°ãŠx" ?Ûᧃºîw†AE¡º®Ã#Â@ŽHÓ*ÄÚò<_Ú¶Å+¹ñ¶ Žc5Ï3ÎèDQ¤¦iÂÙo êºÆ¯ü«‚4M³iÅ¢}ß/I’|¯ª Ϻp7½Ç³ûˆ Øw‹/ó7"vßÏDÖÙ—e‰GÏ,`g¦ïk‚ì…GÍ` pW½ [€»êmX½Dp€õ=e™ÇgÆ€~‰Þ—‘‹up“=Ž˜@(Øå…ÜÉò䈖ß@®€ÖGáÙ¬E(É-p à;_²Àû?AâüÿÏ鯹X@©'!Òø¼ˆóIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample17.png000077500000000000000000000006461375753423500271010ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÄÄ•+;IDATXGÍ–Í̓0 †Íw‚G¸Á6ŒÀ°cÀ‘-`$6€[Gî×Ô*Uœ¸?¿²ß'|‘?š¿Æo X×꺆$I¢î3Ï3íì€8£ª*ô‡ÚHÓ”v¾ó2]×Ñ“ÇqГ QgY–KžçèûžVï¼E€opä-Š¢ð Ž¨ ÇÑ;8¢*€§¾m[Z9GMÀ³ºïûN«ç¨˜Ž£"@b:N´€a‚ƒ#Q¸ã}LÇ ÀëÞ4—é8Á IY–°m½˜à`.zó'¨˜¦é!¸©{Pp‹Íƒ×õ!uw *67BSC\L¿KLp‹ÍƒÍô#âh¦‰ üô)¿Ý–‘~T@ø¢}‘ ³,ûïí5N"*¹ûíõïg߆:\NýÒ‹Ãj IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample18.png000077500000000000000000000004671375753423500271030ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+ÙIDATXGí–Á Å @=:‚GÇr7q„ÃÑ<ú è'_ýbl¤ÐöA.–&/¤UEº˜W`(BHZë$„Xxß{Ÿ3¶ Î/!¥Ì[†ιn•øÇ¶o·ÖæÕ–-ÇqüŒØ" ”ú7ÆäÕ>ìu÷1Æü¤»¥{€Uö J÷«îbV\|ôëa¶ ÌÂ&PÏ6•ùl¸øìü-^{PŽßê„aÀÝÏ@v*÷€k÷¥åúNÙ‚ ,gxº@J:…l¡½lsIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample19.png000077500000000000000000000006201375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+2IDATXGå–± ƒ0EM*JJè`+J:Ø‚1 d ‰  Køè"c¾;)‰ò$ “ÄðïûÛNp_0äF×ñ½†a0Y–™ ^>oÛ–~¹g;×®ëè›iš"â†!=ÑÍ¡eYROÆ<ÏÔ;€„\fš¦{QÎj]-ÏséÆ[À;š¦Ù €à3ÔÄq|¹z * ï{¯êêN˜$‰Ç‘î­¶aýo_^UõÎQs€S=Pq»"§ú8 Á‹¢h Ú•äoOmý’|³l¿t÷Ѹ‚çór r€¼-l¸ËΆí€Fõ€í€Fõ+pÀûÄ“Àí{âÁÊþï=ñ]÷6bŒá;ÔNC.¿)@2ç6,u]¯WÑú'ħ¡”¡1%Ö×e&v•IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample20.png000077500000000000000000000006101375753423500270620ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+*IDATXGí–;ƒ0 †M'FFØàVÜnÄÊ-à8ŒÜ€±õß:R›òhK¨j?É‚( þý IreèD.ò<ïÐ÷=UUEI’Öaý&è-†a¸–e‰‰²4Må‹ïì °pîl‹Ý4M#oDu]Ó²,øÒ®qÖˆ…˪mÛÊÛ ¼È”<Ï_"gá2³Ž©€®ëÞœsÖdv3hØ,Ë>ŽÜa"Àw;ŠÜa"À¯;7Ì-À¯{ˆs%@[÷g¢Nâ(hžgÑ}Ÿà]OFŸ¡>ŒÆq|qŽÍ&Ô9PgÀ^›HuüèÕ ¡ ù°ÔY ªX¥¨J`–~F•Üt1ÑuZñð}°[üàž?M“ŒNø žoʱ{ˆ:Ž-øõ¿€è±šáîs·IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample21.png000066400000000000000000000003741375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEáÞHc‹‰IDATXÃíWË !Ì¡ÿÿe÷¶ìaƒiM]DOAóÐ,QU‰1W"r¯=1NæÐŒ%Þˆ`$vІ[`ÁXçf[7ˆJ¾R™ÉØMîÞ†LË=ÛAÿ½ˆ"Ø×PÀ¾N XfNÊŸ®@*€¯£»V†8õPm ÙmA ?§ž_· 4ñ1;qG IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample22.png000066400000000000000000000003671375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá/ø‘S'„IDATXÃíWAÀ “†ÿ™]wp "ØÄУ)´€Š™Ù B+.‘éù,W\” 2è~%Øñ§W>œ2áW2`O'°¼Ü„¡*{¯QUzêXi_°Jç(ŽLN°Ì×Û0@ts¶`vÀ=ì<ÝÀ,wA ݯeK Œ²¿ñn.>ß ŽIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample23.png000066400000000000000000000003661375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá9 EævƒIDATXÃíWAÀ “Æÿ™]wpK„².®Ji­hîîCXâšOfF[ [>ÿJñæŽ|“ÍhþFJpjpZQð²[°c`T°ÿ,2£/‘ ’`±×oA&¶¡pþYd7º^H 4`Kn€ñ§i þû/¨Ô½%¸×¸.;Ú;›³IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample24.png000066400000000000000000000004001375753423500270600ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá ªŽ¶!IDATXÃí—KÀ DeÂý¯L·M¥ ?%eëBæ (ˆÈ( ž‘Û%+œ¡ò.æ™ Fq°†mf…V:o-d‹µ€hÏ5!)5°¢ˆhõš…ˆF¯ªÐ»'ðý6*Õ÷ `Q>«ú>]`ù5Ï%à53žIÀ£úûuAYÖ¡õ·`ßÍ(kY)'pÏÄ:7ÕL„IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_7_Sample25.png000066400000000000000000000003651375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEáP‹B‚IDATXÃí—QÀ C¥ñþWf0&`]Ç‚¿~@_E«¹»á¯¹Û43j±l9o[=Ÿë&[ѪøNn@ÔB(ÕÓˆú~} #Ó¶úèèÖ¾ OÕ×&ÀPÿŸ×ð$T¿t€ªvNìL¥ÿmA7JÅìÏ´œÀë+@ể¼IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample01.png000077500000000000000000000007541375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dIDATHKí–1’ƒ0 EÉVÐQRÂ)h)9%%· ä”p‹p3èØ?‘–6–Èìdf‹}MŒõeÉ6yìû}’/þýC`Y–¢(<Îó̯uÐçó™¦){ŸÉó|š&ö ` dYÆñ®ˆã˜ýØ)Šº®#Ë0 lz¡/ÂÞ¦¨8 Ï$I¶mËXוŒ>oì"§«}ßÓ€d‚¼Ö¡É§dü|…- +~h`ka ±õ—ÀÑ¡AÓ4ìwÅ-àìœDG‡ÙéŠ[NAªªb0¶€r’ý¶û~t7§%ì@p¢'H }š€¼…dt¹Ó+½PA¤OóÜ,TP@¦Ï&;… Næyôd¡ØtƾìʲäÑö•ÇBfj„l›Îܪï8Žlõ0[Ç"JÁÖ»¼?B­Òä"€üÄc Ï r¡j7e]×&€~¡“Û¶å`ú&¶á” ˜_âÿϯA} +[9ÿïDIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample02.png000077500000000000000000000007441375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dyIDATHKÕ–±q…0 †y© £¤„ XŽ’  c ؂Ѡ#ÿYÊÙò»Ë»K¾&¶ÑÓgcÙäužgòI¾øïÇø3‚u]«ªz9Ð@—˜`lÛV–%‡^Áø²,çÇEÁù4Ò4å8?†€39º®Û÷}žgî;ÐåP±îÿ0 ›‹ˆÜ^7–¬]4Z–eÇq ™Ê¤åDp£LÇq¤4¨Î¦i¨@§i¢q·Ž˜;‡:ÐÅnsÇí<Çy°·²‘´m‹÷ÆqlñÔÔumfQ”Ðó<ã]ýÂI\ Æ {žçœÌñ<̦Ã+¸e§Ôüìº%a‡.¸eïûž"º@^¢jvâæàÑ+º€ÌNH‡ºý.мgˆÀ}Œ»(æÓ(ï+jHô„'õ$°b}rRo|ßUàTÁÜ9Âú¾£¦9NËæÈòHÙó"¡q‰W|jM‡D¤ÆwblD•…ãÿï:I¾Ms×T“÷-IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample03.png000077500000000000000000000007621375753423500270740ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d‡IDATHKµ–;–‚@Ea"Í ]¸BCCvÁ Ó]èÎ4cÞÐo8ESæ¨7±­î®‹Õ)Çq,>É??Æ?÷ûý{b†¶€9Ün·ÃáÀ¡K¿\.gã ½ª*æÓØív¡ÃÔuÍL‚ãñÈÖDèðÌQçó™¡?º®cßä`Tc“@}Fé`HÃëã¥ùj°B©0¤áõ9uÈÖŸQ ¯HÚ)˜e_¯$€¶m™iÚûÙ±ð³ƒXðx<æÅȳƒXN§S ¶d±`}žñƒú¾gwD pn‹÷ßE¨‰ÜT@=¦ÀÚ‹Xs¹$¡ÃÈ›n½žÙt¦€³íݲÑ ø]#s0ºä%†–¼*xö42†oÌ—•Z%ó½¨,ËÔ°Ì<ŸÏý~ŸÚëÁñkËõzeË`.‘ÎïÏИ§¡á%ÜKi$`H` 6nsyà›¦aT` €t̤;dÿ<·g <P*Ö`‹ÃÊbDÊPqµ& Æñª>Z˜ÞeIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample04.png000077500000000000000000000010571375753423500270730ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dÄIDATHKµ–=–Â0 „“­ K™ö¤LÉR¦LÉ BÇ(áÐq4èØyñ8OÈ–-øäŸhlK–)ßïwñM~øû5– \¯×ß ìZŽÈâñxl·[Πór¹pRSÞ«ª¢Ë€Õju>Ÿ95‰)P×5yš¦¡åÇ‘³mLú(жmÙ5q:80& L‚sƒ]žçó¹ßï­Q…) W†K¦ H]´õzýz½``™Ò££,Kg$<€Ô=@ •þÇã‘V–i&2î ÔåèºÎʹȨœky9j§d€Ò˜ÁÚ³ÞA^ô}O¯ža8–#_ìÞûýÎÆâ±ÛíØÈB¡V±s,,y¦@XìÂZ4§V‚¸€ò.ã©btY(ïÑx†ékm%" u"[­pà-€å󋹈s“}´€\>»r~{´NüÏUÂ>σ¾h˜áŒÍfãŒ,øäv»9Û•÷(ä™÷k-ŠŒ»<ºýΛXxW1G¦5{=º dÐ$Гw « I¹ˆ€J¾åDó""à°ž(‰·ÁPXÛÊfó—ÿ¾Å¨s\*) 4tIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample05.png000077500000000000000000000007211375753423500270710ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dfIDATHKÕ–=r„0 FÙT”””p+JJn ƒ[ÀÍ(É—Xã¶~\ìÎ$¯ «Qü°,Û¼îû®>Éýý¾à<Ͼï_OÙ÷2lP"ƒã8š¦¡Ô'u]oÛFy:Ž m[OÊÓq4RUMÓD¡ûžç™¢^€ÓE(wxHÒ´xÎè¢ï™u]é©„Ÿ:é`CZìÞWÃ0„4GÀ×t]Ç»öº.ÊÓñÛ qDx_ø; w(€|K¿g'´£Äá ’ÑQz^1×á øq¶Üá–e¡a²¶)tXwO%Š>QIéµ=Åâ$TXz¼{H'! ŒÒçðIPˆ! âë—g $úÍ/œxŸ ô±ÆýãÜ%Ÿøì '‘ßy¤ð·ÆmïUÞbȾnQƒVFœ2”vÕÇ‘þµ­TA ŸŠF×v¢#Ø{£ü÷¯ëªúk„µ™¾¡IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample06.png000077500000000000000000000007471375753423500271020ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d|IDATHKÍ–=Žƒ@ FÉV”””pŽAIIÉ-8%ÜnFÉ~ _FÎà±I¤•ö5QæÇ/c{FyÇ‘ý%?üôض­®ëÇ;Y–…+RàëºVUÅ¥yžsiK€èEQ0Ršq¹AÔeÉ/ú¾çÜq ÃpÚ‡°ç~ ãö}ç´™ç[~gš&N-ÀÙÏý×,Ëò´mËQ K ³<Ï3G/ÅG®8¡a °3"T2Š®–Gb ’ÃHÏD}8q':ð2Q¦i8íá Ôû %Ú”+L=€gJv—Š%PK*Ë¢¾’ ƒªt]Ç Ï‘È—Nmy£$º?Ÿ[ÍvŒÒ¥–Dȟϡגpâ…¾ŸËïݦ¨$Prâ‰#à÷¤^FGà¶y@}.Kï;d=8”D-xÓ!{C)ˆîË]L޵ @§«&ãÚ[pu¸Dí@Ôæ6×{ã ®I½•ÿæßõ—dÙ/»s™Vä’IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample07.png000077500000000000000000000010011375753423500270630ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d–IDATHKµ–1š‚0…ãV”–”pJŽ`iié ,õ”p ¸™¥ûÖyËÆ™$ë·þ…†ÉðI&ÝãñŸä‹ÿ˲´m»³@|š&æ¥ÁLæyÞï÷L²¨ªjGfû¸u]SɧÄÃ5 F§Ó‰¡_®×+û <ò¼Þ¢<µxÓÄ Y¸eŠR‘†—JrReú/¸˜YiÜn7i¼ÉÏŸçó9Ë2üÃ@o"ØAœqóЋŒª:–eÉ …D^÷ûAQbhoö•”·^P dš…õÐeͶ×ð 8'ã”ôõzµmË9í¸üò6!½[œ­\¯WNlñ ð!­ 9!P8ƒýÕumƒ½õPÔ&Ð@jƒÞ7~È^äYÑõÆ“Q1kLÓt»Ý¬¡( Z{(´ãr¹0B€›µïHç>Òû&( «—ξë‚À¹P*ÞžŽ 8Dôš¦Á,ã¶üoÓOøïÆ|#TÿyòÖQ¶IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample11.png000077500000000000000000000010021375753423500270570ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€—IDATXGí—½q„0……#È !£J $¤‹ ): „(… ÃzX²Ç›ñŒ¿™“…¤}·?âìÌq#oêó6þ–€®ëDEÂqœa®®kµÊÔCÛ¶³ïû¨£¹®;WU¥VóЂ 0:^DØB§`5"Ïs_¬( 5+Ä4MjÄC·!r­ÙoyõìŒK]p¹à Ðð<ï3Ä2×bÇe ~%ÇC>r­[­ù¬®âu"![sS ¶ÀYñ8ýÐdw¨•9OÓT=µãRÄq¬F_ô}­;”YŒOß^Û•ëØJÀÞ¹ŒÄæoD”e©vœC À¡kGI’Ìò.Xž™ŠuÂDƒ°®kL"˜hPöo½s æ³,Û¬…!uGPÖ‡1½nŠæLX `A4*½é0ñc@Ó4§{­Øôù¾vLP>}{Ù sÖÎj‡`ÓçplzWA &¬½êZ¸"â¬m­h!ìoƒÿNo Ä;¿]€á<:gIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample12.png000077500000000000000000000010351375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€²IDATXGå—=’‚@…‡ 34”Œx`hhhhf7 o¡Çà&˜±>ªÙmg‡énk«¬­ýªºd ßÌô&Ã÷F>èóm¼$àr¹¸<Ï]’$£a\×5Ý5‚#ÐÒ4ͰZ­pdA+Ë’fêQ 8ŸÏA§ÜÒ4EZP X.—OζÛíÐ÷ýhpÌEXP àÎᔃ­ç÷-Gñ’€‡Ãáë¾eÔuÑ>zä~¿»,Ëè*<'„: «¢‘өȹÝn42‚ÐÀ·Æ·¹mÛa±X<Ý×¢ž‰ÀÛívONPŽÇãçûýžž’ÑK%üðÍâ˜`'Š¢øçÀÜ ªªr]×ÑÕ7ÒõzMWHˆŠÓé\ùdL”l j~/Øl6³‚ð½•?Íàœ—c¿ô"TüFä÷€ï ŒÏCšJÝQ€Õó—Æ"=$q! ðW/~ÁâUÓG|#‘%Ïý¸˜Cì†RŒ¡yöoý*ö[pŒëõJ#A ¦M¦I-  ^Q@¨ÈL6'Æ’º¢¡±*¯‘R×$€££©ÿýß±sŸ\Îhi —´‹IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample13.png000077500000000000000000000007641375753423500270770ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€‰IDATXGÕ—½q„0F…#È!ƒ.)…(º€’(ìÌÇH¶Ð­¤Ý³=7~3àìÓÏJ\ò8QoäCÅlÛ¦êºVI’\ÇeYô!è.ëº>ªªB‘÷æyÖµy°<Ïs2°]Ò4I°Š¢ 6Móô$¸°Ðz;@ß÷úÎ7Ó4ÝêpaeAY–jßw}u½]ŸÝÁ„40^{ÁÊ;xÛ¶úì²â%Ð10¦¨Šâ_wŽpaÕtÇ×åœ9⃭êö‚‘ ÒS»¶Û Çñ)¸¤õ@¤ëJ¸EÈúëÄ·ÛÃ"A,Ðu)`Št? üÅ~À ‚›1§æW‚% nCeJL"*À n $BDÜ%–“j®Dˆ¨€ý"Iž£åæ9ù H†áë¹Ð0D¿^ÙãÁq*Ë2}åVôU,ùò=[­Ï" BØc‰sÑ*§Ÿ …‰ P‹Ll¹Eêº{†¨ $¤ÅKüD"”¾lƒD„³nüß?§¿Å›”úr£:ÿš˜IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample14.png000077500000000000000000000007541375753423500270770ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€IDATXGÕ—±­„0 †ÃU””ÐÁŒBIIÉŒ@ [ÀHl@ÉçDJòÇÎCB;NNüc;>È®õ"ýùÉö}WMÓ¨,˃ßÖuÕ^  \¶m»êº†’‘–ç¹^‡-‚EÄlY½’†- ,K4Ð0 ÚãúÞ¹ù›¶€PP›¾ï?ìc f-©ªJÇ¡¯Â~6C;ø%ý-d€¸À&ù`$ ð;;!\ØžT‡û'$Ô¤lÓ49A` A&üÔK‚ü\ÝŒãèƒL¤¦Þ Zqž'9 ¥wˆ%û¥°Í”E‚Xç?A"D$6õƒ·më\ƒþàˆ` ˜çùW»æXi8"X°´‡Î€‡Ó@!A ܹ&ƒð— ø"0Höâ”!Ø{`$œ‡±=þÏ{øyŸ ” t.¸Ø&³þð `Ó-Õº®Ó»º O /–Cªê¿üz®ÔöñäÛ,+IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample15.png000077500000000000000000000010651375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€ÊIDATXGÅ–1’ƒ0 EÍV¤£ ¹An–#¤LI™@7HºäÉ‘rƒ¤cù;b1^Û’v—É›Ñ`0 ,É$ý€y#t|p¿ßÍf³1I’|Æ×ë•f…` ´Ün·¾( ,ÝKÓ´¿\.t'Z^že™×ùh!E%àt:yVUÕ·m;»&‚JÀz½ž9c|ù8'‚J€íüù|ÒÕ 7 ~]ÃÒhb»ÝÒHŽª¡ÔF|åynùïqQEÀþê®ëh4a;òƒF ˆ€”ãñø½¾n’!ëÇ9ÍkUx¶8 5%)*À.µ¹åC-À-5Ûöû½·€|Xd3ò9GÈ뺞]ƒ!Oþ}/ˆíX÷Ãá0›wË4„H€» †²ÜMPœs°ÜÐ#ì1bÍÊ+À =Wf˜‡ãñ~. ¬Û¹´Áh¢  E…EiØÿî Äëõ2«ÕŠÎÂÏ.&Hže÷‚!|42¦iñœÏg1 1쵄¡×£1…ðýÄz+]–åì…Z‹õVÀ Ü^/5®wˆŒh„ÈšVßA^äN¢ÂÐ?IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample16.png000077500000000000000000000010031375753423500270650ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+¥IDATXGå—=’ƒ0 …a+JJJ¸ G ¤¤ä”:¸Ü ://coŒW¶¥ìdRì7£ !²üü#ËIÕEòA¾ôçLj Ø÷=©ª*IÓ”4ü¶®«ö~,mÛTžçX¢ eY¦¦iÒ­dEAvè³²,Õ²,º5 ;x×uúí“qo>0̆„ 3ÑÅqªmÛ› Aï¾ï‚ÆFö8´Ñl? Qo{`ÔFƒ0ÛGBÔÛ·ÑŒ7U›¦y¼çÂ’Km4ˆ Î øJÍ—;nçTªÆ-ص$¯vÄÅè°¸£ww;•)Æì´ua °GËu_ÚR°ØÁ¸¹îf UÐXþrÔÆ +šdú]0[¦-Ì…u+ÆÝÏpL®‘èo<ìönwb ÷_„Ú¿õZnnÔA01àf,véD…Äác·1Fí–ì^Ïî Q¾N¡s*}Y|k¡Jɤ"¸å™-PG¬1ßÇøïÿޓ䶧# ЮIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample17.png000077500000000000000000000010211375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+³IDATXGÕ—1’ƒ0 Ea+è()á\#GHIÉ- ã¡ƒ[›%ËgÄ Ñ I¦Éì›Ñ¬×ØÖÇ–d/+Ñù¡¿_ã’€iš¢²,7†z/‚#°˜çy)ŠG¥Æ<šåÃçY–‰Ϭm[šmc Èó\tr¿ß—º®Åg0ìÆ8Ž´Ê9¦€ã¢MÓPï_^¯×r»Ý>Æ'IBOÏ `½Dð]±0ë@š¦ÑûýÞÚëE«“­­Ç1µ6Ô’1Óp (jE›¤ F×uÔr‚°ÀYb( í³£@ îã`T —€¾ï?–‚‹§+1aḈã.HµÂã¸~@r®¥+'Hß©<‡8AÀq¸…:A·áóùÜjú«ª¢ÿ !&ÞKÉ{ì¸HΑãˆt0“W„)ÀåÒà¡ M1OÁâ¨ø·€'ʵ‚%¡ 8.’bxó}žµ n!ð]ÐP¿BîuŽwîÿù]`}ˆ\Gp¦  Gó zJyíúqœ§¡?]‘J­VïÑÏ‹—†)H"¼fÕ—pE„]¼–åJÜݤ®JIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample18.png000077500000000000000000000007261375753423500271020ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+xIDATXGÅ—1Ž„0 Ea+JJJ¸Çà””Ü‚’#PÂ-àf”YþˆH^›ÑŠ'EƒH࿱¢IÝAò"?ççk<ض-©ª*IÓô3p¼,Ë9k-°°®«+Ëm»Œ,ËÜ<ÏçJjX0° (Š"Ø÷½ÇñÏ9 êÕ4Á:giÃ#PJïç-mP Üí7—°´#* ç›BüÕHˆ–pÏ“Jˆ|ÿ¿ ÷„$bˆô&Úp—ˆUA%ðäùæ¿ Q@{ ^ qÆRF z½„È×ñù1Tæy6yž›(Šn†ûx®Kbš¦-Ë2,•×â8þñÕÐ÷=ÌeZ^ã8ÞÔu½½^¯Ãã—a.>!Å+ MÓ÷ UUÝÛPR¼eˆä:Ùƒ›ýÍŽo<¶¿gØ b’Ÿ—a¨ÄÖu=®”`\ ™àóe÷²,[’$oßÀ°¼ž\vS\ð¶m§a‚RC"ìJi‚Ñ\¹DÐ&¥ Ä‹ÕuÝ%54¨'ˆ  ¡qÁaèšO Q+ËòD„J€dcB¾h  ÁÏ™(Ëòr_;"48ݘpÀ¶t&¼ÐdèAĵ+Jš‡S×áB[2 \‡p  Ž;ˆpЙáô°Q·Wë·!D4Ðc\‘iYѼ‘´g§ZV¨NW)§IrÆ)€&“Ö¤yã]$¼AÓ4lŸýéH„<9 €ÿþïØ˜o³5}Ôl¶YaIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample20.png000077500000000000000000000010101375753423500270560ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+ªIDATXGå—1²‚0†Ã«°£¤Ä“hé,-)¹%Þ;½ËN;?³q–¸I6Œ3Λ÷ÍìØd³jö1_ä‡^¿Æß¸^¯f½^›,Ë‚s.— ]5 e†gQ¨UäyNWúQ ¤&·q>Ÿé2j²,g7®ëš>yOnῧZ€'ßn·tT¦ëºÙù!Ô}`µZ™Çã1ǧ2÷û}û@!ZB)Ô» m[™Iäx<Ò»wN§`´4MóšV¬­T`n±î÷{úD&I`œö·ãÒNÁ5!’€[`¼ÊSvŠ%Y¸UUMSÍi’ƒEIyB±uç,pgÁ ƺ X,€‚ Í·S8‹¤jßívÏÃá0;†àE*‘,€'r“cÍùvs—ï}$ ŒÝpvc„¯Ú5M ¨R’©iI¨ú¾Ÿ%ÆzÇ:p—BB%À;œ6¹%& ú6¼Ýn42f³ÙL_ǃD‚h JÂ^çK¥ J+ñàk½RËõuI µˆõÿXH$ €¥¾ž‘,À‰Éh~ü÷ÇÆü‘úà9IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample21.png000066400000000000000000000004661375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá$vX»îÃIDATXÃÝVËÀ Âÿÿ2»-¦R,1Ód§‰-âîÞm‡¡"2ü— ¦í‚~ÝCˆøH ¸ûûíWè š ²j>.CeI°„@4·"’&—JA6ŽÖ„Dgâ!RÊ|tÔîá*¥Eˆ #”ˆfÀWáFHX6×=‰QoˆU†'3Õʪô™g$èè¬ #ûAÙ8Žþ×>P…»#é#Ð0BZlô®UxUº² R#†»DföHçq5§qˆIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample22.png000066400000000000000000000004651375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá/áŠbfÂIDATXÃíWËÀ SÂÿÿ2;-1&S(õqש”òꪙY9hR›zÖZ‡ßQ"ÅãxæÜpK ½ÐRFMcÀÌJ¶‰ŽwÁýzŠyO3ЂÈ’håGçOµ#!è Ø6ŠWNAê2jÏDØÑEÎÃ)xÇðW´^‚DÓ;ÍìÉ:-& ´6DëAØÎ£ —lCz^¡XË'­ {Y½ ³\Î\®²ÂsvWчXJº£Õ~Y>²ħaA6ÍüIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample23.png000066400000000000000000000004631375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEáav üÀIDATXÃÕWAÀ „ÿ™Ýæ  ±KAqw¿6.½6/›=@DÂ}4±ÆŒâÆnÑ^ÕrY »§3¥`ô¶™íe¨]UÐjDLZ\Dâ¹Gõ®Lh‡ú3¾ ŒúŸ1¥’™¼T†_oŸÑ†2+$¦›ÑHœ ùɲG?‚Pö´ƒšÖò2|#¡èícDGåHZ P'¢lçCãm”¾ç!£¹­ZÙˆVü[UÏÇþŽo< eG&#´IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample24.png000066400000000000000000000004631375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá hÀ@×ÀIDATXÃÕWAÀ [ÿÿew_¤Xfæqѵ‹€9ç¼®¡°Ü£h¢\Ù—&@ú©Bbìäïê'(€e:†xgÑ ^!Æ´p“£ã²Eß2)á)å2( ‘òì…¤[¹ê:ýÿ‰ ß@*%»¥Ø£Jγ$èß!A—òÈz+%ªÒ ªê3VkkÉ:z†6G*áñ~ €»úGKùzõð|28"’î »fØQµaVyËdä¬ 7Ä[gQbÀdIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_8_Sample25.png000066400000000000000000000004731375753423500270740ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEár”ªÈIDATXÃÕVÑ€ Æÿÿ²=¹5'!dùÔÒâàà<ê½÷vp‰÷"R÷\$P;ëÂYÁ_£`UîPAƒÎïQܯo˜K®•9ÒÕè¤0ÚxYçiWŠw2E”ð?S`e‡ÞiœÅï+Bd!"7’ð‘HæƒK ž¨ãhðñŒöDÁÓ­¨íi \†ÄÊÉ2!Z]U!Mˆ>ë,àÿ¹ ª²Ë”ÞAìö„\,þ*lX©#òþ‹Ñ™>Ò ŽáH}n;xË—IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample01.png000077500000000000000000000006701375753423500270710ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dMIDATHKí–=’ƒ0 …•­ £¤„£p JJnAÉ ƒ[À‘¸tDk¿0$ز&³)ò5زìç?YÜÖu¥wòƒïÛø ¾ïÓ4½íà*Ñ,Ãg 0 C’$p}&‚®ëàgÇ!Ç1Æ3á£! ðô1Qžçóó<HÀ>Ž#ãüà D¦iŠã˜AQ ÃÀhU IfÒ ÑP˜Ã˜º®iÚhÛ–¾k>¿rÒ Uâ¦8jÐ$¡®Š]h $æ~ô}Ï•Ÿ¯mHÐmŒx†ÇK\–%­ªŽÎ~ß=ÃS‰,ËB‡„*p<Ã,Ëì>kZ7l¼†ÏÝ4 sxa´‚ϽWUÅ4:ŒV¸pƒã»²ØÚæÃ•ÀýRàœoá· `šruÅÍ[”¦é<Ïv}çáE¡õKx÷ì¨ »P¾ËÞpPe4mœ:­:rÄÞ…ÐJ»®³Fô»S§sǵ‹,€.´·kì@Ý£Û‚Žf¾—èvS /ÿxqùëÿ®ùǨhv”;ÂIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample04.png000077500000000000000000000007011375753423500270670ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dVIDATHKí–1’„ E™ õ(ÞÂÐЛxÍôz3C÷/ü²lfª¦jkk_2 ú#Òó<Í'ùâoû¾7Mó° ±®+^|'|pPȸõdƒüJÇ q¢#r<ô:êH/!æ”ü²¯ë—1æ|x¿s}\\-IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample05.png000077500000000000000000000006771375753423500271040ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dTIDATHKí–1Ž… †}[YZZê­,-=‚7ð–z ½™¥ûþ–Ýlò’·_#ÌÀüˆÃàë<Ïâ/ùâ3ƒ}ßÛ¶}ÐXוŽ4xƒK–eiš†<`„‹ƒ"\ÄB;ʲLkD¶mSCÃ0M;†´†.€èUU1€¡ëºã8è6ø2РU  ÔuÍ©Zh‡¯A“@qÌóÌIfChÀqùþæ`í´Æ±#û‚ÐáoNlgX ‡æ pxÆæ‰@« *È<5ƒé„$œ€¾6­2ØB· t‡`±ã8¦Ï3à|â*ö#±sK ú¾çTôhº+àðßFÍ+ú⿽pp7ØF,Î çÿ—|¸~dØJ`NÃl±j±s<,× ¨kRI–ëÄå¡d;GújÒ_-]ì|./¾èÞYJ—¡-ïôwý„¢ø…«ÊÄ´þâIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample06.png000077500000000000000000000007201375753423500270720ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨deIDATHKÝ–;’ƒ0 †­ £¤„›p JJJn@É ƒ[ÀÍ cÿAZÆc$›É$“Ýýš8’,ù!É<ö}7ïä‹߯ç,Ë’çùCªišØÔîàÊ<ÏI’°…N–eã8ò9@š¦ì#DEÀ_VHìå³H¢i²Á&ÖueéÁMEQ°HNáfþS -ŽãmÛ0 ¥‘PéDƒ«“!MÛ¶¥…цG~Ž}¸°ÎOÞ¼*YG‡ <çK@Ì´9€ˆb5õ}Ïjïòª>³`v §ÎYª ª‘?UU±/„À>z]×ÎÔ4 §<ìOišÒÕ ½a£„O¡a‡ S8ºcžg®3WŠBCª¸ÁÞ´áÌÊ—ÖA×u)P"Ù|îÓOpb´…3d“iœUÛ>}Y€Î$Ñ6dHUUô>Ý–M–•„ Ëæ2.ñù` üéÂyû:xo,`×ù7_G}…µ«—eÉ)ÅE\d.:@UrVqEÀoDöë!ÿ¢(B· æý6g¿>ëæö8ûÊs¿]œ‰„ÀaþîÌJð÷+þû¿ë(ºÛIÌ¢—öAKIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample08.png000077500000000000000000000007421375753423500271000ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dwIDATHKå–1Ž„0 E™­()™nÂ1())¹G€nGâ[²þ'†€i¥}Í;ñ8væµ®kô$_ø}Œ? 0Žcžç¯ ô}G ”iš²,Ã< 2ÀIg¨=I„tˆã8PÃ/ ¢—eù½QULÁ½®k86Ú¶…#LÃ#¦)8Ñ¡«‚GK•èŒý­`Rî®ë°N_)¾!¬ Òm¾%¦=îé‚CAº±(ŠèÌÀdá=»ð)H7%—¹ÕDntnénšë¶B)¡]»õLùÇ誀¨&/|ºðpU€±Oº —4Ïéž!^Å­ 8ÎîßhÔ½ypá?Üh^æyÆèŒ›9x¿ß˲ðøó9 í›èvÅù!ýKˆ†«Înu…¢(´KÊí†a'À½š[L¿¸.$:±0­”¡ýºmްÆ);­ÙnÜ ³tÐM/mÜ  æm®nYððß÷(ú1!®M2*…IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample09.png000077500000000000000000000006731375753423500271040ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨dPIDATHKí–±•ƒ0 †I*è()aF ¤d è:Ø6ƒŽSì?<ž‘…c.ÕÝ×DF²þXXÆmÛ‚oòÄï×ø@`Ç,Ë 2h‡ •Hfš¦4M} îëdG°¥>BÃ0`‡U€²ÇqŒ4oŠ¢X–¥m[Œ´Ìá° $I‚ŠªªàPLY–ð‰uæ}T\L=¥>‚ýïSMðˆCÇsðFQT *±¶ÏìalÍEÙû¾‡%£ÖaŸ}íÆÃSŽ s+±Íÿ¢(Zר$þÔu ë>j F+èæÀÀ£DŽüÂ6½Ï¿À%þ·Ž O\ÿmêxâò%šç™î ÂÕ¡iXâ‰ûB/Ä`?Îh²ñM7;¹>/`|ÖmäyNõÁ Ö—|©¡oˆ¶#í"AC¸ ü©Ë¯AðŽãçjÕÃ<IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample10.png000077500000000000000000000007131375753423500270670ustar00rootroot00000000000000‰PNG  IHDR üí£sRGB®ÎégAMA± üa pHYsÃÃÇo¨d`IDATHKÝ–;Ž„0D™ á&p BBBn@ÈȘ[ÀÍÙ®E6î¶GB£ÑìKÀý+ÛøÃcß÷äüðù6>-°®kY–X¦ibD|‘eYŠ¢`bæyfŽ„*ç9kÄHÓ”9²ºÏ샮ëèØ÷mÛÚ¶¥ãªª´qÈv÷i’@ߤCÎg’ÛwŸqw@«KD€m{2ir‰„WˆN¦l='7¼B€ MÓÐä" Ø“K“„=?X]´º¨ùç F“ ªgYfb­ª£ï{“ ¥Ë—@Óßäôy¨ ùÄ+0ÍC=ìP}6î@!…ËV:Áš1_•m½ÎÝ §·yÑêüûí>ŸÀm\×õóùd[1| p¬%sLúÛØæ•{IuœÛXÓ°OºÀ½¤ \¶˜ý÷€Ò—³ÈØEB>m__«!ÕWƒ(-møö¿ë$ùQ4ùþQIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample11.png000077500000000000000000000007031375753423500270670ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€XIDATXGí—1®ƒ0 †C'FFF¸ Ç`ddddcäŒp ¸#í_%UH“Øn+UO¯ŸdQˆÿqB’ã†ú"}ýKÀ²,ª,K•$ÉýŠû·Á ˜çù(Šk%hh‡Ÿ”¨€u]ÉÀ¶¥i*çùSº®ažž“Š ÀèíŽxßwÝzfÇ“/Dp pGOa‹d!Ø3:1VU¥ŸÒáÜ,t]'Ñ4MÿÀ8½0ßv8#’Nˆz¹‹‹Ê‚í ã@z¹Y@š}¸o ŒéåfÁ˜½ó!x–e§ö¶mïm,™!1ãÂöÄ¢lšÆÌg\øžœŒpùè‰eÚÀíöw"ú ø˜€mÛô/!x b`—C9ŽÕßNÈ…ô´+œïàùÎ6 Hv12!}ß{¬’à€ ©Òà€=Y”W‚þjѸB^ løï_ÇJ]ªê¢®+¶IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample12.png000077500000000000000000000007011375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€VIDATXGí—1®ƒ0 †C'FFF8 G`däŒn7cä½_¥$MbµjŸ^?É*JBòÇvš¿¨7rÓ¿oão Ø÷]Õu­²,{0´¯ëªG ÀHaÛ¶³( œ› åy~.ˢ߈“$@²8DHHP–¥µÈ0 ºçÎ4MV¿dÄæy¶&w'LWˆ˜_ßunõCãHD ±sÒã8t«slh§ˆKb¸®â¸$ äW_”pˆÀ—æÄUUYBðì Q±7ĤÆ!®ˆàH@„„ <!fÇKî(J7ý÷>ð¹péhš&írqBT|€^SÀ{dÁnæÇQ÷ÄyZ-ðź›~}¤”m•ˆ¤Ò¶­%!®[PˆÐnŽãÊ6`÷“ô}oM,1É×ÞIš”:@)Y‚XÁíwrùþ7üï”úŸpq2Ö"IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample13.png000077500000000000000000000007671375753423500271030ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€ŒIDATXGÝ—1Ž„0 EÃV””ÐÁM(9%%%7 ä”p 87 dù#Lâ!vŸd Çù1ÄÉÛŽú"?Çï×x$`G•e™ ‚àc¸Æ³Gธ¦iKÓ¯ÊjanÃ0=ä8 hEì œA¨[mÛ²ƒÀʲÜÖuݺ®3Ú )V}ßëº>Z¯p"¤™`àÓ´Eñ™­ ]ˆ$¬€8Ž/$ƒŸÐ~0Æ2œçY-ËrÜ)µ§]í39îÞǨ„I’\hÍNP(®þFôÙû #Qd€‚G§ù¬gnÉJ0¼ðåž$_1DÚª¤ÃK_JÜz–”f˜Ö«i6 ËPé½Ö 뾪ªK°;;Ë2 Ï%Üzq%–Wši»„×OD´HBÿÍÑ›ü/ØÈ|yõ#|²‘½–n p Üæy.ÞôCŒ«' è:ß¡Î(VtW< ¹Û|°z»Ê°Í|fœr¥Bè†äƒ8_6!¾3Öùòßs¥~aDø^å7{†IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample14.png000077500000000000000000000007111375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€^IDATXGí—=Žƒ0…ÍV””ÐÁQè8%%%%%G „[À‘¸%»#áĶÆöƒdÅ®”OzŠ‚Çž'ÿ1ûâF¾ŽßÛ€ LÓ$²,A°¢6й-‹®ëh‰¼ ÃpÇñè…ã4€&—ºbÂj`mð¢(ömÛŽÖ'}ßkqgM°æyÞ£(ò&—¼b‚5DZ6 +¹„3ÀPªëúxꧪ*­/‚׊¹l¨qö&¤³-ašY’$ëºÿð~Þ‹¹`–eÑ’Ÿ‚fÀ„65‘\›‰vzš¦XU(l¤¹£Í#åJ,…bTgD Û¶õ&–B±Fš³`SY–{B}ŽâŒt™PKÔv(Ò4b;ãj Ê[+¢+÷Çÿ¨ˆ~“¿m€^2yž_¯xèÚ•Rݘ5$Š3Ò| ¢[Åi i6OH )q Ì:ϧ35$ñù8½Ù€ß“…Ž˜,€—YIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample15.png000077500000000000000000000006441375753423500270770ustar00rootroot00000000000000‰PNG  IHDR szzôsRGB®ÎégAMA± üa pHYsÂÂ(J€9IDATXGí—;ƒ@ D—T”””pnAIÉM8%ÜnF¹a"V²Ÿ1!"‘x’öz²l"=£.ä±ü^-`G•繊¢ÈixÞ÷ýA‚%1 ƒN’K´8Žu×uKd˜ Irc^¶äu]/O·4M³ñƒ¯€4M7ƒº’ö"˜Yð XJnÀ?71Ì,ÐlKâTÒ%§ hÛvãÏÄZ€oC¹Ž*ƒ×k½¡`Y–½ Áµë=ÁàõÚ+©1½$"°éÖ× œ×ŒOHY–zš¦—ßú>Ãéýª¢úúoq ø]è‹¢÷xRp m˜Ê&i¯bŒ18½ö#Eé4¶%×Å‘fx½>)Fl ”yD›Pó„BSU•5ÙÞ$ÉÁýqz±¥žIŸMrƒÖØIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample16.png000077500000000000000000000007171375753423500271010ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+qIDATXGí—1r„0 EM*JJèà&ƒ’’’[pèàp$n@Iö“q<’eH&3y3šõ.²õ­µeí/Ô/ò¦?½X–EE¡¢(: íišôÓ‹ ó<ïyž#C¢Á¯ï{ÝÓ§€4MÉ`.ƒqõ2¬Ìž kšfﺎ|vš¯V€={Û¶íu]ñ‡Åq¬=xØ‘Í0c¨¬à7^BiÛö³¯”…Gà/1û»ÖÂ#ììÊ[ QhN–,ËÔº®úÛÜ^•pÝòÃî @ÚðØ4ios•Óµ‹XR¡ñ5 §W`BLBöÐ\͈Ä#÷tx‚· Àµ-„Û¡]†tböfðWÔ-ÈÀ  'IrìýÓ|¸EÎ;¸ï-Š€Ù”e)^*¯>6¤€óBŠ‘Á†…¤ê(–¬ªªãð …zð„ÎÚ„]„>"¾øäo½ßRïq[žÙ]!IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample17.png000077500000000000000000000006761375753423500271060ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+`IDATXGí—1rƒ0EE*è(]Â)¨¹%%%7 äÐÁ-àfÐ> ÁBû•IâÉÄofDzµh¿Äj%{ËŠz /úóa<8 èû^Åq¬<Ï»3üŽ~'„ Ã0,Q!a­æûþÒu~J†€àaš "XD¦àY–-Ó4i7êºþäî‚U€)xQº÷Ì|÷c_…UÀív£ƒƒó*0¯Â*à8˜|ç¸ 0 z&I¢[vªªÒ-ëYšçyk¯3Skâmm Ô„ËðÖ8ÎB˜"Ó¶­n‘`l¸fö9q%DSf7M£{?¸ª”²ÇÊY„‹IPÀWEHÐÊožçÆ@»¡^¿KüÈ•ìÛ¶áoðð7Œã¨Ò4¥Ê,|À.8V8Ôƒ+L J@Y–ï^®·§J ÐñPbŒ½ÀP€K)fƒZ`D¸ÿýß±R¯m–APV¥wIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample18.png000077500000000000000000000006631375753423500271030ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+UIDATXGí—˃0†Íž ŽÐ åp¤Ž”]@gpËú쬗Øó@±ÐJûI£yl~ÙÌ#ÅÃbnäËýÞ†XÀ¶m¦m[SEÔ0·,‹óV€+ X×õÑ4 ®IdðçÙ­æaÔu}eeYŠE°Λ÷}ïf~˜¦éÍ"$püá¦g!xæ w=¿„a^þ’S w _;úû¾ÿZÇA&"„—‡p{C³îã‰ùBN ¦½IÃJûÝøˆüF\l§é‹o˜Ïv’,ÉÁz¤DHƒ÷°hD \Ãg‘€˜˜sŽç8Ô$„¸èÉÒUUeŽãxŽmô›ŸãY:¢qÝȼ„¤ÈÖJÓñßé sñ/ ‹UIF¤@±éºN\НTDrÖ×ö«¥Ƶr¤€°¸b’>’pµKX@_E[еÜü÷ܘoŠ‹ó®&P¯oIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample19.png000077500000000000000000000007631375753423500271050ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+•IDATXGå—1vƒ0 †¡##Ùà…1#Gà6ŽG⌔?•Ç•-™G›¡ß{zqlÙú‘±â¤ûAòF>èómœ°,KRUÕÃÆq¤Þ` ´LÓ´—e‰-c cð‰A0Ïs0¨kY–íÃ0Ðl¯mຮÙþ¾ïi¥0^EQ° 7M³oÛF^OÐöC&4ÛÁ @ íÅ`mÛÒ¨C`3m V€ýôxâî÷û÷\˜”V€½—îîÖIYëÀ±µt¬ëJ­/ŽŒPË yÝÆbÀɱçj泿išRë±µdn·Û Hó/û-@ivƒ«@\ÐmLs–‘ú<Ï_æ“`=ܳì¡©–¬‡[Õb Ëþ.áõ8#ÂTK»O"è¡á–i{LâW®d1Çøò+Žc —gÀ-Fš·ïµ WÀ# ¬—)0šK&ƹb¤¹ÀV€½ W ¥ ¨ XÜùGÀ®ë‚a1Áw£b*¡ï¢ª!ø¦H"bŸ–#(Àà ¹"°á¿ÿ;N’Oü»ÿ¾6úIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample20.png000077500000000000000000000007571375753423500271000ustar00rootroot00000000000000‰PNG  IHDR szzôgAMA± üa pHYsÄÄ•+‘IDATXGí—;r„0 †M*è(¡ƒSÐr JJnAÉ ƒ[À‘¸tÄÊÊ;Æ/ä%™dòÍhÖ°2ú­Á²ûA>ð×ɲ,,ÏsÁÉàÞ0 èõ"ó<Y–A†H¾ã8âlV<Žcc —…aè%Â(À¼iô8ŽmÛŽº®50FI’œ(¶ÑuÝiˆ   €ÕË¢¨"(YШ«÷V.æR² mÃu]qÄ_=ŽèðwGŒíûŽ#;Î:PŽèÈ   UÂ(ŠžÊy Û¿ÆT @É(×Ð2ж-Ž)œ¦ ¯n2 ¢¾H^…ç »ÂèaÚÓW"àµlS¶°U¢* ô}L…Qpz™Dø…K/UU®)м8®ÃÃÿ€|ŸÂÛ;"¹PMêˆîä_Àßݳ/oÝišžŽãoÛpbÂ7ÂKÍ dÀô†eYZ!×7&*VjoH5¹*R° {ŠùXP!Ÿ¶ÝÄïø:¾Æ>v§&)&…´IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample21.png000066400000000000000000000004431375753423500270660ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá(Tä°IDATXÃíWI!Âÿ¿Ì\'Æ(ŒÉDoF…–¥DRUm—X/Ñô á ˆãÑ/F£oØkHU·,= Ì5Ð;}ï#‘ZF 7¸cŒ!gµSWN€ä7-^-€|©Îì˜K$M²*¾‘áìšàª°=Þ†&)¶‚ˆ¤‡3ÙD¢Åíðº.€ @<²êóÔqìˆ%Ó•\«*–LCÏ;±Ëdò1ùM>%^IWK%kIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample22.png000066400000000000000000000004371375753423500270720ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá;Ð}娬IDATXÃíWIÀ Âÿ¿L¯HÔ¦zlX†a-©ª¶Ûæ'¨  e"dJ–sKÄYΣº1ÐG6ð€eØ¢ÔúæwAU·òNçGÌ €³úù¼`­|Äp„)©Œn:+N…a Tƒ€RàQ² î$üßQÚRe'H¦±È JYFDž’îÿÏAФNªhFë†g Xz]A¢È zé.øÔ zÆC]‹ªIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample23.png000066400000000000000000000004701375753423500270700ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá ï¿ä5ÅIDATXÃí—Ë€ E“áÿÙV5M#qÁK¶È5ƒò²õÞû¶ð("ÔZƒŒeb–óC6"ïDeô4bdtÅYÈS”„¨sOÑ‘ªä¢%aÄù]yÙŸïÌf9å*!¤¢¹LX™ïAd õ©¤FÙ7!Õ È†Qe'TTð aEuÈP¦áÌÓXùó·âà5€HÈJçffv»ì.IÇÖ€¶”Z™´–3¦úláqÌžžŠô@f¦¥VE†ža²WbK°DcIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample24.png000066400000000000000000000004521375753423500270710ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEጹˆì·IDATXÃíW[À †û_™}-Y jyÅlÑ_J- $"rm\ŒÑÒÆ“ gÖlQ0mæÌÜ œ=‡ûìFöD´dÖÀÌѳça¬Eƒ÷vV!¶ e§3P!>@¤Ò@A¤‰P»÷U_ð2Å3ñiN³¯¤í¬¸ -@¬ ¹Êñ¶>pÿFŸb ÏéœõÂõΈ”q¬í£Óü1y;³´m®Vyè=` Xò5C€D&åÇ7~ŽU]cUªIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/digits/Digit_9_Sample25.png000066400000000000000000000004261375753423500270730ustar00rootroot00000000000000‰PNG  IHDR szzôbKGDÿÿÿ ½§“ pHYsÄÄ•+tIMEá"­ |Y£IDATXÃå—QÀ C…pÿ+³ßÅd´ŒàüvZ´f¤ª: â%‘ÍDäÚ*È‹çý!Œ¾<µâ±©>Ã0©.ðá]ìísà|Öô!HŒÂ¹*P,ëÍ£Ip•ÿC-ˆŠ€?ÇOí@P’¬Êþ„§œÿXsÕø_]p?È3ý)Q¼[±GxÊÁ§v‹‘©§ªáïUIÛ(¾J™@Tj‘‰5IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/000077500000000000000000000000001375753423500236305ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_A_Sample01.png000077500000000000000000000002361375753423500275110ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEße«ÞŸ=IDATÓcüÿÿ? 022200 ‹0¡É!3Òp}­pÝXÒh.B6ŸÓi$FdQ$ ; nUÔ3IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_B_Sample01.png000077500000000000000000000002351375753423500275110ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEß ]ê FÑ2È"£õ}Þ‘nIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_K_Sample01.png000077500000000000000000000002411375753423500275170ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEß6ŽÈ5D@IDATÓ}ÎI Áÿÿ9,)‰K®$€VX‘”ôDDk|šO›]¸v8×ÜÞÈëæj£íõí³ ²˜!ë»IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_N_Sample01.png000077500000000000000000000002511375753423500275230ustar00rootroot00000000000000‰PNG  IHDR PXêsRGB®ÎégAMA± üa pHYsÃÃÇo¨d>IDAT(Scüÿÿ?nÀÄŒ`áC\$ h* ! ˜*P¤1BâF4ˆÖ ˜¢PB‰~D 4wðzIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_O_Sample01.png000077500000000000000000000002401375753423500275220ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEß.¯’Ï?IDATÓ­10ÿÿg;4%V“Nu!æPf€$ÎøÓ»¤ƒ{o2æÃšžóË6mm¡ ÒŠ0&m• ˜#ÿ…FÍ¿IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_P_Sample01.png000077500000000000000000000002271375753423500275300ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEß 8öp56IDATÓcüÿÿ?###*€ˆ31à ,˜: éX0 D8uC,Ân7aÝÔŒãD IEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_Q_Sample01.png000077500000000000000000000002411375753423500275250ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEß"㣷‚@IDATÓ­1 ¯üÿÏ8Ô$ºÉTz@”™ É¢ :®{åD šõ˾Ö/ì8=öN4ât¤×[Ü.ÊCæ£WIEND®B`‚pyclustering-0.10.1.2/pyclustering/samples/images/symbols/Symbol_R_Sample01.png000077500000000000000000000002351375753423500275310ustar00rootroot00000000000000‰PNG  IHDR PXê pHYsÃÃÇo¨dtIMEß#¿¶U= eps: raise AssertionError("Expected: '" + str(argument1) + "', Actual: '" + str(argument2) + "' (eps: '" + str(eps) + "')") @staticmethod def gt(argument1, argument2): if not (argument1 > argument2): raise AssertionError("Expected: '" + str(argument1) + "' > '" + str(argument2) + "', Actual: '" + str(argument1) + "' vs '" + str(argument2) + "'") @staticmethod def ge(argument1, argument2): if not (argument1 >= argument2): raise AssertionError("Expected: '" + str(argument1) + "' >= '" + str(argument2) + "', Actual: '" + str(argument1) + "' vs '" + str(argument2) + "'") @staticmethod def lt(argument1, argument2): if not (argument1 < argument2): raise AssertionError("Expected: '" + str(argument1) + "' < '" + str(argument2) + "', Actual: '" + str(argument1) + "' vs '" + str(argument2) + "'") @staticmethod def le(argument1, argument2): if not (argument1 <= argument2): raise AssertionError("Expected: '" + str(argument1) + "' <= '" + str(argument2) + "', Actual: '" + str(argument1) + "' vs '" + str(argument2) + "'") @staticmethod def true(argument1, **kwargs): message = kwargs.get('message', None) error_message = "Expected: 'True', Actual: '%s'" % str(argument1) if message: error_message = "%s, Info: '%s'" % (error_message, message) if not argument1: raise AssertionError(error_message) @staticmethod def false(argument1, **kwargs): message = kwargs.get('message', None) error_message = "Expected: 'False', Actual: '%s'" % str(argument1) if message: error_message = "%s, Info: '%s'" % (error_message, message) if argument1: raise AssertionError(error_message) @staticmethod def fail(message=None): if message is None: raise AssertionError("Failure") else: raise AssertionError("Failure: '" + message + "'") @staticmethod def exception(expected_exception, callable_object, *args, **kwargs): try: callable_object(*args, **kwargs) except expected_exception: return except Exception as actual_exception: raise AssertionError("Expected: '%s', Actual: '%s'" % (expected_exception.__name__, actual_exception.__class__.__name__)) raise AssertionError("Expected: '%s', Actual: 'None'" % expected_exception.__name__) pyclustering-0.10.1.2/pyclustering/tests/suite_holder.py000077500000000000000000000026751375753423500234460ustar00rootroot00000000000000"""! @brief Test suite storage @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import sys import time import unittest class suite_holder: def __init__(self): self.__suite = unittest.TestSuite() def get_suite(self): return self.__suite def run(self, rerun=2): print(self.__suite) result = unittest.TextTestRunner(stream=sys.stdout, verbosity=3).run(self.__suite) if result.wasSuccessful() is True: return result if len(result.errors) > 0: return result # no need to restart in case of errors for attempt in range(rerun): time.sleep(1) # sleep 1 second to change current time for random seed. print("\n======================================================================") print("Rerun failed tests (attempt: %d)." % (attempt + 1)) print("----------------------------------------------------------------------") failure_suite = unittest.TestSuite() for failure in result.failures: failure_suite.addTest(failure[0]) result = unittest.TextTestRunner(stream=sys.stdout, verbosity=3).run(failure_suite) if result.wasSuccessful() is True: return result return result @staticmethod def fill_suite(test_suite): pass;pyclustering-0.10.1.2/pyclustering/tests/tests_runner.py000077500000000000000000000052101375753423500234770ustar00rootroot00000000000000"""! @brief Test runner for unit and integration tests in the project. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import enum import sys import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.suite_holder import suite_holder from pyclustering import __PYCLUSTERING_ROOT_DIRECTORY__ class pyclustering_integration_tests(suite_holder): def __init__(self): super().__init__() pyclustering_integration_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(integration_suite): integration_suite.addTests(unittest.TestLoader().discover(__PYCLUSTERING_ROOT_DIRECTORY__, "it_*.py")) class pyclustering_unit_tests(suite_holder): def __init__(self): super().__init__() pyclustering_unit_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(unit_suite): unit_suite.addTests(unittest.TestLoader().discover(__PYCLUSTERING_ROOT_DIRECTORY__, "ut_*.py")) class pyclustering_tests(suite_holder): def __init__(self): super().__init__() pyclustering_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(pyclustering_suite): pyclustering_integration_tests.fill_suite(pyclustering_suite) pyclustering_unit_tests.fill_suite(pyclustering_suite) class exit_code(enum.IntEnum): success = 0, error_unknown_type_test = -1, error_too_many_arguments = -2, error_failure = -3 class tests_runner: @staticmethod def run(): result = None return_code = exit_code.success if len(sys.argv) == 1: result = pyclustering_tests().run() elif len(sys.argv) == 2: if sys.argv[1] == "--integration": result = pyclustering_integration_tests().run() elif sys.argv[1] == "--unit": result = pyclustering_unit_tests().run() elif sys.argv[1] == "test": result = pyclustering_tests().run() else: print("Unknown type of test is specified '" + str(sys.argv[1]) + "'.") return_code = exit_code.error_unknown_type_test else: print("Too many arguments '" + str(len(sys.argv)) + "' is used.") return_code = exit_code.error_too_many_arguments # Get execution result if result is not None: if result.wasSuccessful() is False: return_code = exit_code.error_failure exit(return_code) pyclustering-0.10.1.2/pyclustering/utils/000077500000000000000000000000001375753423500203675ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/utils/__init__.py000077500000000000000000001406171375753423500225140ustar00rootroot00000000000000"""! @brief Utils that are used by modules of pyclustering. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import time import numpy from numpy import array from PIL import Image import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from sys import platform as _platform from pyclustering.utils.metric import distance_metric, type_metric ## The number \f$pi\f$ is a mathematical constant, the ratio of a circle's circumference to its diameter. pi = 3.1415926535 def read_sample(filename): """! @brief Returns data sample from simple text file. @details This function should be used for text file with following format: @code point_1_coord_1 point_1_coord_2 ... point_1_coord_n point_2_coord_1 point_2_coord_2 ... point_2_coord_n ... ... @endcode @param[in] filename (string): Path to file with data. @return (list) Points where each point represented by list of coordinates. """ file = open(filename, 'r') sample = [[float(val) for val in line.split()] for line in file if len(line.strip()) > 0] file.close() return sample def calculate_distance_matrix(sample, metric=distance_metric(type_metric.EUCLIDEAN)): """! @brief Calculates distance matrix for data sample (sequence of points) using specified metric (by default Euclidean distance). @param[in] sample (array_like): Data points that are used for distance calculation. @param[in] metric (distance_metric): Metric that is used for distance calculation between two points. @return (list) Matrix distance between data points. """ amount_rows = len(sample) return [[metric(sample[i], sample[j]) for j in range(amount_rows)] for i in range(amount_rows)] def read_image(filename): """! @brief Returns image as N-dimension (depends on the input image) matrix, where one element of list describes pixel. @param[in] filename (string): Path to image. @return (list) Pixels where each pixel described by list of RGB-values. """ with Image.open(filename) as image_source: data = [list(pixel) for pixel in image_source.getdata()] return data def rgb2gray(image_rgb_array): """! @brief Returns image as 1-dimension (gray colored) matrix, where one element of list describes pixel. @details Luma coding is used for transformation and that is calculated directly from gamma-compressed primary intensities as a weighted sum: \f[Y = 0.2989R + 0.587G + 0.114B\f] @param[in] image_rgb_array (list): Image represented by RGB list. @return (list) Image as gray colored matrix, where one element of list describes pixel. @code colored_image = read_image(file_name); gray_image = rgb2gray(colored_image); @endcode @see read_image() """ image_gray_array = [0.0] * len(image_rgb_array) for index in range(0, len(image_rgb_array), 1): image_gray_array[index] = float(image_rgb_array[index][0]) * 0.2989 \ + float(image_rgb_array[index][1]) * 0.5870 \ + float(image_rgb_array[index][2]) * 0.1140 return image_gray_array def stretch_pattern(image_source): """! @brief Returns stretched content as 1-dimension (gray colored) matrix with size of input image. @param[in] image_source (Image): PIL Image instance. @return (list, Image) Stretched image as gray colored matrix and source image. """ wsize, hsize = image_source.size # Crop digit exactly (ws, hs, we, he) = gray_pattern_borders(image_source) image_source = image_source.crop((ws, hs, we, he)) # Stretch it to initial sizes image_source = image_source.resize((wsize, hsize), Image.ANTIALIAS) # Transform image to simple array data = [pixel for pixel in image_source.getdata()] image_pattern = rgb2gray(data) return image_pattern, image_source def gray_pattern_borders(image): """! @brief Returns coordinates of gray image content on the input image. @param[in] image (Image): PIL Image instance that is processed. @return (tuple) Returns coordinates of gray image content as (width_start, height_start, width_end, height_end). """ width, height = image.size width_start = width width_end = 0 height_start = height height_end = 0 row, col = 0, 0 for pixel in image.getdata(): value = float(pixel[0]) * 0.2989 + float(pixel[1]) * 0.5870 + float(pixel[2]) * 0.1140 if value < 128: if width_end < col: width_end = col if height_end < row: height_end = row if width_start > col: width_start = col if height_start > row: height_start = row col += 1 if col >= width: col = 0 row += 1 return width_start, height_start, width_end + 1, height_end + 1 def average_neighbor_distance(points, num_neigh): """! @brief Returns average distance for establish links between specified number of nearest neighbors. @param[in] points (list): Input data, list of points where each point represented by list. @param[in] num_neigh (uint): Number of neighbors that should be used for distance calculation. @return (double) Average distance for establish links between 'num_neigh' in data set 'points'. """ if num_neigh > len(points) - 1: raise NameError('Impossible to calculate average distance to neighbors ' 'when number of object is less than number of neighbors.') dist_matrix = [[0.0 for i in range(len(points))] for _ in range(len(points))] for i in range(0, len(points), 1): for j in range(i + 1, len(points), 1): distance = euclidean_distance(points[i], points[j]) dist_matrix[i][j] = distance dist_matrix[j][i] = distance dist_matrix[i] = sorted(dist_matrix[i]) total_distance = 0 for i in range(0, len(points), 1): # start from 0 - first element is distance to itself. for j in range(0, num_neigh, 1): total_distance += dist_matrix[i][j + 1] return total_distance / (num_neigh * len(points)) def medoid(data, indexes=None, **kwargs): """! @brief Calculate medoid for input points. @param[in] data (list): Set of points for that median should be calculated. @param[in] indexes (list): Indexes of input set of points that will be taken into account during median calculation. @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'metric', 'data_type'). Keyword Args:
- metric (distance_metric): Metric that is used for distance calculation between two points. - data_type (string): Data type of input sample 'data' (available values: 'points', 'distance_matrix'). @return (uint) index of point in input set that corresponds to median. """ index_median = None distance = float('Inf') metric = kwargs.get('metric', type_metric.EUCLIDEAN_SQUARE) data_type = kwargs.get('data_type', 'points') if data_type == 'points': calculator = lambda index1, index2: metric(data[index1], data[index2]) elif data_type == 'distance_matrix': if isinstance(data, numpy.matrix): calculator = lambda index1, index2: data.item(index1, index2) else: calculator = lambda index1, index2: data[index1][index2] else: raise TypeError("Unknown type of data is specified '%s'." % data_type) if indexes is None: range_points = range(len(data)) else: range_points = indexes for index_candidate in range_points: distance_candidate = 0.0 for index in range_points: distance_candidate += calculator(index_candidate, index) if distance_candidate < distance: distance = distance_candidate index_median = index_candidate return index_median def euclidean_distance(a, b): """! @brief Calculate Euclidean distance between vector a and b. @details The Euclidean between vectors (points) a and b is calculated by following formula: \f[ dist(a, b) = \sqrt{ \sum_{i=0}^{N}(b_{i} - a_{i})^{2}) }; \f] Where N is a length of each vector. @param[in] a (list): The first vector. @param[in] b (list): The second vector. @return (double) Euclidian distance between two vectors. @note This function for calculation is faster then standard function in ~100 times! """ distance = euclidean_distance_square(a, b); return distance**(0.5); def euclidean_distance_square(a, b): """! @brief Calculate square Euclidian distance between vector a and b. @param[in] a (list): The first vector. @param[in] b (list): The second vector. @return (double) Square Euclidian distance between two vectors. """ if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ): return (a - b)**2.0; distance = 0.0; for i in range(0, len(a)): distance += (a[i] - b[i])**2.0; return distance; def manhattan_distance(a, b): """! @brief Calculate Manhattan distance between vector a and b. @param[in] a (list): The first cluster. @param[in] b (list): The second cluster. @return (double) Manhattan distance between two vectors. """ if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ): return abs(a - b); distance = 0.0; dimension = len(a); for i in range(0, dimension): distance += abs(a[i] - b[i]); return distance; def average_inter_cluster_distance(cluster1, cluster2, data = None): """! @brief Calculates average inter-cluster distance between two clusters. @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified), or by list of indexes of points from the data (represented by list of points), in this case data should be specified. @param[in] cluster1 (list): The first cluster where each element can represent index from the data or object itself. @param[in] cluster2 (list): The second cluster where each element can represent index from the data or object itself. @param[in] data (list): If specified than elements of clusters will be used as indexes, otherwise elements of cluster will be considered as points. @return (double) Average inter-cluster distance between two clusters. """ distance = 0.0; if (data is None): for i in range(len(cluster1)): for j in range(len(cluster2)): distance += euclidean_distance_square(cluster1[i], cluster2[j]); else: for i in range(len(cluster1)): for j in range(len(cluster2)): distance += euclidean_distance_square(data[ cluster1[i]], data[ cluster2[j]]); distance /= float(len(cluster1) * len(cluster2)); return distance ** 0.5; def average_intra_cluster_distance(cluster1, cluster2, data=None): """! @brief Calculates average intra-cluster distance between two clusters. @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified), or by list of indexes of points from the data (represented by list of points), in this case data should be specified. @param[in] cluster1 (list): The first cluster. @param[in] cluster2 (list): The second cluster. @param[in] data (list): If specified than elements of clusters will be used as indexes, otherwise elements of cluster will be considered as points. @return (double) Average intra-cluster distance between two clusters. """ distance = 0.0 for i in range(len(cluster1) + len(cluster2)): for j in range(len(cluster1) + len(cluster2)): if data is None: # the first point if i < len(cluster1): first_point = cluster1[i] else: first_point = cluster2[i - len(cluster1)] # the second point if j < len(cluster1): second_point = cluster1[j] else: second_point = cluster2[j - len(cluster1)] else: # the first point if i < len(cluster1): first_point = data[cluster1[i]] else: first_point = data[cluster2[i - len(cluster1)]] if j < len(cluster1): second_point = data[cluster1[j]] else: second_point = data[cluster2[j - len(cluster1)]] distance += euclidean_distance_square(first_point, second_point) distance /= float((len(cluster1) + len(cluster2)) * (len(cluster1) + len(cluster2) - 1.0)) return distance ** 0.5 def variance_increase_distance(cluster1, cluster2, data = None): """! @brief Calculates variance increase distance between two clusters. @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified), or by list of indexes of points from the data (represented by list of points), in this case data should be specified. @param[in] cluster1 (list): The first cluster. @param[in] cluster2 (list): The second cluster. @param[in] data (list): If specified than elements of clusters will be used as indexes, otherwise elements of cluster will be considered as points. @return (double) Average variance increase distance between two clusters. """ # calculate local sum if data is None: member_cluster1 = [0.0] * len(cluster1[0]) member_cluster2 = [0.0] * len(cluster2[0]) else: member_cluster1 = [0.0] * len(data[0]) member_cluster2 = [0.0] * len(data[0]) for i in range(len(cluster1)): if data is None: member_cluster1 = list_math_addition(member_cluster1, cluster1[i]) else: member_cluster1 = list_math_addition(member_cluster1, data[ cluster1[i] ]) for j in range(len(cluster2)): if data is None: member_cluster2 = list_math_addition(member_cluster2, cluster2[j]) else: member_cluster2 = list_math_addition(member_cluster2, data[ cluster2[j] ]) member_cluster_general = list_math_addition(member_cluster1, member_cluster2) member_cluster_general = list_math_division_number(member_cluster_general, len(cluster1) + len(cluster2)) member_cluster1 = list_math_division_number(member_cluster1, len(cluster1)) member_cluster2 = list_math_division_number(member_cluster2, len(cluster2)) # calculate global sum distance_general = 0.0 distance_cluster1 = 0.0 distance_cluster2 = 0.0 for i in range(len(cluster1)): if data is None: distance_cluster1 += euclidean_distance_square(cluster1[i], member_cluster1) distance_general += euclidean_distance_square(cluster1[i], member_cluster_general) else: distance_cluster1 += euclidean_distance_square(data[ cluster1[i]], member_cluster1) distance_general += euclidean_distance_square(data[ cluster1[i]], member_cluster_general) for j in range(len(cluster2)): if data is None: distance_cluster2 += euclidean_distance_square(cluster2[j], member_cluster2) distance_general += euclidean_distance_square(cluster2[j], member_cluster_general) else: distance_cluster2 += euclidean_distance_square(data[ cluster2[j]], member_cluster2) distance_general += euclidean_distance_square(data[ cluster2[j]], member_cluster_general) return distance_general - distance_cluster1 - distance_cluster2 def calculate_ellipse_description(covariance, scale = 2.0): """! @brief Calculates description of ellipse using covariance matrix. @param[in] covariance (numpy.array): Covariance matrix for which ellipse area should be calculated. @param[in] scale (float): Scale of the ellipse. @return (float, float, float) Return ellipse description: angle, width, height. """ eigh_values, eigh_vectors = numpy.linalg.eigh(covariance) order = eigh_values.argsort()[::-1] values, vectors = eigh_values[order], eigh_vectors[order] angle = numpy.degrees(numpy.arctan2(*vectors[:,0][::-1])) if 0.0 in values: return 0, 0, 0 width, height = 2.0 * scale * numpy.sqrt(values) return angle, width, height def data_corners(data, data_filter = None): """! @brief Finds maximum and minimum corner in each dimension of the specified data. @param[in] data (list): List of points that should be analysed. @param[in] data_filter (list): List of indexes of the data that should be analysed, if it is 'None' then whole 'data' is analysed to obtain corners. @return (list) Tuple of two points that corresponds to minimum and maximum corner (min_corner, max_corner). """ dimensions = len(data[0]) bypass = data_filter if bypass is None: bypass = range(len(data)) maximum_corner = list(data[bypass[0]][:]) minimum_corner = list(data[bypass[0]][:]) for index_point in bypass: for index_dimension in range(dimensions): if data[index_point][index_dimension] > maximum_corner[index_dimension]: maximum_corner[index_dimension] = data[index_point][index_dimension] if data[index_point][index_dimension] < minimum_corner[index_dimension]: minimum_corner[index_dimension] = data[index_point][index_dimension] return minimum_corner, maximum_corner def norm_vector(vector): """! @brief Calculates norm of an input vector that is known as a vector length. @param[in] vector (list): The input vector whose length is calculated. @return (double) vector norm known as vector length. """ length = 0.0 for component in vector: length += component * component length = length ** 0.5 return length def heaviside(value): """! @brief Calculates Heaviside function that represents step function. @details If input value is greater than 0 then returns 1, otherwise returns 0. @param[in] value (double): Argument of Heaviside function. @return (double) Value of Heaviside function. """ if (value > 0.0): return 1.0; return 0.0; def timedcall(executable_function, *args, **kwargs): """! @brief Executes specified method or function with measuring of execution time. @param[in] executable_function (pointer): Pointer to a function or method that should be called. @param[in] *args: Arguments of the called function or method. @param[in] **kwargs: Arbitrary keyword arguments of the called function or method. @return (tuple) Execution time and result of execution of function or method (execution_time, result_execution). """ time_start = time.perf_counter() result = executable_function(*args, **kwargs) time_end = time.perf_counter() return time_end - time_start, result def extract_number_oscillations(osc_dyn, index = 0, amplitude_threshold = 1.0): """! @brief Extracts number of oscillations of specified oscillator. @param[in] osc_dyn (list): Dynamic of oscillators. @param[in] index (uint): Index of oscillator in dynamic. @param[in] amplitude_threshold (double): Amplitude threshold when oscillation is taken into account, for example, when oscillator amplitude is greater than threshold then oscillation is incremented. @return (uint) Number of oscillations of specified oscillator. """ number_oscillations = 0; waiting_differential = False; threshold_passed = False; high_level_trigger = True if (osc_dyn[0][index] > amplitude_threshold) else False; for values in osc_dyn: if ( (values[index] >= amplitude_threshold) and (high_level_trigger is False) ): high_level_trigger = True; threshold_passed = True; elif ( (values[index] < amplitude_threshold) and (high_level_trigger is True) ): high_level_trigger = False; threshold_passed = True; if (threshold_passed is True): threshold_passed = False; if (waiting_differential is True and high_level_trigger is False): number_oscillations += 1; waiting_differential = False; else: waiting_differential = True; return number_oscillations; def allocate_sync_ensembles(dynamic, tolerance = 0.1, threshold = 1.0, ignore = None): """! @brief Allocate clusters in line with ensembles of synchronous oscillators where each synchronous ensemble corresponds to only one cluster. @param[in] dynamic (dynamic): Dynamic of each oscillator. @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators. @param[in] threshold (double): Amlitude trigger when spike is taken into account. @param[in] ignore (bool): Set of indexes that shouldn't be taken into account. @return (list) Grours (lists) of indexes of synchronous oscillators, for example, [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ]. """ descriptors = [ [] for _ in range(len(dynamic[0])) ]; # Check from the end for obtaining result for index_dyn in range(0, len(dynamic[0]), 1): if ((ignore is not None) and (index_dyn in ignore)): continue; time_stop_simulation = len(dynamic) - 1; active_state = False; if (dynamic[time_stop_simulation][index_dyn] > threshold): active_state = True; # if active state is detected, it means we don't have whole oscillatory period for the considered oscillator, should be skipped. if (active_state is True): while ( (dynamic[time_stop_simulation][index_dyn] > threshold) and (time_stop_simulation > 0) ): time_stop_simulation -= 1; # if there are no any oscillation than let's consider it like noise if (time_stop_simulation == 0): continue; # reset active_state = False; desc = [0, 0, 0]; # end, start, average time of oscillation for t in range(time_stop_simulation, 0, -1): if ( (dynamic[t][index_dyn] > threshold) and (active_state is False) ): desc[0] = t; active_state = True; elif ( (dynamic[t][index_dyn] < threshold) and (active_state is True) ): desc[1] = t; active_state = False; break; if (desc == [0, 0, 0]): continue; desc[2] = desc[1] + (desc[0] - desc[1]) / 2.0; descriptors[index_dyn] = desc; # Cluster allocation sync_ensembles = []; desc_sync_ensembles = []; for index_desc in range(0, len(descriptors), 1): if (descriptors[index_desc] == []): continue; if (len(sync_ensembles) == 0): desc_ensemble = descriptors[index_desc]; reducer = (desc_ensemble[0] - desc_ensemble[1]) * tolerance; desc_ensemble[0] = desc_ensemble[2] + reducer; desc_ensemble[1] = desc_ensemble[2] - reducer; desc_sync_ensembles.append(desc_ensemble); sync_ensembles.append([ index_desc ]); else: oscillator_captured = False; for index_ensemble in range(0, len(sync_ensembles), 1): if ( (desc_sync_ensembles[index_ensemble][0] > descriptors[index_desc][2]) and (desc_sync_ensembles[index_ensemble][1] < descriptors[index_desc][2])): sync_ensembles[index_ensemble].append(index_desc); oscillator_captured = True; break; if (oscillator_captured is False): desc_ensemble = descriptors[index_desc]; reducer = (desc_ensemble[0] - desc_ensemble[1]) * tolerance; desc_ensemble[0] = desc_ensemble[2] + reducer; desc_ensemble[1] = desc_ensemble[2] - reducer; desc_sync_ensembles.append(desc_ensemble); sync_ensembles.append([ index_desc ]); return sync_ensembles; def draw_clusters(data, clusters, noise = [], marker_descr = '.', hide_axes = False, axes = None, display_result = True): """! @brief Displays clusters for data in 2D or 3D. @param[in] data (list): Points that are described by coordinates represented. @param[in] clusters (list): Clusters that are represented by lists of indexes where each index corresponds to point in data. @param[in] noise (list): Points that are regarded to noise. @param[in] marker_descr (string): Marker for displaying points. @param[in] hide_axes (bool): If True - axes is not displayed. @param[in] axes (ax) Matplotlib axes where clusters should be drawn, if it is not specified (None) then new plot will be created. @param[in] display_result (bool): If specified then matplotlib axes will be used for drawing and plot will not be shown. @return (ax) Matplotlib axes where drawn clusters are presented. """ # Get dimension dimension = 0; if ( (data is not None) and (clusters is not None) ): dimension = len(data[0]); elif ( (data is None) and (clusters is not None) ): dimension = len(clusters[0][0]); else: raise NameError('Data or clusters should be specified exactly.'); "Draw clusters" colors = [ 'red', 'blue', 'darkgreen', 'brown', 'violet', 'deepskyblue', 'darkgrey', 'lightsalmon', 'deeppink', 'yellow', 'black', 'mediumspringgreen', 'orange', 'darkviolet', 'darkblue', 'silver', 'lime', 'pink', 'gold', 'bisque' ]; if (len(clusters) > len(colors)): raise NameError('Impossible to represent clusters due to number of specified colors.'); fig = plt.figure(); if (axes is None): # Check for dimensions if ((dimension) == 1 or (dimension == 2)): axes = fig.add_subplot(111); elif (dimension == 3): axes = fig.gca(projection='3d'); else: raise NameError('Drawer supports only 2d and 3d data representation'); color_index = 0; for cluster in clusters: color = colors[color_index]; for item in cluster: if (dimension == 1): if (data is None): axes.plot(item[0], 0.0, color = color, marker = marker_descr); else: axes.plot(data[item][0], 0.0, color = color, marker = marker_descr); if (dimension == 2): if (data is None): axes.plot(item[0], item[1], color = color, marker = marker_descr); else: axes.plot(data[item][0], data[item][1], color = color, marker = marker_descr); elif (dimension == 3): if (data is None): axes.scatter(item[0], item[1], item[2], c = color, marker = marker_descr); else: axes.scatter(data[item][0], data[item][1], data[item][2], c = color, marker = marker_descr); color_index += 1; for item in noise: if (dimension == 1): if (data is None): axes.plot(item[0], 0.0, 'w' + marker_descr); else: axes.plot(data[item][0], 0.0, 'w' + marker_descr); if (dimension == 2): if (data is None): axes.plot(item[0], item[1], 'w' + marker_descr); else: axes.plot(data[item][0], data[item][1], 'w' + marker_descr); elif (dimension == 3): if (data is None): axes.scatter(item[0], item[1], item[2], c = 'w', marker = marker_descr); else: axes.scatter(data[item][0], data[item][1], data[item][2], c = 'w', marker = marker_descr); axes.grid(True); if (hide_axes is True): axes.xaxis.set_ticklabels([]); axes.yaxis.set_ticklabels([]); if (dimension == 3): axes.zaxis.set_ticklabels([]); if (display_result is True): plt.show(); return axes; def draw_dynamics(t, dyn, x_title = None, y_title = None, x_lim = None, y_lim = None, x_labels = True, y_labels = True, separate = False, axes = None): """! @brief Draw dynamics of neurons (oscillators) in the network. @details It draws if matplotlib is not specified (None), othewise it should be performed manually. @param[in] t (list): Values of time (used by x axis). @param[in] dyn (list): Values of output of oscillators (used by y axis). @param[in] x_title (string): Title for Y. @param[in] y_title (string): Title for X. @param[in] x_lim (double): X limit. @param[in] y_lim (double): Y limit. @param[in] x_labels (bool): If True - shows X labels. @param[in] y_labels (bool): If True - shows Y labels. @param[in] separate (list): Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage. @param[in] axes (ax): If specified then matplotlib axes will be used for drawing and plot will not be shown. @return (ax) Axes of matplotlib. """ number_lines = 0; stage_xlim = None; if (x_lim is not None): stage_xlim = x_lim; elif (len(t) > 0): stage_xlim = [0, t[len(t) - 1]]; if ( (isinstance(separate, bool) is True) and (separate is True) ): if (isinstance(dyn[0], list) is True): number_lines = len(dyn[0]); else: number_lines = 1; elif (isinstance(separate, list) is True): number_lines = len(separate); else: number_lines = 1; dysplay_result = False; if (axes is None): dysplay_result = True; (fig, axes) = plt.subplots(number_lines, 1); # Check if we have more than one dynamic if (isinstance(dyn[0], list) is True): num_items = len(dyn[0]); for index in range(0, num_items, 1): y = [item[index] for item in dyn]; if (number_lines > 1): index_stage = -1; # Find required axes for the y if (isinstance(separate, bool) is True): index_stage = index; elif (isinstance(separate, list) is True): for index_group in range(0, len(separate), 1): if (index in separate[index_group]): index_stage = index_group; break; if (index_stage != -1): if (index_stage != number_lines - 1): axes[index_stage].get_xaxis().set_visible(False); axes[index_stage].plot(t, y, 'b-', linewidth = 0.5); set_ax_param(axes[index_stage], x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True); else: axes.plot(t, y, 'b-', linewidth = 0.5); set_ax_param(axes, x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True); else: axes.plot(t, dyn, 'b-', linewidth = 0.5); set_ax_param(axes, x_title, y_title, stage_xlim, y_lim, x_labels, y_labels, True); if (dysplay_result is True): plt.show(); return axes; def set_ax_param(ax, x_title = None, y_title = None, x_lim = None, y_lim = None, x_labels = True, y_labels = True, grid = True): """! @brief Sets parameters for matplotlib ax. @param[in] ax (Axes): Axes for which parameters should applied. @param[in] x_title (string): Title for Y. @param[in] y_title (string): Title for X. @param[in] x_lim (double): X limit. @param[in] y_lim (double): Y limit. @param[in] x_labels (bool): If True - shows X labels. @param[in] y_labels (bool): If True - shows Y labels. @param[in] grid (bool): If True - shows grid. """ from matplotlib.font_manager import FontProperties; from matplotlib import rcParams; if (_platform == "linux") or (_platform == "linux2"): rcParams['font.sans-serif'] = ['Liberation Serif']; else: rcParams['font.sans-serif'] = ['Arial']; rcParams['font.size'] = 12; surface_font = FontProperties(); if (_platform == "linux") or (_platform == "linux2"): surface_font.set_name('Liberation Serif'); else: surface_font.set_name('Arial'); surface_font.set_size('12'); if (y_title is not None): ax.set_ylabel(y_title, fontproperties = surface_font); if (x_title is not None): ax.set_xlabel(x_title, fontproperties = surface_font); if (x_lim is not None): ax.set_xlim(x_lim[0], x_lim[1]); if (y_lim is not None): ax.set_ylim(y_lim[0], y_lim[1]); if (x_labels is False): ax.xaxis.set_ticklabels([]); if (y_labels is False): ax.yaxis.set_ticklabels([]); ax.grid(grid); def draw_dynamics_set(dynamics, xtitle = None, ytitle = None, xlim = None, ylim = None, xlabels = False, ylabels = False): """! @brief Draw lists of dynamics of neurons (oscillators) in the network. @param[in] dynamics (list): List of network outputs that are represented by values of output of oscillators (used by y axis). @param[in] xtitle (string): Title for Y. @param[in] ytitle (string): Title for X. @param[in] xlim (double): X limit. @param[in] ylim (double): Y limit. @param[in] xlabels (bool): If True - shows X labels. @param[in] ylabels (bool): If True - shows Y labels. """ # Calculate edge for confortable representation. number_dynamics = len(dynamics); if (number_dynamics == 1): draw_dynamics(dynamics[0][0], dynamics[0][1], xtitle, ytitle, xlim, ylim, xlabels, ylabels); return; number_cols = int(numpy.ceil(number_dynamics ** 0.5)); number_rows = int(numpy.ceil(number_dynamics / number_cols)); real_index = 0, 0; double_indexer = True; if ( (number_cols == 1) or (number_rows == 1) ): real_index = 0; double_indexer = False; (_, axarr) = plt.subplots(number_rows, number_cols); #plt.setp([ax for ax in axarr], visible = False); for dynamic in dynamics: axarr[real_index] = draw_dynamics(dynamic[0], dynamic[1], xtitle, ytitle, xlim, ylim, xlabels, ylabels, axes = axarr[real_index]); #plt.setp(axarr[real_index], visible = True); if (double_indexer is True): real_index = real_index[0], real_index[1] + 1; if (real_index[1] >= number_cols): real_index = real_index[0] + 1, 0; else: real_index += 1; plt.show(); def draw_image_color_segments(source, clusters, hide_axes = True): """! @brief Shows image segments using colored image. @details Each color on result image represents allocated segment. The first image is initial and other is result of segmentation. @param[in] source (string): Path to image. @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster consists of indexes of pixel from source image. @param[in] hide_axes (bool): If True then axes will not be displayed. """ image_source = Image.open(source); image_size = image_source.size; (fig, axarr) = plt.subplots(1, 2); plt.setp([ax for ax in axarr], visible = False); available_colors = [ (0, 162, 232), (34, 177, 76), (237, 28, 36), (255, 242, 0), (0, 0, 0), (237, 28, 36), (255, 174, 201), (127, 127, 127), (185, 122, 87), (200, 191, 231), (136, 0, 21), (255, 127, 39), (63, 72, 204), (195, 195, 195), (255, 201, 14), (239, 228, 176), (181, 230, 29), (153, 217, 234), (112, 146, 180) ]; image_color_segments = [(255, 255, 255)] * (image_size[0] * image_size[1]); for index_segment in range(len(clusters)): for index_pixel in clusters[index_segment]: image_color_segments[index_pixel] = available_colors[index_segment]; stage = array(image_color_segments, numpy.uint8); stage = numpy.reshape(stage, (image_size[1], image_size[0]) + ((3),)); # ((3),) it's size of RGB - third dimension. image_cluster = Image.fromarray(stage, 'RGB'); axarr[0].imshow(image_source, interpolation = 'none'); axarr[1].imshow(image_cluster, interpolation = 'none'); for i in range(2): plt.setp(axarr[i], visible = True); if (hide_axes is True): axarr[i].xaxis.set_ticklabels([]); axarr[i].yaxis.set_ticklabels([]); axarr[i].xaxis.set_ticks_position('none'); axarr[i].yaxis.set_ticks_position('none'); plt.show(); def draw_image_mask_segments(source, clusters, hide_axes = True): """! @brief Shows image segments using black masks. @details Each black mask of allocated segment is presented on separate plot. The first image is initial and others are black masks of segments. @param[in] source (string): Path to image. @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster consists of indexes of pixel from source image. @param[in] hide_axes (bool): If True then axes will not be displayed. """ if len(clusters) == 0: print("Warning: Nothing to draw - list of clusters is empty.") return image_source = Image.open(source) image_size = image_source.size # Calculate edge for confortable representation. number_clusters = len(clusters) + 1 # show with the source image number_cols = int(numpy.ceil(number_clusters ** 0.5)) number_rows = int(numpy.ceil(number_clusters / number_cols)) real_index = 0, 0 double_indexer = True if (number_cols == 1) or (number_rows == 1): real_index = 0 double_indexer = False (fig, axarr) = plt.subplots(number_rows, number_cols) plt.setp([ax for ax in axarr], visible=False) axarr[real_index].imshow(image_source, interpolation='none') plt.setp(axarr[real_index], visible=True) if hide_axes is True: axarr[real_index].xaxis.set_ticklabels([]) axarr[real_index].yaxis.set_ticklabels([]) axarr[real_index].xaxis.set_ticks_position('none') axarr[real_index].yaxis.set_ticks_position('none') if double_indexer is True: real_index = 0, 1 else: real_index += 1 for cluster in clusters: stage_cluster = [(255, 255, 255)] * (image_size[0] * image_size[1]) for index in cluster: stage_cluster[index] = (0, 0, 0) stage = array(stage_cluster, numpy.uint8) stage = numpy.reshape(stage, (image_size[1], image_size[0]) + ((3),)) # ((3),) it's size of RGB - 3rd dimension. image_cluster = Image.fromarray(stage, 'RGB') axarr[real_index].imshow(image_cluster, interpolation = 'none') plt.setp(axarr[real_index], visible = True) if hide_axes is True: axarr[real_index].xaxis.set_ticklabels([]) axarr[real_index].yaxis.set_ticklabels([]) axarr[real_index].xaxis.set_ticks_position('none') axarr[real_index].yaxis.set_ticks_position('none') if double_indexer is True: real_index = real_index[0], real_index[1] + 1 if real_index[1] >= number_cols: real_index = real_index[0] + 1, 0 else: real_index += 1 plt.show() def find_left_element(sorted_data, right, comparator): """! @brief Returns the element's index at the left side from the right border with the same value as the last element in the range `sorted_data`. @details The element at the right is considered as target to search. `sorted_data` must be sorted collection. The complexity of the algorithm is `O(log(n))`. The algorithm is based on the binary search algorithm. @param[in] sorted_data: input data to find the element. @param[in] right: the index of the right element from that search is started. @param[in] comparator: comparison function object which returns `True` if the first argument is less than the second. @return The element's index at the left side from the right border with the same value as the last element in the range `sorted_data`. """ if len(sorted_data) == 0: raise ValueError("Input data is empty.") left = 0 middle = (right - left) // 2 target = sorted_data[right] while left < right: if comparator(sorted_data[middle], target): left = middle + 1 else: right = middle offset = (right - left) // 2 middle = left + offset return left def linear_sum(list_vector): """! @brief Calculates linear sum of vector that is represented by list, each element can be represented by list - multidimensional elements. @param[in] list_vector (list): Input vector. @return (list|double) Linear sum of vector that can be represented by list in case of multidimensional elements. """ dimension = 1 linear_sum = 0.0 list_representation = (type(list_vector[0]) == list) if list_representation is True: dimension = len(list_vector[0]) linear_sum = [0] * dimension for index_element in range(0, len(list_vector)): if list_representation is True: for index_dimension in range(0, dimension): linear_sum[index_dimension] += list_vector[index_element][index_dimension] else: linear_sum += list_vector[index_element] return linear_sum def square_sum(list_vector): """! @brief Calculates square sum of vector that is represented by list, each element can be represented by list - multidimensional elements. @param[in] list_vector (list): Input vector. @return (double) Square sum of vector. """ square_sum = 0.0 list_representation = (type(list_vector[0]) == list) for index_element in range(0, len(list_vector)): if list_representation is True: square_sum += sum(list_math_multiplication(list_vector[index_element], list_vector[index_element])) else: square_sum += list_vector[index_element] * list_vector[index_element] return square_sum def list_math_subtraction(a, b): """! @brief Calculates subtraction of two lists. @details Each element from list 'a' is subtracted by element from list 'b' accordingly. @param[in] a (list): List of elements that supports mathematical subtraction. @param[in] b (list): List of elements that supports mathematical subtraction. @return (list) Results of subtraction of two lists. """ return [a[i] - b[i] for i in range(len(a))] def list_math_substraction_number(a, b): """! @brief Calculates subtraction between list and number. @details Each element from list 'a' is subtracted by number 'b'. @param[in] a (list): List of elements that supports mathematical subtraction. @param[in] b (list): Value that supports mathematical subtraction. @return (list) Results of subtraction between list and number. """ return [a[i] - b for i in range(len(a))] def list_math_addition(a, b): """! @brief Addition of two lists. @details Each element from list 'a' is added to element from list 'b' accordingly. @param[in] a (list): List of elements that supports mathematic addition.. @param[in] b (list): List of elements that supports mathematic addition.. @return (list) Results of addtion of two lists. """ return [a[i] + b[i] for i in range(len(a))] def list_math_addition_number(a, b): """! @brief Addition between list and number. @details Each element from list 'a' is added to number 'b'. @param[in] a (list): List of elements that supports mathematic addition. @param[in] b (double): Value that supports mathematic addition. @return (list) Result of addtion of two lists. """ return [a[i] + b for i in range(len(a))] def list_math_division_number(a, b): """! @brief Division between list and number. @details Each element from list 'a' is divided by number 'b'. @param[in] a (list): List of elements that supports mathematic division. @param[in] b (double): Value that supports mathematic division. @return (list) Result of division between list and number. """ return [a[i] / b for i in range(len(a))] def list_math_division(a, b): """! @brief Division of two lists. @details Each element from list 'a' is divided by element from list 'b' accordingly. @param[in] a (list): List of elements that supports mathematic division. @param[in] b (list): List of elements that supports mathematic division. @return (list) Result of division of two lists. """ return [a[i] / b[i] for i in range(len(a))] def list_math_multiplication_number(a, b): """! @brief Multiplication between list and number. @details Each element from list 'a' is multiplied by number 'b'. @param[in] a (list): List of elements that supports mathematic division. @param[in] b (double): Number that supports mathematic division. @return (list) Result of division between list and number. """ return [a[i] * b for i in range(len(a))] def list_math_multiplication(a, b): """! @brief Multiplication of two lists. @details Each element from list 'a' is multiplied by element from list 'b' accordingly. @param[in] a (list): List of elements that supports mathematic multiplication. @param[in] b (list): List of elements that supports mathematic multiplication. @return (list) Result of multiplication of elements in two lists. """ return [a[i] * b[i] for i in range(len(a))] pyclustering-0.10.1.2/pyclustering/utils/color.py000077500000000000000000000024011375753423500220570ustar00rootroot00000000000000"""! @brief Colors used by pyclustering library for visualization. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ class color: """! @brief Consists titles of colors that are used by pyclustering for visualization. """ @staticmethod def get_color(sequential_index): """! @brief Returns color using round robin to avoid out of range exception. @param[in] sequential_index (uint): Index that should be converted to valid color index. @return (uint) Color from list color.TITLES. """ return color.TITLES[sequential_index % len(color.TITLES)] ## List of color titles that are used by pyclustering for visualization. TITLES = [ 'red', 'blue', 'darkgreen', 'gold', 'violet', 'deepskyblue', 'darkgrey', 'lightsalmon', 'deeppink', 'yellow', 'black', 'mediumspringgreen', 'orange', 'darkviolet', 'darkblue', 'silver', 'lime', 'pink', 'brown', 'bisque', 'dimgray', 'firebrick', 'darksalmon', 'chartreuse', 'skyblue', 'purple', 'fuchsia', 'palegoldenrod', 'coral', 'hotpink', 'gray', 'tan', 'crimson', 'teal', 'olive'] pyclustering-0.10.1.2/pyclustering/utils/dimension.py000077500000000000000000000055551375753423500227430ustar00rootroot00000000000000"""! @brief Data dimension analyser. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ class dimension_info: """! @brief Analyse input data to extract general information about data dimension. """ def __init__(self, data): if (data is None): raise NameError("Information about dimension of 'None' cannot be obtained"); self.__data = data; self.__dimensions = None; self.__maximum_dimension = None; self.__minimum_dimension = None; self.__width_dimension = None; self.__center_dimension = None; def get_dimensions(self): if (self.__dimensions is None): self.__calculate_dimension(); return self.__dimensions; def get_maximum_coordinate(self): if (self.__maximum_dimension is None): self.__calculate_maxmin_dimension_coordinate(); return self.__maximum_dimension; def get_minimum_coordinate(self): if (self.__minimum_dimension is None): self.__calculate_maxmin_dimension_coordinate(); return self.__minimum_dimension; def get_width(self): if (self.__width_dimension is None): self.__calculate_width(); return self.__width_dimension; def get_center(self): if (self.__center_dimension is None): self.__calculate_center(); return self.__center_dimension; def __calculate_dimension(self): self.__dimensions = len(self.__data[0]); def __calculate_maxmin_dimension_coordinate(self): self.__maximum_dimension = [self.__data[0][i] for i in range(self.get_dimensions())]; self.__minimum_dimension = [self.__data[0][i] for i in range(self.get_dimensions())]; for i in range(len(self.__data)): for dim in range(self.get_dimensions()): if (self.__maximum_dimension[dim] < self.__data[i][dim]): self.__maximum_dimension[dim] = self.__data[i][dim]; elif (self.__minimum_dimension[dim] > self.__data[i][dim]): self.__minimum_dimension[dim] = self.__data[i][dim]; def __calculate_width(self): self.__width_dimension = [0] * self.get_dimensions(); for dim in range(self.get_dimensions()): self.__width_dimension[dim] = self.get_maximum_coordinate()[dim] - self.get_minimum_coordinate()[dim]; def __calculate_center(self): self.__center_dimension = [0] * self.get_dimensions(); for dim in range(self.get_dimensions()): self.__center_dimension[dim] = (self.get_maximum_coordinate()[dim] + self.get_minimum_coordinate()[dim]) / 2.0; pyclustering-0.10.1.2/pyclustering/utils/examples/000077500000000000000000000000001375753423500222055ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/utils/examples/__init__.py000077500000000000000000000002171375753423500243210ustar00rootroot00000000000000"""! @brief Examples of usage of various utils. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """pyclustering-0.10.1.2/pyclustering/utils/examples/utils_examples.py000077500000000000000000000167221375753423500256300ustar00rootroot00000000000000"""! @brief Examples of usage utils. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import pyclustering.tests as utils; from pyclustering.cluster.agglomerative import agglomerative; from pyclustering.samples.definitions import SIMPLE_SAMPLES; import matplotlib.pyplot as plt; def cluster_distances(path_sample, amount_clusters): distances = ['euclidian', 'manhattan', 'avr-inter', 'avr-intra', 'variance']; sample = utils.read_sample(path_sample); agglomerative_instance = agglomerative(sample, amount_clusters); agglomerative_instance.process(); obtained_clusters = agglomerative_instance.get_clusters(); print("Measurements for:", path_sample); for index_cluster in range(len(obtained_clusters)): for index_neighbor in range(index_cluster + 1, len(obtained_clusters), 1): cluster1 = obtained_clusters[index_cluster]; cluster2 = obtained_clusters[index_neighbor]; center_cluster1 = utils.centroid(sample, cluster1); center_cluster2 = utils.centroid(sample, cluster2); for index_distance_type in range(len(distances)): distance = None; distance_type = distances[index_distance_type]; if (distance_type == 'euclidian'): distance = utils.euclidean_distance(center_cluster1, center_cluster2); elif (distance_type == 'manhattan'): distance = utils.manhattan_distance(center_cluster1, center_cluster2); elif (distance_type == 'avr-inter'): distance = utils.average_inter_cluster_distance(cluster1, cluster2, sample); elif (distance_type == 'avr-intra'): distance = utils.average_intra_cluster_distance(cluster1, cluster2, sample); elif (distance_type == 'variance'): distance = utils.variance_increase_distance(cluster1, cluster2, sample); print("\tDistance", distance_type, "from", index_cluster, "to", index_neighbor, "is:", distance); def display_two_dimensional_cluster_distances(path_sample, amount_clusters): distances = ['euclidian', 'manhattan', 'avr-inter', 'avr-intra', 'variance']; ajacency = [ [0] * amount_clusters for i in range(amount_clusters) ]; sample = utils.read_sample(path_sample); agglomerative_instance = agglomerative(sample, amount_clusters); agglomerative_instance.process(); obtained_clusters = agglomerative_instance.get_clusters(); stage = utils.draw_clusters(sample, obtained_clusters, display_result = False); for index_cluster in range(len(ajacency)): for index_neighbor_cluster in range(index_cluster + 1, len(ajacency)): if ( (index_cluster == index_neighbor_cluster) or (ajacency[index_cluster][index_neighbor_cluster] is True) ): continue; ajacency[index_cluster][index_neighbor_cluster] = True; ajacency[index_neighbor_cluster][index_cluster] = True; cluster1 = obtained_clusters[index_cluster]; cluster2 = obtained_clusters[index_neighbor_cluster]; center_cluster1 = utils.centroid(sample, cluster1); center_cluster2 = utils.centroid(sample, cluster2); x_maximum, x_minimum, y_maximum, y_minimum = None, None, None, None; x_index_maximum, y_index_maximum = 1, 1; if (center_cluster2[0] > center_cluster1[0]): x_maximum = center_cluster2[0]; x_minimum = center_cluster1[0]; x_index_maximum = 1; else: x_maximum = center_cluster1[0]; x_minimum = center_cluster2[0]; x_index_maximum = -1; if (center_cluster2[1] > center_cluster1[1]): y_maximum = center_cluster2[1]; y_minimum = center_cluster1[1]; y_index_maximum = 1; else: y_maximum = center_cluster1[1]; y_minimum = center_cluster2[1]; y_index_maximum = -1; print("Cluster 1:", cluster1, ", center:", center_cluster1); print("Cluster 2:", cluster2, ", center:", center_cluster2); stage.annotate(s = '', xy = (center_cluster1[0], center_cluster1[1]), xytext = (center_cluster2[0], center_cluster2[1]), arrowprops = dict(arrowstyle = '<->')); for index_distance_type in range(len(distances)): distance = None; distance_type = distances[index_distance_type]; if (distance_type == 'euclidian'): distance = utils.euclidean_distance(center_cluster1, center_cluster2); elif (distance_type == 'manhattan'): distance = utils.manhattan_distance(center_cluster1, center_cluster2); elif (distance_type == 'avr-inter'): distance = utils.average_inter_cluster_distance(cluster1, cluster2, sample); elif (distance_type == 'avr-intra'): distance = utils.average_intra_cluster_distance(cluster1, cluster2, sample); elif (distance_type == 'variance'): distance = utils.variance_increase_distance(cluster1, cluster2, sample); print("\tCluster distance -", distance_type, ":", distance); x_multiplier = index_distance_type + 3; if (x_index_maximum < 0): x_multiplier = len(distances) - index_distance_type + 3; y_multiplier = index_distance_type + 3; if (y_index_maximum < 0): y_multiplier = len(distances) - index_distance_type + 3; x_text = x_multiplier * (x_maximum - x_minimum) / (len(distances) + 6) + x_minimum; y_text = y_multiplier * (y_maximum - y_minimum) / (len(distances) + 6) + y_minimum; #print(x_text, y_text, "\n"); stage.text(x_text, y_text, distance_type + " {:.3f}".format(distance), fontsize = 9, color='blue'); plt.show(); def display_cluster_distances_simple_sample_01(): display_two_dimensional_cluster_distances(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2); def display_cluster_distances_simple_sample_02(): display_two_dimensional_cluster_distances(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3); def display_cluster_distances_simple_sample_03(): display_two_dimensional_cluster_distances(SIMPLE_SAMPLES.SAMPLE_SIMPLE3, 4); def print_cluster_distances_simple_sample_07(): cluster_distances(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2); def print_cluster_distances_simple_sample_08(): cluster_distances(SIMPLE_SAMPLES.SAMPLE_SIMPLE8, 4); display_cluster_distances_simple_sample_01(); display_cluster_distances_simple_sample_02(); display_cluster_distances_simple_sample_03(); print_cluster_distances_simple_sample_07(); print_cluster_distances_simple_sample_08(); pyclustering-0.10.1.2/pyclustering/utils/graph.py000077500000000000000000000245771375753423500220640ustar00rootroot00000000000000"""! @brief Graph representation (uses format GRPR). @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import matplotlib.pyplot as plt from matplotlib import colors from enum import IntEnum class type_graph_descr(IntEnum): """! @brief Enumeration of graph description. @details Matrix representation is list of lists where number of rows equals number of columns and each element of square matrix determines whether there is connection between two vertices. For example: [ [0, 1, 1], [1, 0, 1], [1, 1, 0] ]. Vector representation is list of lists where index of row corresponds to index of vertex and elements of row consists of indexes of connected vertices. For example: [ [1, 2], [0, 2], [0, 1] ]. """ ## Unknown graph representation. GRAPH_UNKNOWN = 0; ## Matrix graph representation. GRAPH_MATRIX_DESCR = 1; ## Vector graph representation. GRAPH_VECTOR_DESCR = 2; class graph: """! @brief Graph representation. """ def __init__(self, data, type_graph = None, space_descr = None, comments = None): """! @brief Constructor of graph. @param[in] data (list): Representation of graph. Considered as matrix if 'type_graph' is not specified. @param[in] type_graph (type_graph_descr): Type of graph representation in 'data'. @param[in] space_descr (list): Coordinates of each vertex that are used for graph drawing (can be omitted). @param[in] comments (string): Comments related to graph. """ self.__data = data; self.__space_descr = space_descr; self.__comments = comments; if (type_graph is not None): self.__type_graph = type_graph; else: self.__type_graph = type_graph_descr.GRAPH_MATRIX_DESCR; for row in self.__data: if (len(row) != len(self.__data)): self.__type_graph = type_graph_descr.GRAPH_VECTOR_DESCR; break; for element in row: if ( (element != 0) or (element != 1) ): self.__type_graph = type_graph_descr.GRAPH_VECTOR_DESCR; def __len__(self): """! @return (uint) Size of graph defined by number of vertices. """ return len(self.__data); @property def data(self): """! @return (list) Graph representation. """ return self.__data; @property def space_description(self): """! @return (list) Space description. """ if (self.__space_descr == [] or self.__space_descr is None): return None; return self.__space_descr; @property def comments(self): """! @return (string) Comments. """ return self.__comments; @property def type_graph_descr(self): """! @return (type_graph_descr) Type of graph representation. """ return self.__type_graph; def read_graph(filename): """! @brief Read graph from file in GRPR format. @param[in] filename (string): Path to file with graph in GRPR format. @return (graph) Graph that is read from file. """ file = open(filename, 'r'); comments = ""; space_descr = []; data = []; data_type = None; map_data_repr = dict(); # Used as a temporary buffer only when input graph is represented by edges. for line in file: if (line[0] == 'c' or line[0] == 'p'): comments += line[1:]; elif (line[0] == 'r'): node_coordinates = [float(val) for val in line[1:].split()]; if (len(node_coordinates) != 2): raise NameError('Invalid format of space description for node (only 2-dimension space is supported)'); space_descr.append( [float(val) for val in line[1:].split()] ); elif (line[0] == 'm'): if ( (data_type is not None) and (data_type != 'm') ): raise NameError('Invalid format of graph representation (only one type should be used)'); data_type = 'm'; data.append( [float(val) for val in line[1:].split()] ); elif (line[0] == 'v'): if ( (data_type is not None) and (data_type != 'v') ): raise NameError('Invalid format of graph representation (only one type should be used)'); data_type = 'v'; data.append( [float(val) for val in line[1:].split()] ); elif (line[0] == 'e'): if ( (data_type is not None) and (data_type != 'e') ): raise NameError('Invalid format of graph representation (only one type should be used)'); data_type = 'e'; vertices = [int(val) for val in line[1:].split()]; if (vertices[0] not in map_data_repr): map_data_repr[ vertices[0] ] = [ vertices[1] ]; else: map_data_repr[ vertices[0] ].append(vertices[1]) if (vertices[1] not in map_data_repr): map_data_repr[ vertices[1] ] = [ vertices[0] ]; else: map_data_repr[ vertices[1] ].append(vertices[0]); elif (len(line.strip()) == 0): continue; else: print(line); raise NameError('Invalid format of file with graph description'); # In case of edge representation result should be copied. if (data_type == 'e'): for index in range(len(map_data_repr)): data.append([0] * len(map_data_repr)); for index_neighbour in map_data_repr[index + 1]: data[index][index_neighbour - 1] = 1; file.close(); # Set graph description graph_descr = None; if (data_type == 'm'): graph_descr = type_graph_descr.GRAPH_MATRIX_DESCR; elif (data_type == 'v'): graph_descr = type_graph_descr.GRAPH_VECTOR_DESCR; elif (data_type == 'e'): graph_descr = type_graph_descr.GRAPH_MATRIX_DESCR; else: raise NameError('Invalid format of file with graph description'); if (space_descr != []): if (len(data) != len(space_descr)): raise NameError("Invalid format of file with graph - number of nodes is different in space representation and graph description"); return graph(data, graph_descr, space_descr, comments); def draw_graph(graph_instance, map_coloring = None): """! @brief Draw graph. @param[in] graph_instance (graph): Graph that should be drawn. @param[in] map_coloring (list): List of color indexes for each vertex. Size of this list should be equal to size of graph (number of vertices). If it's not specified (None) than graph without coloring will be dwarn. @warning Graph can be represented if there is space representation for it. """ if (graph_instance.space_description is None): raise NameError("The graph haven't got representation in space"); if (map_coloring is not None): if (len(graph_instance) != len(map_coloring)): raise NameError("Size of graph should be equal to size coloring map"); fig = plt.figure(); axes = fig.add_subplot(111); available_colors = ['#00a2e8', '#22b14c', '#ed1c24', '#fff200', '#000000', '#a349a4', '#ffaec9', '#7f7f7f', '#b97a57', '#c8bfe7', '#880015', '#ff7f27', '#3f48cc', '#c3c3c3', '#ffc90e', '#efe4b0', '#b5e61d', '#99d9ea', '#7092b4', '#ffffff']; if (map_coloring is not None): if (len(map_coloring) > len(available_colors)): raise NameError('Impossible to represent colored graph due to number of specified colors.'); x_maximum = -float('inf'); x_minimum = float('inf'); y_maximum = -float('inf'); y_minimum = float('inf'); for i in range(0, len(graph_instance.space_description), 1): if (graph_instance.type_graph_descr == type_graph_descr.GRAPH_MATRIX_DESCR): for j in range(i, len(graph_instance.space_description), 1): # draw connection between two points only one time if (graph_instance.data[i][j] == 1): axes.plot([graph_instance.space_description[i][0], graph_instance.space_description[j][0]], [graph_instance.space_description[i][1], graph_instance.space_description[j][1]], 'k-', linewidth = 1.5); elif (graph_instance.type_graph_descr == type_graph_descr.GRAPH_VECTOR_DESCR): for j in graph_instance.data[i]: if (i > j): # draw connection between two points only one time axes.plot([graph_instance.space_description[i][0], graph_instance.space_description[j][0]], [graph_instance.space_description[i][1], graph_instance.space_description[j][1]], 'k-', linewidth = 1.5); color_node = 'b'; if (map_coloring is not None): color_node = colors.hex2color(available_colors[map_coloring[i]]); axes.plot(graph_instance.space_description[i][0], graph_instance.space_description[i][1], color = color_node, marker = 'o', markersize = 20); if (x_maximum < graph_instance.space_description[i][0]): x_maximum = graph_instance.space_description[i][0]; if (x_minimum > graph_instance.space_description[i][0]): x_minimum = graph_instance.space_description[i][0]; if (y_maximum < graph_instance.space_description[i][1]): y_maximum = graph_instance.space_description[i][1]; if (y_minimum > graph_instance.space_description[i][1]): y_minimum = graph_instance.space_description[i][1]; plt.xlim(x_minimum - 0.5, x_maximum + 0.5); plt.ylim(y_minimum - 0.5, y_maximum + 0.5); plt.show();pyclustering-0.10.1.2/pyclustering/utils/metric.py000077500000000000000000000506211375753423500222330ustar00rootroot00000000000000"""! @brief Module provides various distance metrics - abstraction of the notion of distance in a metric space. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import numpy from enum import IntEnum class type_metric(IntEnum): """! @brief Enumeration of supported metrics in the module for distance calculation between two points. """ ## Euclidean distance, for more information see function 'euclidean_distance'. EUCLIDEAN = 0 ## Square Euclidean distance, for more information see function 'euclidean_distance_square'. EUCLIDEAN_SQUARE = 1 ## Manhattan distance, for more information see function 'manhattan_distance'. MANHATTAN = 2 ## Chebyshev distance, for more information see function 'chebyshev_distance'. CHEBYSHEV = 3 ## Minkowski distance, for more information see function 'minkowski_distance'. MINKOWSKI = 4 ## Canberra distance, for more information see function 'canberra_distance'. CANBERRA = 5 ## Chi square distance, for more information see function 'chi_square_distance'. CHI_SQUARE = 6 ## Gower distance, for more information see function 'gower_distance'. GOWER = 7 ## User defined function for distance calculation between two points. USER_DEFINED = 1000 class distance_metric: """! @brief Distance metric performs distance calculation between two points in line with encapsulated function, for example, euclidean distance or chebyshev distance, or even user-defined. @details Example of Euclidean distance metric: @code metric = distance_metric(type_metric.EUCLIDEAN) distance = metric([1.0, 2.5], [-1.2, 3.4]) @endcode Example of Chebyshev distance metric: @code metric = distance_metric(type_metric.CHEBYSHEV) distance = metric([0.0, 0.0], [2.5, 6.0]) @endcode In following example additional argument should be specified (generally, 'degree' is a optional argument that is equal to '2' by default) that is specific for Minkowski distance: @code metric = distance_metric(type_metric.MINKOWSKI, degree=4) distance = metric([4.0, 9.2, 1.0], [3.4, 2.5, 6.2]) @endcode User may define its own function for distance calculation. In this case input is two points, for example, you want to implement your own version of Manhattan distance: @code from pyclustering.utils.metric import distance_metric, type_metric def my_manhattan(point1, point2): dimension = len(point1) result = 0.0 for i in range(dimension): result += abs(point1[i] - point2[i]) * 0.1 return result metric = distance_metric(type_metric.USER_DEFINED, func=my_manhattan) distance = metric([2.0, 3.0], [1.0, 3.0]) @endcode """ def __init__(self, metric_type, **kwargs): """! @brief Creates distance metric instance for calculation distance between two points. @param[in] metric_type (type_metric): @param[in] **kwargs: Arbitrary keyword arguments (available arguments: 'numpy_usage' 'func' and corresponding additional argument for for specific metric types). Keyword Args:
- func (callable): Callable object with two arguments (point #1 and point #2) or (object #1 and object #2) in case of numpy usage. This argument is used only if metric is 'type_metric.USER_DEFINED'. - degree (numeric): Only for 'type_metric.MINKOWSKI' - degree of Minkowski equation. - max_range (array_like): Only for 'type_metric.GOWER' - max range in each dimension. 'data' can be used instead of this parameter. - data (array_like): Only for 'type_metric.GOWER' - input data that used for 'max_range' calculation. 'max_range' can be used instead of this parameter. - numpy_usage (bool): If True then numpy is used for calculation (by default is False). """ self.__type = metric_type self.__args = kwargs self.__func = self.__args.get('func', None) self.__numpy = self.__args.get('numpy_usage', False) self.__calculator = self.__create_distance_calculator() def __call__(self, point1, point2): """! @brief Calculates distance between two points. @param[in] point1 (list): The first point. @param[in] point2 (list): The second point. @return (double) Distance between two points. """ return self.__calculator(point1, point2) def get_type(self): """! @brief Return type of distance metric that is used. @return (type_metric) Type of distance metric. """ return self.__type def get_arguments(self): """! @brief Return additional arguments that are used by distance metric. @return (dict) Additional arguments. """ return self.__args def get_function(self): """! @brief Return user-defined function for calculation distance metric. @return (callable): User-defined distance metric function. """ return self.__func def enable_numpy_usage(self): """! @brief Start numpy for distance calculation. @details Useful in case matrices to increase performance. No effect in case of type_metric.USER_DEFINED type. """ self.__numpy = True if self.__type != type_metric.USER_DEFINED: self.__calculator = self.__create_distance_calculator() def disable_numpy_usage(self): """! @brief Stop using numpy for distance calculation. @details Useful in case of big amount of small data portion when numpy call is longer than calculation itself. No effect in case of type_metric.USER_DEFINED type. """ self.__numpy = False self.__calculator = self.__create_distance_calculator() def __create_distance_calculator(self): """! @brief Creates distance metric calculator. @return (callable) Callable object of distance metric calculator. """ if self.__numpy is True: return self.__create_distance_calculator_numpy() return self.__create_distance_calculator_basic() def __create_distance_calculator_basic(self): """! @brief Creates distance metric calculator that does not use numpy. @return (callable) Callable object of distance metric calculator. """ if self.__type == type_metric.EUCLIDEAN: return euclidean_distance elif self.__type == type_metric.EUCLIDEAN_SQUARE: return euclidean_distance_square elif self.__type == type_metric.MANHATTAN: return manhattan_distance elif self.__type == type_metric.CHEBYSHEV: return chebyshev_distance elif self.__type == type_metric.MINKOWSKI: return lambda point1, point2: minkowski_distance(point1, point2, self.__args.get('degree', 2)) elif self.__type == type_metric.CANBERRA: return canberra_distance elif self.__type == type_metric.CHI_SQUARE: return chi_square_distance elif self.__type == type_metric.GOWER: max_range = self.__get_gower_max_range() return lambda point1, point2: gower_distance(point1, point2, max_range) elif self.__type == type_metric.USER_DEFINED: return self.__func else: raise ValueError("Unknown type of metric: '%d'", self.__type) def __get_gower_max_range(self): """! @brief Returns max range for Gower distance using input parameters ('max_range' or 'data'). @return (numpy.array) Max range for Gower distance. """ max_range = self.__args.get('max_range', None) if max_range is None: data = self.__args.get('data', None) if data is None: raise ValueError("Gower distance requires 'data' or 'max_range' argument to construct metric.") max_range = numpy.max(data, axis=0) - numpy.min(data, axis=0) self.__args['max_range'] = max_range return max_range def __create_distance_calculator_numpy(self): """! @brief Creates distance metric calculator that uses numpy. @return (callable) Callable object of distance metric calculator. """ if self.__type == type_metric.EUCLIDEAN: return euclidean_distance_numpy elif self.__type == type_metric.EUCLIDEAN_SQUARE: return euclidean_distance_square_numpy elif self.__type == type_metric.MANHATTAN: return manhattan_distance_numpy elif self.__type == type_metric.CHEBYSHEV: return chebyshev_distance_numpy elif self.__type == type_metric.MINKOWSKI: return lambda object1, object2: minkowski_distance_numpy(object1, object2, self.__args.get('degree', 2)) elif self.__type == type_metric.CANBERRA: return canberra_distance_numpy elif self.__type == type_metric.CHI_SQUARE: return chi_square_distance_numpy elif self.__type == type_metric.GOWER: max_range = self.__get_gower_max_range() return lambda object1, object2: gower_distance_numpy(object1, object2, max_range) elif self.__type == type_metric.USER_DEFINED: return self.__func else: raise ValueError("Unknown type of metric: '%d'", self.__type) def euclidean_distance(point1, point2): """! @brief Calculate Euclidean distance between two vectors. @details The Euclidean between vectors (points) a and b is calculated by following formula: \f[ dist(a, b) = \sqrt{ \sum_{i=0}^{N}(a_{i} - b_{i})^{2} }; \f] Where N is a length of each vector. @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @return (double) Euclidean distance between two vectors. @see euclidean_distance_square, manhattan_distance, chebyshev_distance """ distance = euclidean_distance_square(point1, point2) return distance ** 0.5 def euclidean_distance_numpy(object1, object2): """! @brief Calculate Euclidean distance between two objects using numpy. @param[in] object1 (array_like): The first array_like object. @param[in] object2 (array_like): The second array_like object. @return (double) Euclidean distance between two objects. """ if len(object1.shape) > 1 or len(object2.shape) > 1: return numpy.sqrt(numpy.sum(numpy.square(object1 - object2), axis=1)) else: return numpy.sqrt(numpy.sum(numpy.square(object1 - object2))) def euclidean_distance_square(point1, point2): """! @brief Calculate square Euclidean distance between two vectors. \f[ dist(a, b) = \sum_{i=0}^{N}(a_{i} - b_{i})^{2}; \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @return (double) Square Euclidean distance between two vectors. @see euclidean_distance, manhattan_distance, chebyshev_distance """ distance = 0.0 for i in range(len(point1)): distance += (point1[i] - point2[i]) ** 2.0 return distance def euclidean_distance_square_numpy(object1, object2): """! @brief Calculate square Euclidean distance between two objects using numpy. @param[in] object1 (array_like): The first array_like object. @param[in] object2 (array_like): The second array_like object. @return (double) Square Euclidean distance between two objects. """ if len(object1.shape) > 1 or len(object2.shape) > 1: return numpy.sum(numpy.square(object1 - object2), axis=1).T else: return numpy.sum(numpy.square(object1 - object2)) def manhattan_distance(point1, point2): """! @brief Calculate Manhattan distance between between two vectors. \f[ dist(a, b) = \sum_{i=0}^{N}\left | a_{i} - b_{i} \right |; \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @return (double) Manhattan distance between two vectors. @see euclidean_distance_square, euclidean_distance, chebyshev_distance """ distance = 0.0 dimension = len(point1) for i in range(dimension): distance += abs(point1[i] - point2[i]) return distance def manhattan_distance_numpy(object1, object2): """! @brief Calculate Manhattan distance between two objects using numpy. @param[in] object1 (array_like): The first array_like object. @param[in] object2 (array_like): The second array_like object. @return (double) Manhattan distance between two objects. """ if len(object1.shape) > 1 or len(object2.shape) > 1: return numpy.sum(numpy.absolute(object1 - object2), axis=1).T else: return numpy.sum(numpy.absolute(object1 - object2)) def chebyshev_distance(point1, point2): """! @brief Calculate Chebyshev distance (maximum metric) between between two vectors. @details Chebyshev distance is a metric defined on a vector space where the distance between two vectors is the greatest of their differences along any coordinate dimension. \f[ dist(a, b) = \max_{}i\left (\left | a_{i} - b_{i} \right |\right ); \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @return (double) Chebyshev distance between two vectors. @see euclidean_distance_square, euclidean_distance, minkowski_distance """ distance = 0.0 dimension = len(point1) for i in range(dimension): distance = max(distance, abs(point1[i] - point2[i])) return distance def chebyshev_distance_numpy(object1, object2): """! @brief Calculate Chebyshev distance between two objects using numpy. @param[in] object1 (array_like): The first array_like object. @param[in] object2 (array_like): The second array_like object. @return (double) Chebyshev distance between two objects. """ if len(object1.shape) > 1 or len(object2.shape) > 1: return numpy.max(numpy.absolute(object1 - object2), axis=1).T else: return numpy.max(numpy.absolute(object1 - object2)) def minkowski_distance(point1, point2, degree=2): """! @brief Calculate Minkowski distance between two vectors. \f[ dist(a, b) = \sqrt[p]{ \sum_{i=0}^{N}\left(a_{i} - b_{i}\right)^{p} }; \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @param[in] degree (numeric): Degree of that is used for Minkowski distance. @return (double) Minkowski distance between two vectors. @see euclidean_distance """ distance = 0.0 for i in range(len(point1)): distance += (point1[i] - point2[i]) ** degree return distance ** (1.0 / degree) def minkowski_distance_numpy(object1, object2, degree=2): """! @brief Calculate Minkowski distance between objects using numpy. @param[in] object1 (array_like): The first array_like object. @param[in] object2 (array_like): The second array_like object. @param[in] degree (numeric): Degree of that is used for Minkowski distance. @return (double) Minkowski distance between two object. """ if len(object1.shape) > 1 or len(object2.shape) > 1: return numpy.power(numpy.sum(numpy.power(object1 - object2, degree), axis=1), 1/degree) else: return numpy.power(numpy.sum(numpy.power(object1 - object2, degree)), 1 / degree) def canberra_distance(point1, point2): """! @brief Calculate Canberra distance between two vectors. \f[ dist(a, b) = \sum_{i=0}^{N}\frac{\left | a_{i} - b_{i} \right |}{\left | a_{i} \right | + \left | b_{i} \right |}; \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @return (float) Canberra distance between two objects. """ distance = 0.0 for i in range(len(point1)): divider = abs(point1[i]) + abs(point2[i]) if divider == 0.0: continue distance += abs(point1[i] - point2[i]) / divider return distance def canberra_distance_numpy(object1, object2): """! @brief Calculate Canberra distance between two objects using numpy. @param[in] object1 (array_like): The first vector. @param[in] object2 (array_like): The second vector. @return (float) Canberra distance between two objects. """ with numpy.errstate(divide='ignore', invalid='ignore'): result = numpy.divide(numpy.abs(object1 - object2), numpy.abs(object1) + numpy.abs(object2)) if len(result.shape) > 1: return numpy.sum(numpy.nan_to_num(result), axis=1).T else: return numpy.sum(numpy.nan_to_num(result)) def chi_square_distance(point1, point2): """! @brief Calculate Chi square distance between two vectors. \f[ dist(a, b) = \sum_{i=0}^{N}\frac{\left ( a_{i} - b_{i} \right )^{2}}{\left | a_{i} \right | + \left | b_{i} \right |}; \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @return (float) Chi square distance between two objects. """ distance = 0.0 for i in range(len(point1)): divider = abs(point1[i]) + abs(point2[i]) if divider != 0.0: distance += ((point1[i] - point2[i]) ** 2.0) / divider return distance def chi_square_distance_numpy(object1, object2): """! @brief Calculate Chi square distance between two vectors using numpy. @param[in] object1 (array_like): The first vector. @param[in] object2 (array_like): The second vector. @return (float) Chi square distance between two objects. """ with numpy.errstate(divide='ignore', invalid='ignore'): result = numpy.divide(numpy.power(object1 - object2, 2), numpy.abs(object1) + numpy.abs(object2)) if len(result.shape) > 1: return numpy.sum(numpy.nan_to_num(result), axis=1).T else: return numpy.sum(numpy.nan_to_num(result)) def gower_distance(point1, point2, max_range): """! @brief Calculate Gower distance between two vectors. @details Implementation is based on the paper @cite article::utils::metric::gower. Gower distance is calculate using following formula: \f[ dist\left ( a, b \right )=\frac{1}{p}\sum_{i=0}^{p}\frac{\left | a_{i} - b_{i} \right |}{R_{i}}, \f] where \f$R_{i}\f$ is a max range for ith dimension. \f$R\f$ is defined in line following formula: \f[ R=max\left ( X \right )-min\left ( X \right ) \f] @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @param[in] max_range (array_like): Max range in each data dimension. @return (float) Gower distance between two objects. """ distance = 0.0 dimensions = len(point1) for i in range(dimensions): if max_range[i] != 0.0: distance += abs(point1[i] - point2[i]) / max_range[i] return distance / dimensions def gower_distance_numpy(point1, point2, max_range): """! @brief Calculate Gower distance between two vectors using numpy. @param[in] point1 (array_like): The first vector. @param[in] point2 (array_like): The second vector. @param[in] max_range (array_like): Max range in each data dimension. @return (float) Gower distance between two objects. """ with numpy.errstate(divide='ignore', invalid='ignore'): result = numpy.divide(numpy.abs(point1 - point2), max_range) if len(result.shape) > 1: return numpy.sum(numpy.nan_to_num(result), axis=1).T / len(result[0]) else: return numpy.sum(numpy.nan_to_num(result)) / len(point1) pyclustering-0.10.1.2/pyclustering/utils/sampling.py000077500000000000000000000062251375753423500225630ustar00rootroot00000000000000"""! @brief Module provides various random sampling algorithms. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import random def reservoir_r(data, n): """! @brief Performs data sampling using Reservoir Algorithm R. @details Algorithm complexity O(n). Implementation is based on paper @cite article::utils::sampling::1. Average number of uniform random variates: \f$N - n\f$. @param[in] data (list): Input data for sampling. @param[in] n (uint): Size of sample that should be extracted from 'data'. @return (list) Sample with size 'n' from 'data'. Generate random samples with 5 elements and with 3 elements using Reservoir Algorithm R: @code data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sample = reservoir_r(data, 5) # generate sample with 5 elements for 'data'. print(sample) sample = reservoir_r(data, 3) # generate sample with 3 elements for 'data'. print(sample) @endcode Output example for the code above: @code [20, 7, 17, 12, 11] [12, 2, 10] @endcode """ if n > len(data): raise ValueError("Incorrect sampling value 'n' (%d) that should be bigger then data size (%d).") random.seed() reservoir = data[0:n] for i in range(n, len(data)): m = random.randrange(0, i + 1) if m < n: reservoir[m] = data[i] return reservoir def reservoir_x(data, n): """! @brief Performs data sampling using Reservoir Algorithm X. @details Algorithm complexity O(n). Implementation is based on paper @cite article::utils::sampling::1. Average number of uniform random variates: \f[\approx 2n\ln \left (\frac{N}{n} \right)\f] @param[in] data (list): Input data for sampling. @param[in] n (uint): Size of sample that should be extracted from 'data'. @return (list) Sample with size 'n' from 'data'. Generate random sample with 5 elements using Reservoir Algorithm X: @code data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sample = reservoir_x(data, 10) # generate sample with 5 elements for 'data'. print(sample) @endcode Output example for the code above: @code [0, 20, 2, 16, 13, 15, 19, 18, 10, 9] @endcode """ def calculate_skip_value(t, size, skip): return pow(t + 1 - size, skip + 1) / pow(t + 1, skip + 1) def generate_skip_value(t, size): threshold, skip = random.random(), 0 while calculate_skip_value(t, size, skip) > threshold: skip += 1 return skip if n > len(data): raise ValueError("Incorrect sampling value 'n' (%d) that should be bigger then data size (%d).") random.seed() reservoir = data[0:n] i = n while i < len(data): i += generate_skip_value(i, n) if i < len(data): m = random.randrange(0, n) reservoir[m] = data[i] i += 1 return reservoir pyclustering-0.10.1.2/pyclustering/utils/tests/000077500000000000000000000000001375753423500215315ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/utils/tests/__init__.py000077500000000000000000000014071375753423500236470ustar00rootroot00000000000000"""! @brief Test runner for unit and integration tests of utils module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.suite_holder import suite_holder from pyclustering.utils.tests.integration import utils_integration_tests from pyclustering.utils.tests.unit import utils_unit_tests class utils_tests(suite_holder): def __init__(self): super().__init__() utils_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(utils_suite): utils_unit_tests.fill_suite(utils_suite) utils_integration_tests.fill_suite(utils_suite) pyclustering-0.10.1.2/pyclustering/utils/tests/integration/000077500000000000000000000000001375753423500240545ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/utils/tests/integration/__init__.py000077500000000000000000000013441375753423500261720ustar00rootroot00000000000000"""! @brief Integration-test runner for utils. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.suite_holder import suite_holder from pyclustering.utils.tests.integration import it_metric as utils_metric_integration_tests class utils_integration_tests(suite_holder): def __init__(self): super().__init__() utils_integration_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(integration_nnet_suite): integration_nnet_suite.addTests(unittest.TestLoader().loadTestsFromModule(utils_metric_integration_tests)) pyclustering-0.10.1.2/pyclustering/utils/tests/integration/it_metric.py000077500000000000000000000110451375753423500264110ustar00rootroot00000000000000"""! @brief Integration-tests for metrics. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') import numpy from pyclustering.core.metric_wrapper import metric_wrapper from pyclustering.utils.metric import type_metric, distance_metric class MetricUnitTest(unittest.TestCase): def testEuclideanMetric(self): metric_instance = metric_wrapper(type_metric.EUCLIDEAN, [], None) self.assertEqual(2.0, metric_instance([0.0, 0.0], [2.0, 0.0])) def testSquareEuclideanMetric(self): metric_instance = metric_wrapper(type_metric.EUCLIDEAN_SQUARE, [], None) self.assertEqual(4.0, metric_instance([0.0, 0.0], [2.0, 0.0])) def testManhattanMetric(self): metric_instance = metric_wrapper(type_metric.MANHATTAN, [], None) self.assertEqual(3.0, metric_instance([1.0, 2.0], [0.0, 0.0])) def testChebyshevMetric(self): metric_instance = metric_wrapper(type_metric.CHEBYSHEV, [], None) self.assertEqual(4.0, metric_instance([1.0, 4.0], [0.0, 0.0])) def testMinkowskiMetric(self): metric_instance = metric_wrapper(type_metric.MINKOWSKI, [2.0], None) self.assertEqual(2.0, metric_instance([0.0, 0.0], [2.0, 0.0])) def testCanberraMetric(self): metric_instance = metric_wrapper(type_metric.CANBERRA, [], None) self.assertEqual(0.0, metric_instance([0.0, 0.0], [0.0, 0.0])) self.assertEqual(2.0, metric_instance([0.0, 0.0], [1.0, 1.0])) self.assertEqual(1.0, metric_instance([0.75, 0.75], [0.25, 0.25])) self.assertEqual(0.0, metric_instance([-1.0, -1.0], [-1.0, -1.0])) self.assertEqual(0.4, metric_instance([-2.0, -2.0], [-3.0, -3.0])) def testChiSquareMetric(self): metric_instance = metric_wrapper(type_metric.CHI_SQUARE, [], None) self.assertEqual(0.0, metric_instance([0.0, 0.0], [0.0, 0.0])) self.assertEqual(2.0, metric_instance([0.0, 0.0], [1.0, 1.0])) self.assertEqual(0.5, metric_instance([0.75, 0.75], [0.25, 0.25])) self.assertEqual(0.0, metric_instance([-1.0, -1.0], [-1.0, -1.0])) self.assertEqual(0.4, metric_instance([-2.0, -2.0], [-3.0, -3.0])) def testGowerDistance(self): metric_instance = metric_wrapper(type_metric.GOWER, [0.0], None) self.assertEqual(0.0, metric_instance([0.0], [0.0])) metric_instance = metric_wrapper(type_metric.GOWER, [1.0, 1.0], None) self.assertEqual(1.0, metric_instance([0.0, 0.0], [1.0, 1.0])) metric_instance = metric_wrapper(type_metric.GOWER, [0.5, 0.5], None) self.assertEqual(1.0, metric_instance([0.75, 0.75], [0.25, 0.25])) metric_instance = metric_wrapper(type_metric.GOWER, [0.0, 0.0], None) self.assertEqual(0.0, metric_instance([-1.0, -1.0], [-1.0, -1.0])) metric_instance = metric_wrapper(type_metric.GOWER, [1.0, 1.0], None) self.assertEqual(1.0, metric_instance([-2.0, -2.0], [-3.0, -3.0])) def testBuildGowerDistanceFromMetricWithMaxRange(self): metric = distance_metric(type_metric.GOWER, max_range=[2.0, 0.0]) ccore_metric = metric_wrapper.create_instance(metric) self.assertEqual(0.5, ccore_metric([-3.0, -3.0], [-5.0, -3.0])) def testBuildGowerDistanceFromMetricWithNumpyMaxRange(self): metric = distance_metric(type_metric.GOWER, max_range=numpy.array([2.0, 0.0])) ccore_metric = metric_wrapper.create_instance(metric) self.assertEqual(0.5, ccore_metric([-3.0, -3.0], [-5.0, -3.0])) def testBuildGowerDistanceFromMetricWithData(self): metric = distance_metric(type_metric.GOWER, data=[[-3.0, -3.0], [-4.0, -3.0], [-4.5, -3.0], [-5.0, -3.0]]) ccore_metric = metric_wrapper.create_instance(metric) self.assertEqual(0.5, ccore_metric([-3.0, -3.0], [-5.0, -3.0])) def testBuildGowerDistanceFromMetricWithNumpyData(self): metric = distance_metric(type_metric.GOWER, data=numpy.array([[-3.0, -3.0], [-4.0, -3.0], [-4.5, -3.0], [-5.0, -3.0]])) ccore_metric = metric_wrapper.create_instance(metric) self.assertEqual(0.5, ccore_metric([-3.0, -3.0], [-5.0, -3.0])) # TODO: doesn't work for some platforms. #def testUserDefinedMetric(self): # user_metric = lambda p1, p2 : p1[0] + p2[0]; # metric_instance = metric_wrapper(type_metric.USER_DEFINED, [], user_metric); # assertion.eq(2.0, metric_instance([0.0, 0.0], [2.0, 0.0])); # assertion.eq(4.0, metric_instance([3.0, 2.0], [1.0, 5.0]));pyclustering-0.10.1.2/pyclustering/utils/tests/sampling_templates.py000077500000000000000000000022471375753423500260030ustar00rootroot00000000000000"""! @brief Test templates for sampling module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import collections from scipy import stats from pyclustering.tests.assertion import assertion class sampling_test_template: @staticmethod def random_sampling(data, n, algorithm, repeat, ccore=True): for _ in range(repeat): sample = algorithm(data, n) unique_values = set(sample) assertion.eq(n, len(sample)) assertion.eq(len(unique_values), len(sample)) @staticmethod def uniform_distribution(data, n, algorithm, repeat, supremum_cdf=0.06, ccore=True): # Supremum CDF < 0.06 is almost about uniform distribution (for R algorithm). # Supremum CDF < 0.4 is for X algorithm min_value = min(data) max_value = max(data) scale = max_value - min_value stream = collections.deque() for _ in range(repeat): stream += algorithm(data, n) D, pvalue = stats.kstest(stream, stats.uniform(loc=min_value, scale=scale).cdf) assertion.gt(supremum_cdf, D) pyclustering-0.10.1.2/pyclustering/utils/tests/unit/000077500000000000000000000000001375753423500225105ustar00rootroot00000000000000pyclustering-0.10.1.2/pyclustering/utils/tests/unit/__init__.py000077500000000000000000000023141375753423500246240ustar00rootroot00000000000000"""! @brief Unit-test runner for utils module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.tests.suite_holder import suite_holder from pyclustering.utils.tests.unit import ut_dimension as dimension_unit_tests from pyclustering.utils.tests.unit import ut_metric as metric_unit_tests from pyclustering.utils.tests.unit import ut_sampling as sampling_unit_tests from pyclustering.utils.tests.unit import ut_utils as utils_general_unit_tests class utils_unit_tests(suite_holder): def __init__(self): super().__init__() utils_unit_tests.fill_suite(self.get_suite()) @staticmethod def fill_suite(utils_suite): utils_suite.addTests(unittest.TestLoader().loadTestsFromModule(dimension_unit_tests)) utils_suite.addTests(unittest.TestLoader().loadTestsFromModule(metric_unit_tests)) utils_suite.addTests(unittest.TestLoader().loadTestsFromModule(sampling_unit_tests)) utils_suite.addTests(unittest.TestLoader().loadTestsFromModule(utils_general_unit_tests)) pyclustering-0.10.1.2/pyclustering/utils/tests/unit/ut_dimension.py000077500000000000000000000011471375753423500255650ustar00rootroot00000000000000"""! Unit-tests for dimension analyser. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest; # Generate images without having a window appear. import matplotlib; matplotlib.use('Agg'); from pyclustering.utils.dimension import dimension_info; class DimensionUnitTest(unittest.TestCase): def testGetDimension(self): info = dimension_info([ [1], [2], [3], [4], [5] ]); assert 1 == info.get_dimensions(); info = dimension_info([[1, 2], [3, 4]]); assert 2 == info.get_dimensions(); pyclustering-0.10.1.2/pyclustering/utils/tests/unit/ut_metric.py000077500000000000000000000220111375753423500250540ustar00rootroot00000000000000"""! Unit-tests for metric functions. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') import numpy from pyclustering.tests.assertion import assertion import pyclustering.utils.metric as metric class MetricUnitTest(unittest.TestCase): def testCalculateMetric(self): assertion.eq(1.0, metric.distance_metric(metric.type_metric.EUCLIDEAN)([0.0, 1.0], [0.0, 0.0])) assertion.eq(4.0, metric.distance_metric(metric.type_metric.EUCLIDEAN_SQUARE)([2.0, 2.0], [4.0, 2.0])) assertion.eq(4.0, metric.distance_metric(metric.type_metric.MANHATTAN)([1.0, 1.0], [-1.0, -1.0])) assertion.eq(2.0, metric.distance_metric(metric.type_metric.CHEBYSHEV)([2.0, -2.0], [0.0, 0.0])) assertion.eq(2.0, metric.distance_metric(metric.type_metric.MINKOWSKI)([-3.0, -3.0], [-5.0, -3.0])) assertion.eq(2.0, metric.distance_metric(metric.type_metric.MINKOWSKI, degree=2)([-3.0, -3.0], [-5.0, -3.0])) assertion.eq(0.5, metric.distance_metric(metric.type_metric.GOWER, max_range=([2.0, 0.0]))([-3.0, -3.0], [-5.0, -3.0])) assertion.eq(0.5, metric.distance_metric(metric.type_metric.GOWER, data=[[-3.0, -3.0], [-4.0, -3.0], [-4.5, -3.0], [-5.0, -3.0]])([-3.0, -3.0],[-5.0, -3.0])) assertion.eq(4.0, metric.distance_metric(metric.type_metric.USER_DEFINED, func=metric.euclidean_distance_square)([2.0, 2.0], [4.0, 2.0])) user_function = lambda point1, point2: point1[0] + point2[0] + 2 assertion.eq(5.0, metric.distance_metric(metric.type_metric.USER_DEFINED, func=user_function)([2.0, 3.0], [1.0, 3.0])) def testEuclideanDistance(self): assertion.eq(0.0, metric.euclidean_distance([0], [0])) assertion.eq(0.0, metric.euclidean_distance_numpy(numpy.array([0]), numpy.array([0]))) assertion.eq(1.0, metric.euclidean_distance([0.0, 1.0], [0.0, 0.0])) assertion.eq(1.0, metric.euclidean_distance_numpy(numpy.array([0.0, 1.0]), numpy.array([0.0, 0.0]))) assertion.eq(2.0, metric.euclidean_distance([3.0, 3.0], [5.0, 3.0])) assertion.eq(2.0, metric.euclidean_distance_numpy(numpy.array([3.0, 3.0]), numpy.array([5.0, 3.0]))) assertion.eq(2.0, metric.euclidean_distance([-3.0, -3.0], [-5.0, -3.0])) assertion.eq(2.0, metric.euclidean_distance_numpy(numpy.array([-3.0, -3.0]), numpy.array([-5.0, -3.0]))) def testEuclideanDistanceSquare(self): assertion.eq(0.0, metric.euclidean_distance_square([0], [0])) assertion.eq(1.0, metric.euclidean_distance_square([0.0, 1.0], [0.0, 0.0])) assertion.eq(4.0, metric.euclidean_distance_square([2.0, 2.0], [4.0, 2.0])) assertion.eq(4.0, metric.euclidean_distance_square([-2.0, 2.0], [-4.0, 2.0])) def testManhattanDistance(self): assertion.eq(0.0, metric.manhattan_distance([0], [0])) assertion.eq(1.0, metric.manhattan_distance([0.0, 1.0], [0.0, 0.0])) assertion.eq(2.0, metric.manhattan_distance([1.0, 1.0], [0.0, 0.0])) assertion.eq(4.0, metric.manhattan_distance([1.0, 1.0], [-1.0, -1.0])) assertion.eq(2.0, metric.manhattan_distance([-1.0, -1.0], [-2.0, -2.0])) def testChebyshevDistance(self): assertion.eq(0.0, metric.chebyshev_distance([0], [0])) assertion.eq(1.0, metric.chebyshev_distance([1.0, 0.0], [0.0, 0.0])) assertion.eq(1.0, metric.chebyshev_distance([1.0, 1.0], [0.0, 0.0])) assertion.eq(1.0, metric.chebyshev_distance([1.0, -1.0], [0.0, 0.0])) assertion.eq(2.0, metric.chebyshev_distance([2.0, 0.0], [0.0, 0.0])) assertion.eq(2.0, metric.chebyshev_distance([2.0, 1.0], [0.0, 0.0])) assertion.eq(2.0, metric.chebyshev_distance([2.0, -2.0], [0.0, 0.0])) assertion.eq(3.0, metric.chebyshev_distance([2.0, -2.0], [-1.0, -1.0])) def testMinkowskiDistance(self): assertion.eq(0.0, metric.minkowski_distance([0], [0])) assertion.eq(0.0, metric.minkowski_distance([0], [0], 2)) assertion.eq(-2.0, metric.minkowski_distance([3.0, 3.0], [5.0, 3.0], 1)) assertion.eq(2.0, metric.minkowski_distance([3.0, 3.0], [5.0, 3.0], 2)) assertion.eq(2.0, metric.minkowski_distance([3.0, 3.0], [5.0, 3.0], 4)) def testCanberraDistance(self): assertion.eq(0.0, metric.canberra_distance([0], [0])) assertion.eq(0.0, metric.canberra_distance_numpy(numpy.array([0]), numpy.array([0]))) assertion.eq(2.0, metric.canberra_distance([0.0, 0.0], [1.0, 1.0])) assertion.eq(2.0, metric.canberra_distance_numpy(numpy.array([0.0, 0.0]), numpy.array([1.0, 1.0]))) assertion.eq(1.0, metric.canberra_distance([0.75, 0.75], [0.25, 0.25])) assertion.eq(1.0, metric.canberra_distance_numpy(numpy.array([0.75, 0.75]), numpy.array([0.25, 0.25]))) assertion.eq(0.0, metric.canberra_distance([-1.0, -1.0], [-1.0, -1.0])) assertion.eq(0.0, metric.canberra_distance_numpy(numpy.array([-1.0, -1.0]), numpy.array([-1.0, -1.0]))) assertion.eq(0.4, metric.canberra_distance([-2.0, -2.0], [-3.0, -3.0])) assertion.eq(0.4, metric.canberra_distance_numpy(numpy.array([-2.0, -2.0]), numpy.array([-3.0, -3.0]))) def testChiSquareDistance(self): assertion.eq(0.0, metric.chi_square_distance([0], [0])) assertion.eq(0.0, metric.chi_square_distance_numpy(numpy.array([0]), numpy.array([0]))) assertion.eq(2.0, metric.chi_square_distance([0.0, 0.0], [1.0, 1.0])) assertion.eq(2.0, metric.chi_square_distance_numpy(numpy.array([0.0, 0.0]), numpy.array([1.0, 1.0]))) assertion.eq(0.5, metric.chi_square_distance([0.75, 0.75], [0.25, 0.25])) assertion.eq(0.5, metric.chi_square_distance_numpy(numpy.array([0.75, 0.75]), numpy.array([0.25, 0.25]))) assertion.eq(0.0, metric.chi_square_distance([-1.0, -1.0], [-1.0, -1.0])) assertion.eq(0.0, metric.chi_square_distance_numpy(numpy.array([-1.0, -1.0]), numpy.array([-1.0, -1.0]))) assertion.eq(0.4, metric.chi_square_distance([-2.0, -2.0], [-3.0, -3.0])) assertion.eq(0.4, metric.chi_square_distance_numpy(numpy.array([-2.0, -2.0]), numpy.array([-3.0, -3.0]))) def testGowerDistance(self): assertion.eq(0.0, metric.gower_distance([0], [0], [0.0])) assertion.eq(0.0, metric.gower_distance_numpy(numpy.array([0]), numpy.array([0]), numpy.array([0.0]))) assertion.eq(1.0, metric.gower_distance([0.0, 0.0], [1.0, 1.0], [1.0, 1.0])) assertion.eq(1.0, metric.gower_distance_numpy(numpy.array([0.0, 0.0]), numpy.array([1.0, 1.0]), numpy.array([1.0, 1.0]))) assertion.eq(1.0, metric.gower_distance([0.75, 0.75], [0.25, 0.25], [0.5, 0.5])) assertion.eq(1.0, metric.gower_distance_numpy(numpy.array([0.75, 0.75]), numpy.array([0.25, 0.25]), numpy.array([0.5, 0.5]))) assertion.eq(0.0, metric.gower_distance([-1.0, -1.0], [-1.0, -1.0], [0.0, 0.0])) assertion.eq(0.0, metric.gower_distance_numpy(numpy.array([-1.0, -1.0]), numpy.array([-1.0, -1.0]), numpy.array([0.0, 0.0]))) assertion.eq(1.0, metric.gower_distance([-2.0, -2.0], [-3.0, -3.0], [1.0, 1.0])) assertion.eq(1.0, metric.gower_distance_numpy(numpy.array([-2.0, -2.0]), numpy.array([-3.0, -3.0]), numpy.array([1.0, 1.0]))) def testGowerDistanceIntegrity(self): a, b = [1.2, 3.4], [1.0, 2.2] npa, npb = numpy.array(a), numpy.array(b) gower = metric.distance_metric(metric.type_metric.GOWER, data=[a, b], numpy_usage=False) gower_numpy = metric.distance_metric(metric.type_metric.GOWER, data=numpy.array([a, b]), numpy_usage=True) assertion.eq(gower(a, b), gower_numpy(npa, npb)) def testCommonAndNumPyMetricsTwoDimension(self): a = [1.2, 3.4] b = [5.4, -7.1] npa = numpy.array(a) npb = numpy.array(b) assertion.eq(metric.euclidean_distance(a, b), metric.euclidean_distance_numpy(npa, npb)) assertion.eq(metric.euclidean_distance_square(a, b), metric.euclidean_distance_square_numpy(npa, npb)) assertion.eq(metric.manhattan_distance(a, b), metric.manhattan_distance_numpy(npa, npb)) assertion.eq(metric.chebyshev_distance(a, b), metric.chebyshev_distance_numpy(npa, npb)) assertion.eq(metric.minkowski_distance(a, b, 2), metric.minkowski_distance_numpy(npa, npb, 2)) assertion.eq(metric.minkowski_distance(a, b, 4), metric.minkowski_distance_numpy(npa, npb, 4)) assertion.eq(metric.canberra_distance(a, b), metric.canberra_distance_numpy(npa, npb)) assertion.eq(metric.chi_square_distance(a, b), metric.chi_square_distance_numpy(npa, npb)) assertion.eq(metric.chi_square_distance(a, b), metric.chi_square_distance_numpy(npa, npb)) gower = metric.distance_metric(metric.type_metric.GOWER, data=[a, b], numpy_usage=False) gower_numpy = metric.distance_metric(metric.type_metric.GOWER, data=[a, b], numpy_usage=True) assertion.eq(gower(a, b), gower_numpy(npa, npb)) pyclustering-0.10.1.2/pyclustering/utils/tests/unit/ut_sampling.py000077500000000000000000000042021375753423500254050ustar00rootroot00000000000000"""! Unit-tests for sampling functions. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') from pyclustering.utils.tests.sampling_templates import sampling_test_template from pyclustering.utils.sampling import reservoir_x, reservoir_r class sampling_unit_test(unittest.TestCase): def testReservoirR(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.random_sampling(sample, 10, reservoir_r, 10) def testTheSameSizeReservoirR(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.random_sampling(sample, 20, reservoir_r, 10) def testOneElementReservoirR(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.random_sampling(sample, 1, reservoir_r, 10) def testUniformDistributionReservoirR(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.uniform_distribution(sample, 1, reservoir_r, 2500) def testReservoirX(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.random_sampling(sample, 10, reservoir_x, 10) def testTheSameSizeReservoirX(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.random_sampling(sample, 20, reservoir_x, 10) def testOneElementReservoirX(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.random_sampling(sample, 1, reservoir_x, 10) def testUniformDistributionReservoirX(self): sample = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] sampling_test_template.uniform_distribution(sample, 1, reservoir_x, 2500, 0.3) pyclustering-0.10.1.2/pyclustering/utils/tests/unit/ut_utils.py000077500000000000000000000234621375753423500247440ustar00rootroot00000000000000"""! Unit-tests for utils module. @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import unittest # Generate images without having a window appear. import matplotlib matplotlib.use('Agg') import numpy from pyclustering.cluster.kmeans import kmeans from pyclustering.cluster.center_initializer import kmeans_plusplus_initializer import pyclustering.utils as utils from pyclustering.utils import euclidean_distance from pyclustering.utils import average_neighbor_distance from pyclustering.utils import read_sample from pyclustering.utils import data_corners from pyclustering.utils import norm_vector from pyclustering.utils import rgb2gray from pyclustering.utils import extract_number_oscillations from pyclustering.utils import draw_clusters from pyclustering.samples.definitions import SIMPLE_SAMPLES, IMAGE_SIMPLE_SAMPLES class Test(unittest.TestCase): def testEuclideanDistance(self): point1 = [1, 2] point2 = [1, 3] point3 = [4, 6] # Tests for euclidean_distance assert euclidean_distance(point1, point2) == 1 assert euclidean_distance(point1, point1) == 0 assert euclidean_distance(point1, point3) == 5 def testFloatEuclideanDistance(self): assert euclidean_distance(0.5, 1.5) == 1 assert self.float_comparasion(euclidean_distance(1.6, 1.4), 0.2) assert self.float_comparasion(euclidean_distance(4.23, 2.14), 2.09) def testAverageNeighborFourDistance(self): points = [[0.0, 0.0], [0.0, 1.0], [1.0, 1.0], [1.0, 0.0]] assert average_neighbor_distance(points, 1) == 1.0; assert average_neighbor_distance(points, 2) == 1.0; assert self.float_comparasion(average_neighbor_distance(points, 3), 1.1381) def testAverageNeighborFourDistanceNegativeValues(self): points = [[0.0, 0.0], [0.0, -1.0], [-1.0, -1.0], [-1.0, 0.0]] assert average_neighbor_distance(points, 1) == 1.0; assert average_neighbor_distance(points, 2) == 1.0; assert self.float_comparasion(average_neighbor_distance(points, 3), 1.1381) def float_comparasion(self, float1, float2, eps = 0.0001): return (float1 + eps) > float2 and (float1 - eps) < float2 def templateDataCorners(self, data_path, data_filter, expected_result): sample = read_sample(data_path) result = data_corners(sample, data_filter) assert result == expected_result def testDataCornersSampleSimple01(self): self.templateDataCorners(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, None, ([3.423602, 5.364477], [6.978178, 7.850364])) def testDataCornersSampleSimple01WithFilter(self): self.templateDataCorners(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, [0, 1, 2, 3, 4], ([3.423602, 5.364477], [3.936690, 5.663041])) def testDataCornersSampleSimple02(self): self.templateDataCorners(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, None, ([3.177711, 0.022688], [7.835975, 6.704815])) def testDataCornersSampleSimple02WithFilter(self): self.templateDataCorners(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, [10, 11, 12, 13, 14], ([7.062946, 6.022702], [7.500097, 6.704815])) def testVectorLength(self): assert 10 == norm_vector([6, 8]) assert self.float_comparasion(4.219, norm_vector([2.2, 3.6]), 0.001) assert self.float_comparasion(5.280, norm_vector([-4.8, -2.2]), 0.001) def testRgbToGray(self): rgb_pixels = [[127, 127, 127], [255, 255, 255], [0, 0, 0]] result = rgb2gray(rgb_pixels) assert 3 == len(result) assert 127 == round(result[0]) assert 255 == round(result[1]) assert 0 == round(result[2]) def testExtractNumberOscillationsMonotonicDown(self): value = [[10.0], [9.5], [9.0], [8.5], [8.0], [7.5], [7.0], [6.5], [6.0], [5.5], [5.0]] assert extract_number_oscillations(value, 0, 8.0) == 0; def testExtractNumberOscillationsMonotonicUp(self): value = [[1.0], [1.5], [2.0], [2.5], [3.0], [3.5], [4.0], [4.5], [5.0], [5.5], [6.0]] assert extract_number_oscillations(value, 0, 4.0) == 0 def testExtractNumberOscillationsMonotonicUpSlightlyDown(self): value = [[1.0], [1.5], [2.0], [2.5], [3.0], [3.5], [4.0], [4.5], [5.0], [4.5], [4.0]] assert extract_number_oscillations(value, 0, 2.0) == 0 def testExtractNumberOscillationsMonotonicDownSlightlyUp(self): value = [[10.0], [9.5], [9.0], [8.5], [8.0], [7.5], [7.0], [6.5], [7.0], [7.1], [7.3]] assert extract_number_oscillations(value, 0, 7.5) == 0 def testExtractNumberOscillationsOnePeriod(self): value = [[0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 0.5) == 1 def testExtractNumberOscillationsOnePeriodWithHalf(self): value = [[0.0], [1.0], [0.0], [1.0]] assert extract_number_oscillations(value, 0, 0.5) == 1 def testExtractNumberOscillationsTwoPeriods(self): value = [[0.0], [1.0], [0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 0.5) == 2 def testExtractNumberOscillationsThreePeriods(self): value = [[0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 0.5) == 3 def testExtractNumberOscillationsFourPeriods(self): value = [[0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 0.5) == 4 def testExtractNumberOscillationsFourPeriodsOnThreshold(self): value = [[0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 1.0) == 4 def testExtractNumberOscillationsFourPeriodsUnderThreshold(self): value = [[0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 1.5) == 0 def testExtractNumberOscillationsUpDownUp(self): value = [[1.0], [0.0], [1.0]] assert extract_number_oscillations(value, 0, 0.5) == 0 def testExtractNumberOscillationsDownUpDown(self): value = [[0.0], [1.0], [0.0]] assert extract_number_oscillations(value, 0, 0.5) == 1 def templateDrawClustersNoFailure(self, data_path, amount_clusters): sample = read_sample(data_path) initial_centers = kmeans_plusplus_initializer(sample, amount_clusters).initialize() kmeans_instance = kmeans(sample, initial_centers, amount_clusters) kmeans_instance.process() clusters = kmeans_instance.get_clusters() ax = draw_clusters(sample, clusters) assert None != ax; def testDrawClustersOneCluster(self): self.templateDrawClustersNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 1) def testDrawClustersTwoClusters(self): self.templateDrawClustersNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2) def testDrawClustersThreeClusters(self): self.templateDrawClustersNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE2, 3) def testDrawClustersOneDimension(self): self.templateDrawClustersNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE7, 2) def testDrawClustersTwoDimensions(self): self.templateDrawClustersNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE1, 2) def testDrawClustersThreeDimensions(self): self.templateDrawClustersNoFailure(SIMPLE_SAMPLES.SAMPLE_SIMPLE11, 2) def testDrawSegmentationResultNoFailure(self): data = utils.read_image(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01) kmeans_instance = kmeans(data, [[255, 0, 0], [0, 0, 255], [180, 136, 0], [255, 255, 255]]) kmeans_instance.process() clusters = kmeans_instance.get_clusters() utils.draw_image_mask_segments(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, clusters) utils.draw_image_color_segments(IMAGE_SIMPLE_SAMPLES.IMAGE_SIMPLE01, clusters) def testCalculateMatrixDistance(self): data = [[0], [2], [4]] matrix = utils.calculate_distance_matrix(data) assert matrix == [[0.0, 2.0, 4.0], [2.0, 0.0, 2.0], [4.0, 2.0, 0.0]] def testCalculateMatrixDistanceAsNumPy(self): data = numpy.array([[0], [2], [4]]) matrix = utils.calculate_distance_matrix(data) self.assertEqual(matrix, [[0.0, 2.0, 4.0], [2.0, 0.0, 2.0], [4.0, 2.0, 0.0]]) def templateCalculateMatrixDistance(self, data, matrix_expected): matrix = utils.calculate_distance_matrix(data) self.assertEqual(len(matrix), len(matrix_expected)) for i in range(len(matrix)): self.assertEqual(len(matrix[i]), len(matrix_expected[i])) for j in range(len(matrix[i])): if numpy.isnan(matrix_expected[i][j]): self.assertTrue(numpy.isnan(matrix[i][j])) else: self.assertEqual(matrix[i][j], matrix_expected[i][j]) def testCalculateMatrixDistanceAsNumPyWithNan(self): data = numpy.array([[0], [2], [numpy.nan]]) matrix_expected = [[0.0, 2.0, numpy.nan], [2.0, 0.0, numpy.nan], [numpy.nan, numpy.nan, numpy.nan]] self.templateCalculateMatrixDistance(data, matrix_expected) def testCalculateMatrixDistanceAsNumPyWithNan2Dimensional1(self): data = numpy.array([[0.0, 1.0], [2.0, 0.0], [numpy.nan, 0.0]]) matrix_expected = [[0.0, 2.23606797749979, numpy.nan], [2.23606797749979, 0.0, numpy.nan], [numpy.nan, numpy.nan, numpy.nan]] self.templateCalculateMatrixDistance(data, matrix_expected) def testCalculateMatrixDistanceAsNumPyWithNan2Dimensional2(self): data = numpy.array([[0.0, 1.0], [2.0, numpy.nan], [numpy.nan, numpy.nan]]) matrix_expected = [[0.0, numpy.nan, numpy.nan], [numpy.nan, numpy.nan, numpy.nan], [numpy.nan, numpy.nan, numpy.nan]] self.templateCalculateMatrixDistance(data, matrix_expected) pyclustering-0.10.1.2/setup.py000077500000000000000000000076051375753423500162240ustar00rootroot00000000000000"""! @authors Andrei Novikov (pyclustering@yandex.ru) @date 2014-2020 @copyright BSD-3-Clause """ import os import pyclustering from setuptools import setup from setuptools import find_packages from setuptools.command.test import test as command def load_readme(): readme_file = 'PKG-INFO.rst' if os.path.isfile(readme_file): with open(readme_file) as file_descr: return file_descr.read() return "pyclustering is a python data mining library (cluster-analysis, graph coloring, oscillatory networks)" class setup_tests_runner(command): def run_tests(self): from pyclustering.tests.tests_runner import tests_runner tests_runner.run() setup( name='pyclustering', packages=find_packages(), version=pyclustering.__version__, description='pyclustring is a python data mining library', long_description=load_readme(), url='https://github.com/annoviko/pyclustering', project_urls={ 'Homepage': 'https://pyclustering.github.io/', 'Repository': 'https://github.com/annoviko/pyclustering', 'Documentation': 'https://pyclustering.github.io/docs/0.10.1/html/index.html', 'Bug Tracker': 'https://github.com/annoviko/pyclustering/issues' }, license='BSD-3-Clause', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: Education', 'Intended Audience :: Information Technology', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Natural Language :: English', 'Operating System :: Microsoft', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Operating System :: Unix', 'Operating System :: iOS', 'Programming Language :: C', 'Programming Language :: C++', 'Programming Language :: Python :: 3', 'Topic :: Education', 'Topic :: Scientific/Engineering :: Artificial Intelligence', 'Topic :: Scientific/Engineering :: Bio-Informatics', 'Topic :: Scientific/Engineering :: Information Analysis', 'Topic :: Scientific/Engineering :: Visualization', 'Topic :: Software Development :: Libraries' ], keywords='pyclustering data-mining clustering cluster-analysis machine-learning neural-network oscillatory-network', author='Andrei Novikov', author_email='pyclustering@yandex.ru', install_requires=['scipy>=1.1.0', 'matplotlib>=3.0.0', 'numpy>=1.15.2', 'Pillow>=5.2.0'], python_requires='>=3.6', package_data={ 'pyclustering.samples': ['samples/famous/*.*', 'samples/fcps/*.*', 'samples/simple/*.*', 'graphs/*.*', 'images/*.*', 'images/digits/*.*'], 'pyclustering.core': ['64-bit/linux/libpyclustering.so', '32-bit/linux/libpyclustering.so', '64-bit/win/pyclustering.dll', '32-bit/win/pyclustering.dll', '64-bit/macos/libpyclustering.so'], }, data_files=[('', ['LICENSE', 'CHANGES', 'README.rst', 'PKG-INFO.rst'])], cmdclass={'test': setup_tests_runner} )